package channelSer import ( "context" "errors" "fmt" "os" "path" "stat/api/proto" "stat/common/log" "stat/models/adminMod" "stat/models/appInfoMod" "stat/models/channelmod" "stat/models/registermod" "time" "github.com/360EntSecGroup-Skylar/excelize" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo/options" ) // SearchChannelInfo 查询渠道信息 func SearchChannelInfo(ctx context.Context, req *proto.ChannelInfoSearch) ( *proto.ChannelInfoSearchResp, error) { filter := bson.M{} opt := &options.FindOptions{} opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1}) opt.SetSkip((req.PageNum - 1) * req.PageSize) opt.SetLimit(req.PageSize) resp := &proto.ChannelInfoSearchResp{} if req.ID != nil && *req.ID != "" { id, err := primitive.ObjectIDFromHex(*req.ID) if err != nil { return nil, errors.New("ID 格式错误") } filter[channelmod.FN.ChannelInfo.ID] = id } if req.Channel != nil && *req.Channel != "" { filter[channelmod.FN.ChannelInfo.Channel] = bson.M{"$regex": *req.Channel} } if req.AppId != nil { filter[channelmod.FN.ChannelInfo.AppIds] = bson.M{"$in": []int32{*req.AppId}} } if req.Type != nil { filter[channelmod.FN.ChannelInfo.Type] = *req.Type } if req.ParentChannel != nil && *req.ParentChannel != "" { filter[channelmod.FN.ChannelInfo.ParentChannel] = bson.M{"$regex": *req.ParentChannel} } if req.UserName != nil && *req.UserName != "" { filter[channelmod.FN.ChannelInfo.UserName] = *req.UserName } if req.Status != nil { filter[channelmod.FN.ChannelInfo.Status] = *req.Status } if req.Remark != nil && *req.Remark != "" { filter[channelmod.FN.ChannelInfo.Remark] = bson.M{"$regex": *req.Remark} } if req.Mobile != nil && *req.Mobile != "" { filter[channelmod.FN.ChannelInfo.Mobile] = bson.M{"$regex": *req.Mobile} } total, serr := channelmod.CountChannelInfos(ctx, filter) if serr != nil { return nil, serr } if total == 0 { return resp, nil } channelInfoList, err := channelmod.FindManyChannelInfo(ctx, filter, opt) if serr != nil { return nil, err } for i := range channelInfoList { channelInfoList[i].Token = "" } resp.List = channelInfoList resp.Total = total return resp, nil } // SearchChannelInfoExport 导出渠道信息 func SearchChannelInfoExport(ctx context.Context, req *proto.ChannelInfoSearch) (string, error) { filter := bson.M{} opt := &options.FindOptions{} opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1}) opt.SetSkip((req.PageNum - 1) * req.PageSize) opt.SetLimit(req.PageSize) if req.ID != nil && *req.ID != "" { id, err := primitive.ObjectIDFromHex(*req.ID) if err != nil { return "", errors.New("ID 格式错误") } filter[channelmod.FN.ChannelInfo.ID] = id } if req.Channel != nil && *req.Channel != "" { filter[channelmod.FN.ChannelInfo.Channel] = bson.M{"$regex": *req.Channel} } if req.AppId != nil { filter[channelmod.FN.ChannelInfo.AppIds] = bson.M{"$in": []int32{*req.AppId}} } if req.Type != nil { filter[channelmod.FN.ChannelInfo.Type] = *req.Type } if req.ParentChannel != nil && *req.ParentChannel != "" { filter[channelmod.FN.ChannelInfo.ParentChannel] = bson.M{"$regex": *req.ParentChannel} } if req.UserName != nil && *req.UserName != "" { filter[channelmod.FN.ChannelInfo.UserName] = bson.M{"$regex": *req.UserName} } if req.Status != nil { filter[channelmod.FN.ChannelInfo.Status] = *req.Status } if req.Remark != nil && *req.Remark != "" { filter[channelmod.FN.ChannelInfo.Remark] = bson.M{"$regex": *req.Remark} } if req.Remark != nil && *req.Remark != "" { filter[channelmod.FN.ChannelInfo.Remark] = bson.M{"$regex": *req.Remark} } total, serr := channelmod.CountChannelInfos(ctx, filter) if serr != nil { return "", serr } if total == 0 { return "", nil } appList, err := appInfoMod.GetAllAppInfo(ctx) if err != nil { return "", err } channelInfoList, err := channelmod.FindManyChannelInfo(ctx, filter, opt) if serr != nil { return "", err } filePath := fmt.Sprintf("./tmp/兑换记录-%s.xlsx", time.Now().Format("2006-01-02 15:04:05")) if sErr := channelInfoExport(filePath, channelInfoList, appList); sErr != nil { return "", sErr } return filePath, nil } // channelInfoExport 导出 func channelInfoExport(filePath string, list channelmod.ChannelInfoList, appList []appInfoMod.AppInfo) error { f := excelize.NewFile() sheetName := "Sheet1" // 设置列宽 f.SetColWidth("Sheet1", "A", "L", 23) // 设置表头行高 f.SetRowHeight("Sheet1", 1, 25) // 设置表头样式 headStyleID, _ := f.NewStyle(`{ "font":{ "color":"#333333", "bold":true, "size":16, "family":"arial" }, "alignment":{ "vertical":"center", "horizontal":"center", "wrap_text":true } }`) f.SetCellStyle("Sheet1", "A1", "L1", headStyleID) idx := f.NewSheet(sheetName) var exportTransWaterTitle = map[string]string{ "A1": "名称", "B1": "应用列表", "C1": "渠道类型", "D1": "IP", "E1": "下级代理数", "F1": "父渠道", "G1": "禁止登陆", "H1": "渠道状态", "I1": "登陆错误次数", "J1": "创建者", "K1": "创建时间", "L1": "更新时间", } for k, v := range exportTransWaterTitle { f.SetCellValue(sheetName, k, v) } var cLock string var cStatus string for k, v := range list { apps := string2app(appList, v.AppIds) i := 'A' // i 不能超过Z,即列输不能超过26列,超出将出现bug f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.Channel) //名称 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), apps) //应用列表 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.Type.String()) //渠道类型 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.IP) //IP i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ChildCount) //下级代理数 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ParentChannel) //父渠道 i++ if v.Lock { cLock = "封禁" } else if !v.Lock { cLock = "未封禁" } f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), cLock) //禁止登陆 i++ if v.Status { cStatus = "开启" } else if !v.Status { cStatus = "关闭" } f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), cStatus) //渠道状态 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.ShowMagic) //登陆错误次数 i++ f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), v.UserName) //创建者 i++ created := v.CreatedAt.Local().Format("2006-01-02 15:04:05") f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), created) //创建时间 i++ updated := v.UpdatedAt.Local().Format("2006-01-02 15:04:05") f.SetCellValue(sheetName, fmt.Sprintf("%s%d", string(i), k+2), updated) //更新时间 } f.SetActiveSheet(idx) p, _ := os.Getwd() fileName := path.Join(p, filePath) if err := f.SaveAs(fileName); err != nil { log.Error("redeemCodeExport:export save file to disk failed", log.Any("fileName", fileName), log.E(err)) return err } return nil } func string2app(appList []appInfoMod.AppInfo, appIds []int32) string { var result string for count, id := range appIds { if count == len(appIds)-1 { result += GetAppName(appList, id) } else { result += (GetAppName(appList, id) + "、") } } return result } // AddChannelInfo 添加一个媒体视频 func AddChannelInfo(ctx context.Context, username string, req *proto.ChannelInfoAdd) (*channelmod.ChannelInfo, error) { if channelmod.IsOfficialChannelName(req.Channel) { return nil, fmt.Errorf("渠道名字为系统保留字,请换一个渠道名字") } checkFilter := bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel} channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter) if err != nil { return nil, err } if channelInfo.Channel == req.Channel { return channelInfo, errors.New("渠道已经存在") } now := time.Now() newChannelInfo := channelmod.ChannelInfo{ Channel: req.Channel, UserName: username, ParentChannel: req.ParentChannel, Password: req.Password, Status: req.Status, Mobile: req.Mobile, Type: req.Type, Remark: req.Remark, Lock: req.Lock, ChildShowDivideRate: req.ChildShowDivideRate, ShowMagic: 0, CreatedAt: now, UpdatedAt: now, } if req.Type == channelmod.ChannelTypeParent { newChannelInfo.ParentChannel = "" newChannelInfo.ParentAgent = "" } else if req.Type == channelmod.ChannelTypeSecond { parentInfo, err := channelmod.FindOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: req.ParentChannel}) if err != nil { return nil, err } if parentInfo.Channel != req.ParentChannel { return nil, fmt.Errorf("指定的父渠道[%s]不存在", req.ParentChannel) } newChannelInfo.ParentChannel = req.ParentChannel newChannelInfo.ParentAgent = req.ParentChannel } else { return nil, errors.New("后台只支持添加一级和二级渠道,其他级别的渠道请登陆渠道后台添加") } err = channelmod.InsertOneChannelInfo(ctx, &newChannelInfo) if err != nil { log.Error("AddChannelInfo InsertOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err)) return nil, err } if req.Type.IsChild() { setdoc := bson.M{"$inc": bson.M{channelmod.FN.ChannelInfo.ChildCount: 1}} err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: newChannelInfo.ParentChannel}, setdoc) if err != nil { log.Error("AddChannelInfo UpdateOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err)) return nil, err } } return channelmod.FindOneChannelInfo(ctx, checkFilter) } // DelChannelInfo 删除指定渠道信息 func DelChannelInfo(ctx context.Context, channelId string) error { id, err := primitive.ObjectIDFromHex(channelId) if err != nil { return errors.New("ID 格式错误") } // 1. 查询渠道信息 channelFilter := bson.M{channelmod.FN.ChannelInfo.ID: id} channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter) if err != nil { log.Error("DelChannelInfo FindOneChannelInfo", log.Any("channelId", channelId), log.E(err)) return err } // 3. 查询子代理数 childFilter := bson.M{channelmod.FN.ChannelInfo.ParentAgent: channelInfo.Channel} childCount, err := channelmod.CountChannelInfos(ctx, childFilter) if err != nil { log.Error("DelChannelInfo CountChannelDeductionRules", log.Any("channelId", channelId), log.E(err)) return err } if childCount > 0 { return errors.New("代理下级代理不为空,请先删除下级代理") } // 2. 查询渠道绑定应用 ruleFilter := bson.M{channelmod.FN.ChannelDeductionRule.Channel: channelInfo.Channel} ruleCount, err := channelmod.CountChannelDeductionRules(ctx, ruleFilter) if err != nil { log.Error("DelChannelInfo CountChannelDeductionRules", log.Any("channelId", channelId), log.E(err)) return err } if ruleCount > 0 { return errors.New("绑定应用不为空,请先删除绑定应用") } // 4. 删除渠道 _, err = channelmod.DelOneChannelInfo(ctx, channelFilter) if err != nil { return err } // 5 更新父渠道子渠道数量 if channelInfo.Type.IsChild() { setdoc := bson.M{"$inc": bson.M{channelmod.FN.ChannelInfo.ChildCount: -1}} err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.ParentAgent}, setdoc) if err != nil { log.Error("DelChannelInfo UpdateOneChannelInfo", log.Any("channel", channelInfo.ParentAgent), log.E(err)) return err } } return nil } // UpdateChannelInfo 更新指定渠道 func UpdateChannelInfo(ctx context.Context, channelId string, req proto.ChannelInfoUpdate) error { id, err := primitive.ObjectIDFromHex(channelId) if err != nil { return errors.New("ID 格式错误") } filter := bson.M{channelmod.FN.ChannelInfo.ID: id} //更新数据库 setDoc := bson.M{"$set": req} serr := channelmod.UpdateOneChannelInfo(ctx, filter, setDoc) if serr != nil { return serr } return nil } // UpdateOneChannelOwner 更新指定渠道的所有者 func UpdateOneChannelOwner(ctx context.Context, operator, account string, req proto.ChannelOwnerUpdate) error { filter := bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel} cInfo, serr := channelmod.FindOneChannelInfo(ctx, filter) if serr != nil { log.Error("UpdateOneChannelOwner:FindOneChannelInfo err", log.Any("serr", serr), log.Any("req", req)) return serr } else if cInfo != nil && cInfo.Channel == "" { log.Error("UpdateOneChannelOwner:FindOneChannelInfo err", log.Any("serr", serr), log.Any("req", req)) return errors.New("渠道不存在") } if req.UserName == "" { return errors.New("变更的所有者不能为空") } else if req.UserName == cInfo.UserName { return errors.New("变更的所有者不能与之前的相同") // } else if cInfo.Type != 1 { // 只能操作1级渠道 // return errors.New("变更所有者,只能操作1级渠道") } admin, serr := adminMod.FindOnedmin(ctx, bson.M{"name": req.UserName}) if serr != nil { log.Error("UpdateOneChannelOwner:FindOnedmin err", log.Any("serr", serr), log.Any("req", req)) return serr } else if admin != nil && admin.Name == "" { log.Error("UpdateOneChannelOwner:FindOnedmin err", log.Any("serr", serr), log.Any("req", req)) return errors.New("账号不存在") } now := time.Now() // 更新渠道信息 setDoc := bson.M{"$set": bson.M{ channelmod.FN.ChannelInfo.UserName: req.UserName, channelmod.FN.ChannelInfo.UpdatedAt: now, }} serr = channelmod.UpdateOneChannelInfo(ctx, filter, setDoc) if serr != nil { log.Error("UpdateOneChannelOwner:UpdateOneChannelInfo err", log.Any("serr", serr), log.Any("req", req)) return serr } // 更新渠道统计信息 csFilter := bson.M{channelmod.FN.ChannelStat.Channel: cInfo.Channel} csSetDoc := bson.M{"$set": bson.M{channelmod.FN.ChannelStat.UserName: req.UserName}} serr = channelmod.UpdateManyChannelStat(ctx, csFilter, csSetDoc) if serr != nil { log.Error("UpdateOneChannelOwner:UpdateManyChannelStat err", log.Any("serr", serr), log.Any("req", req)) return serr } // 找到一级渠道的所有子渠道 allFlter := bson.M{channelmod.FN.ChannelInfo.ParentChannel: req.Channel} chanIds := make([]string, 0) cInfos, _ := channelmod.FindManyChannelInfo(ctx, allFlter) if len(cInfos) > 0 { for _, info := range cInfos { chanIds = append(chanIds, info.Channel) } // 更新一级渠道的所有子渠道 serr = channelmod.UpdateManyChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: bson.M{"$in": chanIds}}, setDoc) if serr != nil { log.Error("UpdateOneChannelOwner:UpdateManyChannelInfo 2 err", log.Any("serr", serr), log.Any("req", req)) } // 更新一级渠道的所有子渠道统计 serr = channelmod.UpdateManyChannelStat(ctx, bson.M{channelmod.FN.ChannelStat.Channel: bson.M{"$in": chanIds}}, csSetDoc) if serr != nil { log.Error("UpdateOneChannelOwner:UpdateManyChannelStat 2 err", log.Any("serr", serr), log.Any("req", req)) } } // 添加变更记录 new := &channelmod.ChannelOwnerChange{ ID: primitive.NewObjectID(), Channel: cInfo.Channel, OldUser: cInfo.UserName, NewUser: req.UserName, Mark: req.Mark, CreatedAt: now, UpdatedAt: now, Operator: operator, Account: account, } serr = channelmod.InsertOneChannelOwnerChange(ctx, new) if serr != nil { log.Error("UpdateOneChannelOwner:InsertOneChannelOwnerChange err", log.Any("new", new), log.Any("err", serr)) return serr } return nil } // SearchChannelOwnerChangeInfo 查询渠道所有者变更信息 func SearchChannelOwnerChangeInfo(ctx context.Context, req *proto.ChannelOwnerChangeInfoSearch) ( *proto.ChannelOwnerChangeInfoSearchResp, error) { filter := bson.M{} opt := &options.FindOptions{} opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1}) opt.SetSkip((req.PageNum - 1) * req.PageSize) opt.SetLimit(req.PageSize) resp := &proto.ChannelOwnerChangeInfoSearchResp{} if req.ID != nil { filter[channelmod.FN.ChannelOwnerChange.ID] = req.ID } if req.Channel != nil { filter[channelmod.FN.ChannelOwnerChange.Channel] = *req.Channel } if req.OldUser != nil { filter[channelmod.FN.ChannelOwnerChange.OldUser] = *req.OldUser } if req.NewUser != nil { filter[channelmod.FN.ChannelOwnerChange.NewUser] = *req.NewUser } total, serr := channelmod.CountChannelOwnerChanges(ctx, filter) if serr != nil { return nil, serr } if total == 0 { return resp, nil } ownerChangeList, err := channelmod.FindManyChannelOwnerChanges(ctx, filter, opt) if serr != nil { return nil, err } resp.List = ownerChangeList resp.Total = total return resp, nil } // SearchUserInfo 查询用户信息 func SearchUserInfo(ctx context.Context, req *proto.UserInfoSearch) ( *proto.UserInfoSearchResp, error) { resp := &proto.UserInfoSearchResp{} filter := bson.M{} if req.UserId != nil { filter["userId"] = *req.UserId } if req.Channel != nil { filter["districtCode"] = *req.Channel } if req.AppId != nil { filter["appId"] = *req.AppId } if req.IP != nil { filter["ip"] = *req.IP } if req.Start != nil && req.End != nil { filter["createdAt"] = bson.M{"$gt": *req.Start, "$lt": *req.End} } total, err := registermod.CountRegister(ctx, filter) if err != nil { log.Error("SearchUserInfo CountRegister", log.Any("err", err)) return nil, err } opt := &options.FindOptions{} opt.SetSort(bson.M{"createdAt": -1}) opt.SetSkip((req.PageNum - 1) * req.PageSize) opt.SetLimit(req.PageSize) userList, err := registermod.FindManyRegister(ctx, filter, opt) if err != nil { log.Error("SearchUserInfo FindManyRegister", log.Any("err", err)) return nil, err } resp.Total = total resp.List = userList return resp, nil }