mirror of
https://github.com/MCSManager/MCSManager.git
synced 2024-11-27 06:59:54 +08:00
Feat: reinstall instance ui
This commit is contained in:
parent
445e2d2273
commit
d9bccda215
@ -230,13 +230,7 @@ export const createInstance = useDefineApi<
|
||||
url: "/api/instance"
|
||||
});
|
||||
|
||||
export const quickInstallListAddr = useDefineApi<
|
||||
any,
|
||||
{
|
||||
languages: LabelValueOption[];
|
||||
packages: QuickStartTemplate[];
|
||||
}
|
||||
>({
|
||||
export const quickInstallListAddr = useDefineApi<any, QuickStartTemplate>({
|
||||
url: "/api/instance/quick_install_list",
|
||||
method: "GET"
|
||||
});
|
||||
@ -439,3 +433,19 @@ export const scheduleCreate = useDefineApi<
|
||||
url: "/api/protected_schedule",
|
||||
method: "POST"
|
||||
});
|
||||
|
||||
export const reinstallInstance = useDefineApi<
|
||||
{
|
||||
params: {
|
||||
daemonId: string;
|
||||
uuid: string;
|
||||
};
|
||||
data: {
|
||||
targetUrl: string;
|
||||
};
|
||||
},
|
||||
boolean
|
||||
>({
|
||||
url: "/api/protected_instance/install_instance",
|
||||
method: "POST"
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, computed } from "vue";
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import CardPanel from "@/components/CardPanel.vue";
|
||||
import { t } from "@/lang/i18n";
|
||||
import type { LayoutCard } from "@/types";
|
||||
@ -10,7 +10,8 @@ import {
|
||||
PauseCircleOutlined,
|
||||
PlayCircleOutlined,
|
||||
RedoOutlined,
|
||||
LaptopOutlined
|
||||
LaptopOutlined,
|
||||
InteractionOutlined
|
||||
} from "@ant-design/icons-vue";
|
||||
import { CheckCircleOutlined, InfoCircleOutlined } from "@ant-design/icons-vue";
|
||||
import { arrayFilter } from "../../tools/array";
|
||||
@ -30,6 +31,7 @@ import { GLOBAL_INSTANCE_NAME } from "../../config/const";
|
||||
import { INSTANCE_STATUS } from "@/types/const";
|
||||
import { reportErrorMsg } from "@/tools/validator";
|
||||
import TerminalCore from "@/components/TerminalCore.vue";
|
||||
import Reinstall from "./dialogs/Reinstall.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
card: LayoutCard;
|
||||
@ -38,6 +40,7 @@ const props = defineProps<{
|
||||
const { isPhone } = useScreen();
|
||||
const { getMetaOrRouteValue } = useLayoutCardTools(props.card);
|
||||
const { execute, state: instanceInfo, isStopped, isRunning } = useTerminal();
|
||||
const reinstallDialog = ref<InstanceType<typeof Reinstall>>();
|
||||
|
||||
const instanceId = getMetaOrRouteValue("instanceId");
|
||||
const daemonId = getMetaOrRouteValue("daemonId");
|
||||
@ -48,6 +51,14 @@ const updateCmd = computed(() => (instanceInfo.value?.config.updateCommand ? tru
|
||||
const instanceStatusText = computed(() => INSTANCE_STATUS[instanceInfo.value?.status ?? -1]);
|
||||
const quickOperations = computed(() =>
|
||||
arrayFilter([
|
||||
{
|
||||
title: t("重装"),
|
||||
icon: InteractionOutlined,
|
||||
type: "danger",
|
||||
click: () => reinstallDialog.value?.openDialog(),
|
||||
props: {},
|
||||
condition: () => isStopped.value
|
||||
},
|
||||
{
|
||||
title: t("TXT_CODE_57245e94"),
|
||||
icon: PlayCircleOutlined,
|
||||
@ -298,6 +309,8 @@ onMounted(async () => {
|
||||
/>
|
||||
</template>
|
||||
</CardPanel>
|
||||
|
||||
<Reinstall ref="reinstallDialog" :daemon-id="daemonId ?? ''" :instance-id="instanceId ?? ''" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
211
frontend/src/widgets/instance/dialogs/Reinstall.vue
Normal file
211
frontend/src/widgets/instance/dialogs/Reinstall.vue
Normal file
@ -0,0 +1,211 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, reactive } from "vue";
|
||||
import { getCurrentLang, t } from "@/lang/i18n";
|
||||
import { Modal } from "ant-design-vue";
|
||||
import { reportErrorMsg } from "@/tools/validator";
|
||||
import { quickInstallListAddr, reinstallInstance } from "@/services/apis/instance";
|
||||
import type { QuickStartPackages } from "@/types";
|
||||
|
||||
const props = defineProps<{
|
||||
daemonId: string;
|
||||
instanceId: string;
|
||||
}>();
|
||||
|
||||
const open = ref(false);
|
||||
const title = ref("");
|
||||
const openDialog = async () => {
|
||||
open.value = true;
|
||||
try {
|
||||
await getQuickInstallListAddr();
|
||||
if (!appList.value || appList.value.length === 0) {
|
||||
title.value = t("TXT_CODE_c534ca49");
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(err.message);
|
||||
return reportErrorMsg(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const {
|
||||
state: presetList,
|
||||
execute: getQuickInstallListAddr,
|
||||
isLoading: appListLoading
|
||||
} = quickInstallListAddr();
|
||||
|
||||
const ALL_LANG_KEY = "all";
|
||||
const searchForm = reactive({
|
||||
language: getCurrentLang()
|
||||
});
|
||||
|
||||
const appList = computed(() => {
|
||||
// For MCSManager v9
|
||||
const v9List: any[] = presetList.value as unknown as any[];
|
||||
if (v9List?.[0]?.info && v9List?.[0]?.mc) {
|
||||
const list = v9List.map((v) => {
|
||||
return {
|
||||
...v,
|
||||
language: ALL_LANG_KEY,
|
||||
title: v.mc,
|
||||
runtime: `Java ${v.java}+`,
|
||||
description: v.info,
|
||||
hardware: v.remark,
|
||||
size: `${v.size}MB`
|
||||
};
|
||||
});
|
||||
return list as unknown as QuickStartPackages[];
|
||||
}
|
||||
// Check
|
||||
if (!presetList.value?.packages || !presetList.value?.languages) {
|
||||
return [];
|
||||
}
|
||||
let list = presetList.value?.packages;
|
||||
if (searchForm.language)
|
||||
list = list.filter(
|
||||
(item) => item.language === searchForm.language || searchForm.language === ALL_LANG_KEY
|
||||
);
|
||||
return list;
|
||||
});
|
||||
const appLangList = computed(() => {
|
||||
if (presetList.value?.languages instanceof Array) {
|
||||
return presetList.value?.languages;
|
||||
}
|
||||
return [
|
||||
{
|
||||
label: t("TXT_CODE_8a30e150"),
|
||||
value: ALL_LANG_KEY
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const handleSelectTemplate = (item: QuickStartPackages) => {
|
||||
Modal.confirm({
|
||||
title: t("警告"),
|
||||
content: t("选择此模板后,该实例的所有数据将会被删除,是否继续?"),
|
||||
okText: t("继续"),
|
||||
async onOk() {
|
||||
try {
|
||||
await reinstallInstance().execute({
|
||||
params: {
|
||||
daemonId: props.daemonId,
|
||||
uuid: props.instanceId
|
||||
},
|
||||
data: {
|
||||
targetUrl: item.targetLink
|
||||
}
|
||||
});
|
||||
cancel();
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
return reportErrorMsg(err.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const cancel = async () => {
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
openDialog
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:open="open"
|
||||
centered
|
||||
width="100%"
|
||||
:cancel-text="t('TXT_CODE_3b1cc020')"
|
||||
:mask-closable="false"
|
||||
:confirm-loading="false"
|
||||
:footer="null"
|
||||
@cancel="cancel"
|
||||
>
|
||||
<template #title> {{ t("选择实例模板") }} </template>
|
||||
<a-row v-if="appListLoading" :gutter="[24, 24]" style="height: 100%">
|
||||
<a-col :span="24">
|
||||
<div style="height: 50vh">
|
||||
<Loading />
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row v-else :gutter="[24, 24]" style="height: 100%">
|
||||
<a-col :span="24" :md="24">
|
||||
<a-form layout="horizontal" :model="searchForm">
|
||||
<a-form-item class="mb-0">
|
||||
<a-radio-group v-model:value="searchForm.language">
|
||||
<a-radio-button v-for="item in appLangList" :key="item.value" :value="item.value">
|
||||
{{ item.label }}
|
||||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<fade-up-animation>
|
||||
<a-col
|
||||
v-for="item in appList"
|
||||
:key="item.targetLink + item.title"
|
||||
:span="24"
|
||||
:xl="6"
|
||||
:lg="8"
|
||||
:sm="12"
|
||||
>
|
||||
<div style="display: flex; flex-grow: 1; flex-direction: column; height: 100%">
|
||||
<CardPanel style="flex-grow: 1">
|
||||
<template #title>
|
||||
<div class="ellipsis-text" style="max-width: 280px">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</template>
|
||||
<template #body>
|
||||
<div style="min-height: 220px; position: relative">
|
||||
<a-typography-paragraph
|
||||
:ellipsis="{ rows: 3, expandable: true }"
|
||||
:content="item.description"
|
||||
>
|
||||
</a-typography-paragraph>
|
||||
<a-typography-paragraph>
|
||||
<a-typography-text class="color-info">
|
||||
<div>{{ t("TXT_CODE_18b94497") }}: {{ item.runtime }}</div>
|
||||
<div>{{ t("TXT_CODE_683e3033") }}: {{ item.hardware }}</div>
|
||||
<div>{{ t("TXT_CODE_94bb113a") }}: {{ item.size }}</div>
|
||||
</a-typography-text>
|
||||
<br />
|
||||
<a-typography-text class="color-info"> </a-typography-text>
|
||||
<br />
|
||||
<a-typography-text class="color-info"> </a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<a-button
|
||||
block
|
||||
type="primary"
|
||||
ghost
|
||||
style="max-width: 180px"
|
||||
@click="handleSelectTemplate(item)"
|
||||
>
|
||||
<template #icon>
|
||||
<DownloadOutlined />
|
||||
</template>
|
||||
<span>{{ t("TXT_CODE_1704ea49") }}</span>
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</div>
|
||||
</a-col>
|
||||
</fade-up-animation>
|
||||
</a-row>
|
||||
</a-modal>
|
||||
</template>
|
Loading…
Reference in New Issue
Block a user