add follow/unfollow user support in index page

pull/391/head
Michael Li 1 year ago
parent 56d856f50c
commit 2274d128b4
No known key found for this signature in database

@ -76,6 +76,7 @@ All notable changes to paopao-ce are documented in this file.
```sql ```sql
ALTER TABLE `p_comment` ADD COLUMN `is_essence` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否精选'; ALTER TABLE `p_comment` ADD COLUMN `is_essence` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否精选';
``` ```
- add follow/unfollow user support in index page.
## 0.4.2 ## 0.4.2

@ -4,6 +4,7 @@ go 1.20
require ( require (
github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/semver/v3 v3.2.1
github.com/RoaringBitmap/roaring v1.5.0
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868
github.com/alimy/mir/v4 v4.0.0 github.com/alimy/mir/v4 v4.0.0
github.com/alimy/tryst v0.8.3 github.com/alimy/tryst v0.8.3
@ -54,6 +55,7 @@ require (
require ( require (
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/clbanning/mxj v1.8.4 // indirect github.com/clbanning/mxj v1.8.4 // indirect
@ -106,6 +108,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mozillazg/go-httpheader v0.2.1 // indirect github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pyroscope-io/godeltaprof v0.1.2 // indirect github.com/pyroscope-io/godeltaprof v0.1.2 // indirect

@ -112,6 +112,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/RoaringBitmap/roaring v1.5.0 h1:V0VCSiHjroItEYCM3guC8T83ehi5QMt3oM9EefTTOms=
github.com/RoaringBitmap/roaring v1.5.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 h1:uFrPOl1VBt/Abfl2z+A/DFc+AwmFLxEHR1+Yq6cXvww= github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868 h1:uFrPOl1VBt/Abfl2z+A/DFc+AwmFLxEHR1+Yq6cXvww=
github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868/go.mod h1:srphKZ1i+yGXxl/LpBS7ZIECTjCTPzZzAMtJWoG3sLo= github.com/afocus/captcha v0.0.0-20191010092841-4bd1f21c8868/go.mod h1:srphKZ1i+yGXxl/LpBS7ZIECTjCTPzZzAMtJWoG3sLo=
@ -178,6 +180,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
@ -986,6 +989,8 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=

@ -29,6 +29,8 @@ const (
PrefixUserInfo = "paopao:userinfo:" PrefixUserInfo = "paopao:userinfo:"
PrefixUserInfoById = "paopao:userinfo:id:" PrefixUserInfoById = "paopao:userinfo:id:"
PrefixUserInfoByName = "paopao:userinfo:name:" PrefixUserInfoByName = "paopao:userinfo:name:"
PrefixMyFriendIds = "paopao:myfriendids:"
PrefixMyFollowIds = "paopao:myfollowids:"
KeySiteStatus = "paopao:sitestatus" KeySiteStatus = "paopao:sitestatus"
KeyHistoryMaxOnline = "history.max.online" KeyHistoryMaxOnline = "history.max.online"
) )
@ -42,6 +44,8 @@ var (
KeyOnlineUser cache.KeyPool[int64] KeyOnlineUser cache.KeyPool[int64]
KeyUserInfoById cache.KeyPool[int64] KeyUserInfoById cache.KeyPool[int64]
KeyUserInfoByName cache.KeyPool[string] KeyUserInfoByName cache.KeyPool[string]
KeyMyFriendIds cache.KeyPool[int64]
KeyMyFollowIds cache.KeyPool[int64]
) )
func initCacheKeyPool() { func initCacheKeyPool() {
@ -56,6 +60,8 @@ func initCacheKeyPool() {
KeyOnlineUser = intKeyPool[int64](poolSize, PrefixOnlineUser) KeyOnlineUser = intKeyPool[int64](poolSize, PrefixOnlineUser)
KeyUserInfoById = intKeyPool[int64](poolSize, PrefixUserInfoById) KeyUserInfoById = intKeyPool[int64](poolSize, PrefixUserInfoById)
KeyUserInfoByName = strKeyPool(poolSize, PrefixUserInfoById) KeyUserInfoByName = strKeyPool(poolSize, PrefixUserInfoById)
KeyMyFriendIds = intKeyPool[int64](poolSize, PrefixMyFriendIds)
KeyMyFollowIds = intKeyPool[int64](poolSize, PrefixMyFollowIds)
} }
func strKeyPool(size int, prefix string) cache.KeyPool[string] { func strKeyPool(size int, prefix string) cache.KeyPool[string] {

@ -34,6 +34,7 @@ type DataService interface {
UserManageService UserManageService
ContactManageService ContactManageService
FollowingManageService FollowingManageService
UserRelationService
// 安全服务 // 安全服务
SecurityService SecurityService

@ -37,3 +37,11 @@ type FollowingManageService interface {
GetFollowCount(userId int64) (int64, int64, error) GetFollowCount(userId int64) (int64, int64, error)
IsFollow(userId int64, followId int64) bool IsFollow(userId int64, followId int64) bool
} }
// UserRelationService 用户关系服务
type UserRelationService interface {
MyFriendIds(userId int64) ([]int64, error)
MyFollowIds(userId int64) ([]int64, error)
IsMyFriend(userId int64, friendIds []int64) (map[int64]bool, error)
IsMyFollow(userId int64, followIds []int64) (map[int64]bool, error)
}

@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"github.com/RoaringBitmap/roaring/roaring64"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
@ -59,3 +60,47 @@ func (s *cacheDataService) GetUserByUsername(username string) (res *ms.User, err
} }
return return
} }
func (s *cacheDataService) IsMyFriend(userId int64, friendIds []int64) (res map[int64]bool, err error) {
size := len(friendIds)
res = make(map[int64]bool, size)
if size == 0 {
return
}
// 从缓存中获取
key := conf.KeyMyFriendIds.Get(userId)
if data, xerr := s.ac.Get(key); xerr == nil {
bitmap := roaring64.New()
if err = bitmap.UnmarshalBinary(data); err == nil {
for _, friendId := range friendIds {
res[friendId] = bitmap.Contains(uint64(friendId))
}
return
}
}
// 直接查库并触发缓存更新事件
OnCacheMyFriendIdsEvent(s.DataService, userId)
return s.DataService.IsMyFriend(userId, friendIds)
}
func (s *cacheDataService) IsMyFollow(userId int64, followIds []int64) (res map[int64]bool, err error) {
size := len(followIds)
res = make(map[int64]bool, size)
if size == 0 {
return
}
// 从缓存中获取
key := conf.KeyMyFollowIds.Get(userId)
if data, xerr := s.ac.Get(key); xerr == nil {
bitmap := roaring64.New()
if err = bitmap.UnmarshalBinary(data); err == nil {
for _, followId := range followIds {
res[followId] = bitmap.Contains(uint64(followId))
}
return
}
}
// 直接查库并触发缓存更新事件
OnCacheMyFollowIdsEvent(s.DataService, userId, key)
return s.DataService.IsMyFollow(userId, followIds)
}

@ -9,23 +9,23 @@ import (
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"github.com/RoaringBitmap/roaring/roaring64"
"github.com/alimy/tryst/event" "github.com/alimy/tryst/event"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/events" "github.com/rocboss/paopao-ce/internal/events"
"github.com/sirupsen/logrus"
) )
type expireIndexTweetsEvent struct { type expireIndexTweetsEvent struct {
event.UnimplementedEvent event.UnimplementedEvent
tweet *ms.Post
ac core.AppCache ac core.AppCache
keysPattern []string keysPattern []string
} }
type expireHotsTweetsEvent struct { type expireHotsTweetsEvent struct {
event.UnimplementedEvent event.UnimplementedEvent
tweet *ms.Post
ac core.AppCache ac core.AppCache
keyPattern string keyPattern string
} }
@ -46,21 +46,34 @@ type cacheUserInfoEvent struct {
expire int64 expire int64
} }
func onExpireIndexTweetEvent(tweet *ms.Post) { type cacheMyFriendIdsEvent struct {
event.UnimplementedEvent
ac core.AppCache
urs core.UserRelationService
userIds []int64
}
type cacheMyFollowIdsEvent struct {
event.UnimplementedEvent
ac core.AppCache
urs core.UserRelationService
userId int64
key string
}
func OnExpireIndexTweetEvent(userId int64) {
events.OnEvent(&expireIndexTweetsEvent{ events.OnEvent(&expireIndexTweetsEvent{
tweet: tweet,
ac: _appCache, ac: _appCache,
keysPattern: []string{ keysPattern: []string{
conf.PrefixIdxTweetsNewest + "*", conf.PrefixIdxTweetsNewest + "*",
conf.PrefixIdxTweetsHots + "*", conf.PrefixIdxTweetsHots + "*",
fmt.Sprintf("%s%d:*", conf.PrefixUserTweets, tweet.UserID), fmt.Sprintf("%s%d:*", conf.PrefixUserTweets, userId),
}, },
}) })
} }
func onExpireHotsTweetEvent(tweet *ms.Post) { func OnExpireHotsTweetEvent() {
events.OnEvent(&expireHotsTweetsEvent{ events.OnEvent(&expireHotsTweetsEvent{
tweet: tweet,
ac: _appCache, ac: _appCache,
keyPattern: conf.PrefixHotsTweets + "*", keyPattern: conf.PrefixHotsTweets + "*",
}) })
@ -83,6 +96,32 @@ func onCacheUserInfoEvent(key string, data *ms.User) {
}) })
} }
func OnCacheMyFriendIdsEvent(urs core.UserRelationService, userIds ...int64) {
if len(userIds) == 0 {
return
}
events.OnEvent(&cacheMyFriendIdsEvent{
userIds: userIds,
urs: urs,
ac: _appCache,
})
}
func OnCacheMyFollowIdsEvent(urs core.UserRelationService, userId int64, key ...string) {
cacheKey := ""
if len(key) > 0 {
cacheKey = key[0]
} else {
cacheKey = conf.KeyMyFollowIds.Get(userId)
}
events.OnEvent(&cacheMyFollowIdsEvent{
userId: userId,
urs: urs,
key: cacheKey,
ac: _appCache,
})
}
func (e *expireIndexTweetsEvent) Name() string { func (e *expireIndexTweetsEvent) Name() string {
return "expireIndexTweetsEvent" return "expireIndexTweetsEvent"
} }
@ -127,3 +166,49 @@ func (e *cacheUserInfoEvent) Action() (err error) {
} }
return return
} }
func (e *cacheMyFriendIdsEvent) Name() string {
return "cacheMyFriendIdsEvent"
}
func (e *cacheMyFriendIdsEvent) Action() error {
logrus.Debug("cacheMyFriendIdsEvent action runnging")
for _, userId := range e.userIds {
myFriendIds, err := e.urs.MyFriendIds(userId)
if err != nil {
return err
}
bitmap := roaring64.New()
for _, friendId := range myFriendIds {
bitmap.Add(uint64(friendId))
}
data, err := bitmap.MarshalBinary()
if err != nil {
return err
}
e.ac.Set(conf.KeyMyFriendIds.Get(userId), data, 0)
}
return nil
}
func (e *cacheMyFollowIdsEvent) Name() string {
return "cacheMyFollowIdsEvent"
}
func (e *cacheMyFollowIdsEvent) Action() (err error) {
logrus.Debug("cacheMyFollowIdsEvent action runnging")
myFollowIds, err := e.urs.MyFollowIds(e.userId)
if err != nil {
return err
}
bitmap := roaring64.New()
for _, followId := range myFollowIds {
bitmap.Add(uint64(followId))
}
data, err := bitmap.MarshalBinary()
if err != nil {
return err
}
e.ac.Set(e.key, data, 0)
return nil
}

@ -26,15 +26,15 @@ func (s *eventCacheIndexSrv) SendAction(act core.IdxAct, post *ms.Post) {
CollectionCount: post.CollectionCount, CollectionCount: post.CollectionCount,
ShareCount: post.ShareCount, ShareCount: post.ShareCount,
}) })
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
case core.IdxActCreatePost: case core.IdxActCreatePost:
err = s.tms.AddTweetMetric(post.ID) err = s.tms.AddTweetMetric(post.ID)
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
case core.IdxActDeletePost: case core.IdxActDeletePost:
err = s.tms.DeleteTweetMetric(post.ID) err = s.tms.DeleteTweetMetric(post.ID)
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
case core.IdxActStickPost, core.IdxActVisiblePost: case core.IdxActStickPost, core.IdxActVisiblePost:
onExpireIndexTweetEvent(post) OnExpireIndexTweetEvent(post.UserID)
} }
if err != nil { if err != nil {
logrus.Errorf("eventCacheIndexSrv.SendAction(%s) occurs error: %s", act, err) logrus.Errorf("eventCacheIndexSrv.SendAction(%s) occurs error: %s", act, err)

@ -34,6 +34,8 @@ type UserFormated struct {
Status int `json:"status"` Status int `json:"status"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
IsAdmin bool `json:"is_admin"` IsAdmin bool `json:"is_admin"`
IsFriend bool `json:"is_friend"`
IsFollowing bool `json:"is_following"`
} }
func (u *User) Format() *UserFormated { func (u *User) Format() *UserFormated {

@ -41,6 +41,7 @@ type dataSrv struct {
core.UserManageService core.UserManageService
core.ContactManageService core.ContactManageService
core.FollowingManageService core.FollowingManageService
core.UserRelationService
core.SecurityService core.SecurityService
core.AttachmentCheckService core.AttachmentCheckService
} }
@ -71,6 +72,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
UserManageService: newUserManageService(db), UserManageService: newUserManageService(db),
ContactManageService: newContactManageService(db), ContactManageService: newContactManageService(db),
FollowingManageService: newFollowingManageService(db), FollowingManageService: newFollowingManageService(db),
UserRelationService: newUserRelationService(db),
SecurityService: newSecurityService(db, pvs), SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(), AttachmentCheckService: security.NewAttachmentCheckService(),
} }

@ -21,12 +21,22 @@ type userManageSrv struct {
db *gorm.DB db *gorm.DB
} }
type userRelationSrv struct {
db *gorm.DB
}
func newUserManageService(db *gorm.DB) core.UserManageService { func newUserManageService(db *gorm.DB) core.UserManageService {
return &userManageSrv{ return &userManageSrv{
db: db, db: db,
} }
} }
func newUserRelationService(db *gorm.DB) core.UserRelationService {
return &userRelationSrv{
db: db,
}
}
func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) { func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) {
user := &dbr.User{ user := &dbr.User{
Model: &dbr.Model{ Model: &dbr.Model{
@ -83,3 +93,57 @@ func (s *userManageSrv) GetRegisterUserCount() (res int64, err error) {
err = s.db.Model(&dbr.User{}).Count(&res).Error err = s.db.Model(&dbr.User{}).Count(&res).Error
return return
} }
func (s *userRelationSrv) MyFriendIds(userId int64) (res []int64, err error) {
err = s.db.Table(_contact_).Where("user_id=?", userId).Select("friend_id").Find(&res).Error
return
}
func (s *userRelationSrv) MyFollowIds(userId int64) (res []int64, err error) {
err = s.db.Table(_following_).Where("user_id=?", userId).Select("follow_id").Find(&res).Error
return
}
func (s *userRelationSrv) IsMyFriend(userId int64, friendIds []int64) (map[int64]bool, error) {
size := len(friendIds)
res := make(map[int64]bool, size)
if size == 0 {
return res, nil
}
myFriendIds, err := s.MyFriendIds(userId)
if err != nil {
return nil, err
}
for _, friendId := range friendIds {
res[friendId] = false
for _, myFriendId := range myFriendIds {
if friendId == myFriendId {
res[friendId] = true
break
}
}
}
return res, nil
}
func (s *userRelationSrv) IsMyFollow(userId int64, followIds []int64) (map[int64]bool, error) {
size := len(followIds)
res := make(map[int64]bool, size)
if size == 0 {
return res, nil
}
myFollowIds, err := s.MyFollowIds(userId)
if err != nil {
return nil, err
}
for _, followId := range followIds {
res[followId] = false
for _, myFollowId := range myFollowIds {
if followId == myFollowId {
res[followId] = true
break
}
}
}
return res, nil
}

@ -24,6 +24,7 @@ import (
"github.com/rocboss/paopao-ce/internal/events" "github.com/rocboss/paopao-ce/internal/events"
"github.com/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/pkg/app" "github.com/rocboss/paopao-ce/pkg/app"
"github.com/rocboss/paopao-ce/pkg/types"
"github.com/rocboss/paopao-ce/pkg/xerror" "github.com/rocboss/paopao-ce/pkg/xerror"
) )
@ -172,6 +173,36 @@ func (s *BaseServant) Render(c *gin.Context, data any, err mir.Error) {
} }
} }
func (s *DaoServant) PrepareTweets(userId int64, tweets []*ms.PostFormated) error {
userIdSet := make(map[int64]types.Empty, len(tweets))
for _, tweet := range tweets {
userIdSet[tweet.UserID] = types.Empty{}
// 顺便转换一下可见性的值
tweet.Visibility = ms.PostVisibleT(tweet.Visibility.ToOutValue())
}
// guest用户的userId<0
if userId < 0 {
return nil
}
userIds := make([]int64, 0, len(userIdSet))
for id := range userIdSet {
userIds = append(userIds, id)
}
// friendMap, err := s.Ds.IsMyFriend(userId, userIds)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, userIds)
if err != nil {
return err
}
for _, tweet := range tweets {
// tweet.User.IsFriend, tweet.User.IsFollowing = friendMap[tweet.UserID], followMap[tweet.UserID]
tweet.User.IsFollowing = followMap[tweet.UserID]
}
return nil
}
func (s *DaoServant) GetTweetBy(id int64) (*ms.PostFormated, error) { func (s *DaoServant) GetTweetBy(id int64) (*ms.PostFormated, error) {
post, err := s.Ds.GetPostByID(id) post, err := s.Ds.GetPostByID(id)
if err != nil { if err != nil {
@ -278,15 +309,6 @@ func (s *DaoServant) DeleteSearchPost(post *ms.Post) error {
return s.Ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)}) return s.Ts.DeleteDocuments([]string{fmt.Sprintf("%d", post.ID)})
} }
func (s *DaoServant) GetTweetList(conditions ms.ConditionsT, offset, limit int) ([]*ms.Post, []*ms.PostFormated, error) {
posts, err := s.Ds.GetPosts(conditions, offset, limit)
if err != nil {
return nil, nil, err
}
postFormated, err := s.Ds.MergePosts(posts)
return posts, postFormated, err
}
func (s *DaoServant) RelationTypFrom(me *ms.User, username string) (res *cs.VistUser, err error) { func (s *DaoServant) RelationTypFrom(me *ms.User, username string) (res *cs.VistUser, err error) {
res = &cs.VistUser{ res = &cs.VistUser{
RelTyp: cs.RelationSelf, RelTyp: cs.RelationSelf,

@ -8,6 +8,7 @@ import (
"github.com/alimy/mir/v4" "github.com/alimy/mir/v4"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
api "github.com/rocboss/paopao-ce/auto/api/v1" api "github.com/rocboss/paopao-ce/auto/api/v1"
"github.com/rocboss/paopao-ce/internal/dao/cache"
"github.com/rocboss/paopao-ce/internal/model/web" "github.com/rocboss/paopao-ce/internal/model/web"
"github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/internal/servants/chain" "github.com/rocboss/paopao-ce/internal/servants/chain"
@ -84,6 +85,9 @@ func (s *followshipSrv) UnfollowUser(r *web.UnfollowUserReq) mir.Error {
logrus.Errorf("Ds.UnfollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId) logrus.Errorf("Ds.UnfollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId)
return web.ErrUnfollowUserFailed return web.ErrUnfollowUserFailed
} }
// 触发缓存更新事件
cache.OnCacheMyFollowIdsEvent(s.Ds, r.User.ID)
cache.OnExpireIndexTweetEvent(r.User.ID)
return nil return nil
} }
@ -97,6 +101,9 @@ func (s *followshipSrv) FollowUser(r *web.FollowUserReq) mir.Error {
logrus.Errorf("Ds.FollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId) logrus.Errorf("Ds.FollowUser err: %s userId: %d followId: %d", err, r.User.ID, r.UserId)
return web.ErrUnfollowUserFailed return web.ErrUnfollowUserFailed
} }
// 触发缓存更新事件
cache.OnCacheMyFollowIdsEvent(s.Ds, r.User.ID)
cache.OnExpireIndexTweetEvent(r.User.ID)
return nil return nil
} }

@ -55,6 +55,8 @@ func (s *friendshipSrv) DeleteFriend(req *web.DeleteFriendReq) mir.Error {
logrus.Errorf("Ds.DeleteFriend err: %s", err) logrus.Errorf("Ds.DeleteFriend err: %s", err)
return web.ErrDeleteFriendFailed return web.ErrDeleteFriendFailed
} }
// 触发用户关系缓存更新事件
// cache.OnCacheMyFriendIdsEvent(s.Ds, req.User.ID, req.UserId)
return nil return nil
} }
@ -89,6 +91,8 @@ func (s *friendshipSrv) AddFriend(req *web.AddFriendReq) mir.Error {
logrus.Errorf("Ds.AddFriend err: %s", err) logrus.Errorf("Ds.AddFriend err: %s", err)
return web.ErrAddFriendFailed return web.ErrAddFriendFailed
} }
// 触发用户关系缓存更新事件
// cache.OnCacheMyFriendIdsEvent(s.Ds, req.User.ID, req.UserId)
return nil return nil
} }

@ -61,8 +61,14 @@ func (s *looseSrv) Timeline(req *web.TimelineReq) (*web.TimelineResp, mir.Error)
logrus.Errorf("Ds.RevampPosts err: %s", err) logrus.Errorf("Ds.RevampPosts err: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(posts) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, posts); err != nil {
logrus.Errorf("timeline occurs error[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(posts, req.Page, req.PageSize, res.Total) resp := joint.PageRespFrom(posts, req.Page, req.PageSize, res.Total)
return &web.TimelineResp{ return &web.TimelineResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
@ -98,7 +104,7 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
return nil, web.ErrGetPostsUnknowStyle return nil, web.ErrGetPostsUnknowStyle
} }
if xerr != nil { if xerr != nil {
logrus.Errorf("getIndexTweets occurs error: %s", xerr) logrus.Errorf("getIndexTweets occurs error[1]: %s", xerr)
return nil, web.ErrGetPostFailed return nil, web.ErrGetPostFailed
} }
postsFormated, verr := s.Ds.MergePosts(posts) postsFormated, verr := s.Ds.MergePosts(posts)
@ -106,8 +112,14 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
logrus.Errorf("getIndexTweets in merge posts occurs error: %s", verr) logrus.Errorf("getIndexTweets in merge posts occurs error: %s", verr)
return nil, web.ErrGetPostFailed return nil, web.ErrGetPostFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postsFormated) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("getIndexTweets occurs error[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total) resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
// 缓存处理 // 缓存处理
base.OnCacheRespEvent(s.ac, key, resp, s.idxTweetsExpire) base.OnCacheRespEvent(s.ac, key, resp, s.idxTweetsExpire)
@ -198,7 +210,7 @@ func (s *looseSrv) userTweetsFromCache(req *web.GetUserTweetsReq, user *cs.VistU
func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUser) (*web.GetUserTweetsResp, mir.Error) { func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUser) (*web.GetUserTweetsResp, mir.Error) {
stars, totalRows, err := s.Ds.ListUserStarTweets(user, req.PageSize, (req.Page-1)*req.PageSize) stars, totalRows, err := s.Ds.ListUserStarTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
if err != nil { if err != nil {
logrus.Errorf("Ds.GetUserPostStars err: %s", err) logrus.Errorf("getUserStarTweets err[1]: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
var posts []*ms.Post var posts []*ms.Post
@ -212,8 +224,14 @@ func (s *looseSrv) getUserStarTweets(req *web.GetUserTweetsReq, user *cs.VistUse
logrus.Errorf("Ds.MergePosts err: %s", err) logrus.Errorf("Ds.MergePosts err: %s", err)
return nil, web.ErrGetStarsFailed return nil, web.ErrGetStarsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postsFormated) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("getUserStarTweets err[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows) resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
@ -233,21 +251,27 @@ func (s *looseSrv) listUserTweets(req *web.GetUserTweetsReq, user *cs.VistUser)
} else if req.Style == web.UserPostsStyleMedia { } else if req.Style == web.UserPostsStyleMedia {
tweets, total, err = s.Ds.ListUserMediaTweets(user, req.PageSize, (req.Page-1)*req.PageSize) tweets, total, err = s.Ds.ListUserMediaTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
} else { } else {
logrus.Errorf("s.listUserTweets unknow style: %s", req.Style) logrus.Errorf("s.listUserTweets unknow style[1]: %s", req.Style)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
if err != nil { if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err) logrus.Errorf("s.listUserTweets err[2]: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
postFormated, err := s.Ds.MergePosts(tweets) postsFormated, err := s.Ds.MergePosts(tweets)
if err != nil { if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err) logrus.Errorf("s.listUserTweets err[3]: %s", err)
return nil, web.ErrGetPostsFailed
}
userId := int64(-1)
if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("s.listUserTweets err[4]: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
visbleTansform(postFormated)
resp := joint.PageRespFrom(postFormated, req.Page, req.PageSize, total)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
Data: resp, Data: resp,
@ -281,8 +305,14 @@ func (s *looseSrv) getUserPostTweets(req *web.GetUserTweetsReq, user *cs.VistUse
logrus.Errorf("s.GetTweetList error[2]: %s", err) logrus.Errorf("s.GetTweetList error[2]: %s", err)
return nil, web.ErrGetPostsFailed return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postsFormated) if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("s.GetTweetList error[3]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total) resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{

@ -209,7 +209,7 @@ func checkPermision(user *ms.User, targetUserId int64) mir.Error {
} }
// visbleTansform 可见性等价转换,暂时处理方式,后续需要去掉这个步骤 // visbleTansform 可见性等价转换,暂时处理方式,后续需要去掉这个步骤
func visbleTansform(list []*ms.PostFormated) { func _visbleTansform(list []*ms.PostFormated) {
for _, post := range list { for _, post := range list {
post.Visibility = ms.PostVisibleT(post.Visibility.ToOutValue()) post.Visibility = ms.PostVisibleT(post.Visibility.ToOutValue())
} }

@ -1 +1 @@
import{_ as s}from"./main-nav.vue_vue_type_style_index_0_lang-e2b1e404.js";import{u as i}from"./vue-router-e5a2430e.js";import{F as a,e as c,a2 as u}from"./naive-ui-609478ed.js";import{d as l,f as d,k as t,w as o,e as f,A as x}from"./@vue-a481fc63.js";import{_ as g}from"./index-ac7904e2.js";import"./vuex-44de225f.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-4ed09704.js";import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./@css-render-7124a1a5.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */const v=l({__name:"404",setup(h){const e=i(),_=()=>{e.push({path:"/"})};return(k,w)=>{const n=s,p=c,r=u,m=a;return f(),d("div",null,[t(n,{title:"404"}),t(m,{class:"main-content-wrap wrap404",bordered:""},{default:o(()=>[t(r,{status:"404",title:"404 资源不存在",description:"再看看其他的吧"},{footer:o(()=>[t(p,{onClick:_},{default:o(()=>[x("回主页")]),_:1})]),_:1})]),_:1})])}}});const O=g(v,[["__scopeId","data-v-e62daa85"]]);export{O as default}; import{_ as s}from"./main-nav.vue_vue_type_style_index_0_lang-832ff0ed.js";import{u as i}from"./vue-router-e5a2430e.js";import{G as a,e as c,a2 as u}from"./naive-ui-defd0b2d.js";import{d as l,f as d,k as t,w as o,e as f,A as x}from"./@vue-a481fc63.js";import{_ as g}from"./index-537a241d.js";import"./vuex-44de225f.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-4ed09704.js";import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./@css-render-7124a1a5.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */const v=l({__name:"404",setup(h){const e=i(),_=()=>{e.push({path:"/"})};return(k,w)=>{const n=s,p=c,r=u,m=a;return f(),d("div",null,[t(n,{title:"404"}),t(m,{class:"main-content-wrap wrap404",bordered:""},{default:o(()=>[t(r,{status:"404",title:"404 资源不存在",description:"再看看其他的吧"},{footer:o(()=>[t(p,{onClick:_},{default:o(()=>[x("回主页")]),_:1})]),_:1})]),_:1})])}}});const O=g(v,[["__scopeId","data-v-e62daa85"]]);export{O as default};

@ -0,0 +1 @@
import{_ as N}from"./post-skeleton-5d89319a.js";import{_ as R}from"./main-nav.vue_vue_type_style_index_0_lang-832ff0ed.js";import{u as z}from"./vuex-44de225f.js";import{b as A}from"./vue-router-e5a2430e.js";import{H as F,_ as H}from"./index-537a241d.js";import{G as S,R as V,J as q,H as P}from"./naive-ui-defd0b2d.js";import{d as j,H as n,b as D,f as o,k as a,w as p,e as t,bf as u,Y as l,F as E,u as G,q as I,j as s,x as _,l as J}from"./@vue-a481fc63.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-4ed09704.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./@css-render-7124a1a5.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const L={key:0,class:"pagination-wrap"},M={key:0,class:"skeleton-wrap"},O={key:1},T={key:0,class:"empty-wrap"},U={class:"bill-line"},Y=j({__name:"Anouncement",setup($){const d=z(),g=A(),v=n(!1),i=n([]),r=n(+g.query.p||1),f=n(20),c=n(0),h=m=>{r.value=m};return D(()=>{}),(m,K)=>{const k=R,y=V,x=N,w=q,B=P,C=S;return t(),o("div",null,[a(k,{title:"公告"}),a(C,{class:"main-content-wrap",bordered:""},{footer:p(()=>[c.value>1?(t(),o("div",L,[a(y,{page:r.value,"onUpdate:page":h,"page-slot":u(d).state.collapsedRight?5:8,"page-count":c.value},null,8,["page","page-slot","page-count"])])):l("",!0)]),default:p(()=>[v.value?(t(),o("div",M,[a(x,{num:f.value},null,8,["num"])])):(t(),o("div",O,[i.value.length===0?(t(),o("div",T,[a(w,{size:"large",description:"暂无数据"})])):l("",!0),(t(!0),o(E,null,G(i.value,e=>(t(),I(B,{key:e.id},{default:p(()=>[s("div",U,[s("div",null,"NO."+_(e.id),1),s("div",null,_(e.reason),1),s("div",{class:J({income:e.change_amount>=0,out:e.change_amount<0})},_((e.change_amount>0?"+":"")+(e.change_amount/100).toFixed(2)),3),s("div",null,_(u(F)(e.created_on)),1)])]),_:2},1024))),128))]))]),_:1})])}}});const ke=H(Y,[["__scopeId","data-v-d4d04859"]]);export{ke as default};

@ -1 +0,0 @@
import{_ as C}from"./post-skeleton-32ed3219.js";import{_ as N}from"./main-nav.vue_vue_type_style_index_0_lang-e2b1e404.js";import{u as z}from"./vuex-44de225f.js";import{b as A}from"./vue-router-e5a2430e.js";import{F as R,_ as S}from"./index-ac7904e2.js";import{F as V,Q as q,I,G as P}from"./naive-ui-609478ed.js";import{d as j,H as n,b as D,f as o,k as a,w as p,e as t,bf as u,Y as l,F as E,u as G,q as H,j as s,x as _,l as L}from"./@vue-a481fc63.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-4ed09704.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./@css-render-7124a1a5.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const M={key:0,class:"pagination-wrap"},O={key:0,class:"skeleton-wrap"},Q={key:1},T={key:0,class:"empty-wrap"},U={class:"bill-line"},Y=j({__name:"Anouncement",setup($){const d=z(),g=A(),v=n(!1),i=n([]),r=n(+g.query.p||1),f=n(20),c=n(0),h=m=>{r.value=m};return D(()=>{}),(m,J)=>{const k=N,y=q,x=C,w=I,F=P,B=V;return t(),o("div",null,[a(k,{title:"公告"}),a(B,{class:"main-content-wrap",bordered:""},{footer:p(()=>[c.value>1?(t(),o("div",M,[a(y,{page:r.value,"onUpdate:page":h,"page-slot":u(d).state.collapsedRight?5:8,"page-count":c.value},null,8,["page","page-slot","page-count"])])):l("",!0)]),default:p(()=>[v.value?(t(),o("div",O,[a(x,{num:f.value},null,8,["num"])])):(t(),o("div",Q,[i.value.length===0?(t(),o("div",T,[a(w,{size:"large",description:"暂无数据"})])):l("",!0),(t(!0),o(E,null,G(i.value,e=>(t(),H(F,{key:e.id},{default:p(()=>[s("div",U,[s("div",null,"NO."+_(e.id),1),s("div",null,_(e.reason),1),s("div",{class:L({income:e.change_amount>=0,out:e.change_amount<0})},_((e.change_amount>0?"+":"")+(e.change_amount/100).toFixed(2)),3),s("div",null,_(u(R)(e.created_on)),1)])]),_:2},1024))),128))]))]),_:1})])}}});const ke=S(Y,[["__scopeId","data-v-d4d04859"]]);export{ke as default};

@ -1 +1 @@
import{_ as I}from"./whisper-b4b61448.js";import{_ as N,a as V}from"./post-item.vue_vue_type_style_index_0_lang-60ae03c7.js";import{_ as W}from"./post-skeleton-32ed3219.js";import{_ as E}from"./main-nav.vue_vue_type_style_index_0_lang-e2b1e404.js";import{u as G}from"./vuex-44de225f.js";import{b as H}from"./vue-router-e5a2430e.js";import{R as L,_ as Q}from"./index-ac7904e2.js";import{d as T,H as s,b as U,f as o,k as n,w as u,bf as h,Y as w,e,F as k,u as y,q as C}from"./@vue-a481fc63.js";import{F as Y,Q as j,I as A,G as D}from"./naive-ui-609478ed.js";import"./content-3f086a36.js";import"./@vicons-4ed09704.js";import"./paopao-video-player-2fe58954.js";import"./copy-to-clipboard-4ef7d3eb.js";import"./@babel-725317a4.js";import"./toggle-selection-93f4ad84.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./@css-render-7124a1a5.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const J={key:0,class:"skeleton-wrap"},K={key:1},O={key:0,class:"empty-wrap"},X={key:1},Z={key:2},ee={key:0,class:"pagination-wrap"},oe=T({__name:"Collection",setup(te){const m=G(),S=H(),_=s(!1),i=s([]),l=s(+S.query.p||1),p=s(20),r=s(0),c=s(!1),d=s({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),f=t=>{d.value=t,c.value=!0},b=()=>{c.value=!1},v=()=>{_.value=!0,L({page:l.value,page_size:p.value}).then(t=>{_.value=!1,i.value=t.list,r.value=Math.ceil(t.pager.total_rows/p.value),window.scrollTo(0,0)}).catch(t=>{_.value=!1})},x=t=>{l.value=t,v()};return U(()=>{v()}),(t,ne)=>{const R=E,$=W,z=A,B=N,g=D,F=V,M=I,P=Y,q=j;return e(),o("div",null,[n(R,{title:"收藏"}),n(P,{class:"main-content-wrap",bordered:""},{default:u(()=>[_.value?(e(),o("div",J,[n($,{num:p.value},null,8,["num"])])):(e(),o("div",K,[i.value.length===0?(e(),o("div",O,[n(z,{size:"large",description:"暂无数据"})])):w("",!0),h(m).state.desktopModelShow?(e(),o("div",X,[(e(!0),o(k,null,y(i.value,a=>(e(),C(g,{key:a.id},{default:u(()=>[n(B,{post:a,onSendWhisper:f},null,8,["post"])]),_:2},1024))),128))])):(e(),o("div",Z,[(e(!0),o(k,null,y(i.value,a=>(e(),C(g,{key:a.id},{default:u(()=>[n(F,{post:a,onSendWhisper:f},null,8,["post"])]),_:2},1024))),128))]))])),n(M,{show:c.value,user:d.value,onSuccess:b},null,8,["show","user"])]),_:1}),r.value>0?(e(),o("div",ee,[n(q,{page:l.value,"onUpdate:page":x,"page-slot":h(m).state.collapsedRight?5:8,"page-count":r.value},null,8,["page","page-slot","page-count"])])):w("",!0)])}}});const Ne=Q(oe,[["__scopeId","data-v-760779af"]]);export{Ne as default}; import{_ as H}from"./whisper-7c8226c3.js";import{_ as N,a as V}from"./post-item.vue_vue_type_style_index_0_lang-1243f33f.js";import{_ as W}from"./post-skeleton-5d89319a.js";import{_ as E}from"./main-nav.vue_vue_type_style_index_0_lang-832ff0ed.js";import{u as G}from"./vuex-44de225f.js";import{b as I}from"./vue-router-e5a2430e.js";import{R as J,_ as L}from"./index-537a241d.js";import{d as T,H as s,b as U,f as o,k as n,w as u,bf as h,Y as w,e,F as k,u as y,q as C}from"./@vue-a481fc63.js";import{G as Y,R as j,J as A,H as D}from"./naive-ui-defd0b2d.js";import"./content-f21e8034.js";import"./@vicons-4ed09704.js";import"./paopao-video-player-2fe58954.js";import"./copy-to-clipboard-4ef7d3eb.js";import"./@babel-725317a4.js";import"./toggle-selection-93f4ad84.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./@css-render-7124a1a5.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const K={key:0,class:"skeleton-wrap"},O={key:1},Q={key:0,class:"empty-wrap"},X={key:1},Z={key:2},ee={key:0,class:"pagination-wrap"},oe=T({__name:"Collection",setup(te){const m=G(),S=I(),_=s(!1),i=s([]),l=s(+S.query.p||1),p=s(20),r=s(0),c=s(!1),d=s({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),f=t=>{d.value=t,c.value=!0},b=()=>{c.value=!1},v=()=>{_.value=!0,J({page:l.value,page_size:p.value}).then(t=>{_.value=!1,i.value=t.list,r.value=Math.ceil(t.pager.total_rows/p.value),window.scrollTo(0,0)}).catch(t=>{_.value=!1})},x=t=>{l.value=t,v()};return U(()=>{v()}),(t,ne)=>{const R=E,$=W,z=A,B=N,g=D,M=V,P=H,q=Y,F=j;return e(),o("div",null,[n(R,{title:"收藏"}),n(q,{class:"main-content-wrap",bordered:""},{default:u(()=>[_.value?(e(),o("div",K,[n($,{num:p.value},null,8,["num"])])):(e(),o("div",O,[i.value.length===0?(e(),o("div",Q,[n(z,{size:"large",description:"暂无数据"})])):w("",!0),h(m).state.desktopModelShow?(e(),o("div",X,[(e(!0),o(k,null,y(i.value,a=>(e(),C(g,{key:a.id},{default:u(()=>[n(B,{post:a,onSendWhisper:f},null,8,["post"])]),_:2},1024))),128))])):(e(),o("div",Z,[(e(!0),o(k,null,y(i.value,a=>(e(),C(g,{key:a.id},{default:u(()=>[n(M,{post:a,onSendWhisper:f},null,8,["post"])]),_:2},1024))),128))]))])),n(P,{show:c.value,user:d.value,onSuccess:b},null,8,["show","user"])]),_:1}),r.value>0?(e(),o("div",ee,[n(F,{page:l.value,"onUpdate:page":x,"page-slot":h(m).state.collapsedRight?5:8,"page-count":r.value},null,8,["page","page-slot","page-count"])])):w("",!0)])}}});const Ne=L(oe,[["__scopeId","data-v-760779af"]]);export{Ne as default};

@ -1 +1 @@
import{_ as T}from"./whisper-b4b61448.js";import{d as M,c as j,r as A,e as s,f as c,k as t,w as n,j as _,y as G,A as H,x as v,bf as g,h as I,H as a,b as U,Y as S,F as z,u as W,q as E}from"./@vue-a481fc63.js";import{G as L,_ as N,b as Q}from"./index-ac7904e2.js";import{k as Y,r as J}from"./@vicons-4ed09704.js";import{j as x,o as K,e as X,O as Z,M as ee,F as te,Q as ne,I as oe,G as se}from"./naive-ui-609478ed.js";import{_ as ae}from"./post-skeleton-32ed3219.js";import{_ as ce}from"./main-nav.vue_vue_type_style_index_0_lang-e2b1e404.js";import{u as _e}from"./vuex-44de225f.js";import{b as ie}from"./vue-router-e5a2430e.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./evtd-b614532e.js";import"./@css-render-7124a1a5.js";import"./vooks-6d99783e.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const re={class:"contact-item"},le={class:"nickname-wrap"},pe={class:"username-wrap"},ue={class:"user-info"},me={class:"info-item"},de={class:"info-item"},fe={class:"item-header-extra"},ve=M({__name:"contact-item",props:{contact:{}},emits:["send-whisper"],setup(C,{emit:h}){const i=C,r=e=>()=>I(x,null,{default:()=>I(e)}),l=j(()=>[{label:"私信",key:"whisper",icon:r(J)}]),u=e=>{switch(e){case"whisper":const o={id:i.contact.user_id,avatar:i.contact.avatar,username:i.contact.username,nickname:i.contact.nickname,is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1};h("send-whisper",o);break}};return(e,o)=>{const m=K,d=A("router-link"),w=X,k=Z,y=ee;return s(),c("div",re,[t(y,{"content-indented":""},{avatar:n(()=>[t(m,{size:54,src:e.contact.avatar},null,8,["src"])]),header:n(()=>[_("span",le,[t(d,{onClick:o[0]||(o[0]=G(()=>{},["stop"])),class:"username-link",to:{name:"user",query:{s:e.contact.username}}},{default:n(()=>[H(v(e.contact.nickname),1)]),_:1},8,["to"])]),_("span",pe," @"+v(e.contact.username),1),_("div",ue,[_("span",me," UID. "+v(e.contact.user_id),1),_("span",de,v(g(L)(e.contact.created_on))+" 加入 ",1)])]),"header-extra":n(()=>[_("div",fe,[t(k,{placement:"bottom-end",trigger:"click",size:"small",options:l.value,onSelect:u},{default:n(()=>[t(w,{quaternary:"",circle:""},{icon:n(()=>[t(g(x),null,{default:n(()=>[t(g(Y))]),_:1})]),_:1})]),_:1},8,["options"])])]),_:1})])}}});const ge=N(ve,[["__scopeId","data-v-d62f19da"]]),he={key:0,class:"skeleton-wrap"},we={key:1},ke={key:0,class:"empty-wrap"},ye={key:0,class:"pagination-wrap"},Ce=M({__name:"Contacts",setup(C){const h=_e(),i=ie(),r=a(!1),l=a([]),u=a(+i.query.p||1),e=a(20),o=a(0),m=a(!1),d=a({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),w=p=>{d.value=p,m.value=!0},k=()=>{m.value=!1},y=p=>{u.value=p,$()};U(()=>{$()});const $=(p=!1)=>{l.value.length===0&&(r.value=!0),Q({page:u.value,page_size:e.value}).then(f=>{r.value=!1,l.value=f.list,o.value=Math.ceil(f.pager.total_rows/e.value),p&&setTimeout(()=>{window.scrollTo(0,99999)},50)}).catch(f=>{r.value=!1})};return(p,f)=>{const q=ce,B=ae,F=oe,P=ge,V=se,D=T,O=te,R=ne;return s(),c(z,null,[_("div",null,[t(q,{title:"好友"}),t(O,{class:"main-content-wrap",bordered:""},{default:n(()=>[r.value?(s(),c("div",he,[t(B,{num:e.value},null,8,["num"])])):(s(),c("div",we,[l.value.length===0?(s(),c("div",ke,[t(F,{size:"large",description:"暂无数据"})])):S("",!0),(s(!0),c(z,null,W(l.value,b=>(s(),E(V,{class:"list-item",key:b.user_id},{default:n(()=>[t(P,{contact:b,onSendWhisper:w},null,8,["contact"])]),_:2},1024))),128))])),t(D,{show:m.value,user:d.value,onSuccess:k},null,8,["show","user"])]),_:1})]),o.value>0?(s(),c("div",ye,[t(R,{page:u.value,"onUpdate:page":y,"page-slot":g(h).state.collapsedRight?5:8,"page-count":o.value},null,8,["page","page-slot","page-count"])])):S("",!0)],64)}}});const Qe=N(Ce,[["__scopeId","data-v-e20fef94"]]);export{Qe as default}; import{_ as O}from"./whisper-7c8226c3.js";import{d as N,c as T,r as j,e as s,f as c,k as t,w as n,j as _,y as A,A as U,x as v,bf as g,h as I,H as a,b as W,Y as S,F as z,u as E,q as G}from"./@vue-a481fc63.js";import{I as J,_ as P,b as L}from"./index-537a241d.js";import{k as Y,r as K}from"./@vicons-4ed09704.js";import{j as x,o as Q,e as X,P as Z,O as ee,G as te,R as ne,J as oe,H as se}from"./naive-ui-defd0b2d.js";import{_ as ae}from"./post-skeleton-5d89319a.js";import{_ as ce}from"./main-nav.vue_vue_type_style_index_0_lang-832ff0ed.js";import{u as _e}from"./vuex-44de225f.js";import{b as ie}from"./vue-router-e5a2430e.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./evtd-b614532e.js";import"./@css-render-7124a1a5.js";import"./vooks-6d99783e.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const re={class:"contact-item"},le={class:"nickname-wrap"},pe={class:"username-wrap"},ue={class:"user-info"},me={class:"info-item"},de={class:"info-item"},fe={class:"item-header-extra"},ve=N({__name:"contact-item",props:{contact:{}},emits:["send-whisper"],setup(C,{emit:h}){const i=C,r=e=>()=>I(x,null,{default:()=>I(e)}),l=T(()=>[{label:"私信",key:"whisper",icon:r(K)}]),u=e=>{switch(e){case"whisper":const o={id:i.contact.user_id,avatar:i.contact.avatar,username:i.contact.username,nickname:i.contact.nickname,is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1};h("send-whisper",o);break}};return(e,o)=>{const m=Q,d=j("router-link"),w=X,k=Z,y=ee;return s(),c("div",re,[t(y,{"content-indented":""},{avatar:n(()=>[t(m,{size:54,src:e.contact.avatar},null,8,["src"])]),header:n(()=>[_("span",le,[t(d,{onClick:o[0]||(o[0]=A(()=>{},["stop"])),class:"username-link",to:{name:"user",query:{s:e.contact.username}}},{default:n(()=>[U(v(e.contact.nickname),1)]),_:1},8,["to"])]),_("span",pe," @"+v(e.contact.username),1),_("div",ue,[_("span",me," UID. "+v(e.contact.user_id),1),_("span",de,v(g(J)(e.contact.created_on))+" 加入 ",1)])]),"header-extra":n(()=>[_("div",fe,[t(k,{placement:"bottom-end",trigger:"click",size:"small",options:l.value,onSelect:u},{default:n(()=>[t(w,{quaternary:"",circle:""},{icon:n(()=>[t(g(x),null,{default:n(()=>[t(g(Y))]),_:1})]),_:1})]),_:1},8,["options"])])]),_:1})])}}});const ge=P(ve,[["__scopeId","data-v-d62f19da"]]),he={key:0,class:"skeleton-wrap"},we={key:1},ke={key:0,class:"empty-wrap"},ye={key:0,class:"pagination-wrap"},Ce=N({__name:"Contacts",setup(C){const h=_e(),i=ie(),r=a(!1),l=a([]),u=a(+i.query.p||1),e=a(20),o=a(0),m=a(!1),d=a({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),w=p=>{d.value=p,m.value=!0},k=()=>{m.value=!1},y=p=>{u.value=p,$()};W(()=>{$()});const $=(p=!1)=>{l.value.length===0&&(r.value=!0),L({page:u.value,page_size:e.value}).then(f=>{r.value=!1,l.value=f.list,o.value=Math.ceil(f.pager.total_rows/e.value),p&&setTimeout(()=>{window.scrollTo(0,99999)},50)}).catch(f=>{r.value=!1})};return(p,f)=>{const q=ce,B=ae,M=oe,R=ge,V=se,D=O,F=te,H=ne;return s(),c(z,null,[_("div",null,[t(q,{title:"好友"}),t(F,{class:"main-content-wrap",bordered:""},{default:n(()=>[r.value?(s(),c("div",he,[t(B,{num:e.value},null,8,["num"])])):(s(),c("div",we,[l.value.length===0?(s(),c("div",ke,[t(M,{size:"large",description:"暂无数据"})])):S("",!0),(s(!0),c(z,null,E(l.value,b=>(s(),G(V,{class:"list-item",key:b.user_id},{default:n(()=>[t(R,{contact:b,onSendWhisper:w},null,8,["contact"])]),_:2},1024))),128))])),t(D,{show:m.value,user:d.value,onSuccess:k},null,8,["show","user"])]),_:1})]),o.value>0?(s(),c("div",ye,[t(H,{page:u.value,"onUpdate:page":y,"page-slot":g(h).state.collapsedRight?5:8,"page-count":o.value},null,8,["page","page-slot","page-count"])])):S("",!0)],64)}}});const Le=P(Ce,[["__scopeId","data-v-e20fef94"]]);export{Le as default};

File diff suppressed because one or more lines are too long

@ -1 +1 @@
.compose-wrap{width:100%;padding:16px;box-sizing:border-box}.compose-wrap .compose-line{display:flex;flex-direction:row}.compose-wrap .compose-line .compose-user{width:42px;height:42px;display:flex;align-items:center}.compose-wrap .compose-line.compose-options{margin-top:6px;padding-left:42px;display:flex;justify-content:space-between}.compose-wrap .compose-line.compose-options .submit-wrap{display:flex;align-items:center}.compose-wrap .compose-line.compose-options .submit-wrap .text-statistic{margin-right:8px;width:20px;height:20px;transform:rotate(180deg)}.compose-wrap .link-wrap{margin-left:42px;margin-right:42px}.compose-wrap .eye-wrap{margin-left:64px}.compose-wrap .login-only-wrap{display:flex;justify-content:center;width:100%}.compose-wrap .login-only-wrap button{margin:0 4px;width:50%}.compose-wrap .login-wrap{display:flex;justify-content:center;width:100%}.compose-wrap .login-wrap .login-banner{margin-bottom:12px;opacity:.8}.compose-wrap .login-wrap button{margin:0 4px}.attachment-list-wrap{margin-top:12px;margin-left:42px}.attachment-list-wrap .n-upload-file-info__thumbnail{overflow:hidden}.dark .compose-wrap{background-color:#101014bf}.tiny-slide-bar .tiny-slide-bar__list>div.tiny-slide-bar__select .slide-bar-item .slide-bar-item-title[data-v-b0cbbdc2]{color:#18a058;opacity:.8}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item[data-v-b0cbbdc2]{cursor:pointer}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-avatar[data-v-b0cbbdc2]{color:#18a058;opacity:.8}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-title[data-v-b0cbbdc2]{color:#18a058;opacity:.8}.tiny-slide-bar[data-v-b0cbbdc2]{margin-top:-30px;margin-bottom:-30px}.tiny-slide-bar .slide-bar-item[data-v-b0cbbdc2]{min-height:170px;width:64px;display:flex;flex-direction:column;justify-content:center;align-items:center;margin-top:8px}.tiny-slide-bar .slide-bar-item .slide-bar-item-title[data-v-b0cbbdc2]{justify-content:center;font-size:12px;margin-top:4px;height:40px}.load-more[data-v-b0cbbdc2]{margin:20px}.load-more .load-more-wrap[data-v-b0cbbdc2]{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:14px}.load-more .load-more-wrap .load-more-spinner[data-v-b0cbbdc2]{font-size:14px;opacity:.65}.dark .main-content-wrap[data-v-b0cbbdc2],.dark .pagination-wrap[data-v-b0cbbdc2],.dark .empty-wrap[data-v-b0cbbdc2],.dark .skeleton-wrap[data-v-b0cbbdc2]{background-color:#101014bf}.dark .tiny-slide-bar .tiny-slide-bar__list>div.tiny-slide-bar__select .slide-bar-item .slide-bar-item-title[data-v-b0cbbdc2]{color:#63e2b7;opacity:.8}.dark .tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-title[data-v-b0cbbdc2]{color:#63e2b7;opacity:.8} .compose-wrap{width:100%;padding:16px;box-sizing:border-box}.compose-wrap .compose-line{display:flex;flex-direction:row}.compose-wrap .compose-line .compose-user{width:42px;height:42px;display:flex;align-items:center}.compose-wrap .compose-line.compose-options{margin-top:6px;padding-left:42px;display:flex;justify-content:space-between}.compose-wrap .compose-line.compose-options .submit-wrap{display:flex;align-items:center}.compose-wrap .compose-line.compose-options .submit-wrap .text-statistic{margin-right:8px;width:20px;height:20px;transform:rotate(180deg)}.compose-wrap .link-wrap{margin-left:42px;margin-right:42px}.compose-wrap .eye-wrap{margin-left:64px}.compose-wrap .login-only-wrap{display:flex;justify-content:center;width:100%}.compose-wrap .login-only-wrap button{margin:0 4px;width:50%}.compose-wrap .login-wrap{display:flex;justify-content:center;width:100%}.compose-wrap .login-wrap .login-banner{margin-bottom:12px;opacity:.8}.compose-wrap .login-wrap button{margin:0 4px}.attachment-list-wrap{margin-top:12px;margin-left:42px}.attachment-list-wrap .n-upload-file-info__thumbnail{overflow:hidden}.dark .compose-wrap{background-color:#101014bf}.tiny-slide-bar .tiny-slide-bar__list>div.tiny-slide-bar__select .slide-bar-item .slide-bar-item-title[data-v-aee71446]{color:#18a058;opacity:.8}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item[data-v-aee71446]{cursor:pointer}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-avatar[data-v-aee71446]{color:#18a058;opacity:.8}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-title[data-v-aee71446]{color:#18a058;opacity:.8}.tiny-slide-bar[data-v-aee71446]{margin-top:-30px;margin-bottom:-30px}.tiny-slide-bar .slide-bar-item[data-v-aee71446]{min-height:170px;width:64px;display:flex;flex-direction:column;justify-content:center;align-items:center;margin-top:8px}.tiny-slide-bar .slide-bar-item .slide-bar-item-title[data-v-aee71446]{justify-content:center;font-size:12px;margin-top:4px;height:40px}.load-more[data-v-aee71446]{margin:20px}.load-more .load-more-wrap[data-v-aee71446]{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:14px}.load-more .load-more-wrap .load-more-spinner[data-v-aee71446]{font-size:14px;opacity:.65}.dark .main-content-wrap[data-v-aee71446],.dark .pagination-wrap[data-v-aee71446],.dark .empty-wrap[data-v-aee71446],.dark .skeleton-wrap[data-v-aee71446]{background-color:#101014bf}.dark .tiny-slide-bar .tiny-slide-bar__list>div.tiny-slide-bar__select .slide-bar-item .slide-bar-item-title[data-v-aee71446]{color:#63e2b7;opacity:.8}.dark .tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-title[data-v-aee71446]{color:#63e2b7;opacity:.8}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{B as $,C as I,D as M,E as O,_ as D}from"./index-ac7904e2.js";import{z as U}from"./@vicons-4ed09704.js";import{d as F,H as i,c as q,b as A,r as j,e as c,f as _,k as n,w as s,q as b,A as B,x as f,Y as u,bf as h,E as x,al as H,F as Y,u as G}from"./@vue-a481fc63.js";import{o as J,L as C,j as K,e as P,O as Q,M as R,F as W,f as X,g as Z,a as ee,k as oe}from"./naive-ui-609478ed.js";import{_ as te}from"./main-nav.vue_vue_type_style_index_0_lang-e2b1e404.js";import{u as ne}from"./vuex-44de225f.js";import"./vue-router-e5a2430e.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./evtd-b614532e.js";import"./@css-render-7124a1a5.js";import"./vooks-6d99783e.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const se={key:0,class:"tag-item"},ae={key:0,class:"tag-quote"},ce={key:1,class:"tag-quote tag-follow"},le={key:0,class:"options"},ie=F({__name:"tag-item",props:{tag:{},showAction:{type:Boolean},checkFollowing:{type:Boolean}},setup(T){const t=T,r=i(!1),m=q(()=>{let e=[];return t.tag.is_following===0?e.push({label:"关注",key:"follow"}):(t.tag.is_top===0?e.push({label:"置顶",key:"stick"}):e.push({label:"取消置顶",key:"unstick"}),e.push({label:"取消关注",key:"unfollow"})),e}),l=e=>{switch(e){case"follow":M({topic_id:t.tag.id}).then(o=>{t.tag.is_following=1,window.$message.success("关注成功")}).catch(o=>{console.log(o)});break;case"unfollow":I({topic_id:t.tag.id}).then(o=>{t.tag.is_following=0,window.$message.success("取消关注")}).catch(o=>{console.log(o)});break;case"stick":$({topic_id:t.tag.id}).then(o=>{t.tag.is_top=o.top_status,window.$message.success("置顶成功")}).catch(o=>{console.log(o)});break;case"unstick":$({topic_id:t.tag.id}).then(o=>{t.tag.is_top=o.top_status,window.$message.success("取消置顶")}).catch(o=>{console.log(o)});break}};return A(()=>{r.value=!1}),(e,o)=>{const w=j("router-link"),g=J,k=C,a=K,d=P,v=Q,p=R;return!e.checkFollowing||e.checkFollowing&&e.tag.is_following===1?(c(),_("div",se,[n(p,null,{header:s(()=>[(c(),b(k,{type:"success",size:"large",round:"",key:e.tag.id},{avatar:s(()=>[n(g,{src:e.tag.user.avatar},null,8,["src"])]),default:s(()=>[n(w,{class:"hash-link",to:{name:"home",query:{q:e.tag.tag,t:"tag"}}},{default:s(()=>[B(" #"+f(e.tag.tag),1)]),_:1},8,["to"]),e.showAction?u("",!0):(c(),_("span",ae,"("+f(e.tag.quote_num)+")",1)),e.showAction?(c(),_("span",ce,"("+f(e.tag.quote_num)+")",1)):u("",!0)]),_:1}))]),"header-extra":s(()=>[e.showAction?(c(),_("div",le,[n(v,{placement:"bottom-end",trigger:"click",size:"small",options:m.value,onSelect:l},{default:s(()=>[n(d,{type:"success",quaternary:"",circle:"",block:""},{icon:s(()=>[n(a,null,{default:s(()=>[n(h(U))]),_:1})]),_:1})]),_:1},8,["options"])])):u("",!0)]),_:1})])):u("",!0)}}});const _e=F({__name:"Topic",setup(T){const t=ne(),r=i([]),m=i("hot"),l=i(!1),e=i(!1),o=i(!1);x(e,()=>{e.value||(window.$message.success("保存成功"),t.commit("refreshTopicFollow"))});const w=q({get:()=>{let a="编辑";return e.value&&(a="保存"),a},set:a=>{}}),g=()=>{l.value=!0,O({type:m.value,num:50}).then(a=>{r.value=a.topics,l.value=!1}).catch(a=>{console.log(a),l.value=!1})},k=a=>{m.value=a,a=="follow"?o.value=!0:o.value=!1,g()};return A(()=>{g()}),(a,d)=>{const v=te,p=X,L=C,V=Z,E=ie,N=ee,S=oe,z=W;return c(),_("div",null,[n(v,{title:"话题"}),n(z,{class:"main-content-wrap tags-wrap",bordered:""},{default:s(()=>[n(V,{type:"line",animated:"","onUpdate:value":k},H({default:s(()=>[n(p,{name:"hot",tab:"热门"}),n(p,{name:"new",tab:"最新"}),h(t).state.userLogined?(c(),b(p,{key:0,name:"follow",tab:"关注"})):u("",!0)]),_:2},[h(t).state.userLogined?{name:"suffix",fn:s(()=>[n(L,{checked:e.value,"onUpdate:checked":d[0]||(d[0]=y=>e.value=y),checkable:""},{default:s(()=>[B(f(w.value),1)]),_:1},8,["checked"])]),key:"0"}:void 0]),1024),n(S,{show:l.value},{default:s(()=>[n(N,null,{default:s(()=>[(c(!0),_(Y,null,G(r.value,y=>(c(),b(E,{tag:y,showAction:h(t).state.userLogined&&e.value,checkFollowing:o.value},null,8,["tag","showAction","checkFollowing"]))),256))]),_:1})]),_:1},8,["show"])]),_:1})])}}});const Ne=D(_e,[["__scopeId","data-v-1fb31ecf"]]);export{Ne as default}; import{D as $,E as I,F as M,G as O,_ as D}from"./index-537a241d.js";import{z as G}from"./@vicons-4ed09704.js";import{d as F,H as i,c as q,b as A,r as U,e as c,f as _,k as n,w as s,q as b,A as B,x as f,Y as u,bf as h,E as j,al as x,F as H,u as P}from"./@vue-a481fc63.js";import{o as Y,M as C,j as J,e as K,P as Q,O as R,G as W,f as X,g as Z,a as ee,k as oe}from"./naive-ui-defd0b2d.js";import{_ as te}from"./main-nav.vue_vue_type_style_index_0_lang-832ff0ed.js";import{u as ne}from"./vuex-44de225f.js";import"./vue-router-e5a2430e.js";import"./axios-4a70c6fc.js";import"./moment-2ab8298d.js";/* empty css */import"./seemly-76b7b838.js";import"./vueuc-39372edb.js";import"./evtd-b614532e.js";import"./@css-render-7124a1a5.js";import"./vooks-6d99783e.js";import"./vdirs-b0483831.js";import"./@juggle-41516555.js";import"./css-render-6a5c5852.js";import"./@emotion-8a8e73f6.js";import"./lodash-es-8412e618.js";import"./treemate-25c27bff.js";import"./async-validator-dee29e8b.js";import"./date-fns-975a2d8f.js";const se={key:0,class:"tag-item"},ae={key:0,class:"tag-quote"},ce={key:1,class:"tag-quote tag-follow"},le={key:0,class:"options"},ie=F({__name:"tag-item",props:{tag:{},showAction:{type:Boolean},checkFollowing:{type:Boolean}},setup(T){const t=T,r=i(!1),m=q(()=>{let e=[];return t.tag.is_following===0?e.push({label:"关注",key:"follow"}):(t.tag.is_top===0?e.push({label:"置顶",key:"stick"}):e.push({label:"取消置顶",key:"unstick"}),e.push({label:"取消关注",key:"unfollow"})),e}),l=e=>{switch(e){case"follow":M({topic_id:t.tag.id}).then(o=>{t.tag.is_following=1,window.$message.success("关注成功")}).catch(o=>{console.log(o)});break;case"unfollow":I({topic_id:t.tag.id}).then(o=>{t.tag.is_following=0,window.$message.success("取消关注")}).catch(o=>{console.log(o)});break;case"stick":$({topic_id:t.tag.id}).then(o=>{t.tag.is_top=o.top_status,window.$message.success("置顶成功")}).catch(o=>{console.log(o)});break;case"unstick":$({topic_id:t.tag.id}).then(o=>{t.tag.is_top=o.top_status,window.$message.success("取消置顶")}).catch(o=>{console.log(o)});break}};return A(()=>{r.value=!1}),(e,o)=>{const w=U("router-link"),g=Y,k=C,a=J,d=K,v=Q,p=R;return!e.checkFollowing||e.checkFollowing&&e.tag.is_following===1?(c(),_("div",se,[n(p,null,{header:s(()=>[(c(),b(k,{type:"success",size:"large",round:"",key:e.tag.id},{avatar:s(()=>[n(g,{src:e.tag.user.avatar},null,8,["src"])]),default:s(()=>[n(w,{class:"hash-link",to:{name:"home",query:{q:e.tag.tag,t:"tag"}}},{default:s(()=>[B(" #"+f(e.tag.tag),1)]),_:1},8,["to"]),e.showAction?u("",!0):(c(),_("span",ae,"("+f(e.tag.quote_num)+")",1)),e.showAction?(c(),_("span",ce,"("+f(e.tag.quote_num)+")",1)):u("",!0)]),_:1}))]),"header-extra":s(()=>[e.showAction?(c(),_("div",le,[n(v,{placement:"bottom-end",trigger:"click",size:"small",options:m.value,onSelect:l},{default:s(()=>[n(d,{type:"success",quaternary:"",circle:"",block:""},{icon:s(()=>[n(a,null,{default:s(()=>[n(h(G))]),_:1})]),_:1})]),_:1},8,["options"])])):u("",!0)]),_:1})])):u("",!0)}}});const _e=F({__name:"Topic",setup(T){const t=ne(),r=i([]),m=i("hot"),l=i(!1),e=i(!1),o=i(!1);j(e,()=>{e.value||(window.$message.success("保存成功"),t.commit("refreshTopicFollow"))});const w=q({get:()=>{let a="编辑";return e.value&&(a="保存"),a},set:a=>{}}),g=()=>{l.value=!0,O({type:m.value,num:50}).then(a=>{r.value=a.topics,l.value=!1}).catch(a=>{console.log(a),l.value=!1})},k=a=>{m.value=a,a=="follow"?o.value=!0:o.value=!1,g()};return A(()=>{g()}),(a,d)=>{const v=te,p=X,V=C,E=Z,L=ie,N=ee,S=oe,z=W;return c(),_("div",null,[n(v,{title:"话题"}),n(z,{class:"main-content-wrap tags-wrap",bordered:""},{default:s(()=>[n(E,{type:"line",animated:"","onUpdate:value":k},x({default:s(()=>[n(p,{name:"hot",tab:"热门"}),n(p,{name:"new",tab:"最新"}),h(t).state.userLogined?(c(),b(p,{key:0,name:"follow",tab:"关注"})):u("",!0)]),_:2},[h(t).state.userLogined?{name:"suffix",fn:s(()=>[n(V,{checked:e.value,"onUpdate:checked":d[0]||(d[0]=y=>e.value=y),checkable:""},{default:s(()=>[B(f(w.value),1)]),_:1},8,["checked"])]),key:"0"}:void 0]),1024),n(S,{show:l.value},{default:s(()=>[n(N,null,{default:s(()=>[(c(!0),_(H,null,P(r.value,y=>(c(),b(L,{tag:y,showAction:h(t).state.userLogined&&e.value,checkFollowing:o.value},null,8,["tag","showAction","checkFollowing"]))),256))]),_:1})]),_:1},8,["show"])]),_:1})])}}});const Ne=D(_e,[["__scopeId","data-v-1fb31ecf"]]);export{Ne as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{a8 as A}from"./index-ac7904e2.js";import{u as B}from"./vuex-44de225f.js";import{u as E}from"./vue-router-e5a2430e.js";import{j as z}from"./vooks-6d99783e.js";import{$ as C,a0 as N,a1 as P,a2 as D}from"./@vicons-4ed09704.js";import{u as R,a3 as $,a4 as x,j as H,e as I,a5 as V,h as j}from"./naive-ui-609478ed.js";import{d as q,H as h,b as F,e as n,f,bf as a,k as e,w as t,Y as c,j as L,q as _,A as U,x as Y,F as G}from"./@vue-a481fc63.js";const J={key:0},K={class:"navbar"},ae=q({__name:"main-nav",props:{title:{default:""},back:{type:Boolean,default:!1},theme:{type:Boolean,default:!0}},setup(w){const i=w,o=B(),m=E(),l=h(!1),g=h("left"),u=s=>{s?(localStorage.setItem("PAOPAO_THEME","dark"),o.commit("triggerTheme","dark")):(localStorage.setItem("PAOPAO_THEME","light"),o.commit("triggerTheme","light"))},k=()=>{window.history.length<=1?m.push({path:"/"}):m.go(-1)},v=()=>{l.value=!0};return F(()=>{localStorage.getItem("PAOPAO_THEME")||u(z()==="dark"),o.state.desktopModelShow||(window.$store=o,window.$message=R())}),(s,d)=>{const b=A,y=$,M=x,r=H,p=I,O=V,S=j;return n(),f(G,null,[a(o).state.drawerModelShow?(n(),f("div",J,[e(M,{show:l.value,"onUpdate:show":d[0]||(d[0]=T=>l.value=T),width:212,placement:g.value,resizable:""},{default:t(()=>[e(y,null,{default:t(()=>[e(b)]),_:1})]),_:1},8,["show","placement"])])):c("",!0),e(S,{size:"small",bordered:!0,class:"nav-title-card"},{header:t(()=>[L("div",K,[a(o).state.drawerModelShow&&!s.back?(n(),_(p,{key:0,class:"drawer-btn",onClick:v,quaternary:"",circle:"",size:"medium"},{icon:t(()=>[e(r,null,{default:t(()=>[e(a(C))]),_:1})]),_:1})):c("",!0),s.back?(n(),_(p,{key:1,class:"back-btn",onClick:k,quaternary:"",circle:"",size:"small"},{icon:t(()=>[e(r,null,{default:t(()=>[e(a(N))]),_:1})]),_:1})):c("",!0),U(" "+Y(i.title)+" ",1),i.theme?(n(),_(O,{key:2,value:a(o).state.theme==="dark","onUpdate:value":u,size:"small",class:"theme-switch-wrap"},{"checked-icon":t(()=>[e(r,{component:a(P)},null,8,["component"])]),"unchecked-icon":t(()=>[e(r,{component:a(D)},null,8,["component"])]),_:1},8,["value"])):c("",!0)])]),_:1})],64)}}});export{ae as _}; import{a8 as A}from"./index-537a241d.js";import{u as B}from"./vuex-44de225f.js";import{u as E}from"./vue-router-e5a2430e.js";import{j as z}from"./vooks-6d99783e.js";import{$ as C,a0 as N,a1 as P,a2 as D}from"./@vicons-4ed09704.js";import{u as R,a3 as $,a4 as x,j as H,e as I,a5 as V,h as j}from"./naive-ui-defd0b2d.js";import{d as q,H as h,b as F,e as n,f,bf as a,k as e,w as t,Y as c,j as L,q as _,A as U,x as Y,F as G}from"./@vue-a481fc63.js";const J={key:0},K={class:"navbar"},ae=q({__name:"main-nav",props:{title:{default:""},back:{type:Boolean,default:!1},theme:{type:Boolean,default:!0}},setup(w){const i=w,o=B(),m=E(),l=h(!1),g=h("left"),u=s=>{s?(localStorage.setItem("PAOPAO_THEME","dark"),o.commit("triggerTheme","dark")):(localStorage.setItem("PAOPAO_THEME","light"),o.commit("triggerTheme","light"))},k=()=>{window.history.length<=1?m.push({path:"/"}):m.go(-1)},v=()=>{l.value=!0};return F(()=>{localStorage.getItem("PAOPAO_THEME")||u(z()==="dark"),o.state.desktopModelShow||(window.$store=o,window.$message=R())}),(s,d)=>{const b=A,y=$,M=x,r=H,p=I,O=V,S=j;return n(),f(G,null,[a(o).state.drawerModelShow?(n(),f("div",J,[e(M,{show:l.value,"onUpdate:show":d[0]||(d[0]=T=>l.value=T),width:212,placement:g.value,resizable:""},{default:t(()=>[e(y,null,{default:t(()=>[e(b)]),_:1})]),_:1},8,["show","placement"])])):c("",!0),e(S,{size:"small",bordered:!0,class:"nav-title-card"},{header:t(()=>[L("div",K,[a(o).state.drawerModelShow&&!s.back?(n(),_(p,{key:0,class:"drawer-btn",onClick:v,quaternary:"",circle:"",size:"medium"},{icon:t(()=>[e(r,null,{default:t(()=>[e(a(C))]),_:1})]),_:1})):c("",!0),s.back?(n(),_(p,{key:1,class:"back-btn",onClick:k,quaternary:"",circle:"",size:"small"},{icon:t(()=>[e(r,null,{default:t(()=>[e(a(N))]),_:1})]),_:1})):c("",!0),U(" "+Y(i.title)+" ",1),i.theme?(n(),_(O,{key:2,value:a(o).state.theme==="dark","onUpdate:value":u,size:"small",class:"theme-switch-wrap"},{"checked-icon":t(()=>[e(r,{component:a(P)},null,8,["component"])]),"unchecked-icon":t(()=>[e(r,{component:a(D)},null,8,["component"])]),_:1},8,["value"])):c("",!0)])]),_:1})],64)}}});export{ae as _};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{U as r}from"./naive-ui-609478ed.js";import{d as c,e as s,f as n,u as p,j as o,k as t,F as l}from"./@vue-a481fc63.js";import{_ as i}from"./index-ac7904e2.js";const m={class:"user"},u={class:"content"},d=c({__name:"post-skeleton",props:{num:{default:1}},setup(f){return(_,k)=>{const e=r;return s(!0),n(l,null,p(new Array(_.num),a=>(s(),n("div",{class:"skeleton-item",key:a},[o("div",m,[t(e,{circle:"",size:"small"})]),o("div",u,[t(e,{text:"",repeat:3}),t(e,{text:"",style:{width:"60%"}})])]))),128)}}});const b=i(d,[["__scopeId","data-v-ab0015b4"]]);export{b as _}; import{U as r}from"./naive-ui-defd0b2d.js";import{d as c,e as s,f as n,u as p,j as o,k as t,F as l}from"./@vue-a481fc63.js";import{_ as i}from"./index-537a241d.js";const m={class:"user"},u={class:"content"},d=c({__name:"post-skeleton",props:{num:{default:1}},setup(f){return(_,k)=>{const e=r;return s(!0),n(l,null,p(new Array(_.num),a=>(s(),n("div",{class:"skeleton-item",key:a},[o("div",m,[t(e,{circle:"",size:"small"})]),o("div",u,[t(e,{text:"",repeat:3}),t(e,{text:"",style:{width:"60%"}})])]))),128)}}});const b=i(d,[["__scopeId","data-v-ab0015b4"]]);export{b as _};

@ -1 +1 @@
import{X as b,_ as k}from"./index-ac7904e2.js";import{R as B,H as C,S as N,b as R,e as U,i as V}from"./naive-ui-609478ed.js";import{d as $,H as p,e as z,q as H,w as s,j as a,k as n,A as _,x as i}from"./@vue-a481fc63.js";const S={class:"whisper-wrap"},W={class:"whisper-line"},j={class:"whisper-line send-wrap"},q=$({__name:"whisper",props:{show:{type:Boolean,default:!1},user:{}},emits:["success"],setup(r,{emit:u}){const d=r,o=p(""),t=p(!1),c=()=>{u("success")},m=()=>{t.value=!0,b({user_id:d.user.id,content:o.value}).then(e=>{window.$message.success("发送成功"),t.value=!1,o.value="",c()}).catch(e=>{t.value=!1})};return(e,l)=>{const h=B,w=C,f=N,v=R,g=U,y=V;return z(),H(y,{show:e.show,"onUpdate:show":c,class:"whisper-card",preset:"card",size:"small",title:"私信","mask-closable":!1,bordered:!1,style:{width:"360px"}},{default:s(()=>[a("div",S,[n(f,{"show-icon":!1},{default:s(()=>[_(" 即将发送私信给: "),n(w,{style:{"max-width":"100%"}},{default:s(()=>[n(h,{type:"success"},{default:s(()=>[_(i(e.user.nickname)+"@"+i(e.user.username),1)]),_:1})]),_:1})]),_:1}),a("div",W,[n(v,{type:"textarea",placeholder:"请输入私信内容(请勿发送不和谐内容,否则将会被封号)",autosize:{minRows:5,maxRows:10},value:o.value,"onUpdate:value":l[0]||(l[0]=x=>o.value=x),maxlength:"200","show-count":""},null,8,["value"])]),a("div",j,[n(g,{strong:"",secondary:"",type:"primary",loading:t.value,onClick:m},{default:s(()=>[_(" 发送 ")]),_:1},8,["loading"])])])]),_:1},8,["show"])}}});const M=k(q,[["__scopeId","data-v-0cbfe47c"]]);export{M as _}; import{X as b,_ as k}from"./index-537a241d.js";import{S as B,I as C,T as N,b as U,e as V,i as $}from"./naive-ui-defd0b2d.js";import{d as z,H as p,e as I,q as R,w as s,j as a,k as n,A as _,x as i}from"./@vue-a481fc63.js";const S={class:"whisper-wrap"},T={class:"whisper-line"},W={class:"whisper-line send-wrap"},j=z({__name:"whisper",props:{show:{type:Boolean,default:!1},user:{}},emits:["success"],setup(r,{emit:u}){const d=r,o=p(""),t=p(!1),c=()=>{u("success")},m=()=>{t.value=!0,b({user_id:d.user.id,content:o.value}).then(e=>{window.$message.success("发送成功"),t.value=!1,o.value="",c()}).catch(e=>{t.value=!1})};return(e,l)=>{const h=B,w=C,f=N,v=U,g=V,y=$;return I(),R(y,{show:e.show,"onUpdate:show":c,class:"whisper-card",preset:"card",size:"small",title:"私信","mask-closable":!1,bordered:!1,style:{width:"360px"}},{default:s(()=>[a("div",S,[n(f,{"show-icon":!1},{default:s(()=>[_(" 即将发送私信给: "),n(w,{style:{"max-width":"100%"}},{default:s(()=>[n(h,{type:"success"},{default:s(()=>[_(i(e.user.nickname)+"@"+i(e.user.username),1)]),_:1})]),_:1})]),_:1}),a("div",T,[n(v,{type:"textarea",placeholder:"请输入私信内容(请勿发送不和谐内容,否则将会被封号)",autosize:{minRows:5,maxRows:10},value:o.value,"onUpdate:value":l[0]||(l[0]=x=>o.value=x),maxlength:"200","show-count":""},null,8,["value"])]),a("div",W,[n(g,{strong:"",secondary:"",type:"primary",loading:t.value,onClick:m},{default:s(()=>[_(" 发送 ")]),_:1},8,["loading"])])])]),_:1},8,["show"])}}});const H=k(j,[["__scopeId","data-v-0cbfe47c"]]);export{H as _};

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<title></title> <title></title>
<script type="module" crossorigin src="/assets/index-ac7904e2.js"></script> <script type="module" crossorigin src="/assets/index-537a241d.js"></script>
<link rel="modulepreload" crossorigin href="/assets/@vue-a481fc63.js"> <link rel="modulepreload" crossorigin href="/assets/@vue-a481fc63.js">
<link rel="modulepreload" crossorigin href="/assets/vue-router-e5a2430e.js"> <link rel="modulepreload" crossorigin href="/assets/vue-router-e5a2430e.js">
<link rel="modulepreload" crossorigin href="/assets/vuex-44de225f.js"> <link rel="modulepreload" crossorigin href="/assets/vuex-44de225f.js">
@ -26,7 +26,7 @@
<link rel="modulepreload" crossorigin href="/assets/treemate-25c27bff.js"> <link rel="modulepreload" crossorigin href="/assets/treemate-25c27bff.js">
<link rel="modulepreload" crossorigin href="/assets/async-validator-dee29e8b.js"> <link rel="modulepreload" crossorigin href="/assets/async-validator-dee29e8b.js">
<link rel="modulepreload" crossorigin href="/assets/date-fns-975a2d8f.js"> <link rel="modulepreload" crossorigin href="/assets/date-fns-975a2d8f.js">
<link rel="modulepreload" crossorigin href="/assets/naive-ui-609478ed.js"> <link rel="modulepreload" crossorigin href="/assets/naive-ui-defd0b2d.js">
<link rel="modulepreload" crossorigin href="/assets/moment-2ab8298d.js"> <link rel="modulepreload" crossorigin href="/assets/moment-2ab8298d.js">
<link rel="modulepreload" crossorigin href="/assets/@vicons-4ed09704.js"> <link rel="modulepreload" crossorigin href="/assets/@vicons-4ed09704.js">
<link rel="stylesheet" href="/assets/index-c337d1db.css"> <link rel="stylesheet" href="/assets/index-c337d1db.css">

@ -145,6 +145,10 @@ import {
BookmarkOutline, BookmarkOutline,
ChatboxOutline, ChatboxOutline,
ShareSocialOutline, ShareSocialOutline,
PersonAddOutline,
PersonRemoveOutline,
BodyOutline,
WalkOutline,
} from '@vicons/ionicons5'; } from '@vicons/ionicons5';
import { MoreHorizFilled } from '@vicons/material'; import { MoreHorizFilled } from '@vicons/material';
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
@ -153,10 +157,14 @@ const router = useRouter();
const store = useStore(); const store = useStore();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
post: Item.PostProps, post: Item.PostProps,
isOwner: boolean,
addExtraAction: boolean,
}>(), {}); }>(), {});
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'send-whisper', user: Item.UserInfo): void; (e: 'send-whisper', user: Item.UserInfo): void
(e: 'handle-follow-action', user: Item.PostProps): void
(e: 'handle-friend-action', user: Item.PostProps): void
}>(); }>();
const renderIcon = (icon: Component) => { const renderIcon = (icon: Component) => {
@ -182,6 +190,34 @@ const tweetOptions = computed(() => {
key: 'whisper', key: 'whisper',
icon: renderIcon(PaperPlaneOutline) icon: renderIcon(PaperPlaneOutline)
}); });
if (!props.isOwner && props.addExtraAction) {
if (props.post.user.is_following) {
options.push({
label: '',
key: 'unfollow',
icon: renderIcon(WalkOutline)
})
} else {
options.push({
label: '',
key: 'follow',
icon: renderIcon(BodyOutline)
})
}
// if (props.post.user.is_friend) {
// options.push({
// label: '删除好友',
// key: 'delete',
// icon: renderIcon(PersonRemoveOutline)
// });
// } else {
// options.push({
// label: '添加朋友',
// key: 'requesting',
// icon: renderIcon(PersonAddOutline)
// });
// }
}
options.push({ options.push({
label: '', label: '',
key: 'copyTweetLink', key: 'copyTweetLink',
@ -191,7 +227,7 @@ const tweetOptions = computed(() => {
}); });
const handleTweetAction = async ( const handleTweetAction = async (
item: 'copyTweetLink' | 'whisper' item: 'copyTweetLink' | 'whisper' | 'follow' | 'unfollow' | 'delete' | 'requesting'
) => { ) => {
switch (item) { switch (item) {
case 'copyTweetLink': case 'copyTweetLink':
@ -201,6 +237,14 @@ const handleTweetAction = async (
case 'whisper': case 'whisper':
emit('send-whisper', props.post.user); emit('send-whisper', props.post.user);
break; break;
case 'delete':
case 'requesting':
emit('handle-friend-action', props.post);
break;
case 'follow':
case 'unfollow':
emit('handle-follow-action', props.post);
break;
default: default:
break; break;
} }

@ -143,6 +143,10 @@ import {
BookmarkOutline, BookmarkOutline,
ChatboxOutline, ChatboxOutline,
ShareSocialOutline, ShareSocialOutline,
PersonAddOutline,
PersonRemoveOutline,
BodyOutline,
WalkOutline,
} from '@vicons/ionicons5'; } from '@vicons/ionicons5';
import { MoreHorizFilled } from '@vicons/material'; import { MoreHorizFilled } from '@vicons/material';
import copy from "copy-to-clipboard"; import copy from "copy-to-clipboard";
@ -151,10 +155,14 @@ const router = useRouter();
const store = useStore(); const store = useStore();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
post: Item.PostProps, post: Item.PostProps,
isOwner: boolean,
addExtraAction: boolean,
}>(), {}); }>(), {});
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'send-whisper', user: Item.UserInfo): void; (e: 'send-whisper', user: Item.UserInfo): void
(e: 'handle-follow-action', user: Item.PostProps): void
(e: 'handle-friend-action', user: Item.PostProps): void
}>(); }>();
const renderIcon = (icon: Component) => { const renderIcon = (icon: Component) => {
@ -180,6 +188,34 @@ const tweetOptions = computed(() => {
key: 'whisper', key: 'whisper',
icon: renderIcon(PaperPlaneOutline) icon: renderIcon(PaperPlaneOutline)
}); });
if (!props.isOwner && props.addExtraAction) {
if (props.post.user.is_following) {
options.push({
label: '',
key: 'unfollow',
icon: renderIcon(WalkOutline)
})
} else {
options.push({
label: '',
key: 'follow',
icon: renderIcon(BodyOutline)
})
}
// if (props.post.user.is_friend) {
// options.push({
// label: '删除好友',
// key: 'delete',
// icon: renderIcon(PersonRemoveOutline)
// });
// } else {
// options.push({
// label: '添加朋友',
// key: 'requesting',
// icon: renderIcon(PersonAddOutline)
// });
// }
}
options.push({ options.push({
label: '', label: '',
key: 'copyTweetLink', key: 'copyTweetLink',
@ -189,7 +225,7 @@ const tweetOptions = computed(() => {
}); });
const handleTweetAction = async ( const handleTweetAction = async (
item: 'copyTweetLink' | 'whisper' item: 'copyTweetLink' | 'whisper' | 'follow' | 'unfollow' | 'delete' | 'requesting'
) => { ) => {
switch (item) { switch (item) {
case 'copyTweetLink': case 'copyTweetLink':
@ -199,6 +235,14 @@ const handleTweetAction = async (
case 'whisper': case 'whisper':
emit('send-whisper', props.post.user); emit('send-whisper', props.post.user);
break; break;
case 'delete':
case 'requesting':
emit('handle-friend-action', props.post);
break;
case 'follow':
case 'unfollow':
emit('handle-follow-action', props.post);
break;
default: default:
break; break;
} }

@ -40,17 +40,27 @@
</div> </div>
<div v-if="store.state.desktopModelShow"> <div v-if="store.state.desktopModelShow">
<n-list-item v-for="post in list" :key="post.id"> <n-list-item v-for="post in list" :key="post.id">
<post-item :post="post" @send-whisper="onSendWhisper" /> <post-item :post="post"
:isOwner="store.state.userInfo.Id === post.user_id"
:addExtraAction="true"
@send-whisper="onSendWhisper"
@handle-follow-action="onHandleFollowAction" />
</n-list-item> </n-list-item>
</div> </div>
<div v-else> <div v-else>
<n-list-item v-for="post in list" :key="post.id"> <n-list-item v-for="post in list" :key="post.id">
<mobile-post-item :post="post" @send-whisper="onSendWhisper" /> <mobile-post-item :post="post"
:isOwner="store.state.userInfo.Id === post.user_id"
:addExtraAction="true"
@send-whisper="onSendWhisper"
@handle-follow-action="onHandleFollowAction" />
</n-list-item> </n-list-item>
</div> </div>
</div> </div>
<!-- --> <!-- -->
<whisper :show="showWhisper" :user="whisperReceiver" @success="whisperSuccess" /> <whisper :show="showWhisper" :user="whisperReceiver" @success="whisperSuccess" />
<!-- -->
<!-- <whisper-add-friend :show="showAddFriendWhisper" :user="user" @success="addFriendWhisperSuccess" /> -->
</n-list> </n-list>
<n-space v-if="totalPage > 0" justify="center"> <n-space v-if="totalPage > 0" justify="center">
@ -67,12 +77,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed, watch } from 'vue'; import { ref, onMounted, reactive, computed, watch } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useDialog } from 'naive-ui';
import InfiniteLoading from "v3-infinite-loading"; import InfiniteLoading from "v3-infinite-loading";
import { getPosts, getContacts } from '@/api/post'; import { getPosts, getContacts } from '@/api/post';
import { getUserPosts } from '@/api/user'; import { getUserPosts, deleteFriend, followUser, unfollowUser } from '@/api/user';
import SlideBar from '@opentiny/vue-slide-bar'; import SlideBar from '@opentiny/vue-slide-bar';
import allTweets from '@/assets/img/fresh-tweets.png'; import allTweets from '@/assets/img/fresh-tweets.png';
import discoverTweets from '@/assets/img/discover-tweets.jpeg'; import discoverTweets from '@/assets/img/discover-tweets.jpeg';
@ -83,6 +94,7 @@ const enableFriendsBar = (import.meta.env.VITE_ENABLE_FRIENDS_BAR.toLowerCase()
const store = useStore(); const store = useStore();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const dialog = useDialog();
const initBlocks = ref(9) const initBlocks = ref(9)
const wheelBlocks = ref(8) const wheelBlocks = ref(8)
@ -102,6 +114,20 @@ const slideBarList = ref<Item.SlideBarItem[]>([
{ title: '', style: 1, username: '', avatar: '', show: true }, { title: '', style: 1, username: '', avatar: '', show: true },
{ title: '', style: 1, username: '', avatar: '', show: true } { title: '', style: 1, username: '', avatar: '', show: true }
]); ]);
const user = reactive<Item.UserInfo>({
id: 0,
avatar: '',
username: '',
nickname: '',
is_admin: false,
is_friend: false,
is_following: false,
created_on: 0,
follows: 0,
followings: 0,
status: 1,
});
const inActionPost = ref<Item.PostProps | null>(null)
const title = ref<string>("泡泡广场") const title = ref<string>("泡泡广场")
const loading = ref(false); const loading = ref(false);
@ -113,6 +139,7 @@ const page = ref(1);
const pageSize = ref(20); const pageSize = ref(20);
const totalPage = ref(0); const totalPage = ref(0);
const showWhisper = ref(false); const showWhisper = ref(false);
const showAddFriendWhisper = ref(false);
const whisperReceiver = ref<Item.UserInfo>({ const whisperReceiver = ref<Item.UserInfo>({
id: 0, id: 0,
avatar: '', avatar: '',
@ -136,6 +163,74 @@ const whisperSuccess = () => {
showWhisper.value = false; showWhisper.value = false;
}; };
const openAddFriendWhisper = () => {
showAddFriendWhisper.value = true;
};
const openDeleteFriend = (post: Item.PostProps) => {
dialog.warning({
title: '',
content: ' ' + post.user.nickname + ' / ',
positiveText: '',
negativeText: '',
onPositiveClick: () => {
deleteFriend({
user_id: user.id,
}).then((res) => {
window.$message.success('');
post.user.is_friend = false;
})
.catch((_err) => {});
},
});
};
const addFriendWhisperSuccess = () => {
showAddFriendWhisper.value = false;
inActionPost.value = null;
};
const onHandleFriendAction = (post: Item.PostProps) => {
inActionPost.value = post;
user.id = post.user.id;
user.username = post.user.username;
user.nickname = post.user.nickname;
if (post.user.is_friend) {
openDeleteFriend(post);
} else {
openAddFriendWhisper();
}
};
const onHandleFollowAction = (post: Item.PostProps) => {
dialog.success({
title: '',
content:
'' + (post.user.is_following ? '' : '') + '',
positiveText: '',
negativeText: '',
onPositiveClick: () => {
if (post.user.is_following) {
unfollowUser({
user_id: post.user.id,
}).then((_res) => {
window.$message.success('');
post.user.is_following = false;
})
.catch((_err) => {});
} else {
followUser({
user_id: post.user.id,
}).then((_res) => {
window.$message.success('');
post.user.is_following = true;
})
.catch((_err) => {});
}
},
});
};
const updateTitle = () => { const updateTitle = () => {
title.value = '广'; title.value = '广';
if (route.query && route.query.q) { if (route.query && route.query.q) {

Loading…
Cancel
Save