mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-01-18 15:04:04 +08:00
commit
4f90544ab9
6
frontend/components.d.ts
vendored
6
frontend/components.d.ts
vendored
@ -10,10 +10,7 @@ declare module 'vue' {
|
|||||||
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
|
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
|
||||||
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
|
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
|
||||||
AButton: typeof import('ant-design-vue/es')['Button']
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
|
||||||
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
|
|
||||||
ACol: typeof import('ant-design-vue/es')['Col']
|
ACol: typeof import('ant-design-vue/es')['Col']
|
||||||
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
|
|
||||||
ActionButton: typeof import('./src/components/ActionButton.vue')['default']
|
ActionButton: typeof import('./src/components/ActionButton.vue')['default']
|
||||||
ADrawer: typeof import('ant-design-vue/es')['Drawer']
|
ADrawer: typeof import('ant-design-vue/es')['Drawer']
|
||||||
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||||
@ -28,14 +25,11 @@ declare module 'vue' {
|
|||||||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||||
AppHeader: typeof import('./src/components/AppHeader.vue')['default']
|
AppHeader: typeof import('./src/components/AppHeader.vue')['default']
|
||||||
ARadio: typeof import('ant-design-vue/es')['Radio']
|
|
||||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
|
||||||
ARow: typeof import('ant-design-vue/es')['Row']
|
ARow: typeof import('ant-design-vue/es')['Row']
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||||
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
ASkeleton: typeof import('ant-design-vue/es')['Skeleton']
|
||||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
|
||||||
ATable: typeof import('ant-design-vue/es')['Table']
|
ATable: typeof import('ant-design-vue/es')['Table']
|
||||||
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
ATabPane: typeof import('ant-design-vue/es')['TabPane']
|
||||||
ATabs: typeof import('ant-design-vue/es')['Tabs']
|
ATabs: typeof import('ant-design-vue/es')['Tabs']
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useDefineApi } from "@/stores/useDefineApi";
|
import { useDefineApi } from "@/stores/useDefineApi";
|
||||||
import type { InstanceDetail, NodeStatus } from "@/types";
|
import type { InstanceDetail, NodeStatus, Settings } from "@/types";
|
||||||
import type { BaseUserInfo } from "@/types/user";
|
import type { BaseUserInfo } from "@/types/user";
|
||||||
|
|
||||||
// 此处 API 接口可以用中文写注释,后期再统一翻译成英语。
|
// 此处 API 接口可以用中文写注释,后期再统一翻译成英语。
|
||||||
@ -52,3 +52,20 @@ export const remoteInstances = useDefineApi<
|
|||||||
>({
|
>({
|
||||||
url: "/api/service/remote_service_instances"
|
url: "/api/service/remote_service_instances"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 获取设置信息
|
||||||
|
export const settingInfo = useDefineApi<any, Settings>({
|
||||||
|
url: "/api/overview/setting"
|
||||||
|
});
|
||||||
|
|
||||||
|
// 提交设置信息
|
||||||
|
export const setSettingInfo = useDefineApi<
|
||||||
|
| {
|
||||||
|
data: Settings;
|
||||||
|
}
|
||||||
|
| undefined,
|
||||||
|
string
|
||||||
|
>({
|
||||||
|
url: "/api/overview/setting",
|
||||||
|
method: "PUT"
|
||||||
|
});
|
||||||
|
@ -67,3 +67,21 @@ export interface NodeStatus {
|
|||||||
remarks: string;
|
remarks: string;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Settings {
|
||||||
|
httpPort: number;
|
||||||
|
httpIp: any;
|
||||||
|
dataPort: number;
|
||||||
|
forwardType: number;
|
||||||
|
crossDomain: boolean;
|
||||||
|
gzip: boolean;
|
||||||
|
maxCompress: number;
|
||||||
|
maxDownload: number;
|
||||||
|
zipType: number;
|
||||||
|
loginCheckIp: boolean;
|
||||||
|
loginInfo: string;
|
||||||
|
canFileManager: boolean;
|
||||||
|
language: string;
|
||||||
|
quickInstallAddr: string;
|
||||||
|
redisUrl: string;
|
||||||
|
}
|
||||||
|
@ -1,20 +1,44 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LeftMenusPanel from "@/components/LeftMenusPanel.vue";
|
import LeftMenusPanel from "@/components/LeftMenusPanel.vue";
|
||||||
import { t } from "@/lang/i18n";
|
import { t } from "@/lang/i18n";
|
||||||
import type { LayoutCard } from "@/types";
|
import type { LayoutCard, Settings } from "@/types";
|
||||||
import { ref } from "vue";
|
import { onMounted, ref, h } from "vue";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
import {
|
import {
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
ProjectOutlined,
|
ProjectOutlined,
|
||||||
QuestionCircleOutlined,
|
QuestionCircleOutlined,
|
||||||
QuestionOutlined,
|
LoadingOutlined
|
||||||
RobotOutlined
|
|
||||||
} from "@ant-design/icons-vue";
|
} from "@ant-design/icons-vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
import { settingInfo, setSettingInfo } from "@/services/apis";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
card: LayoutCard;
|
card: LayoutCard;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const indicator = h(LoadingOutlined, {
|
||||||
|
style: {
|
||||||
|
fontSize: "24px"
|
||||||
|
},
|
||||||
|
spin: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const { execute, isReady } = settingInfo();
|
||||||
|
const { execute: submitExecute, isLoading: submitIsLoading } = setSettingInfo();
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
const res = await submitExecute({
|
||||||
|
data: {
|
||||||
|
...formData.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (res.value == "OK") {
|
||||||
|
return message.success(t("保存成功"));
|
||||||
|
}
|
||||||
|
message.error(res.value);
|
||||||
|
};
|
||||||
|
|
||||||
const menus = [
|
const menus = [
|
||||||
{
|
{
|
||||||
title: t("基本设置"),
|
title: t("基本设置"),
|
||||||
@ -33,27 +57,38 @@ const menus = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const formData = ref({
|
|
||||||
language: "en_US",
|
|
||||||
tmp: ""
|
|
||||||
});
|
|
||||||
|
|
||||||
const allLanguages = [
|
const allLanguages = [
|
||||||
{
|
{
|
||||||
label: "中文",
|
label: "中文",
|
||||||
value: "zh_CN"
|
value: "zh_cn"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "English",
|
label: "English",
|
||||||
value: "en_US"
|
value: "en_us"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const allYesNo = [
|
||||||
|
{
|
||||||
|
label: t("启用"),
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("禁用"),
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const formData = ref<Settings>({} as Settings);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const res = await execute();
|
||||||
|
formData.value = res.value!;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div></div>
|
|
||||||
|
|
||||||
<CardPanel class="CardWrapper" style="height: 100%" :padding="false">
|
<CardPanel class="CardWrapper" style="height: 100%" :padding="false">
|
||||||
<template #body>
|
<template #body>
|
||||||
<LeftMenusPanel :menus="menus">
|
<LeftMenusPanel :menus="menus">
|
||||||
@ -88,11 +123,12 @@ const allLanguages = [
|
|||||||
{{ t("网页访问端口,请填写一个纯数字,默认端口是 23333 端口。") }}
|
{{ t("网页访问端口,请填写一个纯数字,默认端口是 23333 端口。") }}
|
||||||
</a-typography-paragraph>
|
</a-typography-paragraph>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.tmp"
|
v-model:value="formData.httpPort"
|
||||||
style="max-width: 320px"
|
style="max-width: 320px"
|
||||||
placeholder="请输入内容"
|
:placeholder="t('请输入内容')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-typography-title :level="5">{{ t("登录页文字展示") }}</a-typography-title>
|
<a-typography-title :level="5">{{ t("登录页文字展示") }}</a-typography-title>
|
||||||
<a-typography-paragraph>
|
<a-typography-paragraph>
|
||||||
@ -100,7 +136,11 @@ const allLanguages = [
|
|||||||
{{ t("支持 Markdown 格式") }}
|
{{ t("支持 Markdown 格式") }}
|
||||||
</a-typography-text>
|
</a-typography-text>
|
||||||
</a-typography-paragraph>
|
</a-typography-paragraph>
|
||||||
<a-textarea v-model:value="formData.tmp" :rows="4" placeholder="请输入内容" />
|
<a-textarea
|
||||||
|
v-model:value="formData.loginInfo"
|
||||||
|
:rows="4"
|
||||||
|
:placeholder="t('请输入内容')"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
@ -113,20 +153,190 @@ const allLanguages = [
|
|||||||
}}
|
}}
|
||||||
</a-typography-paragraph>
|
</a-typography-paragraph>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.tmp"
|
v-model:value="formData.httpIp"
|
||||||
style="max-width: 320px"
|
style="max-width: 320px"
|
||||||
placeholder="请输入内容"
|
:placeholder="t('请输入内容')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-typography-title :level="5">{{ t("预设资源下载点") }}</a-typography-title>
|
||||||
|
<a-typography-paragraph type="secondary">
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
"快速安装服务器时的下载源列表,您可以通过更改此地址实现自定义服务端预设下载站。"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</a-typography-paragraph>
|
||||||
|
<a-input
|
||||||
|
v-model:value="formData.quickInstallAddr"
|
||||||
|
style="max-width: 320px"
|
||||||
|
:placeholder="t('请输入内容')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<div class="button">
|
||||||
|
<a-button type="primary" :loading="submitIsLoading" @click="submit()">
|
||||||
|
保存
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
</a-form>
|
</a-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #api> B </template>
|
|
||||||
|
<template #api>
|
||||||
|
<div style="max-height: 500px; overflow-y: auto">
|
||||||
|
<a-typography-title :level="4" class="mb-24">{{ t("安全设置") }}</a-typography-title>
|
||||||
|
<div style="text-align: left">
|
||||||
|
<a-form :model="formData" layout="vertical">
|
||||||
|
<a-typography-title :level="5">
|
||||||
|
{{ t("注意事项") }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<a-typography-text type="secondary">
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
"这些配置设置需要一部分专业知识,您可以根据您的硬件设备来大概猜测哪些值适合您。"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
<br />
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
"一般情况下,默认值可以满足个人日常的使用场景,如果规模一旦更大,对硬件的要求更高,为了不过分损失用户体验,一个合适的阈值是十分重要的."
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</a-typography-text>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-typography-title :level="5">
|
||||||
|
{{ t("准许普通用户使用文件管理功能") }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<a-typography-text type="secondary">
|
||||||
|
{{ t("文件管理是一个较为消耗资源且不易控制的功能。") }}
|
||||||
|
<br />
|
||||||
|
{{
|
||||||
|
t("如果您的普通用户没有文件管理的任何需求,可以禁止用户使用文件管理。")
|
||||||
|
}}
|
||||||
|
</a-typography-text>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
<a-select v-model:value="formData.canFileManager" style="max-width: 320px">
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in allYesNo"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-typography-title :level="5">
|
||||||
|
{{ t("跨域请求 API 接口") }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<a-typography-text type="secondary">
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
"HTTP 响应将会加入 access-control-allow-origin: *,可能会降低安全性,但是会提高开发扩展性。"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</a-typography-text>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
<a-select v-model:value="formData.crossDomain" style="max-width: 320px">
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in allYesNo"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-typography-title :level="5">
|
||||||
|
{{ t("同 IP 登录次数限制") }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<a-typography-text type="secondary">
|
||||||
|
{{
|
||||||
|
t(
|
||||||
|
"此功能将保护您的面板不被单个主机暴力破解密码,每个 IP 只有 10 次密码错误次数。"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</a-typography-text>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
<a-select v-model:value="formData.loginCheckIp" style="max-width: 320px">
|
||||||
|
<a-select-option
|
||||||
|
v-for="item in allYesNo"
|
||||||
|
:key="item.value"
|
||||||
|
:value="item.value"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<div class="button">
|
||||||
|
<a-button type="primary" :loading="submitIsLoading" @click="submit()">
|
||||||
|
保存
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #password>
|
||||||
|
<div style="max-height: 500px; overflow-y: auto">
|
||||||
|
<a-typography-title :level="4" class="mb-24">{{ t("关于") }}</a-typography-title>
|
||||||
|
<div style="text-align: left">
|
||||||
|
<a-form-item>
|
||||||
|
<a-typography-title :level="5">
|
||||||
|
{{ t("软件根据 Apache-2.0 开源软件协议发行") }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<a-typography-text type="secondary">
|
||||||
|
{{ t("https://github.com/MCSManager/MCSManager/blob/master/LICENSE") }}
|
||||||
|
</a-typography-text>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-typography-title :level="5">
|
||||||
|
{{ t("开源项目赞助名单") }}
|
||||||
|
</a-typography-title>
|
||||||
|
<a-typography-paragraph>
|
||||||
|
<a-typography-text type="secondary">
|
||||||
|
{{ t("只含前 40 名赞助者,查看完整赞助名单或进行赞助支持请前往") }}
|
||||||
|
<a href="https://mcsmanager.com/" target="_blank">MCSManager.com</a> .
|
||||||
|
</a-typography-text>
|
||||||
|
</a-typography-paragraph>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</LeftMenusPanel>
|
</LeftMenusPanel>
|
||||||
</template>
|
</template>
|
||||||
</CardPanel>
|
</CardPanel>
|
||||||
|
<div v-if="!isReady" class="loading flex-center w-100 h-100">
|
||||||
|
<a-spin :indicator="indicator" :tip="t('Loading...')" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped>
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -51,9 +51,9 @@ function setupHttp(koaApp: Koa, port: number, host?: string) {
|
|||||||
logger.info($t("app.exitTip", { port }));
|
logger.info($t("app.exitTip", { port }));
|
||||||
logger.info("==================================");
|
logger.info("==================================");
|
||||||
|
|
||||||
if (os.platform() == "win32") {
|
// if (os.platform() == "win32") {
|
||||||
open(`http://localhost:${port}/`).then(() => {});
|
// open(`http://localhost:${port}/`).then(() => {});
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processExit() {
|
async function processExit() {
|
||||||
|
Loading…
Reference in New Issue
Block a user