mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-04-06 17:10:29 +08:00
Feat: add loading ui & refactor settings
This commit is contained in:
parent
8573940e0b
commit
e5304c1f09
@ -1,12 +1,91 @@
|
||||
<!doctype html>
|
||||
<html lang="zh_CN">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Next MCSManager UI 1</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<title>MCSManager Panel</title>
|
||||
|
||||
<style>
|
||||
#before-app-mounted {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(239, 239, 239, 0.801);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
#before-app-mounted .loading {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
text-align: center;
|
||||
left: 0px;
|
||||
animation: rectangle infinite 1s ease-in-out -0.2s;
|
||||
background-color: #000;
|
||||
}
|
||||
#before-app-mounted .loading:after,
|
||||
#before-app-mounted .loading:before {
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
height: 10px;
|
||||
content: "";
|
||||
background-color: #000;
|
||||
}
|
||||
#before-app-mounted .loading:before {
|
||||
left: -14px;
|
||||
animation: rectangle infinite 1s ease-in-out -0.4s;
|
||||
}
|
||||
#before-app-mounted .loading:after {
|
||||
right: -14px;
|
||||
animation: rectangle infinite 1s ease-in-out;
|
||||
}
|
||||
#before-app-mounted .loading-box {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
@keyframes rectangle {
|
||||
0%,
|
||||
100%,
|
||||
80% {
|
||||
height: 20px;
|
||||
box-shadow: 0 0 #000;
|
||||
}
|
||||
40% {
|
||||
height: 30px;
|
||||
box-shadow: 0 -20px #000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
window.closeLoadingContainer = function () {
|
||||
document.getElementById("before-app-mounted").setAttribute("style", "display:none");
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="before-app-mounted">
|
||||
<noscript>You need to enable JavaScript to run this Website.</noscript>
|
||||
<div class="loading-box">
|
||||
<div style="min-height: 50px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
BIN
frontend/public/favicon.ico
Normal file → Executable file
BIN
frontend/public/favicon.ico
Normal file → Executable file
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 66 KiB |
2
frontend/public/robots.txt
Executable file
2
frontend/public/robots.txt
Executable file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
@ -6,14 +6,11 @@ import enUS from "ant-design-vue/es/locale/en_US";
|
||||
import dayjs from "dayjs";
|
||||
import "dayjs/locale/zh-cn";
|
||||
import "dayjs/locale/en";
|
||||
import { onMounted, ref, unref } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useAppConfigStore } from "@/stores/useAppConfigStore";
|
||||
import { useAppStateStore } from "@/stores/useAppStateStore";
|
||||
import { theme } from "ant-design-vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import InputDialogProvider from "./components/InputDialogProvider.vue";
|
||||
import { userInfoApi } from "./services/apis";
|
||||
import { t } from "./lang/i18n";
|
||||
import { router } from "./config/router";
|
||||
|
||||
const { getCurrentLanguage, isDarkTheme } = useAppConfigStore();
|
||||
@ -46,12 +43,14 @@ if (isDarkUI) {
|
||||
|
||||
import { Button, Select, Input, Table, ConfigProvider } from "ant-design-vue";
|
||||
import MyselfInfoDialog from "./components/MyselfInfoDialog.vue";
|
||||
import { closeAppLoading } from "./tools/dom";
|
||||
|
||||
[Button, Select, Input, Table].forEach((element) => {
|
||||
element.props.size.default = "large";
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
closeAppLoading();
|
||||
if (!state.userInfo?.token) {
|
||||
router.push({
|
||||
path: "/login"
|
||||
|
@ -8,4 +8,5 @@
|
||||
--font-h1: 38px;
|
||||
|
||||
--phone-width: 992px;
|
||||
--app-max-width: 1440px;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
--new-card-list-background-color-menu: rgba(129, 129, 129, 0.8);
|
||||
--float-box-bg-color: rgba(235, 235, 235, 0.2);
|
||||
--gray-border-color: var(--color-gray-10);
|
||||
--app-max-width: 1440px;
|
||||
|
||||
--login-panel-bg: rgba(56, 56, 56, 0.8);
|
||||
|
||||
--app-header-bg: var(--color-gray-2);
|
||||
|
@ -8,7 +8,7 @@
|
||||
--new-card-list-background-color-menu: rgba(255, 255, 255, 0.8);
|
||||
--float-box-bg-color: rgba(235, 235, 235, 0.2);
|
||||
--gray-border-color: var(--color-gray-10);
|
||||
--app-max-width: 1440px;
|
||||
|
||||
--login-panel-bg: rgb(255, 255, 255, 0.8);
|
||||
|
||||
--app-header-bg: var(--color-gray-10);
|
||||
|
@ -165,7 +165,7 @@ const handleTabClick = (value: string) => {
|
||||
|
||||
.new-card-list {
|
||||
margin: auto;
|
||||
max-width: 1440px;
|
||||
max-width: var(--app-max-width);
|
||||
}
|
||||
|
||||
.card-list-container {
|
||||
|
@ -16,14 +16,18 @@ import { userInfoApi } from "./services/apis";
|
||||
import { useAppStateStore } from "./stores/useAppStateStore";
|
||||
|
||||
(async function () {
|
||||
const { updateUserInfo } = useAppStateStore();
|
||||
const { execute: reqUserInfo } = userInfoApi();
|
||||
const info = await reqUserInfo();
|
||||
updateUserInfo(info.value);
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
app.use(i18n);
|
||||
app.mount("#app");
|
||||
try {
|
||||
const { updateUserInfo } = useAppStateStore();
|
||||
const { execute: reqUserInfo } = userInfoApi();
|
||||
const info = await reqUserInfo();
|
||||
updateUserInfo(info.value);
|
||||
} catch (err) {
|
||||
console.warn("Failed to get user info: ", err);
|
||||
} finally {
|
||||
const app = createApp(App);
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
app.use(i18n);
|
||||
app.mount("#app");
|
||||
}
|
||||
})();
|
||||
|
@ -1,15 +1,19 @@
|
||||
export function findParentWithClass(element: HTMLElement, className: string): HTMLElement | null {
|
||||
if (element.classList.contains(className)) {
|
||||
return element
|
||||
return element;
|
||||
}
|
||||
let parentElement = element.parentElement
|
||||
let parentElement = element.parentElement;
|
||||
|
||||
while (parentElement !== null) {
|
||||
if (parentElement.classList.contains(className)) {
|
||||
return parentElement
|
||||
return parentElement;
|
||||
}
|
||||
parentElement = parentElement.parentElement
|
||||
parentElement = parentElement.parentElement;
|
||||
}
|
||||
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
export function closeAppLoading() {
|
||||
(window as any).closeLoadingContainer();
|
||||
}
|
||||
|
@ -144,28 +144,32 @@ const loginSuccess = () => {
|
||||
{{ t("使用服务器的 MCSManager 账号进入面板") }}
|
||||
</a-typography-paragraph>
|
||||
<div>
|
||||
<a-input
|
||||
v-model:value="formData.username"
|
||||
:placeholder="t('账号')"
|
||||
size="large"
|
||||
>
|
||||
<template #suffix>
|
||||
<UserOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||
</template>
|
||||
</a-input>
|
||||
<form>
|
||||
<a-input
|
||||
v-model:value="formData.username"
|
||||
:placeholder="t('账号')"
|
||||
size="large"
|
||||
autocomplete="off"
|
||||
>
|
||||
<template #suffix>
|
||||
<UserOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||
</template>
|
||||
</a-input>
|
||||
|
||||
<a-input
|
||||
v-model:value="formData.password"
|
||||
class="mt-20"
|
||||
type="password"
|
||||
:press-enter="handleLogin"
|
||||
:placeholder="t('密码')"
|
||||
size="large"
|
||||
>
|
||||
<template #suffix>
|
||||
<LockOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-input
|
||||
v-model:value="formData.password"
|
||||
class="mt-20"
|
||||
type="password"
|
||||
:press-enter="handleLogin"
|
||||
:placeholder="t('密码')"
|
||||
size="large"
|
||||
autocomplete="off"
|
||||
>
|
||||
<template #suffix>
|
||||
<LockOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||
</template>
|
||||
</a-input>
|
||||
</form>
|
||||
|
||||
<div class="mt-24 flex-between align-center">
|
||||
<div class="mcsmanager-link">
|
||||
@ -343,6 +347,7 @@ const loginSuccess = () => {
|
||||
}
|
||||
|
||||
.mcsmanager-link {
|
||||
font-size: var(--font-body);
|
||||
text-align: right;
|
||||
color: var(--color-gray-7);
|
||||
a {
|
||||
|
@ -4,39 +4,32 @@ import { t } from "@/lang/i18n";
|
||||
import type { LayoutCard, Settings } from "@/types";
|
||||
import { onMounted, ref, h } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import {
|
||||
LockOutlined,
|
||||
ProjectOutlined,
|
||||
QuestionCircleOutlined,
|
||||
LoadingOutlined
|
||||
} from "@ant-design/icons-vue";
|
||||
import { LockOutlined, ProjectOutlined, QuestionCircleOutlined } from "@ant-design/icons-vue";
|
||||
|
||||
import { settingInfo, setSettingInfo } from "@/services/apis";
|
||||
import Loading from "@/components/Loading.vue";
|
||||
|
||||
defineProps<{
|
||||
card: LayoutCard;
|
||||
}>();
|
||||
|
||||
const indicator = h(LoadingOutlined, {
|
||||
style: {
|
||||
fontSize: "24px"
|
||||
},
|
||||
spin: true
|
||||
});
|
||||
|
||||
const { execute, isReady } = settingInfo();
|
||||
const { execute: submitExecute, isLoading: submitIsLoading } = setSettingInfo();
|
||||
|
||||
const formData = ref<Settings>();
|
||||
|
||||
const submit = async () => {
|
||||
const res = await submitExecute({
|
||||
data: {
|
||||
...formData.value
|
||||
if (formData.value) {
|
||||
const res = await submitExecute({
|
||||
data: {
|
||||
...formData.value
|
||||
}
|
||||
});
|
||||
if (res.value == "OK") {
|
||||
return message.success(t("保存成功"));
|
||||
}
|
||||
});
|
||||
if (res.value == "OK") {
|
||||
return message.success(t("保存成功"));
|
||||
message.error(res.value);
|
||||
}
|
||||
message.error(res.value);
|
||||
};
|
||||
|
||||
const menus = [
|
||||
@ -79,8 +72,6 @@ const allYesNo = [
|
||||
}
|
||||
];
|
||||
|
||||
const formData = ref<Settings>({} as Settings);
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await execute();
|
||||
formData.value = res.value!;
|
||||
@ -89,7 +80,7 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<CardPanel class="CardWrapper" style="height: 100%" :padding="false">
|
||||
<CardPanel v-if="isReady && formData" class="CardWrapper" style="height: 100%" :padding="false">
|
||||
<template #body>
|
||||
<LeftMenusPanel :menus="menus">
|
||||
<template #baseInfo>
|
||||
@ -323,7 +314,7 @@ onMounted(async () => {
|
||||
</template>
|
||||
</CardPanel>
|
||||
<div v-if="!isReady" class="loading flex-center w-100 h-100">
|
||||
<a-spin :indicator="indicator" :tip="t('Loading...')" />
|
||||
<Loading></Loading>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -335,8 +326,6 @@ div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user