diff --git a/orion-visor-ui/config/plugin/compress.ts b/orion-visor-ui/config/plugin/compress.ts index ccc33340..4db0e0f7 100644 --- a/orion-visor-ui/config/plugin/compress.ts +++ b/orion-visor-ui/config/plugin/compress.ts @@ -2,7 +2,7 @@ import type { Plugin } from 'vite'; import compressPlugin from 'vite-plugin-compression'; /** - * gzip压缩 + * gzip 压缩 * https://github.com/anncwb/vite-plugin-compression */ export default function configCompressPlugin( @@ -19,7 +19,7 @@ export default function configCompressPlugin( }) ); } - + // br 压缩 if (compress === 'brotli') { plugins.push( compressPlugin({ diff --git a/orion-visor-ui/config/vite.config.base.ts b/orion-visor-ui/config/vite.config.base.ts index 7f0d0086..13c118b1 100644 --- a/orion-visor-ui/config/vite.config.base.ts +++ b/orion-visor-ui/config/vite.config.base.ts @@ -32,6 +32,10 @@ export default defineConfig({ find: 'vue', replacement: 'vue/dist/vue.esm-bundler.js', // compile template }, + { + find: 'guacamole-common-js', + replacement: resolve(__dirname, '../libs/guacamole-common-js') + }, ], extensions: ['.ts', '.js'], }, diff --git a/orion-visor-ui/package.json b/orion-visor-ui/package.json index 6af63764..97463716 100644 --- a/orion-visor-ui/package.json +++ b/orion-visor-ui/package.json @@ -67,6 +67,7 @@ "@commitlint/cli": "^17.1.2", "@commitlint/config-conventional": "^17.1.0", "@types/file-saver": "^2.0.7", + "@types/guacamole-common-js": "^1.5.3", "@types/lodash": "^4.14.186", "@types/mockjs": "^1.0.7", "@types/nprogress": "^0.2.0", diff --git a/orion-visor-ui/pnpm-lock.yaml b/orion-visor-ui/pnpm-lock.yaml index 594ebc41..84568601 100644 --- a/orion-visor-ui/pnpm-lock.yaml +++ b/orion-visor-ui/pnpm-lock.yaml @@ -119,6 +119,9 @@ importers: '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 + '@types/guacamole-common-js': + specifier: ^1.5.3 + version: 1.5.3 '@types/lodash': specifier: ^4.14.186 version: 4.17.14 @@ -1181,6 +1184,9 @@ packages: '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + '@types/guacamole-common-js@1.5.3': + resolution: {integrity: sha512-PDW2kRwwIgzw0ys82X65g13+OHRPW4Ek/919vIoacWGEUU8jGGfULmH+6TuufLDGMO0cqXR03nxer8ceRDmy3g==} + '@types/imagemin-gifsicle@7.0.4': resolution: {integrity: sha512-ZghMBd/Jgqg5utTJNPmvf6DkuHzMhscJ8vgf/7MUGCpO+G+cLrhYltL+5d+h3A1B4W73S2SrmJZ1jS5LACpX+A==} @@ -7207,6 +7213,8 @@ snapshots: '@types/minimatch': 5.1.2 '@types/node': 22.10.5 + '@types/guacamole-common-js@1.5.3': {} + '@types/imagemin-gifsicle@7.0.4': dependencies: '@types/imagemin': 7.0.1 @@ -10828,7 +10836,7 @@ snapshots: dependencies: htmlparser2: 3.10.1 postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) postcss-html@1.7.0: dependencies: @@ -10841,7 +10849,7 @@ snapshots: dependencies: '@babel/core': 7.26.0 postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) transitivePeerDependencies: - supports-color @@ -10852,7 +10860,7 @@ snapshots: postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39): dependencies: postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) remark: 10.0.1 unist-util-find-all-after: 1.0.5 @@ -10913,7 +10921,7 @@ snapshots: dependencies: postcss: 8.4.49 - postcss-syntax@0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39): + postcss-syntax@0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39): dependencies: postcss: 7.0.39 optionalDependencies: @@ -11789,7 +11797,7 @@ snapshots: postcss-sass: 0.3.5 postcss-scss: 2.1.1 postcss-selector-parser: 3.1.2 - postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss-html@1.7.0)(postcss@8.4.49))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) postcss-value-parser: 3.3.1 resolve-from: 4.0.0 signal-exit: 3.0.7 diff --git a/orion-visor-ui/src/App.vue b/orion-visor-ui/src/App.vue index 28159b25..f7cdaf84 100644 --- a/orion-visor-ui/src/App.vue +++ b/orion-visor-ui/src/App.vue @@ -2,7 +2,7 @@ - + diff --git a/orion-visor-ui/src/api/asset/host-config.ts b/orion-visor-ui/src/api/asset/host-config.ts index 9cb3b5ef..7a089263 100644 --- a/orion-visor-ui/src/api/asset/host-config.ts +++ b/orion-visor-ui/src/api/asset/host-config.ts @@ -36,6 +36,21 @@ export interface HostSshConfig extends HostBaseConfig { fileContentCharset?: string; } +// 主机 RDP 配置 +export interface HostRdpConfig extends HostBaseConfig { + identityId?: number; + versionGt81?: boolean; + timezone?: string; + keyboardLayout?: string; + clipboardNormalize?: string; + domain?: string; + preConnectionId?: string; + preConnectionBlob?: string; + remoteApp?: string; + remoteAppDir?: string; + remoteAppArgs?: string; +} + /** * 更新主机配置 */ diff --git a/orion-visor-ui/src/api/asset/host-extra.ts b/orion-visor-ui/src/api/asset/host-extra.ts index 8859f585..564d47e2 100644 --- a/orion-visor-ui/src/api/asset/host-extra.ts +++ b/orion-visor-ui/src/api/asset/host-extra.ts @@ -25,6 +25,13 @@ export interface HostSshExtraSettingModel { identityId: number; } +// RDP 额外配置 +export interface HostRdpExtraSettingModel { + authType: string; + identityId: number; + lowBandwidthMode: boolean; +} + // 标签额外配置 export interface HostLabelExtraSettingModel { alias: string; diff --git a/orion-visor-ui/src/api/asset/host.ts b/orion-visor-ui/src/api/asset/host.ts index 772fa21a..08320dd9 100644 --- a/orion-visor-ui/src/api/asset/host.ts +++ b/orion-visor-ui/src/api/asset/host.ts @@ -1,6 +1,6 @@ import type { HostExtraUpdateRequest, HostSpecExtraModel } from './host-extra'; import type { TableData } from '@arco-design/web-vue'; -import type { DataGrid, OrderDirection, Pagination } from '@/types/global'; +import type { DataGrid, FavoriteItem, OrderDirection, Pagination } from '@/types/global'; import axios from 'axios'; import qs from 'query-string'; @@ -58,9 +58,9 @@ export interface HostQueryRequest extends Pagination, OrderDirection { } /** - * 主机查询响应 + * 主机查询基础响应 */ -export interface HostQueryResponse extends TableData, HostQueryResponseExtra { +export interface HostQueryBaseResponse { id: number; types: Array; osType: string; @@ -74,7 +74,12 @@ export interface HostQueryResponse extends TableData, HostQueryResponseExtra { updateTime: number; creator: string; updater: string; - favorite: boolean; +} + +/** + * 主机查询响应 + */ +export interface HostQueryResponse extends HostQueryBaseResponse, TableData, FavoriteItem, HostQueryResponseExtra { alias: string; color: string; tags: Array<{ id: number, name: string }>; diff --git a/orion-visor-ui/src/api/asset/terminal.ts b/orion-visor-ui/src/api/asset/terminal.ts deleted file mode 100644 index 7d9f9d23..00000000 --- a/orion-visor-ui/src/api/asset/terminal.ts +++ /dev/null @@ -1,73 +0,0 @@ -import axios from 'axios'; -import { createAppWebSocket } from '@/utils/http'; - -// 终端主题 -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/terminal/themes'); -} - -/** - * 获取终端 accessToken - */ -export function getTerminalAccessToken() { - return axios.get('/asset/terminal/access'); -} - -/** - * 获取终端 transferToken - */ -export function getTerminalTransferToken() { - return axios.get('/asset/terminal/transfer'); -} - -/** - * 打开终端 websocket - */ -export const openTerminalAccessChannel = (accessToken: string) => { - return createAppWebSocket(`/terminal/access/${accessToken}`); -}; - -/** - * 打开终端传输 websocket - */ -export const openTerminalTransferChannel = (accessToken: string) => { - return createAppWebSocket(`/terminal/transfer/${accessToken}`); -}; diff --git a/orion-visor-ui/src/api/exec/exec-command-log.ts b/orion-visor-ui/src/api/exec/exec-command-log.ts index f50ef515..a823b346 100644 --- a/orion-visor-ui/src/api/exec/exec-command-log.ts +++ b/orion-visor-ui/src/api/exec/exec-command-log.ts @@ -14,35 +14,35 @@ import qs from 'query-string'; * 分页查询批量执行日志 */ export function getExecCommandLogPage(request: ExecLogQueryRequest) { - return axios.post>('/asset/exec-command-log/query', request); + return axios.post>('/exec/exec-command-log/query', request); } /** * 查询批量执行日志 */ export function getExecCommandLog(id: number) { - return axios.get('/asset/exec-command-log/get', { params: { id } }); + return axios.get('/exec/exec-command-log/get', { params: { id } }); } /** * 查询主机计划任务日志 */ export function getExecCommandHostLog(id: number) { - return axios.get('/asset/exec-command-log/get-host', { params: { id } }); + return axios.get('/exec/exec-command-log/get-host', { params: { id } }); } /** * 查询主机批量执行日志 */ export function getExecCommandHostLogList(logId: number) { - return axios.get>('/asset/exec-command-log/host-list', { params: { logId } }); + return axios.get>('/exec/exec-command-log/host-list', { params: { logId } }); } /** * 查询命令执行状态 */ export function getExecCommandLogStatus(idList: Array) { - return axios.get('/asset/exec-command-log/status', { + return axios.get('/exec/exec-command-log/status', { params: { idList }, promptBizErrorMessage: false, promptRequestErrorMessage: false, @@ -56,21 +56,21 @@ export function getExecCommandLogStatus(idList: Array) { * 查询历史批量执行日志 */ export function getExecCommandLogHistory(limit: number) { - return axios.get>('/asset/exec-command-log/history', { params: { page: 1, limit } }); + return axios.get>('/exec/exec-command-log/history', { params: { page: 1, limit } }); } /** * 删除批量执行日志 */ export function deleteExecCommandLog(id: number) { - return axios.delete('/asset/exec-command-log/delete', { params: { id } }); + return axios.delete('/exec/exec-command-log/delete', { params: { id } }); } /** * 批量删除批量执行日志 */ export function batchDeleteExecCommandLog(idList: Array) { - return axios.delete('/asset/exec-command-log/batch-delete', { + return axios.delete('/exec/exec-command-log/batch-delete', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); @@ -82,21 +82,21 @@ export function batchDeleteExecCommandLog(idList: Array) { * 删除主机批量执行日志 */ export function deleteExecCommandHostLog(id: number) { - return axios.delete('/asset/exec-command-log/delete-host', { params: { id } }); + return axios.delete('/exec/exec-command-log/delete-host', { params: { id } }); } /** * 查询批量执行日志数量 */ export function getExecCommandLogCount(request: ExecLogQueryRequest) { - return axios.post('/asset/exec-command-log/count', request); + return axios.post('/exec/exec-command-log/count', request); } /** * 清空批量执行日志 */ export function clearExecCommandLog(request: ExecLogClearRequest) { - return axios.post('/asset/exec-command-log/clear', request, { + return axios.post('/exec/exec-command-log/clear', request, { timeout: 60000, }); } @@ -105,14 +105,14 @@ export function clearExecCommandLog(request: ExecLogClearRequest) { * 查看批量执行日志 */ export function getExecCommandLogTailToken(id: number) { - return axios.get('/asset/exec-command-log/tail', { params: { id } }); + return axios.get('/exec/exec-command-log/tail', { params: { id } }); } /** * 下载批量执行日志文件 */ export function downloadExecCommandLogFile(id: number) { - return axios.get('/asset/exec-command-log/download', { + return axios.get('/exec/exec-command-log/download', { unwrap: true, responseType: 'blob', params: { id }, @@ -123,12 +123,12 @@ export function downloadExecCommandLogFile(id: number) { * 中断执行命令 */ export function interruptExecCommand(request: ExecLogInterruptRequest) { - return axios.put('/asset/exec-command-log/interrupt', request); + return axios.put('/exec/exec-command-log/interrupt', request); } /** * 中断执行主机命令 */ export function interruptHostExecCommand(request: ExecLogInterruptRequest) { - return axios.put('/asset/exec-command-log/interrupt-host', request); + return axios.put('/exec/exec-command-log/interrupt-host', request); } diff --git a/orion-visor-ui/src/api/exec/exec-command.ts b/orion-visor-ui/src/api/exec/exec-command.ts index a4995405..8d96a621 100644 --- a/orion-visor-ui/src/api/exec/exec-command.ts +++ b/orion-visor-ui/src/api/exec/exec-command.ts @@ -18,12 +18,12 @@ export interface ExecCommandRequest { * 批量执行命令 */ export function batchExecCommand(request: ExecCommandRequest) { - return axios.post('/asset/exec-command/exec', request); + return axios.post('/exec/exec-command/exec', request); } /** * 重新执行命令 */ export function reExecCommand(request: ExecCommandRequest) { - return axios.post('/asset/exec-command/re-exec', request); + return axios.post('/exec/exec-command/re-exec', request); } diff --git a/orion-visor-ui/src/api/exec/exec-job-log.ts b/orion-visor-ui/src/api/exec/exec-job-log.ts index 5142e12f..027aee6b 100644 --- a/orion-visor-ui/src/api/exec/exec-job-log.ts +++ b/orion-visor-ui/src/api/exec/exec-job-log.ts @@ -6,7 +6,7 @@ import type { ExecLogQueryRequest, ExecLogQueryResponse, ExecLogStatusResponse, -} from './exec-log'; +} from '../exec/exec-log'; import axios from 'axios'; import qs from 'query-string'; @@ -14,35 +14,35 @@ import qs from 'query-string'; * 分页查询计划任务日志 */ export function getExecJobLogPage(request: ExecLogQueryRequest) { - return axios.post>('/asset/exec-job-log/query', request); + return axios.post>('/exec/exec-job-log/query', request); } /** * 查询计划任务日志 */ export function getExecJobLog(id: number) { - return axios.get('/asset/exec-job-log/get', { params: { id } }); + return axios.get('/exec/exec-job-log/get', { params: { id } }); } /** * 查询主机计划任务日志 */ export function getExecJobHostLog(id: number) { - return axios.get('/asset/exec-job-log/get-host', { params: { id } }); + return axios.get('/exec/exec-job-log/get-host', { params: { id } }); } /** * 查询主机计划任务日志 */ export function getExecJobHostLogList(logId: number) { - return axios.get>('/asset/exec-job-log/host-list', { params: { logId } }); + return axios.get>('/exec/exec-job-log/host-list', { params: { logId } }); } /** * 查询命令执行状态 */ export function getExecJobLogStatus(idList: Array) { - return axios.get('/asset/exec-job-log/status', { + return axios.get('/exec/exec-job-log/status', { params: { idList }, promptBizErrorMessage: false, promptRequestErrorMessage: false, @@ -56,14 +56,14 @@ export function getExecJobLogStatus(idList: Array) { * 删除计划任务日志 */ export function deleteExecJobLog(id: number) { - return axios.delete('/asset/exec-job-log/delete', { params: { id } }); + return axios.delete('/exec/exec-job-log/delete', { params: { id } }); } /** * 批量删除计划任务日志 */ export function batchDeleteExecJobLog(idList: Array) { - return axios.delete('/asset/exec-job-log/batch-delete', { + return axios.delete('/exec/exec-job-log/batch-delete', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); @@ -75,21 +75,21 @@ export function batchDeleteExecJobLog(idList: Array) { * 删除主机计划任务日志 */ export function deleteExecJobHostLog(id: number) { - return axios.delete('/asset/exec-job-log/delete-host', { params: { id } }); + return axios.delete('/exec/exec-job-log/delete-host', { params: { id } }); } /** * 查询计划任务日志数量 */ export function getExecJobLogCount(request: ExecLogQueryRequest) { - return axios.post('/asset/exec-job-log/count', request); + return axios.post('/exec/exec-job-log/count', request); } /** * 清空计划任务日志 */ export function clearExecJobLog(request: ExecLogClearRequest) { - return axios.post('/asset/exec-job-log/clear', request, { + return axios.post('/exec/exec-job-log/clear', request, { timeout: 60000, }); } @@ -98,14 +98,14 @@ export function clearExecJobLog(request: ExecLogClearRequest) { * 查看计划任务日志 */ export function getExecJobLogTailToken(id: number) { - return axios.get('/asset/exec-job-log/tail', { params: { id } }); + return axios.get('/exec/exec-job-log/tail', { params: { id } }); } /** * 下载计划任务日志文件 */ export function downloadExecJobLogFile(id: number) { - return axios.get('/asset/exec-job-log/download', { + return axios.get('/exec/exec-job-log/download', { unwrap: true, responseType: 'blob', params: { id }, @@ -116,12 +116,12 @@ export function downloadExecJobLogFile(id: number) { * 中断计划任务执行 */ export function interruptExecJob(request: ExecLogInterruptRequest) { - return axios.put('/asset/exec-job-log/interrupt', request); + return axios.put('/exec/exec-job-log/interrupt', request); } /** * 中断计划任务执行主机 */ export function interruptHostExecJob(request: ExecLogInterruptRequest) { - return axios.put('/asset/exec-job-log/interrupt-host', request); + return axios.put('/exec/exec-job-log/interrupt-host', request); } diff --git a/orion-visor-ui/src/api/exec/exec-job.ts b/orion-visor-ui/src/api/exec/exec-job.ts index b65b0529..4823c7a8 100644 --- a/orion-visor-ui/src/api/exec/exec-job.ts +++ b/orion-visor-ui/src/api/exec/exec-job.ts @@ -81,63 +81,70 @@ export interface ExecJobQueryResponse extends TableData { * 创建计划任务 */ export function createExecJob(request: ExecJobCreateRequest) { - return axios.post('/asset/exec-job/create', request); + return axios.post('/exec/exec-job/create', request); } /** * 更新计划任务 */ export function updateExecJob(request: ExecJobUpdateRequest) { - return axios.put('/asset/exec-job/update', request); + return axios.put('/exec/exec-job/update', request); } /** * 更新计划任务状态 */ export function updateExecJobStatus(request: ExecJobUpdateStatusRequest) { - return axios.put('/asset/exec-job/update-status', request); + return axios.put('/exec/exec-job/update-status', request); } /** * 更新计划任务执行用户 */ export function updateExecJobExecUser(request: ExecJobUpdateExecUserRequest) { - return axios.put('/asset/exec-job/update-exec-user', request); + return axios.put('/exec/exec-job/update-exec-user', request); } /** * 查询计划任务 */ export function getExecJob(id: number) { - return axios.get('/asset/exec-job/get', { params: { id } }); + return axios.get('/exec/exec-job/get', { params: { id } }); } /** * 查询全部计划任务 */ export function getExecJobList() { - return axios.get>('/asset/exec-job/list'); + return axios.get>('/exec/exec-job/list'); } /** * 分页查询计划任务 */ export function getExecJobPage(request: ExecJobQueryRequest) { - return axios.post>('/asset/exec-job/query', request); + return axios.post>('/exec/exec-job/query', request); +} + +/** + * 查询计划任务数量 + */ +export function getExecJobCount(request: ExecJobQueryRequest) { + return axios.post('/exec/exec-job/count', request); } /** * 删除计划任务 */ export function deleteExecJob(id: number) { - return axios.delete('/asset/exec-job/delete', { params: { id } }); + return axios.delete('/exec/exec-job/delete', { params: { id } }); } /** * 批量删除计划任务 */ export function batchDeleteExecJob(idList: Array) { - return axios.delete('/asset/exec-job/batch-delete', { + return axios.delete('/exec/exec-job/batch-delete', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); @@ -149,5 +156,5 @@ export function batchDeleteExecJob(idList: Array) { * 手动触发计划任务 */ export function triggerExecJob(id: number) { - return axios.post('/asset/exec-job/trigger', { id }); + return axios.post('/exec/exec-job/trigger', { id }); } diff --git a/orion-visor-ui/src/api/exec/exec-template.ts b/orion-visor-ui/src/api/exec/exec-template.ts index 5f9c5731..2b29c83a 100644 --- a/orion-visor-ui/src/api/exec/exec-template.ts +++ b/orion-visor-ui/src/api/exec/exec-template.ts @@ -52,49 +52,56 @@ export interface ExecTemplateQueryResponse extends TableData { * 创建执行模板 */ export function createExecTemplate(request: ExecTemplateCreateRequest) { - return axios.post('/asset/exec-template/create', request); + return axios.post('/exec/exec-template/create', request); } /** * 更新执行模板 */ export function updateExecTemplate(request: ExecTemplateUpdateRequest) { - return axios.put('/asset/exec-template/update', request); + return axios.put('/exec/exec-template/update', request); } /** * 查询执行模板 */ export function getExecTemplate(id: number) { - return axios.get('/asset/exec-template/get', { params: { id } }); + return axios.get('/exec/exec-template/get', { params: { id } }); } /** * 查询执行模板 */ export function getExecTemplateWithAuthorized(id: number) { - return axios.get('/asset/exec-template/get-with-authorized', { params: { id } }); + return axios.get('/exec/exec-template/get-with-authorized', { params: { id } }); } /** * 分页查询执行模板 */ export function getExecTemplatePage(request: ExecTemplateQueryRequest) { - return axios.post>('/asset/exec-template/query', request); + return axios.post>('/exec/exec-template/query', request); +} + +/** + * 查询执行模板数量 + */ +export function getExecTemplateCount(request: ExecTemplateQueryRequest) { + return axios.post('/exec/exec-template/count', request); } /** * 删除执行模板 */ export function deleteExecTemplate(id: number) { - return axios.delete('/asset/exec-template/delete', { params: { id } }); + return axios.delete('/exec/exec-template/delete', { params: { id } }); } /** * 批量删除执行模板 */ export function batchDeleteExecTemplate(idList: Array) { - return axios.delete('/asset/exec-template/batch-delete', { + return axios.delete('/exec/exec-template/batch-delete', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); diff --git a/orion-visor-ui/src/api/exec/upload-task.ts b/orion-visor-ui/src/api/exec/upload-task.ts index eabfddb1..6b9f5837 100644 --- a/orion-visor-ui/src/api/exec/upload-task.ts +++ b/orion-visor-ui/src/api/exec/upload-task.ts @@ -110,48 +110,48 @@ export interface UploadTaskStatusResponse extends TableData { * 创建上传任务 */ export function createUploadTask(request: UploadTaskCreateRequest) { - return axios.post('/asset/upload-task/create', request); + return axios.post('/exec/upload-task/create', request); } /** * 创建上传任务 */ export function startUploadTask(id: number) { - return axios.post('/asset/upload-task/start', { id }); + return axios.post('/exec/upload-task/start', { id }); } /** * 创建上传任务 */ export function cancelUploadTask(id: number, failed: boolean) { - return axios.post('/asset/upload-task/cancel', { id, failed }); + return axios.post('/exec/upload-task/cancel', { id, failed }); } /** * 查询上传任务 */ export function getUploadTask(id: number) { - return axios.get('/asset/upload-task/get', { params: { id } }); + return axios.get('/exec/upload-task/get', { params: { id } }); } /** * 分页查询上传任务 */ export function getUploadTaskPage(request: UploadTaskQueryRequest) { - return axios.post>('/asset/upload-task/query', request); + return axios.post>('/exec/upload-task/query', request); } /** * 查询上传任务状态 */ export function getUploadTaskStatus(idList: Array, queryFiles: boolean) { - return axios.get>('/asset/upload-task/status', { + return axios.get>('/exec/upload-task/status', { params: { idList, queryFiles }, promptBizErrorMessage: false, promptRequestErrorMessage: false, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); - } + }, }); } @@ -159,14 +159,14 @@ export function getUploadTaskStatus(idList: Array, queryFiles: boolean) * 删除上传任务 */ export function deleteUploadTask(id: number) { - return axios.delete('/asset/upload-task/delete', { params: { id } }); + return axios.delete('/exec/upload-task/delete', { params: { id } }); } /** * 批量删除上传任务 */ export function batchDeleteUploadTask(idList: Array) { - return axios.delete('/asset/upload-task/batch-delete', { + return axios.delete('/exec/upload-task/batch-delete', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); @@ -178,14 +178,14 @@ export function batchDeleteUploadTask(idList: Array) { * 查询批量上传任务数量 */ export function getUploadTaskCount(request: UploadTaskQueryRequest) { - return axios.post('/asset/upload-task/count', request); + return axios.post('/exec/upload-task/count', request); } /** - * 清空查询批量上传任务 + * 清空批量上传任务 */ export function clearUploadTask(request: UploadTaskClearRequest) { - return axios.post('/asset/upload-task/clear', request, { + return axios.post('/exec/upload-task/clear', request, { timeout: 60000, }); } diff --git a/orion-visor-ui/src/api/statistics/asset-statistics.ts b/orion-visor-ui/src/api/statistics/asset-statistics.ts index 4a904af8..e04a5f43 100644 --- a/orion-visor-ui/src/api/statistics/asset-statistics.ts +++ b/orion-visor-ui/src/api/statistics/asset-statistics.ts @@ -1,26 +1,9 @@ -import type { LineSingleChartData } from '@/types/global'; -import type { TerminalConnectLogQueryResponse } from '@/api/asset/terminal-connect-log'; -import type { ExecLogQueryResponse } from '@/api/exec/exec-log'; +import type { PieChartData } from '@/types/global'; import axios from 'axios'; /** - * 资产模块工作台响应 + * 查询主机类型图表 */ -export interface AssetWorkplaceStatisticsResponse { - execJobCount: number; - todayTerminalConnectCount: number; - todayExecCommandCount: number; - weekTerminalConnectCount: number; - weekExecCommandCount: number; - execCommandChart: LineSingleChartData; - terminalConnectChart: LineSingleChartData; - terminalConnectList: Array; - execLogList: Array; -} - -/** - * 查询资产模块工作台统计信息 - */ -export function getAssetWorkplaceStatisticsData() { - return axios.get('/asset/statistics/get-workplace'); +export function getHostTypeChart() { + return axios.get('/asset/statistics/host-type-chart'); } diff --git a/orion-visor-ui/src/api/statistics/exec-statistics.ts b/orion-visor-ui/src/api/statistics/exec-statistics.ts new file mode 100644 index 00000000..8a70e40d --- /dev/null +++ b/orion-visor-ui/src/api/statistics/exec-statistics.ts @@ -0,0 +1,21 @@ +import type { LineSingleChartData } from '@/types/global'; +import type { ExecLogQueryResponse } from '@/api/exec/exec-log'; +import axios from 'axios'; + +/** + * 执行模块工作台响应 + */ +export interface ExecWorkplaceStatisticsResponse { + execJobCount: number; + todayExecCommandCount: number; + weekExecCommandCount: number; + execCommandChart: LineSingleChartData; + execLogList: Array; +} + +/** + * 查询执行模块工作台统计信息 + */ +export function getExecWorkplaceStatisticsData() { + return axios.get('/exec/statistics/get-workplace'); +} diff --git a/orion-visor-ui/src/api/statistics/terminal-statistics.ts b/orion-visor-ui/src/api/statistics/terminal-statistics.ts new file mode 100644 index 00000000..0790ad57 --- /dev/null +++ b/orion-visor-ui/src/api/statistics/terminal-statistics.ts @@ -0,0 +1,23 @@ +import type { LineSingleChartData } from '@/types/global'; +import type { TerminalConnectLogQueryResponse } from '@/api/terminal/terminal-connect-log'; +import axios from 'axios'; + +/** + * 终端模块工作台响应 + */ +export interface TerminalWorkplaceStatisticsResponse { + todayTerminalConnectCount: number; + todayTerminalCommandCount: number; + weekTerminalConnectCount: number; + weekTerminalCommandCount: number; + terminalConnectChart: LineSingleChartData; + terminalCommandChart: LineSingleChartData; + terminalConnectList: Array; +} + +/** + * 查询终端模块工作台统计信息 + */ +export function getTerminalWorkplaceStatisticsData() { + return axios.get('/terminal/statistics/get-workplace'); +} diff --git a/orion-visor-ui/src/api/system/dict-value.ts b/orion-visor-ui/src/api/system/dict-value.ts index 222cd4d8..a5aef100 100644 --- a/orion-visor-ui/src/api/system/dict-value.ts +++ b/orion-visor-ui/src/api/system/dict-value.ts @@ -1,4 +1,4 @@ -import type { DataGrid, Options, OrderDirection, Pagination } from '@/types/global'; +import type { DataGrid, OrderDirection, Options, Pagination } from '@/types/global'; import type { TableData } from '@arco-design/web-vue'; import axios from 'axios'; import qs from 'query-string'; diff --git a/orion-visor-ui/src/api/asset/command-snippet-group.ts b/orion-visor-ui/src/api/terminal/command-snippet-group.ts similarity index 74% rename from orion-visor-ui/src/api/asset/command-snippet-group.ts rename to orion-visor-ui/src/api/terminal/command-snippet-group.ts index ca6eac17..14ecb0e0 100644 --- a/orion-visor-ui/src/api/asset/command-snippet-group.ts +++ b/orion-visor-ui/src/api/terminal/command-snippet-group.ts @@ -28,27 +28,27 @@ export interface CommandSnippetGroupQueryResponse { * 创建命令片段分组 */ export function createCommandSnippetGroup(request: CommandSnippetGroupCreateRequest) { - return axios.post('/asset/command-snippet-group/create', request); + return axios.post('/terminal/command-snippet-group/create', request); } /** * 更新命令片段分组 */ export function updateCommandSnippetGroup(request: CommandSnippetGroupUpdateRequest) { - return axios.put('/asset/command-snippet-group/update', request); + return axios.put('/terminal/command-snippet-group/update', request); } /** * 查询全部命令片段分组 */ export function getCommandSnippetGroupList() { - return axios.get>('/asset/command-snippet-group/list'); + return axios.get>('/terminal/command-snippet-group/list'); } /** * 删除命令片段分组 */ export function deleteCommandSnippetGroup(id: number) { - return axios.delete('/asset/command-snippet-group/delete', { params: { id } }); + return axios.delete('/terminal/command-snippet-group/delete', { params: { id } }); } diff --git a/orion-visor-ui/src/api/asset/command-snippet.ts b/orion-visor-ui/src/api/terminal/command-snippet.ts similarity index 80% rename from orion-visor-ui/src/api/asset/command-snippet.ts rename to orion-visor-ui/src/api/terminal/command-snippet.ts index b78aa06a..a608ddb9 100644 --- a/orion-visor-ui/src/api/asset/command-snippet.ts +++ b/orion-visor-ui/src/api/terminal/command-snippet.ts @@ -43,26 +43,26 @@ export interface CommandSnippetWrapperResponse { * 创建命令片段 */ export function createCommandSnippet(request: CommandSnippetCreateRequest) { - return axios.post('/asset/command-snippet/create', request); + return axios.post('/terminal/command-snippet/create', request); } /** * 更新命令片段 */ export function updateCommandSnippet(request: CommandSnippetUpdateRequest) { - return axios.put('/asset/command-snippet/update', request); + return axios.put('/terminal/command-snippet/update', request); } /** * 查询全部命令片段 */ export function getCommandSnippetList() { - return axios.get('/asset/command-snippet/list'); + return axios.get('/terminal/command-snippet/list'); } /** * 删除命令片段 */ export function deleteCommandSnippet(id: number) { - return axios.delete('/asset/command-snippet/delete', { params: { id } }); + return axios.delete('/terminal/command-snippet/delete', { params: { id } }); } diff --git a/orion-visor-ui/src/api/asset/path-bookmark-group.ts b/orion-visor-ui/src/api/terminal/path-bookmark-group.ts similarity index 74% rename from orion-visor-ui/src/api/asset/path-bookmark-group.ts rename to orion-visor-ui/src/api/terminal/path-bookmark-group.ts index 2fe570c6..90021a40 100644 --- a/orion-visor-ui/src/api/asset/path-bookmark-group.ts +++ b/orion-visor-ui/src/api/terminal/path-bookmark-group.ts @@ -28,27 +28,27 @@ export interface PathBookmarkGroupQueryResponse { * 创建路径书签分组 */ export function createPathBookmarkGroup(request: PathBookmarkGroupCreateRequest) { - return axios.post('/asset/path-bookmark-group/create', request); + return axios.post('/terminal/path-bookmark-group/create', request); } /** * 更新路径书签分组 */ export function updatePathBookmarkGroup(request: PathBookmarkGroupUpdateRequest) { - return axios.put('/asset/path-bookmark-group/update', request); + return axios.put('/terminal/path-bookmark-group/update', request); } /** * 查询全部路径书签分组 */ export function getPathBookmarkGroupList() { - return axios.get>('/asset/path-bookmark-group/list'); + return axios.get>('/terminal/path-bookmark-group/list'); } /** * 删除路径书签分组 */ export function deletePathBookmarkGroup(id: number) { - return axios.delete('/asset/path-bookmark-group/delete', { params: { id } }); + return axios.delete('/terminal/path-bookmark-group/delete', { params: { id } }); } diff --git a/orion-visor-ui/src/api/asset/path-bookmark.ts b/orion-visor-ui/src/api/terminal/path-bookmark.ts similarity index 81% rename from orion-visor-ui/src/api/asset/path-bookmark.ts rename to orion-visor-ui/src/api/terminal/path-bookmark.ts index 37cb7636..17d616bf 100644 --- a/orion-visor-ui/src/api/asset/path-bookmark.ts +++ b/orion-visor-ui/src/api/terminal/path-bookmark.ts @@ -45,26 +45,26 @@ export interface PathBookmarkWrapperResponse { * 创建路径标签 */ export function createPathBookmark(request: PathBookmarkCreateRequest) { - return axios.post('/asset/path-bookmark/create', request); + return axios.post('/terminal/path-bookmark/create', request); } /** * 更新路径标签 */ export function updatePathBookmark(request: PathBookmarkUpdateRequest) { - return axios.put('/asset/path-bookmark/update', request); + return axios.put('/terminal/path-bookmark/update', request); } /** * 分页查询路径标签 */ export function getPathBookmarkList() { - return axios.get('/asset/path-bookmark/list'); + return axios.get('/terminal/path-bookmark/list'); } /** * 删除路径标签 */ export function deletePathBookmark(id: number) { - return axios.delete('/asset/path-bookmark/delete', { params: { id } }); + return axios.delete('/terminal/path-bookmark/delete', { params: { id } }); } diff --git a/orion-visor-ui/src/api/asset/terminal-connect-log.ts b/orion-visor-ui/src/api/terminal/terminal-connect-log.ts similarity index 80% rename from orion-visor-ui/src/api/asset/terminal-connect-log.ts rename to orion-visor-ui/src/api/terminal/terminal-connect-log.ts index 4e1984e1..40d3a92d 100644 --- a/orion-visor-ui/src/api/asset/terminal-connect-log.ts +++ b/orion-visor-ui/src/api/terminal/terminal-connect-log.ts @@ -46,6 +46,7 @@ export interface TerminalConnectLogQueryResponse extends TableData { */ export interface TerminalConnectLogExtra { traceId: string; + channel: string; channelId: string; sessionId: string; address: string; @@ -58,21 +59,21 @@ export interface TerminalConnectLogExtra { * 分页查询终端连接日志 */ export function getTerminalConnectLogPage(request: TerminalConnectLogQueryRequest) { - return axios.post>('/asset/terminal-connect-log/query', request); + return axios.post>('/terminal/terminal-connect-log/query', request); } /** * 查询全部终端连接会话 */ export function getTerminalConnectSessions(request: TerminalConnectLogQueryRequest) { - return axios.post>('/asset/terminal-connect-log/sessions', request); + return axios.post>('/terminal/terminal-connect-log/sessions', request); } /** * 查询用户最近连接的主机 */ export function getLatestConnectHostId(type: string, limit: number) { - return axios.post>('/asset/terminal-connect-log/latest-connect', { + return axios.post>('/terminal/terminal-connect-log/latest-connect', { type, limit }); @@ -82,7 +83,7 @@ export function getLatestConnectHostId(type: string, limit: number) { * 删除终端连接日志 */ export function deleteTerminalConnectLog(idList: Array) { - return axios.delete('/asset/terminal-connect-log/delete', { + return axios.delete('/terminal/terminal-connect-log/delete', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); @@ -94,14 +95,14 @@ export function deleteTerminalConnectLog(idList: Array) { * 查询终端连接日志数量 */ export function getTerminalConnectLogCount(request: TerminalConnectLogQueryRequest) { - return axios.post('/asset/terminal-connect-log/count', request); + return axios.post('/terminal/terminal-connect-log/count', request); } /** * 清空终端连接日志 */ export function clearTerminalConnectLog(request: TerminalConnectLogClearRequest) { - return axios.post('/asset/terminal-connect-log/clear', request, { + return axios.post('/terminal/terminal-connect-log/clear', request, { timeout: 60000, }); } @@ -110,5 +111,5 @@ export function clearTerminalConnectLog(request: TerminalConnectLogClearRequest) * 强制断开终端连接 */ export function hostForceOffline(request: TerminalConnectLogQueryRequest) { - return axios.put('/asset/terminal-connect-log/force-offline', request); + return axios.put('/terminal/terminal-connect-log/force-offline', request); } diff --git a/orion-visor-ui/src/api/asset/terminal-sftp.ts b/orion-visor-ui/src/api/terminal/terminal-sftp.ts similarity index 75% rename from orion-visor-ui/src/api/asset/terminal-sftp.ts rename to orion-visor-ui/src/api/terminal/terminal-sftp.ts index b42f12cc..07b43053 100644 --- a/orion-visor-ui/src/api/asset/terminal-sftp.ts +++ b/orion-visor-ui/src/api/terminal/terminal-sftp.ts @@ -48,14 +48,21 @@ export interface TerminalSftpLogExtra { * 分页查询 SFTP 操作日志 */ export function getTerminalSftpLogPage(request: TerminalSftpLogQueryRequest) { - return axios.post>('/asset/terminal-sftp/query-log', request); + return axios.post>('/terminal/terminal-sftp/query-log', request); +} + +/** + * 查询 SFTP 操作日志数量 + */ +export function getTerminalSftpLogCount(request: TerminalSftpLogQueryRequest) { + return axios.post('/terminal/terminal-sftp/log-count', request); } /** * 删除 SFTP 操作日志 */ export function deleteTerminalSftpLog(idList: Array) { - return axios.delete('/asset/terminal-sftp/delete-log', { + return axios.delete('/terminal/terminal-sftp/delete-log', { params: { idList }, paramsSerializer: params => { return qs.stringify(params, { arrayFormat: 'comma' }); @@ -67,7 +74,7 @@ export function deleteTerminalSftpLog(idList: Array) { * 获取 SFTP 文件内容 */ export function getSftpFileContent(token: string) { - return axios.get('/asset/terminal-sftp/get-content', { + return axios.get('/terminal/terminal-sftp/get-content', { unwrap: true, params: { token }, timeout: 60000 @@ -81,7 +88,7 @@ export function setSftpFileContent(token: string, content: string) { const formData = new FormData(); formData.append('token', token); formData.append('file', new File([content], Date.now() + '', { type: 'text/plain' })); - return axios.post('/asset/terminal-sftp/set-content', formData, { + return axios.post('/terminal/terminal-sftp/set-content', formData, { timeout: 60000, headers: { 'Content-Type': 'multipart/form-data' @@ -93,5 +100,5 @@ export function setSftpFileContent(token: string, content: string) { * 下载文件 */ export function getDownloadTransferUrl(channelId: string, transferToken: string) { - return `${httpBaseUrl}/asset/terminal-sftp/download?channelId=${channelId}&transferToken=${transferToken}`; + return `${httpBaseUrl}/terminal/terminal-sftp/download?channelId=${channelId}&transferToken=${transferToken}`; } diff --git a/orion-visor-ui/src/api/terminal/terminal.ts b/orion-visor-ui/src/api/terminal/terminal.ts new file mode 100644 index 00000000..bca36e55 --- /dev/null +++ b/orion-visor-ui/src/api/terminal/terminal.ts @@ -0,0 +1,46 @@ +import type { TerminalTheme } from '@/views/terminal/interfaces'; +import axios from 'axios'; +import { createAppWebSocket } from '@/utils/http'; + +// 终端访问请求 +export interface TerminalAccessRequest { + hostId?: number; + connectType?: string; + extra?: Record; +} + +/** + * 获取主机终端主题 + */ +export function getTerminalThemes() { + return axios.get>('/terminal/terminal/themes'); +} + +/** + * 获取主机终端 accessToken + */ +export function getTerminalAccessToken(request: TerminalAccessRequest) { + return axios.post('/terminal/terminal/access', request); +} + +/** + * 获取主机终端 transferToken + */ +export function getTerminalTransferToken() { + return axios.get('/terminal/terminal/transfer'); +} + +/** + * 打开主机终端 websocket + */ +export const openTerminalAccessChannel = (protocol: string, accessToken: string) => { + return createAppWebSocket(`/terminal/access/${protocol}/${accessToken}`); +}; + +/** + * 打开主机传输 websocket + */ +export const openTerminalTransferChannel = (accessToken: string) => { + return createAppWebSocket(`/terminal/transfer/${accessToken}`); +}; + diff --git a/orion-visor-ui/src/api/user/role.ts b/orion-visor-ui/src/api/user/role.ts index f1414f8a..100eded2 100644 --- a/orion-visor-ui/src/api/user/role.ts +++ b/orion-visor-ui/src/api/user/role.ts @@ -19,14 +19,6 @@ export interface RoleUpdateRequest extends RoleCreateRequest { id?: number; } -/** - * 角色 分配绑定请求 - */ -export interface RoleGrantMenuRequest extends RoleCreateRequest { - roleId: number; - menuIdList: Array; -} - /** * 角色查询请求 */ @@ -38,6 +30,14 @@ export interface RoleQueryRequest extends Pagination, OrderDirection { description?: string; } +/** + * 角色 分配绑定请求 + */ +export interface RoleGrantMenuRequest extends RoleCreateRequest { + roleId: number; + menuIdList: Array; +} + /** * 角色查询响应 */ diff --git a/orion-visor-ui/src/api/user/user.ts b/orion-visor-ui/src/api/user/user.ts index d682ebe5..fbcd1647 100644 --- a/orion-visor-ui/src/api/user/user.ts +++ b/orion-visor-ui/src/api/user/user.ts @@ -34,11 +34,9 @@ export interface UserQueryRequest extends Pagination, OrderDirection { username?: string; password?: string; nickname?: string; - avatar?: string; mobile?: string; email?: string; status?: number; - lastLoginTime?: string; description?: string; } @@ -158,6 +156,13 @@ export function getUserPage(request: UserQueryRequest) { return axios.post>('/infra/system-user/query', request); } +/** + * 查询用户数量 + */ +export function getUserCount(request: UserQueryRequest) { + return axios.post('/infra/system-user/count', request); +} + /** * 通过 id 删除用户 */ diff --git a/orion-visor-ui/src/assets/style/global.less b/orion-visor-ui/src/assets/style/global.less index 03c2cd50..105f2ba8 100644 --- a/orion-visor-ui/src/assets/style/global.less +++ b/orion-visor-ui/src/assets/style/global.less @@ -205,6 +205,10 @@ body { padding-bottom: 8px; } +.pb12 { + padding-bottom: 12px; +} + .px8 { padding-left: 8px; padding-right: 8px; diff --git a/orion-visor-ui/src/assets/style/host-terminal-layout.less b/orion-visor-ui/src/assets/style/host-terminal-layout.less index 6a5c9396..090d5bf3 100644 --- a/orion-visor-ui/src/assets/style/host-terminal-layout.less +++ b/orion-visor-ui/src/assets/style/host-terminal-layout.less @@ -1,7 +1,7 @@ // 亮色主题配色常量 body { --color-bg-header: #232323; - --color-bg-sidebar: #EBEBEB; + --color-bg-sidebar: #E3E6E9; --color-bg-panel: var(--color-bg-sidebar); --color-bg-content: #FEFEFE; --color-sidebar-icon: #737070; @@ -17,7 +17,7 @@ body { --color-bg-panel-tabs: var(--color-bg-panel); --color-bg-panel-tabs-active: #F9F9F9; --color-bg-panel-icon-1: #F5F5F5; - --color-bg-panel-bar: #F0F0F0; + --color-bg-panel-bar: #F1F2F3; --color-panel-text-1: var(--color-content-text-1); --color-panel-text-2: var(--color-content-text-3); --color-panel-gradient-start: rgba(218, 218, 218, 1); @@ -32,12 +32,14 @@ body { --search-bg-icon-hover-focus: rgba(12, 12, 12, .08); --search-bg-icon-selected: rgba(12, 12, 12, .06); --search-bg-icon-selected-focus: rgba(12, 12, 12, .10); + --color-bg-rdp-toolbar: rgba(255, 255, 255, .4); + --color-bg-rdp-toolbar-hover: rgba(255, 255, 255, .6); } // 暗色主题配色常量 body[terminal-theme='dark'] { --color-bg-header: #232323; - --color-bg-sidebar: #2C2E31; + --color-bg-sidebar: #2A2A2A; --color-bg-panel: var(--color-bg-sidebar); --color-bg-content: #1A1B1C; --color-sidebar-icon: #C3C6C9; @@ -53,7 +55,7 @@ body[terminal-theme='dark'] { --color-bg-panel-tabs: var(--color-bg-panel); --color-bg-panel-tabs-active: #383838; --color-bg-panel-icon-1: var(--color-bg-panel-tabs-active); - --color-bg-panel-bar: #323538; + --color-bg-panel-bar: #343434; --color-panel-text-1: var(--color-content-text-1); --color-panel-text-2: var(--color-content-text-3); --color-panel-gradient-start: rgba(38, 38, 38, 1); diff --git a/orion-visor-ui/src/hooks/copy.ts b/orion-visor-ui/src/hooks/copy.ts index 08ea28dd..6efe9fa9 100644 --- a/orion-visor-ui/src/hooks/copy.ts +++ b/orion-visor-ui/src/hooks/copy.ts @@ -18,7 +18,7 @@ export const copy = async (value: string | undefined, tips: string | boolean = ` }; // 获取剪切板内容 -export const readText = () => { +export const readText = (tips: boolean = true) => { if (navigator.clipboard) { return navigator.clipboard.readText(); } else { @@ -30,7 +30,7 @@ export const readText = () => { textarea.select(); try { const success = document.execCommand('paste'); - if (!success) { + if (!success && tips) { Message.error('当前环境无法读取剪切板内容'); } resolve(textarea.value); diff --git a/orion-visor-ui/src/hooks/favorite.ts b/orion-visor-ui/src/hooks/favorite.ts index 6ea2955c..060e9615 100644 --- a/orion-visor-ui/src/hooks/favorite.ts +++ b/orion-visor-ui/src/hooks/favorite.ts @@ -1,31 +1,37 @@ +import type { FavoriteItem } from '@/types/global'; import type { FavoriteType } from '@/api/meta/favorite'; import { addFavorite, cancelFavorite } from '@/api/meta/favorite'; import { ref } from 'vue'; export default function useFavorite(type: FavoriteType) { const loading = ref(false); - const toggle = async (record: any, id: number, cancelField = 'favorite') => { + + const toggle = async (record: T, id: number) => { + // 防抖 + if (loading.value) { + return; + } const request = { relId: id, type }; try { loading.value = true; - if (record[cancelField]) { + if (record.favorite) { // 取消收藏 await cancelFavorite(request); - record[cancelField] = false; + record.favorite = false; } else { // 添加收藏 await addFavorite(request); - record[cancelField] = true; + record.favorite = true; } } catch (e) { } finally { loading.value = false; } }; + return { loading, toggle }; } - diff --git a/orion-visor-ui/src/hooks/limit.ts b/orion-visor-ui/src/hooks/limit.ts new file mode 100644 index 00000000..920382d6 --- /dev/null +++ b/orion-visor-ui/src/hooks/limit.ts @@ -0,0 +1,26 @@ +import { ref } from 'vue'; +import { Message } from '@arco-design/web-vue'; + +export default function useLimit(limit = 500) { + const last = ref(0); + + const checkLimited = (tips: string | boolean = true) => { + const now = Date.now(); + if (now > last.value + limit) { + last.value = now; + return true; + } else { + if (tips === true) { + Message.error('操作频率过快, 请稍后再试'); + } else if (tips) { + Message.error(tips); + } + return false; + } + }; + + return { + last, + checkLimited, + }; +} diff --git a/orion-visor-ui/src/router/routes/modules/asset-audit.ts b/orion-visor-ui/src/router/routes/modules/asset-audit.ts index 5f1554e8..37a0aca4 100644 --- a/orion-visor-ui/src/router/routes/modules/asset-audit.ts +++ b/orion-visor-ui/src/router/routes/modules/asset-audit.ts @@ -1,27 +1,29 @@ import type { AppRouteRecordRaw } from '../types'; import { DEFAULT_LAYOUT } from '../base'; -const ASSET_AUDIT: AppRouteRecordRaw = { - name: 'assetAuditModule', - path: '/asset-audit-module', - component: DEFAULT_LAYOUT, - children: [ - { - name: 'connectLog', - path: '/audit/connect-log', - component: () => import('@/views/asset-audit/connect-log/index.vue'), - }, - { - name: 'connectSession', - path: '/audit/connect-session', - component: () => import('@/views/asset-audit/connect-session/index.vue'), - }, - { - name: 'sftpLog', - path: '/audit/sftp-log', - component: () => import('@/views/asset-audit/sftp-log/index.vue'), - }, - ], -}; +const ASSET_AUDIT: AppRouteRecordRaw[] = [ + { + name: 'assetAuditModule', + path: '/asset-audit-module', + component: DEFAULT_LAYOUT, + children: [ + { + name: 'connectLog', + path: '/audit/connect-log', + component: () => import('@/views/asset-audit/connect-log/index.vue'), + }, + { + name: 'connectSession', + path: '/audit/connect-session', + component: () => import('@/views/asset-audit/connect-session/index.vue'), + }, + { + name: 'sftpLog', + path: '/audit/sftp-log', + component: () => import('@/views/asset-audit/sftp-log/index.vue'), + }, + ], + }, +]; export default ASSET_AUDIT; diff --git a/orion-visor-ui/src/router/routes/modules/exec.ts b/orion-visor-ui/src/router/routes/modules/exec.ts index ec68a96e..bc012b4c 100644 --- a/orion-visor-ui/src/router/routes/modules/exec.ts +++ b/orion-visor-ui/src/router/routes/modules/exec.ts @@ -43,7 +43,8 @@ const EXEC: Array = [ component: () => import('@/views/exec/exec-template/index.vue'), }, ], - }, { + }, + { name: 'execFullModule', path: '/exec-full-module', component: FULL_LAYOUT, diff --git a/orion-visor-ui/src/router/routes/modules/host.ts b/orion-visor-ui/src/router/routes/modules/terminal.ts similarity index 58% rename from orion-visor-ui/src/router/routes/modules/host.ts rename to orion-visor-ui/src/router/routes/modules/terminal.ts index 1b216f17..4be6031d 100644 --- a/orion-visor-ui/src/router/routes/modules/host.ts +++ b/orion-visor-ui/src/router/routes/modules/terminal.ts @@ -1,15 +1,15 @@ import type { AppRouteRecordRaw } from '../types'; import { FULL_LAYOUT } from '../base'; -const HOST: AppRouteRecordRaw = { - name: 'hostModule', - path: '/host-module', +const TERMINAL: AppRouteRecordRaw = { + name: 'terminalModule', + path: '/terminal-module', component: FULL_LAYOUT, children: [ { name: 'terminal', path: '/terminal', - component: () => import('@/views/host/terminal/index.vue'), + component: () => import('@/views/terminal/index.vue'), meta: { noAffix: true } @@ -17,4 +17,4 @@ const HOST: AppRouteRecordRaw = { ], }; -export default HOST; +export default TERMINAL; diff --git a/orion-visor-ui/src/router/routes/types.ts b/orion-visor-ui/src/router/routes/types.ts index 13f08018..0109bbb4 100644 --- a/orion-visor-ui/src/router/routes/types.ts +++ b/orion-visor-ui/src/router/routes/types.ts @@ -1,5 +1,5 @@ import type { NavigationGuard, RouteMeta } from 'vue-router'; -import { defineComponent } from 'vue'; +import type { defineComponent } from 'vue'; export type Component = | ReturnType diff --git a/orion-visor-ui/src/store/modules/cache/index.ts b/orion-visor-ui/src/store/modules/cache/index.ts index c541e2c6..bc78ccd7 100644 --- a/orion-visor-ui/src/store/modules/cache/index.ts +++ b/orion-visor-ui/src/store/modules/cache/index.ts @@ -2,12 +2,13 @@ import type { CacheState, CacheType } from './types'; import type { AxiosResponse } from 'axios'; import type { TagType } from '@/api/meta/tag'; import { getTagList } from '@/api/meta/tag'; +import type { HostGroupQueryResponse } from '@/api/asset/host-group'; +import { getHostGroupTree } from '@/api/asset/host-group'; +import { getSystemAggregateSetting } from '@/api/system/setting'; import type { HostType } from '@/api/asset/host'; import { getHostList } from '@/api/asset/host'; import type { PreferenceType } from '@/api/user/preference'; import { getPreference } from '@/api/user/preference'; -import type { HostGroupQueryResponse } from '@/api/asset/host-group'; -import { getHostGroupTree } from '@/api/asset/host-group'; import usePermission from '@/hooks/permission'; import { defineStore } from 'pinia'; import { flatNodes } from '@/utils/tree'; @@ -18,12 +19,11 @@ import { getHostKeyList } from '@/api/asset/host-key'; import { getHostIdentityList } from '@/api/asset/host-identity'; import { getMenuList } from '@/api/system/menu'; import { getCurrentAuthorizedHost, getCurrentAuthorizedHostIdentity, getCurrentAuthorizedHostKey } from '@/api/asset/asset-authorized-data'; -import { getCommandSnippetGroupList } from '@/api/asset/command-snippet-group'; +import { getCommandSnippetGroupList } from '@/api/terminal/command-snippet-group'; import { getExecJobList } from '@/api/exec/exec-job'; -import { getPathBookmarkGroupList } from '@/api/asset/path-bookmark-group'; -import { getCommandSnippetList } from '@/api/asset/command-snippet'; -import { getPathBookmarkList } from '@/api/asset/path-bookmark'; -import { getSystemAggregateSetting } from '@/api/system/setting'; +import { getPathBookmarkGroupList } from '@/api/terminal/path-bookmark-group'; +import { getCommandSnippetList } from '@/api/terminal/command-snippet'; +import { getPathBookmarkList } from '@/api/terminal/path-bookmark'; export default defineStore('cache', { state: (): CacheState => ({}), @@ -170,7 +170,7 @@ export default defineStore('cache', { // 获取执行计划列表 async loadExecJobs(force = false) { - return await this.load('execJob', getExecJobList, ['asset:exec-job:query'], force); + return await this.load('execJob', getExecJobList, ['exec:exec-job:query'], force); }, // 加载偏好 diff --git a/orion-visor-ui/src/store/modules/cache/types.ts b/orion-visor-ui/src/store/modules/cache/types.ts index 05bc3d0f..ec83dc71 100644 --- a/orion-visor-ui/src/store/modules/cache/types.ts +++ b/orion-visor-ui/src/store/modules/cache/types.ts @@ -7,7 +7,8 @@ export type CacheType = 'users' | 'menus' | 'roles' | 'authorizedHostKeys' | 'authorizedHostIdentities' | 'commandSnippetGroups' | 'pathBookmarkGroups' | 'commandSnippets' | 'pathBookmarks' - | '*_Tags' | 'preference_*' | 'system_setting' + | 'system_setting' + | '*_Tags' | 'preference_*' | string export interface CacheState { diff --git a/orion-visor-ui/src/store/modules/dict/index.ts b/orion-visor-ui/src/store/modules/dict/index.ts index 72f76e71..581e7bad 100644 --- a/orion-visor-ui/src/store/modules/dict/index.ts +++ b/orion-visor-ui/src/store/modules/dict/index.ts @@ -4,6 +4,8 @@ import type { Options } from '@/types/global'; import { defineStore } from 'pinia'; import { getDictValueList } from '@/api/system/dict-value'; +export const ALL_OPTION: Options = { label: '全部', value: '' }; + export default defineStore('dict', { state: (): DictState => ({}), @@ -25,13 +27,41 @@ export default defineStore('dict', { }, // 获取字典选项 - toOptions(key: string) { - return this.$state[key]; + toOptions(key: string, firstOption: boolean | Record = false): Options[] { + if (firstOption === true) { + return [{ ...ALL_OPTION }, ...this.$state[key]]; + } else if (firstOption) { + return [{ ...ALL_OPTION, ...firstOption }, ...this.$state[key]]; + } else { + return this.$state[key]; + } + }, + + // 转为 unref 的字典选项 + toUnrefOptions(key: string, firstOption: boolean | Record = false): Options[] { + return this.toOptions(key, firstOption) + .map(s => { + return { ...s }; + }); }, // 获取字典选项 - toRadioOptions(key: string) { - return this.$state[key] as RadioOption[]; + toRadioOptions(key: string, firstOption: boolean | Record = false): RadioOption[] { + if (firstOption === true) { + return [{ ...ALL_OPTION }, ...this.$state[key]] as RadioOption[]; + } else if (firstOption) { + return [{ ...ALL_OPTION, ...firstOption }, ...this.$state[key]] as RadioOption[]; + } else { + return this.$state[key] as RadioOption[]; + } + }, + + // 转为 unref 的字典选项 + toUnrefRadioOptions(key: string, firstOption: boolean | Record = false): RadioOption[] { + return this.toRadioOptions(key, firstOption) + .map(s => { + return { ...s }; + }); }, // 获取字典值 diff --git a/orion-visor-ui/src/store/modules/terminal/index.ts b/orion-visor-ui/src/store/modules/terminal/index.ts index 37b4e112..3e32a5fb 100644 --- a/orion-visor-ui/src/store/modules/terminal/index.ts +++ b/orion-visor-ui/src/store/modules/terminal/index.ts @@ -1,31 +1,40 @@ import type { - TerminalActionBarSetting, - TerminalDisplaySetting, TerminalInteractSetting, TerminalPluginsSetting, TerminalPreference, + TerminalRdpActionBarSetting, + TerminalRdpGraphSetting, TerminalSessionSetting, TerminalShortcutSetting, + TerminalSshActionBarSetting, + TerminalSshDisplaySetting, TerminalState } from './types'; -import type { ISshSession, ITerminalSession, PanelSessionTabType, TerminalPanelTabItem } from '@/views/host/terminal/types/define'; +import type { + IDomViewportHandler, + ISshSession, + ITerminalSession, + TerminalSessionTabItem, + TerminalSessionType, + TerminalTheme, + TerminalThemeSchema +} from '@/views/terminal/interfaces'; import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data'; import type { HostQueryResponse } from '@/api/asset/host'; -import type { TerminalTheme, TerminalThemeSchema } from '@/api/asset/terminal'; -import { getTerminalThemes } from '@/api/asset/terminal'; import { markRaw } from 'vue'; +import { getTerminalThemes } from '@/api/terminal/terminal'; import { defineStore } from 'pinia'; import { getPreference, updatePreference } from '@/api/user/preference'; -import { getLatestConnectHostId } from '@/api/asset/terminal-connect-log'; +import { getLatestConnectHostId } from '@/api/terminal/terminal-connect-log'; +import { useCacheStore } from '@/store'; import { nextId } from '@/utils'; import { isObject } from '@/utils/is'; import { Message } from '@arco-design/web-vue'; -import { useCacheStore } from '@/store'; -import { PanelSessionType, TerminalTabs } from '@/views/host/terminal/types/const'; -import TerminalTabManager from '@/views/host/terminal/handler/terminal-tab-manager'; -import TerminalSessionManager from '@/views/host/terminal/handler/terminal-session-manager'; -import TerminalPanelManager from '@/views/host/terminal/handler/terminal-panel-manager'; -import SftpTransferManager from '@/views/host/terminal/handler/sftp-transfer-manager'; +import { TerminalSessionTypes, TerminalTabs } from '@/views/terminal/types/const'; +import TerminalTabManager from '@/views/terminal/service/tab/terminal-tab-manager'; +import TerminalPanelManager from '@/views/terminal/service/tab/terminal-panel-manager'; +import TerminalSessionManager from '@/views/terminal/service/session/terminal-session-manager'; +import SftpTransferManager from '@/views/terminal/service/transfer/sftp-transfer-manager'; // 终端偏好项 export const TerminalPreferenceItem = { @@ -33,10 +42,14 @@ export const TerminalPreferenceItem = { NEW_CONNECTION_TYPE: 'newConnectionType', // 终端主题 THEME: 'theme', - // 显示设置 - DISPLAY_SETTING: 'displaySetting', - // 操作栏设置 - ACTION_BAR_SETTING: 'actionBarSetting', + // ssh 显示设置 + SSH_DISPLAY_SETTING: 'sshDisplaySetting', + // rdp 图形化设置 + RDP_GRAPH_SETTING: 'rdpGraphSetting', + // ssh 操作栏设置 + SSH_ACTION_BAR_SETTING: 'sshActionBarSetting', + // rdp 操作栏设置 + RDP_ACTION_BAR_SETTING: 'rdpActionBarSetting', // 右键菜单设置 RIGHT_MENU_SETTING: 'rightMenuSetting', // 交互设置 @@ -56,8 +69,10 @@ export default defineStore('terminal', { theme: { schema: {} as TerminalThemeSchema } as TerminalTheme, - displaySetting: {} as TerminalDisplaySetting, - actionBarSetting: {} as TerminalActionBarSetting, + sshDisplaySetting: {} as TerminalSshDisplaySetting, + rdpGraphSetting: {} as TerminalRdpGraphSetting, + sshActionBarSetting: {} as TerminalSshActionBarSetting, + rdpActionBarSetting: {} as TerminalRdpActionBarSetting, rightMenuSetting: [], interactSetting: {} as TerminalInteractSetting, pluginsSetting: {} as TerminalPluginsSetting, @@ -147,7 +162,10 @@ export default defineStore('terminal', { }, // 打开会话 - openSession(record: HostQueryResponse, type: PanelSessionTabType, panelIndex: number = 0) { + openSession(record: HostQueryResponse, type: TerminalSessionType, panelIndex: number | undefined = undefined) { + if (panelIndex === undefined) { + panelIndex = this.panelManager.active; + } // 添加到最近连接 this.hosts.latestHosts = [...new Set([record.id, ...this.hosts.latestHosts])]; // 切换到终端面板页面 @@ -163,39 +181,41 @@ export default defineStore('terminal', { ? Math.max(...seqArr) + 1 : 1; // 打开 tab - const sessionId = nextId(10); this.panelManager.getPanel(panelIndex).openTab({ - key: sessionId, - sessionId, + key: nextId(), + panelIndex: panelIndex, seq: nextSeq, + name: record.alias || record.name, title: `(${nextSeq}) ${record.alias || record.name}`, hostId: record.id, address: record.address, color: record.color, icon: type.icon, - type: type.type + type: type.type, + extra: record.extra, }); }, // 重新打开会话 - async reOpenSession(sessionId: string, panelIndex: number = 0) { + async reOpenSession(sessionKey: string) { // 切换到终端面板页面 this.tabManager.openTab(TerminalTabs.TERMINAL_PANEL); - // 获取当前面板 tab 并且分配新的 sessionId - const panel = this.panelManager.getPanel(panelIndex); - const tab = panel.items.find(s => s.sessionId === sessionId); + // 获取当前面板 tab + const tab = this.panelManager.panels + .map(s => s.items) + .flat() + .find(s => s.key === sessionKey); if (!tab) { return; } - const newSessionId = tab.sessionId = nextId(10); // 添加到最近连接 this.hosts.latestHosts = [...new Set([tab.hostId, ...this.hosts.latestHosts])]; // 重新打开会话 - await this.sessionManager.reOpenSession(sessionId, newSessionId); + await this.sessionManager.reOpenSession(sessionKey); }, // 复制并且打开会话 - copySession(item: TerminalPanelTabItem, panelIndex: number = 0) { + copySession(item: TerminalSessionTabItem, panelIndex: number) { const host = this.hosts.hostList .find(s => s.id === item.hostId); if (host) { @@ -207,83 +227,90 @@ export default defineStore('terminal', { } }, - // 获取当前会话类型 - getCurrentSessionType(tips: boolean = false) { + // 检查是否在终端面板 + checkTerminalPanelActive(): boolean { // 获取当前 activeTab const activeTab = this.tabManager.active; if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) { - if (tips) { - Message.warning('请切换到终端标签页'); - } - return; + Message.warning('请切换到终端标签页'); + return false; } - // 获取面板会话 - const type = this.panelManager + return true; + }, + + // 获取当前会话类型 + getCurrentSessionType() { + return this.panelManager .getCurrentPanel() .getCurrentTab() ?.type; - if (!type && tips) { - Message.warning(`请打开 ${type}`); + }, + + // 获取当前 domViewportHandler + getCurrentDomViewportHandler(): IDomViewportHandler | undefined { + // 获取当前会话 + const session = this._getCurrentSession(); + if (!session) { return; } - return type; + return session as unknown as IDomViewportHandler; }, // 获取当前会话 - getCurrentSession(type: string, tips: boolean = false) { + getCurrentSession(type?: string, check: boolean = false) { // 获取当前 activeTab - const activeTab = this.tabManager.active; - if (activeTab !== TerminalTabs.TERMINAL_PANEL.key) { - if (tips) { - Message.warning('请切换到终端标签页'); - } + if (check && !this.checkTerminalPanelActive()) { return; } // 获取当前会话 const session = this._getCurrentSession(type); - if (!session && tips) { - Message.warning(`请打开 ${type}`); + if (!session && check) { + Message.warning(`请打开 ${type || '终端'}`); + return; } return session; }, // 获取当前会话 - _getCurrentSession(type: string): T | undefined { + _getCurrentSession(type?: string): T | undefined { // 获取面板会话 const sessionTab = this.panelManager .getCurrentPanel() .getCurrentTab(); - if (!sessionTab || sessionTab.type !== type) { + if (!sessionTab) { + return; + } + if (type && sessionTab.type !== type) { return; } // 获取会话 - return this.sessionManager.getSession(sessionTab.sessionId); + return this.sessionManager.getSession(sessionTab.key); }, // 拼接命令到当前会话 - appendCommandToCurrentSession(command: string, newLine: boolean = false) { - this.appendCommandToSession(this.getCurrentSession(PanelSessionType.SSH.type, true), command, newLine); + appendCommandToCurrentSession(command: string, newLine: boolean = false, focus?: boolean) { + this.appendCommandToSession(this.getCurrentSession(TerminalSessionTypes.SSH.type, true), command, newLine, focus); }, // 拼接命令到会话 - appendCommandToSession(session: ISshSession | undefined, command: string, newLine: boolean = false) { + appendCommandToSession(session: ISshSession | undefined, command: string, newLine: boolean = false, focus?: boolean) { const handler = session?.handler; if (handler && handler.enabledStatus('checkAppendMissing')) { if (newLine) { command = `${command}\r\n`; } - handler.checkAppendMissing(command); + handler.checkAppendMissing(command, focus); } }, // 粘贴命令到会话 - pasteCommandToSession(session: ISshSession | undefined, command: string, newLine: boolean = false) { + pasteCommandToSession(session: ISshSession | undefined, command: string, newLine: boolean = false, focus?: boolean) { const handler = session?.handler; if (handler && handler.enabledStatus('pasteOrigin')) { if (newLine) { command = `${command}\r\n`; } - handler.pasteOrigin(command); + handler.pasteOrigin(command, focus); } }, diff --git a/orion-visor-ui/src/store/modules/terminal/types.ts b/orion-visor-ui/src/store/modules/terminal/types.ts index 029d4755..f62bea12 100644 --- a/orion-visor-ui/src/store/modules/terminal/types.ts +++ b/orion-visor-ui/src/store/modules/terminal/types.ts @@ -1,6 +1,5 @@ -import type { ISftpTransferManager, ITerminalPanelManager, ITerminalSessionManager, ITerminalTabManager } from '@/views/host/terminal/types/define'; +import type { ISftpTransferManager, ITerminalPanelManager, ITerminalSessionManager, ITerminalTabManager, TerminalTheme } from '@/views/terminal/interfaces'; import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data'; -import type { TerminalTheme } from '@/api/asset/terminal'; export interface TerminalState { preference: TerminalPreference; @@ -16,8 +15,10 @@ export interface TerminalState { export interface TerminalPreference { newConnectionType: string; theme: TerminalTheme; - displaySetting: TerminalDisplaySetting; - actionBarSetting: TerminalActionBarSetting; + sshDisplaySetting: TerminalSshDisplaySetting; + rdpGraphSetting: TerminalRdpGraphSetting; + sshActionBarSetting: TerminalSshActionBarSetting; + rdpActionBarSetting: TerminalRdpActionBarSetting; rightMenuSetting: Array, interactSetting: TerminalInteractSetting; pluginsSetting: TerminalPluginsSetting; @@ -25,8 +26,8 @@ export interface TerminalPreference { shortcutSetting: TerminalShortcutSetting; } -// 显示设置 -export interface TerminalDisplaySetting { +// SSH 显示设置 +export interface TerminalSshDisplaySetting { fontFamily?: string; fontSize?: number; lineHeight?: number; @@ -37,9 +38,44 @@ export interface TerminalDisplaySetting { cursorBlink?: boolean; } -// 操作栏设置 -export interface TerminalActionBarSetting { +// RDP 图形化设置 +export interface TerminalRdpGraphSetting { + displaySize?: string; + displayWidth?: number; + displayHeight?: number; + enableAudioInput?: boolean; + enableAudioOutput?: boolean; + colorDepth?: number; + forceLossless?: boolean; + enableWallpaper?: boolean; + enableTheming?: boolean; + enableFontSmoothing?: boolean; + enableFullWindowDrag?: boolean; + enableDesktopComposition?: boolean; + enableMenuAnimations?: boolean; + disableBitmapCaching?: boolean; + disableOffscreenCaching?: boolean; + disableGlyphCaching?: boolean; +} + +// SSH 操作栏设置 +export interface TerminalSshActionBarSetting { connectStatus?: boolean; + share?: boolean; + + [key: string]: unknown; +} + +// RDP 操作栏设置 +export interface TerminalRdpActionBarSetting { + position?: string; + display?: boolean; + combinationKey?: boolean; + clipboard?: boolean; + upload?: boolean; + saveRdp?: boolean; + disconnect?: boolean; + close?: boolean; [key: string]: unknown; } diff --git a/orion-visor-ui/src/types/global.ts b/orion-visor-ui/src/types/global.ts index a47cd34d..c19b634a 100644 --- a/orion-visor-ui/src/types/global.ts +++ b/orion-visor-ui/src/types/global.ts @@ -31,6 +31,10 @@ export interface PostData { url: string; } +export interface FavoriteItem { + favorite: boolean; +} + export interface OrderDirection { order?: number; } @@ -57,7 +61,25 @@ export interface DataGrid { export type TimeRanger = [string, string]; +export interface StatisticsRangeRequest { + range: string; + startTime: number; +} + export interface LineSingleChartData { x: string[]; data: Array; } + +export interface LineChartData { + x: string[]; + data: Record>; +} + +export interface PieChartData { + data: Record; +} + +export interface BarSingleChartData { + data: Record; +} diff --git a/orion-visor-ui/src/types/protocol/terminal.protocol.ts b/orion-visor-ui/src/types/protocol/terminal.protocol.ts deleted file mode 100644 index 3bb68430..00000000 --- a/orion-visor-ui/src/types/protocol/terminal.protocol.ts +++ /dev/null @@ -1,242 +0,0 @@ -// 终端协议 -export interface Protocol { - type: string; - template: string[]; - - [key: string]: unknown; -} - -// 终端输入消息内容 -export interface InputPayload { - type?: string; - sessionId?: string; - - [key: string]: unknown; -} - -// 终端输出消息内容 -export interface OutputPayload { - type: string; - sessionId: string; - - [key: string]: string; -} - -// 分隔符 -export const SEPARATOR = '|'; - -// 输入协议 -export const InputProtocol = { - // 主机连接检查 - CHECK: { - type: 'ck', - template: ['type', 'sessionId', 'hostId', 'connectType'] - }, - // 连接主机 - CONNECT: { - type: 'co', - template: ['type', 'sessionId', 'terminalType', 'cols', 'rows'] - }, - // 关闭连接 - CLOSE: { - type: 'cl', - template: ['type', 'sessionId'] - }, - // ping - PING: { - type: 'p', - template: ['type'] - }, - // SSH 修改大小 - SSH_RESIZE: { - type: 'rs', - template: ['type', 'sessionId', 'cols', 'rows'] - }, - // SSH 输入 - SSH_INPUT: { - type: 'i', - template: ['type', 'sessionId', 'command'] - }, - // SFTP 文件列表 - SFTP_LIST: { - type: 'ls', - template: ['type', 'sessionId', 'showHiddenFile', 'path'] - }, - // SFTP 创建文件夹 - SFTP_MKDIR: { - type: 'mk', - template: ['type', 'sessionId', 'path'] - }, - // SFTP 创建文件 - SFTP_TOUCH: { - type: 'to', - template: ['type', 'sessionId', 'path'] - }, - // SFTP 移动文件 - SFTP_MOVE: { - type: 'mv', - template: ['type', 'sessionId', 'path', 'target'] - }, - // SFTP 删除文件 - SFTP_REMOVE: { - type: 'rm', - template: ['type', 'sessionId', 'path'] - }, - // SFTP 修改文件权限 - SFTP_CHMOD: { - type: 'cm', - template: ['type', 'sessionId', 'path', 'mod'] - }, - // SFTP 修改文件权限 - SFTP_DOWNLOAD_FLAT_DIRECTORY: { - type: 'df', - template: ['type', 'sessionId', 'currentPath', 'path'] - }, - // SFTP 获取内容 - SFTP_GET_CONTENT: { - type: 'gc', - template: ['type', 'sessionId', 'path'] - }, - // SFTP 修改内容 - SFTP_SET_CONTENT: { - type: 'sc', - template: ['type', 'sessionId', 'path'] - }, -}; - -// 输出协议 -export const OutputProtocol = { - // 主机连接检查 - CHECK: { - type: 'ck', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processCheck' - }, - // 主机连接 - CONNECT: { - type: 'co', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processConnect' - }, - // 主机连接关闭 - CLOSE: { - type: 'cl', - template: ['type', 'sessionId', 'forceClose', 'msg'], - processMethod: 'processClose' - }, - // pong - PONG: { - type: 'p', - template: ['type'], - processMethod: 'processPong' - }, - // SSH 输出 - SSH_OUTPUT: { - type: 'o', - template: ['type', 'sessionId', 'body'], - processMethod: 'processSshOutput' - }, - // SFTP 文件列表 - SFTP_LIST: { - type: 'ls', - template: ['type', 'sessionId', 'path', 'result', 'msg', 'body'], - processMethod: 'processSftpList' - }, - // SFTP 创建文件夹 - SFTP_MKDIR: { - type: 'mk', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processSftpMkdir' - }, - // SFTP 创建文件 - SFTP_TOUCH: { - type: 'to', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processSftpTouch' - }, - // SFTP 移动文件 - SFTP_MOVE: { - type: 'mv', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processSftpMove' - }, - // SFTP 删除文件 - SFTP_REMOVE: { - type: 'rm', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processSftpRemove' - }, - // SFTP 修改文件权限 - SFTP_CHMOD: { - type: 'cm', - template: ['type', 'sessionId', 'result', 'msg'], - processMethod: 'processSftpChmod' - }, - // SFTP 修改文件权限 - SFTP_DOWNLOAD_FLAT_DIRECTORY: { - type: 'df', - template: ['type', 'sessionId', 'currentPath', 'result', 'msg', 'body'], - processMethod: 'processDownloadFlatDirectory' - }, - // SFTP 获取文件内容 - SFTP_GET_CONTENT: { - type: 'gc', - template: ['type', 'sessionId', 'result', 'msg', 'token'], - processMethod: 'processSftpGetContent' - }, - // SFTP 修改文件内容 - SFTP_SET_CONTENT: { - type: 'sc', - template: ['type', 'sessionId', 'result', 'msg', 'token'], - processMethod: 'processSftpSetContent' - }, -}; - -// 解析参数 -export const parse = (payload: string) => { - const protocols = Object.values(OutputProtocol); - const useProtocol = protocols.find(p => payload.startsWith(p.type + SEPARATOR) || p.type === payload); - if (!useProtocol) { - return undefined; - } - const template = useProtocol.template; - const res = {} as OutputPayload; - let curr = 0; - let len = payload.length; - for (let i = 0, pl = template.length; i < pl; i++) { - if (i == pl - 1) { - // 最后一次 - res[template[i]] = payload.substring(curr, len); - } else { - // 非最后一次 - let tmp = ''; - for (; curr < len; curr++) { - const c = payload.charAt(curr); - if (c == SEPARATOR) { - res[template[i]] = tmp; - curr++; - break; - } else { - tmp += c; - } - } - } - } - return res; -}; - -// 格式化参数 -export const format = (protocol: Protocol, payload: InputPayload | OutputPayload) => { - payload.type = protocol.type; - return protocol.template - .map(i => getPayloadValueString(payload[i])) - .join(SEPARATOR); -}; - -// 获取默认值 -export const getPayloadValueString = (value: unknown): any => { - if (value === undefined || value === null) { - return ''; - } - return value; -}; diff --git a/orion-visor-ui/src/utils/env.ts b/orion-visor-ui/src/utils/env.ts index d626e6d3..4227f863 100644 --- a/orion-visor-ui/src/utils/env.ts +++ b/orion-visor-ui/src/utils/env.ts @@ -14,7 +14,7 @@ export const isStandaloneMode = (() => ( // http base url export const httpBaseUrl = (() => { - const configBase = import.meta.env.VITE_API_BASE_URL; + const configBase = import.meta.env.VITE_API_BASE_URL || ''; if (configBase.startsWith('http')) { // 固定 return configBase; @@ -28,7 +28,7 @@ export const httpBaseUrl = (() => { // websocket base url export const webSocketBaseUrl = (() => { - const configBase = import.meta.env.VITE_WS_BASE_URL; + const configBase = import.meta.env.VITE_WS_BASE_URL || ''; if (configBase.startsWith('ws')) { // 固定 return configBase; diff --git a/orion-visor-ui/src/utils/event.ts b/orion-visor-ui/src/utils/event.ts index 211ec956..d1b0fc1b 100644 --- a/orion-visor-ui/src/utils/event.ts +++ b/orion-visor-ui/src/utils/event.ts @@ -1,6 +1,6 @@ -// 添加事件监听器 import type { Ref } from 'vue'; +// 添加事件监听器 export function addEventListen( target: Window | HTMLElement, event: string, diff --git a/orion-visor-ui/src/utils/file.ts b/orion-visor-ui/src/utils/file.ts index cf72abb3..ef1994e7 100644 --- a/orion-visor-ui/src/utils/file.ts +++ b/orion-visor-ui/src/utils/file.ts @@ -27,7 +27,11 @@ export function readBlobText(blob: Blob) { export function readFileText(e: File, encoding = 'UTF-8'): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); - reader.readAsText(e, encoding); + if (encoding === 'base64') { + reader.readAsDataURL(e); + } else { + reader.readAsText(e, encoding); + } reader.onload = res => { resolve(res.target?.result as string); }; diff --git a/orion-visor-ui/src/utils/index.ts b/orion-visor-ui/src/utils/index.ts index 81733805..7fa30497 100644 --- a/orion-visor-ui/src/utils/index.ts +++ b/orion-visor-ui/src/utils/index.ts @@ -167,6 +167,11 @@ export const sleep = (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)); }; +// ansi 着色 +export const ansi = (code: number | string, msg: string, newLine: boolean = true) => { + return `[${code}m${msg}${newLine ? '\r\n' : ''}`; +}; + // 添加后缀 export const addSuffix = (value: any, suffix: string) => { if (value === undefined || value === '') { @@ -206,7 +211,7 @@ export function getUUID() { /** * 获取会话id */ -export const nextId = (len: number): string => { +export const nextId = (len: number = 10): string => { return getUUID().replaceAll('-', '').substring(0, len); }; diff --git a/orion-visor-ui/src/utils/monitor.ts b/orion-visor-ui/src/utils/monitor.ts index 7b490150..0a116560 100644 --- a/orion-visor-ui/src/utils/monitor.ts +++ b/orion-visor-ui/src/utils/monitor.ts @@ -1,4 +1,4 @@ -import { App, ComponentPublicInstance } from 'vue'; +import type { App, ComponentPublicInstance } from 'vue'; import axios from 'axios'; export default function handleError(Vue: App, baseUrl: string) {