Initial commit

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-11-07 10:47:18 +08:00
co-authored by Claude Opus 4.7
commit 79ac89b458
708 changed files with 151634 additions and 0 deletions
+224
View File
@@ -0,0 +1,224 @@
package aicommentrecord
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.AiCommentRecord)
indexes := []mongo.IndexModel{
{Keys: bson.D{{Key: FN.AiCommentRecord.Key, Value: 1}}, Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{FN.AiCommentRecord.Key: bson.M{"$exists": true}})},
{Keys: bson.D{{Key: FN.AiCommentRecord.Vid, Value: 1}, {Key: FN.AiCommentRecord.TaskId, Value: 1}}},
{Keys: bson.D{{Key: FN.AiCommentRecord.ObjType, Value: 1}, {Key: FN.AiCommentRecord.Vid, Value: 1}}},
{Keys: bson.D{{Key: FN.AiCommentRecord.Vid, Value: 1}, {Key: FN.AiCommentRecord.Status, Value: 1}, {Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
{Keys: bson.D{{Key: FN.AiCommentRecord.TaskId, Value: 1}, {Key: FN.AiCommentRecord.Status, Value: 1}}},
{Keys: bson.D{{Key: FN.AiCommentRecord.ObjType, Value: 1}, {Key: FN.AiCommentRecord.Status, Value: 1}, {Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
{Keys: bson.D{{Key: FN.AiCommentRecord.Status, Value: 1}, {Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
{Keys: bson.D{{Key: FN.AiCommentRecord.CreatedAt, Value: 1}}},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(aicommentrecord:Init) Create AiCommentRecord Index failed! err:%+v:", err))
}
}
// Reserve claims one playlet before the external submit request. A failed claim
// can be retried, while a submitted or completed claim blocks duplicate work.
func Reserve(ctx context.Context, record *AiCommentRecord) (bool, *srvdef.SrvErr) {
now := time.Now()
record.Status = StatusSubmitting
record.CreatedAt = now
record.UpdatedAt = now
result, err := db.UpsertOne(ctx, bson.M{FN.AiCommentRecord.Key: record.Key}, bson.M{"$setOnInsert": record})
if err != nil {
log.Warn("aicommentrecord:Reserve failed", log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
if result.UpsertedCount > 0 {
return true, nil
}
result, err = db.UpdateOne(ctx,
bson.M{FN.AiCommentRecord.Key: record.Key, FN.AiCommentRecord.Status: bson.M{"$in": []int{StatusFailed, StatusAbandoned}}},
bson.M{"$set": bson.M{
FN.AiCommentRecord.Status: StatusSubmitting,
FN.AiCommentRecord.TaskId: "",
FN.AiCommentRecord.RetainCount: record.RetainCount,
FN.AiCommentRecord.TargetCount: record.TargetCount,
FN.AiCommentRecord.Title: record.Title,
FN.AiCommentRecord.Desc: record.Desc,
FN.AiCommentRecord.CreatedAt: now,
FN.AiCommentRecord.UpdatedAt: now,
}},
)
if err != nil {
log.Warn("aicommentrecord:Reserve retry failed", log.E(err))
return false, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.ModifiedCount > 0, nil
}
func SetSubmission(ctx context.Context, key, taskID string, status int, desc string) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx,
bson.M{FN.AiCommentRecord.Key: key, FN.AiCommentRecord.Status: StatusSubmitting},
bson.M{"$set": bson.M{
FN.AiCommentRecord.TaskId: taskID,
FN.AiCommentRecord.Status: status,
FN.AiCommentRecord.Desc: desc,
FN.AiCommentRecord.UpdatedAt: time.Now(),
}},
)
if err != nil {
log.Warn("aicommentrecord:SetSubmission failed", log.E(err), log.Any("key", key))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount == 0 {
log.Warn("aicommentrecord:SetSubmission reservation not found", log.Any("key", key))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
func InsertMany(ctx context.Context, records AiCommentRecordList) *srvdef.SrvErr {
if len(records) == 0 {
return nil
}
now := time.Now()
for _, record := range records {
if record.CreatedAt.IsZero() {
record.CreatedAt = now
}
record.UpdatedAt = now
}
if _, err := db.InsertMany(ctx, &records); err != nil {
log.Warn("aicommentrecord:InsertMany db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
func FindByStatus(ctx context.Context, status int, limit int64) (AiCommentRecordList, *srvdef.SrvErr) {
if limit <= 0 {
limit = 100
}
records := make(AiCommentRecordList, 0)
err := db.Find(ctx,
&records,
bson.M{FN.AiCommentRecord.Status: status},
options.Find().SetSort(bson.D{{Key: FN.AiCommentRecord.CreatedAt, Value: 1}}).SetLimit(limit),
)
if err != nil {
log.Warn("aicommentrecord:FindByStatus db.Find failed", log.E(err), log.Any("status", status))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return records, nil
}
func FindFailedForRetry(ctx context.Context, limit int64) (AiCommentRecordList, *srvdef.SrvErr) {
if limit <= 0 {
limit = 100
}
records := make(AiCommentRecordList, 0)
err := db.Find(ctx, &records,
bson.M{FN.AiCommentRecord.Status: StatusFailed},
options.Find().SetSort(bson.D{{Key: FN.AiCommentRecord.UpdatedAt, Value: 1}}).SetLimit(limit),
)
if err != nil {
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return records, nil
}
func SetStatusByKey(ctx context.Context, key string, status int, desc string) *srvdef.SrvErr {
_, err := db.UpdateOne(ctx,
bson.M{FN.AiCommentRecord.Key: key},
bson.M{"$set": bson.M{
FN.AiCommentRecord.Status: status,
FN.AiCommentRecord.Desc: desc,
FN.AiCommentRecord.UpdatedAt: time.Now(),
}},
)
if err != nil {
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
func FindByVIDsAndObjType(ctx context.Context, objType int64, vids []string) (AiCommentRecordList, *srvdef.SrvErr) {
if len(vids) == 0 {
return AiCommentRecordList{}, nil
}
records := make(AiCommentRecordList, 0)
filter := bson.M{FN.AiCommentRecord.Vid: bson.M{"$in": vids}}
if objType > 0 {
filter[FN.AiCommentRecord.ObjType] = objType
}
if err := db.Find(ctx, &records, filter); err != nil {
log.Warn("aicommentrecord:FindByVIDsAndObjType db.Find failed", log.E(err), log.Any("objType", objType), log.Any("vids", vids))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return records, nil
}
func BatchUpdateStatus(ctx context.Context, taskIDs []string, status int) *srvdef.SrvErr {
if len(taskIDs) == 0 {
return nil
}
if _, err := db.UpdateMMany(ctx,
bson.M{FN.AiCommentRecord.TaskId: bson.M{"$in": taskIDs}},
bson.M{"$set": bson.M{
FN.AiCommentRecord.Status: status,
FN.AiCommentRecord.UpdatedAt: time.Now(),
}},
); err != nil {
log.Warn("aicommentrecord:BatchUpdateStatus db.UpdateMMany failed", log.E(err), log.Any("taskIDs", taskIDs))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
func UpdateStatusAndDescByTaskID(ctx context.Context, taskID string, status int, desc string) *srvdef.SrvErr {
if taskID == "" {
return nil
}
if _, err := db.UpdateOne(ctx,
bson.M{FN.AiCommentRecord.TaskId: taskID},
bson.M{"$set": bson.M{
FN.AiCommentRecord.Status: status,
FN.AiCommentRecord.Desc: desc,
FN.AiCommentRecord.UpdatedAt: time.Now(),
}},
); err != nil {
log.Warn("aicommentrecord:UpdateStatusAndDescByTaskID db.UpdateOne failed", log.E(err), log.Any("taskID", taskID))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
func ExpireSubmittedBefore(ctx context.Context, deadline time.Time, desc string) (int64, *srvdef.SrvErr) {
result, err := db.UpdateMMany(ctx,
bson.M{
FN.AiCommentRecord.Status: bson.M{"$in": []int{StatusSubmitting, StatusSubmitted}},
FN.AiCommentRecord.CreatedAt: bson.M{"$lt": deadline},
},
bson.M{"$set": bson.M{
FN.AiCommentRecord.Status: StatusFailed,
FN.AiCommentRecord.Desc: desc,
FN.AiCommentRecord.UpdatedAt: time.Now(),
}},
)
if err != nil {
log.Warn("aicommentrecord:ExpireSubmittedBefore db.UpdateMMany failed", log.E(err), log.Any("deadline", deadline))
return 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.ModifiedCount, nil
}
+42
View File
@@ -0,0 +1,42 @@
package aicommentrecord
type TagAiCommentRecord struct {
Id string
Key string
Vid string
Title string
TaskId string
ObjType string
RetainCount string
TargetCount string
Status string
Desc string
CreatedAt string
UpdatedAt string
DeletedAt string
}
var FN struct {
AiCommentRecord TagAiCommentRecord
}
var TN struct {
AiCommentRecord string
}
func init() {
FN.AiCommentRecord.Id = "_id"
FN.AiCommentRecord.Key = "key"
FN.AiCommentRecord.Vid = "vid"
FN.AiCommentRecord.Title = "title"
FN.AiCommentRecord.TaskId = "task_id"
FN.AiCommentRecord.ObjType = "objType"
FN.AiCommentRecord.RetainCount = "retainCount"
FN.AiCommentRecord.TargetCount = "targetCount"
FN.AiCommentRecord.Status = "status"
FN.AiCommentRecord.Desc = "desc"
FN.AiCommentRecord.CreatedAt = "createdAt"
FN.AiCommentRecord.UpdatedAt = "updatedAt"
FN.AiCommentRecord.DeletedAt = "deletedAt"
TN.AiCommentRecord = "ai_comment_record"
}
+35
View File
@@ -0,0 +1,35 @@
package aicommentrecord
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
StatusSubmitting = 0
StatusSubmitted = 1
StatusSuccess = 2
StatusFailed = 3
StatusAbandoned = 4
)
// AiCommentRecord 记录已提交到自动评论服务的短剧任务,避免重复提交。
// @table:ai_comment_record
type AiCommentRecord struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Key string `json:"key" bson:"key,omitempty"`
Vid string `json:"vid" bson:"vid"`
Title string `json:"title" bson:"title"`
TaskId string `json:"taskId" bson:"task_id"`
ObjType int64 `json:"objType" bson:"objType"`
RetainCount int `json:"retainCount" bson:"retainCount,omitempty"` // 该任务结果需保留的评论数
TargetCount int `json:"targetCount" bson:"targetCount,omitempty"` // 本轮内容最终需要达到的AI评论数
Status int `json:"status" bson:"status"`
Desc string `json:"desc" bson:"desc"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
DeletedAt time.Time `json:"deletedAt" bson:"deletedAt"`
}
type AiCommentRecordList []*AiCommentRecord
+182
View File
@@ -0,0 +1,182 @@
package analyticsdailystat
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.AnalyticsDailyInfo)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.AnalyticsDailyInfo.AppId, Value: 1},
{Key: FN.AnalyticsDailyInfo.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.AnalyticsDailyInfo.SumDate, Value: 1},
{Key: FN.AnalyticsDailyInfo.AppId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.AnalyticsDailyInfo.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(AnalyticsDailyInfo:initAnalyticsDailyInfoIndex) Create AnalyticsDailyInfo Index failed! err:%+v:", err))
}
}
// InsertOneAnalyticsDailyInfo 插入一个评论
func InsertOneAnalyticsDailyInfo(ctx context.Context, AnalyticsDailyInfo *AnalyticsDailyInfo) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, AnalyticsDailyInfo); err != nil {
log.Warn("AnalyticsDailyInfo:InsertOneAnalyticsDailyInfo db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneAnalyticsDailyInfo 删除一个评论
func DelOneAnalyticsDailyInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("AnalyticsDailyInfo:DelOneAnalyticsDailyInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyAnalyticsDailyInfo 删除一个评论评论
func DelManyAnalyticsDailyInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("AnalyticsDailyInfo:DelOneAnalyticsDailyInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneAnalyticsDailyInfo 查找一个评论
func FindOneAnalyticsDailyInfo(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*AnalyticsDailyInfo, *srvdef.SrvErr) {
var AnalyticsDailyInfo AnalyticsDailyInfo
if err := db.FindOneEx(
ctx, &AnalyticsDailyInfo, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("AnalyticsDailyInfo:FindOneAnalyticsDailyInfo db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &AnalyticsDailyInfo, nil
}
// CountAnalyticsDailyInfos 统计评论视频评论数量
func CountAnalyticsDailyInfos(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("AnalyticsDailyInfo:CountAnalyticsDailyInfos db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneAnalyticsDailyInfo 更新一个评论
func UpdateOneAnalyticsDailyInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsDailyInfo:UpdateOneAnalyticsDailyInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("AnalyticsDailyInfo:UpdateOneAnalyticsDailyInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyAnalyticsDailyInfo 更新一批评论
func UpdateManyAnalyticsDailyInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsDailyInfo:UpdateManyAnalyticsDailyInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("AnalyticsDailyInfo:UpdateManyAnalyticsDailyInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrAnalyticsDailyInfoNotExsit, "", "")
}
return nil
}
// FindManyAnalyticsDailyInfo 查找一批评论
func FindManyAnalyticsDailyInfo(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (AnalyticsDailyInfoList, *srvdef.SrvErr) {
data := make(AnalyticsDailyInfoList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("AnalyticsDailyInfo:FindManyAnalyticsDailyInfo db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyAnalyticsDailyInfo 插入一批用户
func InsertManyAnalyticsDailyInfo(ctx context.Context, histrory *AnalyticsDailyInfoList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("AnalyticsDailyInfo:InsertManyAnalyticsDailyInfo db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateAnalyticsDailyInfo 聚合查找一批数据
func AggregateAnalyticsDailyInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsDailyInfo:AggregateAnalyticsDailyInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateAnalyticsDailyInfo 聚合查找一批数据
func ObjectAggregateAnalyticsDailyInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsDailyInfo:AggregateAnalyticsDailyInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+42
View File
@@ -0,0 +1,42 @@
package analyticsdailystat
type TagAnalyticsDailyInfo struct {
AppId string
AppName string
CreatedAt string
Id string
LeadAmount string
LeadNewCount string
SumDate string
UpdatedAt string
YestodayActiveUsers string
YestodayNewUsers string
YestodayPV string
YestodaySessions string
YestodayUV string
}
var FN struct {
AnalyticsDailyInfo TagAnalyticsDailyInfo
}
var TN struct {
AnalyticsDailyInfo string
}
func init() {
FN.AnalyticsDailyInfo.AppId = "appId"
FN.AnalyticsDailyInfo.AppName = "appName"
FN.AnalyticsDailyInfo.CreatedAt = "createdAt"
FN.AnalyticsDailyInfo.Id = "_id"
FN.AnalyticsDailyInfo.LeadAmount = "leadAmount"
FN.AnalyticsDailyInfo.LeadNewCount = "leadNewCount"
FN.AnalyticsDailyInfo.SumDate = "sumDate"
FN.AnalyticsDailyInfo.UpdatedAt = "updatedAt"
FN.AnalyticsDailyInfo.YestodayActiveUsers = "yestodayActiveUsers"
FN.AnalyticsDailyInfo.YestodayNewUsers = "yestodayNewUsers"
FN.AnalyticsDailyInfo.YestodayPV = "yestodayPV"
FN.AnalyticsDailyInfo.YestodaySessions = "yestodaySessions"
FN.AnalyticsDailyInfo.YestodayUV = "yestodayUV"
TN.AnalyticsDailyInfo = "analytics_daily_info"
}
+27
View File
@@ -0,0 +1,27 @@
package analyticsdailystat
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 数据统计
// @table:analytics_daily_info
type AnalyticsDailyInfo struct {
Id primitive.ObjectID `bson:"_id,omitempty"`
SumDate time.Time `json:"sumDate" bson:"sumDate"` // 时间半小时
AppId int64 `json:"appId" bson:"appId"` // appId
AppName string `json:"appName" bson:"appName"` // APP名称
YestodayPV int64 `json:"yestodayPV" bson:"yestodayPV"` // 页面浏览量 (PV)
YestodayUV int64 `json:"yestodayUV" bson:"yestodayUV"` // 独立用户数 (UV)
YestodayActiveUsers int64 `json:"yestodayActiveUsers" bson:"yestodayActiveUsers"` // 活跃用户数
YestodaySessions int64 `json:"yestodaySessions" bson:"yestodaySessions"` // 会话数
YestodayNewUsers int64 `json:"yestodayNewUsers" bson:"yestodayNewUsers"` // 新增数量
LeadNewCount float64 `json:"leadNewCount" bson:"leadNewCount"` // 日导量新增
LeadAmount float64 `json:"leadAmount" bson:"leadAmount"` // 日导量充值
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
}
type AnalyticsDailyInfoList []*AnalyticsDailyInfo
+182
View File
@@ -0,0 +1,182 @@
package analyticsstat
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.AnalyticsInfo)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.AnalyticsInfo.AppId, Value: 1},
{Key: FN.AnalyticsInfo.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.AnalyticsInfo.SumDate, Value: 1},
{Key: FN.AnalyticsInfo.AppId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.AnalyticsInfo.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(AnalyticsInfo:initAnalyticsInfoIndex) Create AnalyticsInfo Index failed! err:%+v:", err))
}
}
// InsertOneAnalyticsInfo 插入一个评论
func InsertOneAnalyticsInfo(ctx context.Context, AnalyticsInfo *AnalyticsInfo) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, AnalyticsInfo); err != nil {
log.Warn("AnalyticsInfo:InsertOneAnalyticsInfo db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneAnalyticsInfo 删除一个评论
func DelOneAnalyticsInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("AnalyticsInfo:DelOneAnalyticsInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyAnalyticsInfo 删除一个评论评论
func DelManyAnalyticsInfo(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("AnalyticsInfo:DelOneAnalyticsInfo db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneAnalyticsInfo 查找一个评论
func FindOneAnalyticsInfo(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*AnalyticsInfo, *srvdef.SrvErr) {
var AnalyticsInfo AnalyticsInfo
if err := db.FindOneEx(
ctx, &AnalyticsInfo, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("AnalyticsInfo:FindOneAnalyticsInfo db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &AnalyticsInfo, nil
}
// CountAnalyticsInfos 统计评论视频评论数量
func CountAnalyticsInfos(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("AnalyticsInfo:CountAnalyticsInfos db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneAnalyticsInfo 更新一个评论
func UpdateOneAnalyticsInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsInfo:UpdateOneAnalyticsInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("AnalyticsInfo:UpdateOneAnalyticsInfo db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyAnalyticsInfo 更新一批评论
func UpdateManyAnalyticsInfo(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("AnalyticsInfo:UpdateManyAnalyticsInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("AnalyticsInfo:UpdateManyAnalyticsInfo db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrAnalyticsInfoNotExsit, "", "")
}
return nil
}
// FindManyAnalyticsInfo 查找一批评论
func FindManyAnalyticsInfo(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (AnalyticsInfoList, *srvdef.SrvErr) {
data := make(AnalyticsInfoList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("AnalyticsInfo:FindManyAnalyticsInfo db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyAnalyticsInfo 插入一批用户
func InsertManyAnalyticsInfo(ctx context.Context, histrory *AnalyticsInfoList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("AnalyticsInfo:InsertManyAnalyticsInfo db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateAnalyticsInfo 聚合查找一批数据
func AggregateAnalyticsInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsInfo:AggregateAnalyticsInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateAnalyticsInfo 聚合查找一批数据
func ObjectAggregateAnalyticsInfo(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("AnalyticsInfo:AggregateAnalyticsInfo db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+42
View File
@@ -0,0 +1,42 @@
package analyticsstat
type TagAnalyticsInfo struct {
ActiveUsers string
AppId string
AppName string
CreatedAt string
DaySumDate string
Id string
SumDate string
UpdatedAt string
YestodayActiveUsers string
YestodayNewUsers string
YestodayPV string
YestodaySessions string
YestodayUV string
}
var FN struct {
AnalyticsInfo TagAnalyticsInfo
}
var TN struct {
AnalyticsInfo string
}
func init() {
FN.AnalyticsInfo.ActiveUsers = "activeUsers"
FN.AnalyticsInfo.AppId = "appId"
FN.AnalyticsInfo.AppName = "appName"
FN.AnalyticsInfo.CreatedAt = "createdAt"
FN.AnalyticsInfo.DaySumDate = "daySumDate"
FN.AnalyticsInfo.Id = "_id"
FN.AnalyticsInfo.SumDate = "sumDate"
FN.AnalyticsInfo.UpdatedAt = "updatedAt"
FN.AnalyticsInfo.YestodayActiveUsers = "yestodayActiveUsers"
FN.AnalyticsInfo.YestodayNewUsers = "yestodayNewUsers"
FN.AnalyticsInfo.YestodayPV = "yestodayPV"
FN.AnalyticsInfo.YestodaySessions = "yestodaySessions"
FN.AnalyticsInfo.YestodayUV = "yestodayUV"
TN.AnalyticsInfo = "analytics_info"
}
+27
View File
@@ -0,0 +1,27 @@
package analyticsstat
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 数据统计
// @table:analytics_info
type AnalyticsInfo struct {
Id primitive.ObjectID `bson:"_id,omitempty"`
SumDate time.Time `json:"sumDate" bson:"sumDate"` // 时间半小时
DaySumDate time.Time `json:"daySumDate" bson:"daySumDate"` // 当天
AppId int64 `json:"appId" bson:"appId"` // appId
AppName string `json:"appName" bson:"appName"` // APP名称
ActiveUsers int64 `json:"activeUsers" bson:"activeUsers"` // 最近半小时活跃数
YestodayPV int64 `json:"yestodayPV" bson:"yestodayPV"` // 页面浏览量 (PV)
YestodayUV int64 `json:"yestodayUV" bson:"yestodayUV"` // 独立用户数 (UV)
YestodayActiveUsers int64 `json:"yestodayActiveUsers" bson:"yestodayActiveUsers"` // 活跃用户数
YestodaySessions int64 `json:"yestodaySessions" bson:"yestodaySessions"` // 会话数
YestodayNewUsers int64 `json:"yestodayNewUsers" bson:"yestodayNewUsers"` // 新增数量
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
}
type AnalyticsInfoList []*AnalyticsInfo
+102
View File
@@ -0,0 +1,102 @@
package announcementmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.Announcement)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Announcement.Status, Value: 1},
{Key: FN.Announcement.Sort, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Announcement.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(announcementmod:Init) Create Announcement Index failed! err:%+v:", err))
}
}
func InsertOneAnnouncement(ctx context.Context, doc *Announcement) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("announcementmod:InsertOneAnnouncement db.InsertOne failed",
log.E(err), log.Any("doc", doc))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
func DelOneAnnouncement(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("announcementmod:DelOneAnnouncement db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
func FindOneAnnouncement(ctx context.Context, filter bson.M) (*Announcement, *srvdef.SrvErr) {
var doc Announcement
if err := db.FindOneEx(ctx, &doc, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("announcementmod:FindOneAnnouncement db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrAnnouncementNotExsit, "", "")
}
return &doc, nil
}
func FindManyAnnouncement(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (AnnouncementList, *srvdef.SrvErr) {
data := make(AnnouncementList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("announcementmod:FindManyAnnouncement db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
func CountAnnouncement(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("announcementmod:CountAnnouncement db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
func UpdateOneAnnouncement(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("announcementmod:UpdateOneAnnouncement db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("announcementmod:UpdateOneAnnouncement not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrAnnouncementNotExsit, "", "")
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package announcementmod
type TagAnnouncement struct {
Id string
Title string
Content string
Sort string
Status string
CreatedAt string
UpdatedAt string
}
var FN struct {
Announcement TagAnnouncement
}
var TN struct {
Announcement string
}
func init() {
FN.Announcement.Id = "_id"
FN.Announcement.Title = "title"
FN.Announcement.Content = "content"
FN.Announcement.Sort = "sort"
FN.Announcement.Status = "status"
FN.Announcement.CreatedAt = "createdAt"
FN.Announcement.UpdatedAt = "updatedAt"
TN.Announcement = "announcement"
}
+17
View File
@@ -0,0 +1,17 @@
package announcementmod
import "time"
// Announcement 公告
// @table:announcement
type Announcement struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"` // 标题
Content string `json:"content" bson:"content"` // 内容
Sort int64 `json:"sort" bson:"sort"` // 排序,越大越靠前
Status bool `json:"status" bson:"status"` // 是否启用
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type AnnouncementList []*Announcement
+42
View File
@@ -0,0 +1,42 @@
package cfg
import (
"context"
"strings"
"sync"
"go.mongodb.org/mongo-driver/bson"
)
var appKeyCache struct {
sync.RWMutex
value string
ready bool
}
// CacheAppKey 把系统配置里的 appKey 放进内存,供媒资写接口读取。
func CacheAppKey(appKey string) {
appKeyCache.Lock()
appKeyCache.value = strings.TrimSpace(appKey)
appKeyCache.ready = true
appKeyCache.Unlock()
}
// CachedAppKey 返回已缓存的 appKey。缓存未建立时读取 sys_cfg 并写入缓存。
func CachedAppKey(ctx context.Context) string {
appKeyCache.RLock()
if appKeyCache.ready {
value := appKeyCache.value
appKeyCache.RUnlock()
return value
}
appKeyCache.RUnlock()
sysCfg, serr := FindOneSysCfg(ctx, bson.M{FN.SysCfg.Id: 1})
if serr != nil || sysCfg == nil {
return ""
}
value := strings.TrimSpace(sysCfg.AppKey)
CacheAppKey(value)
return value
}
+9
View File
@@ -0,0 +1,9 @@
package cfg
import (
"videoweb/pub/mongos"
)
var (
sysCfgColl *mongos.Collection
)
+55
View File
@@ -0,0 +1,55 @@
package cfg
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
// Init 初始化数据
func Init(ctx context.Context) {
sysCfgColl = mongos.Shop.Coll(TN.SysCfg)
}
// FindOneSysCfg 查找一个系统配置
func FindOneSysCfg(ctx context.Context, filter bson.M) (
*SysCfg, *srvdef.SrvErr) {
var sysCfg SysCfg
if err := sysCfgColl.FindOneEx(
ctx, &sysCfg, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("cfg:FindOneSysCfg db.FindOneEx failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return &sysCfg, nil
}
// UpdateOneSysCfg 更新一个系统配置
func UpdateOneSysCfg(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := sysCfgColl.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("cfg:UpdateOneSysCfg db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
func DeleteOneSysCfg(ctx context.Context, filter bson.M) *srvdef.SrvErr {
_, err := sysCfgColl.DeleteOne(ctx, filter)
if err != nil {
log.Warn("cfg:DeleteOneSysCfg db.DeleteOne failed", log.Any("filter", filter), log.E(err))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+90
View File
@@ -0,0 +1,90 @@
package cfg
type TagSysCfg struct {
AppAddr string
OfficialAppAddr string
ForeverUrlAddr string
GitAddr string
GmailAddr string
Id string
ImgAppCdn string
ImgWebCdn string
MediaAppCdn string
MediaWebCdn string
NewUrlAddr string
NewUrlAddr1 string
NewUrlAddr2 string
QQ string
Telegram string
TelegramAdd string
TgGroup string
TranslationAddr string
TwitterAddr string
WatermarkImage string
WatermarkMedia string
WatermarkMediaTop string
WatermarkMediaTopRight string
WatermarkMediaBottomLeft string
CustomerServiceHost string
WeiChart string
DHNewUrlAddr1 string
DHNewUrlAddr2 string
DHNewUrlAddr3 string
DHForeverUrlAddr string
DHTitle string
DHKeyworld string
DHDescription string
DHSiteName string
ChannelCode string
EnableH265 string
AppKey string
}
var FN struct {
SysCfg TagSysCfg
}
var TN struct {
SysCfg string
}
func init() {
FN.SysCfg.AppAddr = "appAddr"
FN.SysCfg.OfficialAppAddr = "officialAppAddr"
FN.SysCfg.ForeverUrlAddr = "foreverUrlAddr"
FN.SysCfg.GitAddr = "gitAddr"
FN.SysCfg.GmailAddr = "gmailAddr"
FN.SysCfg.Id = "_id"
FN.SysCfg.ImgAppCdn = "imgAppCdn"
FN.SysCfg.ImgWebCdn = "imgWebCdn"
FN.SysCfg.MediaAppCdn = "mediaAppCdn"
FN.SysCfg.MediaWebCdn = "mediaWebCdn"
FN.SysCfg.NewUrlAddr = "newUrlAddr"
FN.SysCfg.NewUrlAddr1 = "newUrlAddr1"
FN.SysCfg.NewUrlAddr2 = "newUrlAddr2"
FN.SysCfg.QQ = "qq"
FN.SysCfg.Telegram = "telegram"
FN.SysCfg.TelegramAdd = "telegramAdd"
FN.SysCfg.TgGroup = "tgGroup"
FN.SysCfg.TranslationAddr = "translationAddr"
FN.SysCfg.TwitterAddr = "twitterAddr"
FN.SysCfg.WatermarkImage = "watermarkImage"
FN.SysCfg.WatermarkMedia = "watermarkMedia"
FN.SysCfg.WatermarkMediaTop = "watermarkMediaTop"
FN.SysCfg.WatermarkMediaTopRight = "watermarkMediaTopRight"
FN.SysCfg.WatermarkMediaBottomLeft = "watermarkMediaBottomLeft"
FN.SysCfg.CustomerServiceHost = "customerServiceHost"
FN.SysCfg.WeiChart = "weiChart"
FN.SysCfg.DHNewUrlAddr1 = "dHNewUrlAddr1"
FN.SysCfg.DHNewUrlAddr2 = "dHNewUrlAddr2"
FN.SysCfg.DHNewUrlAddr3 = "dHNewUrlAddr3"
FN.SysCfg.DHForeverUrlAddr = "dHForeverUrlAddr"
FN.SysCfg.DHTitle = "dhTitle"
FN.SysCfg.DHKeyworld = "dhKeyworld"
FN.SysCfg.DHDescription = "dhDescription"
FN.SysCfg.DHSiteName = "dhSiteName"
FN.SysCfg.ChannelCode = "channelCode"
FN.SysCfg.EnableH265 = "enableH265"
FN.SysCfg.AppKey = "appKey"
TN.SysCfg = "sys_cfg"
}
+74
View File
@@ -0,0 +1,74 @@
package cfg
import "strings"
// @table:sys_cfg
type SysCfg struct {
Id int64 `json:"id" bson:"_id"`
UnencryptedCdn string `json:"unencryptedCdn" bson:"unencryptedCdn"` // 不加密资源使用的cdn
SitemapDefaultImages []string `json:"sitemapDefaultImages" bson:"sitemapDefaultImages"` // Sitemap里面默认封面图
ImgAppCdn string `json:"imgAppCdn" bson:"imgAppCdn"` // 图片CDN(app使用)
ImgWebCdn string `json:"imgWebCdn" bson:"imgWebCdn"` // 图片CDN(web使用)
MediaWebCdn string `json:"mediaWebCdn" bson:"mediaWebCdn"` // 视频CDN(web使用)
MediaAppCdn string `json:"mediaAppCdn" bson:"mediaAppCdn"` // 视频CDN(app使用)
ImgAppUsCdn string `json:"imgAppUsCdn" bson:"imgAppUsCdn"` // 图片CDN(海外app使用)
MediaAppUsCdn string `json:"mediaAppUsCdn" bson:"mediaAppUsCdn"` // 视频CDN(海外app使用)
WatermarkImage string `json:"watermarkImage" bson:"watermarkImage"` // 图片水印文件
WatermarkMedia string `json:"watermarkMedia" bson:"watermarkMedia"` // 视频水印文件(底部右边)
WatermarkMediaTop string `json:"watermarkMediaTop" bson:"watermarkMediaTop"` // 视频水印文件(顶部左边)
WatermarkMediaTopRight string `json:"watermarkMediaTopRight" bson:"watermarkMediaTopRight"` // 视频水印文件(顶部右边)
WatermarkMediaBottomLeft string `json:"watermarkMediaBottomLeft" bson:"watermarkMediaBottomLeft"` // 视频水印文件(底部左边)
Mp4Addr string `json:"mp4Addr" bson:"mp4Addr"` // mp4地址(web使用)
PdfAddr string `json:"pdfAddr" bson:"pdfAddr"` // 回家的路PDF
CustomerServiceHost string `json:"customerServiceHost" bson:"customerServiceHost"` // 在线客服
//网站管理
NewUrlAddr string `json:"newUrlAddr" bson:"newUrlAddr"` //最新地址
NewUrlAddr1 string `json:"newUrlAddr1" bson:"newUrlAddr1"` //最新地址(备用地址1)
NewUrlAddr2 string `json:"newUrlAddr2" bson:"newUrlAddr2"` //最新地址(备用地址2)
ForeverUrlAddr string `json:"foreverUrlAddr" bson:"foreverUrlAddr"` //永久地址
GmailAddr string `json:"gmailAddr" bson:"gmailAddr"` //邮箱地址
AppAddr string `json:"appAddr" bson:"appAddr"` //APP下载地址(落地页)
OfficialAppAddr string `json:"officialAppAddr" bson:"officialAppAddr"` //官网app地址
WeiChart string `json:"weiChart" bson:"weiChart"` //微信群
QQ string `json:"qq" bson:"qq"` //qq群
TgGroup string `json:"tgGroup" bson:"tgGroup"` //tg群
PotaoGroup string `json:"potaoGroup" bson:"potaoGroup"` //土豆群
GitAddr string `json:"gitAddr" bson:"gitAddr"` //git地址
TwitterAddr string `json:"twitterAddr" bson:"twitterAddr"` //推特地址
Telegram string `json:"telegram" bson:"telegram"` //商务tg
TelegramAdd string `json:"telegramAdd" bson:"telegramAdd"` //加入我们tg
TranslationAddr string `json:"translationAddr" bson:"translationAddr"` //应用导航
//SEO
WebTitle string `json:"webTitle" bson:"webTitle"` // 网站SEO标题
WebKeyworld []string `json:"webKeyworld" bson:"webKeyworld"` // 网站SEO关键字
WebDescription string `json:"webDescription" bson:"webDescription"` // 网站SEO描述
WebSiteName string `json:"webSiteName" bson:"webSiteName"` // 网站SEO网站名称
WebAddr string `json:"webAddr" bson:"webAddr"` // 网站SEO网站地址
DHNewUrlAddr1 string `json:"dhNewUrlAddr1" bson:"dhNewUrlAddr1"` // 导航页-线路1
DHNewUrlAddr2 string `json:"dhNewUrlAddr2" bson:"dhNewUrlAddr2"` // 导航页-线路2
DHNewUrlAddr3 string `json:"dhNewUrlAddr3" bson:"dhNewUrlAddr3"` // 导航页-线路3
FreeVPN string `json:"freeVPN" bson:"freeVPN"` // 免费vpn链接
UseAddress []string `json:"useAddress" bson:"useAddress"` // 所有使用中的域名
AdvitiesTopicNum int64 `json:"advitiesTopicNum" bson:"advitiesTopicNum"` // 广告间隔
DHTitle string `json:"dhTitle" bson:"dhTitle"` // 导航SEO标题
DHKeyworld []string `json:"dhKeyworld" bson:"dhKeyworld"` // 导航SEO关键字
DHDescription string `json:"dhDescription" bson:"dhDescription"` // 导航SEO描述
DHSiteName string `json:"dhSiteName" bson:"dhSiteName"` // 导航SEO网站名称
ActressBackGround string `json:"actressBackGround" bson:"actressBackGround"` // 女优通用背景图
ChannelCode string `json:"channelCode" bson:"channelCode"` // 渠道码
EnableH265 bool `json:"enableH265" bson:"enableH265"` // 是否允许客户端使用 H265 地址播放
AppKey string `json:"appKey" bson:"appKey"` // 媒资库 appKey,调用 media 写接口时传入
}
// SEOBaseURL 返回与页面 canonical 一致的 SEO 主域。
// 永久域名未配置时回退到 WebAddr,避免生成空地址。
func (c *SysCfg) SEOBaseURL() string {
if c == nil {
return ""
}
base := strings.TrimSpace(c.ForeverUrlAddr)
if base == "" {
base = strings.TrimSpace(c.WebAddr)
}
return strings.TrimRight(base, "/")
}
+40
View File
@@ -0,0 +1,40 @@
package cointransmod
type TagCoinTrans struct {
Id string
UserId string
UserName string
FlowDir string
TranType string
Amount string
BalanceBefore string
BalanceAfter string
OrderNo string
RelatedId string
Remark string
CreatedAt string
}
var FN struct {
CoinTrans TagCoinTrans
}
var TN struct {
CoinTrans string
}
func init() {
FN.CoinTrans.Id = "_id"
FN.CoinTrans.UserId = "userId"
FN.CoinTrans.UserName = "userName"
FN.CoinTrans.FlowDir = "flowDir"
FN.CoinTrans.TranType = "tranType"
FN.CoinTrans.Amount = "amount"
FN.CoinTrans.BalanceBefore = "balanceBefore"
FN.CoinTrans.BalanceAfter = "balanceAfter"
FN.CoinTrans.OrderNo = "orderNo"
FN.CoinTrans.RelatedId = "relatedId"
FN.CoinTrans.Remark = "remark"
FN.CoinTrans.CreatedAt = "createdAt"
TN.CoinTrans = "coin_trans"
}
+80
View File
@@ -0,0 +1,80 @@
package cointransmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.CoinTrans)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
// 按用户+时间倒序查流水(最常用)
{Keys: bson.D{
{Key: FN.CoinTrans.UserId, Value: 1},
{Key: FN.CoinTrans.CreatedAt, Value: -1},
}},
// 按交易类型筛选
{Keys: bson.D{{Key: FN.CoinTrans.TranType, Value: 1}}},
// 按订单号查(幂等校验)
{Keys: bson.D{{Key: FN.CoinTrans.OrderNo, Value: 1}}},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(cointransmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneCoinTrans 写入一条流水记录
func InsertOneCoinTrans(ctx context.Context, doc *CoinTrans) *srvdef.SrvErr {
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Error("cointransmod:InsertOneCoinTrans failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindManyCoinTrans 分页查询流水列表
func FindManyCoinTrans(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (CoinTransList, *srvdef.SrvErr) {
var data CoinTransList
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("cointransmod:FindManyCoinTrans failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountCoinTrans 统计流水条数
func CountCoinTrans(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter)
if err != nil {
log.Warn("cointransmod:CountCoinTrans failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// StatSyncConsumeList 按 ID 游标增量拉取金币消费流水(统计中心)
func StatSyncConsumeList(ctx context.Context, startId int64, size int64) (CoinTransList, error) {
opt := (&options.FindOptions{}).SetLimit(size).SetSort(bson.D{{Key: FN.CoinTrans.Id, Value: 1}})
filter := bson.M{
FN.CoinTrans.Id: bson.M{"$gt": startId},
FN.CoinTrans.FlowDir: FlowOut,
}
list := CoinTransList{}
if err := coll.Find(ctx, &list, filter, opt); err != nil {
return nil, err
}
return list, nil
}
+64
View File
@@ -0,0 +1,64 @@
package cointransmod
import "time"
// FlowDir 收支方向
type FlowDir int8
const (
FlowIn FlowDir = 1 // 收入(充值、赠送)
FlowOut FlowDir = -1 // 支出(消费、解锁)
)
func (f FlowDir) Desc() string {
if f == FlowIn {
return "收入"
}
return "支出"
}
// TranType 交易类型
type TranType int32
const (
TranTypeCoinRecharge TranType = 1 // 金币充值(购买金币)
TranTypeVipGiftCoin TranType = 2 // 购买会员赠送金币
TranTypeDarkAlley TranType = 3 // 历史遗留交易类型(已下线)
TranTypeVideoUnlock TranType = 4 // 视频解锁
TranTypeAdminAdjust TranType = 5 // 管理员手动调整
TranTypeCoinGift TranType = 6 // 金币充值赠送
)
var TranTypeNameMap = map[TranType]string{
TranTypeCoinRecharge: "金币充值",
TranTypeVipGiftCoin: "会员赠送",
TranTypeDarkAlley: "历史交易",
TranTypeVideoUnlock: "视频解锁",
TranTypeAdminAdjust: "管理员调整",
TranTypeCoinGift: "充值赠送",
}
func (t TranType) Desc() string {
if name, ok := TranTypeNameMap[t]; ok {
return name
}
return "未知"
}
// @table: coin_trans
type CoinTrans struct {
Id int64 `json:"id" bson:"_id"` // 唯一ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
UserName string `json:"userName" bson:"userName"` // 用户昵称(快照)
FlowDir FlowDir `json:"flowDir" bson:"flowDir"` // 收支方向:1收入 -1支出
TranType TranType `json:"tranType" bson:"tranType"` // 交易类型
Amount int64 `json:"amount" bson:"amount"` // 本次交易金币数(正整数)
BalanceBefore int64 `json:"balanceBefore" bson:"balanceBefore"` // 交易前余额
BalanceAfter int64 `json:"balanceAfter" bson:"balanceAfter"` // 交易后余额
OrderNo string `json:"orderNo" bson:"orderNo"` // 关联订单号(可为空)
RelatedId int64 `json:"relatedId" bson:"relatedId"` // 关联内容ID(视频等,可为空)
Remark string `json:"remark" bson:"remark"` // 备注描述
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 交易时间
}
type CoinTransList []*CoinTrans
+90
View File
@@ -0,0 +1,90 @@
package commentlikemod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 comment_like 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.CommentLike)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.CommentLike.UserId, Value: 1},
{Key: FN.CommentLike.CommentId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.CommentLike.CommentId, Value: 1},
{Key: FN.CommentLike.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.CommentLike.ObjectType, Value: 1},
{Key: FN.CommentLike.ObjectId, Value: 1},
{Key: FN.CommentLike.CreatedAt, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(commentlikemod:initIndex) 创建索引失败 err:%+v:", err))
}
}
// InsertOneCommentLike 插入一条评论点赞关系
func InsertOneCommentLike(ctx context.Context, doc *CommentLike) (bool, *srvdef.SrvErr) {
if doc.Id == 0 {
doc.Id = mongos.Lid.CommentLike.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
log.Warn("插入评论点赞关系失败", log.Any("doc", doc), log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// DeleteOneCommentLike 删除一条评论点赞关系
func DeleteOneCommentLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("删除评论点赞关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindManyCommentLike 按条件查询评论点赞关系
func FindManyCommentLike(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (CommentLikeList, *srvdef.SrvErr) {
data := make(CommentLikeList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("查询评论点赞关系列表失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
+32
View File
@@ -0,0 +1,32 @@
package commentlikemod
// TagCommentLike 保存 comment_like 集合字段名
type TagCommentLike struct {
Id string
UserId string
CommentId string
ObjectId string
ObjectType string
CreatedAt string
UpdatedAt string
}
var FN struct {
CommentLike TagCommentLike
}
var TN struct {
CommentLike string
}
func init() {
FN.CommentLike.Id = "_id"
FN.CommentLike.UserId = "userId"
FN.CommentLike.CommentId = "commentId"
FN.CommentLike.ObjectId = "objectId"
FN.CommentLike.ObjectType = "objectType"
FN.CommentLike.CreatedAt = "createdAt"
FN.CommentLike.UpdatedAt = "updatedAt"
TN.CommentLike = "comment_like"
}
+19
View File
@@ -0,0 +1,19 @@
package commentlikemod
import "time"
// CommentLike @table: comment_like
//
// CommentLike 评论点赞关系模型
type CommentLike struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 点赞记录ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
CommentId int64 `json:"commentId" bson:"commentId"` // 评论ID
ObjectId int64 `json:"objectId" bson:"objectId"` // 评论对象ID
ObjectType int64 `json:"objectType" bson:"objectType"` // 评论对象类型 10-短剧 11-短剧剧集 20-视频
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// CommentLikeList 评论点赞关系列表
type CommentLikeList []*CommentLike
+241
View File
@@ -0,0 +1,241 @@
package commentmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 表名
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.Comment)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{{Key: FN.Comment.AiTaskId, Value: 1}, {Key: FN.Comment.AiIndex, Value: 1}},
Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{FN.Comment.AiTaskId: bson.M{"$exists": true}}),
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.Id, Value: 1},
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.Level, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
{Key: FN.Comment.ObjectType, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.ParentsId, Value: 1},
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.UserId, Value: 1},
{Key: FN.Comment.ObjectType, Value: 1},
{Key: FN.Comment.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ObjectId, Value: 1},
{Key: FN.Comment.ObjectType, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.ParentsId, Value: 1},
{Key: FN.Comment.CountLike, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.ParentsId, Value: 1},
{Key: FN.Comment.Level, Value: 1},
{Key: FN.Comment.ReviewStatus, Value: 1},
{Key: FN.Comment.CreatedAt, Value: 1},
{Key: FN.Comment.Id, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Comment.TopRank, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(comment:initCommentIndex) Create Comment Index failed! err:%+v:", err))
}
}
// InsertAICommentOnce makes a generated result safe to process again after a crash.
func InsertAICommentOnce(ctx context.Context, comment *CommentModel) (bool, *srvdef.SrvErr) {
filter := bson.M{FN.Comment.AiTaskId: comment.AiTaskId, FN.Comment.AiIndex: comment.AiIndex}
result, err := db.UpsertOne(ctx, filter, bson.M{"$setOnInsert": comment})
if err != nil {
log.Warn("comment:InsertAICommentOnce failed", log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return result.UpsertedCount > 0, nil
}
// InsertOneComment 插入一个评论
func InsertOneComment(ctx context.Context, Comment *CommentModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, Comment); err != nil {
log.Warn("comment:InsertOneComment db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneComment 删除一个评论
func DelOneComment(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("comment:DelOneComment db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyComment 删除一个评论评论
func DelManyComment(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("comment:DelOneComment db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneComment 查找一个评论
func FindOneComment(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (
*CommentModel, *srvdef.SrvErr) {
var Comment CommentModel
if err := db.FindOneEx(
ctx, &Comment, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("comment:FindOneComment db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &Comment, nil
}
// CountComments 统计评论视频评论数量
func CountComments(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("comment:CountComments db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneComment 更新一个评论
func UpdateOneComment(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("comment:UpdateOneComment db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("comment:UpdateOneComment db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyComment 更新一批评论
func UpdateManyComment(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("comment:UpdateManyComment db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("comment:UpdateManyComment db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrCommentNotExsit, "", "")
}
return nil
}
// FindManyComment 查找一批评论
func FindManyComment(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (CommentModelList, *srvdef.SrvErr) {
data := make(CommentModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("comment:FindManyComment db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// InsertManyComment 插入一批用户
func InsertManyComment(ctx context.Context, histrory *CommentModelList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, histrory); err != nil {
log.Warn("comment:InsertManyComment db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// AggregateComment 聚合查找一批数据
func AggregateComment(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("comment:AggregateComment db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateComment 聚合查找一批数据
func ObjectAggregateComment(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := db.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("comment:AggregateComment db.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+60
View File
@@ -0,0 +1,60 @@
package commentmod
type TagComment struct {
CreatedAt string
Id string
Level string
ObjectId string
ParentsId string
ReplyCommentId string
ReplyUserName string
Text string
TopRank string
UpdatedAt string
UserId string
UserName string
UserAvatar string
ReviewStatus string
IsAi string
AiTaskId string
AiIndex string
CommentCount string
CountLike string
Ip string
ObjectName string
ObjectType string
}
var FN struct {
Comment TagComment
}
var TN struct {
Comment string
}
func init() {
FN.Comment.CreatedAt = "createdAt"
FN.Comment.Id = "_id"
FN.Comment.Level = "level"
FN.Comment.ObjectId = "objectId"
FN.Comment.ParentsId = "parentsId"
FN.Comment.ReplyCommentId = "replyCommentId"
FN.Comment.ReplyUserName = "replyUserName"
FN.Comment.Text = "text"
FN.Comment.TopRank = "topRank"
FN.Comment.UpdatedAt = "updatedAt"
FN.Comment.UserId = "userId"
FN.Comment.UserName = "userName"
FN.Comment.UserAvatar = "userAvatar"
FN.Comment.ReviewStatus = "reviewStatus"
FN.Comment.IsAi = "isAi"
FN.Comment.AiTaskId = "aiTaskId"
FN.Comment.AiIndex = "aiIndex"
FN.Comment.Ip = "ip"
FN.Comment.CommentCount = "commentCount"
FN.Comment.CountLike = "countLike"
FN.Comment.ObjectName = "objectName"
FN.Comment.ObjectType = "objectType"
TN.Comment = "_comment"
}
+34
View File
@@ -0,0 +1,34 @@
package commentmod
import (
"time"
)
// 评论管理
// @table:_comment
type CommentModel struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 评论ID
Ip string `json:"ip" bson:"ip"` // 评论IP
ObjectId int64 `json:"objectId" bson:"objectId"` // 对象ID
ObjectType int64 `json:"objectType" bson:"objectType"` // 对象类型
ObjectName string `json:"objectName" bson:"objectName"` // 对象名
UserId int64 `json:"userId" bson:"userId"` // 评论用户ID
UserName string `json:"userName" bson:"userName"` // 用户名称
UserAvatar string `json:"userAvatar" bson:"userAvatar"` // 评论用户头像
Level int64 `json:"level" bson:"level"` // 评论级别,1-一级评论 2-二级评论
ParentsId int64 `json:"parentsId" bson:"parentsId"` // 上级评论ID,一级评论为0
ReplyCommentId int64 `json:"replyCommentId" bson:"replyCommentId"` // 被回复评论ID,一级评论为0
ReplyUserName string `json:"replyUserName" bson:"replyUserName"` // 被回复用户名称
Text string `json:"text" bson:"text"` // 评论内容
CommentCount int64 `json:"commentCount" bson:"commentCount"` // 该评论回复数量
CountLike int64 `json:"countLike" bson:"countLike"` // 评论点赞数
ReviewStatus int `json:"reviewStatus" bson:"reviewStatus"` // 审核状态 0 未审核 1审核成功 2 审核失败
IsAi bool `json:"isAi" bson:"isAi,omitempty"` // 自动生成评论
AiTaskId string `json:"-" bson:"aiTaskId,omitempty"` // 生成任务ID
AiIndex int `json:"-" bson:"aiIndex,omitempty"` // 任务内序号
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `bson:"createdAt" json:"createdAt"` // 创建时间
TopRank int64 `json:"topRank" bson:"topRank"` // 置顶排序
}
type CommentModelList []*CommentModel
+100
View File
@@ -0,0 +1,100 @@
package contactusmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 contactus 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.ContactUs)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.ContactUs.UserId, Value: 1},
{Key: FN.ContactUs.CreatedAt, Value: -1},
{Key: FN.ContactUs.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUs.Status, Value: 1},
{Key: FN.ContactUs.CreatedAt, Value: -1},
{Key: FN.ContactUs.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUs.QuestionType, Value: 1},
{Key: FN.ContactUs.CreatedAt, Value: -1},
{Key: FN.ContactUs.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.ContactUs.CreatedAt, Value: -1},
{Key: FN.ContactUs.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(contactusmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneContactUs 插入一条联系我们数据
//
// 当 doc.Id 为空时,会使用 mongos.Lid.ContactUs 自动生成自增ID
func InsertOneContactUs(ctx context.Context, doc *ContactUs) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.ContactUs.Get()
}
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("联系我们记录写入失败", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindManyContactUs 按条件查询多条联系我们数据
func FindManyContactUs(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (ContactUsList, *srvdef.SrvErr) {
var data ContactUsList
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("联系我们列表查询失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountContactUs 统计满足条件的联系我们数量
func CountContactUs(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("联系我们数量统计失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateManyContactUsWithResult 批量更新联系我们数据,并返回命中数量和修改数量
func UpdateManyContactUsWithResult(ctx context.Context, filter bson.M, update bson.M) (matchedCount int64, modifiedCount int64, serr *srvdef.SrvErr) {
result, err := coll.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("联系我们批量更新失败", log.E(err), log.Any("filter", filter))
return 0, 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.MatchedCount, result.ModifiedCount, nil
}
+40
View File
@@ -0,0 +1,40 @@
package contactusmod
// TagContactUs 保存contactus集合字段名
type TagContactUs struct {
Id string
UserId string
Email string
QuestionType string
Title string
Content string
Attachments string
Status string
Remark string
CreatedAt string
UpdatedAt string
}
var FN struct {
ContactUs TagContactUs
}
var TN struct {
ContactUs string
}
func init() {
FN.ContactUs.Id = "_id"
FN.ContactUs.UserId = "userId"
FN.ContactUs.Email = "email"
FN.ContactUs.QuestionType = "questionType"
FN.ContactUs.Title = "title"
FN.ContactUs.Content = "content"
FN.ContactUs.Attachments = "attachments"
FN.ContactUs.Status = "status"
FN.ContactUs.Remark = "remark"
FN.ContactUs.CreatedAt = "createdAt"
FN.ContactUs.UpdatedAt = "updatedAt"
TN.ContactUs = "contactus"
}
+34
View File
@@ -0,0 +1,34 @@
package contactusmod
import "time"
// ContactUs @table: contactus
//
// ContactUs 联系我们集合模型
type ContactUs struct {
// ID
Id int64 `json:"id" bson:"_id,omitempty"`
// 用户ID
UserId int64 `json:"userId" bson:"userId"`
// 邮箱
Email string `json:"email" bson:"email"`
// 问题类型,1-订单问题、2-账号问题、3-功能问题、4-体验问题、5-其他
QuestionType int32 `json:"questionType" bson:"questionType"`
// 标题
Title string `json:"title" bson:"title"`
// 内容
Content string `json:"content" bson:"content"`
// 附件地址,可存放多张图片或文件地址
Attachments []string `json:"attachments" bson:"attachments"`
// 处理状态,0-待处理、1-已处理
Status int32 `json:"status" bson:"status"`
// 处理备注
Remark string `json:"remark" bson:"remark,omitempty"`
// 创建时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
// 更新时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}
// ContactUsList 联系我们列表
type ContactUsList []*ContactUs
+102
View File
@@ -0,0 +1,102 @@
package detailnavmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.DetailNavModel)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.DetailNavModel.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(detailnavmod:Init) Create DetailNavModel Index failed! err:%+v:", err))
}
}
// InsertOneDetailNav 插入一条详情页导航
func InsertOneDetailNav(ctx context.Context, doc *DetailNavModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("detailnavmod:InsertOneDetailNav db.InsertOne failed",
log.E(err), log.Any("doc", doc))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneDetailNav 删除一条详情页导航
func DelOneDetailNav(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("detailnavmod:DelOneDetailNav db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneDetailNav 查找一条详情页导航
func FindOneDetailNav(ctx context.Context, filter bson.M) (*DetailNavModel, *srvdef.SrvErr) {
var doc DetailNavModel
if err := db.FindOneEx(ctx, &doc, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("detailnavmod:FindOneDetailNav db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyDetailNav 查找多条详情页导航
func FindManyDetailNav(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (DetailNavModelList, *srvdef.SrvErr) {
data := make(DetailNavModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("detailnavmod:FindManyDetailNav db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountDetailNav 统计详情页导航数量
func CountDetailNav(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("detailnavmod:CountDetailNav db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneDetailNav 更新一条详情页导航
func UpdateOneDetailNav(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("detailnavmod:UpdateOneDetailNav db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("detailnavmod:UpdateOneDetailNav not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+30
View File
@@ -0,0 +1,30 @@
package detailnavmod
type TagDetailNavModel struct {
CreatedAt string
ID string
Name string
Url string
Sort string
Status string
UpdatedAt string
}
var FN struct {
DetailNavModel TagDetailNavModel
}
var TN struct {
DetailNavModel string
}
func init() {
FN.DetailNavModel.CreatedAt = "createdAt"
FN.DetailNavModel.ID = "_id"
FN.DetailNavModel.Name = "name"
FN.DetailNavModel.Url = "url"
FN.DetailNavModel.Sort = "sort"
FN.DetailNavModel.Status = "status"
FN.DetailNavModel.UpdatedAt = "updatedAt"
TN.DetailNavModel = "detail_nav"
}
+21
View File
@@ -0,0 +1,21 @@
package detailnavmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 详情页导航配置
// @table:detail_nav
type DetailNavModel struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"` // 导航名称
Url string `json:"url" bson:"url"` // 导航链接
Sort int64 `json:"sort" bson:"sort"` // 排序
Status bool `json:"status" bson:"status"` // 是否启用
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type DetailNavModelList []*DetailNavModel
+58
View File
@@ -0,0 +1,58 @@
package esmod
import (
"context"
"time"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
FiveMinuteScale = 5 //对齐时间(分钟)
)
var (
videoIndex = "webhddjweb_video_index_v1"
playletIndex = "webhddjweb_playlet_index_v1"
)
func GetVideoIndex() string {
return videoIndex
}
func GetPlayletIndex() string {
return playletIndex
}
func GetRecordByESIndex(ctx context.Context, esIndex string) (
*ESTimestamp, *srvdef.SrvErr) {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
esRecord, serr := FindOneESRecord(ctx, filter)
if serr != nil {
if serr.Code != srvdef.ErrNoData {
return nil, serr
}
return nil, nil
}
return &esRecord.Timestamp, nil
}
func SetOneEsRecord(ctx context.Context, esIndex string,
timestamp *ESTimestamp) *srvdef.SrvErr {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
upsertDoc := bson.M{
"$set": bson.M{
FN.ESRecord.Timestamp.T: timestamp.T,
FN.ESRecord.Timestamp.I: timestamp.I,
FN.ESRecord.UpdatedAt: time.Now(),
},
"$setOnInsert": bson.M{
FN.ESRecord.Id: primitive.NewObjectID(),
FN.ESRecord.CreatedAt: time.Now(),
},
}
serr := UpsertOneESRecord(ctx, filter, upsertDoc)
return serr
}
+277
View File
@@ -0,0 +1,277 @@
package esmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/esmanager"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
// Init 初始化数据
func Init(ctx context.Context) {
initDBIndex(ctx)
initIndex()
return
}
// initIndex 初始化索引
func initIndex() {
if esmanager.Instance == nil {
return
}
initPlayletIndex(playletIndex)
}
// initDBIndex 初始化数据库索引
func initDBIndex(ctx context.Context) {
//获取数据库表
db = mongos.Shop.Coll(TN.ESRecord)
// 获取数据库表
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.ESRecord.EsIndex, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(esmod:initDBIndex) Create es_record Index failed! err:%+v:", err))
}
}
func initVideoIndex(esIndex string) {
var setting = esmanager.M{
"settings": esmanager.M{
"number_of_shards": esmanager.NumberOfShards,
"number_of_replicas": esmanager.NumberOfReplicas,
"analysis": esmanager.M{
"analyzer": esmanager.M{
"ik": esmanager.M{
"tokenizer": esmanager.AnalyzerIkSmart,
},
},
},
},
"mappings": esmanager.M{
"properties": esmanager.M{
FN.ESVideo.Title: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.MediaType: esmanager.M{
"type": "integer",
},
FN.ESVideo.Remark: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Desc: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Keyworlds: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.CreatorName: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Bango: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.IssuedBrand: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESVideo.Status: esmanager.M{
"type": "integer",
},
//FN.ESVideo.IsHot: esmanager.M{
// "type": "boolean",
//},
//FN.ESVideo.Sort: esmanager.M{
// "type": "integer",
//},
FN.ESVideo.WatchTimes: esmanager.M{
"type": "integer",
},
FN.ESVideo.ShowTimes: esmanager.M{
"type": "integer",
},
FN.ESVideo.Comments: esmanager.M{
"type": "integer",
},
FN.ESVideo.AddedTime: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESVideo.IssuedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
//FN.ESVideo.CreatedAt: esmanager.M{
// "type": "date",
// "format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
//},
},
},
}
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
log.Warn("初始化视频ES索引失败,跳过索引创建", log.Any("索引", esIndex), log.E(err))
}
}
func initPlayletIndex(esIndex string) {
var setting = esmanager.M{
"settings": esmanager.M{
"number_of_shards": esmanager.NumberOfShards,
"number_of_replicas": esmanager.NumberOfReplicas,
"analysis": esmanager.M{
"analyzer": esmanager.M{
"ik": esmanager.M{
"tokenizer": esmanager.AnalyzerIkSmart,
},
},
},
},
"mappings": esmanager.M{
"properties": esmanager.M{
FN.ESPlaylet.Id: esmanager.M{
"type": "long",
},
FN.ESPlaylet.Status: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.IsFeatured: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.IsRecommend: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.OperateType: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.ShowOnBanner: esmanager.M{
"type": "boolean",
},
FN.ESPlaylet.Banner: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.OnlineAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.ThemeIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.ThemeNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Title: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.PlayName: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Description: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.Slug: esmanager.M{
"type": "keyword",
},
FN.ESPlaylet.Desc: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Anchor: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkSmart,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.Cover: esmanager.M{
"type": "keyword",
"index": false,
},
FN.ESPlaylet.TagIds: esmanager.M{
"type": "long",
},
FN.ESPlaylet.TagNames: esmanager.M{
"type": "text",
"analyzer": esmanager.AnalyzerIkMaxWord,
"search_analyzer": esmanager.AnalyzerIkSmart,
},
FN.ESPlaylet.TotalEpisode: esmanager.M{
"type": "long",
},
FN.ESPlaylet.UpdateStatus: esmanager.M{
"type": "integer",
},
FN.ESPlaylet.CountBrowse: esmanager.M{
"type": "long",
},
FN.ESPlaylet.HeatValue: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CountCollect: esmanager.M{
"type": "long",
},
FN.ESPlaylet.CountLike: esmanager.M{
"type": "long",
},
FN.ESPlaylet.UpdatedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.CreatedAt: esmanager.M{
"type": "date",
"format": "strict_date_optional_time||epoch_millis||yyyy-MM-dd HH:mm:ss",
},
FN.ESPlaylet.SeoInfo: esmanager.M{
"properties": esmanager.M{
"title": esmanager.M{
"type": "keyword",
"index": false,
},
"keyworld": esmanager.M{
"type": "keyword",
"index": false,
},
"description": esmanager.M{
"type": "keyword",
"index": false,
},
},
},
},
},
}
if err := esmanager.Instance.InitIndices(esIndex, setting); err != nil {
log.Warn("初始化短剧ES索引失败,跳过索引创建", log.Any("索引", esIndex), log.E(err))
}
}
+144
View File
@@ -0,0 +1,144 @@
package esmod
import (
"context"
"go.mongodb.org/mongo-driver/bson/primitive"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// InsertOneESRecord 插入ES操作记录
func InsertOneESRecord(ctx context.Context, esRecord *ESRecord) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, esRecord); err != nil {
log.Warn("esmod:InsertOneESRecord db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneESRecord 删除一个ES操作记录
func DelOneESRecord(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("esmod:DelOnAppTag db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneESRecord 查找一个ES操作记录
func FindOneESRecord(ctx context.Context, filter bson.M) (
*ESRecord, *srvdef.SrvErr) {
var esRecord ESRecord
if err := db.FindOneEx(
ctx, &esRecord, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Info("esmod:FindOnESRecord db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &esRecord, nil
}
// CountESRecords 统计ES操作记录
func CountESRecords(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("esmod:CountMediaCats db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneESRecord 更新ES操作记录
func UpdateOneESRecord(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("esmod:UpdateOnESRecord db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("esmod:UpdateOnESRecord db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrMediaRecordNotExsit, "", "")
}
return nil
}
// UpsertOneESRecord 插入或更新一条ES操作记录
func UpsertOneESRecord(ctx context.Context,
filter bson.M, update bson.M) *srvdef.SrvErr {
if _, err := db.UpsertOne(ctx, filter, update); err != nil {
log.Info("esmod:UpsertOneESRecord db.InsertOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// UpdateManyESRecord 更新一批ES操作记录
func UpdateManyESRecord(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMMany(ctx, filter, update)
if err != nil {
log.Warn("esmod:UpdateManyMediaCat db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount <= 0 {
log.Warn("esmod:UpdateManyMediaCat db.UpdateMMany failed",
log.E(err), log.Any("filter", filter))
//return srvdef.New(srvdef.ErrMediaTagNotExsit, "", "")
}
return nil
}
// FindManyESRecord 查找一批ES操作记录
func FindManyESRecord(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (ESRecordList, *srvdef.SrvErr) {
data := make(ESRecordList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("esmod:FindManyESRecord db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
func GetRecordTimeByESIndex(ctx context.Context, esIndex string) (*ESRecord, *srvdef.SrvErr) {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
esRecord, serr := FindOneESRecord(ctx, filter)
if serr != nil {
if serr.Code != srvdef.ErrNoData {
return nil, serr
}
return nil, nil
}
return esRecord, nil
}
func SetOneEsRecordTime(ctx context.Context, esIndex string, recordTime time.Time) *srvdef.SrvErr {
filter := bson.M{FN.ESRecord.EsIndex: esIndex}
upsertDoc := bson.M{
"$set": bson.M{
FN.ESRecord.RecordTime: recordTime,
FN.ESRecord.UpdatedAt: time.Now(),
},
"$setOnInsert": bson.M{
FN.ESRecord.Id: primitive.NewObjectID(),
FN.ESRecord.CreatedAt: time.Now(),
},
}
serr := UpsertOneESRecord(ctx, filter, upsertDoc)
return serr
}
+299
View File
@@ -0,0 +1,299 @@
package esmod
type TagESRecord struct {
CreatedAt string
EsIndex string
Id string
RecordTime string
Timestamp struct {
I string
T string
}
UpdatedAt string
}
type TagESVideo struct {
Id string
Title string
Slug string
MediaType string
AddedTime string
CreatorName string
Keyworlds string
Desc string
Remark string
Status string
IsHot string
Sort string
WatchTimes string
ShowTimes string
Comments string
UpdatedAt string
CreatedAt string
Keyworld string
CreatorId string
FirstTag string
SecondTags string
CoverImg string
Nodes string
Video string
CategoryIds string
Tags string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
IssuedAt string
IssuedBrand string
Bango string
}
type TagESPlaylet struct {
Id string
Status string
IsFeatured string
IsRecommend string
OperateType string
ShowOnBanner string
Banner string
OnlineAt string
ThemeIds string
ThemeNames string
CategoryIds string
Title string
PlayName string
Description string
Slug string
Desc string
Anchor string
Cover string
TagIds string
TagNames string
TotalEpisode string
UpdateStatus string
CountBrowse string
HeatValue string
CountCollect string
CountLike string
UpdatedAt string
CreatedAt string
SeoInfo string
}
type TagESActress struct {
Id string
Alias string
Avatar string
Meas string
Office string
DebutDate string
BornDate string
Region string
Score string
Works string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
Desc string
Status string
CreatedAt string
UpdatedAt string
Rank string
}
type TagESPost struct {
Id string
CreateId string
Title string
Cover string
Thumb string
TagIds string
Kind string
Nodes string
VideoId string
Status string
Remark string
Rank string
AddedTime string
Real struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}
CreatedAt string
UpdatedAt string
Keyworlds string
FirstTag string
Desc string
IsHot string
Sort string
}
var FN struct {
ESRecord TagESRecord
ESVideo TagESVideo
ESPlaylet TagESPlaylet
ESActress TagESActress
ESPost TagESPost
}
var TN struct {
ESRecord string
ESVideo string
ESPlaylet string
ESActress string
ESPost string
}
func init() {
FN.ESRecord = TagESRecord{
CreatedAt: "createdAt",
EsIndex: "esIndex",
Id: "_id",
RecordTime: "recordTime",
Timestamp: struct {
I string
T string
}{
I: "i",
T: "t",
},
UpdatedAt: "updatedAt",
}
FN.ESVideo = TagESVideo{
Id: "_id",
Title: "title",
Slug: "slug",
Desc: "desc",
Status: "status",
AddedTime: "addedTime",
MediaType: "mediaType",
CreatorName: "creatorName",
Keyworlds: "keyworlds",
Remark: "remark",
IsHot: "isHot",
Sort: "sort",
UpdatedAt: "updatedAt",
CreatedAt: "createdAt",
WatchTimes: "watchTimes",
ShowTimes: "showTimes",
Comments: "comments",
IssuedAt: "issuedAt",
IssuedBrand: "issuedBrand",
Bango: "bango",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
}
FN.ESPlaylet = TagESPlaylet{
Id: "id",
Status: "status",
IsFeatured: "isFeatured",
IsRecommend: "isRecommend",
OperateType: "operateType",
ShowOnBanner: "showOnBanner",
Banner: "banner",
OnlineAt: "onlineAt",
ThemeIds: "themeIds",
ThemeNames: "themeNames",
CategoryIds: "categoryIds",
Title: "title",
PlayName: "playName",
Description: "description",
Slug: "slug",
Desc: "desc",
Anchor: "anchor",
Cover: "cover",
TagIds: "tagIds",
TagNames: "tagNames",
TotalEpisode: "totalEpisode",
UpdateStatus: "updateStatus",
CountBrowse: "countBrowse",
HeatValue: "heatValue",
CountCollect: "countCollect",
CountLike: "countLike",
UpdatedAt: "updatedAt",
CreatedAt: "createdAt",
SeoInfo: "seoInfo",
}
FN.ESActress = TagESActress{
Id: "_id",
Alias: "alias",
Avatar: "avatar",
Meas: "meas",
Office: "office",
DebutDate: "debutDate",
BornDate: "bornDate",
Region: "region",
Score: "score",
Works: "works",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
Desc: "desc",
Status: "status",
CreatedAt: "createdAt",
UpdatedAt: "updatedAt",
Rank: "rank",
}
FN.ESPost = TagESPost{
Id: "_id",
CreateId: "createId",
Title: "title",
Cover: "cover",
Thumb: "thumb",
TagIds: "tagIds",
Kind: "kind",
Nodes: "nodes",
VideoId: "videoId",
Status: "status",
Remark: "remark",
Rank: "rank",
AddedTime: "addedTime",
Real: struct {
WatchTimes string
ShowTimes string
Comments string
WeekWatchs string
MonthWatchs string
TodayWatchs string
}{WatchTimes: "watchTimes", ShowTimes: "showTimes", Comments: "comments", WeekWatchs: "weekWatchs", MonthWatchs: "monthWatchs", TodayWatchs: "todayWatchs"},
CreatedAt: "createdAt",
UpdatedAt: "updatedAt",
Keyworlds: "keyworlds",
FirstTag: "firstTag",
Desc: "desc",
IsHot: "isHot",
Sort: "sort",
}
TN.ESRecord = "es_record"
TN.ESVideo = "es_video"
TN.ESPlaylet = "es_playlet"
TN.ESActress = "es_actress"
TN.ESPost = "es_post"
}
+136
View File
@@ -0,0 +1,136 @@
//go:generate gen_bson_tag -m esmod
//esmod essearch数据结构定义
package esmod
import (
"time"
"videoweb/pub/models/playletmod"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/pubdef"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type ESTimestamp struct {
T uint32 `json:"t" bson:"t"`
I uint32 `json:"i" bson:"i"`
}
func (v *ESTimestamp) IsZero() bool {
if v == nil {
return true
}
return v.T == 0 && v.I == 0
}
// ESOperator es操作记录
// @table:es_record
type ESRecord struct {
Id primitive.ObjectID `json:"id" bson:"_id"`
EsIndex string `json:"esIndex" bson:"esIndex"` //es索引名称
Timestamp ESTimestamp `json:"timestamp" bson:"timestamp"` //操作时间
RecordTime time.Time `json:"recordTime" bson:"recordTime"` // 操作记录时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` //更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` //创建时间
}
type ESRecordList []*ESRecord
// ESVideo es中存储的media数据
// @table:es_video
type ESVideo struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Title string `json:"title" bson:"title"` // 帖子标题
Slug string `json:"slug" bson:"slug"` // slug
MediaType videoinformationmod.MediaType `json:"mediaType" bson:"mediaType"` // 资源类型
AddedTime time.Time `json:"addedTime" bson:"addedTime"` // 帖子上架时间
CreatorName string `json:"creatorName" bson:"creatorName"` // 作者名称
Keyworlds string `bson:"keyworlds,omitempty" json:"keyworlds"` // 关键字
Desc string `bson:"desc,omitempty" json:"desc"` // 详细描述
Remark string `bson:"remark,omitempty" json:"remark"` // 备注
Status videoinformationmod.InformationSatus `json:"status" bson:"status"` // 帖子上架状态
IsHot bool `json:"isHot" bson:"isHot"` // 是否热门
Sort int64 `json:"sort" bson:"sort"` // 排序
WatchTimes int64 `json:"watchTimes" bson:"watchTimes"` // 观看次数
ShowTimes int64 `json:"showTimes" bson:"showTimes"` // 展示次数
Comments int64 `json:"comments" bson:"comments"` // 评论条数
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
Keyworld []string `bson:"keyworld,omitempty" json:"keyworld"` // 关键字
CreatorId int64 `json:"creatorId" bson:"creatorId"` // 作者Id
FirstTag string `bson:"firstTag,omitempty" json:"firstTag"` // 一级标签
SecondTags []string `bson:"secondTags,omitempty" json:"secondTags"` // 二级标签标签
CoverImg string `bson:"coverImg,omitempty" json:"coverImg"` // 封面
Nodes []videoinformationmod.Node `json:"nodes" bson:"nodes"` // 节点
Video videoinformationmod.VideoInfo `json:"video" bson:"video"` // 视频
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类Id
Tags []int64 `json:"tags" bson:"tags"` // 标签
Real videoinformationmod.Flow `json:"real" bson:"real"` // 真实流量
VideoCount int64 `json:"videoCount" bson:"videoCount"` // 合集视频数量
}
type ESVideoList []*ESVideo
type ESTotal struct {
Value int64 `json:"value"`
}
type ESVideoSource struct {
ID string `json:"_id"`
Score float32 `json:"_score"`
Source *ESVideo `json:"_source"`
}
// ESVideoHits search media hits
type ESVideoHits struct {
Total ESTotal `json:"total"`
Hits []*ESVideoSource `json:"hits"`
}
// ESPlaylet es中存储的短剧搜索数据
// @table:es_playlet
type ESPlaylet struct {
Id int64 `json:"id" bson:"id"` // 短剧ID
Status playletmod.Status `json:"status" bson:"status"` // 状态: 0下架 1上架
IsFeatured bool `json:"isFeatured" bson:"isFeatured"` // 是否爆剧(true-是,false-否)
IsRecommend bool `json:"isRecommend" bson:"isRecommend"` // 是否推荐 true-推荐,false-不推荐
OperateType playletmod.OperateType `json:"operateType" bson:"operateType"` // 运营类型 1-短剧 2-漫剧
ShowOnBanner bool `json:"showOnBanner" bson:"showOnBanner"` // 是否显示在首页banner
Banner string `json:"banner" bson:"banner"` // banner图
OnlineAt time.Time `json:"onlineAt" bson:"onlineAt"` // 上架时间
ThemeIds []int64 `json:"themeIds" bson:"themeIds"` // 题材ID集合
ThemeNames []string `json:"themeNames" bson:"themeNames"` // 题材名称集合
CategoryIds []int64 `json:"categoryIds" bson:"categoryIds"` // 分类ID集合
Title string `json:"title" bson:"title"` // 标题
PlayName string `json:"playName" bson:"playName"` // 剧名
Description string `json:"description" bson:"description"` // SEO Description
Slug string `json:"slug" bson:"slug"` // slug
Desc string `json:"desc" bson:"desc"` // 简介
Anchor string `json:"anchor" bson:"anchor"` // 作者/演员
Cover string `json:"cover" bson:"cover"` // 封面
TagIds []int64 `json:"tagIds" bson:"tagIds"` // 标签ID集合
TagNames []string `json:"tagNames" bson:"tagNames"` // 标签名称集合
TotalEpisode int64 `json:"totalEpisode" bson:"totalEpisode"` // 总集数
UpdateStatus int `json:"updateStatus" bson:"updateStatus"` // 更新状态 1-连载中 2-已完结
CountBrowse int64 `json:"countBrowse" bson:"countBrowse"` // 观看量
HeatValue int64 `json:"heatValue" bson:"heatValue"` // 热度值
CountCollect int64 `json:"countCollect" bson:"countCollect"` // 收藏数
CountLike int64 `json:"countLike" bson:"countLike"` // 展示点赞数
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
}
type ESPlayletList []*ESPlaylet
type ESPlayletSource struct {
ID string `json:"_id"`
Score float32 `json:"_score"`
Source *ESPlaylet `json:"_source"`
}
// ESPlayletHits search playlet hits
type ESPlayletHits struct {
Total ESTotal `json:"total"`
Hits []*ESPlayletSource `json:"hits"`
}
+47
View File
@@ -0,0 +1,47 @@
package eventmod
import (
"context"
"fmt"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.Event)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Event.Status, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.EventType, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.EventId, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.Status, Value: 1},
{Key: FN.Event.RetryCount, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.Event.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(eventmod:Init) Create Event Index failed! err:%+v:", err))
}
}
+130
View File
@@ -0,0 +1,130 @@
package eventmod
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// InsertOneEvent 插入一个事件
func InsertOneEvent(ctx context.Context, event *Event) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, event); err != nil {
log.Warn("eventmod:InsertOneEvent db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// InsertManyEvent 批量插入事件
func InsertManyEvent(ctx context.Context, events *EventList) *srvdef.SrvErr {
if _, err := db.InsertMany(ctx, events); err != nil {
log.Warn("eventmod:InsertManyEvent db.InsertMany failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneEvent 删除一个事件
func DelOneEvent(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("eventmod:DelOneEvent db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyEvent 批量删除事件
func DelManyEvent(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.DeleteMany(ctx, filter)
if err != nil {
log.Warn("eventmod:DelManyEvent db.DeleteMany failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneEvent 查找一个事件
func FindOneEvent(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*Event, *srvdef.SrvErr) {
var event Event
if err := db.FindOneEx(ctx, &event, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("eventmod:FindOneEvent db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &event, nil
}
// FindManyEvent 查找多个事件
func FindManyEvent(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (EventList, *srvdef.SrvErr) {
data := make(EventList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("eventmod:FindManyEvent db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountEvent 统计事件数量
func CountEvent(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("eventmod:CountEvent db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneEvent 更新一个事件
func UpdateOneEvent(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("eventmod:UpdateOneEvent db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("eventmod:UpdateOneEvent db.UpdateOne not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpdateManyEvent 批量更新事件
func UpdateManyEvent(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("eventmod:UpdateManyEvent db.UpdateMany failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount < 1 {
log.Warn("eventmod:UpdateManyEvent db.UpdateMany not matched",
log.Any("filter", filter))
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// UpsertOneEvent 插入或更新一个事件
func UpsertOneEvent(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
opts := options.Update().SetUpsert(true)
if _, err := db.UpdateOne(ctx, filter, update, opts); err != nil {
log.Warn("eventmod:UpsertOneEvent db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+31
View File
@@ -0,0 +1,31 @@
package eventmod
type TagEvent struct {
ID string //
CreatedAt string // 创建事件
RetryCount string // 重试次数
Status string //
Data string //
EventType string //
EventId string //
UpdatedAt string // 修改时间
}
var FN struct {
Event TagEvent
}
var TN struct {
Event string
}
func init() {
FN.Event.ID = "_id"
FN.Event.CreatedAt = "createdAt"
FN.Event.RetryCount = "retryCount"
FN.Event.Status = "status"
FN.Event.Data = "data"
FN.Event.EventType = "eventType"
FN.Event.EventId = "eventId"
FN.Event.UpdatedAt = "updatedAt"
TN.Event = "event"
}
+32
View File
@@ -0,0 +1,32 @@
package eventmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type EventStatus int
const (
Default EventStatus = 0 // 默认状态,等待上报
Success EventStatus = 1 // 成功
Failure EventStatus = 2 // 失败
)
//go:generate fox mongo --model
//go:generate fox mongo --tag
//go:generate fox mongo --update
// @table:event
// @title:事件表
type Event struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
EventId string `json:"eventId" bson:"eventId"`
EventType string `json:"eventType" bson:"eventType"`
Data string `json:"data" bson:"data"`
Status EventStatus `json:"status" bson:"status"` //
RetryCount int `json:"retryCount" bson:"retryCount"` // 重试次数
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建事件
UpdatedAt time.Time `bson:"updatedAt"` // 修改时间
}
+53
View File
@@ -0,0 +1,53 @@
package eventmod
import (
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type EventList []*Event
type EventUpdate struct {
RetryCount *int `json:"retryCount" bson:"retryCount,omitempty"` // 重试次数
Status *EventStatus `json:"status" bson:"status,omitempty"` //
Data *string `json:"data" bson:"data,omitempty"` //
EventType *string `json:"eventType" bson:"eventType,omitempty"` //
EventId *string `json:"eventId" bson:"eventId,omitempty"` //
UpdatedAt *time.Time `json:"" bson:"updatedAt,omitempty"` // 修改时间
}
type EventQuery struct {
ID *primitive.ObjectID `json:"" bson:"_id,omitempty"` //
RetryCount *int `json:"retryCount" bson:"retryCount,omitempty"` // 重试次数
Status *EventStatus `json:"status" bson:"status,omitempty"` //
Data *string `json:"data" bson:"data,omitempty"` //
EventType *string `json:"eventType" bson:"eventType,omitempty"` //
EventId *string `json:"eventId" bson:"eventId,omitempty"` //
UpdatedAt *time.Time `json:"" bson:"updatedAt,omitempty"` // 修改时间
}
func (query *EventQuery) GetQueryFilter() bson.M {
filter := bson.M{}
if query.ID != nil {
filter[FN.Event.ID] = *query.ID
}
if query.RetryCount != nil {
filter[FN.Event.RetryCount] = *query.RetryCount
}
if query.Status != nil {
filter[FN.Event.Status] = *query.Status
}
if query.Data != nil {
filter[FN.Event.Data] = bson.M{"$regex": primitive.Regex{Pattern: *query.Data, Options: "i"}}
}
if query.EventType != nil {
filter[FN.Event.EventType] = bson.M{"$regex": primitive.Regex{Pattern: *query.EventType, Options: "i"}}
}
if query.EventId != nil {
filter[FN.Event.EventId] = bson.M{"$regex": primitive.Regex{Pattern: *query.EventId, Options: "i"}}
}
if query.UpdatedAt != nil {
filter[FN.Event.UpdatedAt] = *query.UpdatedAt
}
return filter
}
+93
View File
@@ -0,0 +1,93 @@
package feedbackmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 feedback 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.Feedback)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.Feedback.UserId, Value: 1},
{Key: FN.Feedback.CreatedAt, Value: -1},
{Key: FN.Feedback.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Feedback.Status, Value: 1},
{Key: FN.Feedback.CreatedAt, Value: -1},
{Key: FN.Feedback.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.Feedback.CreatedAt, Value: -1},
{Key: FN.Feedback.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(feedbackmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneFeedback 插入一条用户意见反馈数据
//
// 当 doc.Id 为空时,会使用 mongos.Lid.Feedback 自动生成自增ID
func InsertOneFeedback(ctx context.Context, doc *Feedback) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.Feedback.Get()
}
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("用户意见反馈写入失败", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindManyFeedback 按条件查询多条用户意见反馈数据
func FindManyFeedback(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (FeedbackList, *srvdef.SrvErr) {
var data FeedbackList
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("用户意见反馈列表查询失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountFeedback 统计满足条件的用户意见反馈数量
func CountFeedback(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("用户意见反馈数量统计失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateManyFeedbackWithResult 批量更新用户意见反馈数据,并返回命中数量和修改数量
func UpdateManyFeedbackWithResult(ctx context.Context, filter bson.M, update bson.M) (matchedCount int64, modifiedCount int64, serr *srvdef.SrvErr) {
result, err := coll.UpdateMany(ctx, filter, update)
if err != nil {
log.Warn("用户意见反馈批量更新失败", log.E(err), log.Any("filter", filter))
return 0, 0, srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return result.MatchedCount, result.ModifiedCount, nil
}
+38
View File
@@ -0,0 +1,38 @@
package feedbackmod
// TagFeedback 保存feedback集合字段名
type TagFeedback struct {
Id string
UserId string
FeedbackType string
Content string
Screenshots string
Contact string
Status string
Remark string
CreatedAt string
UpdatedAt string
}
var FN struct {
Feedback TagFeedback
}
var TN struct {
Feedback string
}
func init() {
FN.Feedback.Id = "_id"
FN.Feedback.UserId = "userId"
FN.Feedback.FeedbackType = "feedbackType"
FN.Feedback.Content = "content"
FN.Feedback.Screenshots = "screenshots"
FN.Feedback.Contact = "contact"
FN.Feedback.Status = "status"
FN.Feedback.Remark = "remark"
FN.Feedback.CreatedAt = "createdAt"
FN.Feedback.UpdatedAt = "updatedAt"
TN.Feedback = "feedback"
}
+32
View File
@@ -0,0 +1,32 @@
package feedbackmod
import "time"
// Feedback @table: feedback
//
// Feedback 用户意见反馈集合模型
type Feedback struct {
// ID
Id int64 `json:"id" bson:"_id,omitempty"`
// 用户ID
UserId int64 `json:"userId" bson:"userId"`
// 问题类型,1-功能建议、2-播放问题、3-账号问题、4-其他
FeedbackType int32 `json:"feedbackType" bson:"feedbackType"`
// 描述内容
Content string `json:"content" bson:"content"`
// 问题截图,可存放多张图片地址
Screenshots []string `json:"screenshots" bson:"screenshots"`
// 联系方式,可为空
Contact string `json:"contact" bson:"contact,omitempty"`
// 处理状态,0-待处理、1-已处理
Status int32 `json:"status" bson:"status"`
// 处理备注
Remark string `json:"remark" bson:"remark,omitempty"`
// 创建时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
// 更新时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
}
// FeedbackList 用户意见反馈列表
type FeedbackList []*Feedback
+135
View File
@@ -0,0 +1,135 @@
package homebannermod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 home_banner 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.HomeBanner)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.HomeBanner.Status, Value: 1},
{Key: FN.HomeBanner.UpdatedAt, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.CreatedAt, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.Status, Value: 1},
{Key: FN.HomeBanner.CreatedAt, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeBanner.Status, Value: 1},
{Key: FN.HomeBanner.Rank, Value: -1},
{Key: FN.HomeBanner.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(homebannermod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneHomeBanner 插入一条首页 banner 数据
func InsertOneHomeBanner(ctx context.Context, doc *HomeBanner) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.HomeBanner.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("homebannermod:InsertOneHomeBanner failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneHomeBanner 删除一条首页 banner 数据
func DelOneHomeBanner(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("homebannermod:DelOneHomeBanner failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOneHomeBanner 查询一条首页 banner 数据
func FindOneHomeBanner(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*HomeBanner, *srvdef.SrvErr) {
var doc HomeBanner
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("homebannermod:FindOneHomeBanner failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// FindManyHomeBanner 按条件查询多条首页 banner 数据
func FindManyHomeBanner(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (HomeBannerList, *srvdef.SrvErr) {
data := make(HomeBannerList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("homebannermod:FindManyHomeBanner failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountHomeBanner 统计满足条件的首页 banner 数量
func CountHomeBanner(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("homebannermod:CountHomeBanner failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOneHomeBanner 更新一条首页 banner 数据
func UpdateOneHomeBanner(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("homebannermod:UpdateOneHomeBanner failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+41
View File
@@ -0,0 +1,41 @@
package homebannermod
// TagHomeBanner 保存 home_banner 集合字段名
type TagHomeBanner struct {
Id string
Name string
Image string
VerticalImage string
Url string
Rank string
Status string
CreatedById string
CreatedByName string
UpdatedByName string
CreatedAt string
UpdatedAt string
}
var FN struct {
HomeBanner TagHomeBanner
}
var TN struct {
HomeBanner string
}
func init() {
FN.HomeBanner.Id = "_id"
FN.HomeBanner.Name = "name"
FN.HomeBanner.Image = "image"
FN.HomeBanner.VerticalImage = "verticalImage"
FN.HomeBanner.Url = "url"
FN.HomeBanner.Rank = "rank"
FN.HomeBanner.Status = "status"
FN.HomeBanner.CreatedById = "createdById"
FN.HomeBanner.CreatedByName = "createdByName"
FN.HomeBanner.UpdatedByName = "updatedByName"
FN.HomeBanner.CreatedAt = "createdAt"
FN.HomeBanner.UpdatedAt = "updatedAt"
TN.HomeBanner = "home_banner"
}
+24
View File
@@ -0,0 +1,24 @@
package homebannermod
import "time"
// HomeBanner @table: home_banner
//
// HomeBanner 首页 banner 配置集合模型
type HomeBanner struct {
Id int64 `json:"id" bson:"_id,omitempty"` // ID
Name string `json:"name" bson:"name"` // 名称
Image string `json:"image" bson:"image"` // 图片
VerticalImage string `json:"verticalImage" bson:"verticalImage"` // 竖版图片
Url string `json:"url" bson:"url"` // URL
Rank int64 `json:"rank" bson:"rank"` // 排序
Status bool `json:"status" bson:"status"` // 状态 true-启用 false-停用
CreatedById int64 `json:"createdById" bson:"createdById"` // 创建人ID
CreatedByName string `json:"createdByName" bson:"createdByName"` // 创建人名称
UpdatedByName string `json:"updatedByName" bson:"updatedByName"` // 修改人名称
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// HomeBannerList 首页 banner 列表
type HomeBannerList []*HomeBanner
+136
View File
@@ -0,0 +1,136 @@
package homeconfigmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 home_config 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.HomeConfig)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.HomeConfig.Type, Value: 1},
{Key: FN.HomeConfig.SortType, Value: 1},
{Key: FN.HomeConfig.Status, Value: 1},
{Key: FN.HomeConfig.Rank, Value: -1},
{Key: FN.HomeConfig.UpdatedAt, Value: -1},
{Key: FN.HomeConfig.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeConfig.Name, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.HomeConfig.Slug, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.HomeConfig.CreatedAt, Value: -1},
{Key: FN.HomeConfig.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.HomeConfig.Status, Value: 1},
{Key: FN.HomeConfig.Rank, Value: -1},
{Key: FN.HomeConfig.Id, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(homeconfigmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// InsertOneHomeConfig 插入一条首页配置数据
func InsertOneHomeConfig(ctx context.Context, doc *HomeConfig) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.HomeConfig.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
log.Warn("homeconfigmod:InsertOneHomeConfig failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneHomeConfig 删除一条首页配置数据
func DelOneHomeConfig(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("homeconfigmod:DelOneHomeConfig failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindManyHomeConfig 按条件查询多条首页配置数据
func FindManyHomeConfig(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (HomeConfigList, *srvdef.SrvErr) {
data := make(HomeConfigList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("homeconfigmod:FindManyHomeConfig failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountHomeConfig 统计满足条件的首页配置数量
func CountHomeConfig(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("homeconfigmod:CountHomeConfig failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// FindOneHomeConfig 查询一条首页配置
func FindOneHomeConfig(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*HomeConfig, *srvdef.SrvErr) {
var doc HomeConfig
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("homeconfigmod:FindOneHomeConfig failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
// UpdateOneHomeConfig 更新一条首页配置数据
func UpdateOneHomeConfig(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("homeconfigmod:UpdateOneHomeConfig failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+61
View File
@@ -0,0 +1,61 @@
package homeconfigmod
// TagHomeConfig 保存 home_config 集合字段名
type TagHomeConfig struct {
Id string
Name string
Slug string
Desc string
Keyword string
Label string
Style string
CardBackgroundImage string
TopicIds string
CategoryId string
RecommendType string
Type string
Rank string
Limit string
SortType string
Status string
SeoInfo struct {
Description string
Keyworld string
Title string
}
CreatedAt string
UpdatedAt string
}
var FN struct {
HomeConfig TagHomeConfig
}
var TN struct {
HomeConfig string
}
func init() {
FN.HomeConfig.Id = "_id"
FN.HomeConfig.Name = "name"
FN.HomeConfig.Slug = "slug"
FN.HomeConfig.Desc = "desc"
FN.HomeConfig.Keyword = "keyword"
FN.HomeConfig.Label = "label"
FN.HomeConfig.Style = "style"
FN.HomeConfig.CardBackgroundImage = "cardBackgroundImage"
FN.HomeConfig.TopicIds = "topicIds"
FN.HomeConfig.CategoryId = "categoryId"
FN.HomeConfig.RecommendType = "recommendType"
FN.HomeConfig.Type = "type"
FN.HomeConfig.Rank = "rank"
FN.HomeConfig.Limit = "limit"
FN.HomeConfig.SortType = "sortType"
FN.HomeConfig.Status = "status"
FN.HomeConfig.SeoInfo.Description = "seoInfo.webDescription"
FN.HomeConfig.SeoInfo.Keyworld = "seoInfo.webKeyworld"
FN.HomeConfig.SeoInfo.Title = "seoInfo.webTitle"
FN.HomeConfig.CreatedAt = "createdAt"
FN.HomeConfig.UpdatedAt = "updatedAt"
TN.HomeConfig = "home_config"
}
+66
View File
@@ -0,0 +1,66 @@
package homeconfigmod
import (
"strings"
"time"
"videoweb/pub/pubdef"
)
const (
TypePlaylet int32 = 1 // 短剧
TypeTheme int32 = 3 // 题材
)
const (
SortTypeRecommend int32 = 1 // 推荐
SortTypeHot int32 = 2 // 热播
SortTypeLatest int32 = 3 // 最近更新
SortTypeOnlineAt int32 = 4 // 上架时间
SortTypeCategory int32 = 5 // 分类
)
// HomeConfig @table: home_config
//
// HomeConfig 首页配置集合模型
type HomeConfig struct {
Id int64 `json:"id" bson:"_id,omitempty"` // ID
Name string `json:"name" bson:"name"` // 名称
Slug string `json:"slug" bson:"slug"` // slug,H5 更多页路径优先用它
Desc string `json:"desc" bson:"desc"` // 描述
Keyword []string `json:"keyword" bson:"keyword"` // 页面关键字
Label string `json:"label" bson:"label"`
Style string `json:"style" bson:"style"`
CardBackgroundImage string `json:"cardBackgroundImage" bson:"cardBackgroundImage"`
TopicIds []int64 `json:"topicIds" bson:"topicIds"`
CategoryId int64 `json:"categoryId" bson:"categoryId"`
RecommendType int64 `json:"recommendType" bson:"recommendType"` // 参考项目排序;0 沿用本项目 sortType
Type int32 `json:"type" bson:"type"` // 首页配置类型 1-短剧 3-题材
Rank int64 `json:"rank" bson:"rank"` // 排序,越大越靠前
Limit int64 `json:"limit" bson:"limit"` // 首页展示数量,0 时短剧默认12条、题材默认8个
SortType int32 `json:"sortType" bson:"sortType"` // 短剧模块排序 1-推荐 2-热播 3-最近更新 4-上架时间 5-分类,题材模块预览按专题详情默认排序
Status bool `json:"status" bson:"status"` // 上下架状态 true-上架 false-下架
SeoInfo pubdef.SeoValue `json:"seoInfo" bson:"seoInfo"` // Seo相关信息
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// HomeConfigList 首页配置列表
type HomeConfigList []*HomeConfig
// NormalizeKeywords 去掉空白项和重复项,始终返回非 nil 数组
func NormalizeKeywords(items []string) []string {
out := make([]string, 0, len(items))
seen := make(map[string]struct{}, len(items))
for _, item := range items {
item = strings.TrimSpace(item)
if item == "" {
continue
}
if _, ok := seen[item]; ok {
continue
}
seen[item] = struct{}{}
out = append(out, item)
}
return out
}
+105
View File
@@ -0,0 +1,105 @@
package hotsearchmod
import (
"context"
"fmt"
"strings"
"time"
"unicode"
"unicode/utf8"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.HotSearch)
indexes := []mongo.IndexModel{
{
Keys: bson.D{{Key: FN.HotSearch.Keyword, Value: 1}},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.HotSearch.Count, Value: -1},
{Key: FN.HotSearch.UpdatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(hotsearchmod:Init) Create HotSearch Index failed! err:%+v:", err))
}
}
// NormalizeKeyword 去掉首尾空白、压缩中间空格,并限制长度。
func NormalizeKeyword(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
fields := strings.FieldsFunc(raw, unicode.IsSpace)
raw = strings.Join(fields, " ")
if utf8.RuneCountInString(raw) > MaxKeywordRunes {
raw = string([]rune(raw)[:MaxKeywordRunes])
}
return raw
}
// IncrByKeyword 按搜索词累加次数,不存在则插入。
func IncrByKeyword(ctx context.Context, keyword string) *srvdef.SrvErr {
keyword = NormalizeKeyword(keyword)
if keyword == "" {
return nil
}
now := time.Now()
filter := bson.M{FN.HotSearch.Keyword: keyword}
update := bson.M{
"$inc": bson.M{FN.HotSearch.Count: 1},
"$set": bson.M{FN.HotSearch.UpdatedAt: now},
"$setOnInsert": bson.M{
FN.HotSearch.Id: mongos.Lid.HotSearch.Get(),
FN.HotSearch.Keyword: keyword,
FN.HotSearch.CreatedAt: now,
},
}
if _, err := db.UpsertOne(ctx, filter, update); err != nil {
if _, retryErr := db.UpdateOne(ctx, filter, bson.M{
"$inc": bson.M{FN.HotSearch.Count: 1},
"$set": bson.M{FN.HotSearch.UpdatedAt: now},
}); retryErr != nil {
log.Warn("hotsearchmod:IncrByKeyword failed", log.E(err), log.E(retryErr), log.Any("keyword", keyword))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
}
return nil
}
func FindTopHotSearch(ctx context.Context, limit int64) (HotSearchList, *srvdef.SrvErr) {
if limit <= 0 {
limit = TopLimit
}
opts := options.Find().
SetSort(bson.D{
{Key: FN.HotSearch.Count, Value: -1},
{Key: FN.HotSearch.UpdatedAt, Value: -1},
{Key: FN.HotSearch.Id, Value: -1},
}).
SetLimit(limit).
SetProjection(bson.D{
{Key: FN.HotSearch.Id, Value: 1},
{Key: FN.HotSearch.Keyword, Value: 1},
{Key: FN.HotSearch.Count, Value: 1},
})
data := make(HotSearchList, 0)
if err := db.Find(ctx, &data, bson.M{}, opts); err != nil {
log.Warn("hotsearchmod:FindTopHotSearch db.Find failed", log.E(err))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
+31
View File
@@ -0,0 +1,31 @@
package hotsearchmod
import "testing"
func TestNormalizeKeyword(t *testing.T) {
tests := []struct {
name string
raw string
want string
}{
{name: "空串", raw: " ", want: ""},
{name: "压缩空白", raw: " 霸道 总裁\t ", want: "霸道 总裁"},
{name: "截断长度", raw: stringsRepeat("测", 60), want: stringsRepeat("测", MaxKeywordRunes)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NormalizeKeyword(tt.raw); got != tt.want {
t.Fatalf("NormalizeKeyword() = %q, want %q", got, tt.want)
}
})
}
}
func stringsRepeat(s string, n int) string {
out := make([]rune, 0, n)
r := []rune(s)[0]
for i := 0; i < n; i++ {
out = append(out, r)
}
return string(out)
}
+26
View File
@@ -0,0 +1,26 @@
package hotsearchmod
type TagHotSearch struct {
Id string
Keyword string
Count string
CreatedAt string
UpdatedAt string
}
var FN struct {
HotSearch TagHotSearch
}
var TN struct {
HotSearch string
}
func init() {
FN.HotSearch.Id = "_id"
FN.HotSearch.Keyword = "keyword"
FN.HotSearch.Count = "count"
FN.HotSearch.CreatedAt = "createdAt"
FN.HotSearch.UpdatedAt = "updatedAt"
TN.HotSearch = "hot_search"
}
+20
View File
@@ -0,0 +1,20 @@
package hotsearchmod
import "time"
const (
MaxKeywordRunes = 50
TopLimit = 10
)
// HotSearch 热搜词
// @table:hot_search
type HotSearch struct {
Id int64 `json:"id" bson:"_id,omitempty"`
Keyword string `json:"keyword" bson:"keyword"` // 搜索词
Count int64 `json:"count" bson:"count"` // 搜索次数
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 首次记录时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 最近搜索时间
}
type HotSearchList []*HotSearch
+109
View File
@@ -0,0 +1,109 @@
package ipblackmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
// 获取数据库表
db = mongos.Shop.Coll(TN.IPBlackModel)
// 初始化索引
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.IPBlackModel.Ip, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(IPBlackModel:InitIPBlackModel) Create IPBlackModel Index failed! err:%+v:", err))
}
}
// CountIPBlackModel 统计活动数量
func CountIPBlackModel(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.Count(ctx, filter)
if err != nil {
log.Warn("IPBlackModelmod:CountIPBlackModel db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// InsertOneIPBlackModel 插入一条活动
func InsertOneIPBlackModel(ctx context.Context, IPBlackModel *IPBlackModel) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, IPBlackModel); err != nil {
log.Info("IPBlackModelmod:InsertOneIPBlackModel db.InsertOne failed",
log.E(err), log.Any("IPBlackModel", IPBlackModel))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// DelOneIPBlackModel 删除一个活动
func DelOneIPBlackModel(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := db.DeleteOne(ctx, filter)
if err != nil {
log.Warn("IPBlackModelmod:DelOneIPBlackModel db.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// UpdateOneIPBlackModel 更新一个IPBlackModel
func UpdateOneIPBlackModel(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := db.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("IPBlackModelmod:UpdateOneIPBlackModel db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
log.Warn("IPBlackModelmod:UpdateOneIPBlackModel db.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ObjectNotExist, "", "")
}
return nil
}
// FindManyIPBlackModel 查找一批活动数据
func FindManyIPBlackModel(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (IPBlackModelList, *srvdef.SrvErr) {
data := make(IPBlackModelList, 0)
if err := db.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("IPBlackModelmod:FindManyAcivities db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// FindOneIPBlackModel 查找一个媒体
func FindOneIPBlackModel(ctx context.Context, filter bson.M) (
*IPBlackModel, *srvdef.SrvErr) {
var IPBlackModel IPBlackModel
if err := db.FindOneEx(ctx, &IPBlackModel, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("IPBlackModel:FindOneIPBlackModel db.FindOne failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ObjectDayStatDoesNotExist, "", "")
}
return &IPBlackModel, nil
}
+26
View File
@@ -0,0 +1,26 @@
package ipblackmod
type TagIPBlackModel struct {
CreatedAt string
ID string
Ip string
Desc string
UpdatedAt string
}
var FN struct {
IPBlackModel TagIPBlackModel
}
var TN struct {
IPBlackModel string
}
func init() {
FN.IPBlackModel.CreatedAt = "createdAt"
FN.IPBlackModel.ID = "_id"
FN.IPBlackModel.Ip = "ip"
FN.IPBlackModel.UpdatedAt = "updatedAt"
FN.IPBlackModel.Desc = "desc"
TN.IPBlackModel = "ip_black"
}
+18
View File
@@ -0,0 +1,18 @@
package ipblackmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 资源同步
// @table:ip_black
type IPBlackModel struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Ip string `json:"ip" bson:"ip"`
Desc string `json:"desc" bson:"desc"` // 备注
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
type IPBlackModelList []*IPBlackModel
+59
View File
@@ -0,0 +1,59 @@
package ipdailystatmod
import (
"context"
"time"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.IpDailyStat)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.IpDailyStat.AppId, Value: 1},
{Key: FN.IpDailyStat.Date, Value: 1},
},
Options: options.Index().SetUnique(true),
},
}
_, _ = db.CreateIndex(ctx, indexes)
}
func UpsertCount(ctx context.Context, appId int64, date string, count int64) error {
filter := bson.M{
FN.IpDailyStat.AppId: appId,
FN.IpDailyStat.Date: date,
}
update := bson.M{
"$set": bson.M{
FN.IpDailyStat.Count: count,
FN.IpDailyStat.UpdatedAt: time.Now(),
},
}
_, err := db.UpsertOne(ctx, filter, update)
return err
}
func FindCount(ctx context.Context, appId int64, date string) (int64, error) {
filter := bson.M{
FN.IpDailyStat.AppId: appId,
FN.IpDailyStat.Date: date,
}
var stat IpDailyStat
err := db.FindOneEx(ctx, &stat, filter)
if err != nil {
if err == mongo.ErrNoDocuments {
return 0, nil
}
return 0, err
}
return stat.Count, nil
}
+25
View File
@@ -0,0 +1,25 @@
package ipdailystatmod
type tagIpDailyStat struct {
AppId string
Date string
Count string
UpdatedAt string
}
var FN struct {
IpDailyStat tagIpDailyStat
}
var TN struct {
IpDailyStat string
}
func init() {
FN.IpDailyStat.AppId = "appId"
FN.IpDailyStat.Date = "date"
FN.IpDailyStat.Count = "count"
FN.IpDailyStat.UpdatedAt = "updatedAt"
TN.IpDailyStat = "ip_daily_stat"
}
+12
View File
@@ -0,0 +1,12 @@
package ipdailystatmod
import "time"
// IpDailyStat 每日访客 IP 去重统计。
// @table:ip_daily_stat
type IpDailyStat struct {
AppId int64 `bson:"appId"` // 站点 ID
Date string `bson:"date"` // 日期,格式 "20060102"
Count int64 `bson:"count"` // 当日去重 IP 数
UpdatedAt time.Time `bson:"updatedAt"` // 最后同步时间
}
@@ -0,0 +1,73 @@
package m3u8requestlogmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
var db *mongos.Collection
func Init(ctx context.Context) {
db = mongos.Shop.Coll(TN.M3U8RequestLog)
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.VideoId, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.M3U8Path, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.ClientIP, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.Host, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.Status, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.M3U8RequestLog.TokenOK, Value: 1},
{Key: FN.M3U8RequestLog.PathOK, Value: 1},
{Key: FN.M3U8RequestLog.CreatedAt, Value: -1},
},
},
}
if _, err := db.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(m3u8requestlogmod:Init) Create M3U8RequestLog Index failed! err:%+v:", err))
}
}
func InsertOneM3U8RequestLog(ctx context.Context, doc *M3U8RequestLog) *srvdef.SrvErr {
if _, err := db.InsertOne(ctx, doc); err != nil {
log.Warn("m3u8requestlogmod:InsertOneM3U8RequestLog db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
+66
View File
@@ -0,0 +1,66 @@
package m3u8requestlogmod
type TagM3U8RequestLog struct {
CDNDomain string
CFConnectingIP string
ClientIP string
CostMs string
CreatedAt string
Error string
Headers string
Host string
Id string
IsOverseas string
M3U8Path string
PathOK string
Query string
RawQuery string
Referer string
RemoteAddr string
RequestURI string
Status string
T string
Token string
TokenOK string
UserAgent string
VideoId string
XForwardedFor string
XRealIP string
}
var FN struct {
M3U8RequestLog TagM3U8RequestLog
}
var TN struct {
M3U8RequestLog string
}
func init() {
FN.M3U8RequestLog.CDNDomain = "cdnDomain"
FN.M3U8RequestLog.CFConnectingIP = "cfConnectingIP"
FN.M3U8RequestLog.ClientIP = "clientIP"
FN.M3U8RequestLog.CostMs = "costMs"
FN.M3U8RequestLog.CreatedAt = "createdAt"
FN.M3U8RequestLog.Error = "error"
FN.M3U8RequestLog.Headers = "headers"
FN.M3U8RequestLog.Host = "host"
FN.M3U8RequestLog.Id = "_id"
FN.M3U8RequestLog.IsOverseas = "isOverseas"
FN.M3U8RequestLog.M3U8Path = "m3u8Path"
FN.M3U8RequestLog.PathOK = "pathOK"
FN.M3U8RequestLog.Query = "query"
FN.M3U8RequestLog.RawQuery = "rawQuery"
FN.M3U8RequestLog.Referer = "referer"
FN.M3U8RequestLog.RemoteAddr = "remoteAddr"
FN.M3U8RequestLog.RequestURI = "requestURI"
FN.M3U8RequestLog.Status = "status"
FN.M3U8RequestLog.T = "t"
FN.M3U8RequestLog.Token = "token"
FN.M3U8RequestLog.TokenOK = "tokenOK"
FN.M3U8RequestLog.UserAgent = "userAgent"
FN.M3U8RequestLog.VideoId = "videoId"
FN.M3U8RequestLog.XForwardedFor = "xForwardedFor"
FN.M3U8RequestLog.XRealIP = "xRealIP"
TN.M3U8RequestLog = "m3u8_request_log"
}
+37
View File
@@ -0,0 +1,37 @@
package m3u8requestlogmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// M3U8RequestLog records every HLS playlist request for hotlink analysis.
// @table:m3u8_request_log
type M3U8RequestLog struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
CreatedAt time.Time `bson:"createdAt"`
Host string `bson:"host"`
RequestURI string `bson:"requestURI"`
M3U8Path string `bson:"m3u8Path"`
RawQuery string `bson:"rawQuery"`
Query map[string][]string `bson:"query"`
Headers map[string][]string `bson:"headers"`
VideoId int64 `bson:"videoId"`
T int64 `bson:"t"`
Token string `bson:"token"`
ClientIP string `bson:"clientIP"`
RemoteAddr string `bson:"remoteAddr"`
XForwardedFor string `bson:"xForwardedFor"`
XRealIP string `bson:"xRealIP"`
CFConnectingIP string `bson:"cfConnectingIP"`
UserAgent string `bson:"userAgent"`
Referer string `bson:"referer"`
IsOverseas bool `bson:"isOverseas"`
CDNDomain string `bson:"cdnDomain"`
TokenOK bool `bson:"tokenOK"`
PathOK bool `bson:"pathOK"`
Status string `bson:"status"`
Error string `bson:"error"`
CostMs int64 `bson:"costMs"`
}
+113
View File
@@ -0,0 +1,113 @@
package models
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/models/aicommentrecord"
"videoweb/pub/models/announcementmod"
"videoweb/pub/models/cfg"
"videoweb/pub/models/cointransmod"
"videoweb/pub/models/commentlikemod"
"videoweb/pub/models/commentmod"
"videoweb/pub/models/contactusmod"
"videoweb/pub/models/detailnavmod"
"videoweb/pub/models/esmod"
"videoweb/pub/models/eventmod"
"videoweb/pub/models/feedbackmod"
"videoweb/pub/models/homebannermod"
"videoweb/pub/models/homeconfigmod"
"videoweb/pub/models/hotsearchmod"
"videoweb/pub/models/ipblackmod"
"videoweb/pub/models/ipdailystatmod"
"videoweb/pub/models/m3u8requestlogmod"
"videoweb/pub/models/mwacc"
"videoweb/pub/models/oplog"
"videoweb/pub/models/playletbackflowstatmod"
"videoweb/pub/models/playletchaptercollectmod"
"videoweb/pub/models/playletchapterlikemod"
"videoweb/pub/models/playletchaptermod"
"videoweb/pub/models/playletchapterunlockmod"
"videoweb/pub/models/playletcollectmod"
"videoweb/pub/models/playletlikemod"
"videoweb/pub/models/playletmod"
"videoweb/pub/models/playlettagmod"
"videoweb/pub/models/playletthememod"
"videoweb/pub/models/playlettopicgroupmod"
"videoweb/pub/models/playletwatchhistorymod"
"videoweb/pub/models/playletwatchprogressmod"
"videoweb/pub/models/rechargepackagemod"
"videoweb/pub/models/richtextcontentmod"
"videoweb/pub/models/seopushmod"
"videoweb/pub/models/syncfilemod"
"videoweb/pub/models/translationcategorymod"
"videoweb/pub/models/translationmod"
"videoweb/pub/models/userlogin"
"videoweb/pub/models/usermod"
"videoweb/pub/models/uservisitlog"
"videoweb/pub/models/videocategorymod"
"videoweb/pub/models/videocollectmod"
"videoweb/pub/models/videocreatermod"
"videoweb/pub/models/videoinformationmod"
"videoweb/pub/models/videolikemod"
"videoweb/pub/models/videotagmod"
"videoweb/pub/models/videotopicmod"
"videoweb/pub/models/videowatchhistorymod"
"videoweb/pub/models/vipordermod"
)
func Init() {
log.Info("models init start..")
ctx := context.Background()
cfg.Init(ctx)
mwacc.Init(ctx)
oplog.Init(ctx)
m3u8requestlogmod.Init(ctx)
syncfilemod.Init(ctx)
seopushmod.Init(ctx)
richtextcontentmod.Init(ctx)
announcementmod.Init(ctx)
hotsearchmod.Init(ctx)
homebannermod.Init(ctx)
homeconfigmod.Init(ctx)
commentmod.Init(ctx)
aicommentrecord.Init(ctx)
commentlikemod.Init(ctx)
ipblackmod.Init(ctx)
ipdailystatmod.Init(ctx)
esmod.Init(ctx)
detailnavmod.Init(ctx)
eventmod.Init(ctx)
translationcategorymod.Init(ctx)
translationmod.Init(ctx)
playletthememod.Init(ctx)
playlettopicgroupmod.Init(ctx)
playlettagmod.Init(ctx)
playletmod.Init(ctx)
playletbackflowstatmod.Init(ctx)
playletchaptermod.Init(ctx)
playletchapterlikemod.Init(ctx)
playletchaptercollectmod.Init(ctx)
playletchapterunlockmod.Init(ctx)
playletlikemod.Init(ctx)
playletcollectmod.Init(ctx)
playletwatchhistorymod.Init(ctx)
playletwatchprogressmod.Init(ctx)
feedbackmod.Init(ctx)
videocategorymod.Init(ctx)
videocreatermod.Init(ctx)
videotagmod.Init(ctx)
videoinformationmod.Init(ctx)
videolikemod.Init(ctx)
videocollectmod.Init(ctx)
videowatchhistorymod.Init(ctx)
videotopicmod.Init(ctx)
rechargepackagemod.Init(ctx)
cointransmod.Init(ctx)
contactusmod.Init(ctx)
vipordermod.Init(ctx)
usermod.Init(ctx)
userlogin.Init(ctx)
uservisitlog.Init(ctx)
log.Info("models init end")
}
+169
View File
@@ -0,0 +1,169 @@
package mwacc
import (
"context"
"fmt"
"time"
"videoweb/pub/common/errors"
sErr "videoweb/pub/common/errors"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 过滤查询数量
func AccCountByFilter(ctx context.Context, filters primitive.M, opts ...*options.CountOptions) (c int64, err error) {
c, err = mwAccColl.Count(ctx, filters)
return
}
// 过滤查询账号
func FindOneAccByFilter(ctx context.Context, filters primitive.M, opts ...*options.FindOneOptions) (*MwAcc, error) {
var res MwAcc
err := mwAccColl.FindOne(ctx, &res, filters, opts...)
if err != nil {
log.Error("mwacc FindOneAccByFilter err", log.Any("filters", filters), log.E(err))
}
return &res, err
}
// 过滤更新
func UpOneAccByFilter(ctx context.Context, query primitive.M, update primitive.M) (err error) {
_, err = mwAccColl.UpdateOne(ctx, query, primitive.M{"$set": update})
return
}
// 过滤删除角色
func DelAccByFilter(ctx context.Context, filters primitive.M) (err error) {
_, err = mwAccColl.DeleteOne(ctx, filters)
if err != nil {
log.Error("mwacc DelAccByFilter err", log.Any("filters", filters), log.E(err))
}
return
}
// // 更新最后登录时间
// func UpAccLastTimeById(ctx context.Context, id int64) (*mongo.UpdateResult, error) {
// ret, err := mwAccColl.UpdateOne(ctx, primitive.M{FN.MwAcc.Id: id}, primitive.M{"$set": primitive.M{FN.MwAcc.LastTime: time.Now()}})
// if err != nil {
// log.Error("mvacc UpLastTimeById err", log.Any(FN.MwAcc.Id, id), log.E(err))
// }
// return ret, err
// }
// 绑定二维码
func BindAccQurl(ctx context.Context, acc string) (ok bool, err error) {
res, dataErr := FindOneAccByFilter(ctx, primitive.M{
FN.MwAcc.Acc: acc,
})
if dataErr != nil || res.Id == 0 {
err = sErr.MakeWithMsg(sErr.Logo, "用户不存在!")
return false, err
}
if res.IsEnb == false {
err = sErr.MakeWithMsg(sErr.UserPermission, "用户被禁用!")
return false, err
}
err = UpOneAccByFilter(ctx, primitive.M{
FN.MwAcc.Acc: acc,
}, primitive.M{
FN.MwAcc.IsBase32: true,
})
if err != nil {
return false, err
}
return true, err
}
// 插入角色
func AccAdd(ctx context.Context, insertReq *AccInsertDoc) (id int64, ok bool, err error) {
insertReq.Id = int64(mongos.Lid.MwAcc.Get())
insertReq.CreatedAt = time.Now()
_, err = mwAccColl.InsertOne(ctx, insertReq)
if err != nil {
log.ZapLog.Error(fmt.Sprintf("InsertRole mongo error %v", err))
err = errors.MakeWithErr(errors.DBInsert, err)
return 0, false, err
}
return insertReq.Id, true, nil
}
// 获取角色列表
func GetAccList(ctx context.Context, search primitive.M, sort []primitive.M) (
total int64, data []*AccGetListRec, err error) {
var countPipe []primitive.M
countPipe = append(countPipe, search, bson.M{"$count": "total"})
var aggCount AggStatCount
err = mwAccColl.ObjectAggregate(ctx, &aggCount, countPipe)
if err != nil {
return 0, nil, err
}
total = aggCount.Total
var pip []primitive.M
pip = append(pip, search)
pip = append(pip, sort...)
pip = append(pip,
primitive.M{
"$lookup": primitive.M{
"localField": FN.MwAcc.RoleId,
"from": TN.MwRole,
"foreignField": FN.MwRole.Id,
"as": "roles",
},
},
primitive.M{"$unwind": primitive.M{
"path": "$roles",
"preserveNullAndEmptyArrays": true,
},
},
primitive.M{
"$project": primitive.M{
FN.MwAcc.Id: 1,
FN.MwAcc.UserName: 1,
FN.MwAcc.Acc: 1,
FN.MwAcc.Email: 1,
FN.MwAcc.RoleId: 1,
FN.MwAcc.RoleName: "$roles.name",
FN.MwAcc.Base32: 1,
FN.MwAcc.IsBase32: 1,
// mwacc.FN.MwAcc.LastTime: 1,
FN.MwAcc.IsEnb: 1,
FN.MwAcc.Feedback: 1,
FN.MwAcc.CreatedAt: 1,
FN.MwAcc.UpdatedAt: 1,
FN.MwAcc.LimitIP: 1,
},
})
err = mwAccColl.Aggregate(ctx, &data, pip)
if err != nil {
err = errors.MakeWithErr(errors.DBQuery, err)
return
}
return
}
// 过滤查询账号
func FindManyAccByFilter(ctx context.Context, filters primitive.M, opts ...*options.FindOptions) ([]*MwAcc, *srvdef.SrvErr) {
var res []*MwAcc
err := mwAccColl.Find(ctx, &res, filters, opts...)
if err != nil {
log.Error("mwacc FindOneAccByFilter err", log.Any("filters", filters), log.E(err))
return res, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
log.Info("success")
return res, nil
}
+13
View File
@@ -0,0 +1,13 @@
package mwacc
import "videoweb/pub/mongos"
var (
mwAccColl *mongos.Collection = nil
mwRoleColl *mongos.Collection = nil
mwAccTokenColl *mongos.Collection = nil
)
type AggStatCount struct {
Total int64 `bson:"total"`
}
+66
View File
@@ -0,0 +1,66 @@
package mwacc
import (
"context"
"fmt"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
)
// Init 初始化数据
func Init(ctx context.Context) {
mwAccColl = mongos.Shop.Coll(TN.MwAcc)
mwRoleColl = mongos.Shop.Coll(TN.MwRole)
mwAccTokenColl = mongos.Shop.Coll(TN.MwAccToken)
initIndex(ctx)
return
}
// initIndex 初始化索引
func initIndex(ctx context.Context) {
initAccIndex(ctx)
initRoleIndex(ctx)
initAccTokenIndex(ctx)
}
func initAccIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.MwAcc.Id, 1},
},
},
}
if _, err := mwAccColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(mwacc:initAccIndex) Create mwacc Index failed! err:%+v:", err))
}
}
func initRoleIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.MwRole.Id, 1},
},
// Options: options.Index().SetUnique(true),
},
}
if _, err := mwRoleColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(mwacc:initRoleIndex) Create mwacc Index failed! err:%+v:", err))
}
}
func initAccTokenIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.MwAccToken.Id, 1},
},
// Options: options.Index().SetUnique(true),
},
}
if _, err := mwAccTokenColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(mwacc:initAccTokenIndex) Create mwacc Index failed! err:%+v:", err))
}
}
+61
View File
@@ -0,0 +1,61 @@
package mwacc
import (
"strconv"
"videoweb/pub/pubdef"
"go.mongodb.org/mongo-driver/bson"
)
func MakeSearch(keyWords string, status int64, page pubdef.Page) (searchs bson.M) {
var search []bson.M
if len(keyWords) > 0 {
userId, _ := strconv.ParseInt(keyWords, 10, 64)
search = append(search, bson.M{FN.MwAcc.Id: userId})
search = append(search, bson.M{FN.MwAcc.UserName: bson.M{"$regex": keyWords}})
search = append(search, bson.M{FN.MwAcc.Acc: bson.M{"$regex": keyWords}})
search = append(search, bson.M{FN.MwAcc.Email: bson.M{"$regex": keyWords}})
}
match := bson.M{}
if len(search) > 0 {
match["$or"] = search
}
if status > 0 {
if status == 1 {
match[FN.MwAcc.IsEnb] = true
} else {
match[FN.MwAcc.IsEnb] = false
}
}
searchs = bson.M{}
searchs["$match"] = match
return
}
func MakeSort(pageNum int64, pageSize int64) (sort []bson.M) {
sort = append(sort, bson.M{
"$sort": bson.M{
FN.MwAcc.CreatedAt: -1,
},
})
if pageNum <= 0 {
pageNum = 1
}
if pageSize <= 0 {
pageSize = 10
}
skip := (pageNum - 1) * pageSize
sort = append(sort, bson.M{
"$skip": skip,
})
sort = append(sort, bson.M{
"$limit": pageSize,
})
return
}
+130
View File
@@ -0,0 +1,130 @@
// Code generated by gen_bson_tag. DO NOT EDIT.
package mwacc
import (
"context"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// CreateOneMwAcc 创建一个MwAcc
func CreateOneMwAcc(ctx context.Context, data *MwAcc) *srvdef.SrvErr {
_, err := mwAccColl.InsertOne(ctx, data)
if err != nil {
log.Error("mwacc:CreateOneMwAcc db.InsertOne failed",
log.Any("doc", data),
log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindOneMwAcc 查找一个MwAcc
func FindOneMwAcc(ctx context.Context, filter bson.M) (
*MwAcc, *srvdef.SrvErr) {
var data *MwAcc
if err := mwAccColl.FindOneEx(ctx, &data, filter); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("mwacc:FindOneMwAcc mwAccColl.FindOneEx failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return data, nil
}
// DelOneOneMwAcc 删除一个MwAcc
func DelOneOneMwAcc(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := mwAccColl.DeleteOne(ctx, filter)
if err != nil {
log.Warn("mwacc:DelOneOneMwAcc mwAccColl.DeleteOne failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// UpdateOneMwAcc 更新一个MwAcc
func UpdateOneMwAcc(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := mwAccColl.UpdateOne(ctx, filter, update)
if err != nil {
log.Warn("mwacc:UpdateOneMwAcc mwAccColl.UpdateOne failed",
log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// CountMwAccs 统计MwAcc数量
func CountMwAccs(ctx context.Context, filter bson.M) (
int64, *srvdef.SrvErr) {
count, err := mwAccColl.Count(ctx, filter)
if err != nil {
log.Warn("mwacc:CountMwAccs mwAccColl.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// FindManyMwAccs 查找一批MwAcc
func FindManyMwAccs(ctx context.Context, filter bson.M,
opts ...*options.FindOptions) (MwAccList, *srvdef.SrvErr) {
data := make(MwAccList, 0)
if err := mwAccColl.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("mwacc:FindManyMwAccs mwAccColl.Find failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// FindManyMwAccsWithBind 用自己定义结构查找一批MwAcc数据
func FindManyMwAccsWithBind(ctx context.Context, bind interface{}, filter bson.M,
opts ...*options.FindOptions) *srvdef.SrvErr {
if err := mwAccColl.Find(ctx, bind, filter, opts...); err != nil {
log.Warn("mwacc:FindManyMwAccsWithBind mwAccColl.Find failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// AggregateMwAccs 聚合查找一批MwAcc
func AggregateMwAccs(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := mwAccColl.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("mwacc:AggregateMwAccs mwAccColl.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateMwAccs 聚合查找一批MwAcc数据
func ObjectAggregateMwAccs(ctx context.Context,
bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := mwAccColl.ObjectAggregate(ctx, bind, pipeline); err != nil {
log.Warn("mwacc:AggregateMwAccs mwAccColl.Aggregate failed",
log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
// ObjectAggregateMwAccs 批量写入或者更新MwAcc数据
func BulkWriteMwAccs(ctx context.Context,
docs []mongo.WriteModel, opts ...*options.BulkWriteOptions) *srvdef.SrvErr {
_, err := mwAccColl.BulkWrite(ctx, docs, opts...)
if err != nil {
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+158
View File
@@ -0,0 +1,158 @@
package mwacc
import (
"context"
"fmt"
"time"
"videoweb/pub/common/errors"
"videoweb/pub/common/log"
"videoweb/pub/common/pageopt"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
// 角色聚集处理
func RoleAggregate(ctx context.Context, filters []primitive.M, opts ...*options.AggregateOptions) (roles []*MwRole, err error) {
roles = make([]*MwRole, 0)
err = mwRoleColl.Aggregate(ctx, &roles, filters)
return
}
// 过滤查询数量
func RoleCountByFilter(ctx context.Context, filters primitive.M, opts ...*options.CountOptions) (c int64, err error) {
c, err = mwRoleColl.Count(ctx, filters)
return
}
// 过滤查询角色
func FindOneRoleByFilter(ctx context.Context, filters primitive.M, opts ...*options.FindOneOptions) (*MwRole, *srvdef.SrvErr) {
var res MwRole
err := mwRoleColl.FindOne(ctx, &res, filters, opts...)
if err != nil {
log.Error("mwacc FindOneRoleByFilter err", log.Any("filters", filters), log.E(err))
return &res, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return &res, nil
}
// 过滤更新
func UpOneRoleByFilter(ctx context.Context, query primitive.M, update primitive.M) *srvdef.SrvErr {
_, err := mwRoleColl.UpdateOne(ctx, query, update)
if err != nil {
log.Error("mwacc UpOneRoleByFilter: db.UpdateOne err", log.Any("update", update), log.E(err))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// 过滤删除角色
func DelRoleByFilter(ctx context.Context, filters primitive.M) *srvdef.SrvErr {
_, err := mwRoleColl.DeleteOne(ctx, filters)
if err != nil {
log.Error("mwacc DelRoleByFilter err", log.Any("filters", filters), log.E(err))
return srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return nil
}
// 更新角色权限
func UpRoleAuth(ctx context.Context, id int64, keys []string, dataRouter []*Router) (ok bool, err error) {
_, err = mwRoleColl.UpdateOne(ctx, primitive.M{
FN.MwRole.Id: id,
}, primitive.M{
"$set": primitive.M{
FN.MwRole.ApiMenus: keys,
FN.MwRole.Router: dataRouter,
},
})
if err != nil {
log.Error("mvacc UpRoleAuth err", log.Any(FN.MwRole.Id, id), log.E(err))
return false, err
}
return true, nil
}
// 获取角色列表
func GetRoleList(ctx context.Context, skip, limit int64, matchs ...pageopt.Matcher) (data []*RoleGetListRec, err error) {
data = make([]*RoleGetListRec, 0)
err = mwRoleColl.Aggregate(ctx, &data,
[]primitive.M{
{"$match": pageopt.MergeM(matchs)},
{"$sort": primitive.M{FN.MwRole.Id: -1}},
{"$skip": skip},
{"$limit": limit},
{"$lookup": primitive.M{
"localField": FN.MwRole.Id,
"from": TN.MwAcc,
"foreignField": FN.MwAcc.RoleId,
"as": "onlyRole",
}},
{"$project": primitive.M{
FN.MwRole.Id: 1,
FN.MwRole.Name: 1,
FN.MwRole.Desc: 1,
FN.MwRole.IsEnb: 1,
FN.MwRole.ApiMenus: 1,
FN.MwRole.CreatedAt: 1,
FN.MwRole.UpdatedAt: 1,
"account": primitive.M{
"$size": "$onlyRole",
},
}},
})
if err != nil && err.Error() != errors.NotFind {
log.ZapLog.Error(fmt.Sprintf("mwacc GetRoleList error %v", err))
err = errors.MakeWithErr(errors.DBQuery, err)
return
}
return
}
// 下拉列表
func RoleDrop(ctx context.Context) (data []*RoleDropDoc, err error) {
query := primitive.M{FN.MwRole.IsEnb: true}
opt := options.Find().SetProjection(primitive.M{
FN.MwRole.Id: 1,
FN.MwRole.Name: 1,
})
err = mwRoleColl.Find(ctx, &data, query, opt)
if err != nil {
err = errors.MakeWithErr(errors.DBQuery, err)
return
}
return
}
// 插入角色
func RoleAdd(ctx context.Context, name string, desc string, isEnb bool) (ok bool, err error) {
c, err := mwRoleColl.Count(ctx, primitive.M{FN.MwRole.Name: name})
if c > 0 {
err = errors.MakeWithMsg(errors.DBInsert, "角色名称")
return false, err
}
_, err = mwRoleColl.InsertOne(ctx, primitive.M{
FN.MwRole.Id: mongos.Lid.MwRole.Get(),
FN.MwRole.Name: name,
FN.MwRole.Desc: desc,
FN.MwRole.IsEnb: isEnb,
FN.MwRole.CreatedAt: time.Now(),
})
if err != nil {
log.ZapLog.Error(fmt.Sprintf("InsertRole mongo error %v", err))
err = errors.MakeWithErr(errors.DBInsert, err)
return false, err
}
return true, nil
}
+88
View File
@@ -0,0 +1,88 @@
package mwacc
type TagMwRole struct {
ApiMenus string
CreatedAt string
Desc string
Id string
IsEnb string
Name string
Router string
UpdatedAt string
}
type TagMwAcc struct {
Acc string
Base32 string
Code string
CreatedAt string
Email string
Feedback string
Id string
IsBase32 string
IsEnb string
LastTime string
LimitIP string
Pwd string
Qurl string
RoleId string
RoleName string
Token string
UpdatedAt string
UserName string
}
type TagMwAccToken struct {
AccId string
CreatedAt string
Id string
Token string
UpdatedAt string
}
var FN struct {
MwRole TagMwRole
MwAcc TagMwAcc
MwAccToken TagMwAccToken
}
var TN struct {
MwRole string
MwAcc string
MwAccToken string
}
func init() {
FN.MwRole.ApiMenus = "apiMenus"
FN.MwRole.CreatedAt = "createdAt"
FN.MwRole.Desc = "desc"
FN.MwRole.Id = "_id"
FN.MwRole.IsEnb = "isEnb"
FN.MwRole.Name = "name"
FN.MwRole.Router = "router"
FN.MwRole.UpdatedAt = "updatedAt"
FN.MwAcc.Acc = "acc"
FN.MwAcc.Base32 = "base32"
FN.MwAcc.Code = "code"
FN.MwAcc.CreatedAt = "createdAt"
FN.MwAcc.Email = "email"
FN.MwAcc.Feedback = "feedback"
FN.MwAcc.Id = "_id"
FN.MwAcc.IsBase32 = "isBase32"
FN.MwAcc.IsEnb = "isEnb"
FN.MwAcc.LastTime = "lastTime"
FN.MwAcc.LimitIP = "limitIP"
FN.MwAcc.Pwd = "pwd"
FN.MwAcc.Qurl = "qurl"
FN.MwAcc.RoleId = "roleId"
FN.MwAcc.RoleName = "roleName"
FN.MwAcc.Token = "token"
FN.MwAcc.UpdatedAt = "updatedAt"
FN.MwAcc.UserName = "userName"
FN.MwAccToken.AccId = "accId"
FN.MwAccToken.CreatedAt = "createdAt"
FN.MwAccToken.Id = "_id"
FN.MwAccToken.Token = "token"
FN.MwAccToken.UpdatedAt = "updatedAt"
TN.MwRole = "mw_role"
TN.MwAcc = "mw_acc"
TN.MwAccToken = "mw_acc_token"
}
+84
View File
@@ -0,0 +1,84 @@
package mwacc
import (
"context"
"time"
"videoweb/pub/common/errors"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// 过滤更新
func UpOneTokenByFilter(ctx context.Context, query primitive.M, update primitive.M) (err error) {
_, err = mwAccTokenColl.UpdateOne(ctx, query, primitive.M{"$set": update})
return
}
func SaveToken(ctx context.Context, accId int64, token string) (ok bool, err error) {
var booToken MwAccToken
// 查找
err = mwAccTokenColl.FindOne(ctx, &booToken, primitive.M{FN.MwAccToken.AccId: accId})
if booToken.AccId > 0 {
// 更新
err = UpOneTokenByFilter(ctx, primitive.M{
FN.MwAccToken.AccId: accId,
}, primitive.M{
FN.MwAccToken.Token: token,
FN.MwAccToken.UpdatedAt: time.Now(),
})
if err != nil {
return false, err
}
return true, nil
}
if err != nil || booToken.AccId == 0 {
if _, err := mwAccTokenColl.InsertOne(ctx,
primitive.M{
FN.MwAccToken.Id: mongos.Lid.MwAccToken.Get(),
FN.MwAccToken.AccId: accId,
FN.MwAccToken.Token: token,
FN.MwAccToken.CreatedAt: time.Now(),
}); err != nil {
return false, err
}
}
return true, nil
}
func CheckToken(ctx context.Context, token string) (ok bool, err error) {
var booToken MwAccToken
Terr := mwAccTokenColl.FindOne(ctx, &booToken, primitive.M{FN.MwAccToken.Token: token})
if Terr != nil || booToken.AccId == 0 {
err = errors.MakeWithMsg(errors.NoToken, "token 不存在或已过期")
return false, err
}
return true, nil
}
// // 检测Token
// func CheckToken(ctx context.Context, token string) (ok bool, err error) {
// var booToken WebToken
// Terr := tokenColl.FindOne(ctx, &booToken, primitive.M{"token": token})
// if Terr != nil || booToken.Id == 0 {
// err = errors.MakeWithMsg(errors.NoToken, "token 不存在或已过期")
// return
// }
// return true, nil
// }
// 删除token
func DeleteOneToken(ctx context.Context, filter bson.M) *srvdef.SrvErr {
if _, err := mwAccTokenColl.DeleteOne(ctx, filter); err != nil {
log.Warn("mwacc:DeleteOneToken db.DeleteOne failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return nil
}
+78
View File
@@ -0,0 +1,78 @@
package mwacc
import (
"time"
)
type Meta struct {
Title string `bson:"title"`
Icon string `bson:"icon"`
NoCache bool `bson:"noCache"`
}
type Apiurl struct {
Url []string `bson:"url"`
Desc string `bson:"desc"`
Status bool `bson:"status"`
Method []string `bson:"method"`
}
// 编辑返回去的数据
type Router struct {
Path string `bson:"path"`
Component string `bson:"component"`
Redirect string `bson:"redirect"`
Name string `bson:"name"`
IsShow bool `bson:"isShow"`
Hidden bool `bson:"hidden"`
Meta Meta `bson:"meta"`
Children []Router `bson:"children"`
ApiUrl []Apiurl `bson:"apiUrl"`
}
// 角色
// @table:mw_role
type MwRole struct {
Id int64 `bson:"_id"`
Name string `bson:"name"` // 角色名称
Desc string `bson:"desc"` // 描述
IsEnb bool `bson:"isEnb"` // 是否启用 false:禁用 true:启用
ApiMenus []string `bson:"apiMenus"` // 已有权限的api
Router []Router `bson:"router"`
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
}
// 账号
// @table:mw_acc
type MwAcc struct {
Id int64 `bson:"_id"` // id
UserName string `bson:"userName"` // 用户名
Acc string `bson:"acc"` // 账号
Pwd string `bson:"pwd"` // 密码
Email string `bson:"email"` // 邮箱
RoleId int64 `bson:"roleId"` // 角色Id
RoleName string `bson:"roleName"` // 角色名
Base32 string `bson:"base32"` // 二步签名
IsBase32 bool `bson:"isBase32"` // 是否已签名
Code string `bson:"code"` // 验证码
Qurl []byte `bson:"qurl"` // 二维码链接
Token string `bson:"token"` // token
LastTime time.Time `bson:"lastTime"` // 登录时间
IsEnb bool `bson:"isEnb"` // 使能
Feedback string `bson:"feedback"` // 禁用原因
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
LimitIP []string `bson:"limitIP"` // 限制IP
}
type MwAccList []*MwAcc
// 账号Token
// @table:mw_acc_token
type MwAccToken struct {
Id int64 `bson:"_id"` // id
AccId int64 `bson:"accId"` // 账号id
Token string `bson:"token"` // token
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
}
+52
View File
@@ -0,0 +1,52 @@
package mwacc
import (
"time"
)
type AccGetListRec struct {
Id int64 `bson:"_id"` // id
Username string `bson:"username"` // 用户名
Acc string `bson:"acc"` // 用户名
Email string `bson:"email"` // 邮箱
RoleId int64 `bson:"roleId"` // 角色Id
RoleName string `bson:"roleName"` // 角色名
// Base32 string `bson:"base32"` // 二步签名
IsBase32 bool `bson:"isBase32"` // 是否已签名
IsEnb bool `bson:"isEnb"` // 使能
Feedback string `bson:"feedback"` // 禁用原因
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
LimitIP []string `bson:"limitIP"` // 允许访问的IP
}
type RoleGetListRec struct {
Id int64 `bson:"_id"` // 角色Id
Name string `bson:"name"` // 角色名称
Desc string `bson:"desc"` // 描述
IsEnb bool `bson:"isEnb"` // 是否启用 false:禁用 true:启用
ApiMenus []string `bson:"apiMenus"` // 已有权限的api
CreatedAt time.Time `bson:"createdAt"` // 创建时间
UpdatedAt time.Time `bson:"updatedAt"` // 更新时间
AccCount int64 `bson:"accCount"` // 账户数量
}
type AccInsertDoc struct {
Id int64 `bson:"_id"` // id
UserName string `bson:"userName"` // 用户名
Pwd string `bson:"pwd"` // 密码
Acc string `bson:"acc"` // 用户名
Email string `bson:"email"` // 邮箱
RoleId int64 `bson:"roleId"` // 角色Id
Base32 string `bson:"base32"` // 二步签名
IsBase32 bool `bson:"isBase32"` // 是否已签名
IsEnb bool `bson:"isEnb"` // 使能
LastTime time.Time `bson:"lastTime"` // 登录时间
CreatedAt time.Time `bson:"createdAt"` // 创建时间
LimitIP []string `bson:"limitIP"` // 允许访问的IP
}
type RoleDropDoc struct {
Id int64 `bson:"_id"` // 角色Id
Name string `bson:"name"` // 角色名称
}
+9
View File
@@ -0,0 +1,9 @@
package oplog
import (
"videoweb/pub/mongos"
)
var (
opLogColl *mongos.Collection
)
+175
View File
@@ -0,0 +1,175 @@
package oplog
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/common/utils"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Init 初始化数据
func Init(ctx context.Context) {
opLogColl = mongos.ShopLog.Coll(TN.OpLog)
initIndex(ctx)
return
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{FN.OpLog.ActId, 1},
{FN.OpLog.Action, 1},
{FN.OpLog.Path, 1},
},
},
{
Keys: bson.D{
{FN.OpLog.CreatedAt, -1},
},
},
}
if _, err := opLogColl.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(oplog:initIndex) Create adLog Index failed! err:%+v:", err))
}
}
// 添加日志
func AddLog(ctx context.Context, path string, desc string, actId int64, rawData, ip string) (err error) {
_, err = opLogColl.InsertOne(ctx, primitive.M{
FN.OpLog.Id: mongos.Lid.MwOpLog.Get(),
FN.OpLog.Action: desc,
FN.OpLog.Path: path,
FN.OpLog.ActId: actId,
FN.OpLog.RawData: rawData,
FN.OpLog.CreatedAt: utils.Now(),
FN.OpLog.IP: ip,
})
return
}
type LogReq struct {
PageNum int64 `json:"pageNum"` // 页码
PageSize int64 `json:"pageSize"` //
Path *string `json:"path"` // 请求接口
Action *string `json:"action"` // 操作目的
ActId *int64 `json:"actId"` // 操作人Id
StartTime *time.Time `json:"startTime"` // 开始时间
EndTime *time.Time `json:"endTime"` // 开始时间
}
// 操作日志信息
type OpLogInfo struct {
Path string `json:"path" bson:"path"` // 请求接口
ActId int64 `json:"actId" bson:"actId"` // 操作人Id
Action string `json:"action" bson:"action"` // 操作目的
Param string `json:"param" bson:"rawData"` // 操作内容
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 操作时间
ActName string `json:"actName" bson:"actName"` // 操作人
}
type OpPageRes struct {
Total int64 `json:"total" bson:"total"`
List []*OpLogInfo `json:"list" bson:"list"`
}
// 获取日志列表
func PageLogList(ctx context.Context, req *LogReq) (res *OpPageRes, err error) {
filter := bson.M{}
if req.Path != nil && *req.Path != "" {
filter[FN.OpLog.Path] = bson.M{"$regex": req.Path}
}
if req.Action != nil && *req.Action != "" {
filter[FN.OpLog.Action] = req.Action
}
if req.ActId != nil && *req.ActId > 0 {
filter[FN.OpLog.ActId] = req.ActId
}
if req.StartTime != nil && req.EndTime != nil {
filter[FN.OpLog.CreatedAt] = bson.M{"$gte": req.StartTime, "$lt": req.EndTime}
}
res = new(OpPageRes)
res.Total, err = mongos.ShopLog.Coll(TN.OpLog).Count(ctx, filter)
if err != nil {
return
}
sort := bson.M{FN.OpLog.CreatedAt: -1}
opt := &options.FindOptions{}
opt.SetSort(sort)
skip := (req.PageNum - 1) * req.PageSize
opt.SetSkip(skip)
opt.SetLimit(req.PageSize)
list := make(OpLogList, 0)
err = mongos.ShopLog.Coll(TN.OpLog).Find(ctx, &list, filter, opt)
if err != nil {
return
}
actIds := make([]int64, 0)
for _, v := range list {
actIds = append(actIds, v.ActId)
}
// err = opLogColl.Aggregate(ctx, &res.List, []bson.M{
// {"$match": conf},
// {"$sort": bson.M{FN.OpLog.CreatedAt: -1}},
// {"$skip": (req.PageNum - 1) * req.PageSize},
// {"$limit": req.PageSize},
// {"$lookup": bson.M{
// "localField": FN.OpLog.ActId,
// "from": mwacc.TN.MwAcc,
// "foreignField": mwacc.FN.MwAcc.Id,
// "as": "admins",
// }},
// {"$unwind": "$admins"},
// {"$project": bson.M{
// FN.OpLog.Path: 1,
// FN.OpLog.Action: 1,
// FN.OpLog.ActId: 1,
// FN.OpLog.RawData: 1,
// FN.OpLog.CreatedAt: 1,
// "actName": "$admins.userName",
// }},
// })
return
}
// CountOpLogs 计算某个查询的数量
func CountOpLogs(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
total, err := mongos.ShopLog.Coll(TN.OpLog).Count(ctx, filter)
if err != nil {
log.Info("oplog:CountOpLogs db.Count failed",
log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return total, nil
}
// InsertOneUser 插入一个用户
func InsertOneUser(ctx context.Context, opLog *OpLog) *srvdef.SrvErr {
if _, err := mongos.ShopLog.Coll(TN.OpLog).InsertOne(ctx, opLog); err != nil {
log.Warn("oplog:InsertOneUser db.InsertOne failed", log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// FindManyOpLogs 查找一批数据
func FindManyOpLogs(ctx context.Context,
filter bson.M, opts ...*options.FindOptions) (
OpLogList, *srvdef.SrvErr) {
data := make(OpLogList, 0)
if err := mongos.ShopLog.Coll(TN.OpLog).Find(ctx, &data, filter, opts...); err != nil {
log.Warn("oplog:FindManyOpLogs db.Find failed",
log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
+34
View File
@@ -0,0 +1,34 @@
package oplog
type TagOpLog struct {
ActId string
Action string
CreatedAt string
IP string
Id string
IsWhite string
OpType string
Path string
RawData string
}
var FN struct {
OpLog TagOpLog
}
var TN struct {
OpLog string
}
func init() {
FN.OpLog.ActId = "actId"
FN.OpLog.Action = "action"
FN.OpLog.CreatedAt = "createdAt"
FN.OpLog.IP = "ip"
FN.OpLog.Id = "_id"
FN.OpLog.IsWhite = "isWhite"
FN.OpLog.OpType = "opType"
FN.OpLog.Path = "path"
FN.OpLog.RawData = "rawData"
TN.OpLog = "mw_op_log"
}
+22
View File
@@ -0,0 +1,22 @@
package oplog
import (
"time"
"videoweb/pub/common"
)
// 操作日志
// @table:mw_op_log
type OpLog struct {
Id int64 `bson:"_id"` // id
Path string `bson:"path"` // 请求接口
OpType common.ApiOpType `bson:"opType"` // 操作类型
IsWhite bool `bson:"isWhite"` // 是否白名单
ActId int64 `bson:"actId"` // 操作人Id
Action string `bson:"action"` // 操作目的
RawData string `bson:"rawData"` // 原始数据
CreatedAt time.Time `bson:"createdAt"` // 操作时间
IP string `bson:"ip"` // 操作人IP
}
type OpLogList []*OpLog
+172
View File
@@ -0,0 +1,172 @@
package playletbackflowstatmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化原创短剧 AI 内容回流日统计表和查询索引。
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletBackflowDailyStat)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletBackflowDailyStat.DataDate, Value: 1},
{Key: FN.PlayletBackflowDailyStat.ReportStatus, Value: 1},
{Key: FN.PlayletBackflowDailyStat.Id, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletBackflowDailyStat.DataDate, Value: 1},
{Key: FN.PlayletBackflowDailyStat.PlayletId, Value: 1},
},
Options: options.Index().SetUnique(true).SetName("uniq_dataDate_playletId"),
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletbackflowstatmod:initIndex) Create Index failed! err:%+v:", err))
}
}
// UpsertManyPlayletBackflowDailyStats 批量保存每天原创短剧回流数据快照。
func UpsertManyPlayletBackflowDailyStats(ctx context.Context, docs PlayletBackflowDailyStatList) *srvdef.SrvErr {
if len(docs) == 0 {
return nil
}
now := time.Now()
writes := make([]mongo.WriteModel, 0, len(docs))
for _, doc := range docs {
if doc == nil || doc.DataDate == "" || doc.PlayletId <= 0 {
continue
}
doc.UpdatedAt = now
doc.LastStatAt = now
update := bson.M{
"$set": bson.M{
FN.PlayletBackflowDailyStat.DataDate: doc.DataDate,
FN.PlayletBackflowDailyStat.PlayletId: doc.PlayletId,
FN.PlayletBackflowDailyStat.ChapterId: doc.ChapterId,
FN.PlayletBackflowDailyStat.CurrentEpisode: doc.CurrentEpisode,
FN.PlayletBackflowDailyStat.MediaCenterId: doc.MediaCenterId,
FN.PlayletBackflowDailyStat.MediaContentId: doc.MediaContentId,
FN.PlayletBackflowDailyStat.Title: doc.Title,
FN.PlayletBackflowDailyStat.PublishedData: doc.PublishedData,
FN.PlayletBackflowDailyStat.ScriptName: doc.ScriptName,
FN.PlayletBackflowDailyStat.DramaName: doc.DramaName,
FN.PlayletBackflowDailyStat.DramaNo: doc.DramaNo,
FN.PlayletBackflowDailyStat.VideoURL: doc.VideoURL,
FN.PlayletBackflowDailyStat.PlatformURL: doc.PlatformURL,
FN.PlayletBackflowDailyStat.Views: doc.Views,
FN.PlayletBackflowDailyStat.Clicks: doc.Clicks,
FN.PlayletBackflowDailyStat.Likes: doc.Likes,
FN.PlayletBackflowDailyStat.LikeRate: doc.LikeRate,
FN.PlayletBackflowDailyStat.CompletionRate: doc.CompletionRate,
FN.PlayletBackflowDailyStat.PaidRate: doc.PaidRate,
FN.PlayletBackflowDailyStat.Comments: doc.Comments,
FN.PlayletBackflowDailyStat.Shares: doc.Shares,
FN.PlayletBackflowDailyStat.CompletionRateScope: doc.CompletionRateScope,
FN.PlayletBackflowDailyStat.ReportStatus: doc.ReportStatus,
FN.PlayletBackflowDailyStat.ReportError: "",
FN.PlayletBackflowDailyStat.LastStatAt: doc.LastStatAt,
FN.PlayletBackflowDailyStat.UpdatedAt: doc.UpdatedAt,
},
"$setOnInsert": bson.M{
FN.PlayletBackflowDailyStat.Id: primitive.NewObjectID(),
FN.PlayletBackflowDailyStat.ReportRetryCount: int64(0),
FN.PlayletBackflowDailyStat.CreatedAt: now,
},
}
model := mongo.NewUpdateOneModel().
SetFilter(bson.M{
FN.PlayletBackflowDailyStat.DataDate: doc.DataDate,
FN.PlayletBackflowDailyStat.PlayletId: doc.PlayletId,
}).
SetUpdate(update).
SetUpsert(true)
writes = append(writes, model)
}
if len(writes) == 0 {
return nil
}
if _, err := coll.BulkWrite(ctx, writes, options.BulkWrite().SetOrdered(false)); err != nil {
log.Warn("playletbackflowstatmod:UpsertManyPlayletBackflowDailyStats failed", log.E(err), log.Any("count", len(writes)))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// FindManyPlayletBackflowDailyStats 查询原创短剧回流日统计。
func FindManyPlayletBackflowDailyStats(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletBackflowDailyStatList, *srvdef.SrvErr) {
data := make(PlayletBackflowDailyStatList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletbackflowstatmod:FindManyPlayletBackflowDailyStats failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletBackflowDailyStats 统计原创短剧回流日统计条数。
func CountPlayletBackflowDailyStats(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletbackflowstatmod:CountPlayletBackflowDailyStats failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// MarkPlayletBackflowDailyStatsReported 把一批统计记录标记为上报成功。
func MarkPlayletBackflowDailyStatsReported(ctx context.Context, ids []primitive.ObjectID, reportAt time.Time) *srvdef.SrvErr {
if len(ids) == 0 {
return nil
}
_, err := coll.UpdateMany(ctx, bson.M{FN.PlayletBackflowDailyStat.Id: bson.M{"$in": ids}}, bson.M{"$set": bson.M{
FN.PlayletBackflowDailyStat.ReportStatus: ReportStatusSuccess,
FN.PlayletBackflowDailyStat.ReportAt: reportAt,
FN.PlayletBackflowDailyStat.ReportError: "",
FN.PlayletBackflowDailyStat.UpdatedAt: time.Now(),
}})
if err != nil {
log.Warn("playletbackflowstatmod:MarkPlayletBackflowDailyStatsReported failed", log.E(err), log.Any("count", len(ids)))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
// MarkPlayletBackflowDailyStatsFailed 把一批统计记录标记为上报失败。
func MarkPlayletBackflowDailyStatsFailed(ctx context.Context, ids []primitive.ObjectID, reportErr string) *srvdef.SrvErr {
if len(ids) == 0 {
return nil
}
_, err := coll.UpdateMany(ctx, bson.M{FN.PlayletBackflowDailyStat.Id: bson.M{"$in": ids}}, bson.M{
"$set": bson.M{
FN.PlayletBackflowDailyStat.ReportStatus: ReportStatusFailed,
FN.PlayletBackflowDailyStat.ReportError: reportErr,
FN.PlayletBackflowDailyStat.UpdatedAt: time.Now(),
},
"$inc": bson.M{
FN.PlayletBackflowDailyStat.ReportRetryCount: int64(1),
},
})
if err != nil {
log.Warn("playletbackflowstatmod:MarkPlayletBackflowDailyStatsFailed failed", log.E(err), log.Any("count", len(ids)))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
return nil
}
+78
View File
@@ -0,0 +1,78 @@
package playletbackflowstatmod
// TagPlayletBackflowDailyStat 保存 playlet_backflow_daily_stat 集合字段名。
type TagPlayletBackflowDailyStat struct {
Id string
DataDate string
PlayletId string
ChapterId string
CurrentEpisode string
MediaCenterId string
MediaContentId string
Title string
PublishedData string
ScriptName string
DramaName string
DramaNo string
VideoURL string
PlatformURL string
Views string
Clicks string
Likes string
LikeRate string
CompletionRate string
PaidRate string
Comments string
Shares string
CompletionRateScope string
ReportStatus string
ReportRetryCount string
ReportAt string
ReportError string
LastStatAt string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletBackflowDailyStat TagPlayletBackflowDailyStat
}
var TN struct {
PlayletBackflowDailyStat string
}
func init() {
FN.PlayletBackflowDailyStat.Id = "_id"
FN.PlayletBackflowDailyStat.DataDate = "dataDate"
FN.PlayletBackflowDailyStat.PlayletId = "playletId"
FN.PlayletBackflowDailyStat.ChapterId = "chapterId"
FN.PlayletBackflowDailyStat.CurrentEpisode = "currentEpisode"
FN.PlayletBackflowDailyStat.MediaCenterId = "mediaCenterId"
FN.PlayletBackflowDailyStat.MediaContentId = "mediaContentId"
FN.PlayletBackflowDailyStat.Title = "title"
FN.PlayletBackflowDailyStat.PublishedData = "publishedData"
FN.PlayletBackflowDailyStat.ScriptName = "scriptName"
FN.PlayletBackflowDailyStat.DramaName = "dramaName"
FN.PlayletBackflowDailyStat.DramaNo = "dramaNo"
FN.PlayletBackflowDailyStat.VideoURL = "videoUrl"
FN.PlayletBackflowDailyStat.PlatformURL = "platformUrl"
FN.PlayletBackflowDailyStat.Views = "views"
FN.PlayletBackflowDailyStat.Clicks = "clicks"
FN.PlayletBackflowDailyStat.Likes = "likes"
FN.PlayletBackflowDailyStat.LikeRate = "likeRate"
FN.PlayletBackflowDailyStat.CompletionRate = "completionRate"
FN.PlayletBackflowDailyStat.PaidRate = "paidRate"
FN.PlayletBackflowDailyStat.Comments = "comments"
FN.PlayletBackflowDailyStat.Shares = "shares"
FN.PlayletBackflowDailyStat.CompletionRateScope = "completionRateScope"
FN.PlayletBackflowDailyStat.ReportStatus = "reportStatus"
FN.PlayletBackflowDailyStat.ReportRetryCount = "reportRetryCount"
FN.PlayletBackflowDailyStat.ReportAt = "reportAt"
FN.PlayletBackflowDailyStat.ReportError = "reportError"
FN.PlayletBackflowDailyStat.LastStatAt = "lastStatAt"
FN.PlayletBackflowDailyStat.CreatedAt = "createdAt"
FN.PlayletBackflowDailyStat.UpdatedAt = "updatedAt"
TN.PlayletBackflowDailyStat = "playlet_backflow_daily_stat"
}
+55
View File
@@ -0,0 +1,55 @@
package playletbackflowstatmod
import (
"time"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// ReportStatus 是 AI 内容中台数据回流上报状态。
type ReportStatus int64
const (
ReportStatusPending ReportStatus = 0 // 待上报
ReportStatusSuccess ReportStatus = 1 // 上报成功
ReportStatusFailed ReportStatus = 2 // 上报失败
)
// PlayletBackflowDailyStat @table: playlet_backflow_daily_stat
//
// PlayletBackflowDailyStat 保存原创短剧每天回流给 AI 内容中台的数据快照。
type PlayletBackflowDailyStat struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"` // MongoDB ObjectID
DataDate string `json:"dataDate" bson:"dataDate"` // 指标日期,格式 DD/MM/YYYY
PlayletId int64 `json:"playletId" bson:"playletId"` // 业务短剧 ID
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 上报使用的章节 ID
CurrentEpisode int64 `json:"currentEpisode" bson:"currentEpisode"` // 上报使用的章节序号
MediaCenterId int64 `json:"mediaCenterId" bson:"mediaCenterId"` // 媒资库资源 ID
MediaContentId int64 `json:"mediaContentId" bson:"mediaContentId"` // 上报剧集的媒资章节 ID
Title string `json:"title" bson:"title"` // 本地短剧标题
PublishedData string `json:"publishedData" bson:"publishedData"` // 中台字段:视频上线日期
ScriptName string `json:"scriptName" bson:"scriptName"` // 中台字段:剧本名称
DramaName string `json:"dramaName" bson:"dramaName"` // 中台字段:短剧名称
DramaNo string `json:"dramaNo" bson:"dramaNo"` // 中台字段:集数
VideoURL string `json:"videoUrl" bson:"videoUrl"` // 中台字段:成片下载/存储链接
PlatformURL string `json:"platformUrl" bson:"platformUrl"` // 中台字段:产品内播放页链接
Views int64 `json:"views" bson:"views"` // 浏览量
Clicks int64 `json:"clicks" bson:"clicks"` // 播放量
Likes int64 `json:"likes" bson:"likes"` // 点赞量
LikeRate string `json:"likeRate" bson:"likeRate"` // 点赞率
CompletionRate string `json:"completionRate" bson:"completionRate"` // 完播率
PaidRate string `json:"paidRate" bson:"paidRate"` // 付费率
Comments int64 `json:"comments" bson:"comments"` // 评论量
Shares int64 `json:"shares" bson:"shares"` // 分享量
CompletionRateScope string `json:"completionRateScope" bson:"completionRateScope"` // 完播率口径
ReportStatus ReportStatus `json:"reportStatus" bson:"reportStatus"` // 上报状态
ReportRetryCount int64 `json:"reportRetryCount" bson:"reportRetryCount"` // 上报失败次数
ReportAt time.Time `json:"reportAt" bson:"reportAt"` // 最近一次上报成功时间
ReportError string `json:"reportError" bson:"reportError"` // 最近一次上报失败原因
LastStatAt time.Time `json:"lastStatAt" bson:"lastStatAt"` // 最近一次计算时间
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 更新时间
}
// PlayletBackflowDailyStatList 是原创短剧日回流统计列表。
type PlayletBackflowDailyStatList []*PlayletBackflowDailyStat
@@ -0,0 +1,115 @@
package playletchaptercollectmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_chapter_collect 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletChapterCollect)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletChapterCollect.UserId, Value: 1},
{Key: FN.PlayletChapterCollect.ChapterId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.PlayletChapterCollect.ChapterId, Value: 1},
{Key: FN.PlayletChapterCollect.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapterCollect.PlayletId, Value: 1},
{Key: FN.PlayletChapterCollect.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapterCollect.UserId, Value: 1},
{Key: FN.PlayletChapterCollect.CreatedAt, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletchaptercollectmod:initIndex) 创建索引失败 err:%+v:", err))
}
}
// InsertOnePlayletChapterCollect 插入一条短剧剧集收藏关系
func InsertOnePlayletChapterCollect(ctx context.Context, doc *PlayletChapterCollect) (bool, *srvdef.SrvErr) {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapterCollect.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
log.Warn("插入短剧剧集收藏关系失败", log.Any("doc", doc), log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// DeleteOnePlayletChapterCollect 删除一条短剧剧集收藏关系
func DeleteOnePlayletChapterCollect(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("删除短剧剧集收藏关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DeleteManyPlayletChapterCollect 按条件批量删除短剧剧集收藏关系
func DeleteManyPlayletChapterCollect(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteMany(ctx, filter)
if err != nil {
log.Warn("批量删除短剧剧集收藏关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindManyPlayletChapterCollect 按条件查询短剧剧集收藏关系
func FindManyPlayletChapterCollect(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterCollectList, *srvdef.SrvErr) {
data := make(PlayletChapterCollectList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("查询短剧剧集收藏关系列表失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletChapterCollect 统计满足条件的短剧剧集收藏关系数量
func CountPlayletChapterCollect(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("统计短剧剧集收藏关系数量失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
@@ -0,0 +1,30 @@
package playletchaptercollectmod
// TagPlayletChapterCollect 保存 playlet_chapter_collect 集合字段名
type TagPlayletChapterCollect struct {
Id string
UserId string
PlayletId string
ChapterId string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletChapterCollect TagPlayletChapterCollect
}
var TN struct {
PlayletChapterCollect string
}
func init() {
FN.PlayletChapterCollect.Id = "_id"
FN.PlayletChapterCollect.UserId = "userId"
FN.PlayletChapterCollect.PlayletId = "playletId"
FN.PlayletChapterCollect.ChapterId = "chapterId"
FN.PlayletChapterCollect.CreatedAt = "createdAt"
FN.PlayletChapterCollect.UpdatedAt = "updatedAt"
TN.PlayletChapterCollect = "playlet_chapter_collect"
}
@@ -0,0 +1,18 @@
package playletchaptercollectmod
import "time"
// PlayletChapterCollect @table: playlet_chapter_collect
//
// PlayletChapterCollect 短剧剧集收藏关系模型
type PlayletChapterCollect struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 收藏记录ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 短剧剧集ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletChapterCollectList 短剧剧集收藏关系列表
type PlayletChapterCollectList []*PlayletChapterCollect
+105
View File
@@ -0,0 +1,105 @@
package playletchapterlikemod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_chapter_like 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletChapterLike)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletChapterLike.UserId, Value: 1},
{Key: FN.PlayletChapterLike.ChapterId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.PlayletChapterLike.ChapterId, Value: 1},
{Key: FN.PlayletChapterLike.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapterLike.PlayletId, Value: 1},
{Key: FN.PlayletChapterLike.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapterLike.UserId, Value: 1},
{Key: FN.PlayletChapterLike.CreatedAt, Value: -1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletchapterlikemod:initIndex) 创建索引失败 err:%+v:", err))
}
}
// InsertOnePlayletChapterLike 插入一条短剧剧集点赞关系
func InsertOnePlayletChapterLike(ctx context.Context, doc *PlayletChapterLike) (bool, *srvdef.SrvErr) {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapterLike.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
log.Warn("插入短剧剧集点赞关系失败", log.Any("doc", doc), log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// DeleteOnePlayletChapterLike 删除一条短剧剧集点赞关系
func DeleteOnePlayletChapterLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("删除短剧剧集点赞关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DeleteManyPlayletChapterLike 按条件批量删除短剧剧集点赞关系
func DeleteManyPlayletChapterLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteMany(ctx, filter)
if err != nil {
log.Warn("批量删除短剧剧集点赞关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindManyPlayletChapterLike 按条件查询短剧剧集点赞关系
func FindManyPlayletChapterLike(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterLikeList, *srvdef.SrvErr) {
data := make(PlayletChapterLikeList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("查询短剧剧集点赞关系列表失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
+30
View File
@@ -0,0 +1,30 @@
package playletchapterlikemod
// TagPlayletChapterLike 保存 playlet_chapter_like 集合字段名
type TagPlayletChapterLike struct {
Id string
UserId string
PlayletId string
ChapterId string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletChapterLike TagPlayletChapterLike
}
var TN struct {
PlayletChapterLike string
}
func init() {
FN.PlayletChapterLike.Id = "_id"
FN.PlayletChapterLike.UserId = "userId"
FN.PlayletChapterLike.PlayletId = "playletId"
FN.PlayletChapterLike.ChapterId = "chapterId"
FN.PlayletChapterLike.CreatedAt = "createdAt"
FN.PlayletChapterLike.UpdatedAt = "updatedAt"
TN.PlayletChapterLike = "playlet_chapter_like"
}
+18
View File
@@ -0,0 +1,18 @@
package playletchapterlikemod
import "time"
// PlayletChapterLike @table: playlet_chapter_like
//
// PlayletChapterLike 短剧剧集点赞关系模型
type PlayletChapterLike struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 点赞记录ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 短剧剧集ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletChapterLikeList 短剧剧集点赞关系列表
type PlayletChapterLikeList []*PlayletChapterLike
+335
View File
@@ -0,0 +1,335 @@
package playletchaptermod
import (
"context"
"fmt"
"strings"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
const duplicatePlayletChapterMsg = "短剧剧集已存在"
// Init 初始化 playlet_chapter 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletChapter)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
commonIndexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletChapter.PlayletId, Value: 1},
{Key: FN.PlayletChapter.CurrentEpisode, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.PlayletId, Value: 1},
{Key: FN.PlayletChapter.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.CreatedAt, Value: -1},
{Key: FN.PlayletChapter.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.WatermarkStatus, Value: 1},
{Key: FN.PlayletChapter.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.MediaSourceId, Value: 1},
},
Options: options.Index().
SetPartialFilterExpression(bson.M{
FN.PlayletChapter.MediaSourceId: bson.M{"$gt": ""},
}),
},
}
if _, err := coll.CreateIndex(ctx, commonIndexes); err != nil {
panic(fmt.Sprintf("(playletchaptermod:initIndex) Create Index failed! err:%+v:", err))
}
uniqueIndexes := []mongo.IndexModel{
{
// 反向键序避免和线上已有 playletId_1_currentEpisode_1 普通索引冲突,同时兜住同一短剧同一集数的并发重复写入。
Keys: bson.D{
{Key: FN.PlayletChapter.CurrentEpisode, Value: 1},
{Key: FN.PlayletChapter.PlayletId, Value: 1},
},
Options: options.Index().
SetName("uniq_playlet_chapter_episode").
SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.PlayletChapter.PlayletId, Value: 1},
{Key: FN.PlayletChapter.MediaContentId, Value: 1},
},
Options: options.Index().
SetUnique(true).
SetPartialFilterExpression(bson.M{
FN.PlayletChapter.MediaContentId: bson.M{"$gt": 0},
}),
},
}
for _, index := range uniqueIndexes {
if _, err := coll.CreateIndex(ctx, []mongo.IndexModel{index}); err != nil {
if isPlayletChapterDuplicateIndexErr(err) {
log.Warn("短剧章节唯一索引创建失败,请先清理历史重复章节数据", log.E(err), log.Any("index", index.Keys))
continue
}
panic(fmt.Sprintf("(playletchaptermod:initIndex) Create Unique Index failed! err:%+v:", err))
}
}
}
// isPlayletChapterDuplicateIndexErr 判断唯一索引创建时是否命中历史重复数据。
func isPlayletChapterDuplicateIndexErr(err error) bool {
if err == nil {
return false
}
return mongo.IsDuplicateKeyError(err) || strings.Contains(err.Error(), "E11000 duplicate key error")
}
// InsertOnePlayletChapter 插入一条章节数据
func InsertOnePlayletChapter(ctx context.Context, doc *PlayletChapter) *srvdef.SrvErr {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapter.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return duplicatePlayletChapterErr()
}
log.Warn("playletchaptermod:InsertOnePlayletChapter failed", log.Any("doc", doc), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// InsertManyPlayletChapter 批量插入章节数据
func InsertManyPlayletChapter(ctx context.Context, docs PlayletChapterList) *srvdef.SrvErr {
data := make(PlayletChapterList, 0, len(docs))
now := time.Now()
for _, doc := range docs {
if doc == nil {
continue
}
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapter.Get()
}
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
data = append(data, doc)
}
if len(data) == 0 {
return nil
}
if _, err := coll.InsertMany(ctx, &data); err != nil {
if mongo.IsDuplicateKeyError(err) {
return duplicatePlayletChapterErr()
}
log.Warn("playletchaptermod:InsertManyPlayletChapter failed", log.Any("count", len(data)), log.E(err))
return srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return nil
}
// duplicatePlayletChapterErr 返回章节唯一约束冲突的统一业务错误。
func duplicatePlayletChapterErr() *srvdef.SrvErr {
return srvdef.New(srvdef.ErrDbInputExist, duplicatePlayletChapterMsg, duplicatePlayletChapterMsg)
}
// DelOnePlayletChapter 删除一条章节数据
func DelOnePlayletChapter(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("playletchaptermod:DelOnePlayletChapter failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// DelManyPlayletChapter 按条件批量删除章节数据
func DelManyPlayletChapter(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteMany(ctx, filter)
if err != nil {
log.Warn("playletchaptermod:DelManyPlayletChapter failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindOnePlayletChapter 查询一条章节数据
func FindOnePlayletChapter(ctx context.Context, filter bson.M, opts ...*options.FindOneOptions) (*PlayletChapter, *srvdef.SrvErr) {
var doc PlayletChapter
if err := coll.FindOneEx(ctx, &doc, filter, opts...); err != nil {
if err != mongo.ErrNoDocuments {
log.Warn("playletchaptermod:FindOnePlayletChapter failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &doc, nil
}
type firstChapterRow struct {
PlayletId int64 `bson:"_id"`
ChapterId int64 `bson:"chapterId"`
}
// FirstChapterIDs 按集数取每部短剧第一集的章节 ID,排序与详情页选集列表一致。
func FirstChapterIDs(ctx context.Context, playletIDs []int64) (map[int64]int64, *srvdef.SrvErr) {
out := make(map[int64]int64, len(playletIDs))
if len(playletIDs) == 0 {
return out, nil
}
const batchSize = 500
for start := 0; start < len(playletIDs); start += batchSize {
end := start + batchSize
if end > len(playletIDs) {
end = len(playletIDs)
}
pipeline := []bson.M{
{"$match": bson.M{
FN.PlayletChapter.PlayletId: bson.M{"$in": playletIDs[start:end]},
FN.PlayletChapter.Status: StatusUp,
}},
{"$sort": bson.D{
{Key: FN.PlayletChapter.CurrentEpisode, Value: 1},
{Key: FN.PlayletChapter.Id, Value: 1},
}},
{"$group": bson.M{
"_id": "$" + FN.PlayletChapter.PlayletId,
"chapterId": bson.M{"$first": "$_id"},
}},
}
rows := make([]firstChapterRow, 0)
if err := coll.Aggregate(ctx, &rows, pipeline); err != nil {
log.Warn("playletchaptermod:FirstChapterIDs failed", log.E(err), log.Any("count", end-start))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
for _, row := range rows {
if row.PlayletId > 0 && row.ChapterId > 0 {
out[row.PlayletId] = row.ChapterId
}
}
}
return out, nil
}
// FindManyPlayletChapter 按条件查询多条章节数据
func FindManyPlayletChapter(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterList, *srvdef.SrvErr) {
data := make(PlayletChapterList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("playletchaptermod:FindManyPlayletChapter failed", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletChapter 统计满足条件的章节数量
func CountPlayletChapter(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("playletchaptermod:CountPlayletChapter failed", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// UpdateOnePlayletChapter 更新一条章节数据
func UpdateOnePlayletChapter(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateOne(ctx, filter, update)
if err != nil {
if mongo.IsDuplicateKeyError(err) {
return duplicatePlayletChapterErr()
}
log.Warn("playletchaptermod:UpdateOnePlayletChapter failed", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount != 1 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
// IsLinkedMedia 是否短剧媒资:显式标记或已挂到剧集
func IsLinkedMedia(ctx context.Context, isPlaylet bool, ids ...string) bool {
if isPlaylet {
return true
}
return ExistsByMediaIDs(ctx, ids...)
}
// ExistsByMediaIDs 判断媒资 ID 是否属于短剧剧集(mediaSourceId / mediaTaskId)
func ExistsByMediaIDs(ctx context.Context, ids ...string) bool {
clean := uniqueNonEmptyStrings(ids)
if len(clean) == 0 {
return false
}
item, _ := FindOnePlayletChapter(ctx, bson.M{
"$or": []bson.M{
{FN.PlayletChapter.MediaSourceId: bson.M{"$in": clean}},
{FN.PlayletChapter.MediaTaskId: bson.M{"$in": clean}},
},
}, options.FindOne().SetProjection(bson.M{FN.PlayletChapter.Id: 1}))
return item != nil
}
func uniqueNonEmptyStrings(ids []string) []string {
if len(ids) == 0 {
return nil
}
seen := make(map[string]struct{}, len(ids))
out := make([]string, 0, len(ids))
for _, id := range ids {
id = strings.TrimSpace(id)
if id == "" {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
out = append(out, id)
}
return out
}
// UpdateManyPlayletChapter 批量更新章节数据
func UpdateManyPlayletChapter(ctx context.Context, filter bson.M, update bson.M) *srvdef.SrvErr {
result, err := coll.UpdateMany(ctx, filter, update)
if err != nil {
if mongo.IsDuplicateKeyError(err) {
return duplicatePlayletChapterErr()
}
log.Warn("批量更新短剧章节数据失败", log.E(err), log.Any("filter", filter))
return srvdef.New(srvdef.ErrDbUpdateError, "", "")
}
if result.MatchedCount == 0 {
return srvdef.New(srvdef.ErrNoData, "", "")
}
return nil
}
+76
View File
@@ -0,0 +1,76 @@
package playletchaptermod
// TagPlayletChapter 保存 playlet_chapter 集合字段名
type TagPlayletChapter struct {
Id string
PlayletId string
MediaContentId string
CurrentEpisode string
Title string
Md5 string
Hash string
Height string
Width string
Ratio string
VideoUrl string
WatermarkVideoUrl string
MediaSize string
MediaTime string
CountComment string
CountBuy string
CountBrowse string
CountCollect string
CountLike string
CountDisLike string
Status string
PayType string
SingleCoins string
WatermarkStatus string
WatermarkRetryAt string
MediaSourceId string
MediaTaskId string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletChapter TagPlayletChapter
}
var TN struct {
PlayletChapter string
}
func init() {
FN.PlayletChapter.Id = "_id"
FN.PlayletChapter.PlayletId = "playletId"
FN.PlayletChapter.MediaContentId = "mediaContentId"
FN.PlayletChapter.CurrentEpisode = "currentEpisode"
FN.PlayletChapter.Title = "title"
FN.PlayletChapter.Md5 = "md5"
FN.PlayletChapter.Hash = "hash"
FN.PlayletChapter.Height = "height"
FN.PlayletChapter.Width = "width"
FN.PlayletChapter.Ratio = "ratio"
FN.PlayletChapter.VideoUrl = "videoUrl"
FN.PlayletChapter.WatermarkVideoUrl = "watermarkVideoUrl"
FN.PlayletChapter.MediaSize = "mediaSize"
FN.PlayletChapter.MediaTime = "mediaTime"
FN.PlayletChapter.CountComment = "countComment"
FN.PlayletChapter.CountBuy = "countBuy"
FN.PlayletChapter.CountBrowse = "countBrowse"
FN.PlayletChapter.CountCollect = "countCollect"
FN.PlayletChapter.CountLike = "countLike"
FN.PlayletChapter.CountDisLike = "countDisLike"
FN.PlayletChapter.Status = "status"
FN.PlayletChapter.PayType = "payType"
FN.PlayletChapter.SingleCoins = "singleCoins"
FN.PlayletChapter.WatermarkStatus = "watermarkStatus"
FN.PlayletChapter.WatermarkRetryAt = "watermarkRetryAt"
FN.PlayletChapter.MediaSourceId = "mediaSourceId"
FN.PlayletChapter.MediaTaskId = "mediaTaskId"
FN.PlayletChapter.CreatedAt = "createdAt"
FN.PlayletChapter.UpdatedAt = "updatedAt"
TN.PlayletChapter = "playlet_chapter"
}
+87
View File
@@ -0,0 +1,87 @@
package playletchaptermod
import (
"time"
"videoweb/pub/models/playletmod"
"go.mongodb.org/mongo-driver/bson"
)
// Status 剧集上架状态
type Status int32
const (
StatusDown Status = 0 // 下架
StatusUp Status = 1 // 上架
)
// DefaultStatusByMediaSource 根据媒资来源生成默认上架状态
func DefaultStatusByMediaSource(mediaSource string) Status {
if mediaSource == playletmod.MediaSourceHG {
return StatusDown
}
return StatusUp
}
// VisibleStatusFilter 前台可见剧集过滤条件
func VisibleStatusFilter() bson.M {
return bson.M{FN.PlayletChapter.Status: StatusUp}
}
// PayType 支付方式
type PayType int32
const (
PayTypeFree PayType = 0 // 免费
PayTypeCoin PayType = 1 // 金币
PayTypeVip PayType = 2 // VIP
)
// WatermarkStatus 水印状态
type WatermarkStatus int32
const (
WatermarkStatusPending WatermarkStatus = 0 // 未处理(待 mediafile/sync)
WatermarkStatusRegistered WatermarkStatus = 1 // 已登记(原片已登记,待 task/add)
WatermarkStatusProcessing WatermarkStatus = 2 // 处理中(已提交加水印任务,待回写)
WatermarkStatusDone WatermarkStatus = 3 // 已完成
WatermarkStatusFailed WatermarkStatus = 4 // 处理失败
)
// PlayletChapter @table: playlet_chapter
//
// PlayletChapter 连载短剧章节集合模型
type PlayletChapter struct {
Id int64 `json:"id" bson:"_id,omitempty"`
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
MediaContentId uint `json:"mediaContentId" bson:"mediaContentId"` // 媒资中心章节ID
CurrentEpisode int64 `json:"currentEpisode" bson:"currentEpisode"` // 第几集
Title string `json:"title" bson:"title"` // 章节名
Md5 string `json:"md5" bson:"md5"` // 媒体md5
Hash string `json:"hash" bson:"hash"` // 媒体hash
Height int64 `json:"height" bson:"height"` // 高
Width int64 `json:"width" bson:"width"` // 宽
Ratio float64 `json:"ratio" bson:"ratio"` // 宽高比
VideoUrl string `json:"videoUrl" bson:"videoUrl"` // 原片视频地址(加水印后保持不变,方便换水印)
WatermarkVideoUrl string `json:"watermarkVideoUrl" bson:"watermarkVideoUrl"` // 加水印后的视频地址
MediaSize int64 `json:"mediaSize" bson:"mediaSize"` // 资源大小
MediaTime int64 `json:"mediaTime" bson:"mediaTime"` // 影片长度(秒)
CountComment int64 `json:"countComment" bson:"countComment"` // 评论数
CountBuy int64 `json:"countBuy" bson:"countBuy"` // 购买数
CountBrowse int64 `json:"countBrowse" bson:"countBrowse"` // 浏览数
CountCollect int64 `json:"countCollect" bson:"countCollect"` // 收藏数
CountLike int64 `json:"countLike" bson:"countLike"` // 喜欢数
CountDisLike int64 `json:"countDisLike" bson:"countDisLike"` // 不喜欢数
Status Status `json:"status" bson:"status"` // 上架状态 0-下架 1-上架
PayType PayType `json:"payType" bson:"payType"` // 支付方式 0-免费 1-金币 2-VIP
SingleCoins int64 `json:"singleCoins" bson:"singleCoins"` // 单集金币(支付方式为1-金币时候生效)
WatermarkStatus WatermarkStatus `json:"watermarkStatus" bson:"watermarkStatus"` // 水印状态 0-未处理 1-已登记 2-处理中 3-已完成 4-处理失败
WatermarkRetryAt time.Time `json:"watermarkRetryAt,omitempty" bson:"watermarkRetryAt,omitempty"` // 原片未处理完时的下次提交时间,到点前不参与 task/add
MediaSourceId string `json:"mediaSourceId" bson:"mediaSourceId"` // media切片服原片ID
MediaTaskId string `json:"mediaTaskId" bson:"mediaTaskId"` // media切片服水印任务ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletChapterList 章节列表
type PlayletChapterList []*PlayletChapter
+34
View File
@@ -0,0 +1,34 @@
package playletchapterunlockmod
// TagPlayletChapterUnlock 保存 playlet_chapter_unlock 集合字段名。
type TagPlayletChapterUnlock struct {
Id string
UserId string
PlayletId string
ChapterId string
Coins string
OrderNo string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletChapterUnlock TagPlayletChapterUnlock
}
var TN struct {
PlayletChapterUnlock string
}
func init() {
FN.PlayletChapterUnlock.Id = "_id"
FN.PlayletChapterUnlock.UserId = "userId"
FN.PlayletChapterUnlock.PlayletId = "playletId"
FN.PlayletChapterUnlock.ChapterId = "chapterId"
FN.PlayletChapterUnlock.Coins = "coins"
FN.PlayletChapterUnlock.OrderNo = "orderNo"
FN.PlayletChapterUnlock.CreatedAt = "createdAt"
FN.PlayletChapterUnlock.UpdatedAt = "updatedAt"
TN.PlayletChapterUnlock = "playlet_chapter_unlock"
}
@@ -0,0 +1,19 @@
package playletchapterunlockmod
import "time"
// PlayletChapterUnlock @table: playlet_chapter_unlock
//
// PlayletChapterUnlock 记录用户已用金币解锁的短剧剧集;一条记录代表该用户永久可观看该剧集。
type PlayletChapterUnlock struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 解锁记录ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
ChapterId int64 `json:"chapterId" bson:"chapterId"` // 短剧剧集ID
Coins int64 `json:"coins" bson:"coins"` // 解锁消耗金币
OrderNo string `json:"orderNo" bson:"orderNo"` // 解锁流水号
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
type PlayletChapterUnlockList []*PlayletChapterUnlock
@@ -0,0 +1,132 @@
package playletchapterunlockmod
import (
"context"
"fmt"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/common/utils"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_chapter_unlock 集合和索引。
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletChapterUnlock)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletChapterUnlock.UserId, Value: 1},
{Key: FN.PlayletChapterUnlock.ChapterId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.PlayletChapterUnlock.UserId, Value: 1},
{Key: FN.PlayletChapterUnlock.PlayletId, Value: 1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletChapterUnlock.CreatedAt, Value: 1},
{Key: FN.PlayletChapterUnlock.PlayletId, Value: 1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletchapterunlockmod:initIndex) 创建索引失败 err:%+v:", err))
}
}
// InsertOnePlayletChapterUnlock 插入解锁记录。
//
// 返回 inserted=false 表示该用户已经解锁过该剧集;调用方应将其视为幂等成功,不可继续扣费。
func InsertOnePlayletChapterUnlock(ctx context.Context, doc *PlayletChapterUnlock) (bool, *srvdef.SrvErr) {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletChapterUnlock.Get()
}
now := utils.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
log.Warn("插入短剧剧集解锁记录失败", log.Any("doc", doc), log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// ExistsPlayletChapterUnlock 判断用户是否已解锁指定剧集。
func ExistsPlayletChapterUnlock(ctx context.Context, userId int64, chapterId int64) (bool, *srvdef.SrvErr) {
if userId <= 0 || chapterId <= 0 {
return false, nil
}
var doc PlayletChapterUnlock
err := coll.FindOneEx(ctx, &doc, bson.M{
FN.PlayletChapterUnlock.UserId: userId,
FN.PlayletChapterUnlock.ChapterId: chapterId,
}, options.FindOne().SetProjection(bson.D{
{Key: FN.PlayletChapterUnlock.Id, Value: 1},
}))
if err != nil {
if err == mongo.ErrNoDocuments {
return false, nil
}
log.Warn("查询短剧剧集解锁记录失败", log.E(err), log.Any("userId", userId), log.Any("chapterId", chapterId))
return false, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return doc.Id > 0, nil
}
// DeleteManyPlayletChapterUnlock 按条件批量删除剧集解锁记录。
func DeleteManyPlayletChapterUnlock(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteMany(ctx, filter)
if err != nil {
log.Warn("批量删除短剧剧集解锁记录失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindManyPlayletChapterUnlock 按条件查询多条剧集解锁记录。
func FindManyPlayletChapterUnlock(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletChapterUnlockList, *srvdef.SrvErr) {
data := make(PlayletChapterUnlockList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("查询短剧剧集解锁记录列表失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletChapterUnlock 统计满足条件的剧集解锁记录数量
func CountPlayletChapterUnlock(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("统计短剧剧集解锁记录数量失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// AggregatePlayletChapterUnlock 聚合查询剧集解锁记录
func AggregatePlayletChapterUnlock(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("聚合短剧剧集解锁记录失败", log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+130
View File
@@ -0,0 +1,130 @@
package playletcollectmod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_collect 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletCollect)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletCollect.UserId, Value: 1},
{Key: FN.PlayletCollect.PlayletId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.PlayletCollect.PlayletId, Value: 1},
{Key: FN.PlayletCollect.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletCollect.UserId, Value: 1},
{Key: FN.PlayletCollect.CreatedAt, Value: -1},
{Key: FN.PlayletCollect.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletCollect.CreatedAt, Value: 1},
{Key: FN.PlayletCollect.PlayletId, Value: 1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletcollectmod:initIndex) 创建索引失败 err:%+v:", err))
}
}
// InsertOnePlayletCollect 插入一条短剧收藏关系
func InsertOnePlayletCollect(ctx context.Context, doc *PlayletCollect) (bool, *srvdef.SrvErr) {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletCollect.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
log.Warn("插入短剧收藏关系失败", log.Any("doc", doc), log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// ExistsPlayletCollect 查询短剧收藏关系是否存在
func ExistsPlayletCollect(ctx context.Context, filter bson.M) (bool, *srvdef.SrvErr) {
var doc PlayletCollect
if err := coll.FindOneEx(ctx, &doc, filter, options.FindOne().SetProjection(bson.D{
{Key: FN.PlayletCollect.Id, Value: 1},
})); err != nil {
if err == mongo.ErrNoDocuments {
return false, nil
}
log.Warn("查询短剧收藏关系失败", log.E(err), log.Any("filter", filter))
return false, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return true, nil
}
// DeleteOnePlayletCollect 删除一条短剧收藏关系
func DeleteOnePlayletCollect(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("删除短剧收藏关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// FindManyPlayletCollect 按条件查询短剧收藏关系列表
func FindManyPlayletCollect(ctx context.Context, filter bson.M, opts ...*options.FindOptions) (PlayletCollectList, *srvdef.SrvErr) {
data := make(PlayletCollectList, 0)
if err := coll.Find(ctx, &data, filter, opts...); err != nil {
log.Warn("查询短剧收藏关系列表失败", log.E(err), log.Any("filter", filter))
return nil, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return data, nil
}
// CountPlayletCollect 统计满足条件的短剧收藏关系数量
func CountPlayletCollect(ctx context.Context, filter bson.M, opts ...*options.CountOptions) (int64, *srvdef.SrvErr) {
count, err := coll.Count(ctx, filter, opts...)
if err != nil {
log.Warn("统计短剧收藏关系数量失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return count, nil
}
// AggregatePlayletCollect 聚合查询短剧收藏关系
func AggregatePlayletCollect(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("聚合短剧收藏关系失败", log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+28
View File
@@ -0,0 +1,28 @@
package playletcollectmod
// TagPlayletCollect 保存 playlet_collect 集合字段名
type TagPlayletCollect struct {
Id string
UserId string
PlayletId string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletCollect TagPlayletCollect
}
var TN struct {
PlayletCollect string
}
func init() {
FN.PlayletCollect.Id = "_id"
FN.PlayletCollect.UserId = "userId"
FN.PlayletCollect.PlayletId = "playletId"
FN.PlayletCollect.CreatedAt = "createdAt"
FN.PlayletCollect.UpdatedAt = "updatedAt"
TN.PlayletCollect = "playlet_collect"
}
+17
View File
@@ -0,0 +1,17 @@
package playletcollectmod
import "time"
// PlayletCollect @table: playlet_collect
//
// PlayletCollect 短剧收藏关系模型
type PlayletCollect struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 收藏记录ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletCollectList 短剧收藏关系列表
type PlayletCollectList []*PlayletCollect
+110
View File
@@ -0,0 +1,110 @@
package playletlikemod
import (
"context"
"fmt"
"time"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/mongos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var coll *mongos.Collection
// Init 初始化 playlet_like 集合和常用查询索引
func Init(ctx context.Context) {
coll = mongos.Shop.Coll(TN.PlayletLike)
initIndex(ctx)
}
func initIndex(ctx context.Context) {
indexes := []mongo.IndexModel{
{
Keys: bson.D{
{Key: FN.PlayletLike.UserId, Value: 1},
{Key: FN.PlayletLike.PlayletId, Value: 1},
},
Options: options.Index().SetUnique(true),
},
{
Keys: bson.D{
{Key: FN.PlayletLike.PlayletId, Value: 1},
{Key: FN.PlayletLike.CreatedAt, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletLike.UserId, Value: 1},
{Key: FN.PlayletLike.CreatedAt, Value: -1},
{Key: FN.PlayletLike.Id, Value: -1},
},
},
{
Keys: bson.D{
{Key: FN.PlayletLike.CreatedAt, Value: 1},
{Key: FN.PlayletLike.PlayletId, Value: 1},
},
},
}
if _, err := coll.CreateIndex(ctx, indexes); err != nil {
panic(fmt.Sprintf("(playletlikemod:initIndex) 创建索引失败 err:%+v:", err))
}
}
// InsertOnePlayletLike 插入一条短剧点赞关系
func InsertOnePlayletLike(ctx context.Context, doc *PlayletLike) (bool, *srvdef.SrvErr) {
if doc.Id == 0 {
doc.Id = mongos.Lid.PlayletLike.Get()
}
now := time.Now()
if doc.CreatedAt.IsZero() {
doc.CreatedAt = now
}
doc.UpdatedAt = now
if _, err := coll.InsertOne(ctx, doc); err != nil {
if mongo.IsDuplicateKeyError(err) {
return false, nil
}
log.Warn("插入短剧点赞关系失败", log.Any("doc", doc), log.E(err))
return false, srvdef.New(srvdef.ErrDbInsertError, "", "")
}
return true, nil
}
// ExistsPlayletLike 查询短剧点赞关系是否存在
func ExistsPlayletLike(ctx context.Context, filter bson.M) (bool, *srvdef.SrvErr) {
var doc PlayletLike
if err := coll.FindOneEx(ctx, &doc, filter, options.FindOne().SetProjection(bson.D{
{Key: FN.PlayletLike.Id, Value: 1},
})); err != nil {
if err == mongo.ErrNoDocuments {
return false, nil
}
log.Warn("查询短剧点赞关系失败", log.E(err), log.Any("filter", filter))
return false, srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return true, nil
}
// DeleteOnePlayletLike 删除一条短剧点赞关系
func DeleteOnePlayletLike(ctx context.Context, filter bson.M) (int64, *srvdef.SrvErr) {
count, err := coll.DeleteOne(ctx, filter)
if err != nil {
log.Warn("删除短剧点赞关系失败", log.E(err), log.Any("filter", filter))
return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "")
}
return count, nil
}
// AggregatePlayletLike 聚合查询短剧点赞关系
func AggregatePlayletLike(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr {
if err := coll.Aggregate(ctx, bind, pipeline); err != nil {
log.Warn("聚合短剧点赞关系失败", log.E(err), log.Any("pipeline", pipeline))
return srvdef.New(srvdef.ErrDbQueryError, "", "")
}
return nil
}
+28
View File
@@ -0,0 +1,28 @@
package playletlikemod
// TagPlayletLike 保存 playlet_like 集合字段名
type TagPlayletLike struct {
Id string
UserId string
PlayletId string
CreatedAt string
UpdatedAt string
}
var FN struct {
PlayletLike TagPlayletLike
}
var TN struct {
PlayletLike string
}
func init() {
FN.PlayletLike.Id = "_id"
FN.PlayletLike.UserId = "userId"
FN.PlayletLike.PlayletId = "playletId"
FN.PlayletLike.CreatedAt = "createdAt"
FN.PlayletLike.UpdatedAt = "updatedAt"
TN.PlayletLike = "playlet_like"
}
+17
View File
@@ -0,0 +1,17 @@
package playletlikemod
import "time"
// PlayletLike @table: playlet_like
//
// PlayletLike 短剧点赞关系模型
type PlayletLike struct {
Id int64 `json:"id" bson:"_id,omitempty"` // 点赞记录ID
UserId int64 `json:"userId" bson:"userId"` // 用户ID
PlayletId int64 `json:"playletId" bson:"playletId"` // 短剧ID
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 创建时间
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` // 修改时间
}
// PlayletLikeList 短剧点赞关系列表
type PlayletLikeList []*PlayletLike

Some files were not shown because too many files have changed in this diff Show More