diff --git a/par-api/src/main/java/com/par/api/controller/ScriptController.java b/par-api/src/main/java/com/par/api/controller/ScriptController.java index 85e586e..323ea85 100644 --- a/par-api/src/main/java/com/par/api/controller/ScriptController.java +++ b/par-api/src/main/java/com/par/api/controller/ScriptController.java @@ -65,6 +65,34 @@ public class ScriptController { return ApiResponse.success(Map.of("version", v)); } + /** 获取站点类型默认脚本(管理员) */ + @GetMapping("/api/v1/admin/scripts/default/{siteType}") + public ApiResponse> getDefaultScript(@PathVariable String siteType, HttpServletRequest request) { + checkAdmin(request); + String script = GroovyScriptEngine.loadDefaultByType(siteType); + return ApiResponse.success(Map.of("siteType", siteType, "script", script != null ? script : "")); + } + + /** 保存站点类型默认脚本(管理员) */ + @PutMapping("/api/v1/admin/scripts/default/{siteType}") + public ApiResponse saveDefaultScript( + @PathVariable String siteType, + @RequestBody Map payload, + HttpServletRequest request) { + checkAdmin(request); + String script = payload.get("script"); + if (script == null || script.isBlank()) return ApiResponse.error(400, "script is required"); + GroovyScriptEngine.saveDefaultScript(siteType, script); + return ApiResponse.success(); + } + + private void checkAdmin(HttpServletRequest request) { + var level = request.getAttribute("trustLevel"); + if (level == null || !"ADMIN".equals(level.toString())) { + throw new IllegalArgumentException("Admin permission required"); + } + } + /** 上传 Groovy 脚本(PSK 签名认证) */ @PutMapping("/api/v1/scripts/{siteId}") public ApiResponse uploadScript( diff --git a/par-core/src/main/java/com/par/core/adapter/GroovyScriptEngine.java b/par-core/src/main/java/com/par/core/adapter/GroovyScriptEngine.java index 52d1855..5ea03a3 100644 --- a/par-core/src/main/java/com/par/core/adapter/GroovyScriptEngine.java +++ b/par-core/src/main/java/com/par/core/adapter/GroovyScriptEngine.java @@ -43,6 +43,23 @@ public class GroovyScriptEngine { return null; // placeholder, 由 AdapterController 实现具体逻辑 } + /** + * 保存站点类型默认脚本到 classpath + */ + public static void saveDefaultScript(String siteType, String script) { + if (siteType == null || script == null) return; + String key = siteType.toLowerCase(); + DEFAULT_SCRIPTS.put(key, script); + try { + var path = java.nio.file.Paths.get( + GroovyScriptEngine.class.getClassLoader().getResource("scripts/default-" + key + ".groovy").toURI()); + java.nio.file.Files.writeString(path, script, java.nio.charset.StandardCharsets.UTF_8); + log.info("Default script saved: default-{}.groovy", key); + } catch (Exception e) { + log.error("Failed to save default script: {}", key, e); + } + } + /** * 从 classpath 加载默认脚本文件 */ diff --git a/web/src/router/index.js b/web/src/router/index.js index 4d480c6..d625535 100644 --- a/web/src/router/index.js +++ b/web/src/router/index.js @@ -68,7 +68,7 @@ const routes = [ path: 'access-results/check/:siteId', name: 'AccessResultCheck', component: () => import('../views/AccessResultCheck.vue'), - meta: { title: '适配校验详情' } + meta: { title: '脚本编辑' } }, { path: 'site-pages', diff --git a/web/src/views/AccessResults.vue b/web/src/views/AccessResults.vue index 20c3294..8f2c383 100644 --- a/web/src/views/AccessResults.vue +++ b/web/src/views/AccessResults.vue @@ -1,7 +1,36 @@