Files
code-utils/kind_icon.go
2026-08-15 17:18:00 +08:00

205 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
// kind_icon.go启动台可识别 kind 的默认图标(仅本地,不同步;超管维护)。
import (
"encoding/base64"
"errors"
"fmt"
"strings"
"github.com/wailsapp/wails/v3/pkg/application"
)
var knownLaunchKinds = []string{
"node", "go", "python", "java", "php", "dotnet", "exe", "mysql", "redis", "nginx", "web", "other",
}
func isKnownLaunchKind(k string) bool {
for _, x := range knownLaunchKinds {
if x == k {
return true
}
}
return false
}
func (s *Store) ListKindIcons() (map[string]string, error) {
rows, e := s.db.Query(`SELECT kind,value FROM kind_icons WHERE value!=''`)
if e != nil {
return nil, e
}
defer rows.Close()
m := map[string]string{}
for rows.Next() {
var k, v string
if e = rows.Scan(&k, &v); e != nil {
return nil, e
}
m[k] = v
}
return m, rows.Err()
}
func (s *Store) setKindIcon(kind, value string) error {
now := nowRFC()
_, e := s.db.Exec(`INSERT INTO kind_icons(kind,value,updated_at) VALUES(?,?,?)
ON CONFLICT(kind) DO UPDATE SET value=excluded.value,updated_at=excluded.updated_at`, kind, value, now)
return e
}
func (s *Store) clearKindIcon(kind string) error {
_, e := s.db.Exec(`DELETE FROM kind_icons WHERE kind=?`, kind)
return e
}
func (a *App) kindIconAdminGate() error {
if a.syncUserID() != festivalAdminID {
return errors.New("KIND_ICON_ADMIN_ONLY")
}
return nil
}
// ListKindIcons 返回 kind → dataURL。
func (a *App) ListKindIcons() (map[string]string, error) {
if e := a.ready(); e != nil {
return nil, e
}
return a.store.ListKindIcons()
}
// ListKnownLaunchKinds 固定种类列表(前端管理页用)。
func (a *App) ListKnownLaunchKinds() []string {
return append([]string{}, knownLaunchKinds...)
}
// PickKindIcon 超管为某 kind 选择本地图片(缩放后存 dataURL
func (a *App) PickKindIcon(kind string) (string, error) {
if e := a.ready(); e != nil {
return "", e
}
if e := a.kindIconAdminGate(); e != nil {
return "", e
}
kind = strings.TrimSpace(kind)
if !isKnownLaunchKind(kind) {
return "", errors.New("KIND_UNKNOWN")
}
p, e := application.Get().Dialog.OpenFile().
SetTitle(a.localized("选择种类图标", "Choose kind icon")).
AddFilter(a.localized("图片文件", "Image files"), "*.png;*.jpg;*.jpeg;*.gif;*.webp").
PromptForSingleSelection()
if e != nil || strings.TrimSpace(p) == "" {
return "", e
}
data, mime, e := encodeAvatarFile(p)
if e != nil {
return "", e
}
dataURL := fmt.Sprintf("data:%s;base64,%s", mime, base64.StdEncoding.EncodeToString(data))
if e := a.store.setKindIcon(kind, dataURL); e != nil {
return "", e
}
return dataURL, nil
}
// ClearKindIcon 超管清除某 kind 默认图。
func (a *App) ClearKindIcon(kind string) error {
if e := a.ready(); e != nil {
return e
}
if e := a.kindIconAdminGate(); e != nil {
return e
}
kind = strings.TrimSpace(kind)
if !isKnownLaunchKind(kind) {
return errors.New("KIND_UNKNOWN")
}
return a.store.clearKindIcon(kind)
}
// PickLaunchIconImage 为启动台选本地图片base64 dataURL不强制写库
func (a *App) PickLaunchIconImage() (string, error) {
if e := a.ready(); e != nil {
return "", e
}
p, e := application.Get().Dialog.OpenFile().
SetTitle(a.localized("选择应用图标", "Choose app icon")).
AddFilter(a.localized("图片文件", "Image files"), "*.png;*.jpg;*.jpeg;*.gif;*.webp").
PromptForSingleSelection()
if e != nil || strings.TrimSpace(p) == "" {
return "", e
}
data, mime, e := encodeAvatarFile(p)
if e != nil {
return "", e
}
return fmt.Sprintf("data:%s;base64,%s", mime, base64.StdEncoding.EncodeToString(data)), nil
}
// SetLaunchAppIcon 写回已保存应用的图标(空字符串=清除)。
func (a *App) SetLaunchAppIcon(id int64, icon string) error {
if e := a.ready(); e != nil {
return e
}
if _, e := a.store.GetLaunchApp(id); e != nil {
return errors.New("LAUNCH_APP_NOT_FOUND")
}
if e := a.store.setLaunchIcon(id, icon); e != nil {
return e
}
a.emit("launchpad:changed", nil)
return nil
}
// FetchProjectIcon 从项目目录抓取 icon 并写回 projects.icon。
func (a *App) FetchProjectIcon(id int64) (string, error) {
if e := a.ready(); e != nil {
return "", e
}
p, e := a.store.GetProject(id)
if e != nil {
return "", errors.New("PROJECT_NOT_FOUND")
}
u := iconFromDir(p.Path)
if u == "" {
return "", errors.New("ICON_NOT_FOUND")
}
if e := a.store.setProjectIcon(id, u); e != nil {
return "", e
}
return u, nil
}
// SetProjectIcon 写入/清除项目图标。
func (a *App) SetProjectIcon(id int64, icon string) error {
if e := a.ready(); e != nil {
return e
}
if _, e := a.store.GetProject(id); e != nil {
return errors.New("PROJECT_NOT_FOUND")
}
return a.store.setProjectIcon(id, icon)
}
func (s *Store) setProjectIcon(id int64, icon string) error {
_, e := s.db.Exec(`UPDATE projects SET icon=?,updated_at=? WHERE id=?`, icon, now(), id)
return e
}
// DetectProjectLaunchKind 根据项目路径推断启动台 kind用于默认图标回退
func (a *App) DetectProjectLaunchKind(id int64) (string, error) {
if e := a.ready(); e != nil {
return "", e
}
p, e := a.store.GetProject(id)
if e != nil {
return "", errors.New("PROJECT_NOT_FOUND")
}
prof := detectLaunchProfile(p.Path)
if prof.Kind == "" {
return "other", nil
}
return prof.Kind, nil
}