mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-01-12 14:54:34 +08:00
commit
0148c58e44
@ -29,6 +29,8 @@ import LinkCard from "@/widgets/others/LinkCard.vue";
|
||||
import QuickStartFlow from "@/widgets/setupApp/QuickStartFlow.vue";
|
||||
import IframeCard from "@/widgets/others/IframeCard.vue";
|
||||
import ClockCard from "@/widgets/others/ClockCard.vue";
|
||||
import UserStatusBlock from "@/widgets/UserStatusBlock.vue";
|
||||
import UserInstanceList from "@/widgets/UserInstanceList.vue";
|
||||
|
||||
import { NEW_CARD_TYPE } from "../types/index";
|
||||
|
||||
@ -60,7 +62,9 @@ export const LAYOUT_CARD_TYPES: { [key: string]: any } = {
|
||||
IframeCard,
|
||||
TextCard,
|
||||
LinkCard,
|
||||
ClockCard
|
||||
ClockCard,
|
||||
UserStatusBlock,
|
||||
UserInstanceList
|
||||
};
|
||||
|
||||
export interface NewCardItem extends LayoutCard {
|
||||
|
@ -307,6 +307,66 @@ export const ORIGIN_LAYOUT_CONFIG: PageLayoutConfig[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/consumer",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "UserStatusBlock",
|
||||
title: t("实例总计"),
|
||||
meta: {
|
||||
type: "instance_all"
|
||||
},
|
||||
width: 3,
|
||||
height: LayoutCardHeight.SMALL,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "UserStatusBlock",
|
||||
title: t("正在运行"),
|
||||
meta: {
|
||||
type: "instance_running"
|
||||
},
|
||||
width: 3,
|
||||
height: LayoutCardHeight.SMALL,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "UserStatusBlock",
|
||||
title: t("未运行"),
|
||||
meta: {
|
||||
type: "instance_stop"
|
||||
},
|
||||
width: 3,
|
||||
height: LayoutCardHeight.SMALL,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "UserStatusBlock",
|
||||
title: t("维护中"),
|
||||
meta: {
|
||||
type: "instance_error"
|
||||
},
|
||||
width: 3,
|
||||
height: LayoutCardHeight.SMALL,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "UserInstanceList",
|
||||
title: t("实例列表"),
|
||||
meta: {
|
||||
type: "instance_error"
|
||||
},
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
page: "/404",
|
||||
|
@ -1,8 +1,4 @@
|
||||
import {
|
||||
createRouter,
|
||||
createWebHashHistory,
|
||||
type RouteRecordRaw,
|
||||
} from "vue-router";
|
||||
import { createRouter, createWebHashHistory, type RouteRecordRaw } from "vue-router";
|
||||
import LayoutContainer from "@/views/LayoutContainer.vue";
|
||||
import { $t as t } from "@/lang/i18n";
|
||||
import LoginVue from "@/views/Login.vue";
|
||||
@ -31,15 +27,15 @@ let originRouterConfig = [
|
||||
name: t("TXT_CODE_16d71239"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: true,
|
||||
},
|
||||
mainMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/instances",
|
||||
name: t("TXT_CODE_e21473bc"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: true,
|
||||
mainMenu: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@ -52,82 +48,90 @@ let originRouterConfig = [
|
||||
path: "/instances/terminal/files",
|
||||
name: t("TXT_CODE_ae533703"),
|
||||
component: LayoutContainer,
|
||||
meta: {},
|
||||
meta: {}
|
||||
},
|
||||
{
|
||||
path: "/instances/terminal/serverConfig",
|
||||
name: t("TXT_CODE_d07742fe"),
|
||||
component: LayoutContainer,
|
||||
meta: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
meta: {}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "/users",
|
||||
name: t("TXT_CODE_1deaa2dd"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: true,
|
||||
mainMenu: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/users/config",
|
||||
name: t("TXT_CODE_236f70aa"),
|
||||
component: LayoutContainer,
|
||||
meta: {},
|
||||
},
|
||||
],
|
||||
meta: {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "/node",
|
||||
name: t("TXT_CODE_e076d90b"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: true,
|
||||
},
|
||||
mainMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
name: t("TXT_CODE_b5c7b82d"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: true,
|
||||
},
|
||||
mainMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/user",
|
||||
name: t("TXT_CODE_8c3164c9"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: false,
|
||||
},
|
||||
mainMenu: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/404",
|
||||
name: "404",
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: false,
|
||||
},
|
||||
mainMenu: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: LoginVue,
|
||||
meta: {
|
||||
mainMenu: false,
|
||||
},
|
||||
mainMenu: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/quickstart",
|
||||
name: t("TXT_CODE_2799a1dd"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: false,
|
||||
},
|
||||
mainMenu: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/consumer",
|
||||
name: t("用户主页"),
|
||||
component: LayoutContainer,
|
||||
meta: {
|
||||
mainMenu: false
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function routersConfigOptimize(
|
||||
@ -147,7 +151,7 @@ function routersConfigOptimize(
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: routersConfigOptimize(originRouterConfig) as RouteRecordRaw[],
|
||||
routes: routersConfigOptimize(originRouterConfig) as RouteRecordRaw[]
|
||||
});
|
||||
|
||||
export { router, originRouterConfig };
|
||||
|
105
frontend/src/widgets/UserInstanceList.vue
Normal file
105
frontend/src/widgets/UserInstanceList.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<script setup lang="ts">
|
||||
import { t } from "@/lang/i18n";
|
||||
import { onMounted } from "vue";
|
||||
import type { LayoutCard } from "@/types";
|
||||
import { userInfoApi } from "@/services/apis/index";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
defineProps<{
|
||||
card: LayoutCard;
|
||||
}>();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const { execute, state } = userInfoApi();
|
||||
|
||||
const status = {
|
||||
"-1": t("状态未知"),
|
||||
"0": t("已停止"),
|
||||
"1": t("正在停止"),
|
||||
"2": t("正在启动"),
|
||||
"3": t("正在运行")
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("实例名称"),
|
||||
dataIndex: "nickname",
|
||||
key: "nickname"
|
||||
},
|
||||
{
|
||||
title: t("运行状态"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
customRender: (e: { text: "-1" | "1" | "2" | "3" }) => {
|
||||
return status[e.text] || e.text;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("字节流编码"),
|
||||
dataIndex: "ie",
|
||||
customRender: (e: { text: string; record: { oe: string; ie: string } }) => {
|
||||
return `${e.text}/${e.record?.oe}`;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("最后启动"),
|
||||
dataIndex: "lastDatetime",
|
||||
key: "lastDatetime"
|
||||
},
|
||||
{
|
||||
title: t("到期时间"),
|
||||
dataIndex: "endTime",
|
||||
key: "endTime",
|
||||
customRender: (e: { text: string }) => {
|
||||
return e.text || t("无期限");
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("操作"),
|
||||
key: "operate"
|
||||
}
|
||||
];
|
||||
|
||||
const getInstanceList = async () => {
|
||||
await execute({
|
||||
params: {
|
||||
advanced: true
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const operate = (serviceUuid: string, instanceUuid: string) => {
|
||||
router.push({
|
||||
path: "/instances/terminal",
|
||||
query: {
|
||||
serviceUuid,
|
||||
instanceUuid
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getInstanceList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardPanel>
|
||||
<template #title>{{ card.title }}</template>
|
||||
<template #body>
|
||||
<a-table
|
||||
:data-source="state?.instances"
|
||||
:columns="columns"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 'max-content' }"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'operate'">
|
||||
<a-button @click="operate(record.serviceUuid, record.uuid)">{{ t("管理") }}</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</template>
|
@ -217,7 +217,10 @@ onMounted(async () => {
|
||||
{{ t("TXT_CODE_1987587b") }}
|
||||
</a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
<a-input v-model:value="newUserDialog.data.username" :placeholder="t('TXT_CODE_4ea93630')" />
|
||||
<a-input
|
||||
v-model:value="newUserDialog.data.username"
|
||||
:placeholder="t('TXT_CODE_4ea93630')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mb-20">
|
||||
@ -227,7 +230,10 @@ onMounted(async () => {
|
||||
{{ t("TXT_CODE_1f2062c7") }}
|
||||
</a-typography-text>
|
||||
</a-typography-paragraph>
|
||||
<a-input v-model:value="newUserDialog.data.password" :placeholder="t('TXT_CODE_4ea93630')" />
|
||||
<a-input
|
||||
v-model:value="newUserDialog.data.password"
|
||||
:placeholder="t('TXT_CODE_4ea93630')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mb-20">
|
||||
@ -252,11 +258,7 @@ onMounted(async () => {
|
||||
<a-typography-title :level="5">{{ t("TXT_CODE_ef0ce2e") }}</a-typography-title>
|
||||
<a-typography-paragraph>
|
||||
<a-typography-text type="secondary">
|
||||
{{
|
||||
t(
|
||||
"TXT_CODE_9e9d3767"
|
||||
)
|
||||
}}
|
||||
{{ t("TXT_CODE_9e9d3767") }}
|
||||
<br />
|
||||
<a href="https://docs.mcsmanager.com/" target="_blank">
|
||||
{{ t("TXT_CODE_b01f8383") }}
|
||||
|
82
frontend/src/widgets/UserStatusBlock.vue
Normal file
82
frontend/src/widgets/UserStatusBlock.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<script setup lang="ts">
|
||||
import { useLayoutCardTools } from "@/hooks/useCardTools";
|
||||
|
||||
import { t } from "@/lang/i18n";
|
||||
import type { LayoutCard } from "@/types";
|
||||
import { computed, onMounted } from "vue";
|
||||
|
||||
import { userInfoApi } from "@/services/apis/index";
|
||||
|
||||
const props = defineProps<{
|
||||
card: LayoutCard;
|
||||
}>();
|
||||
|
||||
const { execute, state } = userInfoApi();
|
||||
|
||||
const getInstanceList = async () => {
|
||||
await execute({
|
||||
params: {
|
||||
advanced: true
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const { getMetaValue } = useLayoutCardTools(props.card);
|
||||
|
||||
const type = getMetaValue<string>("type");
|
||||
|
||||
const computedStatusList = computed(() => {
|
||||
if (!state.value) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
type: "instance_all",
|
||||
title: t("管理员所分配给您的所有实例总数"),
|
||||
value: state.value.instances.length
|
||||
},
|
||||
{
|
||||
type: "instance_running",
|
||||
title: t("实例正在运行中的数量"),
|
||||
value: state.value.instances.filter((e) => e.status == 3).length
|
||||
},
|
||||
{
|
||||
type: "instance_stop",
|
||||
title: t("实例未处于运行中的数量"),
|
||||
value: state.value.instances.filter((e) => e.status == 0).length
|
||||
},
|
||||
{
|
||||
type: "instance_error",
|
||||
title: t("暂时不可使用的实例数"),
|
||||
value: state.value.instances.filter((e) => e.status == -1 || e.status == 1 || e.status == 2)
|
||||
.length
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
const realStatus = computed(() => computedStatusList.value.find((v) => v.type === type));
|
||||
onMounted(() => {
|
||||
getInstanceList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardPanel class="StatusBlock" style="height: 100%">
|
||||
<template #title>{{ card.title }}</template>
|
||||
<template #body>
|
||||
<a-typography-text class="color-info">
|
||||
{{ realStatus?.title }}
|
||||
</a-typography-text>
|
||||
<div class="value">{{ realStatus?.value }}</div>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.StatusBlock {
|
||||
.value {
|
||||
font-weight: 800;
|
||||
font-size: var(--font-h1);
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user