mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	fix: 问题修复
This commit is contained in:
		@@ -15,7 +15,7 @@ const config = {
 | 
			
		||||
    baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
 | 
			
		||||
 | 
			
		||||
    // 系统版本
 | 
			
		||||
    version: 'v1.8.4',
 | 
			
		||||
    version: 'v1.8.5',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default config;
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,11 @@
 | 
			
		||||
                            />
 | 
			
		||||
 | 
			
		||||
                            <el-option :key="TagResourceTypeEnum.Db.value" :label="TagResourceTypeEnum.Db.label" :value="TagResourceTypeEnum.Db.value" />
 | 
			
		||||
                            <el-option
 | 
			
		||||
                                :key="TagResourceTypeEnum.Redis.value"
 | 
			
		||||
                                :label="TagResourceTypeEnum.Redis.label"
 | 
			
		||||
                                :value="TagResourceTypeEnum.Redis.value"
 | 
			
		||||
                            />
 | 
			
		||||
                        </el-select>
 | 
			
		||||
                    </el-form-item>
 | 
			
		||||
                    <el-form-item prop="resourceCode" label="资源编号" required>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
                <el-form-item prop="authCertName" label="授权凭证" required>
 | 
			
		||||
                    <el-select @change="changeAuthCert" v-model="form.authCertName" placeholder="请选择授权凭证" filterable>
 | 
			
		||||
                    <el-select v-model="form.authCertName" placeholder="请选择授权凭证" filterable>
 | 
			
		||||
                        <el-option v-for="item in state.authCerts" :key="item.id" :label="`${item.name}`" :value="item.name">
 | 
			
		||||
                            {{ item.name }}
 | 
			
		||||
 | 
			
		||||
@@ -39,8 +39,15 @@
 | 
			
		||||
                    </el-select>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
                <el-form-item prop="getDatabaseMode" label="获库方式" required>
 | 
			
		||||
                    <el-select v-model="form.getDatabaseMode" @change="onChangeGetDatabaseMode" placeholder="请选择库名获取方式">
 | 
			
		||||
                        <el-option v-for="item in DbGetDbNamesMode" :key="item.value" :label="item.label" :value="item.value"> </el-option>
 | 
			
		||||
                    </el-select>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
                <el-form-item prop="database" label="数据库名">
 | 
			
		||||
                    <el-select
 | 
			
		||||
                        :disabled="form.getDatabaseMode == DbGetDbNamesMode.Auto.value || !form.authCertName"
 | 
			
		||||
                        v-model="dbNamesSelected"
 | 
			
		||||
                        multiple
 | 
			
		||||
                        clearable
 | 
			
		||||
@@ -49,8 +56,9 @@
 | 
			
		||||
                        filterable
 | 
			
		||||
                        :filter-method="filterDbNames"
 | 
			
		||||
                        allow-create
 | 
			
		||||
                        placeholder="请确保数据库实例信息填写完整后获取库名"
 | 
			
		||||
                        style="width: 100%"
 | 
			
		||||
                        placeholder="获库方式为‘指定库名’时,可选择"
 | 
			
		||||
                        @focus="getAllDatabase(form.authCertName)"
 | 
			
		||||
                        :loading="state.loadingDbNames"
 | 
			
		||||
                    >
 | 
			
		||||
                        <template #header>
 | 
			
		||||
                            <el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="handleCheckAll"> 全选 </el-checkbox>
 | 
			
		||||
@@ -75,7 +83,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { toRefs, reactive, watch, ref, watchEffect } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watch, ref } from 'vue';
 | 
			
		||||
import { dbApi } from './api';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import type { CheckboxValueType } from 'element-plus';
 | 
			
		||||
@@ -86,6 +94,7 @@ import EnumTag from '@/components/enumtag/EnumTag.vue';
 | 
			
		||||
import { AuthCertCiphertextTypeEnum } from '../tag/enums';
 | 
			
		||||
import { resourceAuthCertApi } from '../tag/api';
 | 
			
		||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
			
		||||
import { DbGetDbNamesMode } from './enums';
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    visible: {
 | 
			
		||||
@@ -147,10 +156,10 @@ const rules = {
 | 
			
		||||
            trigger: ['change', 'blur'],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
    database: [
 | 
			
		||||
    getDatabaseMode: [
 | 
			
		||||
        {
 | 
			
		||||
            required: true,
 | 
			
		||||
            message: '请添加数据库',
 | 
			
		||||
            message: '请选择库名获取方式',
 | 
			
		||||
            trigger: ['change', 'blur'],
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
@@ -172,38 +181,45 @@ const state = reactive({
 | 
			
		||||
    authCerts: [] as any,
 | 
			
		||||
    form: {
 | 
			
		||||
        id: null,
 | 
			
		||||
        // tagId: [],
 | 
			
		||||
        name: null,
 | 
			
		||||
        code: '',
 | 
			
		||||
        getDatabaseMode: DbGetDbNamesMode.Auto.value,
 | 
			
		||||
        database: '',
 | 
			
		||||
        remark: '',
 | 
			
		||||
        instanceId: null as any,
 | 
			
		||||
        authCertName: '',
 | 
			
		||||
    },
 | 
			
		||||
    instances: [] as any,
 | 
			
		||||
    loadingDbNames: false,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const { dialogVisible, allDatabases, form, dbNamesSelected } = toRefs(state);
 | 
			
		||||
 | 
			
		||||
watchEffect(() => {
 | 
			
		||||
    state.dialogVisible = props.visible;
 | 
			
		||||
    if (!state.dialogVisible) {
 | 
			
		||||
        return;
 | 
			
		||||
watch(
 | 
			
		||||
    () => props.visible,
 | 
			
		||||
    () => {
 | 
			
		||||
        state.dialogVisible = props.visible;
 | 
			
		||||
        if (!state.dialogVisible) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const db: any = props.db;
 | 
			
		||||
        if (db.code) {
 | 
			
		||||
            state.form = { ...db };
 | 
			
		||||
            if (db.getDatabaseMode == DbGetDbNamesMode.Assign.value) {
 | 
			
		||||
                // 将数据库名使用空格切割,获取所有数据库列表
 | 
			
		||||
                state.dbNamesSelected = db.database.split(' ');
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            state.form = { getDatabaseMode: DbGetDbNamesMode.Auto.value } as any;
 | 
			
		||||
            state.dbNamesSelected = [];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    const db: any = props.db;
 | 
			
		||||
    if (db.code) {
 | 
			
		||||
        state.form = { ...db };
 | 
			
		||||
        // state.form.tagId = newValue.db.tags.map((t: any) => t.tagId);
 | 
			
		||||
        // 将数据库名使用空格切割,获取所有数据库列表
 | 
			
		||||
        state.dbNamesSelected = db.database.split(' ');
 | 
			
		||||
    } else {
 | 
			
		||||
        state.form = {} as any;
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const onChangeGetDatabaseMode = (val: any) => {
 | 
			
		||||
    if (val == DbGetDbNamesMode.Auto.value) {
 | 
			
		||||
        state.dbNamesSelected = [];
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const changeAuthCert = (val: string) => {
 | 
			
		||||
    getAllDatabase(val);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getAuthCerts = async () => {
 | 
			
		||||
@@ -217,15 +233,20 @@ const getAuthCerts = async () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getAllDatabase = async (authCertName: string) => {
 | 
			
		||||
    const req = { ...(props.instance as any) };
 | 
			
		||||
    req.authCert = state.authCerts?.find((x: any) => x.name == authCertName);
 | 
			
		||||
    let dbs = await dbApi.getAllDatabase.request(req);
 | 
			
		||||
    state.allDatabases = dbs;
 | 
			
		||||
    try {
 | 
			
		||||
        state.loadingDbNames = true;
 | 
			
		||||
        const req = { ...(props.instance as any) };
 | 
			
		||||
        req.authCert = state.authCerts?.find((x: any) => x.name == authCertName);
 | 
			
		||||
        let dbs = await dbApi.getAllDatabase.request(req);
 | 
			
		||||
        state.allDatabases = dbs;
 | 
			
		||||
 | 
			
		||||
    // 如果是oracle,且没查出数据库列表,则取实例sid
 | 
			
		||||
    let instance = state.instances.find((item: any) => item.id === state.form.instanceId);
 | 
			
		||||
    if (instance && instance.type === DbType.oracle && dbs.length === 0) {
 | 
			
		||||
        state.allDatabases = [instance.sid];
 | 
			
		||||
        // 如果是oracle,且没查出数据库列表,则取实例sid
 | 
			
		||||
        let instance = state.instances.find((item: any) => item.id === state.form.instanceId);
 | 
			
		||||
        if (instance && instance.type === DbType.oracle && dbs.length === 0) {
 | 
			
		||||
            state.allDatabases = [instance.sid];
 | 
			
		||||
        }
 | 
			
		||||
    } finally {
 | 
			
		||||
        state.loadingDbNames = false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,9 +35,9 @@
 | 
			
		||||
            <template #database="{ data }">
 | 
			
		||||
                <el-popover placement="bottom" :width="200" trigger="click">
 | 
			
		||||
                    <template #reference>
 | 
			
		||||
                        <el-button @click="state.currentDbs = data.database" type="primary" link>查看库</el-button>
 | 
			
		||||
                        <el-button @click="getDbNames(data)" type="primary" link>查看库</el-button>
 | 
			
		||||
                    </template>
 | 
			
		||||
                    <el-table :data="filterDbs" size="small">
 | 
			
		||||
                    <el-table :data="filterDbs" v-loading="state.loadingDbNames" size="small">
 | 
			
		||||
                        <el-table-column prop="dbName" label="数据库">
 | 
			
		||||
                            <template #header>
 | 
			
		||||
                                <el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
 | 
			
		||||
@@ -221,6 +221,8 @@ import DbBackupHistoryList from './DbBackupHistoryList.vue';
 | 
			
		||||
import DbRestoreList from './DbRestoreList.vue';
 | 
			
		||||
import ResourceTags from '../component/ResourceTags.vue';
 | 
			
		||||
import { sleep } from '@/common/utils/loading';
 | 
			
		||||
import { DbGetDbNamesMode } from './enums';
 | 
			
		||||
import { DbInst } from './db';
 | 
			
		||||
 | 
			
		||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
 | 
			
		||||
 | 
			
		||||
@@ -237,6 +239,7 @@ const columns = ref([
 | 
			
		||||
    TableColumn.new('instanceName', '实例名'),
 | 
			
		||||
    TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
 | 
			
		||||
    TableColumn.new('authCertName', '授权凭证'),
 | 
			
		||||
    TableColumn.new('getDatabaseMode', '获库方式').typeTag(DbGetDbNamesMode),
 | 
			
		||||
    TableColumn.new('database', '库').isSlot().setMinWidth(80),
 | 
			
		||||
    TableColumn.new('remark', '备注'),
 | 
			
		||||
    TableColumn.new('code', '编号'),
 | 
			
		||||
@@ -258,7 +261,8 @@ const state = reactive({
 | 
			
		||||
    row: {} as any,
 | 
			
		||||
    dbId: 0,
 | 
			
		||||
    db: '',
 | 
			
		||||
    currentDbs: '',
 | 
			
		||||
    loadingDbNames: false,
 | 
			
		||||
    currentDbNames: [],
 | 
			
		||||
    dbNameSearch: '',
 | 
			
		||||
    instances: [] as any,
 | 
			
		||||
    /**
 | 
			
		||||
@@ -344,15 +348,26 @@ onMounted(async () => {
 | 
			
		||||
    search();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const getDbNames = async (db: any) => {
 | 
			
		||||
    try {
 | 
			
		||||
        state.loadingDbNames = true;
 | 
			
		||||
        state.currentDbNames = await DbInst.getDbNames(db);
 | 
			
		||||
    } finally {
 | 
			
		||||
        state.loadingDbNames = false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const filterDbs = computed(() => {
 | 
			
		||||
    const dbsStr = state.currentDbs;
 | 
			
		||||
    if (!dbsStr) {
 | 
			
		||||
    const dbNames = state.currentDbNames;
 | 
			
		||||
    if (!dbNames) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    const dbs = dbsStr.split(' ').map((db: any) => {
 | 
			
		||||
        return { dbName: db };
 | 
			
		||||
    const dbNameObjs = dbNames.map((x) => {
 | 
			
		||||
        return {
 | 
			
		||||
            dbName: x,
 | 
			
		||||
        };
 | 
			
		||||
    });
 | 
			
		||||
    return dbs.filter((db: any) => {
 | 
			
		||||
    return dbNameObjs.filter((db: any) => {
 | 
			
		||||
        return db.dbName.includes(state.dbNameSearch);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -8,13 +8,18 @@
 | 
			
		||||
            <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="state.currentDbs = scope.row.database" type="primary" link>查看库</el-button>
 | 
			
		||||
                                <el-button @click="getDbNames(scope.row)" type="primary" link>查看库</el-button>
 | 
			
		||||
                            </template>
 | 
			
		||||
                            <el-table :data="filterDbs" size="small">
 | 
			
		||||
                            <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 />
 | 
			
		||||
@@ -57,6 +62,9 @@ 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: {
 | 
			
		||||
@@ -83,7 +91,8 @@ const emit = defineEmits(['update:visible', 'cancel', 'val-change']);
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    dialogVisible: false,
 | 
			
		||||
    dbs: [] as any,
 | 
			
		||||
    currentDbs: '', // 当前数据库名,空格分割库名
 | 
			
		||||
    loadingDbNames: false,
 | 
			
		||||
    currentDbNames: [], // 当前数据库名
 | 
			
		||||
    dbNameSearch: '',
 | 
			
		||||
    dbEditDialog: {
 | 
			
		||||
        visible: false,
 | 
			
		||||
@@ -103,15 +112,26 @@ watchEffect(() => {
 | 
			
		||||
    getDbs();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const getDbNames = async (db: any) => {
 | 
			
		||||
    try {
 | 
			
		||||
        state.loadingDbNames = true;
 | 
			
		||||
        state.currentDbNames = await DbInst.getDbNames(db);
 | 
			
		||||
    } finally {
 | 
			
		||||
        state.loadingDbNames = false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const filterDbs = computed(() => {
 | 
			
		||||
    const dbsStr = state.currentDbs;
 | 
			
		||||
    if (!dbsStr) {
 | 
			
		||||
    const dbNames = state.currentDbNames;
 | 
			
		||||
    if (!dbNames) {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
    const dbs = dbsStr.split(' ').map((db: any) => {
 | 
			
		||||
        return { dbName: db };
 | 
			
		||||
    const dbNameObjs = dbNames.map((x) => {
 | 
			
		||||
        return {
 | 
			
		||||
            dbName: x,
 | 
			
		||||
        };
 | 
			
		||||
    });
 | 
			
		||||
    return dbs.filter((db: any) => {
 | 
			
		||||
    return dbNameObjs.filter((db: any) => {
 | 
			
		||||
        return db.dbName.includes(state.dbNameSearch);
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -272,7 +272,7 @@ const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath)
 | 
			
		||||
// 数据库实例节点类型
 | 
			
		||||
const NodeTypeDbInst = new NodeType(SqlExecNodeType.DbInst).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
 | 
			
		||||
    const params = parentNode.params;
 | 
			
		||||
    const dbs = params.database.split(' ')?.sort();
 | 
			
		||||
    const dbs = (await DbInst.getDbNames(params))?.sort();
 | 
			
		||||
 | 
			
		||||
    const flowProcdef = await procdefApi.getByResource.request({ resourceType: TagResourceTypeEnum.DbName.value, resourceCode: params.code });
 | 
			
		||||
    return dbs.map((x: any) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ export const dbApi = {
 | 
			
		||||
    instances: Api.newGet('/instances'),
 | 
			
		||||
    getInstance: Api.newGet('/instances/{instanceId}'),
 | 
			
		||||
    getAllDatabase: Api.newPost('/instances/databases'),
 | 
			
		||||
    getDbNamesByAc: Api.newGet('/instances/databases/{authCertName}'),
 | 
			
		||||
    getInstanceServerInfo: Api.newGet('/instances/{instanceId}/server-info'),
 | 
			
		||||
    testConn: Api.newPost('/instances/test-conn'),
 | 
			
		||||
    saveInstance: Api.newPost('/instances'),
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ import SvgIcon from '@/components/svgIcon/index.vue';
 | 
			
		||||
import { getDbDialect, noSchemaTypes } from '@/views/ops/db/dialect';
 | 
			
		||||
import TagTreeResourceSelect from '../../component/TagTreeResourceSelect.vue';
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { DbInst } from '../db';
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    dbId: {
 | 
			
		||||
@@ -101,9 +102,9 @@ const noSchemaType = (type: string) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 数据库实例节点类型
 | 
			
		||||
const NodeTypeDbInst = new NodeType(SqlExecNodeType.DbInst).withLoadNodesFunc((parentNode: TagTreeNode) => {
 | 
			
		||||
const NodeTypeDbInst = new NodeType(SqlExecNodeType.DbInst).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
 | 
			
		||||
    const params = parentNode.params;
 | 
			
		||||
    const dbs = params.database.split(' ')?.sort();
 | 
			
		||||
    const dbs = (await DbInst.getDbNames(params))?.sort();
 | 
			
		||||
    let fn: NodeType;
 | 
			
		||||
    if (noSchemaType(params.type)) {
 | 
			
		||||
        fn = MysqlNodeTypes;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
        <el-row class="mb5">
 | 
			
		||||
            <el-popover v-model:visible="state.dumpInfo.visible" trigger="click" :width="470" placement="right">
 | 
			
		||||
                <template #reference>
 | 
			
		||||
                    <el-button class="ml5" type="success" size="small">导出</el-button>
 | 
			
		||||
                    <el-button :disabled="state.dumpInfo.tables?.length == 0" class="ml5" type="success" size="small">导出</el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
                <el-form-item label="导出内容: ">
 | 
			
		||||
                    <el-radio-group v-model="dumpInfo.type">
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import { editor, languages, Position } from 'monaco-editor';
 | 
			
		||||
import { registerCompletionItemProvider } from '@/components/monaco/completionItemProvider';
 | 
			
		||||
import { DbDialect, EditorCompletionItem, getDbDialect } from './dialect';
 | 
			
		||||
import { type RemovableRef, useLocalStorage } from '@vueuse/core';
 | 
			
		||||
import { DbGetDbNamesMode } from './enums';
 | 
			
		||||
 | 
			
		||||
const hintsStorage: RemovableRef<Map<string, any>> = useLocalStorage('db-table-hints', new Map());
 | 
			
		||||
const tableStorage: RemovableRef<Map<string, any>> = useLocalStorage('db-tables', new Map());
 | 
			
		||||
@@ -503,6 +504,19 @@ export class DbInst {
 | 
			
		||||
            col.columnType = col.dataType;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据数据库配置信息获取对应的库名列表
 | 
			
		||||
     * @param db db配置信息
 | 
			
		||||
     * @returns 库名列表
 | 
			
		||||
     */
 | 
			
		||||
    static async getDbNames(db: any) {
 | 
			
		||||
        if (db.getDatabaseMode == DbGetDbNamesMode.Assign.value) {
 | 
			
		||||
            return db.database.split(' ');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return await dbApi.getDbNamesByAc.request({ authCertName: db.authCertName });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,10 @@
 | 
			
		||||
import { EnumValue } from '@/common/Enum';
 | 
			
		||||
 | 
			
		||||
export const DbGetDbNamesMode = {
 | 
			
		||||
    Auto: EnumValue.of(-1, '实时获取').setTagType('warning'),
 | 
			
		||||
    Assign: EnumValue.of(1, '指定库名').setTagType('primary'),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 数据库sql执行类型
 | 
			
		||||
export const DbSqlExecTypeEnum = {
 | 
			
		||||
    Update: EnumValue.of(1, 'UPDATE').setTagColor('#E4F5EB'),
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,69 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-popover placement="right" width="auto" title="机器详情" trigger="click">
 | 
			
		||||
            <template #reference>
 | 
			
		||||
                <el-link @click="getMachineDetail" type="primary">{{ props.code }}</el-link>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-descriptions v-loading="state.loading" :column="3" border>
 | 
			
		||||
                <el-descriptions-item :span="1" label="机器id">{{ state.machineDetail.id }}</el-descriptions-item>
 | 
			
		||||
                <el-descriptions-item :span="1" label="编号">{{ state.machineDetail.code }}</el-descriptions-item>
 | 
			
		||||
                <el-descriptions-item :span="1" label="名称">{{ state.machineDetail.name }}</el-descriptions-item>
 | 
			
		||||
 | 
			
		||||
                <el-descriptions-item :span="3" label="关联标签"><ResourceTags :tags="state.machineDetail.tags" /></el-descriptions-item>
 | 
			
		||||
 | 
			
		||||
                <el-descriptions-item :span="2" label="IP">{{ state.machineDetail.ip }}</el-descriptions-item>
 | 
			
		||||
                <el-descriptions-item :span="1" label="端口">{{ state.machineDetail.port }}</el-descriptions-item>
 | 
			
		||||
 | 
			
		||||
                <el-descriptions-item :span="3" label="备注">{{ state.machineDetail.remark }}</el-descriptions-item>
 | 
			
		||||
 | 
			
		||||
                <el-descriptions-item :span="1.5" label="SSH隧道">{{ state.machineDetail.sshTunnelMachineId > 0 ? '是' : '否' }} </el-descriptions-item>
 | 
			
		||||
                <el-descriptions-item :span="1.5" label="终端回放">{{ state.machineDetail.enableRecorder == 1 ? '是' : '否' }} </el-descriptions-item>
 | 
			
		||||
 | 
			
		||||
                <el-descriptions-item :span="2" label="创建时间">{{ formatDate(state.machineDetail.createTime) }} </el-descriptions-item>
 | 
			
		||||
                <el-descriptions-item :span="1" label="创建者">{{ state.machineDetail.creator }}</el-descriptions-item>
 | 
			
		||||
 | 
			
		||||
                <el-descriptions-item :span="2" label="更新时间">{{ formatDate(state.machineDetail.updateTime) }} </el-descriptions-item>
 | 
			
		||||
                <el-descriptions-item :span="1" label="修改者">{{ state.machineDetail.modifier }}</el-descriptions-item>
 | 
			
		||||
            </el-descriptions>
 | 
			
		||||
        </el-popover>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { reactive } from 'vue';
 | 
			
		||||
import { machineApi } from '../api';
 | 
			
		||||
import { formatDate } from '@/common/utils/format';
 | 
			
		||||
import ResourceTags from '../../component/ResourceTags.vue';
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    code: {
 | 
			
		||||
        type: [String],
 | 
			
		||||
        requierd: true,
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    loading: false,
 | 
			
		||||
    machineDetail: {} as any,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const getMachineDetail = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
        state.machineDetail = {};
 | 
			
		||||
        state.loading = true;
 | 
			
		||||
        const res = await machineApi.list.request({
 | 
			
		||||
            code: props.code,
 | 
			
		||||
        });
 | 
			
		||||
        if (res.total == 0) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        state.machineDetail = res.list?.[0];
 | 
			
		||||
    } finally {
 | 
			
		||||
        state.loading = false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style></style>
 | 
			
		||||
@@ -13,20 +13,13 @@
 | 
			
		||||
                ref="pageTableRef"
 | 
			
		||||
                :page-api="cronJobApi.execList"
 | 
			
		||||
                :lazy="true"
 | 
			
		||||
                :data-handler-fn="parseData"
 | 
			
		||||
                :search-items="searchItems"
 | 
			
		||||
                v-model:query-form="params"
 | 
			
		||||
                :data="state.data.list"
 | 
			
		||||
                :columns="columns"
 | 
			
		||||
            >
 | 
			
		||||
                <template #machineSelect>
 | 
			
		||||
                    <el-select v-model="params.machineId" filterable placeholder="选择机器查询" clearable>
 | 
			
		||||
                        <el-option v-for="ac in machineMap.values()" :key="ac.id" :value="ac.id" :label="ac.ip">
 | 
			
		||||
                            {{ ac.ip }}
 | 
			
		||||
                            <el-divider direction="vertical" border-style="dashed" />
 | 
			
		||||
                            {{ ac.tagPath }}{{ ac.name }}
 | 
			
		||||
                        </el-option>
 | 
			
		||||
                    </el-select>
 | 
			
		||||
                <template #machineCode="{ data }">
 | 
			
		||||
                    <MachineDetail :code="data.machineCode" />
 | 
			
		||||
                </template>
 | 
			
		||||
            </page-table>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
@@ -35,11 +28,12 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { watch, ref, toRefs, reactive, Ref } from 'vue';
 | 
			
		||||
import { cronJobApi, machineApi } from '../api';
 | 
			
		||||
import { cronJobApi } from '../api';
 | 
			
		||||
import PageTable from '@/components/pagetable/PageTable.vue';
 | 
			
		||||
import { TableColumn } from '@/components/pagetable';
 | 
			
		||||
import { CronJobExecStatusEnum } from '../enums';
 | 
			
		||||
import { SearchItem } from '@/components/SearchForm';
 | 
			
		||||
import MachineDetail from '../component/MachineDetail.vue';
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    visible: {
 | 
			
		||||
@@ -55,11 +49,10 @@ const props = defineProps({
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['update:visible', 'update:data', 'cancel']);
 | 
			
		||||
 | 
			
		||||
const searchItems = [SearchItem.slot('machineId', '机器', 'machineSelect'), SearchItem.select('status', '状态').withEnum(CronJobExecStatusEnum)];
 | 
			
		||||
const searchItems = [SearchItem.input('machineCode', '机器编号'), SearchItem.select('status', '状态').withEnum(CronJobExecStatusEnum)];
 | 
			
		||||
 | 
			
		||||
const columns = ref([
 | 
			
		||||
    TableColumn.new('machineIp', '机器IP').setMinWidth(120),
 | 
			
		||||
    TableColumn.new('machineName', '机器名称').setMinWidth(100),
 | 
			
		||||
    TableColumn.new('machineCode', '机器编号').isSlot(),
 | 
			
		||||
    TableColumn.new('status', '状态').typeTag(CronJobExecStatusEnum).setMinWidth(70),
 | 
			
		||||
    TableColumn.new('res', '执行结果').setMinWidth(250).canBeautify(),
 | 
			
		||||
    TableColumn.new('execTime', '执行时间').isTime().setMinWidth(150),
 | 
			
		||||
@@ -75,7 +68,7 @@ const state = reactive({
 | 
			
		||||
        pageSize: 10,
 | 
			
		||||
        cronJobId: 0,
 | 
			
		||||
        status: null,
 | 
			
		||||
        machineId: null,
 | 
			
		||||
        machineCode: '',
 | 
			
		||||
    },
 | 
			
		||||
    // 列表数据
 | 
			
		||||
    data: {
 | 
			
		||||
@@ -85,8 +78,6 @@ const state = reactive({
 | 
			
		||||
    machines: [],
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const machineMap: Map<number, any> = new Map();
 | 
			
		||||
 | 
			
		||||
const { dialogVisible, params } = toRefs(state);
 | 
			
		||||
 | 
			
		||||
watch(props, async (newValue: any) => {
 | 
			
		||||
@@ -95,52 +86,14 @@ watch(props, async (newValue: any) => {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const machineIds = await cronJobApi.relateMachineIds.request({
 | 
			
		||||
        cronJobId: props.data?.id,
 | 
			
		||||
    });
 | 
			
		||||
    const res = await machineApi.list.request({
 | 
			
		||||
        ids: machineIds?.join(','),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    res.list?.forEach((x: any) => {
 | 
			
		||||
        machineMap.set(x.id, x);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    state.params.cronJobId = props.data?.id;
 | 
			
		||||
    search();
 | 
			
		||||
    setTimeout(() => search(), 300);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const search = async () => {
 | 
			
		||||
    pageTableRef.value.search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const parseData = async (res: any) => {
 | 
			
		||||
    const dataList = res.list;
 | 
			
		||||
    // 填充机器信息
 | 
			
		||||
    for (let x of dataList) {
 | 
			
		||||
        const machineId = x.machineId;
 | 
			
		||||
        let machine = machineMap.get(machineId);
 | 
			
		||||
        // 如果未找到,则可能被移除,则调接口查询机器信息
 | 
			
		||||
        if (!machine) {
 | 
			
		||||
            const machineRes = await machineApi.list.request({ ids: machineId });
 | 
			
		||||
            if (!machineRes.list) {
 | 
			
		||||
                machine = {
 | 
			
		||||
                    id: machineId,
 | 
			
		||||
                    ip: machineId,
 | 
			
		||||
                    name: '该机器已被删除',
 | 
			
		||||
                };
 | 
			
		||||
            } else {
 | 
			
		||||
                machine = machineRes.list[0];
 | 
			
		||||
            }
 | 
			
		||||
            machineMap.set(machineId, machine);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        x.machineIp = machine?.ip;
 | 
			
		||||
        x.machineName = machine?.name;
 | 
			
		||||
    }
 | 
			
		||||
    return res;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
    emit('update:visible', false);
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
@@ -152,7 +105,7 @@ const initData = () => {
 | 
			
		||||
    state.data.list = [];
 | 
			
		||||
    state.data.total = 0;
 | 
			
		||||
    state.params.pageNum = 1;
 | 
			
		||||
    state.params.machineId = null;
 | 
			
		||||
    state.params.machineCode = '';
 | 
			
		||||
    state.params.status = null;
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,14 @@
 | 
			
		||||
                <el-button v-auth="'authcert:save'" type="primary" icon="plus" @click="edit(false)">添加</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template #resourceCode="{ data }">
 | 
			
		||||
                <SvgIcon
 | 
			
		||||
                    :name="EnumValue.getEnumByValue(TagResourceTypeEnum, data.resourceType)?.extra.icon"
 | 
			
		||||
                    :color="EnumValue.getEnumByValue(TagResourceTypeEnum, data.resourceType)?.extra.iconColor"
 | 
			
		||||
                />
 | 
			
		||||
                {{ data.resourceCode }}
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template #action="{ data }">
 | 
			
		||||
                <el-button v-auth="'authcert:save'" @click="edit(data)" type="primary" link>编辑</el-button>
 | 
			
		||||
 | 
			
		||||
@@ -41,6 +49,7 @@ import { SearchItem } from '@/components/SearchForm';
 | 
			
		||||
import { AuthCertCiphertextTypeEnum, AuthCertTypeEnum } from './enums';
 | 
			
		||||
import { ResourceTypeEnum, TagResourceTypeEnum } from '@/common/commonEnum';
 | 
			
		||||
import ResourceAuthCertEdit from '../component/ResourceAuthCertEdit.vue';
 | 
			
		||||
import EnumValue from '@/common/Enum';
 | 
			
		||||
 | 
			
		||||
const pageTableRef: Ref<any> = ref(null);
 | 
			
		||||
const state = reactive({
 | 
			
		||||
@@ -50,6 +59,7 @@ const state = reactive({
 | 
			
		||||
        name: null,
 | 
			
		||||
    },
 | 
			
		||||
    searchItems: [
 | 
			
		||||
        SearchItem.input('resourceCode', '资源编号'),
 | 
			
		||||
        SearchItem.input('name', '凭证名称'),
 | 
			
		||||
        SearchItem.select('resourceType', '资源类型').withEnum(ResourceTypeEnum),
 | 
			
		||||
        SearchItem.select('type', '凭证类型').withEnum(AuthCertTypeEnum),
 | 
			
		||||
@@ -60,8 +70,7 @@ const state = reactive({
 | 
			
		||||
        TableColumn.new('type', '凭证类型').typeTag(AuthCertTypeEnum),
 | 
			
		||||
        TableColumn.new('username', '用户名'),
 | 
			
		||||
        TableColumn.new('ciphertextType', '密文类型').typeTag(AuthCertCiphertextTypeEnum),
 | 
			
		||||
        TableColumn.new('resourceType', '资源类型').typeTag(TagResourceTypeEnum),
 | 
			
		||||
        TableColumn.new('resourceCode', '资源编号'),
 | 
			
		||||
        TableColumn.new('resourceCode', '资源编号').isSlot().setAddWidth(30),
 | 
			
		||||
        TableColumn.new('remark', '备注'),
 | 
			
		||||
        TableColumn.new('creator', '创建人'),
 | 
			
		||||
        TableColumn.new('createTime', '创建时间').isTime(),
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user