Files
web_hgdjc_server/web/service/srv_contactus/contactus.go
T
2026-11-07 10:44:09 +08:00

274 lines
8.1 KiB
Go

package srv_contactus
import (
"context"
"regexp"
"strings"
"time"
"videoweb/pub/common/response"
"videoweb/pub/common/srvdef"
"videoweb/pub/models/contactusmod"
"videoweb/pub/models/usermod"
"videoweb/web/api/proto"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
// contactUsDefaultPageSize web端联系我们列表默认每页数量
contactUsDefaultPageSize int64 = 10
// contactUsMaxPageSize web端联系我们列表最大每页数量,避免单次请求拉取过多数据
contactUsMaxPageSize int64 = 100
)
var (
// contactUsWebProjection 只读取web联系我们列表需要展示的字段,减少MongoDB传输开销。
contactUsWebProjection = bson.D{
{Key: contactusmod.FN.ContactUs.Id, Value: 1},
{Key: contactusmod.FN.ContactUs.UserId, Value: 1},
{Key: contactusmod.FN.ContactUs.Email, Value: 1},
{Key: contactusmod.FN.ContactUs.QuestionType, Value: 1},
{Key: contactusmod.FN.ContactUs.Title, Value: 1},
{Key: contactusmod.FN.ContactUs.Content, Value: 1},
{Key: contactusmod.FN.ContactUs.Attachments, Value: 1},
{Key: contactusmod.FN.ContactUs.Status, Value: 1},
{Key: contactusmod.FN.ContactUs.Remark, Value: 1},
{Key: contactusmod.FN.ContactUs.CreatedAt, Value: 1},
{Key: contactusmod.FN.ContactUs.UpdatedAt, Value: 1},
}
// contactUsWebSort web端联系我们列表按创建时间倒序返回。
contactUsWebSort = bson.D{
{Key: contactusmod.FN.ContactUs.CreatedAt, Value: -1},
{Key: contactusmod.FN.ContactUs.Id, Value: -1},
}
)
// ListContactUs 分页查询联系我们列表
func ListContactUs(ctx context.Context, req *proto.ContactUsListReq) (*proto.ContactUsListPageResp, *srvdef.SrvErr) {
if req == nil {
return nil, srvdef.New(srvdef.ErrParamError, "", "")
}
filter, filterErr := buildContactUsListFilter(req)
if filterErr != nil {
return nil, filterErr
}
pageNum, pageSize := normalizeContactUsPage(req.PageNum, req.PageSize)
totalCount, err := contactusmod.CountContactUs(ctx, filter)
if err != nil {
return nil, err
}
resp := &proto.ContactUsListPageResp{
BasePageResp: response.BasePageResp{
TotalCount: totalCount,
PageSize: int(pageSize),
PageNum: int(pageNum),
List: make([]*proto.ContactUsListResp, 0),
},
}
if totalCount == 0 {
return resp, nil
}
list, err := contactusmod.FindManyContactUs(ctx, filter, options.Find().
SetProjection(contactUsWebProjection).
SetSort(contactUsWebSort).
SetSkip((pageNum-1)*pageSize).
SetLimit(pageSize))
if err != nil {
return nil, err
}
userNameMap, err := buildContactUsUserNameMap(ctx, list)
if err != nil {
return nil, err
}
resp.List = contactUsListToWebResp(list, userNameMap)
return resp, nil
}
// HandleContactUs 批量更新联系我们处理状态
func HandleContactUs(ctx context.Context, req *proto.ContactUsHandleReq) (*proto.ContactUsHandleResp, *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 := normalizeContactUsIds(req.Ids)
if err != nil {
return nil, err
}
matchedCount, modifiedCount, err := contactusmod.UpdateManyContactUsWithResult(ctx, bson.M{
contactusmod.FN.ContactUs.Id: bson.M{"$in": ids},
}, bson.M{
"$set": bson.M{
contactusmod.FN.ContactUs.Status: req.Status,
contactusmod.FN.ContactUs.Remark: strings.TrimSpace(req.Remark),
contactusmod.FN.ContactUs.UpdatedAt: time.Now(),
},
})
if err != nil {
return nil, err
}
if matchedCount == 0 {
return nil, srvdef.New(srvdef.ErrNoData, "", "")
}
return &proto.ContactUsHandleResp{
MatchedCount: matchedCount,
ModifiedCount: modifiedCount,
}, nil
}
// buildContactUsListFilter 构造web端联系我们列表查询条件
func buildContactUsListFilter(req *proto.ContactUsListReq) (bson.M, *srvdef.SrvErr) {
filter := bson.M{}
if req.UserId != nil && *req.UserId > 0 {
filter[contactusmod.FN.ContactUs.UserId] = *req.UserId
}
if email := strings.TrimSpace(req.Email); email != "" {
filter[contactusmod.FN.ContactUs.Email] = bson.M{"$regex": regexp.QuoteMeta(email)}
}
if req.Type != nil {
if !isValidContactUsType(*req.Type) {
return nil, srvdef.New(srvdef.ErrParamError, "type无效")
}
filter[contactusmod.FN.ContactUs.QuestionType] = *req.Type
}
if req.Status != nil {
if *req.Status != 0 && *req.Status != 1 {
return nil, srvdef.New(srvdef.ErrParamError, "status无效")
}
filter[contactusmod.FN.ContactUs.Status] = *req.Status
}
createdAt, err := buildContactUsTimeFilter(req.CreateStartTime, req.CreateEndTime)
if err != nil {
return nil, err
}
if len(createdAt) > 0 {
filter[contactusmod.FN.ContactUs.CreatedAt] = createdAt
}
return filter, nil
}
// buildContactUsTimeFilter 按开始时间和结束时间构造createdAt范围查询
func buildContactUsTimeFilter(startTime, endTime string) (bson.M, *srvdef.SrvErr) {
filter := bson.M{}
startTime = strings.TrimSpace(startTime)
endTime = strings.TrimSpace(endTime)
if startTime != "" {
startAt, err := parseContactUsWebTime(startTime)
if err != nil {
return nil, srvdef.New(srvdef.ErrParamError, "createStartTime格式错误")
}
filter["$gte"] = startAt
}
if endTime != "" {
endAt, err := parseContactUsWebTime(endTime)
if err != nil {
return nil, srvdef.New(srvdef.ErrParamError, "createEndTime格式错误")
}
filter["$lte"] = endAt
}
return filter, nil
}
func parseContactUsWebTime(value string) (time.Time, error) {
return time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
}
func normalizeContactUsPage(pageNum, pageSize int64) (int64, int64) {
if pageNum <= 0 {
pageNum = 1
}
if pageSize <= 0 {
pageSize = contactUsDefaultPageSize
}
if pageSize > contactUsMaxPageSize {
pageSize = contactUsMaxPageSize
}
return pageNum, pageSize
}
func normalizeContactUsIds(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 isValidContactUsType(questionType int32) bool {
return questionType >= 1 && questionType <= 5
}
// buildContactUsUserNameMap 批量查询用户名称,避免列表转换时逐条查询用户。
func buildContactUsUserNameMap(ctx context.Context, list contactusmod.ContactUsList) (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
}
// contactUsListToWebResp 转换联系我们列表响应
func contactUsListToWebResp(list contactusmod.ContactUsList, userNameMap map[int64]string) []*proto.ContactUsListResp {
resp := make([]*proto.ContactUsListResp, 0, len(list))
for _, item := range list {
if item == nil {
continue
}
resp = append(resp, &proto.ContactUsListResp{
Id: item.Id,
UserId: item.UserId,
UserName: userNameMap[item.UserId],
Email: item.Email,
Type: item.QuestionType,
Title: item.Title,
Content: item.Content,
Attachments: item.Attachments,
Status: item.Status,
Remark: item.Remark,
CreatedAt: item.CreatedAt,
UpdatedAt: item.UpdatedAt,
})
}
return resp
}