mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
210 lines
6.9 KiB
Vue
210 lines
6.9 KiB
Vue
<template>
|
|
<div class="card !p-2">
|
|
<el-row :gutter="5">
|
|
<el-col :span="4">
|
|
<el-input :placeholder="$t('docker.imageName')" v-model="params.name" plain clearable></el-input>
|
|
</el-col>
|
|
|
|
<el-col :span="4">
|
|
<EnumSelect v-model="params.state" :enums="ImageStateEnum" :placeholder="$t('docker.status')" clearable />
|
|
</el-col>
|
|
|
|
<el-col :span="4">
|
|
<div class="flex items-center gap-2">
|
|
<el-button @click="getImages" type="primary" icon="refresh" circle plain></el-button>
|
|
<el-upload :on-success="uploadSuccess" action="" :http-request="uploadImage" :headers="{ token }" :show-file-list="false" name="file">
|
|
<el-button type="primary" icon="upload" circle plain></el-button>
|
|
</el-upload>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
|
|
<el-table :data="filterTableDatas" v-loading="state.loadingImages">
|
|
<el-table-column prop="id" label="ID" :min-width="100" show-overflow-tooltip>
|
|
<template #default="{ row }">
|
|
<el-link type="primary" :underline="false">
|
|
{{ row.id.split(':')[1].substring(0, 12) }}
|
|
</el-link>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="tags" :label="$t('docker.tag')" :min-width="250">
|
|
<template #default="{ row }">
|
|
<el-tag v-for="tag in row.tags" :key="tag" type="primary">{{ tag || '-' }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="size" :label="$t('docker.size')" :min-width="50">
|
|
<template #default="{ row }">
|
|
{{ formatByteSize(row.size) }}
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="createTime" :label="$t('common.createTime')" width="160">
|
|
<template #default="scope">
|
|
{{ formatDate(scope.row.createTime) }}
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column prop="isUse" :label="$t('common.status')" :min-width="50">
|
|
<template #default="{ row }">
|
|
<EnumTag :enums="ImageStateEnum" :value="row.isUse" />
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column :label="$t('common.operation')" width="130">
|
|
<template #default="{ row }">
|
|
<el-button @click="exportImage(row)" type="warning" link plain>{{ $t('docker.export') }}</el-button>
|
|
|
|
<el-popconfirm :title="$t('docker.stopImageConfirm')" @confirm="imageRemove(row)" width="170">
|
|
<template #reference>
|
|
<el-button :disabled="row.isUse == ImageStateEnum.Used.value" type="danger" link plain>
|
|
{{ $t('common.delete') }}
|
|
</el-button>
|
|
</template>
|
|
</el-popconfirm>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<el-dialog
|
|
v-if="terminalDialog.visible"
|
|
:title="terminalDialog.title"
|
|
v-model="terminalDialog.visible"
|
|
width="80%"
|
|
:close-on-click-modal="false"
|
|
:modal="false"
|
|
@close="closeTerminal"
|
|
draggable
|
|
append-to-body
|
|
>
|
|
<TerminalBody ref="terminal" :socket-url="getDockerExecSocketUrl(params.host, terminalDialog.containerId)" height="560px" />
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, onMounted, reactive, toRefs } from 'vue';
|
|
import { dockerApi, getDockerExecSocketUrl } from '../api';
|
|
import { formatByteSize, formatDate } from '@/common/utils/format';
|
|
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
|
|
import { ImageStateEnum } from '../enums';
|
|
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
|
import { fuzzyMatchField } from '@/common/utils/string';
|
|
import TerminalBody from '@/components/terminal/TerminalBody.vue';
|
|
import config from '@/common/config';
|
|
import { joinClientParams } from '@/common/request';
|
|
import { getToken } from '@/common/utils/storage';
|
|
import { ElMessage } from 'element-plus';
|
|
import { i18n } from '@/i18n';
|
|
|
|
const props = defineProps({
|
|
host: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
});
|
|
|
|
const state = reactive({
|
|
params: {
|
|
host: props.host,
|
|
name: '',
|
|
state: null,
|
|
},
|
|
loadingImages: false,
|
|
images: [],
|
|
terminalDialog: {
|
|
visible: false,
|
|
title: '',
|
|
containerId: '',
|
|
},
|
|
});
|
|
|
|
const { params, terminalDialog } = toRefs(state);
|
|
|
|
const token = getToken();
|
|
|
|
onMounted(() => {
|
|
getImages();
|
|
});
|
|
|
|
const filterTableDatas = computed(() => {
|
|
let tables: any = state.images;
|
|
const nameSearch = state.params.name;
|
|
const stateSearch = state.params.state;
|
|
|
|
if (stateSearch != null) {
|
|
tables = tables.filter((table: any) => {
|
|
return table.isUse === stateSearch;
|
|
});
|
|
}
|
|
|
|
if (nameSearch) {
|
|
tables = fuzzyMatchField(nameSearch, tables, (table: any) => table.tags[0]);
|
|
}
|
|
|
|
return tables;
|
|
});
|
|
|
|
const getImages = async () => {
|
|
state.loadingImages = true;
|
|
try {
|
|
state.images = await dockerApi.images.request(state.params);
|
|
} finally {
|
|
state.loadingImages = false;
|
|
}
|
|
};
|
|
|
|
const exportImage = async (row: any) => {
|
|
const a = document.createElement('a');
|
|
a.setAttribute('href', `${config.baseApiUrl}/docker/images/save?host=${state.params.host}&tag=${row.tags[0]}&${joinClientParams()}`);
|
|
a.setAttribute('target', '_blank');
|
|
a.click();
|
|
};
|
|
|
|
const uploadImage = (content: any) => {
|
|
const params = new FormData();
|
|
// const path = state.nowPath;
|
|
params.append('file', content.file);
|
|
params.append('host', state.params.host);
|
|
params.append('token', token);
|
|
dockerApi.imageUpload
|
|
.xhrReq(params, {
|
|
headers: { 'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryF1uyUD0tWdqmJqpl' },
|
|
// onUploadProgress: onUploadProgress,
|
|
timeout: 3 * 60 * 60 * 1000,
|
|
})
|
|
.then(() => {
|
|
ElMessage.success(i18n.global.t('machine.uploadSuccess'));
|
|
setTimeout(() => {
|
|
getImages();
|
|
}, 3000);
|
|
})
|
|
.catch(() => {
|
|
// state.uploadProgressShow = false;
|
|
});
|
|
ElMessage.info(i18n.global.t('docker.imageUploading'));
|
|
};
|
|
|
|
const uploadSuccess = (res: any) => {
|
|
if (res.code !== 200) {
|
|
ElMessage.error(res.msg);
|
|
}
|
|
};
|
|
|
|
const imageRemove = async (row: any) => {
|
|
await dockerApi.imageRemove.request({ host: state.params.host, imageId: row.id });
|
|
getImages();
|
|
};
|
|
|
|
const openTerminal = (row: any) => {
|
|
state.terminalDialog.containerId = row.containerId;
|
|
state.terminalDialog.title = `Terminal - ${row.name}`;
|
|
state.terminalDialog.visible = true;
|
|
};
|
|
|
|
const closeTerminal = () => {
|
|
state.terminalDialog.visible = false;
|
|
};
|
|
</script>
|