diff --git a/cmd/ace/wire_gen.go b/cmd/ace/wire_gen.go index 7a5189b3..701e9e6b 100644 --- a/cmd/ace/wire_gen.go +++ b/cmd/ace/wire_gen.go @@ -128,7 +128,7 @@ func initWeb() (*app.Web, error) { toolboxLogService := service.NewToolboxLogService(locale, db, containerImageRepo, settingRepo) webHookRepo := data.NewWebHookRepo(locale, db, logger) webHookService := service.NewWebHookService(webHookRepo) - templateRepo := data.NewTemplateRepo() + templateRepo := data.NewTemplateRepo(locale, cacheRepo) templateService := service.NewTemplateService(locale, templateRepo, settingRepo) apacheApp := apache.NewApp(locale) codeserverApp := codeserver.NewApp() diff --git a/internal/biz/cache.go b/internal/biz/cache.go index c2adeec2..98b205ff 100644 --- a/internal/biz/cache.go +++ b/internal/biz/cache.go @@ -8,6 +8,7 @@ const ( CacheKeyCategories CacheKey = "categories" CacheKeyApps CacheKey = "apps" CacheKeyEnvironment CacheKey = "environment" + CacheKeyTemplates CacheKey = "templates" CacheKeyRewrites CacheKey = "rewrites" ) @@ -24,5 +25,6 @@ type CacheRepo interface { UpdateCategories() error UpdateApps() error UpdateEnvironments() error + UpdateTemplates() error UpdateRewrites() error } diff --git a/internal/biz/template.go b/internal/biz/template.go index 5a80b95a..e756a8a9 100644 --- a/internal/biz/template.go +++ b/internal/biz/template.go @@ -6,7 +6,7 @@ import ( ) type TemplateRepo interface { - List() (api.Templates, error) + List() api.Templates Get(slug string) (*api.Template, error) Callback(slug string) error CreateCompose(name, compose string, envs []types.KV, autoFirewall bool) error diff --git a/internal/data/cache.go b/internal/data/cache.go index 21ae520a..cc630752 100644 --- a/internal/data/cache.go +++ b/internal/data/cache.go @@ -97,6 +97,20 @@ func (r *cacheRepo) UpdateEnvironments() error { return r.Set(biz.CacheKeyEnvironment, string(encoded)) } +func (r *cacheRepo) UpdateTemplates() error { + templates, err := r.api.Templates() + if err != nil { + return err + } + + encoded, err := json.Marshal(templates) + if err != nil { + return err + } + + return r.Set(biz.CacheKeyTemplates, string(encoded)) +} + func (r *cacheRepo) UpdateRewrites() error { rewrites, err := r.api.RewritesByType("nginx") if err != nil { diff --git a/internal/data/template.go b/internal/data/template.go index 2e4d7f73..d3f43eee 100644 --- a/internal/data/template.go +++ b/internal/data/template.go @@ -1,6 +1,7 @@ package data import ( + "encoding/json" "fmt" "os" "path/filepath" @@ -12,43 +13,50 @@ import ( "github.com/acepanel/panel/pkg/api" "github.com/acepanel/panel/pkg/firewall" "github.com/acepanel/panel/pkg/types" + "github.com/leonelquinteros/gotext" ) type templateRepo struct { + t *gotext.Locale + cache biz.CacheRepo api *api.API firewall *firewall.Firewall } -func NewTemplateRepo() biz.TemplateRepo { +func NewTemplateRepo(t *gotext.Locale, cache biz.CacheRepo) biz.TemplateRepo { return &templateRepo{ + t: t, + cache: cache, api: api.NewAPI(app.Version, app.Locale), firewall: firewall.NewFirewall(), } } // List 获取所有模版 -func (r *templateRepo) List() (api.Templates, error) { - templates, err := r.api.Templates() +func (r *templateRepo) List() api.Templates { + cached, err := r.cache.Get(biz.CacheKeyTemplates) if err != nil { - return nil, err + return nil } - return *templates, nil + templates := make(api.Templates, 0) + if err = json.Unmarshal([]byte(cached), &templates); err != nil { + return nil + } + + return templates } // Get 获取模版详情 func (r *templateRepo) Get(slug string) (*api.Template, error) { - templates, err := r.api.Templates() - if err != nil { - return nil, err - } + templates := r.List() - for _, t := range *templates { + for _, t := range templates { if t.Slug == slug { return t, nil } } - return nil, fmt.Errorf("template %s not found", slug) + return nil, fmt.Errorf(r.t.Get("template %s not found", slug)) } // Callback 模版下载回调 diff --git a/internal/service/app.go b/internal/service/app.go index 7d1bde4c..62364993 100644 --- a/internal/service/app.go +++ b/internal/service/app.go @@ -219,6 +219,10 @@ func (s *AppService) UpdateCache(w http.ResponseWriter, r *http.Request) { Error(w, http.StatusInternalServerError, "%v", err) return } + if err := s.cacheRepo.UpdateTemplates(); err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } Success(w, nil) } diff --git a/internal/service/cli.go b/internal/service/cli.go index 6d5504e8..c3e9c292 100644 --- a/internal/service/cli.go +++ b/internal/service/cli.go @@ -127,6 +127,9 @@ func (s *CliService) Sync(ctx context.Context, cmd *cli.Command) error { if err := s.cacheRepo.UpdateEnvironments(); err != nil { return errors.New(s.t.Get("Failed to synchronize app data: %v", err)) } + if err := s.cacheRepo.UpdateTemplates(); err != nil { + return errors.New(s.t.Get("Failed to synchronize app data: %v", err)) + } if err := s.cacheRepo.UpdateRewrites(); err != nil { return errors.New(s.t.Get("Failed to synchronize rewrite rules: %v", err)) } diff --git a/internal/service/template.go b/internal/service/template.go index 20911a92..334be67d 100644 --- a/internal/service/template.go +++ b/internal/service/template.go @@ -30,13 +30,7 @@ func (s *TemplateService) List(w http.ResponseWriter, r *http.Request) { return } - templates, err := s.templateRepo.List() - if err != nil { - Error(w, http.StatusInternalServerError, "%v", err) - return - } - - Success(w, templates) + Success(w, s.templateRepo.List()) } // Get 获取模版详情 @@ -47,11 +41,6 @@ func (s *TemplateService) Get(w http.ResponseWriter, r *http.Request) { return } - if offline, _ := s.settingRepo.GetBool(biz.SettingKeyOfflineMode); offline { - Error(w, http.StatusForbidden, s.t.Get("Unable to get template in offline mode")) - return - } - template, err := s.templateRepo.Get(req.Slug) if err != nil { Error(w, http.StatusInternalServerError, "%v", err) @@ -69,11 +58,6 @@ func (s *TemplateService) Create(w http.ResponseWriter, r *http.Request) { return } - if offline, _ := s.settingRepo.GetBool(biz.SettingKeyOfflineMode); offline { - Error(w, http.StatusForbidden, s.t.Get("Unable to create compose from template in offline mode")) - return - } - // 获取模版 template, err := s.templateRepo.Get(req.Slug) if err != nil { diff --git a/web/src/views/app/TemplateDeployModal.vue b/web/src/views/app/TemplateDeployModal.vue index 4074e742..6f1976e2 100644 --- a/web/src/views/app/TemplateDeployModal.vue +++ b/web/src/views/app/TemplateDeployModal.vue @@ -61,34 +61,35 @@ const handleSubmit = async () => { doSubmit.value = true - try { - // 构建环境变量数组 - const envs = Object.entries(deployModel.envs).map(([key, value]) => ({ - key, - value: String(value) - })) + // 构建环境变量数组 + const envs = Object.entries(deployModel.envs).map(([key, value]) => ({ + key, + value: String(value) + })) - // 创建 compose - await templateApi.create({ + // 创建 compose + useRequest( + templateApi.create({ slug: props.template.slug, name: deployModel.name, envs, auto_firewall: deployModel.autoFirewall }) - - window.$message.success($gettext('Created successfully')) - - if (deployModel.autoStart) { - // 自动启动 - upCommand.value = `docker compose -f /opt/ace/server/compose/${deployModel.name}/docker-compose.yml up -d` - upModal.value = true - } else { - show.value = false - emit('success') - } - } finally { - doSubmit.value = false - } + ) + .onSuccess(() => { + window.$message.success($gettext('Created successfully')) + if (deployModel.autoStart) { + // 自动启动 + upCommand.value = `docker compose -f /opt/ace/server/compose/${deployModel.name}/docker-compose.yml up -d` + upModal.value = true + } else { + show.value = false + emit('success') + } + }) + .onComplete(() => { + doSubmit.value = false + }) } // 启动完成 @@ -180,6 +181,7 @@ watch( v-for="env in template.environments" :key="env.name" :label="env.description" + :required="env.default == ''" > { - const cats = new Set() - data.value?.forEach((t: Template) => { - t.categories?.forEach((c) => cats.add(c)) - }) - return Array.from(cats) +const { data: categories } = useRequest(app.categories, { + initialData: [] }) // 过滤后的模版列表 @@ -33,6 +30,11 @@ const filteredTemplates = computed(() => { return (data.value || []).filter((t: Template) => t.categories?.includes(selectedCategory.value)) }) +const getCategoryLabel = (catValue: string) => { + const cat = categories.value.find((c: any) => c.value === catValue) + return cat ? cat.label : catValue +} + const handleCategoryChange = (category: string) => { selectedCategory.value = category } @@ -60,13 +62,13 @@ onMounted(() => { - {{ cat }} + {{ cat.label }} @@ -84,7 +86,7 @@ onMounted(() => { - {{ cat }} + {{ getCategoryLabel(cat) }}