mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-02 11:58:01 +08:00
fix SSH 终端新增标签页打开方式
This commit is contained in:
parent
ecf26c1f2b
commit
f9ee62d30e
@ -5,6 +5,8 @@
|
||||
|
||||
### 🐣 新增功能
|
||||
|
||||
1. 【server】SSH 终端新增标签页打开方式(感谢@hu丶向...🤡)
|
||||
|
||||
### 🐞 解决BUG、优化功能
|
||||
|
||||
1. 【server】db 安全检查时机前置(是否开启 web 访问),避免突然关闭数据库(感谢@信徒)
|
||||
@ -35,6 +37,8 @@
|
||||
|
||||
> 此版本为不兼容升级,需要手动升级操作数据相关迁移,操作流程如下:
|
||||
|
||||
**(下述流程仅供简单思路参考,不同版本间存在部分差异,详细流程还请差异完整文档:[https://jpom.io/pages/upgrade/2.8.x-to-2.9.x](https://jpom.io/pages/upgrade/2.8.x-to-2.9.x) )**
|
||||
|
||||
1. 导出低版本数据
|
||||
1. 启动程序参数里面添加 --backup-h2
|
||||
2. linux 环境举例:`sh /xxxx/Server.sh restart --backup-h2`
|
||||
|
@ -101,6 +101,15 @@ public class SshController extends BaseServerController {
|
||||
return new JsonMessage<>(200, "", list);
|
||||
}
|
||||
|
||||
@GetMapping(value = "get-item.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<SshModel> getItem(@ValidatorItem String id) {
|
||||
SshModel byKey = sshService.getByKey(id, getRequest());
|
||||
Assert.notNull(byKey, "对应的 ssh 不存在");
|
||||
return new JsonMessage<>(200, "", byKey);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
|
@ -9,6 +9,15 @@ export function getSshList(params) {
|
||||
});
|
||||
}
|
||||
|
||||
// 查询单个 ssh
|
||||
export function getItem(params) {
|
||||
return axios({
|
||||
url: "/node/ssh/get-item.json",
|
||||
method: "get",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
// 检查 ssh 是否安装 插件端
|
||||
export function getSshCheckAgent(params) {
|
||||
return axios({
|
||||
|
@ -88,6 +88,7 @@
|
||||
|
||||
<a-menu-item>
|
||||
<a-tooltip
|
||||
placement="leftBottom"
|
||||
title="清除代码(仓库目录)为删除服务器中存储仓库目录里面的所有东西,删除后下次构建将重新拉起仓库里面的文件,一般用于解决服务器中文件和远程仓库中文件有冲突时候使用。执行时间取决于源码目录大小和文件数量如超时请耐心等待,或稍后重试"
|
||||
>
|
||||
<a-button size="small" type="danger" :disabled="!record.sourceDirExist" @click="handleClear(record)">清除代码 </a-button>
|
||||
@ -735,30 +736,30 @@
|
||||
<script>
|
||||
import CustomSelect from "@/components/customSelect";
|
||||
import BuildLog from "./log";
|
||||
import { getRepositoryListAll } from "@/api/repository";
|
||||
import {getRepositoryListAll} from "@/api/repository";
|
||||
import {
|
||||
buildModeMap,
|
||||
clearBuid,
|
||||
deleteBuild,
|
||||
editBuild,
|
||||
getBranchList,
|
||||
buildModeMap,
|
||||
getBuildGroupAll,
|
||||
getBuildList,
|
||||
getTriggerUrl,
|
||||
releaseMethodMap,
|
||||
resetTrigger,
|
||||
startBuild,
|
||||
stopBuild,
|
||||
statusMap,
|
||||
getBuildGroupAll,
|
||||
stopBuild,
|
||||
} from "@/api/build-info";
|
||||
import { getDishPatchListAll, afterOptList, afterOptListSimple } from "@/api/dispatch";
|
||||
import { getProjectListAll, getNodeListAll } from "@/api/node";
|
||||
import { getSshListAll } from "@/api/ssh";
|
||||
import { itemGroupBy, parseTime } from "@/utils/time";
|
||||
import {afterOptList, afterOptListSimple, getDishPatchListAll} from "@/api/dispatch";
|
||||
import {getNodeListAll, getProjectListAll} from "@/api/node";
|
||||
import {getSshListAll} from "@/api/ssh";
|
||||
import {itemGroupBy, parseTime} from "@/utils/time";
|
||||
import codeEditor from "@/components/codeEditor";
|
||||
import { COMPUTED_PAGINATION, CHANGE_PAGE, PAGE_DEFAULT_LIST_QUERY, CRON_DATA_SOURCE } from "@/utils/const";
|
||||
import {CHANGE_PAGE, COMPUTED_PAGINATION, CRON_DATA_SOURCE, PAGE_DEFAULT_LIST_QUERY} from "@/utils/const";
|
||||
import Vue from "vue";
|
||||
import { dockerSwarmListAll, dockerSwarmServicesList } from "@/api/docker-swarm";
|
||||
import {dockerSwarmListAll, dockerSwarmServicesList} from "@/api/docker-swarm";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
87
web-vue/src/pages/ssh/full-terminal.vue
Normal file
87
web-vue/src/pages/ssh/full-terminal.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-spin :spinning="spinning">
|
||||
<a-card
|
||||
size="small"
|
||||
:bodyStyle="{
|
||||
height: `calc(100vh - 45px)`,
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<template v-if="sshData">
|
||||
<a-space>
|
||||
<div>{{ sshData.name }} ({{ sshData.host }})</div>
|
||||
|
||||
<a-button size="small" type="primary" :disabled="!sshData.fileDirs" @click="handleFile()">文件</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<template v-else>loading</template>
|
||||
</template>
|
||||
<a slot="extra" href="#"></a>
|
||||
<terminal v-if="sshData" :sshId="sshData.id" />
|
||||
<template v-else>
|
||||
<a-result status="404" title="404" sub-title="没有对应的SSH">
|
||||
<template #extra>
|
||||
<router-link :to="{ path: '/ssh', query: {} }">
|
||||
<a-button type="primary">返回首页</a-button>
|
||||
</router-link>
|
||||
</template>
|
||||
</a-result>
|
||||
</template>
|
||||
</a-card>
|
||||
</a-spin>
|
||||
<!-- 文件管理 -->
|
||||
<a-drawer v-if="sshData" :title="`${sshData.name} (${sshData.host}) 文件管理`" placement="right" width="90vw" :visible="drawerVisible" @close="onClose">
|
||||
<ssh-file v-if="drawerVisible" :ssh="sshData" />
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import terminal from "./terminal";
|
||||
import {getItem} from "@/api/ssh";
|
||||
import SshFile from "@/pages/ssh/ssh-file";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
terminal,
|
||||
SshFile,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
sshId: "",
|
||||
sshData: null,
|
||||
spinning: true,
|
||||
drawerVisible: false,
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
this.sshId = this.$route.query.id;
|
||||
if (this.sshId) {
|
||||
this.loadItemData();
|
||||
}
|
||||
},
|
||||
beforeDestroy() {},
|
||||
methods: {
|
||||
loadItemData() {
|
||||
getItem({
|
||||
id: this.sshId,
|
||||
}).then((res) => {
|
||||
this.spinning = false;
|
||||
if (res.code === 200) {
|
||||
this.sshData = res.data;
|
||||
}
|
||||
console.log(this.sshData);
|
||||
});
|
||||
},
|
||||
handleFile() {
|
||||
this.drawerVisible = true;
|
||||
},
|
||||
// 关闭抽屉层
|
||||
onClose() {
|
||||
this.drawerVisible = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -74,6 +74,11 @@
|
||||
<a-menu-item key="1">
|
||||
<a-button size="small" type="primary" icon="fullscreen" @click="handleTerminal(record, true)">全屏终端</a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item key="2">
|
||||
<router-link target="_blank" :to="{ path: '/full-terminal', query: { id: record.id, wid: getWorkspaceId } }">
|
||||
<a-button size="small" type="primary" icon="fullscreen"> 新标签终端</a-button>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
|
||||
@ -371,14 +376,14 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { deleteSsh, editSsh, getSshList, getSshCheckAgent, getSshOperationLogList, installAgentNode, getAgent, uploadAgent, syncToWorkspace } from "@/api/ssh";
|
||||
import {deleteSsh, editSsh, getAgent, getSshCheckAgent, getSshList, getSshOperationLogList, installAgentNode, syncToWorkspace, uploadAgent} from "@/api/ssh";
|
||||
import SshFile from "@/pages/ssh/ssh-file";
|
||||
import Terminal from "@/pages/ssh/terminal";
|
||||
import { parseTime } from "@/utils/time";
|
||||
import { COMPUTED_PAGINATION, CHANGE_PAGE, PAGE_DEFAULT_LIST_QUERY } from "@/utils/const";
|
||||
import { getWorkSpaceListAll } from "@/api/workspace";
|
||||
import {parseTime} from "@/utils/time";
|
||||
import {CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY} from "@/utils/const";
|
||||
import {getWorkSpaceListAll} from "@/api/workspace";
|
||||
import Vue from "vue";
|
||||
import { mapGetters } from "vuex";
|
||||
import {mapGetters} from "vuex";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -2,8 +2,8 @@
|
||||
<terminal :url="this.socketUrl" />
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
import { getWebSocketUrl } from "@/utils/const";
|
||||
import {mapGetters} from "vuex";
|
||||
import {getWebSocketUrl} from "@/utils/const";
|
||||
import terminal from "@/components/terminal";
|
||||
|
||||
// https://blog.csdn.net/qq_41840688/article/details/108636267
|
||||
@ -16,13 +16,13 @@ export default {
|
||||
sshId: {
|
||||
type: String,
|
||||
},
|
||||
nodeId: {
|
||||
type: String,
|
||||
default: "system",
|
||||
},
|
||||
tail: {
|
||||
type: String,
|
||||
},
|
||||
// nodeId: {
|
||||
// type: String,
|
||||
// default: "system",
|
||||
// },
|
||||
// tail: {
|
||||
// type: String,
|
||||
// },
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
@ -30,7 +30,7 @@ export default {
|
||||
computed: {
|
||||
...mapGetters(["getLongTermToken"]),
|
||||
socketUrl() {
|
||||
return getWebSocketUrl("/socket/ssh", `userId=${this.getLongTermToken}&id=${this.sshId}&nodeId=${this.nodeId}&type=ssh&tail=${this.tail}`);
|
||||
return getWebSocketUrl("/socket/ssh", `userId=${this.getLongTermToken}&id=${this.sshId}&nodeId=system&type=ssh&tail=${this.tail}`);
|
||||
},
|
||||
},
|
||||
mounted() {},
|
||||
|
@ -8,6 +8,7 @@ import store from "../store/index";
|
||||
|
||||
// 不需要鉴权的名单
|
||||
const whiteList = ["/login", "/install", "/system/ipAccess"];
|
||||
const noTabs = ["/full-terminal"];
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 检测白名单
|
||||
@ -27,6 +28,10 @@ router.beforeEach((to, from, next) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (noTabs.indexOf(to.path) !== -1) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
// 如果存在 token (已经登录)
|
||||
store.dispatch("loadSystemMenus").then(() => {
|
||||
// 存储 store
|
||||
|
@ -202,6 +202,11 @@ const router = new Router({
|
||||
name: "install",
|
||||
component: () => import("../pages/login/install"),
|
||||
},
|
||||
{
|
||||
path: "/full-terminal",
|
||||
name: "full-terminal",
|
||||
component: () => import("../pages/ssh/full-terminal"),
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
name: "404",
|
||||
|
Loading…
Reference in New Issue
Block a user