merge from x/gorm branch

r/paopao-ce-pro
Michael Li 2 years ago
commit f1d479bbc9
No known key found for this signature in database

@ -30,52 +30,124 @@ All notable changes to paopao-ce are documented in this file.
# 模块开启 # 模块开启
VITE_ENABLE_FRIENDS_BAR=true VITE_ENABLE_FRIENDS_BAR=true
``` ```
- add Newest/Hots/Following tweets support in friend bar feature. - add Newest/Hots/Following tweets support in friend bar feature.
mirgration database first(sql ddl file in `scripts/migration/**/*_home_timeline.up.sql`): mirgration database first(sql ddl file in `scripts/migration/**/*_home_timeline.up.sql`):
```sql ```sql
CREATE TABLE `p_post_metric` ( CREATE TABLE `p_post_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT, `id` bigint unsigned NOT NULL AUTO_INCREMENT,
`post_id` bigint unsigned NOT NULL, `post_id` bigint unsigned NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0, `rank_score` bigint unsigned NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0, `incentive_score` int unsigned NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0, `decay_factor` int unsigned NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0, `motivation_factor` int unsigned NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是 `is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0', `created_on` bigint unsigned NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0', `modified_on` bigint unsigned NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0', `deleted_on` bigint unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE KEY `idx_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_post_metric (post_id, rank_score, created_on) INSERT INTO p_post_metric (post_id, rank_score, created_on)
SELECT id AS post_id, SELECT id AS post_id,
comment_count + upvote_count*2 + collection_count*4 AS rank_score, comment_count + upvote_count*2 + collection_count*4 AS rank_score,
created_on created_on
FROM p_post FROM p_post
WHERE is_del=0; WHERE is_del=0;
-- 原来的可见性: 0公开 1私密 2好友可见 3关注可见 -- 原来的可见性: 0公开 1私密 2好友可见 3关注可见
-- 现在的可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开 -- 现在的可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开
UPDATE p_post a UPDATE p_post a, p_post b
SET visibility = ( SET a.visibility = (
SELECT CASE b.visibility
CASE visibility WHEN 0 THEN 90
WHEN 0 THEN 90 WHEN 1 THEN 0
WHEN 1 THEN 0 WHEN 2 THEN 50
WHEN 2 THEN 50 WHEN 3 THEN 60
WHEN 3 THEN 60 ELSE 0
ELSE 0 END
END )
FROM WHERE a.ID = b.ID;
p_post b ```
WHERE - add cache support for index/home etc. page.
a.ID = b.ID - add hots comments support for post detail page.
); - add highlight comments support for post detail page.
```sql mirgration database first(sql ddl file in `scripts/migration/**/*_comment_esence.up.sql`):
- add cache support for index/home etc. page. ```sql
- add hots comments support for post detail page. ALTER TABLE `p_comment` ADD COLUMN `is_essence` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否精选';
```
- add follow/unfollow user support in index/home/collecion/message/post page.
- add simple prometheus metrics support.
add `Metrics` to `conf.yaml` 's `Features` section to enable this feature like below:
```yaml
# file config.yaml
...
Features:
Default: ["Base", "Postgres", "Meili", "LocalOSS", "Metrics", "web"]
JobManager: # Cron Job理器的配置参数
MaxOnlineInterval: "@every 5m" # 更新最大在线人数默认每5分钟更新一次
UpdateMetricsInterval: "@every 5m" # 更新Prometheus指标默认每5分钟更新一次
MetricsServer: # Prometheus Metrics服务
RunMode: debug
HttpIp: 0.0.0.0
HttpPort: 6080
ReadTimeout: 60
WriteTimeout: 60
...
```
- add full support for tweet hots comment logic and add cache support for tweet comments.
mirgration database first(sql ddl file in `scripts/migration/**/*_rank_metrics.up.sql`):
```sql
ALTER TABLE `p_comment` ADD COLUMN `reply_count` int unsigned NOT NULL DEFAULT 0 COMMENT '回复数';
UPDATE p_comment comment
SET reply_count = (
SELECT count(*) FROM p_comment_reply reply WHERE reply.comment_id=comment.id AND reply.is_del=0
)
WHERE is_del=0;
CREATE TABLE `p_comment_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`comment_id` bigint unsigned NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_metric_comment_id_rank_score` (`comment_id`, `rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE `p_user_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`tweets_count` int unsigned NOT NULL DEFAULT 0,
`latest_trends_on` bigint unsigned NOT NULL DEFAULT 0 COMMENT '最新动态时间',
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user_metric_user_id_tweets_count_trends` (`user_id`, `tweets_count`, `latest_trends_on`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;
```
## 0.4.2 ## 0.4.2
### Fixed ### Fixed
- fixed remove multi-objects no effects and occurs resource leak error when use Minio as OSS(Object Storage System).[#371](https://github.com/rocboss/paopao-ce/pull/371) [#372](https://github.com/rocboss/paopao-ce/pull/372) - fixed remove multi-objects no effects and occurs resource leak error when use Minio as OSS(Object Storage System).[#371](https://github.com/rocboss/paopao-ce/pull/371) [#372](https://github.com/rocboss/paopao-ce/pull/372)

@ -18,6 +18,7 @@ type Loose interface {
// Chain provide handlers chain for gin // Chain provide handlers chain for gin
Chain() gin.HandlersChain Chain() gin.HandlersChain
TweetDetail(*web.TweetDetailReq) (*web.TweetDetailResp, mir.Error)
TweetComments(*web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) TweetComments(*web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error)
TopicList(*web.TopicListReq) (*web.TopicListResp, mir.Error) TopicList(*web.TopicListReq) (*web.TopicListResp, mir.Error)
GetUserProfile(*web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error) GetUserProfile(*web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error)
@ -35,6 +36,20 @@ func RegisterLooseServant(e *gin.Engine, s Loose) {
router.Use(middlewares...) router.Use(middlewares...)
// register routes info to router // register routes info to router
router.Handle("GET", "/post", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.TweetDetailReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.TweetDetail(req)
s.Render(c, resp, err)
})
router.Handle("GET", "/post/comments", func(c *gin.Context) { router.Handle("GET", "/post/comments", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -47,7 +62,12 @@ func RegisterLooseServant(e *gin.Engine, s Loose) {
return return
} }
resp, err := s.TweetComments(req) resp, err := s.TweetComments(req)
s.Render(c, resp, err) if err != nil {
s.Render(c, nil, err)
return
}
var rv _render_ = resp
rv.Render(c)
}) })
router.Handle("GET", "/tags", func(c *gin.Context) { router.Handle("GET", "/tags", func(c *gin.Context) {
select { select {
@ -125,6 +145,10 @@ func (UnimplementedLooseServant) Chain() gin.HandlersChain {
return nil return nil
} }
func (UnimplementedLooseServant) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedLooseServant) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) { func (UnimplementedLooseServant) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -27,6 +27,7 @@ type Priv interface {
ThumbsUpTweetComment(*web.TweetCommentThumbsReq) mir.Error ThumbsUpTweetComment(*web.TweetCommentThumbsReq) mir.Error
DeleteCommentReply(*web.DeleteCommentReplyReq) mir.Error DeleteCommentReply(*web.DeleteCommentReplyReq) mir.Error
CreateCommentReply(*web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error) CreateCommentReply(*web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error)
HighlightComment(*web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error)
DeleteComment(*web.DeleteCommentReq) mir.Error DeleteComment(*web.DeleteCommentReq) mir.Error
CreateComment(*web.CreateCommentReq) (*web.CreateCommentResp, mir.Error) CreateComment(*web.CreateCommentReq) (*web.CreateCommentResp, mir.Error)
VisibleTweet(*web.VisibleTweetReq) (*web.VisibleTweetResp, mir.Error) VisibleTweet(*web.VisibleTweetReq) (*web.VisibleTweetResp, mir.Error)
@ -184,6 +185,20 @@ func RegisterPrivServant(e *gin.Engine, s Priv, m ...PrivChain) {
resp, err := s.CreateCommentReply(req) resp, err := s.CreateCommentReply(req)
s.Render(c, resp, err) s.Render(c, resp, err)
}) })
router.Handle("POST", "/post/comment/highlight", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.HighlightCommentReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.HighlightComment(req)
s.Render(c, resp, err)
})
router.Handle("DELETE", "/post/comment", func(c *gin.Context) { router.Handle("DELETE", "/post/comment", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -419,6 +434,10 @@ func (UnimplementedPrivServant) CreateCommentReply(req *web.CreateCommentReplyRe
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedPrivServant) HighlightComment(req *web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) DeleteComment(req *web.DeleteCommentReq) mir.Error { func (UnimplementedPrivServant) DeleteComment(req *web.DeleteCommentReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -15,7 +15,6 @@ import (
type Pub interface { type Pub interface {
_default_ _default_
TweetDetail(*web.TweetDetailReq) (*web.TweetDetailResp, mir.Error)
SendCaptcha(*web.SendCaptchaReq) mir.Error SendCaptcha(*web.SendCaptchaReq) mir.Error
GetCaptcha() (*web.GetCaptchaResp, mir.Error) GetCaptcha() (*web.GetCaptchaResp, mir.Error)
Register(*web.RegisterReq) (*web.RegisterResp, mir.Error) Register(*web.RegisterReq) (*web.RegisterResp, mir.Error)
@ -30,20 +29,6 @@ func RegisterPubServant(e *gin.Engine, s Pub) {
router := e.Group("v1") router := e.Group("v1")
// register routes info to router // register routes info to router
router.Handle("GET", "/post", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.TweetDetailReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.TweetDetail(req)
s.Render(c, resp, err)
})
router.Handle("POST", "/captcha", func(c *gin.Context) { router.Handle("POST", "/captcha", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -110,10 +95,6 @@ func RegisterPubServant(e *gin.Engine, s Pub) {
// UnimplementedPubServant can be embedded to have forward compatible implementations. // UnimplementedPubServant can be embedded to have forward compatible implementations.
type UnimplementedPubServant struct{} type UnimplementedPubServant struct{}
func (UnimplementedPubServant) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPubServant) SendCaptcha(req *web.SendCaptchaReq) mir.Error { func (UnimplementedPubServant) SendCaptcha(req *web.SendCaptchaReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -6,6 +6,7 @@ toolchain go1.21.1
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
@ -29,8 +30,9 @@ require (
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/meilisearch/meilisearch-go v0.25.1 github.com/meilisearch/meilisearch-go v0.25.1
github.com/minio/minio-go/v7 v7.0.63 github.com/minio/minio-go/v7 v7.0.63
github.com/onsi/ginkgo/v2 v2.12.0 github.com/onsi/ginkgo/v2 v2.12.1
github.com/onsi/gomega v1.27.10 github.com/onsi/gomega v1.27.10
github.com/prometheus/client_golang v1.16.0
github.com/pyroscope-io/client v0.7.2 github.com/pyroscope-io/client v0.7.2
github.com/redis/rueidis v1.0.18 github.com/redis/rueidis v1.0.18
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
@ -43,7 +45,7 @@ require (
github.com/tencentyun/cos-go-sdk-v5 v0.7.43 github.com/tencentyun/cos-go-sdk-v5 v0.7.43
github.com/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc github.com/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc
go.uber.org/automaxprocs v1.5.3 go.uber.org/automaxprocs v1.5.3
google.golang.org/grpc v1.58.1 google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0 google.golang.org/protobuf v1.31.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/resty.v1 v1.12.0 gopkg.in/resty.v1 v1.12.0
@ -60,7 +62,10 @@ require (
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 // indirect github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 // indirect github.com/bytecodealliance/wasmtime-go/v12 v12.0.0 // indirect
github.com/cespare/xxhash/v2 v2.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
@ -111,12 +116,14 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
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/pganalyze/pg_query_go/v4 v4.2.3 // indirect github.com/pganalyze/pg_query_go/v4 v4.2.3 // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
@ -124,6 +131,9 @@ require (
github.com/pingcap/log v1.1.0 // indirect github.com/pingcap/log v1.1.0 // indirect
github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1 // indirect github.com/pingcap/tidb/parser v0.0.0-20230815160630-b69fa21942d1 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/pyroscope-io/godeltaprof v0.1.2 // indirect github.com/pyroscope-io/godeltaprof v0.1.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/riza-io/grpc-go v0.2.0 // indirect github.com/riza-io/grpc-go v0.2.0 // 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=
@ -179,10 +181,12 @@ github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
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=
@ -213,6 +217,8 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
@ -956,6 +962,8 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/meilisearch/meilisearch-go v0.25.1 h1:D5wY22sn5kkpRH3uYMGlwltdUEq5regIFmO7awHz3Vo= github.com/meilisearch/meilisearch-go v0.25.1 h1:D5wY22sn5kkpRH3uYMGlwltdUEq5regIFmO7awHz3Vo=
github.com/meilisearch/meilisearch-go v0.25.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= github.com/meilisearch/meilisearch-go v0.25.1/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0=
@ -1006,6 +1014,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=
@ -1032,8 +1042,8 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI= github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ= github.com/onsi/ginkgo/v2 v2.12.1/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -1123,11 +1133,15 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@ -1136,6 +1150,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -1148,6 +1164,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pyroscope-io/client v0.7.2 h1:OX2qdUQsS8RSkn/3C8isD7f/P0YiZQlRbAlecAaj/R8= github.com/pyroscope-io/client v0.7.2 h1:OX2qdUQsS8RSkn/3C8isD7f/P0YiZQlRbAlecAaj/R8=
github.com/pyroscope-io/client v0.7.2/go.mod h1:FEocnjn+Ngzxy6EtU9ZxXWRvQ0+pffkrBxHLnPpxwi8= github.com/pyroscope-io/client v0.7.2/go.mod h1:FEocnjn+Ngzxy6EtU9ZxXWRvQ0+pffkrBxHLnPpxwi8=
@ -2014,8 +2032,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58= google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=

@ -21,16 +21,16 @@ func MustAlipayClient() *alipay.Client {
logrus.Fatalf("alipay.New err: %s", err) logrus.Fatalf("alipay.New err: %s", err)
} }
// 加载应用公钥证书 // 加载应用公钥证书
if err = client.LoadAppPublicCertFromFile(s.AppPublicCertFile); err != nil { if err = client.LoadAppCertPublicKeyFromFile(s.AppPublicCertFile); err != nil {
logrus.Fatalf("client.LoadAppPublicCertFromFile err: %s\n", err) logrus.Fatalf("client.LoadAppCertPublicKeyFromFile err: %s\n", err)
} }
// 加载支付宝根证书 // 加载支付宝根证书
if err = client.LoadAliPayRootCertFromFile(s.RootCertFile); err != nil { if err = client.LoadAliPayRootCertFromFile(s.RootCertFile); err != nil {
logrus.Fatalf("client.LoadAliPayRootCertFromFile err: %s\n", err) logrus.Fatalf("client.LoadAliPayRootCertFromFile err: %s\n", err)
} }
// 加载支付宝公钥证书 // 加载支付宝公钥证书
if err = client.LoadAliPayPublicCertFromFile(s.PublicCertFile); err != nil { if err = client.LoadAlipayCertPublicKeyFromFile(s.PublicCertFile); err != nil {
logrus.Fatalf("client.LoadAliPayPublicCertFromFile err: %s\n", err) logrus.Fatalf("client.LoadAlipayCertPublicKeyFromFile err: %s\n", err)
} }
_alipayClient = client _alipayClient = client
}) })

@ -17,6 +17,9 @@ const (
// 以下包含一些在cache中会用到的key的前缀 // 以下包含一些在cache中会用到的key的前缀
const ( const (
InfixCommentDefault = "default"
InfixCommentHots = "hots"
InfixCommentNewest = "newest"
PrefixNewestTweets = "paopao:newesttweets:" PrefixNewestTweets = "paopao:newesttweets:"
PrefixHotsTweets = "paopao:hotstweets:" PrefixHotsTweets = "paopao:hotstweets:"
PrefixFollowingTweets = "paopao:followingtweets:" PrefixFollowingTweets = "paopao:followingtweets:"
@ -29,6 +32,9 @@ 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:"
PrefixTweetComment = "paopao:comment:"
KeySiteStatus = "paopao:sitestatus" KeySiteStatus = "paopao:sitestatus"
KeyHistoryMaxOnline = "history.max.online" KeyHistoryMaxOnline = "history.max.online"
) )
@ -42,6 +48,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 +64,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] {

@ -26,6 +26,7 @@ var (
PostgresSetting *postgresConf PostgresSetting *postgresConf
Sqlite3Setting *sqlite3Conf Sqlite3Setting *sqlite3Conf
PprofServerSetting *httpServerConf PprofServerSetting *httpServerConf
MetricsServerSetting *httpServerConf
WebServerSetting *httpServerConf WebServerSetting *httpServerConf
AdminServerSetting *httpServerConf AdminServerSetting *httpServerConf
SpaceXServerSetting *httpServerConf SpaceXServerSetting *httpServerConf
@ -78,6 +79,7 @@ func setupSetting(suite []string, noDefault bool) error {
"MetricManager": &MetricManagerSetting, "MetricManager": &MetricManagerSetting,
"JobManager": &JobManagerSetting, "JobManager": &JobManagerSetting,
"PprofServer": &PprofServerSetting, "PprofServer": &PprofServerSetting,
"MetricsServer": &MetricsServerSetting,
"WebServer": &WebServerSetting, "WebServer": &WebServerSetting,
"AdminServer": &AdminServerSetting, "AdminServer": &AdminServerSetting,
"SpaceXServer": &SpaceXServerSetting, "SpaceXServer": &SpaceXServerSetting,

@ -11,8 +11,10 @@ Cache:
UnreadMsgExpire: 60 # 未读消息过期时间,单位秒, 默认60s UnreadMsgExpire: 60 # 未读消息过期时间,单位秒, 默认60s
UserTweetsExpire: 60 # 获取用户推文列表过期时间,单位秒, 默认60s UserTweetsExpire: 60 # 获取用户推文列表过期时间,单位秒, 默认60s
IndexTweetsExpire: 120 # 获取广场推文列表过期时间,单位秒, 默认120s IndexTweetsExpire: 120 # 获取广场推文列表过期时间,单位秒, 默认120s
TweetCommentsExpire: 180 # 获取推文评论过期时间,单位秒, 默认180s
OnlineUserExpire: 300 # 标记在线用户 过期时间,单位秒, 默认300s OnlineUserExpire: 300 # 标记在线用户 过期时间,单位秒, 默认300s
UserInfoExpire: 300 # 获取用户信息过期时间,单位秒, 默认300s UserInfoExpire: 300 # 获取用户信息过期时间,单位秒, 默认300s
UserRelationExpire: 600 # 用户关系信息过期时间,单位秒, 默认600s
EventManager: # 事件管理器的配置参数 EventManager: # 事件管理器的配置参数
MinWorker: 64 # 最小后台工作者, 设置范围[5, ++], 默认64 MinWorker: 64 # 最小后台工作者, 设置范围[5, ++], 默认64
MaxEventBuf: 128 # 最大log缓存条数, 设置范围[10, ++], 默认128 MaxEventBuf: 128 # 最大log缓存条数, 设置范围[10, ++], 默认128
@ -26,7 +28,8 @@ MetricManager: # 指标监控管理器的配置参数
MaxTickCount: 60 # 最大的循环周期, 设置范围[60, ++], 默认60 MaxTickCount: 60 # 最大的循环周期, 设置范围[60, ++], 默认60
TickWaitTime: 1 # 一个周期的等待时间,单位:秒 默认1s TickWaitTime: 1 # 一个周期的等待时间,单位:秒 默认1s
JobManager: # Cron Job理器的配置参数 JobManager: # Cron Job理器的配置参数
MaxOnlineInterval: "@every 5m" # 更新最大在线人数默认每5分钟更新一次 MaxOnlineInterval: "@every 5m" # 更新最大在线人数默认每5分钟更新一次
UpdateMetricsInterval: "@every 5m" # 更新Prometheus指标默认每5分钟更新一次
Features: Features:
Default: [] Default: []
WebServer: # Web服务 WebServer: # Web服务
@ -65,6 +68,12 @@ PprofServer: # Pprof服务
HttpPort: 6060 HttpPort: 6060
ReadTimeout: 60 ReadTimeout: 60
WriteTimeout: 60 WriteTimeout: 60
MetricsServer: # Prometheus Metrics服务
RunMode: debug
HttpIp: 0.0.0.0
HttpPort: 6080
ReadTimeout: 60
WriteTimeout: 60
FrontendWebServer: # Web前端静态资源服务 FrontendWebServer: # Web前端静态资源服务
RunMode: debug RunMode: debug
HttpIp: 0.0.0.0 HttpIp: 0.0.0.0

@ -23,6 +23,7 @@ const (
TableAttachment = "attachment" TableAttachment = "attachment"
TableCaptcha = "captcha" TableCaptcha = "captcha"
TableComment = "comment" TableComment = "comment"
TableCommentMetric = "comment_metric"
TableCommentContent = "comment_content" TableCommentContent = "comment_content"
TableCommentReply = "comment_reply" TableCommentReply = "comment_reply"
TableFollowing = "following" TableFollowing = "following"
@ -39,6 +40,7 @@ const (
TablePostStar = "post_star" TablePostStar = "post_star"
TableTag = "tag" TableTag = "tag"
TableUser = "user" TableUser = "user"
TableUserMetric = "user_metric"
TableWalletRecharge = "wallet_recharge" TableWalletRecharge = "wallet_recharge"
TableWalletStatement = "wallet_statement" TableWalletStatement = "wallet_statement"
) )

@ -102,8 +102,10 @@ type cacheConf struct {
UnreadMsgExpire int64 UnreadMsgExpire int64
UserTweetsExpire int64 UserTweetsExpire int64
IndexTweetsExpire int64 IndexTweetsExpire int64
TweetCommentsExpire int64
OnlineUserExpire int64 OnlineUserExpire int64
UserInfoExpire int64 UserInfoExpire int64
UserRelationExpire int64
} }
type eventManagerConf struct { type eventManagerConf struct {
@ -123,7 +125,8 @@ type metricManagerConf struct {
} }
type jobManagerConf struct { type jobManagerConf struct {
MaxOnlineInterval string MaxOnlineInterval string
UpdateMetricsInterval string
} }
type cacheIndexConf struct { type cacheIndexConf struct {
@ -344,6 +347,7 @@ func (s *databaseConf) TableNames() (res TableNameMap) {
TableAttachment, TableAttachment,
TableCaptcha, TableCaptcha,
TableComment, TableComment,
TableCommentMetric,
TableCommentContent, TableCommentContent,
TableCommentReply, TableCommentReply,
TableFollowing, TableFollowing,
@ -360,6 +364,7 @@ func (s *databaseConf) TableNames() (res TableNameMap) {
TablePostStar, TablePostStar,
TableTag, TableTag,
TableUser, TableUser,
TableUserMetric,
TableWalletRecharge, TableWalletRecharge,
TableWalletStatement, TableWalletStatement,
} }

@ -21,6 +21,7 @@ type CommentService interface {
// CommentManageService 评论管理服务 // CommentManageService 评论管理服务
type CommentManageService interface { type CommentManageService interface {
HighlightComment(userId, commentId int64) (int8, error)
DeleteComment(comment *ms.Comment) error DeleteComment(comment *ms.Comment) error
CreateComment(comment *ms.Comment) (*ms.Comment, error) CreateComment(comment *ms.Comment) (*ms.Comment, error)
CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error) CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error)

@ -15,9 +15,6 @@ type DataService interface {
// 话题服务 // 话题服务
TopicService TopicService
// 广场泡泡服务
// IndexPostsService
// 推文服务 // 推文服务
TweetService TweetService
TweetManageService TweetManageService
@ -25,6 +22,7 @@ type DataService interface {
// 推文指标服务 // 推文指标服务
TweetMetricServantA TweetMetricServantA
CommentMetricServantA
// 评论服务 // 评论服务
CommentService CommentService
@ -34,6 +32,7 @@ type DataService interface {
UserManageService UserManageService
ContactManageService ContactManageService
FollowingManageService FollowingManageService
UserRelationService
// 安全服务 // 安全服务
SecurityService SecurityService

@ -13,8 +13,15 @@ type TweetMetric struct {
UpvoteCount int64 UpvoteCount int64
CollectionCount int64 CollectionCount int64
ShareCount int64 ShareCount int64
ThumbdownCount int64 ThumbsUpCount int64
ThumbupCount int64 ThumbsDownCount int64
}
type CommentMetric struct {
CommentId int64
ReplyCount int32
ThumbsUpCount int32
ThumbsDownCount int32
} }
func (m *TweetMetric) RankScore(motivationFactor int) int64 { func (m *TweetMetric) RankScore(motivationFactor int) int64 {
@ -23,3 +30,10 @@ func (m *TweetMetric) RankScore(motivationFactor int) int64 {
} }
return (m.CommentCount + m.UpvoteCount*2 + m.CollectionCount*4 + m.ShareCount*8) * int64(motivationFactor) return (m.CommentCount + m.UpvoteCount*2 + m.CollectionCount*4 + m.ShareCount*8) * int64(motivationFactor)
} }
func (m *CommentMetric) RankScore(motivationFactor int) int64 {
if motivationFactor == 0 {
motivationFactor = 1
}
return int64(m.ReplyCount*2+m.ThumbsUpCount*4-m.ThumbsDownCount) * int64(motivationFactor)
}

@ -9,7 +9,19 @@ import (
) )
type TweetMetricServantA interface { type TweetMetricServantA interface {
UpdateRankScore(metric *cs.TweetMetric) error UpdateTweetMetric(metric *cs.TweetMetric) error
AddTweetMetric(postId int64) error AddTweetMetric(postId int64) error
DeleteTweetMetric(postId int64) error DeleteTweetMetric(postId int64) error
} }
type CommentMetricServantA interface {
UpdateCommentMetric(metric *cs.CommentMetric) error
AddCommentMetric(commentId int64) error
DeleteCommentMetric(commentId int64) error
}
type UserMetricServantA interface {
UpdateUserMetric(userId int64, action uint8) error
AddUserMetric(userId int64) error
DeleteUserMetric(userId int64) error
}

@ -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,38 @@ 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
expire int64
}
type cacheMyFollowIdsEvent struct {
event.UnimplementedEvent
ac core.AppCache
urs core.UserRelationService
userId int64
key string
expire int64
}
func OnExpireIndexTweetEvent(userId int64) {
// TODO: 这里暴躁的将所有 最新/热门/关注 的推文列表缓存都过期掉,后续需要更精细话处理
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), conf.PrefixIdxTweetsFollowing + "*",
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 +100,34 @@ 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,
expire: conf.CacheSetting.UserRelationExpire,
})
}
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,
expire: conf.CacheSetting.UserRelationExpire,
})
}
func (e *expireIndexTweetsEvent) Name() string { func (e *expireIndexTweetsEvent) Name() string {
return "expireIndexTweetsEvent" return "expireIndexTweetsEvent"
} }
@ -127,3 +172,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, e.expire)
}
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, e.expire)
return nil
}

@ -19,22 +19,22 @@ func (s *eventCacheIndexSrv) SendAction(act core.IdxAct, post *ms.Post) {
err := error(nil) err := error(nil)
switch act { switch act {
case core.IdxActUpdatePost: case core.IdxActUpdatePost:
err = s.tms.UpdateRankScore(&cs.TweetMetric{ err = s.tms.UpdateTweetMetric(&cs.TweetMetric{
PostId: post.ID, PostId: post.ID,
CommentCount: post.CommentCount, CommentCount: post.CommentCount,
UpvoteCount: post.UpvoteCount, UpvoteCount: post.UpvoteCount,
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)

@ -5,6 +5,7 @@
package jinzhu package jinzhu
import ( import (
"fmt"
"time" "time"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
@ -61,20 +62,21 @@ func (s *commentSrv) GetCommentThumbsMap(userId int64, tweetId int64) (cs.Commen
} }
func (s *commentSrv) GetComments(tweetId int64, style cs.StyleCommentType, limit int, offset int) (res []*ms.Comment, total int64, err error) { func (s *commentSrv) GetComments(tweetId int64, style cs.StyleCommentType, limit int, offset int) (res []*ms.Comment, total int64, err error) {
// TODO: 需要优化一下,更精细的调整评论排序策略 db := s.db.Table(_comment_)
sort := "id ASC" sort := "is_essence DESC, id ASC"
switch style { switch style {
case cs.StyleCommentHots: case cs.StyleCommentHots:
// TOOD: 暂时简单排序,后续需要根据 rank_score=评论回复数*2+点赞*4-点踩, order byrank_score DESC // rank_score=评论回复数*2+点赞*4-点踩, order byrank_score DESC
sort = "thumbs_up_count DESC, id DESC" db = db.Joins(fmt.Sprintf("LEFT JOIN %s m ON %s.id=m.comment_id AND m.is_del=0", _commentMetric_, _comment_))
sort = fmt.Sprintf("is_essence DESC, m.rank_score DESC, %s.id DESC", _comment_)
case cs.StyleCommentNewest: case cs.StyleCommentNewest:
sort = "id DESC" sort = "is_essence DESC, id DESC"
case cs.StyleCommentDefault: case cs.StyleCommentDefault:
fallthrough fallthrough
default: default:
// sort = "id ASC" // nothing
} }
db := s.db.Table(_comment_).Where("post_id=?", tweetId) db = db.Where("post_id=?", tweetId)
if err = db.Count(&total).Error; err != nil { if err = db.Count(&total).Error; err != nil {
return return
} }
@ -117,11 +119,9 @@ func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyForma
"comment_id IN ?": ids, "comment_id IN ?": ids,
"ORDER": "id ASC", "ORDER": "id ASC",
}, 0, 0) }, 0, 0)
if err != nil { if err != nil {
return nil, err return nil, err
} }
userIds := []int64{} userIds := []int64{}
for _, reply := range replies { for _, reply := range replies {
userIds = append(userIds, reply.UserID, reply.AtUserID) userIds = append(userIds, reply.UserID, reply.AtUserID)
@ -142,44 +142,61 @@ func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyForma
replyFormated.AtUser = user.Format() replyFormated.AtUser = user.Format()
} }
} }
repliesFormated = append(repliesFormated, replyFormated) repliesFormated = append(repliesFormated, replyFormated)
} }
return repliesFormated, nil return repliesFormated, nil
} }
func (s *commentManageSrv) DeleteComment(comment *ms.Comment) error { func (s *commentManageSrv) HighlightComment(userId, commentId int64) (res int8, err error) {
post := &dbr.Post{}
comment := &dbr.Comment{}
db := s.db.Model(comment)
if err = db.Where("id=?", commentId).First(comment).Error; err != nil {
return
}
if err = s.db.Table(_post_).Where("id=?", comment.PostID).First(post).Error; err != nil {
return
}
if post.UserID != userId {
return 0, cs.ErrNoPermission
}
comment.IsEssence = 1 - comment.IsEssence
return comment.IsEssence, db.Save(comment).Error
}
func (s *commentManageSrv) DeleteComment(comment *ms.Comment) (err error) {
db := s.db.Begin() db := s.db.Begin()
defer db.Rollback() defer db.Rollback()
if err = comment.Delete(db); err != nil {
err := comment.Delete(s.db) return
if err != nil {
return err
} }
err = db.Model(&dbr.TweetCommentThumbs{}).Where("user_id=? AND tweet_id=? AND comment_id=?", comment.UserID, comment.PostID, comment.ID).Updates(map[string]any{ err = db.Model(&dbr.TweetCommentThumbs{}).Where("user_id=? AND tweet_id=? AND comment_id=?", comment.UserID, comment.PostID, comment.ID).Updates(map[string]any{
"deleted_on": time.Now().Unix(), "deleted_on": time.Now().Unix(),
"is_del": 1, "is_del": 1,
}).Error }).Error
if err != nil { if err != nil {
return err return
} }
db.Commit() db.Commit()
return nil return
} }
func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) { func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) {
return comment.Create(s.db) return comment.Create(s.db)
} }
func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error) { func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (res *ms.CommentReply, err error) {
return reply.Create(s.db) if res, err = reply.Create(s.db); err == nil {
// 宽松处理错误
s.db.Table(_comment_).Where("id=?", reply.CommentID).Update("reply_count", gorm.Expr("reply_count+1"))
}
return
} }
func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error) { func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error) {
db := s.db.Begin() db := s.db.Begin()
defer db.Rollback() defer db.Rollback()
err = reply.Delete(s.db) err = reply.Delete(s.db)
if err != nil { if err != nil {
return return
@ -192,6 +209,8 @@ func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error
if err != nil { if err != nil {
return return
} }
// 宽松处理错误
db.Table(_comment_).Where("id=?", reply.CommentID).Update("reply_count", gorm.Expr("reply_count-1"))
db.Commit() db.Commit()
return return
} }

@ -17,6 +17,8 @@ type Comment struct {
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
IP string `json:"ip"` IP string `json:"ip"`
IPLoc string `json:"ip_loc"` IPLoc string `json:"ip_loc"`
IsEssence int8 `json:"is_essense"`
ReplyCount int32 `json:"reply_count"`
ThumbsUpCount int32 `json:"thumbs_up_count"` ThumbsUpCount int32 `json:"thumbs_up_count"`
ThumbsDownCount int32 `json:"-"` ThumbsDownCount int32 `json:"-"`
} }
@ -29,7 +31,9 @@ type CommentFormated struct {
Contents []*CommentContent `json:"contents"` Contents []*CommentContent `json:"contents"`
Replies []*CommentReplyFormated `json:"replies"` Replies []*CommentReplyFormated `json:"replies"`
IPLoc string `json:"ip_loc"` IPLoc string `json:"ip_loc"`
ReplyCount int32 `json:"reply_count"`
ThumbsUpCount int32 `json:"thumbs_up_count"` ThumbsUpCount int32 `json:"thumbs_up_count"`
IsEssence int8 `json:"is_essence"`
IsThumbsUp int8 `json:"is_thumbs_up"` IsThumbsUp int8 `json:"is_thumbs_up"`
IsThumbsDown int8 `json:"is_thumbs_down"` IsThumbsDown int8 `json:"is_thumbs_down"`
CreatedOn int64 `json:"created_on"` CreatedOn int64 `json:"created_on"`
@ -48,7 +52,9 @@ func (c *Comment) Format() *CommentFormated {
Contents: []*CommentContent{}, Contents: []*CommentContent{},
Replies: []*CommentReplyFormated{}, Replies: []*CommentReplyFormated{},
IPLoc: c.IPLoc, IPLoc: c.IPLoc,
ReplyCount: c.ReplyCount,
ThumbsUpCount: c.ThumbsUpCount, ThumbsUpCount: c.ThumbsUpCount,
IsEssence: c.IsEssence,
IsThumbsUp: types.No, IsThumbsUp: types.No,
IsThumbsDown: types.No, IsThumbsDown: types.No,
CreatedOn: c.CreatedOn, CreatedOn: c.CreatedOn,
@ -116,7 +122,6 @@ func (c *Comment) Count(db *gorm.DB, conditions *ConditionsT) (int64, error) {
func (c *Comment) Create(db *gorm.DB) (*Comment, error) { func (c *Comment) Create(db *gorm.DB) (*Comment, error) {
err := db.Create(&c).Error err := db.Create(&c).Error
return c, err return c, err
} }

@ -19,13 +19,53 @@ type PostMetric struct {
MotivationFactor int MotivationFactor int
} }
func (p *PostMetric) Create(db *gorm.DB) (*PostMetric, error) { type CommentMetric struct {
err := db.Create(&p).Error *Model
return p, err CommentId int64
RankScore int64
IncentiveScore int
DecayFactor int
MotivationFactor int
}
type UserMetric struct {
*Model
UserId int64
TweetsCount int
LatestTrendsOn int64
}
func (m *PostMetric) Create(db *gorm.DB) (*PostMetric, error) {
err := db.Create(&m).Error
return m, err
}
func (m *PostMetric) Delete(db *gorm.DB) error {
return db.Model(m).Where("post_id", m.PostId).Updates(map[string]any{
"deleted_on": time.Now().Unix(),
"is_del": 1,
}).Error
}
func (m *CommentMetric) Create(db *gorm.DB) (*CommentMetric, error) {
err := db.Create(&m).Error
return m, err
}
func (m *CommentMetric) Delete(db *gorm.DB) error {
return db.Model(m).Where("comment_id", m.CommentId).Updates(map[string]any{
"deleted_on": time.Now().Unix(),
"is_del": 1,
}).Error
}
func (m *UserMetric) Create(db *gorm.DB) (*UserMetric, error) {
err := db.Create(&m).Error
return m, err
} }
func (p *PostMetric) Delete(db *gorm.DB) error { func (m *UserMetric) Delete(db *gorm.DB) error {
return db.Model(p).Where("post_id", p.PostId).Updates(map[string]any{ return db.Model(m).Where("user_id", m.UserId).Updates(map[string]any{
"deleted_on": time.Now().Unix(), "deleted_on": time.Now().Unix(),
"is_del": 1, "is_del": 1,
}).Error }).Error

@ -28,12 +28,14 @@ type User struct {
} }
type UserFormated struct { type UserFormated struct {
ID int64 `db:"id" json:"id"` ID int64 `db:"id" json:"id"`
Nickname string `json:"nickname"` Nickname string `json:"nickname"`
Username string `json:"username"` Username string `json:"username"`
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 {

@ -15,6 +15,7 @@ var (
_attachment_ string _attachment_ string
_captcha_ string _captcha_ string
_comment_ string _comment_ string
_commentMetric_ string
_commentContent_ string _commentContent_ string
_commentReply_ string _commentReply_ string
_following_ string _following_ string
@ -31,6 +32,7 @@ var (
_postStar_ string _postStar_ string
_tag_ string _tag_ string
_user_ string _user_ string
_userMetric_ string
_walletRecharge_ string _walletRecharge_ string
_walletStatement_ string _walletStatement_ string
) )
@ -42,6 +44,7 @@ func initTableName() {
_attachment_ = m[conf.TableAttachment] _attachment_ = m[conf.TableAttachment]
_captcha_ = m[conf.TableCaptcha] _captcha_ = m[conf.TableCaptcha]
_comment_ = m[conf.TableComment] _comment_ = m[conf.TableComment]
_commentMetric_ = m[conf.TableCommentMetric]
_commentContent_ = m[conf.TableCommentContent] _commentContent_ = m[conf.TableCommentContent]
_commentReply_ = m[conf.TableCommentReply] _commentReply_ = m[conf.TableCommentReply]
_following_ = m[conf.TableFollowing] _following_ = m[conf.TableFollowing]
@ -58,6 +61,7 @@ func initTableName() {
_postStar_ = m[conf.TablePostStar] _postStar_ = m[conf.TablePostStar]
_tag_ = m[conf.TableTag] _tag_ = m[conf.TableTag]
_user_ = m[conf.TableUser] _user_ = m[conf.TableUser]
_userMetric_ = m[conf.TableUserMetric]
_walletRecharge_ = m[conf.TableWalletRecharge] _walletRecharge_ = m[conf.TableWalletRecharge]
_walletStatement_ = m[conf.TableWalletStatement] _walletStatement_ = m[conf.TableWalletStatement]
} }

@ -38,9 +38,11 @@ type dataSrv struct {
core.TweetMetricServantA core.TweetMetricServantA
core.CommentService core.CommentService
core.CommentManageService core.CommentManageService
core.CommentMetricServantA
core.UserManageService core.UserManageService
core.ContactManageService core.ContactManageService
core.FollowingManageService core.FollowingManageService
core.UserRelationService
core.SecurityService core.SecurityService
core.AttachmentCheckService core.AttachmentCheckService
} }
@ -56,10 +58,12 @@ func NewDataService() (core.DataService, core.VersionInfo) {
lazyInitial() lazyInitial()
db := conf.MustGormDB() db := conf.MustGormDB()
pvs := security.NewPhoneVerifyService() pvs := security.NewPhoneVerifyService()
tms := NewTweetMetricServentA(db) tms := newTweetMetricServentA(db)
cms := newCommentMetricServentA(db)
cis := cache.NewEventCacheIndexSrv(tms) cis := cache.NewEventCacheIndexSrv(tms)
ds := &dataSrv{ ds := &dataSrv{
TweetMetricServantA: tms, TweetMetricServantA: tms,
CommentMetricServantA: cms,
WalletService: newWalletService(db), WalletService: newWalletService(db),
MessageService: newMessageService(db), MessageService: newMessageService(db),
TopicService: newTopicService(db), TopicService: newTopicService(db),
@ -71,6 +75,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(),
} }

@ -15,7 +15,15 @@ type tweetMetricSrvA struct {
db *gorm.DB db *gorm.DB
} }
func (s *tweetMetricSrvA) UpdateRankScore(metric *cs.TweetMetric) error { type commentMetricSrvA struct {
db *gorm.DB
}
type userMetricSrvA struct {
db *gorm.DB
}
func (s *tweetMetricSrvA) UpdateTweetMetric(metric *cs.TweetMetric) error {
return s.db.Transaction(func(tx *gorm.DB) (err error) { return s.db.Transaction(func(tx *gorm.DB) (err error) {
postMetric := &dbr.PostMetric{PostId: metric.PostId} postMetric := &dbr.PostMetric{PostId: metric.PostId}
db := s.db.Model(postMetric).Where("post_id=?", metric.PostId) db := s.db.Model(postMetric).Where("post_id=?", metric.PostId)
@ -35,8 +43,54 @@ func (s *tweetMetricSrvA) DeleteTweetMetric(postId int64) (err error) {
return (&dbr.PostMetric{PostId: postId}).Delete(s.db) return (&dbr.PostMetric{PostId: postId}).Delete(s.db)
} }
func NewTweetMetricServentA(db *gorm.DB) core.TweetMetricServantA { func (s *commentMetricSrvA) UpdateCommentMetric(metric *cs.CommentMetric) error {
return s.db.Transaction(func(tx *gorm.DB) (err error) {
commentMetric := &dbr.CommentMetric{CommentId: metric.CommentId}
db := s.db.Model(commentMetric).Where("comment_id=?", metric.CommentId)
db.First(commentMetric)
commentMetric.RankScore = metric.RankScore(commentMetric.MotivationFactor)
err = db.Save(commentMetric).Error
return
})
}
func (s *commentMetricSrvA) AddCommentMetric(commentId int64) (err error) {
_, err = (&dbr.CommentMetric{CommentId: commentId}).Create(s.db)
return
}
func (s *commentMetricSrvA) DeleteCommentMetric(commentId int64) (err error) {
return (&dbr.CommentMetric{CommentId: commentId}).Delete(s.db)
}
func (s *userMetricSrvA) UpdateUserMetric(userId int64, action uint8) error {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) AddUserMetric(userId int64) (err error) {
_, err = (&dbr.UserMetric{UserId: userId}).Create(s.db)
return
}
func (s *userMetricSrvA) DeleteUserMetric(userId int64) (err error) {
return (&dbr.UserMetric{UserId: userId}).Delete(s.db)
}
func newTweetMetricServentA(db *gorm.DB) core.TweetMetricServantA {
return &tweetMetricSrvA{ return &tweetMetricSrvA{
db: db, db: db,
} }
} }
func newCommentMetricServentA(db *gorm.DB) core.CommentMetricServantA {
return &commentMetricSrvA{
db: db,
}
}
func newUserMetricServentA(db *gorm.DB) core.UserMetricServantA {
return &userMetricSrvA{
db: db,
}
}

@ -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
}

@ -65,6 +65,11 @@ func (s *commentManageSrv) DeleteComment(comment *ms.Comment) error {
return nil return nil
} }
func (s *commentManageSrv) HighlightComment(userId, commentId int64) (res int8, err error) {
// TODO
return 0, cs.ErrNotImplemented
}
func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) { func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) {
// TODO // TODO
debug.NotImplemented() debug.NotImplemented()

@ -14,7 +14,15 @@ type tweetMetricSrvA struct {
*pgxSrv *pgxSrv
} }
func (s *tweetMetricSrvA) UpdateRankScore(metric *cs.TweetMetric) error { type commentMetricSrvA struct {
*pgxSrv
}
type userMetricSrvA struct {
*pgxSrv
}
func (s *tweetMetricSrvA) UpdateTweetMetric(metric *cs.TweetMetric) error {
// TODO // TODO
return cs.ErrNotImplemented return cs.ErrNotImplemented
} }
@ -29,8 +37,50 @@ func (s *tweetMetricSrvA) DeleteTweetMetric(postId int64) (err error) {
return cs.ErrNotImplemented return cs.ErrNotImplemented
} }
func NewTweetMetricServentA(db *pgx.Conn) core.TweetMetricServantA { func (s *commentMetricSrvA) UpdateCommentMetric(metric *cs.CommentMetric) error {
// TODO
return cs.ErrNotImplemented
}
func (s *commentMetricSrvA) AddCommentMetric(commentId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func (s *commentMetricSrvA) DeleteCommentMetric(commentId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) UpdateUserMetric(userId int64, action uint8) error {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) AddUserMetric(userId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func (s *userMetricSrvA) DeleteUserMetric(userId int64) (err error) {
// TODO
return cs.ErrNotImplemented
}
func newTweetMetricServentA(db *pgx.Conn) core.TweetMetricServantA {
return &tweetMetricSrvA{ return &tweetMetricSrvA{
pgxSrv: newPgxSrv(db), pgxSrv: newPgxSrv(db),
} }
} }
func newCommentMetricServentA(db *pgx.Conn) core.CommentMetricServantA {
return &commentMetricSrvA{
pgxSrv: newPgxSrv(db),
}
}
func newUserMetricServentA(db *pgx.Conn) core.UserMetricServantA {
return &userMetricSrvA{
pgxSrv: newPgxSrv(db),
}
}

@ -32,9 +32,11 @@ 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
core.TweetMetricServantA core.TweetMetricServantA
core.CommentMetricServantA
} }
type webDataSrvA struct { type webDataSrvA struct {
@ -47,10 +49,12 @@ type webDataSrvA struct {
func NewDataService() (core.DataService, core.VersionInfo) { func NewDataService() (core.DataService, core.VersionInfo) {
db := pgxDB() db := pgxDB()
pvs := security.NewPhoneVerifyService() pvs := security.NewPhoneVerifyService()
tms := NewTweetMetricServentA(db) cms := newCommentMetricServentA(db)
tms := newTweetMetricServentA(db)
cis := cache.NewEventCacheIndexSrv(tms) cis := cache.NewEventCacheIndexSrv(tms)
ds := &dataSrv{ ds := &dataSrv{
TweetMetricServantA: tms, TweetMetricServantA: tms,
CommentMetricServantA: cms,
WalletService: newWalletService(db), WalletService: newWalletService(db),
MessageService: newMessageService(db), MessageService: newMessageService(db),
TopicService: newTopicService(db), TopicService: newTopicService(db),
@ -62,6 +66,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(),
} }

@ -7,6 +7,7 @@ package slonik
import ( import (
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms" "github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/pkg/debug" "github.com/rocboss/paopao-ce/pkg/debug"
) )
@ -19,6 +20,10 @@ type userManageSrv struct {
*pgxSrv *pgxSrv
} }
type userRelationSrv struct {
*pgxSrv
}
func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) { func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) {
// TODO // TODO
debug.NotImplemented() debug.NotImplemented()
@ -67,8 +72,34 @@ func (s *userManageSrv) UpdateUser(user *ms.User) error {
return nil return nil
} }
func (s *userRelationSrv) MyFriendIds(userId int64) (res []int64, err error) {
// TODO
return nil, cs.ErrNotImplemented
}
func (s *userRelationSrv) MyFollowIds(userId int64) (res []int64, err error) {
// TODO
return nil, cs.ErrNotImplemented
}
func (s *userRelationSrv) IsMyFriend(userId int64, friendIds ...int64) (map[int64]bool, error) {
// TODO
return nil, cs.ErrNotImplemented
}
func (s *userRelationSrv) IsMyFollow(userId int64, followIds ...int64) (map[int64]bool, error) {
// TODO
return nil, cs.ErrNotImplemented
}
func newUserManageService(db *pgx.Conn) core.UserManageService { func newUserManageService(db *pgx.Conn) core.UserManageService {
return &userManageSrv{ return &userManageSrv{
pgxSrv: newPgxSrv(db), pgxSrv: newPgxSrv(db),
} }
} }
func newUserRelationService(db *pgx.Conn) core.UserRelationService {
return &userRelationSrv{
pgxSrv: newPgxSrv(db),
}
}

@ -16,7 +16,7 @@ import (
var ( var (
_defaultEventManager EventManager _defaultEventManager EventManager
_defaultJobManager JobManager _defaultJobManager JobManager = emptyJobManager{}
_onceInitial sync.Once _onceInitial sync.Once
) )

@ -6,6 +6,7 @@ package events
import ( import (
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
"github.com/rocboss/paopao-ce/pkg/types"
) )
type ( type (
@ -38,31 +39,49 @@ type JobManager interface {
Schedule(Job) EntryID Schedule(Job) EntryID
} }
type jobManager struct { type emptyJobManager types.Empty
type simpleJobManager struct {
m *cron.Cron m *cron.Cron
} }
func (j *jobManager) Start() { func (emptyJobManager) Start() {
// nothing
}
func (emptyJobManager) Stop() {
// nothing
}
func (emptyJobManager) Remove(id EntryID) {
// nothing
}
func (emptyJobManager) Schedule(job Job) EntryID {
return 0
}
func (j *simpleJobManager) Start() {
j.m.Start() j.m.Start()
} }
func (j *jobManager) Stop() { func (j *simpleJobManager) Stop() {
j.m.Stop() j.m.Stop()
} }
// Remove an entry from being run in the future. // Remove an entry from being run in the future.
func (j *jobManager) Remove(id EntryID) { func (j *simpleJobManager) Remove(id EntryID) {
j.m.Remove(id) j.m.Remove(id)
} }
// Schedule adds a Job to the Cron to be run on the given schedule. // Schedule adds a Job to the Cron to be run on the given schedule.
// The job is wrapped with the configured Chain. // The job is wrapped with the configured Chain.
func (j *jobManager) Schedule(job Job) EntryID { func (j *simpleJobManager) Schedule(job Job) EntryID {
return j.m.Schedule(job, job) return j.m.Schedule(job, job)
} }
func NewJobManager() JobManager { func NewJobManager() JobManager {
return &jobManager{ return &simpleJobManager{
m: cron.New(), m: cron.New(),
} }
} }

@ -0,0 +1,57 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package prometheus
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/sirupsen/logrus"
)
type metrics struct {
siteInfo *prometheus.GaugeVec
ds core.DataService
wc core.WebCache
}
func (m *metrics) updateSiteInfo() {
if onlineUserKeys, err := m.wc.Keys(conf.PrefixOnlineUser + "*"); err == nil {
maxOnline := len(onlineUserKeys)
m.siteInfo.With(prometheus.Labels{"name": "max_online"}).Set(float64(maxOnline))
} else {
logrus.Warnf("update promethues metrics[site_info_max_online] occurs error: %s", err)
}
if registerUserCount, err := m.ds.GetRegisterUserCount(); err == nil {
m.siteInfo.With(prometheus.Labels{"name": "register_user_count"}).Set(float64(registerUserCount))
} else {
logrus.Warnf("update promethues metrics[site_info_register_user_count] occurs error: %s", err)
}
}
func (m *metrics) onUpdate() {
logrus.Debugf("update promethues metrics job running")
m.updateSiteInfo()
}
func newMetrics(reg prometheus.Registerer, ds core.DataService, wc core.WebCache) *metrics {
m := &metrics{
siteInfo: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "paopao",
Subsystem: "site",
Name: "simple_info",
Help: "paopao-ce site simple information.",
},
[]string{
// metric name
"name",
}),
ds: ds,
wc: wc,
}
reg.MustRegister(m.siteInfo)
return m
}

@ -0,0 +1,41 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package prometheus
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/robfig/cron/v3"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/events"
"github.com/sirupsen/logrus"
)
func scheduleJobs(metrics *metrics) {
spec := conf.JobManagerSetting.UpdateMetricsInterval
schedule, err := cron.ParseStandard(spec)
if err != nil {
panic(err)
}
events.OnTask(schedule, metrics.onUpdate)
logrus.Debug("shedule prometheus metrics update jobs complete")
}
func NewHandler(ds core.DataService, wc core.WebCache) http.Handler {
// Create non-global registry.
registry := prometheus.NewRegistry()
// Add go runtime metrics and process collectors.
registry.MustRegister(
collectors.NewGoCollector(),
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
)
metrics := newMetrics(registry, ds, wc)
scheduleJobs(metrics)
return promhttp.HandlerFor(registry, promhttp.HandlerOpts{EnableOpenMetrics: true})
}

@ -7,8 +7,10 @@ package web
import ( import (
"github.com/alimy/mir/v4" "github.com/alimy/mir/v4"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"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/cs" "github.com/rocboss/paopao-ce/internal/core/cs"
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/servants/base" "github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/pkg/app" "github.com/rocboss/paopao-ce/pkg/app"
@ -45,7 +47,9 @@ type TweetCommentsReq struct {
PageSize int `form:"-" binding:"-"` PageSize int `form:"-" binding:"-"`
} }
type TweetCommentsResp base.PageResp type TweetCommentsResp struct {
joint.CachePageResp
}
type TimelineReq struct { type TimelineReq struct {
BaseInfo `form:"-" binding:"-"` BaseInfo `form:"-" binding:"-"`
@ -106,6 +110,13 @@ type TopicListResp struct {
ExtralTopics cs.TagList `json:"extral_topics,omitempty"` ExtralTopics cs.TagList `json:"extral_topics,omitempty"`
} }
type TweetDetailReq struct {
SimpleInfo `form:"-" binding:"-"`
TweetId int64 `form:"id"`
}
type TweetDetailResp ms.PostFormated
func (r *GetUserTweetsReq) SetPageInfo(page int, pageSize int) { func (r *GetUserTweetsReq) SetPageInfo(page int, pageSize int) {
r.Page, r.PageSize = page, pageSize r.Page, r.PageSize = page, pageSize
} }
@ -137,3 +148,17 @@ func (s CommentStyleType) ToInnerValue() (res cs.StyleCommentType) {
} }
return return
} }
func (s CommentStyleType) String() (res string) {
switch s {
case "default":
res = conf.InfixCommentDefault
case "hots":
res = conf.InfixCommentHots
case "newest":
res = conf.InfixCommentNewest
default:
res = "_"
}
return
}

@ -147,6 +147,16 @@ type DeleteCommentReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"` ID int64 `json:"id" binding:"required"`
} }
type HighlightCommentReq struct {
SimpleInfo `json:"-" binding:"-"`
CommentId int64 `json:"id" binding:"required"`
}
type HighlightCommentResp struct {
HighlightStatus int8 `json:"highlight_status"`
}
type DeleteCommentReplyReq struct { type DeleteCommentReplyReq struct {
BaseInfo `json:"-" binding:"-"` BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"` ID int64 `json:"id" binding:"required"`

@ -5,16 +5,9 @@
package web package web
import ( import (
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/pkg/version" "github.com/rocboss/paopao-ce/pkg/version"
) )
type TweetDetailReq struct {
TweetId int64 `form:"id"`
}
type TweetDetailResp ms.PostFormated
type GetCaptchaResp struct { type GetCaptchaResp struct {
Id string `json:"id"` Id string `json:"id"`
Content string `json:"b64s"` Content string `json:"b64s"`

@ -50,14 +50,15 @@ var (
ErrGetPostsUnknowStyle = xerror.NewError(30014, "使用未知样式参数获取动态列表") ErrGetPostsUnknowStyle = xerror.NewError(30014, "使用未知样式参数获取动态列表")
ErrGetPostsNilUser = xerror.NewError(30015, "使用游客账户获取动态详情失败") ErrGetPostsNilUser = xerror.NewError(30015, "使用游客账户获取动态详情失败")
ErrGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败") ErrGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败")
ErrCreateCommentFailed = xerror.NewError(40002, "评论发布失败") ErrCreateCommentFailed = xerror.NewError(40002, "评论发布失败")
ErrGetCommentFailed = xerror.NewError(40003, "获取评论详情失败") ErrGetCommentFailed = xerror.NewError(40003, "获取评论详情失败")
ErrDeleteCommentFailed = xerror.NewError(40004, "评论删除失败") ErrDeleteCommentFailed = xerror.NewError(40004, "评论删除失败")
ErrCreateReplyFailed = xerror.NewError(40005, "评论回复失败") ErrCreateReplyFailed = xerror.NewError(40005, "评论回复失败")
ErrGetReplyFailed = xerror.NewError(40006, "获取评论详情失败") ErrGetReplyFailed = xerror.NewError(40006, "获取评论详情失败")
ErrMaxCommentCount = xerror.NewError(40007, "评论数已达最大限制") ErrMaxCommentCount = xerror.NewError(40007, "评论数已达最大限制")
ErrGetCommentThumbs = xerror.NewError(40008, "获取评论点赞信息失败") ErrGetCommentThumbs = xerror.NewError(40008, "获取评论点赞信息失败")
ErrHighlightCommentFailed = xerror.NewError(40009, "设置精选评论失败")
ErrGetMessagesFailed = xerror.NewError(50001, "获取消息列表失败") ErrGetMessagesFailed = xerror.NewError(50001, "获取消息列表失败")
ErrReadMessageFailed = xerror.NewError(50002, "标记消息已读失败") ErrReadMessageFailed = xerror.NewError(50002, "标记消息已读失败")

@ -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,109 @@ func (s *BaseServant) Render(c *gin.Context, data any, err mir.Error) {
} }
} }
func (s *DaoServant) PrepareUser(userId int64, user *ms.UserFormated) error {
// guest用户的userId<0
if userId < 0 {
return nil
}
// friendMap, err := s.Ds.IsMyFriend(userId, user.ID)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, user.ID)
if err != nil {
return err
}
// user.IsFriend, user.IsFollowing = friendMap[user.ID], followMap[user.ID]
user.IsFollowing = followMap[user.ID]
return nil
}
func (s *DaoServant) PrepareMessages(userId int64, messages []*ms.MessageFormated) error {
// guest用户的userId<0
if userId < 0 {
return nil
}
userIds := make([]int64, 0, len(messages))
for _, msg := range messages {
if msg.SenderUser != nil {
userIds = append(userIds, msg.SenderUserID)
}
if msg.ReceiverUser != nil {
userIds = append(userIds, msg.ReceiverUserID)
}
}
// 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 _, msg := range messages {
if msg.SenderUser != nil {
// msg.SenderUser.IsFriend, msg.SenderUser.IsFollowing = friendMap[msg.SenderUserID], followMap[msg.SenderUserID]
msg.SenderUser.IsFollowing = followMap[msg.SenderUserID]
}
if msg.ReceiverUser != nil {
// msg.ReceiverUser.IsFriend, msg.ReceiverUser.IsFollowing = friendMap[msg.ReceiverUserID], followMap[msg.ReceiverUserID]
msg.ReceiverUser.IsFollowing = followMap[msg.ReceiverUserID]
}
}
return nil
}
func (s *DaoServant) PrepareTweet(userId int64, tweet *ms.PostFormated) error {
// 转换一下可见性的值
tweet.Visibility = ms.PostVisibleT(tweet.Visibility.ToOutValue())
// guest用户的userId<0
if userId < 0 {
return nil
}
// friendMap, err := s.Ds.IsMyFriend(userId, userIds)
// if err != nil {
// return err
// }
followMap, err := s.Ds.IsMyFollow(userId, tweet.UserID)
if err != nil {
return err
}
// tweet.User.IsFriend, tweet.User.IsFollowing = friendMap[tweet.UserID], followMap[tweet.UserID]
tweet.User.IsFollowing = followMap[tweet.UserID]
return nil
}
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 +382,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,

@ -124,6 +124,10 @@ func (s *coreSrv) GetMessages(req *web.GetMessagesReq) (*web.GetMessagesResp, mi
logrus.Errorf("Ds.GetMessages err: %v\n", err) logrus.Errorf("Ds.GetMessages err: %v\n", err)
return nil, web.ErrGetMessagesFailed return nil, web.ErrGetMessagesFailed
} }
if err = s.PrepareMessages(req.UserId, messages); err != nil {
logrus.Errorf("get messages err[2]: %v\n", err)
return nil, web.ErrGetMessagesFailed
}
totalRows, _ := s.Ds.GetMessageCount(req.UserId) totalRows, _ := s.Ds.GetMessageCount(req.UserId)
resp := base.PageRespFrom(messages, req.Page, req.PageSize, totalRows) resp := base.PageRespFrom(messages, req.Page, req.PageSize, totalRows)
return (*web.GetMessagesResp)(resp), nil return (*web.GetMessagesResp)(resp), nil
@ -191,7 +195,6 @@ func (s *coreSrv) GetCollections(req *web.GetCollectionsReq) (*web.GetCollection
logrus.Errorf("Ds.GetUserPostCollectionCount err: %s", err) logrus.Errorf("Ds.GetUserPostCollectionCount err: %s", err)
return nil, web.ErrGetCollectionsFailed return nil, web.ErrGetCollectionsFailed
} }
var posts []*ms.Post var posts []*ms.Post
for _, collection := range collections { for _, collection := range collections {
posts = append(posts, collection.Post) posts = append(posts, collection.Post)
@ -201,8 +204,11 @@ func (s *coreSrv) GetCollections(req *web.GetCollectionsReq) (*web.GetCollection
logrus.Errorf("Ds.MergePosts err: %s", err) logrus.Errorf("Ds.MergePosts err: %s", err)
return nil, web.ErrGetCollectionsFailed return nil, web.ErrGetCollectionsFailed
} }
if err = s.PrepareTweets(req.UserId, postsFormated); err != nil {
logrus.Errorf("get collections prepare tweets err: %s", err)
return nil, web.ErrGetCollectionsFailed
}
resp := base.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows) resp := base.PageRespFrom(postsFormated, req.Page, req.PageSize, totalRows)
return (*web.GetCollectionsResp)(resp), nil return (*web.GetCollectionsResp)(resp), nil
} }

@ -9,13 +9,26 @@ import (
"fmt" "fmt"
"github.com/alimy/tryst/event" "github.com/alimy/tryst/event"
"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/cs"
"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/rocboss/paopao-ce/internal/model/joint" "github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/model/web" "github.com/rocboss/paopao-ce/internal/model/web"
) )
const (
_commentActionCreate uint8 = iota
_commentActionDelete
_commentActionThumbsUp
_commentActionThumbsDown
_commentActionReplyCreate
_commentActionReplyDelete
_commentActionReplyThumbsUp
_commentActionReplyThumbsDown
)
type cacheUnreadMsgEvent struct { type cacheUnreadMsgEvent struct {
event.UnimplementedEvent event.UnimplementedEvent
ds core.DataService ds core.DataService
@ -30,6 +43,25 @@ type createMessageEvent struct {
message *ms.Message message *ms.Message
} }
type commentActionEvent struct {
event.UnimplementedEvent
ds core.DataService
ac core.AppCache
tweetId int64
commentId int64
action uint8
}
func onCommentActionEvent(tweetId int64, commentId int64, action uint8) {
events.OnEvent(&commentActionEvent{
ds: _ds,
ac: _ac,
tweetId: tweetId,
commentId: commentId,
action: action,
})
}
func onCacheUnreadMsgEvent(uid int64) { func onCacheUnreadMsgEvent(uid int64) {
events.OnEvent(&cacheUnreadMsgEvent{ events.OnEvent(&cacheUnreadMsgEvent{
ds: _ds, ds: _ds,
@ -86,3 +118,51 @@ func (e *createMessageEvent) Action() (err error) {
} }
return return
} }
func (e *commentActionEvent) Name() string {
return "updateCommentMetricEvent"
}
func (e *commentActionEvent) Action() (err error) {
// logrus.Debugf("trigger commentActionEvent action commentId[%d]", e.commentId)
switch e.action {
case _commentActionCreate:
err = e.ds.AddCommentMetric(e.commentId)
e.expireAllStyleComments()
case _commentActionDelete:
err = e.ds.DeleteCommentMetric(e.commentId)
e.expireAllStyleComments()
case _commentActionReplyCreate, _commentActionReplyDelete:
err = e.updateCommentMetric()
e.expireAllStyleComments()
case _commentActionThumbsUp, _commentActionThumbsDown:
err = e.updateCommentMetric()
e.expireHotsComments()
default:
// nothing
}
return
}
func (e *commentActionEvent) expireHotsComments() {
e.ac.DelAny(fmt.Sprintf("%s%d:%s:*", conf.PrefixTweetComment, e.tweetId, conf.InfixCommentHots))
}
func (e *commentActionEvent) expireAllStyleComments() {
e.ac.DelAny(fmt.Sprintf("%s%d:*", conf.PrefixTweetComment, e.tweetId))
}
func (e *commentActionEvent) updateCommentMetric() error {
// logrus.Debug("trigger commentActionEvent action[updateCommentMetric]")
comment, err := e.ds.GetCommentByID(e.commentId)
if err != nil {
return err
}
e.ds.UpdateCommentMetric(&cs.CommentMetric{
CommentId: e.commentId,
ReplyCount: comment.ReplyCount,
ThumbsUpCount: comment.ThumbsUpCount,
ThumbsDownCount: comment.ThumbsDownCount,
})
return nil
}

@ -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
} }

@ -32,10 +32,12 @@ type looseSrv struct {
ac core.AppCache ac core.AppCache
userTweetsExpire int64 userTweetsExpire int64
idxTweetsExpire int64 idxTweetsExpire int64
tweetCommentsExpire int64
prefixUserTweets string prefixUserTweets string
prefixIdxTweetsNewest string prefixIdxTweetsNewest string
prefixIdxTweetsHots string prefixIdxTweetsHots string
prefixIdxTweetsFollowing string prefixIdxTweetsFollowing string
prefixTweetComment string
} }
func (s *looseSrv) Chain() gin.HandlersChain { func (s *looseSrv) Chain() gin.HandlersChain {
@ -61,8 +63,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 +106,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 +114,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)
@ -119,17 +133,17 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
} }
func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset int) (res *web.TimelineResp, key string, ok bool) { func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset int) (res *web.TimelineResp, key string, ok bool) {
username := "_"
if req.User != nil {
username = req.User.Username
}
switch req.Style { switch req.Style {
case web.StyleTweetsFollowing: case web.StyleTweetsFollowing:
username := "_"
if req.User != nil {
username = req.User.Username
}
key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsFollowing, username, offset, limit) key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsFollowing, username, offset, limit)
case web.StyleTweetsNewest: case web.StyleTweetsNewest:
key = fmt.Sprintf("%s%d:%d", s.prefixIdxTweetsNewest, offset, limit) key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsNewest, username, offset, limit)
case web.StyleTweetsHots: case web.StyleTweetsHots:
key = fmt.Sprintf("%s%d:%d", s.prefixIdxTweetsHots, offset, limit) key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsHots, username, offset, limit)
default: default:
return return
} }
@ -143,6 +157,18 @@ func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset
return return
} }
func (s *looseSrv) tweetCommentsFromCache(req *web.TweetCommentsReq, limit int, offset int) (res *web.TweetCommentsResp, key string, ok bool) {
key = fmt.Sprintf("%s%d:%s:%d:%d", s.prefixTweetComment, req.TweetId, req.Style, limit, offset)
if data, err := s.ac.Get(key); err == nil {
ok, res = true, &web.TweetCommentsResp{
CachePageResp: joint.CachePageResp{
JsonResp: data,
},
}
}
return
}
func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (res *web.GetUserTweetsResp, err mir.Error) { func (s *looseSrv) GetUserTweets(req *web.GetUserTweetsReq) (res *web.GetUserTweetsResp, err mir.Error) {
user, xerr := s.RelationTypFrom(req.User, req.Username) user, xerr := s.RelationTypFrom(req.User, req.Username)
if xerr != nil { if xerr != nil {
@ -198,7 +224,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 +238,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 +265,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 return nil, web.ErrGetPostsFailed
} }
// TODO: 暂时处理,需要去掉这个步骤 userId := int64(-1)
visbleTansform(postFormated) if req.User != nil {
resp := joint.PageRespFrom(postFormated, req.Page, req.PageSize, total) userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("s.listUserTweets err[4]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
return &web.GetUserTweetsResp{ return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{ CachePageResp: joint.CachePageResp{
Data: resp, Data: resp,
@ -281,8 +319,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{
@ -363,9 +407,18 @@ func (s *looseSrv) TopicList(req *web.TopicListReq) (*web.TopicListResp, mir.Err
}, nil }, nil
} }
func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) { func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (res *web.TweetCommentsResp, err mir.Error) {
comments, totalRows, err := s.Ds.GetComments(req.TweetId, req.Style.ToInnerValue(), req.PageSize, (req.Page-1)*req.PageSize) limit, offset := req.PageSize, (req.Page-1)*req.PageSize
if err != nil { // 尝试直接从缓存中获取数据
key, ok := "", false
if res, key, ok = s.tweetCommentsFromCache(req, limit, offset); ok {
logrus.Debugf("looseSrv.TweetComments from cache key:%s", key)
return
}
comments, totalRows, xerr := s.Ds.GetComments(req.TweetId, req.Style.ToInnerValue(), limit, offset)
if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[1]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
@ -376,25 +429,29 @@ func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsR
commentIDs = append(commentIDs, comment.ID) commentIDs = append(commentIDs, comment.ID)
} }
users, err := s.Ds.GetUsersByIDs(userIDs) users, xerr := s.Ds.GetUsersByIDs(userIDs)
if err != nil { if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[2]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
contents, err := s.Ds.GetCommentContentsByIDs(commentIDs) contents, xerr := s.Ds.GetCommentContentsByIDs(commentIDs)
if err != nil { if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[3]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
replies, err := s.Ds.GetCommentRepliesByID(commentIDs) replies, xerr := s.Ds.GetCommentRepliesByID(commentIDs)
if err != nil { if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[4]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
var commentThumbs, replyThumbs cs.CommentThumbsMap var commentThumbs, replyThumbs cs.CommentThumbsMap
if req.Uid > 0 { if req.Uid > 0 {
commentThumbs, replyThumbs, err = s.Ds.GetCommentThumbsMap(req.Uid, req.TweetId) commentThumbs, replyThumbs, xerr = s.Ds.GetCommentThumbsMap(req.Uid, req.TweetId)
if err != nil { if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[5]: %s", xerr)
return nil, web.ErrGetCommentsFailed return nil, web.ErrGetCommentsFailed
} }
} }
@ -434,8 +491,41 @@ func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsR
} }
commentsFormated = append(commentsFormated, commentFormated) commentsFormated = append(commentsFormated, commentFormated)
} }
resp := base.PageRespFrom(commentsFormated, req.Page, req.PageSize, totalRows) resp := joint.PageRespFrom(commentsFormated, req.Page, req.PageSize, totalRows)
return (*web.TweetCommentsResp)(resp), nil // 缓存处理
base.OnCacheRespEvent(s.ac, key, resp, s.tweetCommentsExpire)
return &web.TweetCommentsResp{
CachePageResp: joint.CachePageResp{
Data: resp,
},
}, nil
}
func (s *looseSrv) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
post, err := s.Ds.GetPostByID(req.TweetId)
if err != nil {
return nil, web.ErrGetPostFailed
}
postContents, err := s.Ds.GetPostContentsByIDs([]int64{post.ID})
if err != nil {
return nil, web.ErrGetPostFailed
}
users, err := s.Ds.GetUsersByIDs([]int64{post.UserID})
if err != nil {
return nil, web.ErrGetPostFailed
}
// 数据整合
postFormated := post.Format()
for _, user := range users {
postFormated.User = user.Format()
}
for _, content := range postContents {
if content.PostID == post.ID {
postFormated.Contents = append(postFormated.Contents, content.Format())
}
}
s.PrepareTweet(req.Uid, postFormated)
return (*web.TweetDetailResp)(postFormated), nil
} }
func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose { func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose {
@ -445,9 +535,11 @@ func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose {
ac: ac, ac: ac,
userTweetsExpire: cs.UserTweetsExpire, userTweetsExpire: cs.UserTweetsExpire,
idxTweetsExpire: cs.IndexTweetsExpire, idxTweetsExpire: cs.IndexTweetsExpire,
tweetCommentsExpire: cs.TweetCommentsExpire,
prefixUserTweets: conf.PrefixUserTweets, prefixUserTweets: conf.PrefixUserTweets,
prefixIdxTweetsNewest: conf.PrefixIdxTweetsNewest, prefixIdxTweetsNewest: conf.PrefixIdxTweetsNewest,
prefixIdxTweetsHots: conf.PrefixIdxTweetsHots, prefixIdxTweetsHots: conf.PrefixIdxTweetsHots,
prefixIdxTweetsFollowing: conf.PrefixIdxTweetsFollowing, prefixIdxTweetsFollowing: conf.PrefixIdxTweetsFollowing,
prefixTweetComment: conf.PrefixTweetComment,
} }
} }

@ -82,6 +82,8 @@ func (s *privSrv) ThumbsDownTweetComment(req *web.TweetCommentThumbsReq) mir.Err
logrus.Errorf("thumbs down tweet comment error: %s req:%v", err, req) logrus.Errorf("thumbs down tweet comment error: %s req:%v", err, req)
return web.ErrThumbsDownTweetComment return web.ErrThumbsDownTweetComment
} }
// 缓存处理
onCommentActionEvent(req.TweetId, req.CommentId, _commentActionThumbsDown)
return nil return nil
} }
@ -90,6 +92,8 @@ func (s *privSrv) ThumbsUpTweetComment(req *web.TweetCommentThumbsReq) mir.Error
logrus.Errorf("thumbs up tweet comment error: %s req:%v", err, req) logrus.Errorf("thumbs up tweet comment error: %s req:%v", err, req)
return web.ErrThumbsUpTweetComment return web.ErrThumbsUpTweetComment
} }
// 缓存处理
onCommentActionEvent(req.TweetId, req.CommentId, _commentActionThumbsUp)
return nil return nil
} }
@ -355,10 +359,14 @@ func (s *privSrv) DeleteCommentReply(req *web.DeleteCommentReplyReq) mir.Error {
logrus.Errorf("s.deletePostCommentReply err: %s", err) logrus.Errorf("s.deletePostCommentReply err: %s", err)
return web.ErrDeleteCommentFailed return web.ErrDeleteCommentFailed
} }
// 缓存处理, 宽松处理错误
if comment, err := s.Ds.GetCommentByID(reply.CommentID); err == nil {
onCommentActionEvent(comment.PostID, comment.ID, _commentActionReplyDelete)
}
return nil return nil
} }
func (s *privSrv) CreateCommentReply(req *web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error) { func (s *privSrv) CreateCommentReply(req *web.CreateCommentReplyReq) (_ *web.CreateCommentReplyResp, xerr mir.Error) {
var ( var (
post *ms.Post post *ms.Post
comment *ms.Comment comment *ms.Comment
@ -433,6 +441,8 @@ func (s *privSrv) CreateCommentReply(req *web.CreateCommentReplyReq) (*web.Creat
}) })
} }
} }
// 缓存处理
onCommentActionEvent(comment.PostID, comment.ID, _commentActionReplyCreate)
return (*web.CreateCommentReplyResp)(reply), nil return (*web.CreateCommentReplyResp)(reply), nil
} }
@ -461,9 +471,22 @@ func (s *privSrv) DeleteComment(req *web.DeleteCommentReq) mir.Error {
logrus.Errorf("Ds.DeleteComment err: %s", err) logrus.Errorf("Ds.DeleteComment err: %s", err)
return web.ErrDeleteCommentFailed return web.ErrDeleteCommentFailed
} }
onCommentActionEvent(comment.PostID, comment.ID, _commentActionDelete)
return nil return nil
} }
func (s *privSrv) HighlightComment(req *web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error) {
status, err := s.Ds.HighlightComment(req.Uid, req.CommentId)
if err == cs.ErrNoPermission {
return nil, web.ErrNoPermission
} else if err != nil {
return nil, web.ErrHighlightCommentFailed
}
return &web.HighlightCommentResp{
HighlightStatus: status,
}, nil
}
func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateCommentResp, xerr mir.Error) { func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateCommentResp, xerr mir.Error) {
var ( var (
mediaContents []string mediaContents []string
@ -553,7 +576,8 @@ func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateComment
CommentID: comment.ID, CommentID: comment.ID,
}) })
} }
// 缓存处理
onCommentActionEvent(comment.PostID, comment.ID, _commentActionCreate)
return (*web.CreateCommentResp)(comment), nil return (*web.CreateCommentResp)(comment), nil
} }

@ -42,34 +42,6 @@ type pubSrv struct {
*base.DaoServant *base.DaoServant
} }
func (s *pubSrv) TweetDetail(req *web.TweetDetailReq) (*web.TweetDetailResp, mir.Error) {
post, err := s.Ds.GetPostByID(req.TweetId)
if err != nil {
return nil, web.ErrGetPostFailed
}
postContents, err := s.Ds.GetPostContentsByIDs([]int64{post.ID})
if err != nil {
return nil, web.ErrGetPostFailed
}
users, err := s.Ds.GetUsersByIDs([]int64{post.UserID})
if err != nil {
return nil, web.ErrGetPostFailed
}
// 数据整合
postFormated := post.Format()
for _, user := range users {
postFormated.User = user.Format()
}
for _, content := range postContents {
if content.PostID == post.ID {
postFormated.Contents = append(postFormated.Contents, content.Format())
}
}
// TODO: 暂时处理办法,后续需要优化去掉这个步骤
postFormated.Visibility = ms.PostVisibleT(postFormated.Visibility.ToOutValue())
return (*web.TweetDetailResp)(postFormated), nil
}
func (s *pubSrv) SendCaptcha(req *web.SendCaptchaReq) mir.Error { func (s *pubSrv) SendCaptcha(req *web.SendCaptchaReq) mir.Error {
ctx := context.Background() ctx := context.Background()

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

@ -15,7 +15,9 @@ type baseHttpService struct {
} }
func (s *baseHttpService) registerRoute(srv Service, h func(e *gin.Engine)) { func (s *baseHttpService) registerRoute(srv Service, h func(e *gin.Engine)) {
h(s.server.e) if h != nil {
h(s.server.e)
}
s.server.addService(srv) s.server.addService(srv)
} }

@ -0,0 +1,63 @@
// Copyright 2023 ROC. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package service
import (
"fmt"
"net/http"
"github.com/Masterminds/semver/v3"
"github.com/fatih/color"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/dao"
"github.com/rocboss/paopao-ce/internal/dao/cache"
"github.com/rocboss/paopao-ce/internal/metrics/prometheus"
)
var (
_ Service = (*metricsService)(nil)
)
type metricsService struct {
*baseHttpService
}
func (s *metricsService) Name() string {
return "MetricsService"
}
func (s *metricsService) Version() *semver.Version {
return semver.MustParse("v0.1.0")
}
func (s *metricsService) OnInit() error {
s.registerRoute(s, nil)
return nil
}
func (s *metricsService) String() string {
return fmt.Sprintf("listen on %s\n", color.GreenString("http://%s:%s", conf.MetricsServerSetting.HttpIp, conf.MetricsServerSetting.HttpPort))
}
func newMetricsService() Service {
addr := conf.MetricsServerSetting.HttpIp + ":" + conf.MetricsServerSetting.HttpPort
server := httpServers.from(addr, func() *httpServer {
ds, wc := dao.DataService(), cache.NewWebCache()
mux := http.NewServeMux()
mux.Handle("/metrics", prometheus.NewHandler(ds, wc))
return &httpServer{
baseServer: newBaseServe(),
server: &http.Server{
Addr: addr,
Handler: mux,
},
}
})
return &metricsService{
baseHttpService: &baseHttpService{
server: server,
},
}
}

@ -10,7 +10,6 @@ import (
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/gin-gonic/gin"
"github.com/rocboss/paopao-ce/internal/conf" "github.com/rocboss/paopao-ce/internal/conf"
) )
@ -31,7 +30,7 @@ func (s *pprofService) Version() *semver.Version {
} }
func (s *pprofService) OnInit() error { func (s *pprofService) OnInit() error {
s.registerRoute(s, func(*gin.Engine) {}) s.registerRoute(s, nil)
return nil return nil
} }
@ -43,10 +42,8 @@ func newPprofService() Service {
addr := conf.PprofServerSetting.HttpIp + ":" + conf.PprofServerSetting.HttpPort addr := conf.PprofServerSetting.HttpIp + ":" + conf.PprofServerSetting.HttpPort
// notice this step just to register pprof server to start. don't share server with pprof. // notice this step just to register pprof server to start. don't share server with pprof.
server := httpServers.from(addr, func() *httpServer { server := httpServers.from(addr, func() *httpServer {
engine := newWebEngine()
return &httpServer{ return &httpServer{
baseServer: newBaseServe(), baseServer: newBaseServe(),
e: engine,
server: &http.Server{ server: &http.Server{
Addr: addr, Addr: addr,
Handler: http.DefaultServeMux, Handler: http.DefaultServeMux,

@ -75,6 +75,9 @@ func newService() (ss []Service) {
"Pprof": func() { "Pprof": func() {
ss = append(ss, newPprofService()) ss = append(ss, newPprofService())
}, },
"Metrics": func() {
ss = append(ss, newMetricsService())
},
}) })
return return
} }

@ -30,7 +30,7 @@ func (s *webService) Name() string {
} }
func (s *webService) Version() *semver.Version { func (s *webService) Version() *semver.Version {
return semver.MustParse("v0.1.0") return semver.MustParse("v0.5.0")
} }
func (s *webService) OnInit() error { func (s *webService) OnInit() error {

@ -29,4 +29,7 @@ type Loose struct {
// TweetComments 获取动态评论 // TweetComments 获取动态评论
TweetComments func(Get, web.TweetCommentsReq) web.TweetCommentsResp `mir:"/post/comments"` TweetComments func(Get, web.TweetCommentsReq) web.TweetCommentsResp `mir:"/post/comments"`
// TweetDetail 获取动态详情
TweetDetail func(Get, web.TweetDetailReq) web.TweetDetailResp `mir:"/post"`
} }

@ -54,6 +54,9 @@ type Priv struct {
// DeletePostComment 删除动态评论 // DeletePostComment 删除动态评论
DeleteComment func(Delete, web.DeleteCommentReq) `mir:"/post/comment"` DeleteComment func(Delete, web.DeleteCommentReq) `mir:"/post/comment"`
// HighlightComment 精选动态评论
HighlightComment func(Post, web.HighlightCommentReq) web.HighlightCommentResp `mir:"/post/comment/highlight"`
// CreateCommentReply 发布评论回复 // CreateCommentReply 发布评论回复
CreateCommentReply func(Post, web.CreateCommentReplyReq) web.CreateCommentReplyResp `mir:"/post/comment/reply"` CreateCommentReply func(Post, web.CreateCommentReplyReq) web.CreateCommentReplyResp `mir:"/post/comment/reply"`
@ -66,7 +69,7 @@ type Priv struct {
// ThumbsDownTweetComment 点踩评论 // ThumbsDownTweetComment 点踩评论
ThumbsDownTweetComment func(Post, web.TweetCommentThumbsReq) `mir:"/tweet/comment/thumbsdown"` ThumbsDownTweetComment func(Post, web.TweetCommentThumbsReq) `mir:"/tweet/comment/thumbsdown"`
// ThumbsUpTweetReply 点赞评论回复 // ThumbsUpTweetReply 点赞评论回复·
ThumbsUpTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsup"` ThumbsUpTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsup"`
// ThumbsDownTweetReply 点踩评论回复 // ThumbsDownTweetReply 点踩评论回复

@ -28,7 +28,4 @@ type Pub struct {
// SendCaptcha 发送验证码 // SendCaptcha 发送验证码
SendCaptcha func(Post, web.SendCaptchaReq) `mir:"/captcha"` SendCaptcha func(Post, web.SendCaptchaReq) `mir:"/captcha"`
// TweetDetail 获取动态详情
TweetDetail func(Get, web.TweetDetailReq) web.TweetDetailResp `mir:"/post"`
} }

@ -0,0 +1 @@
ALTER TABLE `p_comment` DROP COLUMN `is_essence`;

@ -0,0 +1 @@
ALTER TABLE `p_comment` ADD COLUMN `is_essence` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '是否精选';

@ -0,0 +1,3 @@
ALTER TABLE `p_comment` DROP COLUMN `reply_count`;
DROP TABLE IF EXISTS `p_comment_metric`;
DROP TABLE IF EXISTS `p_user_metric`;

@ -0,0 +1,48 @@
ALTER TABLE `p_comment` ADD COLUMN `reply_count` int unsigned NOT NULL DEFAULT 0 COMMENT '回复数';
UPDATE p_comment comment
SET reply_count = (
SELECT count(*) FROM p_comment_reply reply WHERE reply.comment_id=comment.id AND reply.is_del=0
)
WHERE is_del=0;
CREATE TABLE `p_comment_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`comment_id` bigint unsigned NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_metric_comment_id_rank_score` (`comment_id`, `rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE `p_user_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`tweets_count` int unsigned NOT NULL DEFAULT 0,
`latest_trends_on` bigint unsigned NOT NULL DEFAULT 0 COMMENT '最新动态时间',
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` bigint unsigned NOT NULL DEFAULT 0,
`modified_on` bigint unsigned NOT NULL DEFAULT 0,
`deleted_on` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user_metric_user_id_tweets_count_trends` (`user_id`, `tweets_count`, `latest_trends_on`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;

@ -0,0 +1 @@
ALTER TABLE p_comment DROP COLUMN is_essence;

@ -0,0 +1 @@
ALTER TABLE p_comment ADD COLUMN is_essence SMALLINT NOT NULL DEFAULT 0;

@ -0,0 +1,3 @@
ALTER TABLE p_comment DROP COLUMN IF EXISTS reply_count;
DROP TABLE IF EXISTS p_comment_metric;
DROP TABLE IF EXISTS p_user_metric;

@ -0,0 +1,51 @@
ALTER TABLE p_comment ADD COLUMN reply_count INT NOT NULL DEFAULT 0;
WITH comment_reply AS (
SELECT comment_id, count(*) AS count
FROM p_comment_reply
WHERE is_del=0
GROUP By comment_id
)
UPDATE p_comment comment
SET reply_count = reply.count
FROM comment_reply reply
WHERE comment.id = reply.comment_id;
CREATE TABLE p_comment_metric (
id BIGSERIAL PRIMARY KEY,
comment_id BIGINT NOT NULL,
rank_score BIGINT NOT NULL DEFAULT 0,
incentive_score INT NOT NULL DEFAULT 0,
decay_factor INT NOT NULL DEFAULT 0,
motivation_factor INT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_comment_metric_comment_id_rank_score ON p_comment_metric USING btree (comment_id, rank_score);
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE p_user_metric (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
tweets_count INT NOT NULL DEFAULT 0,
latest_trends_on BIGINT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_user_metric_user_id_tweets_count_trends ON p_user_metric USING btree (user_id, tweets_count, latest_trends_on);
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;

@ -0,0 +1 @@
ALTER TABLE "p_comment" DROP COLUMN "is_essence";

@ -0,0 +1 @@
ALTER TABLE "p_comment" ADD COLUMN "is_essence" integer NOT NULL DEFAULT 0;

@ -0,0 +1,3 @@
ALTER TABLE "p_comment" DROP COLUMN "reply_count";
DROP TABLE IF EXISTS "p_comment_metric";
DROP TABLE IF EXISTS "p_user_metric";

@ -0,0 +1,62 @@
ALTER TABLE "p_comment" ADD COLUMN "reply_count" integer NOT NULL DEFAULT 0;
UPDATE p_comment AS comment
SET reply_count = (
SELECT count(*)
FROM
p_comment_reply AS reply
WHERE
comment.id=reply.comment_id AND comment.is_del=0 AND reply.is_del=0
);
CREATE TABLE p_comment_metric (
"id" integer,
"comment_id" integer NOT NULL,
"rank_score" integer NOT NULL DEFAULT 0,
"incentive_score" integer NOT NULL DEFAULT 0,
"decay_factor" integer NOT NULL DEFAULT 0,
"motivation_factor" integer NOT NULL DEFAULT 0,
"is_del" integer NOT NULL DEFAULT 0,
"created_on" integer NOT NULL DEFAULT 0,
"modified_on" integer NOT NULL DEFAULT 0,
"deleted_on" integer NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
);
CREATE INDEX "idx_comment_metric_comment_id_rank_score"
ON "p_comment_metric" (
"comment_id" ASC,
"rank_score" ASC
);
INSERT INTO p_comment_metric (comment_id, rank_score, created_on)
SELECT id AS comment_id,
reply_count*2 + thumbs_up_count*4 - thumbs_down_count AS rank_score,
created_on
FROM p_comment
WHERE is_del=0;
CREATE TABLE "p_user_metric" (
"id" integer,
"user_id" integer NOT NULL,
"tweets_count" integer NOT NULL DEFAULT 0,
"latest_trends_on" integer NOT NULL DEFAULT 0,
"is_del" integer NOT NULL DEFAULT 0,
"created_on" integer NOT NULL DEFAULT 0,
"modified_on" integer NOT NULL DEFAULT 0,
"deleted_on" integer NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
);
CREATE INDEX "idx_user_metric_user_id_tweets_count_trends"
ON "p_user_metric" (
"user_id" ASC,
"tweets_count" ASC,
"latest_trends_on" ASC
);
INSERT INTO p_user_metric (user_id, tweets_count)
SELECT user_id, count(*) AS tweets_count
FROM p_post
WHERE is_del=0
GROUP BY user_id;

@ -6,17 +6,17 @@ SET FOREIGN_KEY_CHECKS = 0;
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_attachment`; DROP TABLE IF EXISTS `p_attachment`;
CREATE TABLE `p_attachment` ( CREATE TABLE `p_attachment` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT, `id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL DEFAULT '0', `user_id` BIGINT NOT NULL DEFAULT '0',
`file_size` bigint unsigned NOT NULL, `file_size` BIGINT NOT NULL,
`img_width` bigint unsigned NOT NULL DEFAULT '0', `img_width` BIGINT NOT NULL DEFAULT '0',
`img_height` bigint unsigned NOT NULL DEFAULT '0', `img_height` BIGINT NOT NULL DEFAULT '0',
`type` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '1图片2视频3其他附件', `type` tinyint NOT NULL DEFAULT '1' COMMENT '1图片2视频3其他附件',
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_attachment_user` (`user_id`) USING BTREE KEY `idx_attachment_user` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=100041 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='附件'; ) ENGINE=InnoDB AUTO_INCREMENT=100041 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='附件';
@ -26,15 +26,15 @@ CREATE TABLE `p_attachment` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_captcha`; DROP TABLE IF EXISTS `p_captcha`;
CREATE TABLE `p_captcha` ( CREATE TABLE `p_captcha` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '验证码ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '验证码ID',
`phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号', `phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
`captcha` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '验证码', `captcha` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '验证码',
`use_times` int unsigned NOT NULL DEFAULT '0' COMMENT '使用次数', `use_times` int NOT NULL DEFAULT '0' COMMENT '使用次数',
`expired_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '过期时间', `expired_on` BIGINT NOT NULL DEFAULT '0' COMMENT '过期时间',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_captcha_phone` (`phone`) USING BTREE, KEY `idx_captcha_phone` (`phone`) USING BTREE,
KEY `idx_captcha_expired_on` (`expired_on`) USING BTREE, KEY `idx_captcha_expired_on` (`expired_on`) USING BTREE,
@ -46,17 +46,19 @@ CREATE TABLE `p_captcha` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_comment`; DROP TABLE IF EXISTS `p_comment`;
CREATE TABLE `p_comment` ( CREATE TABLE `p_comment` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '评论ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '评论ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址', `ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址',
`ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址', `ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址',
`thumbs_up_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞数', `is_essence` tinyint NOT NULL DEFAULT 0 COMMENT '是否精选',
`thumbs_down_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点踩数', `reply_count` int NOT NULL DEFAULT 0 COMMENT '回复数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `thumbs_up_count` int NOT NULL DEFAULT 0 COMMENT '点赞数',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `thumbs_down_count` int NOT NULL DEFAULT 0 COMMENT '点踩数',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_post_id` (`post_id`) USING BTREE, KEY `idx_comment_post_id` (`post_id`) USING BTREE,
KEY `idx_comment_user_id` (`user_id`) USING BTREE KEY `idx_comment_user_id` (`user_id`) USING BTREE
@ -67,16 +69,16 @@ CREATE TABLE `p_comment` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_comment_content`; DROP TABLE IF EXISTS `p_comment_content`;
CREATE TABLE `p_comment_content` ( CREATE TABLE `p_comment_content` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID', `comment_id` BIGINT NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容', `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容',
`type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址', `type` tinyint NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址',
`sort` bigint unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前', `sort` BIGINT NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_content_comment_id` (`comment_id`) USING BTREE, KEY `idx_comment_content_comment_id` (`comment_id`) USING BTREE,
KEY `idx_comment_content_user_id` (`user_id`) USING BTREE, KEY `idx_comment_content_user_id` (`user_id`) USING BTREE,
@ -89,40 +91,59 @@ CREATE TABLE `p_comment_content` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_comment_reply`; DROP TABLE IF EXISTS `p_comment_reply`;
CREATE TABLE `p_comment_reply` ( CREATE TABLE `p_comment_reply` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '回复ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '回复ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID', `comment_id` BIGINT NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`at_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '@用户ID', `at_user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '@用户ID',
`content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容', `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容',
`ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址', `ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址',
`ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址', `ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址',
`thumbs_up_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞数', `thumbs_up_count` int NOT NULL DEFAULT '0' COMMENT '点赞数',
`thumbs_down_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点踩数', `thumbs_down_count` int NOT NULL DEFAULT '0' COMMENT '点踩数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_reply_comment_id` (`comment_id`) USING BTREE KEY `idx_comment_reply_comment_id` (`comment_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12000015 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='评论回复'; ) ENGINE=InnoDB AUTO_INCREMENT=12000015 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='评论回复';
-- ----------------------------
-- Table structure for p_comment_metric
-- ----------------------------
DROP TABLE IF EXISTS `p_comment_metric`;
CREATE TABLE `p_comment_metric` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`comment_id` BIGINT NOT NULL,
`rank_score` BIGINT NOT NULL DEFAULT 0,
`incentive_score` int NOT NULL DEFAULT 0,
`decay_factor` int NOT NULL DEFAULT 0,
`motivation_factor` int NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` BIGINT NOT NULL DEFAULT 0,
`modified_on` BIGINT NOT NULL DEFAULT 0,
`deleted_on` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_comment_metric_comment_id_rank_score` (`comment_id`, `rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ---------------------------- -- ----------------------------
-- Table structure for p_tweet_comment_thumbs -- Table structure for p_tweet_comment_thumbs
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_tweet_comment_thumbs`; DROP TABLE IF EXISTS `p_tweet_comment_thumbs`;
CREATE TABLE `p_tweet_comment_thumbs` ( CREATE TABLE `p_tweet_comment_thumbs` (
`id` BIGINT unsigned NOT NULL AUTO_INCREMENT COMMENT 'thumbs ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'thumbs ID',
`user_id` BIGINT unsigned NOT NULL, `user_id` BIGINT NOT NULL,
`tweet_id` BIGINT unsigned NOT NULL COMMENT '推文ID', `tweet_id` BIGINT NOT NULL COMMENT '推文ID',
`comment_id` BIGINT unsigned NOT NULL COMMENT '评论ID', `comment_id` BIGINT NOT NULL COMMENT '评论ID',
`reply_id` BIGINT unsigned COMMENT '评论回复ID', `reply_id` BIGINT COMMENT '评论回复ID',
`comment_type` TINYINT NOT NULL DEFAULT '0' COMMENT '评论类型 0为推文评论、1为评论回复', `comment_type` TINYINT NOT NULL DEFAULT '0' COMMENT '评论类型 0为推文评论、1为评论回复',
`is_thumbs_up` TINYINT unsigned NOT NULL DEFAULT '0' COMMENT '是否点赞', `is_thumbs_up` TINYINT NOT NULL DEFAULT '0' COMMENT '是否点赞',
`is_thumbs_down` TINYINT unsigned NOT NULL DEFAULT '0' COMMENT '是否点踩', `is_thumbs_down` TINYINT NOT NULL DEFAULT '0' COMMENT '是否点踩',
`created_on` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` TINYINT unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` TINYINT NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_tweet_comment_thumbs_uid_tid` (`user_id`, `tweet_id`) USING BTREE KEY `idx_tweet_comment_thumbs_uid_tid` (`user_id`, `tweet_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='推文评论点赞'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='推文评论点赞';
@ -132,20 +153,20 @@ CREATE TABLE `p_tweet_comment_thumbs` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_message`; DROP TABLE IF EXISTS `p_message`;
CREATE TABLE `p_message` ( CREATE TABLE `p_message` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '消息通知ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '消息通知ID',
`sender_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '发送方用户ID', `sender_user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '发送方用户ID',
`receiver_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '接收方用户ID', `receiver_user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '接收方用户ID',
`type` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '通知类型1动态2评论3回复4私信99系统通知', `type` tinyint NOT NULL DEFAULT '1' COMMENT '通知类型1动态2评论3回复4私信99系统通知',
`brief` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '摘要说明', `brief` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '摘要说明',
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '详细内容', `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '详细内容',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '动态ID', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT '动态ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID', `comment_id` BIGINT NOT NULL DEFAULT '0' COMMENT '评论ID',
`reply_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '回复ID', `reply_id` BIGINT NOT NULL DEFAULT '0' COMMENT '回复ID',
`is_read` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否已读', `is_read` tinyint NOT NULL DEFAULT '0' COMMENT '是否已读',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_message_receiver_user_id` (`receiver_user_id`) USING BTREE, KEY `idx_message_receiver_user_id` (`receiver_user_id`) USING BTREE,
KEY `idx_message_is_read` (`is_read`) USING BTREE, KEY `idx_message_is_read` (`is_read`) USING BTREE,
@ -157,25 +178,25 @@ CREATE TABLE `p_message` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_post`; DROP TABLE IF EXISTS `p_post`;
CREATE TABLE `p_post` ( CREATE TABLE `p_post` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主题ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主题ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`comment_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论数', `comment_count` BIGINT NOT NULL DEFAULT '0' COMMENT '评论数',
`collection_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '收藏数', `collection_count` BIGINT NOT NULL DEFAULT '0' COMMENT '收藏数',
`upvote_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '点赞数', `upvote_count` BIGINT NOT NULL DEFAULT '0' COMMENT '点赞数',
`share_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '分享数', `share_count` BIGINT NOT NULL DEFAULT '0' COMMENT '分享数',
`visibility` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开', `visibility` tinyint NOT NULL DEFAULT '0' COMMENT '可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开',
`is_top` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否置顶', `is_top` tinyint NOT NULL DEFAULT '0' COMMENT '是否置顶',
`is_essence` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否精华', `is_essence` tinyint NOT NULL DEFAULT '0' COMMENT '是否精华',
`is_lock` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否锁定', `is_lock` tinyint NOT NULL DEFAULT '0' COMMENT '是否锁定',
`latest_replied_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '最新回复时间', `latest_replied_on` BIGINT NOT NULL DEFAULT '0' COMMENT '最新回复时间',
`tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标签', `tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标签',
`attachment_price` bigint unsigned NOT NULL DEFAULT '0' COMMENT '附件价格(分)', `attachment_price` BIGINT NOT NULL DEFAULT '0' COMMENT '附件价格(分)',
`ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址', `ip` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP地址',
`ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址', `ip_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_user_id` (`user_id`) USING BTREE, KEY `idx_post_user_id` (`user_id`) USING BTREE,
KEY `idx_post_visibility` (`visibility`) USING BTREE KEY `idx_post_visibility` (`visibility`) USING BTREE
@ -186,16 +207,16 @@ CREATE TABLE `p_post` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_post_metric`; DROP TABLE IF EXISTS `p_post_metric`;
CREATE TABLE `p_post_metric` ( CREATE TABLE `p_post_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT, `id` BIGINT NOT NULL AUTO_INCREMENT,
`post_id` bigint unsigned NOT NULL, `post_id` BIGINT NOT NULL,
`rank_score` bigint unsigned NOT NULL DEFAULT 0, `rank_score` BIGINT NOT NULL DEFAULT 0,
`incentive_score` int unsigned NOT NULL DEFAULT 0, `incentive_score` int NOT NULL DEFAULT 0,
`decay_factor` int unsigned NOT NULL DEFAULT 0, `decay_factor` int NOT NULL DEFAULT 0,
`motivation_factor` int unsigned NOT NULL DEFAULT 0, `motivation_factor` int NOT NULL DEFAULT 0,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是 `is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0', `created_on` BIGINT NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0', `modified_on` BIGINT NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0', `deleted_on` BIGINT NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE KEY `idx_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
@ -205,14 +226,14 @@ CREATE TABLE `p_post_metric` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_post_attachment_bill`; DROP TABLE IF EXISTS `p_post_attachment_bill`;
CREATE TABLE `p_post_attachment_bill` ( CREATE TABLE `p_post_attachment_bill` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '购买记录ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '购买记录ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`paid_amount` bigint unsigned NOT NULL DEFAULT '0' COMMENT '支付金额', `paid_amount` BIGINT NOT NULL DEFAULT '0' COMMENT '支付金额',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_attachment_bill_post_id` (`post_id`) USING BTREE, KEY `idx_post_attachment_bill_post_id` (`post_id`) USING BTREE,
KEY `idx_post_attachment_bill_user_id` (`user_id`) USING BTREE KEY `idx_post_attachment_bill_user_id` (`user_id`) USING BTREE
@ -223,13 +244,13 @@ CREATE TABLE `p_post_attachment_bill` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_post_collection`; DROP TABLE IF EXISTS `p_post_collection`;
CREATE TABLE `p_post_collection` ( CREATE TABLE `p_post_collection` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '收藏ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_collection_post_id` (`post_id`) USING BTREE, KEY `idx_post_collection_post_id` (`post_id`) USING BTREE,
KEY `idx_post_collection_user_id` (`user_id`) USING BTREE KEY `idx_post_collection_user_id` (`user_id`) USING BTREE
@ -240,16 +261,16 @@ CREATE TABLE `p_post_collection` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_post_content`; DROP TABLE IF EXISTS `p_post_content`;
CREATE TABLE `p_post_content` ( CREATE TABLE `p_post_content` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容', `content` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '内容',
`type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址7附件资源8收费资源', `type` tinyint NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址7附件资源8收费资源',
`sort` int unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前', `sort` int NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_content_post_id` (`post_id`) USING BTREE, KEY `idx_post_content_post_id` (`post_id`) USING BTREE,
KEY `idx_post_content_user_id` (`user_id`) USING BTREE KEY `idx_post_content_user_id` (`user_id`) USING BTREE
@ -260,13 +281,13 @@ CREATE TABLE `p_post_content` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_post_star`; DROP TABLE IF EXISTS `p_post_star`;
CREATE TABLE `p_post_star` ( CREATE TABLE `p_post_star` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '收藏ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_post_star_post_id` (`post_id`) USING BTREE, KEY `idx_post_star_post_id` (`post_id`) USING BTREE,
KEY `idx_post_star_user_id` (`user_id`) USING BTREE KEY `idx_post_star_user_id` (`user_id`) USING BTREE
@ -277,14 +298,14 @@ CREATE TABLE `p_post_star` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_tag`; DROP TABLE IF EXISTS `p_tag`;
CREATE TABLE `p_tag` ( CREATE TABLE `p_tag` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '标签ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '标签ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建者ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '创建者ID',
`tag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '标签名', `tag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '标签名',
`quote_num` bigint unsigned NOT NULL DEFAULT '0' COMMENT '引用数', `quote_num` BIGINT NOT NULL DEFAULT '0' COMMENT '引用数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_tag_tag` (`tag`) USING BTREE, UNIQUE KEY `idx_tag_tag` (`tag`) USING BTREE,
KEY `idx_tag_user_id` (`user_id`) USING BTREE, KEY `idx_tag_user_id` (`user_id`) USING BTREE,
@ -296,17 +317,17 @@ CREATE TABLE `p_tag` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_topic_user`; DROP TABLE IF EXISTS `p_topic_user`;
CREATE TABLE `p_topic_user` ( CREATE TABLE `p_topic_user` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `id` BIGINT NOT NULL AUTO_INCREMENT,
`topic_id` BIGINT UNSIGNED NOT NULL COMMENT '标签ID', `topic_id` BIGINT NOT NULL COMMENT '标签ID',
`user_id` BIGINT UNSIGNED NOT NULL COMMENT '创建者ID', `user_id` BIGINT NOT NULL COMMENT '创建者ID',
`alias_name` VARCHAR ( 255 ) COMMENT '别名', `alias_name` VARCHAR ( 255 ) COMMENT '别名',
`remark` VARCHAR ( 512 ) COMMENT '备注', `remark` VARCHAR ( 512 ) COMMENT '备注',
`quote_num` BIGINT UNSIGNED COMMENT '引用数', `quote_num` BIGINT COMMENT '引用数',
`is_top` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '是否置顶 0 为未置顶、1 为已置顶', `is_top` TINYINT NOT NULL DEFAULT '0' COMMENT '是否置顶 0 为未置顶、1 为已置顶',
`created_on` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` TINYINT NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`reserve_a` VARCHAR ( 255 ) COMMENT '保留字段a', `reserve_a` VARCHAR ( 255 ) COMMENT '保留字段a',
`reserve_b` VARCHAR ( 255 ) COMMENT '保留字段b', `reserve_b` VARCHAR ( 255 ) COMMENT '保留字段b',
PRIMARY KEY ( `id` ) USING BTREE, PRIMARY KEY ( `id` ) USING BTREE,
@ -318,37 +339,54 @@ CREATE TABLE `p_topic_user` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_user`; DROP TABLE IF EXISTS `p_user`;
CREATE TABLE `p_user` ( CREATE TABLE `p_user` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '昵称', `nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '昵称',
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名', `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
`phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号', `phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
`password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'MD5密码', `password` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'MD5密码',
`salt` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '盐值', `salt` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '盐值',
`status` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '状态1正常2停用', `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态1正常2停用',
`avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户头像', `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户头像',
`balance` bigint unsigned NOT NULL COMMENT '用户余额(分)', `balance` BIGINT NOT NULL COMMENT '用户余额(分)',
`is_admin` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否管理员', `is_admin` tinyint NOT NULL DEFAULT '0' COMMENT '是否管理员',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_user_username` (`username`) USING BTREE, UNIQUE KEY `idx_user_username` (`username`) USING BTREE,
KEY `idx_user_phone` (`phone`) USING BTREE KEY `idx_user_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=100058 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户'; ) ENGINE=InnoDB AUTO_INCREMENT=100058 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户';
-- ----------------------------
-- Table structure for p_user_metric
-- ----------------------------
DROP TABLE IF EXISTS `p_user_metric`;
CREATE TABLE `p_user_metric` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` BIGINT NOT NULL,
`tweets_count` int NOT NULL DEFAULT 0,
`latest_trends_on` BIGINT NOT NULL DEFAULT 0 COMMENT '最新动态时间',
`is_del` tinyint NOT NULL DEFAULT 0,
`created_on` BIGINT NOT NULL DEFAULT 0,
`modified_on` BIGINT NOT NULL DEFAULT 0,
`deleted_on` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user_metric_user_id_tweets_count_trends` (`user_id`, `tweets_count`, `latest_trends_on`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
-- ---------------------------- -- ----------------------------
-- Table structure for p_following -- Table structure for p_following
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_following`; DROP TABLE IF EXISTS `p_following`;
CREATE TABLE `p_following` ( CREATE TABLE `p_following` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT, `id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL, `user_id` BIGINT NOT NULL,
`follow_id` bigint unsigned NOT NULL, `follow_id` BIGINT NOT NULL,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是 `is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0', `created_on` BIGINT NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0', `modified_on` BIGINT NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0', `deleted_on` BIGINT NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_following_user_follow` (`user_id`,`follow_id`) USING BTREE KEY `idx_following_user_follow` (`user_id`,`follow_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
@ -358,19 +396,19 @@ CREATE TABLE `p_following` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_contact`; DROP TABLE IF EXISTS `p_contact`;
CREATE TABLE `p_contact` ( CREATE TABLE `p_contact` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '联系人ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '联系人ID',
`user_id` bigint unsigned NOT NULL COMMENT '用户ID', `user_id` BIGINT NOT NULL COMMENT '用户ID',
`friend_id` bigint unsigned NOT NULL COMMENT '好友ID', `friend_id` BIGINT NOT NULL COMMENT '好友ID',
`group_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '好友分组ID:默认为0无分组', `group_id` BIGINT NOT NULL DEFAULT '0' COMMENT '好友分组ID:默认为0无分组',
`remark` varchar(32) NOT NULL DEFAULT '' COMMENT '好友备注', `remark` varchar(32) NOT NULL DEFAULT '' COMMENT '好友备注',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '好友状态: 1请求好友, 2已好友, 3拒绝好友, 4已删好友', `status` tinyint NOT NULL DEFAULT '0' COMMENT '好友状态: 1请求好友, 2已好友, 3拒绝好友, 4已删好友',
`is_top` tinyint NOT NULL DEFAULT '0' COMMENT '是否置顶, 0否, 1是', `is_top` tinyint NOT NULL DEFAULT '0' COMMENT '是否置顶, 0否, 1是',
`is_black` tinyint NOT NULL DEFAULT '0' COMMENT '是否为黑名单, 0否, 1是', `is_black` tinyint NOT NULL DEFAULT '0' COMMENT '是否为黑名单, 0否, 1是',
`is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除好友, 0否, 1是', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除好友, 0否, 1是',
`notice_enable` tinyint NOT NULL DEFAULT '0' COMMENT '是否有消息提醒, 0否, 1是', `notice_enable` tinyint NOT NULL DEFAULT '0' COMMENT '是否有消息提醒, 0否, 1是',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_contact_user_friend` (`user_id`,`friend_id`) USING BTREE, UNIQUE KEY `idx_contact_user_friend` (`user_id`,`friend_id`) USING BTREE,
KEY `idx_contact_user_friend_status` (`user_id`, `friend_id`, `status`) USING BTREE KEY `idx_contact_user_friend_status` (`user_id`, `friend_id`, `status`) USING BTREE
@ -381,13 +419,13 @@ CREATE TABLE `p_contact` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_contact_group`; DROP TABLE IF EXISTS `p_contact_group`;
CREATE TABLE `p_contact_group` ( CREATE TABLE `p_contact_group` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '联系人ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '联系人ID',
`user_id` int NOT NULL DEFAULT '0' COMMENT '用户id', `user_id` int NOT NULL DEFAULT '0' COMMENT '用户id',
`name` varchar(32) NOT NULL DEFAULT '' COMMENT '分组名称', `name` varchar(32) NOT NULL DEFAULT '' COMMENT '分组名称',
`is_del` tinyint NOT NULL DEFAULT '1' COMMENT '是否删除, 0否, 1是', `is_del` tinyint NOT NULL DEFAULT '1' COMMENT '是否删除, 0否, 1是',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='联系人分组'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='联系人分组';
@ -396,15 +434,15 @@ CREATE TABLE `p_contact_group` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_wallet_recharge`; DROP TABLE IF EXISTS `p_wallet_recharge`;
CREATE TABLE `p_wallet_recharge` ( CREATE TABLE `p_wallet_recharge` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '充值ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '充值ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`amount` bigint NOT NULL DEFAULT '0' COMMENT '充值金额', `amount` BIGINT NOT NULL DEFAULT '0' COMMENT '充值金额',
`trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '支付宝订单号', `trade_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '支付宝订单号',
`trade_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '交易状态', `trade_status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '交易状态',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_wallet_recharge_user_id` (`user_id`) USING BTREE, KEY `idx_wallet_recharge_user_id` (`user_id`) USING BTREE,
KEY `idx_wallet_recharge_trade_no` (`trade_no`) USING BTREE, KEY `idx_wallet_recharge_trade_no` (`trade_no`) USING BTREE,
@ -416,16 +454,16 @@ CREATE TABLE `p_wallet_recharge` (
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `p_wallet_statement`; DROP TABLE IF EXISTS `p_wallet_statement`;
CREATE TABLE `p_wallet_statement` ( CREATE TABLE `p_wallet_statement` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '账单ID', `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '账单ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID', `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`change_amount` bigint NOT NULL DEFAULT '0' COMMENT '变动金额', `change_amount` BIGINT NOT NULL DEFAULT '0' COMMENT '变动金额',
`balance_snapshot` bigint NOT NULL DEFAULT '0' COMMENT '资金快照', `balance_snapshot` BIGINT NOT NULL DEFAULT '0' COMMENT '资金快照',
`reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '变动原因', `reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '变动原因',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '关联动态', `post_id` BIGINT NOT NULL DEFAULT '0' COMMENT '关联动态',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除', `is_del` tinyint NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
KEY `idx_wallet_statement_user_id` (`user_id`) USING BTREE KEY `idx_wallet_statement_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10010 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='钱包流水'; ) ENGINE=InnoDB AUTO_INCREMENT=10010 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='钱包流水';

@ -65,8 +65,10 @@ CREATE TABLE p_comment (
user_id BIGINT NOT NULL DEFAULT 0, user_id BIGINT NOT NULL DEFAULT 0,
ip VARCHAR(64) NOT NULL DEFAULT '', ip VARCHAR(64) NOT NULL DEFAULT '',
ip_loc VARCHAR(64) NOT NULL DEFAULT '', ip_loc VARCHAR(64) NOT NULL DEFAULT '',
thumbs_up_count int NOT NULL DEFAULT 0, -- 点赞数 is_essence SMALLINT NOT NULL DEFAULT 0,
thumbs_down_count int NOT NULL DEFAULT 0, -- 点踩数 reply_count INT NOT NULL DEFAULT 0, -- 回复数
thumbs_up_count INT NOT NULL DEFAULT 0, -- 点赞数
thumbs_down_count INT NOT NULL DEFAULT 0, -- 点踩数
created_on BIGINT NOT NULL DEFAULT 0, created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0, modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0, deleted_on BIGINT NOT NULL DEFAULT 0,
@ -111,6 +113,20 @@ CREATE TABLE p_comment_reply (
); );
CREATE INDEX idx_comment_reply_comment_id ON p_comment_reply USING btree (comment_id); CREATE INDEX idx_comment_reply_comment_id ON p_comment_reply USING btree (comment_id);
CREATE TABLE p_comment_metric (
id BIGSERIAL PRIMARY KEY,
comment_id BIGINT NOT NULL,
rank_score BIGINT NOT NULL DEFAULT 0,
incentive_score INT NOT NULL DEFAULT 0,
decay_factor INT NOT NULL DEFAULT 0,
motivation_factor INT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_comment_metric_comment_id_rank_score ON p_comment_metric USING btree (comment_id, rank_score);
DROP TABLE IF EXISTS p_tweet_comment_thumbs; DROP TABLE IF EXISTS p_tweet_comment_thumbs;
CREATE TABLE p_tweet_comment_thumbs ( CREATE TABLE p_tweet_comment_thumbs (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
@ -302,6 +318,18 @@ CREATE TABLE p_user (
CREATE UNIQUE INDEX idx_user_username ON p_user USING btree (username); CREATE UNIQUE INDEX idx_user_username ON p_user USING btree (username);
CREATE INDEX idx_user_phone ON p_user USING btree (phone); CREATE INDEX idx_user_phone ON p_user USING btree (phone);
CREATE TABLE p_user_metric (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
tweets_count INT NOT NULL DEFAULT 0,
latest_trends_on BIGINT NOT NULL DEFAULT 0,
is_del SMALLINT NOT NULL DEFAULT 0,
created_on BIGINT NOT NULL DEFAULT 0,
modified_on BIGINT NOT NULL DEFAULT 0,
deleted_on BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX idx_user_metric_user_id_tweets_count_trends ON p_user_metric USING btree (user_id, tweets_count, latest_trends_on);
DROP TABLE IF EXISTS p_following; DROP TABLE IF EXISTS p_following;
CREATE TABLE p_following ( CREATE TABLE p_following (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,

@ -46,6 +46,7 @@ CREATE TABLE "p_comment" (
"user_id" integer NOT NULL, "user_id" integer NOT NULL,
"ip" text(64) NOT NULL, "ip" text(64) NOT NULL,
"ip_loc" text(64) NOT NULL, "ip_loc" text(64) NOT NULL,
"is_essence" integer NOT NULL DEFAULT 0,
"thumbs_up_count" integer NOT NULL DEFAULT 0, -- 点赞数 "thumbs_up_count" integer NOT NULL DEFAULT 0, -- 点赞数
"thumbs_down_count" integer NOT NULL DEFAULT 0, -- 点踩数 "thumbs_down_count" integer NOT NULL DEFAULT 0, -- 点踩数
"created_on" integer NOT NULL, "created_on" integer NOT NULL,
@ -94,6 +95,23 @@ CREATE TABLE "p_comment_reply" (
PRIMARY KEY ("id") PRIMARY KEY ("id")
); );
-- ----------------------------
-- Table structure for p_comment_metric
-- ----------------------------
CREATE TABLE p_comment_metric (
"id" integer,
"comment_id" integer NOT NULL,
"rank_score" integer NOT NULL DEFAULT 0,
"incentive_score" integer NOT NULL DEFAULT 0,
"decay_factor" integer NOT NULL DEFAULT 0,
"motivation_factor" integer NOT NULL DEFAULT 0,
"is_del" integer NOT NULL DEFAULT 0,
"created_on" integer NOT NULL DEFAULT 0,
"modified_on" integer NOT NULL DEFAULT 0,
"deleted_on" integer NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
);
-- ---------------------------- -- ----------------------------
-- Table structure for p_tweet_comment_thumbs -- Table structure for p_tweet_comment_thumbs
-- ---------------------------- -- ----------------------------
@ -354,6 +372,21 @@ CREATE TABLE "p_user" (
PRIMARY KEY ("id") PRIMARY KEY ("id")
); );
-- ----------------------------
-- Table structure for p_user_metric
-- ----------------------------
CREATE TABLE "p_user_metric" (
"id" integer,
"user_id" integer NOT NULL,
"tweets_count" integer NOT NULL DEFAULT 0,
"latest_trends_on" integer NOT NULL DEFAULT 0,
"is_del" integer NOT NULL DEFAULT 0,
"created_on" integer NOT NULL DEFAULT 0,
"modified_on" integer NOT NULL DEFAULT 0,
"deleted_on" integer NOT NULL DEFAULT 0,
PRIMARY KEY ("id")
);
-- ---------------------------- -- ----------------------------
-- Table structure for p_wallet_recharge -- Table structure for p_wallet_recharge
-- ---------------------------- -- ----------------------------
@ -488,6 +521,15 @@ ON "p_comment_reply" (
"comment_id" ASC "comment_id" ASC
); );
-- ----------------------------
-- Indexes structure for table p_comment_metric
-- ----------------------------
CREATE INDEX "idx_comment_metric_comment_id_rank_score"
ON "p_comment_metric" (
"comment_id" ASC,
"rank_score" ASC
);
-- ---------------------------- -- ----------------------------
-- Indexes structure for table idx_tweet_comment_thumbs_uid_tid -- Indexes structure for table idx_tweet_comment_thumbs_uid_tid
-- ---------------------------- -- ----------------------------
@ -643,6 +685,16 @@ ON "p_user" (
"username" ASC "username" ASC
); );
-- ----------------------------
-- Indexes structure for table p_user_metric
-- ----------------------------
CREATE INDEX "idx_user_metric_user_id_tweets_count_trends"
ON "p_user_metric" (
"user_id" ASC,
"tweets_count" ASC,
"latest_trends_on" ASC
);
-- ---------------------------- -- ----------------------------
-- Indexes structure for table p_wallet_recharge -- Indexes structure for table p_wallet_recharge
-- ---------------------------- -- ----------------------------

@ -1 +1 @@
import{_ as s}from"./main-nav.vue_vue_type_style_index_0_lang-2982e04a.js";import{u as i}from"./vue-router-e5a2430e.js";import{F as a,e as c,a2 as u}from"./naive-ui-d8de3dda.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-4a465428.js";import"./vuex-44de225f.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-7a4ef312.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-93352cc4.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-daff1b26.js";import"./vuex-44de225f.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-c265fba6.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};

File diff suppressed because one or more lines are too long

@ -1 +1 @@
import{_ as F}from"./post-skeleton-4d2b103e.js";import{_ as N}from"./main-nav.vue_vue_type_style_index_0_lang-2982e04a.js";import{u as z}from"./vuex-44de225f.js";import{b as A}from"./vue-router-e5a2430e.js";import{E as R,_ as S}from"./index-4a465428.js";import{F as V,Q as q,I as E,G as I}from"./naive-ui-d8de3dda.js";import{d as P,H as n,b as j,f as o,k as a,w as p,e as t,bf as u,Y as l,F as D,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-7a4ef312.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=P({__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 j(()=>{}),(m,J)=>{const k=N,y=q,x=F,w=E,B=I,C=V;return t(),o("div",null,[a(k,{title:"公告"}),a(C,{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(D,null,G(i.value,e=>(t(),H(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: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}; import{_ as N}from"./post-skeleton-8434d30b.js";import{_ as R}from"./main-nav.vue_vue_type_style_index_0_lang-93352cc4.js";import{u as z}from"./vuex-44de225f.js";import{b as A}from"./vue-router-e5a2430e.js";import{I as F,_ as S}from"./index-daff1b26.js";import{G as V,R as q,J as H,H as I}from"./naive-ui-defd0b2d.js";import{d as P,H as n,b as j,f as o,k as a,w as p,e as t,bf as u,Y as l,F as D,u as E,q as G,j as s,x as _,l as J}from"./@vue-a481fc63.js";import"./vooks-6d99783e.js";import"./evtd-b614532e.js";import"./@vicons-c265fba6.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=P({__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 j(()=>{}),(m,K)=>{const k=R,y=q,x=N,w=H,B=I,C=V;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(D,null,E(i.value,e=>(t(),G(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=S(Y,[["__scopeId","data-v-d4d04859"]]);export{ke as default};

@ -0,0 +1 @@
import{_ as T}from"./whisper-9b4eeceb.js";import{_ as U,a as q}from"./post-item.vue_vue_type_style_index_0_lang-c2092e3d.js";import{_ as N}from"./post-skeleton-8434d30b.js";import{_ as V}from"./main-nav.vue_vue_type_style_index_0_lang-93352cc4.js";import{u as W}from"./vuex-44de225f.js";import{b as D}from"./vue-router-e5a2430e.js";import{R as E,u as G,f as J,_ as L}from"./index-daff1b26.js";import{d as Y,H as a,b as j,f as t,k as s,w as f,bf as c,Y as y,e as o,F as C,u as x,q as F}from"./@vue-a481fc63.js";import{F as K,G as Q,R as X,J as Z,H as ee}from"./naive-ui-defd0b2d.js";import"./content-64a02a2f.js";import"./@vicons-c265fba6.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 oe={key:0,class:"skeleton-wrap"},te={key:1},se={key:0,class:"empty-wrap"},ne={key:1},ae={key:2},ie={key:0,class:"pagination-wrap"},le=Y({__name:"Collection",setup(re){const i=W(),S=D(),$=K(),l=a(!1),r=a([]),u=a(+S.query.p||1),p=a(20),m=a(0),d=a(!1),g=a({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),v=e=>{g.value=e,d.value=!0},b=()=>{d.value=!1},w=e=>{$.success({title:"提示",content:"确定"+(e.user.is_following?"取消关注":"关注")+"该用户吗?",positiveText:"确定",negativeText:"取消",onPositiveClick:()=>{e.user.is_following?G({user_id:e.user.id}).then(_=>{window.$message.success("操作成功"),e.user.is_following=!1}).catch(_=>{}):J({user_id:e.user.id}).then(_=>{window.$message.success("关注成功"),e.user.is_following=!0}).catch(_=>{})}})},h=()=>{l.value=!0,E({page:u.value,page_size:p.value}).then(e=>{l.value=!1,r.value=e.list,m.value=Math.ceil(e.pager.total_rows/p.value),window.scrollTo(0,0)}).catch(e=>{l.value=!1})},R=e=>{u.value=e,h()};return j(()=>{h()}),(e,_)=>{const O=V,P=N,z=Z,A=U,k=ee,B=q,H=T,I=Q,M=X;return o(),t("div",null,[s(O,{title:"收藏"}),s(I,{class:"main-content-wrap",bordered:""},{default:f(()=>[l.value?(o(),t("div",oe,[s(P,{num:p.value},null,8,["num"])])):(o(),t("div",te,[r.value.length===0?(o(),t("div",se,[s(z,{size:"large",description:"暂无数据"})])):y("",!0),c(i).state.desktopModelShow?(o(),t("div",ne,[(o(!0),t(C,null,x(r.value,n=>(o(),F(k,{key:n.id},{default:f(()=>[s(A,{post:n,isOwner:c(i).state.userInfo.id==n.user_id,addFollowAction:!0,onSendWhisper:v,onHandleFollowAction:w},null,8,["post","isOwner"])]),_:2},1024))),128))])):(o(),t("div",ae,[(o(!0),t(C,null,x(r.value,n=>(o(),F(k,{key:n.id},{default:f(()=>[s(B,{post:n,isOwner:c(i).state.userInfo.id==n.user_id,addFollowAction:!0,onSendWhisper:v,onHandleFollowAction:w},null,8,["post","isOwner"])]),_:2},1024))),128))]))])),s(H,{show:d.value,user:g.value,onSuccess:b},null,8,["show","user"])]),_:1}),m.value>0?(o(),t("div",ie,[s(M,{page:u.value,"onUpdate:page":R,"page-slot":c(i).state.collapsedRight?5:8,"page-count":m.value},null,8,["page","page-slot","page-count"])])):y("",!0)])}}});const Ne=L(le,[["__scopeId","data-v-c8f8eee7"]]);export{Ne as default};

@ -0,0 +1 @@
.pagination-wrap[data-v-c8f8eee7]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .main-content-wrap[data-v-c8f8eee7],.dark .empty-wrap[data-v-c8f8eee7],.dark .skeleton-wrap[data-v-c8f8eee7]{background-color:#101014bf}

@ -1 +0,0 @@
.pagination-wrap[data-v-760779af]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .main-content-wrap[data-v-760779af],.dark .empty-wrap[data-v-760779af],.dark .skeleton-wrap[data-v-760779af]{background-color:#101014bf}

@ -1 +0,0 @@
import{_ as I}from"./whisper-7dcedd50.js";import{_ as N,a as Q}from"./post-item.vue_vue_type_style_index_0_lang-a5e9cab2.js";import{_ as V}from"./post-skeleton-4d2b103e.js";import{_ as W}from"./main-nav.vue_vue_type_style_index_0_lang-2982e04a.js";import{u as E}from"./vuex-44de225f.js";import{b as G}from"./vue-router-e5a2430e.js";import{Q as H,_ as L}from"./index-4a465428.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-d8de3dda.js";import"./content-0e30acaf.js";import"./@vicons-7a4ef312.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=E(),S=G(),_=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,H({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 $=W,z=V,B=A,F=N,g=D,M=Q,P=I,R=Y,q=j;return e(),o("div",null,[n($,{title:"收藏"}),n(R,{class:"main-content-wrap",bordered:""},{default:u(()=>[_.value?(e(),o("div",J,[n(z,{num:p.value},null,8,["num"])])):(e(),o("div",K,[i.value.length===0?(e(),o("div",O,[n(B,{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(F,{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(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=L(oe,[["__scopeId","data-v-760779af"]]);export{Ne as default};

@ -0,0 +1 @@
import{_ as O}from"./whisper-9b4eeceb.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 J,x as v,bf as g,h as S,H as a,b as U,Y as z,F as I,u as W,q as E}from"./@vue-a481fc63.js";import{J as G,_ as P,b as L}from"./index-daff1b26.js";import{k as Y,r as K}from"./@vicons-c265fba6.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-8434d30b.js";import{_ as ce}from"./main-nav.vue_vue_type_style_index_0_lang-93352cc4.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=>()=>S(x,null,{default:()=>S(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(()=>[J(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(G)(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,$()};U(()=>{$()});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(I,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:"暂无数据"})])):z("",!0),(s(!0),c(I,null,W(l.value,b=>(s(),E(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"])])):z("",!0)],64)}}});const Le=P(Ce,[["__scopeId","data-v-e20fef94"]]);export{Le as default};

@ -1 +0,0 @@
import{_ as T}from"./whisper-7dcedd50.js";import{d as F,c as j,r as A,e as s,f as c,k as t,w as n,j as i,y as H,A as L,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{F as G,_ as N,b as Q}from"./index-4a465428.js";import{i as Y,p as J}from"./@vicons-7a4ef312.js";import{j as x,o as K,e as X,O as Z,L as ee,F as te,Q as ne,I as oe,G as se}from"./naive-ui-d8de3dda.js";import{_ as ae}from"./post-skeleton-4d2b103e.js";import{_ as ce}from"./main-nav.vue_vue_type_style_index_0_lang-2982e04a.js";import{u as ie}from"./vuex-44de225f.js";import{b as _e}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=F({__name:"contact-item",props:{contact:{}},emits:["send-whisper"],setup(C,{emit:h}){const _=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:_.contact.user_id,avatar:_.contact.avatar,username:_.contact.username,nickname:_.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(()=>[i("span",le,[t(d,{onClick:o[0]||(o[0]=H(()=>{},["stop"])),class:"username-link",to:{name:"user",query:{s:e.contact.username}}},{default:n(()=>[L(v(e.contact.nickname),1)]),_:1},8,["to"])]),i("span",pe," @"+v(e.contact.username),1),i("div",ue,[i("span",me," UID. "+v(e.contact.user_id),1),i("span",de,v(g(G)(e.contact.created_on))+" 加入 ",1)])]),"header-extra":n(()=>[i("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=F({__name:"Contacts",setup(C){const h=ie(),_=_e(),r=a(!1),l=a([]),u=a(+_.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,M=oe,P=ge,V=se,D=T,O=te,R=ne;return s(),c(z,null,[i("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(M,{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};

File diff suppressed because one or more lines are too long

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-c53a3615]{color:#18a058;opacity:.8}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item[data-v-c53a3615]{cursor:pointer}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-avatar[data-v-c53a3615]{color:#18a058;opacity:.8}.tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-title[data-v-c53a3615]{color:#18a058;opacity:.8}.tiny-slide-bar[data-v-c53a3615]{margin-top:-30px;margin-bottom:-30px}.tiny-slide-bar .slide-bar-item[data-v-c53a3615]{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-c53a3615]{justify-content:center;font-size:12px;margin-top:4px;height:40px}.load-more[data-v-c53a3615]{margin:20px}.load-more .load-more-wrap[data-v-c53a3615]{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:14px}.load-more .load-more-wrap .load-more-spinner[data-v-c53a3615]{font-size:14px;opacity:.65}.dark .main-content-wrap[data-v-c53a3615],.dark .pagination-wrap[data-v-c53a3615],.dark .empty-wrap[data-v-c53a3615],.dark .skeleton-wrap[data-v-c53a3615]{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-c53a3615]{color:#63e2b7;opacity:.8}.dark .tiny-slide-bar .tiny-slide-bar__list>div:hover .slide-bar-item .slide-bar-item-title[data-v-c53a3615]{color:#63e2b7;opacity:.8}

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
.message-item[data-v-2e510758]{padding:16px}.message-item.unread[data-v-2e510758]{background:#fcfffc}.message-item .sender-wrap[data-v-2e510758]{display:flex;align-items:center}.message-item .sender-wrap .top-tag[data-v-2e510758]{transform:scale(.75)}.message-item .sender-wrap .username[data-v-2e510758]{opacity:.75;font-size:14px}.message-item .timestamp[data-v-2e510758]{opacity:.75;font-size:12px;display:flex;align-items:center}.message-item .timestamp .timestamp-txt[data-v-2e510758]{margin-left:6px}.message-item .brief-wrap[data-v-2e510758]{margin-top:10px}.message-item .brief-wrap .brief-content[data-v-2e510758],.message-item .brief-wrap .whisper-content-wrap[data-v-2e510758],.message-item .brief-wrap .requesting-friend-wrap[data-v-2e510758]{display:flex;width:100%}.message-item .view-link[data-v-2e510758]{margin-left:8px;display:flex;align-items:center}.message-item .status-info[data-v-2e510758]{margin-left:8px;align-items:center}.dark .message-item[data-v-2e510758]{background-color:#101014bf}.dark .message-item.unread[data-v-2e510758]{background:#0f180b}.dark .message-item .brief-wrap[data-v-2e510758]{background-color:#18181c}.skeleton-item[data-v-01d2e871]{padding:12px;display:flex}.skeleton-item .content[data-v-01d2e871]{width:100%}.dark .skeleton-item[data-v-01d2e871]{background-color:#101014bf}.pagination-wrap[data-v-b40dcbaf]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .empty-wrap[data-v-b40dcbaf],.dark .messages-wrap[data-v-b40dcbaf],.dark .pagination-wrap[data-v-b40dcbaf]{background-color:#101014bf}

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.message-item[data-v-282eff6a]{padding:16px}.message-item.unread[data-v-282eff6a]{background:#fcfffc}.message-item .sender-wrap[data-v-282eff6a]{display:flex;align-items:center}.message-item .sender-wrap .top-tag[data-v-282eff6a]{transform:scale(.75)}.message-item .sender-wrap .username[data-v-282eff6a]{opacity:.75;font-size:14px}.message-item .timestamp[data-v-282eff6a]{opacity:.75;font-size:12px;display:flex;align-items:center}.message-item .timestamp .timestamp-txt[data-v-282eff6a]{margin-left:6px}.message-item .brief-wrap[data-v-282eff6a]{margin-top:10px}.message-item .brief-wrap .brief-content[data-v-282eff6a],.message-item .brief-wrap .whisper-content-wrap[data-v-282eff6a],.message-item .brief-wrap .requesting-friend-wrap[data-v-282eff6a]{display:flex;width:100%}.message-item .view-link[data-v-282eff6a]{margin-left:8px;display:flex;align-items:center}.message-item .status-info[data-v-282eff6a]{margin-left:8px;align-items:center}.dark .message-item[data-v-282eff6a]{background-color:#101014bf}.dark .message-item.unread[data-v-282eff6a]{background:#0f180b}.dark .message-item .brief-wrap[data-v-282eff6a]{background-color:#18181c}.skeleton-item[data-v-01d2e871]{padding:12px;display:flex}.skeleton-item .content[data-v-01d2e871]{width:100%}.dark .skeleton-item[data-v-01d2e871]{background-color:#101014bf}.pagination-wrap[data-v-eb622a78]{padding:10px;display:flex;justify-content:center;overflow:hidden}.dark .empty-wrap[data-v-eb622a78],.dark .messages-wrap[data-v-eb622a78],.dark .pagination-wrap[data-v-eb622a78]{background-color:#101014bf}

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 +0,0 @@
.profile-baseinfo[data-v-756dadd0]{display:flex;padding:16px}.profile-baseinfo .avatar[data-v-756dadd0]{width:72px}.profile-baseinfo .base-info[data-v-756dadd0]{position:relative;margin-left:12px;width:calc(100% - 84px)}.profile-baseinfo .base-info .username[data-v-756dadd0]{line-height:16px;font-size:16px}.profile-baseinfo .base-info .userinfo[data-v-756dadd0]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.profile-baseinfo .base-info .userinfo .info-item[data-v-756dadd0]{margin-right:12px}.profile-baseinfo .base-info .top-tag[data-v-756dadd0]{transform:scale(.75)}.profile-tabs-wrap[data-v-756dadd0]{padding:0 16px}.load-more[data-v-756dadd0]{margin:20px}.load-more .load-more-wrap[data-v-756dadd0]{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:14px}.load-more .load-more-wrap .load-more-spinner[data-v-756dadd0]{font-size:14px;opacity:.65}.dark .profile-wrap[data-v-756dadd0],.dark .pagination-wrap[data-v-756dadd0]{background-color:#101014bf}

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.profile-baseinfo[data-v-4727fe2e]{display:flex;padding:16px}.profile-baseinfo .avatar[data-v-4727fe2e]{width:72px}.profile-baseinfo .base-info[data-v-4727fe2e]{position:relative;margin-left:12px;width:calc(100% - 84px)}.profile-baseinfo .base-info .username[data-v-4727fe2e]{line-height:16px;font-size:16px}.profile-baseinfo .base-info .userinfo[data-v-4727fe2e]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.profile-baseinfo .base-info .userinfo .info-item[data-v-4727fe2e]{margin-right:12px}.profile-baseinfo .base-info .top-tag[data-v-4727fe2e]{transform:scale(.75)}.profile-tabs-wrap[data-v-4727fe2e]{padding:0 16px}.load-more[data-v-4727fe2e]{margin:20px}.load-more .load-more-wrap[data-v-4727fe2e]{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:14px}.load-more .load-more-wrap .load-more-spinner[data-v-4727fe2e]{font-size:14px;opacity:.65}.dark .profile-wrap[data-v-4727fe2e],.dark .pagination-wrap[data-v-4727fe2e]{background-color:#101014bf}

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{A as $,B as M,C as O,D as x,_ as z}from"./index-4a465428.js";import{x as D}from"./@vicons-7a4ef312.js";import{d as F,H as i,c as A,b as q,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 H,F as Y,u as G}from"./@vue-a481fc63.js";import{o as J,M as C,j as K,e as P,O as Q,L as R,F as W,f as X,g as Z,a as ee,k as oe}from"./naive-ui-d8de3dda.js";import{_ as te}from"./main-nav.vue_vue_type_style_index_0_lang-2982e04a.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=A(()=>{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":O({topic_id:t.tag.id}).then(o=>{t.tag.is_following=1,window.$message.success("关注成功")}).catch(o=>{console.log(o)});break;case"unfollow":M({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 q(()=>{r.value=!1}),(e,o)=>{const w=U("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(D))]),_: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=A({get:()=>{let a="编辑";return e.value&&(a="保存"),a},set:a=>{}}),g=()=>{l.value=!0,x({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 q(()=>{g()}),(a,d)=>{const v=te,p=X,L=C,V=Z,N=ie,S=ee,E=oe,I=W;return c(),_("div",null,[n(v,{title:"话题"}),n(I,{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(E,{show:l.value},{default:s(()=>[n(S,null,{default:s(()=>[(c(!0),_(Y,null,G(r.value,y=>(c(),b(N,{tag:y,showAction:h(t).state.userLogined&&e.value,checkFollowing:o.value},null,8,["tag","showAction","checkFollowing"]))),256))]),_:1})]),_:1},8,["show"])]),_:1})])}}});const Se=z(_e,[["__scopeId","data-v-1fb31ecf"]]);export{Se as default}; import{E as $,F as M,G as O,H as z,_ as D}from"./index-daff1b26.js";import{D as G}from"./@vicons-c265fba6.js";import{d as F,H as i,c as q,b as A,r as H,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 U,al as j,F as x,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-93352cc4.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":O({topic_id:t.tag.id}).then(o=>{t.tag.is_following=1,window.$message.success("关注成功")}).catch(o=>{console.log(o)});break;case"unfollow":M({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=H("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);U(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,z({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,I=W;return c(),_("div",null,[n(v,{title:"话题"}),n(I,{class:"main-content-wrap tags-wrap",bordered:""},{default:s(()=>[n(E,{type:"line",animated:"","onUpdate:value":k},j({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),_(x,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};

@ -0,0 +1 @@
.profile-tabs-wrap[data-v-8046429c]{padding:0 16px}.profile-baseinfo[data-v-8046429c]{display:flex;padding:16px}.profile-baseinfo .avatar[data-v-8046429c]{width:72px}.profile-baseinfo .base-info[data-v-8046429c]{position:relative;margin-left:12px;width:calc(100% - 84px)}.profile-baseinfo .base-info .username[data-v-8046429c]{line-height:16px;font-size:16px}.profile-baseinfo .base-info .userinfo[data-v-8046429c]{font-size:14px;line-height:14px;margin-top:10px;opacity:.75}.profile-baseinfo .base-info .userinfo .info-item[data-v-8046429c]{margin-right:12px}.profile-baseinfo .base-info .top-tag[data-v-8046429c]{transform:scale(.75)}.profile-baseinfo .user-opts[data-v-8046429c]{position:absolute;top:16px;right:16px;opacity:.75}.load-more[data-v-8046429c]{margin:20px}.load-more .load-more-wrap[data-v-8046429c]{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:14px}.load-more .load-more-wrap .load-more-spinner[data-v-8046429c]{font-size:14px;opacity:.65}.dark .profile-wrap[data-v-8046429c],.dark .pagination-wrap[data-v-8046429c]{background-color:#101014bf}

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save