From b5cdd0b362a5cb5ff50895fb083791f1f22ab7b9 Mon Sep 17 00:00:00 2001 From: lijiahang Date: Wed, 10 Jan 2024 19:30:25 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E7=BB=88?= =?UTF-8?q?=E7=AB=AF=E4=BA=A4=E4=BA=92.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/HostTerminalController.http | 5 + .../controller/HostTerminalController.java | 11 +- .../asset/service/HostTerminalService.java | 10 +- .../service/impl/HostTerminalServiceImpl.java | 17 +- .../template/theme/terminal.theme.json | 290 ++++++++++++++++++ .../asset/meta/TerminalThemeFetcher.java | 88 +++--- orion-ops-ui/src/api/asset/host-terminal.ts | 45 ++- .../src/components/view/editor/index.vue | 8 + .../view/shell-editor/shell-editor-modal.vue | 1 + .../src/store/modules/terminal/index.ts | 22 +- .../src/store/modules/terminal/types.ts | 4 +- .../components/layout/terminal-content.vue | 23 +- .../view-setting/terminal-example.vue | 10 +- .../components/xterm/terminal-view.vue | 17 +- .../host/terminal/handler/terminal-channel.ts | 13 +- .../host/terminal/handler/terminal-session.ts | 1 + .../src/views/host/terminal/index.vue | 8 + 17 files changed, 490 insertions(+), 83 deletions(-) create mode 100644 orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/template/theme/terminal.theme.json diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http index 8b3b3399..10149189 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.http @@ -1,3 +1,8 @@ +### 获取主机终端主题 +GET {{baseUrl}}/asset/host-terminal/themes +Authorization: {{token}} + + ### 获取主机终端连接 token GET {{baseUrl}}/asset/host-terminal/access Authorization: {{token}} diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java index 80e1dd4f..4bb55b71 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/HostTerminalController.java @@ -1,5 +1,6 @@ package com.orion.ops.module.asset.controller; +import com.alibaba.fastjson.JSONArray; import com.orion.ops.framework.web.core.annotation.RestWrapper; import com.orion.ops.module.asset.service.HostTerminalService; import io.swagger.v3.oas.annotations.Operation; @@ -32,11 +33,17 @@ public class HostTerminalController { @Resource private HostTerminalService hostTerminalService; + @GetMapping("/themes") + @Operation(summary = "获取主机终端主题") + public JSONArray getTerminalThemes() { + return hostTerminalService.getTerminalThemes(); + } + @GetMapping("/access") @Operation(summary = "获取主机终端 accessToken") @PreAuthorize("@ss.hasPermission('asset:host-terminal:access')") - public String getHostTerminalAccessToken() { - return hostTerminalService.getHostTerminalAccessToken(); + public String getTerminalAccessToken() { + return hostTerminalService.getTerminalAccessToken(); } } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java index 2e952a94..f3944beb 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/HostTerminalService.java @@ -1,5 +1,6 @@ package com.orion.ops.module.asset.service; +import com.alibaba.fastjson.JSONArray; import com.orion.net.host.SessionStore; import com.orion.ops.module.asset.entity.domain.HostDO; import com.orion.ops.module.asset.entity.dto.HostTerminalAccessDTO; @@ -14,12 +15,19 @@ import com.orion.ops.module.asset.entity.dto.HostTerminalConnectDTO; */ public interface HostTerminalService { + /** + * 获取主机终端主题 + * + * @return themes + */ + JSONArray getTerminalThemes(); + /** * 获取主机终端访问 accessToken * * @return accessToken */ - String getHostTerminalAccessToken(); + String getTerminalAccessToken(); /** * 通过 accessToken 获取主机终端访问信息 diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java index 37c8f6c1..0033717d 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostTerminalServiceImpl.java @@ -1,9 +1,11 @@ package com.orion.ops.module.asset.service.impl; +import com.alibaba.fastjson.JSONArray; import com.orion.lang.exception.AuthenticationException; import com.orion.lang.id.UUIds; import com.orion.lang.utils.Exceptions; import com.orion.lang.utils.Strings; +import com.orion.lang.utils.io.StreamReaders; import com.orion.net.host.SessionHolder; import com.orion.net.host.SessionStore; import com.orion.ops.framework.common.constant.Const; @@ -40,6 +42,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.io.InputStream; import java.util.List; import java.util.Optional; @@ -54,6 +57,8 @@ import java.util.Optional; @Service public class HostTerminalServiceImpl implements HostTerminalService { + private static final String TERMINAL_PATH = "/template/theme/terminal.theme.json"; + @Resource private HostConfigService hostConfigService; @@ -82,7 +87,17 @@ public class HostTerminalServiceImpl implements HostTerminalService { private SystemUserApi systemUserApi; @Override - public String getHostTerminalAccessToken() { + public JSONArray getTerminalThemes() { + try (InputStream in = HostTerminalService.class.getResourceAsStream(TERMINAL_PATH)) { + byte[] bytes = StreamReaders.readAllBytes(in); + return JSONArray.parseArray(new String(bytes)); + } catch (Exception e) { + throw Exceptions.ioRuntime(e); + } + } + + @Override + public String getTerminalAccessToken() { LoginUser user = SecurityUtils.getLoginUser(); log.info("HostConnectService.getHostAccessToken userId: {}", user.getId()); String accessToken = UUIds.random19(); diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/template/theme/terminal.theme.json b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/template/theme/terminal.theme.json new file mode 100644 index 00000000..7b82eb01 --- /dev/null +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/template/theme/terminal.theme.json @@ -0,0 +1,290 @@ +[ + { + "name": "catppuccin-macchiato", + "dark": true, + "schema": { + "background": "#24273A", + "foreground": "#CAD3F5", + "cursor": "#F4DBD6", + "selectionBackground": "#5B6078", + "black": "#494D64", + "red": "#ED8796", + "green": "#A6DA95", + "yellow": "#EED49F", + "blue": "#8AADF4", + "cyan": "#8BD5CA", + "white": "#B8C0E0", + "brightBlack": "#5B6078", + "brightRed": "#ED8796", + "brightGreen": "#A6DA95", + "brightYellow": "#EED49F", + "brightBlue": "#8AADF4", + "brightCyan": "#8BD5CA", + "brightWhite": "#A5ADCB" + } + }, + { + "name": "catppuccin-mocha", + "dark": true, + "schema": { + "background": "#1E1E2E", + "foreground": "#CDD6F4", + "cursor": "#F5E0DC", + "selectionBackground": "#585B70", + "black": "#45475A", + "red": "#F38BA8", + "green": "#A6E3A1", + "yellow": "#F9E2AF", + "blue": "#89B4FA", + "cyan": "#94E2D5", + "white": "#BAC2DE", + "brightBlack": "#585B70", + "brightRed": "#F38BA8", + "brightGreen": "#A6E3A1", + "brightYellow": "#F9E2AF", + "brightBlue": "#89B4FA", + "brightCyan": "#94E2D5", + "brightWhite": "#A6ADC8" + } + }, + { + "name": "OneHalfDark", + "dark": true, + "schema": { + "background": "#282C34", + "foreground": "#DCDFE4", + "cursor": "#A3B3CC", + "selectionBackground": "#474E5D", + "black": "#282C34", + "red": "#E06C75", + "green": "#98C379", + "yellow": "#E5C07B", + "blue": "#61AFEF", + "cyan": "#56B6C2", + "white": "#DCDFE4", + "brightBlack": "#282C34", + "brightRed": "#E06C75", + "brightGreen": "#98C379", + "brightYellow": "#E5C07B", + "brightBlue": "#61AFEF", + "brightCyan": "#56B6C2", + "brightWhite": "#DCDFE4" + } + }, + { + "name": "MaterialDesignColors", + "dark": true, + "schema": { + "background": "#1D262A", + "foreground": "#E7EBED", + "cursor": "#EAEAEA", + "selectionBackground": "#4E6A78", + "black": "#435B67", + "red": "#FC3841", + "green": "#5CF19E", + "yellow": "#FED032", + "blue": "#37B6FF", + "cyan": "#59FFD1", + "white": "#FFFFFF", + "brightBlack": "#A1B0B8", + "brightRed": "#FC746D", + "brightGreen": "#ADF7BE", + "brightYellow": "#FEE16C", + "brightBlue": "#70CFFF", + "brightCyan": "#9AFFE6", + "brightWhite": "#FFFFFF" + } + }, + { + "name": "Dracula", + "dark": true, + "schema": { + "background": "#1E1F29", + "foreground": "#F8F8F2", + "cursor": "#BBBBBB", + "selectionBackground": "#44475A", + "black": "#000000", + "red": "#FF5555", + "green": "#50FA7B", + "yellow": "#F1FA8C", + "blue": "#BD93F9", + "cyan": "#8BE9FD", + "white": "#BBBBBB", + "brightBlack": "#555555", + "brightRed": "#FF5555", + "brightGreen": "#50FA7B", + "brightYellow": "#F1FA8C", + "brightBlue": "#BD93F9", + "brightCyan": "#8BE9FD", + "brightWhite": "#FFFFFF" + } + }, + { + "name": "Dracula+", + "dark": true, + "schema": { + "background": "#212121", + "foreground": "#F8F8F2", + "cursor": "#ECEFF4", + "selectionBackground": "#F8F8F2", + "black": "#21222C", + "red": "#FF5555", + "green": "#50FA7B", + "yellow": "#FFCB6B", + "blue": "#82AAFF", + "cyan": "#8BE9FD", + "white": "#F8F8F2", + "brightBlack": "#545454", + "brightRed": "#FF6E6E", + "brightGreen": "#69FF94", + "brightYellow": "#FFCB6B", + "brightBlue": "#D6ACFF", + "brightCyan": "#A4FFFF", + "brightWhite": "#F8F8F2" + } + }, + { + "name": "Apple System Colors", + "dark": true, + "schema": { + "background": "#1E1E1E", + "foreground": "#FFFFFF", + "cursor": "#98989D", + "selectionBackground": "#3F638B", + "black": "#1A1A1A", + "red": "#CC372E", + "green": "#26A439", + "yellow": "#CDAC08", + "blue": "#0869CB", + "cyan": "#479EC2", + "white": "#98989D", + "brightBlack": "#464646", + "brightRed": "#FF453A", + "brightGreen": "#32D74B", + "brightYellow": "#FFD60A", + "brightBlue": "#0A84FF", + "brightCyan": "#76D6FF", + "brightWhite": "#FFFFFF" + } + }, + { + "name": "Builtin Tango Light", + "dark": false, + "schema": { + "background": "#FFFFFF", + "foreground": "#000000", + "cursor": "#000000", + "selectionBackground": "#B5D5FF", + "black": "#000000", + "red": "#CC0000", + "green": "#4E9A06", + "yellow": "#C4A000", + "blue": "#3465A4", + "cyan": "#06989A", + "white": "#D3D7CF", + "brightBlack": "#555753", + "brightRed": "#EF2929", + "brightGreen": "#8AE234", + "brightYellow": "#FCE94F", + "brightBlue": "#729FCF", + "brightCyan": "#34E2E2", + "brightWhite": "#EEEEEC" + } + }, + { + "name": "Duotone Dark", + "dark": true, + "schema": { + "background": "#1F1D27", + "foreground": "#B7A1FF", + "cursor": "#FF9839", + "selectionBackground": "#353147", + "black": "#1F1D27", + "red": "#D9393E", + "green": "#2DCD73", + "yellow": "#D9B76E", + "blue": "#FFC284", + "cyan": "#2488FF", + "white": "#B7A1FF", + "brightBlack": "#353147", + "brightRed": "#D9393E", + "brightGreen": "#2DCD73", + "brightYellow": "#D9B76E", + "brightBlue": "#FFC284", + "brightCyan": "#2488FF", + "brightWhite": "#EAE5FF" + } + }, + { + "name": "BlulocoLight", + "dark": false, + "schema": { + "background": "#F9F9F9", + "foreground": "#373A41", + "cursor": "#F32759", + "selectionBackground": "#DAF0FF", + "black": "#373A41", + "red": "#D52753", + "green": "#23974A", + "yellow": "#DF631C", + "blue": "#275FE4", + "cyan": "#27618D", + "white": "#BABBC2", + "brightBlack": "#676A77", + "brightRed": "#FF6480", + "brightGreen": "#3CBC66", + "brightYellow": "#C5A332", + "brightBlue": "#0099E1", + "brightCyan": "#6D93BB", + "brightWhite": "#D3D3D3" + } + }, + { + "name": "Chester", + "dark": true, + "schema": { + "background": "#2C3643", + "foreground": "#FFFFFF", + "cursor": "#B4B1B1", + "selectionBackground": "#67747C", + "black": "#080200", + "red": "#FA5E5B", + "green": "#16C98D", + "yellow": "#FFC83F", + "blue": "#288AD6", + "cyan": "#28DDDE", + "white": "#E7E7E7", + "brightBlack": "#6F6B68", + "brightRed": "#FA5E5B", + "brightGreen": "#16C98D", + "brightYellow": "#FEEF6D", + "brightBlue": "#278AD6", + "brightCyan": "#27DEDE", + "brightWhite": "#FFFFFF" + } + }, + { + "name": "CLRS", + "dark": false, + "schema": { + "background": "#FFFFFF", + "foreground": "#262626", + "cursor": "#6FD3FC", + "selectionBackground": "#6FD3FC", + "black": "#000000", + "red": "#F8282A", + "green": "#328A5D", + "yellow": "#FA701D", + "blue": "#135CD0", + "cyan": "#33C3C1", + "white": "#B3B3B3", + "brightBlack": "#555753", + "brightRed": "#FB0416", + "brightGreen": "#2CC631", + "brightYellow": "#FDD727", + "brightBlue": "#1670FF", + "brightCyan": "#3AD5CE", + "brightWhite": "#EEEEEC" + } + } +] \ No newline at end of file diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/test/java/com/orion/ops/module/asset/meta/TerminalThemeFetcher.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/test/java/com/orion/ops/module/asset/meta/TerminalThemeFetcher.java index 77b07983..9a458536 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/test/java/com/orion/ops/module/asset/meta/TerminalThemeFetcher.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/test/java/com/orion/ops/module/asset/meta/TerminalThemeFetcher.java @@ -5,16 +5,13 @@ import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.serializer.ValueFilter; import com.orion.lang.utils.Colors; -import com.orion.lang.utils.awt.Clipboards; import com.orion.lang.utils.collect.Lists; import com.orion.lang.utils.io.FileReaders; import com.orion.lang.utils.io.Files1; -import com.orion.lang.utils.reflect.Fields; import lombok.Data; import java.io.File; -import java.lang.reflect.Field; -import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -30,9 +27,14 @@ public class TerminalThemeFetcher { public static void main(String[] args) { List files = Files1.listFiles("D:\\idea-project\\iTerm2-Color-Schemes\\vhs"); // 过滤的 theme - List schemaFilter = new ArrayList<>(); - // List schemaFilter = Lists.of("oneHalf", "material", "github", "iTerm2", "JetBrains"); - // List schemaFilter = Lists.of("catppuccin", "3024", "OneHalfDark", "OneHalfLight", "MaterialDesignColors", "MaterialOcean", "Solarized Light"); + List schemaFilter = Lists.of( + "catppuccin-macchiato", "catppuccin-mocha", + "OneHalfDark", "MaterialDesignColors", + "Dracula", "Dracula+", + "Apple System Colors", "Builtin Tango Light", + "Duotone Dark", "BlulocoLight", + "Chester", "CLRS" + ); // 颜色大写 ValueFilter colorFilter = (Object object, String name, Object value) -> { if (value instanceof String && value.toString().contains("#")) { @@ -44,32 +46,26 @@ public class TerminalThemeFetcher { // 转换 List arr = files.stream() .filter(f -> Lists.isEmpty(schemaFilter) || schemaFilter.stream() - .anyMatch(s -> f.getName().toLowerCase().contains(s.toLowerCase()))) - .limit(200) + .map(s -> s + ".json") + .anyMatch(s -> f.getName().equalsIgnoreCase(s))) .map(f -> { JSONObject schema = JSONObject.parseObject(new String(FileReaders.readAllBytes(f))); - schema.put("dark", Colors.isDarkColor(schema.getString("background"))); schema.put("selectionBackground", schema.getString("selection")); - // 转为对象 - return JSON.parseObject(JSON.toJSONString(schema, colorFilter), TerminalTheme.class); + TerminalTheme theme = new TerminalTheme(); + theme.setName(schema.getString("name")); + theme.setDark(Colors.isDarkColor(schema.getString("background"))); + theme.setSchema(JSON.parseObject(JSON.toJSONString(schema), TerminalThemeSchema.class)); + return theme; }).collect(Collectors.toList()); - + // 排序 + if (!Lists.isEmpty(schemaFilter)) { + arr.sort(Comparator.comparing(s -> schemaFilter.indexOf(s.getName()))); + } // 打印 json String json = JSON.toJSONString(arr, colorFilter); System.out.println("\n\n" + json); - // 转为 jsCode - List formatter = Fields.getFields(TerminalTheme.class) - .stream() - .map(Field::getName) - .collect(Collectors.toList()); - for (String s : formatter) { - json = json.replaceAll("\"" + s + "\"", s); - } - Clipboards.setString(json); - System.out.println("\n\njsCode 已复制到剪切板"); } - // /* var term = new Terminal(); var doc = document.getElementById('themes'); @@ -110,44 +106,50 @@ public class TerminalThemeFetcher { @JSONField(ordinal = 1) private Boolean dark; @JSONField(ordinal = 2) + private TerminalThemeSchema schema; + } + + @Data + public static class TerminalThemeSchema { + @JSONField(ordinal = 0) private String background; - @JSONField(ordinal = 3) + @JSONField(ordinal = 1) private String foreground; - @JSONField(ordinal = 4) + @JSONField(ordinal = 2) private String cursor; - @JSONField(ordinal = 5) + @JSONField(ordinal = 3) private String selectionBackground; - @JSONField(ordinal = 6) + @JSONField(ordinal = 4) private String black; - @JSONField(ordinal = 7) + @JSONField(ordinal = 5) private String red; - @JSONField(ordinal = 8) + @JSONField(ordinal = 6) private String green; - @JSONField(ordinal = 9) + @JSONField(ordinal = 7) private String yellow; - @JSONField(ordinal = 10) + @JSONField(ordinal = 8) private String blue; - @JSONField(ordinal = 11) + @JSONField(ordinal = 9) private String magenta; - @JSONField(ordinal = 12) + @JSONField(ordinal = 10) private String cyan; - @JSONField(ordinal = 13) + @JSONField(ordinal = 11) private String white; - @JSONField(ordinal = 14) + @JSONField(ordinal = 12) private String brightBlack; - @JSONField(ordinal = 15) + @JSONField(ordinal = 13) private String brightRed; - @JSONField(ordinal = 16) + @JSONField(ordinal = 14) private String brightGreen; - @JSONField(ordinal = 17) + @JSONField(ordinal = 15) private String brightYellow; - @JSONField(ordinal = 18) + @JSONField(ordinal = 16) private String brightBlue; - @JSONField(ordinal = 19) + @JSONField(ordinal = 17) private String brightMagenta; - @JSONField(ordinal = 20) + @JSONField(ordinal = 18) private String brightCyan; - @JSONField(ordinal = 21) + @JSONField(ordinal = 19) private String brightWhite; } diff --git a/orion-ops-ui/src/api/asset/host-terminal.ts b/orion-ops-ui/src/api/asset/host-terminal.ts index e3b93c56..cd12c1f1 100644 --- a/orion-ops-ui/src/api/asset/host-terminal.ts +++ b/orion-ops-ui/src/api/asset/host-terminal.ts @@ -1,8 +1,51 @@ import axios from 'axios'; +// 终端主题 +export interface TerminalTheme { + name: string; + dark: boolean; + schema: TerminalThemeSchema; +} + +// 终端主题 schema +export interface TerminalThemeSchema { + background: string; + foreground: string; + cursor: string; + cursorAccent?: string; + selectionBackground?: string; + selectionForeground?: string; + selectionInactiveBackground?: string; + black: string; + red: string; + green: string; + yellow: string; + blue: string; + magenta: string; + cyan: string; + white: string; + brightBlack: string; + brightRed: string; + brightGreen: string; + brightYellow: string; + brightBlue: string; + brightMagenta: string; + brightCyan: string; + brightWhite: string; + + [key: string]: unknown; +} + +/** + * 获取主机终端主题 + */ +export function getTerminalThemes() { + return axios.get>('/asset/host-terminal/themes'); +} + /** * 获取主机终端 accessToken */ -export function getHostTerminalAccessToken() { +export function getTerminalAccessToken() { return axios.get('/asset/host-terminal/access'); } diff --git a/orion-ops-ui/src/components/view/editor/index.vue b/orion-ops-ui/src/components/view/editor/index.vue index b3a7480f..bc09b9cb 100644 --- a/orion-ops-ui/src/components/view/editor/index.vue +++ b/orion-ops-ui/src/components/view/editor/index.vue @@ -43,6 +43,10 @@ type: Boolean, default: false }, + autoFocus: { + type: Boolean, + default: false + }, language: { type: String, default: 'json', @@ -76,6 +80,10 @@ }; // 创建编辑器 editor = monaco.editor.create(editorContainer.value, options); + // 自动聚焦 + if (props.autoFocus) { + editor.focus(); + } // 监听值的变化 editor.onDidChangeModelContent(() => { const value = editor.getValue(); diff --git a/orion-ops-ui/src/components/view/shell-editor/shell-editor-modal.vue b/orion-ops-ui/src/components/view/shell-editor/shell-editor-modal.vue index 06afb00a..29aa77c6 100644 --- a/orion-ops-ui/src/components/view/shell-editor/shell-editor-modal.vue +++ b/orion-ops-ui/src/components/view/shell-editor/shell-editor-modal.vue @@ -14,6 +14,7 @@
diff --git a/orion-ops-ui/src/store/modules/terminal/index.ts b/orion-ops-ui/src/store/modules/terminal/index.ts index 78f3f32b..398fb0fd 100644 --- a/orion-ops-ui/src/store/modules/terminal/index.ts +++ b/orion-ops-ui/src/store/modules/terminal/index.ts @@ -3,9 +3,10 @@ import { defineStore } from 'pinia'; import { getPreference, updatePreference } from '@/api/user/preference'; import { Message } from '@arco-design/web-vue'; import { useDark } from '@vueuse/core'; -import { DEFAULT_SCHEMA } from '@/views/host/terminal/types/terminal.theme'; import TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager'; import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager'; +import type { TerminalTheme } from '@/api/asset/host-terminal'; +import { getTerminalThemes } from '@/api/asset/host-terminal'; // 暗色主题 export const DarkTheme = { @@ -28,7 +29,8 @@ export default defineStore('terminal', { darkTheme: 'auto', newConnectionType: 'group', displaySetting: {} as TerminalDisplaySetting, - themeSchema: {} as TerminalThemeSchema + themeSchema: {} as TerminalThemeSchema, + theme: {} as TerminalTheme }, tabManager: new TerminalTabManager(), sessionManager: new TerminalSessionManager() @@ -38,25 +40,21 @@ export default defineStore('terminal', { // 加载终端偏好 async fetchPreference() { try { + // 加载偏好 const { data } = await getPreference('TERMINAL'); - // 设置默认终端主题 - if (!data.themeSchema?.name) { - data.themeSchema = DEFAULT_SCHEMA; + // theme 不存在则默认加载第一个 + if (!data.theme) { + const { data: themes } = await getTerminalThemes(); + data.theme = themes[0]; } this.preference = data; - // 设置暗色主题 - const userDarkTheme = data.darkTheme; - if (userDarkTheme === DarkTheme.AUTO) { - this.isDarkTheme = data.themeSchema?.dark === true; - } else { - this.isDarkTheme = userDarkTheme === DarkTheme.DARK; - } } catch (e) { Message.error('配置加载失败'); } }, // 修改暗色主题 + // FIXME 删除 terminalDarkTheme async changeDarkTheme(darkTheme: string) { this.preference.darkTheme = darkTheme; if (darkTheme === DarkTheme.DARK) { diff --git a/orion-ops-ui/src/store/modules/terminal/types.ts b/orion-ops-ui/src/store/modules/terminal/types.ts index 5ce222b4..b5a150e5 100644 --- a/orion-ops-ui/src/store/modules/terminal/types.ts +++ b/orion-ops-ui/src/store/modules/terminal/types.ts @@ -1,5 +1,6 @@ import type { Ref } from 'vue'; -import type { ITerminalTabManager, ITerminalSessionManager } from '@/views/host/terminal/types/terminal.type'; +import type { ITerminalSessionManager, ITerminalTabManager } from '@/views/host/terminal/types/terminal.type'; +import type { TerminalTheme } from '@/api/asset/host-terminal'; export interface TerminalState { isDarkTheme: Ref; @@ -13,6 +14,7 @@ export interface TerminalPreference { darkTheme: string; newConnectionType: string; displaySetting: TerminalDisplaySetting; + theme: TerminalTheme; themeSchema: TerminalThemeSchema; } diff --git a/orion-ops-ui/src/views/host/terminal/components/layout/terminal-content.vue b/orion-ops-ui/src/views/host/terminal/components/layout/terminal-content.vue index 042fafc3..2ce41fc6 100644 --- a/orion-ops-ui/src/views/host/terminal/components/layout/terminal-content.vue +++ b/orion-ops-ui/src/views/host/terminal/components/layout/terminal-content.vue @@ -30,11 +30,30 @@ diff --git a/orion-ops-ui/src/views/host/terminal/components/view-setting/terminal-example.vue b/orion-ops-ui/src/views/host/terminal/components/view-setting/terminal-example.vue index 75102a85..7127b3b1 100644 --- a/orion-ops-ui/src/views/host/terminal/components/view-setting/terminal-example.vue +++ b/orion-ops-ui/src/views/host/terminal/components/view-setting/terminal-example.vue @@ -31,11 +31,11 @@ term.value.open(terminal.value); term.value.write( '[root@OrionServer usr]#\r\n' + - 'dr-xr-xr-x. 2 root root bin\r\n' + - 'dr-xr-xr-x. 2 root root sbin\r\n' + - 'dr-xr-xr-x. 43 root root lib\r\n' + - 'dr-xr-xr-x. 62 root root lib64\r\n' + - 'lrwxrwxrwx. 1 root root tmp' + 'dr-xr-xr-x. 2 root root bin\r\n' + + 'dr-xr-xr-x. 2 root root sbin\r\n' + + 'drwxr-xr-x. 89 root root share\r\n' + + 'drwxr-xr-x. 4 root root src\r\n' + + 'lrwxrwxrwx. 1 root root tmp -> ../var/tmp' ); }); diff --git a/orion-ops-ui/src/views/host/terminal/components/xterm/terminal-view.vue b/orion-ops-ui/src/views/host/terminal/components/xterm/terminal-view.vue index 9490e75e..27c0ab3c 100644 --- a/orion-ops-ui/src/views/host/terminal/components/xterm/terminal-view.vue +++ b/orion-ops-ui/src/views/host/terminal/components/xterm/terminal-view.vue @@ -47,7 +47,8 @@ :body-style="{ padding: '16px 16px 16px 0' }" :dark="themeSchema.dark" cancel-text="关闭" - @ok="writeCommand(modal.getValue())" /> + @ok="writeCommand(modal.getValue())" + @cancel="focus" /> @@ -83,17 +84,18 @@ const session = ref(); // FIXME - // 卸载 最外层 terminal 组件, 卸载 style + // 调教 theme // terminal themes 改成非同步 style + // 从后端获取 theme // (改成可配置/拆分) // 自定义 font siderBar 颜色, 集成到主题里面, 现在的问题是切换主题字体颜色就变了 - // 是否开启 link, url 匹配策略 + // 是否开启 link // 是否开启 image // search color 配置 // 右键菜单补充 // 搜索 - // 搜索插件, link插件 // 截屏 + // 最近连接逻辑 偏好逻辑 // 发送命令 const writeCommandInput = async (e: KeyboardEvent) => { @@ -111,6 +113,11 @@ } }; + // 聚焦 + const focus = () => { + session.value?.focus(); + }; + // 右侧操作 const rightActions = computed>(() => [ { @@ -310,7 +317,7 @@ width: 100%; height: 100%; - ::-webkit-scrollbar { + ::-webkit-scrollbar-track { display: none; } } diff --git a/orion-ops-ui/src/views/host/terminal/handler/terminal-channel.ts b/orion-ops-ui/src/views/host/terminal/handler/terminal-channel.ts index 784ca288..11ec3ba5 100644 --- a/orion-ops-ui/src/views/host/terminal/handler/terminal-channel.ts +++ b/orion-ops-ui/src/views/host/terminal/handler/terminal-channel.ts @@ -1,13 +1,6 @@ -import type { - InputPayload, - ITerminalChannel, - ITerminalOutputProcessor, - ITerminalSessionManager, - OutputPayload, - Protocol, -} from '../types/terminal.type'; +import type { InputPayload, ITerminalChannel, ITerminalOutputProcessor, ITerminalSessionManager, OutputPayload, Protocol, } from '../types/terminal.type'; import { OutputProtocol } from '../types/terminal.protocol'; -import { getHostTerminalAccessToken } from '@/api/asset/host-terminal'; +import { getTerminalAccessToken } from '@/api/asset/host-terminal'; import { Message } from '@arco-design/web-vue'; import { sleep } from '@/utils'; import TerminalOutputProcessor from './terminal-output-processor'; @@ -28,7 +21,7 @@ export default class TerminalChannel implements ITerminalChannel { // 初始化 async init() { // 获取 access - const { data: accessToken } = await getHostTerminalAccessToken(); + const { data: accessToken } = await getTerminalAccessToken(); // 打开会话 this.client = new WebSocket(`${wsBase}/host/terminal/${accessToken}`); this.client.onerror = event => { diff --git a/orion-ops-ui/src/views/host/terminal/handler/terminal-session.ts b/orion-ops-ui/src/views/host/terminal/handler/terminal-session.ts index 2a1a3d38..3b795fc1 100644 --- a/orion-ops-ui/src/views/host/terminal/handler/terminal-session.ts +++ b/orion-ops-ui/src/views/host/terminal/handler/terminal-session.ts @@ -70,6 +70,7 @@ export default class TerminalSession implements ITerminalSession { connect(): void { this.status = TerminalStatus.CONNECTED; this.connected = true; + this.inst.focus(); // 注册输入事件 this.inst.onData(s => { if (!this.canWrite) { diff --git a/orion-ops-ui/src/views/host/terminal/index.vue b/orion-ops-ui/src/views/host/terminal/index.vue index 26b0f2e6..3f9e88cd 100644 --- a/orion-ops-ui/src/views/host/terminal/index.vue +++ b/orion-ops-ui/src/views/host/terminal/index.vue @@ -43,6 +43,7 @@ const dictStore = useDictStore(); const cacheStore = useCacheStore(); + const originTitle = document.title; const render = ref(false); // 关闭视口处理 @@ -54,6 +55,9 @@ // 加载用户终端偏好 onBeforeMount(async () => { await terminalStore.fetchPreference(); + // 设置系统主题配色 + const dark = terminalStore.preference.theme.dark; + document.body.setAttribute('terminal-theme', dark ? 'dark' : 'light'); render.value = true; }); @@ -73,6 +77,10 @@ cacheStore.reset('authorizedHostKeys', 'authorizedHostIdentities'); // 移除关闭视口事件 window.removeEventListener('beforeunload', handleBeforeUnload); + // 去除 body style + document.body.removeAttribute('terminal-theme'); + // 重置 title + document.title = originTitle; });