mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 14:40:12 +01:00
Improve Recent documents (#15824)
* ✨ Improve Recent documents 基于文档最近浏览时间进行排序 * ✨ 支持显示最近关闭文档 * ✨ 支持显示最近关闭文档 * ✨ 支持显示最近关闭文档 * ✨ 支持显示最近关闭文档 * ✨ 支持显示最近关闭文档 * ✨ 支持显示最近关闭文档 * ✨支持Ctrl+Shift+T打开最近关闭的文档 * 🎨 clean code * 🔥 移除表格插入行/列的默认快捷键 * ✨ 最近文档支持显示最近修改文档 * 🎨 * ✨ 最近文档支持查看最近打开 * 🎨 * ⏪ * Update win-build.bat
This commit is contained in:
parent
7e1306cab9
commit
d9e0c56a47
23 changed files with 10579 additions and 10202 deletions
|
|
@ -78,6 +78,10 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||
ginServer.Handle("POST", "/api/storage/getCriteria", model.CheckAuth, getCriteria)
|
||||
ginServer.Handle("POST", "/api/storage/removeCriterion", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeCriterion)
|
||||
ginServer.Handle("POST", "/api/storage/getRecentDocs", model.CheckAuth, getRecentDocs)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocViewTime", model.CheckAuth, updateRecentDocViewTime)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocCloseTime", model.CheckAuth, updateRecentDocCloseTime)
|
||||
ginServer.Handle("POST", "/api/storage/updateRecentDocOpenTime", model.CheckAuth, updateRecentDocOpenTime)
|
||||
|
||||
ginServer.Handle("POST", "/api/storage/getOutlineStorage", model.CheckAuth, getOutlineStorage)
|
||||
ginServer.Handle("POST", "/api/storage/setOutlineStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setOutlineStorage)
|
||||
ginServer.Handle("POST", "/api/storage/removeOutlineStorage", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, removeOutlineStorage)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,18 @@ func getRecentDocs(c *gin.Context) {
|
|||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
data, err := model.GetRecentDocs()
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// 获取排序参数
|
||||
sortBy := "viewedAt" // 默认按浏览时间排序
|
||||
if arg["sortBy"] != nil {
|
||||
sortBy = arg["sortBy"].(string)
|
||||
}
|
||||
|
||||
data, err := model.GetRecentDocs(sortBy)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
|
|
@ -236,3 +247,59 @@ func removeOutlineStorage(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func updateRecentDocViewTime(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
rootID := arg["rootID"].(string)
|
||||
err := model.UpdateRecentDocViewTime(rootID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func updateRecentDocOpenTime(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
rootID := arg["rootID"].(string)
|
||||
err := model.UpdateRecentDocOpenTime(rootID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func updateRecentDocCloseTime(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
rootID := arg["rootID"].(string)
|
||||
err := model.UpdateRecentDocCloseTime(rootID)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,9 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/lute/parse"
|
||||
|
|
@ -32,9 +34,12 @@ import (
|
|||
)
|
||||
|
||||
type RecentDoc struct {
|
||||
RootID string `json:"rootID"`
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
RootID string `json:"rootID"`
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
ViewedAt int64 `json:"viewedAt"` // 浏览时间字段
|
||||
ClosedAt int64 `json:"closedAt"` // 关闭时间字段
|
||||
OpenAt int64 `json:"openAt"` // 文档第一次从文档树加载到页签的时间
|
||||
}
|
||||
|
||||
type OutlineDoc struct {
|
||||
|
|
@ -70,9 +75,12 @@ func RemoveRecentDoc(ids []string) {
|
|||
|
||||
func setRecentDocByTree(tree *parse.Tree) {
|
||||
recentDoc := &RecentDoc{
|
||||
RootID: tree.Root.ID,
|
||||
Icon: tree.Root.IALAttr("icon"),
|
||||
Title: tree.Root.IALAttr("title"),
|
||||
RootID: tree.Root.ID,
|
||||
Icon: tree.Root.IALAttr("icon"),
|
||||
Title: tree.Root.IALAttr("title"),
|
||||
ViewedAt: time.Now().Unix(), // 使用当前时间作为浏览时间
|
||||
ClosedAt: 0, // 初始化关闭时间为0,表示未关闭
|
||||
OpenAt: time.Now().Unix(), // 设置文档打开时间
|
||||
}
|
||||
|
||||
recentDocLock.Lock()
|
||||
|
|
@ -99,10 +107,95 @@ func setRecentDocByTree(tree *parse.Tree) {
|
|||
return
|
||||
}
|
||||
|
||||
func GetRecentDocs() (ret []*RecentDoc, err error) {
|
||||
// 更新文档打开时间(只在第一次从文档树加载到页签时调用)
|
||||
func UpdateRecentDocOpenTime(rootID string) error {
|
||||
recentDocLock.Lock()
|
||||
defer recentDocLock.Unlock()
|
||||
return getRecentDocs()
|
||||
|
||||
recentDocs, err := getRecentDocs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找文档并更新打开时间
|
||||
found := false
|
||||
for _, doc := range recentDocs {
|
||||
if doc.RootID == rootID {
|
||||
doc.OpenAt = time.Now().Unix()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
err = setRecentDocs(recentDocs)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新文档浏览时间
|
||||
func UpdateRecentDocViewTime(rootID string) error {
|
||||
recentDocLock.Lock()
|
||||
defer recentDocLock.Unlock()
|
||||
|
||||
recentDocs, err := getRecentDocs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找文档并更新浏览时间
|
||||
found := false
|
||||
for _, doc := range recentDocs {
|
||||
if doc.RootID == rootID {
|
||||
doc.ViewedAt = time.Now().Unix()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
// 按浏览时间降序排序
|
||||
sort.Slice(recentDocs, func(i, j int) bool {
|
||||
return recentDocs[i].ViewedAt > recentDocs[j].ViewedAt
|
||||
})
|
||||
err = setRecentDocs(recentDocs)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新文档关闭时间
|
||||
func UpdateRecentDocCloseTime(rootID string) error {
|
||||
recentDocLock.Lock()
|
||||
defer recentDocLock.Unlock()
|
||||
|
||||
recentDocs, err := getRecentDocs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 查找文档并更新关闭时间
|
||||
found := false
|
||||
for _, doc := range recentDocs {
|
||||
if doc.RootID == rootID {
|
||||
doc.ClosedAt = time.Now().Unix()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
err = setRecentDocs(recentDocs)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRecentDocs(sortBy ...string) (ret []*RecentDoc, err error) {
|
||||
recentDocLock.Lock()
|
||||
defer recentDocLock.Unlock()
|
||||
return getRecentDocs(sortBy...)
|
||||
}
|
||||
|
||||
func setRecentDocs(recentDocs []*RecentDoc) (err error) {
|
||||
|
|
@ -127,7 +220,7 @@ func setRecentDocs(recentDocs []*RecentDoc) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getRecentDocs() (ret []*RecentDoc, err error) {
|
||||
func getRecentDocs(sortBy ...string) (ret []*RecentDoc, err error) {
|
||||
tmp := []*RecentDoc{}
|
||||
dataPath := filepath.Join(util.DataDir, "storage/recent-doc.json")
|
||||
if !filelock.IsExist(dataPath) {
|
||||
|
|
@ -159,9 +252,77 @@ func getRecentDocs() (ret []*RecentDoc, err error) {
|
|||
notExists = append(notExists, doc.RootID)
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < len(notExists) {
|
||||
setRecentDocs(ret)
|
||||
}
|
||||
|
||||
// 根据排序参数进行排序
|
||||
if len(sortBy) > 0 {
|
||||
switch sortBy[0] {
|
||||
case "closedAt":
|
||||
// 按关闭时间排序
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
if ret[i].ClosedAt == 0 && ret[j].ClosedAt == 0 {
|
||||
// 如果都没有关闭时间,按浏览时间排序
|
||||
return ret[i].ViewedAt > ret[j].ViewedAt
|
||||
}
|
||||
if ret[i].ClosedAt == 0 {
|
||||
return false // 没有关闭时间的排在后面
|
||||
}
|
||||
if ret[j].ClosedAt == 0 {
|
||||
return true // 有关闭时间的排在前面
|
||||
}
|
||||
return ret[i].ClosedAt > ret[j].ClosedAt
|
||||
})
|
||||
case "openAt":
|
||||
// 按打开时间排序
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
if ret[i].OpenAt == 0 && ret[j].OpenAt == 0 {
|
||||
// 如果都没有打开时间,按ID时间排序(ID包含时间信息)
|
||||
return ret[i].RootID > ret[j].RootID
|
||||
}
|
||||
if ret[i].OpenAt == 0 {
|
||||
return false // 没有打开时间的排在后面
|
||||
}
|
||||
if ret[j].OpenAt == 0 {
|
||||
return true // 有打开时间的排在前面
|
||||
}
|
||||
return ret[i].OpenAt > ret[j].OpenAt
|
||||
})
|
||||
default:
|
||||
// 默认按浏览时间排序
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
if ret[i].ViewedAt == 0 && ret[j].ViewedAt == 0 {
|
||||
// 如果都没有浏览时间,按ID时间排序(ID包含时间信息)
|
||||
return ret[i].RootID > ret[j].RootID
|
||||
}
|
||||
if ret[i].ViewedAt == 0 {
|
||||
return false // 没有浏览时间的排在后面
|
||||
}
|
||||
if ret[j].ViewedAt == 0 {
|
||||
return true // 有浏览时间的排在前面
|
||||
}
|
||||
return ret[i].ViewedAt > ret[j].ViewedAt
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// 默认按浏览时间降序排序,如果ViewedAt为0则使用文档创建时间
|
||||
sort.Slice(ret, func(i, j int) bool {
|
||||
if ret[i].ViewedAt == 0 && ret[j].ViewedAt == 0 {
|
||||
// 如果都没有浏览时间,按ID时间排序(ID包含时间信息)
|
||||
return ret[i].RootID > ret[j].RootID
|
||||
}
|
||||
if ret[i].ViewedAt == 0 {
|
||||
return false // 没有浏览时间的排在后面
|
||||
}
|
||||
if ret[j].ViewedAt == 0 {
|
||||
return true // 有浏览时间的排在前面
|
||||
}
|
||||
return ret[i].ViewedAt > ret[j].ViewedAt
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue