mirror of
https://github.com/MCSManager/MCSManager.git
synced 2025-02-23 16:09:37 +08:00
Merge branch 'next' into abandon
This commit is contained in:
commit
6541549732
36
common/global.d.ts
vendored
36
common/global.d.ts
vendored
@ -131,3 +131,39 @@ export interface IPanelOverviewResponse {
|
||||
};
|
||||
remote: IPanelOverviewRemoteResponse[];
|
||||
}
|
||||
|
||||
export interface IJsonData {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface IMapData<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
export interface IPageLayoutConfig {
|
||||
page: string;
|
||||
items: ILayoutCard[];
|
||||
}
|
||||
|
||||
export interface ILayoutCardParams {
|
||||
field: string;
|
||||
label: string;
|
||||
type: "string" | "number" | "boolean" | "instanceId";
|
||||
}
|
||||
|
||||
export interface ILayoutCard {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
width: number;
|
||||
height: string;
|
||||
meta: IJsonData;
|
||||
disableAdd?: boolean;
|
||||
onlyPath?: string[];
|
||||
params?: ILayoutCardParams[];
|
||||
followId?: string;
|
||||
description?: string;
|
||||
allowedPages?: Array<string> | null;
|
||||
line?: number;
|
||||
disableDelete?: boolean;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { $t } from "../i18n";
|
||||
import path from "path";
|
||||
import fs from "fs-extra";
|
||||
|
||||
@ -7,10 +6,8 @@ interface IClassz {
|
||||
}
|
||||
|
||||
class StorageSubsystem {
|
||||
public static readonly STIRAGE_DATA_PATH = path.normalize(path.join(process.cwd(), "data"));
|
||||
public static readonly STIRAGE_INDEX_PATH = path.normalize(
|
||||
path.join(process.cwd(), "data", "index")
|
||||
);
|
||||
public static readonly DATA_PATH = path.normalize(path.join(process.cwd(), "data"));
|
||||
public static readonly INDEX_PATH = path.normalize(path.join(process.cwd(), "data", "index"));
|
||||
|
||||
private checkFileName(name: string) {
|
||||
const blackList = ["\\", "/", ".."];
|
||||
@ -20,21 +17,18 @@ class StorageSubsystem {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stored in local file based on class definition and identifier
|
||||
*/
|
||||
// Stored in local file based on class definition and identifier
|
||||
public store(category: string, uuid: string, object: any) {
|
||||
const dirPath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(StorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
if (!this.checkFileName(uuid))
|
||||
throw new Error($t("TXT_CODE_common.uuidIrregular", { uuid: uuid }));
|
||||
throw new Error(`UUID ${uuid} does not conform to specification`);
|
||||
const filePath = path.join(dirPath, `${uuid}.json`);
|
||||
const data = JSON.stringify(object, null, 4);
|
||||
fs.writeFileSync(filePath, data, { encoding: "utf-8" });
|
||||
}
|
||||
|
||||
// deep copy of the primitive type with the copy target as the prototype
|
||||
// target copy target object copy source
|
||||
protected defineAttr(target: any, object: any): any {
|
||||
for (const v of Object.keys(target)) {
|
||||
const objectValue = object[v];
|
||||
@ -56,10 +50,10 @@ class StorageSubsystem {
|
||||
* Instantiate an object based on the class definition and identifier
|
||||
*/
|
||||
public load(category: string, classz: any, uuid: string) {
|
||||
const dirPath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(StorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
if (!this.checkFileName(uuid))
|
||||
throw new Error($t("TXT_CODE_common.uuidIrregular", { uuid: uuid }));
|
||||
throw new Error(`UUID ${uuid} does not conform to specification`);
|
||||
const filePath = path.join(dirPath, `${uuid}.json`);
|
||||
if (!fs.existsSync(filePath)) return null;
|
||||
const data = fs.readFileSync(filePath, { encoding: "utf-8" });
|
||||
@ -76,7 +70,7 @@ class StorageSubsystem {
|
||||
* Return all identifiers related to this class through the class definition
|
||||
*/
|
||||
public list(category: string) {
|
||||
const dirPath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(StorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
const files = fs.readdirSync(dirPath);
|
||||
const result = new Array<string>();
|
||||
@ -90,7 +84,7 @@ class StorageSubsystem {
|
||||
* Delete an identifier instance of the specified type through the class definition
|
||||
*/
|
||||
public delete(category: string, uuid: string) {
|
||||
const filePath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category, `${uuid}.json`);
|
||||
const filePath = path.join(StorageSubsystem.DATA_PATH, category, `${uuid}.json`);
|
||||
if (!fs.existsSync(filePath)) return;
|
||||
fs.removeSync(filePath);
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
# MCSManager 10.0 网页前端
|
@ -1,7 +1,4 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
import { $t as t } from "@/lang/i18n";
|
||||
import { getRandomId } from "@/tools/randId";
|
||||
import type { JsonData, LayoutCard } from "@/types";
|
||||
import type { IPageLayoutConfig } from "../../../common/global";
|
||||
|
||||
export enum LayoutCardHeight {
|
||||
MINI = "100px",
|
||||
@ -12,12 +9,9 @@ export enum LayoutCardHeight {
|
||||
AUTO = "unset"
|
||||
}
|
||||
|
||||
export interface PageLayoutConfig {
|
||||
page: string;
|
||||
items: LayoutCard[];
|
||||
}
|
||||
export let ORIGIN_LAYOUT_CONFIG: IPageLayoutConfig[] = [];
|
||||
|
||||
export function setAllLayoutConfig(cfg: PageLayoutConfig[]) {
|
||||
export function setAllLayoutConfig(cfg: IPageLayoutConfig[]) {
|
||||
console.debug("设置布局配置:", cfg);
|
||||
ORIGIN_LAYOUT_CONFIG = cfg;
|
||||
}
|
||||
@ -25,457 +19,3 @@ export function setAllLayoutConfig(cfg: PageLayoutConfig[]) {
|
||||
export function getAllLayoutConfig() {
|
||||
return ORIGIN_LAYOUT_CONFIG;
|
||||
}
|
||||
|
||||
// 在 Web 端没有返回用户自定义布局时,使用默认的布局。
|
||||
// 这里是所有不同页面的默认的布局配置
|
||||
export let ORIGIN_LAYOUT_CONFIG: PageLayoutConfig[] = [
|
||||
{
|
||||
page: "/",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_e627e546"),
|
||||
meta: {
|
||||
type: "node"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_88e9361a"),
|
||||
meta: {
|
||||
type: "instance"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_db64faf6"),
|
||||
meta: {
|
||||
type: "users"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_66056676"),
|
||||
meta: {
|
||||
type: "system"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "DataOverview",
|
||||
title: t("TXT_CODE_721157a3"),
|
||||
width: 9,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.MEDIUM
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "QuickStart",
|
||||
title: t("TXT_CODE_2799a1dd"),
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.MEDIUM
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "RequestChart",
|
||||
title: t("TXT_CODE_a4037a98"),
|
||||
width: 6,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceChart",
|
||||
title: t("TXT_CODE_d6d9c42c"),
|
||||
width: 6,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "NodeOverview",
|
||||
title: t("TXT_CODE_bfb50126"),
|
||||
width: 12,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.MEDIUM
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceList",
|
||||
title: t("TXT_CODE_e21473bc"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {
|
||||
viewType: "inner"
|
||||
},
|
||||
type: "Terminal",
|
||||
title: t("TXT_CODE_4ccdd3a0"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.BIG,
|
||||
disableDelete: true
|
||||
},
|
||||
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceBaseInfo",
|
||||
title: t("TXT_CODE_eadb4f60"),
|
||||
width: 4,
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceManagerBtns",
|
||||
title: t("TXT_CODE_efd37c48"),
|
||||
width: 8,
|
||||
height: LayoutCardHeight.SMALL,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal/files",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceFileManager",
|
||||
title: t("文件管理"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal/serverConfig",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceServerConfigOverview",
|
||||
title: t("服务端配置文件"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal/serverConfig/fileEdit",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceServerConfigFile",
|
||||
title: t("编辑服务端配置文件"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/users",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "UserList",
|
||||
title: t("用户列表"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/users/config",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "UserAccessSettings",
|
||||
title: t("用户权限设定"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/settings",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "Settings",
|
||||
title: t("系统设置"),
|
||||
width: 8,
|
||||
height: LayoutCardHeight.MEDIUM,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/node",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "NodeList",
|
||||
title: t("TXT_CODE_20509fa0"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/node/image",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "ImageManager",
|
||||
title: t("镜像管理"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/node/image/new",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "NewImage",
|
||||
title: t("创建镜像"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/quickstart",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "QuickStartFlow",
|
||||
title: t("TXT_CODE_9b99b72e"),
|
||||
width: 8,
|
||||
height: LayoutCardHeight.AUTO
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/quickstart/minecraft",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "McPreset",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/customer",
|
||||
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",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "Page404",
|
||||
title: t("页面未找到"),
|
||||
width: 6,
|
||||
height: LayoutCardHeight.MINI,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { h, ref, createVNode, type Ref, reactive } from "vue";
|
||||
import { t } from "@/lang/i18n";
|
||||
import type { TableProps, UploadProps } from "ant-design-vue";
|
||||
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import type { UploadProps } from "ant-design-vue";
|
||||
import type { Key } from "ant-design-vue/es/table/interface";
|
||||
import { h, ref, createVNode, reactive } from "vue";
|
||||
import { LoadingOutlined, ExclamationCircleOutlined } from "@ant-design/icons-vue";
|
||||
|
||||
import { parseForwardAddress } from "@/tools/protocol";
|
||||
import { number2permission, permission2number } from "@/tools/permission";
|
||||
import { t } from "@/lang/i18n";
|
||||
import {
|
||||
fileList as getFileListApi,
|
||||
getFileStatus as getFileStatusApi,
|
||||
@ -20,9 +20,6 @@ import {
|
||||
downloadAddress,
|
||||
changePermission as changePermissionApi
|
||||
} from "@/services/apis/fileManager";
|
||||
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
|
||||
import type {
|
||||
DataType,
|
||||
OperationForm,
|
||||
@ -31,28 +28,34 @@ import type {
|
||||
Permission
|
||||
} from "@/types/fileManager";
|
||||
|
||||
export const useFileManager = (
|
||||
operationForm: Ref<OperationForm>,
|
||||
breadcrumbs: Breadcrumb[],
|
||||
dataSource: Ref<DataType[] | undefined>,
|
||||
clipboard: Ref<
|
||||
| {
|
||||
type: "copy" | "move";
|
||||
value: string[];
|
||||
}
|
||||
| undefined
|
||||
>,
|
||||
selectionData: Ref<DataType[] | undefined>,
|
||||
instanceId?: string,
|
||||
daemonId?: string
|
||||
) => {
|
||||
export const useFileManager = (instanceId?: string, daemonId?: string) => {
|
||||
const indicator = h(LoadingOutlined, {
|
||||
style: {
|
||||
fontSize: "24px"
|
||||
}
|
||||
});
|
||||
|
||||
const dataSource = ref<DataType[]>();
|
||||
const fileStatus = ref<FileStatus>();
|
||||
const selectedRowKeys = ref<Key[]>([]);
|
||||
const selectionData = ref<DataType[]>();
|
||||
const operationForm = ref<OperationForm>({
|
||||
name: "",
|
||||
current: 1,
|
||||
pageSize: 100,
|
||||
total: 0
|
||||
});
|
||||
|
||||
const breadcrumbs = reactive<Breadcrumb[]>([]);
|
||||
breadcrumbs.push({
|
||||
path: "/",
|
||||
name: "/",
|
||||
disabled: false
|
||||
});
|
||||
|
||||
const clipboard = ref<{
|
||||
type: "copy" | "move";
|
||||
value: string[];
|
||||
}>();
|
||||
|
||||
const dialog = ref({
|
||||
show: false,
|
||||
@ -272,7 +275,7 @@ export const useFileManager = (
|
||||
const zipFile = async () => {
|
||||
if (!selectionData.value || selectionData.value.length === 0)
|
||||
return message.error(t("请先选择文件"));
|
||||
const filename = await openDialog(t("压缩文件"), 't("请输入压缩后的文件名")', "", "zip");
|
||||
const filename = await openDialog(t("压缩文件"), t("请输入压缩后的文件名"), "", "zip");
|
||||
const { execute } = compressFileApi();
|
||||
try {
|
||||
await execute({
|
||||
@ -364,10 +367,9 @@ export const useFileManager = (
|
||||
return false;
|
||||
};
|
||||
|
||||
const rowSelection: TableProps["rowSelection"] = {
|
||||
onChange: (selectedRowKeys: any, selectedRows: DataType[]) => {
|
||||
selectionData.value = selectedRows;
|
||||
}
|
||||
const selectChanged = (_selectedRowKeys: Key[], selectedRows: DataType[]) => {
|
||||
selectionData.value = selectedRows;
|
||||
selectedRowKeys.value = _selectedRowKeys;
|
||||
};
|
||||
|
||||
const rowClickTable = async (item: string, type: number) => {
|
||||
@ -414,6 +416,8 @@ export const useFileManager = (
|
||||
};
|
||||
|
||||
const handleTableChange = (e: { current: number; pageSize: number }) => {
|
||||
selectedRowKeys.value = [];
|
||||
selectionData.value = [];
|
||||
operationForm.value.current = e.current;
|
||||
operationForm.value.pageSize = e.pageSize;
|
||||
getFileList();
|
||||
@ -498,8 +502,13 @@ export const useFileManager = (
|
||||
dialog,
|
||||
percentComplete,
|
||||
spinning,
|
||||
rowSelection,
|
||||
operationForm,
|
||||
dataSource,
|
||||
breadcrumbs,
|
||||
permission,
|
||||
clipboard,
|
||||
selectedRowKeys,
|
||||
selectChanged,
|
||||
openDialog,
|
||||
getFileList,
|
||||
touchFile,
|
||||
|
@ -25,6 +25,7 @@ const { updateUserInfo, state } = useAppStateStore();
|
||||
async function checkPanelStatus() {
|
||||
const status = await panelStatus().execute();
|
||||
state.isInstall = status.value?.isInstall ?? true;
|
||||
state.versionChanged = status.value?.versionChange ? true : false;
|
||||
if (!state.isInstall) {
|
||||
return router.push({
|
||||
path: "/init"
|
||||
@ -34,10 +35,11 @@ async function checkPanelStatus() {
|
||||
|
||||
async function index() {
|
||||
try {
|
||||
await initLayoutConfig();
|
||||
|
||||
const { execute: reqUserInfo } = userInfoApi();
|
||||
const info = await reqUserInfo();
|
||||
updateUserInfo(info.value);
|
||||
await initLayoutConfig();
|
||||
} catch (err) {
|
||||
console.error("Init user info Error:", err);
|
||||
} finally {
|
||||
|
@ -76,8 +76,6 @@ class ApiService {
|
||||
private async sendRequest(reqId: string, config: RequestConfig) {
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
|
||||
console.debug(`[ApiService] Request: ${config.url} \n Full AxiosRequestConfig:`, config);
|
||||
if (!config.timeout) config.timeout = 1000 * 10;
|
||||
const result = await axios(config);
|
||||
const endTime = Date.now();
|
||||
@ -91,8 +89,6 @@ class ApiService {
|
||||
data: realData
|
||||
});
|
||||
|
||||
console.debug("请求响应缓存表长度:", this.responseMap.size);
|
||||
|
||||
this.event.emit(reqId, realData);
|
||||
} catch (error: AxiosError | Error | any) {
|
||||
const axiosErr = error as AxiosError;
|
||||
|
@ -37,6 +37,7 @@ export const panelStatus = useDefineApi<
|
||||
{
|
||||
isInstall: boolean;
|
||||
language: string;
|
||||
versionChange?: string;
|
||||
}
|
||||
>({
|
||||
url: "/api/auth/status",
|
||||
|
@ -7,6 +7,7 @@ import type { BaseUserInfo } from "@/types/user";
|
||||
interface AppStateInfo {
|
||||
userInfo: BaseUserInfo | null;
|
||||
isInstall: boolean;
|
||||
versionChanged: boolean;
|
||||
}
|
||||
|
||||
export const useAppStateStore = createGlobalState(() => {
|
||||
@ -14,7 +15,8 @@ export const useAppStateStore = createGlobalState(() => {
|
||||
|
||||
const state: AppStateInfo = reactive<AppStateInfo>({
|
||||
userInfo: null,
|
||||
isInstall: true
|
||||
isInstall: true,
|
||||
versionChanged: false
|
||||
});
|
||||
|
||||
const cloneState = (): AppStateInfo => {
|
||||
|
@ -1,36 +1,15 @@
|
||||
import type { IGlobalInstanceConfig } from "../../../common/global";
|
||||
import type { LayoutCardHeight } from "@/config/originLayoutConfig";
|
||||
import type {
|
||||
IGlobalInstanceConfig,
|
||||
ILayoutCard as GlobalLayoutCard,
|
||||
ILayoutCardParams as GlobalLayoutCardParams,
|
||||
IJsonData,
|
||||
IMapData
|
||||
} from "../../../common/global";
|
||||
|
||||
export interface JsonData {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface MapData<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
export interface LayoutCardParams {
|
||||
field: string;
|
||||
label: string;
|
||||
type: "string" | "number" | "boolean" | "instanceId";
|
||||
}
|
||||
|
||||
export interface LayoutCard {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
width: number;
|
||||
height: LayoutCardHeight;
|
||||
meta: JsonData;
|
||||
disableAdd?: boolean;
|
||||
onlyPath?: string[];
|
||||
params?: LayoutCardParams[];
|
||||
followId?: string;
|
||||
description?: string;
|
||||
allowedPages?: Array<string> | null;
|
||||
line?: number;
|
||||
disableDelete?: boolean;
|
||||
}
|
||||
export type JsonData = IJsonData;
|
||||
export type MapData<T> = IMapData<T>;
|
||||
export type LayoutCardParams = GlobalLayoutCardParams;
|
||||
export type LayoutCard = GlobalLayoutCard;
|
||||
|
||||
export interface LayoutWithRouter {
|
||||
page: string;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import CardPanel from "@/components/CardPanel.vue";
|
||||
import type { LayoutCard } from "@/types/index";
|
||||
import { ref, computed, reactive, onMounted, watch } from "vue";
|
||||
import { ref, computed, onMounted, watch } from "vue";
|
||||
import { t } from "@/lang/i18n";
|
||||
import { convertFileSize } from "@/tools/fileSize";
|
||||
import dayjs from "dayjs";
|
||||
@ -12,11 +12,9 @@ import { arrayFilter } from "@/tools/array";
|
||||
import { useLayoutCardTools } from "@/hooks/useCardTools";
|
||||
import { throttle } from "lodash";
|
||||
import { getExtName, getFileIcon } from "@/tools/fileManager";
|
||||
|
||||
import { useFileManager } from "@/hooks/usefileManager";
|
||||
import { useFileManager } from "@/hooks/useFileManager";
|
||||
import FileEditor from "./dialogs/FileEditor.vue";
|
||||
|
||||
import type { DataType, OperationForm, Breadcrumb } from "@/types/fileManager";
|
||||
import type { DataType } from "@/types/fileManager";
|
||||
|
||||
const props = defineProps<{
|
||||
card: LayoutCard;
|
||||
@ -28,24 +26,36 @@ const daemonId = getMetaOrRouteValue("daemonId");
|
||||
|
||||
const screen = useScreen();
|
||||
|
||||
const operationForm = ref<OperationForm>({
|
||||
name: "",
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
});
|
||||
|
||||
const selectionData = ref<DataType[]>();
|
||||
|
||||
const dataSource = ref<DataType[]>();
|
||||
|
||||
const breadcrumbs = reactive<Breadcrumb[]>([]);
|
||||
|
||||
breadcrumbs.push({
|
||||
path: "/",
|
||||
name: "/",
|
||||
disabled: false
|
||||
});
|
||||
const {
|
||||
indicator,
|
||||
dialog,
|
||||
percentComplete,
|
||||
spinning,
|
||||
fileStatus,
|
||||
permission,
|
||||
selectedRowKeys,
|
||||
operationForm,
|
||||
dataSource,
|
||||
breadcrumbs,
|
||||
clipboard,
|
||||
selectChanged,
|
||||
getFileList,
|
||||
touchFile,
|
||||
reloadList,
|
||||
setClipBoard,
|
||||
paste,
|
||||
resetName,
|
||||
deleteFile,
|
||||
zipFile,
|
||||
unzipFile,
|
||||
beforeUpload,
|
||||
downloadFile,
|
||||
handleChangeDir,
|
||||
rowClickTable,
|
||||
handleTableChange,
|
||||
getFileStatus,
|
||||
changePermission
|
||||
} = useFileManager(instanceId, daemonId);
|
||||
|
||||
const columns = computed(() => {
|
||||
return arrayFilter([
|
||||
@ -105,45 +115,6 @@ const columns = computed(() => {
|
||||
]);
|
||||
});
|
||||
|
||||
const clipboard = ref<{
|
||||
type: "copy" | "move";
|
||||
value: string[];
|
||||
}>();
|
||||
|
||||
const {
|
||||
indicator,
|
||||
dialog,
|
||||
percentComplete,
|
||||
rowSelection,
|
||||
spinning,
|
||||
fileStatus,
|
||||
permission,
|
||||
getFileList,
|
||||
touchFile,
|
||||
reloadList,
|
||||
setClipBoard,
|
||||
paste,
|
||||
resetName,
|
||||
deleteFile,
|
||||
zipFile,
|
||||
unzipFile,
|
||||
beforeUpload,
|
||||
downloadFile,
|
||||
handleChangeDir,
|
||||
rowClickTable,
|
||||
handleTableChange,
|
||||
getFileStatus,
|
||||
changePermission
|
||||
} = useFileManager(
|
||||
operationForm,
|
||||
breadcrumbs,
|
||||
dataSource,
|
||||
clipboard,
|
||||
selectionData,
|
||||
instanceId,
|
||||
daemonId
|
||||
);
|
||||
|
||||
watch(
|
||||
() => operationForm.value.name,
|
||||
throttle(() => {
|
||||
@ -295,7 +266,10 @@ onMounted(() => {
|
||||
</p>
|
||||
<a-spin :spinning="spinning" :indicator="indicator">
|
||||
<a-table
|
||||
:row-selection="rowSelection"
|
||||
:row-selection="{
|
||||
selectedRowKeys: selectedRowKeys,
|
||||
onChange: selectChanged
|
||||
}"
|
||||
:row-key="(record: DataType) => record.name"
|
||||
:data-source="dataSource"
|
||||
:columns="columns"
|
||||
|
@ -3,7 +3,6 @@
|
||||
"exclude": [],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"lib": [],
|
||||
"types": ["node", "jsdom"]
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,8 @@ interface IClassz {
|
||||
}
|
||||
|
||||
class FileStorageSubsystem implements IStorage {
|
||||
public static readonly STIRAGE_DATA_PATH = path.normalize(path.join(process.cwd(), "data"));
|
||||
public static readonly STIRAGE_INDEX_PATH = path.normalize(
|
||||
path.join(process.cwd(), "data", "index")
|
||||
);
|
||||
public static readonly DATA_PATH = path.normalize(path.join(process.cwd(), "data"));
|
||||
public static readonly INDEX_PATH = path.normalize(path.join(process.cwd(), "data", "index"));
|
||||
|
||||
private checkFileName(name: string) {
|
||||
const blackList = ["\\", "/", ".."];
|
||||
@ -22,7 +20,7 @@ class FileStorageSubsystem implements IStorage {
|
||||
|
||||
// Stored in local file based on class definition and identifier
|
||||
public async store(category: string, uuid: string, object: any) {
|
||||
const dirPath = path.join(FileStorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(FileStorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
if (!this.checkFileName(uuid))
|
||||
throw new Error(`UUID ${uuid} does not conform to specification`);
|
||||
@ -53,7 +51,7 @@ class FileStorageSubsystem implements IStorage {
|
||||
* Instantiate an object based on the class definition and identifier
|
||||
*/
|
||||
public async load(category: string, classz: any, uuid: string) {
|
||||
const dirPath = path.join(FileStorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(FileStorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
if (!this.checkFileName(uuid))
|
||||
throw new Error(`UUID ${uuid} does not conform to specification`);
|
||||
@ -73,7 +71,7 @@ class FileStorageSubsystem implements IStorage {
|
||||
* Return all identifiers related to this class through the class definition
|
||||
*/
|
||||
public async list(category: string) {
|
||||
const dirPath = path.join(FileStorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(FileStorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
const files = fs.readdirSync(dirPath);
|
||||
const result = new Array<string>();
|
||||
@ -87,7 +85,7 @@ class FileStorageSubsystem implements IStorage {
|
||||
* Delete an identifier instance of the specified type through the class definition
|
||||
*/
|
||||
public async delete(category: string, uuid: string) {
|
||||
const filePath = path.join(FileStorageSubsystem.STIRAGE_DATA_PATH, category, `${uuid}.json`);
|
||||
const filePath = path.join(FileStorageSubsystem.DATA_PATH, category, `${uuid}.json`);
|
||||
if (!fs.existsSync(filePath)) return;
|
||||
fs.removeSync(filePath);
|
||||
}
|
||||
|
@ -1,15 +1,9 @@
|
||||
import path from "path";
|
||||
import fs from "fs-extra";
|
||||
|
||||
interface IClassz {
|
||||
name: string;
|
||||
}
|
||||
|
||||
class StorageSubsystem {
|
||||
public static readonly STIRAGE_DATA_PATH = path.normalize(path.join(process.cwd(), "data"));
|
||||
public static readonly STIRAGE_INDEX_PATH = path.normalize(
|
||||
path.join(process.cwd(), "data", "index")
|
||||
);
|
||||
public static readonly DATA_PATH = path.normalize(path.join(process.cwd(), "data"));
|
||||
public static readonly INDEX_PATH = path.normalize(path.join(process.cwd(), "data", "index"));
|
||||
|
||||
private checkFileName(name: string) {
|
||||
const blackList = ["\\", "/", ".."];
|
||||
@ -19,9 +13,24 @@ class StorageSubsystem {
|
||||
return true;
|
||||
}
|
||||
|
||||
public writeFile(name: string, data: string) {
|
||||
const targetPath = path.normalize(path.join(StorageSubsystem.DATA_PATH, name));
|
||||
fs.writeFileSync(targetPath, data, { encoding: "utf-8" });
|
||||
}
|
||||
|
||||
public readFile(name: string) {
|
||||
const targetPath = path.normalize(path.join(StorageSubsystem.DATA_PATH, name));
|
||||
return fs.readFileSync(targetPath, { encoding: "utf-8" });
|
||||
}
|
||||
|
||||
public fileExists(name: string) {
|
||||
const targetPath = path.normalize(path.join(StorageSubsystem.DATA_PATH, name));
|
||||
return fs.existsSync(targetPath);
|
||||
}
|
||||
|
||||
// Stored in local file based on class definition and identifier
|
||||
public store(category: string, uuid: string, object: any) {
|
||||
const dirPath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(StorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
if (!this.checkFileName(uuid))
|
||||
throw new Error(`UUID ${uuid} does not conform to specification`);
|
||||
@ -52,7 +61,7 @@ class StorageSubsystem {
|
||||
* Instantiate an object based on the class definition and identifier
|
||||
*/
|
||||
public load(category: string, classz: any, uuid: string) {
|
||||
const dirPath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(StorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
if (!this.checkFileName(uuid))
|
||||
throw new Error(`UUID ${uuid} does not conform to specification`);
|
||||
@ -72,7 +81,7 @@ class StorageSubsystem {
|
||||
* Return all identifiers related to this class through the class definition
|
||||
*/
|
||||
public list(category: string) {
|
||||
const dirPath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category);
|
||||
const dirPath = path.join(StorageSubsystem.DATA_PATH, category);
|
||||
if (!fs.existsSync(dirPath)) fs.mkdirsSync(dirPath);
|
||||
const files = fs.readdirSync(dirPath);
|
||||
const result = new Array<string>();
|
||||
@ -86,7 +95,7 @@ class StorageSubsystem {
|
||||
* Delete an identifier instance of the specified type through the class definition
|
||||
*/
|
||||
public delete(category: string, uuid: string) {
|
||||
const filePath = path.join(StorageSubsystem.STIRAGE_DATA_PATH, category, `${uuid}.json`);
|
||||
const filePath = path.join(StorageSubsystem.DATA_PATH, category, `${uuid}.json`);
|
||||
if (!fs.existsSync(filePath)) return;
|
||||
fs.removeSync(filePath);
|
||||
}
|
||||
|
@ -1,17 +1,14 @@
|
||||
import Router from "@koa/router";
|
||||
import remoteService from "../../service/system_remote_service";
|
||||
import { setImmediate } from "timers";
|
||||
import permission from "../../middleware/permission";
|
||||
import validator from "../../middleware/validator";
|
||||
import { saveSystemConfig, systemConfig } from "../../setting";
|
||||
import { logger } from "../../service/log";
|
||||
import { i18next } from "../../i18n";
|
||||
import userSystem from "../../service/system_user";
|
||||
import * as fs from "fs-extra";
|
||||
import path from "path";
|
||||
import { getFrontendLayoutConfig, setFrontendLayoutConfig } from "../../service/frontend_layout";
|
||||
|
||||
const router = new Router({ prefix: "/overview" });
|
||||
const LAYOUT_CONFIG_PATH = path.normalize(path.join(process.cwd(), "data", "layout.json"));
|
||||
|
||||
// [Top-level Permission]
|
||||
// Get panel configuration items
|
||||
@ -69,14 +66,14 @@ router.put("/install", async (ctx) => {
|
||||
ctx.body = new Error("The MCSManager has been installed");
|
||||
});
|
||||
|
||||
router.get("/layout", permission({ level: 1 }), async (ctx) => {
|
||||
const layoutConfig = fs.readFileSync(LAYOUT_CONFIG_PATH, "utf-8");
|
||||
ctx.body = layoutConfig;
|
||||
// [Public router]
|
||||
router.get("/layout", async (ctx) => {
|
||||
ctx.body = getFrontendLayoutConfig();
|
||||
});
|
||||
|
||||
router.post("/layout", permission({ level: 10 }), async (ctx) => {
|
||||
const config = ctx.request.body;
|
||||
fs.writeFileSync(LAYOUT_CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8");
|
||||
setFrontendLayoutConfig(config);
|
||||
ctx.body = true;
|
||||
});
|
||||
|
||||
|
@ -10,6 +10,7 @@ import userSystem from "../../service/system_user";
|
||||
import { logger } from "../../service/log";
|
||||
import { $t } from "../../i18n";
|
||||
import axios from "axios";
|
||||
import GlobalVariable from "../../common/global_variable";
|
||||
const router = new Router({ prefix: "/auth" });
|
||||
|
||||
// [Public Permission]
|
||||
@ -66,6 +67,7 @@ router.all(
|
||||
isInstall = false;
|
||||
}
|
||||
ctx.body = {
|
||||
versionChange: GlobalVariable.get("versionChange", null),
|
||||
isInstall,
|
||||
language: systemConfig.language || null
|
||||
};
|
||||
|
491
panel/src/app/service/frontend_layout.ts
Normal file
491
panel/src/app/service/frontend_layout.ts
Normal file
@ -0,0 +1,491 @@
|
||||
import { v4 } from "uuid";
|
||||
import { IPageLayoutConfig } from "../../../../common/global";
|
||||
import { $t as t } from "../i18n";
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import storage from "../common/system_storage";
|
||||
|
||||
const LAYOUT_CONFIG_NAME = "layout.json";
|
||||
|
||||
function getRandomId() {
|
||||
return v4();
|
||||
}
|
||||
|
||||
export function getFrontendLayoutConfig(): string {
|
||||
let layoutConfig: string;
|
||||
if (storage.fileExists(LAYOUT_CONFIG_NAME)) {
|
||||
layoutConfig = storage.readFile(LAYOUT_CONFIG_NAME);
|
||||
}
|
||||
if (layoutConfig) {
|
||||
return layoutConfig as string;
|
||||
} else {
|
||||
setFrontendLayoutConfig(DEFAULT_FRONTEND_LAYOUT_CONFIG);
|
||||
return getFrontendLayoutConfig();
|
||||
}
|
||||
}
|
||||
|
||||
export function setFrontendLayoutConfig(config: IPageLayoutConfig[]) {
|
||||
storage.writeFile(LAYOUT_CONFIG_NAME, JSON.stringify(config, null, 2));
|
||||
}
|
||||
|
||||
export enum LayoutCardHeight {
|
||||
MINI = "100px",
|
||||
SMALL = "200px",
|
||||
MEDIUM = "400px",
|
||||
BIG = "600px",
|
||||
LARGE = "800px",
|
||||
AUTO = "unset"
|
||||
}
|
||||
|
||||
// 默认配置
|
||||
export const DEFAULT_FRONTEND_LAYOUT_CONFIG: IPageLayoutConfig[] = [
|
||||
{
|
||||
page: "/",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_e627e546"),
|
||||
meta: {
|
||||
type: "node"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_88e9361a"),
|
||||
meta: {
|
||||
type: "instance"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_db64faf6"),
|
||||
meta: {
|
||||
type: "users"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
type: "StatusBlock",
|
||||
title: t("TXT_CODE_66056676"),
|
||||
meta: {
|
||||
type: "system"
|
||||
},
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "DataOverview",
|
||||
title: t("TXT_CODE_721157a3"),
|
||||
width: 9,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.MEDIUM
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "QuickStart",
|
||||
title: t("TXT_CODE_2799a1dd"),
|
||||
width: 3,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.MEDIUM
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "RequestChart",
|
||||
title: t("TXT_CODE_a4037a98"),
|
||||
width: 6,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceChart",
|
||||
title: t("TXT_CODE_d6d9c42c"),
|
||||
width: 6,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "NodeOverview",
|
||||
title: t("TXT_CODE_bfb50126"),
|
||||
width: 12,
|
||||
description: t("TXT_CODE_55ade942"),
|
||||
height: LayoutCardHeight.MEDIUM
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceList",
|
||||
title: t("TXT_CODE_e21473bc"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {
|
||||
viewType: "inner"
|
||||
},
|
||||
type: "Terminal",
|
||||
title: t("TXT_CODE_4ccdd3a0"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.BIG,
|
||||
disableDelete: true
|
||||
},
|
||||
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceBaseInfo",
|
||||
title: t("TXT_CODE_eadb4f60"),
|
||||
width: 4,
|
||||
height: LayoutCardHeight.SMALL
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceManagerBtns",
|
||||
title: t("TXT_CODE_efd37c48"),
|
||||
width: 8,
|
||||
height: LayoutCardHeight.SMALL,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal/files",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceFileManager",
|
||||
title: t("文件管理"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal/serverConfig",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceServerConfigOverview",
|
||||
title: t("服务端配置文件"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/instances/terminal/serverConfig/fileEdit",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "InstanceServerConfigFile",
|
||||
title: t("编辑服务端配置文件"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/users",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "UserList",
|
||||
title: t("用户列表"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/users/config",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "UserAccessSettings",
|
||||
title: t("用户权限设定"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/settings",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "Settings",
|
||||
title: t("系统设置"),
|
||||
width: 8,
|
||||
height: LayoutCardHeight.MEDIUM,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/node",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "NodeList",
|
||||
title: t("TXT_CODE_20509fa0"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/node/image",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "ImageManager",
|
||||
title: t("镜像管理"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/node/image/new",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "NewImage",
|
||||
title: t("创建镜像"),
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO,
|
||||
disableDelete: true
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/quickstart",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "QuickStartFlow",
|
||||
title: t("TXT_CODE_9b99b72e"),
|
||||
width: 8,
|
||||
height: LayoutCardHeight.AUTO
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/quickstart/minecraft",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "McPreset",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.AUTO
|
||||
},
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "EmptyCard",
|
||||
title: "",
|
||||
width: 12,
|
||||
height: LayoutCardHeight.MINI
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
page: "/customer",
|
||||
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",
|
||||
items: [
|
||||
{
|
||||
id: getRandomId(),
|
||||
meta: {},
|
||||
type: "Page404",
|
||||
title: t("页面未找到"),
|
||||
width: 6,
|
||||
height: LayoutCardHeight.MINI,
|
||||
disableDelete: true
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
@ -1,21 +1,42 @@
|
||||
import * as fs from "fs-extra";
|
||||
import GlobalVariable from "./common/global_variable";
|
||||
import { logger } from "./service/log";
|
||||
import path from "path";
|
||||
import storage from "./common/system_storage";
|
||||
|
||||
interface PackageInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
daemonVersion: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const PACKAGE_JSON = "package.json";
|
||||
const VERSION_LOG_TEXT_NAME = "current-version.txt";
|
||||
let currentVersion = "";
|
||||
|
||||
export function initVersionManager() {
|
||||
try {
|
||||
GlobalVariable.set("version", "Unknown");
|
||||
if (fs.existsSync(PACKAGE_JSON)) {
|
||||
const data: any = JSON.parse(fs.readFileSync(PACKAGE_JSON, { encoding: "utf-8" }));
|
||||
const data: PackageInfo = JSON.parse(fs.readFileSync(PACKAGE_JSON, { encoding: "utf-8" }));
|
||||
if (data.version) {
|
||||
GlobalVariable.set("version", data.version);
|
||||
currentVersion = String(data.version);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Version Check failure:", error);
|
||||
}
|
||||
|
||||
if (currentVersion && storage.fileExists(VERSION_LOG_TEXT_NAME)) {
|
||||
const LastLaunchedVersion = storage.readFile(VERSION_LOG_TEXT_NAME);
|
||||
if (LastLaunchedVersion && LastLaunchedVersion != currentVersion) {
|
||||
logger.info(`Version changed from ${LastLaunchedVersion} to ${currentVersion}`);
|
||||
GlobalVariable.set("versionChange", currentVersion);
|
||||
}
|
||||
}
|
||||
storage.writeFile(VERSION_LOG_TEXT_NAME, currentVersion);
|
||||
}
|
||||
|
||||
export function getVersion(): string {
|
||||
|
Loading…
Reference in New Issue
Block a user