作者 tangxvhui
@@ -16,7 +16,7 @@ info( @@ -16,7 +16,7 @@ info(
16 service Core { 16 service Core {
17 @doc "用户申请加入公司" 17 @doc "用户申请加入公司"
18 @handler miniUserApplyJoinCompany 18 @handler miniUserApplyJoinCompany
19 - post /mini/user/apply-join-company(MiniUserApplyJoinCompanyRequest) returns (MiniUserApplyJoinCompanyResponse) 19 + post /mini/user/apply_join_company(MiniUserApplyJoinCompanyRequest) returns (MiniUserApplyJoinCompanyResponse)
20 @doc "用户登录" 20 @doc "用户登录"
21 @handler miniUserLogin 21 @handler miniUserLogin
22 post /mini/user/login (MiniUserLoginRequest) returns (MiniUserLoginResponse) 22 post /mini/user/login (MiniUserLoginRequest) returns (MiniUserLoginResponse)
@@ -29,7 +29,7 @@ service Core { @@ -29,7 +29,7 @@ service Core {
29 service Core { 29 service Core {
30 @doc "切换账号" 30 @doc "切换账号"
31 @handler miniUserSwitchAccount 31 @handler miniUserSwitchAccount
32 - post /mini/user/switch-account (MiniUserSwitchAccountRequest) returns (MiniUserLoginResponse) 32 + post /mini/user/switch_account (MiniUserSwitchAccountRequest) returns (MiniUserLoginResponse)
33 @doc "用户信息" 33 @doc "用户信息"
34 @handler miniUserInfo 34 @handler miniUserInfo
35 post /mini/user/info (MiniUserInfoRequest) returns (MiniUserInfoResponse) 35 post /mini/user/info (MiniUserInfoRequest) returns (MiniUserInfoResponse)
@@ -38,22 +38,31 @@ service Core { @@ -38,22 +38,31 @@ service Core {
38 post /mini/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse) 38 post /mini/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse)
39 @doc "用户审核列表" 39 @doc "用户审核列表"
40 @handler miniUserAuditList 40 @handler miniUserAuditList
41 - post /mini/user/audit-list (UserSearchRequest)returns(UserSearchResponse) 41 + post /mini/user/audit_list (UserSearchRequest)returns(UserSearchResponse)
42 @doc "用户审核" 42 @doc "用户审核"
43 @handler miniUserAudit 43 @handler miniUserAudit
44 post /mini/user/audit (MiniUserAuditRequest) 44 post /mini/user/audit (MiniUserAuditRequest)
45 @doc "部门用户列表" 45 @doc "部门用户列表"
46 @handler miniUserDepartmentUsers 46 @handler miniUserDepartmentUsers
47 - post /mini/user/department-users (MiniUserDepartmentUsersRequest) 47 + post /mini/user/department_users (MiniUserDepartmentUsersRequest)
48 @doc "用户列表" 48 @doc "用户列表"
49 @handler miniUsersList 49 @handler miniUsersList
50 - post /mini/user/user-list (MiniUsersListRequest) 50 + post /mini/user/user_list (MiniUsersListRequest)
  51 + @doc "用户快讯"
  52 + @handler miniUserNews
  53 + post /mini/user/news (MiniUserNewsRequest)returns(MiniUserNewsResposne)
51 @doc "关注我的人" 54 @doc "关注我的人"
52 @handler miniUserFollower 55 @handler miniUserFollower
53 post /mini/user/follower (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse) 56 post /mini/user/follower (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse)
54 @doc "我关注的人" 57 @doc "我关注的人"
55 @handler miniUserFollowing 58 @handler miniUserFollowing
56 post /mini/user/following (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse) 59 post /mini/user/following (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse)
  60 + @doc "我关注的人-最新未读列表(未读标红)"
  61 + @handler miniUserFollowingLatestUnreadList
  62 + post /mini/user/following/latest_unread_list (MiniUserFollowedSearchRequest)returns(MiniUserFollowedSearchResponse)
  63 + @doc "我关注的人-标记已读"
  64 + @handler miniUserFollowingMarkRead
  65 + post /mini/user/following/mark_read (MiniUserFollowingMarkReadRequest)
57 @doc "关注" 66 @doc "关注"
58 @handler miniUserFollow 67 @handler miniUserFollow
59 post /mini/user/follow (FollowRequest) 68 post /mini/user/follow (FollowRequest)
@@ -115,6 +124,23 @@ type( @@ -115,6 +124,23 @@ type(
115 ArticleId int64 `json:"articleId,optional"` // 按文章ID(返回文章可见的用户) 124 ArticleId int64 `json:"articleId,optional"` // 按文章ID(返回文章可见的用户)
116 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户 125 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户
117 } 126 }
  127 + MiniUserNewsRequest{
  128 + AuthorId int64 `json:"authorId,optional"` // 特定作者ID
  129 + LastArticleId int64 `json:"lastArticleId,optional"`// 最后文章ID
  130 + Size int `json:"size"` // 数量
  131 + }
  132 + MiniUserNewsResposne{
  133 + List []UserNewsItem `json:"list"`
  134 + Total int64 `json:"total"`
  135 + }
  136 + UserNewsItem{
  137 + NewsId int64 `json:"newsId"` // 快讯ID
  138 + Type string `json:"type"` // 快讯类型 文章:Article 讨论:Discuss ...
  139 + Title string `json:"title"` // 标题
  140 + Summary string `json:"summary"` // 快讯概要
  141 + Time int64 `json:"time"` // 时间
  142 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读
  143 + }
118 MiniUserFollowedSearchRequest{ 144 MiniUserFollowedSearchRequest{
119 Page int `json:"page,optional"` 145 Page int `json:"page,optional"`
120 Size int `json:"size,optional"` 146 Size int `json:"size,optional"`
@@ -123,6 +149,11 @@ type( @@ -123,6 +149,11 @@ type(
123 List []*UserFollowItem `json:"users"` 149 List []*UserFollowItem `json:"users"`
124 Total int64 `json:"total"` 150 Total int64 `json:"total"`
125 } 151 }
  152 +
  153 + MiniUserFollowingMarkReadRequest{
  154 + UserId int64 `json:"userId"`
  155 + }
  156 +
126 UserItem { 157 UserItem {
127 Id int64 `json:"id,omitempty"` // 用户ID 158 Id int64 `json:"id,omitempty"` // 用户ID
128 CompanyId int64 `json:"companyId,omitempty"` // 公司ID 159 CompanyId int64 `json:"companyId,omitempty"` // 公司ID
@@ -176,6 +207,7 @@ type( @@ -176,6 +207,7 @@ type(
176 Position string `json:"position"` // 职位 207 Position string `json:"position"` // 职位
177 Followed bool `json:"followed"` // 关注 208 Followed bool `json:"followed"` // 关注
178 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识 209 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识
  210 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读(小红点)
179 } 211 }
180 ) 212 )
181 213
@@ -229,7 +261,7 @@ service Core { @@ -229,7 +261,7 @@ service Core {
229 post /system/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse) 261 post /system/user/statistics (UserStatisticsRequest) returns (UserStatisticsResponse)
230 @doc "用户列表" 262 @doc "用户列表"
231 @handler systemUsersList 263 @handler systemUsersList
232 - post /system/user/user-list (MiniUsersListRequest) 264 + post /system/user/user_list (MiniUsersListRequest)
233 265
234 @doc "用户详情" 266 @doc "用户详情"
235 @handler systemUserGet 267 @handler systemUserGet
@@ -148,7 +148,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -148,7 +148,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
148 []rest.Route{ 148 []rest.Route{
149 { 149 {
150 Method: http.MethodPost, 150 Method: http.MethodPost,
151 - Path: "/mini/user/apply-join-company", 151 + Path: "/mini/user/apply_join_company",
152 Handler: user.MiniUserApplyJoinCompanyHandler(serverCtx), 152 Handler: user.MiniUserApplyJoinCompanyHandler(serverCtx),
153 }, 153 },
154 { 154 {
@@ -164,7 +164,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -164,7 +164,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
164 []rest.Route{ 164 []rest.Route{
165 { 165 {
166 Method: http.MethodPost, 166 Method: http.MethodPost,
167 - Path: "/mini/user/switch-account", 167 + Path: "/mini/user/switch_account",
168 Handler: user.MiniUserSwitchAccountHandler(serverCtx), 168 Handler: user.MiniUserSwitchAccountHandler(serverCtx),
169 }, 169 },
170 { 170 {
@@ -179,7 +179,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -179,7 +179,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
179 }, 179 },
180 { 180 {
181 Method: http.MethodPost, 181 Method: http.MethodPost,
182 - Path: "/mini/user/audit-list", 182 + Path: "/mini/user/audit_list",
183 Handler: user.MiniUserAuditListHandler(serverCtx), 183 Handler: user.MiniUserAuditListHandler(serverCtx),
184 }, 184 },
185 { 185 {
@@ -189,16 +189,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -189,16 +189,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
189 }, 189 },
190 { 190 {
191 Method: http.MethodPost, 191 Method: http.MethodPost,
192 - Path: "/mini/user/department-users", 192 + Path: "/mini/user/department_users",
193 Handler: user.MiniUserDepartmentUsersHandler(serverCtx), 193 Handler: user.MiniUserDepartmentUsersHandler(serverCtx),
194 }, 194 },
195 { 195 {
196 Method: http.MethodPost, 196 Method: http.MethodPost,
197 - Path: "/mini/user/user-list", 197 + Path: "/mini/user/user_list",
198 Handler: user.MiniUsersListHandler(serverCtx), 198 Handler: user.MiniUsersListHandler(serverCtx),
199 }, 199 },
200 { 200 {
201 Method: http.MethodPost, 201 Method: http.MethodPost,
  202 + Path: "/mini/user/news",
  203 + Handler: user.MiniUserNewsHandler(serverCtx),
  204 + },
  205 + {
  206 + Method: http.MethodPost,
202 Path: "/mini/user/follower", 207 Path: "/mini/user/follower",
203 Handler: user.MiniUserFollowerHandler(serverCtx), 208 Handler: user.MiniUserFollowerHandler(serverCtx),
204 }, 209 },
@@ -209,6 +214,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -209,6 +214,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
209 }, 214 },
210 { 215 {
211 Method: http.MethodPost, 216 Method: http.MethodPost,
  217 + Path: "/mini/user/following/latest_unread_list",
  218 + Handler: user.MiniUserFollowingLatestUnreadListHandler(serverCtx),
  219 + },
  220 + {
  221 + Method: http.MethodPost,
  222 + Path: "/mini/user/following/mark_read",
  223 + Handler: user.MiniUserFollowingMarkReadHandler(serverCtx),
  224 + },
  225 + {
  226 + Method: http.MethodPost,
212 Path: "/mini/user/follow", 227 Path: "/mini/user/follow",
213 Handler: user.MiniUserFollowHandler(serverCtx), 228 Handler: user.MiniUserFollowHandler(serverCtx),
214 }, 229 },
@@ -243,7 +258,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { @@ -243,7 +258,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
243 }, 258 },
244 { 259 {
245 Method: http.MethodPost, 260 Method: http.MethodPost,
246 - Path: "/system/user/user-list", 261 + Path: "/system/user/user_list",
247 Handler: user.SystemUsersListHandler(serverCtx), 262 Handler: user.SystemUsersListHandler(serverCtx),
248 }, 263 },
249 { 264 {
  1 +package user
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/user"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  11 +)
  12 +
  13 +func MiniUserFollowingLatestUnreadListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.MiniUserFollowedSearchRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := user.NewMiniUserFollowingLatestUnreadListLogic(r.Context(), svcCtx)
  22 + resp, err := l.MiniUserFollowingLatestUnreadList(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package user
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/user"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  11 +)
  12 +
  13 +func MiniUserFollowingMarkReadHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.MiniUserFollowingMarkReadRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := user.NewMiniUserFollowingMarkReadLogic(r.Context(), svcCtx)
  22 + resp, err := l.MiniUserFollowingMarkRead(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
  1 +package user
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/result"
  5 + "net/http"
  6 +
  7 + "github.com/zeromicro/go-zero/rest/httpx"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/logic/user"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  10 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  11 +)
  12 +
  13 +func MiniUserNewsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
  14 + return func(w http.ResponseWriter, r *http.Request) {
  15 + var req types.MiniUserNewsRequest
  16 + if err := httpx.Parse(r, &req); err != nil {
  17 + httpx.ErrorCtx(r.Context(), w, err)
  18 + return
  19 + }
  20 +
  21 + l := user.NewMiniUserNewsLogic(r.Context(), svcCtx)
  22 + resp, err := l.MiniUserNews(&req)
  23 + result.HttpResult(r, w, resp, err)
  24 + }
  25 +}
@@ -6,6 +6,7 @@ import ( @@ -6,6 +6,7 @@ import (
6 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain" 6 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
7 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata" 7 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
8 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr" 8 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  9 + "time"
9 10
10 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc" 11 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
11 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types" 12 "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
@@ -32,6 +33,7 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro @@ -32,6 +33,7 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro
32 conn = l.svcCtx.DefaultDBConn() 33 conn = l.svcCtx.DefaultDBConn()
33 user *domain.User 34 user *domain.User
34 targetUser *domain.User 35 targetUser *domain.User
  36 + userFollow *domain.UserFollow
35 userToken = contextdata.GetUserTokenFromCtx(l.ctx) 37 userToken = contextdata.GetUserTokenFromCtx(l.ctx)
36 ) 38 )
37 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil { 39 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil {
@@ -40,6 +42,9 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro @@ -40,6 +42,9 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro
40 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil { 42 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil {
41 return xerr.NewErrMsgErr("关注的用户不存在", err) 43 return xerr.NewErrMsgErr("关注的用户不存在", err)
42 } 44 }
  45 + if userFollow, err = l.svcCtx.UserFollowRepository.FindOneUserFollowing(l.ctx, conn, user.Id, targetUser.Id); err == nil && userFollow != nil {
  46 + return xerr.NewErrMsgErr("用户已关注", err)
  47 + }
43 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error { 48 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
44 if err = user.Follow(targetUser); err != nil { 49 if err = user.Follow(targetUser); err != nil {
45 return err 50 return err
@@ -50,6 +55,14 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro @@ -50,6 +55,14 @@ func (l *MiniUserFollowLogic) MiniUserFollow(req *types.FollowRequest) (err erro
50 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil { 55 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil {
51 return err 56 return err
52 } 57 }
  58 + userFollow = &domain.UserFollow{
  59 + FromUserId: user.Id,
  60 + ToUserId: targetUser.Id,
  61 + LastReadAt: time.Now().Unix(),
  62 + }
  63 + if userFollow, err = l.svcCtx.UserFollowRepository.Insert(ctx, conn, userFollow); err != nil {
  64 + return err
  65 + }
53 return nil 66 return nil
54 }, true); err != nil { 67 }, true); err != nil {
55 return xerr.NewErrMsgErr("关注用户失败", err) 68 return xerr.NewErrMsgErr("关注用户失败", err)
  1 +package user
  2 +
  3 +import (
  4 + "context"
  5 + "github.com/samber/lo"
  6 + "github.com/zeromicro/go-zero/core/collection"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
  9 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  10 +
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  12 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  13 +
  14 + "github.com/zeromicro/go-zero/core/logx"
  15 +)
  16 +
  17 +type MiniUserFollowingLatestUnreadListLogic struct {
  18 + logx.Logger
  19 + ctx context.Context
  20 + svcCtx *svc.ServiceContext
  21 +}
  22 +
  23 +func NewMiniUserFollowingLatestUnreadListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniUserFollowingLatestUnreadListLogic {
  24 + return &MiniUserFollowingLatestUnreadListLogic{
  25 + Logger: logx.WithContext(ctx),
  26 + ctx: ctx,
  27 + svcCtx: svcCtx,
  28 + }
  29 +}
  30 +
  31 +func (l *MiniUserFollowingLatestUnreadListLogic) MiniUserFollowingLatestUnreadList(req *types.MiniUserFollowedSearchRequest) (resp *types.MiniUserFollowedSearchResponse, err error) {
  32 + var (
  33 + conn = l.svcCtx.DefaultDBConn()
  34 + user *domain.User
  35 + userToken = contextdata.GetUserTokenFromCtx(l.ctx)
  36 + limit = 6
  37 + )
  38 + if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil {
  39 + return nil, xerr.NewErrMsgErr("用户不存在", err)
  40 + }
  41 + var (
  42 + users = user.Following
  43 + setUsers = collection.NewSet()
  44 + )
  45 + _, userArticlesUnread, _ := l.svcCtx.ArticleRepository.FindAuthorsLatestFirstUnreadArticle(l.ctx, conn, user.CompanyId, users, user.Id, limit)
  46 + _, userArticlesLatest, _ := l.svcCtx.ArticleRepository.FindAuthorsLatestFirstArticle(l.ctx, conn, user.CompanyId, users, user.Id, limit)
  47 + _, userFollows, _ := l.svcCtx.UserFollowRepository.Find(l.ctx, conn, domain.IndexCompanyId(userToken.CompanyId)().WithKV("fromUserId", user.Id).WithFindOnly())
  48 + resp = &types.MiniUserFollowedSearchResponse{
  49 + Total: int64(len(users)),
  50 + List: make([]*types.UserFollowItem, 0),
  51 + }
  52 + addUser := func(userId int64, readFlag bool) {
  53 + if setUsers.Contains(userId) {
  54 + return
  55 + }
  56 + if len(resp.List) == limit {
  57 + return
  58 + }
  59 + setUsers.Add(userId)
  60 + if foundUser, _ := l.svcCtx.UserRepository.FindOne(l.ctx, conn, userId); foundUser != nil {
  61 + resp.List = append(resp.List, &types.UserFollowItem{
  62 + Id: foundUser.Id,
  63 + Name: foundUser.Name,
  64 + Avatar: foundUser.Avatar,
  65 + Position: foundUser.Position,
  66 + ReadFlag: readFlag,
  67 + })
  68 + }
  69 + return
  70 + }
  71 + userFollowsMap := lo.KeyBy(userFollows, func(item *domain.UserFollow) int64 {
  72 + return item.ToUserId
  73 + })
  74 + lo.ForEach(userArticlesUnread, func(item *domain.Article, index int) {
  75 + var readFlag = true
  76 + if v, ok := userFollowsMap[item.AuthorId]; ok && v.LastReadAt < item.CreatedAt {
  77 + readFlag = false
  78 + }
  79 + addUser(item.AuthorId, readFlag)
  80 + })
  81 + lo.ForEach(userArticlesLatest, func(item *domain.Article, index int) {
  82 + addUser(item.AuthorId, true)
  83 + })
  84 + lo.ForEach(users, func(item int64, index int) {
  85 + addUser(item, true)
  86 + })
  87 + return
  88 +}
  1 +package user
  2 +
  3 +import (
  4 + "context"
  5 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/db/transaction"
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/interanl/pkg/domain"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/contextdata"
  8 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/pkg/xerr"
  9 + "time"
  10 +
  11 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  12 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  13 +
  14 + "github.com/zeromicro/go-zero/core/logx"
  15 +)
  16 +
  17 +type MiniUserFollowingMarkReadLogic struct {
  18 + logx.Logger
  19 + ctx context.Context
  20 + svcCtx *svc.ServiceContext
  21 +}
  22 +
  23 +func NewMiniUserFollowingMarkReadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniUserFollowingMarkReadLogic {
  24 + return &MiniUserFollowingMarkReadLogic{
  25 + Logger: logx.WithContext(ctx),
  26 + ctx: ctx,
  27 + svcCtx: svcCtx,
  28 + }
  29 +}
  30 +
  31 +func (l *MiniUserFollowingMarkReadLogic) MiniUserFollowingMarkRead(req *types.MiniUserFollowingMarkReadRequest) (resp interface{}, err error) {
  32 + var (
  33 + conn = l.svcCtx.DefaultDBConn()
  34 + user *domain.User
  35 + userFollow *domain.UserFollow
  36 + userToken = contextdata.GetUserTokenFromCtx(l.ctx)
  37 + )
  38 + if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil {
  39 + return nil, xerr.NewErrMsgErr("用户不存在", err)
  40 + }
  41 + if userFollow, err = l.svcCtx.UserFollowRepository.FindOneUserFollowing(l.ctx, conn, userToken.UserId, user.Id); err != nil {
  42 + return nil, xerr.NewErrMsgErr("用户还未关注", err)
  43 + }
  44 + if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
  45 + userFollow.LastReadAt = time.Now().Unix()
  46 + if userFollow, err = l.svcCtx.UserFollowRepository.UpdateWithVersion(ctx, conn, userFollow); err != nil {
  47 + return err
  48 + }
  49 + return nil
  50 + }, true); err != nil {
  51 + return nil, xerr.NewErrMsgErr("关注用户标记已读失败", err)
  52 + }
  53 + resp = struct{}{}
  54 + return
  55 +}
  1 +package user
  2 +
  3 +import (
  4 + "context"
  5 +
  6 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/svc"
  7 + "gitlab.fjmaimaimai.com/allied-creation/sumifcc-discuss/cmd/discuss/api/internal/types"
  8 +
  9 + "github.com/zeromicro/go-zero/core/logx"
  10 +)
  11 +
  12 +type MiniUserNewsLogic struct {
  13 + logx.Logger
  14 + ctx context.Context
  15 + svcCtx *svc.ServiceContext
  16 +}
  17 +
  18 +func NewMiniUserNewsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MiniUserNewsLogic {
  19 + return &MiniUserNewsLogic{
  20 + Logger: logx.WithContext(ctx),
  21 + ctx: ctx,
  22 + svcCtx: svcCtx,
  23 + }
  24 +}
  25 +
  26 +func (l *MiniUserNewsLogic) MiniUserNews(req *types.MiniUserNewsRequest) (resp *types.MiniUserNewsResposne, err error) {
  27 + // todo: add your logic here and delete this line
  28 +
  29 + return
  30 +}
@@ -32,6 +32,7 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err @@ -32,6 +32,7 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err
32 conn = l.svcCtx.DefaultDBConn() 32 conn = l.svcCtx.DefaultDBConn()
33 user *domain.User 33 user *domain.User
34 targetUser *domain.User 34 targetUser *domain.User
  35 + userFollow *domain.UserFollow
35 userToken = contextdata.GetUserTokenFromCtx(l.ctx) 36 userToken = contextdata.GetUserTokenFromCtx(l.ctx)
36 ) 37 )
37 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil { 38 if user, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, userToken.UserId); err != nil {
@@ -40,6 +41,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err @@ -40,6 +41,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err
40 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil { 41 if targetUser, err = l.svcCtx.UserRepository.FindOne(l.ctx, conn, req.UserId); err != nil {
41 return xerr.NewErrMsgErr("关注的用户不存在", err) 42 return xerr.NewErrMsgErr("关注的用户不存在", err)
42 } 43 }
  44 + if userFollow, err = l.svcCtx.UserFollowRepository.FindOneUserFollowing(l.ctx, conn, user.Id, targetUser.Id); err != nil {
  45 + return xerr.NewErrMsgErr("用户还未关注", err)
  46 + }
43 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error { 47 if err = transaction.UseTrans(l.ctx, l.svcCtx.DB, func(ctx context.Context, conn transaction.Conn) error {
44 if err = user.Unfollow(targetUser); err != nil { 48 if err = user.Unfollow(targetUser); err != nil {
45 return err 49 return err
@@ -50,6 +54,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err @@ -50,6 +54,9 @@ func (l *MiniUserUnFollowLogic) MiniUserUnFollow(req *types.FollowRequest) (err
50 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil { 54 if targetUser, err = l.svcCtx.UserRepository.UpdateWithVersion(ctx, conn, targetUser); err != nil {
51 return err 55 return err
52 } 56 }
  57 + if userFollow, err = l.svcCtx.UserFollowRepository.Delete(ctx, conn, userFollow); err != nil {
  58 + return err
  59 + }
53 return nil 60 return nil
54 }, true); err != nil { 61 }, true); err != nil {
55 return xerr.NewErrMsgErr("关注用户失败", err) 62 return xerr.NewErrMsgErr("关注用户失败", err)
@@ -440,6 +440,26 @@ type MiniUsersListRequest struct { @@ -440,6 +440,26 @@ type MiniUsersListRequest struct {
440 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户 440 RoleId int64 `json:"roleId,optional"` // 按角色角色关联的用户
441 } 441 }
442 442
  443 +type MiniUserNewsRequest struct {
  444 + AuthorId int64 `json:"authorId,optional"` // 特定作者ID
  445 + LastArticleId int64 `json:"lastArticleId,optional"` // 最后文章ID
  446 + Size int `json:"size"` // 数量
  447 +}
  448 +
  449 +type MiniUserNewsResposne struct {
  450 + List []UserNewsItem `json:"list"`
  451 + Total int64 `json:"total"`
  452 +}
  453 +
  454 +type UserNewsItem struct {
  455 + NewsId int64 `json:"newsId"` // 快讯ID
  456 + Type string `json:"type"` // 快讯类型 文章:Article 讨论:Discuss ...
  457 + Title string `json:"title"` // 标题
  458 + Summary string `json:"summary"` // 快讯概要
  459 + Time int64 `json:"time"` // 时间
  460 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读
  461 +}
  462 +
443 type MiniUserFollowedSearchRequest struct { 463 type MiniUserFollowedSearchRequest struct {
444 Page int `json:"page,optional"` 464 Page int `json:"page,optional"`
445 Size int `json:"size,optional"` 465 Size int `json:"size,optional"`
@@ -450,6 +470,10 @@ type MiniUserFollowedSearchResponse struct { @@ -450,6 +470,10 @@ type MiniUserFollowedSearchResponse struct {
450 Total int64 `json:"total"` 470 Total int64 `json:"total"`
451 } 471 }
452 472
  473 +type MiniUserFollowingMarkReadRequest struct {
  474 + UserId int64 `json:"userId"`
  475 +}
  476 +
453 type UserItem struct { 477 type UserItem struct {
454 Id int64 `json:"id,omitempty"` // 用户ID 478 Id int64 `json:"id,omitempty"` // 用户ID
455 CompanyId int64 `json:"companyId,omitempty"` // 公司ID 479 CompanyId int64 `json:"companyId,omitempty"` // 公司ID
@@ -507,6 +531,7 @@ type UserFollowItem struct { @@ -507,6 +531,7 @@ type UserFollowItem struct {
507 Position string `json:"position"` // 职位 531 Position string `json:"position"` // 职位
508 Followed bool `json:"followed"` // 关注 532 Followed bool `json:"followed"` // 关注
509 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识 533 MutualFollowed bool `json:"mutualFollowed"` // 互相关注标识
  534 + ReadFlag bool `json:"readFlag"` // 已读标识 true:已读 false:未读(小红点)
510 } 535 }
511 536
512 type MiniMyLikeRequest struct { 537 type MiniMyLikeRequest struct {
@@ -9,12 +9,14 @@ import ( @@ -9,12 +9,14 @@ import (
9 ) 9 )
10 10
11 type UserFollow struct { 11 type UserFollow struct {
12 - Id int64 // 唯一标识  
13 -  
14 - CreatedAt int64 `json:"createdAt,omitempty"`  
15 - UpdatedAt int64 `json:"updatedAt,omitempty"`  
16 - DeletedAt int64 `json:"deletedAt,omitempty"`  
17 - Version int `json:"version,omitempty"` 12 + Id int64 // 唯一标识
  13 + FromUserId int64
  14 + ToUserId int64
  15 + LastReadAt int64
  16 + CreatedAt int64
  17 + UpdatedAt int64
  18 + DeletedAt int64
  19 + Version int
18 } 20 }
19 21
20 func (m *UserFollow) TableName() string { 22 func (m *UserFollow) TableName() string {
@@ -157,6 +157,127 @@ func (repository *ArticleRepository) Find(ctx context.Context, conn transaction. @@ -157,6 +157,127 @@ func (repository *ArticleRepository) Find(ctx context.Context, conn transaction.
157 return total, dms, nil 157 return total, dms, nil
158 } 158 }
159 159
  160 +// FindAuthorsLatestArticle 作者最新的文章
  161 +func (repository *ArticleRepository) FindAuthorsLatestArticle(ctx context.Context, conn transaction.Conn,
  162 + companyId int64, authors []int64, whoRead int64, lastId int64, limit int) (int64, []*domain.Article, error) {
  163 + var (
  164 + tx = conn.DB()
  165 + ms []*models.Article
  166 + dms = make([]*domain.Article, 0)
  167 + total int64
  168 + )
  169 + queryFunc := func() (interface{}, error) {
  170 + tx = tx.Model(&ms).
  171 + Where("id < ?", lastId).
  172 + Where("company_id=?", companyId).
  173 + Where("author_id in (?)", authors).
  174 + Where("target_user=0 or who_read @>'[?]'", whoRead).
  175 + Where("show = 1").
  176 + Order("id desc")
  177 + if limit > 0 {
  178 + tx.Limit(limit)
  179 + }
  180 + if total, tx = transaction.PaginationAndCount(ctx, tx, domain.NewQueryOptions().WithFindOnly(), &ms); tx.Error != nil {
  181 + return dms, tx.Error
  182 + }
  183 + return dms, nil
  184 + }
  185 +
  186 + if _, err := repository.Query(queryFunc); err != nil {
  187 + return 0, nil, err
  188 + }
  189 +
  190 + for _, item := range ms {
  191 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  192 + return 0, dms, err
  193 + } else {
  194 + dms = append(dms, dm)
  195 + }
  196 + }
  197 + return total, dms, nil
  198 +}
  199 +
  200 +// FindAuthorsLatestFirstArticle 作者最新的第一篇文章
  201 +func (repository *ArticleRepository) FindAuthorsLatestFirstArticle(ctx context.Context, conn transaction.Conn,
  202 + companyId int64, authors []int64, whoRead int64, limit int) (int64, []*domain.Article, error) {
  203 + var (
  204 + tx = conn.DB()
  205 + ms []*models.Article
  206 + dms = make([]*domain.Article, 0)
  207 + total int64
  208 + )
  209 + queryFunc := func() (interface{}, error) {
  210 + tx = tx.Model(&ms).Select("max(id) id", "max(author_id) author_id", "max(created_at) created_at").
  211 + Where("company_id=?", companyId).
  212 + Where("author_id in (?)", authors).
  213 + Where("target_user=0 or who_read @>'[?]'", whoRead).
  214 + Where("show = 1").
  215 + Group("author_id").
  216 + Order("id desc")
  217 + if limit > 0 {
  218 + tx.Limit(limit)
  219 + }
  220 + if total, tx = transaction.PaginationAndCount(ctx, tx, domain.NewQueryOptions().WithFindOnly(), &ms); tx.Error != nil {
  221 + return dms, tx.Error
  222 + }
  223 + return dms, nil
  224 + }
  225 +
  226 + if _, err := repository.Query(queryFunc); err != nil {
  227 + return 0, nil, err
  228 + }
  229 +
  230 + for _, item := range ms {
  231 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  232 + return 0, dms, err
  233 + } else {
  234 + dms = append(dms, dm)
  235 + }
  236 + }
  237 + return total, dms, nil
  238 +}
  239 +
  240 +// FindAuthorsLatestFirstUnreadArticle 作者最新的第一篇未读文章
  241 +func (repository *ArticleRepository) FindAuthorsLatestFirstUnreadArticle(ctx context.Context, conn transaction.Conn,
  242 + companyId int64, authors []int64, whoRead int64, limit int) (int64, []*domain.Article, error) {
  243 + var (
  244 + tx = conn.DB()
  245 + ms []*models.Article
  246 + dms = make([]*domain.Article, 0)
  247 + total int64
  248 + )
  249 + queryFunc := func() (interface{}, error) {
  250 + tx = tx.Model(&ms).Select("max(id) id", "max(author_id) author_id", "max(created_at) created_at").
  251 + Where("company_id=?", companyId).
  252 + Where("author_id in (?)", authors).
  253 + Where("target_user=0 or who_read @>'[?]'", whoRead).
  254 + Where("show = 1").
  255 + Where("id not in (select article_id from user_read_article where user_id = ?)", whoRead).
  256 + Group("author_id").
  257 + Order("id desc")
  258 + if limit > 0 {
  259 + tx.Limit(limit)
  260 + }
  261 + if total, tx = transaction.PaginationAndCount(ctx, tx, domain.NewQueryOptions().WithFindOnly(), &ms); tx.Error != nil {
  262 + return dms, tx.Error
  263 + }
  264 + return dms, nil
  265 + }
  266 +
  267 + if _, err := repository.Query(queryFunc); err != nil {
  268 + return 0, nil, err
  269 + }
  270 +
  271 + for _, item := range ms {
  272 + if dm, err := repository.ModelToDomainModel(item); err != nil {
  273 + return 0, dms, err
  274 + } else {
  275 + dms = append(dms, dm)
  276 + }
  277 + }
  278 + return total, dms, nil
  279 +}
  280 +
160 func (repository *ArticleRepository) ModelToDomainModel(from *models.Article) (*domain.Article, error) { 281 func (repository *ArticleRepository) ModelToDomainModel(from *models.Article) (*domain.Article, error) {
161 to := &domain.Article{ 282 to := &domain.Article{
162 Id: from.Id, 283 Id: from.Id,
@@ -111,6 +111,26 @@ func (repository *UserFollowRepository) FindOne(ctx context.Context, conn transa @@ -111,6 +111,26 @@ func (repository *UserFollowRepository) FindOne(ctx context.Context, conn transa
111 return repository.ModelToDomainModel(m) 111 return repository.ModelToDomainModel(m)
112 } 112 }
113 113
  114 +func (repository *UserFollowRepository) FindOneUserFollowing(ctx context.Context, conn transaction.Conn, userId int64, followingId int64) (*domain.UserFollow, error) {
  115 + var (
  116 + err error
  117 + tx = conn.DB()
  118 + m = new(models.UserFollow)
  119 + )
  120 + queryFunc := func() (interface{}, error) {
  121 + tx = tx.Model(m).Where("from_user_id = ?", userId).Where("to_user_id = ?", followingId).First(m)
  122 + if errors.Is(tx.Error, gorm.ErrRecordNotFound) {
  123 + return nil, domain.ErrNotFound
  124 + }
  125 + return m, tx.Error
  126 + }
  127 + cacheModel := new(models.UserFollow)
  128 + if err = repository.QueryCache(cacheModel.CacheKeyFunc, m, queryFunc); err != nil {
  129 + return nil, err
  130 + }
  131 + return repository.ModelToDomainModel(m)
  132 +}
  133 +
114 func (repository *UserFollowRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.UserFollow, error) { 134 func (repository *UserFollowRepository) Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*domain.UserFollow, error) {
115 var ( 135 var (
116 tx = conn.DB() 136 tx = conn.DB()
@@ -120,6 +140,12 @@ func (repository *UserFollowRepository) Find(ctx context.Context, conn transacti @@ -120,6 +140,12 @@ func (repository *UserFollowRepository) Find(ctx context.Context, conn transacti
120 ) 140 )
121 queryFunc := func() (interface{}, error) { 141 queryFunc := func() (interface{}, error) {
122 tx = tx.Model(&ms).Order("id desc") 142 tx = tx.Model(&ms).Order("id desc")
  143 + if v, ok := queryOptions["fromUserId"]; ok {
  144 + tx.Where("from_user_id = ?", v)
  145 + }
  146 + if v, ok := queryOptions["toUserIds"]; ok {
  147 + tx.Where("to_user_id in (?)", v)
  148 + }
123 if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil { 149 if total, tx = transaction.PaginationAndCount(ctx, tx, queryOptions, &ms); tx.Error != nil {
124 return dms, tx.Error 150 return dms, tx.Error
125 } 151 }
@@ -38,6 +38,8 @@ type ArticleRepository interface { @@ -38,6 +38,8 @@ type ArticleRepository interface {
38 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *Article) (*Article, error) 38 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *Article) (*Article, error)
39 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*Article, error) 39 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*Article, error)
40 Find(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*Article, error) 40 Find(ctx context.Context, conn transaction.Conn, companyId int64, queryOptions map[string]interface{}) (int64, []*Article, error)
  41 + FindAuthorsLatestFirstArticle(ctx context.Context, conn transaction.Conn, companyId int64, authors []int64, whoRead int64, limit int) (int64, []*Article, error)
  42 + FindAuthorsLatestFirstUnreadArticle(ctx context.Context, conn transaction.Conn, companyId int64, authors []int64, whoRead int64, limit int) (int64, []*Article, error)
41 IncreaseCountLove(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //点赞数量变动 43 IncreaseCountLove(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //点赞数量变动
42 IncreaseCountComment(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //评论数量变动 44 IncreaseCountComment(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //评论数量变动
43 IncreaseCountRead(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //浏览数量变动 45 IncreaseCountRead(ctx context.Context, conn transaction.Conn, incr int, articleId int64) error //浏览数量变动
@@ -7,8 +7,9 @@ import ( @@ -7,8 +7,9 @@ import (
7 7
8 type UserFollow struct { 8 type UserFollow struct {
9 Id int64 `json:"id,omitempty"` // 唯一标识 9 Id int64 `json:"id,omitempty"` // 唯一标识
10 - FromUserId int64 `json:"fromUserId,omitempty"` /// 发起关注的人  
11 - ToUserId int64 `json:"toUserId,omitempty"` /// 被关注的人 10 + FromUserId int64 `json:"fromUserId,omitempty"` // 发起关注的人
  11 + ToUserId int64 `json:"toUserId,omitempty"` // 被关注的人
  12 + LastReadAt int64 `json:"lastReadAt,omitempty"` // 上一次读取信息时间
12 CreatedAt int64 `json:"createdAt,omitempty"` 13 CreatedAt int64 `json:"createdAt,omitempty"`
13 UpdatedAt int64 `json:"updatedAt,omitempty"` 14 UpdatedAt int64 `json:"updatedAt,omitempty"`
14 DeletedAt int64 `json:"deletedAt,omitempty"` 15 DeletedAt int64 `json:"deletedAt,omitempty"`
@@ -21,6 +22,7 @@ type UserFollowRepository interface { @@ -21,6 +22,7 @@ type UserFollowRepository interface {
21 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error) 22 UpdateWithVersion(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error)
22 Delete(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error) 23 Delete(ctx context.Context, conn transaction.Conn, dm *UserFollow) (*UserFollow, error)
23 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*UserFollow, error) 24 FindOne(ctx context.Context, conn transaction.Conn, id int64) (*UserFollow, error)
  25 + FindOneUserFollowing(ctx context.Context, conn transaction.Conn, userId int64, followingId int64) (*UserFollow, error)
24 Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*UserFollow, error) 26 Find(ctx context.Context, conn transaction.Conn, queryOptions map[string]interface{}) (int64, []*UserFollow, error)
25 } 27 }
26 28