feat: v3 增强 - FTS5全文搜索+双向链接/知识图谱+自动保存草稿+标签管理+实时预览编辑器+PWA
- FTS5中文分词搜索(需-tags=sqlite_fts5) - [[wiki链接]]反向链接+SVG知识图谱 - 自动保存草稿(不触发版本历史) - 标签重命名/合并/删除+使用统计 - 后台编辑实时预览+格式工具栏 - PWA manifest+service worker+移动端适配 - 冒烟测试扩至66例全通过
This commit is contained in:
@@ -661,3 +661,132 @@ func sanitizeFileName(name string) string {
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// ─────────────── 自动保存草稿 ───────────────
|
||||
|
||||
// SaveDraft 保存笔记草稿(自动保存)
|
||||
func (h *NoteHandler) SaveDraft(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, "无效的笔记 ID")
|
||||
return
|
||||
}
|
||||
var req struct {
|
||||
Content string `json:"content"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
fail(c, http.StatusBadRequest, "请求参数错误")
|
||||
return
|
||||
}
|
||||
if err := h.svc.SaveDraft(uint(id), req.Content); err != nil {
|
||||
fail(c, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, nil)
|
||||
}
|
||||
|
||||
// DiscardDraft 清除指定笔记的草稿
|
||||
func (h *NoteHandler) DiscardDraft(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, "无效的笔记 ID")
|
||||
return
|
||||
}
|
||||
if err := h.svc.ClearDraft(uint(id)); err != nil {
|
||||
fail(c, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, nil)
|
||||
}
|
||||
|
||||
// ─────────────── 双向链接 / 知识图谱 ───────────────
|
||||
|
||||
// GetBacklinks 获取指定笔记的反向链接列表
|
||||
func (h *NoteHandler) GetBacklinks(c *gin.Context) {
|
||||
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, "无效的笔记 ID")
|
||||
return
|
||||
}
|
||||
links, err := h.svc.GetBacklinks(uint(id), "")
|
||||
if err != nil {
|
||||
fail(c, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, links)
|
||||
}
|
||||
|
||||
// GetKnowledgeGraph 获取知识图谱数据(节点 + 边)
|
||||
func (h *NoteHandler) GetKnowledgeGraph(c *gin.Context) {
|
||||
graph, err := h.svc.GetKnowledgeGraph()
|
||||
if err != nil {
|
||||
fail(c, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, graph)
|
||||
}
|
||||
|
||||
// ─────────────── 标签管理 ───────────────
|
||||
|
||||
// GetTagUsage 获取标签及使用次数
|
||||
func (h *NoteHandler) GetTagUsage(c *gin.Context) {
|
||||
usage, err := h.svc.GetTagUsage()
|
||||
if err != nil {
|
||||
fail(c, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, usage)
|
||||
}
|
||||
|
||||
// RenameTag 重命名标签
|
||||
func (h *NoteHandler) RenameTag(c *gin.Context) {
|
||||
var req struct {
|
||||
OldName string `json:"old_name" binding:"required"`
|
||||
NewName string `json:"new_name" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
fail(c, http.StatusBadRequest, "请求参数错误")
|
||||
return
|
||||
}
|
||||
changed, err := h.svc.RenameTag(req.OldName, req.NewName)
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, gin.H{"changed": changed})
|
||||
}
|
||||
|
||||
// MergeTag 合并标签(from → to)
|
||||
func (h *NoteHandler) MergeTag(c *gin.Context) {
|
||||
var req struct {
|
||||
From string `json:"from" binding:"required"`
|
||||
To string `json:"to" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
fail(c, http.StatusBadRequest, "请求参数错误")
|
||||
return
|
||||
}
|
||||
changed, err := h.svc.MergeTag(req.From, req.To)
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, gin.H{"changed": changed})
|
||||
}
|
||||
|
||||
// DeleteTag 删除标签(从所有笔记中移除)
|
||||
func (h *NoteHandler) DeleteTag(c *gin.Context) {
|
||||
var req struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
fail(c, http.StatusBadRequest, "请求参数错误")
|
||||
return
|
||||
}
|
||||
changed, err := h.svc.DeleteTag(req.Name)
|
||||
if err != nil {
|
||||
fail(c, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
success(c, gin.H{"changed": changed})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user