c8f03dd932
功能特性: - Markdown 编辑与实时预览 - 代码语法高亮 - 目录树形结构管理 - 图片粘贴上传 - Markdown 文件导入导出 - 笔记密码保护 - 前后端分离架构 技术栈: - Go + Gin + GORM + SQLite - 原生 HTML/CSS/JavaScript - Highlight.js
230 líneas
5.3 KiB
Go
230 líneas
5.3 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"note-manager/model"
|
|
"note-manager/repository"
|
|
)
|
|
|
|
// NoteService 笔记业务逻辑层
|
|
type NoteService struct {
|
|
repo *repository.NoteRepository
|
|
pageSize int
|
|
}
|
|
|
|
// NewNoteService 创建服务实例
|
|
func NewNoteService(repo *repository.NoteRepository, pageSize int) *NoteService {
|
|
return &NoteService{repo: repo, pageSize: pageSize}
|
|
}
|
|
|
|
// CreateNote 创建笔记或目录
|
|
func (s *NoteService) CreateNote(req model.NoteCreateRequest) (*model.Note, error) {
|
|
note := &model.Note{
|
|
Title: req.Title,
|
|
Content: req.Content,
|
|
Category: req.Category,
|
|
Tags: req.Tags,
|
|
IsFolder: req.IsFolder,
|
|
SortOrder: req.SortOrder,
|
|
IsPublic: true, // 默认公开
|
|
}
|
|
if req.Password != "" {
|
|
note.Password = model.HashPassword(req.Password)
|
|
}
|
|
if req.IsPinned != nil {
|
|
note.IsPinned = *req.IsPinned
|
|
}
|
|
if req.IsFavorite != nil {
|
|
note.IsFavorite = *req.IsFavorite
|
|
}
|
|
if req.IsPublic != nil {
|
|
note.IsPublic = *req.IsPublic
|
|
}
|
|
if req.ParentID != nil {
|
|
note.ParentID = *req.ParentID
|
|
}
|
|
|
|
if err := s.repo.Create(note); err != nil {
|
|
return nil, fmt.Errorf("创建笔记失败: %w", err)
|
|
}
|
|
return note, nil
|
|
}
|
|
|
|
// GetNote 获取单条笔记
|
|
func (s *NoteService) GetNote(id uint) (*model.Note, error) {
|
|
note, err := s.repo.GetByID(id)
|
|
if err != nil {
|
|
return nil, errors.New("笔记不存在")
|
|
}
|
|
return note, nil
|
|
}
|
|
|
|
// GetNoteContent 获取笔记内容(需要密码验证)
|
|
func (s *NoteService) GetNoteContent(id uint, password string) (*model.Note, error) {
|
|
note, err := s.repo.GetByID(id)
|
|
if err != nil {
|
|
return nil, errors.New("笔记不存在")
|
|
}
|
|
// 检查密码
|
|
if note.Password != "" {
|
|
if !model.CheckPassword(password, note.Password) {
|
|
return nil, errors.New("密码错误")
|
|
}
|
|
}
|
|
return note, nil
|
|
}
|
|
|
|
// UpdateNote 更新笔记或目录
|
|
func (s *NoteService) UpdateNote(id uint, req model.NoteUpdateRequest) (*model.Note, error) {
|
|
note, err := s.repo.GetByID(id)
|
|
if err != nil {
|
|
return nil, errors.New("笔记不存在")
|
|
}
|
|
|
|
if req.Title != nil {
|
|
note.Title = *req.Title
|
|
}
|
|
if req.Content != nil {
|
|
note.Content = *req.Content
|
|
}
|
|
if req.Category != nil {
|
|
note.Category = *req.Category
|
|
}
|
|
if req.Tags != nil {
|
|
note.Tags = *req.Tags
|
|
}
|
|
if req.IsPinned != nil {
|
|
note.IsPinned = *req.IsPinned
|
|
}
|
|
if req.IsFavorite != nil {
|
|
note.IsFavorite = *req.IsFavorite
|
|
}
|
|
if req.IsPublic != nil {
|
|
note.IsPublic = *req.IsPublic
|
|
}
|
|
if req.ParentID != nil {
|
|
note.ParentID = *req.ParentID
|
|
}
|
|
if req.IsFolder != nil {
|
|
note.IsFolder = *req.IsFolder
|
|
}
|
|
if req.SortOrder != nil {
|
|
note.SortOrder = *req.SortOrder
|
|
}
|
|
if req.RemovePassword != nil && *req.RemovePassword {
|
|
note.Password = ""
|
|
} else if req.Password != nil {
|
|
note.Password = model.HashPassword(*req.Password)
|
|
}
|
|
|
|
if err := s.repo.Update(note); err != nil {
|
|
return nil, fmt.Errorf("更新笔记失败: %w", err)
|
|
}
|
|
return note, nil
|
|
}
|
|
|
|
// DeleteNote 删除笔记或目录(目录会删除所有子项)
|
|
func (s *NoteService) DeleteNote(id uint) error {
|
|
note, err := s.repo.GetByID(id)
|
|
if err != nil {
|
|
return errors.New("笔记不存在")
|
|
}
|
|
if note.IsFolder {
|
|
return s.repo.DeleteWithChildren(id)
|
|
}
|
|
return s.repo.Delete(id)
|
|
}
|
|
|
|
// GetAllTree 获取所有笔记和目录的树形结构(管理后台用)
|
|
func (s *NoteService) GetAllTree() ([]model.NoteListItem, error) {
|
|
return s.repo.GetAllTree()
|
|
}
|
|
|
|
// GetPublicTree 获取公开笔记的树形结构(前台用)
|
|
func (s *NoteService) GetPublicTree() ([]model.NoteListItem, error) {
|
|
return s.repo.GetPublicTree()
|
|
}
|
|
|
|
// ListNotes 获取笔记列表
|
|
func (s *NoteService) ListNotes(pageStr, pageSizeStr, category, tag string, pinned, favorite *bool) ([]model.NoteListItem, int64, int, error) {
|
|
page := parseInt(pageStr, 1)
|
|
pageSize := parseInt(pageSizeStr, s.pageSize)
|
|
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if pageSize < 1 || pageSize > 100 {
|
|
pageSize = s.pageSize
|
|
}
|
|
|
|
items, total, err := s.repo.List(repository.ListQuery{
|
|
Page: page,
|
|
PageSize: pageSize,
|
|
Category: category,
|
|
Tag: tag,
|
|
Pinned: pinned,
|
|
Favorite: favorite,
|
|
})
|
|
if err != nil {
|
|
return nil, 0, 0, fmt.Errorf("获取笔记列表失败: %w", err)
|
|
}
|
|
|
|
totalPages := int(total) / pageSize
|
|
if int(total)%pageSize > 0 {
|
|
totalPages++
|
|
}
|
|
|
|
return items, total, totalPages, nil
|
|
}
|
|
|
|
// GetByParentID 获取指定目录下的所有项目
|
|
func (s *NoteService) GetByParentID(parentID uint) ([]model.NoteListItem, error) {
|
|
return s.repo.GetByParentID(parentID)
|
|
}
|
|
|
|
// SearchNotes 搜索笔记
|
|
func (s *NoteService) SearchNotes(keyword, pageStr, pageSizeStr string) ([]model.NoteListItem, int64, int, error) {
|
|
if keyword == "" {
|
|
return nil, 0, 0, errors.New("搜索关键词不能为空")
|
|
}
|
|
|
|
page := parseInt(pageStr, 1)
|
|
pageSize := parseInt(pageSizeStr, s.pageSize)
|
|
|
|
items, total, err := s.repo.Search(keyword, page, pageSize)
|
|
if err != nil {
|
|
return nil, 0, 0, fmt.Errorf("搜索笔记失败: %w", err)
|
|
}
|
|
|
|
totalPages := int(total) / pageSize
|
|
if int(total)%pageSize > 0 {
|
|
totalPages++
|
|
}
|
|
|
|
return items, total, totalPages, nil
|
|
}
|
|
|
|
// GetCategories 获取所有分类
|
|
func (s *NoteService) GetCategories() ([]string, error) {
|
|
return s.repo.GetCategories()
|
|
}
|
|
|
|
// GetTags 获取所有标签
|
|
func (s *NoteService) GetTags() ([]string, error) {
|
|
return s.repo.GetTags()
|
|
}
|
|
|
|
func parseInt(s string, defaultVal int) int {
|
|
if s == "" {
|
|
return defaultVal
|
|
}
|
|
v, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return defaultVal
|
|
}
|
|
return v
|
|
}
|