From 7da9171dde8deeaa2a3114de4f558029ad19ce75 Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Sun, 20 Oct 2024 22:20:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8F=92=E4=BB=B6=E4=BC=98=E5=85=88?= =?UTF-8?q?=E7=BA=A7=E6=9B=B4=E6=94=B9=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/api/http/controller/groups/plugins.py | 6 ++ pkg/plugin/manager.py | 15 +++ web/package-lock.json | 19 ++++ web/package.json | 1 + web/src/pages/Plugins.vue | 121 ++++++++++++++++++++-- 5 files changed, 151 insertions(+), 11 deletions(-) diff --git a/pkg/api/http/controller/groups/plugins.py b/pkg/api/http/controller/groups/plugins.py index 22a3e944..26133c29 100644 --- a/pkg/api/http/controller/groups/plugins.py +++ b/pkg/api/http/controller/groups/plugins.py @@ -29,3 +29,9 @@ class PluginsRouterGroup(group.RouterGroup): target_enabled = data.get('target_enabled') await self.ap.plugin_mgr.update_plugin_status(plugin_name, target_enabled) return self.success() + + @self.route('/reorder', methods=['PUT']) + async def _() -> str: + data = await quart.request.json + await self.ap.plugin_mgr.reorder_plugins(data.get('plugins')) + return self.success() diff --git a/pkg/plugin/manager.py b/pkg/plugin/manager.py index bc8f7817..0295ac44 100644 --- a/pkg/plugin/manager.py +++ b/pkg/plugin/manager.py @@ -203,3 +203,18 @@ class PluginManager: return True else: return False + + async def reorder_plugins(self, plugins: list[dict]): + + for plugin in plugins: + plugin_name = plugin.get('name') + plugin_priority = plugin.get('priority') + + for plugin in self.plugins: + if plugin.plugin_name == plugin_name: + plugin.priority = plugin_priority + break + + self.plugins.sort(key=lambda x: x.priority, reverse=True) + + await self.setting.dump_container_setting(self.plugins) diff --git a/web/package-lock.json b/web/package-lock.json index b099d1a2..205a2956 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -20,6 +20,7 @@ "core-js": "^3.37.1", "roboto-fontface": "*", "vue": "^3.4.31", + "vuedraggable": "^4.1.0", "vuetify": "^3.6.11", "vuex": "^4.0.2" }, @@ -4627,6 +4628,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sortablejs": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz", + "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==", + "license": "MIT" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5256,6 +5263,18 @@ "vue": "^3.2.0" } }, + "node_modules/vuedraggable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz", + "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==", + "license": "MIT", + "dependencies": { + "sortablejs": "1.14.0" + }, + "peerDependencies": { + "vue": "^3.0.1" + } + }, "node_modules/vuetify": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.2.tgz", diff --git a/web/package.json b/web/package.json index 71ca5ba8..c02f2737 100644 --- a/web/package.json +++ b/web/package.json @@ -20,6 +20,7 @@ "core-js": "^3.37.1", "roboto-fontface": "*", "vue": "^3.4.31", + "vuedraggable": "^4.1.0", "vuetify": "^3.6.11", "vuex": "^4.0.2" }, diff --git a/web/src/pages/Plugins.vue b/web/src/pages/Plugins.vue index 984cefb7..798d9ad2 100644 --- a/web/src/pages/Plugins.vue +++ b/web/src/pages/Plugins.vue @@ -8,6 +8,40 @@ @@ -17,7 +51,8 @@
- +
@@ -26,9 +61,11 @@ import PageTitle from '@/components/PageTitle.vue' import PluginCard from '@/components/PluginCard.vue' +import draggable from 'vuedraggable' + import { ref, getCurrentInstance, onMounted } from 'vue' -import {inject} from "vue"; +import { inject } from "vue"; const snackbar = inject('snackbar'); @@ -64,19 +101,35 @@ const togglePlugin = (plugin) => { }) } +const isOrchestrationDialogActive = ref(false) +const saveOrder = () => { + // 为所有插件的 priority 赋值,倒序 + plugins.value.forEach(plugin => { + plugin.priority = plugins.value.length - plugins.value.indexOf(plugin) + }) + + proxy.$axios.put('/plugins/reorder', { + plugins: plugins.value + }).then(res => { + refresh() + snackbar.success('插件优先级已保存') + isOrchestrationDialogActive.value = false + }).catch(error => { + snackbar.error(error) + }) +} +#plugin-orchestration-list { + max-height: 20rem; + overflow-y: auto; + margin-inline: 1rem; + width: calc(100% - 2rem); + /* background-color: aqua; */ +} + +#plugin-orchestration-draggable { + display: flex; + flex-direction: column; + align-items: center; +} + +.plugin-orchestration-item { + cursor: move; + width: calc(100% - 2rem); + box-shadow: 0.1rem 0.1rem 0.2rem 0.05rem #ccc; + background-color: #ffffff; + display: flex; + flex-direction: row; + padding: 0.5rem; + justify-content: space-between; +} + +.plugin-orchestration-item-title { + display: flex; + flex-direction: column; +} + +.plugin-orchestration-item-author { + color: #666; + font-size: 0.7rem; +} + +.plugin-orchestration-item-name { + font-size: 1.1rem; + font-weight: 500; +} + +.plugin-orchestration-item-action { + display: flex; + flex-direction: row; + align-items: center; +} + \ No newline at end of file