diff --git a/mayfly_go_web/package.json b/mayfly_go_web/package.json index 8952d80c..8aaa34fc 100644 --- a/mayfly_go_web/package.json +++ b/mayfly_go_web/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.1.0", + "@vueuse/core": "^10.7.0", "asciinema-player": "^3.6.2", "axios": "^1.6.2", "clipboard": "^2.0.11", @@ -21,7 +22,7 @@ "jsencrypt": "^3.3.2", "lodash": "^4.17.21", "mitt": "^3.0.1", - "monaco-editor": "^0.44.0", + "monaco-editor": "^0.45.0", "monaco-sql-languages": "^0.11.0", "monaco-themes": "^0.4.4", "nprogress": "^0.2.0", @@ -32,7 +33,7 @@ "splitpanes": "^3.1.5", "sql-formatter": "^14.0.0", "uuid": "^9.0.1", - "vue": "^3.3.10", + "vue": "^3.3.11", "vue-router": "^4.2.5", "xterm": "^5.3.0", "xterm-addon-fit": "^0.8.0", @@ -54,7 +55,7 @@ "prettier": "^3.1.0", "sass": "^1.69.0", "typescript": "^5.3.2", - "vite": "^5.0.5", + "vite": "^5.0.7", "vue-eslint-parser": "^9.3.2" }, "browserslist": [ diff --git a/mayfly_go_web/src/App.vue b/mayfly_go_web/src/App.vue index 2bc3b6ca..44a1f7e5 100644 --- a/mayfly_go_web/src/App.vue +++ b/mayfly_go_web/src/App.vue @@ -28,6 +28,7 @@ import Setings from '@/layout/navBars/breadcrumb/setings.vue'; import mittBus from '@/common/utils/mitt'; import { getThemeConfig } from './common/utils/storage'; import { useWatermark } from '@/common/sysconfig'; +import { useIntervalFn } from '@vueuse/core'; const setingsRef = ref(); const route = useRoute(); @@ -40,12 +41,6 @@ const openSetingsDrawer = () => { setingsRef.value.openDrawer(); }; -const prefers = matchMedia('(prefers-color-scheme: dark)'); -const switchDarkFollowOS = () => { - // 跟随系统主题 - themeConfigStores.switchDark(prefers.matches); -}; - // 页面加载时 onMounted(() => { nextTick(() => { @@ -60,7 +55,6 @@ onMounted(() => { themeConfigStores.setThemeConfig({ themeConfig: tc }); document.documentElement.style.cssText = getLocal('themeConfigStyle'); } - switchDarkFollowOS(); // 是否开启水印 useWatermark().then((res) => { @@ -77,36 +71,35 @@ watch( setTimeout(() => { setWatermarkContent(); refreshWatermarkTime(); + resume(); }, 500); + } else { + pause(); } } ); +// 刷新水印时间 +const { pause, resume } = useIntervalFn(() => { + if (!themeConfig.value.isWatermark) { + pause(); + } + refreshWatermarkTime(); +}, 60000); + const setWatermarkContent = () => { themeConfigStores.setWatermarkUser(); - themeConfigStores.setWatermarkNowTime(); }; -let refreshWatermarkTimeInterval: any = null; /** * 刷新水印时间 */ const refreshWatermarkTime = () => { - if (refreshWatermarkTimeInterval) { - clearInterval(refreshWatermarkTimeInterval); - } - refreshWatermarkTimeInterval = setInterval(() => { - if (themeConfig.value.isWatermark) { - themeConfigStores.setWatermarkNowTime(); - } else { - clearInterval(refreshWatermarkTimeInterval); - } - }, 60000); + themeConfigStores.setWatermarkNowTime(); }; // 页面销毁时,关闭监听布局配置 onUnmounted(() => { - clearInterval(refreshWatermarkTimeInterval); mittBus.off('openSetingsDrawer', () => {}); }); diff --git a/mayfly_go_web/src/common/Api.ts b/mayfly_go_web/src/common/Api.ts index b66493cb..baa03dbc 100644 --- a/mayfly_go_web/src/common/Api.ts +++ b/mayfly_go_web/src/common/Api.ts @@ -49,32 +49,27 @@ class Api { * 请求对应的该api * @param {Object} param 请求该api的参数 */ - request(param: any = null, options: any = null, headers: any = null): Promise { + request(param: any = null, options: any = {}): Promise { if (this.beforeHandler) { 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的参数 */ - requestCanCancel(key: string, param: any = null, options: any = null, headers: any = null): Promise { + allowCancelReq(key: string, param: any = null, options: RequestInit = {}): Promise { let controller = Api.abortControllers.get(key); if (!controller) { controller = new AbortController(); Api.abortControllers.set(key, controller); } - if (options) { - options.signal = controller.signal; - } else { - options = { - signal: controller.signal, - }; - } + options.signal = controller.signal; - return this.request(param, options, headers); + return this.request(param, options); } /** 静态方法 **/ diff --git a/mayfly_go_web/src/common/request.ts b/mayfly_go_web/src/common/request.ts index b55fc039..52e520e0 100755 --- a/mayfly_go_web/src/common/request.ts +++ b/mayfly_go_web/src/common/request.ts @@ -1,11 +1,20 @@ import router from '../router'; -import Axios from 'axios'; import config from './config'; import { getClientId, getToken } from './utils/storage'; import { templateResolve } from './utils/string'; import { ElMessage } from 'element-plus'; import axios from 'axios'; +export default { + request, + fetchReq, + get, + post, + put, + del, + getApiUrl, +}; + export interface Result { /** * 响应码 @@ -30,6 +39,7 @@ enum ResultEnum { } const baseUrl: string = config.baseApiUrl; +// const baseUrl: string = 'http://localhost:18888/api'; // const baseWsUrl: string = config.baseWsUrl; /** @@ -42,13 +52,13 @@ function notifyErrorMsg(msg: string) { } // create an axios instance -const service = Axios.create({ +const axiosInst = axios.create({ baseURL: baseUrl, // url = base url + request url timeout: 60000, // request timeout }); // request interceptor -service.interceptors.request.use( +axiosInst.interceptors.request.use( (config: any) => { // do something before request is sent const token = getToken(); @@ -65,21 +75,8 @@ service.interceptors.request.use( ); // response interceptor -service.interceptors.response.use( - (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); - }, +axiosInst.interceptors.response.use( + (response) => response, (e: any) => { const rejectPromise = Promise.reject(e); @@ -125,35 +122,37 @@ service.interceptors.response.use( * @param {Object} uri uri * @param {Object} params 参数 */ -function request(method: string, url: string, params: any = null, headers: any = null, options: any = null): Promise { - if (!url) throw new Error('请求url不能为空'); +function request(method: string, url: string, params: any = null, options: any = {}): Promise { + if (!url) { + throw new Error('请求url不能为空'); + } + // 简单判断该url是否是restful风格 if (url.indexOf('{') != -1) { url = templateResolve(url, params); } - const query: any = { + + const req: any = { method, - url: url, + url, ...options, }; - if (headers) { - query.headers = headers; - } // post和put使用json格式传参 if (method === 'post' || method === 'put') { - query.data = params; + req.data = params; } else { - query.params = params; + req.params = params; } - return service - .request(query) - .then((res) => res) + + return axiosInst + .request(req) + .then((response) => { + // 获取请求返回结果 + const result: Result = response.data; + return parseResult(result); + }) .catch((e) => { - // 如果返回的code不为成功,则会返回对应的错误msg,则直接统一通知即可。忽略登录超时或没有权限的提示(直接跳转至401页面) - if (e.msg && e?.code != ResultEnum.NO_PERMISSION) { - notifyErrorMsg(e.msg); - } 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} params 参数 */ -function get(url: string, params: any = null, headers: any = null, options: any = null): Promise { - return request('get', url, params, headers, options); +function get(url: string, params: any = null, options: any = {}): Promise { + return request('get', url, params, options); } -function post(url: string, params: any = null, headers: any = null, options: any = null): Promise { - return request('post', url, params, headers, options); +function post(url: string, params: any = null, options: any = {}): Promise { + return request('post', url, params, options); } -function put(url: string, params: any = null, headers: any = null, options: any = null): Promise { - return request('put', url, params, headers, options); +function put(url: string, params: any = null, options: any = {}): Promise { + return request('put', url, params, options); } -function del(url: string, params: any = null, headers: any = null, options: any = null): Promise { - return request('delete', url, params, headers, options); +function del(url: string, params: any = null, options: any = {}): Promise { + return request('delete', url, params, options); } function getApiUrl(url: string) { @@ -191,11 +190,80 @@ export function joinClientParams(): string { return `token=${getToken()}&clientId=${getClientId()}`; } -export default { - request, - get, - post, - put, - del, - getApiUrl, -}; +async function fetchReq(method: string, url: string, params: any = null, options: RequestInit = {}): Promise { + options.method = method; + + if (params) { + // post和put使用json格式传参 + if (method === 'post' || method === 'put') { + 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); +} diff --git a/mayfly_go_web/src/common/sysconfig.ts b/mayfly_go_web/src/common/sysconfig.ts index 8392de87..76323f19 100644 --- a/mayfly_go_web/src/common/sysconfig.ts +++ b/mayfly_go_web/src/common/sysconfig.ts @@ -2,8 +2,8 @@ import openApi from './openApi'; // 登录是否使用验证码配置key const AccountLoginSecurity = 'AccountLoginSecurity'; -const UseLoginCaptchaConfigKey = 'UseLoginCaptcha'; const UseWatermarkConfigKey = 'UseWatermark'; +const MachineConfig = 'MachineConfig'; /** * 获取系统配置值 @@ -43,15 +43,6 @@ export async function getAccountLoginSecurity(): Promise { return jsonValue; } -/** - * 是否使用登录验证码 - * - * @returns - */ -export async function useLoginCaptcha(): Promise { - return await getBoolConfigValue(UseLoginCaptchaConfigKey, true); -} - /** * 是否启用水印信息配置 * @@ -75,13 +66,6 @@ export async function useWatermark(): Promise { } } -function convertBool(value: string, defaultValue: boolean) { - if (!value) { - return defaultValue; - } - return value == '1' || value == 'true'; -} - /** * 获取LDAP登录配置 * @@ -91,3 +75,32 @@ export async function getLdapEnabled(): Promise { const value = await openApi.getLdapEnabled(); return convertBool(value, false); } + +/** + * 是否启用水印信息配置 + * + * @returns + */ +export async function getMachineConfig(): Promise { + 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'; +} diff --git a/mayfly_go_web/src/common/use.ts b/mayfly_go_web/src/common/use.ts deleted file mode 100644 index 90bd83a4..00000000 --- a/mayfly_go_web/src/common/use.ts +++ /dev/null @@ -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 }; -} diff --git a/mayfly_go_web/src/common/utils/format.ts b/mayfly_go_web/src/common/utils/format.ts index 52e9d542..a3ea3e58 100644 --- a/mayfly_go_web/src/common/utils/format.ts +++ b/mayfly_go_web/src/common/utils/format.ts @@ -15,6 +15,37 @@ export function formatByteSize(size: number, fixed = 2) { 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字符串 * @param txt json字符串 diff --git a/mayfly_go_web/src/components/contextmenu/index.vue b/mayfly_go_web/src/components/contextmenu/index.vue index acda639e..809d4c3a 100644 --- a/mayfly_go_web/src/components/contextmenu/index.vue +++ b/mayfly_go_web/src/components/contextmenu/index.vue @@ -34,8 +34,8 @@ + diff --git a/mayfly_go_web/src/components/dynamic-form/DynamicFormDialog.vue b/mayfly_go_web/src/components/dynamic-form/DynamicFormDialog.vue index 42b50130..be800e8d 100644 --- a/mayfly_go_web/src/components/dynamic-form/DynamicFormDialog.vue +++ b/mayfly_go_web/src/components/dynamic-form/DynamicFormDialog.vue @@ -1,60 +1,55 @@ - diff --git a/mayfly_go_web/src/components/dynamic-form/DynamicFormEdit.vue b/mayfly_go_web/src/components/dynamic-form/DynamicFormEdit.vue new file mode 100644 index 00000000..3e510d3f --- /dev/null +++ b/mayfly_go_web/src/components/dynamic-form/DynamicFormEdit.vue @@ -0,0 +1,60 @@ + + + + diff --git a/mayfly_go_web/src/components/dynamic-form/index.js b/mayfly_go_web/src/components/dynamic-form/index.js index 1cf99d33..2cf9481e 100644 --- a/mayfly_go_web/src/components/dynamic-form/index.js +++ b/mayfly_go_web/src/components/dynamic-form/index.js @@ -1,2 +1,3 @@ export { default as DynamicForm } from './DynamicForm.vue'; -export { default as DynamicFormDialog } from './DynamicFormDialog.vue'; \ No newline at end of file +export { default as DynamicFormDialog } from './DynamicFormDialog.vue'; +export { default as DynamicFormEdit } from './DynamicFormEdit.vue'; diff --git a/mayfly_go_web/src/layout/navBars/breadcrumb/user.vue b/mayfly_go_web/src/layout/navBars/breadcrumb/user.vue index 8bb1035e..edf6de75 100644 --- a/mayfly_go_web/src/layout/navBars/breadcrumb/user.vue +++ b/mayfly_go_web/src/layout/navBars/breadcrumb/user.vue @@ -2,8 +2,8 @@
diff --git a/mayfly_go_web/src/store/themeConfig.ts b/mayfly_go_web/src/store/themeConfig.ts index f8635891..6de03321 100644 --- a/mayfly_go_web/src/store/themeConfig.ts +++ b/mayfly_go_web/src/store/themeConfig.ts @@ -146,18 +146,6 @@ export const useThemeConfig = defineStore('themeConfig', { setThemeConfig(data: ThemeConfigState) { 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) { this.themeConfig.watermarkText = []; diff --git a/mayfly_go_web/src/views/ops/component/TagTree.vue b/mayfly_go_web/src/views/ops/component/TagTree.vue index c841f5f8..96601b31 100644 --- a/mayfly_go_web/src/views/ops/component/TagTree.vue +++ b/mayfly_go_web/src/views/ops/component/TagTree.vue @@ -46,8 +46,8 @@ import { onMounted, reactive, ref, watch, toRefs, onUnmounted } from 'vue'; import { NodeType, TagTreeNode } from './tag'; import TagInfo from './TagInfo.vue'; import { Contextmenu } from '@/components/contextmenu'; -import { useViewport } from '@/common/use'; import { tagApi } from '../tag/api'; +import { useWindowSize } from '@vueuse/core'; const props = defineProps({ resourceType: { @@ -78,7 +78,7 @@ const emit = defineEmits(['nodeClick', 'currentContextmenuClick']); const treeRef: any = ref(null); const contextmenuRef = ref(); -const { vh } = useViewport(); +const { height: vh } = useWindowSize(); const state = reactive({ height: 600 as any, diff --git a/mayfly_go_web/src/views/ops/db/DbList.vue b/mayfly_go_web/src/views/ops/db/DbList.vue index 641d976f..4070df15 100644 --- a/mayfly_go_web/src/views/ops/db/DbList.vue +++ b/mayfly_go_web/src/views/ops/db/DbList.vue @@ -45,14 +45,20 @@ 删除 -