更新若干功能
This commit is contained in:
51
database.go
51
database.go
@@ -55,6 +55,8 @@ func OpenStore(path string) (*Store, error) {
|
||||
db.Close()
|
||||
return nil, err
|
||||
}
|
||||
// 每次打开库:把上次异常退出留下的 running 任务标为失败(表不存在时忽略)。
|
||||
s.markInterruptedPackTasks()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -66,7 +68,12 @@ func OpenStore(path string) (*Store, error) {
|
||||
// v6:新增 day_briefs(工作台 AI 今日规划 / 下班日报)。
|
||||
// v7:新增 launch_apps(启动台保存的应用与启停命令)。
|
||||
// v8:todos/tickets 新增 team_id 团队共享列。
|
||||
const schemaVersion = 8
|
||||
// v9:新增 launch_logs(启动台进程输出,仅本地,不同步)。
|
||||
// v10:launch_apps 新增 icon(本地抓取的 favicon/logo dataURL)。
|
||||
// v11:launch_apps 新增 category(我的应用分类筛选)。
|
||||
// v12:launch_categories 一级分类;launch_apps.category_id;projects.icon;kind_icons。
|
||||
// v13:pack_tasks / pack_task_logs(打包任务与控制台输出,仅本地,不同步)。
|
||||
const schemaVersion = 13
|
||||
|
||||
func (s *Store) migrate() error {
|
||||
// PRAGMA 是连接级/文件级配置,不属于迁移,每次打开都需执行。
|
||||
@@ -111,6 +118,14 @@ func (s *Store) migrate() error {
|
||||
`CREATE TABLE IF NOT EXISTS ai_summaries(project_id INTEGER NOT NULL, kind TEXT NOT NULL, content TEXT NOT NULL DEFAULT '', provider TEXT NOT NULL DEFAULT '', generated_at TEXT NOT NULL, PRIMARY KEY(project_id,kind), FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE)`,
|
||||
`CREATE TABLE IF NOT EXISTS day_briefs(kind TEXT PRIMARY KEY, content TEXT NOT NULL DEFAULT '', provider TEXT NOT NULL DEFAULT '', generated_at TEXT NOT NULL)`,
|
||||
`CREATE TABLE IF NOT EXISTS launch_apps(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, kind TEXT NOT NULL DEFAULT 'other', port INTEGER NOT NULL DEFAULT 0, dir TEXT NOT NULL DEFAULT '', start_cmd TEXT NOT NULL DEFAULT '', stop_cmd TEXT NOT NULL DEFAULT '', last_pid INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL)`,
|
||||
`CREATE TABLE IF NOT EXISTS launch_logs(id INTEGER PRIMARY KEY AUTOINCREMENT, app_id INTEGER NOT NULL, level TEXT NOT NULL DEFAULT 'info', line TEXT NOT NULL, created_at TEXT NOT NULL)`,
|
||||
`CREATE TABLE IF NOT EXISTS launch_categories(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, sort INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL)`,
|
||||
`CREATE TABLE IF NOT EXISTS kind_icons(kind TEXT PRIMARY KEY, value TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT '')`,
|
||||
`CREATE TABLE IF NOT EXISTS pack_tasks(id TEXT PRIMARY KEY, title TEXT NOT NULL DEFAULT '', cmd TEXT NOT NULL DEFAULT '', dir TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'running', pid INTEGER NOT NULL DEFAULT 0, started_at TEXT NOT NULL DEFAULT '', ended_at TEXT NOT NULL DEFAULT '', error TEXT NOT NULL DEFAULT '')`,
|
||||
`CREATE TABLE IF NOT EXISTS pack_task_logs(id INTEGER PRIMARY KEY AUTOINCREMENT, task_id TEXT NOT NULL, line TEXT NOT NULL, created_at TEXT NOT NULL)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_launch_logs_app ON launch_logs(app_id, id DESC)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_pack_tasks_started ON pack_tasks(started_at DESC)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_pack_task_logs_task ON pack_task_logs(task_id, id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_ai_messages_conv ON ai_messages(conversation_id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_messages_read ON messages(is_read)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_todos_status ON todos(deleted,status)`,
|
||||
@@ -150,6 +165,34 @@ func (s *Store) migrate() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ok, err := s.columnExists("launch_apps", "icon"); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
if _, err = s.db.Exec(`ALTER TABLE launch_apps ADD COLUMN icon TEXT NOT NULL DEFAULT ''`); err != nil {
|
||||
return fmt.Errorf("database migration: %w", err)
|
||||
}
|
||||
}
|
||||
if ok, err := s.columnExists("launch_apps", "category"); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
if _, err = s.db.Exec(`ALTER TABLE launch_apps ADD COLUMN category TEXT NOT NULL DEFAULT ''`); err != nil {
|
||||
return fmt.Errorf("database migration: %w", err)
|
||||
}
|
||||
}
|
||||
if ok, err := s.columnExists("launch_apps", "category_id"); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
if _, err = s.db.Exec(`ALTER TABLE launch_apps ADD COLUMN category_id INTEGER NOT NULL DEFAULT 0`); err != nil {
|
||||
return fmt.Errorf("database migration: %w", err)
|
||||
}
|
||||
}
|
||||
if ok, err := s.columnExists("projects", "icon"); err != nil {
|
||||
return err
|
||||
} else if !ok {
|
||||
if _, err = s.db.Exec(`ALTER TABLE projects ADD COLUMN icon TEXT NOT NULL DEFAULT ''`); err != nil {
|
||||
return fmt.Errorf("database migration: %w", err)
|
||||
}
|
||||
}
|
||||
_, _ = s.db.Exec(`INSERT OR IGNORE INTO project_groups(id,name,created_at,updated_at) VALUES(1,'My Projects',?,?)`, time.Now().Format(time.RFC3339), time.Now().Format(time.RFC3339))
|
||||
_, _ = s.db.Exec(`UPDATE projects SET group_id=1 WHERE group_id IS NULL OR group_id=0`)
|
||||
defaults := map[string][]string{"general": {".git", ".idea", ".vscode", "node_modules", "dist", "coverage", "*.min.js", "*.min.css", ".DS_Store"}, "php": {"vendor", "storage/framework", "bootstrap/cache", ".phpunit.cache"}, "go": {"go.sum"}, "vue": {".nuxt", ".next", ".output", "unpackage"}}
|
||||
@@ -291,7 +334,7 @@ func (s *Store) DeleteProjectGroup(id int64) error {
|
||||
return tx.Commit()
|
||||
}
|
||||
func (s *Store) ListProjects(groupID int64) ([]Project, error) {
|
||||
q := `SELECT p.id,p.name,p.path,p.description,p.group_id,COALESCE(g.name,''),p.created_at,p.updated_at FROM projects p LEFT JOIN project_groups g ON g.id=p.group_id`
|
||||
q := `SELECT p.id,p.name,p.path,p.description,p.group_id,COALESCE(g.name,''),COALESCE(p.icon,''),p.created_at,p.updated_at FROM projects p LEFT JOIN project_groups g ON g.id=p.group_id`
|
||||
args := []any{}
|
||||
if groupID > 0 {
|
||||
q += ` WHERE p.group_id=?`
|
||||
@@ -305,7 +348,7 @@ func (s *Store) ListProjects(groupID int64) ([]Project, error) {
|
||||
out := []Project{}
|
||||
for rows.Next() {
|
||||
var p Project
|
||||
if e = rows.Scan(&p.ID, &p.Name, &p.Path, &p.Description, &p.GroupID, &p.GroupName, &p.CreatedAt, &p.UpdatedAt); e != nil {
|
||||
if e = rows.Scan(&p.ID, &p.Name, &p.Path, &p.Description, &p.GroupID, &p.GroupName, &p.Icon, &p.CreatedAt, &p.UpdatedAt); e != nil {
|
||||
rows.Close()
|
||||
return nil, e
|
||||
}
|
||||
@@ -326,7 +369,7 @@ func (s *Store) ListProjects(groupID int64) ([]Project, error) {
|
||||
}
|
||||
func (s *Store) GetProject(id int64) (Project, error) {
|
||||
var p Project
|
||||
e := s.db.QueryRow(`SELECT p.id,p.name,p.path,p.description,p.group_id,COALESCE(g.name,''),p.created_at,p.updated_at FROM projects p LEFT JOIN project_groups g ON g.id=p.group_id WHERE p.id=?`, id).Scan(&p.ID, &p.Name, &p.Path, &p.Description, &p.GroupID, &p.GroupName, &p.CreatedAt, &p.UpdatedAt)
|
||||
e := s.db.QueryRow(`SELECT p.id,p.name,p.path,p.description,p.group_id,COALESCE(g.name,''),COALESCE(p.icon,''),p.created_at,p.updated_at FROM projects p LEFT JOIN project_groups g ON g.id=p.group_id WHERE p.id=?`, id).Scan(&p.ID, &p.Name, &p.Path, &p.Description, &p.GroupID, &p.GroupName, &p.Icon, &p.CreatedAt, &p.UpdatedAt)
|
||||
if e != nil {
|
||||
return p, e
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user