Feat: useInstanceState hook

This commit is contained in:
unitwk 2023-08-31 23:57:34 +08:00
parent 276dc729ad
commit 386dc0c7fb
5 changed files with 232 additions and 43 deletions

View File

@ -14,7 +14,8 @@ export function executeRequest<T>(config: RequestConfig) {
{
immediate: false,
shallow: false as any,
throwError: true
throwError: true,
resetOnExecute: false
}
);
}

View File

@ -0,0 +1,138 @@
import type { InstanceDetail, MapData } from "@/types";
import { t } from "@/lang/i18n";
import { computed, onMounted, onUnmounted, ref, type Ref } from "vue";
import { getInstanceInfo } from "@/services/apis/instance";
export const INSTANCE_STATUS_TEXT: MapData<string> = {
"-1": t("维护中"),
"0": t("未运行"),
"1": t("停止中"),
"2": t("启动中"),
"3": t("运行中")
};
export const TYPE_UNIVERSAL = "universal";
export const TYPE_WEB_SHELL = "universal/web_shell";
export const TYPE_MINECRAFT_MCDR = "universal/mcdr";
export const TYPE_MINECRAFT_JAVA = "minecraft/java";
export const TYPE_MINECRAFT_BUKKIT = "minecraft/java/bukkit";
export const TYPE_MINECRAFT_SPIGOT = "minecraft/java/spigot";
export const TYPE_MINECRAFT_PAPER = "minecraft/java/paper";
export const TYPE_MINECRAFT_FORGE = "minecraft/java/forge";
export const TYPE_MINECRAFT_FABRIC = "minecraft/java/fabric";
export const TYPE_MINECRAFT_BUNGEECORD = "minecraft/java/bungeecord";
export const TYPE_MINECRAFT_VELOCITY = "minecraft/java/velocity";
export const TYPE_MINECRAFT_GEYSER = "minecraft/java/geyser";
export const TYPE_MINECRAFT_SPONGE = "minecraft/java/sponge";
export const TYPE_MINECRAFT_MOHIST = "minecraft/java/mohist";
export const TYPE_MINECRAFT_BEDROCK = "minecraft/bedrock";
export const TYPE_MINECRAFT_BDS = "minecraft/bedrock/bds";
export const TYPE_MINECRAFT_NUKKIT = "minecraft/bedrock/nukkit";
export const TYPE_STEAM_SERVER_UNIVERSAL = "steam/universal";
export const INSTANCE_TYPE_TRANSLATION: MapData<string> = {
[TYPE_UNIVERSAL]: "General Console Application",
[TYPE_STEAM_SERVER_UNIVERSAL]: "Steam Game Server",
[TYPE_MINECRAFT_JAVA]: "MC Java Edition",
[TYPE_MINECRAFT_BEDROCK]: "MC Bedrock Edition",
[TYPE_MINECRAFT_SPIGOT]: "MC Spigot",
[TYPE_MINECRAFT_PAPER]: "MC Paper",
[TYPE_MINECRAFT_BUNGEECORD]: "MC BungeeCord",
[TYPE_MINECRAFT_VELOCITY]: "MC Velocity",
[TYPE_MINECRAFT_BDS]: "MC Bedrock",
[TYPE_MINECRAFT_SPONGE]: "MC Sponge",
[TYPE_MINECRAFT_FORGE]: "MC Forge",
[TYPE_MINECRAFT_FABRIC]: "MC Fabric",
[TYPE_MINECRAFT_BUKKIT]: "MC Bukkit",
[TYPE_MINECRAFT_GEYSER]: "MC Geyser",
[TYPE_MINECRAFT_MCDR]: "MC MCDR",
[TYPE_WEB_SHELL]: "Web Shell"
};
interface Params {
instanceId?: string;
daemonId?: string;
autoRefresh?: boolean;
instanceInfo?: Ref<InstanceDetail | undefined>;
}
export interface InstanceMoreDetail extends InstanceDetail {
moreInfo?: {
isRunning: boolean;
isStopped: boolean;
instanceTypeText: string;
statusText: string;
};
}
export function useInstanceMoreDetail(info: InstanceMoreDetail): InstanceMoreDetail {
const { statusText, isRunning, isStopped, instanceTypeText } = useInstanceInfo({
instanceInfo: ref(info)
});
info.moreInfo = {
statusText: statusText.value,
isRunning: isRunning.value,
isStopped: isStopped.value,
instanceTypeText: instanceTypeText.value
};
return info;
}
export function useInstanceInfo(params: Params) {
let task: NodeJS.Timer | undefined;
const { daemonId, instanceId, instanceInfo, autoRefresh } = params;
const { execute, state, isLoading, isReady } = getInstanceInfo();
let finalState = state;
if (instanceInfo) finalState = instanceInfo;
const isRunning = computed(() => finalState?.value?.status === 3);
const isStopped = computed(() => finalState?.value?.status === 0);
const instanceTypeText = computed(() => {
return INSTANCE_TYPE_TRANSLATION[String(finalState?.value?.config.type)] || t("未知类型");
});
const statusText = computed(
() => String(INSTANCE_STATUS_TEXT[String(finalState?.value?.status)]) || t("未知状态")
);
onMounted(async () => {
if (instanceId && daemonId) {
await execute({
params: {
uuid: instanceId,
remote_uuid: daemonId
}
});
if (autoRefresh) {
task = setInterval(async () => {
await execute({
params: {
uuid: instanceId,
remote_uuid: daemonId
}
});
}, 3000);
}
}
});
onUnmounted(() => {
if (task) clearInterval(task);
task = undefined;
});
return {
isLoading,
isReady,
instanceInfo: state,
execute,
statusText,
isRunning,
isStopped,
instanceTypeText
};
}

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
import CardPanel from "@/components/CardPanel.vue";
import type { LayoutCard } from "@/types/index";
import { ref, onMounted } from "vue";
import { ref, onMounted, computed } from "vue";
import { t } from "@/lang/i18n";
import {
SearchOutlined,
@ -17,6 +17,10 @@ import type { NodeStatus } from "../types/index";
import { message } from "ant-design-vue";
import { computeNodeName } from "../tools/nodes";
import Loading from "@/components/Loading.vue";
import { useInstanceInfo } from "@/hooks/useInstance";
import type { InstanceMoreDetail } from "../hooks/useInstance";
import { CheckCircleOutlined, ExclamationCircleOutlined } from "@ant-design/icons-vue";
import { useInstanceMoreDetail } from "../hooks/useInstance";
const props = defineProps<{
card: LayoutCard;
@ -33,6 +37,15 @@ const currentRemoteNode = ref<NodeStatus>();
const { execute: getNodes, state: nodes } = remoteNodeList();
const { execute: getInstances, state: instances, isLoading } = remoteInstances();
const instancesMoreInfo = computed(() => {
const newInstances: InstanceMoreDetail[] = [];
for (const instance of instances.value?.data || []) {
const instanceMoreInfo = useInstanceMoreDetail(instance);
newInstances.push(instanceMoreInfo);
}
return newInstances;
});
const initNodes = async () => {
await getNodes();
if (!nodes.value?.length) {
@ -133,7 +146,7 @@ const handleChangeNode = () => {};
</div>
</a-col>
<template v-if="!isLoading">
<a-col v-for="item in instances?.data" :key="item" :span="24" :md="6">
<a-col v-for="item in instancesMoreInfo" :key="item" :span="24" :md="6">
<CardPanel
class="instance-card"
style="height: 100%"
@ -144,11 +157,21 @@ const handleChangeNode = () => {};
<a-typography-paragraph>
<div>
{{ t("状态:") }}
{{ item.status }}
<span v-if="item.moreInfo?.isRunning" class="color-success">
<CheckCircleOutlined />
{{ item.moreInfo?.statusText }}
</span>
<span v-else-if="item.moreInfo?.isStopped" class="color-info">
{{ item.moreInfo?.statusText }}
</span>
<span v-else>
<ExclamationCircleOutlined />
{{ item.moreInfo?.statusText }}
</span>
</div>
<div>
{{ t("类型:") }}
{{ item.config.type }}
{{ item.moreInfo?.instanceTypeText }}
</div>
<div>
{{ t("启动时间:") }}

View File

@ -1,9 +1,10 @@
<script setup lang="ts">
import type { LayoutCard } from "@/types";
import { useLayoutCardTools } from "../../hooks/useCardTools";
import { getInstanceInfo } from "@/services/apis/instance";
import { onMounted } from "vue";
import { t } from "@/lang/i18n";
import { useInstanceInfo } from "@/hooks/useInstance";
import { CheckCircleOutlined, ExclamationCircleOutlined } from "@ant-design/icons-vue";
const props = defineProps<{
card: LayoutCard;
@ -14,7 +15,12 @@ const { getMetaOrRouteValue } = useLayoutCardTools(props.card);
const instanceId = getMetaOrRouteValue("instanceId");
const daemonId = getMetaOrRouteValue("daemonId");
const { execute, state: instanceInfo } = getInstanceInfo();
const { statusText, isRunning, isStopped, instanceTypeText, instanceInfo, execute } =
useInstanceInfo({
instanceId,
daemonId,
autoRefresh: true
});
onMounted(async () => {
if (instanceId && daemonId) {
@ -37,10 +43,21 @@ onMounted(async () => {
<a-typography-paragraph>
{{ t("名称:") }}{{ instanceInfo?.config.nickname }}
</a-typography-paragraph>
<a-typography-paragraph> {{ t("类型:") }}{{ instanceTypeText }} </a-typography-paragraph>
<a-typography-paragraph>
{{ t("类型:") }}{{ instanceInfo?.config.type }}
<span>{{ t("状态:") }}</span>
<span v-if="isRunning" class="color-success">
<CheckCircleOutlined />
{{ statusText }}
</span>
<span v-else-if="isStopped" class="color-info">
<ExclamationCircleOutlined />
{{ statusText }}
</span>
<span v-else>
{{ statusText }}
</span>
</a-typography-paragraph>
<a-typography-paragraph> {{ t("状态:") }}{{ instanceInfo?.status }} </a-typography-paragraph>
<a-typography-paragraph>
{{ t("最后启动:") }}{{ instanceInfo?.config.lastDatetime }}
</a-typography-paragraph>

View File

@ -3,11 +3,12 @@ import CardPanel from "@/components/CardPanel.vue";
import { t } from "@/lang/i18n";
import type { LayoutCard } from "@/types";
import {
CloudDownloadOutlined,
CodeOutlined,
DownOutlined,
PauseCircleOutlined,
PlayCircleOutlined,
PlaySquareOutlined
ReconciliationOutlined
} from "@ant-design/icons-vue";
import { arrayFilter } from "../../tools/array";
import { useTerminal } from "../../hooks/useTerminal";
@ -16,19 +17,22 @@ import { useLayoutCardTools } from "@/hooks/useCardTools";
import { getRandomId } from "../../tools/randId";
import IconBtn from "@/components/IconBtn.vue";
import { openInstance, stopInstance } from "@/services/apis/instance";
import { CloseOutlined } from "@ant-design/icons-vue";
const props = defineProps<{
card: LayoutCard;
}>();
const { getMetaOrRouteValue } = useLayoutCardTools(props.card);
const { execute, initTerminalWindow, sendCommand } = useTerminal();
const instanceId = getMetaOrRouteValue("instanceId");
const daemonId = getMetaOrRouteValue("daemonId");
const terminalDomId = computed(() => `terminal-window-${getRandomId()}`);
const commandInputValue = ref("");
const quickOperations = arrayFilter([
const quickOperations = computed(() =>
arrayFilter([
{
title: t("开启程序"),
icon: PlayCircleOutlined,
@ -57,27 +61,33 @@ const quickOperations = arrayFilter([
danger: true
}
}
]);
])
);
const instanceOperations = arrayFilter([
{
title: t("重启"),
icon: PlaySquareOutlined,
icon: ReconciliationOutlined,
click: () => {
console.log(3);
}
},
{
title: t("终止"),
icon: CloseOutlined,
click: () => {
console.log(3);
}
},
{
title: t("更新"),
icon: PlaySquareOutlined,
icon: CloudDownloadOutlined,
click: () => {
console.log(4);
}
}
]);
const { execute, initTerminalWindow, sendCommand } = useTerminal();
const handleSendCommand = () => {
sendCommand(commandInputValue.value);
commandInputValue.value = "";
@ -88,6 +98,7 @@ const initTerminal = () => {
if (dom) {
initTerminalWindow(dom);
}
throw new Error("init terminal failed");
};
onMounted(async () => {
@ -97,7 +108,6 @@ onMounted(async () => {
daemonId
});
}
initTerminal();
});
</script>