cyi-box: Memphis-style toolbox admin platform

Go(fun)+SQLite backend, Vue 3 frontend. Modules: dashboard, pay gateway
(Epay-compatible + CDK stock), license/card system (per-app appid, domain
binding), AI memory bank with built-in MCP server (/mcp, FTS5 search,
signed read links), server SSH monitor + terminal + SFTP, proxy pool with
protocol-level alive checks, DB manager (mysql/pg/sqlite + SQL
autocomplete + import/export), disk share, vault (AES-GCM + TOTP),
bookmarks, dev tools.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
2026-10-01 01:58:47 +08:00
co-authored by Devin
commit 834ecacdb9
326 changed files with 27813 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
package service
import (
"fmt"
"strings"
"github.com/cyi-cc/fun"
"github.com/cyi-cc/cyi-box/backend/internal/dto"
"github.com/cyi-cc/cyi-box/backend/internal/store"
)
// ToolSvc 工具箱注册表:List 登录用户可见(驱动侧边导航),管理端点为 admin
type ToolSvc struct {
fun.Ctx
Store *store.Store
}
func (s *ToolSvc) List() ([]dto.ToolView, error) {
tools, err := s.Store.ListTools(true)
if err != nil {
return nil, fmt.Errorf("tool: list failed: %w", err)
}
return toolViews(tools), nil
}
func (s *ToolSvc) AdminList() ([]dto.ToolView, error) {
tools, err := s.Store.ListTools(false)
if err != nil {
return nil, fmt.Errorf("tool: list failed: %w", err)
}
return toolViews(tools), nil
}
func (s *ToolSvc) SaveTool(d dto.SaveToolDto) (dto.ToolView, error) {
name := strings.TrimSpace(d.Name)
url := strings.TrimSpace(d.Url)
if name == "" || len(name) > 32 {
return dto.ToolView{}, fun.Error(4001, "工具名必填且不超过 32 字符")
}
t := store.Tool{
Name: name,
Url: url,
Sort: 0,
Enabled: true,
}
if d.Id != nil {
t.Id = *d.Id
}
if d.Icon != nil {
t.Icon = strings.TrimSpace(*d.Icon)
}
if d.Description != nil {
t.Description = strings.TrimSpace(*d.Description)
}
if d.Sort != nil {
t.Sort = *d.Sort
}
if d.Enabled != nil {
t.Enabled = *d.Enabled
}
if err := s.Store.SaveTool(&t); err != nil {
return dto.ToolView{}, fmt.Errorf("tool: save failed: %w", err)
}
views := toolViews([]store.Tool{t})
return views[0], nil
}
func (s *ToolSvc) DeleteTool(d dto.DeleteToolDto) (dto.OkView, error) {
if err := s.Store.DeleteTool(d.Id); err != nil {
return dto.OkView{}, fmt.Errorf("tool: delete failed: %w", err)
}
return dto.OkView{Message: "已删除"}, nil
}
func toolViews(tools []store.Tool) []dto.ToolView {
views := make([]dto.ToolView, 0, len(tools))
for _, t := range tools {
views = append(views, dto.ToolView{
Id: t.Id,
Name: t.Name,
Icon: t.Icon,
Url: t.Url,
Description: t.Description,
Sort: t.Sort,
Enabled: t.Enabled,
})
}
return views
}