mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-01-24 15:14:01 +08:00
commit
95b963f497
1
frontend/components.d.ts
vendored
1
frontend/components.d.ts
vendored
@ -22,6 +22,7 @@ declare module 'vue' {
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
AInputGroup: typeof import('ant-design-vue/es')['InputGroup']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
AMenu: typeof import('ant-design-vue/es')['Menu']
|
||||
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
|
||||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
||||
|
@ -4,6 +4,32 @@ import type { BaseUserInfo } from "@/types/user";
|
||||
import type { IPanelOverviewResponse } from "../../../../common/global";
|
||||
|
||||
// 此处 API 接口可以用中文写注释,后期再统一翻译成英语。
|
||||
// 面板安装
|
||||
export const panelInstall = useDefineApi<
|
||||
{
|
||||
data: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
},
|
||||
any
|
||||
>({
|
||||
url: "/api/auth/install",
|
||||
method: "POST"
|
||||
});
|
||||
|
||||
// 安装前更新相关配置
|
||||
export const updateSettings = useDefineApi<
|
||||
{
|
||||
data: {
|
||||
language: string;
|
||||
};
|
||||
},
|
||||
any
|
||||
>({
|
||||
url: "/api/overview/install",
|
||||
method: "PUT"
|
||||
});
|
||||
|
||||
// 面板状态
|
||||
export const panelStatus = useDefineApi<
|
||||
|
@ -1,74 +1,228 @@
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, reactive } from "vue";
|
||||
import CardPanel from "@/components/CardPanel.vue";
|
||||
import { t, i18n } from "@/lang/i18n";
|
||||
import { panelInstall, updateSettings } from "@/services/apis";
|
||||
import { message } from "ant-design-vue";
|
||||
import type { FormInstance } from "ant-design-vue";
|
||||
import { useAppRouters } from "@/hooks/useAppRouters";
|
||||
import { useAppStateStore } from "@/stores/useAppStateStore";
|
||||
|
||||
const skeletons = [
|
||||
{ span: 6, rows: 4 },
|
||||
{ span: 6, rows: 4 },
|
||||
{ span: 6, rows: 4 },
|
||||
{ span: 6, rows: 4 },
|
||||
{ span: 24, rows: 9 },
|
||||
{ span: 8, rows: 6 },
|
||||
{ span: 16, rows: 6 },
|
||||
{ span: 8, rows: 6 },
|
||||
{ span: 16, rows: 6 }
|
||||
];
|
||||
|
||||
const { updateUserInfo, state: appState } = useAppStateStore();
|
||||
const step = ref(1);
|
||||
const { toPage } = useAppRouters();
|
||||
const formRef = ref<FormInstance>();
|
||||
const formData = reactive({
|
||||
username: "",
|
||||
password: ""
|
||||
});
|
||||
|
||||
const { execute: createAdminUser } = panelInstall();
|
||||
const installLoading = ref(false);
|
||||
const createUser = async () => {
|
||||
try {
|
||||
installLoading.value = true;
|
||||
await formRef.value?.validate();
|
||||
await createAdminUser({
|
||||
data: formData
|
||||
});
|
||||
await updateUserInfo();
|
||||
step.value++;
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
message.error(err.message);
|
||||
} finally {
|
||||
installLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const { execute: execUpdateSettings, isLoading: nextStepLoading } = updateSettings();
|
||||
const selectLanguage = async (lang: "en_US" | "zh_CN") => {
|
||||
try {
|
||||
await execUpdateSettings({
|
||||
data: {
|
||||
language: lang
|
||||
}
|
||||
});
|
||||
i18n.global.locale = lang;
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
message.error(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const toQuickStart = () => {
|
||||
toPage({
|
||||
path: "/quickstart",
|
||||
query: {
|
||||
from_install: 1
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const toOverview = () => {
|
||||
toPage({
|
||||
path: "/",
|
||||
query: {
|
||||
from_install: 1
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
const language = window.navigator.language;
|
||||
if (language.includes("zh")) {
|
||||
await selectLanguage("zh_CN");
|
||||
} else {
|
||||
await selectLanguage("en_US");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-row :gutter="[24, 24]">
|
||||
<a-col :span="6">
|
||||
<a-col v-for="i in skeletons" :key="i" :span="i.span">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 4 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 4 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 4 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 4 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 9 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 6 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="16">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 6 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 6 }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
<a-col :span="16">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<a-skeleton :paragraph="{ rows: 6 }" />
|
||||
<a-skeleton :paragraph="{ rows: i.rows }" />
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<div class="install-page-container">
|
||||
<div v-if="step === 1" class="install-page-container" style="text-align: center">
|
||||
<CardPanel class="install-panel">
|
||||
<template #body> 安装页面 </template>
|
||||
<template #body>
|
||||
<a-typography>
|
||||
<a-typography-title :level="3">
|
||||
{{ t("欢迎使用 MCSManager 管理面板") }}
|
||||
</a-typography-title>
|
||||
<a-typography-paragraph>
|
||||
<a-typography-text>
|
||||
{{ t("开源,分布式,开箱即用,支持 Minecraft 游戏服务端和所有控制台程序的管理面板") }}
|
||||
</a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
</a-typography>
|
||||
<a-button
|
||||
v-if="appState.isInstall"
|
||||
disabled
|
||||
class="mt-45 mb-45"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="step = 2"
|
||||
>
|
||||
{{ t("面板已安装,不可重复安装") }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else
|
||||
:loading="nextStepLoading"
|
||||
class="mt-45 mb-45"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="step = 2"
|
||||
>
|
||||
{{ t("开始使用") }}
|
||||
</a-button>
|
||||
<a-typography>
|
||||
<a-typography-paragraph>
|
||||
<a-typography-text>
|
||||
<a href="https://mcsmanager.com/" target="_blank" rel="noopener noreferrer">
|
||||
Reference: https://mcsmanager.com/
|
||||
</a>
|
||||
</a-typography-text>
|
||||
<br />
|
||||
<a-typography-text> Released under the Apache-2.0 License. </a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
</a-typography>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</div>
|
||||
<div v-if="step === 2" class="install-page-container">
|
||||
<CardPanel class="install-panel">
|
||||
<template #body>
|
||||
<a-typography>
|
||||
<a-typography-title :level="3">
|
||||
{{ t("创建一个访问面板的管理员账号") }}
|
||||
</a-typography-title>
|
||||
<a-typography-paragraph>
|
||||
<a-typography-text>
|
||||
{{ t("用户名支持任何语言,请务必保证您的密码安全。") }}
|
||||
</a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
</a-typography>
|
||||
<a-form ref="formRef" :model="formData" :label-col="{ span: 4 }" autocomplete="off">
|
||||
<a-form-item
|
||||
:label="t('用户名')"
|
||||
name="username"
|
||||
:rules="[{ required: true, message: t('请输入用户名') }]"
|
||||
>
|
||||
<a-input v-model:value="formData.username" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:label="t('密码')"
|
||||
name="password"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{9,36}$/,
|
||||
message: t('密码必须是 9 到 36 个字符,并且包含大小写字母和数字')
|
||||
}
|
||||
]"
|
||||
>
|
||||
<a-input-password v-model:value="formData.password" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :wrapper-col="{ offset: 4, span: 16 }">
|
||||
<a-button :loading="installLoading" type="primary" @click="createUser">
|
||||
{{ t("创建账号") }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</div>
|
||||
<div v-if="step === 3" class="install-page-container">
|
||||
<CardPanel class="install-panel">
|
||||
<template #body>
|
||||
<a-typography>
|
||||
<a-typography-title :level="3">
|
||||
{{ t("大功告成!") }}
|
||||
</a-typography-title>
|
||||
<a-typography-paragraph>
|
||||
<a-typography-text>
|
||||
{{ t("最后,您是第一次使用此软件吗?") }}
|
||||
</a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
</a-typography>
|
||||
<div class="final-btn mb-15" @click="toQuickStart">
|
||||
<a-typography-title :level="5">
|
||||
{{ t("首次使用") }}
|
||||
</a-typography-title>
|
||||
<a-typography-text>
|
||||
{{ t("我们将引导你使用并部署你的应用程序。") }}
|
||||
</a-typography-text>
|
||||
</div>
|
||||
<div class="final-btn" @click="toOverview">
|
||||
<a-typography-title :level="5">
|
||||
{{ t("老用户") }}
|
||||
</a-typography-title>
|
||||
<a-typography-text>
|
||||
{{ t("以更专业化的界面供你使用。") }}
|
||||
</a-typography-text>
|
||||
</div>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</div>
|
||||
</template>
|
||||
@ -90,11 +244,28 @@
|
||||
|
||||
.install-panel {
|
||||
transition: all 0.6s;
|
||||
max-width: 420px;
|
||||
max-height: 400px;
|
||||
max-width: 460px;
|
||||
max-height: 360px;
|
||||
width: 100%;
|
||||
background-color: var(--login-panel-bg);
|
||||
backdrop-filter: saturate(120%) blur(12px);
|
||||
padding: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.final-btn {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--color-gray-2);
|
||||
background-color: var(--color-gray-2);
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: all 0.4s;
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--color-gray-8);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ const selectType = (type: number) => {
|
||||
case 5:
|
||||
dockerFile.value = defaultDockerFile;
|
||||
name.value = "mcsm-custom";
|
||||
version.value = "lasted";
|
||||
version.value = "latest";
|
||||
break;
|
||||
default:
|
||||
return message.error(t("未知的环境类型"));
|
||||
|
Loading…
Reference in New Issue
Block a user