diff --git a/mayfly_go_web/src/theme/app.scss b/mayfly_go_web/src/theme/app.scss index d4537490..1bce375d 100644 --- a/mayfly_go_web/src/theme/app.scss +++ b/mayfly_go_web/src/theme/app.scss @@ -1,225 +1,261 @@ /* 初始化样式 ------------------------------- */ * { - margin: 0; - padding: 0; - box-sizing: border-box; - outline: none !important; + margin: 0; + padding: 0; + box-sizing: border-box; + outline: none !important; } html, body, #app { - margin: 0; - padding: 0; - width: 100%; - height: 100%; - font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; - font-weight: 450; - -webkit-font-smoothing: antialiased; - -webkit-tap-highlight-color: transparent; - background-color: #f8f8f8; - font-size: 14px; - overflow: hidden; - position: relative; + margin: 0; + padding: 0; + width: 100%; + height: 100%; + font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif; + font-weight: 450; + -webkit-font-smoothing: antialiased; + -webkit-tap-highlight-color: transparent; + background-color: #f8f8f8; + font-size: 14px; + overflow: hidden; + position: relative; } /* 主布局样式 ------------------------------- */ .layout-container { - width: 100%; - height: 100%; - .layout-aside { - background: var(--bg-menuBar); - box-shadow: 2px 0 6px rgb(0 21 41 / 1%); - height: inherit; - position: relative; - z-index: 1; - display: flex; - flex-direction: column; - overflow-x: hidden !important; - .el-scrollbar__view { - overflow: hidden; - } - } - .layout-header { - padding: 0 !important; - } - .layout-main { - padding: 0 !important; - overflow: hidden; - width: 100%; - background-color: #f8f8f8; - } - .el-scrollbar { - width: 100%; - } - .layout-view-bg-white { - background: white; - width: 100%; - height: 100%; - border-radius: 4px; - border: 1px solid #ebeef5; - } - .layout-el-aside-br-color { - border-right: 1px solid rgb(238, 238, 238); - } - .layout-aside-width-default { - width: 220px !important; - transition: width 0.3s ease; - } - .layout-aside-width64 { - width: 64px !important; - transition: width 0.3s ease; - } - .layout-aside-width1 { - width: 1px !important; - transition: width 0.3s ease; - } - .layout-scrollbar { - @extend .el-scrollbar; - padding: 10px; - } - .layout-mian-height-50 { - height: calc(100vh - 50px); - } - .layout-columns-warp { - flex: 1; - display: flex; - overflow: hidden; - } - .layout-hide { - display: none; - } + width: 100%; + height: 100%; + + .layout-aside { + background: var(--bg-menuBar); + box-shadow: 2px 0 6px rgb(0 21 41 / 1%); + height: inherit; + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + overflow-x: hidden !important; + + .el-scrollbar__view { + overflow: hidden; + } + } + + .layout-header { + padding: 0 !important; + } + + .layout-main { + padding: 0 !important; + overflow: hidden; + width: 100%; + background-color: #f8f8f8; + } + + .el-scrollbar { + width: 100%; + } + + .layout-view-bg-white { + background: white; + width: 100%; + height: 100%; + border-radius: 4px; + border: 1px solid #ebeef5; + } + + .layout-el-aside-br-color { + border-right: 1px solid rgb(238, 238, 238); + } + + .layout-aside-width-default { + width: 220px !important; + transition: width 0.3s ease; + } + + .layout-aside-width64 { + width: 64px !important; + transition: width 0.3s ease; + } + + .layout-aside-width1 { + width: 1px !important; + transition: width 0.3s ease; + } + + .layout-scrollbar { + @extend .el-scrollbar; + padding: 10px; + } + + .layout-mian-height-50 { + height: calc(100vh - 50px); + } + + .layout-columns-warp { + flex: 1; + display: flex; + overflow: hidden; + } + + .layout-hide { + display: none; + } } /* element plus 全局样式 ------------------------------- */ .layout-breadcrumb-seting { - .el-drawer__header { - padding: 0 15px !important; - height: 50px; - display: flex; - align-items: center; - margin-bottom: 0 !important; - border-bottom: 1px solid rgb(230, 230, 230); - } - .el-divider { - background-color: rgb(230, 230, 230); - } + .el-drawer__header { + padding: 0 15px !important; + height: 50px; + display: flex; + align-items: center; + margin-bottom: 0 !important; + border-bottom: 1px solid rgb(230, 230, 230); + } + + .el-divider { + background-color: rgb(230, 230, 230); + } } /* nprogress 进度条跟随主题颜色 ------------------------------- */ #nprogress { - .bar { - background: var(--color-primary) !important; - z-index: 9999999 !important; - } + .bar { + background: var(--color-primary) !important; + z-index: 9999999 !important; + } } /* flex 弹性布局 ------------------------------- */ .flex { - display: flex; + display: flex; } + .flex-auto { - flex: 1; + flex: 1; } + .flex-center { - @extend .flex; - flex-direction: column; - width: 100%; - overflow: hidden; + @extend .flex; + flex-direction: column; + width: 100%; + overflow: hidden; } + .flex-margin { - margin: auto; + margin: auto; } + .flex-warp { - display: flex; - flex-wrap: wrap; - align-content: flex-start; - margin: 0 -5px; - .flex-warp-item { - padding: 5px; - .flex-warp-item-box { - width: 100%; - height: 100%; - } - } + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin: 0 -5px; + + .flex-warp-item { + padding: 5px; + + .flex-warp-item-box { + width: 100%; + height: 100%; + } + } } /* 宽高 100% ------------------------------- */ .w100 { - width: 100% !important; + width: 100% !important; } + .h100 { - height: 100% !important; + height: 100% !important; } + .vh100 { - height: 100vh !important; + height: 100vh !important; } + .max100vh { - max-height: 100vh !important; + max-height: 100vh !important; } + .min100vh { - min-height: 100vh !important; + min-height: 100vh !important; } /* 颜色值 ------------------------------- */ .color-primary { - color: var(--color-primary); + color: var(--color-primary); } + .color-success { - color: var(--color-success); + color: var(--color-success); } + .color-warning { - color: var(--color-warning); + color: var(--color-warning); } + .color-danger { - color: var(--color-danger); + color: var(--color-danger); } + .color-info { - color: var(--color-info); + color: var(--color-info); } /* 字体大小全局样式 ------------------------------- */ @for $i from 10 through 32 { - .font#{$i} { - font-size: #{$i}px !important; - } + .font#{$i} { + font-size: #{$i}px !important; + } } /* 外边距、内边距全局样式 ------------------------------- */ @for $i from 1 through 35 { - .mt#{$i} { - margin-top: #{$i}px !important; - } - .mr#{$i} { - margin-right: #{$i}px !important; - } - .mb#{$i} { - margin-bottom: #{$i}px !important; - } - .ml#{$i} { - margin-left: #{$i}px !important; - } - .pt#{$i} { - padding-top: #{$i}px !important; - } - .pr#{$i} { - padding-right: #{$i}px !important; - } - .pb#{$i} { - padding-bottom: #{$i}px !important; - } - .pl#{$i} { - padding-left: #{$i}px !important; - } + .mt#{$i} { + margin-top: #{$i}px !important; + } + + .mr#{$i} { + margin-right: #{$i}px !important; + } + + .mb#{$i} { + margin-bottom: #{$i}px !important; + } + + .ml#{$i} { + margin-left: #{$i}px !important; + } + + .pt#{$i} { + padding-top: #{$i}px !important; + } + + .pr#{$i} { + padding-right: #{$i}px !important; + } + + .pb#{$i} { + padding-bottom: #{$i}px !important; + } + + .pl#{$i} { + padding-left: #{$i}px !important; + } } @@ -249,15 +285,22 @@ body, .el-menu .fa:not(.is-children) { font-size: 14px; } -.gray-mode{ + +.gray-mode { filter: grayscale(100%); } -.fade-enter-active, .fade-leave-active { +.fade-enter-active, +.fade-leave-active { transition: opacity .2s ease-in-out; } -.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { + +.fade-enter, +.fade-leave-to + +/* .fade-leave-active below version 2.1.8 */ + { opacity: 0; } @@ -270,7 +313,7 @@ body, -webkit-user-select: none; -ms-user-select: none; user-select: none; - } +} .toolbar { width: 100%; @@ -297,4 +340,14 @@ body, .f12 { font-size: 12px +} + +.icon-middle { + .el-icon { + display: inline-flex; + justify-content: center; + align-items: center; + cursor: pointer; + vertical-align: middle; + } } \ No newline at end of file diff --git a/mayfly_go_web/src/views/ops/component/TagMenu.vue b/mayfly_go_web/src/views/ops/component/TagMenu.vue deleted file mode 100644 index 81f173d6..00000000 --- a/mayfly_go_web/src/views/ops/component/TagMenu.vue +++ /dev/null @@ -1,124 +0,0 @@ - - - - - \ No newline at end of file diff --git a/mayfly_go_web/src/views/ops/component/TagTree.vue b/mayfly_go_web/src/views/ops/component/TagTree.vue new file mode 100644 index 00000000..63a7a71f --- /dev/null +++ b/mayfly_go_web/src/views/ops/component/TagTree.vue @@ -0,0 +1,122 @@ + + + + + \ No newline at end of file diff --git a/mayfly_go_web/src/views/ops/component/tag.ts b/mayfly_go_web/src/views/ops/component/tag.ts new file mode 100644 index 00000000..39df81ca --- /dev/null +++ b/mayfly_go_web/src/views/ops/component/tag.ts @@ -0,0 +1,38 @@ +export class TagTreeNode { + /** + * 节点id + */ + key: any + + /** + * 节点名称 + */ + label: string + + /** + * 树节点类型 + */ + type: any + + isLeaf: boolean = false; + + params: any; + + static TagPath = -1; + + constructor(key: any, label: string, type?: any) { + this.key = key; + this.label = label; + this.type = type || TagTreeNode.TagPath; + } + + withIsLeaf(isLeaf: boolean) { + this.isLeaf = isLeaf; + return this; + } + + withParams(params: any) { + this.params = params; + return this; + } +} \ No newline at end of file diff --git a/mayfly_go_web/src/views/ops/db/SqlExec.vue b/mayfly_go_web/src/views/ops/db/SqlExec.vue index 47539e27..4ef39b2e 100644 --- a/mayfly_go_web/src/views/ops/db/SqlExec.vue +++ b/mayfly_go_web/src/views/ops/db/SqlExec.vue @@ -23,8 +23,51 @@ - + + + @@ -53,19 +96,33 @@ - - \ No newline at end of file diff --git a/mayfly_go_web/src/views/ops/db/db.ts b/mayfly_go_web/src/views/ops/db/db.ts index 0384381e..8be66b81 100644 --- a/mayfly_go_web/src/views/ops/db/db.ts +++ b/mayfly_go_web/src/views/ops/db/db.ts @@ -411,6 +411,11 @@ export class TabInfo { */ key: string + /** + * 菜单树节点key + */ + treeNodeKey: string + /** * 数据库实例id */ diff --git a/mayfly_go_web/src/views/ops/machine/FileManage.vue b/mayfly_go_web/src/views/ops/machine/FileManage.vue index 284d8a70..124bfc8b 100755 --- a/mayfly_go_web/src/views/ops/machine/FileManage.vue +++ b/mayfly_go_web/src/views/ops/machine/FileManage.vue @@ -446,7 +446,6 @@ const showCreateFileDialog = (node: any) => { const createFile = async () => { const node = state.createFileDialog.node; - console.log(node.data); const name = state.createFileDialog.name; const type = state.createFileDialog.type; const path = node.data.path + '/' + name; diff --git a/mayfly_go_web/src/views/ops/mongo/MongoDataOp.vue b/mayfly_go_web/src/views/ops/mongo/MongoDataOp.vue index ad22b7af..779d7d51 100644 --- a/mayfly_go_web/src/views/ops/mongo/MongoDataOp.vue +++ b/mayfly_go_web/src/views/ops/mongo/MongoDataOp.vue @@ -2,12 +2,50 @@
- + + + + + + - + - + { - if (inst) { - if (!state.instances.dbs[inst.id]) { - const res = await mongoApi.databases.request({ id: inst.id }); - state.instances.dbs[inst.id] = res.Databases; - fn && fn(res.Databases) +/** + * instmap; tagPaht -> mongo info[] + */ +const instMap: Map = new Map(); + +const getInsts = async () => { + const res = await mongoApi.mongoList.request({ pageNum: 1, pageSize: 1000, }); + if (!res.total) return + for (const mongoInfo of res.list) { + const tagPath = mongoInfo.tagPath; + let mongoInsts = instMap.get(tagPath) || []; + mongoInsts.push(mongoInfo); + instMap.set(tagPath, mongoInsts); + } +} + +/** + * 加载文件树节点 + * @param {Object} node + * @param {Object} resolve + */ +const loadNode = async (node: any) => { + // 一级为tagPath + if (node.level === 0) { + await getInsts(); + const tagPaths = instMap.keys(); + const tagNodes = []; + for (let tagPath of tagPaths) { + tagNodes.push(new TagTreeNode(tagPath, tagPath)); } + return tagNodes; + } + + const data = node.data; + const params = data.params; + const nodeType = data.type; + + // 点击标签 -> 显示mongo信息列表 + if (nodeType === TagTreeNode.TagPath) { + const mongoInfos = instMap.get(data.key) + return mongoInfos?.map((x: any) => { + return new TagTreeNode(`${data.key}.${x.id}`, x.name, NodeType.Mongo).withParams(x); + }); + } + + // 点击mongo -> 加载mongo数据库列表 + if (nodeType === NodeType.Mongo) { + return await getDatabases(params); + } + + // 点击数据库列表 -> 加载数据库下拥有的菜单列表 + if (nodeType === NodeType.Dbs) { + return [new TagTreeNode(`${params.id}.${params.dbName}.mongo-coll`, '集合', NodeType.CollMenu).withParams(params)]; + } + + // 点击数据库集合节点 -> 加载集合列表 + if (nodeType === NodeType.CollMenu) { + return await getCollections(params.id, params.dbName) + } + + return []; +}; + +/** + * 获取实例的所有库信息 + * @param inst 实例信息 + */ +const getDatabases = async (inst: any) => { + const res = await mongoApi.databases.request({ id: inst.id }); + return res.Databases.map((x: any) => { + const dbName = x.Name; + return new TagTreeNode(`${inst.id}.${dbName}`, dbName, NodeType.Dbs).withParams({ + id: inst.id, + dbName, + size: x.SizeOnDisk, + }) + }) +} + +/** + * 获取集合列表信息 + * @param inst + */ +const getCollections = async (id: any, database: string) => { + const colls = await mongoApi.collections.request({ id, database }); + return colls.map((x: any) => { + return new TagTreeNode(`${id}.${database}.${x}`, x, NodeType.Coll).withIsLeaf(true).withParams({ + id, + database, + collection: x, + }); + }); +} + +const nodeClick = (data: any) => { + // 点击集合 + if (data.type === NodeType.Coll) { + const { id, database, collection } = data.params; + changeCollection(id, database, collection); } } -const loadTableNames = async (inst: any, database: string, fn: Function) => { - let tbs = await mongoApi.collections.request({ id: inst.id, database }); - let tables = []; - for (let tb of tbs) { - tables.push({ tableName: tb, show: true }) - } - state.instances.tables[inst.id + database] = tables - fn(tables) -} - -const changeCollection = (inst: any, schema: string, collection: string) => { - const label = `${inst.id}:\`${schema}\`.${collection}`; +const changeCollection = (id: any, schema: string, collection: string) => { + const label = `${id}:\`${schema}\`.${collection}`; let dataTab = state.dataTabs[label]; if (!dataTab) { // 默认查询参数 @@ -186,7 +317,7 @@ const changeCollection = (inst: any, schema: string, collection: string) => { key: label, label: label, name: label, - mongoId: inst.id, + mongoId: id, database: schema, collection, datas: [], @@ -359,28 +490,13 @@ const removeDataTab = (targetName: string) => { delete state.dataTabs[targetName]; }; -const loadInstances = async () => { - const res = await mongoApi.mongoList.request({ pageNum: 1, pageSize: 1000, }); - if (!res.total) return - state.instances = { tags: {}, tree: {}, dbs: {}, tables: {} }; // 初始化变量 - for (const db of res.list) { - let arr = state.instances.tree[db.tagId] || [] - const { tagId, tagPath } = db - // tags - state.instances.tags[db.tagId] = { tagId, tagPath } - // 实例 - arr.push(db) - state.instances.tree[db.tagId] = arr; - } -} - const getNowDataTab = () => { return state.dataTabs[state.activeName] } - diff --git a/mayfly_go_web/src/views/ops/redis/DataOperation.vue b/mayfly_go_web/src/views/ops/redis/DataOperation.vue index e5521814..42d27068 100644 --- a/mayfly_go_web/src/views/ops/redis/DataOperation.vue +++ b/mayfly_go_web/src/views/ops/redis/DataOperation.vue @@ -2,9 +2,38 @@
- + + + + + + + +
@@ -87,17 +116,26 @@ - diff --git a/mayfly_go_web/src/views/ops/redis/RedisEdit.vue b/mayfly_go_web/src/views/ops/redis/RedisEdit.vue index ddda05e5..a894370f 100644 --- a/mayfly_go_web/src/views/ops/redis/RedisEdit.vue +++ b/mayfly_go_web/src/views/ops/redis/RedisEdit.vue @@ -32,6 +32,13 @@ + + + + + diff --git a/mayfly_go_web/src/views/ops/redis/RedisInstanceTree.vue b/mayfly_go_web/src/views/ops/redis/RedisInstanceTree.vue deleted file mode 100644 index 41cfef53..00000000 --- a/mayfly_go_web/src/views/ops/redis/RedisInstanceTree.vue +++ /dev/null @@ -1,100 +0,0 @@ - - - - - \ No newline at end of file diff --git a/server/internal/db/application/db_sql_exec.go b/server/internal/db/application/db_sql_exec.go index 3a3cbffe..21ed3556 100644 --- a/server/internal/db/application/db_sql_exec.go +++ b/server/internal/db/application/db_sql_exec.go @@ -155,12 +155,15 @@ func doSelect(selectStmt *sqlparser.Select, execSqlReq *DbSqlExecReq) (*DbSqlExe selectExprsStr := sqlparser.String(selectStmt.SelectExprs) if selectExprsStr == "*" || strings.Contains(selectExprsStr, ".*") || len(strings.Split(selectExprsStr, ",")) > 1 { - limit := selectStmt.Limit - biz.NotNil(limit, "请完善分页信息后执行") - count, err := strconv.Atoi(sqlparser.String(limit.Rowcount)) - biz.ErrIsNil(err, "分页参数有误") + // 如果配置为0,则不校验分页参数 maxCount := sysapp.GetConfigApp().GetConfig(sysentity.ConfigKeyDbQueryMaxCount).IntValue(200) - biz.IsTrue(count <= maxCount, fmt.Sprintf("查询结果集数需小于系统配置的%d条", maxCount)) + if maxCount != 0 { + limit := selectStmt.Limit + biz.NotNil(limit, "请完善分页信息后执行") + count, err := strconv.Atoi(sqlparser.String(limit.Rowcount)) + biz.ErrIsNil(err, "分页参数有误") + biz.IsTrue(count <= maxCount, fmt.Sprintf("查询结果集数需小于系统配置的%d条", maxCount)) + } } return doRead(execSqlReq)