mirror of
https://gitee.com/dromara/mayfly-go
synced 2026-01-03 13:16:35 +08:00
refactor: sql取消执行逻辑调整、前端使用vueuse重构部分代码
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.1.0",
|
"@element-plus/icons-vue": "^2.1.0",
|
||||||
|
"@vueuse/core": "^10.7.0",
|
||||||
"asciinema-player": "^3.6.2",
|
"asciinema-player": "^3.6.2",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"monaco-editor": "^0.44.0",
|
"monaco-editor": "^0.45.0",
|
||||||
"monaco-sql-languages": "^0.11.0",
|
"monaco-sql-languages": "^0.11.0",
|
||||||
"monaco-themes": "^0.4.4",
|
"monaco-themes": "^0.4.4",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
"splitpanes": "^3.1.5",
|
"splitpanes": "^3.1.5",
|
||||||
"sql-formatter": "^14.0.0",
|
"sql-formatter": "^14.0.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vue": "^3.3.10",
|
"vue": "^3.3.11",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"xterm": "^5.3.0",
|
"xterm": "^5.3.0",
|
||||||
"xterm-addon-fit": "^0.8.0",
|
"xterm-addon-fit": "^0.8.0",
|
||||||
@@ -54,7 +55,7 @@
|
|||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"sass": "^1.69.0",
|
"sass": "^1.69.0",
|
||||||
"typescript": "^5.3.2",
|
"typescript": "^5.3.2",
|
||||||
"vite": "^5.0.5",
|
"vite": "^5.0.7",
|
||||||
"vue-eslint-parser": "^9.3.2"
|
"vue-eslint-parser": "^9.3.2"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import Setings from '@/layout/navBars/breadcrumb/setings.vue';
|
|||||||
import mittBus from '@/common/utils/mitt';
|
import mittBus from '@/common/utils/mitt';
|
||||||
import { getThemeConfig } from './common/utils/storage';
|
import { getThemeConfig } from './common/utils/storage';
|
||||||
import { useWatermark } from '@/common/sysconfig';
|
import { useWatermark } from '@/common/sysconfig';
|
||||||
|
import { useIntervalFn } from '@vueuse/core';
|
||||||
|
|
||||||
const setingsRef = ref();
|
const setingsRef = ref();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -40,12 +41,6 @@ const openSetingsDrawer = () => {
|
|||||||
setingsRef.value.openDrawer();
|
setingsRef.value.openDrawer();
|
||||||
};
|
};
|
||||||
|
|
||||||
const prefers = matchMedia('(prefers-color-scheme: dark)');
|
|
||||||
const switchDarkFollowOS = () => {
|
|
||||||
// 跟随系统主题
|
|
||||||
themeConfigStores.switchDark(prefers.matches);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -60,7 +55,6 @@ onMounted(() => {
|
|||||||
themeConfigStores.setThemeConfig({ themeConfig: tc });
|
themeConfigStores.setThemeConfig({ themeConfig: tc });
|
||||||
document.documentElement.style.cssText = getLocal('themeConfigStyle');
|
document.documentElement.style.cssText = getLocal('themeConfigStyle');
|
||||||
}
|
}
|
||||||
switchDarkFollowOS();
|
|
||||||
|
|
||||||
// 是否开启水印
|
// 是否开启水印
|
||||||
useWatermark().then((res) => {
|
useWatermark().then((res) => {
|
||||||
@@ -77,36 +71,35 @@ watch(
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setWatermarkContent();
|
setWatermarkContent();
|
||||||
refreshWatermarkTime();
|
refreshWatermarkTime();
|
||||||
|
resume();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
} else {
|
||||||
|
pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 刷新水印时间
|
||||||
|
const { pause, resume } = useIntervalFn(() => {
|
||||||
|
if (!themeConfig.value.isWatermark) {
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
refreshWatermarkTime();
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
const setWatermarkContent = () => {
|
const setWatermarkContent = () => {
|
||||||
themeConfigStores.setWatermarkUser();
|
themeConfigStores.setWatermarkUser();
|
||||||
themeConfigStores.setWatermarkNowTime();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let refreshWatermarkTimeInterval: any = null;
|
|
||||||
/**
|
/**
|
||||||
* 刷新水印时间
|
* 刷新水印时间
|
||||||
*/
|
*/
|
||||||
const refreshWatermarkTime = () => {
|
const refreshWatermarkTime = () => {
|
||||||
if (refreshWatermarkTimeInterval) {
|
themeConfigStores.setWatermarkNowTime();
|
||||||
clearInterval(refreshWatermarkTimeInterval);
|
|
||||||
}
|
|
||||||
refreshWatermarkTimeInterval = setInterval(() => {
|
|
||||||
if (themeConfig.value.isWatermark) {
|
|
||||||
themeConfigStores.setWatermarkNowTime();
|
|
||||||
} else {
|
|
||||||
clearInterval(refreshWatermarkTimeInterval);
|
|
||||||
}
|
|
||||||
}, 60000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 页面销毁时,关闭监听布局配置
|
// 页面销毁时,关闭监听布局配置
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
clearInterval(refreshWatermarkTimeInterval);
|
|
||||||
mittBus.off('openSetingsDrawer', () => {});
|
mittBus.off('openSetingsDrawer', () => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -49,32 +49,27 @@ class Api {
|
|||||||
* 请求对应的该api
|
* 请求对应的该api
|
||||||
* @param {Object} param 请求该api的参数
|
* @param {Object} param 请求该api的参数
|
||||||
*/
|
*/
|
||||||
request(param: any = null, options: any = null, headers: any = null): Promise<any> {
|
request(param: any = null, options: any = {}): Promise<any> {
|
||||||
if (this.beforeHandler) {
|
if (this.beforeHandler) {
|
||||||
this.beforeHandler(param);
|
this.beforeHandler(param);
|
||||||
}
|
}
|
||||||
return request.request(this.method, this.url, param, headers, options);
|
return request.request(this.method, this.url, param, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求对应的该api
|
* 允许取消的请求, 使用Api.cancelReq(key) 取消请求
|
||||||
|
* @param key 用于取消该key关联的请求
|
||||||
* @param {Object} param 请求该api的参数
|
* @param {Object} param 请求该api的参数
|
||||||
*/
|
*/
|
||||||
requestCanCancel(key: string, param: any = null, options: any = null, headers: any = null): Promise<any> {
|
allowCancelReq(key: string, param: any = null, options: RequestInit = {}): Promise<any> {
|
||||||
let controller = Api.abortControllers.get(key);
|
let controller = Api.abortControllers.get(key);
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
controller = new AbortController();
|
controller = new AbortController();
|
||||||
Api.abortControllers.set(key, controller);
|
Api.abortControllers.set(key, controller);
|
||||||
}
|
}
|
||||||
if (options) {
|
options.signal = controller.signal;
|
||||||
options.signal = controller.signal;
|
|
||||||
} else {
|
|
||||||
options = {
|
|
||||||
signal: controller.signal,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.request(param, options, headers);
|
return this.request(param, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 静态方法 **/
|
/** 静态方法 **/
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
import router from '../router';
|
import router from '../router';
|
||||||
import Axios from 'axios';
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { getClientId, getToken } from './utils/storage';
|
import { getClientId, getToken } from './utils/storage';
|
||||||
import { templateResolve } from './utils/string';
|
import { templateResolve } from './utils/string';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
request,
|
||||||
|
fetchReq,
|
||||||
|
get,
|
||||||
|
post,
|
||||||
|
put,
|
||||||
|
del,
|
||||||
|
getApiUrl,
|
||||||
|
};
|
||||||
|
|
||||||
export interface Result {
|
export interface Result {
|
||||||
/**
|
/**
|
||||||
* 响应码
|
* 响应码
|
||||||
@@ -30,6 +39,7 @@ enum ResultEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const baseUrl: string = config.baseApiUrl;
|
const baseUrl: string = config.baseApiUrl;
|
||||||
|
// const baseUrl: string = 'http://localhost:18888/api';
|
||||||
// const baseWsUrl: string = config.baseWsUrl;
|
// const baseWsUrl: string = config.baseWsUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,13 +52,13 @@ function notifyErrorMsg(msg: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create an axios instance
|
// create an axios instance
|
||||||
const service = Axios.create({
|
const axiosInst = axios.create({
|
||||||
baseURL: baseUrl, // url = base url + request url
|
baseURL: baseUrl, // url = base url + request url
|
||||||
timeout: 60000, // request timeout
|
timeout: 60000, // request timeout
|
||||||
});
|
});
|
||||||
|
|
||||||
// request interceptor
|
// request interceptor
|
||||||
service.interceptors.request.use(
|
axiosInst.interceptors.request.use(
|
||||||
(config: any) => {
|
(config: any) => {
|
||||||
// do something before request is sent
|
// do something before request is sent
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
@@ -65,21 +75,8 @@ service.interceptors.request.use(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// response interceptor
|
// response interceptor
|
||||||
service.interceptors.response.use(
|
axiosInst.interceptors.response.use(
|
||||||
(response) => {
|
(response) => response,
|
||||||
// 获取请求返回结果
|
|
||||||
const res: Result = response.data;
|
|
||||||
if (res.code === ResultEnum.SUCCESS) {
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
// 如果提示没有权限,则移除token,使其重新登录
|
|
||||||
if (res.code === ResultEnum.NO_PERMISSION) {
|
|
||||||
router.push({
|
|
||||||
path: '/401',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Promise.reject(res);
|
|
||||||
},
|
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
const rejectPromise = Promise.reject(e);
|
const rejectPromise = Promise.reject(e);
|
||||||
|
|
||||||
@@ -125,35 +122,37 @@ service.interceptors.response.use(
|
|||||||
* @param {Object} uri uri
|
* @param {Object} uri uri
|
||||||
* @param {Object} params 参数
|
* @param {Object} params 参数
|
||||||
*/
|
*/
|
||||||
function request(method: string, url: string, params: any = null, headers: any = null, options: any = null): Promise<any> {
|
function request(method: string, url: string, params: any = null, options: any = {}): Promise<any> {
|
||||||
if (!url) throw new Error('请求url不能为空');
|
if (!url) {
|
||||||
|
throw new Error('请求url不能为空');
|
||||||
|
}
|
||||||
|
|
||||||
// 简单判断该url是否是restful风格
|
// 简单判断该url是否是restful风格
|
||||||
if (url.indexOf('{') != -1) {
|
if (url.indexOf('{') != -1) {
|
||||||
url = templateResolve(url, params);
|
url = templateResolve(url, params);
|
||||||
}
|
}
|
||||||
const query: any = {
|
|
||||||
|
const req: any = {
|
||||||
method,
|
method,
|
||||||
url: url,
|
url,
|
||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
if (headers) {
|
|
||||||
query.headers = headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// post和put使用json格式传参
|
// post和put使用json格式传参
|
||||||
if (method === 'post' || method === 'put') {
|
if (method === 'post' || method === 'put') {
|
||||||
query.data = params;
|
req.data = params;
|
||||||
} else {
|
} else {
|
||||||
query.params = params;
|
req.params = params;
|
||||||
}
|
}
|
||||||
return service
|
|
||||||
.request(query)
|
return axiosInst
|
||||||
.then((res) => res)
|
.request(req)
|
||||||
|
.then((response) => {
|
||||||
|
// 获取请求返回结果
|
||||||
|
const result: Result = response.data;
|
||||||
|
return parseResult(result);
|
||||||
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
// 如果返回的code不为成功,则会返回对应的错误msg,则直接统一通知即可。忽略登录超时或没有权限的提示(直接跳转至401页面)
|
|
||||||
if (e.msg && e?.code != ResultEnum.NO_PERMISSION) {
|
|
||||||
notifyErrorMsg(e.msg);
|
|
||||||
}
|
|
||||||
return Promise.reject(e);
|
return Promise.reject(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -165,20 +164,20 @@ function request(method: string, url: string, params: any = null, headers: any =
|
|||||||
* @param {Object} url uri
|
* @param {Object} url uri
|
||||||
* @param {Object} params 参数
|
* @param {Object} params 参数
|
||||||
*/
|
*/
|
||||||
function get(url: string, params: any = null, headers: any = null, options: any = null): Promise<any> {
|
function get(url: string, params: any = null, options: any = {}): Promise<any> {
|
||||||
return request('get', url, params, headers, options);
|
return request('get', url, params, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function post(url: string, params: any = null, headers: any = null, options: any = null): Promise<any> {
|
function post(url: string, params: any = null, options: any = {}): Promise<any> {
|
||||||
return request('post', url, params, headers, options);
|
return request('post', url, params, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function put(url: string, params: any = null, headers: any = null, options: any = null): Promise<any> {
|
function put(url: string, params: any = null, options: any = {}): Promise<any> {
|
||||||
return request('put', url, params, headers, options);
|
return request('put', url, params, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function del(url: string, params: any = null, headers: any = null, options: any = null): Promise<any> {
|
function del(url: string, params: any = null, options: any = {}): Promise<any> {
|
||||||
return request('delete', url, params, headers, options);
|
return request('delete', url, params, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getApiUrl(url: string) {
|
function getApiUrl(url: string) {
|
||||||
@@ -191,11 +190,80 @@ export function joinClientParams(): string {
|
|||||||
return `token=${getToken()}&clientId=${getClientId()}`;
|
return `token=${getToken()}&clientId=${getClientId()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
async function fetchReq(method: string, url: string, params: any = null, options: RequestInit = {}): Promise<any> {
|
||||||
request,
|
options.method = method;
|
||||||
get,
|
|
||||||
post,
|
if (params) {
|
||||||
put,
|
// post和put使用json格式传参
|
||||||
del,
|
if (method === 'post' || method === 'put') {
|
||||||
getApiUrl,
|
options.body = JSON.stringify(params);
|
||||||
};
|
} else {
|
||||||
|
const searchParam = new URLSearchParams();
|
||||||
|
Object.keys(params).forEach((key) => {
|
||||||
|
const val = params[key];
|
||||||
|
if (val) {
|
||||||
|
searchParam.append(key, val);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
url = `${url}?${searchParam.toString()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part 1: Add headers and attach auth token
|
||||||
|
const headers = new Headers(options.headers || {});
|
||||||
|
|
||||||
|
const token = getToken();
|
||||||
|
if (token) {
|
||||||
|
headers.set('Authorization', token);
|
||||||
|
headers.set('ClientId', getClientId());
|
||||||
|
}
|
||||||
|
options.headers = headers;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res: Response = await fetch(`${baseUrl}${url}`, options);
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`请求响应错误: 状态码=${res.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonRes = await res.json();
|
||||||
|
// 获取请求返回结果
|
||||||
|
const result: Result = jsonRes;
|
||||||
|
return parseResult(result);
|
||||||
|
} catch (e: any) {
|
||||||
|
const rejectPromise = Promise.reject(e);
|
||||||
|
|
||||||
|
if (e?.name == 'AbortError') {
|
||||||
|
console.log('请求已取消');
|
||||||
|
return rejectPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.message) {
|
||||||
|
notifyErrorMsg(e.message);
|
||||||
|
return rejectPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyErrorMsg('网络请求错误');
|
||||||
|
console.error(e);
|
||||||
|
return rejectPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseResult(result: Result) {
|
||||||
|
if (result.code === ResultEnum.SUCCESS) {
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果提示没有权限,则移除token,使其重新登录
|
||||||
|
if (result.code === ResultEnum.NO_PERMISSION) {
|
||||||
|
router.push({
|
||||||
|
path: '/401',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果返回的code不为成功,则会返回对应的错误msg,则直接统一通知即可。忽略登录超时或没有权限的提示(直接跳转至401页面)
|
||||||
|
if (result.msg && result?.code != ResultEnum.NO_PERMISSION) {
|
||||||
|
notifyErrorMsg(result.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(result);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import openApi from './openApi';
|
|||||||
|
|
||||||
// 登录是否使用验证码配置key
|
// 登录是否使用验证码配置key
|
||||||
const AccountLoginSecurity = 'AccountLoginSecurity';
|
const AccountLoginSecurity = 'AccountLoginSecurity';
|
||||||
const UseLoginCaptchaConfigKey = 'UseLoginCaptcha';
|
|
||||||
const UseWatermarkConfigKey = 'UseWatermark';
|
const UseWatermarkConfigKey = 'UseWatermark';
|
||||||
|
const MachineConfig = 'MachineConfig';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统配置值
|
* 获取系统配置值
|
||||||
@@ -43,15 +43,6 @@ export async function getAccountLoginSecurity(): Promise<any> {
|
|||||||
return jsonValue;
|
return jsonValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否使用登录验证码
|
|
||||||
*
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export async function useLoginCaptcha(): Promise<boolean> {
|
|
||||||
return await getBoolConfigValue(UseLoginCaptchaConfigKey, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否启用水印信息配置
|
* 是否启用水印信息配置
|
||||||
*
|
*
|
||||||
@@ -75,13 +66,6 @@ export async function useWatermark(): Promise<any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function convertBool(value: string, defaultValue: boolean) {
|
|
||||||
if (!value) {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
return value == '1' || value == 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取LDAP登录配置
|
* 获取LDAP登录配置
|
||||||
*
|
*
|
||||||
@@ -91,3 +75,32 @@ export async function getLdapEnabled(): Promise<any> {
|
|||||||
const value = await openApi.getLdapEnabled();
|
const value = await openApi.getLdapEnabled();
|
||||||
return convertBool(value, false);
|
return convertBool(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否启用水印信息配置
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function getMachineConfig(): Promise<any> {
|
||||||
|
const value = await getConfigValue(MachineConfig);
|
||||||
|
const defaultValue = {
|
||||||
|
// 默认1gb
|
||||||
|
uploadMaxFileSize: '1GB',
|
||||||
|
};
|
||||||
|
if (!value) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const jsonValue = JSON.parse(value);
|
||||||
|
return jsonValue;
|
||||||
|
} catch (e) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertBool(value: string, defaultValue: boolean) {
|
||||||
|
if (!value) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return value == '1' || value == 'true';
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const vw = ref(document.documentElement.clientWidth);
|
|
||||||
const vh = ref(document.documentElement.clientHeight);
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
vw.value = document.documentElement.clientWidth;
|
|
||||||
vh.value = document.documentElement.clientHeight;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取视图宽高
|
|
||||||
* @returns 视图宽高
|
|
||||||
*/
|
|
||||||
export function useViewport() {
|
|
||||||
return { vw, vh };
|
|
||||||
}
|
|
||||||
@@ -15,6 +15,37 @@ export function formatByteSize(size: number, fixed = 2) {
|
|||||||
return parseFloat((size / Math.pow(base, exponent)).toFixed(fixed)) + units[exponent];
|
return parseFloat((size / Math.pow(base, exponent)).toFixed(fixed)) + units[exponent];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 容量转为对应的字节大小,如 1KB转为 1024
|
||||||
|
* @param sizeString 1kb 1gb等
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function convertToBytes(sizeStr: string) {
|
||||||
|
sizeStr = sizeStr.trim();
|
||||||
|
const unit = sizeStr.slice(-2);
|
||||||
|
|
||||||
|
const valueStr = sizeStr.slice(0, -2);
|
||||||
|
const value = parseInt(valueStr, 10);
|
||||||
|
|
||||||
|
let bytes = 0;
|
||||||
|
|
||||||
|
switch (unit.toUpperCase()) {
|
||||||
|
case 'KB':
|
||||||
|
bytes = value * 1024;
|
||||||
|
break;
|
||||||
|
case 'MB':
|
||||||
|
bytes = value * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
case 'GB':
|
||||||
|
bytes = value * 1024 * 1024 * 1024;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Invalid size unit');
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化json字符串
|
* 格式化json字符串
|
||||||
* @param txt json字符串
|
* @param txt json字符串
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
<script setup lang="ts" name="layoutTagsViewContextmenu">
|
<script setup lang="ts" name="layoutTagsViewContextmenu">
|
||||||
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
|
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
|
||||||
import { ContextmenuItem } from './index';
|
import { ContextmenuItem } from './index';
|
||||||
import { useViewport } from '@/common/use';
|
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
|
import { useWindowSize } from '@vueuse/core';
|
||||||
|
|
||||||
// 定义父组件传过来的值
|
// 定义父组件传过来的值
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -57,7 +57,7 @@ const props = defineProps({
|
|||||||
// 定义子组件向父组件传值/事件
|
// 定义子组件向父组件传值/事件
|
||||||
const emit = defineEmits(['currentContextmenuClick']);
|
const emit = defineEmits(['currentContextmenuClick']);
|
||||||
|
|
||||||
const { vw, vh } = useViewport();
|
const { width: vw, height: vh } = useWindowSize();
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
|
|||||||
@@ -1,212 +1,43 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="dynamic-form">
|
<div class="dynamic-form">
|
||||||
<el-form
|
<el-form v-bind="$attrs" ref="formRef" :model="formData" label-width="auto">
|
||||||
:model="form"
|
<el-form-item v-for="item in formItems as any" :key="item.name" :prop="item.model" :label="item.name" required>
|
||||||
ref="dynamicForm"
|
<el-input v-if="!item.options" v-model="formData[item.model]" :placeholder="item.placeholder" autocomplete="off" clearable></el-input>
|
||||||
:label-width="formInfo.labelWidth ? formInfo.labelWidth : '100px'"
|
|
||||||
:size="formInfo.size ? formInfo.size : 'small'"
|
|
||||||
>
|
|
||||||
<el-row v-for="fr in formInfo.formRows" :key="fr.key">
|
|
||||||
<el-col v-for="item in fr" :key="item.key" :span="item.span ? item.span : 24 / fr.length">
|
|
||||||
<el-form-item :prop="item.name" :label="item.label" :label-width="item.labelWidth" :required="item.required" :rules="item.rules">
|
|
||||||
<!-- input输入框 -->
|
|
||||||
<el-input
|
|
||||||
v-if="item.type === 'input'"
|
|
||||||
v-model.trim="form[item.name]"
|
|
||||||
:placeholder="item.placeholder"
|
|
||||||
:type="item.inputType"
|
|
||||||
clearable
|
|
||||||
|
|
||||||
@change="item.change ? item.change(form) : ''"
|
<el-select v-else v-model="formData[item.model]" :placeholder="item.placeholder" filterable autocomplete="off" clearable style="width: 100%">
|
||||||
></el-input>
|
<el-option v-for="option in item.options.split(',')" :key="option" :label="option" :value="option" />
|
||||||
|
</el-select>
|
||||||
<!-- 普通文本信息(可用于不可修改字段等) -->
|
</el-form-item>
|
||||||
<span v-else-if="item.type === 'text'">{{ form[item.name] }}</span>
|
</el-form>
|
||||||
|
</div>
|
||||||
<!-- select选择框 -->
|
|
||||||
<!-- optionProps.label: 指定option中的label为options对象的某个属性值,默认就是label字段 -->
|
|
||||||
<!-- optionProps.value: 指定option中的value为options对象的某个属性值,默认就是value字段 -->
|
|
||||||
<el-select
|
|
||||||
v-else-if="item.type === 'select'"
|
|
||||||
v-model.trim="form[item.name]"
|
|
||||||
:placeholder="item.placeholder"
|
|
||||||
:filterable="item.filterable"
|
|
||||||
:remote="item.remote"
|
|
||||||
:remote-method="item.remoteMethod"
|
|
||||||
@focus="item.focus ? item.focus(form) : ''"
|
|
||||||
clearable
|
|
||||||
:disabled="item.updateDisabled && form.id != null"
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="i in item.options"
|
|
||||||
:key="i.key"
|
|
||||||
:label="i[item.optionProps ? item.optionProps.label || 'label' : 'label']"
|
|
||||||
:value="i[item.optionProps ? item.optionProps.value || 'value' : 'value']"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-row type="flex" justify="center">
|
|
||||||
<slot name="btns" :submitDisabled="submitDisabled" :data="form" :submit="submit">
|
|
||||||
<el-button @click="reset" size="small">重 置</el-button>
|
|
||||||
<el-button type="primary" @click="submit" size="small">保 存</el-button>
|
|
||||||
</slot>
|
|
||||||
</el-row>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { watch, ref, toRefs, reactive, onMounted, defineComponent } from 'vue';
|
import { useVModel } from '@vueuse/core';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'DynamicForm',
|
formItems: { type: Array },
|
||||||
|
modelValue: { type: Object },
|
||||||
props: {
|
|
||||||
formInfo: { type: Object },
|
|
||||||
formData: { type: [Object, Boolean] },
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props: any, context) {
|
|
||||||
const dynamicForm: any = ref();
|
|
||||||
const state = reactive({
|
|
||||||
form: {},
|
|
||||||
submitDisabled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(props.formData, (newValue, oldValue) => {
|
|
||||||
if (props.formData) {
|
|
||||||
state.form = { ...props.formData };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const submit = () => {
|
|
||||||
dynamicForm.value.validate((valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
// 提交的表单数据
|
|
||||||
const subform = { ...state.form };
|
|
||||||
const operation = state.form['id'] ? props.formInfo['updateApi'] : props.formInfo['createApi'];
|
|
||||||
if (operation) {
|
|
||||||
state.submitDisabled = true;
|
|
||||||
operation.request(state.form).then(
|
|
||||||
(res: any) => {
|
|
||||||
ElMessage.success('保存成功');
|
|
||||||
context.emit('submitSuccess', subform);
|
|
||||||
state.submitDisabled = false;
|
|
||||||
// this.cancel()
|
|
||||||
},
|
|
||||||
(e: any) => {
|
|
||||||
state.submitDisabled = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ElMessage.error('表单未设置对应的提交权限');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const reset = () => {
|
|
||||||
context.emit('reset');
|
|
||||||
resetFieldsAndData();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重置表单以及表单数据
|
|
||||||
*/
|
|
||||||
const resetFieldsAndData = () => {
|
|
||||||
// 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
|
|
||||||
const df: any = dynamicForm;
|
|
||||||
df.resetFields();
|
|
||||||
// 重置表单数据
|
|
||||||
state.form = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
dynamicForm,
|
|
||||||
submit,
|
|
||||||
reset,
|
|
||||||
resetFieldsAndData,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// @Component({
|
|
||||||
// name: 'DynamicForm'
|
|
||||||
// })
|
|
||||||
// export default class DynamicForm extends Vue {
|
|
||||||
// @Prop()
|
|
||||||
// formInfo: object
|
|
||||||
// @Prop()
|
|
||||||
// formData: [object,boolean]|undefined
|
|
||||||
|
|
||||||
// form = {}
|
const emit = defineEmits(['update:modelValue']);
|
||||||
// submitDisabled = false
|
|
||||||
|
|
||||||
// @Watch('formData', { deep: true })
|
const formRef: any = ref();
|
||||||
// onRoleChange() {
|
|
||||||
// if (this.formData) {
|
|
||||||
// this.form = { ...this.formData }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// submit() {
|
const formData: any = useVModel(props, 'modelValue', emit);
|
||||||
// const dynamicForm: any = this.$refs['dynamicForm']
|
|
||||||
// dynamicForm.validate((valid: boolean) => {
|
|
||||||
// if (valid) {
|
|
||||||
// // 提交的表单数据
|
|
||||||
// const subform = { ...this.form }
|
|
||||||
// const operation = this.form['id']
|
|
||||||
// ? this.formInfo['updateApi']
|
|
||||||
// : this.formInfo['createApi']
|
|
||||||
// if (operation) {
|
|
||||||
// this.submitDisabled = true
|
|
||||||
// operation.request(this.form).then(
|
|
||||||
// (res: any) => {
|
|
||||||
// ElMessage.success('保存成功')
|
|
||||||
// this.$emit('submitSuccess', subform)
|
|
||||||
// this.submitDisabled = false
|
|
||||||
// // this.cancel()
|
|
||||||
// },
|
|
||||||
// (e: any) => {
|
|
||||||
// this.submitDisabled = false
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
// } else {
|
|
||||||
// ElMessage.error('表单未设置对应的提交权限')
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// reset() {
|
const validate = async (func: any) => {
|
||||||
// this.$emit('reset')
|
await formRef.value.validate(func);
|
||||||
// this.resetFieldsAndData()
|
};
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
const resetFields = () => {
|
||||||
// * 重置表单以及表单数据
|
formRef.value.resetFields();
|
||||||
// */
|
};
|
||||||
// resetFieldsAndData() {
|
|
||||||
// // 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
|
|
||||||
// const df: any = this.$refs['dynamicForm']
|
|
||||||
// df.resetFields()
|
|
||||||
// // 重置表单数据
|
|
||||||
// this.form = {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
// mounted() {
|
defineExpose({
|
||||||
// // 组件可能还没有初始化,第一次初始化的时候无法watch对象
|
validate,
|
||||||
// this.form = { ...this.formData }
|
resetFields,
|
||||||
// }
|
});
|
||||||
|
|
||||||
// }
|
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss"></style>
|
||||||
|
|||||||
@@ -1,60 +1,55 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="form-dialog">
|
<div class="form-dialog">
|
||||||
<el-dialog :title="title" v-model="visible" :width="dialogWidth ? dialogWidth : '500px'">
|
<el-dialog @close="close" v-bind="$attrs" :title="title" v-model="dialogVisible" :width="width">
|
||||||
<dynamic-form ref="df" :form-info="formInfo" :form-data="formData" @submitSuccess="submitSuccess">
|
<dynamic-form ref="df" :form-items="formItems" v-model="formData" />
|
||||||
<template #btns="props">
|
|
||||||
<slot name="btns">
|
<template #footer>
|
||||||
<el-button :disabled="props.submitDisabled" type="primary" @click="props.submit" size="small">保 存</el-button>
|
<span>
|
||||||
<el-button :disabled="props.submitDisabled" @click="close()" size="small">取 消</el-button>
|
<slot name="btns">
|
||||||
</slot>
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
</template>
|
<el-button type="primary" @click="confirm">确 定</el-button>
|
||||||
</dynamic-form>
|
</slot>
|
||||||
</el-dialog>
|
</span>
|
||||||
</div>
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { watch, ref, toRefs, reactive, onMounted, defineComponent } from 'vue';
|
import { ref } from 'vue';
|
||||||
import DynamicForm from './DynamicForm.vue';
|
import DynamicForm from './DynamicForm.vue';
|
||||||
export default defineComponent({
|
import { useVModel } from '@vueuse/core';
|
||||||
name: 'DynamicFormDialog',
|
|
||||||
components: {
|
|
||||||
DynamicForm,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
visible: { type: Boolean },
|
|
||||||
dialogWidth: { type: String },
|
|
||||||
title: { type: String },
|
|
||||||
formInfo: { type: Object },
|
|
||||||
formData: { type: [Object, Boolean] },
|
|
||||||
},
|
|
||||||
|
|
||||||
setup(props: any, context) {
|
const emit = defineEmits(['update:visible', 'update:modelValue', 'close', 'confirm']);
|
||||||
const df: any = ref();
|
|
||||||
|
|
||||||
const close = () => {
|
const props = defineProps({
|
||||||
// 更新父组件visible prop对应的值为false
|
title: { type: String },
|
||||||
context.emit('update:visible', false);
|
visible: { type: Boolean },
|
||||||
// 关闭窗口,则将表单数据置为null
|
width: { type: [String, Number], default: '500px' },
|
||||||
context.emit('update:formData', null);
|
formItems: { type: Array },
|
||||||
context.emit('close');
|
modelValue: { type: Object },
|
||||||
// 取消动态表单的校验以及form数据
|
|
||||||
setTimeout(() => {
|
|
||||||
df.resetFieldsAndData();
|
|
||||||
}, 200);
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitSuccess = (form: any) => {
|
|
||||||
context.emit('submitSuccess', form);
|
|
||||||
close();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
df,
|
|
||||||
close,
|
|
||||||
submitSuccess,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const df: any = ref();
|
||||||
|
|
||||||
|
const formData: any = useVModel(props, 'modelValue', emit);
|
||||||
|
const dialogVisible: any = useVModel(props, 'visible', emit);
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit('close');
|
||||||
|
// 取消动态表单的校验
|
||||||
|
setTimeout(() => {
|
||||||
|
formData.value = {};
|
||||||
|
df.value.resetFields();
|
||||||
|
}, 200);
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirm = () => {
|
||||||
|
df.value.validate((valid: any) => {
|
||||||
|
if (!valid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
emit('confirm', formData.value);
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dynamic-form-edit w100">
|
||||||
|
<el-table :data="formItems" stripe class="w100" empty-text="暂无表单项">
|
||||||
|
<el-table-column prop="name" label="model" min-width="100px">
|
||||||
|
<template #header>
|
||||||
|
<el-button class="ml0" type="primary" circle size="small" icon="Plus" @click="addItem()"> </el-button>
|
||||||
|
<span class="ml10">model</span>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row['model']" placeholder="字段model" clearable> </el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="name" label="label" min-width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row['name']" placeholder="字段title" clearable> </el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="placeholder" label="字段说明" min-width="140px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row['placeholder']" placeholder="字段说明" clearable> </el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="options" label="可选值" min-width="140px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row['options']" placeholder="可选值 ,分割" clearable> </el-input>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" wdith="20px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="danger" @click="deleteItem(scope.$index)" icon="delete" plain></el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVModel } from '@vueuse/core';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Array },
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
const formItems: any = useVModel(props, 'modelValue', emit);
|
||||||
|
|
||||||
|
const addItem = () => {
|
||||||
|
formItems.value.push({});
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteItem = (index: any) => {
|
||||||
|
formItems.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss"></style>
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export { default as DynamicForm } from './DynamicForm.vue';
|
export { default as DynamicForm } from './DynamicForm.vue';
|
||||||
export { default as DynamicFormDialog } from './DynamicFormDialog.vue';
|
export { default as DynamicFormDialog } from './DynamicFormDialog.vue';
|
||||||
|
export { default as DynamicFormEdit } from './DynamicFormEdit.vue';
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
<div class="layout-navbars-breadcrumb-user" :style="{ flex: layoutUserFlexNum }">
|
<div class="layout-navbars-breadcrumb-user" :style="{ flex: layoutUserFlexNum }">
|
||||||
<div class="layout-navbars-breadcrumb-user-icon">
|
<div class="layout-navbars-breadcrumb-user-icon">
|
||||||
<el-switch
|
<el-switch
|
||||||
@change="switchDark(state.isDark)"
|
@change="switchDark()"
|
||||||
v-model="state.isDark"
|
v-model="isDark"
|
||||||
active-action-icon="Moon"
|
active-action-icon="Moon"
|
||||||
inactive-action-icon="Sunny"
|
inactive-action-icon="Sunny"
|
||||||
style="--el-switch-off-color: #c4c9c4; --el-switch-on-color: #2c2c2c"
|
style="--el-switch-off-color: #c4c9c4; --el-switch-on-color: #2c2c2c"
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="layoutBreadcrumbUser">
|
<script setup lang="ts" name="layoutBreadcrumbUser">
|
||||||
import { ref, computed, reactive, onMounted } from 'vue';
|
import { ref, computed, reactive, onMounted, watch } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
import screenfull from 'screenfull';
|
import screenfull from 'screenfull';
|
||||||
@@ -83,17 +83,17 @@ import { resetRoute } from '@/router/index';
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useUserInfo } from '@/store/userInfo';
|
import { useUserInfo } from '@/store/userInfo';
|
||||||
import { useThemeConfig } from '@/store/themeConfig';
|
import { useThemeConfig } from '@/store/themeConfig';
|
||||||
import { clearSession, removeLocal } from '@/common/utils/storage';
|
import { clearSession } from '@/common/utils/storage';
|
||||||
import UserNews from '@/layout/navBars/breadcrumb/userNews.vue';
|
import UserNews from '@/layout/navBars/breadcrumb/userNews.vue';
|
||||||
import SearchMenu from '@/layout/navBars/breadcrumb/search.vue';
|
import SearchMenu from '@/layout/navBars/breadcrumb/search.vue';
|
||||||
import mittBus from '@/common/utils/mitt';
|
import mittBus from '@/common/utils/mitt';
|
||||||
import openApi from '@/common/openApi';
|
import openApi from '@/common/openApi';
|
||||||
import { saveThemeConfig, getThemeConfig } from '@/common/utils/storage';
|
import { saveThemeConfig, getThemeConfig } from '@/common/utils/storage';
|
||||||
|
import { useDark, usePreferredDark } from '@vueuse/core';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const searchRef = ref();
|
const searchRef = ref();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isDark: false,
|
|
||||||
isScreenfull: false,
|
isScreenfull: false,
|
||||||
isShowUserNewsPopover: false,
|
isShowUserNewsPopover: false,
|
||||||
disabledI18n: 'zh-cn',
|
disabledI18n: 'zh-cn',
|
||||||
@@ -165,8 +165,21 @@ const onHandleCommandClick = (path: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const switchDark = (isDark: boolean) => {
|
const isDark = useDark();
|
||||||
themeConfigStore.switchDark(isDark);
|
const preDark = usePreferredDark();
|
||||||
|
|
||||||
|
watch(preDark, (newValue) => {
|
||||||
|
isDark.value = newValue;
|
||||||
|
switchDark();
|
||||||
|
});
|
||||||
|
|
||||||
|
const switchDark = () => {
|
||||||
|
themeConfig.value.isDark = isDark.value;
|
||||||
|
if (isDark.value) {
|
||||||
|
themeConfig.value.editorTheme = 'vs-dark';
|
||||||
|
} else {
|
||||||
|
themeConfig.value.editorTheme = 'vs';
|
||||||
|
}
|
||||||
saveThemeConfig(themeConfig.value);
|
saveThemeConfig(themeConfig.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,14 +189,14 @@ const onSearchClick = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 组件大小改变
|
// 组件大小改变
|
||||||
const onComponentSizeChange = (size: string) => {
|
// const onComponentSizeChange = (size: string) => {
|
||||||
removeLocal('themeConfig');
|
// removeLocal('themeConfig');
|
||||||
themeConfig.value.globalComponentSize = size;
|
// themeConfig.value.globalComponentSize = size;
|
||||||
saveThemeConfig(themeConfig.value);
|
// saveThemeConfig(themeConfig.value);
|
||||||
// proxy.$ELEMENT.size = size;
|
// // proxy.$ELEMENT.size = size;
|
||||||
initComponentSize();
|
// initComponentSize();
|
||||||
window.location.reload();
|
// window.location.reload();
|
||||||
};
|
// };
|
||||||
|
|
||||||
// 初始化全局组件大小
|
// 初始化全局组件大小
|
||||||
const initComponentSize = () => {
|
const initComponentSize = () => {
|
||||||
@@ -208,7 +221,7 @@ onMounted(() => {
|
|||||||
const themeConfig = getThemeConfig();
|
const themeConfig = getThemeConfig();
|
||||||
if (themeConfig) {
|
if (themeConfig) {
|
||||||
initComponentSize();
|
initComponentSize();
|
||||||
state.isDark = themeConfig.isDark;
|
isDark.value = themeConfig.isDark;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -146,18 +146,6 @@ export const useThemeConfig = defineStore('themeConfig', {
|
|||||||
setThemeConfig(data: ThemeConfigState) {
|
setThemeConfig(data: ThemeConfigState) {
|
||||||
this.themeConfig = data.themeConfig;
|
this.themeConfig = data.themeConfig;
|
||||||
},
|
},
|
||||||
// 切换暗模式
|
|
||||||
switchDark(isDark: boolean) {
|
|
||||||
this.themeConfig.isDark = isDark;
|
|
||||||
const body = document.documentElement as HTMLElement;
|
|
||||||
if (isDark) {
|
|
||||||
body.setAttribute('class', 'dark');
|
|
||||||
this.themeConfig.editorTheme = 'vs-dark';
|
|
||||||
} else {
|
|
||||||
body.setAttribute('class', '');
|
|
||||||
this.themeConfig.editorTheme = 'vs';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 设置水印配置信息
|
// 设置水印配置信息
|
||||||
setWatermarkConfig(useWatermarkConfig: any) {
|
setWatermarkConfig(useWatermarkConfig: any) {
|
||||||
this.themeConfig.watermarkText = [];
|
this.themeConfig.watermarkText = [];
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ import { onMounted, reactive, ref, watch, toRefs, onUnmounted } from 'vue';
|
|||||||
import { NodeType, TagTreeNode } from './tag';
|
import { NodeType, TagTreeNode } from './tag';
|
||||||
import TagInfo from './TagInfo.vue';
|
import TagInfo from './TagInfo.vue';
|
||||||
import { Contextmenu } from '@/components/contextmenu';
|
import { Contextmenu } from '@/components/contextmenu';
|
||||||
import { useViewport } from '@/common/use';
|
|
||||||
import { tagApi } from '../tag/api';
|
import { tagApi } from '../tag/api';
|
||||||
|
import { useWindowSize } from '@vueuse/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
resourceType: {
|
resourceType: {
|
||||||
@@ -78,7 +78,7 @@ const emit = defineEmits(['nodeClick', 'currentContextmenuClick']);
|
|||||||
const treeRef: any = ref(null);
|
const treeRef: any = ref(null);
|
||||||
const contextmenuRef = ref();
|
const contextmenuRef = ref();
|
||||||
|
|
||||||
const { vh } = useViewport();
|
const { height: vh } = useWindowSize();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
height: 600 as any,
|
height: 600 as any,
|
||||||
|
|||||||
@@ -45,14 +45,20 @@
|
|||||||
<el-button v-auth="perms.delDb" :disabled="selectionData.length < 1" @click="deleteDb()" type="danger" icon="delete">删除</el-button>
|
<el-button v-auth="perms.delDb" :disabled="selectionData.length < 1" @click="deleteDb()" type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #tagPath="{ data }">
|
<template #type="{ data }">
|
||||||
<resource-tag :resource-code="data.code" :resource-type="TagResourceTypeEnum.Db.value" />
|
<el-tooltip :content="data.type" placement="top">
|
||||||
|
<SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
|
||||||
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #host="{ data }">
|
<template #host="{ data }">
|
||||||
{{ `${data.host}:${data.port}` }}
|
{{ `${data.host}:${data.port}` }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #tagPath="{ data }">
|
||||||
|
<resource-tag :resource-code="data.code" :resource-type="TagResourceTypeEnum.Db.value" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<span v-if="actionBtns[perms.saveDb]">
|
<span v-if="actionBtns[perms.saveDb]">
|
||||||
<el-button type="primary" @click="editDb(data)" link>编辑</el-button>
|
<el-button type="primary" @click="editDb(data)" link>编辑</el-button>
|
||||||
@@ -173,6 +179,7 @@ import { DbType } from './dialect';
|
|||||||
import { tagApi } from '../tag/api';
|
import { tagApi } from '../tag/api';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { getDbDialect } from './dialect/index';
|
||||||
|
|
||||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
||||||
|
|
||||||
@@ -186,7 +193,7 @@ const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect'), Tabl
|
|||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('instanceName', '实例名'),
|
TableColumn.new('instanceName', '实例名'),
|
||||||
TableColumn.new('type', '类型'),
|
TableColumn.new('type', '类型').isSlot().setAddWidth(-15).alignCenter(),
|
||||||
TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
|
TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
|
||||||
TableColumn.new('username', 'username'),
|
TableColumn.new('username', 'username'),
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
|
|||||||
@@ -20,6 +20,12 @@
|
|||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template #type="{ data }">
|
||||||
|
<el-tooltip :content="data.type" placement="top">
|
||||||
|
<SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<el-button @click="showInfo(data)" link>详情</el-button>
|
<el-button @click="showInfo(data)" link>详情</el-button>
|
||||||
<el-button v-if="actionBtns[perms.saveInstance]" @click="editInstance(data)" type="primary" link>编辑</el-button>
|
<el-button v-if="actionBtns[perms.saveInstance]" @click="editInstance(data)" type="primary" link>编辑</el-button>
|
||||||
@@ -66,6 +72,8 @@ import { dateFormat } from '@/common/utils/date';
|
|||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
|
import { getDbDialect } from './dialect';
|
||||||
|
|
||||||
const InstanceEdit = defineAsyncComponent(() => import('./InstanceEdit.vue'));
|
const InstanceEdit = defineAsyncComponent(() => import('./InstanceEdit.vue'));
|
||||||
|
|
||||||
@@ -78,7 +86,7 @@ const queryConfig = [TableQuery.text('name', '名称')];
|
|||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
TableColumn.new('name', '名称'),
|
TableColumn.new('name', '名称'),
|
||||||
TableColumn.new('type', '类型'),
|
TableColumn.new('type', '类型').isSlot().setAddWidth(-15).alignCenter(),
|
||||||
TableColumn.new('host', 'host:port').setFormatFunc((data: any) => `${data.host}:${data.port}`),
|
TableColumn.new('host', 'host:port').setFormatFunc((data: any) => `${data.host}:${data.port}`),
|
||||||
TableColumn.new('username', '用户名'),
|
TableColumn.new('username', '用户名'),
|
||||||
TableColumn.new('params', '连接参数'),
|
TableColumn.new('params', '连接参数'),
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ export const dbApi = {
|
|||||||
param.sql = Base64.encode(param.sql);
|
param.sql = Base64.encode(param.sql);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
sqlExecCancel: Api.newPost('/dbs/{id}/exec-sql/cancel/{execId}'),
|
|
||||||
// 保存sql
|
// 保存sql
|
||||||
saveSql: Api.newPost('/dbs/{id}/sql'),
|
saveSql: Api.newPost('/dbs/{id}/sql'),
|
||||||
// 获取保存的sql
|
// 获取保存的sql
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="float: right" class="fl">
|
<div class="fr">
|
||||||
<el-button @click="saveSql()" type="primary" icon="document-add" plain size="small">保存SQL</el-button>
|
<el-button @click="saveSql()" type="primary" icon="document-add" plain size="small">保存SQL</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { h, nextTick, onMounted, reactive, toRefs, ref } from 'vue';
|
import { h, nextTick, onMounted, reactive, toRefs, ref, onBeforeUnmount } from 'vue';
|
||||||
import { getToken } from '@/common/utils/storage';
|
import { getToken } from '@/common/utils/storage';
|
||||||
import { notBlank } from '@/common/assert';
|
import { notBlank } from '@/common/assert';
|
||||||
import { format as sqlFormatter } from 'sql-formatter';
|
import { format as sqlFormatter } from 'sql-formatter';
|
||||||
@@ -150,8 +150,8 @@ import { ElNotification } from 'element-plus';
|
|||||||
import syssocket from '@/common/syssocket';
|
import syssocket from '@/common/syssocket';
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
import { getDbDialect } from '../../dialect';
|
import { getDbDialect } from '../../dialect';
|
||||||
import { randomUuid } from '@/common/utils/string';
|
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
import { Splitpanes, Pane } from 'splitpanes';
|
||||||
|
import Api from '@/common/Api';
|
||||||
|
|
||||||
const emits = defineEmits(['saveSqlSuccess']);
|
const emits = defineEmits(['saveSqlSuccess']);
|
||||||
|
|
||||||
@@ -252,6 +252,12 @@ onMounted(async () => {
|
|||||||
await getNowDbInst().loadDbHints(props.dbName);
|
await getNowDbInst().loadDbHints(props.dbName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
state.execResTabs.forEach((x: ExecResTab) => {
|
||||||
|
Api.removeAbortKey(x.loadingKey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const onRemoveTab = (targetId: number) => {
|
const onRemoveTab = (targetId: number) => {
|
||||||
let activeTab = state.activeTab;
|
let activeTab = state.activeTab;
|
||||||
const tabs = [...state.execResTabs];
|
const tabs = [...state.execResTabs];
|
||||||
@@ -347,7 +353,8 @@ const onRunSql = async (newTab = false) => {
|
|||||||
execRes.errorMsg = '';
|
execRes.errorMsg = '';
|
||||||
execRes.sql = '';
|
execRes.sql = '';
|
||||||
|
|
||||||
const loadingKey = randomUuid();
|
// 用于取消执行
|
||||||
|
const loadingKey = Api.genAbortKey(execRes.loadingKey);
|
||||||
execRes.loadingKey = loadingKey;
|
execRes.loadingKey = loadingKey;
|
||||||
|
|
||||||
const colAndData: any = await getNowDbInst().runSql(props.dbName, sql, execRemark, loadingKey);
|
const colAndData: any = await getNowDbInst().runSql(props.dbName, sql, execRemark, loadingKey);
|
||||||
@@ -397,7 +404,7 @@ const onRunSql = async (newTab = false) => {
|
|||||||
const getSql = () => {
|
const getSql = () => {
|
||||||
let res = '' as string | undefined;
|
let res = '' as string | undefined;
|
||||||
// 编辑器还没初始化
|
// 编辑器还没初始化
|
||||||
if (!monacoEditor?.getModel) {
|
if (!monacoEditor?.getModel()) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// 选择选中的sql
|
// 选择选中的sql
|
||||||
@@ -405,6 +412,7 @@ const getSql = () => {
|
|||||||
if (selection) {
|
if (selection) {
|
||||||
res = monacoEditor.getModel()?.getValueInRange(selection);
|
res = monacoEditor.getModel()?.getValueInRange(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 整个编辑器的sql
|
// 整个编辑器的sql
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return monacoEditor.getModel()?.getValue();
|
return monacoEditor.getModel()?.getValue();
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ import { ContextmenuItem, Contextmenu } from '@/components/contextmenu';
|
|||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
import { exportCsv, exportFile } from '@/common/utils/export';
|
import { exportCsv, exportFile } from '@/common/utils/export';
|
||||||
import { dateStrFormat } from '@/common/utils/date';
|
import { dateStrFormat } from '@/common/utils/date';
|
||||||
import { dbApi } from '../../api';
|
import Api from '@/common/Api';
|
||||||
|
import { useIntervalFn } from '@vueuse/core';
|
||||||
|
|
||||||
const emits = defineEmits(['dataDelete', 'sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
const emits = defineEmits(['dataDelete', 'sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
||||||
|
|
||||||
@@ -285,7 +286,9 @@ const selectionRowsMap: Map<number, any> = new Map();
|
|||||||
const cellUpdateMap: Map<number, UpdatedRow> = new Map();
|
const cellUpdateMap: Map<number, UpdatedRow> = new Map();
|
||||||
|
|
||||||
// 数据加载时间计时器
|
// 数据加载时间计时器
|
||||||
let execTimeInterval: any = null;
|
const { pause, resume } = useIntervalFn(() => {
|
||||||
|
state.execTime += 0.1;
|
||||||
|
}, 100);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
dbId: 0, // 当前选中操作的数据库实例
|
dbId: 0, // 当前选中操作的数据库实例
|
||||||
@@ -429,22 +432,17 @@ const setTableColumns = (columns: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const startLoading = () => {
|
const startLoading = () => {
|
||||||
if (execTimeInterval) {
|
state.execTime = 0;
|
||||||
endLoading();
|
resume();
|
||||||
}
|
|
||||||
execTimeInterval = setInterval(() => {
|
|
||||||
state.execTime += 0.1; // 每秒递增执行时间
|
|
||||||
}, 100);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const endLoading = () => {
|
const endLoading = () => {
|
||||||
state.execTime = 0;
|
pause();
|
||||||
clearInterval(execTimeInterval);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelLoading = async () => {
|
const cancelLoading = async () => {
|
||||||
if (props.loadingKey) {
|
if (props.loadingKey) {
|
||||||
await dbApi.sqlExecCancel.request({ id: state.dbId, execId: props.loadingKey });
|
Api.cancelReq(props.loadingKey);
|
||||||
endLoading();
|
endLoading();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -197,9 +197,17 @@ export class DbInst {
|
|||||||
* @param remark 执行备注
|
* @param remark 执行备注
|
||||||
*/
|
*/
|
||||||
async runSql(dbName: string, sql: string, remark: string = '', key: string = '') {
|
async runSql(dbName: string, sql: string, remark: string = '', key: string = '') {
|
||||||
|
if (key) {
|
||||||
|
return await dbApi.sqlExec.allowCancelReq(key, {
|
||||||
|
id: this.id,
|
||||||
|
db: dbName,
|
||||||
|
sql: sql.trim(),
|
||||||
|
remark,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return await dbApi.sqlExec.request({
|
return await dbApi.sqlExec.request({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
execId: key,
|
|
||||||
db: dbName,
|
db: dbName,
|
||||||
sql: sql.trim(),
|
sql: sql.trim(),
|
||||||
remark,
|
remark,
|
||||||
|
|||||||
@@ -24,39 +24,17 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row style="margin-left: 30px; margin-bottom: 5px">
|
<el-form-item class="w100">
|
||||||
<el-button @click="onAddParam" type="success">新增占位符参数</el-button>
|
<template #label>
|
||||||
</el-row>
|
<el-tooltip placement="top">
|
||||||
<el-form-item :key="param" v-for="(param, index) in params" prop="params" :label="`参数${index + 1}`">
|
<template #content>
|
||||||
<el-row>
|
<span v-pre>1. 脚本内容中可使用{{.model}}作为占位符 </span>
|
||||||
<el-col :span="5">
|
<br />2. 执行脚本时可输入对应表单内容对占位符进行替换后执行
|
||||||
<el-input v-model.trim="param.model" placeholder="内容中用{{.model}}替换"></el-input>
|
</template>
|
||||||
</el-col>
|
<span> 参数<SvgIcon name="question-filled" /> </span>
|
||||||
<span :span="1">
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
</template>
|
||||||
</span>
|
<dynamic-form-edit v-model="params" />
|
||||||
<el-col :span="4">
|
|
||||||
<el-input v-model.trim="param.name" placeholder="字段名"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="4">
|
|
||||||
<el-input v-model="param.placeholder" placeholder="字段说明"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="4">
|
|
||||||
<el-input v-model="param.options" placeholder="可选值 ,分割"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="2">
|
|
||||||
<el-button @click="onDeleteParam(index)" type="danger">删除</el-button>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item required prop="script" class="100w">
|
<el-form-item required prop="script" class="100w">
|
||||||
@@ -82,6 +60,8 @@ import { ElMessage } from 'element-plus';
|
|||||||
import { machineApi } from './api';
|
import { machineApi } from './api';
|
||||||
import { ScriptResultEnum } from './enums';
|
import { ScriptResultEnum } from './enums';
|
||||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
|
import { DynamicFormEdit } from '@/components/dynamic-form';
|
||||||
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -171,14 +151,6 @@ watch(props, (newValue: any) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const onAddParam = () => {
|
|
||||||
state.params.push({ name: '', model: '', placeholder: '' });
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteParam = (idx: number) => {
|
|
||||||
state.params.splice(idx, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const btnOk = () => {
|
const btnOk = () => {
|
||||||
state.form.machineId = isCommon.value ? 9999999 : (machineId?.value as any);
|
state.form.machineId = isCommon.value ? 9999999 : (machineId?.value as any);
|
||||||
scriptForm.value.validate((valid: any) => {
|
scriptForm.value.validate((valid: any) => {
|
||||||
|
|||||||
@@ -45,35 +45,16 @@
|
|||||||
</page-table>
|
</page-table>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog title="脚本参数" v-model="scriptParamsDialog.visible" width="400px">
|
<dynamic-form-dialog
|
||||||
<el-form ref="paramsForm" :model="scriptParamsDialog.params" label-width="auto">
|
title="脚本参数"
|
||||||
<el-form-item v-for="item in scriptParamsDialog.paramsFormItem as any" :key="item.name" :prop="item.model" :label="item.name" required>
|
width="400px"
|
||||||
<el-input
|
v-model:visible="scriptParamsDialog.visible"
|
||||||
v-if="!item.options"
|
ref="paramsForm"
|
||||||
v-model="scriptParamsDialog.params[item.model]"
|
:form-items="scriptParamsDialog.paramsFormItem"
|
||||||
:placeholder="item.placeholder"
|
v-model="scriptParamsDialog.params"
|
||||||
autocomplete="off"
|
@confirm="hasParamsRun"
|
||||||
clearable
|
>
|
||||||
></el-input>
|
</dynamic-form-dialog>
|
||||||
<el-select
|
|
||||||
v-else
|
|
||||||
v-model="scriptParamsDialog.params[item.model]"
|
|
||||||
:placeholder="item.placeholder"
|
|
||||||
filterable
|
|
||||||
autocomplete="off"
|
|
||||||
clearable
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option v-for="option in item.options.split(',')" :key="option" :label="option" :value="option" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button type="primary" @click="hasParamsRun()">确 定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<el-dialog title="执行结果" v-model="resultDialog.visible" width="50%">
|
<el-dialog title="执行结果" v-model="resultDialog.visible" width="50%">
|
||||||
<div style="white-space: pre-line; padding: 10px; color: #000000">
|
<div style="white-space: pre-line; padding: 10px; color: #000000">
|
||||||
@@ -115,6 +96,7 @@ import { ScriptResultEnum, ScriptTypeEnum } from './enums';
|
|||||||
import ScriptEdit from './ScriptEdit.vue';
|
import ScriptEdit from './ScriptEdit.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||||
|
import { DynamicFormDialog } from '@/components/dynamic-form';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: { type: Boolean },
|
visible: { type: Boolean },
|
||||||
@@ -204,20 +186,9 @@ const runScript = async (script: any) => {
|
|||||||
|
|
||||||
// 有参数的脚本执行函数
|
// 有参数的脚本执行函数
|
||||||
const hasParamsRun = async () => {
|
const hasParamsRun = async () => {
|
||||||
// 如果脚本参数弹窗显示,则校验参数表单数据通过后执行
|
await run(state.scriptParamsDialog.script);
|
||||||
if (state.scriptParamsDialog.visible) {
|
state.scriptParamsDialog.visible = false;
|
||||||
paramsForm.value.validate((valid: any) => {
|
state.scriptParamsDialog.script = null;
|
||||||
if (valid) {
|
|
||||||
run(state.scriptParamsDialog.script);
|
|
||||||
state.scriptParamsDialog.params = {};
|
|
||||||
state.scriptParamsDialog.visible = false;
|
|
||||||
state.scriptParamsDialog.script = null;
|
|
||||||
paramsForm.value.resetFields();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const run = async (script: any) => {
|
const run = async (script: any) => {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
:on-success="uploadSuccess"
|
:on-success="uploadSuccess"
|
||||||
action=""
|
action=""
|
||||||
:http-request="getUploadFile"
|
:http-request="uploadFile"
|
||||||
:headers="{ token }"
|
:headers="{ token }"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
name="file"
|
name="file"
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
ref="folderUploadRef"
|
ref="folderUploadRef"
|
||||||
webkitdirectory
|
webkitdirectory
|
||||||
directory
|
directory
|
||||||
@change="getFolder"
|
@change="uploadFolder"
|
||||||
style="display: none"
|
style="display: none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
|
|
||||||
<el-table-column prop="size" label="大小" width="100" sortable>
|
<el-table-column prop="size" label="大小" width="100" sortable>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == '-'"> {{ formatFileSize(scope.row.size) }} </span>
|
<span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == '-'"> {{ formatByteSize(scope.row.size) }} </span>
|
||||||
<span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == 'd' && scope.row.dirSize"> {{ scope.row.dirSize }} </span>
|
<span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == 'd' && scope.row.dirSize"> {{ scope.row.dirSize }} </span>
|
||||||
<span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == 'd' && !scope.row.dirSize">
|
<span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == 'd' && !scope.row.dirSize">
|
||||||
<el-button @click="getDirSize(scope.row)" type="primary" link :loading="scope.row.loadingDirSize">计算</el-button>
|
<el-button @click="getDirSize(scope.row)" type="primary" link :loading="scope.row.loadingDirSize">计算</el-button>
|
||||||
@@ -280,6 +280,8 @@ import { isTrue } from '@/common/assert';
|
|||||||
import MachineFileContent from './MachineFileContent.vue';
|
import MachineFileContent from './MachineFileContent.vue';
|
||||||
import { notBlank } from '@/common/assert';
|
import { notBlank } from '@/common/assert';
|
||||||
import { getToken } from '@/common/utils/storage';
|
import { getToken } from '@/common/utils/storage';
|
||||||
|
import { formatByteSize, convertToBytes } from '@/common/utils/format';
|
||||||
|
import { getMachineConfig } from '@/common/sysconfig';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
machineId: { type: Number },
|
machineId: { type: Number },
|
||||||
@@ -326,14 +328,15 @@ const state = reactive({
|
|||||||
type: folderType,
|
type: folderType,
|
||||||
data: null as any,
|
data: null as any,
|
||||||
},
|
},
|
||||||
file: null as any,
|
machineConfig: { uploadMaxFileSize: '1GB' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { basePath, nowPath, loading, fileNameFilter, progressNum, uploadProgressShow, fileContent, createFileDialog } = toRefs(state);
|
const { basePath, nowPath, loading, fileNameFilter, progressNum, uploadProgressShow, fileContent, createFileDialog } = toRefs(state);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
state.basePath = props.path;
|
state.basePath = props.path;
|
||||||
setFiles(props.path);
|
setFiles(props.path);
|
||||||
|
state.machineConfig = await getMachineConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
const filterFiles = computed(() =>
|
const filterFiles = computed(() =>
|
||||||
@@ -616,16 +619,24 @@ function addFinderToList() {
|
|||||||
folderUploadRef.value.click();
|
folderUploadRef.value.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFolder(e: any) {
|
function uploadFolder(e: any) {
|
||||||
//e.target.files为文件夹里面的文件
|
//e.target.files为文件夹里面的文件
|
||||||
// 把文件夹数据放到formData里面,下面的files和paths字段根据接口来定
|
// 把文件夹数据放到formData里面,下面的files和paths字段根据接口来定
|
||||||
var form = new FormData();
|
var form = new FormData();
|
||||||
form.append('basePath', state.nowPath);
|
form.append('basePath', state.nowPath);
|
||||||
|
|
||||||
|
let totalFileSize = 0;
|
||||||
for (let file of e.target.files) {
|
for (let file of e.target.files) {
|
||||||
|
totalFileSize += file.size;
|
||||||
form.append('files', file);
|
form.append('files', file);
|
||||||
form.append('paths', file.webkitRelativePath);
|
form.append('paths', file.webkitRelativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (!checkUploadFileSize(totalFileSize)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 上传操作
|
// 上传操作
|
||||||
machineApi.uploadFile
|
machineApi.uploadFile
|
||||||
.request(form, {
|
.request(form, {
|
||||||
@@ -660,7 +671,7 @@ const onUploadProgress = (progressEvent: any) => {
|
|||||||
state.progressNum = complete;
|
state.progressNum = complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUploadFile = (content: any) => {
|
const uploadFile = (content: any) => {
|
||||||
const params = new FormData();
|
const params = new FormData();
|
||||||
const path = state.nowPath;
|
const path = state.nowPath;
|
||||||
params.append('file', content.file);
|
params.append('file', content.file);
|
||||||
@@ -695,7 +706,16 @@ const uploadSuccess = (res: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const beforeUpload = (file: File) => {
|
const beforeUpload = (file: File) => {
|
||||||
state.file = file;
|
return checkUploadFileSize(file.size);
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkUploadFileSize = (fileSize: number) => {
|
||||||
|
const bytes = convertToBytes(state.machineConfig.uploadMaxFileSize);
|
||||||
|
if (fileSize > bytes) {
|
||||||
|
ElMessage.error(`上传的文件超过系统配置的[${state.machineConfig.uploadMaxFileSize}]`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const dontOperate = (data: any) => {
|
const dontOperate = (data: any) => {
|
||||||
@@ -704,27 +724,6 @@ const dontOperate = (data: any) => {
|
|||||||
return ls.indexOf(path) != -1;
|
return ls.indexOf(path) != -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化文件大小
|
|
||||||
* @param {*} value
|
|
||||||
*/
|
|
||||||
const formatFileSize = (size: any) => {
|
|
||||||
const value = Number(size);
|
|
||||||
if (size && !isNaN(value)) {
|
|
||||||
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'BB'];
|
|
||||||
let index = 0;
|
|
||||||
let k = value;
|
|
||||||
if (value >= 1024) {
|
|
||||||
while (k > 1024) {
|
|
||||||
k = k / 1024;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return `${k.toFixed(2)}${units[index]}`;
|
|
||||||
}
|
|
||||||
return '-';
|
|
||||||
};
|
|
||||||
|
|
||||||
defineExpose({ showFileContent });
|
defineExpose({ showFileContent });
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-dialog :title="title" v-model="dvisible" :show-close="false" :before-close="cancel" width="750px" :destroy-on-close="true">
|
<el-dialog :title="title" v-model="dvisible" :show-close="false" :before-close="cancel" width="900px" :destroy-on-close="true">
|
||||||
<el-form ref="configForm" :model="form" label-width="auto">
|
<el-form ref="configForm" :model="form" label-width="auto">
|
||||||
<el-form-item prop="name" label="配置项" required>
|
<el-form-item prop="name" label="配置项" required>
|
||||||
<el-input v-model="form.name"></el-input>
|
<el-input v-model="form.name"></el-input>
|
||||||
@@ -22,43 +22,10 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row style="margin-left: 30px; margin-bottom: 5px">
|
<el-form-item label="配置项" class="w100">
|
||||||
<el-button @click="onAddParam" size="small" type="success">新增配置项</el-button>
|
<dynamic-form-edit v-model="params" />
|
||||||
</el-row>
|
|
||||||
<el-form-item :key="param" v-for="(param, index) in params" prop="params" :label="`参数${index + 1}`">
|
|
||||||
<el-row>
|
|
||||||
<el-col :span="5">
|
|
||||||
<el-input v-model="param.model" placeholder="model"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="4">
|
|
||||||
<el-input v-model="param.name" placeholder="字段名"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="4">
|
|
||||||
<el-input v-model="param.placeholder" placeholder="字段说明"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="4">
|
|
||||||
<el-input v-model="param.options" placeholder="可选值 ,分割"></el-input>
|
|
||||||
</el-col>
|
|
||||||
<span :span="1">
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
</span>
|
|
||||||
<el-col :span="2">
|
|
||||||
<el-button @click="onDeleteParam(index)" size="small" type="danger">删除</el-button>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- <el-form-item prop="value" label="配置值:" required>
|
|
||||||
<el-input v-model="form.value"></el-input>
|
|
||||||
</el-form-item> -->
|
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input v-model="form.remark" type="textarea" :rows="2"></el-input>
|
<el-input v-model="form.remark" type="textarea" :rows="2"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -76,6 +43,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, toRefs, reactive, watch } from 'vue';
|
import { ref, toRefs, reactive, watch } from 'vue';
|
||||||
import { configApi, accountApi } from '../api';
|
import { configApi, accountApi } from '../api';
|
||||||
|
import { DynamicFormEdit } from '@/components/dynamic-form';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -139,14 +107,6 @@ watch(props, (newValue: any) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const onAddParam = () => {
|
|
||||||
state.params.push({ name: '', model: '', placeholder: '' });
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteParam = (idx: number) => {
|
|
||||||
state.params.splice(idx, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
// 更新父组件visible prop对应的值为false
|
// 更新父组件visible prop对应的值为false
|
||||||
emit('update:visible', false);
|
emit('update:visible', false);
|
||||||
|
|||||||
@@ -25,41 +25,20 @@
|
|||||||
</template>
|
</template>
|
||||||
</page-table>
|
</page-table>
|
||||||
|
|
||||||
<el-dialog :before-close="closeSetConfigDialog" title="配置项设置" v-model="paramsDialog.visible" width="600px">
|
<el-dialog @close="closeSetConfigDialog" title="配置项设置" v-model="paramsDialog.visible" width="600px">
|
||||||
<el-form v-if="paramsDialog.paramsFormItem.length > 0" ref="paramsFormRef" :model="paramsDialog.params" label-width="auto">
|
<dynamic-form
|
||||||
<el-form-item v-for="item in paramsDialog.paramsFormItem" :key="item.name" :prop="item.model" :label="item.name" required>
|
ref="paramsFormRef"
|
||||||
<el-input
|
v-if="paramsDialog.paramsFormItem.length > 0"
|
||||||
v-if="!item.options && !item.type"
|
:form-items="paramsDialog.paramsFormItem"
|
||||||
v-model="paramsDialog.params[item.model]"
|
v-model="paramsDialog.params"
|
||||||
:placeholder="item.placeholder"
|
/>
|
||||||
autocomplete="off"
|
|
||||||
clearable
|
|
||||||
></el-input>
|
|
||||||
<el-checkbox
|
|
||||||
v-else-if="item.type == 'checkbox'"
|
|
||||||
v-model="paramsDialog.params[item.model]"
|
|
||||||
autocomplete="off"
|
|
||||||
:label="item.placeholder"
|
|
||||||
clearable
|
|
||||||
/>
|
|
||||||
<el-select
|
|
||||||
v-else
|
|
||||||
v-model="paramsDialog.params[item.model]"
|
|
||||||
:placeholder="item.placeholder"
|
|
||||||
filterable
|
|
||||||
autocomplete="off"
|
|
||||||
clearable
|
|
||||||
style="width: 100%"
|
|
||||||
>
|
|
||||||
<el-option v-for="option in item.options.split(',')" :key="option" :label="option" :value="option" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<el-form v-else ref="paramsFormRef" label-width="auto">
|
<el-form v-else ref="paramsFormRef" label-width="auto">
|
||||||
<el-form-item label="配置值" required>
|
<el-form-item label="配置值" required>
|
||||||
<el-input v-model="paramsDialog.params" :placeholder="paramsDialog.config.remark" autocomplete="off" clearable></el-input>
|
<el-input v-model="paramsDialog.params" :placeholder="paramsDialog.config.remark" autocomplete="off" clearable></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="closeSetConfigDialog()">取 消</el-button>
|
<el-button @click="closeSetConfigDialog()">取 消</el-button>
|
||||||
@@ -80,6 +59,7 @@ import { ElMessage } from 'element-plus';
|
|||||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||||
import { TableColumn } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
import { hasPerms } from '@/components/auth/auth';
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
import { DynamicForm } from '@/components/dynamic-form';
|
||||||
|
|
||||||
const perms = {
|
const perms = {
|
||||||
saveConfig: 'config:save',
|
saveConfig: 'config:save',
|
||||||
@@ -163,7 +143,7 @@ const closeSetConfigDialog = () => {
|
|||||||
const setConfig = async () => {
|
const setConfig = async () => {
|
||||||
let paramsValue = state.paramsDialog.params;
|
let paramsValue = state.paramsDialog.params;
|
||||||
if (state.paramsDialog.paramsFormItem.length > 0) {
|
if (state.paramsDialog.paramsFormItem.length > 0) {
|
||||||
await paramsFormRef.value.validate(async (valid: boolean) => {
|
await paramsFormRef.value.validate((valid: boolean) => {
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
paramsValue = null as any;
|
paramsValue = null as any;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -345,6 +345,11 @@
|
|||||||
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz"
|
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz"
|
||||||
integrity sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA==
|
integrity sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA==
|
||||||
|
|
||||||
|
"@types/web-bluetooth@^0.0.20":
|
||||||
|
version "0.0.20"
|
||||||
|
resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz#f066abfcd1cbe66267cdbbf0de010d8a41b41597"
|
||||||
|
integrity sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^6.7.4":
|
"@typescript-eslint/eslint-plugin@^6.7.4":
|
||||||
version "6.7.4"
|
version "6.7.4"
|
||||||
resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d"
|
resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d"
|
||||||
@@ -445,6 +450,16 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
source-map-js "^1.0.2"
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
|
"@vue/compiler-core@3.3.11":
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.3.11.tgz#9fa26f8c81b9b34365f94ce1ed4d0e6e6f94a2ac"
|
||||||
|
integrity sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.23.5"
|
||||||
|
"@vue/shared" "3.3.11"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
"@vue/compiler-dom@3.3.10":
|
"@vue/compiler-dom@3.3.10":
|
||||||
version "3.3.10"
|
version "3.3.10"
|
||||||
resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.3.10.tgz#183811252be6aff4ac923f783124bb1590301907"
|
resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.3.10.tgz#183811252be6aff4ac923f783124bb1590301907"
|
||||||
@@ -453,7 +468,31 @@
|
|||||||
"@vue/compiler-core" "3.3.10"
|
"@vue/compiler-core" "3.3.10"
|
||||||
"@vue/shared" "3.3.10"
|
"@vue/shared" "3.3.10"
|
||||||
|
|
||||||
"@vue/compiler-sfc@3.3.10", "@vue/compiler-sfc@^3.3.10":
|
"@vue/compiler-dom@3.3.11":
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.3.11.tgz#36a76ea3a296d41bad133a6912cb0a847d969e4f"
|
||||||
|
integrity sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-core" "3.3.11"
|
||||||
|
"@vue/shared" "3.3.11"
|
||||||
|
|
||||||
|
"@vue/compiler-sfc@3.3.11":
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.3.11.tgz#acfae240c875d067e0e2c9a4e2d910074408c73b"
|
||||||
|
integrity sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/parser" "^7.23.5"
|
||||||
|
"@vue/compiler-core" "3.3.11"
|
||||||
|
"@vue/compiler-dom" "3.3.11"
|
||||||
|
"@vue/compiler-ssr" "3.3.11"
|
||||||
|
"@vue/reactivity-transform" "3.3.11"
|
||||||
|
"@vue/shared" "3.3.11"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
magic-string "^0.30.5"
|
||||||
|
postcss "^8.4.32"
|
||||||
|
source-map-js "^1.0.2"
|
||||||
|
|
||||||
|
"@vue/compiler-sfc@^3.3.10":
|
||||||
version "3.3.10"
|
version "3.3.10"
|
||||||
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.3.10.tgz#8eb97d42f276089ec58fd0565ef3a813bceeaa87"
|
resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.3.10.tgz#8eb97d42f276089ec58fd0565ef3a813bceeaa87"
|
||||||
integrity sha512-xpcTe7Rw7QefOTRFFTlcfzozccvjM40dT45JtrE3onGm/jBLZ0JhpKu3jkV7rbDFLeeagR/5RlJ2Y9SvyS0lAg==
|
integrity sha512-xpcTe7Rw7QefOTRFFTlcfzozccvjM40dT45JtrE3onGm/jBLZ0JhpKu3jkV7rbDFLeeagR/5RlJ2Y9SvyS0lAg==
|
||||||
@@ -477,6 +516,14 @@
|
|||||||
"@vue/compiler-dom" "3.3.10"
|
"@vue/compiler-dom" "3.3.10"
|
||||||
"@vue/shared" "3.3.10"
|
"@vue/shared" "3.3.10"
|
||||||
|
|
||||||
|
"@vue/compiler-ssr@3.3.11":
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.3.11.tgz#598942a73b64f2bd3f95908b104a7fbb55fc41a2"
|
||||||
|
integrity sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==
|
||||||
|
dependencies:
|
||||||
|
"@vue/compiler-dom" "3.3.11"
|
||||||
|
"@vue/shared" "3.3.11"
|
||||||
|
|
||||||
"@vue/devtools-api@^6.5.0":
|
"@vue/devtools-api@^6.5.0":
|
||||||
version "6.5.0"
|
version "6.5.0"
|
||||||
resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
|
resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07"
|
||||||
@@ -493,43 +540,69 @@
|
|||||||
estree-walker "^2.0.2"
|
estree-walker "^2.0.2"
|
||||||
magic-string "^0.30.5"
|
magic-string "^0.30.5"
|
||||||
|
|
||||||
"@vue/reactivity@3.3.10":
|
"@vue/reactivity-transform@3.3.11":
|
||||||
version "3.3.10"
|
version "3.3.11"
|
||||||
resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.3.10.tgz#78fe3da319276d9e6d0f072037532928c472a287"
|
resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.3.11.tgz#2bd486f4eff60c8724309925618891e722fcfadc"
|
||||||
integrity sha512-H5Z7rOY/JLO+e5a6/FEXaQ1TMuOvY4LDVgT+/+HKubEAgs9qeeZ+NhADSeEtrNQeiKLDuzeKc8v0CUFpB6Pqgw==
|
integrity sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/shared" "3.3.10"
|
"@babel/parser" "^7.23.5"
|
||||||
|
"@vue/compiler-core" "3.3.11"
|
||||||
|
"@vue/shared" "3.3.11"
|
||||||
|
estree-walker "^2.0.2"
|
||||||
|
magic-string "^0.30.5"
|
||||||
|
|
||||||
"@vue/runtime-core@3.3.10":
|
"@vue/reactivity@3.3.11":
|
||||||
version "3.3.10"
|
version "3.3.11"
|
||||||
resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.3.10.tgz#d7b78c5c0500b856cf9447ef81d4a1b1438fd5bb"
|
resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.3.11.tgz#91f8e6c9ac60a595a5278c836b197628fd947a0d"
|
||||||
integrity sha512-DZ0v31oTN4YHX9JEU5VW1LoIVgFovWgIVb30bWn9DG9a7oA415idcwsRNNajqTx8HQJyOaWfRKoyuP2P2TYIag==
|
integrity sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/reactivity" "3.3.10"
|
"@vue/shared" "3.3.11"
|
||||||
"@vue/shared" "3.3.10"
|
|
||||||
|
|
||||||
"@vue/runtime-dom@3.3.10":
|
"@vue/runtime-core@3.3.11":
|
||||||
version "3.3.10"
|
version "3.3.11"
|
||||||
resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.3.10.tgz#130dfffb8fee8051671aaf80c5104d2020544950"
|
resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.3.11.tgz#63defba57bc54c1dac68a95b56c2633b1419193d"
|
||||||
integrity sha512-c/jKb3ny05KJcYk0j1m7Wbhrxq7mZYr06GhKykDMNRRR9S+/dGT8KpHuNQjv3/8U4JshfkAk6TpecPD3B21Ijw==
|
integrity sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/runtime-core" "3.3.10"
|
"@vue/reactivity" "3.3.11"
|
||||||
"@vue/shared" "3.3.10"
|
"@vue/shared" "3.3.11"
|
||||||
|
|
||||||
|
"@vue/runtime-dom@3.3.11":
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.3.11.tgz#1146d8d280b0fec4d2e18c4a4c8f8121d0cecc09"
|
||||||
|
integrity sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==
|
||||||
|
dependencies:
|
||||||
|
"@vue/runtime-core" "3.3.11"
|
||||||
|
"@vue/shared" "3.3.11"
|
||||||
csstype "^3.1.2"
|
csstype "^3.1.2"
|
||||||
|
|
||||||
"@vue/server-renderer@3.3.10":
|
"@vue/server-renderer@3.3.11":
|
||||||
version "3.3.10"
|
version "3.3.11"
|
||||||
resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.3.10.tgz#f23d151f0e5021ebdc730052d9934c9178486742"
|
resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.3.11.tgz#409aed8031a125791e2143552975ecd1958ad601"
|
||||||
integrity sha512-0i6ww3sBV3SKlF3YTjSVqKQ74xialMbjVYGy7cOTi7Imd8ediE7t72SK3qnvhrTAhOvlQhq6Bk6nFPdXxe0sAg==
|
integrity sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/compiler-ssr" "3.3.10"
|
"@vue/compiler-ssr" "3.3.11"
|
||||||
"@vue/shared" "3.3.10"
|
"@vue/shared" "3.3.11"
|
||||||
|
|
||||||
"@vue/shared@3.3.10":
|
"@vue/shared@3.3.10":
|
||||||
version "3.3.10"
|
version "3.3.10"
|
||||||
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.10.tgz#1583a8d85a957d8b819078c465d2a11db7914b2f"
|
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.10.tgz#1583a8d85a957d8b819078c465d2a11db7914b2f"
|
||||||
integrity sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==
|
integrity sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw==
|
||||||
|
|
||||||
|
"@vue/shared@3.3.11":
|
||||||
|
version "3.3.11"
|
||||||
|
resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.11.tgz#f6a038e15237edefcc90dbfe7edb806dd355c7bd"
|
||||||
|
integrity sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==
|
||||||
|
|
||||||
|
"@vueuse/core@^10.7.0":
|
||||||
|
version "10.7.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-10.7.0.tgz#34f2f02f179dc0dcffc2be70d6b1233e011404b9"
|
||||||
|
integrity sha512-4EUDESCHtwu44ZWK3Gc/hZUVhVo/ysvdtwocB5vcauSV4B7NiGY5972WnsojB3vRNdxvAt7kzJWE2h9h7C9d5w==
|
||||||
|
dependencies:
|
||||||
|
"@types/web-bluetooth" "^0.0.20"
|
||||||
|
"@vueuse/metadata" "10.7.0"
|
||||||
|
"@vueuse/shared" "10.7.0"
|
||||||
|
vue-demi ">=0.14.6"
|
||||||
|
|
||||||
"@vueuse/core@^9.1.0":
|
"@vueuse/core@^9.1.0":
|
||||||
version "9.2.0"
|
version "9.2.0"
|
||||||
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.2.0.tgz"
|
resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.2.0.tgz"
|
||||||
@@ -540,11 +613,23 @@
|
|||||||
"@vueuse/shared" "9.2.0"
|
"@vueuse/shared" "9.2.0"
|
||||||
vue-demi "*"
|
vue-demi "*"
|
||||||
|
|
||||||
|
"@vueuse/metadata@10.7.0":
|
||||||
|
version "10.7.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-10.7.0.tgz#7b05e6cfd376aa9bb339a81e16a89c12f3e88c03"
|
||||||
|
integrity sha512-GlaH7tKP2iBCZ3bHNZ6b0cl9g0CJK8lttkBNUX156gWvNYhTKEtbweWLm9rxCPIiwzYcr/5xML6T8ZUEt+DkvA==
|
||||||
|
|
||||||
"@vueuse/metadata@9.2.0":
|
"@vueuse/metadata@9.2.0":
|
||||||
version "9.2.0"
|
version "9.2.0"
|
||||||
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.2.0.tgz"
|
resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.2.0.tgz"
|
||||||
integrity sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw==
|
integrity sha512-exN4KE6iquxDCdt72BgEhb3tlOpECtD61AUdXnUqBTIUCl70x1Ar/QXo3bYcvxmdMS2/peQyfeTzBjRTpvL5xw==
|
||||||
|
|
||||||
|
"@vueuse/shared@10.7.0":
|
||||||
|
version "10.7.0"
|
||||||
|
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-10.7.0.tgz#21e425cc5ede421e0cda38ac59a0beee6da86b1b"
|
||||||
|
integrity sha512-kc00uV6CiaTdc3i1CDC4a3lBxzaBE9AgYNtFN87B5OOscqeWElj/uza8qVDmk7/U8JbqoONLbtqiLJ5LGRuqlw==
|
||||||
|
dependencies:
|
||||||
|
vue-demi ">=0.14.6"
|
||||||
|
|
||||||
"@vueuse/shared@9.2.0":
|
"@vueuse/shared@9.2.0":
|
||||||
version "9.2.0"
|
version "9.2.0"
|
||||||
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.2.0.tgz"
|
resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.2.0.tgz"
|
||||||
@@ -1419,10 +1504,10 @@ mitt@^3.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
|
resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
|
||||||
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
|
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
|
||||||
|
|
||||||
monaco-editor@^0.44.0:
|
monaco-editor@^0.45.0:
|
||||||
version "0.44.0"
|
version "0.45.0"
|
||||||
resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.44.0.tgz#3c0fe3655923bbf7dd647057302070b5095b6c59"
|
resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.45.0.tgz#6939123a6254aea9fea2d647697f846306dd4448"
|
||||||
integrity sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==
|
integrity sha512-mjv1G1ZzfEE3k9HZN0dQ2olMdwIfaeAAjFiwNprLfYNRSz7ctv9XuCT7gPtBGrMUeV1/iZzYKj17Khu1hxoHOA==
|
||||||
|
|
||||||
monaco-sql-languages@^0.11.0:
|
monaco-sql-languages@^0.11.0:
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
@@ -1859,10 +1944,10 @@ uuid@^9.0.1:
|
|||||||
resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
resolved "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
||||||
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
||||||
|
|
||||||
vite@^5.0.5:
|
vite@^5.0.7:
|
||||||
version "5.0.5"
|
version "5.0.7"
|
||||||
resolved "https://registry.npmmirror.com/vite/-/vite-5.0.5.tgz#3eebe3698e3b32cea36350f58879258fec858a3c"
|
resolved "https://registry.npmmirror.com/vite/-/vite-5.0.7.tgz#ad081d735f6769f76b556818500bdafb72c3fe93"
|
||||||
integrity sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg==
|
integrity sha512-B4T4rJCDPihrQo2B+h1MbeGL/k/GMAHzhQ8S0LjQ142s6/+l3hHTT095ORvsshj4QCkoWu3Xtmob5mazvakaOw==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.19.3"
|
esbuild "^0.19.3"
|
||||||
postcss "^8.4.32"
|
postcss "^8.4.32"
|
||||||
@@ -1880,6 +1965,11 @@ vue-demi@>=0.14.5:
|
|||||||
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9"
|
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9"
|
||||||
integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
|
integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
|
||||||
|
|
||||||
|
vue-demi@>=0.14.6:
|
||||||
|
version "0.14.6"
|
||||||
|
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz#dc706582851dc1cdc17a0054f4fec2eb6df74c92"
|
||||||
|
integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==
|
||||||
|
|
||||||
vue-eslint-parser@^9.3.1:
|
vue-eslint-parser@^9.3.1:
|
||||||
version "9.3.1"
|
version "9.3.1"
|
||||||
resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz#429955e041ae5371df5f9e37ebc29ba046496182"
|
resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz#429955e041ae5371df5f9e37ebc29ba046496182"
|
||||||
@@ -1913,16 +2003,16 @@ vue-router@^4.2.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@vue/devtools-api" "^6.5.0"
|
"@vue/devtools-api" "^6.5.0"
|
||||||
|
|
||||||
vue@^3.3.10:
|
vue@^3.3.11:
|
||||||
version "3.3.10"
|
version "3.3.11"
|
||||||
resolved "https://registry.npmmirror.com/vue/-/vue-3.3.10.tgz#6e19c1982ee655a14babe1610288b90005f02ab1"
|
resolved "https://registry.npmmirror.com/vue/-/vue-3.3.11.tgz#898d97025f73cdb5fc4e3ae3fd07a54615232140"
|
||||||
integrity sha512-zg6SIXZdTBwiqCw/1p+m04VyHjLfwtjwz8N57sPaBhEex31ND0RYECVOC1YrRwMRmxFf5T1dabl6SGUbMKKuVw==
|
integrity sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vue/compiler-dom" "3.3.10"
|
"@vue/compiler-dom" "3.3.11"
|
||||||
"@vue/compiler-sfc" "3.3.10"
|
"@vue/compiler-sfc" "3.3.11"
|
||||||
"@vue/runtime-dom" "3.3.10"
|
"@vue/runtime-dom" "3.3.11"
|
||||||
"@vue/server-renderer" "3.3.10"
|
"@vue/server-renderer" "3.3.11"
|
||||||
"@vue/shared" "3.3.10"
|
"@vue/shared" "3.3.11"
|
||||||
|
|
||||||
which@^2.0.1:
|
which@^2.0.1:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
"mayfly-go/pkg/ws"
|
"mayfly-go/pkg/ws"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -84,9 +83,6 @@ func (d *Db) DeleteDb(rc *req.Ctx) {
|
|||||||
|
|
||||||
/** 数据库操作相关、执行sql等 ***/
|
/** 数据库操作相关、执行sql等 ***/
|
||||||
|
|
||||||
// 取消执行sql函数map; key -> execId ; value -> cancelFunc
|
|
||||||
var cancelExecSqlMap = sync.Map{}
|
|
||||||
|
|
||||||
func (d *Db) ExecSql(rc *req.Ctx) {
|
func (d *Db) ExecSql(rc *req.Ctx) {
|
||||||
g := rc.GinCtx
|
g := rc.GinCtx
|
||||||
form := &form.DbSqlExecForm{}
|
form := &form.DbSqlExecForm{}
|
||||||
@@ -112,14 +108,9 @@ func (d *Db) ExecSql(rc *req.Ctx) {
|
|||||||
DbConn: dbConn,
|
DbConn: dbConn,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := rc.MetaCtx
|
// 比前端超时时间稍微快一点,可以提示到前端
|
||||||
// 如果存在执行id,则保存取消函数,用于后续可能的取消操作
|
ctx, cancel := context.WithTimeout(rc.MetaCtx, 58*time.Second)
|
||||||
if form.ExecId != "" {
|
defer cancel()
|
||||||
cancelCtx, cancel := context.WithTimeout(rc.MetaCtx, 55*time.Second)
|
|
||||||
ctx = cancelCtx
|
|
||||||
cancelExecSqlMap.Store(form.ExecId, cancel)
|
|
||||||
defer cancelExecSqlMap.Delete(form.ExecId)
|
|
||||||
}
|
|
||||||
|
|
||||||
sqls, err := sqlparser.SplitStatementToPieces(sql, sqlparser.WithDialect(dbConn.Info.Type.Dialect()))
|
sqls, err := sqlparser.SplitStatementToPieces(sql, sqlparser.WithDialect(dbConn.Info.Type.Dialect()))
|
||||||
biz.ErrIsNil(err, "SQL解析错误,请检查您的执行SQL")
|
biz.ErrIsNil(err, "SQL解析错误,请检查您的执行SQL")
|
||||||
@@ -150,14 +141,6 @@ func (d *Db) ExecSql(rc *req.Ctx) {
|
|||||||
rc.ResData = colAndRes
|
rc.ResData = colAndRes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Db) CancelExecSql(rc *req.Ctx) {
|
|
||||||
execId := ginx.PathParam(rc.GinCtx, "execId")
|
|
||||||
if cancelFunc, ok := cancelExecSqlMap.LoadAndDelete(execId); ok {
|
|
||||||
rc.ReqParam = execId
|
|
||||||
cancelFunc.(context.CancelFunc)()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// progressCategory sql文件执行进度消息类型
|
// progressCategory sql文件执行进度消息类型
|
||||||
const progressCategory = "execSqlFileProgress"
|
const progressCategory = "execSqlFileProgress"
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ func InitDbRouter(router *gin.RouterGroup) {
|
|||||||
|
|
||||||
req.NewPost(":dbId/exec-sql", d.ExecSql).Log(req.NewLog("db-执行Sql")),
|
req.NewPost(":dbId/exec-sql", d.ExecSql).Log(req.NewLog("db-执行Sql")),
|
||||||
|
|
||||||
req.NewPost(":dbId/exec-sql/cancel/:execId", d.CancelExecSql).Log(req.NewLog("db-取消执行Sql")),
|
|
||||||
|
|
||||||
req.NewPost(":dbId/exec-sql-file", d.ExecSqlFile).Log(req.NewLogSave("db-执行Sql文件")),
|
req.NewPost(":dbId/exec-sql-file", d.ExecSqlFile).Log(req.NewLogSave("db-执行Sql文件")),
|
||||||
|
|
||||||
req.NewGet(":dbId/dump", d.DumpSql).Log(req.NewLogSave("db-导出sql文件")).NoRes(),
|
req.NewGet(":dbId/dump", d.DumpSql).Log(req.NewLogSave("db-导出sql文件")).NoRes(),
|
||||||
|
|||||||
Reference in New Issue
Block a user