feat: add pin topic support

pull/455/head
Michael Li 2 years ago
parent 6c51c79a39
commit 8967359c15
No known key found for this signature in database

@ -5,6 +5,7 @@ All notable changes to paopao-ce are documented in this file.
### Added ### Added
- add all-in-one docker image build scripts. - add all-in-one docker image build scripts.
- frontend: add tweets filter support use tag for home page and make it as default behavior. - frontend: add tweets filter support use tag for home page and make it as default behavior.
- add pin topic support.
## 0.5.2 ## 0.5.2
### Change ### Change

@ -20,6 +20,7 @@ type Priv interface {
UnfollowTopic(*web.UnfollowTopicReq) mir.Error UnfollowTopic(*web.UnfollowTopicReq) mir.Error
FollowTopic(*web.FollowTopicReq) mir.Error FollowTopic(*web.FollowTopicReq) mir.Error
PinTopic(*web.PinTopicReq) (*web.PinTopicResp, mir.Error)
StickTopic(*web.StickTopicReq) (*web.StickTopicResp, mir.Error) StickTopic(*web.StickTopicReq) (*web.StickTopicResp, mir.Error)
ThumbsDownTweetReply(*web.TweetReplyThumbsReq) mir.Error ThumbsDownTweetReply(*web.TweetReplyThumbsReq) mir.Error
ThumbsUpTweetReply(*web.TweetReplyThumbsReq) mir.Error ThumbsUpTweetReply(*web.TweetReplyThumbsReq) mir.Error
@ -91,6 +92,20 @@ func RegisterPrivServant(e *gin.Engine, s Priv, m ...PrivChain) {
} }
s.Render(c, nil, s.FollowTopic(req)) s.Render(c, nil, s.FollowTopic(req))
}) })
router.Handle("POST", "/topic/pin", func(c *gin.Context) {
select {
case <-c.Request.Context().Done():
return
default:
}
req := new(web.PinTopicReq)
if err := s.Bind(c, req); err != nil {
s.Render(c, nil, err)
return
}
resp, err := s.PinTopic(req)
s.Render(c, resp, err)
})
router.Handle("POST", "/topic/stick", func(c *gin.Context) { router.Handle("POST", "/topic/stick", func(c *gin.Context) {
select { select {
case <-c.Request.Context().Done(): case <-c.Request.Context().Done():
@ -406,6 +421,10 @@ func (UnimplementedPrivServant) FollowTopic(req *web.FollowTopicReq) mir.Error {
return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }
func (UnimplementedPrivServant) PinTopic(req *web.PinTopicReq) (*web.PinTopicResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
}
func (UnimplementedPrivServant) StickTopic(req *web.StickTopicReq) (*web.StickTopicResp, mir.Error) { func (UnimplementedPrivServant) StickTopic(req *web.StickTopicReq) (*web.StickTopicResp, mir.Error) {
return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented)) return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
} }

@ -9,6 +9,7 @@ const (
TagTypeHot TagType = "hot" TagTypeHot TagType = "hot"
TagTypeNew TagType = "new" TagTypeNew TagType = "new"
TagTypeFollow TagType = "follow" TagTypeFollow TagType = "follow"
TagTypePin TagType = "pin"
TagTypeHotExtral TagType = "hot_extral" TagTypeHotExtral TagType = "hot_extral"
) )
@ -40,6 +41,7 @@ type TagItem struct {
QuoteNum int64 `json:"quote_num"` QuoteNum int64 `json:"quote_num"`
IsFollowing int8 `json:"is_following"` IsFollowing int8 `json:"is_following"`
IsTop int8 `json:"is_top"` IsTop int8 `json:"is_top"`
IsPin int8 `json:"is_pin"`
} }
func (t *TagInfo) Format() *TagItem { func (t *TagInfo) Format() *TagItem {
@ -51,5 +53,6 @@ func (t *TagInfo) Format() *TagItem {
QuoteNum: t.QuoteNum, QuoteNum: t.QuoteNum,
IsFollowing: 0, IsFollowing: 0,
IsTop: 0, IsTop: 0,
IsPin: 0,
} }
} }

@ -16,10 +16,11 @@ type TopicService interface {
TagsByKeyword(keyword string) (cs.TagInfoList, error) TagsByKeyword(keyword string) (cs.TagInfoList, error)
GetHotTags(userId int64, limit int, offset int) (cs.TagList, error) GetHotTags(userId int64, limit int, offset int) (cs.TagList, error)
GetNewestTags(userId int64, limit int, offset int) (cs.TagList, error) GetNewestTags(userId int64, limit int, offset int) (cs.TagList, error)
GetFollowTags(userId int64, limit int, offset int) (cs.TagList, error) GetFollowTags(userId int64, is_pin bool, limit int, offset int) (cs.TagList, error)
FollowTopic(userId int64, topicId int64) error FollowTopic(userId int64, topicId int64) error
UnfollowTopic(userId int64, topicId int64) error UnfollowTopic(userId int64, topicId int64) error
StickTopic(userId int64, topicId int64) (int8, error) StickTopic(userId int64, topicId int64) (int8, error)
PinTopic(userId int64, topicId int64) (int8, error)
} }
// TopicServantA 话题服务(版本A) // TopicServantA 话题服务(版本A)

@ -25,6 +25,7 @@ type TopicUser struct {
Remark string `json:"-"` Remark string `json:"-"`
QuoteNum int64 `json:"quote_num"` QuoteNum int64 `json:"quote_num"`
IsTop int8 `json:"is_top"` IsTop int8 `json:"is_top"`
IsPin int8 `json:"is_pin"`
ReserveA string `json:"-"` ReserveA string `json:"-"`
ReserveB string `json:"-"` ReserveB string `json:"-"`
} }

@ -33,6 +33,7 @@ type topicSrvA struct {
type topicInfo struct { type topicInfo struct {
TopicId int64 TopicId int64
IsTop int8 IsTop int8
IsPin int8
} }
func newTopicService(db *gorm.DB) core.TopicService { func newTopicService(db *gorm.DB) core.TopicService {
@ -110,17 +111,18 @@ func (s *topicSrv) GetNewestTags(userId int64, limit int, offset int) (cs.TagLis
return s.tagsFormatA(userId, tags) return s.tagsFormatA(userId, tags)
} }
func (s *topicSrv) GetFollowTags(userId int64, limit int, offset int) (cs.TagList, error) { func (s *topicSrv) GetFollowTags(userId int64, is_pin bool, limit int, offset int) (cs.TagList, error) {
if userId < 0 { if userId < 0 {
return nil, nil return nil, nil
} }
userTopics := []*topicInfo{} userTopics := []*topicInfo{}
err := s.db.Model(&dbr.TopicUser{}). db := s.db.Model(&dbr.TopicUser{}).Order("is_top DESC").Limit(limit).Offset(offset)
Where("user_id=?", userId). if is_pin {
Order("is_top DESC"). db = db.Where("user_id=? AND is_pin=1", userId)
Limit(limit). } else {
Offset(offset). db = db.Where("user_id=?", userId)
Find(&userTopics).Error }
err := db.Find(&userTopics).Error
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -207,7 +209,7 @@ func (s *topicSrv) tagsFormatA(userId int64, tags cs.TagList) (cs.TagList, error
} }
for _, tag := range tags { for _, tag := range tags {
if info, exist := userTopicsMap[tag.ID]; exist { if info, exist := userTopicsMap[tag.ID]; exist {
tag.IsFollowing, tag.IsTop = 1, info.IsTop tag.IsFollowing, tag.IsTop, tag.IsPin = 1, info.IsTop, info.IsPin
} }
} }
} }
@ -238,7 +240,7 @@ func (s *topicSrv) tagsFormatB(userTopicsMap map[int64]*topicInfo, tags cs.TagIn
if len(userTopicsMap) > 0 { if len(userTopicsMap) > 0 {
for _, tag := range tagList { for _, tag := range tagList {
if info, exist := userTopicsMap[tag.ID]; exist { if info, exist := userTopicsMap[tag.ID]; exist {
tag.IsFollowing, tag.IsTop = 1, info.IsTop tag.IsFollowing, tag.IsTop, tag.IsPin = 1, info.IsTop, info.IsPin
} }
} }
} }
@ -409,3 +411,27 @@ func (s *topicSrv) StickTopic(userId int64, topicId int64) (status int8, err err
db.Commit() db.Commit()
return return
} }
func (s *topicSrv) PinTopic(userId int64, topicId int64) (status int8, err error) {
db := s.db.Begin()
defer db.Rollback()
m := &dbr.TopicUser{}
err = db.Model(m).
Where("user_id=? and topic_id=?", userId, topicId).
UpdateColumn("is_pin", gorm.Expr("1-is_pin")).Error
if err != nil {
return
}
status = -1
err = db.Model(m).Where("user_id=? and topic_id=?", userId, topicId).Select("is_pin").Scan(&status).Error
if err != nil {
return
}
if status < 0 {
return -1, errors.New("topic not exist")
}
db.Commit()
return
}

@ -20,6 +20,7 @@ const (
TagTypeHot = cs.TagTypeHot TagTypeHot = cs.TagTypeHot
TagTypeNew = cs.TagTypeNew TagTypeNew = cs.TagTypeNew
TagTypeFollow = cs.TagTypeFollow TagTypeFollow = cs.TagTypeFollow
TagTypePin = cs.TagTypePin
TagTypeHotExtral = cs.TagTypeHotExtral TagTypeHotExtral = cs.TagTypeHotExtral
) )

@ -207,6 +207,15 @@ type StickTopicResp struct {
StickStatus int8 `json:"top_status"` StickStatus int8 `json:"top_status"`
} }
type PinTopicReq struct {
SimpleInfo `json:"-" binding:"-"`
TopicId int64 `json:"topic_id" binding:"required"`
}
type PinTopicResp struct {
PinStatus int8 `json:"pin_status"`
}
type FollowTopicReq struct { type FollowTopicReq struct {
SimpleInfo `json:"-" binding:"-"` SimpleInfo `json:"-" binding:"-"`
TopicId int64 `json:"topic_id" binding:"required"` TopicId int64 `json:"topic_id" binding:"required"`

@ -95,6 +95,7 @@ var (
ErrFollowTopicFailed = xerror.NewError(90001, "关注话题失败") ErrFollowTopicFailed = xerror.NewError(90001, "关注话题失败")
ErrUnfollowTopicFailed = xerror.NewError(90002, "取消关注话题失败") ErrUnfollowTopicFailed = xerror.NewError(90002, "取消关注话题失败")
ErrStickTopicFailed = xerror.NewError(90003, "更行话题置顶状态失败") ErrStickTopicFailed = xerror.NewError(90003, "更行话题置顶状态失败")
ErrPinTopicFailed = xerror.NewError(90005, "更行话题钉住状态失败")
ErrThumbsUpTweetComment = xerror.NewError(90101, "评论点赞失败") ErrThumbsUpTweetComment = xerror.NewError(90101, "评论点赞失败")
ErrThumbsDownTweetComment = xerror.NewError(90102, "评论点踩失败") ErrThumbsDownTweetComment = xerror.NewError(90102, "评论点踩失败")
ErrThumbsUpTweetReply = xerror.NewError(90103, "评论回复点赞失败") ErrThumbsUpTweetReply = xerror.NewError(90103, "评论回复点赞失败")

@ -384,7 +384,9 @@ func (s *looseSrv) TopicList(req *web.TopicListReq) (*web.TopicListResp, mir.Err
case web.TagTypeNew: case web.TagTypeNew:
tags, err = s.Ds.GetNewestTags(req.Uid, num, 0) tags, err = s.Ds.GetNewestTags(req.Uid, num, 0)
case web.TagTypeFollow: case web.TagTypeFollow:
tags, err = s.Ds.GetFollowTags(req.Uid, num, 0) tags, err = s.Ds.GetFollowTags(req.Uid, false, num, 0)
case web.TagTypePin:
tags, err = s.Ds.GetFollowTags(req.Uid, true, num, 0)
case web.TagTypeHotExtral: case web.TagTypeHotExtral:
extralNum := req.ExtralNum extralNum := req.ExtralNum
if extralNum <= 0 { if extralNum <= 0 {
@ -392,7 +394,7 @@ func (s *looseSrv) TopicList(req *web.TopicListReq) (*web.TopicListResp, mir.Err
} }
tags, err = s.Ds.GetHotTags(req.Uid, num, 0) tags, err = s.Ds.GetHotTags(req.Uid, num, 0)
if err == nil { if err == nil {
extralTags, err = s.Ds.GetFollowTags(req.Uid, extralNum, 0) extralTags, err = s.Ds.GetFollowTags(req.Uid, false, extralNum, 0)
} }
default: default:
// TODO: return good error // TODO: return good error

@ -124,6 +124,17 @@ func (s *privSrv) StickTopic(req *web.StickTopicReq) (*web.StickTopicResp, mir.E
}, nil }, nil
} }
func (s *privSrv) PinTopic(req *web.PinTopicReq) (*web.PinTopicResp, mir.Error) {
status, err := s.Ds.PinTopic(req.Uid, req.TopicId)
if err != nil {
logrus.Errorf("user(%d) pin topic(%d) failed: %s", req.Uid, req.TopicId, err)
return nil, web.ErrPinTopicFailed
}
return &web.PinTopicResp{
PinStatus: status,
}, nil
}
func (s *privSrv) UploadAttachment(req *web.UploadAttachmentReq) (*web.UploadAttachmentResp, mir.Error) { func (s *privSrv) UploadAttachment(req *web.UploadAttachmentReq) (*web.UploadAttachmentResp, mir.Error) {
defer req.File.Close() defer req.File.Close()

@ -75,9 +75,12 @@ type Priv struct {
// ThumbsDownTweetReply 点踩评论回复 // ThumbsDownTweetReply 点踩评论回复
ThumbsDownTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsdown"` ThumbsDownTweetReply func(Post, web.TweetReplyThumbsReq) `mir:"/tweet/reply/thumbsdown"`
// StickTopic 置顶动态 // StickTopic 置顶话题
StickTopic func(Post, web.StickTopicReq) web.StickTopicResp `mir:"/topic/stick"` StickTopic func(Post, web.StickTopicReq) web.StickTopicResp `mir:"/topic/stick"`
// PinTopic 钉住话题
PinTopic func(Post, web.PinTopicReq) web.PinTopicResp `mir:"/topic/pin"`
// FollowTopic 关注话题 // FollowTopic 关注话题
FollowTopic func(Post, web.FollowTopicReq) `mir:"/topic/follow"` FollowTopic func(Post, web.FollowTopicReq) `mir:"/topic/follow"`

@ -0,0 +1,2 @@
ALTER TABLE `p_topic_user` DROP COLUMN `is_pin`;
DROP INDEX IF EXISTS `idx_topic_user_uid_ispin`;

@ -0,0 +1,2 @@
ALTER TABLE `p_topic_user` ADD COLUMN `is_pin` TINYINT NOT NULL DEFAULT 0 COMMENT '是否钉住 0 为未钉住、1 为已钉住';
CREATE INDEX `idx_topic_user_uid_ispin` ON `p_topic_user` (`user_id`, `is_pin`) USING BTREE;

@ -0,0 +1,2 @@
ALTER TABLE p_topic_user DROP COLUMN is_pin;
DROP INDEX IF EXISTS idx_topic_user_uid_ispin;

@ -0,0 +1,2 @@
ALTER TABLE p_topic_user ADD COLUMN is_pin SMALLINT NOT NULL DEFAULT 0; -- 是否钉住 0 为未钉住、1 为已钉住
CREATE INDEX idx_topic_user_uid_ispin ON p_topic_user USING btree ( user_id, is_pin );

@ -0,0 +1,2 @@
ALTER TABLE "p_topic_user" DROP COLUMN "is_pin";
DROP INDEX IF EXISTS "idx_topic_user_uid_ispin";

@ -0,0 +1,6 @@
ALTER TABLE "p_topic_user" ADD COLUMN "is_pin" integer NOT NULL DEFAULT 0;
CREATE INDEX "main"."idx_topic_user_uid_ispin"
ON "p_topic_user" (
"user_id" ASC,
"is_pin" ASC
);

@ -324,6 +324,7 @@ CREATE TABLE `p_topic_user` (
`remark` VARCHAR ( 512 ) COMMENT '备注', `remark` VARCHAR ( 512 ) COMMENT '备注',
`quote_num` BIGINT COMMENT '引用数', `quote_num` BIGINT COMMENT '引用数',
`is_top` TINYINT NOT NULL DEFAULT '0' COMMENT '是否置顶 0 为未置顶、1 为已置顶', `is_top` TINYINT NOT NULL DEFAULT '0' COMMENT '是否置顶 0 为未置顶、1 为已置顶',
`is_pin` TINYINT NOT NULL DEFAULT '0' COMMENT '是否钉住 0 为未钉住、1 为已钉住',
`created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间', `created_on` BIGINT NOT NULL DEFAULT '0' COMMENT '创建时间',
`modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间', `modified_on` BIGINT NOT NULL DEFAULT '0' COMMENT '修改时间',
`deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间', `deleted_on` BIGINT NOT NULL DEFAULT '0' COMMENT '删除时间',
@ -331,7 +332,8 @@ CREATE TABLE `p_topic_user` (
`reserve_a` VARCHAR ( 255 ) COMMENT '保留字段a', `reserve_a` VARCHAR ( 255 ) COMMENT '保留字段a',
`reserve_b` VARCHAR ( 255 ) COMMENT '保留字段b', `reserve_b` VARCHAR ( 255 ) COMMENT '保留字段b',
PRIMARY KEY ( `id` ) USING BTREE, PRIMARY KEY ( `id` ) USING BTREE,
UNIQUE KEY `idx_topic_user_uid_tid` ( `topic_id`, `user_id` ) USING BTREE UNIQUE KEY `idx_topic_user_uid_tid` ( `topic_id`, `user_id` ) USING BTREE,
KEY `idx_topic_user_uid_ispin` ( `user_id`, `is_pin`) USING BTREE
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户话题'; ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户话题';
-- ---------------------------- -- ----------------------------

@ -265,6 +265,7 @@ CREATE TABLE p_topic_user (
remark VARCHAR ( 512 ),-- 备注 remark VARCHAR ( 512 ),-- 备注
quote_num BIGINT,-- 引用数 quote_num BIGINT,-- 引用数
is_top SMALLINT NOT NULL DEFAULT 0,-- 是否置顶 0 为未置顶、1 为已置顶 is_top SMALLINT NOT NULL DEFAULT 0,-- 是否置顶 0 为未置顶、1 为已置顶
is_pin SMALLINT NOT NULL DEFAULT 0,-- 是否钉住 0 为未钉住、1 为已钉住
created_on BIGINT NOT NULL DEFAULT 0,-- 创建时间 created_on BIGINT NOT NULL DEFAULT 0,-- 创建时间
modified_on BIGINT NOT NULL DEFAULT 0,-- 修改时间 modified_on BIGINT NOT NULL DEFAULT 0,-- 修改时间
deleted_on BIGINT NOT NULL DEFAULT 0,-- 删除时间 deleted_on BIGINT NOT NULL DEFAULT 0,-- 删除时间
@ -273,6 +274,7 @@ CREATE TABLE p_topic_user (
reserve_b VARCHAR ( 255 ) -- 保留字段b reserve_b VARCHAR ( 255 ) -- 保留字段b
); );
CREATE UNIQUE INDEX idx_topic_user_uid_tid ON p_topic_user USING btree ( topic_id, user_id ); CREATE UNIQUE INDEX idx_topic_user_uid_tid ON p_topic_user USING btree ( topic_id, user_id );
CREATE INDEX idx_topic_user_uid_ispin ON p_topic_user USING btree ( user_id, is_pin );
CREATE SEQUENCE IF NOT EXISTS user_id_seq AS BIGINT MINVALUE 100058 NO MAXVALUE; CREATE SEQUENCE IF NOT EXISTS user_id_seq AS BIGINT MINVALUE 100058 NO MAXVALUE;
DROP TABLE IF EXISTS p_user; DROP TABLE IF EXISTS p_user;

@ -341,6 +341,7 @@ CREATE TABLE "p_topic_user" (
"remark" text ( 512 ),-- 备注 "remark" text ( 512 ),-- 备注
"quote_num" integer,-- 引用数 "quote_num" integer,-- 引用数
"is_top" integer NOT NULL DEFAULT 0,-- 是否置顶 0 为未置顶、1 为已置顶 "is_top" integer NOT NULL DEFAULT 0,-- 是否置顶 0 为未置顶、1 为已置顶
"is_pin" integer NOT NULL DEFAULT 0,-- 是否钉住 0 为未钉住、1 为已钉住
"created_on" integer NOT NULL DEFAULT 0,-- 创建时间 "created_on" integer NOT NULL DEFAULT 0,-- 创建时间
"modified_on" integer NOT NULL DEFAULT 0,-- 修改时间 "modified_on" integer NOT NULL DEFAULT 0,-- 修改时间
"deleted_on" integer NOT NULL DEFAULT 0,-- 删除时间 "deleted_on" integer NOT NULL DEFAULT 0,-- 删除时间
@ -680,6 +681,11 @@ ON "p_topic_user" (
"topic_id", "topic_id",
"user_id" "user_id"
); );
CREATE INDEX "main"."idx_topic_user_uid_ispin"
ON "p_topic_user" (
"user_id" ASC,
"is_pin" ASC
);
-- ---------------------------- -- ----------------------------
-- Indexes structure for table p_user -- Indexes structure for table p_user

@ -1 +0,0 @@
import{_ as i}from"./main-nav.vue_vue_type_style_index_0_lang-BjPLRZmS.js";import{u as s}from"./vue-router-4Hko0_3l.js";import{G as a,e as c,a2 as u}from"./naive-ui-h5SFsZhx.js";import{d as l,f as d,k as t,w as o,e as f,A as x}from"./@vue-Hd4uXz5f.js";import{_ as g}from"./index-hCGTp9pQ.js";import"./vuex-qScXS-uk.js";import"./vooks-v147mXjr.js";import"./evtd-9ZCiDXyn.js";import"./@vicons-V6UxFD2Y.js";import"./seemly-hKSMrbh9.js";import"./vueuc-xP2DxDTa.js";import"./@css-render-oW_PeE7K.js";import"./vdirs-gz97tqc5.js";import"./@juggle--NVrOerG.js";import"./css-render-Adblu2bf.js";import"./@emotion-vV6BesBt.js";import"./lodash-es-KEIJqYRD.js";import"./treemate-hmrDCADh.js";import"./async-validator-BHjhHa7C.js";import"./date-fns-E8ESfRGG.js";import"./axios-kMxbiGYq.js";import"./moment-jIwEdMgI.js";/* empty css */const h=l({__name:"404",setup(k){const n=s(),e=()=>{n.push({path:"/"})};return(w,v)=>{const r=i,p=c,_=u,m=a;return f(),d("div",null,[t(r,{title:"404"}),t(m,{class:"main-content-wrap wrap404",bordered:""},{default:o(()=>[t(_,{status:"404",title:"404 资源不存在",description:"再看看其他的吧"},{footer:o(()=>[t(p,{onClick:e},{default:o(()=>[x("回主页")]),_:1})]),_:1})]),_:1})])}}}),O=g(h,[["__scopeId","data-v-e62daa85"]]);export{O as default};

@ -1 +0,0 @@
import{_ as N}from"./post-skeleton-7Ej5SbSK.js";import{_ as R}from"./main-nav.vue_vue_type_style_index_0_lang-BjPLRZmS.js";import{u as z}from"./vuex-qScXS-uk.js";import{b as F}from"./vue-router-4Hko0_3l.js";import{J as S,_ as V}from"./index-hCGTp9pQ.js";import{G as A,R as H,J,H as P}from"./naive-ui-h5SFsZhx.js";import{d as j,H as n,b as q,f as e,k as a,w as p,e as o,bf as u,Z as l,F as D,x as E,t as _,j as s,l as G,v as I}from"./@vue-Hd4uXz5f.js";import"./vooks-v147mXjr.js";import"./evtd-9ZCiDXyn.js";import"./@vicons-V6UxFD2Y.js";import"./axios-kMxbiGYq.js";import"./moment-jIwEdMgI.js";/* empty css */import"./seemly-hKSMrbh9.js";import"./vueuc-xP2DxDTa.js";import"./@css-render-oW_PeE7K.js";import"./vdirs-gz97tqc5.js";import"./@juggle--NVrOerG.js";import"./css-render-Adblu2bf.js";import"./@emotion-vV6BesBt.js";import"./lodash-es-KEIJqYRD.js";import"./treemate-hmrDCADh.js";import"./async-validator-BHjhHa7C.js";import"./date-fns-E8ESfRGG.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"},Z=j({__name:"Anouncement",setup($){const d=z(),g=F(),v=n(!1),r=n([]),i=n(+g.query.p||1),f=n(20),m=n(0),h=c=>{i.value=c};return q(()=>{}),(c,K)=>{const k=R,y=H,w=N,x=J,B=P,C=A;return o(),e("div",null,[a(k,{title:"公告"}),a(C,{class:"main-content-wrap",bordered:""},{footer:p(()=>[m.value>1?(o(),e("div",L,[a(y,{page:i.value,"onUpdate:page":h,"page-slot":u(d).state.collapsedRight?5:8,"page-count":m.value},null,8,["page","page-slot","page-count"])])):l("",!0)]),default:p(()=>[v.value?(o(),e("div",M,[a(w,{num:f.value},null,8,["num"])])):(o(),e("div",O,[r.value.length===0?(o(),e("div",T,[a(x,{size:"large",description:"暂无数据"})])):l("",!0),(o(!0),e(D,null,E(r.value,t=>(o(),I(B,{key:t.id},{default:p(()=>[s("div",U,[s("div",null,"NO."+_(t.id),1),s("div",null,_(t.reason),1),s("div",{class:G({income:t.change_amount>=0,out:t.change_amount<0})},_((t.change_amount>0?"+":"")+(t.change_amount/100).toFixed(2)),3),s("div",null,_(u(S)(t.created_on)),1)])]),_:2},1024))),128))]))]),_:1})])}}}),kt=V(Z,[["__scopeId","data-v-d4d04859"]]);export{kt as default};

@ -1 +0,0 @@
import{_ as D}from"./whisper-eOJK7zKF.js";import{_ as R,a as U}from"./post-item.vue_vue_type_style_index_0_lang-ZiwC8_Kt.js";import{_ as q}from"./post-skeleton-7Ej5SbSK.js";import{_ as E}from"./main-nav.vue_vue_type_style_index_0_lang-BjPLRZmS.js";import{u as G}from"./vuex-qScXS-uk.js";import{b as J}from"./vue-router-4Hko0_3l.js";import{W as L}from"./v3-infinite-loading-9ocfqcSa.js";import{T as Z,u as K,f as Q,_ as X}from"./index-hCGTp9pQ.js";import{d as Y,H as t,b as ee,f as n,k as a,w as u,v as d,Z as h,e as o,bf as f,F as b,x as $,j as z,t as oe}from"./@vue-Hd4uXz5f.js";import{F as se,G as te,a as ne,J as ae,k as ie,H as le}from"./naive-ui-h5SFsZhx.js";import"./content-9A-T5SpY.js";import"./@vicons-V6UxFD2Y.js";import"./paopao-video-player-iTSRV7j7.js";import"./copy-to-clipboard-l6UqHK6O.js";import"./@babel-5-cIlDoe.js";import"./toggle-selection-fekekO1r.js";import"./vooks-v147mXjr.js";import"./evtd-9ZCiDXyn.js";import"./axios-kMxbiGYq.js";import"./moment-jIwEdMgI.js";/* empty css */import"./seemly-hKSMrbh9.js";import"./vueuc-xP2DxDTa.js";import"./@css-render-oW_PeE7K.js";import"./vdirs-gz97tqc5.js";import"./@juggle--NVrOerG.js";import"./css-render-Adblu2bf.js";import"./@emotion-vV6BesBt.js";import"./lodash-es-KEIJqYRD.js";import"./treemate-hmrDCADh.js";import"./async-validator-BHjhHa7C.js";import"./date-fns-E8ESfRGG.js";const re={key:0,class:"skeleton-wrap"},_e={key:1},ue={key:0,class:"empty-wrap"},ce={key:1},me={key:2},pe={class:"load-more-wrap"},de={class:"load-more-spinner"},fe=Y({__name:"Collection",setup(ve){const v=G(),A=J(),B=se(),c=t(!1),_=t(!1),s=t([]),l=t(+A.query.p||1),w=t(20),m=t(0),g=t(!1),k=t({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),y=e=>{k.value=e,g.value=!0},I=()=>{g.value=!1},x=e=>{B.success({title:"提示",content:"确定"+(e.user.is_following?"取消关注":"关注")+"该用户吗?",positiveText:"确定",negativeText:"取消",onPositiveClick:()=>{e.user.is_following?K({user_id:e.user.id}).then(r=>{window.$message.success("操作成功"),C(e.user_id,!1)}).catch(r=>{}):Q({user_id:e.user.id}).then(r=>{window.$message.success("关注成功"),C(e.user_id,!0)}).catch(r=>{})}})};function C(e,r){for(let p in s.value)s.value[p].user_id==e&&(s.value[p].user.is_following=r)}const F=()=>{c.value=!0,Z({page:l.value,page_size:w.value}).then(e=>{c.value=!1,e.list.length===0&&(_.value=!0),l.value>1?s.value=s.value.concat(e.list):(s.value=e.list,window.scrollTo(0,0)),m.value=Math.ceil(e.pager.total_rows/w.value)}).catch(e=>{c.value=!1,l.value>1&&l.value--})},M=()=>{l.value<m.value||m.value==0?(_.value=!1,l.value++,F()):_.value=!0};return ee(()=>{F()}),(e,r)=>{const p=E,O=q,P=ae,T=R,S=le,H=U,N=D,V=te,W=ie,j=ne;return o(),n("div",null,[a(p,{title:"收藏"}),a(V,{class:"main-content-wrap",bordered:""},{default:u(()=>[c.value&&s.value.length===0?(o(),n("div",re,[a(O,{num:w.value},null,8,["num"])])):(o(),n("div",_e,[s.value.length===0?(o(),n("div",ue,[a(P,{size:"large",description:"暂无数据"})])):h("",!0),f(v).state.desktopModelShow?(o(),n("div",ce,[(o(!0),n(b,null,$(s.value,i=>(o(),d(S,{key:i.id},{default:u(()=>[a(T,{post:i,isOwner:f(v).state.userInfo.id==i.user_id,addFollowAction:!0,onSendWhisper:y,onHandleFollowAction:x},null,8,["post","isOwner"])]),_:2},1024))),128))])):(o(),n("div",me,[(o(!0),n(b,null,$(s.value,i=>(o(),d(S,{key:i.id},{default:u(()=>[a(H,{post:i,isOwner:f(v).state.userInfo.id==i.user_id,addFollowAction:!0,onSendWhisper:y,onHandleFollowAction:x},null,8,["post","isOwner"])]),_:2},1024))),128))]))])),a(N,{show:g.value,user:k.value,onSuccess:I},null,8,["show","user"])]),_:1}),m.value>0?(o(),d(j,{key:0,justify:"center"},{default:u(()=>[a(f(L),{class:"load-more",slots:{complete:"没有更多收藏了",error:"加载出错"},onInfinite:M},{spinner:u(()=>[z("div",pe,[_.value?h("",!0):(o(),d(W,{key:0,size:14})),z("span",de,oe(_.value?"没有更多收藏了":"加载更多"),1)])]),_:1})]),_:1})):h("",!0)])}}}),Ze=X(fe,[["__scopeId","data-v-735372fb"]]);export{Ze as default};

@ -1 +0,0 @@
import{_ as W}from"./whisper-eOJK7zKF.js";import{d as P,c as A,r as R,e as s,f as p,k as t,w as o,y as E,t as d,A as G,j as a,bf as g,h as S,H as r,b as J,v as C,Z as b,F as M,x as K}from"./@vue-Hd4uXz5f.js";import{K as L,_ as x,X as U}from"./index-hCGTp9pQ.js";import{k as X,r as Z}from"./@vicons-V6UxFD2Y.js";import{j as N,o as Q,e as Y,P as ee,O as te,G as ne,a as oe,J as se,k as ae,H as ce}from"./naive-ui-h5SFsZhx.js";import{_ as ie}from"./post-skeleton-7Ej5SbSK.js";import{_ as re}from"./main-nav.vue_vue_type_style_index_0_lang-BjPLRZmS.js";import{W as le}from"./v3-infinite-loading-9ocfqcSa.js";import{b as _e}from"./vue-router-4Hko0_3l.js";import"./vuex-qScXS-uk.js";import"./axios-kMxbiGYq.js";import"./moment-jIwEdMgI.js";/* empty css */import"./seemly-hKSMrbh9.js";import"./vueuc-xP2DxDTa.js";import"./evtd-9ZCiDXyn.js";import"./@css-render-oW_PeE7K.js";import"./vooks-v147mXjr.js";import"./vdirs-gz97tqc5.js";import"./@juggle--NVrOerG.js";import"./css-render-Adblu2bf.js";import"./@emotion-vV6BesBt.js";import"./lodash-es-KEIJqYRD.js";import"./treemate-hmrDCADh.js";import"./async-validator-BHjhHa7C.js";import"./date-fns-E8ESfRGG.js";const ue={class:"contact-item"},pe={class:"nickname-wrap"},me={class:"username-wrap"},de={class:"user-info"},fe={class:"info-item"},ve={class:"info-item"},he={class:"item-header-extra"},ge=P({__name:"contact-item",props:{contact:{}},emits:["send-whisper"],setup(z,{emit:w}){const _=w,l=e=>()=>S(N,null,{default:()=>S(e)}),n=z,c=A(()=>[{label:"私信 @"+n.contact.username,key:"whisper",icon:l(Z)}]),m=e=>{switch(e){case"whisper":const i={id:n.contact.user_id,avatar:n.contact.avatar,username:n.contact.username,nickname:n.contact.nickname,is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1};_("send-whisper",i);break}};return(e,i)=>{const f=Q,k=R("router-link"),y=Y,$=ee,v=te;return s(),p("div",ue,[t(v,{"content-indented":""},{avatar:o(()=>[t(f,{size:54,src:e.contact.avatar},null,8,["src"])]),header:o(()=>[a("span",pe,[t(k,{onClick:i[0]||(i[0]=E(()=>{},["stop"])),class:"username-link",to:{name:"user",query:{s:e.contact.username}}},{default:o(()=>[G(d(e.contact.nickname),1)]),_:1},8,["to"])]),a("span",me," @"+d(e.contact.username),1),a("div",de,[a("span",fe," UID. "+d(e.contact.user_id),1),a("span",ve,d(g(L)(e.contact.created_on))+" 加入 ",1)])]),"header-extra":o(()=>[a("div",he,[t($,{placement:"bottom-end",trigger:"click",size:"small",options:c.value,onSelect:m},{default:o(()=>[t(y,{quaternary:"",circle:""},{icon:o(()=>[t(g(N),null,{default:o(()=>[t(g(X))]),_:1})]),_:1})]),_:1},8,["options"])])]),_:1})])}}}),we=x(ge,[["__scopeId","data-v-42e975ce"]]),ke={key:0,class:"skeleton-wrap"},ye={key:1},$e={key:0,class:"empty-wrap"},Ce={class:"load-more-wrap"},be={class:"load-more-spinner"},ze=P({__name:"Contacts",setup(z){const w=_e(),_=r(!1),l=r(!1),n=r([]),c=r(+w.query.p||1),m=r(20),e=r(0),i=r(!1),f=r({id:0,avatar:"",username:"",nickname:"",is_admin:!1,is_friend:!0,is_following:!1,created_on:0,follows:0,followings:0,status:1}),k=h=>{f.value=h,i.value=!0},y=()=>{i.value=!1},$=()=>{c.value<e.value||e.value==0?(l.value=!1,c.value++,v()):l.value=!0};J(()=>{v()});const v=(h=!1)=>{n.value.length===0&&(_.value=!0),U({page:c.value,page_size:m.value}).then(u=>{_.value=!1,u.list.length===0&&(l.value=!0),c.value>1?n.value=n.value.concat(u.list):(n.value=u.list,h&&setTimeout(()=>{window.scrollTo(0,99999)},50)),e.value=Math.ceil(u.pager.total_rows/m.value)}).catch(u=>{_.value=!1,c.value>1&&c.value--})};return(h,u)=>{const B=re,V=ie,j=se,q=we,D=ce,F=W,H=ne,O=ae,T=oe;return s(),p(M,null,[a("div",null,[t(B,{title:"好友"}),t(H,{class:"main-content-wrap",bordered:""},{default:o(()=>[_.value&&n.value.length===0?(s(),p("div",ke,[t(V,{num:m.value},null,8,["num"])])):(s(),p("div",ye,[n.value.length===0?(s(),p("div",$e,[t(j,{size:"large",description:"暂无数据"})])):b("",!0),(s(!0),p(M,null,K(n.value,I=>(s(),C(D,{class:"list-item",key:I.user_id},{default:o(()=>[t(q,{contact:I,onSendWhisper:k},null,8,["contact"])]),_:2},1024))),128))])),t(F,{show:i.value,user:f.value,onSuccess:y},null,8,["show","user"])]),_:1})]),e.value>0?(s(),C(T,{key:0,justify:"center"},{default:o(()=>[t(g(le),{class:"load-more",slots:{complete:"没有更多好友了",error:"加载出错"},onInfinite:$},{spinner:o(()=>[a("div",Ce,[l.value?b("",!0):(s(),C(O,{key:0,size:14})),a("span",be,d(l.value?"没有更多好友了":"加载更多"),1)])]),_:1})]),_:1})):b("",!0)],64)}}}),Qe=x(ze,[["__scopeId","data-v-69277f0c"]]);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

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 @@
.tag-item .tag-quote{margin-left:12px;font-size:14px;opacity:.75}.tag-item .tag-follow{margin-right:22px}.tag-item .options{margin-left:-32px;margin-bottom:4px;opacity:.55}.tag-item .n-thing .n-thing-header{margin-bottom:0}.tag-item .n-thing .n-thing-avatar-header-wrapper{align-items:center}.tags-wrap[data-v-1fb31ecf]{padding:20px}.dark .tags-wrap[data-v-1fb31ecf]{background-color:#101014bf}

@ -1 +0,0 @@
import{E as I,F as A,G as M,H as O,I as z,_ as D}from"./index-hCGTp9pQ.js";import{D as G}from"./@vicons-V6UxFD2Y.js";import{d as q,H as u,c as T,b as B,r as H,e as c,f as r,k as n,w as s,t as h,A as C,Z as m,v as $,bf as w,E as j,am as P,F as Z,x}from"./@vue-Hd4uXz5f.js";import{o as J,M as V,j as K,e as Q,P as R,O as W,G as X,f as Y,g as ee,a as oe,k as te}from"./naive-ui-h5SFsZhx.js";import{_ as ne}from"./main-nav.vue_vue_type_style_index_0_lang-BjPLRZmS.js";import{u as se}from"./vuex-qScXS-uk.js";import"./vue-router-4Hko0_3l.js";import"./axios-kMxbiGYq.js";import"./moment-jIwEdMgI.js";/* empty css */import"./seemly-hKSMrbh9.js";import"./vueuc-xP2DxDTa.js";import"./evtd-9ZCiDXyn.js";import"./@css-render-oW_PeE7K.js";import"./vooks-v147mXjr.js";import"./vdirs-gz97tqc5.js";import"./@juggle--NVrOerG.js";import"./css-render-Adblu2bf.js";import"./@emotion-vV6BesBt.js";import"./lodash-es-KEIJqYRD.js";import"./treemate-hmrDCADh.js";import"./async-validator-BHjhHa7C.js";import"./date-fns-E8ESfRGG.js";const ae={key:0,class:"tag-item"},ce={key:0,class:"tag-quote"},le={key:1,class:"tag-quote tag-follow"},ie={key:0,class:"options"},_e=q({__name:"tag-item",props:{tag:{},showAction:{type:Boolean},checkFollowing:{type:Boolean}},setup(F){const i=u(!1),t=F,g=T(()=>t.tag.user?t.tag.user.avatar:I),_=T(()=>{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":A({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":A({topic_id:t.tag.id}).then(o=>{t.tag.is_top=o.top_status,window.$message.success("取消置顶")}).catch(o=>{console.log(o)});break}};return B(()=>{i.value=!1}),(e,o)=>{const d=H("router-link"),k=J,a=V,f=K,v=Q,p=R,b=W;return!e.checkFollowing||e.checkFollowing&&e.tag.is_following===1?(c(),r("div",ae,[n(b,null,{header:s(()=>[(c(),$(a,{type:"success",size:"large",round:"",key:e.tag.id},{avatar:s(()=>[n(k,{src:g.value},null,8,["src"])]),default:s(()=>[n(d,{class:"hash-link",to:{name:"home",query:{q:e.tag.tag,t:"tag"}}},{default:s(()=>[C(" #"+h(e.tag.tag),1)]),_:1},8,["to"]),e.showAction?m("",!0):(c(),r("span",ce,"("+h(e.tag.quote_num)+")",1)),e.showAction?(c(),r("span",le,"("+h(e.tag.quote_num)+")",1)):m("",!0)]),_:1}))]),"header-extra":s(()=>[e.showAction?(c(),r("div",ie,[n(p,{placement:"bottom-end",trigger:"click",size:"small",options:_.value,onSelect:l},{default:s(()=>[n(v,{type:"success",quaternary:"",circle:"",block:""},{icon:s(()=>[n(f,null,{default:s(()=>[n(w(G))]),_:1})]),_:1})]),_:1},8,["options"])])):m("",!0)]),_:1})])):m("",!0)}}}),ue=q({__name:"Topic",setup(F){const i=se(),t=u([]),g=u("hot"),_=u(!1),l=u(!1),e=u(!1);j(l,()=>{l.value||(window.$message.success("保存成功"),i.commit("refreshTopicFollow"))});const o=T({get:()=>{let a="编辑";return l.value&&(a="保存"),a},set:a=>{}}),d=()=>{_.value=!0,z({type:g.value,num:50}).then(a=>{t.value=a.topics,_.value=!1}).catch(a=>{console.log(a),_.value=!1})},k=a=>{g.value=a,a=="follow"?e.value=!0:e.value=!1,d()};return B(()=>{d()}),(a,f)=>{const v=ne,p=Y,b=V,E=ee,L=_e,N=oe,S=te,U=X;return c(),r("div",null,[n(v,{title:"话题"}),n(U,{class:"main-content-wrap tags-wrap",bordered:""},{default:s(()=>[n(E,{type:"line",animated:"","onUpdate:value":k},P({default:s(()=>[n(p,{name:"hot",tab:"热门"}),n(p,{name:"new",tab:"最新"}),w(i).state.userLogined?(c(),$(p,{key:0,name:"follow",tab:"关注"})):m("",!0)]),_:2},[w(i).state.userLogined?{name:"suffix",fn:s(()=>[n(b,{checked:l.value,"onUpdate:checked":f[0]||(f[0]=y=>l.value=y),checkable:""},{default:s(()=>[C(h(o.value),1)]),_:1},8,["checked"])]),key:"0"}:void 0]),1024),n(S,{show:_.value},{default:s(()=>[n(N,null,{default:s(()=>[(c(!0),r(Z,null,x(t.value,y=>(c(),$(L,{tag:y,showAction:w(i).state.userLogined&&l.value,checkFollowing:e.value},null,8,["tag","showAction","checkFollowing"]))),256))]),_:1})]),_:1},8,["show"])]),_:1})])}}}),Se=D(ue,[["__scopeId","data-v-1fb31ecf"]]);export{Se as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

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

@ -1 +0,0 @@
import{N as b,_ as B}from"./index-hCGTp9pQ.js";import{S as N,I as C,T as V,b as W,e as z,i as A}from"./naive-ui-h5SFsZhx.js";import{d as F,H as i,e as I,v as R,w as s,j as a,k as n,A as l,t as r}from"./@vue-Hd4uXz5f.js";const S={class:"whisper-wrap"},T={class:"whisper-line"},U={class:"whisper-line send-wrap"},j=F({__name:"whisper-add-friend",props:{show:{type:Boolean,default:!1},user:{}},emits:["success"],setup(p,{emit:u}){const d=p,o=i(""),t=i(!1),m=u,_=()=>{m("success")},h=()=>{t.value=!0,b({user_id:d.user.id,greetings:o.value}).then(e=>{window.$message.success("发送成功"),t.value=!1,o.value="",_()}).catch(e=>{t.value=!1})};return(e,c)=>{const w=N,f=C,g=V,v=W,y=z,x=A;return I(),R(x,{show:e.show,"onUpdate:show":_,class:"whisper-card",preset:"card",size:"small",title:"申请添加朋友","mask-closable":!1,bordered:!1,style:{width:"360px"}},{default:s(()=>[a("div",S,[n(g,{"show-icon":!1},{default:s(()=>[l(" 发送添加朋友申请给: "),n(f,{style:{"max-width":"100%"}},{default:s(()=>[n(w,{type:"success"},{default:s(()=>[l(r(e.user.nickname)+"@"+r(e.user.username),1)]),_:1})]),_:1})]),_:1}),a("div",T,[n(v,{type:"textarea",placeholder:"请输入真挚的问候语",autosize:{minRows:5,maxRows:10},value:o.value,"onUpdate:value":c[0]||(c[0]=k=>o.value=k),maxlength:"120","show-count":""},null,8,["value"])]),a("div",U,[n(y,{strong:"",secondary:"",type:"primary",loading:t.value,onClick:h},{default:s(()=>[l(" 发送 ")]),_:1},8,["loading"])])])]),_:1},8,["show"])}}}),M=B(j,[["__scopeId","data-v-60be56a2"]]);export{M as W};

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

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0" />
<link rel="manifest" href="/manifest.json" /> <link rel="manifest" href="/manifest.json" />
<title></title> <title></title>
<script type="module" crossorigin src="/assets/index-hCGTp9pQ.js"></script> <script type="module" crossorigin src="/assets/index-8lD1klqH.js"></script>
<link rel="modulepreload" crossorigin href="/assets/@vue-Hd4uXz5f.js"> <link rel="modulepreload" crossorigin href="/assets/@vue-Hd4uXz5f.js">
<link rel="modulepreload" crossorigin href="/assets/vue-router-4Hko0_3l.js"> <link rel="modulepreload" crossorigin href="/assets/vue-router-4Hko0_3l.js">
<link rel="modulepreload" crossorigin href="/assets/vuex-qScXS-uk.js"> <link rel="modulepreload" crossorigin href="/assets/vuex-qScXS-uk.js">

@ -286,6 +286,17 @@ export const stickTopic = (
}); });
}; };
/** 置顶/取消置顶话题 */
export const pinTopic = (
data: NetParams.PostPinTopic
): Promise<NetReq.PostPinTopic> => {
return request({
method: "post",
url: "/v1/topic/pin",
data,
});
};
/** 关注话题 */ /** 关注话题 */
export const followTopic = ( export const followTopic = (
data: NetParams.PostFollowTopic data: NetParams.PostFollowTopic

@ -1,5 +1,5 @@
<template> <template>
<div v-if="!checkFollowing || (checkFollowing && tag.is_following === 1)" class="tag-item"> <div v-if="(!checkFollowing && !checkPin) || (checkFollowing && tag.is_following === 1) || (checkPin && tag.is_following === 1 && tag.is_pin === 1)" class="tag-item">
<n-thing> <n-thing>
<template #header> <template #header>
<n-tag <n-tag
@ -56,7 +56,7 @@
import { ref, onMounted, computed } from 'vue'; import { ref, onMounted, computed } from 'vue';
import { MoreVertOutlined } from '@vicons/material'; import { MoreVertOutlined } from '@vicons/material';
import type { DropdownOption } from 'naive-ui'; import type { DropdownOption } from 'naive-ui';
import { stickTopic, followTopic, unfollowTopic } from '@/api/post'; import { pinTopic, stickTopic, followTopic, unfollowTopic } from '@/api/post';
import defaultUserAvatar from '@/assets/img/logo.png'; import defaultUserAvatar from '@/assets/img/logo.png';
const hasFollowing= ref(false); const hasFollowing= ref(false);
@ -65,6 +65,7 @@ const props = withDefaults(
tag: Item.TagProps; tag: Item.TagProps;
showAction: boolean; showAction: boolean;
checkFollowing: boolean; checkFollowing: boolean;
checkPin: boolean;
}>(), }>(),
{} {}
); );
@ -75,7 +76,7 @@ const tagUserAvatar = computed(() => {
} else { } else {
return defaultUserAvatar return defaultUserAvatar
} }
}) });
const tagOptions = computed(() => { const tagOptions = computed(() => {
@ -86,6 +87,17 @@ const tagOptions = computed(() => {
key: 'follow', key: 'follow',
}); });
} else { } else {
if (props.tag.is_pin === 0) {
options.push({
label: '',
key: 'pin',
});
} else {
options.push({
label: '',
key: 'unpin',
});
}
if (props.tag.is_top === 0) { if (props.tag.is_top === 0) {
options.push({ options.push({
label: '', label: '',
@ -106,14 +118,14 @@ const tagOptions = computed(() => {
}); });
const handleTagAction = ( const handleTagAction = (
item: 'follow' | 'unfollow' | 'stick' | 'unstick' item: 'follow' | 'unfollow' | 'pin' | 'unpin' | 'stick' | 'unstick'
) => { ) => {
switch (item) { switch (item) {
case 'follow': case 'follow':
followTopic({ followTopic({
topic_id: props.tag.id topic_id: props.tag.id
}) })
.then((res) => { .then((_res) => {
props.tag.is_following = 1 props.tag.is_following = 1
window.$message.success(`关注成功`); window.$message.success(`关注成功`);
}) })
@ -125,7 +137,7 @@ const handleTagAction = (
unfollowTopic({ unfollowTopic({
topic_id: props.tag.id topic_id: props.tag.id
}) })
.then((res) => { .then((_res) => {
props.tag.is_following = 0 props.tag.is_following = 0
window.$message.success(`取消关注`); window.$message.success(`取消关注`);
}) })
@ -133,6 +145,30 @@ const handleTagAction = (
console.log(err); console.log(err);
}); });
break; break;
case 'pin':
pinTopic({
topic_id: props.tag.id
})
.then((_res) => {
props.tag.is_pin = 1;
window.$message.success(`钉住成功`);
})
.catch((err) => {
console.log(err);
});
break;
case 'unpin':
pinTopic({
topic_id: props.tag.id
})
.then((_res) => {
props.tag.is_pin = 0;
window.$message.success(`取消钉住`);
})
.catch((err) => {
console.log(err);
});
break;
case 'stick': case 'stick':
stickTopic({ stickTopic({
topic_id: props.tag.id topic_id: props.tag.id

@ -345,6 +345,8 @@ declare module Item {
is_following?: 0 | 1; is_following?: 0 | 1;
/** 是否置顶0为未置顶1为已置顶 */ /** 是否置顶0为未置顶1为已置顶 */
is_top?: 0 | 1; is_top?: 0 | 1;
/** 是否钉住0为未钉住1为已钉住 */
is_pin?: 0 | 1;
/** 是否删除0为未删除1为已删除 */ /** 是否删除0为未删除1为已删除 */
is_del?: 0 | 1; is_del?: 0 | 1;
} }

@ -202,7 +202,7 @@ declare module NetParams {
} }
interface PostGetTags { interface PostGetTags {
type: "hot" | "new" | "follow" | "hot_extral"; type: "hot" | "new" | "follow" | "pin" | "hot_extral";
num: number; num: number;
extral_num?: number; extral_num?: number;
} }
@ -278,6 +278,10 @@ declare module NetParams {
topic_id: number; topic_id: number;
} }
interface PostPinTopic {
topic_id: number;
}
interface PostFollowTopic { interface PostFollowTopic {
topic_id: number; topic_id: number;
} }

@ -203,6 +203,11 @@ declare module NetReq {
top_status: 0 | 1; top_status: 0 | 1;
} }
interface PostPinTopic {
/** 钉住状态0为未钉住1为钉住*/
pin_status: 0 | 1;
}
interface PostFollowTopic {} interface PostFollowTopic {}
interface PostUnfollowTopic {} interface PostUnfollowTopic {}

@ -6,8 +6,8 @@
<n-tabs type="line" animated @update:value="changeTab"> <n-tabs type="line" animated @update:value="changeTab">
<n-tab-pane name="hot" tab="热门" /> <n-tab-pane name="hot" tab="热门" />
<n-tab-pane name="new" tab="最新" /> <n-tab-pane name="new" tab="最新" />
<n-tab-pane v-if="store.state.userLogined" <n-tab-pane name="follow" tab="关注" v-if="store.state.userLogined" />
name="follow" tab="关注" /> <n-tab-pane name="pin" tab="钉住" v-if="store.state.userLogined" />
<template v-if="store.state.userLogined" #suffix> <template v-if="store.state.userLogined" #suffix>
<n-tag v-model:checked="tagsChecked" checkable> <n-tag v-model:checked="tagsChecked" checkable>
{{tagsEditText}} {{tagsEditText}}
@ -21,9 +21,13 @@
:tag="tag" :tag="tag"
:showAction="store.state.userLogined && tagsChecked" :showAction="store.state.userLogined && tagsChecked"
:checkFollowing="inFollowTab" :checkFollowing="inFollowTab"
:checkPin="inPinTab"
> >
</tag-item> </tag-item>
</n-space> </n-space>
<div class="empty-wrap" v-if="tags.length === 0">
<n-empty size="large" description="暂无数据" />
</div>
</n-spin> </n-spin>
</n-list> </n-list>
</div> </div>
@ -36,10 +40,11 @@ import { useStore } from 'vuex';
const store = useStore(); const store = useStore();
const tags = ref<Item.TagProps[]>([]); const tags = ref<Item.TagProps[]>([]);
const tagType = ref<"hot" | "new" | "follow">('hot'); const tagType = ref<"hot" | "new" | "follow" | "pin">('hot');
const loading = ref(false); const loading = ref(false);
const tagsChecked = ref(false) const tagsChecked = ref(false)
const inFollowTab = ref(false) const inFollowTab = ref(false)
const inPinTab = ref(false)
watch(tagsChecked, () => { watch(tagsChecked, () => {
if (!tagsChecked.value) { if (!tagsChecked.value) {
@ -70,17 +75,15 @@ const loadTags = () => {
loading.value = false; loading.value = false;
}) })
.catch((err) => { .catch((err) => {
tags.value = [];
console.log(err); console.log(err);
loading.value = false; loading.value = false;
}); });
}; };
const changeTab = (tab: "hot" | "new" | "follow") => { const changeTab = (tab: "hot" | "new" | "follow" | "pin") => {
tagType.value = tab; tagType.value = tab;
if (tab == "follow") { inFollowTab.value = (tab === "follow")
inFollowTab.value = true inPinTab.value = (tab === "pin")
} else {
inFollowTab.value = false
}
loadTags(); loadTags();
}; };
onMounted(() => { onMounted(() => {
@ -93,7 +96,7 @@ onMounted(() => {
padding: 20px; padding: 20px;
} }
.dark { .dark {
.tags-wrap { .tags-wrap, .empty-wrap {
background-color: rgba(16, 16, 20, 0.75); background-color: rgba(16, 16, 20, 0.75);
} }
} }

Loading…
Cancel
Save