mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
refactor: 动态路由调整&分隔面板使用element自带组件
This commit is contained in:
@@ -11,32 +11,31 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@logicflow/core": "^2.0.13",
|
"@logicflow/core": "^2.0.15",
|
||||||
"@logicflow/extension": "^2.0.18",
|
"@logicflow/extension": "^2.0.20",
|
||||||
"@vueuse/core": "^13.3.0",
|
"@vueuse/core": "^13.3.0",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-search": "^0.15.0",
|
"@xterm/addon-search": "^0.15.0",
|
||||||
"@xterm/addon-web-links": "^0.11.0",
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"asciinema-player": "^3.9.0",
|
"asciinema-player": "^3.10.0",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"echarts": "^5.6.0",
|
"echarts": "^5.6.0",
|
||||||
"element-plus": "^2.9.11",
|
"element-plus": "^2.10.1",
|
||||||
"js-base64": "^3.7.7",
|
"js-base64": "^3.7.7",
|
||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"monaco-editor": "^0.52.2",
|
"monaco-editor": "^0.52.2",
|
||||||
"monaco-sql-languages": "^0.14.0",
|
"monaco-sql-languages": "^0.15.0",
|
||||||
"monaco-themes": "^0.4.5",
|
"monaco-themes": "^0.4.5",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.3",
|
||||||
"qrcode.vue": "^3.6.0",
|
"qrcode.vue": "^3.6.0",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"sortablejs": "^1.15.6",
|
"sortablejs": "^1.15.6",
|
||||||
"splitpanes": "^4.0.4",
|
|
||||||
"sql-formatter": "^15.6.1",
|
"sql-formatter": "^15.6.1",
|
||||||
"trzsz": "^1.1.5",
|
"trzsz": "^1.1.5",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
@@ -62,7 +61,7 @@
|
|||||||
"eslint-plugin-vue": "^10.1.0",
|
"eslint-plugin-vue": "^10.1.0",
|
||||||
"postcss": "^8.5.4",
|
"postcss": "^8.5.4",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"sass": "^1.89.0",
|
"sass": "^1.89.1",
|
||||||
"tailwindcss": "^4.1.8",
|
"tailwindcss": "^4.1.8",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vite": "^6.3.5",
|
"vite": "^6.3.5",
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default {
|
|||||||
success: 'Success',
|
success: 'Success',
|
||||||
menuCodeTips: `The menu type is the access path (if the menu path does not begin with '/', the access address will automatically concatenate the parent menu path), otherwise it is the unique code of the resource`,
|
menuCodeTips: `The menu type is the access path (if the menu path does not begin with '/', the access address will automatically concatenate the parent menu path), otherwise it is the unique code of the resource`,
|
||||||
menuCodePlaceholder: `A menu that does not begin with '/' will automatically concatenate the parent menu path`,
|
menuCodePlaceholder: `A menu that does not begin with '/' will automatically concatenate the parent menu path`,
|
||||||
routerNameTips: 'For component caching to work, match the vue component name, such as ResourceLis',
|
routerNameTips:
|
||||||
|
'For component caching to work, the key for route.ts in the frontend module should match the vue component name, such as ResourceList',
|
||||||
componentPathTips: 'Access path components, such as: ` system/resource/ResourceList `, default in ` views ` directory',
|
componentPathTips: 'Access path components, such as: ` system/resource/ResourceList `, default in ` views ` directory',
|
||||||
isCacheTips: `If yes is selected, it will be 'keepalive' cached (reentering the page without refreshing the page and requesting data again), and needs the route name to match the vue component name`,
|
isCacheTips: `If yes is selected, it will be 'keepalive' cached (reentering the page without refreshing the page and requesting data again), and needs the route name to match the vue component name`,
|
||||||
isHideTips:
|
isHideTips:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export default {
|
|||||||
success: '成功',
|
success: '成功',
|
||||||
menuCodeTips: `菜单类型则为访问路径(若菜单路径不以'/'开头则访问地址会自动拼接父菜单路径)、否则为资源唯一编码`,
|
menuCodeTips: `菜单类型则为访问路径(若菜单路径不以'/'开头则访问地址会自动拼接父菜单路径)、否则为资源唯一编码`,
|
||||||
menuCodePlaceholder: `菜单不以'/'开头则自动拼接父菜单路径`,
|
menuCodePlaceholder: `菜单不以'/'开头则自动拼接父菜单路径`,
|
||||||
routerNameTips: '与vue的组件名一致才可使组件缓存生效,如ResourceList',
|
routerNameTips: '前端模块下route.ts中对应的key,与vue的组件名一致才可使组件缓存生效,如ResourceList',
|
||||||
componentPathTips: '访问的组件路径,如:`system/resource/ResourceList`,默认在`views`目录下',
|
componentPathTips: '访问的组件路径,如:`system/resource/ResourceList`,默认在`views`目录下',
|
||||||
isCacheTips: '选择是则会被`keep-alive`缓存(重新进入页面不会刷新页面及重新请求数据),需要路由名与vue的组件名一致',
|
isCacheTips: '选择是则会被`keep-alive`缓存(重新进入页面不会刷新页面及重新请求数据),需要路由名与vue的组件名一致',
|
||||||
isHideTips: '选择隐藏则路由将不会出现在菜单栏中,但仍然可以访问。禁用则不可访问与操作',
|
isHideTips: '选择隐藏则路由将不会出现在菜单栏中,但仍然可以访问。禁用则不可访问与操作',
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import 'element-plus/dist/index.css';
|
|||||||
import 'element-plus/theme-chalk/dark/css-vars.css';
|
import 'element-plus/theme-chalk/dark/css-vars.css';
|
||||||
import { i18n } from '@/i18n/index';
|
import { i18n } from '@/i18n/index';
|
||||||
|
|
||||||
import 'splitpanes/dist/splitpanes.css';
|
|
||||||
|
|
||||||
import '@/theme/index.scss';
|
import '@/theme/index.scss';
|
||||||
import '@/theme/tailwind.css';
|
import '@/theme/tailwind.css';
|
||||||
import '@/assets/font/font.css';
|
import '@/assets/font/font.css';
|
||||||
|
|||||||
@@ -9,15 +9,21 @@ import { RouteRecordRaw } from 'vue-router';
|
|||||||
import { LAYOUT_ROUTE_NAME } from './staticRouter';
|
import { LAYOUT_ROUTE_NAME } from './staticRouter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取目录下的 .vue、.tsx 全部文件
|
* 获取目录下的 route.ts 全部文件
|
||||||
* @method import.meta.glob
|
* @method import.meta.glob
|
||||||
* @link 参考:https://cn.vitejs.dev/guide/features.html#json
|
* @link 参考:https://cn.vitejs.dev/guide/features.html#json
|
||||||
*/
|
*/
|
||||||
const viewsModules: Record<string, Function> = import.meta.glob(['../views/**/*.{vue,tsx}']);
|
const routeModules: Record<string, any> = import.meta.glob(['../views/**/route.{ts,js}'], { eager: true });
|
||||||
const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...viewsModules });
|
|
||||||
|
|
||||||
// 后端控制路由:执行路由数据初始化
|
// 后端控制路由:执行路由数据初始化
|
||||||
export async function initBackendRoutes() {
|
export async function initBackendRoutes() {
|
||||||
|
let allModuleRoutes = {};
|
||||||
|
for (const path in routeModules) {
|
||||||
|
// 获取默认导出的路由
|
||||||
|
const routes = routeModules[path]?.default;
|
||||||
|
allModuleRoutes = { ...allModuleRoutes, ...routes };
|
||||||
|
}
|
||||||
|
|
||||||
const token = getToken(); // 获取浏览器缓存 token 值
|
const token = getToken(); // 获取浏览器缓存 token 值
|
||||||
if (!token) {
|
if (!token) {
|
||||||
// 无 token 停止执行下一步
|
// 无 token 停止执行下一步
|
||||||
@@ -29,7 +35,7 @@ export async function initBackendRoutes() {
|
|||||||
|
|
||||||
const cacheList: Array<string> = [];
|
const cacheList: Array<string> = [];
|
||||||
// 处理路由(component)
|
// 处理路由(component)
|
||||||
const routes = backEndRouterConverter(menuRoute, (router: any) => {
|
const routes = backEndRouterConverter(allModuleRoutes, menuRoute, (router: any) => {
|
||||||
// 可能为false时不存在isKeepAlive属性
|
// 可能为false时不存在isKeepAlive属性
|
||||||
if (!router.meta.isKeepAlive) {
|
if (!router.meta.isKeepAlive) {
|
||||||
router.meta.isKeepAlive = false;
|
router.meta.isKeepAlive = false;
|
||||||
@@ -88,7 +94,7 @@ type RouterConvCallbackFunc = (router: any) => void;
|
|||||||
* @param meta.linkType ==> 外链类型, 内嵌: 以iframe展示、外链: 新标签打开
|
* @param meta.linkType ==> 外链类型, 内嵌: 以iframe展示、外链: 新标签打开
|
||||||
* @param meta.link ==> 外链地址
|
* @param meta.link ==> 外链地址
|
||||||
* */
|
* */
|
||||||
export function backEndRouterConverter(routes: any, callbackFunc: RouterConvCallbackFunc = null as any, parentPath: string = '/') {
|
export function backEndRouterConverter(allModuleRoutes: any, routes: any, callbackFunc: RouterConvCallbackFunc = null as any, parentPath: string = '/') {
|
||||||
if (!routes) {
|
if (!routes) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -101,12 +107,6 @@ export function backEndRouterConverter(routes: any, callbackFunc: RouterConvCall
|
|||||||
// 将json字符串的meta转为对象
|
// 将json字符串的meta转为对象
|
||||||
item.meta = JSON.parse(item.meta);
|
item.meta = JSON.parse(item.meta);
|
||||||
|
|
||||||
// 将meta.comoponet 解析为route.component
|
|
||||||
if (item.meta.component) {
|
|
||||||
item.component = dynamicImport(dynamicViewsModules, item.meta.component);
|
|
||||||
delete item.meta['component'];
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = item.code;
|
let path = item.code;
|
||||||
// 如果不是以 / 开头,则路径需要拼接父路径
|
// 如果不是以 / 开头,则路径需要拼接父路径
|
||||||
if (!path.startsWith('/')) {
|
if (!path.startsWith('/')) {
|
||||||
@@ -121,6 +121,8 @@ export function backEndRouterConverter(routes: any, callbackFunc: RouterConvCall
|
|||||||
|
|
||||||
// route.name == resource.meta.routeName
|
// route.name == resource.meta.routeName
|
||||||
item.name = item.meta.routeName;
|
item.name = item.meta.routeName;
|
||||||
|
// routerName == 模块下route.ts 字段key == 组件名
|
||||||
|
item.component = allModuleRoutes[item.meta.routeName];
|
||||||
delete item.meta['routeName'];
|
delete item.meta['routeName'];
|
||||||
|
|
||||||
// route.redirect == resource.meta.redirect
|
// route.redirect == resource.meta.redirect
|
||||||
@@ -130,35 +132,9 @@ export function backEndRouterConverter(routes: any, callbackFunc: RouterConvCall
|
|||||||
}
|
}
|
||||||
// 存在回调,则执行回调
|
// 存在回调,则执行回调
|
||||||
callbackFunc && callbackFunc(item);
|
callbackFunc && callbackFunc(item);
|
||||||
item.children && backEndRouterConverter(item.children, callbackFunc, item.path);
|
item.children && backEndRouterConverter(allModuleRoutes, item.children, callbackFunc, item.path);
|
||||||
routeItems.push(item);
|
routeItems.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return routeItems;
|
return routeItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 后端路由 component 转换函数
|
|
||||||
* @param dynamicViewsModules 获取目录下的 .vue、.tsx 全部文件
|
|
||||||
* @param component 当前要处理项 component
|
|
||||||
* @returns 返回处理成函数后的 component
|
|
||||||
*/
|
|
||||||
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
|
|
||||||
const keys = Object.keys(dynamicViewsModules);
|
|
||||||
const matchKeys = keys.filter((key) => {
|
|
||||||
const k = key.replace(/..\/views|../, '');
|
|
||||||
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (matchKeys?.length === 1) {
|
|
||||||
return dynamicViewsModules[matchKeys[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchKeys?.length > 1) {
|
|
||||||
console.error('匹配到多个相似组件路径, 可添加后缀.vue或.tsx进行区分或者重命名组件名, 请调整...', matchKeys);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn(`未匹配到[${component}]组件名对应的组件文件`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,4 +5,3 @@
|
|||||||
@use './waves.scss';
|
@use './waves.scss';
|
||||||
@use './dark.scss';
|
@use './dark.scss';
|
||||||
@use './iconSelector.scss';
|
@use './iconSelector.scss';
|
||||||
@use './splitpanes.scss';
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/** splitpanes **/
|
|
||||||
.splitpanes.default-theme .splitpanes {
|
|
||||||
background: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitpanes.default-theme .splitpanes__pane {
|
|
||||||
background: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.default-theme.splitpanes--vertical>.splitpanes__splitter {
|
|
||||||
border-left: 1px solid var(--bg-main-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.default-theme.splitpanes--horizontal>.splitpanes__splitter {
|
|
||||||
border-top: 1px solid var(--bg-main-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 竖线样式
|
|
||||||
.splitpanes.default-theme .splitpanes__splitter::before,
|
|
||||||
.splitpanes.default-theme .splitpanes__splitter::after {
|
|
||||||
background-color: var(--el-color-info-light-5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitpanes.default-theme .splitpanes__splitter:hover::before,
|
|
||||||
.splitpanes.default-theme .splitpanes__splitter:hover::after {
|
|
||||||
background-color: var(--el-color-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitpanes.default-theme .splitpanes__splitter {
|
|
||||||
min-width: 6px;
|
|
||||||
background: var(--el-color-info-light-8) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitpanes.default-theme .splitpanes__splitter:hover {
|
|
||||||
background: var(--el-color-success-light-8) !important;
|
|
||||||
}
|
|
||||||
1
frontend/src/types/shim.d.ts
vendored
1
frontend/src/types/shim.d.ts
vendored
@@ -2,5 +2,4 @@
|
|||||||
declare module 'jsoneditor';
|
declare module 'jsoneditor';
|
||||||
declare module 'asciinema-player';
|
declare module 'asciinema-player';
|
||||||
declare module 'vue-grid-layout';
|
declare module 'vue-grid-layout';
|
||||||
declare module 'splitpanes';
|
|
||||||
declare module 'uuid';
|
declare module 'uuid';
|
||||||
|
|||||||
5
frontend/src/views/flow/route.ts
Normal file
5
frontend/src/views/flow/route.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
ProcdefList: () => import('@/views/flow/ProcdefList.vue'),
|
||||||
|
ProcinstList: () => import('@/views/flow/ProcinstList.vue'),
|
||||||
|
ProcinstTaskList: () => import('@/views/flow/ProcinstTaskList.vue'),
|
||||||
|
};
|
||||||
3
frontend/src/views/home/route.ts
Normal file
3
frontend/src/views/home/route.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
Home: () => import('@/views/home/Home.vue'),
|
||||||
|
};
|
||||||
4
frontend/src/views/msg/route.ts
Normal file
4
frontend/src/views/msg/route.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
ChannelList: () => import('@/views/msg/channel/ChannelList.vue'),
|
||||||
|
TmplList: () => import('@/views/msg/tmpl/TmplList.vue'),
|
||||||
|
};
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<Splitpanes class="default-theme" @resize="handleResize">
|
<el-splitter @resize="handleResize">
|
||||||
<Pane :size="leftPaneSize" max-size="30">
|
<el-splitter-panel :size="leftPaneSize + '%'" max="30%">
|
||||||
<slot name="left"></slot>
|
<slot name="left"></slot>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
|
|
||||||
<Pane>
|
<el-splitter-panel>
|
||||||
<slot name="right"></slot>
|
<slot name="right"></slot>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
</Splitpanes>
|
</el-splitter>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Pane, Splitpanes } from 'splitpanes';
|
|
||||||
import { useWindowSize } from '@vueuse/core';
|
import { useWindowSize } from '@vueuse/core';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { DbSqlExecTypeEnum, DbSqlExecStatusEnum } from './enums';
|
|||||||
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 { SearchItem } from '@/components/SearchForm';
|
import { SearchItem } from '@/components/SearchForm';
|
||||||
|
import { formatDate } from '@/common/utils/format';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dbId: {
|
dbId: {
|
||||||
@@ -62,6 +63,21 @@ const searchItems = [
|
|||||||
SearchItem.slot('db', 'db.db', 'dbSelect'),
|
SearchItem.slot('db', 'db.db', 'dbSelect'),
|
||||||
SearchItem.input('table', 'db.table'),
|
SearchItem.input('table', 'db.table'),
|
||||||
SearchItem.select('type', 'db.stmtType').withEnum(DbSqlExecTypeEnum),
|
SearchItem.select('type', 'db.stmtType').withEnum(DbSqlExecTypeEnum),
|
||||||
|
SearchItem.input('keyword', 'common.keyword'),
|
||||||
|
SearchItem.datePicker('execTimeRange', 'db.execTime')
|
||||||
|
.withSpan(2)
|
||||||
|
.withOneProps('type', 'datetimerange')
|
||||||
|
.withOneProps('format', 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
.withOneProps('value-format', 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
.bindEvent('change', (value: any) => {
|
||||||
|
if (!value) {
|
||||||
|
state.query.startTime = '';
|
||||||
|
state.query.endTime = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.query.startTime = formatDate(value[0]);
|
||||||
|
state.query.endTime = formatDate(value[1]);
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
@@ -88,6 +104,9 @@ const state = reactive({
|
|||||||
table: '',
|
table: '',
|
||||||
status: [DbSqlExecStatusEnum.Success.value, DbSqlExecStatusEnum.Fail.value].join(','),
|
status: [DbSqlExecStatusEnum.Success.value, DbSqlExecStatusEnum.Fail.value].join(','),
|
||||||
type: null,
|
type: null,
|
||||||
|
keyword: '',
|
||||||
|
startTime: '',
|
||||||
|
endTime: '',
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip :show-after="1000" class="box-item" effect="dark" content="format sql" placement="top">
|
<el-tooltip :show-after="1000" class="box-item" effect="dark" content="format sql" placement="top">
|
||||||
<el-link @click="formatSql()" type="primary" underline="never" icon="MagicStick"> </el-link>
|
<el-link @click="onFormatSql()" type="primary" underline="never" icon="MagicStick"> </el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
@@ -39,19 +39,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Splitpanes
|
<el-splitter style="height: calc(100vh - 200px)" layout="vertical" @resize-end="onResizeTableHeight">
|
||||||
@pane-maximize="resizeTableHeight({ panes: [{ size: 0 }] })"
|
<el-splitter-panel :size="state.editorSize" max="80%">
|
||||||
@resize="resizeTableHeight"
|
|
||||||
horizontal
|
|
||||||
class="default-theme"
|
|
||||||
style="height: calc(100vh - 233px)"
|
|
||||||
>
|
|
||||||
<Pane :size="state.editorSize" max-size="80">
|
|
||||||
<MonacoEditor ref="monacoEditorRef" class="mt-1" v-model="state.sql" language="sql" height="100%" :id="'MonacoTextarea-' + getKey()" />
|
<MonacoEditor ref="monacoEditorRef" class="mt-1" v-model="state.sql" language="sql" height="100%" :id="'MonacoTextarea-' + getKey()" />
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
|
|
||||||
<Pane :size="100 - state.editorSize">
|
<el-splitter-panel>
|
||||||
<div class="mt-1 sql-exec-res !h-full">
|
<div class="sql-exec-res !h-full">
|
||||||
<el-tabs
|
<el-tabs
|
||||||
class="!h-full !w-full"
|
class="!h-full !w-full"
|
||||||
v-if="state.execResTabs.length > 0"
|
v-if="state.execResTabs.length > 0"
|
||||||
@@ -128,8 +122,8 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
</Splitpanes>
|
</el-splitter>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -151,9 +145,9 @@ import { dbApi } from '../../api';
|
|||||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
import { joinClientParams } from '@/common/request';
|
import { joinClientParams } from '@/common/request';
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
import { Pane, Splitpanes } from 'splitpanes';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
import { useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||||
|
import { useDebounceFn, useEventListener } from '@vueuse/core';
|
||||||
|
|
||||||
const emits = defineEmits(['saveSqlSuccess']);
|
const emits = defineEmits(['saveSqlSuccess']);
|
||||||
|
|
||||||
@@ -241,10 +235,11 @@ onMounted(async () => {
|
|||||||
console.log('in query mounted');
|
console.log('in query mounted');
|
||||||
|
|
||||||
// 第一个pane为sql editor
|
// 第一个pane为sql editor
|
||||||
resizeTableHeight({ panes: [{ size: state.editorSize }] });
|
onResizeTableHeight(0, [-1]);
|
||||||
window.onresize = () => {
|
useEventListener(
|
||||||
resizeTableHeight({ panes: [{ size: state.editorSize }] });
|
'resize',
|
||||||
};
|
useDebounceFn(() => onResizeTableHeight(0, [-1]), 200)
|
||||||
|
);
|
||||||
|
|
||||||
// 默认新建一个结果集tab
|
// 默认新建一个结果集tab
|
||||||
state.execResTabs.push(new ExecResTab(1));
|
state.execResTabs.push(new ExecResTab(1));
|
||||||
@@ -279,12 +274,24 @@ const onRemoveTab = (targetId: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resizeTableHeight = (e: any) => {
|
const onResizeTableHeight = (index: number, sizes: number[]) => {
|
||||||
|
if (!sizes || sizes.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const vh = window.innerHeight;
|
const vh = window.innerHeight;
|
||||||
state.editorSize = e.panes[0].size;
|
const plitpaneHeight = vh - 200;
|
||||||
const plitpaneHeight = vh - 233;
|
|
||||||
const editorHeight = plitpaneHeight * (state.editorSize / 100);
|
let editorHeight = sizes[0];
|
||||||
state.tableDataHeight = plitpaneHeight - editorHeight - 40 + 'px';
|
if (editorHeight < 0 || editorHeight > plitpaneHeight - 43) {
|
||||||
|
// 默认占50%
|
||||||
|
editorHeight = plitpaneHeight / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tableDataHeight = plitpaneHeight - editorHeight - 43;
|
||||||
|
|
||||||
|
state.editorSize = editorHeight;
|
||||||
|
state.tableDataHeight = tableDataHeight + 'px';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getKey = () => {
|
const getKey = () => {
|
||||||
@@ -535,7 +542,7 @@ const saveSql = async () => {
|
|||||||
/**
|
/**
|
||||||
* 格式化sql
|
* 格式化sql
|
||||||
*/
|
*/
|
||||||
const formatSql = () => {
|
const onFormatSql = () => {
|
||||||
let selection = monacoEditor.getSelection();
|
let selection = monacoEditor.getSelection();
|
||||||
if (!selection) {
|
if (!selection) {
|
||||||
return;
|
return;
|
||||||
@@ -715,7 +722,7 @@ const initMonacoEditor = () => {
|
|||||||
// @param editor The editor instance is passed in as a convenience
|
// @param editor The editor instance is passed in as a convenience
|
||||||
run: async function () {
|
run: async function () {
|
||||||
try {
|
try {
|
||||||
await formatSql();
|
await onFormatSql();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
e.message && ElMessage.error(e.message);
|
e.message && ElMessage.error(e.message);
|
||||||
}
|
}
|
||||||
|
|||||||
6
frontend/src/views/ops/db/route.ts
Normal file
6
frontend/src/views/ops/db/route.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
InstanceList: () => import('@/views/ops/db/InstanceList.vue'),
|
||||||
|
SqlExec: () => import('@/views/ops/db/SqlExec.vue'),
|
||||||
|
SyncTaskList: () => import('@/views/ops/db/SyncTaskList.vue'),
|
||||||
|
DbTransferList: () => import('@/views/ops/db/DbTransferList.vue'),
|
||||||
|
};
|
||||||
4
frontend/src/views/ops/es/route.ts
Normal file
4
frontend/src/views/ops/es/route.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
EsInstanceList: () => import('@/views/ops/es/EsInstanceList.vue'),
|
||||||
|
EsOperation: () => import('@/views/ops/es/EsOperation.vue'),
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<ResourceOpPanel @resized="onResizeTagTree">
|
<ResourceOpPanel @resize="onResizeTagTree">
|
||||||
<template #left>
|
<template #left>
|
||||||
<tag-tree
|
<tag-tree
|
||||||
ref="tagTreeRef"
|
ref="tagTreeRef"
|
||||||
|
|||||||
6
frontend/src/views/ops/machine/route.ts
Normal file
6
frontend/src/views/ops/machine/route.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
MachineList: () => import('@/views/ops/machine/MachineList.vue'),
|
||||||
|
MachineOp: () => import('@/views/ops/machine/MachineOp.vue'),
|
||||||
|
CronJobList: () => import('@/views/ops/machine/cronjob/CronJobList.vue'),
|
||||||
|
SecurityConfList: () => import('@/views/ops/machine/security/SecurityConfList.vue'),
|
||||||
|
};
|
||||||
4
frontend/src/views/ops/mongo/route.ts
Normal file
4
frontend/src/views/ops/mongo/route.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
MongoList: () => import('@/views/ops/mongo/MongoList.vue'),
|
||||||
|
MongoDataOp: () => import('@/views/ops/mongo/MongoDataOp.vue'),
|
||||||
|
};
|
||||||
@@ -43,8 +43,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #right>
|
<template #right>
|
||||||
<Splitpanes class="default-theme">
|
<el-splitter>
|
||||||
<Pane size="35" max-size="50">
|
<el-splitter-panel size="35%" max="50%">
|
||||||
<div class="key-list-vtree h-full card !p-1">
|
<div class="key-list-vtree h-full card !p-1">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
@@ -141,9 +141,9 @@
|
|||||||
|
|
||||||
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
|
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
|
|
||||||
<Pane>
|
<el-splitter-panel>
|
||||||
<div class="h-full card !p-1 key-deatil">
|
<div class="h-full card !p-1 key-deatil">
|
||||||
<el-tabs class="h-full" @tab-remove="removeDataTab" v-model="state.activeName">
|
<el-tabs class="h-full" @tab-remove="removeDataTab" v-model="state.activeName">
|
||||||
<el-tab-pane class="h-full" closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
<el-tab-pane class="h-full" closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
||||||
@@ -151,8 +151,8 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
</Splitpanes>
|
</el-splitter>
|
||||||
</template>
|
</template>
|
||||||
</ResourceOpPanel>
|
</ResourceOpPanel>
|
||||||
|
|
||||||
@@ -196,7 +196,6 @@ import { keysToTree, sortByTreeNodes, keysToList } from './utils';
|
|||||||
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
||||||
import { sleep } from '@/common/utils/loading';
|
import { sleep } from '@/common/utils/loading';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
|
||||||
import { RedisInst } from './redis';
|
import { RedisInst } from './redis';
|
||||||
import { useAutoOpenResource } from '@/store/autoOpenResource';
|
import { useAutoOpenResource } from '@/store/autoOpenResource';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|||||||
4
frontend/src/views/ops/redis/route.ts
Normal file
4
frontend/src/views/ops/redis/route.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
RedisList: () => import('@/views/ops/redis/RedisList.vue'),
|
||||||
|
DataOperation: () => import('@/views/ops/redis/DataOperation.vue'),
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tag-tree-list card h-full flex">
|
<div class="tag-tree-list card !p-2 h-full flex">
|
||||||
<Splitpanes class="default-theme">
|
<el-splitter>
|
||||||
<Pane size="30" min-size="25" max-size="35" class="flex flex-col flex-1">
|
<el-splitter-panel size="30%" min="25%" max="35%" class="flex flex-col flex-1">
|
||||||
<div class="card !p-1 !mb-1 !mr-1 flex justify-between">
|
<div class="card !p-1 !mb-1 !mr-1 flex justify-between">
|
||||||
<div class="mb-1">
|
<div class="mb-1">
|
||||||
<el-input v-model="filterTag" clearable :placeholder="$t('tag.nameFilterPlaceholder')" class="mr-2 !w-[200px]" />
|
<el-input v-model="filterTag" clearable :placeholder="$t('tag.nameFilterPlaceholder')" class="mr-2 !w-[200px]" />
|
||||||
@@ -63,9 +63,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
|
|
||||||
<Pane min-size="40" size="70">
|
<el-splitter-panel>
|
||||||
<div class="ml-2 h-full">
|
<div class="ml-2 h-full">
|
||||||
<el-tabs class="h-full" @tab-change="onTabChange" v-model="state.activeTabName" v-if="currentTag">
|
<el-tabs class="h-full" @tab-change="onTabChange" v-model="state.activeTabName" v-if="currentTag">
|
||||||
<el-tab-pane :label="$t('common.detail')" :name="TagDetail">
|
<el-tab-pane :label="$t('common.detail')" :name="TagDetail">
|
||||||
@@ -134,8 +134,8 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
</Splitpanes>
|
</el-splitter>
|
||||||
|
|
||||||
<el-dialog width="500px" :title="saveTabDialog.title" :before-close="onCancelSaveTag" v-model="saveTabDialog.visible">
|
<el-dialog width="500px" :title="saveTabDialog.title" :before-close="onCancelSaveTag" v-model="saveTabDialog.visible">
|
||||||
<el-form ref="tagForm" :rules="rules" :model="saveTabDialog.form" label-width="auto">
|
<el-form ref="tagForm" :rules="rules" :model="saveTabDialog.form" label-width="auto">
|
||||||
@@ -167,7 +167,6 @@ import { tagApi } from './api';
|
|||||||
import { formatDate } from '@/common/utils/format';
|
import { formatDate } from '@/common/utils/format';
|
||||||
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu/index';
|
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu/index';
|
||||||
import { useUserInfo } from '@/store/userInfo';
|
import { useUserInfo } from '@/store/userInfo';
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||||
import EnumValue from '@/common/Enum';
|
import EnumValue from '@/common/Enum';
|
||||||
|
|||||||
5
frontend/src/views/ops/tag/route.ts
Normal file
5
frontend/src/views/ops/tag/route.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
TagTreeList: () => import('@/views/ops/tag/TagTreeList.vue'),
|
||||||
|
TeamList: () => import('@/views/ops/tag/TeamList.vue'),
|
||||||
|
AuthCertList: () => import('@/views/ops/tag/AuthCertList.vue'),
|
||||||
|
};
|
||||||
@@ -58,6 +58,10 @@ import config from '@/common/config';
|
|||||||
import { joinClientParams } from '@/common/request';
|
import { joinClientParams } from '@/common/request';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'Personal',
|
||||||
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
|
|||||||
3
frontend/src/views/personal/route.ts
Normal file
3
frontend/src/views/personal/route.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
Personal: () => import('@/views/personal/index.vue'),
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-popover
|
<el-popover
|
||||||
v-if="props.username"
|
v-if="props.username && props.username != '-'"
|
||||||
@show="getAccountInfo(props.username)"
|
@show="getAccountInfo(props.username)"
|
||||||
placement="top-start"
|
placement="top-start"
|
||||||
:title="$t('system.account.accountInfo')"
|
:title="$t('system.account.accountInfo')"
|
||||||
|
|||||||
@@ -33,16 +33,6 @@
|
|||||||
<el-input v-model.trim="form.meta.routeName"></el-input>
|
<el-input v-model.trim="form.meta.routeName"></el-input>
|
||||||
</FormItemTooltip>
|
</FormItemTooltip>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="form.type === menuTypeValue">
|
|
||||||
<FormItemTooltip
|
|
||||||
class="!w-full"
|
|
||||||
:label="$t('system.menu.componentPath')"
|
|
||||||
prop="meta.component"
|
|
||||||
:tooltip="$t('system.menu.componentPathTips')"
|
|
||||||
>
|
|
||||||
<el-input v-model.trim="form.meta.component"></el-input>
|
|
||||||
</FormItemTooltip>
|
|
||||||
</el-col>
|
|
||||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="form.type === menuTypeValue">
|
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="form.type === menuTypeValue">
|
||||||
<FormItemTooltip class="!w-full" :label="$t('system.menu.isCache')" prop="meta.isKeepAlive" :tooltip="$t('system.menu.isCacheTips')">
|
<FormItemTooltip class="!w-full" :label="$t('system.menu.isCache')" prop="meta.isKeepAlive" :tooltip="$t('system.menu.isCacheTips')">
|
||||||
<el-select v-model="form.meta.isKeepAlive" class="!w-full">
|
<el-select v-model="form.meta.isKeepAlive" class="!w-full">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card system-resource-list h-full flex">
|
<div class="card !p-2 system-resource-list h-full flex">
|
||||||
<Splitpanes class="default-theme">
|
<el-splitter>
|
||||||
<Pane size="30" min-size="25" max-size="35" class="flex flex-col flex-1">
|
<el-splitter-panel size="30%" max="35%" min="25%" class="flex flex-col flex-1">
|
||||||
<div class="card !p-1 mr-1 flex justify-between">
|
<div class="card !p-1 mr-1 flex justify-between">
|
||||||
<div class="mb-1">
|
<div class="mb-1">
|
||||||
<el-input v-model="filterResource" clearable :placeholder="$t('system.menu.filterPlaceholder')" class="mr-2 !w-[200px]" />
|
<el-input v-model="filterResource" clearable :placeholder="$t('system.menu.filterPlaceholder')" class="mr-2 !w-[200px]" />
|
||||||
@@ -60,9 +60,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
|
|
||||||
<Pane min-size="40" size="70">
|
<el-splitter-panel>
|
||||||
<div class="ml-2">
|
<div class="ml-2">
|
||||||
<el-tabs v-model="state.activeTabName" @tab-click="onTabClick" v-if="currentResource">
|
<el-tabs v-model="state.activeTabName" @tab-click="onTabClick" v-if="currentResource">
|
||||||
<el-tab-pane :label="$t('common.detail')" :name="ResourceDetail">
|
<el-tab-pane :label="$t('common.detail')" :name="ResourceDetail">
|
||||||
@@ -78,9 +78,6 @@
|
|||||||
<el-descriptions-item v-if="currentResource.type == menuTypeValue" :label="$t('system.menu.routerName')">
|
<el-descriptions-item v-if="currentResource.type == menuTypeValue" :label="$t('system.menu.routerName')">
|
||||||
{{ currentResource.meta.routeName }}
|
{{ currentResource.meta.routeName }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item v-if="currentResource.type == menuTypeValue" :label="$t('system.menu.componentPath')">
|
|
||||||
{{ currentResource.meta.component }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item v-if="currentResource.type == menuTypeValue" :label="$t('system.menu.isCache')">
|
<el-descriptions-item v-if="currentResource.type == menuTypeValue" :label="$t('system.menu.isCache')">
|
||||||
{{ currentResource.meta.isKeepAlive ? $t('system.menu.yes') : $t('system.menu.no') }}
|
{{ currentResource.meta.isKeepAlive ? $t('system.menu.yes') : $t('system.menu.no') }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@@ -126,8 +123,8 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</el-splitter-panel>
|
||||||
</Splitpanes>
|
</el-splitter>
|
||||||
|
|
||||||
<ResourceEdit
|
<ResourceEdit
|
||||||
:title="dialogForm.title"
|
:title="dialogForm.title"
|
||||||
@@ -152,7 +149,6 @@ import { resourceApi } from '../api';
|
|||||||
import { formatDate } from '@/common/utils/format';
|
import { formatDate } from '@/common/utils/format';
|
||||||
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||||
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
|
||||||
import { isPrefixSubsequence } from '@/common/utils/string';
|
import { isPrefixSubsequence } from '@/common/utils/string';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg } from '@/hooks/useI18n';
|
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg } from '@/hooks/useI18n';
|
||||||
|
|||||||
7
frontend/src/views/system/route.ts
Normal file
7
frontend/src/views/system/route.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default {
|
||||||
|
AccountList: () => import('@/views/system/account/AccountList.vue'),
|
||||||
|
ResourceList: () => import('@/views/system/resource/ResourceList.vue'),
|
||||||
|
RoleList: () => import('@/views/system/role/RoleList.vue'),
|
||||||
|
ConfigList: () => import('@/views/system/config/ConfigList.vue'),
|
||||||
|
SyslogList: () => import('@/views/system/syslog/SyslogList.vue'),
|
||||||
|
};
|
||||||
@@ -24,21 +24,21 @@ require (
|
|||||||
github.com/mojocn/base64Captcha v1.3.8 // 验证码
|
github.com/mojocn/base64Captcha v1.3.8 // 验证码
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pkg/sftp v1.13.9
|
github.com/pkg/sftp v1.13.9
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.5.0
|
||||||
github.com/redis/go-redis/v9 v9.8.0
|
github.com/redis/go-redis/v9 v9.10.0
|
||||||
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
||||||
github.com/sijms/go-ora/v2 v2.8.24
|
github.com/sijms/go-ora/v2 v2.8.24
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/tidwall/gjson v1.18.0
|
github.com/tidwall/gjson v1.18.0
|
||||||
github.com/veops/go-ansiterm v0.0.5
|
github.com/veops/go-ansiterm v0.0.5
|
||||||
go.mongodb.org/mongo-driver v1.16.0 // mongo
|
go.mongodb.org/mongo-driver v1.16.0 // mongo
|
||||||
golang.org/x/crypto v0.38.0 // ssh
|
golang.org/x/crypto v0.39.0 // ssh
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.30.0
|
||||||
golang.org/x/sync v0.14.0
|
golang.org/x/sync v0.15.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
// gorm
|
// gorm
|
||||||
gorm.io/driver/mysql v1.5.7
|
gorm.io/driver/mysql v1.6.0
|
||||||
gorm.io/gorm v1.30.0
|
gorm.io/gorm v1.30.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ require (
|
|||||||
golang.org/x/image v0.23.0 // indirect
|
golang.org/x/image v0.23.0 // indirect
|
||||||
golang.org/x/net v0.34.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/text v0.25.0 // indirect
|
golang.org/x/text v0.26.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
modernc.org/libc v1.22.5 // indirect
|
modernc.org/libc v1.22.5 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ func createSqlExecRecord(ctx context.Context, execSqlReq *dto.DbSqlExecReq, sql
|
|||||||
dbSqlExecRecord.Sql = sql
|
dbSqlExecRecord.Sql = sql
|
||||||
dbSqlExecRecord.Remark = execSqlReq.Remark
|
dbSqlExecRecord.Remark = execSqlReq.Remark
|
||||||
dbSqlExecRecord.Status = entity.DbSqlExecStatusSuccess
|
dbSqlExecRecord.Status = entity.DbSqlExecStatusSuccess
|
||||||
dbSqlExecRecord.FillBaseInfo(model.IdGenTypeNone, contextx.GetLoginAccount(ctx))
|
|
||||||
return dbSqlExecRecord
|
return dbSqlExecRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +129,7 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *dto.DbSqlExecRe
|
|||||||
}
|
}
|
||||||
execRes.ErrorMsg = err.Error()
|
execRes.ErrorMsg = err.Error()
|
||||||
} else {
|
} else {
|
||||||
d.saveSqlExecLog(dbSqlExecRecord, dbSqlExecRecord.Res)
|
d.saveSqlExecLog(ctx, dbSqlExecRecord, dbSqlExecRecord.Res)
|
||||||
}
|
}
|
||||||
allExecRes = append(allExecRes, execRes)
|
allExecRes = append(allExecRes, execRes)
|
||||||
return nil
|
return nil
|
||||||
@@ -191,7 +190,7 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *dto.DbSqlExecRe
|
|||||||
}
|
}
|
||||||
execRes.ErrorMsg = err.Error()
|
execRes.ErrorMsg = err.Error()
|
||||||
} else {
|
} else {
|
||||||
d.saveSqlExecLog(dbSqlExecRecord, execRes.Res)
|
d.saveSqlExecLog(ctx, dbSqlExecRecord, execRes.Res)
|
||||||
}
|
}
|
||||||
allExecRes = append(allExecRes, execRes)
|
allExecRes = append(allExecRes, execRes)
|
||||||
}
|
}
|
||||||
@@ -318,10 +317,10 @@ func (d *dbSqlExecAppImpl) GetPageList(condition *entity.DbSqlExecQuery, orderBy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存sql执行记录,如果是查询类则根据系统配置判断是否保存
|
// 保存sql执行记录,如果是查询类则根据系统配置判断是否保存
|
||||||
func (d *dbSqlExecAppImpl) saveSqlExecLog(dbSqlExecRecord *entity.DbSqlExec, res any) {
|
func (d *dbSqlExecAppImpl) saveSqlExecLog(ctx context.Context, dbSqlExecRecord *entity.DbSqlExec, res any) {
|
||||||
if dbSqlExecRecord.Type != entity.DbSqlExecTypeQuery {
|
if dbSqlExecRecord.Type != entity.DbSqlExecTypeQuery {
|
||||||
dbSqlExecRecord.Res = jsonx.ToStr(res)
|
dbSqlExecRecord.Res = jsonx.ToStr(res)
|
||||||
d.dbSqlExecRepo.Insert(context.TODO(), dbSqlExecRecord)
|
d.dbSqlExecRepo.Insert(ctx, dbSqlExecRecord)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +328,7 @@ func (d *dbSqlExecAppImpl) saveSqlExecLog(dbSqlExecRecord *entity.DbSqlExec, res
|
|||||||
dbSqlExecRecord.Table = "-"
|
dbSqlExecRecord.Table = "-"
|
||||||
dbSqlExecRecord.OldValue = "-"
|
dbSqlExecRecord.OldValue = "-"
|
||||||
dbSqlExecRecord.Type = entity.DbSqlExecTypeQuery
|
dbSqlExecRecord.Type = entity.DbSqlExecTypeQuery
|
||||||
d.dbSqlExecRepo.Insert(context.TODO(), dbSqlExecRecord)
|
d.dbSqlExecRepo.Insert(ctx, dbSqlExecRecord)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ type DbSqlExecQuery struct {
|
|||||||
Table string `json:"table" form:"table"`
|
Table string `json:"table" form:"table"`
|
||||||
Type int8 `json:"type" form:"type"` // 类型
|
Type int8 `json:"type" form:"type"` // 类型
|
||||||
FlowBizKey string `json:"flowBizKey" form:"flowBizKey"`
|
FlowBizKey string `json:"flowBizKey" form:"flowBizKey"`
|
||||||
|
Keyword string `json:"keyword" form:"keyword"`
|
||||||
|
StartTime string `json:"startTime" form:"startTime"`
|
||||||
|
EndTime string `json:"endTime" form:"endTime"`
|
||||||
|
|
||||||
Status []int8
|
Status []int8
|
||||||
CreatorId uint64
|
CreatorId uint64
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ func (d *dbSqlExecRepoImpl) GetPageList(condition *entity.DbSqlExecQuery, orderB
|
|||||||
Eq("creator_id", condition.CreatorId).
|
Eq("creator_id", condition.CreatorId).
|
||||||
Eq("flow_biz_key", condition.FlowBizKey).
|
Eq("flow_biz_key", condition.FlowBizKey).
|
||||||
In("status", condition.Status).
|
In("status", condition.Status).
|
||||||
|
Like("sql", condition.Keyword).
|
||||||
|
Ge("create_time", condition.StartTime).
|
||||||
|
Le("create_time", condition.EndTime).
|
||||||
RLike("db", condition.Db).OrderBy(orderBy...)
|
RLike("db", condition.Db).OrderBy(orderBy...)
|
||||||
return d.PageByCond(qd, condition.PageParam)
|
return d.PageByCond(qd, condition.PageParam)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ func (la *LoginAccount) GetAesKey() string {
|
|||||||
|
|
||||||
// 系统账号
|
// 系统账号
|
||||||
var SysAccount = &LoginAccount{
|
var SysAccount = &LoginAccount{
|
||||||
Id: 1,
|
Id: 0,
|
||||||
Username: "system",
|
Username: "-",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user