Initial commit: web_hghl_server

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 16:28:14 +08:00
co-authored by Claude Opus 4.7
commit 65fca60622
653 changed files with 135901 additions and 0 deletions
@@ -0,0 +1,79 @@
package questionnaireser
import (
"context"
"fmt"
"time"
"videoweb/app/api/proto"
"videoweb/pub/common/enum/redisconst"
"videoweb/pub/common/log"
"videoweb/pub/common/srvdef"
"videoweb/pub/models/questionnairemod"
"videoweb/pub/redis"
"go.mongodb.org/mongo-driver/bson/primitive"
)
const (
maxFiles = 3
)
// Submit 提交问卷(App端)
// ip:客户端真实 IP;req.UserId 为 0 表示匿名用户,仅按 IP 限流
func Submit(ctx context.Context, ip string, req *proto.QuestionnaireSubmitReq) *srvdef.SrvErr {
// IP 维度:同一 IP 每分钟只能提交一次
ipCount, err := redis.Incr(redisconst.QuestionnaireLimitIpKey(ip), redisconst.QuestionnaireLimitExpire)
if err != nil {
log.Error("问卷提交IP限频Redis异常", log.E(err))
}
if ipCount > 1 {
return srvdef.New(srvdef.ErrOperationTooFrequently, "user operation is too frequent", "提交太频繁,请稍后再试")
}
// 用户维度:登录用户(userId > 0)每分钟只能提交一次
if req.UserId > 0 {
userCount, err := redis.Incr(redisconst.QuestionnaireLimitUserKey(req.UserId), redisconst.QuestionnaireLimitExpire)
if err != nil {
log.Error("问卷提交用户限频Redis异常", log.E(err))
}
if userCount > 1 {
return srvdef.New(srvdef.ErrOperationTooFrequently, "user operation is too frequent", "提交太频繁,请稍后再试")
}
}
// 校验附件数量限制
fileCount := 0
if req.Attachments != nil && len(req.Attachments) > 0 {
fileCount = len(req.Attachments)
}
if fileCount > maxFiles {
return srvdef.New(srvdef.ErrParamError, fmt.Sprintf("文件不超过%d个", fileCount), "")
}
attachments := req.Attachments
if attachments == nil {
attachments = []questionnairemod.Attachment{}
}
now := time.Now()
doc := &questionnairemod.QuestionnaireModel{
Id: primitive.NewObjectID(),
UserId: req.UserId,
QuestionType: req.QuestionType,
Frequency: req.Frequency,
Province: req.Province,
City: req.City,
Operator: req.Operator,
NetworkType: req.NetworkType,
DeviceType: req.DeviceType,
DeviceModel: req.DeviceModel,
Description: req.Description,
Contact: req.Contact,
Status: questionnairemod.StatusPending,
Attachments: attachments,
CreatedAt: now,
UpdatedAt: now,
}
return questionnairemod.InsertOne(ctx, doc)
}