feat: 系统升级支持数据库自动迁移,避免手动执行升级脚本

This commit is contained in:
meilin.huang
2025-02-13 21:11:23 +08:00
parent efb2b7368c
commit aa393590b2
78 changed files with 1965 additions and 1827 deletions

View File

@@ -11,15 +11,15 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^12.4.0",
"asciinema-player": "^3.8.1",
"@vueuse/core": "^12.5.0",
"asciinema-player": "^3.9.0",
"axios": "^1.6.2",
"clipboard": "^2.0.11",
"cropperjs": "^1.6.1",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"echarts": "^5.6.0",
"element-plus": "^2.9.3",
"element-plus": "^2.9.4",
"js-base64": "^3.7.7",
"jsencrypt": "^3.3.2",
"lodash": "^4.17.21",
@@ -28,16 +28,16 @@
"monaco-sql-languages": "^0.12.2",
"monaco-themes": "^0.4.4",
"nprogress": "^0.2.0",
"pinia": "^2.3.0",
"pinia": "^2.3.1",
"qrcode.vue": "^3.6.0",
"screenfull": "^6.0.2",
"sortablejs": "^1.15.6",
"splitpanes": "^3.1.5",
"sql-formatter": "^15.4.5",
"splitpanes": "^3.1.8",
"sql-formatter": "^15.4.10",
"trzsz": "^1.1.5",
"uuid": "^9.0.1",
"vue": "^3.5.13",
"vue-i18n": "^11.0.1",
"vue-i18n": "^11.1.0",
"vue-router": "^4.5.0",
"vuedraggable": "^4.1.0",
"xterm": "^5.3.0",
@@ -60,9 +60,9 @@
"eslint": "^8.35.0",
"eslint-plugin-vue": "^9.31.0",
"prettier": "^3.2.5",
"sass": "^1.83.4",
"sass": "^1.84.0",
"typescript": "^5.7.3",
"vite": "^6.0.7",
"vite": "^6.1.0",
"vite-plugin-progress": "0.0.7",
"vue-eslint-parser": "^9.4.3"
},

View File

@@ -1,4 +1,4 @@
function getBaseApiUrl() {
export function getBaseApiUrl() {
let path = window.location.pathname;
if (path == '/') {
return window.location.host;
@@ -15,7 +15,7 @@ const config = {
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
// 系统版本
version: 'v1.9.2',
version: 'v1.9.3',
};
export default config;

View File

@@ -54,3 +54,67 @@ export function getValueByPath(obj: any, path: string) {
return result;
}
/**
* 根据字段路径设置字段值,若路径不存在,则建对应的路径对象信息
* @param obj 对象
* @param path 字段路径
* @param value 字段值
*/
export function setValueByPath(obj: any, path: string[], value: any) {
for (let i = 0; i < path.length - 1; i++) {
const key = path[i];
if (!obj[key]) {
obj[key] = {};
}
obj = obj[key];
}
obj[path[path.length - 1]] = value;
}
/**
* 使用递归函数进行深度克隆,并支持通过回调函数进行指定字段值的调整
*
* @param obj 要克隆的对象
* @param callback 回调函数,在每个字段被克隆之前调用,可以调整字段的值
* @param hash 用于处理循环引用的 WeakMap
* @returns 深度克隆后的对象
*/
export function deepClone(
obj: any,
callback: (key: string | number, value: any) => any = (key: string | number, value: any) => value,
hash = new WeakMap()
): any {
if (Object(obj) !== obj) return obj; // 基本数据类型直接返回
if (hash.has(obj)) return hash.get(obj); // 处理循环引用
let result: any;
if (obj instanceof Set) {
result = new Set();
hash.set(obj, result);
obj.forEach((val) => result.add(deepClone(val, callback, hash)));
} else if (obj instanceof Map) {
result = new Map();
hash.set(obj, result);
obj.forEach((val, key) => result.set(key, deepClone(val, callback, hash)));
} else if (obj instanceof Date) {
result = new Date(obj.getTime());
} else if (obj instanceof RegExp) {
result = new RegExp(obj);
} else if (typeof obj === 'object') {
result = Array.isArray(obj) ? [] : {};
hash.set(obj, result);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
let value = obj[key];
value = callback(key, value);
result[key] = deepClone(value, callback, hash);
}
}
} else {
result = obj;
}
return result;
}

View File

@@ -203,6 +203,15 @@ export function randomPassword(length = 10) {
return password.join('');
}
export function randomString(length = 8) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += getRandomChar(chars);
}
return result;
}
function getRandomChar(charSet: string) {
const randomIndex = Math.floor(Math.random() * charSet.length);
return charSet[randomIndex];

View File

@@ -42,6 +42,7 @@ function initI18n() {
// https://vue-i18n.intlify.dev/guide/essentials/fallback.html#explicit-fallback-with-one-locale
return createI18n({
legacy: false,
globalInjection: true, // 在所有组件中都可以使用 $i18n $t $rt $d $n $tm
silentTranslationWarn: true,
missingWarn: false,
silentFallbackWarn: true,

View File

@@ -57,7 +57,7 @@
</template>
<template #default="scope">
<AccountSelectFormItem v-model="scope.row.userId" label="" />
<AccountSelectFormItem style="margin-bottom: 0px" v-model="scope.row.userId" label="" />
</template>
</el-table-column>

View File

@@ -95,7 +95,7 @@ const encryptField = async (param: any, field: string) => {
if (process.env.NODE_ENV === 'development') {
console.log(param[field]);
}
// 使用rsa公钥加密sql
// 使用aes加密sql
param['_encrypted'] = 1;
param[field] = AesEncrypt(param[field]);
// console.log('解密结果', DesDecrypt(param[field]));

View File

@@ -235,14 +235,22 @@ const cmHeaderDesc = new ContextmenuItem('desc', 'db.desc')
const cmHeaderFixed = new ContextmenuItem('fixed', 'db.fixed')
.withIcon('Paperclip')
.withOnClick((data: any) => {
data.fixed = true;
state.columns.forEach((column: any) => {
if (column.dataKey == data.dataKey) {
column.fixed = true;
}
});
})
.withHideFunc((data: any) => data.fixed);
const cmHeaderCancelFixed = new ContextmenuItem('cancelFixed', 'db.cancelFiexd')
.withIcon('Minus')
.withOnClick((data: any) => {
data.fixed = false;
state.columns.forEach((column: any) => {
if (column.dataKey == data.dataKey) {
column.fixed = false;
}
});
})
.withHideFunc((data: any) => !data.fixed);

View File

@@ -11,6 +11,8 @@ const pathResolve = (dir: string): any => {
const { VITE_PORT, VITE_OPEN, VITE_PUBLIC_PATH, VITE_EDITOR } = loadEnv();
const isProd = process.env.NODE_ENV === 'production';
const alias: Record<string, string> = {
'@': pathResolve('src/'),
};
@@ -28,7 +30,7 @@ const viteConfig: UserConfig = {
resolve: {
alias,
},
base: process.env.NODE_ENV === 'production' ? VITE_PUBLIC_PATH : './',
base: isProd ? VITE_PUBLIC_PATH : './',
optimizeDeps: {
include: ['element-plus/es/locale/lang/zh-cn'],
},
@@ -63,6 +65,9 @@ const viteConfig: UserConfig = {
},
},
},
esbuild: {
drop: isProd ? ['console', 'debugger'] : [],
},
define: {
__VUE_I18N_LEGACY_API__: JSON.stringify(false),
__VUE_I18N_FULL_INSTALL__: JSON.stringify(false),