From 9b41cb9d9405b4e064d94a27b28a5475245168b0 Mon Sep 17 00:00:00 2001 From: hujiebin Date: Tue, 20 Jun 2023 10:46:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9C=AA=E8=83=BD=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E7=9A=84=EF=BC=8C=E7=AD=89=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E9=9C=80=E6=B1=82=E5=90=8E=E5=86=8D=E5=81=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _const/enum/country_e/enum.go | 25 +++ _const/enum/groupPower_e/enum.go | 60 ++++++ _const/enum/group_e/enum.go | 101 ++++++++++ _const/enum/user_e/user.go | 48 ++++- _const/redis_key/group_k/keys.go | 8 + cv/user_cv/user.go | 58 ++++++ domain/model/groupPower_m/groupPower.go | 67 +++++++ domain/model/group_m/groupInfo.go | 53 +++++ domain/model/group_m/room.go | 58 ++++++ domain/model/user_m/like.go | 104 ++++++++++ domain/model/user_m/relation.go | 121 ++++++++++++ domain/service/user_s/user.go | 245 ++++++++++++++++++++++++ route/router.go | 1 + route/user_r/user.go | 36 ++++ 14 files changed, 980 insertions(+), 5 deletions(-) create mode 100644 _const/enum/country_e/enum.go create mode 100644 _const/enum/groupPower_e/enum.go create mode 100644 _const/enum/group_e/enum.go create mode 100644 _const/redis_key/group_k/keys.go create mode 100644 domain/model/groupPower_m/groupPower.go create mode 100644 domain/model/group_m/groupInfo.go create mode 100644 domain/model/group_m/room.go create mode 100644 domain/model/user_m/like.go create mode 100644 domain/model/user_m/relation.go create mode 100644 domain/service/user_s/user.go create mode 100644 route/user_r/user.go diff --git a/_const/enum/country_e/enum.go b/_const/enum/country_e/enum.go new file mode 100644 index 0000000..1f09c39 --- /dev/null +++ b/_const/enum/country_e/enum.go @@ -0,0 +1,25 @@ +package country_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +// 国家角色 +type CountryMgrRole mysql.Type + +const ( + // 国家管理员 + CountryMgrManager CountryMgrRole = 1 + // 国家助理 + CountryMgrAssistant CountryMgrRole = 2 +) + +// 角色权限 +type ManagerPrivilegeItem mysql.Type + +const ( + // 重置用户头像 + ManagerPrivilegeItemResetAvatar ManagerPrivilegeItem = 1 + // 重置群组头像 + ManagerPrivilegeItemResetFaceUrl ManagerPrivilegeItem = 2 + // 删除广播 + ManagerPrivilegeItemDeleteGlobalBroadcast ManagerPrivilegeItem = 3 +) diff --git a/_const/enum/groupPower_e/enum.go b/_const/enum/groupPower_e/enum.go new file mode 100644 index 0000000..12a90f4 --- /dev/null +++ b/_const/enum/groupPower_e/enum.go @@ -0,0 +1,60 @@ +package groupPower_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +//国家势力状态 +type GroupPowerStatus = mysql.Type + +const ( + //上架 + GroupPowerUserHas GroupPowerStatus = 1 + //未上架 + GroupPowerUserNo GroupPowerStatus = 2 + //解散 + GroupPowerDissolve GroupPowerStatus = 3 +) + +//国家势力用户角色 +type GroupPowerUserRole = mysql.Type + +const ( + // 普通用户 + GroupPowerUserRoleUser GroupPowerUserRole = 1 + // 势力主 + GroupPowerUserRoleMgr GroupPowerUserRole = 2 + // 管理员 + GroupPowerUserRoleAdmin GroupPowerUserRole = 3 +) + +//国家势力日志操作类型 +type GroupPowerUserLogType = mysql.Type + +const ( + //加入 + GroupPowerUserLogTypeUserJoin GroupPowerUserLogType = 1 + //用户自己离开 + GroupPowerUserLogTypeUserLeave GroupPowerUserLogType = 2 + //运营平台赋予管理者 + GroupPowerUserLogTypeOwerJoin GroupPowerUserLogType = 3 + //管理人让用户离开 + GroupPowerUserLogTypeMgrLeave GroupPowerUserLogType = 4 + //管理人解散 + GroupPowerUserLogDissolve GroupPowerUserLogType = 5 +) + +type GroupPowerDiamondLogType = mysql.Type + +const ( + //群组原因加入 + GroupPowerDiamondLogTypeByGroup GroupPowerDiamondLogType = 1 + //群主原因加入 + GroupPowerDiamondLogTypeByGroupOwer GroupPowerDiamondLogType = 2 +) + +type PowerSupportAwardState = uint + +const ( + PowerSuppportNo PowerSupportAwardState = 0 // 未达到要求 + PowerSuppportAwarded PowerSupportAwardState = 1 // 已经领取 + PowerSuppportWaiting PowerSupportAwardState = 2 // 待领取 +) diff --git a/_const/enum/group_e/enum.go b/_const/enum/group_e/enum.go new file mode 100644 index 0000000..437696a --- /dev/null +++ b/_const/enum/group_e/enum.go @@ -0,0 +1,101 @@ +package group_e + +import "git.hilo.cn/hilo-common/resource/mysql" + +type MsgStatusGroupUser = mysql.Type + +const ( + //正常: 灰点+震动 + NormalMsgStatusGroupUser MsgStatusGroupUser = 0 + //静音:灰点 + MuteMsgStatusGroupUser MsgStatusGroupUser = 1 + //免打扰:什么也没有 + DoNotDisturbMsgStatusGroupUser MsgStatusGroupUser = 2 + + OverseaRoom = 1 + LocalRoom = 2 +) + +// 公屏消息 +type TypePublicScreenMsg = mysql.Type + +const ( + UserJoinPublicScreenMsg TypePublicScreenMsg = 1 // 加入群组 + UserKickPublicScreenMsg TypePublicScreenMsg = 2 // 踢出房间 + UserBannedPublicScreenMsg TypePublicScreenMsg = 3 // 拉黑用户 + RoleAssignedPublicScreenMsg TypePublicScreenMsg = 4 // 添加角色 + RoleRemovedPublicScreenMsg TypePublicScreenMsg = 5 // 移除角色 + ClientSendMsgLocal TypePublicScreenMsg = 6 // 客户端占用 + RollDiceMsg TypePublicScreenMsg = 7 // 掷骰子结果 + GroupGiftMsg TypePublicScreenMsg = 8 //全服礼物 + GroupSupportH5 TypePublicScreenMsg = 9 //群组支持H5 + JumpMessage TypePublicScreenMsg = 10 // 可跳转的公屏消息 + RocketAwardMsg TypePublicScreenMsg = 11 // 火箭获奖消息 + LockyboxAwardMsg TypePublicScreenMsg = 12 // 幸运盒子公屏中奖 + FruitMachineAwardMsg TypePublicScreenMsg = 13 // 水果机中奖 + EnterRoomMsg TypePublicScreenMsg = 14 // 用户进入房间 +) + +// 信令消息(不显示公屏工,不记入消息历史,不影响未读数) +type TypeSignalMsg = mysql.Type + +const ( + GroupEditProfileSignal TypeSignalMsg = 1 + GroupRoleChangeSignal TypeSignalMsg = 2 + GroupMicChangeSignal TypeSignalMsg = 3 //保留 + GroupMsgBannedSignal TypeSignalMsg = 4 + GroupMemberRemoveSignal TypeSignalMsg = 5 + GroupGiftSignal TypeSignalMsg = 6 //礼物 + GroupMicInSignal TypeSignalMsg = 7 + GroupMicOutSignal TypeSignalMsg = 8 + GroupMicLockSignal TypeSignalMsg = 9 + GroupMicUnLockSignal TypeSignalMsg = 10 + GroupMicSpeechOpenSignal TypeSignalMsg = 11 + GroupMicSpeechCloseSignal TypeSignalMsg = 12 + GroupKickOut TypeSignalMsg = 13 //保留 + GroupSocketMicOutSignal TypeSignalMsg = 14 //保留 + GroupInviteMicInSignal TypeSignalMsg = 15 //邀请上麦保留 + GroupInSignal TypeSignalMsg = 16 //进入房间,进房特效 + GroupMicEmoji TypeSignalMsg = 17 //麦上表情 + GroupLuckyWheel TypeSignalMsg = 18 //转盘的通知信令 + GroupOutSignal TypeSignalMsg = 19 //离开房间 + GroupRocketState TypeSignalMsg = 20 //火箭状态变化 + GroupOnlineUser TypeSignalMsg = 21 //房间在线用户信息 + GroupMicChange TypeSignalMsg = 22 //房间麦位上的变量 + GroupMemberInvite TypeSignalMsg = 23 //房间-邀请用户成为会员 + GroupRoleChange TypeSignalMsg = 24 //房间-用户群组身份变化 + GroupClearScreen TypeSignalMsg = 25 //房间-清理公屏 + GroupRoomGiftSignal TypeSignalMsg = 26 //全房间送礼物 +) + +//群组麦位数量类型 +type GroupMicNumType = mysql.Type + +const ( + OneMicNumType GroupMicNumType = 5 + TwoMicNumType GroupMicNumType = 10 + ThreeMicNumType GroupMicNumType = 3 + FourMicNumType GroupMicNumType = 4 + SixMicNumType GroupMicNumType = 6 + SevenMicNumType GroupMicNumType = 7 + EightMicNumType GroupMicNumType = 8 + NineMicNumType GroupMicNumType = 9 + ElevenMicNumType GroupMicNumType = 11 + TwelveMicNumType GroupMicNumType = 12 + ThirteenMicNumType GroupMicNumType = 13 + FourteenMicNumType GroupMicNumType = 14 + FifteenMicNumType GroupMicNumType = 15 + SixteenMicNumType GroupMicNumType = 16 + SeventeenMicNumType GroupMicNumType = 17 + EighteenMicNumType GroupMicNumType = 18 + NineteenMicNumType GroupMicNumType = 19 + TwentyMicNumType GroupMicNumType = 20 + //5个麦位 + FiveMicNumType GroupMicNumType = 1 + //10个麦位 + TenMicNumType GroupMicNumType = 2 + // + + SUPPORT_LEVEL_BOUNDARY_HOUR = 0 + SUPPORT_LEVEL_PERIOD_DAY = 7 +) diff --git a/_const/enum/user_e/user.go b/_const/enum/user_e/user.go index 971af4d..c745240 100755 --- a/_const/enum/user_e/user.go +++ b/_const/enum/user_e/user.go @@ -1,6 +1,8 @@ package user_e -import "git.hilo.cn/hilo-common/resource/mysql" +import ( + "git.hilo.cn/hilo-common/resource/mysql" +) type ThirdPartyType = mysql.Type @@ -12,6 +14,17 @@ const ( WeChat ThirdPartyType = 5 ) +type CountType mysql.Type + +const ( + //我喜欢的数量 + CountTypeLike CountType = 1 + //我拉黑的数量 + CountTypeBlock CountType = 2 + //我被喜欢的次数 + CountTypeLikeMe CountType = 3 +) + type UserStatus mysql.Type const ( @@ -24,8 +37,33 @@ const ( type UserVipType = mysql.Type const ( - // 男 - UserMan = 1 - // 女 - UserWomen = 2 + //购买 + UserVipTypeBuy UserVipType = 1 + //赠送 + UserVipTypeGive UserVipType = 2 ) + +type UserLikeOperateType = mysql.Type + +const ( + //增加喜欢 + LikeAdd UserLikeOperateType = 1 + //取消喜欢 + LikeCancel UserLikeOperateType = 2 +) + +type UserLikeSceneType = mysql.Type + +const ( + Match UserLikeSceneType = 1 + Video UserLikeSceneType = 2 +) + +type InteractionType = mysql.Type + +const ( + InteractPrivateGift InteractionType = 1 + InteractVideo InteractionType = 2 +) + + diff --git a/_const/redis_key/group_k/keys.go b/_const/redis_key/group_k/keys.go new file mode 100644 index 0000000..7007daa --- /dev/null +++ b/_const/redis_key/group_k/keys.go @@ -0,0 +1,8 @@ +package group_k + +//在房间的人 +const groupRoomLiving = "group_room_living" + +func GetPrefixGroupRoomLiving() string { + return groupRoomLiving +} diff --git a/cv/user_cv/user.go b/cv/user_cv/user.go index 419988e..7c21fbd 100644 --- a/cv/user_cv/user.go +++ b/cv/user_cv/user.go @@ -6,6 +6,7 @@ import ( "git.hilo.cn/hilo-common/resource/mysql" "git.hilo.cn/hilo-common/rpc" "gorm.io/gorm" + "hilo-user/_const/enum/country_e" "hilo-user/cv/headwear_cv" "hilo-user/cv/medal_cv" "hilo-user/cv/noble_cv" @@ -355,3 +356,60 @@ type CvUserTiny struct { //生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示 Birthday *uint64 `json:"birthday"` } + +//用户详细信息 +type CvUserDetail struct { + CvUserBase + //统计:我喜欢多少人 + ILikeCount *uint32 `json:"iLikeCount"` + //统计:多少人喜欢你, (本才才有数据,不是本人,数据为nil) + LikeCount *uint32 `json:"likeCount"` + //统计:多少人访问你 + VisitCount *uint32 `json:"visitCount"` + //消息提醒, 1:开启,2:关闭 + IsPush *uint8 `json:"isPush"` + //钻石数量(本人才有数据,不是本人,数据为nil) + DiamondNum *uint32 `json:"diamondNum"` + //粉钻数量(本人才有数据,不是本人,数据为nil) + PinkDiamondNum *uint32 `json:"pinkDiamondNum"` + //是否喜欢(本人没有数据,//20210205 已废弃nil,产品说:可以自己喜欢自己) + IsLike *bool `json:"isLike"` + //ID + //ID *mysql.ID `json:"id,omitempty"` + //是否工会成员, 只有是自己查自己,这个才有值,其它全为nil + //IsTradeUnion *bool `json:"isTradeUnion"` + //工会成员,是否开启了,匹配通知,只有 isTradeUnion值为true,这里才有值, + //IsTradeUnionMatchNotification *bool `json:"isTradeUnionMatchNotification"` + //是否可以免费通话,自己本人没有数据 + //IsVideoFreeCan *bool `json:"isVideoCanFree"` + //别人是否喜欢我,自己本人没有数据 (20210205 已废弃nil,产品说:可以自己喜欢自己) + IsLikeMe *bool `json:"isLikeMe"` + HeartValue uint32 `json:"heartValue"` // 与我之间永恒之心的值 + HeartValueMax uint32 `json:"heartValueMax"` // 与我之间永恒之心的最大值(0代表没有永恒之心,即没有相互关注) + MeetDays uint `json:"meetDays"` // 成长关系建立的时间(天数) + WealthUserGrade uint32 `json:"wealthUserGrade"` //财富等级 + CharmUserGrade uint32 `json:"charmUserGrade"` //魅力等级 + ActivityUserGrade uint32 `json:"activityUserGrade"` //活跃等级 + CurrentRoom string `json:"currentRoom"` // 当前用户所在房间(产品叫“群组”) + MyGroupPower uint64 `json:"myGroupPower"` // 当前用户所在势力 + MyGroupPowerName string `json:"myGroupPowerName"` // 当前用户所在势力绑定群组的名称 + GroupPower rpc.CvGroupPowerInfo `json:"groupPower"` // 家族 + GroupId string `json:"groupId"` // 当前用户拥有的群组id(产品叫“群组”),如果没有则为空,拥有多个,返回第一个 + PhoneInfo *UserPhoneInfo `json:"phoneInfo"` // 用户绑定的手机信息 + ThirdList []int8 `json:"thirdList"` // 用户绑定的第三方平台列表;类型 1:phone, 2:google, 3:facebook 4:apple 5:wechat" Enums(1,2,3,4,5) + CountryManager *CVCountryManager `json:"countryManager,omitempty"` // 国家管理员 + Cp *rpc.CvCp `json:"cp,omitempty"` // cp信息 +} + +type UserPhoneInfo struct { + Phone string `json:"phone"` + PhoneCountry string `json:"phoneCountry"` + AreaCode string `json:"areaCode"` + Icon string `json:"icon"` +} + +// cv国家管理人员 +type CVCountryManager struct { + Country string `json:"country"` // 国家name + Role country_e.CountryMgrRole `json:"role" swaggertype:"integer"` // 角色 1:国家管理员 2:国家助理 +} diff --git a/domain/model/groupPower_m/groupPower.go b/domain/model/groupPower_m/groupPower.go new file mode 100644 index 0000000..a427d5a --- /dev/null +++ b/domain/model/groupPower_m/groupPower.go @@ -0,0 +1,67 @@ +package groupPower_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "hilo-user/_const/enum/groupPower_e" + "hilo-user/domain/model/group_m" + "hilo-user/myerr" +) + +type GroupPowerUser struct { + mysql.Entity + *domain.Model `gorm:"-"` + GroupPowerId mysql.ID + UserId mysql.ID + Role groupPower_e.GroupPowerUserRole +} + +// 查询用户加入的国家势力ID及名称(势力绑定的群组的名称) +func GetUserGroupPower(model *domain.Model, userId uint64) (uint64, string, error) { + gpu, err := GetGroupPowerUserOrNil(model, userId) + if err != nil { + return 0, "", err + } + if gpu == nil || gpu.GroupPowerId == 0 { + return 0, "", nil + } + gp, err := GetGroupPowerOrErr(model, gpu.GroupPowerId) + if err != nil { + return 0, "", err + } + + powerName := "" + if gp != nil && len(gp.GroupUid) > 0 { + gi, err := group_m.GetGroupInfo(model, gp.GroupUid) + if err != nil { + return 0, "", err + } + if gi != nil { + // 只要前15个字 + s := []rune(gi.Name) + if len(s) <= 15 { + powerName = string(s) + } else { + powerName = string(s[0:15]) + } + } + } + return gpu.GroupPowerId, powerName, nil +} + +//获取用户所在的国家势力信息,不存在则为nil +func GetGroupPowerUserOrNil(model *domain.Model, userId mysql.ID) (*GroupPowerUser, error) { + groupPowerUser := GroupPowerUser{} + if err := model.Db.Where(&GroupPowerUser{ + UserId: userId, + }).First(&groupPowerUser).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, myerr.WrapErr(err) + } + } + groupPowerUser.Model = model + return &groupPowerUser, nil +} diff --git a/domain/model/group_m/groupInfo.go b/domain/model/group_m/groupInfo.go new file mode 100644 index 0000000..d51ac9f --- /dev/null +++ b/domain/model/group_m/groupInfo.go @@ -0,0 +1,53 @@ +package group_m + +import ( + "git.hilo.cn/hilo-common/domain" + "gorm.io/gorm" + "hilo-user/_const/enum/group_e" + "hilo-user/myerr/bizerr" + "time" +) + +type GroupInfo struct { + Id int64 + ImGroupId string + TxGroupId string + Type uint16 + Code string + OriginCode string + Owner uint64 + Name string + Introduction string + Notification string + FaceUrl string + Country string + ChannelId string + Password string + EntryLevel uint32 // obsolete + MicOn bool + LoadHistory bool + ThemeId int16 + MicNumType group_e.GroupMicNumType + TouristMic uint8 // 游客是否能上麦1是2否 + TouristSendMsg uint8 // 游客是否能发消息1是2否 + TouristSendPic uint8 // 游客是否能发图片1是2否 + MemberFee uint64 // 加入会员需要黄钻数 + CreatedTime time.Time `gorm:"->"` + UpdatedTime time.Time `gorm:"->"` +} + +func GetGroupInfo(model *domain.Model, groupId string) (*GroupInfo, error) { + if len(groupId) <= 0 { + return nil, bizerr.GroupNotFound + } + r := GroupInfo{} + err := model.Db.Where(&GroupInfo{ImGroupId: groupId}).First(&r).Error + if err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, err + } + } + return &r, nil +} diff --git a/domain/model/group_m/room.go b/domain/model/group_m/room.go new file mode 100644 index 0000000..12319ad --- /dev/null +++ b/domain/model/group_m/room.go @@ -0,0 +1,58 @@ +package group_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/mylogrus" + "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/resource/redisCli" + "hilo-user/_const/redis_key/group_k" + "hilo-user/myerr" + "strconv" + "strings" + "time" +) + +const expireMinute = 60 * 60 * 12 + +//获取在房间的用户 返回值:map,key:userId, value:groupUuid +func RoomLivingUserIdFilter(model *domain.Model, userIds []mysql.ID) (map[mysql.ID]string, error) { + userIdSet := map[mysql.ID]struct{}{} + for i, _ := range userIds { + userIdSet[userIds[i]] = struct{}{} + } + key := group_k.GetPrefixGroupRoomLiving() + if err := ClearExpired(model, key, expireMinute); err != nil { + return nil, myerr.WrapErr(err) + } + + groupUserIdstrs, err := redisCli.GetRedis().ZRange(model, key, 0, -1).Result() + if err != nil { + return nil, myerr.WrapErr(err) + } + + resultUserSet := map[mysql.ID]string{} + for i, _ := range groupUserIdstrs { + tempGroupUid, userId := analysisMemberStr(groupUserIdstrs[i]) + mylogrus.MyLog.Debugf("RoomLivingUserIdFilter, analysisMemberStr %s, %d", tempGroupUid, userId) + + if _, flag := userIdSet[userId]; flag { + resultUserSet[userId] = tempGroupUid + } + } + return resultUserSet, nil +} + +func ClearExpired(model *domain.Model, key string, expireSec int64) error { + return model.Redis.ZRemRangeByScore(model, key, + "0", strconv.FormatInt(time.Now().Unix()-expireSec, 10)).Err() +} + +func analysisMemberStr(memberStr string) (string, uint64) { + strs := strings.Split(memberStr, "_") + groupUid := strs[0] + userId, err := strconv.ParseUint(strs[1], 10, 64) + if err != nil { + mylogrus.MyLog.Errorf("analysisMemberStr memberStr:%v err:%+v", memberStr, err) + } + return groupUid, userId +} diff --git a/domain/model/user_m/like.go b/domain/model/user_m/like.go new file mode 100644 index 0000000..27b4500 --- /dev/null +++ b/domain/model/user_m/like.go @@ -0,0 +1,104 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "hilo-user/_const/enum/user_e" + "hilo-user/myerr" +) + +//用户喜欢 +type UserLike struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId mysql.ID + LikeUserId mysql.ID + SceneType user_e.UserLikeSceneType +} + +type UserLikeOperate struct { + mysql.Entity + UserId mysql.ID + LikeUserId mysql.ID + Type user_e.UserLikeOperateType + SceneType user_e.UserLikeSceneType +} + +func AddUserLikeOperate(model *domain.Model, userId mysql.ID, likeUserId mysql.ID, t user_e.UserLikeOperateType, sceneType user_e.UserLikeSceneType) (mysql.ID, error) { + userLikeOperate := UserLikeOperate{ + UserId: userId, + LikeUserId: likeUserId, + Type: t, + SceneType: sceneType, + } + if err := model.Db.Create(&userLikeOperate).Error; err != nil { + return 0, myerr.WrapErr(err) + } else { + return userLikeOperate.ID, nil + } +} + +func initUserLike(model *domain.Model, userId mysql.ID) *UserLike { + return &UserLike{ + Model: model, + UserId: userId, + } +} + +/*func GetUserLike(model *domain.Model, userId mysql.ID, likeUserId mysql.ID) (*UserLike, error) { + var userLike UserLike + err := model.Db.Where(&UserLike{ + UserId: userId, + LikeUserId: likeUserId, + }).First(&userLike).Error + if err == nil { + return &userLike, nil + } else if err == gorm.ErrRecordNotFound { + return nil, nil + } else { + return nil, myerr.WrapErr(err) + } +}*/ + +//喜欢 +func (userLike *UserLike) like(likeUserId mysql.ID, sceneType user_e.UserLikeSceneType) (*UserLike, mysql.ID, error) { + err := userLike.Db.Where(&UserLike{ + UserId: userLike.UserId, + LikeUserId: likeUserId, + }).First(userLike).Error + //已经喜欢 + if err == nil { + return nil, 0, myerr.NewWaring("已经标记喜欢") + } else if err == gorm.ErrRecordNotFound { + userLikeOperateId, err := AddUserLikeOperate(userLike.Model, userLike.UserId, likeUserId, user_e.LikeAdd, sceneType) + if err != nil { + return nil, 0, err + } + userLike.LikeUserId = likeUserId + userLike.SceneType = sceneType + return userLike, userLikeOperateId, nil + } else { + return nil, 0, myerr.WrapErr(err) + } +} + +//取消喜欢 +func (userLike *UserLike) likeCancel(likeUserId mysql.ID) (*UserLike, error) { + err := userLike.Db.Where(&UserLike{ + UserId: userLike.UserId, + LikeUserId: likeUserId, + }).First(userLike).Error + // + if err == nil { + if _, err := AddUserLikeOperate(userLike.Model, userLike.UserId, likeUserId, user_e.LikeCancel, userLike.SceneType); err != nil { + return nil, err + } + userLike.SetDel() + return userLike, nil + } else if err == gorm.ErrRecordNotFound { + return nil, myerr.NewWaring("没有喜欢的记录") + } else { + return nil, myerr.WrapErr(err) + } +} diff --git a/domain/model/user_m/relation.go b/domain/model/user_m/relation.go new file mode 100644 index 0000000..df8e78d --- /dev/null +++ b/domain/model/user_m/relation.go @@ -0,0 +1,121 @@ +package user_m + +import ( + "git.hilo.cn/hilo-common/_const/common" + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/resource/mysql" + "gorm.io/gorm" + "hilo-user/myerr" + "time" +) + +type Relation struct { + // 永恒之心值 + HeartValue uint32 `json:"heartValue"` + // 永恒之心的最大值(0代表没有永恒之心,即没有相互关注) + HeartValueMax uint32 `json:"heartValueMax"` + // 成长关系建立的时间(天数) + MeetDays uint `json:"meetDays"` +} + +//用户成长关系 +type UserRelation struct { + mysql.Entity + *domain.Model `gorm:"-"` + UserId_1 mysql.ID + UserId_2 mysql.ID + HeartValue uint32 +} + +// 查询成长关系 +func GetRelation(model *domain.Model, userId1, userId2 mysql.ID) (Relation, error) { + result := Relation{0, 0, 0} + if userId1 == userId2 { + return result, nil + } + // 保证uid小的在前面 + if userId1 > userId2 { + userId1, userId2 = userId2, userId1 + } + rel := UserRelation{UserId_1: userId1, UserId_2: userId2, HeartValue: 0} + if err := model.DB().Model(&UserRelation{}).Where(&UserRelation{ + UserId_1: userId1, + UserId_2: userId2, + }).First(&rel).Error; err != nil { + if err == gorm.ErrRecordNotFound { + // 没有成长关系的情况 + return result, nil + } else { + return result, myerr.WrapErr(err) + } + } + result.HeartValueMax = common.HEART_VALUE_MAX + + result.HeartValue = rel.HeartValue + if result.HeartValue > common.HEART_VALUE_MAX { + result.HeartValue = common.HEART_VALUE_MAX + } + d := uint(time.Since(rel.CreatedTime).Hours() / 24) + if d < 0 { + d = 0 + } + result.MeetDays = d + + return result, nil +} + +// 批量查询成长关系 +func BatchGetRelations(model *domain.Model, userId mysql.ID, others []mysql.ID) (map[mysql.ID]Relation, error) { + smaller := make([]mysql.ID, 0) + greater := make([]mysql.ID, 0) + for _, i := range others { + if i < userId { + smaller = append(smaller, i) + } else if i > userId { + greater = append(greater, i) + } + } + rows := make([]UserRelation, 0) + result := make(map[mysql.ID]Relation, 0) + var err error + if len(greater) > 0 { + if err = model.DB().Model(&UserRelation{}).Where("user_id_1 = ? AND user_id_2 IN ?", userId, greater).Find(&rows).Error; err != nil { + return result, err + } + } + + for _, i := range rows { + if i.HeartValue > common.HEART_VALUE_MAX { + i.HeartValue = common.HEART_VALUE_MAX + } + d := uint(time.Since(i.CreatedTime).Hours() / 24) + if d < 0 { + d = 0 + } + result[i.UserId_2] = Relation{HeartValue: i.HeartValue, HeartValueMax: common.HEART_VALUE_MAX, MeetDays: d} + } + + rows = make([]UserRelation, 0) + if len(smaller) > 0 { + if err = model.DB().Model(&UserRelation{}).Where("user_id_1 IN ? AND user_id_2 = ?", smaller, userId).Find(&rows).Error; err != nil { + return result, err + } + } + for _, i := range rows { + if i.HeartValue > common.HEART_VALUE_MAX { + i.HeartValue = common.HEART_VALUE_MAX + } + d := uint(time.Since(i.CreatedTime).Hours() / 24) + if d < 0 { + d = 0 + } + result[i.UserId_1] = Relation{HeartValue: i.HeartValue, HeartValueMax: common.HEART_VALUE_MAX, MeetDays: d} + } + // 补上没有成长关系的人 + for _, u := range others { + if _, exists := result[u]; !exists { + result[u] = Relation{0, 0, 0} + } + } + return result, err +} diff --git a/domain/service/user_s/user.go b/domain/service/user_s/user.go new file mode 100644 index 0000000..0cb7214 --- /dev/null +++ b/domain/service/user_s/user.go @@ -0,0 +1,245 @@ +package user_s + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/mycontext" + "git.hilo.cn/hilo-common/resource/mysql" + "git.hilo.cn/hilo-common/rpc" + "gorm.io/gorm" + "hilo-user/cv/headwear_cv" + "hilo-user/cv/medal_cv" + "hilo-user/cv/property_cv" + "hilo-user/cv/user_cv" + "hilo-user/domain/model/group_m" + "hilo-user/domain/model/noble_m" + "hilo-user/domain/model/user_m" + "hilo-user/myerr" +) + +type UserService struct { + svc *domain.Service +} + +func NewUserService(myContext *mycontext.MyContext) *UserService { + svc := domain.CreateService(myContext) + return &UserService{svc} +} + +//用户基本信息 +func (s *UserService) GetUserDetail(userId mysql.ID, myUserId mysql.ID, lang ...string) (*user_cv.CvUserDetail, error) { + model := domain.CreateModelContext(s.svc.MyContext) + model.Log.Infof("GetUserDetail %d begin", userId) + var user user_m.User + var err error + if err = model.DB().First(&user, userId).Error; err != nil { + return nil, myerr.WrapErr(err) + } + + //统计喜欢 + var likeN int64 + if err := model.DB().Model(&user_m.UserLike{}).Where(&user_m.UserLike{ + UserId: myUserId, + LikeUserId: userId, + }).Count(&likeN).Error; err != nil { + return nil, myerr.WrapErr(err) + } + + var likeMe int64 + if err := model.DB().Model(&user_m.UserLike{}).Where(&user_m.UserLike{ + UserId: userId, + LikeUserId: myUserId, + }).Count(&likeMe).Error; err != nil { + return nil, myerr.WrapErr(err) + } + + rel := make(map[mysql.ID]user_m.Relation, 1) + rel[userId], _ = user_m.GetRelation(model, myUserId, userId) + + var wealthUserScore user_m.MatchWealthUserScore + if err := mysql.Db.Model(&user_m.MatchWealthUserScore{}).Where(&user_m.MatchWealthUserScore{UserId: userId}).First(&wealthUserScore).Error; err != nil { + if err != nil { + if err == gorm.ErrRecordNotFound { + wealthUserScore = user_m.MatchWealthUserScore{ + UserId: userId, + Score: 0, + Grade: 0, + } + } else { + return nil, myerr.WrapErr(err) + } + } + } + + var charmUserScore user_m.MatchCharmUserScore + if err := mysql.Db.Model(&user_m.MatchCharmUserScore{}).Where(&user_m.MatchCharmUserScore{ + UserId: userId, + }).First(&charmUserScore).Error; err != nil { + if err != nil { + if err == gorm.ErrRecordNotFound { + charmUserScore = user_m.MatchCharmUserScore{ + UserId: userId, + Score: 0, + Grade: 0, + } + } else { + return nil, myerr.WrapErr(err) + } + } + } + + var activityUserScore user_m.MatchActityUserScore + if err := mysql.Db.Model(&user_m.MatchActityUserScore{}).Where(&user_m.MatchActityUserScore{ + UserId: userId, + }).First(&activityUserScore).Error; err != nil { + if err != nil { + if err == gorm.ErrRecordNotFound { + activityUserScore = user_m.MatchActityUserScore{ + UserId: userId, + Score: 0, + Grade: 0, + } + } else { + return nil, myerr.WrapErr(err) + } + } + } + isVip, expireTime, err := user_m.IsVip(userId) + if err != nil { + return nil, myerr.WrapErr(err) + } + svip, err := rpc.GetUserSvip(model, userId) + if err != nil { + return nil, myerr.WrapErr(err) + } + + headwear, err := headwear_cv.GetCvHeadwear(userId) + if err != nil { + return nil, err + } + + medals := make(map[uint64][]uint32, 0) + medals[userId], err = user_m.GetUserMedalMerge(model.Log, mysql.Db, userId) + if err != nil { + return nil, err + } + + medals, medalInfo, err := medal_cv.GetMedalInfoMap(mysql.Db, medals) + if err != nil { + return nil, err + } + + rooms, err := group_m.RoomLivingUserIdFilter(model, []uint64{userId}) + if err != nil { + return nil, err + } + // 2022-05-13 个人详情页:当用户在加锁的房间时,不显示进入房间的图标 + if g, ok := rooms[userId]; ok { + gi, err := group_m.GetGroupInfo(model, g) + if err != nil { + return nil, err + } + if gi != nil && len(gi.Password) > 0 { + rooms[userId] = "" + } + } + cp, _ := rpc.GetUserCp(model, userId, lang...) // todo last + + groupPowerId, groupPowerName, err := groupPower_m.GetUserGroupPower(model, userId) + if err != nil { + return nil, err + } + powers := map[mysql.ID]uint64{userId: groupPowerId} + powerNames := map[mysql.ID]string{userId: groupPowerName} + groupPower, _ := rpc.GetGroupPower(model, groupPowerId) + + up := user_m.UserProperty{} + rides, err := up.BatchGet(mysql.Db, []uint64{userId}) + if err != nil { + return nil, err + } + + //rp := res_m.ResProperty{} + //properties, err := rp.GetAll(mysql.Db) + properties, err := property_cv.GetPropertyAll(mysql.Db) + if err != nil { + return nil, err + } + ride := property_cv.CvProperty{ + Id: rides[user.ID], + PicUrl: properties[rides[user.ID]].PicUrl, + EffectUrl: properties[rides[user.ID]].EffectUrl, + SenderAvatar: properties[rides[user.ID]].SenderAvatar, + ReceiverAvatar: properties[rides[user.ID]].ReceiverAvatar, + Using: true, + } + noble, err := noble_m.FindActiveNoble(mysql.Db, userId) + if err != nil { + return nil, err + } + + //判断是不是工会 + userTradeUnion, err := bv.GetUserTradeUnion(myUserId) + if err != nil { + return nil, err + } + + superManagerMap, err := GetSuperManagerMap([]uint64{userId}) + if err != nil { + return nil, err + } + + // 群组信息 + myGroups, err := group_m.FindGroupByOwner(model, userId) + if err != nil { + return nil, err + } + + // 手机绑定信息 + // 第三方账号绑定信息 + phoneInfo := new(model2.UserPhoneInfo) + var thirdList []int8 + if userId == myUserId { + thirdList = make([]int8, 0, 5) + // 手机绑定信息 + bindInfo, err := dao.UserBindInfoDb.GetByUserId(userId) + if err != nil && err != gorm.ErrRecordNotFound { + return nil, err + } + if bindInfo != nil { + if len(bindInfo.Phone) > 2 { + phoneInfo.Phone = bindInfo.Phone[:2] + "****" + bindInfo.Phone[len(bindInfo.Phone)-2:] + } + phoneInfo.PhoneCountry = bindInfo.PhoneCountry + phoneInfo.AreaCode = bindInfo.AreaCode + phoneInfo.Icon = bindInfo.Icon + thirdList = append(thirdList, 1) + } + // 第三方账号绑定信息 + thirdInfoList, err := dao.UserOauthDb.GetByUserId(userId, 0) + if err != nil { + return nil, err + } + if thirdInfoList != nil { + for _, v := range thirdInfoList { + thirdList = append(thirdList, v.ThirdPartyType) + } + } + } + // 国家管理员 + countryManager, err := country_m.GetCountryMgr(model, userId) + if err != nil { + return nil, err + } + var cvCountryManager *CVCountryManager + if countryManager != nil { + cvCountryManager = &CVCountryManager{ + Country: countryManager.Country, + Role: countryManager.Role, + } + } + + return userToDetailOne(model, &user, myUserId, userTradeUnion, likeN > 0, likeMe > 0, + rel, isVip, expireTime, svip, headwear, ride, wealthUserScore.Grade, charmUserScore.Grade, + activityUserScore.Grade, medals[userId], medalInfo[userId], rooms[userId], powers[userId], powerNames[userId], groupPower, + noble, superManagerMap[userId], myGroups, phoneInfo, thirdList, cvCountryManager, cp) +} diff --git a/route/router.go b/route/router.go index dfda755..c558200 100755 --- a/route/router.go +++ b/route/router.go @@ -28,6 +28,7 @@ func InitRouter() *gin.Engine { { user.GET("/nameplate", wrapper(user_r.UserNameplate)) user.GET("/bag/:resType", wrapper(user_r.UserBag)) + } cp := v2.Group("/cp") { diff --git a/route/user_r/user.go b/route/user_r/user.go new file mode 100644 index 0000000..8c8d6cb --- /dev/null +++ b/route/user_r/user.go @@ -0,0 +1,36 @@ +package user_r + +import ( + "git.hilo.cn/hilo-common/domain" + "git.hilo.cn/hilo-common/mycontext" + "github.com/gin-gonic/gin" + "hilo-user/req" + "hilo-user/resp" +) + +// @Tags 用户 +// @Summary 获取用户详细信息 +// @Param token header string true "token" +// @Param timestamp header string true "时间戳" +// @Param nonce header string true "随机数字" +// @Param signature header string true "sha1加密结果" +// @Param deviceType header string true "系统类型 ios android" +// @Param deviceVersion header string true "系统版本" +// @Success 200 {object} user_cv.CvUserDetail +// @Router /v1/user/detail [get] +func UserDetail(c *gin.Context) (*mycontext.MyContext, error) { + myContext := mycontext.CreateMyContext(c.Keys) + userId, err := req.GetUserId(c) + if err != nil { + return myContext, err + } + + model := domain.CreateModelContext(myContext) + + cvUserDetail, err := cv.GetUserDetail(model, userId, userId) + if err != nil { + return myContext, err + } + resp.ResponseOk(c, cvUserDetail) + return myContext, nil +} -- 2.22.0