mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	refactor: 数据库管理迁移至数据库实例-库管理、机器管理-文件支持用户和组信息查看
This commit is contained in:
		@@ -15,7 +15,7 @@ const config = {
 | 
				
			|||||||
    baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
 | 
					    baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 系统版本
 | 
					    // 系统版本
 | 
				
			||||||
    version: 'v1.8.5',
 | 
					    version: 'v1.8.6',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default config;
 | 
					export default config;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,7 @@ const state = reactive({
 | 
				
			|||||||
        search: null as any,
 | 
					        search: null as any,
 | 
				
			||||||
        weblinks: null as any,
 | 
					        weblinks: null as any,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    status: TerminalStatus.NoConnected,
 | 
					    status: -11,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(() => {
 | 
					onMounted(() => {
 | 
				
			||||||
@@ -96,6 +96,7 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function init() {
 | 
					function init() {
 | 
				
			||||||
 | 
					    state.status = TerminalStatus.NoConnected;
 | 
				
			||||||
    if (term) {
 | 
					    if (term) {
 | 
				
			||||||
        console.log('重新连接...');
 | 
					        console.log('重新连接...');
 | 
				
			||||||
        close();
 | 
					        close();
 | 
				
			||||||
@@ -105,7 +106,7 @@ function init() {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function initTerm() {
 | 
					async function initTerm() {
 | 
				
			||||||
    term = new Terminal({
 | 
					    term = new Terminal({
 | 
				
			||||||
        fontSize: themeConfig.value.terminalFontSize || 15,
 | 
					        fontSize: themeConfig.value.terminalFontSize || 15,
 | 
				
			||||||
        fontWeight: themeConfig.value.terminalFontWeight || 'normal',
 | 
					        fontWeight: themeConfig.value.terminalFontWeight || 'normal',
 | 
				
			||||||
@@ -155,6 +156,7 @@ function initSocket() {
 | 
				
			|||||||
        state.status = TerminalStatus.Connected;
 | 
					        state.status = TerminalStatus.Connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        focus();
 | 
					        focus();
 | 
				
			||||||
 | 
					        fitTerminal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 如果有初始要执行的命令,则发送执行命令
 | 
					        // 如果有初始要执行的命令,则发送执行命令
 | 
				
			||||||
        if (props.cmd) {
 | 
					        if (props.cmd) {
 | 
				
			||||||
@@ -209,7 +211,6 @@ function loadAddon() {
 | 
				
			|||||||
        // tell trzsz the terminal columns has been changed
 | 
					        // tell trzsz the terminal columns has been changed
 | 
				
			||||||
        trzsz.setTerminalColumns(size.cols);
 | 
					        trzsz.setTerminalColumns(size.cols);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    window.addEventListener('resize', () => state.addon.fit.fit());
 | 
					 | 
				
			||||||
    // enable drag files or directories to upload
 | 
					    // enable drag files or directories to upload
 | 
				
			||||||
    terminalRef.value.addEventListener('dragover', (event: Event) => event.preventDefault());
 | 
					    terminalRef.value.addEventListener('dragover', (event: Event) => event.preventDefault());
 | 
				
			||||||
    terminalRef.value.addEventListener('drop', (event: any) => {
 | 
					    terminalRef.value.addEventListener('drop', (event: any) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,15 @@
 | 
				
			|||||||
 | 
					import EnumValue from '@/common/Enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum TerminalStatus {
 | 
					export enum TerminalStatus {
 | 
				
			||||||
    Error = -1,
 | 
					    Error = -1,
 | 
				
			||||||
    NoConnected = 0,
 | 
					    NoConnected = 0,
 | 
				
			||||||
    Connected = 1,
 | 
					    Connected = 1,
 | 
				
			||||||
    Disconnected = 2,
 | 
					    Disconnected = 2,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const TerminalStatusEnum = {
 | 
				
			||||||
 | 
					    Error: EnumValue.of(TerminalStatus.Error, '连接出错').setExtra({ iconColor: 'var(--el-color-error)' }),
 | 
				
			||||||
 | 
					    NoConnected: EnumValue.of(TerminalStatus.NoConnected, '未连接').setExtra({ iconColor: 'var(--el-color-primary)' }),
 | 
				
			||||||
 | 
					    Connected: EnumValue.of(TerminalStatus.Connected, '连接成功').setExtra({ iconColor: 'var(--el-color-success)' }),
 | 
				
			||||||
 | 
					    Disconnected: EnumValue.of(TerminalStatus.Disconnected, '连接失败').setExtra({ iconColor: 'var(--el-color-error)' }),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,93 +1,112 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div class="db-list">
 | 
					    <div class="db-list">
 | 
				
			||||||
        <page-table
 | 
					        <el-drawer
 | 
				
			||||||
            ref="pageTableRef"
 | 
					            :title="title"
 | 
				
			||||||
            :page-api="dbApi.dbs"
 | 
					            v-model="dialogVisible"
 | 
				
			||||||
            :before-query-fn="checkRouteTagPath"
 | 
					            @open="search"
 | 
				
			||||||
            :search-items="searchItems"
 | 
					            :before-close="cancel"
 | 
				
			||||||
            v-model:query-form="query"
 | 
					            :destroy-on-close="true"
 | 
				
			||||||
            :columns="columns"
 | 
					            :close-on-click-modal="true"
 | 
				
			||||||
            lazy
 | 
					            size="60%"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <template #instanceSelect>
 | 
					            <template #header>
 | 
				
			||||||
                <el-select remote :remote-method="getInstances" v-model="query.instanceId" placeholder="输入并选择实例" filterable clearable>
 | 
					                <DrawerHeader :header="title" :back="cancel">
 | 
				
			||||||
                    <el-option v-for="item in state.instances" :key="item.id" :label="`${item.name}`" :value="item.id">
 | 
					                    <template #extra>
 | 
				
			||||||
                        {{ item.name }}
 | 
					                        <div class="mr20">
 | 
				
			||||||
                        <el-divider direction="vertical" border-style="dashed" />
 | 
					                            <span>{{ $props.instance?.tags?.[0]?.codePath }}</span>
 | 
				
			||||||
 | 
					                            <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
                        {{ item.type }} / {{ item.host }}:{{ item.port }}
 | 
					                            <SvgIcon :name="getDbDialect($props.instance?.type).getInfo()?.icon" :size="20" />
 | 
				
			||||||
                        <el-divider direction="vertical" border-style="dashed" />
 | 
					                            <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
                        {{ item.username }}
 | 
					                            <span>{{ $props.instance?.host }}:{{ $props.instance?.port }}</span>
 | 
				
			||||||
                    </el-option>
 | 
					                        </div>
 | 
				
			||||||
                </el-select>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #type="{ data }">
 | 
					 | 
				
			||||||
                <el-tooltip :content="data.type" placement="top">
 | 
					 | 
				
			||||||
                    <SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
 | 
					 | 
				
			||||||
                </el-tooltip>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #host="{ data }">
 | 
					 | 
				
			||||||
                {{ `${data.host}:${data.port}` }}
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #database="{ data }">
 | 
					 | 
				
			||||||
                <el-popover placement="bottom" :width="200" trigger="click">
 | 
					 | 
				
			||||||
                    <template #reference>
 | 
					 | 
				
			||||||
                        <el-button @click="getDbNames(data)" type="primary" link>查看库</el-button>
 | 
					 | 
				
			||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                    <el-table :data="filterDbs" v-loading="state.loadingDbNames" size="small">
 | 
					                </DrawerHeader>
 | 
				
			||||||
                        <el-table-column prop="dbName" label="数据库">
 | 
					 | 
				
			||||||
                            <template #header>
 | 
					 | 
				
			||||||
                                <el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
 | 
					 | 
				
			||||||
                            </template>
 | 
					 | 
				
			||||||
                        </el-table-column>
 | 
					 | 
				
			||||||
                    </el-table>
 | 
					 | 
				
			||||||
                </el-popover>
 | 
					 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <template #tagPath="{ data }">
 | 
					            <page-table
 | 
				
			||||||
                <ResourceTags :tags="data.tags" />
 | 
					                ref="pageTableRef"
 | 
				
			||||||
            </template>
 | 
					                :page-api="dbApi.dbs"
 | 
				
			||||||
 | 
					                v-model:query-form="query"
 | 
				
			||||||
 | 
					                :columns="columns"
 | 
				
			||||||
 | 
					                lazy
 | 
				
			||||||
 | 
					                show-selection
 | 
				
			||||||
 | 
					                v-model:selection-data="state.selectionData"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <template #tableHeader>
 | 
				
			||||||
 | 
					                    <el-button v-auth="perms.saveDb" type="primary" circle icon="Plus" @click="editDb(null)"> </el-button>
 | 
				
			||||||
 | 
					                    <el-button v-auth="perms.delDb" :disabled="state.selectionData.length < 1" @click="deleteDb" type="danger" circle icon="delete"></el-button>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <template #action="{ data }">
 | 
					                <template #type="{ data }">
 | 
				
			||||||
                <el-button type="primary" @click="onShowSqlExec(data)" link>SQL记录</el-button>
 | 
					                    <el-tooltip :content="data.type" placement="top">
 | 
				
			||||||
                <el-divider direction="vertical" border-style="dashed" />
 | 
					                        <SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
 | 
				
			||||||
 | 
					                    </el-tooltip>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-dropdown @command="handleMoreActionCommand">
 | 
					                <template #database="{ data }">
 | 
				
			||||||
                    <span class="el-dropdown-link-more">
 | 
					                    <el-popover placement="bottom" :width="200" trigger="click">
 | 
				
			||||||
                        更多
 | 
					                        <template #reference>
 | 
				
			||||||
                        <el-icon class="el-icon--right">
 | 
					                            <el-button @click="getDbNames(data)" type="primary" link>查看库</el-button>
 | 
				
			||||||
                            <arrow-down />
 | 
					                        </template>
 | 
				
			||||||
                        </el-icon>
 | 
					                        <el-table :data="filterDbs" v-loading="state.loadingDbNames" size="small">
 | 
				
			||||||
                    </span>
 | 
					                            <el-table-column prop="dbName" label="数据库">
 | 
				
			||||||
                    <template #dropdown>
 | 
					                                <template #header>
 | 
				
			||||||
                        <el-dropdown-menu>
 | 
					                                    <el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'detail', data }"> 详情 </el-dropdown-item>
 | 
					                                </template>
 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'dumpDb', data }"> 导出 </el-dropdown-item>
 | 
					                            </el-table-column>
 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'backupDb', data }" v-if="actionBtns[perms.backupDb] && supportAction('backupDb', data.type)">
 | 
					                        </el-table>
 | 
				
			||||||
                                备份任务
 | 
					                    </el-popover>
 | 
				
			||||||
                            </el-dropdown-item>
 | 
					                </template>
 | 
				
			||||||
                            <el-dropdown-item
 | 
					 | 
				
			||||||
                                :command="{ type: 'backupHistory', data }"
 | 
					 | 
				
			||||||
                                v-if="actionBtns[perms.backupDb] && supportAction('backupDb', data.type)"
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                                备份历史
 | 
					 | 
				
			||||||
                            </el-dropdown-item>
 | 
					 | 
				
			||||||
                            <el-dropdown-item
 | 
					 | 
				
			||||||
                                :command="{ type: 'restoreDb', data }"
 | 
					 | 
				
			||||||
                                v-if="actionBtns[perms.restoreDb] && supportAction('restoreDb', data.type)"
 | 
					 | 
				
			||||||
                            >
 | 
					 | 
				
			||||||
                                恢复任务
 | 
					 | 
				
			||||||
                            </el-dropdown-item>
 | 
					 | 
				
			||||||
                        </el-dropdown-menu>
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                </el-dropdown>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
        </page-table>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <el-dialog width="750px" :title="`${db} 数据库导出`" v-model="exportDialog.visible">
 | 
					                <template #tagPath="{ data }">
 | 
				
			||||||
 | 
					                    <ResourceTags :tags="data.tags" />
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <template #action="{ data }">
 | 
				
			||||||
 | 
					                    <el-button v-auth="perms.saveDb" @click="editDb(data)" type="primary" link>编辑</el-button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="onShowSqlExec(data)" link>SQL记录</el-button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-dropdown @command="handleMoreActionCommand">
 | 
				
			||||||
 | 
					                        <span class="el-dropdown-link-more">
 | 
				
			||||||
 | 
					                            更多
 | 
				
			||||||
 | 
					                            <el-icon class="el-icon--right">
 | 
				
			||||||
 | 
					                                <arrow-down />
 | 
				
			||||||
 | 
					                            </el-icon>
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                        <template #dropdown>
 | 
				
			||||||
 | 
					                            <el-dropdown-menu>
 | 
				
			||||||
 | 
					                                <el-dropdown-item :command="{ type: 'dumpDb', data }"> 导出 </el-dropdown-item>
 | 
				
			||||||
 | 
					                                <el-dropdown-item
 | 
				
			||||||
 | 
					                                    :command="{ type: 'backupDb', data }"
 | 
				
			||||||
 | 
					                                    v-if="actionBtns[perms.backupDb] && supportAction('backupDb', data.type)"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    备份任务
 | 
				
			||||||
 | 
					                                </el-dropdown-item>
 | 
				
			||||||
 | 
					                                <el-dropdown-item
 | 
				
			||||||
 | 
					                                    :command="{ type: 'backupHistory', data }"
 | 
				
			||||||
 | 
					                                    v-if="actionBtns[perms.backupDb] && supportAction('backupDb', data.type)"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    备份历史
 | 
				
			||||||
 | 
					                                </el-dropdown-item>
 | 
				
			||||||
 | 
					                                <el-dropdown-item
 | 
				
			||||||
 | 
					                                    :command="{ type: 'restoreDb', data }"
 | 
				
			||||||
 | 
					                                    v-if="actionBtns[perms.restoreDb] && supportAction('restoreDb', data.type)"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                    恢复任务
 | 
				
			||||||
 | 
					                                </el-dropdown-item>
 | 
				
			||||||
 | 
					                            </el-dropdown-menu>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </el-dropdown>
 | 
				
			||||||
 | 
					                </template>
 | 
				
			||||||
 | 
					            </page-table>
 | 
				
			||||||
 | 
					        </el-drawer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <el-dialog width="750px" :title="`${exportDialog.db} 数据库导出`" v-model="exportDialog.visible">
 | 
				
			||||||
            <el-row justify="space-between">
 | 
					            <el-row justify="space-between">
 | 
				
			||||||
                <el-col :span="9">
 | 
					                <el-col :span="9">
 | 
				
			||||||
                    <el-form-item label="导出内容: ">
 | 
					                    <el-form-item label="导出内容: ">
 | 
				
			||||||
@@ -168,54 +187,29 @@
 | 
				
			|||||||
            <db-restore-list :dbId="dbRestoreDialog.dbId" :dbNames="dbRestoreDialog.dbs" />
 | 
					            <db-restore-list :dbId="dbRestoreDialog.dbId" :dbNames="dbRestoreDialog.dbs" />
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <el-dialog v-if="infoDialog.visible" v-model="infoDialog.visible" :before-close="onBeforeCloseInfoDialog">
 | 
					        <db-edit
 | 
				
			||||||
            <el-descriptions title="详情" :column="3" border>
 | 
					            @confirm="confirmEditDb"
 | 
				
			||||||
                <el-descriptions-item :span="2" label="名称">{{ infoDialog.data?.name }}</el-descriptions-item>
 | 
					            @cancel="cancelEditDb"
 | 
				
			||||||
                <el-descriptions-item :span="1" label="id">{{ infoDialog.data?.id }}</el-descriptions-item>
 | 
					            :title="dbEditDialog.title"
 | 
				
			||||||
 | 
					            v-model:visible="dbEditDialog.visible"
 | 
				
			||||||
                <el-descriptions-item :span="3" label="关联标签"><ResourceTags :tags="infoDialog.data.tags" /></el-descriptions-item>
 | 
					            :instance="props.instance"
 | 
				
			||||||
                <el-descriptions-item :span="3" label="数据库实例名称">{{ infoDialog.instance?.name }}</el-descriptions-item>
 | 
					            v-model:db="dbEditDialog.data"
 | 
				
			||||||
 | 
					        ></db-edit>
 | 
				
			||||||
                <el-descriptions-item :span="2" label="主机">{{ infoDialog.instance?.host }}</el-descriptions-item>
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="1" label="端口">{{ infoDialog.instance?.port }}</el-descriptions-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="2" label="授权凭证">{{ infoDialog.instance.authCertName }}</el-descriptions-item>
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="1" label="类型">
 | 
					 | 
				
			||||||
                    <SvgIcon :name="getDbDialect(infoDialog.instance?.type).getInfo().icon" :size="20" />{{ infoDialog.instance?.type }}
 | 
					 | 
				
			||||||
                </el-descriptions-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="3" label="数据库">{{ infoDialog.data?.database }}</el-descriptions-item>
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="3" label="备注">{{ infoDialog.data?.remark }}</el-descriptions-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="2" label="创建时间">{{ formatDate(infoDialog.data?.createTime) }} </el-descriptions-item>
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="1" label="创建者">{{ infoDialog.data?.creator }}</el-descriptions-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="2" label="更新时间">{{ formatDate(infoDialog.data?.updateTime) }} </el-descriptions-item>
 | 
					 | 
				
			||||||
                <el-descriptions-item :span="1" label="修改者">{{ infoDialog.data?.modifier }}</el-descriptions-item>
 | 
					 | 
				
			||||||
            </el-descriptions>
 | 
					 | 
				
			||||||
        </el-dialog>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        <db-edit @val-change="search()" :title="dbEditDialog.title" v-model:visible="dbEditDialog.visible" v-model:db="dbEditDialog.data"></db-edit>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { computed, defineAsyncComponent, onMounted, reactive, ref, Ref, toRefs } from 'vue';
 | 
					import { computed, defineAsyncComponent, reactive, ref, Ref, toRefs } from 'vue';
 | 
				
			||||||
import { dbApi } from './api';
 | 
					import { dbApi } from './api';
 | 
				
			||||||
import config from '@/common/config';
 | 
					import config from '@/common/config';
 | 
				
			||||||
import { joinClientParams } from '@/common/request';
 | 
					import { joinClientParams } from '@/common/request';
 | 
				
			||||||
import { isTrue } from '@/common/assert';
 | 
					import { isTrue } from '@/common/assert';
 | 
				
			||||||
import { formatDate } from '@/common/utils/format';
 | 
					 | 
				
			||||||
import PageTable from '@/components/pagetable/PageTable.vue';
 | 
					import PageTable from '@/components/pagetable/PageTable.vue';
 | 
				
			||||||
import { TableColumn } from '@/components/pagetable';
 | 
					import { TableColumn } from '@/components/pagetable';
 | 
				
			||||||
import { hasPerms } from '@/components/auth/auth';
 | 
					import { hasPerms } from '@/components/auth/auth';
 | 
				
			||||||
import DbSqlExecLog from './DbSqlExecLog.vue';
 | 
					import DbSqlExecLog from './DbSqlExecLog.vue';
 | 
				
			||||||
import { DbType } from './dialect';
 | 
					import { DbType } from './dialect';
 | 
				
			||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
					 | 
				
			||||||
import { useRoute } from 'vue-router';
 | 
					 | 
				
			||||||
import { getDbDialect } from './dialect/index';
 | 
					import { getDbDialect } from './dialect/index';
 | 
				
			||||||
import { getTagPathSearchItem } from '../component/tag';
 | 
					 | 
				
			||||||
import { SearchItem } from '@/components/SearchForm';
 | 
					 | 
				
			||||||
import DbBackupList from './DbBackupList.vue';
 | 
					import DbBackupList from './DbBackupList.vue';
 | 
				
			||||||
import DbBackupHistoryList from './DbBackupHistoryList.vue';
 | 
					import DbBackupHistoryList from './DbBackupHistoryList.vue';
 | 
				
			||||||
import DbRestoreList from './DbRestoreList.vue';
 | 
					import DbRestoreList from './DbRestoreList.vue';
 | 
				
			||||||
@@ -223,44 +217,47 @@ import ResourceTags from '../component/ResourceTags.vue';
 | 
				
			|||||||
import { sleep } from '@/common/utils/loading';
 | 
					import { sleep } from '@/common/utils/loading';
 | 
				
			||||||
import { DbGetDbNamesMode } from './enums';
 | 
					import { DbGetDbNamesMode } from './enums';
 | 
				
			||||||
import { DbInst } from './db';
 | 
					import { DbInst } from './db';
 | 
				
			||||||
 | 
					import { ElMessage, ElMessageBox } from 'element-plus';
 | 
				
			||||||
 | 
					import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
 | 
					const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const searchItems = [
 | 
					const props = defineProps({
 | 
				
			||||||
    getTagPathSearchItem(TagResourceTypeEnum.DbName.value),
 | 
					    instance: {
 | 
				
			||||||
    SearchItem.slot('instanceId', '实例', 'instanceSelect'),
 | 
					        type: [Object],
 | 
				
			||||||
    SearchItem.input('code', '编号'),
 | 
					        required: true,
 | 
				
			||||||
];
 | 
					    },
 | 
				
			||||||
 | 
					    title: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const dialogVisible = defineModel<boolean>('visible');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const emit = defineEmits(['cancel']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const columns = ref([
 | 
					const columns = ref([
 | 
				
			||||||
    TableColumn.new('tags[0].tagPath', '关联标签').isSlot('tagPath').setAddWidth(20),
 | 
					 | 
				
			||||||
    TableColumn.new('name', '名称'),
 | 
					    TableColumn.new('name', '名称'),
 | 
				
			||||||
    TableColumn.new('type', '类型').isSlot().setAddWidth(-15).alignCenter(),
 | 
					 | 
				
			||||||
    TableColumn.new('instanceName', '实例名'),
 | 
					 | 
				
			||||||
    TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
 | 
					 | 
				
			||||||
    TableColumn.new('authCertName', '授权凭证'),
 | 
					    TableColumn.new('authCertName', '授权凭证'),
 | 
				
			||||||
    TableColumn.new('getDatabaseMode', '获库方式').typeTag(DbGetDbNamesMode),
 | 
					    TableColumn.new('getDatabaseMode', '获库方式').typeTag(DbGetDbNamesMode),
 | 
				
			||||||
    TableColumn.new('database', '库').isSlot().setMinWidth(80),
 | 
					    TableColumn.new('database', '库').isSlot().setMinWidth(80),
 | 
				
			||||||
    TableColumn.new('remark', '备注'),
 | 
					    TableColumn.new('remark', '备注'),
 | 
				
			||||||
    TableColumn.new('code', '编号'),
 | 
					    TableColumn.new('code', '编号'),
 | 
				
			||||||
 | 
					    TableColumn.new('action', '操作').isSlot().setMinWidth(210).fixedRight().alignCenter(),
 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const perms = {
 | 
					const perms = {
 | 
				
			||||||
 | 
					    base: 'db',
 | 
				
			||||||
 | 
					    saveDb: 'db:save',
 | 
				
			||||||
 | 
					    delDb: 'db:del',
 | 
				
			||||||
    backupDb: 'db:backup',
 | 
					    backupDb: 'db:backup',
 | 
				
			||||||
    restoreDb: 'db:restore',
 | 
					    restoreDb: 'db:restore',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 该用户拥有的的操作列按钮权限
 | 
					 | 
				
			||||||
// const actionBtns = hasPerms([perms.base, perms.saveDb]);
 | 
					 | 
				
			||||||
const actionBtns = hasPerms(Object.values(perms));
 | 
					const actionBtns = hasPerms(Object.values(perms));
 | 
				
			||||||
const actionColumn = TableColumn.new('action', '操作').isSlot().setMinWidth(180).fixedRight().alignCenter();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute();
 | 
					 | 
				
			||||||
const pageTableRef: Ref<any> = ref(null);
 | 
					const pageTableRef: Ref<any> = ref(null);
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
    row: {} as any,
 | 
					 | 
				
			||||||
    dbId: 0,
 | 
					 | 
				
			||||||
    db: '',
 | 
					 | 
				
			||||||
    loadingDbNames: false,
 | 
					    loadingDbNames: false,
 | 
				
			||||||
    currentDbNames: [],
 | 
					    currentDbNames: [],
 | 
				
			||||||
    dbNameSearch: '',
 | 
					    dbNameSearch: '',
 | 
				
			||||||
@@ -268,29 +265,20 @@ const state = reactive({
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 选中的数据
 | 
					     * 选中的数据
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    selectionData: [],
 | 
					    selectionData: [] as any,
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 查询条件
 | 
					     * 查询条件
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    query: {
 | 
					    query: {
 | 
				
			||||||
        tagPath: '',
 | 
					        instanceId: 0,
 | 
				
			||||||
        instanceId: null,
 | 
					 | 
				
			||||||
        pageNum: 1,
 | 
					        pageNum: 1,
 | 
				
			||||||
        pageSize: 0,
 | 
					        pageSize: 0,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    infoDialog: {
 | 
					 | 
				
			||||||
        visible: false,
 | 
					 | 
				
			||||||
        data: null as any,
 | 
					 | 
				
			||||||
        instance: null as any,
 | 
					 | 
				
			||||||
        query: {
 | 
					 | 
				
			||||||
            instanceId: 0,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    // sql执行记录弹框
 | 
					    // sql执行记录弹框
 | 
				
			||||||
    sqlExecLogDialog: {
 | 
					    sqlExecLogDialog: {
 | 
				
			||||||
        title: '',
 | 
					        title: '',
 | 
				
			||||||
        visible: false,
 | 
					        visible: false,
 | 
				
			||||||
        dbs: [],
 | 
					        dbs: [] as any,
 | 
				
			||||||
        dbId: 0,
 | 
					        dbId: 0,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    // 数据库备份弹框
 | 
					    // 数据库备份弹框
 | 
				
			||||||
@@ -321,6 +309,7 @@ const state = reactive({
 | 
				
			|||||||
    exportDialog: {
 | 
					    exportDialog: {
 | 
				
			||||||
        visible: false,
 | 
					        visible: false,
 | 
				
			||||||
        dbId: 0,
 | 
					        dbId: 0,
 | 
				
			||||||
 | 
					        db: '',
 | 
				
			||||||
        type: 3,
 | 
					        type: 3,
 | 
				
			||||||
        data: [] as any,
 | 
					        data: [] as any,
 | 
				
			||||||
        value: [],
 | 
					        value: [],
 | 
				
			||||||
@@ -339,14 +328,12 @@ const state = reactive({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { db, query, infoDialog, sqlExecLogDialog, exportDialog, dbEditDialog, dbBackupDialog, dbBackupHistoryDialog, dbRestoreDialog } = toRefs(state);
 | 
					const { query, sqlExecLogDialog, exportDialog, dbEditDialog, dbBackupDialog, dbBackupHistoryDialog, dbRestoreDialog } = toRefs(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(async () => {
 | 
					const search = async () => {
 | 
				
			||||||
    if (Object.keys(actionBtns).length > 0) {
 | 
					    state.query.instanceId = props.instance?.id;
 | 
				
			||||||
        columns.value.push(actionColumn);
 | 
					    pageTableRef.value.search();
 | 
				
			||||||
    }
 | 
					};
 | 
				
			||||||
    search();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getDbNames = async (db: any) => {
 | 
					const getDbNames = async (db: any) => {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
@@ -372,42 +359,46 @@ const filterDbs = computed(() => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const checkRouteTagPath = (query: any) => {
 | 
					const editDb = (data: any) => {
 | 
				
			||||||
    if (route.query.tagPath) {
 | 
					 | 
				
			||||||
        query.tagPath = route.query.tagPath as string;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return query;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const search = async (tagPath: string = '') => {
 | 
					 | 
				
			||||||
    if (tagPath) {
 | 
					 | 
				
			||||||
        state.query.tagPath = tagPath;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pageTableRef.value.search();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const showInfo = async (info: any) => {
 | 
					 | 
				
			||||||
    state.infoDialog.data = info;
 | 
					 | 
				
			||||||
    state.infoDialog.query.instanceId = info.instanceId;
 | 
					 | 
				
			||||||
    const res = await dbApi.getInstance.request(state.infoDialog.query);
 | 
					 | 
				
			||||||
    state.infoDialog.instance = res;
 | 
					 | 
				
			||||||
    state.infoDialog.visible = true;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const onBeforeCloseInfoDialog = () => {
 | 
					 | 
				
			||||||
    state.infoDialog.visible = false;
 | 
					 | 
				
			||||||
    state.infoDialog.data = null;
 | 
					 | 
				
			||||||
    state.infoDialog.instance = null;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getInstances = async (instanceName = '') => {
 | 
					 | 
				
			||||||
    if (!instanceName) {
 | 
					 | 
				
			||||||
        state.instances = [];
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const data = await dbApi.instances.request({ name: instanceName });
 | 
					 | 
				
			||||||
    if (data) {
 | 
					    if (data) {
 | 
				
			||||||
        state.instances = data.list;
 | 
					        state.dbEditDialog.data = { ...data };
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        state.dbEditDialog.data = {
 | 
				
			||||||
 | 
					            instanceId: props.instance.id,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    state.dbEditDialog.title = data ? '编辑数据库' : '新增数据库';
 | 
				
			||||||
 | 
					    state.dbEditDialog.visible = true;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const confirmEditDb = async (db: any) => {
 | 
				
			||||||
 | 
					    db.instanceId = props.instance.id;
 | 
				
			||||||
 | 
					    await dbApi.saveDb.request(db);
 | 
				
			||||||
 | 
					    ElMessage.success('保存成功');
 | 
				
			||||||
 | 
					    search();
 | 
				
			||||||
 | 
					    cancelEditDb();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cancelEditDb = () => {
 | 
				
			||||||
 | 
					    state.dbEditDialog.visible = false;
 | 
				
			||||||
 | 
					    state.dbEditDialog.data = {};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const deleteDb = async () => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        await ElMessageBox.confirm(`确定删除【${state.selectionData.map((x: any) => x.name).join(', ')}】库?`, '提示', {
 | 
				
			||||||
 | 
					            confirmButtonText: '确定',
 | 
				
			||||||
 | 
					            cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            type: 'warning',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        for (let db of state.selectionData) {
 | 
				
			||||||
 | 
					            await dbApi.deleteDb.request({ id: db.id });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ElMessage.success('删除成功');
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					        search();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -415,10 +406,6 @@ const handleMoreActionCommand = (commond: any) => {
 | 
				
			|||||||
    const data = commond.data;
 | 
					    const data = commond.data;
 | 
				
			||||||
    const type = commond.type;
 | 
					    const type = commond.type;
 | 
				
			||||||
    switch (type) {
 | 
					    switch (type) {
 | 
				
			||||||
        case 'detail': {
 | 
					 | 
				
			||||||
            showInfo(data);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        case 'dumpDb': {
 | 
					        case 'dumpDb': {
 | 
				
			||||||
            onDumpDbs(data);
 | 
					            onDumpDbs(data);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@@ -441,7 +428,9 @@ const handleMoreActionCommand = (commond: any) => {
 | 
				
			|||||||
const onShowSqlExec = async (row: any) => {
 | 
					const onShowSqlExec = async (row: any) => {
 | 
				
			||||||
    state.sqlExecLogDialog.title = `${row.name}`;
 | 
					    state.sqlExecLogDialog.title = `${row.name}`;
 | 
				
			||||||
    state.sqlExecLogDialog.dbId = row.id;
 | 
					    state.sqlExecLogDialog.dbId = row.id;
 | 
				
			||||||
    state.sqlExecLogDialog.dbs = row.database.split(' ');
 | 
					    DbInst.getDbNames(row).then((res) => {
 | 
				
			||||||
 | 
					        state.sqlExecLogDialog.dbs = res;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    state.sqlExecLogDialog.visible = true;
 | 
					    state.sqlExecLogDialog.visible = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -454,26 +443,32 @@ const onBeforeCloseSqlExecDialog = () => {
 | 
				
			|||||||
const onShowDbBackupDialog = async (row: any) => {
 | 
					const onShowDbBackupDialog = async (row: any) => {
 | 
				
			||||||
    state.dbBackupDialog.title = `${row.name}`;
 | 
					    state.dbBackupDialog.title = `${row.name}`;
 | 
				
			||||||
    state.dbBackupDialog.dbId = row.id;
 | 
					    state.dbBackupDialog.dbId = row.id;
 | 
				
			||||||
    state.dbBackupDialog.dbs = row.database.split(' ');
 | 
					    DbInst.getDbNames(row).then((res) => {
 | 
				
			||||||
 | 
					        state.sqlExecLogDialog.dbs = res;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    state.dbBackupDialog.visible = true;
 | 
					    state.dbBackupDialog.visible = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onShowDbBackupHistoryDialog = async (row: any) => {
 | 
					const onShowDbBackupHistoryDialog = async (row: any) => {
 | 
				
			||||||
    state.dbBackupHistoryDialog.title = `${row.name}`;
 | 
					    state.dbBackupHistoryDialog.title = `${row.name}`;
 | 
				
			||||||
    state.dbBackupHistoryDialog.dbId = row.id;
 | 
					    state.dbBackupHistoryDialog.dbId = row.id;
 | 
				
			||||||
    state.dbBackupHistoryDialog.dbs = row.database.split(' ');
 | 
					    DbInst.getDbNames(row).then((res) => {
 | 
				
			||||||
 | 
					        state.sqlExecLogDialog.dbs = res;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    state.dbBackupHistoryDialog.visible = true;
 | 
					    state.dbBackupHistoryDialog.visible = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onShowDbRestoreDialog = async (row: any) => {
 | 
					const onShowDbRestoreDialog = async (row: any) => {
 | 
				
			||||||
    state.dbRestoreDialog.title = `${row.name}`;
 | 
					    state.dbRestoreDialog.title = `${row.name}`;
 | 
				
			||||||
    state.dbRestoreDialog.dbId = row.id;
 | 
					    state.dbRestoreDialog.dbId = row.id;
 | 
				
			||||||
    state.dbRestoreDialog.dbs = row.database.split(' ');
 | 
					    DbInst.getDbNames(row).then((res) => {
 | 
				
			||||||
 | 
					        state.sqlExecLogDialog.dbs = res;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    state.dbRestoreDialog.visible = true;
 | 
					    state.dbRestoreDialog.visible = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onDumpDbs = async (row: any) => {
 | 
					const onDumpDbs = async (row: any) => {
 | 
				
			||||||
    const dbs = row.database.split(' ');
 | 
					    const dbs = await DbInst.getDbNames(row);
 | 
				
			||||||
    const data = [];
 | 
					    const data = [];
 | 
				
			||||||
    for (let name of dbs) {
 | 
					    for (let name of dbs) {
 | 
				
			||||||
        data.push({
 | 
					        data.push({
 | 
				
			||||||
@@ -481,6 +476,7 @@ const onDumpDbs = async (row: any) => {
 | 
				
			|||||||
            label: name,
 | 
					            label: name,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    state.exportDialog.db = row.name;
 | 
				
			||||||
    state.exportDialog.value = [];
 | 
					    state.exportDialog.value = [];
 | 
				
			||||||
    state.exportDialog.data = data;
 | 
					    state.exportDialog.data = data;
 | 
				
			||||||
    state.exportDialog.dbId = row.id;
 | 
					    state.exportDialog.dbId = row.id;
 | 
				
			||||||
@@ -524,7 +520,10 @@ const supportAction = (action: string, dbType: string): boolean => {
 | 
				
			|||||||
    return actions.includes(action);
 | 
					    return actions.includes(action);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
defineExpose({ search });
 | 
					const cancel = () => {
 | 
				
			||||||
 | 
					    dialogVisible.value = false;
 | 
				
			||||||
 | 
					    emit('cancel');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
.db-list {
 | 
					.db-list {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,190 +0,0 @@
 | 
				
			|||||||
<template>
 | 
					 | 
				
			||||||
    <div>
 | 
					 | 
				
			||||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
 | 
					 | 
				
			||||||
            <template #header>
 | 
					 | 
				
			||||||
                <DrawerHeader :header="title" :back="cancel" />
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <el-table :data="state.dbs" stripe>
 | 
					 | 
				
			||||||
                <el-table-column prop="name" label="名称" show-overflow-tooltip min-width="100"> </el-table-column>
 | 
					 | 
				
			||||||
                <el-table-column prop="authCertName" label="授权凭证" min-width="120" show-overflow-tooltip> </el-table-column>
 | 
					 | 
				
			||||||
                <el-table-column prop="getDatabaseMode" label="获库方式" min-width="80">
 | 
					 | 
				
			||||||
                    <template #default="scope">
 | 
					 | 
				
			||||||
                        <EnumTag :enums="DbGetDbNamesMode" :value="scope.row.getDatabaseMode" />
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                </el-table-column>
 | 
					 | 
				
			||||||
                <el-table-column prop="database" label="库" min-width="80">
 | 
					 | 
				
			||||||
                    <template #default="scope">
 | 
					 | 
				
			||||||
                        <el-popover placement="bottom" :width="200" trigger="click">
 | 
					 | 
				
			||||||
                            <template #reference>
 | 
					 | 
				
			||||||
                                <el-button @click="getDbNames(scope.row)" type="primary" link>查看库</el-button>
 | 
					 | 
				
			||||||
                            </template>
 | 
					 | 
				
			||||||
                            <el-table :data="filterDbs" size="small" v-loading="state.loadingDbNames">
 | 
					 | 
				
			||||||
                                <el-table-column prop="dbName" label="数据库">
 | 
					 | 
				
			||||||
                                    <template #header>
 | 
					 | 
				
			||||||
                                        <el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
 | 
					 | 
				
			||||||
                                    </template>
 | 
					 | 
				
			||||||
                                </el-table-column>
 | 
					 | 
				
			||||||
                            </el-table>
 | 
					 | 
				
			||||||
                        </el-popover>
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                </el-table-column>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-table-column prop="remark" label="备注" show-overflow-tooltip min-width="120"> </el-table-column>
 | 
					 | 
				
			||||||
                <el-table-column prop="code" label="编号" show-overflow-tooltip min-width="120"> </el-table-column>
 | 
					 | 
				
			||||||
                <el-table-column min-wdith="120px">
 | 
					 | 
				
			||||||
                    <template #header>
 | 
					 | 
				
			||||||
                        操作
 | 
					 | 
				
			||||||
                        <el-button v-auth="perms.saveDb" type="primary" circle size="small" icon="Plus" @click="editDb(null)"> </el-button>
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                    <template #default="scope">
 | 
					 | 
				
			||||||
                        <el-button v-auth="perms.saveDb" @click="editDb(scope.row)" type="primary" icon="edit" link></el-button>
 | 
					 | 
				
			||||||
                        <el-button class="ml1" v-auth="perms.delDb" type="danger" @click="deleteDb(scope.row)" icon="delete" link></el-button>
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                </el-table-column>
 | 
					 | 
				
			||||||
            </el-table>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <db-edit
 | 
					 | 
				
			||||||
                @confirm="confirmEditDb"
 | 
					 | 
				
			||||||
                @cancel="cancelEditDb"
 | 
					 | 
				
			||||||
                :title="dbEditDialog.title"
 | 
					 | 
				
			||||||
                v-model:visible="dbEditDialog.visible"
 | 
					 | 
				
			||||||
                :instance="props.instance"
 | 
					 | 
				
			||||||
                v-model:db="dbEditDialog.data"
 | 
					 | 
				
			||||||
            ></db-edit>
 | 
					 | 
				
			||||||
        </el-drawer>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script lang="ts" setup>
 | 
					 | 
				
			||||||
import { computed, reactive, toRefs, watchEffect } from 'vue';
 | 
					 | 
				
			||||||
import { dbApi } from './api';
 | 
					 | 
				
			||||||
import { ElMessage, ElMessageBox } from 'element-plus';
 | 
					 | 
				
			||||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
 | 
					 | 
				
			||||||
import DbEdit from './DbEdit.vue';
 | 
					 | 
				
			||||||
import EnumTag from '@/components/enumtag/EnumTag.vue';
 | 
					 | 
				
			||||||
import { DbGetDbNamesMode } from './enums';
 | 
					 | 
				
			||||||
import { DbInst } from './db';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const props = defineProps({
 | 
					 | 
				
			||||||
    visible: {
 | 
					 | 
				
			||||||
        type: Boolean,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    instance: {
 | 
					 | 
				
			||||||
        type: [Object],
 | 
					 | 
				
			||||||
        required: true,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    title: {
 | 
					 | 
				
			||||||
        type: String,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const perms = {
 | 
					 | 
				
			||||||
    base: 'db',
 | 
					 | 
				
			||||||
    saveDb: 'db:save',
 | 
					 | 
				
			||||||
    delDb: 'db:del',
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//定义事件
 | 
					 | 
				
			||||||
const emit = defineEmits(['update:visible', 'cancel', 'val-change']);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const state = reactive({
 | 
					 | 
				
			||||||
    dialogVisible: false,
 | 
					 | 
				
			||||||
    dbs: [] as any,
 | 
					 | 
				
			||||||
    loadingDbNames: false,
 | 
					 | 
				
			||||||
    currentDbNames: [], // 当前数据库名
 | 
					 | 
				
			||||||
    dbNameSearch: '',
 | 
					 | 
				
			||||||
    dbEditDialog: {
 | 
					 | 
				
			||||||
        visible: false,
 | 
					 | 
				
			||||||
        data: null as any,
 | 
					 | 
				
			||||||
        title: '新增数据库',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { dialogVisible, dbEditDialog } = toRefs(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
watchEffect(() => {
 | 
					 | 
				
			||||||
    state.dialogVisible = props.visible;
 | 
					 | 
				
			||||||
    if (!state.dialogVisible) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    getDbs();
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getDbNames = async (db: any) => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
        state.loadingDbNames = true;
 | 
					 | 
				
			||||||
        state.currentDbNames = await DbInst.getDbNames(db);
 | 
					 | 
				
			||||||
    } finally {
 | 
					 | 
				
			||||||
        state.loadingDbNames = false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const filterDbs = computed(() => {
 | 
					 | 
				
			||||||
    const dbNames = state.currentDbNames;
 | 
					 | 
				
			||||||
    if (!dbNames) {
 | 
					 | 
				
			||||||
        return [];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const dbNameObjs = dbNames.map((x) => {
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            dbName: x,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    return dbNameObjs.filter((db: any) => {
 | 
					 | 
				
			||||||
        return db.dbName.includes(state.dbNameSearch);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const cancel = () => {
 | 
					 | 
				
			||||||
    emit('update:visible', false);
 | 
					 | 
				
			||||||
    emit('cancel');
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const getDbs = () => {
 | 
					 | 
				
			||||||
    dbApi.dbs.request({ pageSize: 200, instanceId: props.instance.id }).then((res: any) => {
 | 
					 | 
				
			||||||
        state.dbs = res.list || [];
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const editDb = (data: any) => {
 | 
					 | 
				
			||||||
    if (data) {
 | 
					 | 
				
			||||||
        state.dbEditDialog.data = { ...data };
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        state.dbEditDialog.data = {
 | 
					 | 
				
			||||||
            instanceId: props.instance.id,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    state.dbEditDialog.title = data ? '编辑数据库' : '新增数据库';
 | 
					 | 
				
			||||||
    state.dbEditDialog.visible = true;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const deleteDb = async (db: any) => {
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
        await ElMessageBox.confirm(`确定删除【${db.name}】库?`, '提示', {
 | 
					 | 
				
			||||||
            confirmButtonText: '确定',
 | 
					 | 
				
			||||||
            cancelButtonText: '取消',
 | 
					 | 
				
			||||||
            type: 'warning',
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        await dbApi.deleteDb.request({ id: db.id });
 | 
					 | 
				
			||||||
        ElMessage.success('删除成功');
 | 
					 | 
				
			||||||
        getDbs();
 | 
					 | 
				
			||||||
    } catch (err) {
 | 
					 | 
				
			||||||
        //
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const confirmEditDb = async (db: any) => {
 | 
					 | 
				
			||||||
    db.instanceId = props.instance.id;
 | 
					 | 
				
			||||||
    await dbApi.saveDb.request(db);
 | 
					 | 
				
			||||||
    ElMessage.success('保存成功');
 | 
					 | 
				
			||||||
    getDbs();
 | 
					 | 
				
			||||||
    cancelEditDb();
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const cancelEditDb = () => {
 | 
					 | 
				
			||||||
    state.dbEditDialog.visible = false;
 | 
					 | 
				
			||||||
    state.dbEditDialog.data = {};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
<style lang="scss"></style>
 | 
					 | 
				
			||||||
@@ -35,7 +35,7 @@
 | 
				
			|||||||
            <template #action="{ data }">
 | 
					            <template #action="{ data }">
 | 
				
			||||||
                <el-button @click="showInfo(data)" link>详情</el-button>
 | 
					                <el-button @click="showInfo(data)" link>详情</el-button>
 | 
				
			||||||
                <el-button v-if="actionBtns[perms.saveInstance]" @click="editInstance(data)" type="primary" link>编辑</el-button>
 | 
					                <el-button v-if="actionBtns[perms.saveInstance]" @click="editInstance(data)" type="primary" link>编辑</el-button>
 | 
				
			||||||
                <el-button v-if="actionBtns[perms.saveDb]" @click="editDb(data)" type="primary" link>库配置</el-button>
 | 
					                <el-button v-if="actionBtns[perms.saveDb]" @click="editDb(data)" type="primary" link>库管理</el-button>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
        </page-table>
 | 
					        </page-table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,7 +68,7 @@
 | 
				
			|||||||
            v-model:data="instanceEditDialog.data"
 | 
					            v-model:data="instanceEditDialog.data"
 | 
				
			||||||
        ></instance-edit>
 | 
					        ></instance-edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <instance-db-conf :title="dbEditDialog.title" v-model:visible="dbEditDialog.visible" :instance="dbEditDialog.instance" />
 | 
					        <DbList :title="dbEditDialog.title" v-model:visible="dbEditDialog.visible" :instance="dbEditDialog.instance" />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,7 +89,7 @@ import { getTagPathSearchItem } from '../component/tag';
 | 
				
			|||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
					import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const InstanceEdit = defineAsyncComponent(() => import('./InstanceEdit.vue'));
 | 
					const InstanceEdit = defineAsyncComponent(() => import('./InstanceEdit.vue'));
 | 
				
			||||||
const InstanceDbConf = defineAsyncComponent(() => import('./InstanceDbConf.vue'));
 | 
					const DbList = defineAsyncComponent(() => import('./DbList.vue'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
    lazy: {
 | 
					    lazy: {
 | 
				
			||||||
@@ -215,7 +215,7 @@ const deleteInstance = async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const editDb = (data: any) => {
 | 
					const editDb = (data: any) => {
 | 
				
			||||||
    state.dbEditDialog.instance = data;
 | 
					    state.dbEditDialog.instance = data;
 | 
				
			||||||
    state.dbEditDialog.title = `配置 "${data.name}" 数据库`;
 | 
					    state.dbEditDialog.title = `管理 "${data.name}" 数据库`;
 | 
				
			||||||
    state.dbEditDialog.visible = true;
 | 
					    state.dbEditDialog.visible = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,20 +34,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <Pane>
 | 
					            <Pane>
 | 
				
			||||||
                <div class="machine-terminal-tabs card pd5">
 | 
					                <div class="machine-terminal-tabs card pd5">
 | 
				
			||||||
                    <el-tabs
 | 
					                    <el-tabs v-if="state.tabs.size > 0" type="card" @tab-remove="onRemoveTab" style="width: 100%" v-model="state.activeTermName" class="h100">
 | 
				
			||||||
                        v-if="state.tabs.size > 0"
 | 
					 | 
				
			||||||
                        type="card"
 | 
					 | 
				
			||||||
                        @tab-remove="onRemoveTab"
 | 
					 | 
				
			||||||
                        @tab-change="onTabChange"
 | 
					 | 
				
			||||||
                        style="width: 100%"
 | 
					 | 
				
			||||||
                        v-model="state.activeTermName"
 | 
					 | 
				
			||||||
                        class="h100"
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                        <el-tab-pane class="h100" closable v-for="dt in state.tabs.values()" :label="dt.label" :name="dt.key" :key="dt.key">
 | 
					                        <el-tab-pane class="h100" closable v-for="dt in state.tabs.values()" :label="dt.label" :name="dt.key" :key="dt.key">
 | 
				
			||||||
                            <template #label>
 | 
					                            <template #label>
 | 
				
			||||||
                                <el-popconfirm @confirm="handleReconnect(dt, true)" title="确认重新连接?">
 | 
					                                <el-popconfirm @confirm="handleReconnect(dt, true)" title="确认重新连接?">
 | 
				
			||||||
                                    <template #reference>
 | 
					                                    <template #reference>
 | 
				
			||||||
                                        <el-icon class="mr5" :color="dt.status == 1 ? '#67c23a' : '#f56c6c'" :title="dt.status == 1 ? '' : '点击重连'"
 | 
					                                        <el-icon
 | 
				
			||||||
 | 
					                                            class="mr5"
 | 
				
			||||||
 | 
					                                            :color="EnumValue.getEnumByValue(TerminalStatusEnum, dt.status)?.extra?.iconColor"
 | 
				
			||||||
 | 
					                                            :title="dt.status == TerminalStatusEnum.Connected.value ? '' : '点击重连'"
 | 
				
			||||||
                                            ><Connection />
 | 
					                                            ><Connection />
 | 
				
			||||||
                                        </el-icon>
 | 
					                                        </el-icon>
 | 
				
			||||||
                                    </template>
 | 
					                                    </template>
 | 
				
			||||||
@@ -62,7 +57,7 @@
 | 
				
			|||||||
                                        <el-descriptions :column="1" size="small">
 | 
					                                        <el-descriptions :column="1" size="small">
 | 
				
			||||||
                                            <el-descriptions-item label="机器名"> {{ dt.params?.name }} </el-descriptions-item>
 | 
					                                            <el-descriptions-item label="机器名"> {{ dt.params?.name }} </el-descriptions-item>
 | 
				
			||||||
                                            <el-descriptions-item label="host"> {{ dt.params?.ip }} : {{ dt.params?.port }} </el-descriptions-item>
 | 
					                                            <el-descriptions-item label="host"> {{ dt.params?.ip }} : {{ dt.params?.port }} </el-descriptions-item>
 | 
				
			||||||
                                            <el-descriptions-item label="username"> {{ dt.params?.username }} </el-descriptions-item>
 | 
					                                            <el-descriptions-item label="username"> {{ dt.params?.selectAuthCert.username }} </el-descriptions-item>
 | 
				
			||||||
                                            <el-descriptions-item label="remark"> {{ dt.params?.remark }} </el-descriptions-item>
 | 
					                                            <el-descriptions-item label="remark"> {{ dt.params?.remark }} </el-descriptions-item>
 | 
				
			||||||
                                        </el-descriptions>
 | 
					                                        </el-descriptions>
 | 
				
			||||||
                                    </template>
 | 
					                                    </template>
 | 
				
			||||||
@@ -165,13 +160,14 @@ import TagTree from '../component/TagTree.vue';
 | 
				
			|||||||
import { Pane, Splitpanes } from 'splitpanes';
 | 
					import { Pane, Splitpanes } from 'splitpanes';
 | 
				
			||||||
import { ContextmenuItem } from '@/components/contextmenu/index';
 | 
					import { ContextmenuItem } from '@/components/contextmenu/index';
 | 
				
			||||||
import TerminalBody from '@/components/terminal/TerminalBody.vue';
 | 
					import TerminalBody from '@/components/terminal/TerminalBody.vue';
 | 
				
			||||||
import { TerminalStatus } from '@/components/terminal/common';
 | 
					import { TerminalStatus, TerminalStatusEnum } from '@/components/terminal/common';
 | 
				
			||||||
import MachineRdp from '@/components/terminal-rdp/MachineRdp.vue';
 | 
					import MachineRdp from '@/components/terminal-rdp/MachineRdp.vue';
 | 
				
			||||||
import MachineFile from '@/views/ops/machine/file/MachineFile.vue';
 | 
					import MachineFile from '@/views/ops/machine/file/MachineFile.vue';
 | 
				
			||||||
import ResourceTags from '../component/ResourceTags.vue';
 | 
					import ResourceTags from '../component/ResourceTags.vue';
 | 
				
			||||||
import { MachineProtocolEnum } from './enums';
 | 
					import { MachineProtocolEnum } from './enums';
 | 
				
			||||||
import { useAutoOpenResource } from '@/store/autoOpenResource';
 | 
					import { useAutoOpenResource } from '@/store/autoOpenResource';
 | 
				
			||||||
import { storeToRefs } from 'pinia';
 | 
					import { storeToRefs } from 'pinia';
 | 
				
			||||||
 | 
					import EnumValue from '@/common/Enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 组件
 | 
					// 组件
 | 
				
			||||||
const ScriptManage = defineAsyncComponent(() => import('./ScriptManage.vue'));
 | 
					const ScriptManage = defineAsyncComponent(() => import('./ScriptManage.vue'));
 | 
				
			||||||
@@ -340,8 +336,13 @@ watch(
 | 
				
			|||||||
watch(
 | 
					watch(
 | 
				
			||||||
    () => state.activeTermName,
 | 
					    () => state.activeTermName,
 | 
				
			||||||
    (newValue, oldValue) => {
 | 
					    (newValue, oldValue) => {
 | 
				
			||||||
 | 
					        fitTerminal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        oldValue && terminalRefs[oldValue]?.blur && terminalRefs[oldValue]?.blur();
 | 
					        oldValue && terminalRefs[oldValue]?.blur && terminalRefs[oldValue]?.blur();
 | 
				
			||||||
        terminalRefs[newValue]?.focus && terminalRefs[newValue]?.focus();
 | 
					        terminalRefs[newValue]?.focus && terminalRefs[newValue]?.focus();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const nowTab = state.tabs.get(state.activeTermName);
 | 
				
			||||||
 | 
					        tagTreeRef.value.setCurrentKey(nowTab?.authCert);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -509,7 +510,7 @@ const onRemoveTab = (targetName: string) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        state.tabs.delete(targetName);
 | 
					        state.tabs.delete(targetName);
 | 
				
			||||||
        state.activeTermName = activeTermName;
 | 
					        state.activeTermName = activeTermName;
 | 
				
			||||||
        onTabChange();
 | 
					        // onTabChange();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -535,21 +536,13 @@ const onResizeTagTree = () => {
 | 
				
			|||||||
    fitTerminal();
 | 
					    fitTerminal();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const onTabChange = () => {
 | 
					 | 
				
			||||||
    fitTerminal();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const nowTab = state.tabs.get(state.activeTermName);
 | 
					 | 
				
			||||||
    tagTreeRef.value.setCurrentKey(nowTab?.authCert);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const fitTerminal = () => {
 | 
					const fitTerminal = () => {
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
        let info = state.tabs.get(state.activeTermName);
 | 
					        let info = state.tabs.get(state.activeTermName);
 | 
				
			||||||
        if (info) {
 | 
					        if (info) {
 | 
				
			||||||
            terminalRefs[info.key]?.fitTerminal && terminalRefs[info.key]?.fitTerminal();
 | 
					            terminalRefs[info.key]?.fitTerminal && terminalRefs[info.key]?.fitTerminal();
 | 
				
			||||||
            terminalRefs[info.key]?.focus && terminalRefs[info.key]?.focus();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }, 100);
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const handleReconnect = (tab: any, force = false) => {
 | 
					const handleReconnect = (tab: any, force = false) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@ export const machineApi = {
 | 
				
			|||||||
    process: Api.newGet('/machines/{id}/process'),
 | 
					    process: Api.newGet('/machines/{id}/process'),
 | 
				
			||||||
    // 终止进程
 | 
					    // 终止进程
 | 
				
			||||||
    killProcess: Api.newDelete('/machines/{id}/process'),
 | 
					    killProcess: Api.newDelete('/machines/{id}/process'),
 | 
				
			||||||
 | 
					    users: Api.newGet('/machines/{id}/users'),
 | 
				
			||||||
 | 
					    groups: Api.newGet('/machines/{id}/groups'),
 | 
				
			||||||
    testConn: Api.newPost('/machines/test-conn'),
 | 
					    testConn: Api.newPost('/machines/test-conn'),
 | 
				
			||||||
    // 保存按钮
 | 
					    // 保存按钮
 | 
				
			||||||
    saveMachine: Api.newPost('/machines'),
 | 
					    saveMachine: Api.newPost('/machines'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
        <el-dialog
 | 
					        <el-dialog
 | 
				
			||||||
            :title="title"
 | 
					            :title="title"
 | 
				
			||||||
            v-model="dialogVisible"
 | 
					            v-model="dialogVisible"
 | 
				
			||||||
 | 
					            @open="search()"
 | 
				
			||||||
            :close-on-click-modal="false"
 | 
					            :close-on-click-modal="false"
 | 
				
			||||||
            :before-close="cancel"
 | 
					            :before-close="cancel"
 | 
				
			||||||
            :show-close="true"
 | 
					            :show-close="true"
 | 
				
			||||||
@@ -27,7 +28,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { watch, ref, toRefs, reactive, Ref } from 'vue';
 | 
					import { ref, toRefs, reactive, Ref } from 'vue';
 | 
				
			||||||
import { cronJobApi } from '../api';
 | 
					import { cronJobApi } from '../api';
 | 
				
			||||||
import PageTable from '@/components/pagetable/PageTable.vue';
 | 
					import PageTable from '@/components/pagetable/PageTable.vue';
 | 
				
			||||||
import { TableColumn } from '@/components/pagetable';
 | 
					import { TableColumn } from '@/components/pagetable';
 | 
				
			||||||
@@ -47,8 +48,6 @@ const props = defineProps({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emit = defineEmits(['update:visible', 'update:data', 'cancel']);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const searchItems = [SearchItem.input('machineCode', '机器编号'), SearchItem.select('status', '状态').withEnum(CronJobExecStatusEnum)];
 | 
					const searchItems = [SearchItem.input('machineCode', '机器编号'), SearchItem.select('status', '状态').withEnum(CronJobExecStatusEnum)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const columns = ref([
 | 
					const columns = ref([
 | 
				
			||||||
@@ -65,7 +64,7 @@ const state = reactive({
 | 
				
			|||||||
    tags: [] as any,
 | 
					    tags: [] as any,
 | 
				
			||||||
    params: {
 | 
					    params: {
 | 
				
			||||||
        pageNum: 1,
 | 
					        pageNum: 1,
 | 
				
			||||||
        pageSize: 10,
 | 
					        pageSize: 8,
 | 
				
			||||||
        cronJobId: 0,
 | 
					        cronJobId: 0,
 | 
				
			||||||
        status: null,
 | 
					        status: null,
 | 
				
			||||||
        machineCode: '',
 | 
					        machineCode: '',
 | 
				
			||||||
@@ -78,24 +77,17 @@ const state = reactive({
 | 
				
			|||||||
    machines: [],
 | 
					    machines: [],
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { dialogVisible, params } = toRefs(state);
 | 
					const { params } = toRefs(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(props, async (newValue: any) => {
 | 
					const dialogVisible = defineModel<boolean>('visible');
 | 
				
			||||||
    state.dialogVisible = newValue.visible;
 | 
					 | 
				
			||||||
    if (!newValue.visible) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    state.params.cronJobId = props.data?.id;
 | 
					 | 
				
			||||||
    setTimeout(() => search(), 300);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const search = async () => {
 | 
					const search = async () => {
 | 
				
			||||||
 | 
					    state.params.cronJobId = props.data?.id;
 | 
				
			||||||
    pageTableRef.value.search();
 | 
					    pageTableRef.value.search();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cancel = () => {
 | 
					const cancel = () => {
 | 
				
			||||||
    emit('update:visible', false);
 | 
					    dialogVisible.value = false;
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
        initData();
 | 
					        initData();
 | 
				
			||||||
    }, 500);
 | 
					    }, 500);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,12 +18,12 @@
 | 
				
			|||||||
                        </el-select>
 | 
					                        </el-select>
 | 
				
			||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
                <el-table-column prop="path" label="路径" min-width="150px" show-overflow-tooltip>
 | 
					                <el-table-column prop="path" label="路径" min-width="180" show-overflow-tooltip>
 | 
				
			||||||
                    <template #default="scope">
 | 
					                    <template #default="scope">
 | 
				
			||||||
                        <el-input v-model="scope.row.path" :disabled="scope.row.id != null" clearable> </el-input>
 | 
					                        <el-input v-model="scope.row.path" :disabled="scope.row.id != null" clearable> </el-input>
 | 
				
			||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
                <el-table-column label="操作" min-wdith="120px">
 | 
					                <el-table-column label="操作" min-width="130">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                    <template #default="scope">
 | 
				
			||||||
                        <el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="success-filled" plain></el-button>
 | 
					                        <el-button v-if="scope.row.id == null" @click="addFiles(scope.row)" type="success" icon="success-filled" plain></el-button>
 | 
				
			||||||
                        <el-button v-if="scope.row.id != null" @click="getConf(scope.row)" type="primary" icon="tickets" plain></el-button>
 | 
					                        <el-button v-if="scope.row.id != null" @click="getConf(scope.row)" type="primary" icon="tickets" plain></el-button>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@
 | 
				
			|||||||
            >
 | 
					            >
 | 
				
			||||||
                <el-table-column type="selection" width="30" />
 | 
					                <el-table-column type="selection" width="30" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-table-column prop="name" label="名称">
 | 
					                <el-table-column prop="name" label="名称" min-width="380">
 | 
				
			||||||
                    <template #header>
 | 
					                    <template #header>
 | 
				
			||||||
                        <div class="machine-file-table-header">
 | 
					                        <div class="machine-file-table-header">
 | 
				
			||||||
                            <div>
 | 
					                            <div>
 | 
				
			||||||
@@ -171,7 +171,7 @@
 | 
				
			|||||||
                    </template>
 | 
					                    </template>
 | 
				
			||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-table-column prop="size" label="大小" width="100" sortable>
 | 
					                <el-table-column prop="size" label="大小" min-width="90" sortable>
 | 
				
			||||||
                    <template #default="scope">
 | 
					                    <template #default="scope">
 | 
				
			||||||
                        <span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == '-'"> {{ formatByteSize(scope.row.size) }} </span>
 | 
					                        <span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == '-'"> {{ formatByteSize(scope.row.size) }} </span>
 | 
				
			||||||
                        <span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == 'd' && scope.row.dirSize"> {{ scope.row.dirSize }} </span>
 | 
					                        <span style="color: #67c23a; font-weight: bold" v-if="scope.row.type == 'd' && scope.row.dirSize"> {{ scope.row.dirSize }} </span>
 | 
				
			||||||
@@ -182,7 +182,11 @@
 | 
				
			|||||||
                </el-table-column>
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-table-column prop="mode" label="属性" width="110"> </el-table-column>
 | 
					                <el-table-column prop="mode" label="属性" width="110"> </el-table-column>
 | 
				
			||||||
                <el-table-column prop="modTime" label="修改时间" width="165" sortable> </el-table-column>
 | 
					                <el-table-column v-if="$props.protocol == MachineProtocolEnum.Ssh.value" prop="username" label="用户" min-width="55" show-overflow-tooltip>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column v-if="$props.protocol == MachineProtocolEnum.Ssh.value" prop="groupname" label="组" min-width="55" show-overflow-tooltip>
 | 
				
			||||||
 | 
					                </el-table-column>
 | 
				
			||||||
 | 
					                <el-table-column prop="modTime" label="修改时间" width="160" sortable> </el-table-column>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-table-column width="100">
 | 
					                <el-table-column width="100">
 | 
				
			||||||
                    <template #header>
 | 
					                    <template #header>
 | 
				
			||||||
@@ -288,6 +292,7 @@ import MachineFileContent from './MachineFileContent.vue';
 | 
				
			|||||||
import { getToken } from '@/common/utils/storage';
 | 
					import { getToken } from '@/common/utils/storage';
 | 
				
			||||||
import { convertToBytes, formatByteSize } from '@/common/utils/format';
 | 
					import { convertToBytes, formatByteSize } from '@/common/utils/format';
 | 
				
			||||||
import { getMachineConfig } from '@/common/sysconfig';
 | 
					import { getMachineConfig } from '@/common/sysconfig';
 | 
				
			||||||
 | 
					import { MachineProtocolEnum } from '../enums';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
    machineId: { type: Number },
 | 
					    machineId: { type: Number },
 | 
				
			||||||
@@ -303,6 +308,9 @@ const folderUploadRef: any = ref();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const folderType = 'd';
 | 
					const folderType = 'd';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const userMap = new Map<number, any>();
 | 
				
			||||||
 | 
					const groupMap = new Map<number, any>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 路径分隔符
 | 
					// 路径分隔符
 | 
				
			||||||
const pathSep = '/';
 | 
					const pathSep = '/';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -343,10 +351,50 @@ const { basePath, nowPath, loading, fileNameFilter, progressNum, uploadProgressS
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
onMounted(async () => {
 | 
					onMounted(async () => {
 | 
				
			||||||
    state.basePath = props.path;
 | 
					    state.basePath = props.path;
 | 
				
			||||||
 | 
					    const machineId = props.machineId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (props.protocol == MachineProtocolEnum.Ssh.value) {
 | 
				
			||||||
 | 
					        machineApi.users.request({ id: machineId }).then((res: any) => {
 | 
				
			||||||
 | 
					            for (let user of res) {
 | 
				
			||||||
 | 
					                userMap.set(user.uid, user);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        machineApi.groups.request({ id: machineId }).then((res: any) => {
 | 
				
			||||||
 | 
					            for (let group of res) {
 | 
				
			||||||
 | 
					                groupMap.set(group.gid, group);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setFiles(props.path);
 | 
					    setFiles(props.path);
 | 
				
			||||||
    state.machineConfig = await getMachineConfig();
 | 
					    state.machineConfig = await getMachineConfig();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// watch(
 | 
				
			||||||
 | 
					//     () => props.machineId,
 | 
				
			||||||
 | 
					//     () => {
 | 
				
			||||||
 | 
					//         if (props.protocol != MachineProtocolEnum.Ssh.value) {
 | 
				
			||||||
 | 
					//             userMap.clear();
 | 
				
			||||||
 | 
					//             groupMap.clear();
 | 
				
			||||||
 | 
					//             return;
 | 
				
			||||||
 | 
					//         }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//         const machineId = props.machineId;
 | 
				
			||||||
 | 
					//         machineApi.users.request({ machineId }).then((res: any) => {
 | 
				
			||||||
 | 
					//             for (let user of res) {
 | 
				
			||||||
 | 
					//                 userMap.set(user.uid, user);
 | 
				
			||||||
 | 
					//             }
 | 
				
			||||||
 | 
					//         });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//         machineApi.groups.request({ machineId }).then((res: any) => {
 | 
				
			||||||
 | 
					//             for (let group of res) {
 | 
				
			||||||
 | 
					//                 groupMap.set(group.gid, group);
 | 
				
			||||||
 | 
					//             }
 | 
				
			||||||
 | 
					//         });
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					// );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const filterFiles = computed(() =>
 | 
					const filterFiles = computed(() =>
 | 
				
			||||||
    state.files.filter((data: any) => !state.fileNameFilter || data.name.toLowerCase().includes(state.fileNameFilter.toLowerCase()))
 | 
					    state.files.filter((data: any) => !state.fileNameFilter || data.name.toLowerCase().includes(state.fileNameFilter.toLowerCase()))
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
@@ -517,6 +565,11 @@ const lsFile = async (path: string) => {
 | 
				
			|||||||
        path,
 | 
					        path,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    for (const file of res) {
 | 
					    for (const file of res) {
 | 
				
			||||||
 | 
					        if (props.protocol == MachineProtocolEnum.Ssh.value) {
 | 
				
			||||||
 | 
					            file.username = userMap.get(file.uid)?.uname || file.uid;
 | 
				
			||||||
 | 
					            file.groupname = groupMap.get(file.gid)?.gname || file.gid;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const type = file.type;
 | 
					        const type = file.type;
 | 
				
			||||||
        if (type == folderType) {
 | 
					        if (type == folderType) {
 | 
				
			||||||
            file.isFolder = true;
 | 
					            file.isFolder = true;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@
 | 
				
			|||||||
            </el-table-column>
 | 
					            </el-table-column>
 | 
				
			||||||
            <el-table-column prop="codePaths" label="关联机器" min-width="250px" show-overflow-tooltip>
 | 
					            <el-table-column prop="codePaths" label="关联机器" min-width="250px" show-overflow-tooltip>
 | 
				
			||||||
                <template #default="scope">
 | 
					                <template #default="scope">
 | 
				
			||||||
                    <TagCodePath :path="scope.row.tags.map((tag: any) => tag.codePath)" />
 | 
					                    <TagCodePath :path="scope.row.tags?.map((tag: any) => tag.codePath)" />
 | 
				
			||||||
                </template>
 | 
					                </template>
 | 
				
			||||||
            </el-table-column>
 | 
					            </el-table-column>
 | 
				
			||||||
            <el-table-column prop="remark" label="备注" show-overflow-tooltip width="120px"> </el-table-column>
 | 
					            <el-table-column prop="remark" label="备注" show-overflow-tooltip width="120px"> </el-table-column>
 | 
				
			||||||
@@ -173,7 +173,7 @@ const openFormDialog = (data: any) => {
 | 
				
			|||||||
        state.form = { ...DefaultForm };
 | 
					        state.form = { ...DefaultForm };
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        state.form = _.cloneDeep(data);
 | 
					        state.form = _.cloneDeep(data);
 | 
				
			||||||
        state.form.codePaths = data.tags.map((tag: any) => tag.codePath);
 | 
					        state.form.codePaths = data.tags?.map((tag: any) => tag.codePath);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    state.dialogVisible = true;
 | 
					    state.dialogVisible = true;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,31 +100,34 @@ const { dvisible, params, form } = toRefs(state);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const { isFetching: saveBtnLoading, execute: saveConfigExec } = configApi.save.useApi(form);
 | 
					const { isFetching: saveBtnLoading, execute: saveConfigExec } = configApi.save.useApi(form);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watchEffect(() => {
 | 
					watch(
 | 
				
			||||||
    state.dvisible = props.visible;
 | 
					    () => props.visible,
 | 
				
			||||||
    if (!state.dvisible) {
 | 
					    () => {
 | 
				
			||||||
        return;
 | 
					        state.dvisible = props.visible;
 | 
				
			||||||
    }
 | 
					        if (!state.dvisible) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (props.data) {
 | 
					        if (props.data) {
 | 
				
			||||||
        state.form = { ...(props.data as any) };
 | 
					            state.form = { ...(props.data as any) };
 | 
				
			||||||
        if (state.form.params) {
 | 
					            if (state.form.params) {
 | 
				
			||||||
            state.params = JSON.parse(state.form.params);
 | 
					                state.params = JSON.parse(state.form.params);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                state.params = [];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            state.form = { permission: 'all' } as any;
 | 
				
			||||||
            state.params = [];
 | 
					            state.params = [];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        state.form = { permission: 'all' } as any;
 | 
					 | 
				
			||||||
        state.params = [];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state.form.permission != 'all') {
 | 
					        if (state.form.permission != 'all') {
 | 
				
			||||||
        const accounts = state.form.permission.split(',');
 | 
					            const accounts = state.form.permission.split(',');
 | 
				
			||||||
        state.permissionAccount = accounts.slice(0, accounts.length - 1);
 | 
					            state.permissionAccount = accounts.slice(0, accounts.length - 1);
 | 
				
			||||||
    } else {
 | 
					        } else {
 | 
				
			||||||
        state.permissionAccount = [];
 | 
					            state.permissionAccount = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cancel = () => {
 | 
					const cancel = () => {
 | 
				
			||||||
    // 更新父组件visible prop对应的值为false
 | 
					    // 更新父组件visible prop对应的值为false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,10 +57,20 @@ func (d *Db) Dbs(rc *req.Ctx) {
 | 
				
			|||||||
	res, err := d.DbApp.GetPageList(queryCond, page, &dbvos)
 | 
						res, err := d.DbApp.GetPageList(queryCond, page, &dbvos)
 | 
				
			||||||
	biz.ErrIsNil(err)
 | 
						biz.ErrIsNil(err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 填充标签信息
 | 
						instances, _ := d.InstanceApp.GetByIds(collx.ArrayMap(dbvos, func(i *vo.DbListVO) uint64 {
 | 
				
			||||||
	d.TagApp.FillTagInfo(tagentity.TagTypeDbName, collx.ArrayMap(dbvos, func(dbvo *vo.DbListVO) tagentity.ITagResource {
 | 
							return i.InstanceId
 | 
				
			||||||
		return dbvo
 | 
						}))
 | 
				
			||||||
	})...)
 | 
						instancesMap := collx.ArrayToMap(instances, func(i *entity.DbInstance) uint64 {
 | 
				
			||||||
 | 
							return i.Id
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						for _, dbvo := range dbvos {
 | 
				
			||||||
 | 
							di := instancesMap[dbvo.InstanceId]
 | 
				
			||||||
 | 
							if di != nil {
 | 
				
			||||||
 | 
								dbvo.InstanceType = di.Type
 | 
				
			||||||
 | 
								dbvo.Host = di.Host
 | 
				
			||||||
 | 
								dbvo.Port = di.Port
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc.ResData = res
 | 
						rc.ResData = res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,26 +2,22 @@ package vo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/internal/db/domain/entity"
 | 
						"mayfly-go/internal/db/domain/entity"
 | 
				
			||||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
					 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DbListVO struct {
 | 
					type DbListVO struct {
 | 
				
			||||||
	tagentity.ResourceTags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Id              *int64                   `json:"id"`
 | 
						Id              *int64                   `json:"id"`
 | 
				
			||||||
	Code            string                   `json:"code"`
 | 
						Code            string                   `json:"code"`
 | 
				
			||||||
	Name            *string                  `json:"name"`
 | 
						Name            *string                  `json:"name"`
 | 
				
			||||||
	GetDatabaseMode entity.DbGetDatabaseMode `json:"getDatabaseMode"` // 获取数据库方式
 | 
						GetDatabaseMode entity.DbGetDatabaseMode `json:"getDatabaseMode"` // 获取数据库方式
 | 
				
			||||||
	Database        *string                  `json:"database"`
 | 
						Database        *string                  `json:"database"`
 | 
				
			||||||
	Remark          *string                  `json:"remark"`
 | 
						Remark          *string                  `json:"remark"`
 | 
				
			||||||
 | 
						InstanceId      uint64                   `json:"instanceId"`
 | 
				
			||||||
 | 
						AuthCertName    string                   `json:"authCertName"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	InstanceId   *int64  `json:"instanceId"`
 | 
						InstanceType string `json:"type" gorm:"-"`
 | 
				
			||||||
	AuthCertName string  `json:"authCertName"`
 | 
						Host         string `json:"host" gorm:"-"`
 | 
				
			||||||
	InstanceName *string `json:"instanceName"`
 | 
						Port         int    `json:"port" gorm:"-"`
 | 
				
			||||||
	InstanceType *string `json:"type"`
 | 
					 | 
				
			||||||
	Host         string  `json:"host"`
 | 
					 | 
				
			||||||
	Port         int     `json:"port"`
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CreateTime *time.Time `json:"createTime"`
 | 
						CreateTime *time.Time `json:"createTime"`
 | 
				
			||||||
	Creator    *string    `json:"creator"`
 | 
						Creator    *string    `json:"creator"`
 | 
				
			||||||
@@ -30,7 +26,3 @@ type DbListVO struct {
 | 
				
			|||||||
	Modifier   *string    `json:"modifier"`
 | 
						Modifier   *string    `json:"modifier"`
 | 
				
			||||||
	ModifierId *int64     `json:"modifierId"`
 | 
						ModifierId *int64     `json:"modifierId"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (d DbListVO) GetCode() string {
 | 
					 | 
				
			||||||
	return d.Code
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,16 +87,20 @@ func (app *dbTransferAppImpl) CreateLog(ctx context.Context, taskId uint64) (uin
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (app *dbTransferAppImpl) Run(ctx context.Context, taskId uint64, logId uint64) {
 | 
					func (app *dbTransferAppImpl) Run(ctx context.Context, taskId uint64, logId uint64) {
 | 
				
			||||||
 | 
						defer app.logApp.Flush(logId, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	task, err := app.GetById(taskId)
 | 
						task, err := app.GetById(taskId)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logx.Errorf("创建DBMS-执行数据迁移日志失败:%v", err)
 | 
							logx.Errorf("创建DBMS-执行数据迁移日志失败:%v", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if app.IsRunning(taskId) {
 | 
				
			||||||
 | 
							logx.Warnf("[%d]该任务正在运行中...", taskId)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	start := time.Now()
 | 
						start := time.Now()
 | 
				
			||||||
 | 
					 | 
				
			||||||
	defer app.logApp.Flush(logId, true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 修改状态与关联日志id
 | 
						// 修改状态与关联日志id
 | 
				
			||||||
	task.LogId = logId
 | 
						task.LogId = logId
 | 
				
			||||||
	task.RunningState = entity.DbTransferTaskRunStateRunning
 | 
						task.RunningState = entity.DbTransferTaskRunStateRunning
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,16 +27,10 @@ type DbTransferLogQuery struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 数据库查询实体,不与数据库表字段一一对应
 | 
					// 数据库查询实体,不与数据库表字段一一对应
 | 
				
			||||||
type DbQuery struct {
 | 
					type DbQuery struct {
 | 
				
			||||||
	Id       uint64 `form:"id"`
 | 
						Id         uint64 `form:"id"`
 | 
				
			||||||
	Code     string `json:"code" form:"code"`
 | 
						TagPath    string `form:"tagPath"`
 | 
				
			||||||
	Name     string `orm:"column(name)" json:"name"`
 | 
						Code       string `json:"code" form:"code"`
 | 
				
			||||||
	Database string `orm:"column(database)" json:"database"`
 | 
						Codes      []string
 | 
				
			||||||
	Remark   string `json:"remark"`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Codes   []string
 | 
					 | 
				
			||||||
	TagIds  []uint64 `orm:"column(tag_id)"`
 | 
					 | 
				
			||||||
	TagPath string   `form:"tagPath"`
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	InstanceId uint64 `form:"instanceId"`
 | 
						InstanceId uint64 `form:"instanceId"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,6 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/db/domain/entity"
 | 
						"mayfly-go/internal/db/domain/entity"
 | 
				
			||||||
	"mayfly-go/internal/db/domain/repository"
 | 
						"mayfly-go/internal/db/domain/repository"
 | 
				
			||||||
	"mayfly-go/pkg/base"
 | 
						"mayfly-go/pkg/base"
 | 
				
			||||||
	"mayfly-go/pkg/gormx"
 | 
					 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,16 +17,6 @@ func newDbRepo() repository.Db {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// 分页获取数据库信息列表
 | 
					// 分页获取数据库信息列表
 | 
				
			||||||
func (d *dbRepoImpl) GetDbList(condition *entity.DbQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
 | 
					func (d *dbRepoImpl) GetDbList(condition *entity.DbQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
 | 
				
			||||||
	qd := gormx.NewQueryWithTableName("t_db db").Joins("JOIN t_db_instance inst ON db.instance_id = inst.id").
 | 
						pd := model.NewCond().Eq("instance_id", condition.InstanceId).In("code", condition.Codes)
 | 
				
			||||||
		WithCond(model.NewCond().Columns("db.*, inst.name instance_name, inst.type instance_type, inst.host, inst.port ").
 | 
						return d.PageByCondToAny(pd, pageParam, toEntity)
 | 
				
			||||||
			Eq("db.instance_id", condition.InstanceId).
 | 
					 | 
				
			||||||
			Eq("db.id", condition.Id).
 | 
					 | 
				
			||||||
			Like("db.database", condition.Database).
 | 
					 | 
				
			||||||
			Eq("db.code", condition.Code).
 | 
					 | 
				
			||||||
			In("db.code", condition.Codes).
 | 
					 | 
				
			||||||
			Eq0("db."+model.DeletedColumn, model.ModelUndeleted).
 | 
					 | 
				
			||||||
			Eq0("inst."+model.DeletedColumn, model.ModelUndeleted),
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return gormx.PageQuery(qd, pageParam, toEntity)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,6 +173,22 @@ func (m *Machine) KillProcess(rc *req.Ctx) {
 | 
				
			|||||||
	biz.ErrIsNil(err, "终止进程失败: %s", res)
 | 
						biz.ErrIsNil(err, "终止进程失败: %s", res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) GetUsers(rc *req.Ctx) {
 | 
				
			||||||
 | 
						cli, err := m.MachineApp.GetCli(GetMachineId(rc))
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
 | 
				
			||||||
 | 
						res, err := cli.GetUsers()
 | 
				
			||||||
 | 
						biz.ErrIsNil(err)
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *Machine) GetGroups(rc *req.Ctx) {
 | 
				
			||||||
 | 
						cli, err := m.MachineApp.GetCli(GetMachineId(rc))
 | 
				
			||||||
 | 
						biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
 | 
				
			||||||
 | 
						res, err := cli.GetGroups()
 | 
				
			||||||
 | 
						biz.ErrIsNil(err)
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *Machine) WsSSH(g *gin.Context) {
 | 
					func (m *Machine) WsSSH(g *gin.Context) {
 | 
				
			||||||
	wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
 | 
						wsConn, err := ws.Upgrader.Upgrade(g.Writer, g.Request, nil)
 | 
				
			||||||
	defer func() {
 | 
						defer func() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,9 +28,11 @@ import (
 | 
				
			|||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/may-fly/cast"
 | 
						"github.com/may-fly/cast"
 | 
				
			||||||
 | 
						"github.com/pkg/sftp"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineFile struct {
 | 
					type MachineFile struct {
 | 
				
			||||||
 | 
						MachineApp     application.Machine     `inject:""`
 | 
				
			||||||
	MachineFileApp application.MachineFile `inject:""`
 | 
						MachineFileApp application.MachineFile `inject:""`
 | 
				
			||||||
	MsgApp         msgapp.Msg              `inject:""`
 | 
						MsgApp         msgapp.Msg              `inject:""`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -159,15 +161,21 @@ func (m *MachineFile) GetDirEntry(rc *req.Ctx) {
 | 
				
			|||||||
			path = readPath + name
 | 
								path = readPath + name
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fisVO = append(fisVO, vo.MachineFileInfo{
 | 
							mfi := vo.MachineFileInfo{
 | 
				
			||||||
			Name:    fi.Name(),
 | 
								Name:    fi.Name(),
 | 
				
			||||||
			Size:    fi.Size(),
 | 
								Size:    fi.Size(),
 | 
				
			||||||
			Path:    path,
 | 
								Path:    path,
 | 
				
			||||||
			Type:    getFileType(fi.Mode()),
 | 
								Type:    getFileType(fi.Mode()),
 | 
				
			||||||
			Mode:    fi.Mode().String(),
 | 
								Mode:    fi.Mode().String(),
 | 
				
			||||||
			ModTime: timex.DefaultFormat(fi.ModTime()),
 | 
								ModTime: timex.DefaultFormat(fi.ModTime()),
 | 
				
			||||||
		})
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if sftpFs, ok := fi.Sys().(*sftp.FileStat); ok {
 | 
				
			||||||
 | 
								mfi.UID = sftpFs.UID
 | 
				
			||||||
 | 
								mfi.GID = sftpFs.GID
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fisVO = append(fisVO, mfi)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sort.Sort(vo.MachineFileInfos(fisVO))
 | 
						sort.Sort(vo.MachineFileInfos(fisVO))
 | 
				
			||||||
	rc.ResData = fisVO
 | 
						rc.ResData = fisVO
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,6 +78,9 @@ type MachineFileInfo struct {
 | 
				
			|||||||
	Type    string `json:"type"`
 | 
						Type    string `json:"type"`
 | 
				
			||||||
	Mode    string `json:"mode"`
 | 
						Mode    string `json:"mode"`
 | 
				
			||||||
	ModTime string `json:"modTime"`
 | 
						ModTime string `json:"modTime"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UID uint32 `json:"uid"`
 | 
				
			||||||
 | 
						GID uint32 `json:"gid"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineFileInfos []MachineFileInfo
 | 
					type MachineFileInfos []MachineFileInfo
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,8 +222,7 @@ func (m *machineFileAppImpl) MkDir(ctx context.Context, opParam *dto.MachineFile
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sftpCli.MkdirAll(path)
 | 
						return mi, sftpCli.MkdirAll(path)
 | 
				
			||||||
	return mi, err
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *machineFileAppImpl) CreateFile(ctx context.Context, opParam *dto.MachineFileOp) (*mcm.MachineInfo, error) {
 | 
					func (m *machineFileAppImpl) CreateFile(ctx context.Context, opParam *dto.MachineFileOp) (*mcm.MachineInfo, error) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pagePar
 | 
				
			|||||||
		Like("ip", condition.Ip).
 | 
							Like("ip", condition.Ip).
 | 
				
			||||||
		Like("name", condition.Name).
 | 
							Like("name", condition.Name).
 | 
				
			||||||
		In("code", condition.Codes).
 | 
							In("code", condition.Codes).
 | 
				
			||||||
		Like("code", condition.Code).
 | 
							Eq("code", condition.Code).
 | 
				
			||||||
		Eq("protocol", condition.Protocol)
 | 
							Eq("protocol", condition.Protocol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return m.PageByCondToAny(qd, pageParam, toEntity)
 | 
						return m.PageByCondToAny(qd, pageParam, toEntity)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/logx"
 | 
						"mayfly-go/pkg/logx"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/may-fly/cast"
 | 
				
			||||||
	"github.com/pkg/sftp"
 | 
						"github.com/pkg/sftp"
 | 
				
			||||||
	"golang.org/x/crypto/ssh"
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -66,30 +67,6 @@ func (c *Cli) Run(shell string) (string, error) {
 | 
				
			|||||||
	return string(buf), nil
 | 
						return string(buf), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetAllStats 获取机器的所有状态信息
 | 
					 | 
				
			||||||
func (c *Cli) GetAllStats() *Stats {
 | 
					 | 
				
			||||||
	stats := new(Stats)
 | 
					 | 
				
			||||||
	res, err := c.Run(StatsShell)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		logx.Errorf("执行机器[id=%d, name=%s]运行状态信息脚本失败: %s", c.Info.Id, c.Info.Name, err.Error())
 | 
					 | 
				
			||||||
		return stats
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	infos := strings.Split(res, "-----")
 | 
					 | 
				
			||||||
	if len(infos) < 8 {
 | 
					 | 
				
			||||||
		return stats
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	getUptime(infos[0], stats)
 | 
					 | 
				
			||||||
	getHostname(infos[1], stats)
 | 
					 | 
				
			||||||
	getLoad(infos[2], stats)
 | 
					 | 
				
			||||||
	getMemInfo(infos[3], stats)
 | 
					 | 
				
			||||||
	getFSInfo(infos[4], stats)
 | 
					 | 
				
			||||||
	getInterfaces(infos[5], stats)
 | 
					 | 
				
			||||||
	getInterfaceInfo(infos[6], stats)
 | 
					 | 
				
			||||||
	getCPU(infos[7], stats)
 | 
					 | 
				
			||||||
	return stats
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Close 关闭client并从缓存中移除,如果使用隧道则也关闭
 | 
					// Close 关闭client并从缓存中移除,如果使用隧道则也关闭
 | 
				
			||||||
func (c *Cli) Close() {
 | 
					func (c *Cli) Close() {
 | 
				
			||||||
	m := c.Info
 | 
						m := c.Info
 | 
				
			||||||
@@ -115,3 +92,77 @@ func (c *Cli) Close() {
 | 
				
			|||||||
		CloseSshTunnelMachine(int(sshTunnelMachineId), m.GetTunnelId())
 | 
							CloseSshTunnelMachine(int(sshTunnelMachineId), m.GetTunnelId())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetAllStats 获取机器的所有状态信息
 | 
				
			||||||
 | 
					func (c *Cli) GetAllStats() *Stats {
 | 
				
			||||||
 | 
						stats := new(Stats)
 | 
				
			||||||
 | 
						res, err := c.Run(StatsShell)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							logx.Errorf("执行机器[id=%d, name=%s]运行状态信息脚本失败: %s", c.Info.Id, c.Info.Name, err.Error())
 | 
				
			||||||
 | 
							return stats
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						infos := strings.Split(res, "-----")
 | 
				
			||||||
 | 
						if len(infos) < 8 {
 | 
				
			||||||
 | 
							return stats
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						getUptime(infos[0], stats)
 | 
				
			||||||
 | 
						getHostname(infos[1], stats)
 | 
				
			||||||
 | 
						getLoad(infos[2], stats)
 | 
				
			||||||
 | 
						getMemInfo(infos[3], stats)
 | 
				
			||||||
 | 
						getFSInfo(infos[4], stats)
 | 
				
			||||||
 | 
						getInterfaces(infos[5], stats)
 | 
				
			||||||
 | 
						getInterfaceInfo(infos[6], stats)
 | 
				
			||||||
 | 
						getCPU(infos[7], stats)
 | 
				
			||||||
 | 
						return stats
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUsers 读取/etc/passwd,获取系统所有用户信息
 | 
				
			||||||
 | 
					func (c *Cli) GetUsers() ([]*UserInfo, error) {
 | 
				
			||||||
 | 
						res, err := c.Run("cat /etc/passwd")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var users []*UserInfo
 | 
				
			||||||
 | 
						userLines := strings.Split(res, "\n")
 | 
				
			||||||
 | 
						for _, userLine := range userLines {
 | 
				
			||||||
 | 
							if userLine == "" {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fields := strings.Split(userLine, ":")
 | 
				
			||||||
 | 
							user := &UserInfo{
 | 
				
			||||||
 | 
								Username: fields[0],
 | 
				
			||||||
 | 
								UID:      cast.ToUint32(fields[2]),
 | 
				
			||||||
 | 
								GID:      cast.ToUint32(fields[3]),
 | 
				
			||||||
 | 
								HomeDir:  fields[5],
 | 
				
			||||||
 | 
								Shell:    fields[6],
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							users = append(users, user)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return users, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetGroups 读取/etc/group,获取系统所有组信息
 | 
				
			||||||
 | 
					func (c *Cli) GetGroups() ([]*GroupInfo, error) {
 | 
				
			||||||
 | 
						res, err := c.Run("cat /etc/group")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var groups []*GroupInfo
 | 
				
			||||||
 | 
						groupLines := strings.Split(res, "\n")
 | 
				
			||||||
 | 
						for _, groupLine := range groupLines {
 | 
				
			||||||
 | 
							if groupLine == "" {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							fields := strings.Split(groupLine, ":")
 | 
				
			||||||
 | 
							group := &GroupInfo{
 | 
				
			||||||
 | 
								Groupname: fields[0],
 | 
				
			||||||
 | 
								GID:       cast.ToUint32(fields[2]),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							groups = append(groups, group)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return groups, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -287,3 +287,16 @@ func getCPU(cpuInfo string, stats *Stats) (err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type UserInfo struct {
 | 
				
			||||||
 | 
						UID      uint32 `json:"uid"`
 | 
				
			||||||
 | 
						Username string `json:"uname"`
 | 
				
			||||||
 | 
						GID      uint32 `json:"gid"`
 | 
				
			||||||
 | 
						HomeDir  string `json:"homeDir"` // 用户登录后的起始工作目录
 | 
				
			||||||
 | 
						Shell    string `json:"shell"`   // 用户登录时使用的 shell 程序
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type GroupInfo struct {
 | 
				
			||||||
 | 
						GID       uint32 `json:"gid"`
 | 
				
			||||||
 | 
						Groupname string `json:"gname"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,10 @@ func InitMachineRouter(router *gin.RouterGroup) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			req.NewGet(":machineId/process", m.GetProcess),
 | 
								req.NewGet(":machineId/process", m.GetProcess),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req.NewGet(":machineId/users", m.GetUsers),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								req.NewGet(":machineId/groups", m.GetGroups),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			req.NewDelete(":machineId/process", m.KillProcess).Log(req.NewLogSave("终止进程")).RequiredPermissionCode("machine:killprocess"),
 | 
								req.NewDelete(":machineId/process", m.KillProcess).Log(req.NewLogSave("终止进程")).RequiredPermissionCode("machine:killprocess"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			req.NewPost("", m.SaveMachine).Log(req.NewLogSave("保存机器信息")).RequiredPermission(saveMachineP),
 | 
								req.NewPost("", m.SaveMachine).Log(req.NewLogSave("保存机器信息")).RequiredPermission(saveMachineP),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import "fmt"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AppName = "mayfly-go"
 | 
						AppName = "mayfly-go"
 | 
				
			||||||
	Version = "v1.8.5"
 | 
						Version = "v1.8.6"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetAppInfo() string {
 | 
					func GetAppInfo() string {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -761,11 +761,10 @@ INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight
 | 
				
			|||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(45, 3, '12sSjal1/lskeiql1/Ljewisd3/', 2, 1, '脚本管理-保存脚本按钮', 'machine:script:save', 120000000, 'null', 1, 'admin', 1, 'admin', '2021-06-08 11:09:01', '2021-06-08 11:09:01', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(45, 3, '12sSjal1/lskeiql1/Ljewisd3/', 2, 1, '脚本管理-保存脚本按钮', 'machine:script:save', 120000000, 'null', 1, 'admin', 1, 'admin', '2021-06-08 11:09:01', '2021-06-08 11:09:01', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(46, 3, '12sSjal1/lskeiql1/Ljeew43/', 2, 1, '脚本管理-删除按钮', 'machine:script:del', 130000000, 'null', 1, 'admin', 1, 'admin', '2021-06-08 11:09:27', '2021-06-08 11:09:27', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(46, 3, '12sSjal1/lskeiql1/Ljeew43/', 2, 1, '脚本管理-删除按钮', 'machine:script:del', 130000000, 'null', 1, 'admin', 1, 'admin', '2021-06-08 11:09:27', '2021-06-08 11:09:27', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(47, 3, '12sSjal1/lskeiql1/ODewix43/', 2, 1, '脚本管理-执行按钮', 'machine:script:run', 140000000, 'null', 1, 'admin', 1, 'admin', '2021-06-08 11:09:50', '2021-06-08 11:09:50', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(47, 3, '12sSjal1/lskeiql1/ODewix43/', 2, 1, '脚本管理-执行按钮', 'machine:script:run', 140000000, 'null', 1, 'admin', 1, 'admin', '2021-06-08 11:09:50', '2021-06-08 11:09:50', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(49, 36, 'dbms23ax/xleaiec2/', 1, 1, '数据库管理', 'dbs', 20000000, '{"component":"ops/db/DbList","icon":"Coin","isKeepAlive":true,"routeName":"DbList"}', 1, 'admin', 1, 'admin', '2021-07-07 15:13:55', '2023-03-15 17:31:28', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(54, 135, 'dbms23ax/X0f4BxT0/leix3Axl/', 2, 1, '数据库保存', 'db:save', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-08 17:30:36', '2021-07-08 17:31:05', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(54, 49, 'dbms23ax/xleaiec2/leix3Axl/', 2, 1, '数据库保存', 'db:save', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-08 17:30:36', '2021-07-08 17:31:05', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(55, 135, 'dbms23ax/X0f4BxT0/ygjL3sxA/', 2, 1, '数据库删除', 'db:del', 20000000, 'null', 1, 'admin', 1, 'admin', '2021-07-08 17:30:48', '2021-07-08 17:30:48', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(55, 49, 'dbms23ax/xleaiec2/ygjL3sxA/', 2, 1, '数据库删除', 'db:del', 20000000, 'null', 1, 'admin', 1, 'admin', '2021-07-08 17:30:48', '2021-07-08 17:30:48', 0, NULL);
 | 
					 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(57, 3, '12sSjal1/lskeiql1/OJewex43/', 2, 1, '基本权限', 'machine', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-09 10:48:02', '2021-07-09 10:48:02', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(57, 3, '12sSjal1/lskeiql1/OJewex43/', 2, 1, '基本权限', 'machine', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-09 10:48:02', '2021-07-09 10:48:02', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(58, 49, 'dbms23ax/xleaiec2/AceXe321/', 2, 1, '基本权限', 'db', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-09 10:48:22', '2021-07-09 10:48:22', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(58, 135, 'dbms23ax/X0f4BxT0/AceXe321/', 2, 1, '数据库基本权限', 'db', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-09 10:48:22', '2021-07-09 10:48:22', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(59, 38, 'dbms23ax/exaeca2x/ealcia23/', 2, 1, '基本权限', 'db:exec', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-09 10:50:13', '2021-07-09 10:50:13', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(59, 38, 'dbms23ax/exaeca2x/ealcia23/', 2, 1, '基本权限', 'db:exec', 10000000, 'null', 1, 'admin', 1, 'admin', '2021-07-09 10:50:13', '2021-07-09 10:50:13', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(60, 0, 'RedisXq4/', 1, 1, 'Redis', '/redis', 50000001, '{"icon":"iconfont icon-redis","isKeepAlive":true,"routeName":"RDS"}', 1, 'admin', 1, 'admin', '2021-07-19 20:15:41', '2023-03-15 16:44:59', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(60, 0, 'RedisXq4/', 1, 1, 'Redis', '/redis', 50000001, '{"icon":"iconfont icon-redis","isKeepAlive":true,"routeName":"RDS"}', 1, 'admin', 1, 'admin', '2021-07-19 20:15:41', '2023-03-15 16:44:59', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(61, 60, 'RedisXq4/Exitx4al/', 1, 1, '数据操作', 'data-operation', 10000000, '{"component":"ops/redis/DataOperation","icon":"iconfont icon-redis","isKeepAlive":true,"routeName":"DataOperation"}', 1, 'admin', 1, 'admin', '2021-07-19 20:17:29', '2023-03-15 16:37:50', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(61, 60, 'RedisXq4/Exitx4al/', 1, 1, '数据操作', 'data-operation', 10000000, '{"component":"ops/redis/DataOperation","icon":"iconfont icon-redis","isKeepAlive":true,"routeName":"DataOperation"}', 1, 'admin', 1, 'admin', '2021-07-19 20:17:29', '2023-03-15 16:37:50', 0, NULL);
 | 
				
			||||||
@@ -814,8 +813,8 @@ INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight
 | 
				
			|||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(152, 150, 'Jra0n7De/zvAMo2vk/', 2, 1, '编辑', 'db:sync:save', 1703641320, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-27 09:42:00', '2023-12-27 09:42:12', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(152, 150, 'Jra0n7De/zvAMo2vk/', 2, 1, '编辑', 'db:sync:save', 1703641320, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-27 09:42:00', '2023-12-27 09:42:12', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(151, 150, 'Jra0n7De/uAnHZxEV/', 2, 1, '基本权限', 'db:sync', 1703641202, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-27 09:40:02', '2023-12-27 09:40:02', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(151, 150, 'Jra0n7De/uAnHZxEV/', 2, 1, '基本权限', 'db:sync', 1703641202, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-27 09:40:02', '2023-12-27 09:40:02', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(150, 36, 'Jra0n7De/', 1, 1, '数据同步', 'sync', 1693040707, '{"component":"ops/db/SyncTaskList","icon":"Coin","isKeepAlive":true,"routeName":"SyncTaskList"}', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-22 09:51:34', '2023-12-27 10:16:57', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(150, 36, 'Jra0n7De/', 1, 1, '数据同步', 'sync', 1693040707, '{"component":"ops/db/SyncTaskList","icon":"Coin","isKeepAlive":true,"routeName":"SyncTaskList"}', 12, 'liuzongyang', 12, 'liuzongyang', '2023-12-22 09:51:34', '2023-12-27 10:16:57', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(160, 49, 'dbms23ax/xleaiec2/3NUXQFIO/', 2, 1, '数据库备份', 'db:backup', 1705973876, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:37:56', '2024-01-23 09:37:56', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(160, 135, 'dbms23ax/X0f4BxT0/3NUXQFIO/', 2, 1, '数据库备份', 'db:backup', 1705973876, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:37:56', '2024-01-23 09:37:56', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(161, 49, 'dbms23ax/xleaiec2/ghErkTdb/', 2, 1, '数据库恢复', 'db:restore', 1705973909, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:38:29', '2024-01-23 09:38:29', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(161, 135, 'dbms23ax/X0f4BxT0/ghErkTdb/', 2, 1, '数据库恢复', 'db:restore', 1705973909, 'null', 1, 'admin', 1, 'admin', '2024-01-23 09:38:29', '2024-01-23 09:38:29', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208354, 1708911264, '6egfEVYr/fw0Hhvye/b4cNf3iq/', 2, 1, '删除流程', 'flow:procdef:del', 1709208354, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:54', '2024-02-29 20:05:54', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208354, 1708911264, '6egfEVYr/fw0Hhvye/b4cNf3iq/', 2, 1, '删除流程', 'flow:procdef:del', 1709208354, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:54', '2024-02-29 20:05:54', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208339, 1708911264, '6egfEVYr/fw0Hhvye/r9ZMTHqC/', 2, 1, '保存流程', 'flow:procdef:save', 1709208339, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:40', '2024-02-29 20:05:40', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709208339, 1708911264, '6egfEVYr/fw0Hhvye/r9ZMTHqC/', 2, 1, '保存流程', 'flow:procdef:save', 1709208339, 'null', 1, 'admin', 1, 'admin', '2024-02-29 20:05:40', '2024-02-29 20:05:40', 0, NULL);
 | 
				
			||||||
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709103180, 1708910975, '6egfEVYr/oNCIbynR/', 1, 1, '我的流程', 'procinsts', 1708911263, '{"component":"flow/ProcinstList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstList"}', 1, 'admin', 1, 'admin', '2024-02-28 14:53:00', '2024-02-29 20:36:07', 0, NULL);
 | 
					INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1709103180, 1708910975, '6egfEVYr/oNCIbynR/', 1, 1, '我的流程', 'procinsts', 1708911263, '{"component":"flow/ProcinstList","icon":"Tickets","isKeepAlive":true,"routeName":"ProcinstList"}', 1, 'admin', 1, 'admin', '2024-02-28 14:53:00', '2024-02-29 20:36:07', 0, NULL);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								server/resources/script/sql/v1.8/v1.8.6.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								server/resources/script/sql/v1.8/v1.8.6.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					UPDATE t_sys_resource SET pid=135, ui_path='dbms23ax/X0f4BxT0/leix3Axl/', `type`=2, status=1, name='数据库保存', code='db:save', weight=1693041085, meta='null', creator_id=1, creator='admin', modifier_id=1, modifier='admin', create_time='2021-07-08 17:30:36', update_time='2024-05-17 21:50:01', is_deleted=0, delete_time=NULL WHERE id=54;
 | 
				
			||||||
 | 
					UPDATE t_sys_resource SET pid=135, ui_path='dbms23ax/X0f4BxT0/ygjL3sxA/', `type`=2, status=1, name='数据库删除', code='db:del', weight=1693041086, meta='null', creator_id=1, creator='admin', modifier_id=1, modifier='admin', create_time='2021-07-08 17:30:48', update_time='2024-05-17 21:50:04', is_deleted=0, delete_time=NULL WHERE id=55;
 | 
				
			||||||
 | 
					UPDATE t_sys_resource SET pid=135, ui_path='dbms23ax/X0f4BxT0/AceXe321/', `type`=2, status=1, name='数据库基本权限', code='db', weight=1693041085, meta='null', creator_id=1, creator='admin', modifier_id=1, modifier='admin', create_time='2021-07-09 10:48:22', update_time='2024-05-17 21:52:52', is_deleted=0, delete_time=NULL WHERE id=58;
 | 
				
			||||||
 | 
					UPDATE t_sys_resource SET pid=135, ui_path='dbms23ax/X0f4BxT0/3NUXQFIO/', `type`=2, status=1, name='数据库备份', code='db:backup', weight=1693041087, meta='null', creator_id=1, creator='admin', modifier_id=1, modifier='admin', create_time='2024-01-23 09:37:56', update_time='2024-05-17 21:50:07', is_deleted=0, delete_time=NULL WHERE id=160;
 | 
				
			||||||
 | 
					UPDATE t_sys_resource SET pid=135, ui_path='dbms23ax/X0f4BxT0/ghErkTdb/', `type`=2, status=1, name='数据库恢复', code='db:restore', weight=1693041088, meta='null', creator_id=1, creator='admin', modifier_id=1, modifier='admin', create_time='2024-01-23 09:38:29', update_time='2024-05-17 21:50:10', is_deleted=0, delete_time=NULL WHERE id=161;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DELETE FROM t_sys_resource WHERE id=49;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user