mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
feat: mongo优化
This commit is contained in:
@@ -10,7 +10,7 @@ RUN yarn
|
|||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
# 构建后端资源
|
# 构建后端资源
|
||||||
FROM golang:1.20-alpine3.16 as be-builder
|
FROM golang:1.21.0 as be-builder
|
||||||
|
|
||||||
ENV GOPROXY https://goproxy.cn
|
ENV GOPROXY https://goproxy.cn
|
||||||
WORKDIR /mayfly
|
WORKDIR /mayfly
|
||||||
@@ -31,6 +31,9 @@ FROM alpine:3.16
|
|||||||
|
|
||||||
RUN apk add --no-cache ca-certificates bash expat
|
RUN apk add --no-cache ca-certificates bash expat
|
||||||
|
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/\$TZ /etc/localtime && echo \$TZ > /etc/timezone
|
||||||
|
|
||||||
WORKDIR /mayfly
|
WORKDIR /mayfly
|
||||||
|
|
||||||
COPY --from=be-builder /mayfly/mayfly-go /usr/local/bin/mayfly-go
|
COPY --from=be-builder /mayfly/mayfly-go /usr/local/bin/mayfly-go
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
export enum ResultEnum {
|
|
||||||
SUCCESS = 200,
|
|
||||||
ERROR = 400,
|
|
||||||
PARAM_ERROR = 405,
|
|
||||||
SERVER_ERROR = 500,
|
|
||||||
NO_PERMISSION = 501,
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,7 @@ export function exportCsv(filename: string, columns: string[], datas: []) {
|
|||||||
let link = document.createElement('a');
|
let link = document.createElement('a');
|
||||||
let exportContent = '\uFEFF';
|
let exportContent = '\uFEFF';
|
||||||
let blob = new Blob([exportContent + csvString], {
|
let blob = new Blob([exportContent + csvString], {
|
||||||
type: 'text/plain;charset=utrf-8',
|
type: 'text/plain;charset=utf-8',
|
||||||
});
|
});
|
||||||
link.id = 'download-csv';
|
link.id = 'download-csv';
|
||||||
link.setAttribute('href', URL.createObjectURL(blob));
|
link.setAttribute('href', URL.createObjectURL(blob));
|
||||||
|
|||||||
@@ -35,55 +35,81 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="20">
|
<el-col :span="20">
|
||||||
<el-container id="mongo-tab" style="border: 1px solid #eee; margin-top: 1px">
|
<div id="mongo-tab" style="border: 1px solid #eee; margin-top: 1px">
|
||||||
<el-tabs @tab-remove="removeDataTab" style="width: 100%; margin-left: 5px" v-model="state.activeName">
|
<el-row v-if="nowColl">
|
||||||
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
<el-descriptions :column="10" size="small" border>
|
||||||
<el-row>
|
<!-- <el-descriptions-item label-align="right" label="tag">xxx</el-descriptions-item> -->
|
||||||
<el-col :span="2">
|
|
||||||
<div>
|
|
||||||
<el-link @click="findCommand(state.activeName)" icon="refresh" :underline="false" class=""> </el-link>
|
|
||||||
<el-link @click="onEditDoc(null)" class="ml5" type="primary" icon="plus" :underline="false"> </el-link>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="22">
|
|
||||||
<el-input
|
|
||||||
ref="findParamInputRef"
|
|
||||||
v-model="dt.findParamStr"
|
|
||||||
placeholder="点击输入相应查询条件"
|
|
||||||
@focus="showFindDialog(dt.key)"
|
|
||||||
>
|
|
||||||
<template #prepend>查询参数</template>
|
|
||||||
</el-input>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-row :style="`height: ${dataHeight}; overflow: auto;`">
|
|
||||||
<el-col :span="6" v-for="item in dt.datas" :key="item">
|
|
||||||
<el-card :body-style="{ padding: '0px', position: 'relative' }">
|
|
||||||
<el-input type="textarea" v-model="item.value" :rows="10" />
|
|
||||||
<div style="padding: 3px; float: right" class="mr5 mongo-doc-btns">
|
|
||||||
<div>
|
|
||||||
<el-link @click="onEditDoc(item)" :underline="false" type="success" icon="MagicStick"></el-link>
|
|
||||||
|
|
||||||
<!-- <el-divider direction="vertical" border-style="dashed" /> -->
|
<el-descriptions-item label="ns" label-align="right">
|
||||||
|
{{ nowColl.stats.ns }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="count" label-align="right">
|
||||||
|
{{ nowColl.stats.count }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="avgObjSize" label-align="right">
|
||||||
|
{{ formatByteSize(nowColl.stats.avgObjSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="size" label-align="right">
|
||||||
|
{{ formatByteSize(nowColl.stats.size) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="totalSize" label-align="right">
|
||||||
|
{{ formatByteSize(nowColl.stats.totalSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="storageSize" label-align="right">
|
||||||
|
{{ formatByteSize(nowColl.stats.storageSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="freeStorageSize" label-align="right">
|
||||||
|
{{ formatByteSize(nowColl.stats.freeStorageSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<!-- <el-link @click="onSaveDoc(item.value)" :underline="false"
|
<el-row type="flex">
|
||||||
type="warning" icon="DocumentChecked"></el-link> -->
|
<el-tabs @tab-remove="removeDataTab" style="width: 100%; margin-left: 5px" v-model="state.activeName">
|
||||||
|
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-row>
|
||||||
|
<el-col :span="2">
|
||||||
<el-popconfirm @confirm="onDeleteDoc(item.value)" title="确定删除该文档?">
|
<div class="mt5">
|
||||||
<template #reference>
|
<el-link @click="findCommand(state.activeName)" icon="refresh" :underline="false" class=""> </el-link>
|
||||||
<el-link :underline="false" type="danger" icon="DocumentDelete"> </el-link>
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
</template>
|
<el-link v-auth="perms.saveData" @click="onEditDoc(null)" type="primary" icon="plus" :underline="false"> </el-link>
|
||||||
</el-popconfirm>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-col>
|
||||||
</el-col>
|
<el-col :span="22">
|
||||||
</el-row>
|
<el-input
|
||||||
</el-tab-pane>
|
ref="findParamInputRef"
|
||||||
</el-tabs>
|
v-model="dt.findParamStr"
|
||||||
</el-container>
|
placeholder="点击输入相应查询条件"
|
||||||
|
@focus="showFindDialog(dt.key)"
|
||||||
|
>
|
||||||
|
<template #prepend>查询参数</template>
|
||||||
|
</el-input>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :style="`height: ${dataHeight}; overflow: auto;`">
|
||||||
|
<el-col :span="6" v-for="item in dt.datas" :key="item">
|
||||||
|
<el-card :body-style="{ padding: '0px', position: 'relative' }">
|
||||||
|
<el-input type="textarea" v-model="item.value" :rows="10" />
|
||||||
|
<div style="padding: 3px; float: right" class="mr5 mongo-doc-btns">
|
||||||
|
<div>
|
||||||
|
<el-link @click="onEditDoc(item)" :underline="false" type="success" icon="MagicStick"></el-link>
|
||||||
|
|
||||||
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
|
<el-popconfirm @confirm="onDeleteDoc(item.value)" title="确定删除该文档?" width="160">
|
||||||
|
<template #reference>
|
||||||
|
<el-link v-auth="perms.delData" :underline="false" type="danger" icon="DocumentDelete"> </el-link>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
@@ -120,7 +146,7 @@
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<div>
|
<div>
|
||||||
<el-button @click="docEditDialog.visible = false">取 消</el-button>
|
<el-button @click="docEditDialog.visible = false">取 消</el-button>
|
||||||
<el-button @click="onSaveDoc" type="primary">确 定</el-button>
|
<el-button v-auth="perms.saveData" @click="onSaveDoc" type="primary">确 定</el-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@@ -131,7 +157,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { mongoApi } from './api';
|
import { mongoApi } from './api';
|
||||||
import { defineAsyncComponent, reactive, ref, toRefs } from 'vue';
|
import { computed, defineAsyncComponent, reactive, ref, toRefs } from 'vue';
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
import { isTrue, notBlank } from '@/common/assert';
|
import { isTrue, notBlank } from '@/common/assert';
|
||||||
@@ -141,6 +167,11 @@ import { formatByteSize } from '@/common/utils/format';
|
|||||||
|
|
||||||
const MonacoEditor = defineAsyncComponent(() => import('@/components/monaco/MonacoEditor.vue'));
|
const MonacoEditor = defineAsyncComponent(() => import('@/components/monaco/MonacoEditor.vue'));
|
||||||
|
|
||||||
|
const perms = {
|
||||||
|
saveData: 'mongo:data:save',
|
||||||
|
delData: 'mongo:data:del',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 树节点类型
|
* 树节点类型
|
||||||
*/
|
*/
|
||||||
@@ -154,7 +185,7 @@ class NodeType {
|
|||||||
const findParamInputRef: any = ref(null);
|
const findParamInputRef: any = ref(null);
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tags: [],
|
tags: [],
|
||||||
dataHeight: `${window.innerHeight - 194}px`,
|
dataHeight: `${window.innerHeight - 194 - 35}px`,
|
||||||
mongoList: [] as any,
|
mongoList: [] as any,
|
||||||
activeName: '', // 当前操作的tab
|
activeName: '', // 当前操作的tab
|
||||||
dataTabs: {} as any, // 数据tabs
|
dataTabs: {} as any, // 数据tabs
|
||||||
@@ -185,6 +216,10 @@ const state = reactive({
|
|||||||
|
|
||||||
const { dataHeight, findDialog, docEditDialog } = toRefs(state);
|
const { dataHeight, findDialog, docEditDialog } = toRefs(state);
|
||||||
|
|
||||||
|
const nowColl = computed(() => {
|
||||||
|
return getNowDataTab();
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* instmap; tagPaht -> mongo info[]
|
* instmap; tagPaht -> mongo info[]
|
||||||
*/
|
*/
|
||||||
@@ -279,15 +314,15 @@ const getCollections = async (id: any, database: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const nodeClick = (data: any) => {
|
const nodeClick = async (data: any) => {
|
||||||
// 点击集合
|
// 点击集合
|
||||||
if (data.type === NodeType.Coll) {
|
if (data.type === NodeType.Coll) {
|
||||||
const { id, database, collection } = data.params;
|
const { id, database, collection } = data.params;
|
||||||
changeCollection(id, database, collection);
|
await changeCollection(id, database, collection);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeCollection = (id: any, schema: string, collection: string) => {
|
const changeCollection = async (id: any, schema: string, collection: string) => {
|
||||||
const label = `${id}:\`${schema}\`.${collection}`;
|
const label = `${id}:\`${schema}\`.${collection}`;
|
||||||
let dataTab = state.dataTabs[label];
|
let dataTab = state.dataTabs[label];
|
||||||
if (!dataTab) {
|
if (!dataTab) {
|
||||||
@@ -345,6 +380,7 @@ const findCommand = async (key: string) => {
|
|||||||
ElMessage.error('filter或sort字段json字符串值错误。注意: json key需双引号');
|
ElMessage.error('filter或sort字段json字符串值错误。注意: json key需双引号');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const datas = await mongoApi.findCommand.request({
|
const datas = await mongoApi.findCommand.request({
|
||||||
id: dataTab.mongoId,
|
id: dataTab.mongoId,
|
||||||
database: dataTab.database,
|
database: dataTab.database,
|
||||||
@@ -355,6 +391,17 @@ const findCommand = async (key: string) => {
|
|||||||
skip: findParma.skip || 0,
|
skip: findParma.skip || 0,
|
||||||
});
|
});
|
||||||
state.dataTabs[key].datas = wrapDatas(datas);
|
state.dataTabs[key].datas = wrapDatas(datas);
|
||||||
|
|
||||||
|
// 获取coll stats
|
||||||
|
state.dataTabs[key].stats = await mongoApi.runCommand.request({
|
||||||
|
id: dataTab.mongoId,
|
||||||
|
database: dataTab.database,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
collStats: dataTab.collection,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
352
mayfly_go_web/src/views/ops/mongo/MongoDbs.vue
Normal file
352
mayfly_go_web/src/views/ops/mongo/MongoDbs.vue
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog width="800px" title="数据库列表" :before-close="close" v-model="databaseDialog.visible">
|
||||||
|
<div class="mb5">
|
||||||
|
<el-button @click="showCreateDbDialog" type="primary" icon="plus" size="small">新建</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table :data="databaseDialog.data" :max-height="500">
|
||||||
|
<el-table-column min-width="130" property="Name" label="库名" />
|
||||||
|
<el-table-column min-width="90" property="SizeOnDisk" label="size">
|
||||||
|
<template #default="scope">
|
||||||
|
{{ formatByteSize(scope.row.SizeOnDisk) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column min-width="80" property="Empty" label="是否为空" />
|
||||||
|
|
||||||
|
<el-table-column min-width="150" label="操作">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-link type="success" @click="showDatabaseStats(scope.row.Name)" plain size="small" :underline="false">stats</el-link>
|
||||||
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
<el-link type="primary" @click="showCollections(scope.row.Name)" plain size="small" :underline="false">集合</el-link>
|
||||||
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
<el-popconfirm @confirm="onDeleteDb(scope.row.Name)" title="确定删除该库?">
|
||||||
|
<template #reference>
|
||||||
|
<el-link type="danger" plain size="small" :underline="false">删除</el-link>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog width="700px" :title="databaseDialog.statsDialog.title" v-model="databaseDialog.statsDialog.visible">
|
||||||
|
<el-descriptions title="库状态信息" :column="3" border>
|
||||||
|
<el-descriptions-item label="db" label-align="right" align="center">
|
||||||
|
{{ databaseDialog.statsDialog.data.db }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="collections" label-align="right" align="center">
|
||||||
|
{{ databaseDialog.statsDialog.data.collections }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="objects" label-align="right" align="center">
|
||||||
|
{{ databaseDialog.statsDialog.data.objects }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="indexes" label-align="right" align="center">
|
||||||
|
{{ databaseDialog.statsDialog.data.indexes }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="avgObjSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.avgObjSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="dataSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.dataSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="totalSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.totalSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="storageSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.storageSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="fsTotalSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.fsTotalSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="fsUsedSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.fsUsedSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="indexSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(databaseDialog.statsDialog.data.indexSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-dialog>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog width="600px" :title="collectionsDialog.title" v-model="collectionsDialog.visible">
|
||||||
|
<div class="mb5">
|
||||||
|
<el-button @click="showCreateCollectionDialog" type="primary" icon="plus" size="small">新建</el-button>
|
||||||
|
</div>
|
||||||
|
<el-table stripe :data="collectionsDialog.data" :max-height="500">
|
||||||
|
<el-table-column prop="name" label="名称" show-overflow-tooltip> </el-table-column>
|
||||||
|
<el-table-column min-width="80" label="操作">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-link type="success" @click="showCollectionStats(scope.row.name)" plain size="small" :underline="false">stats</el-link>
|
||||||
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
<el-popconfirm @confirm="onDeleteCollection(scope.row.name)" width="160" title="确定删除该集合?">
|
||||||
|
<template #reference>
|
||||||
|
<el-link type="danger" plain size="small" :underline="false">删除</el-link>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<el-dialog width="700px" :title="collectionsDialog.statsDialog.title" v-model="collectionsDialog.statsDialog.visible">
|
||||||
|
<el-descriptions title="集合状态信息" :column="3" border>
|
||||||
|
<el-descriptions-item label="ns" label-align="right" :span="2" align="center">
|
||||||
|
{{ collectionsDialog.statsDialog.data.ns }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="count" label-align="right" align="center">
|
||||||
|
{{ collectionsDialog.statsDialog.data.count }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="avgObjSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(collectionsDialog.statsDialog.data.avgObjSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="nindexes" label-align="right" align="center">
|
||||||
|
{{ collectionsDialog.statsDialog.data.nindexes }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="size" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(collectionsDialog.statsDialog.data.size) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="totalSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(collectionsDialog.statsDialog.data.totalSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="storageSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(collectionsDialog.statsDialog.data.storageSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="freeStorageSize" label-align="right" align="center">
|
||||||
|
{{ formatByteSize(collectionsDialog.statsDialog.data.freeStorageSize) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-dialog>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog width="400px" title="新建库&集合" v-model="createDbDialog.visible" :destroy-on-close="true">
|
||||||
|
<el-form :model="createDbDialog.form" label-width="auto">
|
||||||
|
<el-form-item prop="dbName" label="库名" required>
|
||||||
|
<el-input v-model="createDbDialog.form.dbName" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="collectionName" label="集合名" required>
|
||||||
|
<el-input v-model="createDbDialog.form.collectionName" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div>
|
||||||
|
<el-button @click="createDbDialog.visible = false">取 消</el-button>
|
||||||
|
<el-button @click="onCreateDb" type="primary">确 定</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog width="400px" title="新建集合" v-model="createCollectionDialog.visible" :destroy-on-close="true">
|
||||||
|
<el-form :model="createCollectionDialog.form" label-width="auto">
|
||||||
|
<el-form-item prop="name" label="集合名" required>
|
||||||
|
<el-input v-model="createCollectionDialog.form.name" clearable></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div>
|
||||||
|
<el-button @click="createCollectionDialog.visible = false">取 消</el-button>
|
||||||
|
<el-button @click="onCreateCollection" type="primary">确 定</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { mongoApi } from './api';
|
||||||
|
import { watch, toRefs, reactive } from 'vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: [Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//定义事件
|
||||||
|
const emit = defineEmits(['update:visible']);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
databaseDialog: {
|
||||||
|
visible: false,
|
||||||
|
data: [],
|
||||||
|
statsDialog: {
|
||||||
|
visible: false,
|
||||||
|
data: {} as any,
|
||||||
|
title: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
collectionsDialog: {
|
||||||
|
database: '',
|
||||||
|
visible: false,
|
||||||
|
data: [],
|
||||||
|
title: '',
|
||||||
|
statsDialog: {
|
||||||
|
visible: false,
|
||||||
|
data: {} as any,
|
||||||
|
title: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
createCollectionDialog: {
|
||||||
|
visible: false,
|
||||||
|
form: {
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
createDbDialog: {
|
||||||
|
visible: false,
|
||||||
|
form: {
|
||||||
|
dbName: '',
|
||||||
|
collectionName: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { databaseDialog, collectionsDialog, createCollectionDialog, createDbDialog } = toRefs(state);
|
||||||
|
|
||||||
|
watch(props, async (newValue: any) => {
|
||||||
|
if (!newValue.visible) {
|
||||||
|
state.databaseDialog.visible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showDatabases();
|
||||||
|
});
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit('update:visible', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showDatabases = async () => {
|
||||||
|
state.databaseDialog.data = (await mongoApi.databases.request({ id: props.id })).Databases;
|
||||||
|
state.databaseDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showDatabaseStats = async (dbName: string) => {
|
||||||
|
state.databaseDialog.statsDialog.data = await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: dbName,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
dbStats: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
state.databaseDialog.statsDialog.title = `'${dbName}' stats`;
|
||||||
|
state.databaseDialog.statsDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const showCollections = async (database: string) => {
|
||||||
|
state.collectionsDialog.database = database;
|
||||||
|
state.collectionsDialog.data = [];
|
||||||
|
setCollections(database);
|
||||||
|
state.collectionsDialog.title = `'${database}' 集合`;
|
||||||
|
state.collectionsDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCollections = async (database: string) => {
|
||||||
|
const res = await mongoApi.collections.request({ id: props.id, database });
|
||||||
|
const collections = [] as any;
|
||||||
|
for (let r of res) {
|
||||||
|
collections.push({ name: r });
|
||||||
|
}
|
||||||
|
state.collectionsDialog.data = collections;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示集合状态
|
||||||
|
*/
|
||||||
|
const showCollectionStats = async (collection: string) => {
|
||||||
|
state.collectionsDialog.statsDialog.data = await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: state.collectionsDialog.database,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
collStats: collection,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
state.collectionsDialog.statsDialog.title = `'${collection}' stats`;
|
||||||
|
state.collectionsDialog.statsDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除集合
|
||||||
|
*/
|
||||||
|
const onDeleteCollection = async (collection: string) => {
|
||||||
|
await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: state.collectionsDialog.database,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
drop: collection,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
ElMessage.success('集合删除成功');
|
||||||
|
setCollections(state.collectionsDialog.database);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showCreateCollectionDialog = () => {
|
||||||
|
state.createCollectionDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCreateCollection = async () => {
|
||||||
|
const form = state.createCollectionDialog.form;
|
||||||
|
await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: state.collectionsDialog.database,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
create: form.name,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
ElMessage.success('集合创建成功');
|
||||||
|
state.createCollectionDialog.visible = false;
|
||||||
|
state.createCollectionDialog.form = {} as any;
|
||||||
|
setCollections(state.collectionsDialog.database);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showCreateDbDialog = () => {
|
||||||
|
state.createDbDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCreateDb = async () => {
|
||||||
|
const form = state.createDbDialog.form;
|
||||||
|
await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: form.dbName,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
create: form.collectionName,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
ElMessage.success('数据库与集合创建成功');
|
||||||
|
state.createDbDialog.visible = false;
|
||||||
|
state.createDbDialog.form = {} as any;
|
||||||
|
showDatabases();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteDb = async (db: string) => {
|
||||||
|
await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: db,
|
||||||
|
command: [
|
||||||
|
{
|
||||||
|
dropDatabase: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
ElMessage.success('库删除成功');
|
||||||
|
showDatabases();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
@@ -34,136 +34,15 @@
|
|||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<el-button @click="showDatabases(data.id)" link>数据库</el-button>
|
<el-button @click="showDatabases(data.id)" link>数据库</el-button>
|
||||||
|
|
||||||
<el-button type="primary" @click="editMongo(data)" link>编辑</el-button>
|
<el-button @click="showUsers(data.id)" link type="success">cmd</el-button>
|
||||||
|
|
||||||
|
<el-button @click="editMongo(data)" link type="primary">编辑</el-button>
|
||||||
</template>
|
</template>
|
||||||
</page-table>
|
</page-table>
|
||||||
|
|
||||||
<el-dialog width="800px" :title="databaseDialog.title" v-model="databaseDialog.visible">
|
<mongo-dbs v-model:visible="dbsVisible" :id="state.dbOps.dbId"></mongo-dbs>
|
||||||
<el-table :data="databaseDialog.data" size="small">
|
|
||||||
<el-table-column min-width="130" property="Name" label="库名" />
|
|
||||||
<el-table-column min-width="90" property="SizeOnDisk" label="size">
|
|
||||||
<template #default="scope">
|
|
||||||
{{ formatByteSize(scope.row.SizeOnDisk) }}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column min-width="80" property="Empty" label="是否为空" />
|
|
||||||
|
|
||||||
<el-table-column min-width="150" label="操作">
|
<mongo-run-command v-model:visible="usersVisible" :id="state.dbOps.dbId" />
|
||||||
<template #default="scope">
|
|
||||||
<el-link type="success" @click="showDatabaseStats(scope.row.Name)" plain size="small" :underline="false">stats</el-link>
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
<el-link type="primary" @click="showCollections(scope.row.Name)" plain size="small" :underline="false">集合</el-link>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
|
|
||||||
<el-dialog width="700px" :title="databaseDialog.statsDialog.title" v-model="databaseDialog.statsDialog.visible">
|
|
||||||
<el-descriptions title="库状态信息" :column="3" border size="small">
|
|
||||||
<el-descriptions-item label="db" label-align="right" align="center">
|
|
||||||
{{ databaseDialog.statsDialog.data.db }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="collections" label-align="right" align="center">
|
|
||||||
{{ databaseDialog.statsDialog.data.collections }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="objects" label-align="right" align="center">
|
|
||||||
{{ databaseDialog.statsDialog.data.objects }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="indexes" label-align="right" align="center">
|
|
||||||
{{ databaseDialog.statsDialog.data.indexes }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="avgObjSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.avgObjSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="dataSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.dataSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="totalSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.totalSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="storageSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.storageSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="fsTotalSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.fsTotalSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="fsUsedSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.fsUsedSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="indexSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(databaseDialog.statsDialog.data.indexSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</el-dialog>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<el-dialog width="600px" :title="collectionsDialog.title" v-model="collectionsDialog.visible">
|
|
||||||
<div>
|
|
||||||
<el-button @click="showCreateCollectionDialog" type="primary" icon="plus" size="small">新建</el-button>
|
|
||||||
</div>
|
|
||||||
<el-table border stripe :data="collectionsDialog.data" size="small">
|
|
||||||
<el-table-column prop="name" label="名称" show-overflow-tooltip> </el-table-column>
|
|
||||||
<el-table-column min-width="80" label="操作">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-link type="success" @click="showCollectionStats(scope.row.name)" plain size="small" :underline="false">stats</el-link>
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
<el-popconfirm @confirm="onDeleteCollection(scope.row.name)" title="确定删除该集合?">
|
|
||||||
<template #reference>
|
|
||||||
<el-link type="danger" plain size="small" :underline="false">删除</el-link>
|
|
||||||
</template>
|
|
||||||
</el-popconfirm>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
|
|
||||||
<el-dialog width="700px" :title="collectionsDialog.statsDialog.title" v-model="collectionsDialog.statsDialog.visible">
|
|
||||||
<el-descriptions title="集合状态信息" :column="3" border size="small">
|
|
||||||
<el-descriptions-item label="ns" label-align="right" :span="2" align="center">
|
|
||||||
{{ collectionsDialog.statsDialog.data.ns }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="count" label-align="right" align="center">
|
|
||||||
{{ collectionsDialog.statsDialog.data.count }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="avgObjSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(collectionsDialog.statsDialog.data.avgObjSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="nindexes" label-align="right" align="center">
|
|
||||||
{{ collectionsDialog.statsDialog.data.nindexes }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<el-descriptions-item label="size" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(collectionsDialog.statsDialog.data.size) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="totalSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(collectionsDialog.statsDialog.data.totalSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="storageSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(collectionsDialog.statsDialog.data.storageSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="freeStorageSize" label-align="right" align="center">
|
|
||||||
{{ formatByteSize(collectionsDialog.statsDialog.data.freeStorageSize) }}
|
|
||||||
</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</el-dialog>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<el-dialog width="400px" title="新建集合" v-model="createCollectionDialog.visible" :destroy-on-close="true">
|
|
||||||
<el-form :model="createCollectionDialog.form" label-width="auto">
|
|
||||||
<el-form-item prop="name" label="集合名" required>
|
|
||||||
<el-input v-model="createCollectionDialog.form.name" clearable></el-input>
|
|
||||||
</el-form-item>
|
|
||||||
<!-- <el-form-item label="描述:">
|
|
||||||
<el-input v-model="showEnvDialog.envForm.remark" auto-complete="off"></el-input>
|
|
||||||
</el-form-item> -->
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<div>
|
|
||||||
<el-button @click="createCollectionDialog.visible = false">取 消</el-button>
|
|
||||||
<el-button @click="onCreateCollection" type="primary">确 定</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<mongo-edit
|
<mongo-edit
|
||||||
@val-change="valChange"
|
@val-change="valChange"
|
||||||
@@ -176,14 +55,16 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { mongoApi } from './api';
|
import { mongoApi } from './api';
|
||||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
import { defineAsyncComponent, ref, toRefs, reactive, onMounted } from 'vue';
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import MongoEdit from './MongoEdit.vue';
|
|
||||||
import { formatByteSize } from '@/common/utils/format';
|
|
||||||
import TagInfo from '../component/TagInfo.vue';
|
import TagInfo from '../component/TagInfo.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';
|
||||||
|
|
||||||
|
const MongoEdit = defineAsyncComponent(() => import('./MongoEdit.vue'));
|
||||||
|
const MongoDbs = defineAsyncComponent(() => import('./MongoDbs.vue'));
|
||||||
|
const MongoRunCommand = defineAsyncComponent(() => import('./MongoRunCommand.vue'));
|
||||||
|
|
||||||
const pageTableRef: any = ref(null);
|
const pageTableRef: any = ref(null);
|
||||||
|
|
||||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect')];
|
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect')];
|
||||||
@@ -193,7 +74,7 @@ const columns = ref([
|
|||||||
TableColumn.new('uri', '连接uri'),
|
TableColumn.new('uri', '连接uri'),
|
||||||
TableColumn.new('createTime', '创建时间').isTime(),
|
TableColumn.new('createTime', '创建时间').isTime(),
|
||||||
TableColumn.new('creator', '创建人'),
|
TableColumn.new('creator', '创建人'),
|
||||||
TableColumn.new('action', '操作').isSlot().setMinWidth(100).fixedRight().alignCenter(),
|
TableColumn.new('action', '操作').isSlot().setMinWidth(145).fixedRight().alignCenter(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -215,126 +96,24 @@ const state = reactive({
|
|||||||
data: null as any,
|
data: null as any,
|
||||||
title: '新增mongo',
|
title: '新增mongo',
|
||||||
},
|
},
|
||||||
databaseDialog: {
|
dbsVisible: false,
|
||||||
visible: false,
|
usersVisible: false,
|
||||||
data: [],
|
|
||||||
title: '',
|
|
||||||
statsDialog: {
|
|
||||||
visible: false,
|
|
||||||
data: {} as any,
|
|
||||||
title: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
collectionsDialog: {
|
|
||||||
database: '',
|
|
||||||
visible: false,
|
|
||||||
data: [],
|
|
||||||
title: '',
|
|
||||||
statsDialog: {
|
|
||||||
visible: false,
|
|
||||||
data: {} as any,
|
|
||||||
title: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
createCollectionDialog: {
|
|
||||||
visible: false,
|
|
||||||
form: {
|
|
||||||
name: '',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const { tags, list, total, selectionData, query, mongoEditDialog, databaseDialog, collectionsDialog, createCollectionDialog } = toRefs(state);
|
const { tags, list, total, selectionData, query, mongoEditDialog, dbsVisible, usersVisible } = toRefs(state);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
const showDatabases = async (id: number) => {
|
const showDatabases = async (id: number) => {
|
||||||
// state.query.tagPath = row.tagPath
|
|
||||||
state.dbOps.dbId = id;
|
state.dbOps.dbId = id;
|
||||||
|
state.dbsVisible = true;
|
||||||
state.databaseDialog.data = (await mongoApi.databases.request({ id })).Databases;
|
|
||||||
state.databaseDialog.title = `数据库列表`;
|
|
||||||
state.databaseDialog.visible = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const showDatabaseStats = async (dbName: string) => {
|
const showUsers = async (id: number) => {
|
||||||
state.databaseDialog.statsDialog.data = await mongoApi.runCommand.request({
|
state.dbOps.dbId = id;
|
||||||
id: state.dbOps.dbId,
|
state.usersVisible = true;
|
||||||
database: dbName,
|
|
||||||
command: {
|
|
||||||
dbStats: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
state.databaseDialog.statsDialog.title = `'${dbName}' stats`;
|
|
||||||
state.databaseDialog.statsDialog.visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const showCollections = async (database: string) => {
|
|
||||||
state.collectionsDialog.database = database;
|
|
||||||
state.collectionsDialog.data = [];
|
|
||||||
setCollections(database);
|
|
||||||
state.collectionsDialog.title = `'${database}' 集合`;
|
|
||||||
state.collectionsDialog.visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setCollections = async (database: string) => {
|
|
||||||
const res = await mongoApi.collections.request({ id: state.dbOps.dbId, database });
|
|
||||||
const collections = [] as any;
|
|
||||||
for (let r of res) {
|
|
||||||
collections.push({ name: r });
|
|
||||||
}
|
|
||||||
state.collectionsDialog.data = collections;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示集合状态
|
|
||||||
*/
|
|
||||||
const showCollectionStats = async (collection: string) => {
|
|
||||||
state.collectionsDialog.statsDialog.data = await mongoApi.runCommand.request({
|
|
||||||
id: state.dbOps.dbId,
|
|
||||||
database: state.collectionsDialog.database,
|
|
||||||
command: {
|
|
||||||
collStats: collection,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
state.collectionsDialog.statsDialog.title = `'${collection}' stats`;
|
|
||||||
state.collectionsDialog.statsDialog.visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除集合
|
|
||||||
*/
|
|
||||||
const onDeleteCollection = async (collection: string) => {
|
|
||||||
await mongoApi.runCommand.request({
|
|
||||||
id: state.dbOps.dbId,
|
|
||||||
database: state.collectionsDialog.database,
|
|
||||||
command: {
|
|
||||||
drop: collection,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
ElMessage.success('集合删除成功');
|
|
||||||
setCollections(state.collectionsDialog.database);
|
|
||||||
};
|
|
||||||
|
|
||||||
const showCreateCollectionDialog = () => {
|
|
||||||
state.createCollectionDialog.visible = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCreateCollection = async () => {
|
|
||||||
const form = state.createCollectionDialog.form;
|
|
||||||
await mongoApi.runCommand.request({
|
|
||||||
id: state.dbOps.dbId,
|
|
||||||
database: state.collectionsDialog.database,
|
|
||||||
command: {
|
|
||||||
create: form.name,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
ElMessage.success('集合创建成功');
|
|
||||||
state.createCollectionDialog.visible = false;
|
|
||||||
state.createCollectionDialog.form = {} as any;
|
|
||||||
setCollections(state.collectionsDialog.database);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteMongo = async () => {
|
const deleteMongo = async () => {
|
||||||
|
|||||||
196
mayfly_go_web/src/views/ops/mongo/MongoRunCommand.vue
Normal file
196
mayfly_go_web/src/views/ops/mongo/MongoRunCommand.vue
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-dialog width="700px" title="runCommand" v-model="runCmdDialog.visible" :before-close="close" :destroy-on-close="true">
|
||||||
|
<el-form label-width="auto">
|
||||||
|
<el-row class="mb10">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="模板">
|
||||||
|
<el-select class="w100" @change="changeCmd" filterable v-model="runCmdDialog.cmdName" placeholder="选择命令模板">
|
||||||
|
<el-option v-for="item in mongoCmds" :key="item.name" :label="`${item.name} | ${item.description}`" :value="item.name" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="库">
|
||||||
|
<el-select v-model="runCmdDialog.db" filterable placeholder="选择库">
|
||||||
|
<el-option v-for="item in dbs" :key="item.Name" :label="item.Name" :value="item.Name" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-form-item class="ml10">
|
||||||
|
<el-button @click="onRunCommand" type="primary">Run</el-button>
|
||||||
|
<el-tooltip effect="dark" placement="top">
|
||||||
|
<template #content> 更多命令查看-> https://www.mongodb.com/docs/manual/reference/command/ </template>
|
||||||
|
<span class="ml10">
|
||||||
|
<el-icon><InfoFilled /></el-icon>
|
||||||
|
</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-form-item label="cmd">
|
||||||
|
<monaco-editor style="width: 100%" height="235px" v-model="runCmdDialog.cmd" language="json" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="res">
|
||||||
|
<monaco-editor style="width: 100%" height="235px" v-model="runCmdDialog.cmdRes" language="json" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { mongoApi } from './api';
|
||||||
|
import { watch, defineAsyncComponent, toRefs, reactive } from 'vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
const MonacoEditor = defineAsyncComponent(() => import('@/components/monaco/MonacoEditor.vue'));
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: [Number],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
//定义事件
|
||||||
|
const emit = defineEmits(['update:visible']);
|
||||||
|
|
||||||
|
const mongoCmds = {
|
||||||
|
usersInfo: {
|
||||||
|
name: 'usersInfo',
|
||||||
|
description: '获取用户信息',
|
||||||
|
cmd: {
|
||||||
|
usersInfo: 1,
|
||||||
|
showCredentials: false,
|
||||||
|
showCustomData: false,
|
||||||
|
showPrivileges: false,
|
||||||
|
showAuthenticationRestrictions: false,
|
||||||
|
filter: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
createUser: {
|
||||||
|
name: 'createUser',
|
||||||
|
description: '创建新用户',
|
||||||
|
cmd: {
|
||||||
|
createUser: '<username>',
|
||||||
|
pwd: '<cleartext password>',
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
role: '<role>',
|
||||||
|
db: '<database>',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grantRolesToUser: {
|
||||||
|
name: 'grantRolesToUser',
|
||||||
|
description: '授予对用户的额外角色',
|
||||||
|
cmd: {
|
||||||
|
grantRolesToUser: '<user>',
|
||||||
|
roles: [''],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dropUser: {
|
||||||
|
name: 'dropUser',
|
||||||
|
description: '删除用户',
|
||||||
|
cmd: {
|
||||||
|
dropUser: '<user>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
roleInfo: {
|
||||||
|
name: 'roleInfo',
|
||||||
|
description: '获取角色信息',
|
||||||
|
cmd: {
|
||||||
|
rolesInfo: 1,
|
||||||
|
showAuthenticationRestrictions: false,
|
||||||
|
showBuiltinRoles: true,
|
||||||
|
showPrivileges: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
createRole: {
|
||||||
|
name: 'createRole',
|
||||||
|
description: '创建角色',
|
||||||
|
cmd: {
|
||||||
|
createRole: '<new role>',
|
||||||
|
privileges: [{ resource: {}, actions: ['<action>'] }],
|
||||||
|
roles: [{ role: '<role>', db: '<database>' }],
|
||||||
|
authenticationRestrictions: [
|
||||||
|
{
|
||||||
|
clientSource: ['<IP> | <CIDR range>'],
|
||||||
|
serverAddress: ['<IP> |<CIDR range>'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
writeConcern: '<write concern document>',
|
||||||
|
comment: '<any>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
dbs: [] as any,
|
||||||
|
selectDbDisabled: false,
|
||||||
|
runCmdDialog: {
|
||||||
|
visible: false,
|
||||||
|
cmdName: '',
|
||||||
|
db: '',
|
||||||
|
cmd: '',
|
||||||
|
cmdRes: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { dbs, runCmdDialog } = toRefs(state);
|
||||||
|
|
||||||
|
watch(props, async (newValue: any) => {
|
||||||
|
if (!newValue.visible) {
|
||||||
|
state.runCmdDialog.visible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.runCmdDialog.visible = newValue.visible;
|
||||||
|
state.dbs = (await mongoApi.databases.request({ id: props.id })).Databases;
|
||||||
|
});
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit('update:visible', false);
|
||||||
|
state.runCmdDialog.cmd = '';
|
||||||
|
state.runCmdDialog.cmdRes = '';
|
||||||
|
state.runCmdDialog.cmdName = '';
|
||||||
|
state.runCmdDialog.db = '';
|
||||||
|
state.dbs = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeCmd = (val: any) => {
|
||||||
|
const mongoCmd = mongoCmds[val];
|
||||||
|
state.runCmdDialog.cmd = JSON.stringify(mongoCmd.cmd, null, 4);
|
||||||
|
state.runCmdDialog.db = state?.dbs[0]?.Name;
|
||||||
|
state.runCmdDialog.cmdRes = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const onRunCommand = async () => {
|
||||||
|
const orderCmds = [] as any;
|
||||||
|
const cmdObj = JSON.parse(state.runCmdDialog.cmd);
|
||||||
|
|
||||||
|
for (let item of Object.keys(cmdObj)) {
|
||||||
|
let obj = {};
|
||||||
|
obj[item] = cmdObj[item];
|
||||||
|
orderCmds.push(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.runCmdDialog.cmdRes = '';
|
||||||
|
const res = await mongoApi.runCommand.request({
|
||||||
|
id: props.id,
|
||||||
|
database: state.runCmdDialog.db,
|
||||||
|
command: orderCmds,
|
||||||
|
});
|
||||||
|
state.runCmdDialog.cmdRes = JSON.stringify(res, null, 4);
|
||||||
|
ElMessage.success('执行成功');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
@@ -701,10 +701,10 @@ concat-map@0.0.1:
|
|||||||
resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz"
|
resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz"
|
||||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||||
|
|
||||||
countup.js@^2.0.7:
|
countup.js@^2.7.0:
|
||||||
version "2.0.8"
|
version "2.7.0"
|
||||||
resolved "https://registry.nlark.com/countup.js/download/countup.js-2.0.8.tgz"
|
resolved "https://registry.npmmirror.com/countup.js/-/countup.js-2.7.0.tgz#a5521bd935f0ae83417d0128e73f2a2d2543c9c7"
|
||||||
integrity sha1-7KDDHJ2z93acuklNkxXNUtuq8bk=
|
integrity sha512-IP9nYLGgW//0If73eXQdFlReGhpFGHaStqB1v82FknxnUWueF6HFuuOXySW4sEDMc88PsZL1EOn/NPkfTZalmQ==
|
||||||
|
|
||||||
cropperjs@^1.5.11:
|
cropperjs@^1.5.11:
|
||||||
version "1.5.12"
|
version "1.5.12"
|
||||||
@@ -1414,10 +1414,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.40.0:
|
monaco-editor@^0.41.0:
|
||||||
version "0.40.0"
|
version "0.41.0"
|
||||||
resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.40.0.tgz#d10834e15ad50a15ec61fd01892e508464ebe2fe"
|
resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.41.0.tgz#2ba31e5af7e3ae93ac5d7467ec2772ef9b3d967f"
|
||||||
integrity sha512-1wymccLEuFSMBvCk/jT1YDW/GuxMLYwnFwF9CDyYCxoTw2Pt379J3FUhwy9c43j51JdcxVPjwk0jm0EVDsBS2g==
|
integrity sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==
|
||||||
|
|
||||||
monaco-sql-languages@^0.11.0:
|
monaco-sql-languages@^0.11.0:
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
@@ -1575,7 +1575,7 @@ postcss@^8.1.10:
|
|||||||
picocolors "^1.0.0"
|
picocolors "^1.0.0"
|
||||||
source-map-js "^1.0.1"
|
source-map-js "^1.0.1"
|
||||||
|
|
||||||
postcss@^8.4.26:
|
postcss@^8.4.27:
|
||||||
version "8.4.27"
|
version "8.4.27"
|
||||||
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057"
|
resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.27.tgz#234d7e4b72e34ba5a92c29636734349e0d9c3057"
|
||||||
integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==
|
integrity sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==
|
||||||
@@ -1666,10 +1666,10 @@ rimraf@^3.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.1.3"
|
glob "^7.1.3"
|
||||||
|
|
||||||
rollup@^3.25.2:
|
rollup@^3.27.1:
|
||||||
version "3.26.2"
|
version "3.28.0"
|
||||||
resolved "https://registry.npmmirror.com/rollup/-/rollup-3.26.2.tgz#2e76a37606cb523fc9fef43e6f59c93f86d95e7c"
|
resolved "https://registry.npmmirror.com/rollup/-/rollup-3.28.0.tgz#a3c70004b01934760c0cb8df717c7a1d932389a2"
|
||||||
integrity sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==
|
integrity sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
@@ -1855,14 +1855,14 @@ uri-js@^4.2.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
vite@^4.4.7:
|
vite@^4.4.9:
|
||||||
version "4.4.7"
|
version "4.4.9"
|
||||||
resolved "https://registry.npmmirror.com/vite/-/vite-4.4.7.tgz#71b8a37abaf8d50561aca084dbb77fa342824154"
|
resolved "https://registry.npmmirror.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d"
|
||||||
integrity sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==
|
integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild "^0.18.10"
|
esbuild "^0.18.10"
|
||||||
postcss "^8.4.26"
|
postcss "^8.4.27"
|
||||||
rollup "^3.25.2"
|
rollup "^3.27.1"
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "~2.3.2"
|
fsevents "~2.3.2"
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
module mayfly-go
|
module mayfly-go
|
||||||
|
|
||||||
go 1.20
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/buger/jsonparser v1.1.1
|
github.com/buger/jsonparser v1.1.1
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/go-gormigrate/gormigrate/v2 v2.1.0
|
github.com/go-gormigrate/gormigrate/v2 v2.1.0
|
||||||
|
github.com/go-playground/locales v0.14.1
|
||||||
|
github.com/go-playground/universal-translator v0.18.1
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0
|
||||||
github.com/go-sql-driver/mysql v1.7.1
|
github.com/go-sql-driver/mysql v1.7.1
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||||
github.com/gorilla/websocket v1.5.0
|
github.com/gorilla/websocket v1.5.0
|
||||||
github.com/lib/pq v1.10.7
|
github.com/lib/pq v1.10.9
|
||||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230712084735-068dc2aee82d
|
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230712084735-068dc2aee82d
|
||||||
github.com/mojocn/base64Captcha v1.3.5 // 验证码
|
github.com/mojocn/base64Captcha v1.3.5 // 验证码
|
||||||
github.com/pkg/sftp v1.13.5
|
github.com/pkg/sftp v1.13.6
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/redis/go-redis/v9 v9.0.5
|
github.com/redis/go-redis/v9 v9.1.0
|
||||||
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
github.com/robfig/cron/v3 v3.0.1 // 定时任务
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2
|
||||||
go.mongodb.org/mongo-driver v1.11.4 // mongo
|
go.mongodb.org/mongo-driver v1.12.1 // mongo
|
||||||
golang.org/x/crypto v0.11.0 // ssh
|
golang.org/x/crypto v0.12.0 // ssh
|
||||||
golang.org/x/oauth2 v0.10.0
|
golang.org/x/oauth2 v0.11.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
// gorm
|
// gorm
|
||||||
gorm.io/driver/mysql v1.5.1
|
gorm.io/driver/mysql v1.5.1
|
||||||
gorm.io/gorm v1.25.2
|
gorm.io/gorm v1.25.4
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -35,9 +38,6 @@ require (
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
|
||||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
@@ -48,25 +48,26 @@ require (
|
|||||||
github.com/klauspost/compress v1.13.6 // indirect
|
github.com/klauspost/compress v1.13.6 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||||
github.com/kr/fs v0.1.0 // indirect
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.1 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
|
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 // indirect
|
||||||
golang.org/x/net v0.12.0 // indirect
|
golang.org/x/net v0.14.0 // indirect
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||||
golang.org/x/sys v0.10.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.12.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ type MongoCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MongoRunCommand struct {
|
type MongoRunCommand struct {
|
||||||
Database string `binding:"required" json:"database"`
|
Database string `binding:"required" json:"database"`
|
||||||
Command map[string]any `json:"command"`
|
Command []map[string]any `json:"command"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MongoFindCommand struct {
|
type MongoFindCommand struct {
|
||||||
|
|||||||
@@ -91,12 +91,24 @@ func (m *Mongo) RunCommand(rc *req.Ctx) {
|
|||||||
commandForm := new(form.MongoRunCommand)
|
commandForm := new(form.MongoRunCommand)
|
||||||
ginx.BindJsonAndValid(rc.GinCtx, commandForm)
|
ginx.BindJsonAndValid(rc.GinCtx, commandForm)
|
||||||
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
cli := m.MongoApp.GetMongoCli(m.GetMongoId(rc.GinCtx))
|
||||||
|
rc.ReqParam = commandForm
|
||||||
|
|
||||||
|
// 顺序执行
|
||||||
|
commands := bson.D{}
|
||||||
|
for _, cmd := range commandForm.Command {
|
||||||
|
e := bson.E{}
|
||||||
|
for k, v := range cmd {
|
||||||
|
e.Key = k
|
||||||
|
e.Value = v
|
||||||
|
}
|
||||||
|
commands = append(commands, e)
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
var bm bson.M
|
var bm bson.M
|
||||||
err := cli.Database(commandForm.Database).RunCommand(
|
err := cli.Database(commandForm.Database).RunCommand(
|
||||||
ctx,
|
ctx,
|
||||||
commandForm.Command,
|
commands,
|
||||||
).Decode(&bm)
|
).Decode(&bm)
|
||||||
|
|
||||||
biz.ErrIsNilAppendErr(err, "执行命令失败: %s")
|
biz.ErrIsNilAppendErr(err, "执行命令失败: %s")
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ func InitMongoRouter(router *gin.RouterGroup) {
|
|||||||
TagApp: tagapp.GetTagTreeApp(),
|
TagApp: tagapp.GetTagTreeApp(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveDataPerm := req.NewPermission("mongo:data:save")
|
||||||
|
|
||||||
reqs := [...]*req.Conf{
|
reqs := [...]*req.Conf{
|
||||||
// 获取所有mongo列表
|
// 获取所有mongo列表
|
||||||
req.NewGet("", ma.Mongos),
|
req.NewGet("", ma.Mongos),
|
||||||
@@ -39,13 +41,13 @@ func InitMongoRouter(router *gin.RouterGroup) {
|
|||||||
// 执行mongo find命令
|
// 执行mongo find命令
|
||||||
req.NewPost(":id/command/find", ma.FindCommand),
|
req.NewPost(":id/command/find", ma.FindCommand),
|
||||||
|
|
||||||
req.NewPost(":id/command/update-by-id", ma.UpdateByIdCommand).Log(req.NewLogSave("mongo-更新文档")),
|
req.NewPost(":id/command/update-by-id", ma.UpdateByIdCommand).RequiredPermission(saveDataPerm).Log(req.NewLogSave("mongo-更新文档")),
|
||||||
|
|
||||||
// 执行mongo delete by id命令
|
// 执行mongo delete by id命令
|
||||||
req.NewPost(":id/command/delete-by-id", ma.DeleteByIdCommand).Log(req.NewLogSave("mongo-删除文档")),
|
req.NewPost(":id/command/delete-by-id", ma.DeleteByIdCommand).RequiredPermission(req.NewPermission("mongo:data:del")).Log(req.NewLogSave("mongo-删除文档")),
|
||||||
|
|
||||||
// 执行mongo insert 命令
|
// 执行mongo insert 命令
|
||||||
req.NewPost(":id/command/insert", ma.InsertOneCommand).Log(req.NewLogSave("mogno-插入文档")),
|
req.NewPost(":id/command/insert", ma.InsertOneCommand).RequiredPermission(saveDataPerm).Log(req.NewLogSave("mogno-插入文档")),
|
||||||
}
|
}
|
||||||
|
|
||||||
req.BatchSetGroup(m, reqs[:])
|
req.BatchSetGroup(m, reqs[:])
|
||||||
|
|||||||
Reference in New Issue
Block a user