feat: 更新评论输入框的占位符,支持自定义占位符文本
All checks were successful
Push to Helm Chart Repository / build (push) Successful in 27s

This commit is contained in:
2025-09-12 16:27:12 +08:00
parent 0a7cbc00fc
commit 3fdd801d28
3 changed files with 132 additions and 129 deletions

View File

@ -1,179 +1,179 @@
package service package service
import ( import (
"context" "context"
"strconv" "strconv"
"github.com/snowykami/neo-blog/pkg/constant" "github.com/snowykami/neo-blog/pkg/constant"
"github.com/snowykami/neo-blog/internal/ctxutils" "github.com/snowykami/neo-blog/internal/ctxutils"
"github.com/snowykami/neo-blog/internal/dto" "github.com/snowykami/neo-blog/internal/dto"
"github.com/snowykami/neo-blog/internal/model" "github.com/snowykami/neo-blog/internal/model"
"github.com/snowykami/neo-blog/internal/repo" "github.com/snowykami/neo-blog/internal/repo"
"github.com/snowykami/neo-blog/pkg/errs" "github.com/snowykami/neo-blog/pkg/errs"
) )
type CommentService struct{} type CommentService struct{}
func NewCommentService() *CommentService { func NewCommentService() *CommentService {
return &CommentService{} return &CommentService{}
} }
func (cs *CommentService) CreateComment(ctx context.Context, req *dto.CreateCommentReq) (uint, error) { func (cs *CommentService) CreateComment(ctx context.Context, req *dto.CreateCommentReq) (uint, error) {
currentUser, ok := ctxutils.GetCurrentUser(ctx) currentUser, ok := ctxutils.GetCurrentUser(ctx)
if !ok { if !ok {
return 0, errs.ErrUnauthorized return 0, errs.ErrUnauthorized
} }
if ok, err := cs.checkTargetExists(req.TargetID, req.TargetType); !ok { if ok, err := cs.checkTargetExists(req.TargetID, req.TargetType); !ok {
if err != nil { if err != nil {
return 0, errs.New(errs.ErrBadRequest.Code, "target not found", err) return 0, errs.New(errs.ErrBadRequest.Code, "target not found", err)
} }
return 0, errs.ErrBadRequest return 0, errs.ErrBadRequest
} }
comment := &model.Comment{ comment := &model.Comment{
Content: req.Content, Content: req.Content,
ReplyID: req.ReplyID, ReplyID: req.ReplyID,
TargetID: req.TargetID, TargetID: req.TargetID,
TargetType: req.TargetType, TargetType: req.TargetType,
UserID: currentUser.ID, UserID: currentUser.ID,
IsPrivate: req.IsPrivate, IsPrivate: req.IsPrivate,
RemoteAddr: req.RemoteAddr, RemoteAddr: req.RemoteAddr,
UserAgent: req.UserAgent, UserAgent: req.UserAgent,
} }
commentID, err := repo.Comment.CreateComment(comment) commentID, err := repo.Comment.CreateComment(comment)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return commentID, nil return commentID, nil
} }
func (cs *CommentService) UpdateComment(ctx context.Context, req *dto.UpdateCommentReq) error { func (cs *CommentService) UpdateComment(ctx context.Context, req *dto.UpdateCommentReq) error {
currentUser, ok := ctxutils.GetCurrentUser(ctx) currentUser, ok := ctxutils.GetCurrentUser(ctx)
if !ok { if !ok {
return errs.ErrUnauthorized return errs.ErrUnauthorized
} }
comment, err := repo.Comment.GetComment(strconv.Itoa(int(req.CommentID))) comment, err := repo.Comment.GetComment(strconv.Itoa(int(req.CommentID)))
if err != nil { if err != nil {
return err return err
} }
if currentUser.ID != comment.UserID { if currentUser.ID != comment.UserID {
return errs.ErrForbidden return errs.ErrForbidden
} }
comment.Content = req.Content comment.Content = req.Content
comment.IsPrivate = req.IsPrivate comment.IsPrivate = req.IsPrivate
err = repo.Comment.UpdateComment(comment) err = repo.Comment.UpdateComment(comment)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func (cs *CommentService) DeleteComment(ctx context.Context, commentID string) error { func (cs *CommentService) DeleteComment(ctx context.Context, commentID string) error {
currentUser, ok := ctxutils.GetCurrentUser(ctx) currentUser, ok := ctxutils.GetCurrentUser(ctx)
if !ok { if !ok {
return errs.ErrUnauthorized return errs.ErrUnauthorized
} }
if commentID == "" { if commentID == "" {
return errs.ErrBadRequest return errs.ErrBadRequest
} }
comment, err := repo.Comment.GetComment(commentID) comment, err := repo.Comment.GetComment(commentID)
if err != nil { if err != nil {
return errs.New(errs.ErrNotFound.Code, "comment not found", err) return errs.New(errs.ErrNotFound.Code, "comment not found", err)
} }
if comment.UserID != currentUser.ID { if comment.UserID != currentUser.ID {
return errs.ErrForbidden return errs.ErrForbidden
} }
if err := repo.Comment.DeleteComment(commentID); err != nil { if err := repo.Comment.DeleteComment(commentID); err != nil {
return err return err
} }
return nil return nil
} }
func (cs *CommentService) GetComment(ctx context.Context, commentID string) (*dto.CommentDto, error) { func (cs *CommentService) GetComment(ctx context.Context, commentID string) (*dto.CommentDto, error) {
comment, err := repo.Comment.GetComment(commentID) comment, err := repo.Comment.GetComment(commentID)
if err != nil { if err != nil {
return nil, errs.New(errs.ErrNotFound.Code, "comment not found", err) return nil, errs.New(errs.ErrNotFound.Code, "comment not found", err)
} }
commentDto := dto.CommentDto{ commentDto := dto.CommentDto{
ID: comment.ID, ID: comment.ID,
TargetID: comment.TargetID, TargetID: comment.TargetID,
TargetType: comment.TargetType, TargetType: comment.TargetType,
Content: comment.Content, Content: comment.Content,
ReplyID: comment.ReplyID, ReplyID: comment.ReplyID,
Depth: comment.Depth, Depth: comment.Depth,
CreatedAt: comment.CreatedAt.String(), CreatedAt: comment.CreatedAt.String(),
UpdatedAt: comment.UpdatedAt.String(), UpdatedAt: comment.UpdatedAt.String(),
User: comment.User.ToDto(), User: comment.User.ToDto(),
} }
return &commentDto, err return &commentDto, err
} }
func (cs *CommentService) GetCommentList(ctx context.Context, req *dto.GetCommentListReq) ([]dto.CommentDto, error) { func (cs *CommentService) GetCommentList(ctx context.Context, req *dto.GetCommentListReq) ([]dto.CommentDto, error) {
currentUserID := uint(0) currentUserID := uint(0)
if currentUser, ok := ctxutils.GetCurrentUser(ctx); ok { if currentUser, ok := ctxutils.GetCurrentUser(ctx); ok {
currentUserID = currentUser.ID currentUserID = currentUser.ID
} }
comments, err := repo.Comment.ListComments(currentUserID, req.TargetID, req.CommentID, req.TargetType, req.Page, req.Size, req.OrderBy, req.Desc, req.Depth) comments, err := repo.Comment.ListComments(currentUserID, req.TargetID, req.CommentID, req.TargetType, req.Page, req.Size, req.OrderBy, req.Desc, req.Depth)
if err != nil { if err != nil {
return nil, errs.New(errs.ErrInternalServer.Code, "failed to list comments", err) return nil, errs.New(errs.ErrInternalServer.Code, "failed to list comments", err)
} }
commentDtos := make([]dto.CommentDto, 0) commentDtos := make([]dto.CommentDto, 0)
for _, comment := range comments { for _, comment := range comments {
//replyCount, _ := repo.Comment.CountReplyComments(currentUserID, comment.ID) //replyCount, _ := repo.Comment.CountReplyComments(currentUserID, comment.ID)
isLiked := false isLiked := false
if currentUserID != 0 { if currentUserID != 0 {
isLiked, _ = repo.Like.IsLiked(currentUserID, comment.ID, constant.TargetTypeComment) isLiked, _ = repo.Like.IsLiked(currentUserID, comment.ID, constant.TargetTypeComment)
} }
commentDto := dto.CommentDto{ commentDto := dto.CommentDto{
ID: comment.ID, ID: comment.ID,
Content: comment.Content, Content: comment.Content,
TargetID: comment.TargetID, TargetID: comment.TargetID,
TargetType: comment.TargetType, TargetType: comment.TargetType,
ReplyID: comment.ReplyID, ReplyID: comment.ReplyID,
CreatedAt: comment.CreatedAt.String(), CreatedAt: comment.CreatedAt.String(),
UpdatedAt: comment.UpdatedAt.String(), UpdatedAt: comment.UpdatedAt.String(),
Depth: comment.Depth, Depth: comment.Depth,
User: comment.User.ToDto(), User: comment.User.ToDto(),
ReplyCount: comment.CommentCount, ReplyCount: comment.CommentCount,
LikeCount: comment.LikeCount, LikeCount: comment.LikeCount,
IsLiked: isLiked, IsLiked: isLiked,
IsPrivate: comment.IsPrivate, IsPrivate: comment.IsPrivate,
} }
commentDtos = append(commentDtos, commentDto) commentDtos = append(commentDtos, commentDto)
} }
return commentDtos, nil return commentDtos, nil
} }
func (cs *CommentService) checkTargetExists(targetID uint, targetType string) (bool, error) { func (cs *CommentService) checkTargetExists(targetID uint, targetType string) (bool, error) {
switch targetType { switch targetType {
case constant.TargetTypePost: case constant.TargetTypePost:
if _, err := repo.Post.GetPostByID(strconv.Itoa(int(targetID))); err != nil { if _, err := repo.Post.GetPostByID(strconv.Itoa(int(targetID))); err != nil {
return false, errs.New(errs.ErrNotFound.Code, "post not found", err) return false, errs.New(errs.ErrNotFound.Code, "post not found", err)
} }
default: default:
return false, errs.New(errs.ErrBadRequest.Code, "invalid target type", nil) return false, errs.New(errs.ErrBadRequest.Code, "invalid target type", nil)
} }
return true, nil return true, nil
} }

View File

@ -16,12 +16,14 @@ export function CommentInput(
onCommentSubmitted, onCommentSubmitted,
initContent = "", initContent = "",
initIsPrivate = false, initIsPrivate = false,
placeholder = "",
isUpdate = false isUpdate = false
}: { }: {
user: User | null, user: User | null,
onCommentSubmitted: ({ commentContent, isPrivate }: { commentContent: string, isPrivate: boolean }) => void, onCommentSubmitted: ({ commentContent, isPrivate }: { commentContent: string, isPrivate: boolean }) => void,
initContent?: string, initContent?: string,
initIsPrivate?: boolean, initIsPrivate?: boolean,
placeholder?: string,
isUpdate?: boolean, isUpdate?: boolean,
} }
) { ) {
@ -65,7 +67,7 @@ export function CommentInput(
</div> </div>
<div className="flex-1 pl-2 fade-in-up"> <div className="flex-1 pl-2 fade-in-up">
<Textarea <Textarea
placeholder={user ? (isPrivate ? t("private_placeholder") : t("placeholder")) : t("login_required", { loginButton: "登录" })} placeholder={placeholder || (user ? (isPrivate ? t("private_placeholder") : t("placeholder")) : t("login_required", { loginButton: "登录" }))}
className="w-full p-2 border border-gray-300 rounded-md fade-in-up" className="w-full p-2 border border-gray-300 rounded-md fade-in-up"
value={commentContent} value={commentContent}
onChange={(e) => setCommentContent(e.target.value)} onChange={(e) => setCommentContent(e.target.value)}

View File

@ -268,6 +268,7 @@ export function CommentItem(
user={user} user={user}
onCommentSubmitted={onReply} onCommentSubmitted={onReply}
initIsPrivate={isPrivate} initIsPrivate={isPrivate}
placeholder={`${t("reply")} ${comment.user.nickname} :`}
/>} />}
{activeInput && activeInput.type === 'edit' && activeInput.id === comment.id && <CommentInput {activeInput && activeInput.type === 'edit' && activeInput.id === comment.id && <CommentInput
user={user} user={user}