mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	feat: 调整单个数据库资源可配置多个数据库
This commit is contained in:
		@@ -1,14 +1,14 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <el-form class="search-form" label-position="right" :inline="true" label-width="60px">
 | 
					        <el-form class="search-form" label-position="right" :inline="true">
 | 
				
			||||||
            <el-form-item prop="project" label="项目" label-width="40px">
 | 
					            <el-form-item prop="project" label="项目" label-width="40px">
 | 
				
			||||||
                <el-select v-model="projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
					                <el-select v-model="projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
				
			||||||
                    <el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"></el-option>
 | 
					                    <el-option v-for="item in projects" :key="item.id" :label="`${item.name} [${item.remark}]`" :value="item.id"></el-option>
 | 
				
			||||||
                </el-select>
 | 
					                </el-select>
 | 
				
			||||||
            </el-form-item>
 | 
					            </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <el-form-item prop="env" label="环境" label-width="40px">
 | 
					            <el-form-item prop="env" label="env" label-width="33px">
 | 
				
			||||||
                <el-select style="width: 100px" v-model="envId" placeholder="环境" @change="changeEnv" filterable>
 | 
					                <el-select style="width: 80px" v-model="envId" placeholder="环境" @change="changeEnv" filterable>
 | 
				
			||||||
                    <el-option v-for="item in envs" :key="item.id" :label="item.name" :value="item.id">
 | 
					                    <el-option v-for="item in envs" :key="item.id" :label="item.name" :value="item.id">
 | 
				
			||||||
                        <span style="float: left">{{ item.name }}</span>
 | 
					                        <span style="float: left">{{ item.name }}</span>
 | 
				
			||||||
                        <span style="float: right; color: #8492a6; font-size: 13px">{{ item.remark }}</span>
 | 
					                        <span style="float: right; color: #8492a6; font-size: 13px">{{ item.remark }}</span>
 | 
				
			||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { toRefs, reactive, watch, defineComponent, onMounted } from 'vue';
 | 
					import { toRefs, reactive, defineComponent, onMounted } from 'vue';
 | 
				
			||||||
import { projectApi } from '../project/api';
 | 
					import { projectApi } from '../project/api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
@@ -52,8 +52,6 @@ export default defineComponent({
 | 
				
			|||||||
            envId: null,
 | 
					            envId: null,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        watch(props, (newValue, oldValue) => {});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        onMounted(async () => {
 | 
					        onMounted(async () => {
 | 
				
			||||||
            state.projects = await projectApi.accountProjects.request(null);
 | 
					            state.projects = await projectApi.accountProjects.request(null);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,6 +83,9 @@ export default defineComponent({
 | 
				
			|||||||
        dbId: {
 | 
					        dbId: {
 | 
				
			||||||
            type: Number,
 | 
					            type: Number,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        db: {
 | 
				
			||||||
 | 
					            type: String,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    setup(props: any, { emit }) {
 | 
					    setup(props: any, { emit }) {
 | 
				
			||||||
        const formRef: any = ref();
 | 
					        const formRef: any = ref();
 | 
				
			||||||
@@ -202,6 +205,7 @@ export default defineComponent({
 | 
				
			|||||||
            SqlExecBox({
 | 
					            SqlExecBox({
 | 
				
			||||||
                sql: sql,
 | 
					                sql: sql,
 | 
				
			||||||
                dbId: props.dbId as any,
 | 
					                dbId: props.dbId as any,
 | 
				
			||||||
 | 
					                db: props.db,
 | 
				
			||||||
                runSuccessCallback: () => {
 | 
					                runSuccessCallback: () => {
 | 
				
			||||||
                    ElMessage.success('创建成功');
 | 
					                    ElMessage.success('创建成功');
 | 
				
			||||||
                    proxy.$parent.tableInfo({ id: props.dbId });
 | 
					                    proxy.$parent.tableInfo({ id: props.dbId });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" width="35%">
 | 
					        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" :destroy-on-close="true" width="35%">
 | 
				
			||||||
            <el-form :model="form" ref="dbForm" :rules="rules" label-width="85px">
 | 
					            <el-form :model="form" ref="dbForm" :rules="rules" label-width="85px">
 | 
				
			||||||
                <el-form-item prop="projectId" label="项目:" required>
 | 
					                <el-form-item prop="projectId" label="项目:" required>
 | 
				
			||||||
                    <el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
					                    <el-select style="width: 100%" v-model="form.projectId" placeholder="请选择项目" @change="changeProject" filterable>
 | 
				
			||||||
@@ -30,24 +30,45 @@
 | 
				
			|||||||
                <el-form-item prop="username" label="用户名:" required>
 | 
					                <el-form-item prop="username" label="用户名:" required>
 | 
				
			||||||
                    <el-input v-model.trim="form.username" placeholder="请输入用户名"></el-input>
 | 
					                    <el-input v-model.trim="form.username" placeholder="请输入用户名"></el-input>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
                <el-form-item prop="password" label="密码:" required>
 | 
					                <el-form-item prop="password" label="密码:">
 | 
				
			||||||
                    <el-input
 | 
					                    <el-input
 | 
				
			||||||
                        type="password"
 | 
					                        type="password"
 | 
				
			||||||
                        show-password
 | 
					                        show-password
 | 
				
			||||||
                        v-model.trim="form.password"
 | 
					                        v-model.trim="form.password"
 | 
				
			||||||
                        placeholder="请输入密码"
 | 
					                        placeholder="请输入密码,新增为必填项"
 | 
				
			||||||
                        autocomplete="new-password"
 | 
					                        autocomplete="new-password"
 | 
				
			||||||
                    ></el-input>
 | 
					                    ></el-input>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
                <el-form-item prop="database" label="数据库名:" required>
 | 
					                <el-form-item prop="database" label="数据库名:" required>
 | 
				
			||||||
                    <el-input v-model.trim="form.database" placeholder="请输入数据库名"></el-input>
 | 
					                    <el-tag
 | 
				
			||||||
 | 
					                        v-for="db in databaseList"
 | 
				
			||||||
 | 
					                        :key="db"
 | 
				
			||||||
 | 
					                        class="ml5 mt5"
 | 
				
			||||||
 | 
					                        type="success"
 | 
				
			||||||
 | 
					                        effect="plain"
 | 
				
			||||||
 | 
					                        closable
 | 
				
			||||||
 | 
					                        :disable-transitions="false"
 | 
				
			||||||
 | 
					                        @close="handleClose(db)"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        {{ db }}
 | 
				
			||||||
 | 
					                    </el-tag>
 | 
				
			||||||
 | 
					                    <el-input
 | 
				
			||||||
 | 
					                        v-if="inputDbVisible"
 | 
				
			||||||
 | 
					                        ref="InputDbRef"
 | 
				
			||||||
 | 
					                        v-model="inputDbValue"
 | 
				
			||||||
 | 
					                        style="width: 120px; margin-left: 5px; margin-top: 5px"
 | 
				
			||||||
 | 
					                        size="small"
 | 
				
			||||||
 | 
					                        @keyup.enter="handleInputDbConfirm"
 | 
				
			||||||
 | 
					                        @blur="handleInputDbConfirm"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <el-button v-else class="ml5 mt5" size="small" @click="showInputDb"> + 添加数据库 </el-button>
 | 
				
			||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
            </el-form>
 | 
					            </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
					 | 
				
			||||||
                    <el-button @click="cancel()">取 消</el-button>
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
@@ -55,10 +76,11 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { toRefs, reactive, watch, defineComponent, ref } from 'vue';
 | 
					import { toRefs, reactive, nextTick, watch, defineComponent, ref } from 'vue';
 | 
				
			||||||
import { dbApi } from './api';
 | 
					import { dbApi } from './api';
 | 
				
			||||||
import { projectApi } from '../project/api.ts';
 | 
					import { projectApi } from '../project/api.ts';
 | 
				
			||||||
import { ElMessage } from 'element-plus';
 | 
					import { ElMessage } from 'element-plus';
 | 
				
			||||||
 | 
					import type { ElInput } from 'element-plus';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
    name: 'DbEdit',
 | 
					    name: 'DbEdit',
 | 
				
			||||||
@@ -78,16 +100,22 @@ export default defineComponent({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    setup(props: any, { emit }) {
 | 
					    setup(props: any, { emit }) {
 | 
				
			||||||
        const dbForm: any = ref(null);
 | 
					        const dbForm: any = ref(null);
 | 
				
			||||||
 | 
					        const InputDbRef = ref<InstanceType<typeof ElInput>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const state = reactive({
 | 
					        const state = reactive({
 | 
				
			||||||
            dialogVisible: false,
 | 
					            dialogVisible: false,
 | 
				
			||||||
            projects: [],
 | 
					            projects: [],
 | 
				
			||||||
            envs: [],
 | 
					            envs: [],
 | 
				
			||||||
 | 
					            databaseList: [] as any,
 | 
				
			||||||
 | 
					            inputDbVisible: false,
 | 
				
			||||||
 | 
					            inputDbValue: '',
 | 
				
			||||||
            form: {
 | 
					            form: {
 | 
				
			||||||
                id: null,
 | 
					                id: null,
 | 
				
			||||||
                name: null,
 | 
					                name: null,
 | 
				
			||||||
                port: 3306,
 | 
					                port: 3306,
 | 
				
			||||||
                username: null,
 | 
					                username: null,
 | 
				
			||||||
                password: null,
 | 
					                password: null,
 | 
				
			||||||
 | 
					                database: '',
 | 
				
			||||||
                project: null,
 | 
					                project: null,
 | 
				
			||||||
                projectId: null,
 | 
					                projectId: null,
 | 
				
			||||||
                envId: null,
 | 
					                envId: null,
 | 
				
			||||||
@@ -144,17 +172,17 @@ export default defineComponent({
 | 
				
			|||||||
                        trigger: ['change', 'blur'],
 | 
					                        trigger: ['change', 'blur'],
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                password: [
 | 
					                // password: [
 | 
				
			||||||
                    {
 | 
					                //     {
 | 
				
			||||||
                        required: true,
 | 
					                //         required: true,
 | 
				
			||||||
                        message: '请输入密码',
 | 
					                //         message: '请输入密码',
 | 
				
			||||||
                        trigger: ['change', 'blur'],
 | 
					                //         trigger: ['change', 'blur'],
 | 
				
			||||||
                    },
 | 
					                //     },
 | 
				
			||||||
                ],
 | 
					                // ],
 | 
				
			||||||
                database: [
 | 
					                database: [
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        required: true,
 | 
					                        required: true,
 | 
				
			||||||
                        message: '请输入数据库名',
 | 
					                        message: '请添加数据库',
 | 
				
			||||||
                        trigger: ['change', 'blur'],
 | 
					                        trigger: ['change', 'blur'],
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
@@ -162,17 +190,47 @@ export default defineComponent({
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        watch(props, async (newValue) => {
 | 
					        watch(props, async (newValue) => {
 | 
				
			||||||
            state.dialogVisible = newValue.visible;
 | 
					 | 
				
			||||||
            state.projects = newValue.projects;
 | 
					            state.projects = newValue.projects;
 | 
				
			||||||
            if (newValue.db) {
 | 
					            if (newValue.db) {
 | 
				
			||||||
                getEnvs(newValue.db.projectId);
 | 
					                getEnvs(newValue.db.projectId);
 | 
				
			||||||
                state.form = { ...newValue.db };
 | 
					                state.form = { ...newValue.db };
 | 
				
			||||||
 | 
					                // 将数据库名使用空格切割,获取所有数据库列表
 | 
				
			||||||
 | 
					                state.databaseList = newValue.db.database.split(' ');
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                state.envs = [];
 | 
					                state.envs = [];
 | 
				
			||||||
                state.form = { port: 3306 } as any;
 | 
					                state.form = { port: 3306 } as any;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            state.dialogVisible = newValue.visible;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const handleClose = (db: string) => {
 | 
				
			||||||
 | 
					            state.databaseList.splice(state.databaseList.indexOf(db), 1);
 | 
				
			||||||
 | 
					            changeDatabase();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const showInputDb = () => {
 | 
				
			||||||
 | 
					            state.inputDbVisible = true;
 | 
				
			||||||
 | 
					            nextTick(() => {
 | 
				
			||||||
 | 
					                InputDbRef.value!.input!.focus();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const handleInputDbConfirm = () => {
 | 
				
			||||||
 | 
					            if (state.inputDbValue) {
 | 
				
			||||||
 | 
					                state.databaseList.push(state.inputDbValue);
 | 
				
			||||||
 | 
					                changeDatabase();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            state.inputDbVisible = false;
 | 
				
			||||||
 | 
					            state.inputDbValue = '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 改变表单中的数据库字段,方便表单错误提示。如全部删光,可提示请添加数据库
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const changeDatabase = () => {
 | 
				
			||||||
 | 
					            state.form.database = state.databaseList.length == 0 ? '' : state.databaseList.join(' ');
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const getEnvs = async (projectId: any) => {
 | 
					        const getEnvs = async (projectId: any) => {
 | 
				
			||||||
            state.envs = await projectApi.projectEnvs.request({ projectId });
 | 
					            state.envs = await projectApi.projectEnvs.request({ projectId });
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -216,10 +274,17 @@ export default defineComponent({
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const resetInputDb = () => {
 | 
				
			||||||
 | 
					            state.inputDbVisible = false;
 | 
				
			||||||
 | 
					            state.databaseList = [];
 | 
				
			||||||
 | 
					            state.inputDbValue = '';
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const cancel = () => {
 | 
					        const cancel = () => {
 | 
				
			||||||
            emit('update:visible', false);
 | 
					            emit('update:visible', false);
 | 
				
			||||||
            emit('cancel');
 | 
					            emit('cancel');
 | 
				
			||||||
            setTimeout(() => {
 | 
					            setTimeout(() => {
 | 
				
			||||||
 | 
					                resetInputDb();
 | 
				
			||||||
                dbForm.value.resetFields();
 | 
					                dbForm.value.resetFields();
 | 
				
			||||||
                //  重置对象属性为null
 | 
					                //  重置对象属性为null
 | 
				
			||||||
                state.form = {} as any;
 | 
					                state.form = {} as any;
 | 
				
			||||||
@@ -229,6 +294,10 @@ export default defineComponent({
 | 
				
			|||||||
        return {
 | 
					        return {
 | 
				
			||||||
            ...toRefs(state),
 | 
					            ...toRefs(state),
 | 
				
			||||||
            dbForm,
 | 
					            dbForm,
 | 
				
			||||||
 | 
					            InputDbRef,
 | 
				
			||||||
 | 
					            handleClose,
 | 
				
			||||||
 | 
					            showInputDb,
 | 
				
			||||||
 | 
					            handleInputDbConfirm,
 | 
				
			||||||
            changeProject,
 | 
					            changeProject,
 | 
				
			||||||
            changeEnv,
 | 
					            changeEnv,
 | 
				
			||||||
            btnOk,
 | 
					            btnOk,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,9 +14,6 @@
 | 
				
			|||||||
                        </el-select>
 | 
					                        </el-select>
 | 
				
			||||||
                    </el-form-item>
 | 
					                    </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <el-form-item>
 | 
					 | 
				
			||||||
                        <el-input v-model="query.database" placeholder="请输入数据库" auto-complete="off" clearable></el-input>
 | 
					 | 
				
			||||||
                    </el-form-item>
 | 
					 | 
				
			||||||
                    <el-form-item>
 | 
					                    <el-form-item>
 | 
				
			||||||
                        <el-button v-waves type="primary" icon="search" @click="search()">查询</el-button>
 | 
					                        <el-button v-waves type="primary" icon="search" @click="search()">查询</el-button>
 | 
				
			||||||
                    </el-form-item>
 | 
					                    </el-form-item>
 | 
				
			||||||
@@ -39,7 +36,20 @@
 | 
				
			|||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
                <el-table-column prop="type" label="类型" min-width="80"></el-table-column>
 | 
					                <el-table-column prop="type" label="类型" min-width="80"></el-table-column>
 | 
				
			||||||
                <el-table-column prop="database" label="数据库" min-width="120"></el-table-column>
 | 
					                <el-table-column prop="database" label="数据库" min-width="120">
 | 
				
			||||||
 | 
					                    <template #default="scope">
 | 
				
			||||||
 | 
					                        <el-tag
 | 
				
			||||||
 | 
					                            @click="showTableInfo(scope.row, db)"
 | 
				
			||||||
 | 
					                            effect="plain"
 | 
				
			||||||
 | 
					                            type="success"
 | 
				
			||||||
 | 
					                            size="small"
 | 
				
			||||||
 | 
					                            v-for="db in scope.row.dbs"
 | 
				
			||||||
 | 
					                            :key="db"
 | 
				
			||||||
 | 
					                            style="cursor: pointer"
 | 
				
			||||||
 | 
					                            >{{ db }}</el-tag
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                    </template>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
                <el-table-column prop="username" label="用户名" min-width="100"></el-table-column>
 | 
					                <el-table-column prop="username" label="用户名" min-width="100"></el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-table-column min-width="115" prop="creator" label="创建账号"></el-table-column>
 | 
					                <el-table-column min-width="115" prop="creator" label="创建账号"></el-table-column>
 | 
				
			||||||
@@ -49,11 +59,8 @@
 | 
				
			|||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-table-column fixed="right" label="更多信息" min-width="100">
 | 
					                <!-- <el-table-column fixed="right" label="更多信息" min-width="100">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                </el-table-column> -->
 | 
				
			||||||
                        <el-link @click.prevent="tableInfo(scope.row)" type="success">表信息</el-link>
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                </el-table-column>
 | 
					 | 
				
			||||||
            </el-table>
 | 
					            </el-table>
 | 
				
			||||||
            <el-row style="margin-top: 20px" type="flex" justify="end">
 | 
					            <el-row style="margin-top: 20px" type="flex" justify="end">
 | 
				
			||||||
                <el-pagination
 | 
					                <el-pagination
 | 
				
			||||||
@@ -67,12 +74,7 @@
 | 
				
			|||||||
            </el-row>
 | 
					            </el-row>
 | 
				
			||||||
        </el-card>
 | 
					        </el-card>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <el-dialog
 | 
					        <el-dialog width="75%" :title="`${db} 表信息`" :before-close="closeTableInfo" v-model="tableInfoDialog.visible">
 | 
				
			||||||
            width="75%"
 | 
					 | 
				
			||||||
            :title="`${chooseData ? chooseData.database : ''} 表信息`"
 | 
					 | 
				
			||||||
            :before-close="closeTableInfo"
 | 
					 | 
				
			||||||
            v-model="tableInfoDialog.visible"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
            <el-row class="mb10">
 | 
					            <el-row class="mb10">
 | 
				
			||||||
                <el-button type="primary" size="small" @click="tableCreateDialog.visible = true">创建表</el-button>
 | 
					                <el-button type="primary" size="small" @click="tableCreateDialog.visible = true">创建表</el-button>
 | 
				
			||||||
            </el-row>
 | 
					            </el-row>
 | 
				
			||||||
@@ -173,6 +175,7 @@ export default defineComponent({
 | 
				
			|||||||
    setup() {
 | 
					    setup() {
 | 
				
			||||||
        const state = reactive({
 | 
					        const state = reactive({
 | 
				
			||||||
            dbId: 0,
 | 
					            dbId: 0,
 | 
				
			||||||
 | 
					            db: '',
 | 
				
			||||||
            permissions: {
 | 
					            permissions: {
 | 
				
			||||||
                saveDb: 'db:save',
 | 
					                saveDb: 'db:save',
 | 
				
			||||||
                delDb: 'db:del',
 | 
					                delDb: 'db:del',
 | 
				
			||||||
@@ -235,6 +238,11 @@ export default defineComponent({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const search = async () => {
 | 
					        const search = async () => {
 | 
				
			||||||
            let res: any = await dbApi.dbs.request(state.query);
 | 
					            let res: any = await dbApi.dbs.request(state.query);
 | 
				
			||||||
 | 
					            // 切割数据库
 | 
				
			||||||
 | 
					            res.list.forEach((e: any) => {
 | 
				
			||||||
 | 
					                e.popoverSelectDbVisible = false;
 | 
				
			||||||
 | 
					                e.dbs = e.database.split(' ');
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
            state.datas = res.list;
 | 
					            state.datas = res.list;
 | 
				
			||||||
            state.total = res.total;
 | 
					            state.total = res.total;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -247,10 +255,10 @@ export default defineComponent({
 | 
				
			|||||||
        const editDb = (isAdd = false) => {
 | 
					        const editDb = (isAdd = false) => {
 | 
				
			||||||
            if (isAdd) {
 | 
					            if (isAdd) {
 | 
				
			||||||
                state.dbEditDialog.data = null;
 | 
					                state.dbEditDialog.data = null;
 | 
				
			||||||
                state.dbEditDialog.title = '新增数据库';
 | 
					                state.dbEditDialog.title = '新增数据库资源';
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                state.dbEditDialog.data = state.chooseData;
 | 
					                state.dbEditDialog.data = state.chooseData;
 | 
				
			||||||
                state.dbEditDialog.title = '修改数据库';
 | 
					                state.dbEditDialog.title = '修改数据库资源';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            state.dbEditDialog.visible = true;
 | 
					            state.dbEditDialog.visible = true;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -274,9 +282,10 @@ export default defineComponent({
 | 
				
			|||||||
            } catch (err) {}
 | 
					            } catch (err) {}
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const tableInfo = async (row: any) => {
 | 
					        const showTableInfo = async (row: any, db: string) => {
 | 
				
			||||||
            state.tableInfoDialog.infos = await dbApi.tableInfos.request({ id: row.id });
 | 
					            state.tableInfoDialog.infos = await dbApi.tableInfos.request({ id: row.id, db });
 | 
				
			||||||
            state.dbId = row.id;
 | 
					            state.dbId = row.id;
 | 
				
			||||||
 | 
					            state.db = db;
 | 
				
			||||||
            state.tableInfoDialog.visible = true;
 | 
					            state.tableInfoDialog.visible = true;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -289,6 +298,7 @@ export default defineComponent({
 | 
				
			|||||||
            state.chooseTableName = row.tableName;
 | 
					            state.chooseTableName = row.tableName;
 | 
				
			||||||
            state.columnDialog.columns = await dbApi.columnMetadata.request({
 | 
					            state.columnDialog.columns = await dbApi.columnMetadata.request({
 | 
				
			||||||
                id: state.chooseId,
 | 
					                id: state.chooseId,
 | 
				
			||||||
 | 
					                db: state.db,
 | 
				
			||||||
                tableName: row.tableName,
 | 
					                tableName: row.tableName,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -299,6 +309,7 @@ export default defineComponent({
 | 
				
			|||||||
            state.chooseTableName = row.tableName;
 | 
					            state.chooseTableName = row.tableName;
 | 
				
			||||||
            state.indexDialog.indexs = await dbApi.tableIndex.request({
 | 
					            state.indexDialog.indexs = await dbApi.tableIndex.request({
 | 
				
			||||||
                id: state.chooseId,
 | 
					                id: state.chooseId,
 | 
				
			||||||
 | 
					                db: state.db,
 | 
				
			||||||
                tableName: row.tableName,
 | 
					                tableName: row.tableName,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -309,6 +320,7 @@ export default defineComponent({
 | 
				
			|||||||
            state.chooseTableName = row.tableName;
 | 
					            state.chooseTableName = row.tableName;
 | 
				
			||||||
            const res = await dbApi.tableDdl.request({
 | 
					            const res = await dbApi.tableDdl.request({
 | 
				
			||||||
                id: state.chooseId,
 | 
					                id: state.chooseId,
 | 
				
			||||||
 | 
					                db: state.db,
 | 
				
			||||||
                tableName: row.tableName,
 | 
					                tableName: row.tableName,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            state.ddlDialog.ddl = res[0]['Create Table'];
 | 
					            state.ddlDialog.ddl = res[0]['Create Table'];
 | 
				
			||||||
@@ -329,8 +341,9 @@ export default defineComponent({
 | 
				
			|||||||
                SqlExecBox({
 | 
					                SqlExecBox({
 | 
				
			||||||
                    sql: `DROP TABLE ${tableName}`,
 | 
					                    sql: `DROP TABLE ${tableName}`,
 | 
				
			||||||
                    dbId: state.chooseId,
 | 
					                    dbId: state.chooseId,
 | 
				
			||||||
 | 
					                    db: state.db,
 | 
				
			||||||
                    runSuccessCallback: async () => {
 | 
					                    runSuccessCallback: async () => {
 | 
				
			||||||
                        state.tableInfoDialog.infos = await dbApi.tableInfos.request({ id: state.chooseId });
 | 
					                        state.tableInfoDialog.infos = await dbApi.tableInfos.request({ id: state.chooseId, db: state.db });
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            } catch (err) {}
 | 
					            } catch (err) {}
 | 
				
			||||||
@@ -345,7 +358,7 @@ export default defineComponent({
 | 
				
			|||||||
            editDb,
 | 
					            editDb,
 | 
				
			||||||
            valChange,
 | 
					            valChange,
 | 
				
			||||||
            deleteDb,
 | 
					            deleteDb,
 | 
				
			||||||
            tableInfo,
 | 
					            showTableInfo,
 | 
				
			||||||
            closeTableInfo,
 | 
					            closeTableInfo,
 | 
				
			||||||
            showColumns,
 | 
					            showColumns,
 | 
				
			||||||
            showTableIndex,
 | 
					            showTableIndex,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,21 +7,33 @@
 | 
				
			|||||||
        <div class="toolbar">
 | 
					        <div class="toolbar">
 | 
				
			||||||
            <el-row type="flex" justify="space-between">
 | 
					            <el-row type="flex" justify="space-between">
 | 
				
			||||||
                <el-col :span="24">
 | 
					                <el-col :span="24">
 | 
				
			||||||
                    <project-env-select @changeProjectEnv="changeProjectEnv" @clear="clearDb">
 | 
					                    <project-env-select @changeProjectEnv="changeProjectEnv">
 | 
				
			||||||
                        <template #default>
 | 
					                        <template #default>
 | 
				
			||||||
                            <el-form-item label="数据库">
 | 
					                            <el-form-item label="资源">
 | 
				
			||||||
                                <el-select v-model="dbId" placeholder="请选择数据库" @change="changeDb" @clear="clearDb" clearable filterable>
 | 
					                                <el-select
 | 
				
			||||||
                                    <el-option v-for="item in dbs" :key="item.id" :label="item.database" :value="item.id">
 | 
					                                    v-model="dbId"
 | 
				
			||||||
                                        <span style="float: left">{{ item.database }}</span>
 | 
					                                    placeholder="请选择资源实例"
 | 
				
			||||||
 | 
					                                    @change="changeDbInstance"
 | 
				
			||||||
 | 
					                                    filterable
 | 
				
			||||||
 | 
					                                    style="width: 150px"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    <el-option v-for="item in dbs" :key="item.id" :label="item.name" :value="item.id">
 | 
				
			||||||
 | 
					                                        <span style="float: left">{{ item.name }}</span>
 | 
				
			||||||
                                        <span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{
 | 
					                                        <span style="float: right; color: #8492a6; margin-left: 6px; font-size: 13px">{{
 | 
				
			||||||
                                            `${item.name}  [${item.type}]`
 | 
					                                            `${item.host}:${item.port} ${item.type}`
 | 
				
			||||||
                                        }}</span>
 | 
					                                        }}</span>
 | 
				
			||||||
                                    </el-option>
 | 
					                                    </el-option>
 | 
				
			||||||
                                </el-select>
 | 
					                                </el-select>
 | 
				
			||||||
                            </el-form-item>
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <el-form-item label-width="40" label="表">
 | 
					                            <el-form-item label="数据库">
 | 
				
			||||||
                                <el-select v-model="tableName" placeholder="选择表查看表数据" @change="changeTable" filterable style="width: 300px">
 | 
					                                <el-select v-model="db" placeholder="请选择数据库" @change="changeDb" @clear="clearDb" clearable filterable style="width: 150px">
 | 
				
			||||||
 | 
					                                    <el-option v-for="item in databaseList" :key="item" :label="item" :value="item"> </el-option>
 | 
				
			||||||
 | 
					                                </el-select>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-form-item label-width="20" label="表">
 | 
				
			||||||
 | 
					                                <el-select v-model="tableName" placeholder="选择表查看表数据" @change="changeTable" filterable style="width: 250px">
 | 
				
			||||||
                                    <el-option
 | 
					                                    <el-option
 | 
				
			||||||
                                        v-for="item in tableMetadata"
 | 
					                                        v-for="item in tableMetadata"
 | 
				
			||||||
                                        :key="item.tableName"
 | 
					                                        :key="item.tableName"
 | 
				
			||||||
@@ -139,7 +151,12 @@
 | 
				
			|||||||
                        </el-tooltip>
 | 
					                        </el-tooltip>
 | 
				
			||||||
                    </el-row>
 | 
					                    </el-row>
 | 
				
			||||||
                    <el-row class="mt5">
 | 
					                    <el-row class="mt5">
 | 
				
			||||||
                        <el-input v-model="dt.condition" placeholder="若需条件过滤,可选择列并点击对应的字段并输入需要过滤的内容点击查询按钮即可" clearable size="small">
 | 
					                        <el-input
 | 
				
			||||||
 | 
					                            v-model="dt.condition"
 | 
				
			||||||
 | 
					                            placeholder="若需条件过滤,可选择列并点击对应的字段并输入需要过滤的内容点击查询按钮即可"
 | 
				
			||||||
 | 
					                            clearable
 | 
				
			||||||
 | 
					                            size="small"
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
                            <template #prepend>
 | 
					                            <template #prepend>
 | 
				
			||||||
                                <el-popover trigger="click" :width="270" placement="right">
 | 
					                                <el-popover trigger="click" :width="270" placement="right">
 | 
				
			||||||
                                    <template #reference>
 | 
					                                    <template #reference>
 | 
				
			||||||
@@ -245,9 +262,11 @@ export default defineComponent({
 | 
				
			|||||||
        const state = reactive({
 | 
					        const state = reactive({
 | 
				
			||||||
            token: token,
 | 
					            token: token,
 | 
				
			||||||
            defalutLimit: 25, // 默认查询数量
 | 
					            defalutLimit: 25, // 默认查询数量
 | 
				
			||||||
            dbs: [],
 | 
					            dbs: [], // 数据库实例列表
 | 
				
			||||||
 | 
					            databaseList: [], // 数据库实例拥有的数据库列表,1数据库实例  -> 多数据库
 | 
				
			||||||
 | 
					            db: '', // 当前操作的数据库
 | 
				
			||||||
            tables: [],
 | 
					            tables: [],
 | 
				
			||||||
            dbId: null,
 | 
					            dbId: null, // 当前选中操作的数据库实例
 | 
				
			||||||
            tableName: '',
 | 
					            tableName: '',
 | 
				
			||||||
            tableMetadata: [],
 | 
					            tableMetadata: [],
 | 
				
			||||||
            columnMetadata: [],
 | 
					            columnMetadata: [],
 | 
				
			||||||
@@ -344,6 +363,8 @@ export default defineComponent({
 | 
				
			|||||||
        const changeProjectEnv = (projectId: any, envId: any) => {
 | 
					        const changeProjectEnv = (projectId: any, envId: any) => {
 | 
				
			||||||
            state.dbs = [];
 | 
					            state.dbs = [];
 | 
				
			||||||
            state.dbId = null;
 | 
					            state.dbId = null;
 | 
				
			||||||
 | 
					            state.db = '';
 | 
				
			||||||
 | 
					            state.databaseList = [];
 | 
				
			||||||
            clearDb();
 | 
					            clearDb();
 | 
				
			||||||
            if (envId != null) {
 | 
					            if (envId != null) {
 | 
				
			||||||
                state.params.envId = envId;
 | 
					                state.params.envId = envId;
 | 
				
			||||||
@@ -403,6 +424,7 @@ export default defineComponent({
 | 
				
			|||||||
        const runSql = (sql: string) => {
 | 
					        const runSql = (sql: string) => {
 | 
				
			||||||
            return dbApi.sqlExec.request({
 | 
					            return dbApi.sqlExec.request({
 | 
				
			||||||
                id: state.dbId,
 | 
					                id: state.dbId,
 | 
				
			||||||
 | 
					                db: state.db,
 | 
				
			||||||
                sql: sql.trim(),
 | 
					                sql: sql.trim(),
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -540,26 +562,35 @@ export default defineComponent({
 | 
				
			|||||||
            return selectSql;
 | 
					            return selectSql;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * 选择数据库实例事件
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        const changeDbInstance = (dbId: any) => {
 | 
				
			||||||
 | 
					            state.db = '';
 | 
				
			||||||
 | 
					            state.databaseList = (state.dbs.find((e: any) => e.id == dbId) as any).database.split(' ');
 | 
				
			||||||
 | 
					            clearDb();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * 更改数据库事件
 | 
					         * 更改数据库事件
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        const changeDb = (id: number) => {
 | 
					        const changeDb = (db: string) => {
 | 
				
			||||||
            if (!id) {
 | 
					            if (!db) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            clearDb();
 | 
					            clearDb();
 | 
				
			||||||
            dbApi.tableMetadata.request({ id }).then((res) => {
 | 
					            dbApi.tableMetadata.request({ id: state.dbId, db }).then((res) => {
 | 
				
			||||||
                state.tableMetadata = res;
 | 
					                state.tableMetadata = res;
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            dbApi.hintTables
 | 
					            dbApi.hintTables
 | 
				
			||||||
                .request({
 | 
					                .request({
 | 
				
			||||||
                    id: state.dbId,
 | 
					                    id: state.dbId,
 | 
				
			||||||
 | 
					                    db,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .then((res) => {
 | 
					                .then((res) => {
 | 
				
			||||||
                    state.cmOptions.hintOptions.tables = res;
 | 
					                    state.cmOptions.hintOptions.tables = res;
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					 | 
				
			||||||
            getSqlNames();
 | 
					            getSqlNames();
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -631,6 +662,7 @@ export default defineComponent({
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            columns = await dbApi.columnMetadata.request({
 | 
					            columns = await dbApi.columnMetadata.request({
 | 
				
			||||||
                id: state.dbId,
 | 
					                id: state.dbId,
 | 
				
			||||||
 | 
					                db: state.db,
 | 
				
			||||||
                tableName: tableName,
 | 
					                tableName: tableName,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            tableMap.set(tableName, columns);
 | 
					            tableMap.set(tableName, columns);
 | 
				
			||||||
@@ -709,7 +741,7 @@ export default defineComponent({
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
        const getUserSql = () => {
 | 
					        const getUserSql = () => {
 | 
				
			||||||
            notBlank(state.dbId, '请先选择数据库');
 | 
					            notBlank(state.dbId, '请先选择数据库');
 | 
				
			||||||
            dbApi.getSql.request({ id: state.dbId, type: 1, name: state.sqlName }).then((res) => {
 | 
					            dbApi.getSql.request({ id: state.dbId, type: 1, name: state.sqlName, db: state.db }).then((res) => {
 | 
				
			||||||
                if (res) {
 | 
					                if (res) {
 | 
				
			||||||
                    setCodermirrorValue(res.sql);
 | 
					                    setCodermirrorValue(res.sql);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
@@ -733,6 +765,7 @@ export default defineComponent({
 | 
				
			|||||||
            dbApi.getSqlNames
 | 
					            dbApi.getSqlNames
 | 
				
			||||||
                .request({
 | 
					                .request({
 | 
				
			||||||
                    id: state.dbId,
 | 
					                    id: state.dbId,
 | 
				
			||||||
 | 
					                    db: state.db,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .then((res) => {
 | 
					                .then((res) => {
 | 
				
			||||||
                    if (res && res.length > 0) {
 | 
					                    if (res && res.length > 0) {
 | 
				
			||||||
@@ -750,13 +783,14 @@ export default defineComponent({
 | 
				
			|||||||
        const saveSql = async () => {
 | 
					        const saveSql = async () => {
 | 
				
			||||||
            const sql = codemirror.getValue();
 | 
					            const sql = codemirror.getValue();
 | 
				
			||||||
            notEmpty(sql, 'sql内容不能为空');
 | 
					            notEmpty(sql, 'sql内容不能为空');
 | 
				
			||||||
            notBlank(state.dbId, '请先选择数据库');
 | 
					            notBlank(state.dbId, '请先选择数据库实例');
 | 
				
			||||||
            await dbApi.saveSql.request({ id: state.dbId, sql: sql, type: 1, name: state.sqlName });
 | 
					            await dbApi.saveSql.request({ id: state.dbId, db: state.db, sql: sql, type: 1, name: state.sqlName });
 | 
				
			||||||
            ElMessage.success('保存成功');
 | 
					            ElMessage.success('保存成功');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            dbApi.getSqlNames
 | 
					            dbApi.getSqlNames
 | 
				
			||||||
                .request({
 | 
					                .request({
 | 
				
			||||||
                    id: state.dbId,
 | 
					                    id: state.dbId,
 | 
				
			||||||
 | 
					                    db: state.db,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
                .then((res) => {
 | 
					                .then((res) => {
 | 
				
			||||||
                    if (res) {
 | 
					                    if (res) {
 | 
				
			||||||
@@ -773,7 +807,7 @@ export default defineComponent({
 | 
				
			|||||||
                    cancelButtonText: '取消',
 | 
					                    cancelButtonText: '取消',
 | 
				
			||||||
                    type: 'warning',
 | 
					                    type: 'warning',
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                await dbApi.deleteDbSql.request({ id: state.dbId, name: state.sqlName });
 | 
					                await dbApi.deleteDbSql.request({ id: state.dbId, name: state.sqlName, db: state.db });
 | 
				
			||||||
                ElMessage.success('删除成功');
 | 
					                ElMessage.success('删除成功');
 | 
				
			||||||
                getSqlNames();
 | 
					                getSqlNames();
 | 
				
			||||||
            } catch (err) {}
 | 
					            } catch (err) {}
 | 
				
			||||||
@@ -909,6 +943,7 @@ export default defineComponent({
 | 
				
			|||||||
            SqlExecBox({
 | 
					            SqlExecBox({
 | 
				
			||||||
                sql: sql,
 | 
					                sql: sql,
 | 
				
			||||||
                dbId: state.dbId as any,
 | 
					                dbId: state.dbId as any,
 | 
				
			||||||
 | 
					                db: state.db,
 | 
				
			||||||
                runSuccessCallback: successFunc,
 | 
					                runSuccessCallback: successFunc,
 | 
				
			||||||
                cancelCallback: cancelFunc,
 | 
					                cancelCallback: cancelFunc,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@@ -991,6 +1026,7 @@ export default defineComponent({
 | 
				
			|||||||
            changeSqlTemplate,
 | 
					            changeSqlTemplate,
 | 
				
			||||||
            deleteSql,
 | 
					            deleteSql,
 | 
				
			||||||
            saveSql,
 | 
					            saveSql,
 | 
				
			||||||
 | 
					            changeDbInstance,
 | 
				
			||||||
            changeDb,
 | 
					            changeDb,
 | 
				
			||||||
            clearDb,
 | 
					            clearDb,
 | 
				
			||||||
            formatSql,
 | 
					            formatSql,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import SqlExecDialog from './SqlExecDialog.vue'
 | 
				
			|||||||
export type SqlExecProps = {
 | 
					export type SqlExecProps = {
 | 
				
			||||||
    sql: string
 | 
					    sql: string
 | 
				
			||||||
    dbId: number,
 | 
					    dbId: number,
 | 
				
			||||||
 | 
					    db: string,
 | 
				
			||||||
    runSuccessCallback?: Function,
 | 
					    runSuccessCallback?: Function,
 | 
				
			||||||
    cancelCallback?: Function
 | 
					    cancelCallback?: Function
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,9 @@ export default defineComponent({
 | 
				
			|||||||
        dbId: {
 | 
					        dbId: {
 | 
				
			||||||
            type: [Number],
 | 
					            type: [Number],
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        db: {
 | 
				
			||||||
 | 
					            type: String,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        sql: {
 | 
					        sql: {
 | 
				
			||||||
            type: String,
 | 
					            type: String,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -49,6 +52,7 @@ export default defineComponent({
 | 
				
			|||||||
            dialogVisible: false,
 | 
					            dialogVisible: false,
 | 
				
			||||||
            sqlValue: '',
 | 
					            sqlValue: '',
 | 
				
			||||||
            dbId: 0,
 | 
					            dbId: 0,
 | 
				
			||||||
 | 
					            db: '',
 | 
				
			||||||
            btnLoading: false,
 | 
					            btnLoading: false,
 | 
				
			||||||
            cmOptions: {
 | 
					            cmOptions: {
 | 
				
			||||||
                tabSize: 4,
 | 
					                tabSize: 4,
 | 
				
			||||||
@@ -77,6 +81,7 @@ export default defineComponent({
 | 
				
			|||||||
                state.btnLoading = true;
 | 
					                state.btnLoading = true;
 | 
				
			||||||
                await dbApi.sqlExec.request({
 | 
					                await dbApi.sqlExec.request({
 | 
				
			||||||
                    id: state.dbId,
 | 
					                    id: state.dbId,
 | 
				
			||||||
 | 
					                    db: state.db,
 | 
				
			||||||
                    sql: state.sqlValue.trim(),
 | 
					                    sql: state.sqlValue.trim(),
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                runSuccess = true;
 | 
					                runSuccess = true;
 | 
				
			||||||
@@ -110,6 +115,7 @@ export default defineComponent({
 | 
				
			|||||||
            cancelCallback = props.cancelCallback;
 | 
					            cancelCallback = props.cancelCallback;
 | 
				
			||||||
            state.sqlValue = sqlFormatter(props.sql);
 | 
					            state.sqlValue = sqlFormatter(props.sql);
 | 
				
			||||||
            state.dbId = props.dbId;
 | 
					            state.dbId = props.dbId;
 | 
				
			||||||
 | 
					            state.db = props.db;
 | 
				
			||||||
            state.dialogVisible = true;
 | 
					            state.dialogVisible = true;
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,8 +32,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
					 | 
				
			||||||
                    <el-button @click="cancel()">取 消</el-button>
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -326,8 +326,6 @@ export default defineComponent({
 | 
				
			|||||||
        return {
 | 
					        return {
 | 
				
			||||||
            ...toRefs(state),
 | 
					            ...toRefs(state),
 | 
				
			||||||
            choose,
 | 
					            choose,
 | 
				
			||||||
            // monitor,
 | 
					 | 
				
			||||||
            // closeMonitor,
 | 
					 | 
				
			||||||
            showTerminal,
 | 
					            showTerminal,
 | 
				
			||||||
            openFormDialog,
 | 
					            openFormDialog,
 | 
				
			||||||
            deleteMachine,
 | 
					            deleteMachine,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="cancel()" :disabled="submitDisabled" size="small">关 闭</el-button>
 | 
				
			||||||
                    <el-button
 | 
					                    <el-button
 | 
				
			||||||
                        v-auth="'machine:script:save'"
 | 
					                        v-auth="'machine:script:save'"
 | 
				
			||||||
                        type="primary"
 | 
					                        type="primary"
 | 
				
			||||||
@@ -44,7 +45,6 @@
 | 
				
			|||||||
                        :disabled="submitDisabled"
 | 
					                        :disabled="submitDisabled"
 | 
				
			||||||
                        >保 存</el-button
 | 
					                        >保 存</el-button
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                    <el-button @click="cancel()" :disabled="submitDisabled" size="small">关 闭</el-button>
 | 
					 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,8 +71,8 @@
 | 
				
			|||||||
            </el-form>
 | 
					            </el-form>
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
                    <el-button @click="addProject" type="primary">确 定</el-button>
 | 
					 | 
				
			||||||
                    <el-button @click="cancelAddProject()">取 消</el-button>
 | 
					                    <el-button @click="cancelAddProject()">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button @click="addProject" type="primary">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
@@ -103,8 +103,8 @@
 | 
				
			|||||||
                </el-form>
 | 
					                </el-form>
 | 
				
			||||||
                <template #footer>
 | 
					                <template #footer>
 | 
				
			||||||
                    <div class="dialog-footer">
 | 
					                    <div class="dialog-footer">
 | 
				
			||||||
                        <el-button v-auth="permissions.saveEnv" @click="addEnv" type="primary" :loading="btnLoading">确 定</el-button>
 | 
					 | 
				
			||||||
                        <el-button @click="cancelAddEnv()">取 消</el-button>
 | 
					                        <el-button @click="cancelAddEnv()">取 消</el-button>
 | 
				
			||||||
 | 
					                        <el-button v-auth="permissions.saveEnv" @click="addEnv" type="primary" :loading="btnLoading">确 定</el-button>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </template>
 | 
					                </template>
 | 
				
			||||||
            </el-dialog>
 | 
					            </el-dialog>
 | 
				
			||||||
@@ -163,8 +163,8 @@
 | 
				
			|||||||
                </el-form>
 | 
					                </el-form>
 | 
				
			||||||
                <template #footer>
 | 
					                <template #footer>
 | 
				
			||||||
                    <div class="dialog-footer">
 | 
					                    <div class="dialog-footer">
 | 
				
			||||||
                        <el-button v-auth="permissions.saveMember" @click="addMember" type="primary" :loading="btnLoading">确 定</el-button>
 | 
					 | 
				
			||||||
                        <el-button @click="cancelAddMember()">取 消</el-button>
 | 
					                        <el-button @click="cancelAddMember()">取 消</el-button>
 | 
				
			||||||
 | 
					                        <el-button v-auth="permissions.saveMember" @click="addMember" type="primary" :loading="btnLoading">确 定</el-button>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </template>
 | 
					                </template>
 | 
				
			||||||
            </el-dialog>
 | 
					            </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,8 +32,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
					 | 
				
			||||||
                    <el-button @click="cancel()">取 消</el-button>
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                     <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,8 @@
 | 
				
			|||||||
        </el-form>
 | 
					        </el-form>
 | 
				
			||||||
        <template #footer>
 | 
					        <template #footer>
 | 
				
			||||||
            <div class="dialog-footer">
 | 
					            <div class="dialog-footer">
 | 
				
			||||||
                <el-button @click="saveValue" type="primary">确 定</el-button>
 | 
					 | 
				
			||||||
                <el-button @click="cancel()">取 消</el-button>
 | 
					                <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                <el-button @click="saveValue" type="primary">确 定</el-button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
    </el-dialog>
 | 
					    </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,10 +82,12 @@
 | 
				
			|||||||
                </el-row>
 | 
					                </el-row>
 | 
				
			||||||
            </el-form>
 | 
					            </el-form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div style="text-align: center" class="dialog-footer mt10">
 | 
					            <template #footer>
 | 
				
			||||||
                <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
					                <div class="dialog-footer mt10">
 | 
				
			||||||
                    <el-button @click="cancel()">取 消</el-button>
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,8 +19,8 @@
 | 
				
			|||||||
            </el-tree>
 | 
					            </el-tree>
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
                    <el-button type="primary" @click="btnOk">确 定</el-button>
 | 
					 | 
				
			||||||
                    <el-button @click="cancel">取 消</el-button>
 | 
					                    <el-button @click="cancel">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,8 +14,8 @@
 | 
				
			|||||||
            </el-form>
 | 
					            </el-form>
 | 
				
			||||||
            <template #footer>
 | 
					            <template #footer>
 | 
				
			||||||
                <div class="dialog-footer">
 | 
					                <div class="dialog-footer">
 | 
				
			||||||
                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
					 | 
				
			||||||
                    <el-button @click="cancel()">取 消</el-button>
 | 
					                    <el-button @click="cancel()">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,6 @@ func (d *Db) Dbs(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	g := rc.GinCtx
 | 
						g := rc.GinCtx
 | 
				
			||||||
	m := &entity.Db{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
 | 
						m := &entity.Db{EnvId: uint64(ginx.QueryInt(g, "envId", 0)),
 | 
				
			||||||
		ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
 | 
							ProjectId: uint64(ginx.QueryInt(g, "projectId", 0)),
 | 
				
			||||||
		Database:  g.Query("database"),
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	m.CreatorId = rc.LoginAccount.Id
 | 
						m.CreatorId = rc.LoginAccount.Id
 | 
				
			||||||
	rc.ResData = d.DbApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.SelectDataDbVO))
 | 
						rc.ResData = d.DbApp.GetPageList(m, ginx.GetPageParam(rc.GinCtx), new([]vo.SelectDataDbVO))
 | 
				
			||||||
@@ -54,37 +53,38 @@ func (d *Db) DeleteDb(rc *ctx.ReqCtx) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) TableInfos(rc *ctx.ReqCtx) {
 | 
					func (d *Db) TableInfos(rc *ctx.ReqCtx) {
 | 
				
			||||||
	rc.ResData = d.DbApp.GetDbInstance(GetDbId(rc.GinCtx)).GetTableInfos()
 | 
						rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableInfos()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) TableIndex(rc *ctx.ReqCtx) {
 | 
					func (d *Db) TableIndex(rc *ctx.ReqCtx) {
 | 
				
			||||||
	tn := rc.GinCtx.Query("tableName")
 | 
						tn := rc.GinCtx.Query("tableName")
 | 
				
			||||||
	biz.NotEmpty(tn, "tableName不能为空")
 | 
						biz.NotEmpty(tn, "tableName不能为空")
 | 
				
			||||||
	rc.ResData = d.DbApp.GetDbInstance(GetDbId(rc.GinCtx)).GetTableIndex(tn)
 | 
						rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetTableIndex(tn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *Db) GetCreateTableDdl(rc *ctx.ReqCtx) {
 | 
					func (d *Db) GetCreateTableDdl(rc *ctx.ReqCtx) {
 | 
				
			||||||
	tn := rc.GinCtx.Query("tableName")
 | 
						tn := rc.GinCtx.Query("tableName")
 | 
				
			||||||
	biz.NotEmpty(tn, "tableName不能为空")
 | 
						biz.NotEmpty(tn, "tableName不能为空")
 | 
				
			||||||
	rc.ResData = d.DbApp.GetDbInstance(GetDbId(rc.GinCtx)).GetCreateTableDdl(tn)
 | 
						rc.ResData = d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx)).GetCreateTableDdl(tn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/exec-sql [get]
 | 
					// @router /api/db/:dbId/exec-sql [get]
 | 
				
			||||||
func (d *Db) ExecSql(rc *ctx.ReqCtx) {
 | 
					func (d *Db) ExecSql(rc *ctx.ReqCtx) {
 | 
				
			||||||
	g := rc.GinCtx
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbInstance := d.DbApp.GetDbInstance(GetDbId(g))
 | 
						id, db := GetIdAndDb(g)
 | 
				
			||||||
	biz.IsTrue(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "您无权操作该资源")
 | 
						dbInstance := d.DbApp.GetDbInstance(id, db)
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbInstance.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 去除前后空格及换行符
 | 
						// 去除前后空格及换行符
 | 
				
			||||||
	sql := strings.TrimFunc(g.Query("sql"), func(r rune) bool {
 | 
						sql := strings.TrimFunc(g.Query("sql"), func(r rune) bool {
 | 
				
			||||||
		s := string(r)
 | 
							s := string(r)
 | 
				
			||||||
		return s == " " || s == "\n"
 | 
							return s == " " || s == "\n"
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	rc.ReqParam = sql
 | 
						rc.ReqParam = fmt.Sprintf("db: %d:%s | sql: %s", id, db, sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	biz.NotEmpty(sql, "sql不能为空")
 | 
						biz.NotEmpty(sql, "sql不能为空")
 | 
				
			||||||
	if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") {
 | 
						if strings.HasPrefix(sql, "SELECT") || strings.HasPrefix(sql, "select") || strings.HasPrefix(sql, "show") {
 | 
				
			||||||
		colNames, res, err := dbInstance.SelectData(sql)
 | 
							colNames, res, err := dbInstance.SelectData(sql)
 | 
				
			||||||
		biz.ErrIsNilAppendErr(err, "查询失败: %s")
 | 
							biz.ErrIsNilAppendErr(err, "查询失败: %s")
 | 
				
			||||||
		colAndRes := make(map[string]interface{})
 | 
							colAndRes := make(map[string]interface{})
 | 
				
			||||||
@@ -119,10 +119,10 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	bytes, _ := ioutil.ReadAll(file)
 | 
						bytes, _ := ioutil.ReadAll(file)
 | 
				
			||||||
	sqlContent := string(bytes)
 | 
						sqlContent := string(bytes)
 | 
				
			||||||
	sqls := strings.Split(sqlContent, ";")
 | 
						sqls := strings.Split(sqlContent, ";")
 | 
				
			||||||
	dbId := GetDbId(g)
 | 
						dbId, db := GetIdAndDb(g)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		db := d.DbApp.GetDbInstance(dbId)
 | 
							db := d.DbApp.GetDbInstance(dbId, db)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dbEntity := d.DbApp.GetById(dbId)
 | 
							dbEntity := d.DbApp.GetById(dbId)
 | 
				
			||||||
		dbInfo := fmt.Sprintf("于%s的%s环境", dbEntity.Name, dbEntity.Env)
 | 
							dbInfo := fmt.Sprintf("于%s的%s环境", dbEntity.Name, dbEntity.Env)
 | 
				
			||||||
@@ -136,7 +136,7 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}()
 | 
							}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		biz.IsTrue(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "您无权操作该资源")
 | 
							biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, db.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, sql := range sqls {
 | 
							for _, sql := range sqls {
 | 
				
			||||||
			sql = strings.Trim(sql, " ")
 | 
								sql = strings.Trim(sql, " ")
 | 
				
			||||||
@@ -155,8 +155,8 @@ func (d *Db) ExecSqlFile(rc *ctx.ReqCtx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/t-metadata [get]
 | 
					// @router /api/db/:dbId/t-metadata [get]
 | 
				
			||||||
func (d *Db) TableMA(rc *ctx.ReqCtx) {
 | 
					func (d *Db) TableMA(rc *ctx.ReqCtx) {
 | 
				
			||||||
	dbi := d.DbApp.GetDbInstance(GetDbId(rc.GinCtx))
 | 
						dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
 | 
				
			||||||
	biz.IsTrue(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
 | 
				
			||||||
	rc.ResData = dbi.GetTableMetedatas()
 | 
						rc.ResData = dbi.GetTableMetedatas()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,15 +166,15 @@ func (d *Db) ColumnMA(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	tn := g.Query("tableName")
 | 
						tn := g.Query("tableName")
 | 
				
			||||||
	biz.NotEmpty(tn, "tableName不能为空")
 | 
						biz.NotEmpty(tn, "tableName不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbi := d.DbApp.GetDbInstance(GetDbId(rc.GinCtx))
 | 
						dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
 | 
				
			||||||
	biz.IsTrue(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
 | 
				
			||||||
	rc.ResData = dbi.GetColumnMetadatas(tn)
 | 
						rc.ResData = dbi.GetColumnMetadatas(tn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/hint-tables [get]
 | 
					// @router /api/db/:dbId/hint-tables [get]
 | 
				
			||||||
func (d *Db) HintTables(rc *ctx.ReqCtx) {
 | 
					func (d *Db) HintTables(rc *ctx.ReqCtx) {
 | 
				
			||||||
	dbi := d.DbApp.GetDbInstance(GetDbId(rc.GinCtx))
 | 
						dbi := d.DbApp.GetDbInstance(GetIdAndDb(rc.GinCtx))
 | 
				
			||||||
	biz.IsTrue(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(d.ProjectApp.CanAccess(rc.LoginAccount.Id, dbi.ProjectId), "%s")
 | 
				
			||||||
	// 获取所有表
 | 
						// 获取所有表
 | 
				
			||||||
	tables := dbi.GetTableMetedatas()
 | 
						tables := dbi.GetTableMetedatas()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,7 +225,7 @@ func (d *Db) SaveSql(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	biz.ErrIsNil(err, "该数据库信息不存在")
 | 
						biz.ErrIsNil(err, "该数据库信息不存在")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
						// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
				
			||||||
	dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name}
 | 
						dbSql := &entity.DbSql{Type: dbSqlForm.Type, DbId: dbId, Name: dbSqlForm.Name, Db: dbSqlForm.Db}
 | 
				
			||||||
	dbSql.CreatorId = account.Id
 | 
						dbSql.CreatorId = account.Id
 | 
				
			||||||
	e := model.GetBy(dbSql)
 | 
						e := model.GetBy(dbSql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -241,8 +241,9 @@ func (d *Db) SaveSql(rc *ctx.ReqCtx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 获取所有保存的sql names
 | 
					// 获取所有保存的sql names
 | 
				
			||||||
func (d *Db) GetSqlNames(rc *ctx.ReqCtx) {
 | 
					func (d *Db) GetSqlNames(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						id, db := GetIdAndDb(rc.GinCtx)
 | 
				
			||||||
	// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
						// 获取用于是否有该dbsql的保存记录,有则更改,否则新增
 | 
				
			||||||
	dbSql := &entity.DbSql{Type: 1, DbId: GetDbId(rc.GinCtx)}
 | 
						dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
 | 
				
			||||||
	dbSql.CreatorId = rc.LoginAccount.Id
 | 
						dbSql.CreatorId = rc.LoginAccount.Id
 | 
				
			||||||
	var sqls []entity.DbSql
 | 
						var sqls []entity.DbSql
 | 
				
			||||||
	model.ListBy(dbSql, &sqls, "id", "name")
 | 
						model.ListBy(dbSql, &sqls, "id", "name")
 | 
				
			||||||
@@ -262,8 +263,9 @@ func (d *Db) DeleteSql(rc *ctx.ReqCtx) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// @router /api/db/:dbId/sql [get]
 | 
					// @router /api/db/:dbId/sql [get]
 | 
				
			||||||
func (d *Db) GetSql(rc *ctx.ReqCtx) {
 | 
					func (d *Db) GetSql(rc *ctx.ReqCtx) {
 | 
				
			||||||
 | 
						id, db := GetIdAndDb(rc.GinCtx)
 | 
				
			||||||
	// 根据创建者id, 数据库id,以及sql模板名称查询保存的sql信息
 | 
						// 根据创建者id, 数据库id,以及sql模板名称查询保存的sql信息
 | 
				
			||||||
	dbSql := &entity.DbSql{Type: 1, DbId: GetDbId(rc.GinCtx)}
 | 
						dbSql := &entity.DbSql{Type: 1, DbId: id, Db: db}
 | 
				
			||||||
	dbSql.CreatorId = rc.LoginAccount.Id
 | 
						dbSql.CreatorId = rc.LoginAccount.Id
 | 
				
			||||||
	dbSql.Name = rc.GinCtx.Query("name")
 | 
						dbSql.Name = rc.GinCtx.Query("name")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -279,3 +281,9 @@ func GetDbId(g *gin.Context) uint64 {
 | 
				
			|||||||
	biz.IsTrue(dbId > 0, "dbId错误")
 | 
						biz.IsTrue(dbId > 0, "dbId错误")
 | 
				
			||||||
	return uint64(dbId)
 | 
						return uint64(dbId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetIdAndDb(g *gin.Context) (uint64, string) {
 | 
				
			||||||
 | 
						db := g.Query("db")
 | 
				
			||||||
 | 
						biz.NotEmpty(db, "db不能为空")
 | 
				
			||||||
 | 
						return GetDbId(g), db
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ type DbForm struct {
 | 
				
			|||||||
	Host      string `binding:"required" json:"host"`
 | 
						Host      string `binding:"required" json:"host"`
 | 
				
			||||||
	Port      int    `binding:"required" json:"port"`
 | 
						Port      int    `binding:"required" json:"port"`
 | 
				
			||||||
	Username  string `binding:"required" json:"username"`
 | 
						Username  string `binding:"required" json:"username"`
 | 
				
			||||||
	Password  string `binding:"required" json:"password"`
 | 
						Password  string `json:"password"`
 | 
				
			||||||
	Database  string `binding:"required" json:"database"`
 | 
						Database  string `binding:"required" json:"database"`
 | 
				
			||||||
	ProjectId uint64 `binding:"required" json:"projectId"`
 | 
						ProjectId uint64 `binding:"required" json:"projectId"`
 | 
				
			||||||
	Project   string `json:"project"`
 | 
						Project   string `json:"project"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,6 +41,7 @@ type DbSqlSaveForm struct {
 | 
				
			|||||||
	Name string
 | 
						Name string
 | 
				
			||||||
	Sql  string `binding:"required"`
 | 
						Sql  string `binding:"required"`
 | 
				
			||||||
	Type int    `binding:"required"`
 | 
						Type int    `binding:"required"`
 | 
				
			||||||
 | 
						Db   string `binding:"required"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineFileUpdateForm struct {
 | 
					type MachineFileUpdateForm struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,7 +104,7 @@ func (m *Machine) GetProcess(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	cmd += "| head -n " + count
 | 
						cmd += "| head -n " + count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
 | 
						cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
 | 
				
			||||||
	biz.IsTrue(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res, err := cli.Run(cmd)
 | 
						res, err := cli.Run(cmd)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "获取进程信息失败: %s")
 | 
						biz.ErrIsNilAppendErr(err, "获取进程信息失败: %s")
 | 
				
			||||||
@@ -117,7 +117,7 @@ func (m *Machine) KillProcess(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	biz.NotEmpty(pid, "进程id不能为空")
 | 
						biz.NotEmpty(pid, "进程id不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
 | 
						cli := m.MachineApp.GetCli(GetMachineId(rc.GinCtx))
 | 
				
			||||||
	biz.IsTrue(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := cli.Run("kill -9 " + pid)
 | 
						_, err := cli.Run("kill -9 " + pid)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "终止进程失败: %s")
 | 
						biz.ErrIsNilAppendErr(err, "终止进程失败: %s")
 | 
				
			||||||
@@ -145,7 +145,7 @@ func (m *Machine) WsSSH(g *gin.Context) {
 | 
				
			|||||||
	rows := ginx.QueryInt(g, "rows", 40)
 | 
						rows := ginx.QueryInt(g, "rows", 40)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cli := m.MachineApp.GetCli(GetMachineId(g))
 | 
						cli := m.MachineApp.GetCli(GetMachineId(g))
 | 
				
			||||||
	biz.IsTrue(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sws, err := machine.NewLogicSshWsSession(cols, rows, cli, wsConn)
 | 
						sws, err := machine.NewLogicSshWsSession(cols, rows, cli, wsConn)
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "连接失败:%s")
 | 
						biz.ErrIsNilAppendErr(err, "连接失败:%s")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,7 +64,7 @@ func (m *MachineScript) RunMachineScript(rc *ctx.ReqCtx) {
 | 
				
			|||||||
		script = utils.TemplateParse(ms.Script, utils.Json2Map(params))
 | 
							script = utils.TemplateParse(ms.Script, utils.Json2Map(params))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cli := m.MachineApp.GetCli(machineId)
 | 
						cli := m.MachineApp.GetCli(machineId)
 | 
				
			||||||
	biz.IsTrue(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(m.ProjectApp.CanAccess(rc.LoginAccount.Id, cli.GetMachine().ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res, err := cli.Run(script)
 | 
						res, err := cli.Run(script)
 | 
				
			||||||
	// 记录请求参数
 | 
						// 记录请求参数
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,7 +86,7 @@ func (r *Redis) Scan(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	g := rc.GinCtx
 | 
						g := rc.GinCtx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
						ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
				
			||||||
	biz.IsTrue(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	keys, cursor := ri.Scan(uint64(ginx.PathParamInt(g, "cursor")), g.Query("match"), int64(ginx.PathParamInt(g, "count")))
 | 
						keys, cursor := ri.Scan(uint64(ginx.PathParamInt(g, "cursor")), g.Query("match"), int64(ginx.PathParamInt(g, "count")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -126,7 +126,7 @@ func (r *Redis) DeleteKey(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	biz.NotEmpty(key, "key不能为空")
 | 
						biz.NotEmpty(key, "key不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
						ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
				
			||||||
	biz.IsTrue(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc.ReqParam = key
 | 
						rc.ReqParam = key
 | 
				
			||||||
	ri.Cli.Del(key)
 | 
						ri.Cli.Del(key)
 | 
				
			||||||
@@ -138,7 +138,7 @@ func (r *Redis) checkKey(rc *ctx.ReqCtx) (*application.RedisInstance, string) {
 | 
				
			|||||||
	biz.NotEmpty(key, "key不能为空")
 | 
						biz.NotEmpty(key, "key不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
						ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
				
			||||||
	biz.IsTrue(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ri, key
 | 
						return ri, key
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -163,7 +163,7 @@ func (r *Redis) SetStringValue(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	ginx.BindJsonAndValid(g, keyValue)
 | 
						ginx.BindJsonAndValid(g, keyValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
						ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
				
			||||||
	biz.IsTrue(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	str, err := ri.Cli.Set(keyValue.Key, keyValue.Value, time.Second*time.Duration(keyValue.Timed)).Result()
 | 
						str, err := ri.Cli.Set(keyValue.Key, keyValue.Value, time.Second*time.Duration(keyValue.Timed)).Result()
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
 | 
						biz.ErrIsNilAppendErr(err, "保存字符串值失败: %s")
 | 
				
			||||||
@@ -176,7 +176,7 @@ func (r *Redis) SetHashValue(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	ginx.BindJsonAndValid(g, hashValue)
 | 
						ginx.BindJsonAndValid(g, hashValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
						ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
				
			||||||
	biz.IsTrue(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key := hashValue.Key
 | 
						key := hashValue.Key
 | 
				
			||||||
	// 简单处理->先删除,后新增
 | 
						// 简单处理->先删除,后新增
 | 
				
			||||||
@@ -203,7 +203,7 @@ func (r *Redis) SetSetValue(rc *ctx.ReqCtx) {
 | 
				
			|||||||
	ginx.BindJsonAndValid(g, keyvalue)
 | 
						ginx.BindJsonAndValid(g, keyvalue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
						ri := r.RedisApp.GetRedisInstance(uint64(ginx.PathParamInt(g, "id")))
 | 
				
			||||||
	biz.IsTrue(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "您无权操作该资源")
 | 
						biz.ErrIsNilAppendErr(r.ProjectApp.CanAccess(rc.LoginAccount.Id, ri.ProjectId), "%s")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key := keyvalue.Key
 | 
						key := keyvalue.Key
 | 
				
			||||||
	// 简单处理->先删除,后新增
 | 
						// 简单处理->先删除,后新增
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/base/cache"
 | 
						"mayfly-go/base/cache"
 | 
				
			||||||
	"mayfly-go/base/global"
 | 
						"mayfly-go/base/global"
 | 
				
			||||||
	"mayfly-go/base/model"
 | 
						"mayfly-go/base/model"
 | 
				
			||||||
 | 
						"mayfly-go/base/utils"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/entity"
 | 
						"mayfly-go/server/devops/domain/entity"
 | 
				
			||||||
	"mayfly-go/server/devops/domain/repository"
 | 
						"mayfly-go/server/devops/domain/repository"
 | 
				
			||||||
	"mayfly-go/server/devops/infrastructure/persistence"
 | 
						"mayfly-go/server/devops/infrastructure/persistence"
 | 
				
			||||||
@@ -35,7 +36,9 @@ type Db interface {
 | 
				
			|||||||
	Delete(id uint64)
 | 
						Delete(id uint64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 获取数据库连接实例
 | 
						// 获取数据库连接实例
 | 
				
			||||||
	GetDbInstance(id uint64) *DbInstance
 | 
						// @param id 数据库实例id
 | 
				
			||||||
 | 
						// @param db 数据库
 | 
				
			||||||
 | 
						GetDbInstance(id uint64, db string) *DbInstance
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type dbAppImpl struct {
 | 
					type dbAppImpl struct {
 | 
				
			||||||
@@ -71,29 +74,60 @@ func (d *dbAppImpl) Save(dbEntity *entity.Db) {
 | 
				
			|||||||
	// 默认tcp连接
 | 
						// 默认tcp连接
 | 
				
			||||||
	dbEntity.Network = "tcp"
 | 
						dbEntity.Network = "tcp"
 | 
				
			||||||
	// 测试连接
 | 
						// 测试连接
 | 
				
			||||||
	TestConnection(dbEntity)
 | 
						if dbEntity.Password != "" {
 | 
				
			||||||
 | 
							TestConnection(*dbEntity)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 查找是否存在该库
 | 
						// 查找是否存在该库
 | 
				
			||||||
	oldDb := &entity.Db{Host: dbEntity.Host, Port: dbEntity.Port, Database: dbEntity.Database}
 | 
						oldDb := &entity.Db{Host: dbEntity.Host, Port: dbEntity.Port, EnvId: dbEntity.EnvId}
 | 
				
			||||||
	err := d.GetDbBy(oldDb)
 | 
						err := d.GetDbBy(oldDb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if dbEntity.Id == 0 {
 | 
						if dbEntity.Id == 0 {
 | 
				
			||||||
		biz.IsTrue(err != nil, "该库已存在")
 | 
							biz.NotEmpty(dbEntity.Password, "密码不能为空")
 | 
				
			||||||
 | 
							biz.IsTrue(err != nil, "该数据库实例已存在")
 | 
				
			||||||
		d.dbRepo.Insert(dbEntity)
 | 
							d.dbRepo.Insert(dbEntity)
 | 
				
			||||||
	} else {
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 如果存在该库,则校验修改的库是否为该库
 | 
						// 如果存在该库,则校验修改的库是否为该库
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
			biz.IsTrue(oldDb.Id == dbEntity.Id, "该库已存在")
 | 
							biz.IsTrue(oldDb.Id == dbEntity.Id, "该数据库实例已存在")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbId := dbEntity.Id
 | 
				
			||||||
 | 
						old := d.GetById(dbId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var oldDbs []interface{}
 | 
				
			||||||
 | 
						for _, v := range strings.Split(old.Database, " ") {
 | 
				
			||||||
 | 
							oldDbs = append(oldDbs, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var newDbs []interface{}
 | 
				
			||||||
 | 
						for _, v := range strings.Split(dbEntity.Database, " ") {
 | 
				
			||||||
 | 
							newDbs = append(newDbs, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// 比较新旧数据库列表,需要将移除的数据库相关联的信息删除
 | 
				
			||||||
 | 
						_, delDb, _ := utils.ArrayCompare(newDbs, oldDbs, func(i1, i2 interface{}) bool {
 | 
				
			||||||
 | 
							return i1.(string) == i2.(string)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						for _, v := range delDb {
 | 
				
			||||||
		// 先关闭数据库连接
 | 
							// 先关闭数据库连接
 | 
				
			||||||
		CloseDb(dbEntity.Id)
 | 
							CloseDb(dbEntity.Id, v.(string))
 | 
				
			||||||
		d.dbRepo.Update(dbEntity)
 | 
							// 删除该库关联的所有sql记录
 | 
				
			||||||
 | 
							d.dbSqlRepo.DeleteBy(&entity.DbSql{DbId: dbId, Db: v.(string)})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d.dbRepo.Update(dbEntity)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (d *dbAppImpl) Delete(id uint64) {
 | 
					func (d *dbAppImpl) Delete(id uint64) {
 | 
				
			||||||
 | 
						db := d.GetById(id)
 | 
				
			||||||
 | 
						dbs := strings.Split(db.Database, " ")
 | 
				
			||||||
 | 
						for _, v := range dbs {
 | 
				
			||||||
		// 关闭连接
 | 
							// 关闭连接
 | 
				
			||||||
	CloseDb(id)
 | 
							CloseDb(id, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	d.dbRepo.Delete(id)
 | 
						d.dbRepo.Delete(id)
 | 
				
			||||||
	// 删除该库下用户保存的所有sql信息
 | 
						// 删除该库下用户保存的所有sql信息
 | 
				
			||||||
	d.dbSqlRepo.DeleteBy(&entity.DbSql{DbId: id})
 | 
						d.dbSqlRepo.DeleteBy(&entity.DbSql{DbId: id})
 | 
				
			||||||
@@ -101,13 +135,13 @@ func (d *dbAppImpl) Delete(id uint64) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var mutex sync.Mutex
 | 
					var mutex sync.Mutex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (da *dbAppImpl) GetDbInstance(id uint64) *DbInstance {
 | 
					func (da *dbAppImpl) GetDbInstance(id uint64, db string) *DbInstance {
 | 
				
			||||||
	mutex.Lock()
 | 
						mutex.Lock()
 | 
				
			||||||
	defer mutex.Unlock()
 | 
						defer mutex.Unlock()
 | 
				
			||||||
	// Id不为0,则为需要缓存
 | 
						// Id不为0,则为需要缓存
 | 
				
			||||||
	needCache := id != 0
 | 
						needCache := id != 0
 | 
				
			||||||
	if needCache {
 | 
						if needCache {
 | 
				
			||||||
		load, ok := dbCache.Get(id)
 | 
							load, ok := dbCache.Get(GetDbCacheKey(id, db))
 | 
				
			||||||
		if ok {
 | 
							if ok {
 | 
				
			||||||
			return load.(*DbInstance)
 | 
								return load.(*DbInstance)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -115,8 +149,11 @@ func (da *dbAppImpl) GetDbInstance(id uint64) *DbInstance {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	d := da.GetById(id)
 | 
						d := da.GetById(id)
 | 
				
			||||||
	biz.NotNil(d, "数据库信息不存在")
 | 
						biz.NotNil(d, "数据库信息不存在")
 | 
				
			||||||
	global.Log.Infof("连接db: %s:%d/%s", d.Host, d.Port, d.Database)
 | 
						biz.IsTrue(strings.Contains(d.Database, db), "未配置该库的操作权限")
 | 
				
			||||||
 | 
						global.Log.Infof("连接db: %s:%d/%s", d.Host, d.Port, db)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 将数据库替换为要访问的数据库,原本数据库为空格拼接的所有库
 | 
				
			||||||
 | 
						d.Database = db
 | 
				
			||||||
	DB, err := sql.Open(d.Type, getDsn(d))
 | 
						DB, err := sql.Open(d.Type, getDsn(d))
 | 
				
			||||||
	biz.ErrIsNil(err, fmt.Sprintf("Open %s failed, err:%v\n", d.Type, err))
 | 
						biz.ErrIsNil(err, fmt.Sprintf("Open %s failed, err:%v\n", d.Type, err))
 | 
				
			||||||
	perr := DB.Ping()
 | 
						perr := DB.Ping()
 | 
				
			||||||
@@ -131,33 +168,39 @@ func (da *dbAppImpl) GetDbInstance(id uint64) *DbInstance {
 | 
				
			|||||||
	// 设置闲置连接数
 | 
						// 设置闲置连接数
 | 
				
			||||||
	DB.SetMaxIdleConns(1)
 | 
						DB.SetMaxIdleConns(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbi := &DbInstance{Id: id, Type: d.Type, ProjectId: d.ProjectId, db: DB}
 | 
						cacheKey := GetDbCacheKey(id, db)
 | 
				
			||||||
 | 
						dbi := &DbInstance{Id: cacheKey, Type: d.Type, ProjectId: d.ProjectId, db: DB}
 | 
				
			||||||
	if needCache {
 | 
						if needCache {
 | 
				
			||||||
		dbCache.Put(id, dbi)
 | 
							dbCache.Put(cacheKey, dbi)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return dbi
 | 
						return dbi
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//------------------------------------------------------------------------------
 | 
					//------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 客户端连接缓存,30分钟内没有访问则会被关闭
 | 
					// 客户端连接缓存,30分钟内没有访问则会被关闭, key为数据库实例id:数据库
 | 
				
			||||||
var dbCache = cache.NewTimedCache(30*time.Minute, 5*time.Second).
 | 
					var dbCache = cache.NewTimedCache(30*time.Minute, 5*time.Second).
 | 
				
			||||||
	WithUpdateAccessTime(true).
 | 
						WithUpdateAccessTime(true).
 | 
				
			||||||
	OnEvicted(func(key interface{}, value interface{}) {
 | 
						OnEvicted(func(key interface{}, value interface{}) {
 | 
				
			||||||
		global.Log.Info(fmt.Sprintf("删除db连接缓存 id: %d", key))
 | 
							global.Log.Info(fmt.Sprintf("删除db连接缓存 id: %s", key))
 | 
				
			||||||
		value.(*DbInstance).Close()
 | 
							value.(*DbInstance).Close()
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetDbInstanceByCache(id uint64) *DbInstance {
 | 
					func GetDbCacheKey(dbId uint64, db string) string {
 | 
				
			||||||
	if load, ok := dbCache.Get(fmt.Sprint(id)); ok {
 | 
						return fmt.Sprintf("%d:%s", dbId, db)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetDbInstanceByCache(id string) *DbInstance {
 | 
				
			||||||
 | 
						if load, ok := dbCache.Get(id); ok {
 | 
				
			||||||
		return load.(*DbInstance)
 | 
							return load.(*DbInstance)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestConnection(d *entity.Db) {
 | 
					func TestConnection(d entity.Db) {
 | 
				
			||||||
	biz.NotNil(d, "数据库信息不存在")
 | 
						// 验证第一个库是否可以连接即可
 | 
				
			||||||
	DB, err := sql.Open(d.Type, getDsn(d))
 | 
						d.Database = strings.Split(d.Database, " ")[0]
 | 
				
			||||||
 | 
						DB, err := sql.Open(d.Type, getDsn(&d))
 | 
				
			||||||
	biz.ErrIsNil(err, "Open %s failed, err:%v\n", d.Type, err)
 | 
						biz.ErrIsNil(err, "Open %s failed, err:%v\n", d.Type, err)
 | 
				
			||||||
	defer DB.Close()
 | 
						defer DB.Close()
 | 
				
			||||||
	perr := DB.Ping()
 | 
						perr := DB.Ping()
 | 
				
			||||||
@@ -166,7 +209,7 @@ func TestConnection(d *entity.Db) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// db实例
 | 
					// db实例
 | 
				
			||||||
type DbInstance struct {
 | 
					type DbInstance struct {
 | 
				
			||||||
	Id        uint64
 | 
						Id        string
 | 
				
			||||||
	Type      string
 | 
						Type      string
 | 
				
			||||||
	ProjectId uint64
 | 
						ProjectId uint64
 | 
				
			||||||
	db        *sql.DB
 | 
						db        *sql.DB
 | 
				
			||||||
@@ -264,7 +307,9 @@ func getDsn(d *entity.Db) string {
 | 
				
			|||||||
	return ""
 | 
						return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func CloseDb(id uint64) {
 | 
					// 关闭该数据库所有连接
 | 
				
			||||||
 | 
					func CloseDb(dbId uint64, db string) {
 | 
				
			||||||
 | 
						id := GetDbCacheKey(dbId, db)
 | 
				
			||||||
	if di := GetDbInstanceByCache(id); di != nil {
 | 
						if di := GetDbInstanceByCache(id); di != nil {
 | 
				
			||||||
		di.Close()
 | 
							di.Close()
 | 
				
			||||||
		dbCache.Delete(id)
 | 
							dbCache.Delete(id)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,7 +37,7 @@ type Project interface {
 | 
				
			|||||||
	DeleteMember(projectId, accountId uint64)
 | 
						DeleteMember(projectId, accountId uint64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 账号是否有权限访问该项目关联的资源信息
 | 
						// 账号是否有权限访问该项目关联的资源信息
 | 
				
			||||||
	CanAccess(accountId, projectId uint64) bool
 | 
						CanAccess(accountId, projectId uint64) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type projectAppImpl struct {
 | 
					type projectAppImpl struct {
 | 
				
			||||||
@@ -120,6 +120,9 @@ func (p *projectAppImpl) DeleteMember(projectId, accountId uint64) {
 | 
				
			|||||||
	p.projectMemberRepo.DeleteByPidMid(projectId, accountId)
 | 
						p.projectMemberRepo.DeleteByPidMid(projectId, accountId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *projectAppImpl) CanAccess(accountId, projectId uint64) bool {
 | 
					func (p *projectAppImpl) CanAccess(accountId, projectId uint64) error {
 | 
				
			||||||
	return p.projectMemberRepo.IsExist(projectId, accountId)
 | 
						if p.projectMemberRepo.IsExist(projectId, accountId) {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return biz.NewBizErr("您无权操作该资源")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ type DbSql struct {
 | 
				
			|||||||
	model.Model `orm:"-"`
 | 
						model.Model `orm:"-"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DbId uint64 `json:"dbId"`
 | 
						DbId uint64 `json:"dbId"`
 | 
				
			||||||
 | 
						Db   string `json:"db"`
 | 
				
			||||||
	Type int    `json:"type"` // 类型
 | 
						Type int    `json:"type"` // 类型
 | 
				
			||||||
	Sql  string `json:"sql"`
 | 
						Sql  string `json:"sql"`
 | 
				
			||||||
	Name string `json:"name"`
 | 
						Name string `json:"name"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,13 +21,13 @@ SET FOREIGN_KEY_CHECKS = 0;
 | 
				
			|||||||
DROP TABLE IF EXISTS `t_db`;
 | 
					DROP TABLE IF EXISTS `t_db`;
 | 
				
			||||||
CREATE TABLE `t_db` (
 | 
					CREATE TABLE `t_db` (
 | 
				
			||||||
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 | 
					  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
  `name` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '数据库名称',
 | 
					  `name` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '数据库实例名称',
 | 
				
			||||||
  `host` varchar(20) COLLATE utf8mb4_bin NOT NULL,
 | 
					  `host` varchar(20) COLLATE utf8mb4_bin NOT NULL,
 | 
				
			||||||
  `port` int(8) NOT NULL,
 | 
					  `port` int(8) NOT NULL,
 | 
				
			||||||
  `username` varchar(255) COLLATE utf8mb4_bin NOT NULL,
 | 
					  `username` varchar(255) COLLATE utf8mb4_bin NOT NULL,
 | 
				
			||||||
  `password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `type` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '数据库类型(mysql...)',
 | 
					  `type` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '数据库实例类型(mysql...)',
 | 
				
			||||||
  `database` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `database` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '数据库,空格分割多个数据库',
 | 
				
			||||||
  `network` varchar(8) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `network` varchar(8) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `project_id` bigint(20) DEFAULT NULL,
 | 
					  `project_id` bigint(20) DEFAULT NULL,
 | 
				
			||||||
  `project` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `project` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
@@ -41,7 +41,7 @@ CREATE TABLE `t_db` (
 | 
				
			|||||||
  `modifier_id` bigint(20) DEFAULT NULL,
 | 
					  `modifier_id` bigint(20) DEFAULT NULL,
 | 
				
			||||||
  `modifier` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `modifier` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  PRIMARY KEY (`id`)
 | 
					  PRIMARY KEY (`id`)
 | 
				
			||||||
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据库信息表';
 | 
					) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据库资源信息表';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- ----------------------------
 | 
					-- ----------------------------
 | 
				
			||||||
-- Records of t_db
 | 
					-- Records of t_db
 | 
				
			||||||
@@ -55,7 +55,8 @@ COMMIT;
 | 
				
			|||||||
DROP TABLE IF EXISTS `t_db_sql`;
 | 
					DROP TABLE IF EXISTS `t_db_sql`;
 | 
				
			||||||
CREATE TABLE `t_db_sql` (
 | 
					CREATE TABLE `t_db_sql` (
 | 
				
			||||||
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
					  `id` bigint(20) NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
  `db_id` bigint(20) NOT NULL COMMENT '数据库id',
 | 
					  `db_id` bigint(20) NOT NULL COMMENT '数据库实例id',
 | 
				
			||||||
 | 
					  `db` varchar(125) NOT NULL COMMENT '数据库',
 | 
				
			||||||
  `name` varchar(60) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'sql模板名',
 | 
					  `name` varchar(60) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'sql模板名',
 | 
				
			||||||
  `sql` text COLLATE utf8mb4_bin,
 | 
					  `sql` text COLLATE utf8mb4_bin,
 | 
				
			||||||
  `type` tinyint(8) NOT NULL,
 | 
					  `type` tinyint(8) NOT NULL,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user