56 lines
1.7 KiB
Go
56 lines
1.7 KiB
Go
package main
|
||
|
||
// search.go 全局搜索(Ctrl+K 命令面板):项目 / 待办 / 工单 / AI 会话各取前 8 条。
|
||
|
||
import "strings"
|
||
|
||
// escapeLike 转义 LIKE 通配符,配合 ESCAPE '\' 使用。
|
||
func escapeLike(s string) string {
|
||
r := strings.NewReplacer(`\`, `\\`, `%`, `\%`, `_`, `\_`)
|
||
return r.Replace(s)
|
||
}
|
||
|
||
func (a *App) GlobalSearch(q string) ([]SearchHit, error) {
|
||
if e := a.ready(); e != nil {
|
||
return nil, e
|
||
}
|
||
q = strings.TrimSpace(q)
|
||
out := []SearchHit{}
|
||
if q == "" {
|
||
return out, nil
|
||
}
|
||
pat := "%" + escapeLike(q) + "%"
|
||
type src struct {
|
||
kind, query string
|
||
args int // pat 占位数量
|
||
}
|
||
for _, s := range []src{
|
||
{"project", `SELECT id,name,path,'' FROM projects WHERE name LIKE ? ESCAPE '\' OR path LIKE ? ESCAPE '\' ORDER BY updated_at DESC LIMIT 8`, 2},
|
||
{"todo", `SELECT id,title,status,priority FROM todos WHERE deleted=0 AND (title LIKE ? ESCAPE '\' OR content LIKE ? ESCAPE '\') ORDER BY updated_at DESC LIMIT 8`, 2},
|
||
{"ticket", `SELECT id,title,status,priority FROM tickets WHERE deleted=0 AND (title LIKE ? ESCAPE '\' OR description LIKE ? ESCAPE '\') ORDER BY updated_at DESC LIMIT 8`, 2},
|
||
{"conversation", `SELECT id,title,provider,'' FROM ai_conversations WHERE title LIKE ? ESCAPE '\' ORDER BY updated_at DESC LIMIT 8`, 1},
|
||
} {
|
||
args := make([]any, s.args)
|
||
for i := range args {
|
||
args[i] = pat
|
||
}
|
||
rows, e := a.store.db.Query(s.query, args...)
|
||
if e != nil {
|
||
return nil, e
|
||
}
|
||
for rows.Next() {
|
||
h := SearchHit{Kind: s.kind}
|
||
if e := rows.Scan(&h.ID, &h.Title, &h.Sub, &h.Extra); e != nil {
|
||
rows.Close()
|
||
return nil, e
|
||
}
|
||
out = append(out, h)
|
||
}
|
||
rows.Close()
|
||
if e := rows.Err(); e != nil {
|
||
return nil, e
|
||
}
|
||
}
|
||
return out, nil
|
||
}
|