272 lines
7.8 KiB
Go
272 lines
7.8 KiB
Go
package srv_feedback
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
"videoweb/pub/common/response"
|
|
"videoweb/pub/common/srvdef"
|
|
"videoweb/pub/models/feedbackmod"
|
|
"videoweb/pub/models/usermod"
|
|
"videoweb/web/api/proto"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
)
|
|
|
|
const (
|
|
// feedbackDefaultPageSize web端意见反馈列表默认每页数量
|
|
feedbackDefaultPageSize int64 = 10
|
|
// feedbackMaxPageSize web端意见反馈列表最大每页数量,避免单次请求拉取过多数据
|
|
feedbackMaxPageSize int64 = 100
|
|
)
|
|
|
|
var (
|
|
// feedbackWebProjection 只读取web意见反馈列表需要展示的字段,减少MongoDB传输开销。
|
|
feedbackWebProjection = bson.D{
|
|
{Key: feedbackmod.FN.Feedback.Id, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.UserId, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.FeedbackType, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.Content, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.Screenshots, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.Contact, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.Status, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.Remark, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.CreatedAt, Value: 1},
|
|
{Key: feedbackmod.FN.Feedback.UpdatedAt, Value: 1},
|
|
}
|
|
|
|
// feedbackWebSort web端意见反馈列表按创建时间倒序返回。
|
|
feedbackWebSort = bson.D{
|
|
{Key: feedbackmod.FN.Feedback.CreatedAt, Value: -1},
|
|
{Key: feedbackmod.FN.Feedback.Id, Value: -1},
|
|
}
|
|
)
|
|
|
|
// ListFeedback 分页查询意见反馈列表
|
|
func ListFeedback(ctx context.Context, req *proto.FeedbackListReq) (*proto.FeedbackListPageResp, *srvdef.SrvErr) {
|
|
if req == nil {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "", "")
|
|
}
|
|
filter, filterErr := buildFeedbackListFilter(req)
|
|
if filterErr != nil {
|
|
return nil, filterErr
|
|
}
|
|
pageNum, pageSize := normalizeFeedbackPage(req.PageNum, req.PageSize)
|
|
totalCount, err := feedbackmod.CountFeedback(ctx, filter)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp := &proto.FeedbackListPageResp{
|
|
BasePageResp: response.BasePageResp{
|
|
TotalCount: totalCount,
|
|
PageSize: int(pageSize),
|
|
PageNum: int(pageNum),
|
|
List: make([]*proto.FeedbackListResp, 0),
|
|
},
|
|
}
|
|
if totalCount == 0 {
|
|
return resp, nil
|
|
}
|
|
list, err := feedbackmod.FindManyFeedback(ctx, filter, options.Find().
|
|
SetProjection(feedbackWebProjection).
|
|
SetSort(feedbackWebSort).
|
|
SetSkip((pageNum-1)*pageSize).
|
|
SetLimit(pageSize))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userNameMap, err := buildFeedbackUserNameMap(ctx, list)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp.List = feedbackListToWebResp(list, userNameMap)
|
|
return resp, nil
|
|
}
|
|
|
|
// HandleFeedback 批量更新意见反馈处理状态
|
|
func HandleFeedback(ctx context.Context, req *proto.FeedbackHandleReq) (*proto.FeedbackHandleResp, *srvdef.SrvErr) {
|
|
if req == nil || len(req.Ids) == 0 {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "ids不能为空")
|
|
}
|
|
if req.Status != 0 && req.Status != 1 {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "status无效")
|
|
}
|
|
ids, err := normalizeFeedbackIds(req.Ids)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
matchedCount, modifiedCount, err := feedbackmod.UpdateManyFeedbackWithResult(ctx, bson.M{
|
|
feedbackmod.FN.Feedback.Id: bson.M{"$in": ids},
|
|
}, bson.M{
|
|
"$set": bson.M{
|
|
feedbackmod.FN.Feedback.Status: req.Status,
|
|
feedbackmod.FN.Feedback.Remark: strings.TrimSpace(req.Remark),
|
|
feedbackmod.FN.Feedback.UpdatedAt: time.Now(),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if matchedCount == 0 {
|
|
return nil, srvdef.New(srvdef.ErrNoData, "", "")
|
|
}
|
|
return &proto.FeedbackHandleResp{
|
|
MatchedCount: matchedCount,
|
|
ModifiedCount: modifiedCount,
|
|
}, nil
|
|
}
|
|
|
|
// buildFeedbackListFilter 构造web端意见反馈列表查询条件
|
|
func buildFeedbackListFilter(req *proto.FeedbackListReq) (bson.M, *srvdef.SrvErr) {
|
|
filter := bson.M{}
|
|
if req.UserId != nil && *req.UserId > 0 {
|
|
filter[feedbackmod.FN.Feedback.UserId] = *req.UserId
|
|
}
|
|
if req.Type != nil {
|
|
if !isValidFeedbackType(*req.Type) {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "type无效")
|
|
}
|
|
filter[feedbackmod.FN.Feedback.FeedbackType] = *req.Type
|
|
}
|
|
if req.Status != nil {
|
|
if *req.Status != 0 && *req.Status != 1 {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "status无效")
|
|
}
|
|
filter[feedbackmod.FN.Feedback.Status] = *req.Status
|
|
}
|
|
createdAt, err := buildFeedbackTimeFilter(req.CreateStartTime, req.CreateEndTime)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(createdAt) > 0 {
|
|
filter[feedbackmod.FN.Feedback.CreatedAt] = createdAt
|
|
}
|
|
return filter, nil
|
|
}
|
|
|
|
// buildFeedbackTimeFilter 按开始时间和结束时间构造createdAt范围查询
|
|
func buildFeedbackTimeFilter(startTime, endTime string) (bson.M, *srvdef.SrvErr) {
|
|
filter := bson.M{}
|
|
startTime = strings.TrimSpace(startTime)
|
|
endTime = strings.TrimSpace(endTime)
|
|
if startTime != "" {
|
|
startAt, err := parseFeedbackWebTime(startTime)
|
|
if err != nil {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "createStartTime格式错误")
|
|
}
|
|
filter["$gte"] = startAt
|
|
}
|
|
if endTime != "" {
|
|
endAt, err := parseFeedbackWebTime(endTime)
|
|
if err != nil {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "createEndTime格式错误")
|
|
}
|
|
filter["$lte"] = endAt
|
|
}
|
|
return filter, nil
|
|
}
|
|
|
|
func parseFeedbackWebTime(value string) (time.Time, error) {
|
|
return time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
|
|
}
|
|
|
|
func normalizeFeedbackPage(pageNum, pageSize int64) (int64, int64) {
|
|
if pageNum <= 0 {
|
|
pageNum = 1
|
|
}
|
|
if pageSize <= 0 {
|
|
pageSize = feedbackDefaultPageSize
|
|
}
|
|
if pageSize > feedbackMaxPageSize {
|
|
pageSize = feedbackMaxPageSize
|
|
}
|
|
return pageNum, pageSize
|
|
}
|
|
|
|
func normalizeFeedbackIds(rawIds []int64) ([]int64, *srvdef.SrvErr) {
|
|
ids := make([]int64, 0, len(rawIds))
|
|
seen := make(map[int64]struct{}, len(rawIds))
|
|
for _, id := range rawIds {
|
|
if id <= 0 {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "ids包含无效id")
|
|
}
|
|
if _, ok := seen[id]; ok {
|
|
continue
|
|
}
|
|
seen[id] = struct{}{}
|
|
ids = append(ids, id)
|
|
}
|
|
if len(ids) == 0 {
|
|
return nil, srvdef.New(srvdef.ErrParamError, "ids不能为空")
|
|
}
|
|
return ids, nil
|
|
}
|
|
|
|
func isValidFeedbackType(feedbackType int32) bool {
|
|
return feedbackType >= 1 && feedbackType <= 5
|
|
}
|
|
|
|
// buildFeedbackUserNameMap 批量查询反馈用户名称,避免列表转换时逐条查询用户。
|
|
func buildFeedbackUserNameMap(ctx context.Context, list feedbackmod.FeedbackList) (map[int64]string, *srvdef.SrvErr) {
|
|
userIds := make([]int64, 0, len(list))
|
|
seen := make(map[int64]struct{}, len(list))
|
|
for _, item := range list {
|
|
if item == nil || item.UserId <= 0 {
|
|
continue
|
|
}
|
|
if _, ok := seen[item.UserId]; ok {
|
|
continue
|
|
}
|
|
seen[item.UserId] = struct{}{}
|
|
userIds = append(userIds, item.UserId)
|
|
}
|
|
userNameMap := make(map[int64]string, len(userIds))
|
|
if len(userIds) == 0 {
|
|
return userNameMap, nil
|
|
}
|
|
users, err := usermod.FindManyUser(ctx, bson.M{
|
|
usermod.FN.User.Id: bson.M{"$in": userIds},
|
|
}, options.Find().SetProjection(bson.M{
|
|
usermod.FN.User.Id: 1,
|
|
usermod.FN.User.NickName: 1,
|
|
}))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, user := range users {
|
|
if user != nil {
|
|
userNameMap[user.Id] = user.NickName
|
|
}
|
|
}
|
|
return userNameMap, nil
|
|
}
|
|
|
|
// feedbackListToWebResp 转换意见反馈列表响应
|
|
func feedbackListToWebResp(list feedbackmod.FeedbackList, userNameMap map[int64]string) []*proto.FeedbackListResp {
|
|
resp := make([]*proto.FeedbackListResp, 0, len(list))
|
|
for _, item := range list {
|
|
if item == nil {
|
|
continue
|
|
}
|
|
screenshots := item.Screenshots
|
|
if screenshots == nil {
|
|
screenshots = make([]string, 0)
|
|
}
|
|
resp = append(resp, &proto.FeedbackListResp{
|
|
Id: item.Id,
|
|
UserId: item.UserId,
|
|
UserName: userNameMap[item.UserId],
|
|
Type: item.FeedbackType,
|
|
Content: item.Content,
|
|
Screenshots: screenshots,
|
|
Contact: item.Contact,
|
|
Status: item.Status,
|
|
Remark: item.Remark,
|
|
CreatedAt: item.CreatedAt,
|
|
UpdatedAt: item.UpdatedAt,
|
|
})
|
|
}
|
|
return resp
|
|
}
|