feat: add terminal icon for installed App (#9331)

* feat: add terminal icon for installed App

* refactor: 应用卡片打开容器终端,适配多个容器情况
This commit is contained in:
BugKing 2025-07-01 15:45:57 +08:00 committed by GitHub
parent 810ea9c421
commit 7a45548387
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 47 additions and 5 deletions

View file

@ -131,6 +131,25 @@
</el-button> </el-button>
</el-tooltip> </el-tooltip>
</span> </span>
<span class="ml-1">
<el-tooltip
v-if="mode !== 'upgrade'"
effect="dark"
:content="$t('menu.terminal')"
placement="top"
>
<el-button
type="primary"
link
@click="openTerminal(installed)"
:disabled="installed.status !== 'Running'"
>
<el-icon>
<SvgIcon iconName="p-terminal2" />
</el-icon>
</el-button>
</el-tooltip>
</span>
<span class="ml-1" v-if="mode === 'installed'"> <span class="ml-1" v-if="mode === 'installed'">
<el-tooltip <el-tooltip
effect="dark" effect="dark"
@ -385,6 +404,7 @@
<PortJumpDialog ref="dialogPortJumpRef" /> <PortJumpDialog ref="dialogPortJumpRef" />
<AppIgnore ref="ignoreRef" @close="search" /> <AppIgnore ref="ignoreRef" @close="search" />
<ComposeLogs ref="composeLogRef" /> <ComposeLogs ref="composeLogRef" />
<TerminalDialog ref="dialogTerminalRef" />
<TaskLog ref="taskLogRef" @close="search" /> <TaskLog ref="taskLogRef" @close="search" />
<Detail ref="detailRef" /> <Detail ref="detailRef" />
<IgnoreApp ref="ignoreAppRef" @close="search" /> <IgnoreApp ref="ignoreAppRef" @close="search" />
@ -404,6 +424,7 @@ import AppParams from './detail/index.vue';
import AppUpgrade from './upgrade/index.vue'; import AppUpgrade from './upgrade/index.vue';
import AppIgnore from './ignore/index.vue'; import AppIgnore from './ignore/index.vue';
import ComposeLogs from '@/components/log/compose/index.vue'; import ComposeLogs from '@/components/log/compose/index.vue';
import TerminalDialog from '@/views/container/container/terminal/index.vue';
import { App } from '@/api/interface/app'; import { App } from '@/api/interface/app';
import Status from '@/components/status/index.vue'; import Status from '@/components/status/index.vue';
import { getAge, jumpToPath, toLink } from '@/utils/util'; import { getAge, jumpToPath, toLink } from '@/utils/util';
@ -415,6 +436,7 @@ import Detail from '@/views/app-store/detail/index.vue';
import IgnoreApp from '@/views/app-store/installed/ignore/create/index.vue'; import IgnoreApp from '@/views/app-store/installed/ignore/create/index.vue';
import { getAgentSettingByKey } from '@/api/modules/setting'; import { getAgentSettingByKey } from '@/api/modules/setting';
import Tags from '@/views/app-store/components/tag.vue'; import Tags from '@/views/app-store/components/tag.vue';
import SvgIcon from '@/components/svg-icon/svg-icon.vue';
const data = ref<any>(); const data = ref<any>();
const loading = ref(false); const loading = ref(false);
@ -442,6 +464,7 @@ const upgradeRef = ref();
const ignoreRef = ref(); const ignoreRef = ref();
const dialogPortJumpRef = ref(); const dialogPortJumpRef = ref();
const composeLogRef = ref(); const composeLogRef = ref();
const dialogTerminalRef = ref();
const taskLogRef = ref(); const taskLogRef = ref();
const searchReq = reactive({ const searchReq = reactive({
page: 1, page: 1,
@ -700,6 +723,11 @@ const openLog = (row: any) => {
} }
}; };
const openTerminal = (row: any) => {
const title = i18n.global.t('app.app') + ' ' + row.name;
dialogTerminalRef.value!.acceptParams({ containerID: row.container, title: title });
};
const getConfig = async () => { const getConfig = async () => {
try { try {
const res = await getAgentSettingByKey('SystemIP'); const res = await getAgentSettingByKey('SystemIP');
@ -778,4 +806,9 @@ onUnmounted(() => {
margin-left: 0; margin-left: 0;
} }
} }
.svg-icon {
width: 100%;
height: 100%;
padding: 0;
}
</style> </style>

View file

@ -298,7 +298,8 @@ const onMonitor = (row: any) => {
const dialogTerminalRef = ref(); const dialogTerminalRef = ref();
const onTerminal = (row: any) => { const onTerminal = (row: any) => {
dialogTerminalRef.value!.acceptParams({ containerID: row.containerID, container: row.name }); const title = i18n.global.t('menu.container') + ' ' + row.name;
dialogTerminalRef.value!.acceptParams({ containerID: row.containerID, title: title });
}; };
const buttons = [ const buttons = [

View file

@ -614,7 +614,8 @@ const onMonitor = (row: any) => {
const dialogTerminalRef = ref(); const dialogTerminalRef = ref();
const onTerminal = (row: any) => { const onTerminal = (row: any) => {
dialogTerminalRef.value!.acceptParams({ containerID: row.containerID, container: row.name }); const title = i18n.global.t('menu.container') + ' ' + row.name;
dialogTerminalRef.value!.acceptParams({ containerID: row.containerID, title: title });
}; };
const onInspect = async (id: string) => { const onInspect = async (id: string) => {

View file

@ -9,6 +9,11 @@
> >
<template #content> <template #content>
<el-form ref="formRef" :model="form" label-position="top"> <el-form ref="formRef" :model="form" label-position="top">
<el-form-item :label="$t('menu.container')" prop="containerID" v-if="form.containerIDList.length > 1">
<el-select placeholder="container" clearable v-model="form.containerID">
<el-option v-for="item in form.containerIDList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.table.user')" prop="user"> <el-form-item :label="$t('commons.table.user')" prop="user">
<el-input placeholder="root" clearable v-model="form.user" /> <el-input placeholder="root" clearable v-model="form.user" />
</el-form-item> </el-form-item>
@ -67,18 +72,20 @@ const form = reactive({
command: '', command: '',
user: '', user: '',
containerID: '', containerID: '',
containerIDList: [],
}); });
const formRef = ref(); const formRef = ref();
const terminalRef = ref<InstanceType<typeof Terminal> | null>(null); const terminalRef = ref<InstanceType<typeof Terminal> | null>(null);
interface DialogProps { interface DialogProps {
containerID: string; containerID: string;
container: string; title: string;
} }
const acceptParams = async (params: DialogProps): Promise<void> => { const acceptParams = async (params: DialogProps): Promise<void> => {
terminalVisible.value = true; terminalVisible.value = true;
form.containerID = params.containerID; form.containerIDList = params.containerID.split(',');
title.value = params.container; form.containerID = form.containerIDList[0];
title.value = params.title;
form.isCustom = false; form.isCustom = false;
form.user = ''; form.user = '';
form.command = '/bin/sh'; form.command = '/bin/sh';