Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b2753a2b7 | ||
|
|
29b44b8b77 | ||
|
|
7290b1364c | ||
|
|
3851ead8bb | ||
|
|
305312cc26 |
@@ -53,7 +53,7 @@
|
||||
|
||||
* 🔗 演示地址: http://101.43.254.243:1081/
|
||||
* 🔏 演示账号: admin/admin
|
||||
* ⭐ 体验后可以点一下 `star` 这对我很重要! [github](https://github.com/dromara/orion-visor) [gitee](https://gitee.com/dromara/orion-visor) [gitcode](https://gitcode.com/qq_41011894/orion-visor/overview)
|
||||
* ⭐ 体验后可以点一下 `star` 这对我很重要! [github](https://github.com/dromara/orion-visor) [gitee](https://gitee.com/dromara/orion-visor) [gitcode](https://gitcode.com/dromara/orion-visor/overview)
|
||||
* 🌈 如果本项目对你有帮助请帮忙推广一下 让更多的人知道此项目!
|
||||
* 🎭 演示环境部分功能不可用, 完整功能请本地部署!
|
||||
* 📛 演示环境请不要随便删除数据!
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
orion-visor-service:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.1
|
||||
privileged: true
|
||||
ports:
|
||||
- 1081:80
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
- orion-visor-mysql
|
||||
- orion-visor-redis
|
||||
orion-visor-mysql:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.1
|
||||
privileged: true
|
||||
ports:
|
||||
- 3307:3306
|
||||
@@ -52,7 +52,7 @@ services:
|
||||
retries: 10
|
||||
start_period: 3s
|
||||
orion-visor-redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.1
|
||||
privileged: true
|
||||
ports:
|
||||
- 6380:6379
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3.3'
|
||||
services:
|
||||
orion-visor-service:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-service:2.1.1
|
||||
privileged: true
|
||||
ports:
|
||||
- 1081:80
|
||||
@@ -32,7 +32,7 @@ services:
|
||||
- orion-visor-mysql
|
||||
- orion-visor-redis
|
||||
orion-visor-mysql:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-mysql:2.1.1
|
||||
privileged: true
|
||||
ports:
|
||||
- 3307:3306
|
||||
@@ -52,7 +52,7 @@ services:
|
||||
retries: 10
|
||||
start_period: 3s
|
||||
orion-visor-redis:
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.0
|
||||
image: registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:2.1.1
|
||||
privileged: true
|
||||
ports:
|
||||
- 6380:6379
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
version=2.1.0
|
||||
version=2.1.1
|
||||
cp -r ../../sql ./sql
|
||||
docker build -t orion-visor-mysql:${version} .
|
||||
rm -rf ./sql
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
version=2.1.0
|
||||
version=2.1.1
|
||||
docker build -t orion-visor-redis:${version} .
|
||||
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:${version}
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/lijiahangmax/orion-visor-redis:${version}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#/bin/bash
|
||||
version=2.1.0
|
||||
version=2.1.1
|
||||
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
|
||||
mv ../../orion-visor-ui/dist ./dist
|
||||
docker build -t orion-visor-service:${version} .
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<url>https://github.com/dromara/orion-visor</url>
|
||||
|
||||
<properties>
|
||||
<revision>2.1.0</revision>
|
||||
<revision>2.1.1</revision>
|
||||
<spring.boot.version>2.7.17</spring.boot.version>
|
||||
<spring.boot.admin.version>2.7.15</spring.boot.admin.version>
|
||||
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>
|
||||
|
||||
@@ -14,7 +14,7 @@ public interface AppConst extends OrionConst {
|
||||
/**
|
||||
* 同 ${orion.version} 迭代时候需要手动更改
|
||||
*/
|
||||
String VERSION = "2.1.0";
|
||||
String VERSION = "2.1.1";
|
||||
|
||||
/**
|
||||
* 同 ${spring.application.name}
|
||||
|
||||
@@ -94,8 +94,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
#foreach($field in ${table.fields})
|
||||
#if(${dictMap.containsKey(${field.propertyName})})
|
||||
<!-- $field.comment -->
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VITE_API_BASE_URL= 'http://127.0.0.1:9200/orion-visor/api'
|
||||
VITE_WS_BASE_URL= 'ws://127.0.0.1:9200/orion-visor/keep-alive'
|
||||
VITE_APP_VERSION= '2.1.0'
|
||||
VITE_APP_VERSION= '2.1.1'
|
||||
VITE_APP_RELEASE= 'community'
|
||||
VITE_SFTP_PREVIEW_MB= 2
|
||||
VITE_DEMO_MODE= false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VITE_API_BASE_URL= '/orion-visor/api'
|
||||
VITE_WS_BASE_URL= '/orion-visor/keep-alive'
|
||||
VITE_APP_VERSION= '2.1.0'
|
||||
VITE_APP_VERSION= '2.1.1'
|
||||
VITE_APP_RELEASE= 'community'
|
||||
VITE_SFTP_PREVIEW_MB= 2
|
||||
VITE_DEMO_MODE= false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "orion-visor-ui",
|
||||
"description": "Orion Visor UI",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"private": true,
|
||||
"author": "Jiahang Li",
|
||||
"license": "Apache 2.0",
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-dropdown trigger="click" @select="s => changeLocale(s as string)">
|
||||
<a-dropdown trigger="click" @select="(s: string) => changeLocale(s)">
|
||||
<div ref="localeRef" class="trigger-btn" />
|
||||
<template #content>
|
||||
<a-doption v-for="item in locales"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
:checkable="checkable"
|
||||
:check-strictly="true"
|
||||
@drop="moveGroup"
|
||||
@select="(s) => emits('onSelected', s)">
|
||||
@select="(s: any) => emits('onSelected', s)">
|
||||
<!-- 标题 -->
|
||||
<template #title="node">
|
||||
<!-- 修改名称输入框 -->
|
||||
|
||||
@@ -119,11 +119,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.exec-host-items {
|
||||
width: 100%;
|
||||
height: calc(100% - 38px);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.log-header) {
|
||||
|
||||
@@ -13,23 +13,26 @@
|
||||
</div>
|
||||
<!-- 主机列表 -->
|
||||
<div class="exec-host-items">
|
||||
<div v-for="item in hosts"
|
||||
:key="item.id"
|
||||
class="exec-host-item"
|
||||
:class="[ current === item.id ? 'exec-host-item-selected' : '' ]"
|
||||
@click="emits('selected', item.id)">
|
||||
<!-- 主机名称 -->
|
||||
<div class="exec-host-item-name">
|
||||
<span class="host-name">{{ item.hostName }}</span>
|
||||
<span class="host-address">{{ item.hostAddress }}</span>
|
||||
<a-scrollbar>
|
||||
<div v-for="(item, index) in hosts"
|
||||
:key="item.id"
|
||||
class="exec-host-item"
|
||||
:class="[ current === item.id ? 'exec-host-item-selected' : '' ]"
|
||||
:style="{ marginBottom: index === hosts.length -1 ? 0 : '8px' }"
|
||||
@click="emits('selected', item.id)">
|
||||
<!-- 主机名称 -->
|
||||
<div class="exec-host-item-name">
|
||||
<span class="host-name">{{ item.hostName }}</span>
|
||||
<span class="host-address">{{ item.hostAddress }}</span>
|
||||
</div>
|
||||
<!-- 状态 -->
|
||||
<div class="exec-host-item-status">
|
||||
<a-tag :color="getDictValue(execHostStatusKey, item.status, 'execColor')">
|
||||
{{ getDictValue(execHostStatusKey, item.status) }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 状态 -->
|
||||
<div class="exec-host-item-status">
|
||||
<a-tag :color="getDictValue(execHostStatusKey, item.status, 'execColor')">
|
||||
{{ getDictValue(execHostStatusKey, item.status) }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</a-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -78,13 +81,19 @@
|
||||
}
|
||||
|
||||
.exec-host-items {
|
||||
position: absolute;
|
||||
width: calc(100% - 32px);
|
||||
height: calc(100% - 68px);
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100% - 38px);
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
:deep(.arco-scrollbar) {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&-container {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +108,6 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
background: var(--color-fill-2);
|
||||
transition: all .2s;
|
||||
user-select: none;
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
:scroll="{ x: '100%', y: '60vh' }"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 模板名称 -->
|
||||
<template #name="{ record }">
|
||||
<span class="span-blue">{{ record.name }}</span>
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 修改前 -->
|
||||
<template #beforeValue="{ record }">
|
||||
<span class="copy-left"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<!-- 一级菜单 -->
|
||||
<a-menu-item v-if="!menu.children?.length"
|
||||
:key="menu.name"
|
||||
@click="(e) => goto(e, menu)">
|
||||
@click="(e: any) => goto(e, menu)">
|
||||
<!-- 图标 -->
|
||||
<template #icon>
|
||||
<component v-if="menu.meta?.icon" :is="menu.meta?.icon" />
|
||||
@@ -34,7 +34,7 @@
|
||||
<!-- 子菜单 -->
|
||||
<a-menu-item v-for="child in menu.children"
|
||||
:key="child.name"
|
||||
@click="(e) => goto(e, child)">
|
||||
@click="(e: any) => goto(e, child)">
|
||||
<!-- 图标 -->
|
||||
<template #icon v-if="child.meta?.icon">
|
||||
<component :is="child.meta?.icon" />
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
v-model:page-size="(pagination as any).pageSize"
|
||||
v-bind="pagination as any"
|
||||
:auto-adjust="false"
|
||||
@change="page => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, page, (pagination as any).pageSize)"
|
||||
@page-size-change="limit => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, 1, limit)" />
|
||||
@change="(page: number) => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, page, (pagination as any).pageSize)"
|
||||
@page-size-change="(limit: number) => bubblesEmitter(HeaderEmitter.PAGE_CHANGE, 1, limit)" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作部分 -->
|
||||
@@ -48,8 +48,8 @@
|
||||
:placeholder="searchInputPlaceholder as string"
|
||||
size="small"
|
||||
allow-clear
|
||||
@input="(e) => bubblesEmitter(HeaderEmitter.UPDATE_SEARCH_VALUE, e)"
|
||||
@change="(e) => bubblesEmitter(HeaderEmitter.UPDATE_SEARCH_VALUE, e)"
|
||||
@input="(e: string) => bubblesEmitter(HeaderEmitter.UPDATE_SEARCH_VALUE, e)"
|
||||
@change="(e: string) => bubblesEmitter(HeaderEmitter.UPDATE_SEARCH_VALUE, e)"
|
||||
@keyup.enter="bubblesEmitter(HeaderEmitter.SEARCH)" />
|
||||
</div>
|
||||
<!-- 过滤条件 -->
|
||||
|
||||
10
orion-visor-ui/src/store/modules/cache/index.ts
vendored
10
orion-visor-ui/src/store/modules/cache/index.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import type { CacheState } from './types';
|
||||
import type { CacheState, CacheType } from './types';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import type { TagType } from '@/api/meta/tag';
|
||||
import { getTagList } from '@/api/meta/tag';
|
||||
@@ -19,14 +19,6 @@ import { getCommandSnippetGroupList } from '@/api/asset/command-snippet-group';
|
||||
import { getExecJobList } from '@/api/job/exec-job';
|
||||
import { getPathBookmarkGroupList } from '@/api/asset/path-bookmark-group';
|
||||
|
||||
export type CacheType = 'users' | 'menus' | 'roles'
|
||||
| 'hostGroups' | 'hostKeys' | 'hostIdentities'
|
||||
| 'dictKeys'
|
||||
| 'authorizedHostKeys' | 'authorizedHostIdentities'
|
||||
| 'commandSnippetGroups' | 'pathBookmarkGroups'
|
||||
| 'execJob'
|
||||
| string
|
||||
|
||||
export default defineStore('cache', {
|
||||
state: (): CacheState => ({}),
|
||||
|
||||
|
||||
29
orion-visor-ui/src/store/modules/cache/types.ts
vendored
29
orion-visor-ui/src/store/modules/cache/types.ts
vendored
@@ -1,23 +1,12 @@
|
||||
import type { UserQueryResponse } from '@/api/user/user';
|
||||
import type { MenuQueryResponse } from '@/api/system/menu';
|
||||
import type { RoleQueryResponse } from '@/api/user/role';
|
||||
import type { HostQueryResponse } from '@/api/asset/host';
|
||||
import type { HostGroupQueryResponse } from '@/api/asset/host-group';
|
||||
import type { HostKeyQueryResponse } from '@/api/asset/host-key';
|
||||
import type { HostIdentityQueryResponse } from '@/api/asset/host-identity';
|
||||
import type { DictKeyQueryResponse } from '@/api/system/dict-key';
|
||||
// 缓存类型
|
||||
export type CacheType = 'users' | 'menus' | 'roles'
|
||||
| 'hostGroups' | 'hostKeys' | 'hostIdentities'
|
||||
| 'dictKeys'
|
||||
| 'authorizedHostKeys' | 'authorizedHostIdentities'
|
||||
| 'commandSnippetGroups' | 'pathBookmarkGroups'
|
||||
| 'execJob'
|
||||
| string
|
||||
|
||||
export interface CacheState {
|
||||
users?: UserQueryResponse[];
|
||||
menus?: MenuQueryResponse[];
|
||||
roles?: RoleQueryResponse[];
|
||||
hosts?: HostQueryResponse[];
|
||||
hostGroups?: HostGroupQueryResponse[];
|
||||
hostKeys?: HostKeyQueryResponse[];
|
||||
hostIdentities?: HostIdentityQueryResponse[];
|
||||
dictKeys?: DictKeyQueryResponse[];
|
||||
authorizedHostKeys?: HostKeyQueryResponse[];
|
||||
authorizedHostIdentities?: HostIdentityQueryResponse[];
|
||||
|
||||
[key: string]: unknown;
|
||||
[key: CacheType]: unknown;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { RouteMeta, RouteRecordNormalized } from 'vue-router';
|
||||
import type { MenuState } from './types';
|
||||
import type { MenuQueryResponse } from '@/api/system/menu';
|
||||
import router from '@/router';
|
||||
import { defineStore } from 'pinia';
|
||||
import { Notification } from '@arco-design/web-vue';
|
||||
import { getMenuList } from '@/api/user/auth';
|
||||
import router from '@/router';
|
||||
import { EnabledStatus } from '@/types/const';
|
||||
|
||||
export default defineStore('menu', {
|
||||
|
||||
@@ -100,8 +100,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 连接用户 -->
|
||||
<template #username="{ record }">
|
||||
{{ record.username }}
|
||||
|
||||
@@ -84,8 +84,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 操作用户 -->
|
||||
<template #username="{ record }">
|
||||
{{ record.username }}
|
||||
|
||||
@@ -102,8 +102,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 类型 -->
|
||||
<template #type="{ record }">
|
||||
<a-tag :color="getDictValue(identityTypeKey, record.type, 'color')">
|
||||
|
||||
@@ -87,8 +87,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 操作 -->
|
||||
<template #handle="{ record }">
|
||||
<div class="table-handle-wrapper">
|
||||
|
||||
@@ -127,8 +127,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 主机类型 -->
|
||||
<template #type="{ record }">
|
||||
<a-tag :color="getDictValue(hostTypeKey, record.type, 'color')">
|
||||
|
||||
@@ -108,8 +108,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)"
|
||||
@expand="loadExecHost">
|
||||
<!-- 展开表格 -->
|
||||
<template #expand-row="{ record }">
|
||||
@@ -165,7 +165,7 @@
|
||||
type="text"
|
||||
size="mini"
|
||||
title="ctrl + 左键新页面打开"
|
||||
@click="(e) => emits('viewLog', record.id, e.ctrlKey)">
|
||||
@click="(e: any) => emits('viewLog', record.id, e.ctrlKey)">
|
||||
日志
|
||||
</a-button>
|
||||
<!-- 中断 -->
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
<a-empty description="无执行记录" />
|
||||
</div>
|
||||
<!-- 批量执行日志 -->
|
||||
<div v-else class="exec-history-rows">
|
||||
<div v-for="record in historyLogs"
|
||||
<a-scrollbar v-else>
|
||||
<div v-for="(record, index) in historyLogs"
|
||||
:key="record.id"
|
||||
:style="{ marginBottom: index === historyLogs.length -1 ? 0 : '8px' }"
|
||||
class="exec-history"
|
||||
@click="emits('selected', record)">
|
||||
<!-- 机器数量 -->
|
||||
@@ -32,7 +33,7 @@
|
||||
{{ record.description }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -110,14 +111,16 @@
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.exec-history-rows {
|
||||
position: absolute;
|
||||
width: calc(100% - 32px);
|
||||
height: calc(100% - 64px);
|
||||
overflow: auto;
|
||||
.container {
|
||||
:deep(.arco-scrollbar) {
|
||||
position: absolute;
|
||||
width: calc(100% - 32px);
|
||||
height: calc(100% - 64px);
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
&-container {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +130,6 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
background: var(--color-fill-2);
|
||||
transition: all .2s;
|
||||
user-select: none;
|
||||
|
||||
@@ -77,8 +77,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 模板命令 -->
|
||||
<template #command="{ record }">
|
||||
<span class="copy-left" @click="copy(record.command, '已复制')">
|
||||
|
||||
@@ -107,8 +107,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 上传路径 -->
|
||||
<template #remotePath="{ record }">
|
||||
<span class="text-copy span-blue" @click="copy(record.remotePath)">
|
||||
|
||||
@@ -320,6 +320,18 @@
|
||||
height: calc(100% - 56px);
|
||||
overflow: auto;
|
||||
padding-bottom: 4px;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb {
|
||||
background: var(--color-fill-4);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-skeleton {
|
||||
|
||||
@@ -75,9 +75,8 @@
|
||||
import type { HostQueryResponse } from '@/api/asset/host';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { PanelSessionType, TerminalTabs } from '../../types/const';
|
||||
import { PanelSessionType, TerminalTabs, emptyRecommendCount } from '../../types/const';
|
||||
|
||||
const totalCount = 7;
|
||||
const { tabManager, hosts, openSession } = useTerminalStore();
|
||||
|
||||
const combinedHandlers = ref<Array<CombinedHandlerItem>>([{
|
||||
@@ -103,7 +102,7 @@
|
||||
...hosts.hostList.filter(s => s.favorite).map(s => s.id),
|
||||
...hosts.hostList.map(s => s.id)
|
||||
])
|
||||
].slice(0, totalCount - 1)
|
||||
].slice(0, emptyRecommendCount - 1)
|
||||
.map(s => hosts.hostList.find(t => t.id === s) as HostQueryResponse)
|
||||
.filter(Boolean)
|
||||
.map(s => {
|
||||
@@ -116,10 +115,10 @@
|
||||
// 插入主机列表
|
||||
combinedHandlers.value.push(...combinedHosts);
|
||||
// 不足显示的行数用设置补充
|
||||
if (totalCount - 1 - combinedHosts.length > 0) {
|
||||
if (emptyRecommendCount - 1 - combinedHosts.length > 0) {
|
||||
const fillTabs = Object.values(TerminalTabs)
|
||||
.filter(s => s.key !== TerminalTabs.NEW_CONNECTION.key)
|
||||
.slice(0, totalCount - 1 - combinedHosts.length)
|
||||
.slice(0, emptyRecommendCount - 1 - combinedHosts.length)
|
||||
.map(s => {
|
||||
return {
|
||||
title: s.title,
|
||||
@@ -147,23 +146,19 @@
|
||||
|
||||
.combined-container {
|
||||
padding: 12px;
|
||||
margin: 64px auto 0 auto;
|
||||
margin: 32px auto 0 auto;
|
||||
width: @container-width;
|
||||
height: @container-height;
|
||||
max-height: @container-height;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: content-box;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.combined-handler {
|
||||
width: @container-width - @transform-x;
|
||||
height: @handler-height;
|
||||
max-height: @handler-height;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 6px;
|
||||
color: var(--color-content-text-1);
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
:editable="true"
|
||||
:hide-content="true"
|
||||
:auto-switch="true"
|
||||
@tab-click="k => tabManager.clickTab(k as string)"
|
||||
@delete="k => tabManager.deleteTab(k as string)">
|
||||
@tab-click="(k: string) => tabManager.clickTab(k)"
|
||||
@delete="(k: string) => tabManager.deleteTab(k)">
|
||||
<a-tab-pane v-for="tab in tabManager.items"
|
||||
:key="tab.key">
|
||||
<!-- 标题 -->
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
:auto-switch="true"
|
||||
:show-add-button="true"
|
||||
@add="openNewConnect"
|
||||
@tab-click="k => panel.clickTab(k as string)"
|
||||
@delete="k => panel.deleteTab(k as string)">
|
||||
@tab-click="(k: string) => panel.clickTab(k)"
|
||||
@delete="(k: string) => panel.deleteTab(k)">
|
||||
<!-- 右侧按钮 -->
|
||||
<template #extra>
|
||||
<a-space class="panel-extra">
|
||||
|
||||
@@ -134,10 +134,4 @@
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.list-view-container {
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
type="button"
|
||||
class="usn"
|
||||
:options="toRadioOptions(newConnectionTypeKey)"
|
||||
@change="s => updateTerminalPreference(TerminalPreferenceItem.NEW_CONNECTION_TYPE, s as string, true)" />
|
||||
@change="(s: string) => updateTerminalPreference(TerminalPreferenceItem.NEW_CONNECTION_TYPE, s, true)" />
|
||||
<!-- 过滤 -->
|
||||
<a-auto-complete v-model="filterValue"
|
||||
class="host-filter"
|
||||
|
||||
@@ -320,6 +320,18 @@
|
||||
height: calc(100% - 56px);
|
||||
overflow: auto;
|
||||
padding-bottom: 4px;
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb {
|
||||
background: var(--color-fill-4);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-skeleton {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<a-input size="small"
|
||||
:ref="setAutoFocus as unknown as VNodeRef"
|
||||
:model-value="filterValue[0]"
|
||||
@input="(value) => setFilterValue([value])"
|
||||
@input="(value: string) => setFilterValue([value])"
|
||||
@press-enter="handleFilterConfirm" />
|
||||
<!-- 按钮 -->
|
||||
<div class="name-filter-footer">
|
||||
|
||||
@@ -10,13 +10,15 @@
|
||||
:unmount-on-close="true"
|
||||
:on-before-ok="handlerOk"
|
||||
@cancel="handleClose">
|
||||
<!-- 上传目录 -->
|
||||
<div class="item-wrapper">
|
||||
<div class="form-item">
|
||||
<span class="item-label">上传至文件夹</span>
|
||||
<a-input class="item-input"
|
||||
v-model="parentPath"
|
||||
placeholder="上传目录" />
|
||||
<div class="upload-container">
|
||||
<!-- 上传目录 -->
|
||||
<div class="item-wrapper">
|
||||
<div class="form-item">
|
||||
<span class="item-label">上传至文件夹</span>
|
||||
<a-input class="item-input"
|
||||
v-model="parentPath"
|
||||
placeholder="上传目录" />
|
||||
</div>
|
||||
</div>
|
||||
<a-space>
|
||||
<!-- 选择文件 -->
|
||||
@@ -112,7 +114,7 @@
|
||||
}
|
||||
// 获取上传的文件
|
||||
const files = fileList.value.map(s => s.file as File);
|
||||
// 上传
|
||||
// 普通上传
|
||||
transferManager.addUpload(hostId.value, parentPath.value, files);
|
||||
Message.success('已开始上传, 点击右侧传输列表查看进度');
|
||||
// 清空
|
||||
@@ -136,6 +138,11 @@
|
||||
@file-size-width: 82px;
|
||||
@item-label: 104px;
|
||||
|
||||
.upload-container {
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.item-wrapper {
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
@@ -163,6 +170,11 @@
|
||||
width: 376px;
|
||||
}
|
||||
|
||||
.form-help {
|
||||
margin: 4px 0 0 @item-label;
|
||||
font-size: 12px;
|
||||
color: var(--color-text-2);
|
||||
}
|
||||
}
|
||||
|
||||
.file-list-uploader {
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
width: 100%;
|
||||
height: calc(100% - @ssh-header-height);
|
||||
position: relative;
|
||||
padding: 6px 0 0 6px;
|
||||
padding: 8px;
|
||||
|
||||
.ssh-inst {
|
||||
width: 100%;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { ISftpSession, ISftpSessionResolver, ITerminalChannel, TerminalPanelTabItem } from '../types/define';
|
||||
import { h } from 'vue';
|
||||
import { InputProtocol } from '@/types/protocol/terminal.protocol';
|
||||
import { PanelSessionType } from '../types/const';
|
||||
import { Modal } from '@arco-design/web-vue';
|
||||
@@ -77,15 +78,32 @@ export default class SftpSession extends BaseSession implements ISftpSession {
|
||||
};
|
||||
|
||||
// 删除文件
|
||||
remove(path: string[]) {
|
||||
remove(paths: string[]) {
|
||||
// 内容
|
||||
const contentNode = h('div', {
|
||||
style: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
maxHeight: '40vh',
|
||||
overflowY: 'auto'
|
||||
}
|
||||
},
|
||||
paths.map(s => {
|
||||
return h('span', { style: { marginTop: '4px' } }, s);
|
||||
}));
|
||||
// 提示
|
||||
Modal.confirm({
|
||||
title: '删除确认',
|
||||
content: `确定要删除 ${path.join(',')} 吗? 确定后将立即删除且无法恢复!`,
|
||||
title: '确定后将立即删除这些文件且无法恢复!',
|
||||
modalStyle: { padding: '24px 32px' },
|
||||
bodyStyle: { marginTop: '-14px' },
|
||||
okButtonProps: { status: 'danger' },
|
||||
okText: '删除',
|
||||
content: () => contentNode,
|
||||
onOk: () => {
|
||||
this.resolver.setLoading(true);
|
||||
this.channel.send(InputProtocol.SFTP_REMOVE, {
|
||||
sessionId: this.sessionId,
|
||||
path: path.join('|')
|
||||
path: paths.join('|')
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -43,7 +43,6 @@ export default class SftpTransferManager implements ISftpTransferManager {
|
||||
file: s
|
||||
};
|
||||
});
|
||||
this.transferList.push(...items);
|
||||
// 开始传输
|
||||
this.startTransfer(items);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import type { ShortcutKeyItem } from './define';
|
||||
|
||||
// 首页推荐数量
|
||||
export const emptyRecommendCount = 7;
|
||||
|
||||
// 终端 tab
|
||||
export const TerminalTabs = {
|
||||
NEW_CONNECTION: {
|
||||
|
||||
@@ -93,8 +93,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)"
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)"
|
||||
@expand="loadExecHost">
|
||||
<!-- 展开表格 -->
|
||||
<template #expand-row="{ record }">
|
||||
@@ -148,7 +148,7 @@
|
||||
type="text"
|
||||
size="mini"
|
||||
title="ctrl + 左键新页面打开"
|
||||
@click="(e) => emits('viewLog', record.id, e.ctrlKey)">
|
||||
@click="(e: any) => emits('viewLog', record.id, e.ctrlKey)">
|
||||
日志
|
||||
</a-button>
|
||||
<!-- 中断 -->
|
||||
|
||||
@@ -421,7 +421,7 @@
|
||||
|
||||
.command-editor {
|
||||
width: 100%;
|
||||
height: calc(100vh - 318px);
|
||||
height: calc(100vh - 324px);
|
||||
}
|
||||
|
||||
:deep(.arco-input-append) {
|
||||
|
||||
@@ -84,8 +84,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- cron -->
|
||||
<template #expression="{ record }">
|
||||
<span class="copy-left"
|
||||
@@ -118,7 +118,7 @@
|
||||
:unchecked-text="getDictValue(execJobStatusKey, ExecJobStatus.DISABLED)"
|
||||
:checked-value="ExecJobStatus.ENABLED"
|
||||
:unchecked-value="ExecJobStatus.DISABLED"
|
||||
:before-change="s => updateStatus(record.id, s as number)" />
|
||||
:before-change="(s: number) => updateStatus(record.id, s)" />
|
||||
<!-- 状态 不可编辑 -->
|
||||
<a-tag v-else :color="getDictValue(execJobStatusKey, record.status, 'color')">
|
||||
{{ getDictValue(execJobStatusKey, record.status) }}
|
||||
|
||||
@@ -91,8 +91,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 配置项 -->
|
||||
<template #keyName="{ record }">
|
||||
<span class="text-copy" @click="copy(record.keyName)">{{ record.keyName }}</span>
|
||||
|
||||
@@ -77,8 +77,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 配置项 -->
|
||||
<template #keyName="{record}">
|
||||
{{ record.keyName }}<span style="margin: 0 4px;">-</span>{{ record.keyDescription }}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
position="left"
|
||||
:lazy-load="true"
|
||||
:destroy-on-hide="true"
|
||||
@tab-click="k => clickTab(k as string)">
|
||||
@tab-click="(k: string) => clickTab(k)">
|
||||
<!-- 个人信息 -->
|
||||
<a-tab-pane key="mineInfo"
|
||||
v-if="!user || hasPermission('infra:system-user:update')"
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 操作模块 -->
|
||||
<template #module="{ record }">
|
||||
<span>{{ getDictValue(operatorLogModuleKey, record.module) }}</span>
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 操作模块 -->
|
||||
<template #module="{ record }">
|
||||
<span>{{ getDictValue(operatorLogModuleKey, record.module) }}</span>
|
||||
|
||||
@@ -60,8 +60,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 编码 -->
|
||||
<template #code="{ record }">
|
||||
<a-tag>{{ record.code }}</a-tag>
|
||||
@@ -77,7 +77,7 @@
|
||||
:unchecked-text="getDictValue(roleStatusKey, RoleStatus.DISABLED)"
|
||||
:checked-value="RoleStatus.ENABLED"
|
||||
:unchecked-value="RoleStatus.DISABLED"
|
||||
:before-change="(s) => updateStatus(record.id, s as number)" />
|
||||
:before-change="(s: number) => updateStatus(record.id, s)" />
|
||||
<!-- 无修改权限 -->
|
||||
<span v-else>
|
||||
<span class="circle" :style="{
|
||||
|
||||
@@ -88,8 +88,8 @@
|
||||
:data="tableRenderData"
|
||||
:pagination="pagination"
|
||||
:bordered="false"
|
||||
@page-change="(page) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size) => fetchTableData(1, size)">
|
||||
@page-change="(page: number) => fetchTableData(page, pagination.pageSize)"
|
||||
@page-size-change="(size: number) => fetchTableData(1, size)">
|
||||
<!-- 用户名 -->
|
||||
<template #username="{ record }">
|
||||
<span class="text-copy" @click="copy(record.username)">
|
||||
@@ -107,7 +107,7 @@
|
||||
:unchecked-text="getDictValue(userStatusKey, UserStatus.DISABLED)"
|
||||
:checked-value="UserStatus.ENABLED"
|
||||
:unchecked-value="UserStatus.DISABLED"
|
||||
:before-change="(s) => updateStatus(record.id, s as number)" />
|
||||
:before-change="(s: number) => updateStatus(record.id, s)" />
|
||||
<!-- 无修改权限 -->
|
||||
<span v-else>
|
||||
<span class="circle" :style="{
|
||||
|
||||
Reference in New Issue
Block a user