mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-02-05 15:29:35 +08:00
commit
fa3c5adbc3
1
frontend/components.d.ts
vendored
1
frontend/components.d.ts
vendored
@ -44,6 +44,7 @@ declare module 'vue' {
|
||||
CardPanel: typeof import('./src/components/CardPanel.vue')['default']
|
||||
CopyButton: typeof import('./src/components/CopyButton.vue')['default']
|
||||
DataStatistic: typeof import('./src/components/DataStatistic.vue')['default']
|
||||
ErrorCard: typeof import('./src/components/ErrorCard.vue')['default']
|
||||
IconBtn: typeof import('./src/components/IconBtn.vue')['default']
|
||||
InnerCard: typeof import('./src/components/InnerCard.vue')['default']
|
||||
InputDialogProvider: typeof import('./src/components/InputDialogProvider.vue')['default']
|
||||
|
53
frontend/src/components/ErrorCard.vue
Normal file
53
frontend/src/components/ErrorCard.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<script setup lang="ts">
|
||||
import CardPanel from "@/components/CardPanel.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
title: string,
|
||||
details?: string
|
||||
}>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-100 w-100">
|
||||
<CardPanel>
|
||||
<template #body>
|
||||
<div class="error-panel">
|
||||
<div class="error-card">
|
||||
<div class="error-title">
|
||||
<a-typography-title :level="3">
|
||||
{{ props.title }}
|
||||
</a-typography-title>
|
||||
</div>
|
||||
<div v-if="props.details" class="error-details">
|
||||
<a-typography>
|
||||
{{ props.details }}
|
||||
</a-typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.error-panel {
|
||||
height: 100% !important;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.error-card {
|
||||
background-color: #fff2f0;
|
||||
border: 1px solid #ffccc7;
|
||||
box-sizing: border-box;
|
||||
padding: 32px 32px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
border-radius: 8px;
|
||||
width: 400px;
|
||||
height: 247.2px;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
import { useDefineApi } from "@/stores/useDefineApi";
|
||||
import type { InstanceDetail, NodeStatus, Settings, UserInfo } from "@/types";
|
||||
import type { InstanceDetail, NodeStatus, Settings, UserInfo, UserInstance } from "@/types";
|
||||
import type { BaseUserInfo } from "@/types/user";
|
||||
import type { IPanelOverviewResponse } from "../../../../common/global";
|
||||
|
||||
@ -8,12 +8,12 @@ import type { IPanelOverviewResponse } from "../../../../common/global";
|
||||
// 用户登录
|
||||
export const loginUser = useDefineApi<
|
||||
| {
|
||||
// Post
|
||||
data: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
// Post
|
||||
data: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
| undefined,
|
||||
// Response
|
||||
{
|
||||
@ -35,6 +35,16 @@ export const userInfoApi = useDefineApi<any, BaseUserInfo>({
|
||||
url: "/api/auth/"
|
||||
});
|
||||
|
||||
export const userInfoApiAdvanced = useDefineApi<
|
||||
{
|
||||
params: {
|
||||
uuid: string;
|
||||
advanced: boolean;
|
||||
};
|
||||
}, BaseUserInfo>({
|
||||
url: "/api/auth/"
|
||||
});
|
||||
|
||||
// 获取远程服务列表
|
||||
export const remoteNodeList = useDefineApi<any, NodeStatus[]>({
|
||||
url: "/api/service/remote_services_list"
|
||||
@ -68,8 +78,8 @@ export const settingInfo = useDefineApi<any, Settings>({
|
||||
// 提交设置信息
|
||||
export const setSettingInfo = useDefineApi<
|
||||
| {
|
||||
data: Settings;
|
||||
}
|
||||
data: Settings;
|
||||
}
|
||||
| undefined,
|
||||
string
|
||||
>({
|
||||
@ -119,6 +129,22 @@ export const addUser = useDefineApi<
|
||||
method: "POST"
|
||||
});
|
||||
|
||||
// 用户管理 用户配置
|
||||
export const updateUserInstance = useDefineApi<
|
||||
{
|
||||
data: {
|
||||
config: {
|
||||
instances: UserInstance[];
|
||||
}
|
||||
uuid: string
|
||||
};
|
||||
},
|
||||
boolean
|
||||
>({
|
||||
url: "/api/auth",
|
||||
method: "PUT"
|
||||
});
|
||||
|
||||
// 获取总览
|
||||
|
||||
// 获取设置信息
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import type { IGlobalInstanceConfig } from "./../../../common/global";
|
||||
import type { IGlobalInstanceConfig } from "../../../common/global";
|
||||
import type { LayoutCardHeight } from "@/config/originLayoutConfig";
|
||||
|
||||
export interface JsonData {
|
||||
@ -95,6 +94,20 @@ export interface UserInfo {
|
||||
passWordType: number;
|
||||
loginTime: string;
|
||||
isInit: boolean;
|
||||
instances: any[];
|
||||
instances: UserInstance[];
|
||||
apiKey: string;
|
||||
}
|
||||
|
||||
export interface UserInstance {
|
||||
endTime: string;
|
||||
hostIp: string;
|
||||
ie: string;
|
||||
instanceUuid: string;
|
||||
lastDatetime: string;
|
||||
nickname: string;
|
||||
oe: string;
|
||||
remarks: string;
|
||||
serviceUuid: string;
|
||||
status: number;
|
||||
stopCommand: string;
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
import type { UserInstance } from "@/types/index";
|
||||
|
||||
export interface BaseUserInfo {
|
||||
uuid: string;
|
||||
userName: string;
|
||||
loginTime: string;
|
||||
registerTime: string;
|
||||
instances: any[];
|
||||
instances: UserInstance[];
|
||||
permission: number;
|
||||
token: string;
|
||||
apiKey: string;
|
||||
|
@ -1,69 +1,95 @@
|
||||
<script setup lang="ts">
|
||||
import CardPanel from "@/components/CardPanel.vue";
|
||||
import type { LayoutCard } from "@/types/index";
|
||||
import { computed } from "vue";
|
||||
import type { LayoutCard, UserInstance } from "@/types";
|
||||
import { computed, ref } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import { t } from "@/lang/i18n";
|
||||
import BetweenMenus from "@/components/BetweenMenus.vue";
|
||||
import { useScreen } from "@/hooks/useScreen";
|
||||
import { arrayFilter } from "@/tools/array";
|
||||
import { useAppRouters } from "@/hooks/useAppRouters";
|
||||
|
||||
interface InstanceBaseInfo {
|
||||
key?: number | string;
|
||||
uuid: string;
|
||||
name: string;
|
||||
daemon: string;
|
||||
limitTime: string;
|
||||
status: number;
|
||||
}
|
||||
import { userInfoApiAdvanced } from "@/services/apis";
|
||||
import { useLayoutCardTools } from "@/hooks/useCardTools";
|
||||
import ErrorCard from "@/components/ErrorCard.vue";
|
||||
import { updateUserInstance } from "@/services/apis";
|
||||
|
||||
const props = defineProps<{
|
||||
card: LayoutCard;
|
||||
uuid: string;
|
||||
}>();
|
||||
|
||||
const { getRouteParamsUrl, toPage } = useAppRouters();
|
||||
const screen = useScreen();
|
||||
|
||||
const handleDelete = (user: InstanceBaseInfo) => {};
|
||||
let dataSource: Ref<UserInstance[]> = ref([]);
|
||||
const { getMetaOrRouteValue } = useLayoutCardTools(props.card);
|
||||
let userUuid: string | undefined = getMetaOrRouteValue("uuid");
|
||||
|
||||
const dataSource: InstanceBaseInfo[] = [
|
||||
{
|
||||
key: "1",
|
||||
name: "实例名称1",
|
||||
daemon: "守护进程1",
|
||||
limitTime: "限制时间1",
|
||||
status: 1,
|
||||
uuid: "1"
|
||||
const handleDelete = async (deletedInstance: UserInstance) => {
|
||||
for (let valueKey = 0; valueKey < dataSource.value.length; valueKey++) {
|
||||
const instance = dataSource.value[valueKey];
|
||||
if (deletedInstance.serviceUuid == instance.serviceUuid && deletedInstance.instanceUuid == instance.instanceUuid) {
|
||||
dataSource.value.splice(valueKey, 1);
|
||||
await updateUserInstance().execute({
|
||||
data: {
|
||||
config: {
|
||||
instances: dataSource.value
|
||||
},
|
||||
uuid: <string>userUuid
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
async function refreshChart() {
|
||||
if (userUuid == null) {
|
||||
return;
|
||||
}
|
||||
const rawUserInfo = (await userInfoApiAdvanced().execute({
|
||||
params: {
|
||||
uuid: <string>userUuid,
|
||||
advanced: true
|
||||
}
|
||||
})).value;
|
||||
if (!rawUserInfo) {
|
||||
return;
|
||||
}
|
||||
const newDataSource: UserInstance[] = [];
|
||||
for (const instance of rawUserInfo.instances) {
|
||||
newDataSource.push(instance);
|
||||
}
|
||||
dataSource.value = newDataSource;
|
||||
}
|
||||
|
||||
refreshChart();
|
||||
|
||||
const columns = computed(() => {
|
||||
return arrayFilter([
|
||||
{
|
||||
align: "center",
|
||||
title: "所属节点",
|
||||
dataIndex: "daemon",
|
||||
title: t("所属节点"),
|
||||
dataIndex: "serviceUuid",
|
||||
key: "daemon",
|
||||
minWidth: "200px"
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
title: "实例名称",
|
||||
dataIndex: "name",
|
||||
title: t("实例名称"),
|
||||
dataIndex: "nickname",
|
||||
key: "name",
|
||||
minWidth: "200px"
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
title: "到期时间",
|
||||
dataIndex: "limitTime",
|
||||
title: t("到期时间"),
|
||||
dataIndex: "lastDatetime",
|
||||
key: "limitTime",
|
||||
minWidth: "200px",
|
||||
condition: () => !screen.isPhone.value
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
title: "实例状态",
|
||||
title: t("实例状态"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
minWidth: "200px",
|
||||
@ -71,9 +97,10 @@ const columns = computed(() => {
|
||||
},
|
||||
{
|
||||
align: "center",
|
||||
title: "操作",
|
||||
key: "action",
|
||||
minWidth: "200px"
|
||||
title: t("操作"),
|
||||
key: "operation",
|
||||
minWidth: "200px",
|
||||
scopedSlots: { customRender: "operation" }
|
||||
}
|
||||
]);
|
||||
});
|
||||
@ -82,34 +109,39 @@ const columns = computed(() => {
|
||||
<template>
|
||||
<div style="height: 100%" class="container">
|
||||
<a-row :gutter="[24, 24]" style="height: 100%">
|
||||
<a-col :span="24">
|
||||
<BetweenMenus>
|
||||
<template #left>
|
||||
<a-typography-title class="mb-0" :level="4">
|
||||
{{ t("TXT_CODE_e1c9a6ac") }}
|
||||
</a-typography-title>
|
||||
</template>
|
||||
<template #right>
|
||||
<a-button type="primary">{{ t("TXT_CODE_a60466a1") }}</a-button>
|
||||
</template>
|
||||
</BetweenMenus>
|
||||
</a-col>
|
||||
<div v-if="userUuid" class="h-100 w-100">
|
||||
<a-col :span="24">
|
||||
<BetweenMenus>
|
||||
<template #left>
|
||||
<a-typography-title class="mb-0" :level="4">
|
||||
{{ t("TXT_CODE_e1c9a6ac") }}
|
||||
</a-typography-title>
|
||||
</template>
|
||||
<template #right>
|
||||
<a-button type="primary">{{ t("TXT_CODE_a60466a1") }}</a-button>
|
||||
</template>
|
||||
</BetweenMenus>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<CardPanel style="height: 100%">
|
||||
<template #body>
|
||||
<a-table :data-source="dataSource" :columns="columns">
|
||||
<template #bodyCell="{ column }">
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-button danger>
|
||||
{{ t("TXT_CODE_ecbd7449") }}
|
||||
</a-button>
|
||||
<a-col :span="24">
|
||||
<CardPanel class="h-100">
|
||||
<template #body>
|
||||
<a-table :data-source="dataSource" :columns="columns">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'operation'">
|
||||
<a-button danger @click="handleDelete(record)">
|
||||
{{ t("TXT_CODE_ecbd7449") }}
|
||||
</a-button>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
</a-table>
|
||||
</template>
|
||||
</CardPanel>
|
||||
</a-col>
|
||||
</div>
|
||||
<div v-else class="h-100 w-100">
|
||||
<ErrorCard :title="t('缺少参数,组件无法运作')" :details="t('请添加 get 参数 uuid')" style="min-height: 600px" />
|
||||
</div>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
Loading…
Reference in New Issue
Block a user