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

@ -57,24 +57,96 @@ All notable changes to paopao-ce are documented in this file.
-- 原来的可见性: 0公开 1私密 2好友可见 3关注可见
-- 现在的可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开
UPDATE p_post a
SET visibility = (
SELECT
CASE visibility
UPDATE p_post a, p_post b
SET a.visibility = (
CASE b.visibility
WHEN 0 THEN 90
WHEN 1 THEN 0
WHEN 2 THEN 50
WHEN 3 THEN 60
ELSE 0
END
FROM
p_post b
WHERE
a.ID = b.ID
);
```sql
)
WHERE a.ID = b.ID;
```
- add cache support for index/home etc. page.
- add hots comments support for post detail page.
- add highlight comments support for post detail page.
mirgration database first(sql ddl file in `scripts/migration/**/*_comment_esence.up.sql`):
```sql
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
### Fixed

@ -18,6 +18,7 @@ type Loose interface {
// Chain provide handlers chain for gin
Chain() gin.HandlersChain
TweetDetail(*web.TweetDetailReq) (*web.TweetDetailResp, mir.Error)
TweetComments(*web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error)
TopicList(*web.TopicListReq) (*web.TopicListResp, mir.Error)
GetUserProfile(*web.GetUserProfileReq) (*web.GetUserProfileResp, mir.Error)
@ -35,6 +36,20 @@ func RegisterLooseServant(e *gin.Engine, s Loose) {
router.Use(middlewares...)
// 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) {
select {
case <-c.Request.Context().Done():
@ -47,7 +62,12 @@ func RegisterLooseServant(e *gin.Engine, s Loose) {
return
}
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) {
select {
@ -125,6 +145,10 @@ func (UnimplementedLooseServant) Chain() gin.HandlersChain {
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) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}

@ -27,6 +27,7 @@ type Priv interface {
ThumbsUpTweetComment(*web.TweetCommentThumbsReq) mir.Error
DeleteCommentReply(*web.DeleteCommentReplyReq) mir.Error
CreateCommentReply(*web.CreateCommentReplyReq) (*web.CreateCommentReplyResp, mir.Error)
HighlightComment(*web.HighlightCommentReq) (*web.HighlightCommentResp, mir.Error)
DeleteComment(*web.DeleteCommentReq) mir.Error
CreateComment(*web.CreateCommentReq) (*web.CreateCommentResp, 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)
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) {
select {
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))
}
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 {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}

@ -15,7 +15,6 @@ import (
type Pub interface {
_default_
TweetDetail(*web.TweetDetailReq) (*web.TweetDetailResp, mir.Error)
SendCaptcha(*web.SendCaptchaReq) mir.Error
GetCaptcha() (*web.GetCaptchaResp, mir.Error)
Register(*web.RegisterReq) (*web.RegisterResp, mir.Error)
@ -30,20 +29,6 @@ func RegisterPubServant(e *gin.Engine, s Pub) {
router := e.Group("v1")
// 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) {
select {
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.
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 {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}

@ -6,6 +6,7 @@ toolchain go1.21.1
require (
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/alimy/mir/v4 v4.0.0
github.com/alimy/tryst v0.8.3
@ -29,8 +30,9 @@ require (
github.com/json-iterator/go v1.1.12
github.com/meilisearch/meilisearch-go v0.25.1
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/prometheus/client_golang v1.16.0
github.com/pyroscope-io/client v0.7.2
github.com/redis/rueidis v1.0.18
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/yinheli/mahonia v0.0.0-20131226213531-0eef680515cc
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
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/resty.v1 v1.12.0
@ -60,7 +62,10 @@ require (
github.com/andybalholm/brotli v1.0.5 // 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/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/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // 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-isatty v0.0.19 // 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/sha256-simd v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // 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/pganalyze/pg_query_go/v4 v4.2.3 // 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/tidb/parser v0.0.0-20230815160630-b69fa21942d1 // 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // 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-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/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/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=
@ -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-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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
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/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/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/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
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/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.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/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
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/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.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/meilisearch/meilisearch-go v0.25.1 h1:D5wY22sn5kkpRH3uYMGlwltdUEq5regIFmO7awHz3Vo=
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/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
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-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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.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/v2 v2.12.0 h1:UIVDowFPwpg6yMUpPjGkYvf06K3RAiJXUhCxEwQVHRI=
github.com/onsi/ginkgo/v2 v2.12.0/go.mod h1:ZNEzXISYlqpb8S36iN71ifqLi3vVD1rVJGvWRCJOUpQ=
github.com/onsi/ginkgo/v2 v2.12.1 h1:uHNEO1RP2SpuZApSkel9nEh1/Mu+hmQe7Q+Pepg5OYA=
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-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
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.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.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-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-20190812154241-14fe0d1b01d4/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-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
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.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.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-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
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.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.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/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=
@ -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.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.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
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/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=

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

@ -17,6 +17,9 @@ const (
// 以下包含一些在cache中会用到的key的前缀
const (
InfixCommentDefault = "default"
InfixCommentHots = "hots"
InfixCommentNewest = "newest"
PrefixNewestTweets = "paopao:newesttweets:"
PrefixHotsTweets = "paopao:hotstweets:"
PrefixFollowingTweets = "paopao:followingtweets:"
@ -29,6 +32,9 @@ const (
PrefixUserInfo = "paopao:userinfo:"
PrefixUserInfoById = "paopao:userinfo:id:"
PrefixUserInfoByName = "paopao:userinfo:name:"
PrefixMyFriendIds = "paopao:myfriendids:"
PrefixMyFollowIds = "paopao:myfollowids:"
PrefixTweetComment = "paopao:comment:"
KeySiteStatus = "paopao:sitestatus"
KeyHistoryMaxOnline = "history.max.online"
)
@ -42,6 +48,8 @@ var (
KeyOnlineUser cache.KeyPool[int64]
KeyUserInfoById cache.KeyPool[int64]
KeyUserInfoByName cache.KeyPool[string]
KeyMyFriendIds cache.KeyPool[int64]
KeyMyFollowIds cache.KeyPool[int64]
)
func initCacheKeyPool() {
@ -56,6 +64,8 @@ func initCacheKeyPool() {
KeyOnlineUser = intKeyPool[int64](poolSize, PrefixOnlineUser)
KeyUserInfoById = intKeyPool[int64](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] {

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

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

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

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

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

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

@ -13,8 +13,15 @@ type TweetMetric struct {
UpvoteCount int64
CollectionCount int64
ShareCount int64
ThumbdownCount int64
ThumbupCount int64
ThumbsUpCount int64
ThumbsDownCount int64
}
type CommentMetric struct {
CommentId int64
ReplyCount int32
ThumbsUpCount int32
ThumbsDownCount int32
}
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)
}
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 {
UpdateRankScore(metric *cs.TweetMetric) error
UpdateTweetMetric(metric *cs.TweetMetric) error
AddTweetMetric(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)
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"
"encoding/gob"
"github.com/RoaringBitmap/roaring/roaring64"
"github.com/rocboss/paopao-ce/internal/conf"
"github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/core/ms"
@ -59,3 +60,47 @@ func (s *cacheDataService) GetUserByUsername(username string) (res *ms.User, err
}
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"
"fmt"
"github.com/RoaringBitmap/roaring/roaring64"
"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/ms"
"github.com/rocboss/paopao-ce/internal/events"
"github.com/sirupsen/logrus"
)
type expireIndexTweetsEvent struct {
event.UnimplementedEvent
tweet *ms.Post
ac core.AppCache
keysPattern []string
}
type expireHotsTweetsEvent struct {
event.UnimplementedEvent
tweet *ms.Post
ac core.AppCache
keyPattern string
}
@ -46,21 +46,38 @@ type cacheUserInfoEvent struct {
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{
tweet: tweet,
ac: _appCache,
keysPattern: []string{
conf.PrefixIdxTweetsNewest + "*",
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{
tweet: tweet,
ac: _appCache,
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 {
return "expireIndexTweetsEvent"
}
@ -127,3 +172,49 @@ func (e *cacheUserInfoEvent) Action() (err error) {
}
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)
switch act {
case core.IdxActUpdatePost:
err = s.tms.UpdateRankScore(&cs.TweetMetric{
err = s.tms.UpdateTweetMetric(&cs.TweetMetric{
PostId: post.ID,
CommentCount: post.CommentCount,
UpvoteCount: post.UpvoteCount,
CollectionCount: post.CollectionCount,
ShareCount: post.ShareCount,
})
onExpireIndexTweetEvent(post)
OnExpireIndexTweetEvent(post.UserID)
case core.IdxActCreatePost:
err = s.tms.AddTweetMetric(post.ID)
onExpireIndexTweetEvent(post)
OnExpireIndexTweetEvent(post.UserID)
case core.IdxActDeletePost:
err = s.tms.DeleteTweetMetric(post.ID)
onExpireIndexTweetEvent(post)
OnExpireIndexTweetEvent(post.UserID)
case core.IdxActStickPost, core.IdxActVisiblePost:
onExpireIndexTweetEvent(post)
OnExpireIndexTweetEvent(post.UserID)
}
if err != nil {
logrus.Errorf("eventCacheIndexSrv.SendAction(%s) occurs error: %s", act, err)

@ -5,6 +5,7 @@
package jinzhu
import (
"fmt"
"time"
"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) {
// TODO: 需要优化一下,更精细的调整评论排序策略
sort := "id ASC"
db := s.db.Table(_comment_)
sort := "is_essence DESC, id ASC"
switch style {
case cs.StyleCommentHots:
// TOOD: 暂时简单排序,后续需要根据 rank_score=评论回复数*2+点赞*4-点踩, order byrank_score DESC
sort = "thumbs_up_count DESC, id DESC"
// rank_score=评论回复数*2+点赞*4-点踩, order byrank_score 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:
sort = "id DESC"
sort = "is_essence DESC, id DESC"
case cs.StyleCommentDefault:
fallthrough
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 {
return
}
@ -117,11 +119,9 @@ func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyForma
"comment_id IN ?": ids,
"ORDER": "id ASC",
}, 0, 0)
if err != nil {
return nil, err
}
userIds := []int64{}
for _, reply := range replies {
userIds = append(userIds, reply.UserID, reply.AtUserID)
@ -142,44 +142,61 @@ func (s *commentSrv) GetCommentRepliesByID(ids []int64) ([]*ms.CommentReplyForma
replyFormated.AtUser = user.Format()
}
}
repliesFormated = append(repliesFormated, replyFormated)
}
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()
defer db.Rollback()
err := comment.Delete(s.db)
if err != nil {
return err
if err = comment.Delete(db); err != nil {
return
}
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(),
"is_del": 1,
}).Error
if err != nil {
return err
return
}
db.Commit()
return nil
return
}
func (s *commentManageSrv) CreateComment(comment *ms.Comment) (*ms.Comment, error) {
return comment.Create(s.db)
}
func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (*ms.CommentReply, error) {
return reply.Create(s.db)
func (s *commentManageSrv) CreateCommentReply(reply *ms.CommentReply) (res *ms.CommentReply, err error) {
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) {
db := s.db.Begin()
defer db.Rollback()
err = reply.Delete(s.db)
if err != nil {
return
@ -192,6 +209,8 @@ func (s *commentManageSrv) DeleteCommentReply(reply *ms.CommentReply) (err error
if err != nil {
return
}
// 宽松处理错误
db.Table(_comment_).Where("id=?", reply.CommentID).Update("reply_count", gorm.Expr("reply_count-1"))
db.Commit()
return
}

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

@ -19,13 +19,53 @@ type PostMetric struct {
MotivationFactor int
}
func (p *PostMetric) Create(db *gorm.DB) (*PostMetric, error) {
err := db.Create(&p).Error
return p, err
type CommentMetric struct {
*Model
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 {
return db.Model(p).Where("post_id", p.PostId).Updates(map[string]any{
func (m *UserMetric) Delete(db *gorm.DB) error {
return db.Model(m).Where("user_id", m.UserId).Updates(map[string]any{
"deleted_on": time.Now().Unix(),
"is_del": 1,
}).Error

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

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

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

@ -15,7 +15,15 @@ type tweetMetricSrvA struct {
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) {
postMetric := &dbr.PostMetric{PostId: 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)
}
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{
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
}
type userRelationSrv struct {
db *gorm.DB
}
func newUserManageService(db *gorm.DB) core.UserManageService {
return &userManageSrv{
db: db,
}
}
func newUserRelationService(db *gorm.DB) core.UserRelationService {
return &userRelationSrv{
db: db,
}
}
func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) {
user := &dbr.User{
Model: &dbr.Model{
@ -83,3 +93,57 @@ func (s *userManageSrv) GetRegisterUserCount() (res int64, err error) {
err = s.db.Model(&dbr.User{}).Count(&res).Error
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
}
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) {
// TODO
debug.NotImplemented()

@ -14,7 +14,15 @@ type tweetMetricSrvA struct {
*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
return cs.ErrNotImplemented
}
@ -29,8 +37,50 @@ func (s *tweetMetricSrvA) DeleteTweetMetric(postId int64) (err error) {
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{
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.ContactManageService
core.FollowingManageService
core.UserRelationService
core.SecurityService
core.AttachmentCheckService
core.TweetMetricServantA
core.CommentMetricServantA
}
type webDataSrvA struct {
@ -47,10 +49,12 @@ type webDataSrvA struct {
func NewDataService() (core.DataService, core.VersionInfo) {
db := pgxDB()
pvs := security.NewPhoneVerifyService()
tms := NewTweetMetricServentA(db)
cms := newCommentMetricServentA(db)
tms := newTweetMetricServentA(db)
cis := cache.NewEventCacheIndexSrv(tms)
ds := &dataSrv{
TweetMetricServantA: tms,
CommentMetricServantA: cms,
WalletService: newWalletService(db),
MessageService: newMessageService(db),
TopicService: newTopicService(db),
@ -62,6 +66,7 @@ func NewDataService() (core.DataService, core.VersionInfo) {
UserManageService: newUserManageService(db),
ContactManageService: newContactManageService(db),
FollowingManageService: newFollowingManageService(db),
UserRelationService: newUserRelationService(db),
SecurityService: newSecurityService(db, pvs),
AttachmentCheckService: security.NewAttachmentCheckService(),
}

@ -7,6 +7,7 @@ package slonik
import (
"github.com/jackc/pgx/v5"
"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/pkg/debug"
)
@ -19,6 +20,10 @@ type userManageSrv struct {
*pgxSrv
}
type userRelationSrv struct {
*pgxSrv
}
func (s *userManageSrv) GetUserByID(id int64) (*ms.User, error) {
// TODO
debug.NotImplemented()
@ -67,8 +72,34 @@ func (s *userManageSrv) UpdateUser(user *ms.User) error {
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 {
return &userManageSrv{
pgxSrv: newPgxSrv(db),
}
}
func newUserRelationService(db *pgx.Conn) core.UserRelationService {
return &userRelationSrv{
pgxSrv: newPgxSrv(db),
}
}

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

@ -6,6 +6,7 @@ package events
import (
"github.com/robfig/cron/v3"
"github.com/rocboss/paopao-ce/pkg/types"
)
type (
@ -38,31 +39,49 @@ type JobManager interface {
Schedule(Job) EntryID
}
type jobManager struct {
type emptyJobManager types.Empty
type simpleJobManager struct {
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()
}
func (j *jobManager) Stop() {
func (j *simpleJobManager) Stop() {
j.m.Stop()
}
// 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)
}
// Schedule adds a Job to the Cron to be run on the given schedule.
// 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)
}
func NewJobManager() JobManager {
return &jobManager{
return &simpleJobManager{
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 (
"github.com/alimy/mir/v4"
"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/cs"
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/servants/base"
"github.com/rocboss/paopao-ce/pkg/app"
@ -45,7 +47,9 @@ type TweetCommentsReq struct {
PageSize int `form:"-" binding:"-"`
}
type TweetCommentsResp base.PageResp
type TweetCommentsResp struct {
joint.CachePageResp
}
type TimelineReq struct {
BaseInfo `form:"-" binding:"-"`
@ -106,6 +110,13 @@ type TopicListResp struct {
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) {
r.Page, r.PageSize = page, pageSize
}
@ -137,3 +148,17 @@ func (s CommentStyleType) ToInnerValue() (res cs.StyleCommentType) {
}
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:"-"`
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 {
BaseInfo `json:"-" binding:"-"`
ID int64 `json:"id" binding:"required"`

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

@ -58,6 +58,7 @@ var (
ErrGetReplyFailed = xerror.NewError(40006, "获取评论详情失败")
ErrMaxCommentCount = xerror.NewError(40007, "评论数已达最大限制")
ErrGetCommentThumbs = xerror.NewError(40008, "获取评论点赞信息失败")
ErrHighlightCommentFailed = xerror.NewError(40009, "设置精选评论失败")
ErrGetMessagesFailed = xerror.NewError(50001, "获取消息列表失败")
ErrReadMessageFailed = xerror.NewError(50002, "标记消息已读失败")

@ -24,6 +24,7 @@ import (
"github.com/rocboss/paopao-ce/internal/events"
"github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/pkg/app"
"github.com/rocboss/paopao-ce/pkg/types"
"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) {
post, err := s.Ds.GetPostByID(id)
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)})
}
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) {
res = &cs.VistUser{
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)
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)
resp := base.PageRespFrom(messages, req.Page, req.PageSize, totalRows)
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)
return nil, web.ErrGetCollectionsFailed
}
var posts []*ms.Post
for _, collection := range collections {
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)
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)
return (*web.GetCollectionsResp)(resp), nil
}

@ -9,13 +9,26 @@ import (
"fmt"
"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/cs"
"github.com/rocboss/paopao-ce/internal/core/ms"
"github.com/rocboss/paopao-ce/internal/events"
"github.com/rocboss/paopao-ce/internal/model/joint"
"github.com/rocboss/paopao-ce/internal/model/web"
)
const (
_commentActionCreate uint8 = iota
_commentActionDelete
_commentActionThumbsUp
_commentActionThumbsDown
_commentActionReplyCreate
_commentActionReplyDelete
_commentActionReplyThumbsUp
_commentActionReplyThumbsDown
)
type cacheUnreadMsgEvent struct {
event.UnimplementedEvent
ds core.DataService
@ -30,6 +43,25 @@ type createMessageEvent struct {
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) {
events.OnEvent(&cacheUnreadMsgEvent{
ds: _ds,
@ -86,3 +118,51 @@ func (e *createMessageEvent) Action() (err error) {
}
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/gin-gonic/gin"
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/servants/base"
"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)
return web.ErrUnfollowUserFailed
}
// 触发缓存更新事件
cache.OnCacheMyFollowIdsEvent(s.Ds, r.User.ID)
cache.OnExpireIndexTweetEvent(r.User.ID)
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)
return web.ErrUnfollowUserFailed
}
// 触发缓存更新事件
cache.OnCacheMyFollowIdsEvent(s.Ds, r.User.ID)
cache.OnExpireIndexTweetEvent(r.User.ID)
return nil
}

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

@ -32,10 +32,12 @@ type looseSrv struct {
ac core.AppCache
userTweetsExpire int64
idxTweetsExpire int64
tweetCommentsExpire int64
prefixUserTweets string
prefixIdxTweetsNewest string
prefixIdxTweetsHots string
prefixIdxTweetsFollowing string
prefixTweetComment string
}
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)
return nil, web.ErrGetPostsFailed
}
// TODO: 暂时处理,需要去掉这个步骤
visbleTansform(posts)
userId := int64(-1)
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)
return &web.TimelineResp{
CachePageResp: joint.CachePageResp{
@ -98,7 +106,7 @@ func (s *looseSrv) getIndexTweets(req *web.TimelineReq, limit int, offset int) (
return nil, web.ErrGetPostsUnknowStyle
}
if xerr != nil {
logrus.Errorf("getIndexTweets occurs error: %s", xerr)
logrus.Errorf("getIndexTweets occurs error[1]: %s", xerr)
return nil, web.ErrGetPostFailed
}
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)
return nil, web.ErrGetPostFailed
}
// TODO: 暂时处理,需要去掉这个步骤
visbleTansform(postsFormated)
userId := int64(-1)
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)
// 缓存处理
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) {
switch req.Style {
case web.StyleTweetsFollowing:
username := "_"
if req.User != nil {
username = req.User.Username
}
switch req.Style {
case web.StyleTweetsFollowing:
key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsFollowing, username, offset, limit)
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:
key = fmt.Sprintf("%s%d:%d", s.prefixIdxTweetsHots, offset, limit)
key = fmt.Sprintf("%s%s:%d:%d", s.prefixIdxTweetsHots, username, offset, limit)
default:
return
}
@ -143,6 +157,18 @@ func (s *looseSrv) indexTweetsFromCache(req *web.TimelineReq, limit int, offset
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) {
user, xerr := s.RelationTypFrom(req.User, req.Username)
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) {
stars, totalRows, err := s.Ds.ListUserStarTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
if err != nil {
logrus.Errorf("Ds.GetUserPostStars err: %s", err)
logrus.Errorf("getUserStarTweets err[1]: %s", err)
return nil, web.ErrGetStarsFailed
}
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)
return nil, web.ErrGetStarsFailed
}
// TODO: 暂时处理,需要去掉这个步骤
visbleTansform(postsFormated)
userId := int64(-1)
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)
return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{
@ -233,21 +265,27 @@ func (s *looseSrv) listUserTweets(req *web.GetUserTweetsReq, user *cs.VistUser)
} else if req.Style == web.UserPostsStyleMedia {
tweets, total, err = s.Ds.ListUserMediaTweets(user, req.PageSize, (req.Page-1)*req.PageSize)
} else {
logrus.Errorf("s.listUserTweets unknow style: %s", req.Style)
logrus.Errorf("s.listUserTweets unknow style[1]: %s", req.Style)
return nil, web.ErrGetPostsFailed
}
if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err)
logrus.Errorf("s.listUserTweets err[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
postFormated, err := s.Ds.MergePosts(tweets)
postsFormated, err := s.Ds.MergePosts(tweets)
if err != nil {
logrus.Errorf("s.listUserTweets err: %s", err)
logrus.Errorf("s.listUserTweets err[3]: %s", err)
return nil, web.ErrGetPostsFailed
}
// TODO: 暂时处理,需要去掉这个步骤
visbleTansform(postFormated)
resp := joint.PageRespFrom(postFormated, req.Page, req.PageSize, total)
userId := int64(-1)
if req.User != nil {
userId = req.User.ID
}
if err := s.PrepareTweets(userId, postsFormated); err != nil {
logrus.Errorf("s.listUserTweets err[4]: %s", err)
return nil, web.ErrGetPostsFailed
}
resp := joint.PageRespFrom(postsFormated, req.Page, req.PageSize, total)
return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{
Data: resp,
@ -281,8 +319,14 @@ func (s *looseSrv) getUserPostTweets(req *web.GetUserTweetsReq, user *cs.VistUse
logrus.Errorf("s.GetTweetList error[2]: %s", err)
return nil, web.ErrGetPostsFailed
}
// TODO: 暂时处理,需要去掉这个步骤
visbleTansform(postsFormated)
userId := int64(-1)
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)
return &web.GetUserTweetsResp{
CachePageResp: joint.CachePageResp{
@ -363,9 +407,18 @@ func (s *looseSrv) TopicList(req *web.TopicListReq) (*web.TopicListResp, mir.Err
}, nil
}
func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsResp, mir.Error) {
comments, totalRows, err := s.Ds.GetComments(req.TweetId, req.Style.ToInnerValue(), req.PageSize, (req.Page-1)*req.PageSize)
if err != nil {
func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (res *web.TweetCommentsResp, err mir.Error) {
limit, offset := req.PageSize, (req.Page-1)*req.PageSize
// 尝试直接从缓存中获取数据
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
}
@ -376,25 +429,29 @@ func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsR
commentIDs = append(commentIDs, comment.ID)
}
users, err := s.Ds.GetUsersByIDs(userIDs)
if err != nil {
users, xerr := s.Ds.GetUsersByIDs(userIDs)
if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[2]: %s", xerr)
return nil, web.ErrGetCommentsFailed
}
contents, err := s.Ds.GetCommentContentsByIDs(commentIDs)
if err != nil {
contents, xerr := s.Ds.GetCommentContentsByIDs(commentIDs)
if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[3]: %s", xerr)
return nil, web.ErrGetCommentsFailed
}
replies, err := s.Ds.GetCommentRepliesByID(commentIDs)
if err != nil {
replies, xerr := s.Ds.GetCommentRepliesByID(commentIDs)
if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[4]: %s", xerr)
return nil, web.ErrGetCommentsFailed
}
var commentThumbs, replyThumbs cs.CommentThumbsMap
if req.Uid > 0 {
commentThumbs, replyThumbs, err = s.Ds.GetCommentThumbsMap(req.Uid, req.TweetId)
if err != nil {
commentThumbs, replyThumbs, xerr = s.Ds.GetCommentThumbsMap(req.Uid, req.TweetId)
if xerr != nil {
logrus.Errorf("looseSrv.TweetComments occurs error[5]: %s", xerr)
return nil, web.ErrGetCommentsFailed
}
}
@ -434,8 +491,41 @@ func (s *looseSrv) TweetComments(req *web.TweetCommentsReq) (*web.TweetCommentsR
}
commentsFormated = append(commentsFormated, commentFormated)
}
resp := base.PageRespFrom(commentsFormated, req.Page, req.PageSize, totalRows)
return (*web.TweetCommentsResp)(resp), nil
resp := joint.PageRespFrom(commentsFormated, req.Page, req.PageSize, totalRows)
// 缓存处理
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 {
@ -445,9 +535,11 @@ func newLooseSrv(s *base.DaoServant, ac core.AppCache) api.Loose {
ac: ac,
userTweetsExpire: cs.UserTweetsExpire,
idxTweetsExpire: cs.IndexTweetsExpire,
tweetCommentsExpire: cs.TweetCommentsExpire,
prefixUserTweets: conf.PrefixUserTweets,
prefixIdxTweetsNewest: conf.PrefixIdxTweetsNewest,
prefixIdxTweetsHots: conf.PrefixIdxTweetsHots,
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)
return web.ErrThumbsDownTweetComment
}
// 缓存处理
onCommentActionEvent(req.TweetId, req.CommentId, _commentActionThumbsDown)
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)
return web.ErrThumbsUpTweetComment
}
// 缓存处理
onCommentActionEvent(req.TweetId, req.CommentId, _commentActionThumbsUp)
return nil
}
@ -355,10 +359,14 @@ func (s *privSrv) DeleteCommentReply(req *web.DeleteCommentReplyReq) mir.Error {
logrus.Errorf("s.deletePostCommentReply err: %s", err)
return web.ErrDeleteCommentFailed
}
// 缓存处理, 宽松处理错误
if comment, err := s.Ds.GetCommentByID(reply.CommentID); err == nil {
onCommentActionEvent(comment.PostID, comment.ID, _commentActionReplyDelete)
}
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 (
post *ms.Post
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
}
@ -461,9 +471,22 @@ func (s *privSrv) DeleteComment(req *web.DeleteCommentReq) mir.Error {
logrus.Errorf("Ds.DeleteComment err: %s", err)
return web.ErrDeleteCommentFailed
}
onCommentActionEvent(comment.PostID, comment.ID, _commentActionDelete)
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) {
var (
mediaContents []string
@ -553,7 +576,8 @@ func (s *privSrv) CreateComment(req *web.CreateCommentReq) (_ *web.CreateComment
CommentID: comment.ID,
})
}
// 缓存处理
onCommentActionEvent(comment.PostID, comment.ID, _commentActionCreate)
return (*web.CreateCommentResp)(comment), nil
}

@ -42,34 +42,6 @@ type pubSrv struct {
*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 {
ctx := context.Background()

@ -207,10 +207,3 @@ func checkPermision(user *ms.User, targetUserId int64) mir.Error {
}
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)) {
if h != nil {
h(s.server.e)
}
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/fatih/color"
"github.com/gin-gonic/gin"
"github.com/rocboss/paopao-ce/internal/conf"
)
@ -31,7 +30,7 @@ func (s *pprofService) Version() *semver.Version {
}
func (s *pprofService) OnInit() error {
s.registerRoute(s, func(*gin.Engine) {})
s.registerRoute(s, nil)
return nil
}
@ -43,10 +42,8 @@ func newPprofService() Service {
addr := conf.PprofServerSetting.HttpIp + ":" + conf.PprofServerSetting.HttpPort
// notice this step just to register pprof server to start. don't share server with pprof.
server := httpServers.from(addr, func() *httpServer {
engine := newWebEngine()
return &httpServer{
baseServer: newBaseServe(),
e: engine,
server: &http.Server{
Addr: addr,
Handler: http.DefaultServeMux,

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

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

@ -29,4 +29,7 @@ type Loose struct {
// TweetComments 获取动态评论
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 删除动态评论
DeleteComment func(Delete, web.DeleteCommentReq) `mir:"/post/comment"`
// HighlightComment 精选动态评论
HighlightComment func(Post, web.HighlightCommentReq) web.HighlightCommentResp `mir:"/post/comment/highlight"`
// CreateCommentReply 发布评论回复
CreateCommentReply func(Post, web.CreateCommentReplyReq) web.CreateCommentReplyResp `mir:"/post/comment/reply"`
@ -66,7 +69,7 @@ type Priv struct {
// ThumbsDownTweetComment 点踩评论
ThumbsDownTweetComment func(Post, web.TweetCommentThumbsReq) `mir:"/tweet/comment/thumbsdown"`
// ThumbsUpTweetReply 点赞评论回复
// ThumbsUpTweetReply 点赞评论回复·
ThumbsUpTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsup"`
// ThumbsDownTweetReply 点踩评论回复

@ -28,7 +28,4 @@ type Pub struct {
// SendCaptcha 发送验证码
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`;
CREATE TABLE `p_attachment` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL DEFAULT '0',
`file_size` bigint unsigned NOT NULL,
`img_width` bigint unsigned NOT NULL DEFAULT '0',
`img_height` bigint unsigned NOT NULL DEFAULT '0',
`type` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '1图片2视频3其他附件',
`id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` BIGINT NOT NULL DEFAULT '0',
`file_size` BIGINT NOT NULL,
`img_width` BIGINT NOT NULL DEFAULT '0',
`img_height` BIGINT NOT NULL DEFAULT '0',
`type` tinyint NOT NULL DEFAULT '1' COMMENT '1图片2视频3其他附件',
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_attachment_user` (`user_id`) USING BTREE
) 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`;
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 '手机号',
`captcha` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '验证码',
`use_times` int unsigned NOT NULL DEFAULT '0' COMMENT '使用次数',
`expired_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '过期时间',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`use_times` int NOT NULL DEFAULT '0' COMMENT '使用次数',
`expired_on` BIGINT NOT NULL DEFAULT '0' COMMENT '过期时间',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_captcha_phone` (`phone`) 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`;
CREATE TABLE `p_comment` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '评论ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '评论ID',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST 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_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_down_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点踩数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`is_essence` tinyint NOT NULL DEFAULT 0 COMMENT '是否精选',
`reply_count` int NOT NULL DEFAULT 0 COMMENT '回复数',
`thumbs_up_count` int NOT NULL DEFAULT 0 COMMENT '点赞数',
`thumbs_down_count` int NOT NULL DEFAULT 0 COMMENT '点踩数',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_comment_post_id` (`post_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`;
CREATE TABLE `p_comment_content` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`comment_id` BIGINT 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 '内容',
`type` tinyint unsigned NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址',
`sort` bigint unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`type` tinyint NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址',
`sort` BIGINT NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_comment_content_comment_id` (`comment_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`;
CREATE TABLE `p_comment_reply` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '回复ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`at_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '@用户ID',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '回复ID',
`comment_id` BIGINT NOT NULL DEFAULT '0' COMMENT '评论ID',
`user_id` BIGINT 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 '内容',
`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城市地址',
`thumbs_up_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞数',
`thumbs_down_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点踩数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`thumbs_up_count` int NOT NULL DEFAULT '0' COMMENT '点赞数',
`thumbs_down_count` int NOT NULL DEFAULT '0' COMMENT '点踩数',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_comment_reply_comment_id` (`comment_id`) USING BTREE
) 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
-- ----------------------------
DROP TABLE IF EXISTS `p_tweet_comment_thumbs`;
CREATE TABLE `p_tweet_comment_thumbs` (
`id` BIGINT unsigned NOT NULL AUTO_INCREMENT COMMENT 'thumbs ID',
`user_id` BIGINT unsigned NOT NULL,
`tweet_id` BIGINT unsigned NOT NULL COMMENT '推文ID',
`comment_id` BIGINT unsigned NOT NULL COMMENT '评论ID',
`reply_id` BIGINT unsigned COMMENT '评论回复ID',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'thumbs ID',
`user_id` BIGINT NOT NULL,
`tweet_id` BIGINT NOT NULL COMMENT '推文ID',
`comment_id` BIGINT NOT NULL COMMENT '评论ID',
`reply_id` BIGINT COMMENT '评论回复ID',
`comment_type` TINYINT NOT NULL DEFAULT '0' COMMENT '评论类型 0为推文评论、1为评论回复',
`is_thumbs_up` TINYINT unsigned NOT NULL DEFAULT '0' COMMENT '是否点赞',
`is_thumbs_down` TINYINT unsigned NOT NULL DEFAULT '0' COMMENT '是否点踩',
`created_on` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` TINYINT unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`is_thumbs_up` TINYINT NOT NULL DEFAULT '0' COMMENT '是否点赞',
`is_thumbs_down` TINYINT NOT NULL DEFAULT '0' COMMENT '是否点踩',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_tweet_comment_thumbs_uid_tid` (`user_id`, `tweet_id`) USING BTREE
) 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`;
CREATE TABLE `p_message` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '消息通知ID',
`sender_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '发送方用户ID',
`receiver_user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '接收方用户ID',
`type` tinyint unsigned NOT NULL DEFAULT '1' COMMENT '通知类型1动态2评论3回复4私信99系统通知',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '消息通知ID',
`sender_user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '发送方用户ID',
`receiver_user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '接收方用户ID',
`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 '摘要说明',
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '详细内容',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '动态ID',
`comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论ID',
`reply_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '回复ID',
`is_read` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否已读',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT '动态ID',
`comment_id` BIGINT NOT NULL DEFAULT '0' COMMENT '评论ID',
`reply_id` BIGINT NOT NULL DEFAULT '0' COMMENT '回复ID',
`is_read` tinyint NOT NULL DEFAULT '0' COMMENT '是否已读',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_message_receiver_user_id` (`receiver_user_id`) 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`;
CREATE TABLE `p_post` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主题ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`comment_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '评论数',
`collection_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '收藏数',
`upvote_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '点赞数',
`share_count` bigint unsigned NOT NULL DEFAULT '0' COMMENT '分享数',
`visibility` tinyint unsigned 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_essence` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否精华',
`is_lock` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否锁定',
`latest_replied_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '最新回复时间',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主题ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`comment_count` BIGINT NOT NULL DEFAULT '0' COMMENT '评论数',
`collection_count` BIGINT NOT NULL DEFAULT '0' COMMENT '收藏数',
`upvote_count` BIGINT NOT NULL DEFAULT '0' COMMENT '点赞数',
`share_count` BIGINT NOT NULL DEFAULT '0' COMMENT '分享数',
`visibility` tinyint NOT NULL DEFAULT '0' COMMENT '可见性: 0私密 10充电可见 20订阅可见 30保留 40保留 50好友可见 60关注可见 70保留 80保留 90公开',
`is_top` tinyint NOT NULL DEFAULT '0' COMMENT '是否置顶',
`is_essence` tinyint NOT NULL DEFAULT '0' COMMENT '是否精华',
`is_lock` tinyint 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 '标签',
`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_loc` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'IP城市地址',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_post_user_id` (`user_id`) USING BTREE,
KEY `idx_post_visibility` (`visibility`) USING BTREE
@ -186,16 +207,16 @@ CREATE TABLE `p_post` (
-- ----------------------------
DROP TABLE IF EXISTS `p_post_metric`;
CREATE TABLE `p_post_metric` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`post_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,
`id` BIGINT NOT NULL AUTO_INCREMENT,
`post_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, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned 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_post_metric_post_id_rank_score` (`post_id`,`rank_score`) USING BTREE
) 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`;
CREATE TABLE `p_post_attachment_bill` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '购买记录ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`paid_amount` bigint unsigned NOT NULL DEFAULT '0' COMMENT '支付金额',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '购买记录ID',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`paid_amount` BIGINT NOT NULL DEFAULT '0' COMMENT '支付金额',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_post_attachment_bill_post_id` (`post_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`;
CREATE TABLE `p_post_collection` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_post_collection_post_id` (`post_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`;
CREATE TABLE `p_post_content` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '内容ID',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`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收费资源',
`sort` int unsigned NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`type` tinyint NOT NULL DEFAULT '2' COMMENT '类型1标题2文字段落3图片地址4视频地址5语音地址6链接地址7附件资源8收费资源',
`sort` int NOT NULL DEFAULT '100' COMMENT '排序,越小越靠前',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_post_content_post_id` (`post_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`;
CREATE TABLE `p_post_star` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '收藏ID',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'POST ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_post_star_post_id` (`post_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`;
CREATE TABLE `p_tag` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '标签ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建者ID',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '标签ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '创建者ID',
`tag` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '标签名',
`quote_num` bigint unsigned NOT NULL DEFAULT '0' COMMENT '引用数',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`quote_num` BIGINT NOT NULL DEFAULT '0' COMMENT '引用数',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
UNIQUE KEY `idx_tag_tag` (`tag`) 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`;
CREATE TABLE `p_topic_user` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`topic_id` BIGINT UNSIGNED NOT NULL COMMENT '标签ID',
`user_id` BIGINT UNSIGNED NOT NULL COMMENT '创建者ID',
`id` BIGINT NOT NULL AUTO_INCREMENT,
`topic_id` BIGINT NOT NULL COMMENT '标签ID',
`user_id` BIGINT NOT NULL COMMENT '创建者ID',
`alias_name` VARCHAR ( 255 ) COMMENT '别名',
`remark` VARCHAR ( 512 ) COMMENT '备注',
`quote_num` BIGINT UNSIGNED COMMENT '引用数',
`is_top` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '是否置顶 0 为未置顶、1 为已置顶',
`created_on` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`quote_num` BIGINT COMMENT '引用数',
`is_top` TINYINT NOT NULL DEFAULT '0' COMMENT '是否置顶 0 为未置顶、1 为已置顶',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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 为已删除',
`reserve_a` VARCHAR ( 255 ) COMMENT '保留字段a',
`reserve_b` VARCHAR ( 255 ) COMMENT '保留字段b',
PRIMARY KEY ( `id` ) USING BTREE,
@ -318,37 +339,54 @@ CREATE TABLE `p_topic_user` (
-- ----------------------------
DROP TABLE IF EXISTS `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 '昵称',
`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 '手机号',
`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 '盐值',
`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 '用户头像',
`balance` bigint unsigned NOT NULL COMMENT '用户余额(分)',
`is_admin` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否管理员',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`balance` BIGINT NOT NULL COMMENT '用户余额(分)',
`is_admin` tinyint NOT NULL DEFAULT '0' COMMENT '是否管理员',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
UNIQUE KEY `idx_user_username` (`username`) USING BTREE,
KEY `idx_user_phone` (`phone`) USING BTREE
) 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
-- ----------------------------
DROP TABLE IF EXISTS `p_following`;
CREATE TABLE `p_following` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`follow_id` bigint unsigned NOT NULL,
`id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` BIGINT NOT NULL,
`follow_id` BIGINT NOT NULL,
`is_del` tinyint NOT NULL DEFAULT 0, -- 是否删除, 0否, 1是
`created_on` bigint unsigned NOT NULL DEFAULT '0',
`modified_on` bigint unsigned NOT NULL DEFAULT '0',
`deleted_on` bigint unsigned 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_following_user_follow` (`user_id`,`follow_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
@ -358,19 +396,19 @@ CREATE TABLE `p_following` (
-- ----------------------------
DROP TABLE IF EXISTS `p_contact`;
CREATE TABLE `p_contact` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '联系人ID',
`user_id` bigint unsigned NOT NULL COMMENT '用户ID',
`friend_id` bigint unsigned NOT NULL COMMENT '好友ID',
`group_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '好友分组ID:默认为0无分组',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '联系人ID',
`user_id` BIGINT NOT NULL COMMENT '用户ID',
`friend_id` BIGINT NOT NULL COMMENT '好友ID',
`group_id` BIGINT NOT NULL DEFAULT '0' COMMENT '好友分组ID:默认为0无分组',
`remark` varchar(32) NOT NULL DEFAULT '' COMMENT '好友备注',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '好友状态: 1请求好友, 2已好友, 3拒绝好友, 4已删好友',
`is_top` 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是',
`notice_enable` tinyint NOT NULL DEFAULT '0' COMMENT '是否有消息提醒, 0否, 1是',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`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
@ -381,13 +419,13 @@ CREATE TABLE `p_contact` (
-- ----------------------------
DROP TABLE IF EXISTS `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',
`name` varchar(32) NOT NULL DEFAULT '' COMMENT '分组名称',
`is_del` tinyint NOT NULL DEFAULT '1' COMMENT '是否删除, 0否, 1是',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
PRIMARY KEY (`id`) USING BTREE
) 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`;
CREATE TABLE `p_wallet_recharge` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '充值ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`amount` bigint NOT NULL DEFAULT '0' COMMENT '充值金额',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '充值ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`amount` BIGINT NOT NULL DEFAULT '0' 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 '交易状态',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_wallet_recharge_user_id` (`user_id`) 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`;
CREATE TABLE `p_wallet_statement` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '账单ID',
`user_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '用户ID',
`change_amount` bigint NOT NULL DEFAULT '0' COMMENT '变动金额',
`balance_snapshot` bigint NOT NULL DEFAULT '0' COMMENT '资金快照',
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '账单ID',
`user_id` BIGINT NOT NULL DEFAULT '0' COMMENT '用户ID',
`change_amount` 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 '变动原因',
`post_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '关联动态',
`created_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` bigint unsigned NOT NULL DEFAULT '0' COMMENT '删除时间',
`is_del` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0 为未删除、1 为已删除',
`post_id` BIGINT NOT NULL DEFAULT '0' COMMENT '关联动态',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`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,
KEY `idx_wallet_statement_user_id` (`user_id`) USING BTREE
) 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,
ip VARCHAR(64) NOT NULL DEFAULT '',
ip_loc VARCHAR(64) NOT NULL DEFAULT '',
thumbs_up_count int NOT NULL DEFAULT 0, -- 点赞数
thumbs_down_count int NOT NULL DEFAULT 0, -- 点踩数
is_essence SMALLINT 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,
modified_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 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;
CREATE TABLE p_tweet_comment_thumbs (
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 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;
CREATE TABLE p_following (
id BIGSERIAL PRIMARY KEY,

@ -46,6 +46,7 @@ CREATE TABLE "p_comment" (
"user_id" integer NOT NULL,
"ip" 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_down_count" integer NOT NULL DEFAULT 0, -- 点踩数
"created_on" integer NOT NULL,
@ -94,6 +95,23 @@ CREATE TABLE "p_comment_reply" (
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
-- ----------------------------
@ -354,6 +372,21 @@ CREATE TABLE "p_user" (
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
-- ----------------------------
@ -488,6 +521,15 @@ ON "p_comment_reply" (
"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
-- ----------------------------
@ -643,6 +685,16 @@ ON "p_user" (
"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
-- ----------------------------

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