perf: Optimize the frontend architecture. (#12479)

This commit is contained in:
CityFun
2026-04-13 18:36:28 +08:00
committed by GitHub
parent 89888cef73
commit 6dc218cf80
134 changed files with 703 additions and 1020 deletions

1
.gitignore vendored
View File

@@ -9,7 +9,6 @@ build/1panel-core
# Mac
.DS_Store
*/.DS_Store
# VS Code
.vscode

View File

@@ -40,7 +40,7 @@ module.exports = {
'no-irregular-whitespace': 'off', // 禁止不规则的空白
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/no-unused-vars': ['error', { caughtErrors: 'none' }], // 保持现有 catch(error) 写法,不在依赖升级时强制清理
'@typescript-eslint/no-inferrable-types': 'off', // 可以轻松推断的显式类型可能会增加不必要的冗长
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
@@ -49,7 +49,10 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off', // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明
'@typescript-eslint/no-var-requires': 'off', // 不允许在 import 语句中使用 require 语句
'@typescript-eslint/no-empty-function': 'off', // 禁止空函数
'@typescript-eslint/no-empty-object-type': 'off', // 保持现有 {} 类型写法,不在规则升级时批量重构
'@typescript-eslint/no-use-before-define': 'off', // 禁止在变量定义之前使用它们
'@typescript-eslint/no-unused-expressions': 'off', // 保持现有短路表达式调用写法
'@typescript-eslint/no-unsafe-function-type': 'off', // 保持现有 Function 类型写法,不在本轮升级中扩散修改
'@typescript-eslint/ban-ts-comment': 'off', // 禁止 @ts-<directive> 使用注释或要求在指令后进行描述
'@typescript-eslint/no-non-null-assertion': 'off', // 不允许使用后缀运算符的非空断言(!)
'@typescript-eslint/explicit-module-boundary-types': 'off', // 要求导出函数和类的公共类方法的显式返回和参数类型
@@ -69,5 +72,6 @@ module.exports = {
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
'vue/require-default-prop': 'off', // 此规则要求为每个 prop 为必填时,必须提供默认值
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/no-dupe-keys': 'off', // 保持现有仓库的 script/template 同名用法,不在依赖升级时引入额外改造
},
};

View File

@@ -1,6 +1,6 @@
module.exports = {
'*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
'{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write --parser json'],
'package.json': ['prettier --write'],
'*.vue': ['eslint --fix', 'prettier --write'],
'*.{scss,less,styl,html}': ['prettier --write'],

View File

@@ -29,7 +29,7 @@
"@element-plus/icons-vue": "^1.1.4",
"@vue-office/docx": "^1.6.2",
"@vue-office/excel": "^1.7.8",
"@vueuse/core": "^8.9.4",
"@vueuse/core": "^12.8.2",
"@xterm/addon-fit": "^0.10.0",
"@xterm/xterm": "^5.5.0",
"anser": "^2.3.2",
@@ -39,8 +39,6 @@
"dompurify": "^3.3.1",
"echarts": "^5.5.0",
"element-plus": "2.11.9",
"fit2cloud-ui-plus": "^1.2.4",
"highlight.js": "^11.9.0",
"js-base64": "^3.7.7",
"jsencrypt": "^3.3.2",
"md-editor-v3": "^2.11.3",
@@ -53,7 +51,7 @@
"screenfull": "^6.0.2",
"sortablejs": "^1.15.7",
"uuid": "^10.0.0",
"vue": "^3.4.27",
"vue": "^3.5.32",
"vue-clipboard3": "^2.0.0",
"vue-codemirror": "^6.1.1",
"vue-demi": "^0.14.6",
@@ -63,36 +61,34 @@
"devDependencies": {
"@types/node": "^20.14.8",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.22.0",
"@typescript-eslint/eslint-plugin": "^8.58.1",
"@typescript-eslint/parser": "^8.58.1",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.1.1",
"@vue/compiler-sfc": "^3.5.32",
"autoprefixer": "^10.4.7",
"commitizen": "^4.2.4",
"esbuild": "^0.27.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^8.7.1",
"lint-staged": "^12.4.2",
"eslint-config-prettier": "^9.1.2",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-vue": "^9.33.0",
"lint-staged": "^16.4.0",
"postcss": "^8.4.31",
"postcss-html": "^1.4.1",
"prettier": "^2.6.2",
"prettier": "^3.8.2",
"rollup-plugin-visualizer": "^5.5.4",
"sass": "^1.83.0",
"standard-version": "^9.5.0",
"tailwindcss": "^3.4.1",
"typescript": "^4.5.4",
"typescript": "^5.9.2",
"unplugin-auto-import": "^0.16.4",
"unplugin-vue-components": "^0.25.0",
"unplugin-vue-define-options": "^3.0.0-beta.23",
"vite": "^7.1.5",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eslint2": "^5.0.3",
"vite-plugin-html": "^3.2.2",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vite-svg-loader": "^5.1.0",
"vue-tsc": "^0.29.8"
"vue-tsc": "^2.2.12"
},
"trustedDependencies": [
"@parcel/watcher",

View File

@@ -1,5 +1,4 @@
import axios, { AxiosRequestConfig, Canceler } from 'axios';
import { isFunction } from '@vueuse/core';
import qs from 'qs';
// * 声明一个 Map 用于存储每个请求的标识 和 取消函数
@@ -39,7 +38,7 @@ export class AxiosCanceler {
if (pendingMap.has(url)) {
// 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
const cancel = pendingMap.get(url);
isFunction(cancel) && cancel();
typeof cancel === 'function' && cancel();
pendingMap.delete(url);
}
}
@@ -49,7 +48,7 @@ export class AxiosCanceler {
*/
removeAllPending() {
pendingMap.forEach((cancel) => {
isFunction(cancel) && cancel();
typeof cancel === 'function' && cancel();
});
pendingMap.clear();
}

View File

@@ -13,7 +13,7 @@ export const checkStatus = (status: number, msg: string): void => {
MsgError(msg ? msg : i18n.global.t('commons.res.notFound'));
break;
case 403:
globalStore.setLogStatus(false);
globalStore.isLogin = false;
router.replace({ name: 'entrance', params: { code: globalStore.entrance } });
MsgError(msg ? msg : i18n.global.t('commons.res.forbidden'));
break;

View File

@@ -5,7 +5,7 @@ import { checkStatus } from './helper/check-status';
import router from '@/routers';
import { GlobalStore } from '@/store';
import { MsgError } from '@/utils/message';
import { Base64 } from 'js-base64';
import { encodeBase64 } from '@/utils/base64';
import i18n from '@/lang';
import { changeToLocal } from '@/utils/node';
import { getCookie } from '@/utils/auth';
@@ -44,7 +44,7 @@ class RequestHttp {
config.url === '/core/auth/passkey/begin' ||
config.url === '/core/auth/passkey/finish'
) {
let entrance = Base64.encode(globalStore.entrance);
let entrance = encodeBase64(globalStore.entrance);
config.headers.EntranceCode = entrance;
}
const method = (config.method || 'get').toUpperCase();
@@ -53,7 +53,7 @@ class RequestHttp {
const csrfToken = getCookie('pcsrftoken');
if (csrfToken) {
config.headers['X-CSRF-Token'] = csrfToken;
globalStore.setCsrfToken(csrfToken);
globalStore.csrfToken = csrfToken;
}
}
return {
@@ -69,7 +69,7 @@ class RequestHttp {
(response: AxiosResponse) => {
const { data } = response;
if (data.code == ResultEnum.OVERDUE || data.code == ResultEnum.FORBIDDEN) {
globalStore.setLogStatus(false);
globalStore.isLogin = false;
router.push({
name: 'entrance',
params: { code: globalStore.entrance },
@@ -90,13 +90,15 @@ class RequestHttp {
window.location.reload();
return;
}
if (data.code == ResultEnum.ERRGLOBALLOADDING) {
globalStore.setGlobalLoading(true);
globalStore.setLoadingText(data.message);
if (data.code == ResultEnum.ERRGLOBALLOADING) {
globalStore.$patch({
isLoading: true,
loadingText: data.message,
});
return;
} else {
if (globalStore.isLoading) {
globalStore.setGlobalLoading(false);
globalStore.isLoading = false;
}
}
if (data.code == ResultEnum.ERRAUTH) {

View File

@@ -210,7 +210,7 @@ export namespace App {
linkDB: boolean;
}
export interface AppInstalledInfo {
export interface AppInstalledOption {
id: number;
key: string;
name: string;
@@ -267,7 +267,7 @@ export namespace App {
export interface AppService {
label: string;
value: string;
config?: Object;
config?: object;
from?: string;
status: string;
}

View File

@@ -157,10 +157,6 @@ export namespace Container {
ipv6: string;
macAddr: string;
}
export interface ContainerInfo {
name: string;
state: string;
}
export interface ContainerItemStats {
sizeRw: number;
sizeRootFs: number;

View File

@@ -39,7 +39,7 @@ export namespace Cronjob {
files: Array<Item>;
sourceDir: string;
snapshotRule: snapshotRule;
ignoreAppIDs: Array<Number>;
ignoreAppIDs: Array<number>;
withImage: boolean;
websiteList: Array<string>;
@@ -165,7 +165,7 @@ export namespace Cronjob {
}
export interface snapshotRule {
withImage: boolean;
ignoreAppIDs: Array<Number>;
ignoreAppIDs: Array<number>;
}
export interface SpecObj {
specType: string;

View File

@@ -185,6 +185,8 @@ export namespace Database {
format: string;
username: string;
password: string;
superUser: boolean;
isDelete: string;
description: string;
}
export interface PostgresqlConfUpdateByFile {
@@ -202,19 +204,6 @@ export namespace Database {
superUser: boolean;
description: string;
}
export interface PostgresqlDBInfo {
id: number;
createdAt: Date;
name: string;
mysqlName: string;
from: string;
format: string;
username: string;
password: string;
superUser: boolean;
isDelete: string;
description: string;
}
export interface ChangeInfo {
id: number;
from: string;

View File

@@ -4,7 +4,7 @@ export namespace HostTool {
config: {};
}
export interface Supersivor extends HostTool {
export interface Supervisor extends HostTool {
configPath: string;
includeDir: string;
logPath: string;
@@ -17,24 +17,24 @@ export namespace HostTool {
serviceName: string;
}
export interface SupersivorConfig {
export interface SupervisorConfig {
type: string;
operate: string;
content?: string;
}
export interface SupersivorConfigRes {
export interface SupervisorConfigRes {
type: string;
content: string;
}
export interface SupersivorInit {
export interface SupervisorInit {
type: string;
configPath: string;
serviceName: string;
}
export interface SupersivorProcess {
export interface SupervisorProcess {
operate: string;
name: string;
command: string;

View File

@@ -51,7 +51,7 @@ export namespace Runtime {
name: string;
appDetailID: number;
image: string;
params: Object;
params: object;
type: string;
resource: string;
appID?: number;
@@ -211,7 +211,7 @@ export namespace Runtime {
id: number;
}
export interface SupersivorProcess {
export interface SupervisorProcess {
operate: string;
name: string;
command: string;

View File

@@ -204,20 +204,20 @@ export namespace Website {
export interface DnsAccount extends CommonModel {
name: string;
type: string;
authorization: Object;
authorization: object;
}
export interface DnsAccountCreate {
name: string;
type: string;
authorization: Object;
authorization: object;
}
export interface DnsAccountUpdate {
id: number;
name: string;
type: string;
authorization: Object;
authorization: object;
}
export interface SSL extends CommonModel {
@@ -403,7 +403,7 @@ export namespace Website {
content: string;
}
export interface CustomRewirte {
export interface CustomRewrite {
operate: string;
name: string;
content: string;

View File

@@ -47,7 +47,7 @@ export const searchAppInstalled = (search: App.AppInstallSearch, node?: string)
};
export const listAppInstalled = () => {
return http.get<Array<App.AppInstalledInfo>>('apps/installed/list');
return http.get<Array<App.AppInstalledOption>>('apps/installed/list');
};
export const getAppPort = (type: string, name: string) => {

View File

@@ -1,6 +1,6 @@
import http from '@/api';
import { deepCopy } from '@/utils/misc';
import { Base64 } from 'js-base64';
import { encodeBase64Fields } from '@/utils/base64';
import { ResPage } from '../interface';
import { Backup } from '../interface/backup';
import { TimeoutEnum } from '@/enums/http-enum';
@@ -17,12 +17,7 @@ export const searchBackup = (params: Backup.SearchWithType) => {
};
export const checkBackup = (params: Backup.BackupOperate) => {
let request = deepCopy(params) as Backup.BackupOperate;
if (request.accessKey) {
request.accessKey = Base64.encode(request.accessKey);
}
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
encodeBase64Fields(request, ['accessKey', 'credential']);
if (!params.isPublic || !globalStore.isProductPro) {
return http.postLocalNode<Backup.CheckResult>(`/backups/conn/check`, request);
}
@@ -30,12 +25,7 @@ export const checkBackup = (params: Backup.BackupOperate) => {
};
export const listBucket = (params: Backup.ForBucket) => {
let request = deepCopy(params) as Backup.BackupOperate;
if (request.accessKey) {
request.accessKey = Base64.encode(request.accessKey);
}
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
encodeBase64Fields(request, ['accessKey', 'credential']);
if (!params.isPublic || !globalStore.isProductPro) {
return http.postLocalNode('/backups/buckets', request, TimeoutEnum.T_40S);
}
@@ -64,11 +54,11 @@ export const deleteBackupRecord = (params: { ids: number[] }, node?: string) =>
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/record/del${query}`, params);
};
export const updateRecordDescription = (id: Number, description: String, node?: string) => {
export const updateRecordDescription = (id: number, description: string, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/record/description/update${query}`, { id: id, description: description });
};
export const uploadByRecover = (filePath: string, targetDir: String, node?: string) => {
export const uploadByRecover = (filePath: string, targetDir: string, node?: string) => {
const query = node ? `?operateNode=${node}` : '';
return http.post(`/backups/upload${query}`, { filePath: filePath, targetDir: targetDir });
};
@@ -99,12 +89,7 @@ export const getClientInfo = (clientType: string) => {
};
export const addBackup = (params: Backup.BackupOperate) => {
let request = deepCopy(params) as Backup.BackupOperate;
if (request.accessKey) {
request.accessKey = Base64.encode(request.accessKey);
}
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
encodeBase64Fields(request, ['accessKey', 'credential']);
let urlItem = '/core/backups';
if (!params.isPublic) {
urlItem = '/backups';
@@ -113,12 +98,7 @@ export const addBackup = (params: Backup.BackupOperate) => {
};
export const editBackup = (params: Backup.BackupOperate) => {
let request = deepCopy(params) as Backup.BackupOperate;
if (request.accessKey) {
request.accessKey = Base64.encode(request.accessKey);
}
if (request.credential) {
request.credential = Base64.encode(request.credential);
}
encodeBase64Fields(request, ['accessKey', 'credential']);
let urlItem = '/core/backups/update';
if (!params.isPublic) {
urlItem = '/backups/update';

View File

@@ -177,7 +177,7 @@ export const createImageRepo = (params: Container.RepoCreate) => {
export const updateImageRepo = (params: Container.RepoUpdate) => {
return http.post(`/containers/repo/update`, params, TimeoutEnum.T_40S);
};
export const deleteImageRepo = (id: Number) => {
export const deleteImageRepo = (id: number) => {
return http.post(`/containers/repo/del`, { id: id }, TimeoutEnum.T_40S);
};

View File

@@ -9,7 +9,7 @@ export const searchCronjobPage = (params: Cronjob.Search, node?: string) => {
};
export const loadNextHandle = (spec: string) => {
return http.post<Array<String>>(`/cronjobs/next`, { spec: spec });
return http.post<Array<string>>(`/cronjobs/next`, { spec: spec });
};
export const editCronjobGroup = (id: number, groupID: number) => {

View File

@@ -1,6 +1,6 @@
import http from '@/api';
import { deepCopy } from '@/utils/misc';
import { Base64 } from 'js-base64';
import { encodeBase64, encodeBase64Fields } from '@/utils/base64';
import { ResPage, DescriptionUpdate } from '../interface';
import { Database } from '../interface/database';
import { TimeoutEnum } from '@/enums/http-enum';
@@ -19,9 +19,7 @@ export const updateDBFile = (params: Database.DBConfUpdate) => {
// pg
export const addPostgresqlDB = (params: Database.PostgresqlDBCreate) => {
let request = deepCopy(params) as Database.PostgresqlDBCreate;
if (request.password) {
request.password = Base64.encode(request.password);
}
encodeBase64Fields(request, ['password']);
return http.post(`/databases/pg`, request, TimeoutEnum.T_40S);
};
export const bindPostgresqlUser = (params: Database.PgBind) => {
@@ -45,9 +43,7 @@ export const deleteCheckPostgresqlDB = (params: Database.PostgresqlDBDeleteCheck
};
export const updatePostgresqlPassword = (params: Database.ChangeInfo) => {
let request = deepCopy(params) as Database.ChangeInfo;
if (request.value) {
request.value = Base64.encode(request.value);
}
encodeBase64Fields(request, ['value']);
return http.post(`/databases/pg/password`, request, TimeoutEnum.T_40S);
};
export const deletePostgresqlDB = (params: Database.PostgresqlDBDelete) => {
@@ -61,16 +57,12 @@ export const searchMysqlDBs = (params: Database.SearchDBWithPage, node?: string)
};
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
let request = deepCopy(params) as Database.MysqlDBCreate;
if (request.password) {
request.password = Base64.encode(request.password);
}
encodeBase64Fields(request, ['password']);
return http.post(`/databases`, request);
};
export const bindUser = (params: Database.BindUser) => {
let request = deepCopy(params) as Database.BindUser;
if (request.password) {
request.password = Base64.encode(request.password);
}
encodeBase64Fields(request, ['password']);
return http.post(`/databases/bind`, request);
};
export const loadDBFromRemote = (params: Database.MysqlLoadDB) => {
@@ -81,9 +73,7 @@ export const updateMysqlAccess = (params: Database.ChangeInfo) => {
};
export const updateMysqlPassword = (params: Database.ChangeInfo) => {
let request = deepCopy(params) as Database.ChangeInfo;
if (request.value) {
request.value = Base64.encode(request.value);
}
encodeBase64Fields(request, ['value']);
return http.post(`/databases/change/password`, request);
};
export const updateMysqlDescription = (params: DescriptionUpdate) => {
@@ -133,7 +123,7 @@ export const installRedisCli = () => {
};
export const changeRedisPassword = (database: string, password: string) => {
if (password) {
password = Base64.encode(password);
password = encodeBase64(password);
}
return http.post(`/databases/redis/password`, { database: database, value: password });
};
@@ -164,9 +154,7 @@ export const listDbItems = (type: string) => {
export const checkDatabase = (params: Database.DatabaseCreate) => {
let request = deepCopy(params) as Database.DatabaseCreate;
if (request.ssl) {
request.clientKey = Base64.encode(request.clientKey);
request.clientCert = Base64.encode(request.clientCert);
request.rootCert = Base64.encode(request.rootCert);
encodeBase64Fields(request, ['clientKey', 'clientCert', 'rootCert']);
}
return http.post<boolean>(`/databases/db/check`, request, TimeoutEnum.T_60S);
@@ -174,9 +162,7 @@ export const checkDatabase = (params: Database.DatabaseCreate) => {
export const addDatabase = (params: Database.DatabaseCreate) => {
let request = deepCopy(params) as Database.DatabaseCreate;
if (request.ssl) {
request.clientKey = Base64.encode(request.clientKey);
request.clientCert = Base64.encode(request.clientCert);
request.rootCert = Base64.encode(request.rootCert);
encodeBase64Fields(request, ['clientKey', 'clientCert', 'rootCert']);
}
return http.post(`/databases/db`, request, TimeoutEnum.T_60S);
@@ -184,9 +170,7 @@ export const addDatabase = (params: Database.DatabaseCreate) => {
export const editDatabase = (params: Database.DatabaseUpdate) => {
let request = deepCopy(params) as Database.DatabaseCreate;
if (request.ssl) {
request.clientKey = Base64.encode(request.clientKey);
request.clientCert = Base64.encode(request.clientCert);
request.rootCert = Base64.encode(request.rootCert);
encodeBase64Fields(request, ['clientKey', 'clientCert', 'rootCert']);
}
return http.post(`/databases/db/update`, request, TimeoutEnum.T_60S);

View File

@@ -10,19 +10,19 @@ export const operateSupervisor = (operate: string) => {
return http.post<any>(`/hosts/tool/operate`, { type: 'supervisord', operate: operate });
};
export const operateSupervisorConfig = (req: HostTool.SupersivorConfig) => {
return http.post<HostTool.SupersivorConfigRes>(`/hosts/tool/config`, req);
export const operateSupervisorConfig = (req: HostTool.SupervisorConfig) => {
return http.post<HostTool.SupervisorConfigRes>(`/hosts/tool/config`, req);
};
export const getSupervisorLog = () => {
return http.post<any>(`/hosts/tool/log`, { type: 'supervisord' });
};
export const initSupervisor = (req: HostTool.SupersivorInit) => {
export const initSupervisor = (req: HostTool.SupervisorInit) => {
return http.post<any>(`/hosts/tool/init`, req);
};
export const createSupervisorProcess = (req: HostTool.SupersivorProcess) => {
export const createSupervisorProcess = (req: HostTool.SupervisorProcess) => {
return http.post<any>(`/hosts/tool/supervisor/process`, req);
};
@@ -31,7 +31,7 @@ export const operateSupervisorProcess = (req: HostTool.ProcessReq) => {
};
export const getSupervisorProcess = () => {
return http.get<HostTool.SupersivorProcess[]>(`/hosts/tool/supervisor/process`, {}, { timeout: TimeoutEnum.T_3M });
return http.get<HostTool.SupervisorProcess[]>(`/hosts/tool/supervisor/process`, {}, { timeout: TimeoutEnum.T_3M });
};
export const operateSupervisorProcessFile = (req: HostTool.ProcessFileReq) => {

View File

@@ -3,7 +3,7 @@ import { ResPage, ReqPage } from '../interface';
import { Host } from '../interface/host';
import { TimeoutEnum } from '@/enums/http-enum';
import { deepCopy } from '@/utils/misc';
import { Base64 } from 'js-base64';
import { encodeBase64Fields } from '@/utils/base64';
// firewall
export const loadFireBaseInfo = (tab: string) => {
@@ -105,28 +105,12 @@ export const updateSSHByFile = (key: string, value: string, path = '') => {
};
export const createCert = (params: Host.RootCert) => {
let request = deepCopy(params) as Host.RootCert;
if (request.passPhrase) {
request.passPhrase = Base64.encode(request.passPhrase);
}
if (request.privateKey) {
request.privateKey = Base64.encode(request.privateKey);
}
if (request.publicKey) {
request.publicKey = Base64.encode(request.publicKey);
}
encodeBase64Fields(request, ['passPhrase', 'privateKey', 'publicKey']);
return http.post(`/hosts/ssh/cert`, request);
};
export const editCert = (params: Host.RootCert) => {
let request = deepCopy(params) as Host.RootCert;
if (request.passPhrase) {
request.passPhrase = Base64.encode(request.passPhrase);
}
if (request.privateKey) {
request.privateKey = Base64.encode(request.privateKey);
}
if (request.publicKey) {
request.publicKey = Base64.encode(request.publicKey);
}
encodeBase64Fields(request, ['passPhrase', 'privateKey', 'publicKey']);
return http.post(`/hosts/ssh/cert/update`, request);
};
export const searchCert = (params: ReqPage) => {

View File

@@ -118,7 +118,7 @@ export const operateSupervisorProcessFile = (req: Runtime.ProcessFileReq) => {
return http.post<string>(`/runtimes/supervisor/process/file`, req, TimeoutEnum.T_60S);
};
export const createSupervisorProcess = (req: Runtime.SupersivorProcess) => {
export const createSupervisorProcess = (req: Runtime.SupervisorProcess) => {
return http.post(`/runtimes/supervisor/process`, req);
};

View File

@@ -1,6 +1,6 @@
import http from '@/api';
import { deepCopy } from '@/utils/misc';
import { Base64 } from 'js-base64';
import { encodeBase64Fields } from '@/utils/base64';
import { ResPage, SearchWithPage, DescriptionUpdate, ReqPage } from '../interface';
import { Setting } from '../interface/setting';
import { TimeoutEnum } from '@/enums/http-enum';
@@ -119,9 +119,7 @@ export const defaultMenu = () => {
};
export const updateProxy = (params: Setting.ProxyUpdate) => {
let request = deepCopy(params) as Setting.ProxyUpdate;
if (request.proxyPasswd) {
request.proxyPasswd = Base64.encode(request.proxyPasswd);
}
encodeBase64Fields(request, ['proxyPasswd']);
request.proxyType = request.proxyType === 'close' ? '' : request.proxyType;
return http.post(`/core/settings/proxy/update`, request);
};

View File

@@ -1,7 +1,7 @@
import http from '@/api';
import { ResPage } from '../interface';
import { Host } from '../interface/host';
import { Base64 } from 'js-base64';
import { encodeBase64Fields } from '@/utils/base64';
import { deepCopy } from '@/utils/misc';
export const searchHosts = (params: Host.SearchWithPage) => {
return http.postLocalNode<ResPage<Host.Host>>(`/hosts/search`, params);
@@ -17,12 +17,7 @@ export const updateLocalConn = (param: { withReset: boolean; defaultConn: string
};
export const addHost = (params: Host.HostOperate) => {
let request = deepCopy(params) as Host.HostOperate;
if (request.password) {
request.password = Base64.encode(request.password);
}
if (request.privateKey) {
request.privateKey = Base64.encode(request.privateKey);
}
encodeBase64Fields(request, ['password', 'privateKey']);
if (params.isLocal) {
return http.post(`/settings/ssh`, request);
}
@@ -30,12 +25,7 @@ export const addHost = (params: Host.HostOperate) => {
};
export const testByInfo = (params: Host.HostConnTest) => {
let request = deepCopy(params) as Host.HostOperate;
if (request.password) {
request.password = Base64.encode(request.password);
}
if (request.privateKey) {
request.privateKey = Base64.encode(request.privateKey);
}
encodeBase64Fields(request, ['password', 'privateKey']);
if (params.isLocal) {
return http.post<boolean>(`/settings/ssh/check/info`, request);
}
@@ -46,12 +36,7 @@ export const testByID = (id: number) => {
};
export const editHost = (params: Host.HostOperate) => {
let request = deepCopy(params) as Host.HostOperate;
if (request.password) {
request.password = Base64.encode(request.password);
}
if (request.privateKey) {
request.privateKey = Base64.encode(request.privateKey);
}
encodeBase64Fields(request, ['password', 'privateKey']);
return http.postLocalNode(`/hosts/update`, request);
};
export const editHostGroup = (params: Host.GroupChange) => {

View File

@@ -1,7 +1,7 @@
import http from '@/api';
import { ReqPage, ResPage, UpdateByFile } from '../interface';
import { Toolbox } from '../interface/toolbox';
import { Base64 } from 'js-base64';
import { encodeBase64, encodeBase64Fields } from '@/utils/base64';
import { TimeoutEnum } from '@/enums/http-enum';
import { deepCopy } from '@/utils/misc';
// device
@@ -21,7 +21,7 @@ export const updateDeviceHost = (param: Array<Toolbox.TimeZoneOptions>) => {
return http.post(`/toolbox/device/update/host`, param, TimeoutEnum.T_60S);
};
export const updateDevicePasswd = (user: string, passwd: string) => {
return http.post(`/toolbox/device/update/passwd`, { user: user, passwd: Base64.encode(passwd) }, TimeoutEnum.T_60S);
return http.post(`/toolbox/device/update/passwd`, { user: user, passwd: encodeBase64(passwd) }, TimeoutEnum.T_60S);
};
export const updateDeviceSwap = (params: Toolbox.SwapHelper) => {
return http.post(`/toolbox/device/update/swap`, params, TimeoutEnum.T_10M);
@@ -91,17 +91,13 @@ export const syncFtp = () => {
export const createFtp = (params: Toolbox.FtpCreate) => {
let request = deepCopy(params) as Toolbox.FtpCreate;
if (request.password) {
request.password = Base64.encode(request.password);
}
encodeBase64Fields(request, ['password']);
return http.post(`/toolbox/ftp`, request);
};
export const updateFtp = (params: Toolbox.FtpUpdate) => {
let request = deepCopy(params) as Toolbox.FtpUpdate;
if (request.password) {
request.password = Base64.encode(request.password);
}
encodeBase64Fields(request, ['password']);
return http.post(`/toolbox/ftp/update`, request);
};

View File

@@ -4,7 +4,7 @@ import { Website } from '../interface/website';
import { File } from '../interface/file';
import { TimeoutEnum } from '@/enums/http-enum';
import { deepCopy } from '@/utils/misc';
import { Base64 } from 'js-base64';
import { encodeBase64Fields } from '@/utils/base64';
export const searchWebsites = (req: Website.WebSiteSearch, node?: string) => {
const params = node ? `?operateNode=${node}` : '';
@@ -17,9 +17,7 @@ export const listWebsites = () => {
export const createWebsite = (req: Website.WebSiteCreateReq) => {
let request = deepCopy(req) as Website.WebSiteCreateReq;
if (request.ftpPassword) {
request.ftpPassword = Base64.encode(request.ftpPassword);
}
encodeBase64Fields(request, ['ftpPassword']);
return http.post<any>(`/websites`, request, TimeoutEnum.T_10M);
};
@@ -350,7 +348,7 @@ export const changeDatabase = (req: Website.ChangeDatabase) => {
return http.post(`/websites/databases`, req);
};
export const operateCustomRewrite = (req: Website.CustomRewirte) => {
export const operateCustomRewrite = (req: Website.CustomRewrite) => {
return http.post(`/websites/rewrite/custom`, req);
};

View File

@@ -59,7 +59,7 @@ interface DialogProps {
names: Array<string>;
api: Function;
params: Object;
params: object;
successMsg: string;
noMsg: boolean;
}

View File

@@ -8,7 +8,9 @@
</div>
</template>
<script setup lang="ts" name="404"></script>
<script setup lang="ts">
defineOptions({ name: '404' });
</script>
<style scoped lang="scss">
.not-container {

View File

@@ -1,55 +0,0 @@
<template>
<div class="not-container">
<img src="@/assets/images/unsafe.svg" class="not-img" alt="404" />
<div class="not-detail">
<h2>{{ $t('commons.login.notSafe') }}</h2>
<h4>{{ $t('commons.login.errDomain1') }}</h4>
<div>
<h4>{{ $t('commons.login.errHelper') }} 1pctl reset domain</h4>
<div class="float-left cursor-pointer">
<el-icon color="#409EFC" class="ml-1.5 mt-8" :size="18" @click="copyText('1pctl reset domain')">
<DocumentCopy />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="404">
import { copyText } from '@/utils/clipboard';
</script>
<style scoped lang="scss">
.not-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
.not-img {
margin-top: 300px;
}
.not-detail {
margin-top: 300px;
display: flex;
flex-direction: column;
h2,
h4 {
padding: 0;
margin: 0;
}
h2 {
font-size: 60px;
color: #434e59;
}
h4 {
margin: 30px 0 20px;
float: left;
font-size: 19px;
font-weight: normal;
color: #848587;
}
}
}
</style>

View File

@@ -1,54 +0,0 @@
<template>
<div class="not-container">
<img src="@/assets/images/unsafe.svg" class="not-img" alt="404" />
<div class="not-detail">
<h2>{{ $t('commons.login.notSafe') }}</h2>
<h4>{{ $t('commons.login.errIP1') }}</h4>
<div>
<h4>{{ $t('commons.login.errHelper') }} 1pctl reset ips</h4>
<div class="float-left cursor-pointer">
<el-icon color="#409EFC" class="ml-1.5 mt-8" :size="18" @click="copyText('1pctl reset ips')">
<DocumentCopy />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="404">
import { copyText } from '@/utils/clipboard';
</script>
<style scoped lang="scss">
.not-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
.not-img {
margin-top: 300px;
}
.not-detail {
margin-top: 300px;
display: flex;
flex-direction: column;
h2,
h4 {
padding: 0;
margin: 0;
}
h2 {
font-size: 60px;
color: #434e59;
}
h4 {
margin: 30px 0 20px;
float: left;
font-size: 19px;
font-weight: normal;
color: #848587;
}
}
}
</style>

View File

@@ -1,41 +0,0 @@
<template>
<div>
<div>
<el-row type="flex" justify="center">
<h1>{{ loadErrInfo() }}</h1>
</el-row>
</div>
<hr />
<div>
<el-row type="flex" justify="center"><span>nginx</span></el-row>
</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
code: String,
});
const loadErrInfo = () => {
switch (props.code) {
case '400':
return '400 Bad Request';
case '401':
return '401 Unauthorized';
case '403':
return '403 Forbidden';
case '404':
return '404 Not Found';
case '408':
return '408 Request Timeout';
case '416':
return '416 Requested Not Satisfiable';
}
};
</script>
<style scoped lang="scss">
.container {
margin-left: 40%;
}
</style>

View File

@@ -1,55 +0,0 @@
<template>
<div class="not-container">
<img src="@/assets/images/unsafe.svg" class="not-img" alt="404" />
<div class="not-detail">
<h2>{{ $t('commons.login.notSafe') }}</h2>
<h4>{{ $t('commons.login.safeEntrance1') }}</h4>
<div>
<h4>{{ $t('commons.login.safeEntrance2') }}</h4>
<div class="float-left cursor-pointer">
<el-icon color="#409EFC" class="ml-1.5 mt-8" :size="18" @click="copyText('1pctl user-info')">
<DocumentCopy />
</el-icon>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts" name="404">
import { copyText } from '@/utils/clipboard';
</script>
<style scoped lang="scss">
.not-container {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
.not-img {
margin-top: 300px;
}
.not-detail {
margin-top: 300px;
display: flex;
flex-direction: column;
h2,
h4 {
padding: 0;
margin: 0;
}
h2 {
font-size: 60px;
color: #434e59;
}
h4 {
margin: 30px 0 20px;
float: left;
font-size: 19px;
font-weight: normal;
color: #848587;
}
}
}
</style>

View File

@@ -147,7 +147,7 @@ const getRoleNum = (roleStr: string, role: Role) => {
}
};
const changeMode = (val: String) => {
const changeMode = (val: string) => {
if (val === '' || val.length !== 4) {
return;
}

View File

@@ -89,7 +89,7 @@ const showBack = computed(() => {
});
</script>
<style lang="scss">
<style lang="scss" scoped>
@use '@/styles/mixins.scss' as *;
.content-container__app {
@@ -106,13 +106,16 @@ const showBack = computed(() => {
.content-container__title {
font-weight: 400;
font-size: 18px;
.el-button + .el-button {
:deep(.el-button + .el-button) {
margin: 0 !important;
}
.el-button-group > .el-button + .el-button {
:deep(.el-button-group > .el-button + .el-button) {
margin-left: 0 !important;
}
.el-button-group > .el-button:not(:last-child) {
:deep(.el-button-group > .el-button:not(:last-child)) {
margin-right: -1px !important;
}
}

View File

@@ -78,7 +78,7 @@ onBeforeUnmount(() => {
defineExpose({ acceptParams });
</script>
<style lang="scss">
<style lang="scss" scoped>
.fullScreen {
border: none;
}

View File

@@ -41,10 +41,10 @@
:class="['log-item', { 'task-mode': isTaskMode }]"
:style="{ height: `${logHeight}px` }"
>
<hightlight :log="log" :type="config.colorMode ?? 'nginx'"></hightlight>
<Highlight :log="log" :type="config.colorMode ?? 'nginx'"></Highlight>
</div>
</div>
<hightlight v-if="logs.length === 0" :log="$t('commons.log.noLog')" type="system"></hightlight>
<Highlight v-if="logs.length === 0" :log="$t('commons.log.noLog')" type="system"></Highlight>
</div>
</div>
</template>
@@ -54,7 +54,7 @@ import { downloadFile } from '@/utils/file';
import { readByLine } from '@/api/modules/files';
import { GlobalStore } from '@/store';
import bus from '@/global/bus';
import hightlight from '@/components/log/custom-hightlight/index.vue';
import Highlight from '@/components/log/custom-highlight/index.vue';
const globalStore = GlobalStore();
interface LogProps {

View File

@@ -16,7 +16,6 @@
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
import { listAllNodes } from '@/api/modules/setting';
import { useGlobalStore } from '@/composables/useGlobalStore';
const { globalStore } = useGlobalStore();

View File

@@ -68,10 +68,11 @@ onMounted(() => {
});
</script>
<style lang="scss">
<style lang="scss" scoped>
.router_card {
--el-card-padding: 0;
.el-card__body {
:deep(.el-card__body) {
display: flex;
justify-content: space-between;
align-items: center;
@@ -79,7 +80,7 @@ onMounted(() => {
}
.router_card_button {
.el-radio-button__inner {
:deep(.el-radio-button__inner) {
min-width: 100px;
height: 100%;
background-color: var(--panel-button-active) !important;
@@ -88,7 +89,7 @@ onMounted(() => {
color: var(--el-text-color-regular) !important;
}
.el-radio-button__original-radio:checked + .el-radio-button__inner {
:deep(.el-radio-button__original-radio:checked + .el-radio-button__inner) {
color: var(--panel-button-text-color) !important;
background-color: var(--panel-button-bg-color) !important;
border-color: var(--panel-color-primary) !important;

View File

@@ -21,7 +21,7 @@ import { ref, watch, onBeforeUnmount, nextTick, computed, onMounted } from 'vue'
import { Terminal } from '@xterm/xterm';
import '@xterm/xterm/css/xterm.css';
import { FitAddon } from '@xterm/addon-fit';
import { Base64 } from 'js-base64';
import { decodeBase64, encodeBase64 } from '@/utils/base64';
import { GlobalStore, TerminalStore } from '@/store';
const globalStore = GlobalStore();
@@ -268,7 +268,7 @@ const onWSReceive = (message: MessageEvent) => {
case 'cmd': {
term.value.element && term.value.focus();
if (wsMsg.data) {
let receiveMsg = Base64.decode(wsMsg.data);
let receiveMsg = decodeBase64(wsMsg.data);
if (initCmd.value != '') {
receiveMsg = receiveMsg?.replace(initCmd.value.trim(), '').trim();
initCmd.value = '';
@@ -356,7 +356,7 @@ function sendMsg(data: string, line: string = '') {
terminalSocket.value!.send(
JSON.stringify({
type: 'cmd',
data: Base64.encode(data),
data: encodeBase64(data),
line,
}),
);
@@ -507,7 +507,9 @@ onBeforeUnmount(() => {
.ai-notice-fade-enter-active,
.ai-notice-fade-leave-active {
transition: opacity 180ms ease, transform 180ms ease;
transition:
opacity 180ms ease,
transform 180ms ease;
}
.ai-mask-fade-enter-active,

View File

@@ -10,7 +10,7 @@ export enum ResultEnum {
FORBIDDEN = 403,
NOTFOUND = 404,
ERRAUTH = 406,
ERRGLOBALLOADDING = 407,
ERRGLOBALLOADING = 407,
ERRXPACK = 410,
NodeUnBind = 411,
TIMEOUT = 20000,

View File

@@ -1,14 +1,18 @@
import i18n from '@/lang';
import { FormItemRule } from 'element-plus';
const checkNoSpace = (rule: any, value: any, callback: any) => {
type ValidatorValue = string;
type ValidatorCallback = (error?: Error) => void;
type RuleValidator = (rule: FormItemRule, value: ValidatorValue, callback: ValidatorCallback) => void;
const checkNoSpace: RuleValidator = (_rule, value, callback) => {
if (value.indexOf(' ') !== -1) {
return callback(new Error(i18n.global.t('setting.noSpace')));
}
callback();
};
const checkIp = (rule: any, value: any, callback: any) => {
const checkIp: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.requiredInput')));
} else {
@@ -22,7 +26,7 @@ const checkIp = (rule: any, value: any, callback: any) => {
}
};
const checkIpv4 = (rule: any, value: any, callback: any) => {
const checkIpv4: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
@@ -36,7 +40,7 @@ const checkIpv4 = (rule: any, value: any, callback: any) => {
}
};
const checkIpV6 = (rule: any, value: any, callback: any) => {
const checkIpV6: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.requiredInput')));
} else {
@@ -63,7 +67,7 @@ const checkIpV6 = (rule: any, value: any, callback: any) => {
}
};
const checkIpV4V6OrDomain = (rule: any, value: any, callback: any) => {
const checkIpV4V6OrDomain: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.requiredInput')));
} else {
@@ -92,7 +96,7 @@ const checkIpV4V6OrDomain = (rule: any, value: any, callback: any) => {
}
};
const checkDomainOrIP = (rule: any, value: any, callback: any) => {
const checkDomainOrIP: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
@@ -109,7 +113,7 @@ const checkDomainOrIP = (rule: any, value: any, callback: any) => {
}
};
const checkHost = (rule: any, value: any, callback: any) => {
const checkHost: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.requiredInput')));
} else {
@@ -124,7 +128,7 @@ const checkHost = (rule: any, value: any, callback: any) => {
}
};
const checkIllegal = (rule: any, value: any, callback: any) => {
const checkIllegal: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.requiredInput')));
return;
@@ -147,7 +151,7 @@ const checkIllegal = (rule: any, value: any, callback: any) => {
}
};
const complexityPassword = (rule: any, value: any, callback: any) => {
const complexityPassword: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.complexityPassword')));
} else {
@@ -160,7 +164,7 @@ const complexityPassword = (rule: any, value: any, callback: any) => {
}
};
const checkName = (rule: any, value: any, callback: any) => {
const checkName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.commonName')));
} else {
@@ -173,7 +177,7 @@ const checkName = (rule: any, value: any, callback: any) => {
}
};
const checkUserName = (rule: any, value: any, callback: any) => {
const checkUserName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.userName')));
} else {
@@ -186,7 +190,7 @@ const checkUserName = (rule: any, value: any, callback: any) => {
}
};
const checkSimpleName = (rule: any, value: any, callback: any) => {
const checkSimpleName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.simpleName')));
} else {
@@ -199,7 +203,7 @@ const checkSimpleName = (rule: any, value: any, callback: any) => {
}
};
const checkSimplePassword = (rule: any, value: any, callback: any) => {
const checkSimplePassword: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.simplePassword')));
} else {
@@ -212,7 +216,7 @@ const checkSimplePassword = (rule: any, value: any, callback: any) => {
}
};
const checkAuthBasicPassword = (rule: any, value: any, callback: any) => {
const checkAuthBasicPassword: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.authBasicPassword')));
} else {
@@ -225,7 +229,7 @@ const checkAuthBasicPassword = (rule: any, value: any, callback: any) => {
}
};
const checkDBName = (rule: any, value: any, callback: any) => {
const checkDBName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.dbName')));
} else {
@@ -238,7 +242,7 @@ const checkDBName = (rule: any, value: any, callback: any) => {
}
};
const checkComposeName = (rule: any, value: any, callback: any) => {
const checkComposeName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.composeName')));
} else {
@@ -251,7 +255,7 @@ const checkComposeName = (rule: any, value: any, callback: any) => {
}
};
const checkImageName = (rule: any, value: any, callback: any) => {
const checkImageName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.imageName')));
} else {
@@ -264,7 +268,7 @@ const checkImageName = (rule: any, value: any, callback: any) => {
}
};
const checkVolumeName = (rule: any, value: any, callback: any) => {
const checkVolumeName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.volumeName')));
} else {
@@ -277,7 +281,7 @@ const checkVolumeName = (rule: any, value: any, callback: any) => {
}
};
const checkLinuxName = (rule: any, value: any, callback: any) => {
const checkLinuxName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.linuxName', ['/\\:*?\'"()<>|'])));
} else {
@@ -290,7 +294,7 @@ const checkLinuxName = (rule: any, value: any, callback: any) => {
}
};
const checkSupervisorName = (rule: any, value: any, callback: any) => {
const checkSupervisorName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.supervisorName')));
} else {
@@ -303,7 +307,7 @@ const checkSupervisorName = (rule: any, value: any, callback: any) => {
}
};
const checkDatabaseName = (rule: any, value: any, callback: any) => {
const checkDatabaseName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.databaseName')));
} else {
@@ -316,7 +320,7 @@ const checkDatabaseName = (rule: any, value: any, callback: any) => {
}
};
const checkAppName = (rule: any, value: any, callback: any) => {
const checkAppName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.appName')));
} else {
@@ -329,7 +333,7 @@ const checkAppName = (rule: any, value: any, callback: any) => {
}
};
const checkAlias = (rule: any, value: any, callback: any) => {
const checkAlias: RuleValidator = (_rule, value, callback) => {
if (!value) {
callback(new Error(i18n.global.t('commons.rule.alias')));
return;
@@ -342,7 +346,7 @@ const checkAlias = (rule: any, value: any, callback: any) => {
}
};
const checkDomain = (rule: any, value: any, callback: any) => {
const checkDomain: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.domain')));
} else {
@@ -356,7 +360,7 @@ const checkDomain = (rule: any, value: any, callback: any) => {
}
};
const checkDomainWithPort = (rule: any, value: any, callback: any) => {
const checkDomainWithPort: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.domain')));
} else {
@@ -370,7 +374,7 @@ const checkDomainWithPort = (rule: any, value: any, callback: any) => {
}
};
const checkIntegerNumber = (rule: any, value: any, callback: any) => {
const checkIntegerNumber: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.integer')));
} else {
@@ -383,7 +387,7 @@ const checkIntegerNumber = (rule: any, value: any, callback: any) => {
}
};
const checkIntegerNumberWith0 = (rule: any, value: any, callback: any) => {
const checkIntegerNumberWith0: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.integer')));
} else {
@@ -396,7 +400,7 @@ const checkIntegerNumberWith0 = (rule: any, value: any, callback: any) => {
}
};
const checkFloatNumber = (rule: any, value: any, callback: any) => {
const checkFloatNumber: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.integer')));
} else {
@@ -409,7 +413,7 @@ const checkFloatNumber = (rule: any, value: any, callback: any) => {
}
};
const checkParamCommon = (rule: any, value: any, callback: any) => {
const checkParamCommon: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.paramName')));
} else {
@@ -422,7 +426,7 @@ const checkParamCommon = (rule: any, value: any, callback: any) => {
}
};
const checkParamComplexity = (rule: any, value: any, callback: any) => {
const checkParamComplexity: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.paramComplexity', ['.%@!~_-'])));
} else {
@@ -435,7 +439,7 @@ const checkParamComplexity = (rule: any, value: any, callback: any) => {
}
};
const checkParamUrlAndPort = (rule: any, value: any, callback: any) => {
const checkParamUrlAndPort: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.paramUrlAndPort')));
} else {
@@ -449,7 +453,7 @@ const checkParamUrlAndPort = (rule: any, value: any, callback: any) => {
}
};
const checkPort = (rule: any, value: any, callback: any) => {
const checkPort: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.port')));
} else {
@@ -462,7 +466,7 @@ const checkPort = (rule: any, value: any, callback: any) => {
}
};
const checkDoc = (rule: any, value: any, callback: any) => {
const checkDoc: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.nginxDoc')));
} else {
@@ -487,7 +491,7 @@ export function checkNumberRange(min: number, max: number): FormItemRule {
}
export function checkFloatNumberRange(min: number, max: number): FormItemRule {
let validatorFunc = function (rule: any, value: any, callback: any) {
const validatorFunc: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.disableFunction')));
} else {
@@ -506,7 +510,7 @@ export function checkFloatNumberRange(min: number, max: number): FormItemRule {
};
}
const checkContainerName = (rule: any, value: any, callback: any) => {
const checkContainerName: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
@@ -519,7 +523,7 @@ const checkContainerName = (rule: any, value: any, callback: any) => {
}
};
const checkDisableFunctions = (rule: any, value: any, callback: any) => {
const checkDisableFunctions: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.disableFunction')));
} else {
@@ -532,7 +536,7 @@ const checkDisableFunctions = (rule: any, value: any, callback: any) => {
}
};
const checkLeechExts = (rule: any, value: any, callback: any) => {
const checkLeechExts: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.leechExts')));
} else {
@@ -545,7 +549,7 @@ const checkLeechExts = (rule: any, value: any, callback: any) => {
}
};
const checkParamSimple = (rule: any, value: any, callback: any) => {
const checkParamSimple: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
@@ -558,7 +562,7 @@ const checkParamSimple = (rule: any, value: any, callback: any) => {
}
};
const checkFilePermission = (rule, value, callback) => {
const checkFilePermission: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.filePermission')));
} else {
@@ -571,7 +575,7 @@ const checkFilePermission = (rule, value, callback) => {
}
};
const checkPHPExtensions = (rule, value, callback) => {
const checkPHPExtensions: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.phpExtension')));
} else {
@@ -584,7 +588,7 @@ const checkPHPExtensions = (rule, value, callback) => {
}
};
const checkHttpOrHttps = (rule, value, callback) => {
const checkHttpOrHttps: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback(new Error(i18n.global.t('commons.rule.paramHttp')));
} else {
@@ -597,7 +601,7 @@ const checkHttpOrHttps = (rule, value, callback) => {
}
};
const checkPhone = (rule: any, value: any, callback: any) => {
const checkPhone: RuleValidator = (_rule, value, callback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
@@ -615,7 +619,7 @@ export function checkMaxLength(maxLength: number): FormItemRule {
required: false,
trigger: 'blur',
type: 'string',
validator: (rule: any, value: any, callback: any) => {
validator: (_rule: FormItemRule, value: ValidatorValue, callback: ValidatorCallback) => {
if (value === '' || typeof value === 'undefined' || value == null) {
callback();
} else {
@@ -629,7 +633,7 @@ export function checkMaxLength(maxLength: number): FormItemRule {
};
}
const checkIpv4orV6 = (rule: any, value: any, callback: any) => {
const checkIpv4orV6: RuleValidator = (_rule, value, callback) => {
if (value === '' || value == null) {
return callback();
}

View File

@@ -203,12 +203,6 @@ const message = {
errorMfaInfo: 'Invalid authentication info, try again.',
captchaHelper: 'Captcha',
errorCaptcha: 'Invalid captcha code',
notSafe: 'Access Denied',
safeEntrance1: 'Secure entry is enabled in this environment',
safeEntrance2: 'Run this command over SSH to view the panel entry: 1pctl user-info',
errIP1: 'IP allowlist is enabled in this environment',
errDomain1: 'Domain binding is enabled in this environment',
errHelper: 'To reset binding info, run this command over SSH: ',
codeInput: 'Enter the 6-digit MFA code',
mfaTitle: 'MFA Verification',
mfaCode: 'MFA verification code',

View File

@@ -205,14 +205,6 @@ const message = {
errorMfaInfo: 'Información de autenticación inválida, inténtalo nuevamente.',
captchaHelper: 'Captcha',
errorCaptcha: 'Código captcha inválido',
notSafe: 'Acceso denegado',
safeEntrance1: 'El inicio de sesión seguro está habilitado en el entorno actual',
safeEntrance2:
'Ingrese el siguiente comando en la terminal SSH para ver la entrada al panel: 1pctl user-info',
errIP1: 'El acceso mediante dirección IP autorizada está habilitado en el entorno actual',
errDomain1: 'La vinculación del nombre de dominio de acceso está habilitada en el entorno actual',
errHelper:
'Para restablecer la información de vinculación, ejecute el siguiente comando en la terminal SSH: ',
codeInput: 'Por favor, ingrese el código de verificación de 6 dígitos del validador MFA',
mfaTitle: 'Autenticación MFA',
mfaCode: 'Código de verificación MFA',

View File

@@ -204,12 +204,6 @@ const message = {
errorMfaInfo: '認証情報が誤っていないもう一度やり直してください',
captchaHelper: 'キャプチャ',
errorCaptcha: 'Captchaコードエラー',
notSafe: 'アクセスが拒否されました',
safeEntrance1: '安全なログインは現在の環境で有効になっています',
safeEntrance2: 'SSH端末に次のコマンドを入力してパネルエントリを表示します:1PCTLユーザー-INFO',
errIP1: '現在の環境で認定されたIPアドレスアクセスが有効になっています',
errDomain1: 'アクセスドメイン名のバインディングが現在の環境で有効になっています',
errHelper: 'バインディング情報をリセットするにはSSH端末で次のコマンドを実行します',
codeInput: 'MFAバリデーターの6桁の検証コードを入力してください',
mfaTitle: 'MFA認定',
mfaCode: 'MFA検証コード',

View File

@@ -202,12 +202,6 @@ const message = {
errorMfaInfo: '인증 정보가 잘못되었습니다. 다시 시도해주세요!',
captchaHelper: '캡챠',
errorCaptcha: '캡챠 코드 오류!',
notSafe: '접근이 거부되었습니다',
safeEntrance1: '현재 환경에서 보안 로그인이 활성화되었습니다',
safeEntrance2: 'SSH 터미널에서 다음 명령어를 입력하여 패널 진입 경로를 확인하세요: 1pctl user-info',
errIP1: '현재 환경에서 승인된 IP 주소 접근이 활성화되었습니다',
errDomain1: '현재 환경에서 도메인 이름 바인딩이 활성화되었습니다',
errHelper: '바인딩 정보를 재설정하려면 SSH 터미널에서 다음 명령어를 실행하세요:',
codeInput: 'MFA 인증기의 6자리 인증 코드를 입력하세요',
mfaTitle: 'MFA 인증',
mfaCode: 'MFA 인증 코드',

View File

@@ -205,12 +205,6 @@ const message = {
errorMfaInfo: 'Maklumat pengesahan tidak betul, sila cuba lagi!',
captchaHelper: 'Captcha',
errorCaptcha: 'Ralat kod captcha!',
notSafe: 'Akses Ditolak',
safeEntrance1: 'Log masuk selamat telah diaktifkan dalam persekitaran semasa',
safeEntrance2: 'Masukkan arahan berikut pada terminal SSH untuk melihat pintu masuk panel: 1pctl user-info',
errIP1: 'Akses alamat IP yang dibenarkan diaktifkan dalam persekitaran semasa',
errDomain1: 'Pengikatan nama domain akses diaktifkan dalam persekitaran semasa',
errHelper: 'Untuk menetapkan semula maklumat pengikatan, jalankan arahan berikut pada terminal SSH: ',
codeInput: 'Sila masukkan kod pengesahan 6 digit dari pengesah MFA',
mfaTitle: 'Pengesahan MFA',
mfaCode: 'Kod pengesahan MFA',

View File

@@ -203,13 +203,6 @@ const message = {
errorMfaInfo: 'Informações de autenticação incorretas, tente novamente!',
captchaHelper: 'Captcha',
errorCaptcha: 'Erro no código Captcha!',
notSafe: 'Acesso Negado',
safeEntrance1: 'O login seguro foi habilitado no ambiente atual',
safeEntrance2:
'Digite o seguinte comando no terminal SSH para visualizar a entrada do painel: 1pctl user-info',
errIP1: 'O acesso por endereço IP autorizado está habilitado no ambiente atual',
errDomain1: 'O acesso por nome de domínio vinculado está habilitado no ambiente atual',
errHelper: 'Para redefinir as informações de vinculação, execute o seguinte comando no terminal SSH:',
codeInput: 'Por favor, insira o código de verificação de 6 dígitos do validador MFA',
mfaTitle: 'Autenticação MFA',
mfaCode: 'Código de verificação MFA',

View File

@@ -203,12 +203,6 @@ const message = {
errorMfaInfo: 'Неверная информация аутентификации, попробуйте еще раз!',
captchaHelper: 'Капча',
errorCaptcha: 'Ошибка кода капчи!',
notSafe: 'Доступ запрещен',
safeEntrance1: 'В текущей среде включен безопасный вход',
safeEntrance2: 'Введите следующую команду в SSH-терминале для просмотра входа в панель: 1pctl user-info',
errIP1: 'В текущей среде включен доступ по авторизованному IP-адресу',
errDomain1: 'В текущей среде включена привязка домена доступа',
errHelper: 'Для сброса информации о привязке выполните следующую команду в SSH-терминале: ',
codeInput: 'Пожалуйста, введите 6-значный код подтверждения MFA',
mfaTitle: 'MFA Сертификация',
mfaCode: 'MFA код подтверждения',

View File

@@ -207,12 +207,6 @@ const message = {
errorMfaInfo: 'Yanlış kimlik doğrulama bilgisi, lütfen tekrar deneyin!',
captchaHelper: 'Güvenlik kodu',
errorCaptcha: 'Güvenlik kodu hatası!',
notSafe: 'Erişim Reddedildi',
safeEntrance1: 'Mevcut ortamda güvenli giriş etkinleştirildi',
safeEntrance2: 'Panel girişini görüntülemek için SSH terminalinde şu komutu girin: 1pctl user-info',
errIP1: 'Mevcut ortamda yetkili IP adresi erişimi etkinleştirildi',
errDomain1: 'Mevcut ortamda erişim alan adı bağlama etkinleştirildi',
errHelper: 'Bağlama bilgilerini sıfırlamak için SSH terminalinde şu komutu çalıştırın: ',
codeInput: 'MFA doğrulayıcının 6 haneli doğrulama kodunu girin',
mfaTitle: 'MFA Sertifikasyonu',
mfaCode: 'MFA doğrulama kodu',

View File

@@ -200,12 +200,6 @@ const message = {
errorMfaInfo: '錯誤的驗證資訊請重試',
captchaHelper: '驗證碼',
errorCaptcha: '驗證碼錯誤',
notSafe: '暫無權限存取',
safeEntrance1: '當前環境已啟用安全入口',
safeEntrance2: ' SSH 終端輸入以下指令來檢視面板入口: 1pctl user-info',
errIP1: '當前環境已啟用授權 IP',
errDomain1: '當前環境已啟用網域綁定',
errHelper: '可在 SSH 終端輸入以下指令來重設綁定資訊: ',
codeInput: '請輸入 MFA 驗證器的 6 位驗證碼',
mfaTitle: 'MFA 認證',
mfaCode: 'MFA 驗證碼',

View File

@@ -189,12 +189,6 @@ const message = {
errorMfaInfo: '错误的验证信息请重试',
captchaHelper: '验证码',
errorCaptcha: '验证码错误',
notSafe: '暂无权限访问',
safeEntrance1: '当前环境已经开启了安全入口登录',
safeEntrance2: ' SSH 终端输入以下命令来查看面板入口: 1pctl user-info',
errIP1: '当前环境已经开启了授权 IP 访问',
errDomain1: '当前环境已经开启了访问域名绑定',
errHelper: '可在 SSH 终端输入以下命令来重置绑定信息: ',
mfaTitle: 'MFA 认证',
mfaCode: 'MFA 验证码',
passkey: '使用通行密钥',

View File

@@ -1,6 +1,8 @@
<template>
<div>
<el-popover
ref="nodeChangeRef"
v-model:visible="popoverVisible"
placement="right-end"
:show-arrow="false"
:offset="0"
@@ -87,7 +89,7 @@
<script setup lang="ts">
import { GlobalStore, MenuStore } from '@/store';
import { DropdownInstance } from 'element-plus';
import type { PopoverInstance } from 'element-plus';
import { countExecutingTask } from '@/api/modules/log';
import { MsgError, MsgSuccess } from '@/utils/message';
import i18n from '@/lang';
@@ -106,7 +108,8 @@ const menuStore = MenuStore();
const nodes = ref([]);
const nodeOptions = ref([]);
const loading = ref();
const nodeChangeRef = ref<DropdownInstance>();
const popoverVisible = ref(false);
const nodeChangeRef = ref<PopoverInstance>();
const props = defineProps({
version: String,
});
@@ -126,7 +129,7 @@ bus.on('refreshTask', () => {
});
const openChangeNode = () => {
nodeChangeRef.value?.handleOpen();
popoverVisible.value = true;
};
const loadCurrentName = () => {
@@ -261,7 +264,7 @@ const logout = () => {
.then(async () => {
await logOutApi();
router.push({ name: 'entrance', params: { code: globalStore.entrance } });
globalStore.setLogStatus(false);
globalStore.isLogin = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {});

View File

@@ -3,7 +3,7 @@
<el-sub-menu v-if="subItem?.children?.length > 1" :index="subItem.path" popper-class="sidebar-container-popper">
<template #title>
<el-icon>
<SvgIcon :iconName="(subItem.meta?.icon as string)" />
<SvgIcon :iconName="subItem.meta?.icon as string" />
</el-icon>
<span>{{ $t(subItem.meta?.title as string, 2) }}</span>
</template>
@@ -12,7 +12,7 @@
<el-menu-item v-else-if="subItem?.children?.length === 1" :index="subItem.children[0].path">
<el-icon>
<SvgIcon :iconName="(subItem.meta?.icon as string)" />
<SvgIcon :iconName="subItem.meta?.icon as string" />
</el-icon>
<template #title>
<span>{{ $t(subItem.meta?.title as string, 2) }}</span>
@@ -21,7 +21,7 @@
<el-menu-item v-else-if="subItem.path === '/xpack/upage'" :index="''" @click="goUpage">
<el-icon v-if="subItem.meta?.icon && level === 0">
<SvgIcon :iconName="(subItem.meta?.icon as string)" />
<SvgIcon :iconName="subItem.meta?.icon as string" />
</el-icon>
<template #title>
<span v-if="subItem.meta?.icon && level === 0">{{ $t(subItem.meta?.title as string, 2) }}</span>
@@ -31,7 +31,7 @@
<el-menu-item v-else :index="subItem.path">
<el-icon v-if="subItem.meta?.icon && level === 0">
<SvgIcon :iconName="(subItem.meta?.icon as string)" />
<SvgIcon :iconName="subItem.meta?.icon as string" />
</el-icon>
<template #title>
<span v-if="subItem.meta?.icon && level === 0">{{ $t(subItem.meta?.title as string, 2) }}</span>

View File

@@ -1,59 +1,20 @@
@use '@/styles/var.scss' as *;
.el-menu {
user-select: none;
background: none;
width: 100%;
padding: 0 7px;
.el-menu-item {
border-radius: 4px;
background-color: var(--el-menu-item-bg-color);
margin: 7px 0;
height: 42px;
box-shadow: 0px 0px 4px rgba(0, 94, 235, 0.1);
box-sizing: border-box;
&:hover {
.el-icon {
color: var(--el-color-primary);
}
.sidebar-container {
:deep(.el-menu) {
user-select: none;
background: none;
width: 100%;
padding: 0 7px;
span {
color: var(--el-color-primary);
}
}
&.is-active {
background-color: var(--el-menu-item-bg-color-active);
box-shadow: 0px 0px 4px rgba(0, 94, 235, 0.1), inset 0 0 0 2px var(--el-color-primary);
&::before {
position: absolute;
border-radius: 4px;
left: 12px;
width: 4px;
height: 14px;
content: '';
background: var(--el-color-primary);
}
}
}
.el-sub-menu {
&.is-active {
.el-sub-menu__title {
span {
color: var(--el-color-primary);
}
.el-icon {
color: var(--el-color-primary);
}
}
}
.el-sub-menu__title {
background-color: var(--el-menu-item-bg-color);
box-shadow: 0 0 4px rgba(0, 94, 235, 0.1);
margin-top: 7px;
height: 42px;
.el-menu-item {
border-radius: 4px;
background-color: var(--el-menu-item-bg-color);
margin: 7px 0;
height: 42px;
box-shadow: 0px 0px 4px rgba(0, 94, 235, 0.1);
box-sizing: border-box;
&:hover {
.el-icon {
color: var(--el-color-primary);
@@ -63,25 +24,74 @@
color: var(--el-color-primary);
}
}
&.is-active {
background-color: var(--el-menu-item-bg-color-active);
box-shadow: 0px 0px 4px rgba(0, 94, 235, 0.1), inset 0 0 0 2px var(--el-color-primary);
&::before {
position: absolute;
border-radius: 4px;
left: 12px;
width: 4px;
height: 14px;
content: '';
background: var(--el-color-primary);
}
}
}
.el-menu {
padding: 0;
.el-menu-item {
box-shadow: none;
padding-left: 35px;
.el-sub-menu {
&.is-active {
.el-sub-menu__title {
span {
color: var(--el-color-primary);
}
.el-icon {
color: var(--el-color-primary);
}
}
}
.el-sub-menu__title {
background-color: var(--el-menu-item-bg-color);
box-shadow: 0 0 4px rgba(0, 94, 235, 0.1);
margin-top: 7px;
height: 42px;
border-radius: 4px;
&:hover {
.el-icon {
color: var(--el-color-primary);
}
span {
color: var(--el-color-primary);
}
}
}
.el-menu {
padding: 0;
.el-menu-item {
box-shadow: none;
padding-left: 35px;
}
}
}
}
}
.sidebar-container-popper {
:deep(.sidebar-container-popper) {
.el-menu {
background-color: var(--el-menu-bg-color);
padding: 4px 8px;
}
}
.el-sub-menu__title {
:deep(.el-sub-menu__title) {
padding-right: 0;
}

View File

@@ -36,7 +36,6 @@ import Collapse from './components/Collapse.vue';
import SubItem from './components/SubItem.vue';
import { menuList } from '@/routers/router';
import { GlobalStore, MenuStore } from '@/store';
import { isString } from '@vueuse/core';
import { getSettingInfo } from '@/api/modules/setting';
import PrimaryMenu from '@/assets/images/menu-bg.svg?component';
@@ -47,7 +46,7 @@ const version = ref();
const activeMenu = computed(() => {
const { meta, path } = route;
return isString(meta.activeMenu) ? meta.activeMenu : path;
return typeof meta.activeMenu === 'string' ? meta.activeMenu : path;
});
const isCollapse = computed((): boolean => menuStore.isCollapse);
@@ -181,14 +180,14 @@ onMounted(() => {
});
</script>
<style lang="scss">
<style lang="scss" scoped>
@use 'index';
.background {
z-index: 20;
}
.custom-menu .el-menu-item {
.custom-menu :deep(.el-menu-item) {
white-space: normal !important;
word-break: break-word;
overflow-wrap: break-word;

View File

@@ -106,7 +106,12 @@ const handleCollapse = () => {
};
const loadContent = () => {
let itemName = globalStore.watermark.content.replaceAll(
const watermark = globalStore.watermark;
if (!watermark) {
return '';
}
let itemName = watermark.content.replaceAll(
'${nodeName}',
globalStore.currentNode === 'local' ? globalStore.getMasterAlias() : globalStore.currentNode,
);

View File

@@ -1,6 +1,6 @@
import { Layout } from '@/routers/constant';
const databaseRouter = {
const aiRouter = {
sort: 4,
path: '/ai',
name: 'AI-Menu',
@@ -76,4 +76,4 @@ const databaseRouter = {
],
};
export default databaseRouter;
export default aiRouter;

View File

@@ -109,7 +109,7 @@ const settingRouter = {
component: () => import('@/views/setting/expired.vue'),
meta: {
requiresAuth: true,
activeMenu: 'Expired',
activeMenu: '/settings',
ignoreTab: true,
},
},

View File

@@ -12,7 +12,6 @@ const homeRouter: RouteRecordRaw = {
component: Layout,
redirect: '/',
meta: {
keepAlive: true,
title: 'menu.home',
icon: 'p-home',
},
@@ -23,6 +22,7 @@ const homeRouter: RouteRecordRaw = {
component: () => import('@/views/home/index.vue'),
meta: {
requiresAuth: true,
keepAlive: true,
},
},
],

View File

@@ -36,7 +36,7 @@ export interface GlobalState {
themeConfig: ThemeConfigProp;
isFullScreen: boolean;
openMenuTabs: boolean;
watermark: Watermark;
watermark: Watermark | null;
watermarkShow: boolean;
isOnRestart: boolean;
agreeLicense: boolean;

View File

@@ -1,6 +1,6 @@
import { defineStore } from 'pinia';
import piniaPersistConfig from '@/config/pinia-persist';
import { GlobalState, ThemeConfigProp } from '../interface';
import { GlobalState } from '../interface';
import { DeviceType } from '@/enums/app';
import i18n, { setActiveLocale } from '@/lang';
@@ -76,35 +76,14 @@ const GlobalStore = defineStore({
isMaster: (state) => state.currentNode === 'local',
},
actions: {
setOpenMenuTabs(openMenuTabs: boolean) {
this.openMenuTabs = openMenuTabs;
},
setScreenFull() {
this.isFullScreen = !this.isFullScreen;
},
setLogStatus(login: boolean) {
this.isLogin = login;
},
setGlobalLoading(loading: boolean) {
this.isLoading = loading;
},
setLoadingText(text: string) {
this.loadingText = text;
},
setCsrfToken(token: string) {
this.csrfToken = token;
},
async updateLanguage(language: string) {
const activeLocale = await setActiveLocale(language);
this.language = activeLocale;
return activeLocale;
},
setThemeConfig(themeConfig: ThemeConfigProp) {
this.themeConfig = themeConfig;
},
setAgreeLicense(agree: boolean) {
this.agreeLicense = agree;
},
toggleDevice(value: DeviceType) {
this.device = value;
},
@@ -117,27 +96,6 @@ const GlobalStore = defineStore({
isMasterPro() {
return this.isMasterProductPro;
},
setLastFilePath(path: string) {
this.lastFilePath = path;
},
setCurrentDB(name: string) {
this.currentDB = name;
},
setCurrentPgDB(name: string) {
this.currentPgDB = name;
},
setCurrentRedisDB(name: string) {
this.currentRedisDB = name;
},
setShowEntranceWarn(show: boolean) {
this.showEntranceWarn = show;
},
setDefaultNetwork(net: string) {
this.defaultNetwork = net;
},
setDefaultIO(net: string) {
this.defaultIO = net;
},
},
persist: piniaPersistConfig('GlobalState'),
});

View File

@@ -16,38 +16,6 @@ export const TerminalStore = defineStore({
scrollback: 1000,
scrollSensitivity: 6,
}),
actions: {
setLineHeight(lineHeight: number) {
this.lineHeight = lineHeight;
},
setLetterSpacing(letterSpacing: number) {
this.letterSpacing = letterSpacing;
},
setFontSize(fontSize: number) {
this.fontSize = fontSize;
},
setFontFamily(fontFamily: string) {
this.fontFamily = fontFamily;
},
setBackgroundColor(backgroundColor: string) {
this.backgroundColor = backgroundColor;
},
setForegroundColor(foregroundColor: string) {
this.foregroundColor = foregroundColor;
},
setCursorBlink(cursorBlink: string) {
this.cursorBlink = cursorBlink;
},
setCursorStyle(cursorStyle: string) {
this.cursorStyle = cursorStyle;
},
setScrollback(scrollback: number) {
this.scrollback = scrollback;
},
setScrollSensitivity(scrollSensitivity: number) {
this.scrollSensitivity = scrollSensitivity;
},
},
persist: piniaPersistConfig('TerminalState'),
});

View File

@@ -1,7 +1,7 @@
@use './element.scss';
@use './element-dark.scss';
@use './fu.scss';
@use './moblie.scss';
@use './mobile.scss';
@use './reset.scss';
@use './var.scss';
@use 'md-editor-v3/lib/style.css';

View File

@@ -0,0 +1,18 @@
import { Base64 } from 'js-base64';
type StringLikeRecord = Record<string, unknown>;
export const encodeBase64 = (value: string) => Base64.encode(value);
export const decodeBase64 = (value: string) => Base64.decode(value);
export const encodeBase64Fields = <T extends StringLikeRecord>(target: T, fields: Array<keyof T>) => {
fields.forEach((field) => {
const value = target[field];
if (typeof value === 'string' && value) {
target[field] = encodeBase64(value) as T[keyof T];
}
});
return target;
};

View File

@@ -1,28 +0,0 @@
import { isJson } from './misc';
export function formatImageStdout(stdout: string) {
let lines = stdout.split('\r\n');
for (let i = 0; i < lines.length; i++) {
if (isJson(lines[i])) {
const data = JSON.parse(lines[i]);
if (data.errorDetail || data.error) {
lines[i] = data.errorDetail || data.errorDetail;
lines[i] = data.error || data.error;
continue;
}
if (data.stream) {
lines[i] = data.stream;
continue;
}
if (data.id) {
lines[i] = data.id + ': ' + data.status;
} else {
lines[i] = data.status;
}
if (data.progress) {
lines[i] = lines[i] + data.progress;
}
}
}
return lines.join('\r\n');
}

View File

@@ -1,23 +1,3 @@
import fs from 'fs';
import path from 'path';
import dotenv from 'dotenv';
export function isDevFn(mode: string): boolean {
return mode === 'development';
}
export function isProdFn(mode: string): boolean {
return mode === 'production';
}
/**
* Whether to generate package preview
*/
export function isReportMode(): boolean {
return process.env.VITE_REPORT === 'true';
}
// Read all environment variable configuration files to process.env
export function wrapperEnv(envConf: Recordable): ViteEnv {
const ret: any = {};
@@ -38,36 +18,3 @@ export function wrapperEnv(envConf: Recordable): ViteEnv {
}
return ret;
}
/**
* Get the environment variables starting with the specified prefix
* @param match prefix
* @param confFiles ext
*/
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.production']) {
let envConfig = {};
confFiles.forEach((item) => {
try {
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)));
envConfig = { ...envConfig, ...env };
} catch (error) {
console.error(`Error in parsing ${item}`, error);
}
});
Object.keys(envConfig).forEach((key) => {
const reg = new RegExp(`^(${match})`);
if (!reg.test(key)) {
Reflect.deleteProperty(envConfig, key);
}
});
return envConfig;
}
/**
* Get user root directory
* @param dir file path
*/
export function getRootPath(...dir: string[]) {
return path.resolve(process.cwd(), ...dir);
}

View File

@@ -39,7 +39,7 @@ export function isJson(str: string) {
}
}
function compareById(a: any, b: any) {
function compareBySort(a: any, b: any) {
return a.sort - b.sort;
}
@@ -49,10 +49,10 @@ export function sortMenu(arr: any[]) {
}
arr.forEach((item) => {
if (item.children && Array.isArray(item.children)) {
item.children.sort(compareById);
item.children.sort(compareBySort);
}
});
arr.sort(compareById);
arr.sort(compareBySort);
}
export function isPunycoded(domain: string): boolean {

View File

@@ -5,6 +5,7 @@ import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
let initialized = false;
let languageSupportPromise: Promise<void> | null = null;
export function setupMonacoEnvironment() {
if (initialized) {
@@ -30,3 +31,17 @@ export function setupMonacoEnvironment() {
},
};
}
export async function loadMonacoLanguageSupport() {
if (!languageSupportPromise) {
languageSupportPromise = Promise.all([
import('monaco-editor/esm/vs/basic-languages/monaco.contribution'),
import('monaco-editor/esm/vs/language/json/monaco.contribution'),
import('monaco-editor/esm/vs/language/css/monaco.contribution'),
import('monaco-editor/esm/vs/language/html/monaco.contribution'),
import('monaco-editor/esm/vs/language/typescript/monaco.contribution'),
]).then(() => undefined);
}
await languageSupportPromise;
}

View File

@@ -68,8 +68,8 @@ export function computeSizeFromByte(size: number): string {
if (size < num) return size + ' B';
if (size < Math.pow(num, 2)) return (size / num).toFixed(2) + ' KB';
if (size < Math.pow(num, 3)) return (size / Math.pow(num, 2)).toFixed(2) + ' MB';
if (size < Math.pow(num, 4)) return (size / Math.pow(num, 2)).toFixed(2) + ' GB';
return (size / Math.pow(num, 5)).toFixed(2) + ' TB';
if (size < Math.pow(num, 4)) return (size / Math.pow(num, 3)).toFixed(2) + ' GB';
return (size / Math.pow(num, 4)).toFixed(2) + ' TB';
}
export function computeSizeFromKBs(size: number): string {

View File

@@ -69,7 +69,7 @@ const loadDataFromDB = async () => {
const res = await getSettingInfo();
document.title = res.data.panelName;
globalStore.entrance = res.data.securityEntrance;
globalStore.setOpenMenuTabs(res.data.menuTabs === 'Enable');
globalStore.openMenuTabs = res.data.menuTabs === 'Enable';
};
export async function loadProductProFromDB() {

View File

@@ -255,10 +255,13 @@ const loadProviders = async () => {
value: item.provider,
label: getAgentProviderDisplayName(item.provider, item.displayName),
}));
providerModels.value = filteredData.reduce((acc, item) => {
acc[item.provider] = item.models || [];
return acc;
}, {} as Record<string, AI.ProviderModelInfo[]>);
providerModels.value = filteredData.reduce(
(acc, item) => {
acc[item.provider] = item.models || [];
return acc;
},
{} as Record<string, AI.ProviderModelInfo[]>,
);
if (!providerOptions.value.find((item) => item.value === form.provider) && providerOptions.value.length > 0) {
form.provider = providerOptions.value[0].value;
}

View File

@@ -318,10 +318,13 @@ const loadProviders = async () => {
value: item.provider,
label: getAgentProviderDisplayName(item.provider, item.displayName),
}));
providerBaseURL.value = filteredData.reduce((acc, item) => {
acc[item.provider] = item.baseUrl || '';
return acc;
}, {} as Record<string, string>);
providerBaseURL.value = filteredData.reduce(
(acc, item) => {
acc[item.provider] = item.baseUrl || '';
return acc;
},
{} as Record<string, string>,
);
if (!form.provider && providerOptions.value.length > 0) {
form.provider = providerOptions.value[0].value;
handleProviderChange();

View File

@@ -31,7 +31,7 @@
</template>
<script setup lang="ts">
import { defineProps, reactive } from 'vue';
import { reactive } from 'vue';
import { FormRules } from 'element-plus';
import { Rules } from '@/global/form-rules';
import { AI } from '@/api/interface/ai';

View File

@@ -79,6 +79,14 @@ const handleChange = async (target: LocalTab) => {
</script>
<style lang="scss" scoped>
.content-container__search {
margin-top: 7px;
:deep(.el-card) {
--el-card-padding: 12px;
}
}
.local-model-content {
:deep(.content-container__app) {
margin-top: 7px;

View File

@@ -144,7 +144,7 @@
</div>
</template>
<script lang="ts" setup name="AppInstallForm">
<script lang="ts" setup>
import { App } from '@/api/interface/app';
import { getAppByKey, getAppDetail, getAppInstalledByID } from '@/api/modules/app';
import { getAppStoreConfig } from '@/api/modules/setting';
@@ -158,6 +158,7 @@ import { computeSizeFromMB } from '@/utils/size';
import { loadResourceLimit } from '@/api/modules/container';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { loadOptionalComponent } from '@/extensions/optional';
defineOptions({ name: 'AppInstallForm' });
const { isOffLine, isMasterProductPro, isMaster } = useGlobalStore();
const PushtoNode = defineAsyncComponent(() => loadOptionalComponent('/src/xpack/views/ssl/index.vue'));

View File

@@ -20,7 +20,7 @@
<TaskLog ref="taskLogRef" />
</template>
<script lang="ts" setup name="AppInstallPage">
<script lang="ts" setup>
import { useRouter } from 'vue-router';
import AppInstallForm from '@/views/app-store/detail/form/index.vue';
import { installApp } from '@/api/modules/app';
@@ -30,6 +30,7 @@ import { routerToName } from '@/utils/router';
import TaskLog from '@/components/log/task/index.vue';
import i18n from '@/lang';
import { installAppToNodes } from '@/api/modules/app';
defineOptions({ name: 'AppInstallPage' });
const router = useRouter();
const open = ref(false);

View File

@@ -198,7 +198,7 @@ const updateParam = () => {
emit('update:form', form);
};
const isMysql = (form: Object, envKey: string) => {
const isMysql = (form: object, envKey: string) => {
return form['PANEL_DB_HOST'] != undefined && (form[envKey] == 'mysql' || form[envKey] == 'mariadb');
};

View File

@@ -57,7 +57,7 @@ import ErrPrompt from '@/components/error-prompt/index.vue';
interface CheckRrops {
items: App.AppInstallResource[];
installID: Number;
installID: number;
key: string;
}
const installData = ref<CheckRrops>({
@@ -121,7 +121,7 @@ const onConfirm = () => {
installedOp(deleteReq).then(() => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
open.value = false;
em('close', open);
em('close', open.value);
});
});
};

View File

@@ -83,7 +83,7 @@ const em = defineEmits(['close']);
const handleClose = () => {
open.value = false;
em('close', open);
em('close', open.value);
};
const handleFormSubmit = () => {

View File

@@ -194,7 +194,7 @@ import { loadResourceLimit } from '@/api/modules/container';
import { Container } from '@/api/interface/container';
interface ParamProps {
id: Number;
id: number;
app: any;
}
const paramData = ref<ParamProps>({
@@ -470,11 +470,11 @@ const changeUnit = () => {
defineExpose({ acceptParams });
</script>
<style lang="scss">
<style lang="scss" scoped>
.change-button {
margin-top: 5px;
}
.system-label {
:deep(.system-label) {
width: 40% !important;
white-space: nowrap !important;
}

View File

@@ -39,7 +39,7 @@ const em = defineEmits(['close']);
const handleClose = () => {
open.value = false;
em('close', open);
em('close', open.value);
};
const acceptParams = () => {

View File

@@ -20,34 +20,56 @@
<script setup lang="ts">
import { nextTick, ref } from 'vue';
import { setupMonacoEnvironment } from '@/utils/monaco';
import * as monaco from 'monaco-editor';
import { loadMonacoLanguageSupport, setupMonacoEnvironment } from '@/utils/monaco';
setupMonacoEnvironment();
type MonacoEditorApi = typeof import('monaco-editor/esm/vs/editor/editor.api');
const open = ref(false);
const newContent = ref('');
const oldContent = ref('');
const em = defineEmits(['confirm']);
let originalModel = null;
let modifiedModel = null;
let editor: monaco.editor.IStandaloneDiffEditor = null;
let monaco: MonacoEditorApi | null = null;
let originalModel: MonacoEditorApi['editor']['ITextModel'] | null = null;
let modifiedModel: MonacoEditorApi['editor']['ITextModel'] | null = null;
let editor: MonacoEditorApi['editor']['IStandaloneDiffEditor'] | null = null;
const container = ref();
const ensureMonaco = async () => {
if (monaco) {
return monaco;
}
setupMonacoEnvironment();
const [monacoModule] = await Promise.all([
import('monaco-editor/esm/vs/editor/editor.api'),
loadMonacoLanguageSupport(),
]);
monaco = monacoModule;
return monaco;
};
const disposeModels = () => {
originalModel?.dispose();
modifiedModel?.dispose();
originalModel = null;
modifiedModel = null;
};
const handleClose = () => {
open.value = false;
if (editor) {
editor.dispose();
editor = null;
}
disposeModels();
};
const acceptParams = (oldCompose: string, newCompose: string) => {
const acceptParams = async (oldCompose: string, newCompose: string) => {
oldContent.value = oldCompose;
newContent.value = newCompose;
open.value = true;
initEditor();
await initEditor();
};
const confirm = (useEditor: boolean) => {
@@ -61,24 +83,35 @@ const confirm = (useEditor: boolean) => {
handleClose();
};
const initEditor = () => {
nextTick(() => {
originalModel = monaco.editor.createModel(oldContent.value, 'yaml');
modifiedModel = monaco.editor.createModel(newContent.value, 'yaml');
const initEditor = async () => {
const monacoApi = await ensureMonaco();
await nextTick();
editor = monaco.editor.createDiffEditor(container.value, {
theme: 'vs-dark',
readOnly: false,
automaticLayout: true,
folding: true,
roundedSelection: false,
overviewRulerBorder: false,
});
if (!container.value) {
return;
}
editor.setModel({
original: originalModel,
modified: modifiedModel,
});
if (editor) {
editor.dispose();
editor = null;
}
disposeModels();
originalModel = monacoApi.editor.createModel(oldContent.value, 'yaml');
modifiedModel = monacoApi.editor.createModel(newContent.value, 'yaml');
editor = monacoApi.editor.createDiffEditor(container.value, {
theme: 'vs-dark',
readOnly: false,
automaticLayout: true,
folding: true,
roundedSelection: false,
overviewRulerBorder: false,
});
editor.setModel({
original: originalModel,
modified: modifiedModel,
});
};

View File

@@ -135,7 +135,7 @@ const newContent = ref('');
const em = defineEmits(['close']);
const handleClose = () => {
open.value = false;
em('close', open);
em('close', open.value);
};
const newCompose = ref('');

View File

@@ -951,7 +951,9 @@ const onOpenLog = (row: any) => {
opacity: 0;
max-height: 0;
overflow: hidden;
transition: opacity 0.2s, max-height 0.2s;
transition:
opacity 0.2s,
max-height 0.2s;
}
.compose-item:hover .compose-actions,

View File

@@ -345,7 +345,7 @@ import { ElForm } from 'element-plus';
import Confirm from '@/views/container/container/operate/confirm.vue';
import Volume from '@/views/container/container/operate/volume.vue';
import Network from '@/views/container/container/operate/network.vue';
import ExtraHosts from '@/views/website/runtime/components/extra_hosts/index.vue';
import ExtraHosts from '@/views/website/runtime/components/extra-hosts/index.vue';
import {
listImage,
createContainer,

View File

@@ -376,7 +376,7 @@ const mysqlName = (appType: string) => {
const goRemoteDB = async () => {
if (currentDB.value) {
globalStore.setCurrentDB(currentDB.value.database);
globalStore.currentDB = currentDB.value.database;
}
routerToName('MySQL-Remote');
};
@@ -389,7 +389,7 @@ const passwordRef = ref();
const onSetting = async () => {
if (currentDB.value) {
globalStore.setCurrentDB(currentDB.value.database);
globalStore.currentDB = currentDB.value.database;
}
routerToNameWithParams('MySQL-Setting', { type: currentDB.value.type, database: currentDB.value.database });
};
@@ -398,7 +398,7 @@ const changeDatabase = async () => {
for (const item of dbOptionsLocal.value) {
if (item.database == currentDBName.value) {
currentDB.value = item;
globalStore.setCurrentDB(currentDB.value.database);
globalStore.currentDB = currentDB.value.database;
appKey.value = item.type;
appName.value = item.database;
search();
@@ -410,7 +410,7 @@ const changeDatabase = async () => {
if (item.database == currentDBName.value) {
maskShow.value = false;
currentDB.value = item;
globalStore.setCurrentDB(currentDB.value.database);
globalStore.currentDB = currentDB.value.database;
break;
}
}

View File

@@ -335,7 +335,7 @@ const onChangeConn = async () => {
const goRemoteDB = async () => {
if (currentDB.value) {
globalStore.setCurrentPgDB(currentDB.value.database);
globalStore.currentPgDB = currentDB.value.database;
}
routerToName('PostgreSQL-Remote');
};
@@ -348,7 +348,7 @@ const passwordRef = ref();
const onSetting = async () => {
if (currentDB.value) {
globalStore.setCurrentPgDB(currentDB.value.database);
globalStore.currentPgDB = currentDB.value.database;
}
routerToNameWithParams('PostgreSQL-Setting', { type: currentDB.value.type, database: currentDB.value.database });
};
@@ -357,7 +357,7 @@ const changeDatabase = async () => {
for (const item of dbOptionsLocal.value) {
if (item.database == currentDBName.value) {
currentDB.value = item;
globalStore.setCurrentPgDB(currentDB.value.database);
globalStore.currentPgDB = currentDB.value.database;
appKey.value = item.type;
appName.value = item.database;
search();
@@ -369,7 +369,7 @@ const changeDatabase = async () => {
if (item.database == currentDBName.value) {
maskShow.value = false;
currentDB.value = item;
globalStore.setCurrentPgDB(currentDB.value.database);
globalStore.currentPgDB = currentDB.value.database;
break;
}
}

View File

@@ -200,7 +200,7 @@ const getAppDetail = (key: string) => {
};
const goRemoteDB = async () => {
if (currentDB.value) {
globalStore.setCurrentRedisDB(currentDBName.value);
globalStore.currentRedisDB = currentDBName.value;
}
routerToName('Redis-Remote');
};
@@ -226,7 +226,7 @@ const changeDatabase = async () => {
for (const item of dbOptionsLocal.value) {
if (item.database == currentDBName.value) {
currentDB.value = item;
globalStore.setCurrentRedisDB(currentDB.value.database);
globalStore.currentRedisDB = currentDB.value.database;
appKey.value = item.type;
appName.value = item.database;
appStatusRef.value?.onCheck(appKey.value, appName.value);
@@ -237,7 +237,7 @@ const changeDatabase = async () => {
for (const item of dbOptionsRemote.value) {
if (item.database == currentDBName.value) {
currentDB.value = item;
globalStore.setCurrentRedisDB(currentDB.value.database);
globalStore.currentRedisDB = currentDB.value.database;
break;
}
}

View File

@@ -256,8 +256,8 @@
baseInfo.prettyDistro
? baseInfo.prettyDistro
: baseInfo.platformVersion
? baseInfo.platform + '-' + baseInfo.platformVersion
: baseInfo.platform
? baseInfo.platform + '-' + baseInfo.platformVersion
: baseInfo.platform
}}
</el-descriptions-item>
<el-descriptions-item
@@ -830,8 +830,8 @@ const handleCopy = () => {
(baseInfo.value.prettyDistro
? baseInfo.value.prettyDistro
: baseInfo.value.platformVersion
? baseInfo.value.platform + '-' + baseInfo.value.platformVersion
: baseInfo.value.platform) +
? baseInfo.value.platform + '-' + baseInfo.value.platformVersion
: baseInfo.value.platform) +
'\n' +
i18n.global.t('home.kernelVersion') +
': ' +
@@ -943,7 +943,7 @@ const loadData = async () => {
};
const hideEntrance = () => {
globalStore.setShowEntranceWarn(false);
globalStore.showEntranceWarn = false;
};
const loadUpgradeStatus = async () => {
@@ -1089,7 +1089,7 @@ onBeforeUnmount(() => {
});
</script>
<style lang="scss">
<style lang="scss" scoped>
.h-overview {
text-align: center;
@@ -1146,21 +1146,21 @@ onBeforeUnmount(() => {
.my-carousel {
&.no-indicator {
.el-carousel__indicators {
:deep(.el-carousel__indicators) {
display: none;
}
}
.el-carousel__button {
:deep(.el-carousel__button) {
margin-bottom: -4px;
background-color: var(--el-text-color-regular);
}
.el-carousel__indicator.is-active .el-carousel__button {
:deep(.el-carousel__indicator.is-active .el-carousel__button) {
background-color: var(--panel-color-primary);
}
.el-descriptions .el-descriptions__body .el-descriptions__table {
:deep(.el-descriptions .el-descriptions__body .el-descriptions__table) {
border-spacing: 0 5px !important;
}
}
@@ -1200,7 +1200,7 @@ onBeforeUnmount(() => {
top: -10px;
left: 20px;
.el-tag {
:deep(.el-tag) {
margin-right: 10px;
margin-bottom: 10px;
}
@@ -1245,7 +1245,7 @@ onBeforeUnmount(() => {
word-wrap: break-word;
white-space: pre-wrap;
.md-editor {
:deep(.md-editor) {
background-color: transparent;
}
}

View File

@@ -389,8 +389,7 @@
import { batchCheckFiles, createFile, getFileContent, getFilesTree, saveFileContent } from '@/api/modules/files';
import i18n from '@/lang';
import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message';
import { setupMonacoEnvironment } from '@/utils/monaco';
import * as monaco from 'monaco-editor';
import { loadMonacoLanguageSupport, setupMonacoEnvironment } from '@/utils/monaco';
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import { Languages } from '@/global/mimetype';
@@ -407,9 +406,57 @@ import { GlobalStore } from '@/store';
import CodeTabs from './tabs/index.vue';
import noUpdateImage from '@/assets/images/no_update_app.svg';
let editor: monaco.editor.IStandaloneCodeEditor | undefined;
type MonacoEditorApi = typeof import('monaco-editor/esm/vs/editor/editor.api');
setupMonacoEnvironment();
let monacoApi: MonacoEditorApi | null = null;
let monacoThemeInitialized = false;
let editor: MonacoEditorApi['editor']['IStandaloneCodeEditor'] | undefined;
const eolLf = ref(0);
const eolCrlf = ref(1);
const ensureMonaco = async () => {
if (monacoApi) {
return monacoApi;
}
setupMonacoEnvironment();
const [monacoModule] = await Promise.all([
import('monaco-editor/esm/vs/editor/editor.api'),
loadMonacoLanguageSupport(),
]);
monacoApi = monacoModule;
eolLf.value = monacoApi.editor.EndOfLineSequence.LF;
eolCrlf.value = monacoApi.editor.EndOfLineSequence.CRLF;
if (!monacoThemeInitialized) {
monacoApi.editor.defineTheme('vs', {
base: 'vs',
inherit: true,
rules: [{ token: '' }],
colors: {
'editor.background': '#f8f6f6',
'minimap.background': '#f4f4f4',
'scrollbar.shadow': '#e1e1e1',
'scrollbarSlider.background': '#e1e1e1',
'scrollbarSlider.hoverBackground': '#cccccc',
'scrollbarSlider.activeBackground': '#bfbfbf',
},
});
monacoThemeInitialized = true;
}
return monacoApi;
};
const disposeEditor = () => {
if (!editor) {
return;
}
clearPendingLineHighlight();
editor.dispose();
editor = undefined;
};
interface EditProps {
language: string;
content: string;
@@ -451,7 +498,7 @@ const clearPendingLineHighlight = () => {
const revealPendingInitialLine = () => {
const line = pendingInitialLine.value;
if (!editor || line < 1) {
if (!editor || !monacoApi || line < 1) {
return;
}
const model = editor.getModel();
@@ -469,7 +516,7 @@ const revealPendingInitialLine = () => {
editor.revealLineInCenter(targetLine);
lineHighlightDecorationIds = editor.deltaDecorations(lineHighlightDecorationIds, [
{
range: new monaco.Range(targetLine, 1, targetLine, model.getLineMaxColumn(targetLine)),
range: new monacoApi.Range(targetLine, 1, targetLine, model.getLineMaxColumn(targetLine)),
options: {
isWholeLine: true,
className: 'ai-search-target-line',
@@ -525,25 +572,11 @@ const isFullscreen = ref(false);
const config = reactive<EditorConfig>({
theme: 'vs-dark',
language: 'plaintext',
eol: monaco.editor.EndOfLineSequence.LF,
eol: eolLf.value,
wordWrap: 'on',
minimap: false,
});
monaco.editor.defineTheme('vs', {
base: 'vs',
inherit: true,
rules: [{ token: '' }],
colors: {
'editor.background': '#f8f6f6',
'minimap.background': '#f4f4f4',
'scrollbar.shadow': '#e1e1e1',
'scrollbarSlider.background': '#e1e1e1',
'scrollbarSlider.hoverBackground': '#cccccc',
'scrollbarSlider.activeBackground': '#bfbfbf',
},
});
const selectTab = ref();
const fileTabs = ref([]);
const maxTabs = 10;
@@ -583,7 +616,7 @@ const removeTab = (targetPath: TabPaneName) => {
saveTabsToStorage();
if (fileTabs.value.length === 0) {
selectTab.value = '';
editor.dispose();
disposeEditor();
}
};
@@ -638,7 +671,7 @@ const removeAllTab = (targetPath: string, type: 'left' | 'right' | 'all') => {
if (type === 'all') {
selectTab.value = '';
editor.dispose();
disposeEditor();
} else if (newTabs.length > 0) {
getContent(activeName, '');
}
@@ -714,16 +747,16 @@ const changeTab = (targetPath: TabPaneName) => {
getContent(targetPath.toString(), '');
};
const eols = [
const eols = computed(() => [
{
label: 'LF (Linux)',
value: monaco.editor.EndOfLineSequence.LF,
value: eolLf.value,
},
{
label: 'CRLF (Windows)',
value: monaco.editor.EndOfLineSequence.CRLF,
value: eolCrlf.value,
},
];
]);
const themes = [
{
@@ -754,8 +787,7 @@ const handleClose = () => {
fileTabs.value = [];
isEdit.value = false;
if (editor) {
clearPendingLineHighlight();
editor.dispose();
disposeEditor();
}
em('close', open.value);
};
@@ -825,13 +857,23 @@ const toggleFullscreen = () => {
};
const changeLanguage = (command: string) => {
if (!editor || !monacoApi) {
return;
}
config.language = command;
monaco.editor.setModelLanguage(editor.getModel(), config.language);
const model = editor.getModel();
if (!model) {
return;
}
monacoApi.editor.setModelLanguage(model, config.language);
};
const changeTheme = (command: string) => {
if (!monacoApi) {
return;
}
config.theme = command;
monaco.editor.setTheme(config.theme);
monacoApi.editor.setTheme(config.theme);
const themes = {
vs: 'monaco-editor-tree-light',
'vs-dark': 'monaco-editor-tree-dark',
@@ -851,8 +893,11 @@ const changeTheme = (command: string) => {
};
const changeEOL = (command: number) => {
if (!editor) {
return;
}
config.eol = command;
editor.getModel().pushEOL(config.eol);
editor.getModel()?.pushEOL(config.eol);
};
const changeWarp = (command: string) => {
@@ -873,44 +918,43 @@ const changeMinimap = (command: boolean) => {
});
};
const initEditor = () => {
if (editor) {
editor.dispose();
}
nextTick(() => {
editor = monaco.editor.create(codeBox.value as HTMLElement, {
theme: config.theme,
value: form.value.content,
readOnly: false,
automaticLayout: true,
language: config.language,
folding: true,
roundedSelection: false,
overviewRulerBorder: false,
wordWrap: config.wordWrap,
minimap: {
enabled: config.minimap,
},
lineNumbersMinChars: 6,
});
if (editor.getModel().getValue() === '') {
let defaultContent = '';
editor.getModel().setValue(defaultContent);
}
const initEditor = async () => {
const monaco = await ensureMonaco();
editor.getModel().pushEOL(config.eol);
disposeEditor();
await nextTick();
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, quickSave);
editor.onDidChangeModelContent(() => {
if (editor) {
form.value.content = editor.getValue();
isEdit.value = true;
}
});
revealPendingInitialLine();
editor = monaco.editor.create(codeBox.value as HTMLElement, {
theme: config.theme,
value: form.value.content,
readOnly: false,
automaticLayout: true,
language: config.language,
folding: true,
roundedSelection: false,
overviewRulerBorder: false,
wordWrap: config.wordWrap,
minimap: {
enabled: config.minimap,
},
lineNumbersMinChars: 6,
});
if (editor.getModel()?.getValue() === '') {
editor.getModel()?.setValue('');
}
editor.getModel()?.pushEOL(config.eol);
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, quickSave);
editor.onDidChangeModelContent(() => {
if (editor) {
form.value.content = editor.getValue();
isEdit.value = true;
}
});
revealPendingInitialLine();
};
const quickSave = () => {
@@ -939,6 +983,8 @@ const saveContent = async () => {
};
const acceptParams = async (props: EditProps) => {
const monaco = await ensureMonaco();
pendingInitialLine.value = props.initialLine && props.initialLine > 0 ? Math.floor(props.initialLine) : 0;
form.value.content = props.content;
oldFileContent.value = props.content;
@@ -978,7 +1024,7 @@ const acceptParams = async (props: EditProps) => {
editor.setValue(form.value.content);
const model = editor.getModel();
if (model) {
monaco.editor.setModelLanguage(model, config.language);
monacoApi?.editor.setModelLanguage(model, config.language);
}
isEdit.value = false;
revealPendingInitialLine();
@@ -1011,8 +1057,8 @@ const getDirectoryPath = (filePath: string) => {
return directoryPath;
};
const onOpen = () => {
initEditor();
const onOpen = async () => {
await initEditor();
changeTheme(config.theme);
search(directoryPath.value).then((res) => {
handleSearchResult(res);

View File

@@ -85,7 +85,7 @@ const handleClose = () => {
if (fileForm.value) {
fileForm.value.resetFields();
}
em('close', open);
em('close', open.value);
open.value = false;
};

View File

@@ -60,7 +60,7 @@ let setRole = ref(false);
const fileRef = ref();
interface CreateProps {
file: Object;
file: object;
}
const propData = ref<CreateProps>({
file: {},
@@ -74,7 +74,7 @@ const handleClose = () => {
if (fileForm.value) {
fileForm.value.resetFields();
}
em('close', open);
em('close', open.value);
};
const rules = reactive<FormRules>({

View File

@@ -68,7 +68,7 @@ const handleClose = () => {
fileForm.value.resetFields();
}
open.value = false;
em('close', open);
em('close', open.value);
};
const getLinkPath = (path: string) => {

View File

@@ -50,7 +50,7 @@ const handleClose = () => {
if (fileForm.value) {
fileForm.value.resetFields();
}
em('close', open);
em('close', open.value);
};
let addForm = ref({

View File

@@ -1131,12 +1131,12 @@ const jump = async (url: string) => {
let searchResult = await searchFile();
if (!searchResult.data.path) {
req.path = oldUrl;
globalStore.setLastFilePath(req.path);
globalStore.lastFilePath = req.path;
MsgWarning(i18n.global.t('commons.res.notFound'));
return;
}
req.path = searchResult.data.path;
globalStore.setLastFilePath(req.path);
globalStore.lastFilePath = req.path;
handleSearchResult(searchResult);
getPaths(req.path);
updateTab(req.path);
@@ -1453,14 +1453,14 @@ const openBatchRole = (items: File.File[]) => {
batchRoleRef.value.acceptParams({ files: items });
};
const closeWget = (submit: Boolean) => {
const closeWget = (submit: boolean) => {
search();
if (submit) {
openProcess();
}
};
const closeMovePage = (submit: Boolean) => {
const closeMovePage = (submit: boolean) => {
if (submit) {
search();
closeMove();
@@ -1490,7 +1490,7 @@ const getWgetProcess = async () => {
} catch (error) {}
};
const openRename = (item: File.File, source: String) => {
const openRename = (item: File.File, source: string) => {
fileRename.path = req.path;
fileRename.oldName = item.name;
if (source === 'right') {
@@ -2049,14 +2049,14 @@ function getInitialPath(): string {
if (routePath && typeof routePath === 'string') {
const p = routePath.trim();
if (p !== '') {
globalStore.setLastFilePath(p);
globalStore.lastFilePath = p;
return p;
}
}
const tab = editableTabs.value.find((t) => t.id === editableTabsKey.value);
if (tab && typeof tab.path === 'string' && tab.path.trim() !== '') {
const p = tab.path.trim();
globalStore.setLastFilePath(p);
globalStore.lastFilePath = p;
return p;
}
if (typeof globalStore.lastFilePath === 'string' && globalStore.lastFilePath.trim() !== '') {
@@ -2151,7 +2151,7 @@ const changeTab = (targetPath: TabPaneName) => {
saveStorageTabs();
saveStorageTabsKey();
req.path = current ? current.path : '';
globalStore.setLastFilePath(req.path);
globalStore.lastFilePath = req.path;
getPaths(req.path);
search();
};

View File

@@ -81,7 +81,7 @@ const em = defineEmits(['close']);
const handleClose = () => {
closeSocket();
open.value = false;
em('close', open);
em('close', open.value);
};
const isWsOpen = () => {

View File

@@ -64,7 +64,7 @@ const onSave = async (formEl: FormInstance | undefined) => {
if (!valid) return;
await updateMonitorSetting('DefaultIO', form.defaultIO)
.then(async () => {
globalStore.setDefaultIO(form.defaultIO);
globalStore.defaultIO = form.defaultIO;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;
drawerVisible.value = false;

View File

@@ -64,7 +64,7 @@ const onSave = async (formEl: FormInstance | undefined) => {
if (!valid) return;
await updateMonitorSetting('DefaultNetwork', form.defaultNetwork)
.then(async () => {
globalStore.setDefaultNetwork(form.defaultNetwork);
globalStore.defaultNetwork = form.defaultNetwork;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;
drawerVisible.value = false;

Some files were not shown because too many files have changed in this diff Show More