mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c4cb4234fd | 
@@ -14,7 +14,7 @@ services:
 | 
				
			|||||||
    restart: always
 | 
					    restart: always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  server:
 | 
					  server:
 | 
				
			||||||
    image: ccr.ccs.tencentyun.com/mayfly/mayfly-go:v1.8.3
 | 
					    image: ccr.ccs.tencentyun.com/mayfly/mayfly-go:v1.8.5
 | 
				
			||||||
    build:
 | 
					    build:
 | 
				
			||||||
      context: .
 | 
					      context: .
 | 
				
			||||||
      dockerfile: Dockerfile
 | 
					      dockerfile: Dockerfile
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
    "cropperjs": "^1.6.1",
 | 
					    "cropperjs": "^1.6.1",
 | 
				
			||||||
    "dayjs": "^1.11.11",
 | 
					    "dayjs": "^1.11.11",
 | 
				
			||||||
    "echarts": "^5.5.0",
 | 
					    "echarts": "^5.5.0",
 | 
				
			||||||
    "element-plus": "^2.7.2",
 | 
					    "element-plus": "^2.7.3",
 | 
				
			||||||
    "js-base64": "^3.7.7",
 | 
					    "js-base64": "^3.7.7",
 | 
				
			||||||
    "jsencrypt": "^3.3.2",
 | 
					    "jsencrypt": "^3.3.2",
 | 
				
			||||||
    "lodash": "^4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
@@ -55,7 +55,7 @@
 | 
				
			|||||||
    "eslint": "^8.35.0",
 | 
					    "eslint": "^8.35.0",
 | 
				
			||||||
    "eslint-plugin-vue": "^9.25.0",
 | 
					    "eslint-plugin-vue": "^9.25.0",
 | 
				
			||||||
    "prettier": "^3.2.5",
 | 
					    "prettier": "^3.2.5",
 | 
				
			||||||
    "sass": "^1.76.0",
 | 
					    "sass": "^1.77.1",
 | 
				
			||||||
    "typescript": "^5.4.5",
 | 
					    "typescript": "^5.4.5",
 | 
				
			||||||
    "vite": "^5.2.11",
 | 
					    "vite": "^5.2.11",
 | 
				
			||||||
    "vue-eslint-parser": "^9.4.2"
 | 
					    "vue-eslint-parser": "^9.4.2"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.4',
 | 
					    version: 'v1.8.5',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default config;
 | 
					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.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-select>
 | 
				
			||||||
                    </el-form-item>
 | 
					                    </el-form-item>
 | 
				
			||||||
                    <el-form-item prop="resourceCode" label="资源编号" required>
 | 
					                    <el-form-item prop="resourceCode" label="资源编号" required>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@
 | 
				
			|||||||
                </el-form-item>
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-form-item prop="authCertName" label="授权凭证" required>
 | 
					                <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">
 | 
					                        <el-option v-for="item in state.authCerts" :key="item.id" :label="`${item.name}`" :value="item.name">
 | 
				
			||||||
                            {{ item.name }}
 | 
					                            {{ item.name }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,8 +39,15 @@
 | 
				
			|||||||
                    </el-select>
 | 
					                    </el-select>
 | 
				
			||||||
                </el-form-item>
 | 
					                </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-form-item prop="database" label="数据库名">
 | 
				
			||||||
                    <el-select
 | 
					                    <el-select
 | 
				
			||||||
 | 
					                        :disabled="form.getDatabaseMode == DbGetDbNamesMode.Auto.value || !form.authCertName"
 | 
				
			||||||
                        v-model="dbNamesSelected"
 | 
					                        v-model="dbNamesSelected"
 | 
				
			||||||
                        multiple
 | 
					                        multiple
 | 
				
			||||||
                        clearable
 | 
					                        clearable
 | 
				
			||||||
@@ -49,8 +56,9 @@
 | 
				
			|||||||
                        filterable
 | 
					                        filterable
 | 
				
			||||||
                        :filter-method="filterDbNames"
 | 
					                        :filter-method="filterDbNames"
 | 
				
			||||||
                        allow-create
 | 
					                        allow-create
 | 
				
			||||||
                        placeholder="请确保数据库实例信息填写完整后获取库名"
 | 
					                        placeholder="获库方式为‘指定库名’时,可选择"
 | 
				
			||||||
                        style="width: 100%"
 | 
					                        @focus="getAllDatabase(form.authCertName)"
 | 
				
			||||||
 | 
					                        :loading="state.loadingDbNames"
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        <template #header>
 | 
					                        <template #header>
 | 
				
			||||||
                            <el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="handleCheckAll"> 全选 </el-checkbox>
 | 
					                            <el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="handleCheckAll"> 全选 </el-checkbox>
 | 
				
			||||||
@@ -75,7 +83,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { toRefs, reactive, watch, ref, watchEffect } from 'vue';
 | 
					import { toRefs, reactive, watch, ref } from 'vue';
 | 
				
			||||||
import { dbApi } from './api';
 | 
					import { dbApi } from './api';
 | 
				
			||||||
import { ElMessage } from 'element-plus';
 | 
					import { ElMessage } from 'element-plus';
 | 
				
			||||||
import type { CheckboxValueType } 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 { AuthCertCiphertextTypeEnum } from '../tag/enums';
 | 
				
			||||||
import { resourceAuthCertApi } from '../tag/api';
 | 
					import { resourceAuthCertApi } from '../tag/api';
 | 
				
			||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
					import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
				
			||||||
 | 
					import { DbGetDbNamesMode } from './enums';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
    visible: {
 | 
					    visible: {
 | 
				
			||||||
@@ -147,10 +156,10 @@ const rules = {
 | 
				
			|||||||
            trigger: ['change', 'blur'],
 | 
					            trigger: ['change', 'blur'],
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    database: [
 | 
					    getDatabaseMode: [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            required: true,
 | 
					            required: true,
 | 
				
			||||||
            message: '请添加数据库',
 | 
					            message: '请选择库名获取方式',
 | 
				
			||||||
            trigger: ['change', 'blur'],
 | 
					            trigger: ['change', 'blur'],
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
@@ -172,38 +181,45 @@ const state = reactive({
 | 
				
			|||||||
    authCerts: [] as any,
 | 
					    authCerts: [] as any,
 | 
				
			||||||
    form: {
 | 
					    form: {
 | 
				
			||||||
        id: null,
 | 
					        id: null,
 | 
				
			||||||
        // tagId: [],
 | 
					 | 
				
			||||||
        name: null,
 | 
					        name: null,
 | 
				
			||||||
        code: '',
 | 
					        code: '',
 | 
				
			||||||
 | 
					        getDatabaseMode: DbGetDbNamesMode.Auto.value,
 | 
				
			||||||
        database: '',
 | 
					        database: '',
 | 
				
			||||||
        remark: '',
 | 
					        remark: '',
 | 
				
			||||||
        instanceId: null as any,
 | 
					        instanceId: null as any,
 | 
				
			||||||
        authCertName: '',
 | 
					        authCertName: '',
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    instances: [] as any,
 | 
					    instances: [] as any,
 | 
				
			||||||
 | 
					    loadingDbNames: false,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { dialogVisible, allDatabases, form, dbNamesSelected } = toRefs(state);
 | 
					const { dialogVisible, allDatabases, form, dbNamesSelected } = toRefs(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watchEffect(() => {
 | 
					watch(
 | 
				
			||||||
    state.dialogVisible = props.visible;
 | 
					    () => props.visible,
 | 
				
			||||||
    if (!state.dialogVisible) {
 | 
					    () => {
 | 
				
			||||||
        return;
 | 
					        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 };
 | 
					const onChangeGetDatabaseMode = (val: any) => {
 | 
				
			||||||
        // state.form.tagId = newValue.db.tags.map((t: any) => t.tagId);
 | 
					    if (val == DbGetDbNamesMode.Auto.value) {
 | 
				
			||||||
        // 将数据库名使用空格切割,获取所有数据库列表
 | 
					 | 
				
			||||||
        state.dbNamesSelected = db.database.split(' ');
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        state.form = {} as any;
 | 
					 | 
				
			||||||
        state.dbNamesSelected = [];
 | 
					        state.dbNamesSelected = [];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const changeAuthCert = (val: string) => {
 | 
					 | 
				
			||||||
    getAllDatabase(val);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getAuthCerts = async () => {
 | 
					const getAuthCerts = async () => {
 | 
				
			||||||
@@ -217,15 +233,20 @@ const getAuthCerts = async () => {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getAllDatabase = async (authCertName: string) => {
 | 
					const getAllDatabase = async (authCertName: string) => {
 | 
				
			||||||
    const req = { ...(props.instance as any) };
 | 
					    try {
 | 
				
			||||||
    req.authCert = state.authCerts?.find((x: any) => x.name == authCertName);
 | 
					        state.loadingDbNames = true;
 | 
				
			||||||
    let dbs = await dbApi.getAllDatabase.request(req);
 | 
					        const req = { ...(props.instance as any) };
 | 
				
			||||||
    state.allDatabases = dbs;
 | 
					        req.authCert = state.authCerts?.find((x: any) => x.name == authCertName);
 | 
				
			||||||
 | 
					        let dbs = await dbApi.getAllDatabase.request(req);
 | 
				
			||||||
 | 
					        state.allDatabases = dbs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 如果是oracle,且没查出数据库列表,则取实例sid
 | 
					        // 如果是oracle,且没查出数据库列表,则取实例sid
 | 
				
			||||||
    let instance = state.instances.find((item: any) => item.id === state.form.instanceId);
 | 
					        let instance = state.instances.find((item: any) => item.id === state.form.instanceId);
 | 
				
			||||||
    if (instance && instance.type === DbType.oracle && dbs.length === 0) {
 | 
					        if (instance && instance.type === DbType.oracle && dbs.length === 0) {
 | 
				
			||||||
        state.allDatabases = [instance.sid];
 | 
					            state.allDatabases = [instance.sid];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					        state.loadingDbNames = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,9 +35,9 @@
 | 
				
			|||||||
            <template #database="{ data }">
 | 
					            <template #database="{ data }">
 | 
				
			||||||
                <el-popover placement="bottom" :width="200" trigger="click">
 | 
					                <el-popover placement="bottom" :width="200" trigger="click">
 | 
				
			||||||
                    <template #reference>
 | 
					                    <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>
 | 
					                    </template>
 | 
				
			||||||
                    <el-table :data="filterDbs" size="small">
 | 
					                    <el-table :data="filterDbs" v-loading="state.loadingDbNames" size="small">
 | 
				
			||||||
                        <el-table-column prop="dbName" label="数据库">
 | 
					                        <el-table-column prop="dbName" label="数据库">
 | 
				
			||||||
                            <template #header>
 | 
					                            <template #header>
 | 
				
			||||||
                                <el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
 | 
					                                <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 DbRestoreList from './DbRestoreList.vue';
 | 
				
			||||||
import ResourceTags from '../component/ResourceTags.vue';
 | 
					import ResourceTags from '../component/ResourceTags.vue';
 | 
				
			||||||
import { sleep } from '@/common/utils/loading';
 | 
					import { sleep } from '@/common/utils/loading';
 | 
				
			||||||
 | 
					import { DbGetDbNamesMode } from './enums';
 | 
				
			||||||
 | 
					import { DbInst } from './db';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
 | 
					const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -237,6 +239,7 @@ const columns = ref([
 | 
				
			|||||||
    TableColumn.new('instanceName', '实例名'),
 | 
					    TableColumn.new('instanceName', '实例名'),
 | 
				
			||||||
    TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
 | 
					    TableColumn.new('host', 'ip:port').isSlot().setAddWidth(40),
 | 
				
			||||||
    TableColumn.new('authCertName', '授权凭证'),
 | 
					    TableColumn.new('authCertName', '授权凭证'),
 | 
				
			||||||
 | 
					    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', '编号'),
 | 
				
			||||||
@@ -258,7 +261,8 @@ const state = reactive({
 | 
				
			|||||||
    row: {} as any,
 | 
					    row: {} as any,
 | 
				
			||||||
    dbId: 0,
 | 
					    dbId: 0,
 | 
				
			||||||
    db: '',
 | 
					    db: '',
 | 
				
			||||||
    currentDbs: '',
 | 
					    loadingDbNames: false,
 | 
				
			||||||
 | 
					    currentDbNames: [],
 | 
				
			||||||
    dbNameSearch: '',
 | 
					    dbNameSearch: '',
 | 
				
			||||||
    instances: [] as any,
 | 
					    instances: [] as any,
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -344,15 +348,26 @@ onMounted(async () => {
 | 
				
			|||||||
    search();
 | 
					    search();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getDbNames = async (db: any) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        state.loadingDbNames = true;
 | 
				
			||||||
 | 
					        state.currentDbNames = await DbInst.getDbNames(db);
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					        state.loadingDbNames = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const filterDbs = computed(() => {
 | 
					const filterDbs = computed(() => {
 | 
				
			||||||
    const dbsStr = state.currentDbs;
 | 
					    const dbNames = state.currentDbNames;
 | 
				
			||||||
    if (!dbsStr) {
 | 
					    if (!dbNames) {
 | 
				
			||||||
        return [];
 | 
					        return [];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const dbs = dbsStr.split(' ').map((db: any) => {
 | 
					    const dbNameObjs = dbNames.map((x) => {
 | 
				
			||||||
        return { dbName: db };
 | 
					        return {
 | 
				
			||||||
 | 
					            dbName: x,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return dbs.filter((db: any) => {
 | 
					    return dbNameObjs.filter((db: any) => {
 | 
				
			||||||
        return db.dbName.includes(state.dbNameSearch);
 | 
					        return db.dbName.includes(state.dbNameSearch);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,13 +8,18 @@
 | 
				
			|||||||
            <el-table :data="state.dbs" stripe>
 | 
					            <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="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="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">
 | 
					                <el-table-column prop="database" label="库" min-width="80">
 | 
				
			||||||
                    <template #default="scope">
 | 
					                    <template #default="scope">
 | 
				
			||||||
                        <el-popover placement="bottom" :width="200" trigger="click">
 | 
					                        <el-popover placement="bottom" :width="200" trigger="click">
 | 
				
			||||||
                            <template #reference>
 | 
					                            <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>
 | 
					                            </template>
 | 
				
			||||||
                            <el-table :data="filterDbs" size="small">
 | 
					                            <el-table :data="filterDbs" size="small" v-loading="state.loadingDbNames">
 | 
				
			||||||
                                <el-table-column prop="dbName" label="数据库">
 | 
					                                <el-table-column prop="dbName" label="数据库">
 | 
				
			||||||
                                    <template #header>
 | 
					                                    <template #header>
 | 
				
			||||||
                                        <el-input v-model="state.dbNameSearch" size="small" placeholder="库名: 输入可过滤" clearable />
 | 
					                                        <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 { ElMessage, ElMessageBox } from 'element-plus';
 | 
				
			||||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
 | 
					import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
 | 
				
			||||||
import DbEdit from './DbEdit.vue';
 | 
					import DbEdit from './DbEdit.vue';
 | 
				
			||||||
 | 
					import EnumTag from '@/components/enumtag/EnumTag.vue';
 | 
				
			||||||
 | 
					import { DbGetDbNamesMode } from './enums';
 | 
				
			||||||
 | 
					import { DbInst } from './db';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
    visible: {
 | 
					    visible: {
 | 
				
			||||||
@@ -83,7 +91,8 @@ const emit = defineEmits(['update:visible', 'cancel', 'val-change']);
 | 
				
			|||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
    dialogVisible: false,
 | 
					    dialogVisible: false,
 | 
				
			||||||
    dbs: [] as any,
 | 
					    dbs: [] as any,
 | 
				
			||||||
    currentDbs: '', // 当前数据库名,空格分割库名
 | 
					    loadingDbNames: false,
 | 
				
			||||||
 | 
					    currentDbNames: [], // 当前数据库名
 | 
				
			||||||
    dbNameSearch: '',
 | 
					    dbNameSearch: '',
 | 
				
			||||||
    dbEditDialog: {
 | 
					    dbEditDialog: {
 | 
				
			||||||
        visible: false,
 | 
					        visible: false,
 | 
				
			||||||
@@ -103,15 +112,26 @@ watchEffect(() => {
 | 
				
			|||||||
    getDbs();
 | 
					    getDbs();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getDbNames = async (db: any) => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        state.loadingDbNames = true;
 | 
				
			||||||
 | 
					        state.currentDbNames = await DbInst.getDbNames(db);
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					        state.loadingDbNames = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const filterDbs = computed(() => {
 | 
					const filterDbs = computed(() => {
 | 
				
			||||||
    const dbsStr = state.currentDbs;
 | 
					    const dbNames = state.currentDbNames;
 | 
				
			||||||
    if (!dbsStr) {
 | 
					    if (!dbNames) {
 | 
				
			||||||
        return [];
 | 
					        return [];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const dbs = dbsStr.split(' ').map((db: any) => {
 | 
					    const dbNameObjs = dbNames.map((x) => {
 | 
				
			||||||
        return { dbName: db };
 | 
					        return {
 | 
				
			||||||
 | 
					            dbName: x,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return dbs.filter((db: any) => {
 | 
					    return dbNameObjs.filter((db: any) => {
 | 
				
			||||||
        return db.dbName.includes(state.dbNameSearch);
 | 
					        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 NodeTypeDbInst = new NodeType(SqlExecNodeType.DbInst).withLoadNodesFunc(async (parentNode: TagTreeNode) => {
 | 
				
			||||||
    const params = parentNode.params;
 | 
					    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 });
 | 
					    const flowProcdef = await procdefApi.getByResource.request({ resourceType: TagResourceTypeEnum.DbName.value, resourceCode: params.code });
 | 
				
			||||||
    return dbs.map((x: any) => {
 | 
					    return dbs.map((x: any) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@ export const dbApi = {
 | 
				
			|||||||
    instances: Api.newGet('/instances'),
 | 
					    instances: Api.newGet('/instances'),
 | 
				
			||||||
    getInstance: Api.newGet('/instances/{instanceId}'),
 | 
					    getInstance: Api.newGet('/instances/{instanceId}'),
 | 
				
			||||||
    getAllDatabase: Api.newPost('/instances/databases'),
 | 
					    getAllDatabase: Api.newPost('/instances/databases'),
 | 
				
			||||||
 | 
					    getDbNamesByAc: Api.newGet('/instances/databases/{authCertName}'),
 | 
				
			||||||
    getInstanceServerInfo: Api.newGet('/instances/{instanceId}/server-info'),
 | 
					    getInstanceServerInfo: Api.newGet('/instances/{instanceId}/server-info'),
 | 
				
			||||||
    testConn: Api.newPost('/instances/test-conn'),
 | 
					    testConn: Api.newPost('/instances/test-conn'),
 | 
				
			||||||
    saveInstance: Api.newPost('/instances'),
 | 
					    saveInstance: Api.newPost('/instances'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,6 +25,7 @@ import SvgIcon from '@/components/svgIcon/index.vue';
 | 
				
			|||||||
import { getDbDialect, noSchemaTypes } from '@/views/ops/db/dialect';
 | 
					import { getDbDialect, noSchemaTypes } from '@/views/ops/db/dialect';
 | 
				
			||||||
import TagTreeResourceSelect from '../../component/TagTreeResourceSelect.vue';
 | 
					import TagTreeResourceSelect from '../../component/TagTreeResourceSelect.vue';
 | 
				
			||||||
import { computed } from 'vue';
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { DbInst } from '../db';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
    dbId: {
 | 
					    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 params = parentNode.params;
 | 
				
			||||||
    const dbs = params.database.split(' ')?.sort();
 | 
					    const dbs = (await DbInst.getDbNames(params))?.sort();
 | 
				
			||||||
    let fn: NodeType;
 | 
					    let fn: NodeType;
 | 
				
			||||||
    if (noSchemaType(params.type)) {
 | 
					    if (noSchemaType(params.type)) {
 | 
				
			||||||
        fn = MysqlNodeTypes;
 | 
					        fn = MysqlNodeTypes;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
        <el-row class="mb5">
 | 
					        <el-row class="mb5">
 | 
				
			||||||
            <el-popover v-model:visible="state.dumpInfo.visible" trigger="click" :width="470" placement="right">
 | 
					            <el-popover v-model:visible="state.dumpInfo.visible" trigger="click" :width="470" placement="right">
 | 
				
			||||||
                <template #reference>
 | 
					                <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>
 | 
					                </template>
 | 
				
			||||||
                <el-form-item label="导出内容: ">
 | 
					                <el-form-item label="导出内容: ">
 | 
				
			||||||
                    <el-radio-group v-model="dumpInfo.type">
 | 
					                    <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 { registerCompletionItemProvider } from '@/components/monaco/completionItemProvider';
 | 
				
			||||||
import { DbDialect, EditorCompletionItem, getDbDialect } from './dialect';
 | 
					import { DbDialect, EditorCompletionItem, getDbDialect } from './dialect';
 | 
				
			||||||
import { type RemovableRef, useLocalStorage } from '@vueuse/core';
 | 
					import { type RemovableRef, useLocalStorage } from '@vueuse/core';
 | 
				
			||||||
 | 
					import { DbGetDbNamesMode } from './enums';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const hintsStorage: RemovableRef<Map<string, any>> = useLocalStorage('db-table-hints', new Map());
 | 
					const hintsStorage: RemovableRef<Map<string, any>> = useLocalStorage('db-table-hints', new Map());
 | 
				
			||||||
const tableStorage: RemovableRef<Map<string, any>> = useLocalStorage('db-tables', new Map());
 | 
					const tableStorage: RemovableRef<Map<string, any>> = useLocalStorage('db-tables', new Map());
 | 
				
			||||||
@@ -503,6 +504,19 @@ export class DbInst {
 | 
				
			|||||||
            col.columnType = col.dataType;
 | 
					            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';
 | 
					import { EnumValue } from '@/common/Enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const DbGetDbNamesMode = {
 | 
				
			||||||
 | 
					    Auto: EnumValue.of(-1, '实时获取').setTagType('warning'),
 | 
				
			||||||
 | 
					    Assign: EnumValue.of(1, '指定库名').setTagType('primary'),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 数据库sql执行类型
 | 
					// 数据库sql执行类型
 | 
				
			||||||
export const DbSqlExecTypeEnum = {
 | 
					export const DbSqlExecTypeEnum = {
 | 
				
			||||||
    Update: EnumValue.of(1, 'UPDATE').setTagColor('#E4F5EB'),
 | 
					    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"
 | 
					                ref="pageTableRef"
 | 
				
			||||||
                :page-api="cronJobApi.execList"
 | 
					                :page-api="cronJobApi.execList"
 | 
				
			||||||
                :lazy="true"
 | 
					                :lazy="true"
 | 
				
			||||||
                :data-handler-fn="parseData"
 | 
					 | 
				
			||||||
                :search-items="searchItems"
 | 
					                :search-items="searchItems"
 | 
				
			||||||
                v-model:query-form="params"
 | 
					                v-model:query-form="params"
 | 
				
			||||||
                :data="state.data.list"
 | 
					                :data="state.data.list"
 | 
				
			||||||
                :columns="columns"
 | 
					                :columns="columns"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                <template #machineSelect>
 | 
					                <template #machineCode="{ data }">
 | 
				
			||||||
                    <el-select v-model="params.machineId" filterable placeholder="选择机器查询" clearable>
 | 
					                    <MachineDetail :code="data.machineCode" />
 | 
				
			||||||
                        <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>
 | 
					                </template>
 | 
				
			||||||
            </page-table>
 | 
					            </page-table>
 | 
				
			||||||
        </el-dialog>
 | 
					        </el-dialog>
 | 
				
			||||||
@@ -35,11 +28,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { watch, ref, toRefs, reactive, Ref } from 'vue';
 | 
					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 PageTable from '@/components/pagetable/PageTable.vue';
 | 
				
			||||||
import { TableColumn } from '@/components/pagetable';
 | 
					import { TableColumn } from '@/components/pagetable';
 | 
				
			||||||
import { CronJobExecStatusEnum } from '../enums';
 | 
					import { CronJobExecStatusEnum } from '../enums';
 | 
				
			||||||
import { SearchItem } from '@/components/SearchForm';
 | 
					import { SearchItem } from '@/components/SearchForm';
 | 
				
			||||||
 | 
					import MachineDetail from '../component/MachineDetail.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
    visible: {
 | 
					    visible: {
 | 
				
			||||||
@@ -55,11 +49,10 @@ const props = defineProps({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const emit = defineEmits(['update:visible', 'update:data', 'cancel']);
 | 
					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([
 | 
					const columns = ref([
 | 
				
			||||||
    TableColumn.new('machineIp', '机器IP').setMinWidth(120),
 | 
					    TableColumn.new('machineCode', '机器编号').isSlot(),
 | 
				
			||||||
    TableColumn.new('machineName', '机器名称').setMinWidth(100),
 | 
					 | 
				
			||||||
    TableColumn.new('status', '状态').typeTag(CronJobExecStatusEnum).setMinWidth(70),
 | 
					    TableColumn.new('status', '状态').typeTag(CronJobExecStatusEnum).setMinWidth(70),
 | 
				
			||||||
    TableColumn.new('res', '执行结果').setMinWidth(250).canBeautify(),
 | 
					    TableColumn.new('res', '执行结果').setMinWidth(250).canBeautify(),
 | 
				
			||||||
    TableColumn.new('execTime', '执行时间').isTime().setMinWidth(150),
 | 
					    TableColumn.new('execTime', '执行时间').isTime().setMinWidth(150),
 | 
				
			||||||
@@ -75,7 +68,7 @@ const state = reactive({
 | 
				
			|||||||
        pageSize: 10,
 | 
					        pageSize: 10,
 | 
				
			||||||
        cronJobId: 0,
 | 
					        cronJobId: 0,
 | 
				
			||||||
        status: null,
 | 
					        status: null,
 | 
				
			||||||
        machineId: null,
 | 
					        machineCode: '',
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    // 列表数据
 | 
					    // 列表数据
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
@@ -85,8 +78,6 @@ const state = reactive({
 | 
				
			|||||||
    machines: [],
 | 
					    machines: [],
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const machineMap: Map<number, any> = new Map();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const { dialogVisible, params } = toRefs(state);
 | 
					const { dialogVisible, params } = toRefs(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(props, async (newValue: any) => {
 | 
					watch(props, async (newValue: any) => {
 | 
				
			||||||
@@ -95,52 +86,14 @@ watch(props, async (newValue: any) => {
 | 
				
			|||||||
        return;
 | 
					        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;
 | 
					    state.params.cronJobId = props.data?.id;
 | 
				
			||||||
    search();
 | 
					    setTimeout(() => search(), 300);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const search = async () => {
 | 
					const search = async () => {
 | 
				
			||||||
    pageTableRef.value.search();
 | 
					    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 = () => {
 | 
					const cancel = () => {
 | 
				
			||||||
    emit('update:visible', false);
 | 
					    emit('update:visible', false);
 | 
				
			||||||
    setTimeout(() => {
 | 
					    setTimeout(() => {
 | 
				
			||||||
@@ -152,7 +105,7 @@ const initData = () => {
 | 
				
			|||||||
    state.data.list = [];
 | 
					    state.data.list = [];
 | 
				
			||||||
    state.data.total = 0;
 | 
					    state.data.total = 0;
 | 
				
			||||||
    state.params.pageNum = 1;
 | 
					    state.params.pageNum = 1;
 | 
				
			||||||
    state.params.machineId = null;
 | 
					    state.params.machineCode = '';
 | 
				
			||||||
    state.params.status = null;
 | 
					    state.params.status = null;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,14 @@
 | 
				
			|||||||
                <el-button v-auth="'authcert:save'" type="primary" icon="plus" @click="edit(false)">添加</el-button>
 | 
					                <el-button v-auth="'authcert:save'" type="primary" icon="plus" @click="edit(false)">添加</el-button>
 | 
				
			||||||
            </template>
 | 
					            </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 }">
 | 
					            <template #action="{ data }">
 | 
				
			||||||
                <el-button v-auth="'authcert:save'" @click="edit(data)" type="primary" link>编辑</el-button>
 | 
					                <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 { AuthCertCiphertextTypeEnum, AuthCertTypeEnum } from './enums';
 | 
				
			||||||
import { ResourceTypeEnum, TagResourceTypeEnum } from '@/common/commonEnum';
 | 
					import { ResourceTypeEnum, TagResourceTypeEnum } from '@/common/commonEnum';
 | 
				
			||||||
import ResourceAuthCertEdit from '../component/ResourceAuthCertEdit.vue';
 | 
					import ResourceAuthCertEdit from '../component/ResourceAuthCertEdit.vue';
 | 
				
			||||||
 | 
					import EnumValue from '@/common/Enum';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pageTableRef: Ref<any> = ref(null);
 | 
					const pageTableRef: Ref<any> = ref(null);
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
@@ -50,6 +59,7 @@ const state = reactive({
 | 
				
			|||||||
        name: null,
 | 
					        name: null,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    searchItems: [
 | 
					    searchItems: [
 | 
				
			||||||
 | 
					        SearchItem.input('resourceCode', '资源编号'),
 | 
				
			||||||
        SearchItem.input('name', '凭证名称'),
 | 
					        SearchItem.input('name', '凭证名称'),
 | 
				
			||||||
        SearchItem.select('resourceType', '资源类型').withEnum(ResourceTypeEnum),
 | 
					        SearchItem.select('resourceType', '资源类型').withEnum(ResourceTypeEnum),
 | 
				
			||||||
        SearchItem.select('type', '凭证类型').withEnum(AuthCertTypeEnum),
 | 
					        SearchItem.select('type', '凭证类型').withEnum(AuthCertTypeEnum),
 | 
				
			||||||
@@ -60,8 +70,7 @@ const state = reactive({
 | 
				
			|||||||
        TableColumn.new('type', '凭证类型').typeTag(AuthCertTypeEnum),
 | 
					        TableColumn.new('type', '凭证类型').typeTag(AuthCertTypeEnum),
 | 
				
			||||||
        TableColumn.new('username', '用户名'),
 | 
					        TableColumn.new('username', '用户名'),
 | 
				
			||||||
        TableColumn.new('ciphertextType', '密文类型').typeTag(AuthCertCiphertextTypeEnum),
 | 
					        TableColumn.new('ciphertextType', '密文类型').typeTag(AuthCertCiphertextTypeEnum),
 | 
				
			||||||
        TableColumn.new('resourceType', '资源类型').typeTag(TagResourceTypeEnum),
 | 
					        TableColumn.new('resourceCode', '资源编号').isSlot().setAddWidth(30),
 | 
				
			||||||
        TableColumn.new('resourceCode', '资源编号'),
 | 
					 | 
				
			||||||
        TableColumn.new('remark', '备注'),
 | 
					        TableColumn.new('remark', '备注'),
 | 
				
			||||||
        TableColumn.new('creator', '创建人'),
 | 
					        TableColumn.new('creator', '创建人'),
 | 
				
			||||||
        TableColumn.new('createTime', '创建时间').isTime(),
 | 
					        TableColumn.new('createTime', '创建时间').isTime(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -123,9 +123,8 @@ func (a *AccountLogin) RefreshToken(rc *req.Ctx) {
 | 
				
			|||||||
	biz.NotEmpty(refreshToken, "refresh_token不能为空")
 | 
						biz.NotEmpty(refreshToken, "refresh_token不能为空")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	accountId, username, err := req.ParseToken(refreshToken)
 | 
						accountId, username, err := req.ParseToken(refreshToken)
 | 
				
			||||||
	if err != nil {
 | 
						biz.IsTrueBy(err == nil, errorx.PermissionErr)
 | 
				
			||||||
		panic(errorx.PermissionErr)
 | 
					
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	token, refreshToken, err := req.CreateToken(accountId, username)
 | 
						token, refreshToken, err := req.CreateToken(accountId, username)
 | 
				
			||||||
	biz.ErrIsNil(err)
 | 
						biz.ErrIsNil(err)
 | 
				
			||||||
	rc.ResData = collx.Kvs("token", token, "refresh_token", refreshToken)
 | 
						rc.ResData = collx.Kvs("token", token, "refresh_token", refreshToken)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,6 +114,12 @@ func (d *Instance) GetDatabaseNames(rc *req.Ctx) {
 | 
				
			|||||||
	rc.ResData = res
 | 
						rc.ResData = res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (d *Instance) GetDatabaseNamesByAc(rc *req.Ctx) {
 | 
				
			||||||
 | 
						res, err := d.InstanceApp.GetDatabasesByAc(rc.PathParam("ac"))
 | 
				
			||||||
 | 
						biz.ErrIsNil(err)
 | 
				
			||||||
 | 
						rc.ResData = res
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 获取数据库实例server信息
 | 
					// 获取数据库实例server信息
 | 
				
			||||||
func (d *Instance) GetDbServer(rc *req.Ctx) {
 | 
					func (d *Instance) GetDbServer(rc *req.Ctx) {
 | 
				
			||||||
	instanceId := getInstanceId(rc)
 | 
						instanceId := getInstanceId(rc)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,16 @@
 | 
				
			|||||||
package form
 | 
					package form
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "mayfly-go/internal/db/domain/entity"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DbForm struct {
 | 
					type DbForm struct {
 | 
				
			||||||
	Id             uint64 `json:"id"`
 | 
						Id              uint64                   `json:"id"`
 | 
				
			||||||
	Code           string `binding:"required" json:"code"`
 | 
						Code            string                   `binding:"required" json:"code"`
 | 
				
			||||||
	Name           string `binding:"required" json:"name"`
 | 
						Name            string                   `binding:"required" json:"name"`
 | 
				
			||||||
	Database       string `json:"database"`
 | 
						GetDatabaseMode entity.DbGetDatabaseMode `json:"getDatabaseMode"` // 获取数据库方式
 | 
				
			||||||
	Remark         string `json:"remark"`
 | 
						Database        string                   `json:"database"`
 | 
				
			||||||
	InstanceId     uint64 `binding:"required" json:"instanceId"`
 | 
						Remark          string                   `json:"remark"`
 | 
				
			||||||
	AuthCertName   string `json:"authCertName"`
 | 
						InstanceId      uint64                   `binding:"required" json:"instanceId"`
 | 
				
			||||||
	FlowProcdefKey string `json:"flowProcdefKey"`
 | 
						AuthCertName    string                   `json:"authCertName"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DbSqlSaveForm struct {
 | 
					type DbSqlSaveForm struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
package vo
 | 
					package vo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"mayfly-go/internal/db/domain/entity"
 | 
				
			||||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
						tagentity "mayfly-go/internal/tag/domain/entity"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -8,11 +9,12 @@ import (
 | 
				
			|||||||
type DbListVO struct {
 | 
					type DbListVO struct {
 | 
				
			||||||
	tagentity.ResourceTags
 | 
						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"`
 | 
				
			||||||
	Database *string `json:"database"`
 | 
						GetDatabaseMode entity.DbGetDatabaseMode `json:"getDatabaseMode"` // 获取数据库方式
 | 
				
			||||||
	Remark   *string `json:"remark"`
 | 
						Database        *string                  `json:"database"`
 | 
				
			||||||
 | 
						Remark          *string                  `json:"remark"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	InstanceId   *int64  `json:"instanceId"`
 | 
						InstanceId   *int64  `json:"instanceId"`
 | 
				
			||||||
	AuthCertName string  `json:"authCertName"`
 | 
						AuthCertName string  `json:"authCertName"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -194,7 +194,7 @@ func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
 | 
				
			|||||||
		di.Id = db.Id
 | 
							di.Id = db.Id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		checkDb := di.GetDatabase()
 | 
							checkDb := di.GetDatabase()
 | 
				
			||||||
		if !strings.Contains(" "+db.Database+" ", " "+checkDb+" ") {
 | 
							if db.GetDatabaseMode == entity.DbGetDatabaseModeAssign && !strings.Contains(" "+db.Database+" ", " "+checkDb+" ") {
 | 
				
			||||||
			return nil, errorx.NewBiz("未配置数据库【%s】的操作权限", dbName)
 | 
								return nil, errorx.NewBiz("未配置数据库【%s】的操作权限", dbName)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -410,7 +410,7 @@ func (app *dataSyncAppImpl) InitCronJob() {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 修改执行中状态为待执行
 | 
						// 修改执行中状态为待执行
 | 
				
			||||||
	_ = app.UpdateByCond(context.TODO(), &entity.DataSyncTask{RunningState: entity.DataSyncTaskRunStateRunning}, &entity.DataSyncTask{RunningState: entity.DataSyncTaskRunStateReady})
 | 
						_ = app.UpdateByCond(context.TODO(), &entity.DataSyncTask{RunningState: entity.DataSyncTaskRunStateReady}, &entity.DataSyncTask{RunningState: entity.DataSyncTaskRunStateRunning})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 把所有正常任务添加到定时任务中
 | 
						// 把所有正常任务添加到定时任务中
 | 
				
			||||||
	pageParam := &model.PageParam{
 | 
						pageParam := &model.PageParam{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,9 @@ type Instance interface {
 | 
				
			|||||||
	// GetDatabases 获取数据库实例的所有数据库列表
 | 
						// GetDatabases 获取数据库实例的所有数据库列表
 | 
				
			||||||
	GetDatabases(entity *entity.DbInstance, authCert *tagentity.ResourceAuthCert) ([]string, error)
 | 
						GetDatabases(entity *entity.DbInstance, authCert *tagentity.ResourceAuthCert) ([]string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// GetDatabasesByAc 根据授权凭证名获取所有数据库名称列表
 | 
				
			||||||
 | 
						GetDatabasesByAc(acName string) ([]string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ToDbInfo 根据实例与授权凭证返回对应的DbInfo
 | 
						// ToDbInfo 根据实例与授权凭证返回对应的DbInfo
 | 
				
			||||||
	ToDbInfo(instance *entity.DbInstance, authCertName string, database string) (*dbi.DbInfo, error)
 | 
						ToDbInfo(instance *entity.DbInstance, authCertName string, database string) (*dbi.DbInfo, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -53,6 +56,8 @@ type instanceAppImpl struct {
 | 
				
			|||||||
	restoreApp          *DbRestoreApp           `inject:"DbRestoreApp"`
 | 
						restoreApp          *DbRestoreApp           `inject:"DbRestoreApp"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ (Instance) = (*instanceAppImpl)(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 注入DbInstanceRepo
 | 
					// 注入DbInstanceRepo
 | 
				
			||||||
func (app *instanceAppImpl) InjectDbInstanceRepo(repo repository.Instance) {
 | 
					func (app *instanceAppImpl) InjectDbInstanceRepo(repo repository.Instance) {
 | 
				
			||||||
	app.Repo = repo
 | 
						app.Repo = repo
 | 
				
			||||||
@@ -118,7 +123,7 @@ func (app *instanceAppImpl) SaveDbInstance(ctx context.Context, instance *dto.Sa
 | 
				
			|||||||
		return instanceEntity.Id, app.Tx(ctx, func(ctx context.Context) error {
 | 
							return instanceEntity.Id, app.Tx(ctx, func(ctx context.Context) error {
 | 
				
			||||||
			return app.Insert(ctx, instanceEntity)
 | 
								return app.Insert(ctx, instanceEntity)
 | 
				
			||||||
		}, func(ctx context.Context) error {
 | 
							}, func(ctx context.Context) error {
 | 
				
			||||||
			return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
								return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
				ResourceCode: instanceEntity.Code,
 | 
									ResourceCode: instanceEntity.Code,
 | 
				
			||||||
				ResourceType: tagentity.TagType(resourceType),
 | 
									ResourceType: tagentity.TagType(resourceType),
 | 
				
			||||||
				AuthCerts:    authCerts,
 | 
									AuthCerts:    authCerts,
 | 
				
			||||||
@@ -147,7 +152,7 @@ func (app *instanceAppImpl) SaveDbInstance(ctx context.Context, instance *dto.Sa
 | 
				
			|||||||
	return oldInstance.Id, app.Tx(ctx, func(ctx context.Context) error {
 | 
						return oldInstance.Id, app.Tx(ctx, func(ctx context.Context) error {
 | 
				
			||||||
		return app.UpdateById(ctx, instanceEntity)
 | 
							return app.UpdateById(ctx, instanceEntity)
 | 
				
			||||||
	}, func(ctx context.Context) error {
 | 
						}, func(ctx context.Context) error {
 | 
				
			||||||
		return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
							return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
			ResourceCode: oldInstance.Code,
 | 
								ResourceCode: oldInstance.Code,
 | 
				
			||||||
			ResourceType: tagentity.TagType(resourceType),
 | 
								ResourceType: tagentity.TagType(resourceType),
 | 
				
			||||||
			AuthCerts:    authCerts,
 | 
								AuthCerts:    authCerts,
 | 
				
			||||||
@@ -205,7 +210,7 @@ func (app *instanceAppImpl) Delete(ctx context.Context, instanceId uint64) error
 | 
				
			|||||||
		return app.DeleteById(ctx, instanceId)
 | 
							return app.DeleteById(ctx, instanceId)
 | 
				
			||||||
	}, func(ctx context.Context) error {
 | 
						}, func(ctx context.Context) error {
 | 
				
			||||||
		// 删除该实例关联的授权凭证信息
 | 
							// 删除该实例关联的授权凭证信息
 | 
				
			||||||
		return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
							return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
			ResourceCode: instance.Code,
 | 
								ResourceCode: instance.Code,
 | 
				
			||||||
			ResourceType: tagentity.TagType(consts.ResourceTypeDb),
 | 
								ResourceType: tagentity.TagType(consts.ResourceTypeDb),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
@@ -239,16 +244,22 @@ func (app *instanceAppImpl) GetDatabases(ed *entity.DbInstance, authCert *tagent
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ed.Network = ed.GetNetwork()
 | 
						return app.getDatabases(ed, authCert)
 | 
				
			||||||
	dbi := app.toDbInfoByAc(ed, authCert, "")
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dbConn, err := dbm.Conn(dbi)
 | 
					func (app *instanceAppImpl) GetDatabasesByAc(acName string) ([]string, error) {
 | 
				
			||||||
 | 
						ac, err := app.resourceAuthCertApp.GetAuthCert(acName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, errorx.NewBiz("该授权凭证不存在")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer dbConn.Close()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dbConn.GetMetaData().GetDbNames()
 | 
						instance := &entity.DbInstance{Code: ac.ResourceCode}
 | 
				
			||||||
 | 
						err = app.GetByCond(instance)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, errorx.NewBiz("不存在该授权凭证对应的数据库实例信息")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return app.getDatabases(instance, ac)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (app *instanceAppImpl) ToDbInfo(instance *entity.DbInstance, authCertName string, database string) (*dbi.DbInfo, error) {
 | 
					func (app *instanceAppImpl) ToDbInfo(instance *entity.DbInstance, authCertName string, database string) (*dbi.DbInfo, error) {
 | 
				
			||||||
@@ -260,6 +271,19 @@ func (app *instanceAppImpl) ToDbInfo(instance *entity.DbInstance, authCertName s
 | 
				
			|||||||
	return app.toDbInfoByAc(instance, ac, database), nil
 | 
						return app.toDbInfoByAc(instance, ac, database), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (app *instanceAppImpl) getDatabases(instance *entity.DbInstance, ac *tagentity.ResourceAuthCert) ([]string, error) {
 | 
				
			||||||
 | 
						instance.Network = instance.GetNetwork()
 | 
				
			||||||
 | 
						dbi := app.toDbInfoByAc(instance, ac, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbConn, err := dbm.Conn(dbi)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer dbConn.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dbConn.GetMetaData().GetDbNames()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (app *instanceAppImpl) toDbInfoByAc(instance *entity.DbInstance, ac *tagentity.ResourceAuthCert, database string) *dbi.DbInfo {
 | 
					func (app *instanceAppImpl) toDbInfoByAc(instance *entity.DbInstance, ac *tagentity.ResourceAuthCert, database string) *dbi.DbInfo {
 | 
				
			||||||
	di := new(dbi.DbInfo)
 | 
						di := new(dbi.DbInfo)
 | 
				
			||||||
	di.InstanceId = instance.Id
 | 
						di.InstanceId = instance.Id
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,18 @@ import (
 | 
				
			|||||||
type Db struct {
 | 
					type Db struct {
 | 
				
			||||||
	model.Model
 | 
						model.Model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Code         string `orm:"column(code)" json:"code"`
 | 
						Code            string            `orm:"column(code)" json:"code"`
 | 
				
			||||||
	Name         string `orm:"column(name)" json:"name"`
 | 
						Name            string            `orm:"column(name)" json:"name"`
 | 
				
			||||||
	Database     string `orm:"column(database)" json:"database"`
 | 
						GetDatabaseMode DbGetDatabaseMode `json:"getDatabaseMode"` // 获取数据库方式
 | 
				
			||||||
	Remark       string `json:"remark"`
 | 
						Database        string            `orm:"column(database)" json:"database"`
 | 
				
			||||||
	InstanceId   uint64
 | 
						Remark          string            `json:"remark"`
 | 
				
			||||||
	AuthCertName string `json:"authCertName"`
 | 
						InstanceId      uint64
 | 
				
			||||||
 | 
						AuthCertName    string `json:"authCertName"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type DbGetDatabaseMode int8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						DbGetDatabaseModeAuto   DbGetDatabaseMode = -1 // 自动获取(根据凭证获取对应所有库名)
 | 
				
			||||||
 | 
						DbGetDatabaseModeAssign DbGetDatabaseMode = 1  // 指定库名
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ type InstanceQuery struct {
 | 
				
			|||||||
	Name    string `json:"name" form:"name"`
 | 
						Name    string `json:"name" form:"name"`
 | 
				
			||||||
	Code    string `json:"code" form:"code"`
 | 
						Code    string `json:"code" form:"code"`
 | 
				
			||||||
	Host    string `json:"host" form:"host"`
 | 
						Host    string `json:"host" form:"host"`
 | 
				
			||||||
	TagPath string `json:"host" form:"tagPath"`
 | 
						TagPath string `json:"tagPath" form:"tagPath"`
 | 
				
			||||||
	Codes   []string
 | 
						Codes   []string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,9 @@ func InitInstanceRouter(router *gin.RouterGroup) {
 | 
				
			|||||||
		// 获取数据库实例的所有数据库名
 | 
							// 获取数据库实例的所有数据库名
 | 
				
			||||||
		req.NewPost("/databases", d.GetDatabaseNames),
 | 
							req.NewPost("/databases", d.GetDatabaseNames),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 根据授权凭证名获取其所有库名
 | 
				
			||||||
 | 
							req.NewGet("/databases/:ac", d.GetDatabaseNamesByAc),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req.NewGet(":instanceId/server-info", d.GetDbServer),
 | 
							req.NewGet(":instanceId/server-info", d.GetDbServer),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req.NewDelete(":instanceId", d.DeleteInstance).Log(req.NewLogSave("db-删除数据库实例")),
 | 
							req.NewDelete(":instanceId", d.DeleteInstance).Log(req.NewLogSave("db-删除数据库实例")),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,13 +8,14 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/machine/domain/entity"
 | 
						"mayfly-go/internal/machine/domain/entity"
 | 
				
			||||||
	tagapp "mayfly-go/internal/tag/application"
 | 
						tagapp "mayfly-go/internal/tag/application"
 | 
				
			||||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
						tagentity "mayfly-go/internal/tag/domain/entity"
 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
						"mayfly-go/pkg/biz"
 | 
				
			||||||
	"mayfly-go/pkg/req"
 | 
						"mayfly-go/pkg/req"
 | 
				
			||||||
	"mayfly-go/pkg/scheduler"
 | 
						"mayfly-go/pkg/scheduler"
 | 
				
			||||||
	"mayfly-go/pkg/utils/collx"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/may-fly/cast"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineCronJob struct {
 | 
					type MachineCronJob struct {
 | 
				
			||||||
@@ -58,9 +59,7 @@ func (m *MachineCronJob) Delete(rc *req.Ctx) {
 | 
				
			|||||||
	ids := strings.Split(idsStr, ",")
 | 
						ids := strings.Split(idsStr, ",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, v := range ids {
 | 
						for _, v := range ids {
 | 
				
			||||||
		value, err := strconv.Atoi(v)
 | 
							m.MachineCronJobApp.Delete(rc.MetaCtx, cast.ToUint64(v))
 | 
				
			||||||
		biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
 | 
					 | 
				
			||||||
		m.MachineCronJobApp.Delete(rc.MetaCtx, uint64(value))
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,8 +11,9 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/utils/collx"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
	"mayfly-go/pkg/utils/jsonx"
 | 
						"mayfly-go/pkg/utils/jsonx"
 | 
				
			||||||
	"mayfly-go/pkg/utils/stringx"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"strconv"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/may-fly/cast"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineScript struct {
 | 
					type MachineScript struct {
 | 
				
			||||||
@@ -42,9 +43,7 @@ func (m *MachineScript) DeleteMachineScript(rc *req.Ctx) {
 | 
				
			|||||||
	ids := strings.Split(idsStr, ",")
 | 
						ids := strings.Split(idsStr, ",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, v := range ids {
 | 
						for _, v := range ids {
 | 
				
			||||||
		value, err := strconv.Atoi(v)
 | 
							m.MachineScriptApp.Delete(rc.MetaCtx, cast.ToUint64(v))
 | 
				
			||||||
		biz.ErrIsNilAppendErr(err, "string类型转换为int异常: %s")
 | 
					 | 
				
			||||||
		m.MachineScriptApp.Delete(rc.MetaCtx, uint64(value))
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,7 +108,7 @@ func (m *machineAppImpl) SaveMachine(ctx context.Context, param *dto.SaveMachine
 | 
				
			|||||||
		return m.Tx(ctx, func(ctx context.Context) error {
 | 
							return m.Tx(ctx, func(ctx context.Context) error {
 | 
				
			||||||
			return m.Insert(ctx, me)
 | 
								return m.Insert(ctx, me)
 | 
				
			||||||
		}, func(ctx context.Context) error {
 | 
							}, func(ctx context.Context) error {
 | 
				
			||||||
			return m.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
								return m.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
				ResourceCode: me.Code,
 | 
									ResourceCode: me.Code,
 | 
				
			||||||
				ResourceType: resourceType,
 | 
									ResourceType: resourceType,
 | 
				
			||||||
				AuthCerts:    authCerts,
 | 
									AuthCerts:    authCerts,
 | 
				
			||||||
@@ -138,7 +138,7 @@ func (m *machineAppImpl) SaveMachine(ctx context.Context, param *dto.SaveMachine
 | 
				
			|||||||
	return m.Tx(ctx, func(ctx context.Context) error {
 | 
						return m.Tx(ctx, func(ctx context.Context) error {
 | 
				
			||||||
		return m.UpdateById(ctx, me)
 | 
							return m.UpdateById(ctx, me)
 | 
				
			||||||
	}, func(ctx context.Context) error {
 | 
						}, func(ctx context.Context) error {
 | 
				
			||||||
		return m.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
							return m.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
			ResourceCode: oldMachine.Code,
 | 
								ResourceCode: oldMachine.Code,
 | 
				
			||||||
			ResourceType: resourceType,
 | 
								ResourceType: resourceType,
 | 
				
			||||||
			AuthCerts:    authCerts,
 | 
								AuthCerts:    authCerts,
 | 
				
			||||||
@@ -219,7 +219,7 @@ func (m *machineAppImpl) Delete(ctx context.Context, id uint64) error {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}, func(ctx context.Context) error {
 | 
							}, func(ctx context.Context) error {
 | 
				
			||||||
			return m.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
								return m.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
				ResourceCode: machine.Code,
 | 
									ResourceCode: machine.Code,
 | 
				
			||||||
				ResourceType: resourceType,
 | 
									ResourceType: resourceType,
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
@@ -334,6 +334,7 @@ func (m *machineAppImpl) getMachineAndAuthCert(machineId uint64) (*entity.Machin
 | 
				
			|||||||
func (m *machineAppImpl) toMi(me *entity.Machine, authCert *tagentity.ResourceAuthCert) (*mcm.MachineInfo, error) {
 | 
					func (m *machineAppImpl) toMi(me *entity.Machine, authCert *tagentity.ResourceAuthCert) (*mcm.MachineInfo, error) {
 | 
				
			||||||
	mi := new(mcm.MachineInfo)
 | 
						mi := new(mcm.MachineInfo)
 | 
				
			||||||
	mi.Id = me.Id
 | 
						mi.Id = me.Id
 | 
				
			||||||
 | 
						mi.Code = me.Code
 | 
				
			||||||
	mi.Name = me.Name
 | 
						mi.Name = me.Name
 | 
				
			||||||
	mi.Ip = me.Ip
 | 
						mi.Ip = me.Ip
 | 
				
			||||||
	mi.Port = me.Port
 | 
						mi.Port = me.Port
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,13 +8,11 @@ import (
 | 
				
			|||||||
	tagapp "mayfly-go/internal/tag/application"
 | 
						tagapp "mayfly-go/internal/tag/application"
 | 
				
			||||||
	tagentity "mayfly-go/internal/tag/domain/entity"
 | 
						tagentity "mayfly-go/internal/tag/domain/entity"
 | 
				
			||||||
	"mayfly-go/pkg/base"
 | 
						"mayfly-go/pkg/base"
 | 
				
			||||||
	"mayfly-go/pkg/biz"
 | 
					 | 
				
			||||||
	"mayfly-go/pkg/errorx"
 | 
						"mayfly-go/pkg/errorx"
 | 
				
			||||||
	"mayfly-go/pkg/logx"
 | 
						"mayfly-go/pkg/logx"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/rediscli"
 | 
						"mayfly-go/pkg/rediscli"
 | 
				
			||||||
	"mayfly-go/pkg/scheduler"
 | 
						"mayfly-go/pkg/scheduler"
 | 
				
			||||||
	"mayfly-go/pkg/utils/anyx"
 | 
					 | 
				
			||||||
	"mayfly-go/pkg/utils/collx"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
	"mayfly-go/pkg/utils/stringx"
 | 
						"mayfly-go/pkg/utils/stringx"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@@ -178,43 +176,35 @@ func (m *machineCronJobAppImpl) addCronJob(mcj *entity.MachineCronJob) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *machineCronJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineCronJob) {
 | 
					func (m *machineCronJobAppImpl) runCronJob0(mid uint64, cronJob *entity.MachineCronJob) {
 | 
				
			||||||
	defer func() {
 | 
						execRes := &entity.MachineCronJobExec{
 | 
				
			||||||
		if err := recover(); err != nil {
 | 
							CronJobId: cronJob.Id,
 | 
				
			||||||
			res := anyx.ToString(err)
 | 
							ExecTime:  time.Now(),
 | 
				
			||||||
			m.machineCronJobExecRepo.Insert(context.TODO(), &entity.MachineCronJobExec{
 | 
						}
 | 
				
			||||||
				MachineId: mid,
 | 
					 | 
				
			||||||
				CronJobId: cronJob.Id,
 | 
					 | 
				
			||||||
				ExecTime:  time.Now(),
 | 
					 | 
				
			||||||
				Status:    entity.MachineCronJobExecStatusError,
 | 
					 | 
				
			||||||
				Res:       res,
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			logx.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	machineCli, err := m.machineApp.GetCli(uint64(mid))
 | 
						machineCli, err := m.machineApp.GetCli(uint64(mid))
 | 
				
			||||||
	biz.ErrIsNilAppendErr(err, "获取客户端连接失败: %s")
 | 
						res := ""
 | 
				
			||||||
	res, err := machineCli.Run(cronJob.Script)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if res == "" {
 | 
							machine, _ := m.machineApp.GetById(mid)
 | 
				
			||||||
			res = err.Error()
 | 
							execRes.MachineCode = machine.Code
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		logx.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		logx.Debugf("机器:[%d]执行[%s]计划任务成功, 执行结果: %s", mid, cronJob.Name, res)
 | 
							execRes.MachineCode = machineCli.Info.Code
 | 
				
			||||||
 | 
							res, err = machineCli.Run(cronJob.Script)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if res == "" {
 | 
				
			||||||
 | 
									res = err.Error()
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								logx.Errorf("机器:[%d]执行[%s]计划任务失败: %s", mid, cronJob.Name, res)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								logx.Debugf("机器:[%d]执行[%s]计划任务成功, 执行结果: %s", mid, cronJob.Name, res)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						execRes.Res = res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if cronJob.SaveExecResType == entity.SaveExecResTypeNo ||
 | 
						if cronJob.SaveExecResType == entity.SaveExecResTypeNo ||
 | 
				
			||||||
		(cronJob.SaveExecResType == entity.SaveExecResTypeOnError && err == nil) {
 | 
							(cronJob.SaveExecResType == entity.SaveExecResTypeOnError && err == nil) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	execRes := &entity.MachineCronJobExec{
 | 
					 | 
				
			||||||
		MachineId: mid,
 | 
					 | 
				
			||||||
		CronJobId: cronJob.Id,
 | 
					 | 
				
			||||||
		ExecTime:  time.Now(),
 | 
					 | 
				
			||||||
		Res:       res,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		execRes.Status = entity.MachineCronJobExecStatusSuccess
 | 
							execRes.Status = entity.MachineCronJobExecStatusSuccess
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,8 +63,8 @@ func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsCon
 | 
				
			|||||||
		termOpRecord.MachineId = cli.Info.Id
 | 
							termOpRecord.MachineId = cli.Info.Id
 | 
				
			||||||
		termOpRecord.Username = cli.Info.Username
 | 
							termOpRecord.Username = cli.Info.Username
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 回放文件路径为: 基础配置路径/操作日期(202301)/day/hour/randstr.cast
 | 
							// 回放文件路径为: 基础配置路径/机器编号/操作日期(202301)/day/hour/randstr.cast
 | 
				
			||||||
		recRelPath := path.Join(now.Format("200601"), fmt.Sprintf("%d", now.Day()), fmt.Sprintf("%d", now.Hour()))
 | 
							recRelPath := path.Join(cli.Info.Code, now.Format("200601"), fmt.Sprintf("%d", now.Day()), fmt.Sprintf("%d", now.Hour()))
 | 
				
			||||||
		// 文件绝对路径
 | 
							// 文件绝对路径
 | 
				
			||||||
		recAbsPath := path.Join(config.GetMachine().TerminalRecPath, recRelPath)
 | 
							recAbsPath := path.Join(config.GetMachine().TerminalRecPath, recRelPath)
 | 
				
			||||||
		os.MkdirAll(recAbsPath, 0766)
 | 
							os.MkdirAll(recAbsPath, 0766)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,11 +23,11 @@ type MachineCronJob struct {
 | 
				
			|||||||
type MachineCronJobExec struct {
 | 
					type MachineCronJobExec struct {
 | 
				
			||||||
	model.DeletedModel
 | 
						model.DeletedModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CronJobId uint64    `json:"cronJobId" form:"cronJobId"`
 | 
						CronJobId   uint64    `json:"cronJobId" form:"cronJobId"`
 | 
				
			||||||
	MachineId uint64    `json:"machineId" form:"machineId"`
 | 
						MachineCode string    `json:"machineCode" form:"machineCode"`
 | 
				
			||||||
	Status    int       `json:"status" form:"status"` // 执行状态
 | 
						Status      int       `json:"status" form:"status"` // 执行状态
 | 
				
			||||||
	Res       string    `json:"res"`                  // 执行结果
 | 
						Res         string    `json:"res"`                  // 执行结果
 | 
				
			||||||
	ExecTime  time.Time `json:"execTime"`
 | 
						ExecTime    time.Time `json:"execTime"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ package entity
 | 
				
			|||||||
import "time"
 | 
					import "time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type MachineQuery struct {
 | 
					type MachineQuery struct {
 | 
				
			||||||
	Ids      string `json:"ids" form:"ids"`
 | 
						Id       uint64 `json:"id" form:"id"`
 | 
				
			||||||
	Code     string `json:"code" form:"code"`
 | 
						Code     string `json:"code" form:"code"`
 | 
				
			||||||
	Name     string `json:"name" form:"name"`
 | 
						Name     string `json:"name" form:"name"`
 | 
				
			||||||
	Status   int8   `json:"status" form:"status"`
 | 
						Status   int8   `json:"status" form:"status"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,6 @@ import (
 | 
				
			|||||||
	"mayfly-go/internal/machine/domain/repository"
 | 
						"mayfly-go/internal/machine/domain/repository"
 | 
				
			||||||
	"mayfly-go/pkg/base"
 | 
						"mayfly-go/pkg/base"
 | 
				
			||||||
	"mayfly-go/pkg/model"
 | 
						"mayfly-go/pkg/model"
 | 
				
			||||||
	"mayfly-go/pkg/utils/collx"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/may-fly/cast"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type machineRepoImpl struct {
 | 
					type machineRepoImpl struct {
 | 
				
			||||||
@@ -22,6 +18,7 @@ func newMachineRepo() repository.Machine {
 | 
				
			|||||||
// 分页获取机器信息列表
 | 
					// 分页获取机器信息列表
 | 
				
			||||||
func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
 | 
					func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
 | 
				
			||||||
	qd := model.NewCond().
 | 
						qd := model.NewCond().
 | 
				
			||||||
 | 
							Eq("id", condition.Id).
 | 
				
			||||||
		Eq("status", condition.Status).
 | 
							Eq("status", condition.Status).
 | 
				
			||||||
		Like("ip", condition.Ip).
 | 
							Like("ip", condition.Ip).
 | 
				
			||||||
		Like("name", condition.Name).
 | 
							Like("name", condition.Name).
 | 
				
			||||||
@@ -29,11 +26,5 @@ func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pagePar
 | 
				
			|||||||
		Like("code", condition.Code).
 | 
							Like("code", condition.Code).
 | 
				
			||||||
		Eq("protocol", condition.Protocol)
 | 
							Eq("protocol", condition.Protocol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if condition.Ids != "" {
 | 
					 | 
				
			||||||
		qd.In("id", collx.ArrayMap[string, uint64](strings.Split(condition.Ids, ","), func(val string) uint64 {
 | 
					 | 
				
			||||||
			return cast.ToUint64(val)
 | 
					 | 
				
			||||||
		}))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m.PageByCondToAny(qd, pageParam, toEntity)
 | 
						return m.PageByCondToAny(qd, pageParam, toEntity)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import (
 | 
				
			|||||||
	"golang.org/x/crypto/ssh"
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 机器客户端
 | 
					// Cli 机器客户端
 | 
				
			||||||
type Cli struct {
 | 
					type Cli struct {
 | 
				
			||||||
	Info *MachineInfo // 机器信息
 | 
						Info *MachineInfo // 机器信息
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,7 +17,7 @@ type Cli struct {
 | 
				
			|||||||
	sftpClient *sftp.Client // sftp客户端
 | 
						sftpClient *sftp.Client // sftp客户端
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 获取sftp client
 | 
					// GetSftpCli 获取sftp client
 | 
				
			||||||
func (c *Cli) GetSftpCli() (*sftp.Client, error) {
 | 
					func (c *Cli) GetSftpCli() (*sftp.Client, error) {
 | 
				
			||||||
	if c.sshClient == nil {
 | 
						if c.sshClient == nil {
 | 
				
			||||||
		return nil, errorx.NewBiz("请先进行机器客户端连接")
 | 
							return nil, errorx.NewBiz("请先进行机器客户端连接")
 | 
				
			||||||
@@ -36,7 +36,7 @@ func (c *Cli) GetSftpCli() (*sftp.Client, error) {
 | 
				
			|||||||
	return sftpclient, nil
 | 
						return sftpclient, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 获取session
 | 
					// GetSession 获取session
 | 
				
			||||||
func (c *Cli) GetSession() (*ssh.Session, error) {
 | 
					func (c *Cli) GetSession() (*ssh.Session, error) {
 | 
				
			||||||
	if c.sshClient == nil {
 | 
						if c.sshClient == nil {
 | 
				
			||||||
		return nil, errorx.NewBiz("请先进行机器客户端连接")
 | 
							return nil, errorx.NewBiz("请先进行机器客户端连接")
 | 
				
			||||||
@@ -49,7 +49,7 @@ func (c *Cli) GetSession() (*ssh.Session, error) {
 | 
				
			|||||||
	return session, nil
 | 
						return session, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 执行shell
 | 
					// Run 执行shell
 | 
				
			||||||
// @param shell shell脚本命令
 | 
					// @param shell shell脚本命令
 | 
				
			||||||
// @return 返回执行成功或错误的消息
 | 
					// @return 返回执行成功或错误的消息
 | 
				
			||||||
func (c *Cli) Run(shell string) (string, error) {
 | 
					func (c *Cli) Run(shell string) (string, error) {
 | 
				
			||||||
@@ -58,14 +58,15 @@ func (c *Cli) Run(shell string) (string, error) {
 | 
				
			|||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer session.Close()
 | 
						defer session.Close()
 | 
				
			||||||
	buf, err := session.CombinedOutput(shell)
 | 
						// 将可能存在的windows换行符替换为linux格式
 | 
				
			||||||
 | 
						buf, err := session.CombinedOutput(strings.ReplaceAll(shell, "\r\n", "\n"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return string(buf), err
 | 
							return string(buf), err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return string(buf), nil
 | 
						return string(buf), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 获取机器的所有状态信息
 | 
					// GetAllStats 获取机器的所有状态信息
 | 
				
			||||||
func (c *Cli) GetAllStats() *Stats {
 | 
					func (c *Cli) GetAllStats() *Stats {
 | 
				
			||||||
	stats := new(Stats)
 | 
						stats := new(Stats)
 | 
				
			||||||
	res, err := c.Run(StatsShell)
 | 
						res, err := c.Run(StatsShell)
 | 
				
			||||||
@@ -89,7 +90,7 @@ func (c *Cli) GetAllStats() *Stats {
 | 
				
			|||||||
	return stats
 | 
						return stats
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 关闭client并从缓存中移除,如果使用隧道则也关闭
 | 
					// Close 关闭client并从缓存中移除,如果使用隧道则也关闭
 | 
				
			||||||
func (c *Cli) Close() {
 | 
					func (c *Cli) Close() {
 | 
				
			||||||
	m := c.Info
 | 
						m := c.Info
 | 
				
			||||||
	logx.Debugf("close machine cli -> id=%d, name=%s, ip=%s", m.Id, m.Name, m.Ip)
 | 
						logx.Debugf("close machine cli -> id=%d, name=%s, ip=%s", m.Id, m.Name, m.Ip)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ import (
 | 
				
			|||||||
type MachineInfo struct {
 | 
					type MachineInfo struct {
 | 
				
			||||||
	Key      string `json:"key"` // 缓存key
 | 
						Key      string `json:"key"` // 缓存key
 | 
				
			||||||
	Id       uint64 `json:"id"`
 | 
						Id       uint64 `json:"id"`
 | 
				
			||||||
 | 
						Code     string `json:"code"`
 | 
				
			||||||
	Name     string `json:"name"`
 | 
						Name     string `json:"name"`
 | 
				
			||||||
	Protocol int    `json:"protocol"`
 | 
						Protocol int    `json:"protocol"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,7 +128,7 @@ func (r *redisAppImpl) SaveRedis(ctx context.Context, param *dto.SaveRedis) erro
 | 
				
			|||||||
				ParentTagCodePaths: tagCodePaths,
 | 
									ParentTagCodePaths: tagCodePaths,
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}, func(ctx context.Context) error {
 | 
							}, func(ctx context.Context) error {
 | 
				
			||||||
			return r.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
								return r.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
				ResourceCode: re.Code,
 | 
									ResourceCode: re.Code,
 | 
				
			||||||
				ResourceType: tagentity.TagTypeRedis,
 | 
									ResourceType: tagentity.TagTypeRedis,
 | 
				
			||||||
				AuthCerts:    []*tagentity.ResourceAuthCert{param.AuthCert},
 | 
									AuthCerts:    []*tagentity.ResourceAuthCert{param.AuthCert},
 | 
				
			||||||
@@ -170,7 +170,7 @@ func (r *redisAppImpl) SaveRedis(ctx context.Context, param *dto.SaveRedis) erro
 | 
				
			|||||||
			ParentTagCodePaths: tagCodePaths,
 | 
								ParentTagCodePaths: tagCodePaths,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}, func(ctx context.Context) error {
 | 
						}, func(ctx context.Context) error {
 | 
				
			||||||
		return r.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
							return r.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
			ResourceCode: oldRedis.Code,
 | 
								ResourceCode: oldRedis.Code,
 | 
				
			||||||
			ResourceType: tagentity.TagTypeRedis,
 | 
								ResourceType: tagentity.TagTypeRedis,
 | 
				
			||||||
			AuthCerts:    []*tagentity.ResourceAuthCert{param.AuthCert},
 | 
								AuthCerts:    []*tagentity.ResourceAuthCert{param.AuthCert},
 | 
				
			||||||
@@ -200,7 +200,7 @@ func (r *redisAppImpl) Delete(ctx context.Context, id uint64) error {
 | 
				
			|||||||
			},
 | 
								},
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}, func(ctx context.Context) error {
 | 
						}, func(ctx context.Context) error {
 | 
				
			||||||
		return r.resourceAuthCertApp.RelateAuthCert(ctx, &tagapp.RelateAuthCertParam{
 | 
							return r.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
 | 
				
			||||||
			ResourceCode: re.Code,
 | 
								ResourceCode: re.Code,
 | 
				
			||||||
			ResourceType: tagentity.TagTypeRedis,
 | 
								ResourceType: tagentity.TagTypeRedis,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,6 @@ package vo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"mayfly-go/internal/tag/application/dto"
 | 
						"mayfly-go/internal/tag/application/dto"
 | 
				
			||||||
	"mayfly-go/pkg/utils/collx"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TagTreeVOS []*dto.SimpleTagTree
 | 
					type TagTreeVOS []*dto.SimpleTagTree
 | 
				
			||||||
@@ -18,14 +17,21 @@ func (m *TagTreeVOS) ToTrees(pid uint64) []*TagTreeItem {
 | 
				
			|||||||
		return ttis
 | 
							return ttis
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ttis = collx.ArrayMap(*m, func(tr *dto.SimpleTagTree) *TagTreeItem { return &TagTreeItem{SimpleTagTree: tr} })
 | 
						tagMap := make(map[string]*TagTreeItem)
 | 
				
			||||||
	tagMap := collx.ArrayToMap(ttis, func(item *TagTreeItem) string {
 | 
						var roots []*TagTreeItem
 | 
				
			||||||
		return item.CodePath
 | 
						for _, tag := range *m {
 | 
				
			||||||
	})
 | 
							tti := &TagTreeItem{SimpleTagTree: tag}
 | 
				
			||||||
 | 
							tagMap[tag.CodePath] = tti
 | 
				
			||||||
 | 
							ttis = append(ttis, tti)
 | 
				
			||||||
 | 
							if tti.IsRoot() {
 | 
				
			||||||
 | 
								roots = append(roots, tti)
 | 
				
			||||||
 | 
								tti.Root = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, node := range ttis {
 | 
						for _, node := range ttis {
 | 
				
			||||||
		// 根节点
 | 
							// 根节点
 | 
				
			||||||
		if node.IsRoot() {
 | 
							if node.Root {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		parentCodePath := node.GetParentPath(0)
 | 
							parentCodePath := node.GetParentPath(0)
 | 
				
			||||||
@@ -35,5 +41,5 @@ func (m *TagTreeVOS) ToTrees(pid uint64) []*TagTreeItem {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return collx.ArrayFilter(ttis, func(tti *TagTreeItem) bool { return tti.IsRoot() })
 | 
						return roots
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								server/internal/tag/application/dto/auth_cert.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								server/internal/tag/application/dto/auth_cert.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package dto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "mayfly-go/internal/tag/domain/entity"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type RelateAuthCert struct {
 | 
				
			||||||
 | 
						ResourceCode string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 资源标签类型
 | 
				
			||||||
 | 
						ResourceType entity.TagType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 空数组则为删除该资源绑定的授权凭证
 | 
				
			||||||
 | 
						AuthCerts []*entity.ResourceAuthCert
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -43,6 +43,7 @@ type SimpleTagTree struct {
 | 
				
			|||||||
	CodePath string         `json:"codePath"` // 标识路径,tag1/tag2/tagType1|tagCode/tagType2|yyycode/,非普通标签类型段含有标签类型
 | 
						CodePath string         `json:"codePath"` // 标识路径,tag1/tag2/tagType1|tagCode/tagType2|yyycode/,非普通标签类型段含有标签类型
 | 
				
			||||||
	Name     string         `json:"name"`     // 名称
 | 
						Name     string         `json:"name"`     // 名称
 | 
				
			||||||
	Remark   string         `json:"remark"`
 | 
						Remark   string         `json:"remark"`
 | 
				
			||||||
 | 
						Root     bool           `json:"-" gorm:"-"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (pt *SimpleTagTree) IsRoot() bool {
 | 
					func (pt *SimpleTagTree) IsRoot() bool {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,21 +12,11 @@ import (
 | 
				
			|||||||
	"mayfly-go/pkg/utils/collx"
 | 
						"mayfly-go/pkg/utils/collx"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RelateAuthCertParam struct {
 | 
					 | 
				
			||||||
	ResourceCode string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 资源标签类型
 | 
					 | 
				
			||||||
	ResourceType entity.TagType
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 空数组则为删除该资源绑定的授权凭证
 | 
					 | 
				
			||||||
	AuthCerts []*entity.ResourceAuthCert
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type ResourceAuthCert interface {
 | 
					type ResourceAuthCert interface {
 | 
				
			||||||
	base.App[*entity.ResourceAuthCert]
 | 
						base.App[*entity.ResourceAuthCert]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// RelateAuthCert 关联资源授权凭证信息
 | 
						// RelateAuthCert 关联资源授权凭证信息
 | 
				
			||||||
	RelateAuthCert(ctx context.Context, param *RelateAuthCertParam) error
 | 
						RelateAuthCert(ctx context.Context, param *dto.RelateAuthCert) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// SaveAuthCert 保存授权凭证信息
 | 
						// SaveAuthCert 保存授权凭证信息
 | 
				
			||||||
	SaveAuthCert(ctx context.Context, rac *entity.ResourceAuthCert) error
 | 
						SaveAuthCert(ctx context.Context, rac *entity.ResourceAuthCert) error
 | 
				
			||||||
@@ -64,7 +54,7 @@ func (r *resourceAuthCertAppImpl) InjectResourceAuthCertRepo(resourceAuthCertRep
 | 
				
			|||||||
	r.Repo = resourceAuthCertRepo
 | 
						r.Repo = resourceAuthCertRepo
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *resourceAuthCertAppImpl) RelateAuthCert(ctx context.Context, params *RelateAuthCertParam) error {
 | 
					func (r *resourceAuthCertAppImpl) RelateAuthCert(ctx context.Context, params *dto.RelateAuthCert) error {
 | 
				
			||||||
	resourceCode := params.ResourceCode
 | 
						resourceCode := params.ResourceCode
 | 
				
			||||||
	resourceType := int8(params.ResourceType)
 | 
						resourceType := int8(params.ResourceType)
 | 
				
			||||||
	resourceAuthCerts := params.AuthCerts
 | 
						resourceAuthCerts := params.AuthCerts
 | 
				
			||||||
@@ -92,11 +82,6 @@ func (r *resourceAuthCertAppImpl) RelateAuthCert(ctx context.Context, params *Re
 | 
				
			|||||||
		resourceAuthCert.ResourceType = int8(resourceType)
 | 
							resourceAuthCert.ResourceType = int8(resourceType)
 | 
				
			||||||
		name2AuthCert[resourceAuthCert.Name] = resourceAuthCert
 | 
							name2AuthCert[resourceAuthCert.Name] = resourceAuthCert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		existNameAc := &entity.ResourceAuthCert{Name: resourceAuthCert.Name}
 | 
					 | 
				
			||||||
		if resourceAuthCert.Id == 0 && r.GetByCond(existNameAc) == nil && existNameAc.ResourceCode != resourceCode {
 | 
					 | 
				
			||||||
			return errorx.NewBiz("授权凭证的名称不能重复[%s]", resourceAuthCert.Name)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// 公共授权凭证,则无需进行密文加密,密文即为公共授权凭证名
 | 
							// 公共授权凭证,则无需进行密文加密,密文即为公共授权凭证名
 | 
				
			||||||
		if resourceAuthCert.CiphertextType == entity.AuthCertCiphertextTypePublic {
 | 
							if resourceAuthCert.CiphertextType == entity.AuthCertCiphertextTypePublic {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
@@ -111,63 +96,66 @@ func (r *resourceAuthCertAppImpl) RelateAuthCert(ctx context.Context, params *Re
 | 
				
			|||||||
	oldAuthCert, _ := r.ListByCond(&entity.ResourceAuthCert{ResourceCode: resourceCode, ResourceType: resourceType})
 | 
						oldAuthCert, _ := r.ListByCond(&entity.ResourceAuthCert{ResourceCode: resourceCode, ResourceType: resourceType})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 新增、删除以及不变的授权凭证名
 | 
						// 新增、删除以及不变的授权凭证名
 | 
				
			||||||
	var adds, dels, unmodifys []string
 | 
						var addAcNames, delAcNames, unmodifyAcNames []string
 | 
				
			||||||
	if len(oldAuthCert) == 0 {
 | 
						if len(oldAuthCert) == 0 {
 | 
				
			||||||
		logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-不存在已有的授权凭证信息, 为新增资源授权凭证", resourceType, resourceCode)
 | 
							logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-不存在已有的授权凭证信息, 为新增资源授权凭证", resourceType, resourceCode)
 | 
				
			||||||
		adds = collx.MapKeys(name2AuthCert)
 | 
							addAcNames = collx.MapKeys(name2AuthCert)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		oldNames := collx.ArrayMap(oldAuthCert, func(ac *entity.ResourceAuthCert) string {
 | 
							oldNames := collx.ArrayMap(oldAuthCert, func(ac *entity.ResourceAuthCert) string {
 | 
				
			||||||
			return ac.Name
 | 
								return ac.Name
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		adds, dels, unmodifys = collx.ArrayCompare[string](collx.MapKeys(name2AuthCert), oldNames)
 | 
							addAcNames, delAcNames, unmodifyAcNames = collx.ArrayCompare[string](collx.MapKeys(name2AuthCert), oldNames)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addAuthCerts := make([]*entity.ResourceAuthCert, 0)
 | 
						addAuthCerts := make([]*entity.ResourceAuthCert, 0)
 | 
				
			||||||
	for _, add := range adds {
 | 
						for _, addAcName := range addAcNames {
 | 
				
			||||||
		addAc := name2AuthCert[add]
 | 
							addAc := name2AuthCert[addAcName]
 | 
				
			||||||
		addAc.Id = 0
 | 
							addAc.Id = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							existNameAc := &entity.ResourceAuthCert{Name: addAcName}
 | 
				
			||||||
 | 
							if r.GetByCond(existNameAc) == nil && existNameAc.ResourceCode != resourceCode {
 | 
				
			||||||
 | 
								return errorx.NewBiz("授权凭证的名称不能重复[%s]", addAcName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		addAuthCerts = append(addAuthCerts, addAc)
 | 
							addAuthCerts = append(addAuthCerts, addAc)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 处理新增的授权凭证
 | 
						// 处理新增的授权凭证
 | 
				
			||||||
	if len(addAuthCerts) > 0 {
 | 
						if len(addAuthCerts) > 0 {
 | 
				
			||||||
		logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-新增授权凭证-[%v]", resourceType, resourceCode, adds)
 | 
							logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-新增授权凭证-[%v]", resourceType, resourceCode, addAcNames)
 | 
				
			||||||
		if err := r.BatchInsert(ctx, addAuthCerts); err != nil {
 | 
							if err := r.BatchInsert(ctx, addAuthCerts); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, del := range dels {
 | 
						for _, delAcName := range delAcNames {
 | 
				
			||||||
		logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-删除授权凭证-[%v]", resourceType, resourceCode, del)
 | 
							logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-删除授权凭证-[%v]", resourceType, resourceCode, delAcName)
 | 
				
			||||||
		if err := r.DeleteByCond(ctx, &entity.ResourceAuthCert{ResourceCode: resourceCode, ResourceType: resourceType, Name: del}); err != nil {
 | 
							if err := r.DeleteByCond(ctx, &entity.ResourceAuthCert{ResourceCode: resourceCode, ResourceType: resourceType, Name: delAcName}); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(unmodifys) > 0 {
 | 
						if len(unmodifyAcNames) > 0 {
 | 
				
			||||||
		// 旧凭证名 -> 旧凭证
 | 
							// 旧凭证名 -> 旧凭证
 | 
				
			||||||
		oldName2AuthCert := collx.ArrayToMap(oldAuthCert, func(ac *entity.ResourceAuthCert) string {
 | 
							oldName2AuthCert := collx.ArrayToMap(oldAuthCert, func(ac *entity.ResourceAuthCert) string {
 | 
				
			||||||
			return ac.Name
 | 
								return ac.Name
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		acTagType := GetResourceAuthCertTagType(params.ResourceType)
 | 
							acTagType := GetResourceAuthCertTagType(params.ResourceType)
 | 
				
			||||||
		for _, unmodify := range unmodifys {
 | 
							for _, unmodifyAcName := range unmodifyAcNames {
 | 
				
			||||||
			unmodifyAc := name2AuthCert[unmodify]
 | 
								unmodifyAc := name2AuthCert[unmodifyAcName]
 | 
				
			||||||
			if unmodifyAc.Id == 0 {
 | 
					 | 
				
			||||||
				continue
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			oldAuthCert := oldName2AuthCert[unmodify]
 | 
								oldAuthCert := oldName2AuthCert[unmodifyAcName]
 | 
				
			||||||
			if !unmodifyAc.HasChanged(oldAuthCert) {
 | 
								if !unmodifyAc.HasChanged(oldAuthCert) {
 | 
				
			||||||
				logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-授权凭证[%s]未发生字段变更", resourceType, resourceCode, unmodify)
 | 
									logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-授权凭证[%s]未发生字段变更", resourceType, resourceCode, unmodifyAcName)
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// 如果修改了用户名,且该凭证关联至标签,则需要更新对应的标签名(资源授权凭证类型的标签名为username)
 | 
								// 如果修改了用户名,且该凭证关联至标签,则需要更新对应的标签名(资源授权凭证类型的标签名为username)
 | 
				
			||||||
			if oldAuthCert.Username != unmodifyAc.Username && acTagType != 0 {
 | 
								if oldAuthCert.Username != unmodifyAc.Username && acTagType != 0 {
 | 
				
			||||||
				r.tagTreeApp.UpdateTagName(ctx, acTagType, unmodify, unmodifyAc.Username)
 | 
									r.tagTreeApp.UpdateTagName(ctx, acTagType, unmodifyAcName, unmodifyAc.Username)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-更新授权凭证-[%v]", resourceType, resourceCode, unmodify)
 | 
								logx.DebugfContext(ctx, "RelateAuthCert[%d-%s]-更新授权凭证-[%v]", resourceType, resourceCode, unmodifyAcName)
 | 
				
			||||||
			if err := r.UpdateById(ctx, unmodifyAc); err != nil {
 | 
								if err := r.UpdateByCond(ctx, unmodifyAc, &entity.ResourceAuthCert{Name: unmodifyAcName, ResourceCode: resourceCode, ResourceType: resourceType}); err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,7 +103,7 @@ func (m *ResourceAuthCert) HasChanged(rac *ResourceAuthCert) bool {
 | 
				
			|||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return m.Username != rac.Username ||
 | 
						return m.Username != rac.Username ||
 | 
				
			||||||
		m.Ciphertext != rac.Ciphertext ||
 | 
							(m.Ciphertext != "" && rac.Ciphertext != "" && m.Ciphertext != rac.Ciphertext) ||
 | 
				
			||||||
		m.CiphertextType != rac.CiphertextType ||
 | 
							m.CiphertextType != rac.CiphertextType ||
 | 
				
			||||||
		m.Remark != rac.Remark ||
 | 
							m.Remark != rac.Remark ||
 | 
				
			||||||
		m.Type != rac.Type ||
 | 
							m.Type != rac.Type ||
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import "fmt"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	AppName = "mayfly-go"
 | 
						AppName = "mayfly-go"
 | 
				
			||||||
	Version = "v1.8.4"
 | 
						Version = "v1.8.5"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func GetAppInfo() string {
 | 
					func GetAppInfo() string {
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							@@ -36,6 +36,7 @@ CREATE TABLE `t_db` (
 | 
				
			|||||||
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
 | 
					  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
  `code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `name` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
 | 
					  `get_database_mode` tinyint NULL COMMENT '库名获取方式(-1.实时获取、1.指定库名)',
 | 
				
			||||||
  `database` varchar(1000) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `database` varchar(1000) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `remark` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
					  `remark` varchar(191) COLLATE utf8mb4_bin DEFAULT NULL,
 | 
				
			||||||
  `instance_id` bigint unsigned NOT NULL,
 | 
					  `instance_id` bigint unsigned NOT NULL,
 | 
				
			||||||
@@ -464,9 +465,9 @@ DROP TABLE IF EXISTS `t_machine_cron_job_exec`;
 | 
				
			|||||||
CREATE TABLE `t_machine_cron_job_exec` (
 | 
					CREATE TABLE `t_machine_cron_job_exec` (
 | 
				
			||||||
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
 | 
					  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
  `cron_job_id` bigint DEFAULT NULL,
 | 
					  `cron_job_id` bigint DEFAULT NULL,
 | 
				
			||||||
  `machine_id` bigint DEFAULT NULL,
 | 
					  `machine_code` varchar(36) DEFAULT NULL,
 | 
				
			||||||
  `status` tinyint DEFAULT NULL COMMENT '状态',
 | 
					  `status` tinyint DEFAULT NULL COMMENT '状态',
 | 
				
			||||||
  `res` varchar(1000) DEFAULT NULL COMMENT '执行结果',
 | 
					  `res` varchar(4000) DEFAULT NULL COMMENT '执行结果',
 | 
				
			||||||
  `exec_time` datetime DEFAULT NULL COMMENT '执行时间',
 | 
					  `exec_time` datetime DEFAULT NULL COMMENT '执行时间',
 | 
				
			||||||
  `is_deleted` tinyint NOT NULL DEFAULT 0,
 | 
					  `is_deleted` tinyint NOT NULL DEFAULT 0,
 | 
				
			||||||
  `delete_time` datetime DEFAULT NULL,
 | 
					  `delete_time` datetime DEFAULT NULL,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								server/resources/script/sql/v1.8/v1.8.5.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								server/resources/script/sql/v1.8/v1.8.5.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					ALTER TABLE t_db ADD get_database_mode tinyint NULL COMMENT '库名获取方式(-1.实时获取、1.指定库名)';
 | 
				
			||||||
 | 
					UPDATE t_db SET get_database_mode = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE t_machine_cron_job_exec ADD machine_code varchar(36) NULL COMMENT '机器编号';
 | 
				
			||||||
 | 
					ALTER TABLE t_machine_cron_job_exec DROP COLUMN machine_id;
 | 
				
			||||||
		Reference in New Issue
	
	Block a user