From bb28e5ef6db23d3b03100eaf3037c7edd2643dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Mon, 12 Jan 2026 22:17:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20app=E6=94=AF=E6=8C=81=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/biz/app.go | 1 + internal/data/app.go | 9 +++ internal/http/request/app.go | 4 + internal/route/http.go | 1 + internal/service/app.go | 15 ++++ web/src/api/panel/app/index.ts | 2 + web/src/views/home/IndexView.vue | 135 ++++++++++++++++++++++--------- 7 files changed, 127 insertions(+), 40 deletions(-) diff --git a/internal/biz/app.go b/internal/biz/app.go index a0a2277f..38e4f845 100644 --- a/internal/biz/app.go +++ b/internal/biz/app.go @@ -32,4 +32,5 @@ type AppRepo interface { UnInstall(slug string) error Update(slug string) error UpdateShow(slug string, show bool) error + UpdateOrder(slugs []string) error } diff --git a/internal/data/app.go b/internal/data/app.go index d0b69bf3..ae8969b8 100644 --- a/internal/data/app.go +++ b/internal/data/app.go @@ -359,6 +359,15 @@ func (r *appRepo) UpdateShow(slug string, show bool) error { return r.db.Save(item).Error } +func (r *appRepo) UpdateOrder(slugs []string) error { + for i, slug := range slugs { + if err := r.db.Model(&biz.App{}).Where("slug = ?", slug).Update("show_order", i).Error; err != nil { + return err + } + } + return nil +} + func (r *appRepo) preCheck(app *api.App) error { var apps []string var installed []string diff --git a/internal/http/request/app.go b/internal/http/request/app.go index 15066eb8..137e4adc 100644 --- a/internal/http/request/app.go +++ b/internal/http/request/app.go @@ -17,3 +17,7 @@ type AppUpdateShow struct { Slug string `json:"slug" form:"slug" validate:"required|exists:apps,slug"` Show bool `json:"show" form:"show"` } + +type AppUpdateOrder struct { + Slugs []string `json:"slugs" form:"slugs" validate:"required"` +} diff --git a/internal/route/http.go b/internal/route/http.go index c2fbcccd..b5d7544e 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -288,6 +288,7 @@ func (route *Http) Register(r *chi.Mux) { r.Post("/uninstall", route.app.Uninstall) r.Post("/update", route.app.Update) r.Post("/update_show", route.app.UpdateShow) + r.Post("/update_order", route.app.UpdateOrder) r.Get("/is_installed", route.app.IsInstalled) r.Get("/update_cache", route.app.UpdateCache) }) diff --git a/internal/service/app.go b/internal/service/app.go index bcb391be..7d1bde4c 100644 --- a/internal/service/app.go +++ b/internal/service/app.go @@ -162,6 +162,21 @@ func (s *AppService) UpdateShow(w http.ResponseWriter, r *http.Request) { Success(w, nil) } +func (s *AppService) UpdateOrder(w http.ResponseWriter, r *http.Request) { + req, err := Bind[request.AppUpdateOrder](r) + if err != nil { + Error(w, http.StatusUnprocessableEntity, "%v", err) + return + } + + if err = s.appRepo.UpdateOrder(req.Slugs); err != nil { + Error(w, http.StatusInternalServerError, "%v", err) + return + } + + Success(w, nil) +} + func (s *AppService) IsInstalled(w http.ResponseWriter, r *http.Request) { req, err := Bind[request.AppSlugs](r) if err != nil { diff --git a/web/src/api/panel/app/index.ts b/web/src/api/panel/app/index.ts index 979a5943..d61e4f6b 100644 --- a/web/src/api/panel/app/index.ts +++ b/web/src/api/panel/app/index.ts @@ -15,6 +15,8 @@ export default { update: (slug: string): any => http.Post('/app/update', { slug }), // 设置首页显示 updateShow: (slug: string, show: boolean): any => http.Post('/app/update_show', { slug, show }), + // 更新首页显示排序 + updateOrder: (slugs: string[]): any => http.Post('/app/update_order', { slugs }), // 应用是否已安装 isInstalled: (slugs: string): any => http.Get('/app/is_installed', { params: { slugs } }), // 更新缓存 diff --git a/web/src/views/home/IndexView.vue b/web/src/views/home/IndexView.vue index 8b15507e..1f2d3c85 100644 --- a/web/src/views/home/IndexView.vue +++ b/web/src/views/home/IndexView.vue @@ -15,7 +15,9 @@ import { use } from 'echarts/core' import { CanvasRenderer } from 'echarts/renderers' import { NButton, NPopconfirm, useThemeVars } from 'naive-ui' import { useGettext } from 'vue3-gettext' +import draggable from 'vuedraggable' +import app from '@/api/panel/app' import home from '@/api/panel/home' import TheIconLocal from '@/components/custom/TheIconLocal.vue' import { router } from '@/router' @@ -63,14 +65,14 @@ const { data: systemInfo } = useRequest(home.systemInfo, { } }) const { data: apps, loading: appLoading } = useRequest(home.apps, { - initialData: { - description: '', - icon: '', - name: '', - slug: '', - version: '' - } + initialData: [] }) + +const handleAppOrderChange = async () => { + const slugs = apps.value.map((item: { slug: string }) => item.slug) + await app.updateOrder(slugs) + window.$message.success($gettext('Order updated')) +} const { data: countInfo } = useRequest(home.countInfo, { initialData: { website: 0, @@ -715,41 +717,45 @@ if (import.meta.hot) { - - - - - - - - - - - - - + + {{ $gettext('You have not set any apps to display here!') }} @@ -890,3 +896,52 @@ if (import.meta.hot) { + +