mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 16:30:25 +08:00 
			
		
		
		
	!99 feat: DBMS新增kingbaseES、vastbase,还有一些优化
* refactor: 重构机器列表展示 * fix:修复编辑表问题 * refactor: 优化下拉实例显示 * feat: DBMS新增kingbaseES(已测试postgres、oracle兼容模式) 、vastbase
This commit is contained in:
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -88,6 +88,20 @@
 | 
				
			|||||||
      "font_class": "gauss",
 | 
					      "font_class": "gauss",
 | 
				
			||||||
      "unicode": "e683",
 | 
					      "unicode": "e683",
 | 
				
			||||||
      "unicode_decimal": 59011
 | 
					      "unicode_decimal": 59011
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "icon_id": "34836637",
 | 
				
			||||||
 | 
					      "name": "kingbase",
 | 
				
			||||||
 | 
					      "font_class": "kingbase",
 | 
				
			||||||
 | 
					      "unicode": "e882",
 | 
				
			||||||
 | 
					      "unicode_decimal": 59522
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "icon_id": "33047500",
 | 
				
			||||||
 | 
					      "name": "vastbase",
 | 
				
			||||||
 | 
					      "font_class": "vastbase",
 | 
				
			||||||
 | 
					      "unicode": "e62b",
 | 
				
			||||||
 | 
					      "unicode_decimal": 58923
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,7 +189,7 @@ const emit = defineEmits(['update:queryForm', 'update:selectionData', 'pageChang
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export interface PageTableProps {
 | 
					export interface PageTableProps {
 | 
				
			||||||
    size?: string;
 | 
					    size?: string;
 | 
				
			||||||
    pageApi: Api; // 请求表格数据的 api
 | 
					    pageApi?: Api; // 请求表格数据的 api
 | 
				
			||||||
    columns: TableColumn[]; // 列配置项  ==> 必传
 | 
					    columns: TableColumn[]; // 列配置项  ==> 必传
 | 
				
			||||||
    showSelection?: boolean;
 | 
					    showSelection?: boolean;
 | 
				
			||||||
    selectable?: (row: any) => boolean; // 是否可选
 | 
					    selectable?: (row: any) => boolean; // 是否可选
 | 
				
			||||||
@@ -257,7 +257,7 @@ const changeSimpleFormItem = (searchItem: SearchItem) => {
 | 
				
			|||||||
    nowSearchItem.value = searchItem;
 | 
					    nowSearchItem.value = searchItem;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const { tableData, total, loading, search, reset, getTableData, handlePageNumChange, handlePageSizeChange } = usePageTable(
 | 
					let { tableData, total, loading, search, reset, getTableData, handlePageNumChange, handlePageSizeChange } = usePageTable(
 | 
				
			||||||
    props.pageable,
 | 
					    props.pageable,
 | 
				
			||||||
    props.pageApi,
 | 
					    props.pageApi,
 | 
				
			||||||
    queryForm,
 | 
					    queryForm,
 | 
				
			||||||
@@ -288,6 +288,13 @@ watch(isShowSearch, () => {
 | 
				
			|||||||
    calcuTableHeight();
 | 
					    calcuTableHeight();
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					watch(
 | 
				
			||||||
 | 
					    () => props.data,
 | 
				
			||||||
 | 
					    (newValue: any) => {
 | 
				
			||||||
 | 
					        tableData = newValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(async () => {
 | 
					onMounted(async () => {
 | 
				
			||||||
    calcuTableHeight();
 | 
					    calcuTableHeight();
 | 
				
			||||||
    useEventListener(window, 'resize', calcuTableHeight);
 | 
					    useEventListener(window, 'resize', calcuTableHeight);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,7 +104,11 @@ const loadTags = async () => {
 | 
				
			|||||||
    const tags = await tagApi.getResourceTagPaths.request({ resourceType: props.resourceType });
 | 
					    const tags = await tagApi.getResourceTagPaths.request({ resourceType: props.resourceType });
 | 
				
			||||||
    const tagNodes = [];
 | 
					    const tagNodes = [];
 | 
				
			||||||
    for (let tagPath of tags) {
 | 
					    for (let tagPath of tags) {
 | 
				
			||||||
        tagNodes.push(new TagTreeNode(tagPath, tagPath, props.tagPathNodeType));
 | 
					        let isLeaf = false;
 | 
				
			||||||
 | 
					        if (!props.tagPathNodeType?.hasLoadNodesFunc) {
 | 
				
			||||||
 | 
					            isLeaf = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tagNodes.push(new TagTreeNode(tagPath, tagPath, props.tagPathNodeType).withIsLeaf(isLeaf));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return tagNodes;
 | 
					    return tagNodes;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,9 @@
 | 
				
			|||||||
        v-model="modelValue"
 | 
					        v-model="modelValue"
 | 
				
			||||||
        @change="changeNode"
 | 
					        @change="changeNode"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
 | 
					        <template #prefix="{ node, data }">
 | 
				
			||||||
 | 
					            <slot name="iconPrefix" :node="node" :data="data" />
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
        <template #default="{ node, data }">
 | 
					        <template #default="{ node, data }">
 | 
				
			||||||
            <span>
 | 
					            <span>
 | 
				
			||||||
                <span v-if="data.type.value == TagTreeNode.TagPath">
 | 
					                <span v-if="data.type.value == TagTreeNode.TagPath">
 | 
				
			||||||
@@ -33,7 +36,7 @@
 | 
				
			|||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { onMounted, reactive, ref, watch, toRefs } from 'vue';
 | 
					import { onMounted, reactive, ref, toRefs, watch } from 'vue';
 | 
				
			||||||
import { NodeType, TagTreeNode } from './tag';
 | 
					import { NodeType, TagTreeNode } from './tag';
 | 
				
			||||||
import TagInfo from './TagInfo.vue';
 | 
					import TagInfo from './TagInfo.vue';
 | 
				
			||||||
import { tagApi } from '../tag/api';
 | 
					import { tagApi } from '../tag/api';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,6 +89,8 @@ export class NodeType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    contextMenuItems: ContextmenuItem[];
 | 
					    contextMenuItems: ContextmenuItem[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hasLoadNodesFunc: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    loadNodesFunc: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>;
 | 
					    loadNodesFunc: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nodeClickFunc: (node: TagTreeNode) => void;
 | 
					    nodeClickFunc: (node: TagTreeNode) => void;
 | 
				
			||||||
@@ -104,6 +106,7 @@ export class NodeType {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    withLoadNodesFunc(func: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>) {
 | 
					    withLoadNodesFunc(func: (parentNode: TagTreeNode) => Promise<TagTreeNode[]>) {
 | 
				
			||||||
        this.loadNodesFunc = func;
 | 
					        this.loadNodesFunc = func;
 | 
				
			||||||
 | 
					        this.hasLoadNodesFunc = true;
 | 
				
			||||||
        return this;
 | 
					        return this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@
 | 
				
			|||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <template #type="{ data }">
 | 
					            <template #type="{ data }">
 | 
				
			||||||
                <el-tooltip :content="data.type" placement="top">
 | 
					                <el-tooltip :content="getDbDialect(data.type).getInfo().name" placement="top">
 | 
				
			||||||
                    <SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
 | 
					                    <SvgIcon :name="getDbDialect(data.type).getInfo().icon" :size="20" />
 | 
				
			||||||
                </el-tooltip>
 | 
					                </el-tooltip>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@
 | 
				
			|||||||
                            <db-select-tree
 | 
					                            <db-select-tree
 | 
				
			||||||
                                placeholder="请选择源数据库"
 | 
					                                placeholder="请选择源数据库"
 | 
				
			||||||
                                v-model:db-id="form.srcDbId"
 | 
					                                v-model:db-id="form.srcDbId"
 | 
				
			||||||
 | 
					                                v-model:inst-name="form.srcInstName"
 | 
				
			||||||
                                v-model:db-name="form.srcDbName"
 | 
					                                v-model:db-name="form.srcDbName"
 | 
				
			||||||
                                v-model:tag-path="form.srcTagPath"
 | 
					                                v-model:tag-path="form.srcTagPath"
 | 
				
			||||||
                                v-model:db-type="form.srcDbType"
 | 
					                                v-model:db-type="form.srcDbType"
 | 
				
			||||||
@@ -56,8 +57,10 @@
 | 
				
			|||||||
                            <db-select-tree
 | 
					                            <db-select-tree
 | 
				
			||||||
                                placeholder="请选择目标数据库"
 | 
					                                placeholder="请选择目标数据库"
 | 
				
			||||||
                                v-model:db-id="form.targetDbId"
 | 
					                                v-model:db-id="form.targetDbId"
 | 
				
			||||||
 | 
					                                v-model:inst-name="form.targetInstName"
 | 
				
			||||||
                                v-model:db-name="form.targetDbName"
 | 
					                                v-model:db-name="form.targetDbName"
 | 
				
			||||||
                                v-model:tag-path="form.targetTagPath"
 | 
					                                v-model:tag-path="form.targetTagPath"
 | 
				
			||||||
 | 
					                                v-model:db-type="form.targetDbType"
 | 
				
			||||||
                                @select-db="onSelectTargetDb"
 | 
					                                @select-db="onSelectTargetDb"
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                        </el-form-item>
 | 
					                        </el-form-item>
 | 
				
			||||||
@@ -182,7 +185,7 @@ import { ElMessage } from 'element-plus';
 | 
				
			|||||||
import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
 | 
					import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
 | 
				
			||||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
 | 
					import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
 | 
				
			||||||
import { DbInst, registerDbCompletionItemProvider } from '@/views/ops/db/db';
 | 
					import { DbInst, registerDbCompletionItemProvider } from '@/views/ops/db/db';
 | 
				
			||||||
import {DbType, getDbDialect} from '@/views/ops/db/dialect'
 | 
					import { DbType, getDbDialect } from '@/views/ops/db/dialect';
 | 
				
			||||||
import CrontabInput from '@/components/crontab/CrontabInput.vue';
 | 
					import CrontabInput from '@/components/crontab/CrontabInput.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
@@ -227,13 +230,16 @@ type FormData = {
 | 
				
			|||||||
    taskName?: string;
 | 
					    taskName?: string;
 | 
				
			||||||
    taskCron: string;
 | 
					    taskCron: string;
 | 
				
			||||||
    srcDbId?: number;
 | 
					    srcDbId?: number;
 | 
				
			||||||
 | 
					    srcInstName?: string;
 | 
				
			||||||
    srcDbName?: string;
 | 
					    srcDbName?: string;
 | 
				
			||||||
    srcDbType?: string;
 | 
					    srcDbType?: string;
 | 
				
			||||||
    srcTagPath?: string;
 | 
					    srcTagPath?: string;
 | 
				
			||||||
    targetDbId?: number;
 | 
					    targetDbId?: number;
 | 
				
			||||||
 | 
					    targetInstName?: string;
 | 
				
			||||||
    targetDbName?: string;
 | 
					    targetDbName?: string;
 | 
				
			||||||
    targetTagPath?: string;
 | 
					    targetTagPath?: string;
 | 
				
			||||||
    targetTableName?: string;
 | 
					    targetTableName?: string;
 | 
				
			||||||
 | 
					    targetDbType?: string;
 | 
				
			||||||
    dataSql?: string;
 | 
					    dataSql?: string;
 | 
				
			||||||
    pageSize?: number;
 | 
					    pageSize?: number;
 | 
				
			||||||
    updField?: string;
 | 
					    updField?: string;
 | 
				
			||||||
@@ -304,7 +310,8 @@ watch(dialogVisible, async (newValue: boolean) => {
 | 
				
			|||||||
        // 初始化实例
 | 
					        // 初始化实例
 | 
				
			||||||
        db.databases = db.database?.split(' ').sort() || [];
 | 
					        db.databases = db.database?.split(' ').sort() || [];
 | 
				
			||||||
        state.srcDbInst = DbInst.getOrNewInst(db);
 | 
					        state.srcDbInst = DbInst.getOrNewInst(db);
 | 
				
			||||||
        state.form.srcDbType = state.srcDbInst.type
 | 
					        state.form.srcDbType = state.srcDbInst.type;
 | 
				
			||||||
 | 
					        state.form.srcInstName = db.instanceName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //  初始化target数据源
 | 
					    //  初始化target数据源
 | 
				
			||||||
@@ -315,6 +322,8 @@ watch(dialogVisible, async (newValue: boolean) => {
 | 
				
			|||||||
        // 初始化实例
 | 
					        // 初始化实例
 | 
				
			||||||
        db.databases = db.database?.split(' ').sort() || [];
 | 
					        db.databases = db.database?.split(' ').sort() || [];
 | 
				
			||||||
        state.targetDbInst = DbInst.getOrNewInst(db);
 | 
					        state.targetDbInst = DbInst.getOrNewInst(db);
 | 
				
			||||||
 | 
					        state.form.targetDbType = state.targetDbInst.type;
 | 
				
			||||||
 | 
					        state.form.targetInstName = db.instanceName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (targetDbId && state.form.targetDbName) {
 | 
					    if (targetDbId && state.form.targetDbName) {
 | 
				
			||||||
@@ -414,15 +423,15 @@ const handleGetSrcFields = async () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // 执行sql
 | 
					    // 执行sql
 | 
				
			||||||
    // oracle的分页关键字不一样
 | 
					    // oracle的分页关键字不一样
 | 
				
			||||||
    let limit = ' limit 1'
 | 
					    let limit = ' limit 1';
 | 
				
			||||||
    if(state.form.srcDbType === DbType.oracle){
 | 
					    if (state.form.srcDbType === DbType.oracle) {
 | 
				
			||||||
      limit = ' where rownum <= 1'
 | 
					        limit = ' where rownum <= 1';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    const res = await dbApi.sqlExec.request({
 | 
					    const res = await dbApi.sqlExec.request({
 | 
				
			||||||
        id: state.form.srcDbId,
 | 
					        id: state.form.srcDbId,
 | 
				
			||||||
        db: state.form.srcDbName,
 | 
					        db: state.form.srcDbName,
 | 
				
			||||||
        sql: `select * from (${state.form.dataSql}) t ${limit}`
 | 
					        sql: `select * from (${state.form.dataSql}) t ${limit}`,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!res.columns) {
 | 
					    if (!res.columns) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,9 @@
 | 
				
			|||||||
        :resource-type="TagResourceTypeEnum.Db.value"
 | 
					        :resource-type="TagResourceTypeEnum.Db.value"
 | 
				
			||||||
        :tag-path-node-type="NodeTypeTagPath"
 | 
					        :tag-path-node-type="NodeTypeTagPath"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
 | 
					        <template #iconPrefix>
 | 
				
			||||||
 | 
					            <SvgIcon v-if="dbType && getDbDialect(dbType)" :name="getDbDialect(dbType).getInfo().icon" :size="18" />
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
        <template #prefix="{ data }">
 | 
					        <template #prefix="{ data }">
 | 
				
			||||||
            <SvgIcon v-if="data.type.value == SqlExecNodeType.DbInst" :name="getDbDialect(data.params.type).getInfo().icon" :size="18" />
 | 
					            <SvgIcon v-if="data.type.value == SqlExecNodeType.DbInst" :name="getDbDialect(data.params.type).getInfo().icon" :size="18" />
 | 
				
			||||||
            <SvgIcon v-if="data.icon" :name="data.icon.name" :color="data.icon.color" />
 | 
					            <SvgIcon v-if="data.icon" :name="data.icon.name" :color="data.icon.color" />
 | 
				
			||||||
@@ -27,6 +30,9 @@ const props = defineProps({
 | 
				
			|||||||
    dbId: {
 | 
					    dbId: {
 | 
				
			||||||
        type: Number,
 | 
					        type: Number,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    instName: {
 | 
				
			||||||
 | 
					        type: String,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    dbName: {
 | 
					    dbName: {
 | 
				
			||||||
        type: String,
 | 
					        type: String,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@@ -38,7 +44,7 @@ const props = defineProps({
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const emits = defineEmits(['update:dbName', 'update:tagPath', 'update:dbId', 'update:dbType', 'selectDb']);
 | 
					const emits = defineEmits(['update:dbName', 'update:tagPath', 'update:instName', 'update:dbId', 'update:dbType', 'selectDb']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 树节点类型
 | 
					 * 树节点类型
 | 
				
			||||||
@@ -56,7 +62,7 @@ class SqlExecNodeType {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const selectNode = computed({
 | 
					const selectNode = computed({
 | 
				
			||||||
    get: () => {
 | 
					    get: () => {
 | 
				
			||||||
        return props.dbName ? `${props.tagPath} - ${props.dbId} - ${props.dbName}` : '';
 | 
					        return props.dbName ? `${props.tagPath} > ${props.instName} > ${props.dbName}` : '';
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    set: () => {
 | 
					    set: () => {
 | 
				
			||||||
        //
 | 
					        //
 | 
				
			||||||
@@ -151,6 +157,7 @@ const changeNode = (nodeData: TagTreeNode) => {
 | 
				
			|||||||
    const params = nodeData.params;
 | 
					    const params = nodeData.params;
 | 
				
			||||||
    // postgres
 | 
					    // postgres
 | 
				
			||||||
    emits('update:dbName', params.db);
 | 
					    emits('update:dbName', params.db);
 | 
				
			||||||
 | 
					    emits('update:instName', params.name);
 | 
				
			||||||
    emits('update:dbId', params.id);
 | 
					    emits('update:dbId', params.id);
 | 
				
			||||||
    emits('update:tagPath', params.tagPath);
 | 
					    emits('update:tagPath', params.tagPath);
 | 
				
			||||||
    emits('update:dbType', params.type);
 | 
					    emits('update:dbType', params.type);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -272,6 +272,18 @@ watch(props, async (newValue) => {
 | 
				
			|||||||
    dbDialect = getDbDialect(newValue.dbType);
 | 
					    dbDialect = getDbDialect(newValue.dbType);
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 切换到索引tab时,刷新索引字段下拉选项
 | 
				
			||||||
 | 
					watch(
 | 
				
			||||||
 | 
					    () => state.activeName,
 | 
				
			||||||
 | 
					    (newValue) => {
 | 
				
			||||||
 | 
					        if (newValue === '2') {
 | 
				
			||||||
 | 
					            state.tableData.indexs.columns = state.tableData.fields.res.map((a) => {
 | 
				
			||||||
 | 
					                return { name: a.name, remark: a.remark };
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const cancel = () => {
 | 
					const cancel = () => {
 | 
				
			||||||
    emit('update:visible', false);
 | 
					    emit('update:visible', false);
 | 
				
			||||||
    reset();
 | 
					    reset();
 | 
				
			||||||
@@ -391,22 +403,22 @@ const genSql = () => {
 | 
				
			|||||||
    let data = state.tableData;
 | 
					    let data = state.tableData;
 | 
				
			||||||
    // 创建表
 | 
					    // 创建表
 | 
				
			||||||
    if (!props.data?.edit) {
 | 
					    if (!props.data?.edit) {
 | 
				
			||||||
        if (state.activeName === '1') {
 | 
					        let createTable = dbDialect.getCreateTableSql(data);
 | 
				
			||||||
            return dbDialect.getCreateTableSql(data);
 | 
					        let createIndex = '';
 | 
				
			||||||
        } else if (state.activeName === '2' && data.indexs.res.length > 0) {
 | 
					        if (data.indexs.res.length > 0) {
 | 
				
			||||||
            return dbDialect.getCreateIndexSql(data);
 | 
					            createIndex = dbDialect.getCreateIndexSql(data);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        return createTable + ';' + createIndex;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        // 修改
 | 
					        // 修改列
 | 
				
			||||||
        if (state.activeName === '1') {
 | 
					        let changeColData = filterChangedData(state.tableData.fields.oldFields, state.tableData.fields.res, 'name');
 | 
				
			||||||
            // 修改列
 | 
					        let colSql = dbDialect.getModifyColumnSql(data, data.tableName, changeColData);
 | 
				
			||||||
            let changeData = filterChangedData(state.tableData.fields.oldFields, state.tableData.fields.res, 'name');
 | 
					        // 修改索引
 | 
				
			||||||
            return dbDialect.getModifyColumnSql(data, data.tableName, changeData);
 | 
					        let changeIdxData = filterChangedData(state.tableData.indexs.oldIndexs, state.tableData.indexs.res, 'indexName');
 | 
				
			||||||
        } else if (state.activeName === '2') {
 | 
					        let idxSql = dbDialect.getModifyIndexSql(data, data.tableName, changeIdxData);
 | 
				
			||||||
            // 修改索引
 | 
					        // 修改表名
 | 
				
			||||||
            let changeData = filterChangedData(state.tableData.indexs.oldIndexs, state.tableData.indexs.res, 'indexName');
 | 
					
 | 
				
			||||||
            return dbDialect.getModifyIndexSql(data, data.tableName, changeData);
 | 
					        return colSql + ';' + idxSql;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ import { MariadbDialect } from '@/views/ops/db/dialect/mariadb_dialect';
 | 
				
			|||||||
import { SqliteDialect } from '@/views/ops/db/dialect/sqlite_dialect';
 | 
					import { SqliteDialect } from '@/views/ops/db/dialect/sqlite_dialect';
 | 
				
			||||||
import { MssqlDialect } from '@/views/ops/db/dialect/mssql_dialect';
 | 
					import { MssqlDialect } from '@/views/ops/db/dialect/mssql_dialect';
 | 
				
			||||||
import { GaussDialect } from '@/views/ops/db/dialect/gauss_dialect';
 | 
					import { GaussDialect } from '@/views/ops/db/dialect/gauss_dialect';
 | 
				
			||||||
 | 
					import { KingbaseEsDialect } from '@/views/ops/db/dialect/kingbaseES_dialect';
 | 
				
			||||||
 | 
					import { VastbaseDialect } from '@/views/ops/db/dialect/vastbase_dialect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface sqlColumnType {
 | 
					export interface sqlColumnType {
 | 
				
			||||||
    udtName: string;
 | 
					    udtName: string;
 | 
				
			||||||
@@ -122,13 +124,15 @@ export const DbType = {
 | 
				
			|||||||
    oracle: 'oracle',
 | 
					    oracle: 'oracle',
 | 
				
			||||||
    sqlite: 'sqlite',
 | 
					    sqlite: 'sqlite',
 | 
				
			||||||
    mssql: 'mssql', // ms sqlserver
 | 
					    mssql: 'mssql', // ms sqlserver
 | 
				
			||||||
 | 
					    kingbaseEs: 'kingbaseEs', // 人大金仓 pgsql模式 https://help.kingbase.com.cn/v8/index.html
 | 
				
			||||||
 | 
					    vastbase: 'vastbase', // https://docs.vastdata.com.cn/zh/docs/VastbaseG100Ver2.2.5/doc/%E5%BC%80%E5%8F%91%E8%80%85%E6%8C%87%E5%8D%97/SQL%E5%8F%82%E8%80%83/SQL%E5%8F%82%E8%80%83.html
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// mysql兼容的数据库
 | 
					// mysql兼容的数据库
 | 
				
			||||||
export const noSchemaTypes = [DbType.mysql, DbType.mariadb, DbType.sqlite];
 | 
					export const noSchemaTypes = [DbType.mysql, DbType.mariadb, DbType.sqlite];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 有schema层的数据库
 | 
					// 有schema层的数据库
 | 
				
			||||||
export const schemaDbTypes = [DbType.postgresql, DbType.gauss, DbType.dm, DbType.oracle, DbType.mssql];
 | 
					export const schemaDbTypes = [DbType.postgresql, DbType.gauss, DbType.dm, DbType.oracle, DbType.mssql, DbType.kingbaseEs, DbType.vastbase];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const editDbTypes = [...noSchemaTypes, ...schemaDbTypes];
 | 
					export const editDbTypes = [...noSchemaTypes, ...schemaDbTypes];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -218,8 +222,8 @@ export const getDbDialectMap = () => {
 | 
				
			|||||||
    return dbType2DialectMap;
 | 
					    return dbType2DialectMap;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getDbDialect = (dbType: string): DbDialect => {
 | 
					export const getDbDialect = (dbType?: string): DbDialect => {
 | 
				
			||||||
    return dbType2DialectMap.get(dbType) || mysqlDialect;
 | 
					    return dbType2DialectMap.get(dbType!) || mysqlDialect;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(function () {
 | 
					(function () {
 | 
				
			||||||
@@ -232,4 +236,6 @@ export const getDbDialect = (dbType: string): DbDialect => {
 | 
				
			|||||||
    registerDbDialect(DbType.oracle, new OracleDialect());
 | 
					    registerDbDialect(DbType.oracle, new OracleDialect());
 | 
				
			||||||
    registerDbDialect(DbType.sqlite, new SqliteDialect());
 | 
					    registerDbDialect(DbType.sqlite, new SqliteDialect());
 | 
				
			||||||
    registerDbDialect(DbType.mssql, new MssqlDialect());
 | 
					    registerDbDialect(DbType.mssql, new MssqlDialect());
 | 
				
			||||||
 | 
					    registerDbDialect(DbType.kingbaseEs, new KingbaseEsDialect());
 | 
				
			||||||
 | 
					    registerDbDialect(DbType.vastbase, new VastbaseDialect());
 | 
				
			||||||
})();
 | 
					})();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								mayfly_go_web/src/views/ops/db/dialect/kingbaseES_dialect.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								mayfly_go_web/src/views/ops/db/dialect/kingbaseES_dialect.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import { DialectInfo } from './index';
 | 
				
			||||||
 | 
					import { PostgresqlDialect } from '@/views/ops/db/dialect/postgres_dialect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let kbpgDialectInfo: DialectInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class KingbaseEsDialect extends PostgresqlDialect {
 | 
				
			||||||
 | 
					    getInfo(): DialectInfo {
 | 
				
			||||||
 | 
					        if (kbpgDialectInfo) {
 | 
				
			||||||
 | 
					            return kbpgDialectInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kbpgDialectInfo = {} as DialectInfo;
 | 
				
			||||||
 | 
					        Object.assign(kbpgDialectInfo, super.getInfo());
 | 
				
			||||||
 | 
					        kbpgDialectInfo.name = 'KingbaseES';
 | 
				
			||||||
 | 
					        kbpgDialectInfo.icon = 'iconfont icon-kingbase';
 | 
				
			||||||
 | 
					        return kbpgDialectInfo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -303,11 +303,15 @@ class PostgresqlDialect implements DbDialect {
 | 
				
			|||||||
        // CREATE UNIQUE INDEX idx_column_name ON your_table (column1, column2);
 | 
					        // CREATE UNIQUE INDEX idx_column_name ON your_table (column1, column2);
 | 
				
			||||||
        // COMMENT ON INDEX idx_column_name IS 'Your index comment here';
 | 
					        // COMMENT ON INDEX idx_column_name IS 'Your index comment here';
 | 
				
			||||||
        // 创建索引
 | 
					        // 创建索引
 | 
				
			||||||
 | 
					        let schema = tableData.db.split('/')[1];
 | 
				
			||||||
 | 
					        let dbTable = `${this.quoteIdentifier(schema)}.${this.quoteIdentifier(tableData.tableName)}`;
 | 
				
			||||||
        let sql: string[] = [];
 | 
					        let sql: string[] = [];
 | 
				
			||||||
        tableData.indexs.res.forEach((a: any) => {
 | 
					        tableData.indexs.res.forEach((a: any) => {
 | 
				
			||||||
            sql.push(` create ${a.unique ? 'UNIQUE' : ''} index ${a.indexName} ("${a.columnNames.join('","')})"`);
 | 
					            // 字段名用双引号包裹
 | 
				
			||||||
 | 
					            let colArr = a.columnNames.map((a: string) => `${this.quoteIdentifier(a)}`);
 | 
				
			||||||
 | 
					            sql.push(`CREATE ${a.unique ? 'UNIQUE' : ''} INDEX ${this.quoteIdentifier(a.indexName)} on ${dbTable} (${colArr.join(',')})`);
 | 
				
			||||||
            if (a.indexComment) {
 | 
					            if (a.indexComment) {
 | 
				
			||||||
                sql.push(`COMMENT ON INDEX ${a.indexName} IS '${a.indexComment}'`);
 | 
					                sql.push(`COMMENT ON INDEX ${schema}.${this.quoteIdentifier(a.indexName)} IS '${a.indexComment}'`);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return sql.join(';');
 | 
					        return sql.join(';');
 | 
				
			||||||
@@ -367,6 +371,9 @@ class PostgresqlDialect implements DbDialect {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getModifyIndexSql(tableData: any, tableName: string, changeData: { del: any[]; add: any[]; upd: any[] }): string {
 | 
					    getModifyIndexSql(tableData: any, tableName: string, changeData: { del: any[]; add: any[]; upd: any[] }): string {
 | 
				
			||||||
 | 
					        let schema = tableData.db.split('/')[1];
 | 
				
			||||||
 | 
					        let dbTable = `${this.quoteIdentifier(schema)}.${this.quoteIdentifier(tableName)}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 不能直接修改索引名或字段、需要先删后加
 | 
					        // 不能直接修改索引名或字段、需要先删后加
 | 
				
			||||||
        let dropIndexNames: string[] = [];
 | 
					        let dropIndexNames: string[] = [];
 | 
				
			||||||
        let addIndexs: any[] = [];
 | 
					        let addIndexs: any[] = [];
 | 
				
			||||||
@@ -400,9 +407,11 @@ class PostgresqlDialect implements DbDialect {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (addIndexs.length > 0) {
 | 
					            if (addIndexs.length > 0) {
 | 
				
			||||||
                addIndexs.forEach((a) => {
 | 
					                addIndexs.forEach((a) => {
 | 
				
			||||||
                    sql.push(`CREATE ${a.unique ? 'UNIQUE' : ''} INDEX ${a.indexName}(${a.columnNames.join(',')})`);
 | 
					                    // 字段名用双引号包裹
 | 
				
			||||||
 | 
					                    let colArr = a.columnNames.map((a: string) => `${this.quoteIdentifier(a)}`);
 | 
				
			||||||
 | 
					                    sql.push(`CREATE ${a.unique ? 'UNIQUE' : ''} INDEX ${this.quoteIdentifier(a.indexName)} on ${dbTable} (${colArr.join(',')})`);
 | 
				
			||||||
                    if (a.indexComment) {
 | 
					                    if (a.indexComment) {
 | 
				
			||||||
                        sql.push(`COMMENT ON INDEX ${a.indexName} IS '${a.indexComment}'`);
 | 
					                        sql.push(`COMMENT ON INDEX ${schema}.${this.quoteIdentifier(a.indexName)} IS '${a.indexComment}'`);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								mayfly_go_web/src/views/ops/db/dialect/vastbase_dialect.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								mayfly_go_web/src/views/ops/db/dialect/vastbase_dialect.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import { DialectInfo } from './index';
 | 
				
			||||||
 | 
					import { PostgresqlDialect } from '@/views/ops/db/dialect/postgres_dialect';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let vastDialectInfo: DialectInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class VastbaseDialect extends PostgresqlDialect {
 | 
				
			||||||
 | 
					    getInfo(): DialectInfo {
 | 
				
			||||||
 | 
					        if (vastDialectInfo) {
 | 
				
			||||||
 | 
					            return vastDialectInfo;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vastDialectInfo = {} as DialectInfo;
 | 
				
			||||||
 | 
					        Object.assign(vastDialectInfo, super.getInfo());
 | 
				
			||||||
 | 
					        vastDialectInfo.name = 'VastbaseG100';
 | 
				
			||||||
 | 
					        vastDialectInfo.icon = 'iconfont icon-vastbase';
 | 
				
			||||||
 | 
					        return vastDialectInfo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,191 +1,207 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div>
 | 
					    <div class="flex-all-center">
 | 
				
			||||||
        <page-table
 | 
					        <Splitpanes class="default-theme">
 | 
				
			||||||
            ref="pageTableRef"
 | 
					            <Pane size="20" max-size="30">
 | 
				
			||||||
            :page-api="machineApi.list"
 | 
					                <tag-tree :resource-type="TagResourceTypeEnum.Machine.value" :tag-path-node-type="NodeTypeTagPath" />
 | 
				
			||||||
            :before-query-fn="checkRouteTagPath"
 | 
					            </Pane>
 | 
				
			||||||
            :search-items="searchItems"
 | 
					 | 
				
			||||||
            v-model:query-form="params"
 | 
					 | 
				
			||||||
            :show-selection="true"
 | 
					 | 
				
			||||||
            v-model:selection-data="state.selectionData"
 | 
					 | 
				
			||||||
            :columns="columns"
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
            <template #tableHeader>
 | 
					 | 
				
			||||||
                <el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
 | 
					 | 
				
			||||||
                <el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete">删除</el-button>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <template #ipPort="{ data }">
 | 
					            <Pane>
 | 
				
			||||||
                <el-link :disabled="data.status == -1" @click="showMachineStats(data)" type="primary" :underline="false">
 | 
					                <div>
 | 
				
			||||||
                    {{ `${data.ip}:${data.port}` }}
 | 
					                    <page-table :data="state.pageData" :pageable="false" :show-selection="true" v-model:selection-data="state.selectionData" :columns="columns">
 | 
				
			||||||
                </el-link>
 | 
					                        <template #tableHeader>
 | 
				
			||||||
            </template>
 | 
					                            <el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
 | 
				
			||||||
 | 
					                            <el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()" type="danger" icon="delete"
 | 
				
			||||||
            <template #stat="{ data }">
 | 
					                                >删除</el-button
 | 
				
			||||||
                <span v-if="!data.stat">-</span>
 | 
					 | 
				
			||||||
                <div v-else>
 | 
					 | 
				
			||||||
                    <el-row>
 | 
					 | 
				
			||||||
                        <el-text size="small" style="font-size: 10px">
 | 
					 | 
				
			||||||
                            内存(可用/总):
 | 
					 | 
				
			||||||
                            <span :class="getStatsFontClass(data.stat.memAvailable, data.stat.memTotal)"
 | 
					 | 
				
			||||||
                                >{{ formatByteSize(data.stat.memAvailable, 1) }}/{{ formatByteSize(data.stat.memTotal, 1) }}
 | 
					 | 
				
			||||||
                            </span>
 | 
					 | 
				
			||||||
                        </el-text>
 | 
					 | 
				
			||||||
                    </el-row>
 | 
					 | 
				
			||||||
                    <el-row>
 | 
					 | 
				
			||||||
                        <el-text style="font-size: 10px" size="small">
 | 
					 | 
				
			||||||
                            CPU(空闲): <span :class="getStatsFontClass(data.stat.cpuIdle, 100)">{{ data.stat.cpuIdle.toFixed(0) }}%</span>
 | 
					 | 
				
			||||||
                        </el-text>
 | 
					 | 
				
			||||||
                    </el-row>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #fs="{ data }">
 | 
					 | 
				
			||||||
                <span v-if="!data.stat?.fsInfos">-</span>
 | 
					 | 
				
			||||||
                <div v-else>
 | 
					 | 
				
			||||||
                    <el-row v-for="(i, idx) in data.stat.fsInfos.slice(0, 2)" :key="i.mountPoint">
 | 
					 | 
				
			||||||
                        <el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
 | 
					 | 
				
			||||||
                            {{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
 | 
					 | 
				
			||||||
                        </el-text>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                        <!-- 展示剩余的磁盘信息 -->
 | 
					 | 
				
			||||||
                        <el-popover :show-after="300" v-if="data.stat.fsInfos.length > 2 && idx == 1" placement="top-start" width="230" trigger="hover">
 | 
					 | 
				
			||||||
                            <template #reference>
 | 
					 | 
				
			||||||
                                <SvgIcon class="mt5 ml5" color="var(--el-color-primary)" name="MoreFilled" />
 | 
					 | 
				
			||||||
                            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <el-row v-for="i in data.stat.fsInfos.slice(2)" :key="i.mountPoint">
 | 
					 | 
				
			||||||
                                <el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
 | 
					 | 
				
			||||||
                                    {{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
 | 
					 | 
				
			||||||
                                </el-text>
 | 
					 | 
				
			||||||
                            </el-row>
 | 
					 | 
				
			||||||
                        </el-popover>
 | 
					 | 
				
			||||||
                    </el-row>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #status="{ data }">
 | 
					 | 
				
			||||||
                <el-switch
 | 
					 | 
				
			||||||
                    v-auth:disabled="'machine:update'"
 | 
					 | 
				
			||||||
                    :width="52"
 | 
					 | 
				
			||||||
                    v-model="data.status"
 | 
					 | 
				
			||||||
                    :active-value="1"
 | 
					 | 
				
			||||||
                    :inactive-value="-1"
 | 
					 | 
				
			||||||
                    inline-prompt
 | 
					 | 
				
			||||||
                    active-text="启用"
 | 
					 | 
				
			||||||
                    inactive-text="停用"
 | 
					 | 
				
			||||||
                    style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
 | 
					 | 
				
			||||||
                    @change="changeStatus(data)"
 | 
					 | 
				
			||||||
                ></el-switch>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #tagPath="{ data }">
 | 
					 | 
				
			||||||
                <resource-tag :resource-code="data.code" :resource-type="TagResourceTypeEnum.Machine.value" />
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <template #action="{ data }">
 | 
					 | 
				
			||||||
                <span v-auth="'machine:terminal'">
 | 
					 | 
				
			||||||
                    <el-tooltip :show-after="500" content="按住ctrl则为新标签打开" placement="top">
 | 
					 | 
				
			||||||
                        <el-button :disabled="data.status == -1" type="primary" @click="showTerminal(data, $event)" link>终端</el-button>
 | 
					 | 
				
			||||||
                    </el-tooltip>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    <el-divider direction="vertical" border-style="dashed" />
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <span v-auth="'machine:file'">
 | 
					 | 
				
			||||||
                    <el-button type="success" :disabled="data.status == -1" @click="showFileManage(data)" link>文件</el-button>
 | 
					 | 
				
			||||||
                    <el-divider direction="vertical" border-style="dashed" />
 | 
					 | 
				
			||||||
                </span>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-button :disabled="data.status == -1" type="warning" @click="serviceManager(data)" link>脚本</el-button>
 | 
					 | 
				
			||||||
                <el-divider direction="vertical" border-style="dashed" />
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                <el-dropdown @command="handleCommand">
 | 
					 | 
				
			||||||
                    <span class="el-dropdown-link-machine-list">
 | 
					 | 
				
			||||||
                        更多
 | 
					 | 
				
			||||||
                        <el-icon class="el-icon--right">
 | 
					 | 
				
			||||||
                            <arrow-down />
 | 
					 | 
				
			||||||
                        </el-icon>
 | 
					 | 
				
			||||||
                    </span>
 | 
					 | 
				
			||||||
                    <template #dropdown>
 | 
					 | 
				
			||||||
                        <el-dropdown-menu>
 | 
					 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'detail', data }"> 详情 </el-dropdown-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'edit', data }" v-if="actionBtns[perms.updateMachine]"> 编辑 </el-dropdown-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'process', data }" :disabled="data.status == -1"> 进程 </el-dropdown-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <el-dropdown-item :command="{ type: 'terminalRec', data }" v-if="actionBtns[perms.updateMachine] && data.enableRecorder == 1">
 | 
					 | 
				
			||||||
                                终端回放
 | 
					 | 
				
			||||||
                            </el-dropdown-item>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                            <el-dropdown-item
 | 
					 | 
				
			||||||
                                :command="{ type: 'closeCli', data }"
 | 
					 | 
				
			||||||
                                v-if="actionBtns[perms.closeCli]"
 | 
					 | 
				
			||||||
                                :disabled="!data.hasCli || data.status == -1"
 | 
					 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                关闭连接
 | 
					                        </template>
 | 
				
			||||||
                            </el-dropdown-item>
 | 
					 | 
				
			||||||
                        </el-dropdown-menu>
 | 
					 | 
				
			||||||
                    </template>
 | 
					 | 
				
			||||||
                </el-dropdown>
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
        </page-table>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <el-dialog v-model="infoDialog.visible">
 | 
					                        <template #ipPort="{ data }">
 | 
				
			||||||
            <el-descriptions title="详情" :column="3" border>
 | 
					                            <el-link :disabled="data.status == -1" @click="showMachineStats(data)" type="primary" :underline="false">
 | 
				
			||||||
                <el-descriptions-item :span="1.5" label="机器id">{{ infoDialog.data.id }}</el-descriptions-item>
 | 
					                                {{ `${data.ip}:${data.port}` }}
 | 
				
			||||||
                <el-descriptions-item :span="1.5" label="名称">{{ infoDialog.data.name }}</el-descriptions-item>
 | 
					                            </el-link>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="3" label="标签路径">{{ infoDialog.data.tagPath }}</el-descriptions-item>
 | 
					                        <template #stat="{ data }">
 | 
				
			||||||
 | 
					                            <span v-if="!data.stat">-</span>
 | 
				
			||||||
 | 
					                            <div v-else>
 | 
				
			||||||
 | 
					                                <el-row>
 | 
				
			||||||
 | 
					                                    <el-text size="small" style="font-size: 10px">
 | 
				
			||||||
 | 
					                                        内存(可用/总):
 | 
				
			||||||
 | 
					                                        <span :class="getStatsFontClass(data.stat.memAvailable, data.stat.memTotal)"
 | 
				
			||||||
 | 
					                                            >{{ formatByteSize(data.stat.memAvailable, 1) }}/{{ formatByteSize(data.stat.memTotal, 1) }}
 | 
				
			||||||
 | 
					                                        </span>
 | 
				
			||||||
 | 
					                                    </el-text>
 | 
				
			||||||
 | 
					                                </el-row>
 | 
				
			||||||
 | 
					                                <el-row>
 | 
				
			||||||
 | 
					                                    <el-text style="font-size: 10px" size="small">
 | 
				
			||||||
 | 
					                                        CPU(空闲): <span :class="getStatsFontClass(data.stat.cpuIdle, 100)">{{ data.stat.cpuIdle.toFixed(0) }}%</span>
 | 
				
			||||||
 | 
					                                    </el-text>
 | 
				
			||||||
 | 
					                                </el-row>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="2" label="IP">{{ infoDialog.data.ip }}</el-descriptions-item>
 | 
					                        <template #fs="{ data }">
 | 
				
			||||||
                <el-descriptions-item :span="1" label="端口">{{ infoDialog.data.port }}</el-descriptions-item>
 | 
					                            <span v-if="!data.stat?.fsInfos">-</span>
 | 
				
			||||||
 | 
					                            <div v-else>
 | 
				
			||||||
 | 
					                                <el-row v-for="(i, idx) in data.stat.fsInfos.slice(0, 2)" :key="i.mountPoint">
 | 
				
			||||||
 | 
					                                    <el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
 | 
				
			||||||
 | 
					                                        {{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
 | 
				
			||||||
 | 
					                                    </el-text>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="2" label="用户名">{{ infoDialog.data.username }}</el-descriptions-item>
 | 
					                                    <!-- 展示剩余的磁盘信息 -->
 | 
				
			||||||
                <el-descriptions-item :span="1" label="认证方式">
 | 
					                                    <el-popover
 | 
				
			||||||
                    {{ infoDialog.data.authCertId > 1 ? '授权凭证' : '密码' }}
 | 
					                                        :show-after="300"
 | 
				
			||||||
                </el-descriptions-item>
 | 
					                                        v-if="data.stat.fsInfos.length > 2 && idx == 1"
 | 
				
			||||||
 | 
					                                        placement="top-start"
 | 
				
			||||||
 | 
					                                        width="230"
 | 
				
			||||||
 | 
					                                        trigger="hover"
 | 
				
			||||||
 | 
					                                    >
 | 
				
			||||||
 | 
					                                        <template #reference>
 | 
				
			||||||
 | 
					                                            <SvgIcon class="mt5 ml5" color="var(--el-color-primary)" name="MoreFilled" />
 | 
				
			||||||
 | 
					                                        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="3" label="备注">{{ infoDialog.data.remark }}</el-descriptions-item>
 | 
					                                        <el-row v-for="i in data.stat.fsInfos.slice(2)" :key="i.mountPoint">
 | 
				
			||||||
 | 
					                                            <el-text style="font-size: 10px" size="small" :class="getStatsFontClass(i.free, i.used + i.free)">
 | 
				
			||||||
 | 
					                                                {{ i.mountPoint }} => {{ formatByteSize(i.free, 0) }}/{{ formatByteSize(i.used + i.free, 0) }}
 | 
				
			||||||
 | 
					                                            </el-text>
 | 
				
			||||||
 | 
					                                        </el-row>
 | 
				
			||||||
 | 
					                                    </el-popover>
 | 
				
			||||||
 | 
					                                </el-row>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="1.5" label="SSH隧道">{{ infoDialog.data.sshTunnelMachineId > 0 ? '是' : '否' }} </el-descriptions-item>
 | 
					                        <template #status="{ data }">
 | 
				
			||||||
                <el-descriptions-item :span="1.5" label="终端回放">{{ infoDialog.data.enableRecorder == 1 ? '是' : '否' }} </el-descriptions-item>
 | 
					                            <el-switch
 | 
				
			||||||
 | 
					                                v-auth:disabled="'machine:update'"
 | 
				
			||||||
 | 
					                                :width="52"
 | 
				
			||||||
 | 
					                                v-model="data.status"
 | 
				
			||||||
 | 
					                                :active-value="1"
 | 
				
			||||||
 | 
					                                :inactive-value="-1"
 | 
				
			||||||
 | 
					                                inline-prompt
 | 
				
			||||||
 | 
					                                active-text="启用"
 | 
				
			||||||
 | 
					                                inactive-text="停用"
 | 
				
			||||||
 | 
					                                style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
 | 
				
			||||||
 | 
					                                @change="changeStatus(data)"
 | 
				
			||||||
 | 
					                            ></el-switch>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="2" label="创建时间">{{ dateFormat(infoDialog.data.createTime) }} </el-descriptions-item>
 | 
					                        <template #action="{ data }">
 | 
				
			||||||
                <el-descriptions-item :span="1" label="创建者">{{ infoDialog.data.creator }}</el-descriptions-item>
 | 
					                            <span v-auth="'machine:terminal'">
 | 
				
			||||||
 | 
					                                <el-tooltip :show-after="500" content="按住ctrl则为新标签打开" placement="top">
 | 
				
			||||||
 | 
					                                    <el-button :disabled="data.status == -1" type="primary" @click="showTerminal(data, $event)" link>终端</el-button>
 | 
				
			||||||
 | 
					                                </el-tooltip>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <el-descriptions-item :span="2" label="更新时间">{{ dateFormat(infoDialog.data.updateTime) }} </el-descriptions-item>
 | 
					                                <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
                <el-descriptions-item :span="1" label="修改者">{{ infoDialog.data.modifier }}</el-descriptions-item>
 | 
					                            </span>
 | 
				
			||||||
            </el-descriptions>
 | 
					 | 
				
			||||||
        </el-dialog>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <terminal-dialog ref="terminalDialogRef" :visibleMinimize="true">
 | 
					                            <span v-auth="'machine:file'">
 | 
				
			||||||
            <template #headerTitle="{ terminalInfo }">
 | 
					                                <el-button type="success" :disabled="data.status == -1" @click="showFileManage(data)" link>文件</el-button>
 | 
				
			||||||
                {{ `${(terminalInfo.terminalId + '').slice(-2)}` }}
 | 
					                                <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
                <el-divider direction="vertical" />
 | 
					                            </span>
 | 
				
			||||||
                {{ `${terminalInfo.meta.username}@${terminalInfo.meta.ip}:${terminalInfo.meta.port}` }}
 | 
					 | 
				
			||||||
                <el-divider direction="vertical" />
 | 
					 | 
				
			||||||
                {{ terminalInfo.meta.name }}
 | 
					 | 
				
			||||||
            </template>
 | 
					 | 
				
			||||||
        </terminal-dialog>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <machine-edit
 | 
					                            <el-button :disabled="data.status == -1" type="warning" @click="serviceManager(data)" link>脚本</el-button>
 | 
				
			||||||
            :title="machineEditDialog.title"
 | 
					                            <el-divider direction="vertical" border-style="dashed" />
 | 
				
			||||||
            v-model:visible="machineEditDialog.visible"
 | 
					 | 
				
			||||||
            v-model:machine="machineEditDialog.data"
 | 
					 | 
				
			||||||
            @valChange="submitSuccess"
 | 
					 | 
				
			||||||
        ></machine-edit>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <process-list v-model:visible="processDialog.visible" v-model:machineId="processDialog.machineId" />
 | 
					                            <el-dropdown @command="handleCommand">
 | 
				
			||||||
 | 
					                                <span class="el-dropdown-link-machine-list">
 | 
				
			||||||
 | 
					                                    更多
 | 
				
			||||||
 | 
					                                    <el-icon class="el-icon--right">
 | 
				
			||||||
 | 
					                                        <arrow-down />
 | 
				
			||||||
 | 
					                                    </el-icon>
 | 
				
			||||||
 | 
					                                </span>
 | 
				
			||||||
 | 
					                                <template #dropdown>
 | 
				
			||||||
 | 
					                                    <el-dropdown-menu>
 | 
				
			||||||
 | 
					                                        <el-dropdown-item :command="{ type: 'detail', data }"> 详情 </el-dropdown-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <script-manage :title="serviceDialog.title" v-model:visible="serviceDialog.visible" v-model:machineId="serviceDialog.machineId" />
 | 
					                                        <el-dropdown-item :command="{ type: 'edit', data }" v-if="actionBtns[perms.updateMachine]"> 编辑 </el-dropdown-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <file-conf-list :title="fileDialog.title" v-model:visible="fileDialog.visible" v-model:machineId="fileDialog.machineId" />
 | 
					                                        <el-dropdown-item :command="{ type: 'process', data }" :disabled="data.status == -1"> 进程 </el-dropdown-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <machine-stats v-model:visible="machineStatsDialog.visible" :machineId="machineStatsDialog.machineId" :title="machineStatsDialog.title"></machine-stats>
 | 
					                                        <el-dropdown-item
 | 
				
			||||||
 | 
					                                            :command="{ type: 'terminalRec', data }"
 | 
				
			||||||
 | 
					                                            v-if="actionBtns[perms.updateMachine] && data.enableRecorder == 1"
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            终端回放
 | 
				
			||||||
 | 
					                                        </el-dropdown-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <machine-rec v-model:visible="machineRecDialog.visible" :machineId="machineRecDialog.machineId" :title="machineRecDialog.title"></machine-rec>
 | 
					                                        <el-dropdown-item
 | 
				
			||||||
 | 
					                                            :command="{ type: 'closeCli', data }"
 | 
				
			||||||
 | 
					                                            v-if="actionBtns[perms.closeCli]"
 | 
				
			||||||
 | 
					                                            :disabled="!data.hasCli || data.status == -1"
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            关闭连接
 | 
				
			||||||
 | 
					                                        </el-dropdown-item>
 | 
				
			||||||
 | 
					                                    </el-dropdown-menu>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-dropdown>
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </page-table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <el-dialog v-model="infoDialog.visible">
 | 
				
			||||||
 | 
					                        <el-descriptions title="详情" :column="3" border>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1.5" label="机器id">{{ infoDialog.data.id }}</el-descriptions-item>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1.5" label="名称">{{ infoDialog.data.name }}</el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="3" label="标签路径">{{ infoDialog.data.tagPath }}</el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="2" label="IP">{{ infoDialog.data.ip }}</el-descriptions-item>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1" label="端口">{{ infoDialog.data.port }}</el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="2" label="用户名">{{ infoDialog.data.username }}</el-descriptions-item>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1" label="认证方式">
 | 
				
			||||||
 | 
					                                {{ infoDialog.data.authCertId > 1 ? '授权凭证' : '密码' }}
 | 
				
			||||||
 | 
					                            </el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="3" label="备注">{{ infoDialog.data.remark }}</el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1.5" label="SSH隧道">{{ infoDialog.data.sshTunnelMachineId > 0 ? '是' : '否' }} </el-descriptions-item>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1.5" label="终端回放">{{ infoDialog.data.enableRecorder == 1 ? '是' : '否' }} </el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="2" label="创建时间">{{ dateFormat(infoDialog.data.createTime) }} </el-descriptions-item>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1" label="创建者">{{ infoDialog.data.creator }}</el-descriptions-item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="2" label="更新时间">{{ dateFormat(infoDialog.data.updateTime) }} </el-descriptions-item>
 | 
				
			||||||
 | 
					                            <el-descriptions-item :span="1" label="修改者">{{ infoDialog.data.modifier }}</el-descriptions-item>
 | 
				
			||||||
 | 
					                        </el-descriptions>
 | 
				
			||||||
 | 
					                    </el-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <terminal-dialog ref="terminalDialogRef" :visibleMinimize="true">
 | 
				
			||||||
 | 
					                        <template #headerTitle="{ terminalInfo }">
 | 
				
			||||||
 | 
					                            {{ `${(terminalInfo.terminalId + '').slice(-2)}` }}
 | 
				
			||||||
 | 
					                            <el-divider direction="vertical" />
 | 
				
			||||||
 | 
					                            {{ `${terminalInfo.meta.username}@${terminalInfo.meta.ip}:${terminalInfo.meta.port}` }}
 | 
				
			||||||
 | 
					                            <el-divider direction="vertical" />
 | 
				
			||||||
 | 
					                            {{ terminalInfo.meta.name }}
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                    </terminal-dialog>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <machine-edit
 | 
				
			||||||
 | 
					                        :title="machineEditDialog.title"
 | 
				
			||||||
 | 
					                        v-model:visible="machineEditDialog.visible"
 | 
				
			||||||
 | 
					                        v-model:machine="machineEditDialog.data"
 | 
				
			||||||
 | 
					                        @valChange="submitSuccess"
 | 
				
			||||||
 | 
					                    ></machine-edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <process-list v-model:visible="processDialog.visible" v-model:machineId="processDialog.machineId" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <script-manage :title="serviceDialog.title" v-model:visible="serviceDialog.visible" v-model:machineId="serviceDialog.machineId" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <file-conf-list :title="fileDialog.title" v-model:visible="fileDialog.visible" v-model:machineId="fileDialog.machineId" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <machine-stats
 | 
				
			||||||
 | 
					                        v-model:visible="machineStatsDialog.visible"
 | 
				
			||||||
 | 
					                        :machineId="machineStatsDialog.machineId"
 | 
				
			||||||
 | 
					                        :title="machineStatsDialog.title"
 | 
				
			||||||
 | 
					                    ></machine-stats>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <machine-rec
 | 
				
			||||||
 | 
					                        v-model:visible="machineRecDialog.visible"
 | 
				
			||||||
 | 
					                        :machineId="machineRecDialog.machineId"
 | 
				
			||||||
 | 
					                        :title="machineRecDialog.title"
 | 
				
			||||||
 | 
					                    ></machine-rec>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </Pane>
 | 
				
			||||||
 | 
					        </Splitpanes>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -202,8 +218,9 @@ import { hasPerms } from '@/components/auth/auth';
 | 
				
			|||||||
import { formatByteSize } from '@/common/utils/format';
 | 
					import { formatByteSize } from '@/common/utils/format';
 | 
				
			||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
					import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
				
			||||||
import { SearchItem } from '@/components/SearchForm';
 | 
					import { SearchItem } from '@/components/SearchForm';
 | 
				
			||||||
import { getTagPathSearchItem } from '../component/tag';
 | 
					import { getTagPathSearchItem, NodeType, TagTreeNode } from '../component/tag';
 | 
				
			||||||
 | 
					import TagTree from '../component/TagTree.vue';
 | 
				
			||||||
 | 
					import { Splitpanes, Pane } from 'splitpanes';
 | 
				
			||||||
// 组件
 | 
					// 组件
 | 
				
			||||||
const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
 | 
					const TerminalDialog = defineAsyncComponent(() => import('@/components/terminal/TerminalDialog.vue'));
 | 
				
			||||||
const MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
 | 
					const MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
 | 
				
			||||||
@@ -235,7 +252,6 @@ const columns = [
 | 
				
			|||||||
    TableColumn.new('fs', '磁盘(挂载点=>可用/总)').isSlot().setAddWidth(20),
 | 
					    TableColumn.new('fs', '磁盘(挂载点=>可用/总)').isSlot().setAddWidth(20),
 | 
				
			||||||
    TableColumn.new('username', '用户名'),
 | 
					    TableColumn.new('username', '用户名'),
 | 
				
			||||||
    TableColumn.new('status', '状态').isSlot().setMinWidth(85),
 | 
					    TableColumn.new('status', '状态').isSlot().setMinWidth(85),
 | 
				
			||||||
    TableColumn.new('tagPath', '关联标签').isSlot().setAddWidth(10).alignCenter(),
 | 
					 | 
				
			||||||
    TableColumn.new('remark', '备注'),
 | 
					    TableColumn.new('remark', '备注'),
 | 
				
			||||||
    TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
 | 
					    TableColumn.new('action', '操作').isSlot().setMinWidth(238).fixedRight().alignCenter(),
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
@@ -243,6 +259,10 @@ const columns = [
 | 
				
			|||||||
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
 | 
					// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
 | 
				
			||||||
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
 | 
					const actionBtns = hasPerms([perms.updateMachine, perms.closeCli]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MachineNodeType {
 | 
				
			||||||
 | 
					    static Machine = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state = reactive({
 | 
					const state = reactive({
 | 
				
			||||||
    params: {
 | 
					    params: {
 | 
				
			||||||
        pageNum: 1,
 | 
					        pageNum: 1,
 | 
				
			||||||
@@ -251,6 +271,7 @@ const state = reactive({
 | 
				
			|||||||
        name: null,
 | 
					        name: null,
 | 
				
			||||||
        tagPath: '',
 | 
					        tagPath: '',
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    pageData: [] as any[],
 | 
				
			||||||
    infoDialog: {
 | 
					    infoDialog: {
 | 
				
			||||||
        visible: false,
 | 
					        visible: false,
 | 
				
			||||||
        data: null as any,
 | 
					        data: null as any,
 | 
				
			||||||
@@ -291,7 +312,21 @@ const state = reactive({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const { params, infoDialog, selectionData, serviceDialog, processDialog, fileDialog, machineStatsDialog, machineEditDialog, machineRecDialog } = toRefs(state);
 | 
					const { params, infoDialog, selectionData, serviceDialog, processDialog, fileDialog, machineStatsDialog, machineEditDialog, machineRecDialog } = toRefs(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
onMounted(async () => {});
 | 
					const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath).withLoadNodesFunc(async (node: any) => {
 | 
				
			||||||
 | 
					    // 加载标签树下的机器列表
 | 
				
			||||||
 | 
					    state.params.tagPath = node.key;
 | 
				
			||||||
 | 
					    state.params.pageNum = 1;
 | 
				
			||||||
 | 
					    state.params.pageSize = 1000;
 | 
				
			||||||
 | 
					    const res = await search();
 | 
				
			||||||
 | 
					    // 把list 根据name字段排序
 | 
				
			||||||
 | 
					    res.list = res.list.sort((a: any, b: any) => a.name.localeCompare(b.name));
 | 
				
			||||||
 | 
					    state.pageData = res.list;
 | 
				
			||||||
 | 
					    return res.list.map((x: any) => new TagTreeNode(x.id, x.name, NodeTypeMachine).withParams(x).withIsLeaf(true));
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const NodeTypeMachine = new NodeType(MachineNodeType.Machine).withNodeClickFunc((node: any) => {
 | 
				
			||||||
 | 
					    state.pageData = [node.params];
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const checkRouteTagPath = (query: any) => {
 | 
					const checkRouteTagPath = (query: any) => {
 | 
				
			||||||
    if (route.query.tagPath) {
 | 
					    if (route.query.tagPath) {
 | 
				
			||||||
@@ -421,7 +456,9 @@ const showMachineStats = async (machine: any) => {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const search = async () => {
 | 
					const search = async () => {
 | 
				
			||||||
    pageTableRef.value.search();
 | 
					    const res = await machineApi.list.request(state.params);
 | 
				
			||||||
 | 
					    state.pageData = res.list;
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const submitSuccess = () => {
 | 
					const submitSuccess = () => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -154,7 +154,7 @@ func (d *dbAppImpl) GetDbConn(dbId uint64, dbName string) (*dbi.DbConn, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		checkDb := dbName
 | 
							checkDb := dbName
 | 
				
			||||||
		// 兼容pgsql/dm db/schema模式
 | 
							// 兼容pgsql/dm db/schema模式
 | 
				
			||||||
		if dbi.DbTypePostgres.Equal(instance.Type) || dbi.DbTypeGauss.Equal(instance.Type) || dbi.DbTypeDM.Equal(instance.Type) || dbi.DbTypeOracle.Equal(instance.Type) || dbi.DbTypeMssql.Equal(instance.Type) {
 | 
							if dbi.DbTypePostgres.Equal(instance.Type) || dbi.DbTypeGauss.Equal(instance.Type) || dbi.DbTypeDM.Equal(instance.Type) || dbi.DbTypeOracle.Equal(instance.Type) || dbi.DbTypeMssql.Equal(instance.Type) || dbi.DbTypeKingbaseEs.Equal(instance.Type) || dbi.DbTypeVastbase.Equal(instance.Type) {
 | 
				
			||||||
			ss := strings.Split(dbName, "/")
 | 
								ss := strings.Split(dbName, "/")
 | 
				
			||||||
			if len(ss) > 1 {
 | 
								if len(ss) > 1 {
 | 
				
			||||||
				checkDb = ss[0]
 | 
									checkDb = ss[0]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,14 +11,16 @@ import (
 | 
				
			|||||||
type DbType string
 | 
					type DbType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	DbTypeMysql    DbType = "mysql"
 | 
						DbTypeMysql      DbType = "mysql"
 | 
				
			||||||
	DbTypeMariadb  DbType = "mariadb"
 | 
						DbTypeMariadb    DbType = "mariadb"
 | 
				
			||||||
	DbTypePostgres DbType = "postgres"
 | 
						DbTypePostgres   DbType = "postgres"
 | 
				
			||||||
	DbTypeGauss    DbType = "gauss"
 | 
						DbTypeGauss      DbType = "gauss"
 | 
				
			||||||
	DbTypeDM       DbType = "dm"
 | 
						DbTypeDM         DbType = "dm"
 | 
				
			||||||
	DbTypeOracle   DbType = "oracle"
 | 
						DbTypeOracle     DbType = "oracle"
 | 
				
			||||||
	DbTypeSqlite   DbType = "sqlite"
 | 
						DbTypeSqlite     DbType = "sqlite"
 | 
				
			||||||
	DbTypeMssql    DbType = "mssql"
 | 
						DbTypeMssql      DbType = "mssql"
 | 
				
			||||||
 | 
						DbTypeKingbaseEs DbType = "kingbaseEs"
 | 
				
			||||||
 | 
						DbTypeVastbase   DbType = "vastbase"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ToDbType(dbType string) DbType {
 | 
					func ToDbType(dbType string) DbType {
 | 
				
			||||||
@@ -44,7 +46,7 @@ func (dbType DbType) QuoteIdentifier(name string) string {
 | 
				
			|||||||
	switch dbType {
 | 
						switch dbType {
 | 
				
			||||||
	case DbTypeMysql, DbTypeMariadb:
 | 
						case DbTypeMysql, DbTypeMariadb:
 | 
				
			||||||
		return quoteIdentifier(name, "`")
 | 
							return quoteIdentifier(name, "`")
 | 
				
			||||||
	case DbTypePostgres, DbTypeGauss:
 | 
						case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
				
			||||||
		return quoteIdentifier(name, `"`)
 | 
							return quoteIdentifier(name, `"`)
 | 
				
			||||||
	case DbTypeMssql:
 | 
						case DbTypeMssql:
 | 
				
			||||||
		return fmt.Sprintf("[%s]", name)
 | 
							return fmt.Sprintf("[%s]", name)
 | 
				
			||||||
@@ -57,7 +59,7 @@ func (dbType DbType) RemoveQuote(name string) string {
 | 
				
			|||||||
	switch dbType {
 | 
						switch dbType {
 | 
				
			||||||
	case DbTypeMysql, DbTypeMariadb:
 | 
						case DbTypeMysql, DbTypeMariadb:
 | 
				
			||||||
		return removeQuote(name, "`")
 | 
							return removeQuote(name, "`")
 | 
				
			||||||
	case DbTypePostgres, DbTypeGauss:
 | 
						case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
				
			||||||
		return removeQuote(name, `"`)
 | 
							return removeQuote(name, `"`)
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return removeQuote(name, `"`)
 | 
							return removeQuote(name, `"`)
 | 
				
			||||||
@@ -70,7 +72,7 @@ func (dbType DbType) QuoteLiteral(literal string) string {
 | 
				
			|||||||
		literal = strings.ReplaceAll(literal, `\`, `\\`)
 | 
							literal = strings.ReplaceAll(literal, `\`, `\\`)
 | 
				
			||||||
		literal = strings.ReplaceAll(literal, `'`, `''`)
 | 
							literal = strings.ReplaceAll(literal, `'`, `''`)
 | 
				
			||||||
		return "'" + literal + "'"
 | 
							return "'" + literal + "'"
 | 
				
			||||||
	case DbTypePostgres, DbTypeGauss:
 | 
						case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
				
			||||||
		return pq.QuoteLiteral(literal)
 | 
							return pq.QuoteLiteral(literal)
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return pq.QuoteLiteral(literal)
 | 
							return pq.QuoteLiteral(literal)
 | 
				
			||||||
@@ -85,6 +87,10 @@ func (dbType DbType) MetaDbName() string {
 | 
				
			|||||||
		return "postgres"
 | 
							return "postgres"
 | 
				
			||||||
	case DbTypeDM:
 | 
						case DbTypeDM:
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
 | 
						case DbTypeKingbaseEs:
 | 
				
			||||||
 | 
							return "security"
 | 
				
			||||||
 | 
						case DbTypeVastbase:
 | 
				
			||||||
 | 
							return "vastbase"
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -94,7 +100,7 @@ func (dbType DbType) Dialect() sqlparser.Dialect {
 | 
				
			|||||||
	switch dbType {
 | 
						switch dbType {
 | 
				
			||||||
	case DbTypeMysql, DbTypeMariadb:
 | 
						case DbTypeMysql, DbTypeMariadb:
 | 
				
			||||||
		return sqlparser.MysqlDialect{}
 | 
							return sqlparser.MysqlDialect{}
 | 
				
			||||||
	case DbTypePostgres, DbTypeGauss:
 | 
						case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
				
			||||||
		return sqlparser.PostgresDialect{}
 | 
							return sqlparser.PostgresDialect{}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return sqlparser.PostgresDialect{}
 | 
							return sqlparser.PostgresDialect{}
 | 
				
			||||||
@@ -122,7 +128,7 @@ func (dbType DbType) StmtSetForeignKeyChecks(check bool) string {
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			return "SET FOREIGN_KEY_CHECKS = 0;\n"
 | 
								return "SET FOREIGN_KEY_CHECKS = 0;\n"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case DbTypePostgres, DbTypeGauss:
 | 
						case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
				
			||||||
		// not currently supported postgres
 | 
							// not currently supported postgres
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
@@ -134,7 +140,7 @@ func (dbType DbType) StmtUseDatabase(dbName string) string {
 | 
				
			|||||||
	switch dbType {
 | 
						switch dbType {
 | 
				
			||||||
	case DbTypeMysql, DbTypeMariadb:
 | 
						case DbTypeMysql, DbTypeMariadb:
 | 
				
			||||||
		return fmt.Sprintf("USE %s;\n", dbType.QuoteIdentifier(dbName))
 | 
							return fmt.Sprintf("USE %s;\n", dbType.QuoteIdentifier(dbName))
 | 
				
			||||||
	case DbTypePostgres, DbTypeGauss:
 | 
						case DbTypePostgres, DbTypeGauss, DbTypeKingbaseEs, DbTypeVastbase:
 | 
				
			||||||
		// not currently supported postgres
 | 
							// not currently supported postgres
 | 
				
			||||||
		return ""
 | 
							return ""
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,6 @@
 | 
				
			|||||||
--MSSQL_DBS 数据库名信息
 | 
					--MSSQL_DBS 数据库名信息
 | 
				
			||||||
SELECT name AS dbname
 | 
					SELECT name AS dbname
 | 
				
			||||||
FROM sys.databases
 | 
					FROM sys.databases
 | 
				
			||||||
WHERE owner_sid = SUSER_SID()
 | 
					 | 
				
			||||||
  and name not in ('master', 'tempdb', 'model', 'msdb')
 | 
					 | 
				
			||||||
---------------------------------------
 | 
					---------------------------------------
 | 
				
			||||||
--MSSQL_TABLE_DETAIL 查询表名和表注释
 | 
					--MSSQL_TABLE_DETAIL 查询表名和表注释
 | 
				
			||||||
SELECT t.name   AS tableName,
 | 
					SELECT t.name   AS tableName,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
--ORACLE_DB_SCHEMAS 库schemas
 | 
					--ORACLE_DB_SCHEMAS 库schemas
 | 
				
			||||||
select distinct owner as SCHEMA_NAME
 | 
					select USERNAME
 | 
				
			||||||
from all_objects
 | 
					from sys.all_users
 | 
				
			||||||
order by owner
 | 
					order by USERNAME
 | 
				
			||||||
---------------------------------------
 | 
					---------------------------------------
 | 
				
			||||||
--ORACLE_TABLE_INFO 表详细信息
 | 
					--ORACLE_TABLE_INFO 表详细信息
 | 
				
			||||||
select a.TABLE_NAME,
 | 
					select a.TABLE_NAME,
 | 
				
			||||||
@@ -10,9 +10,9 @@ select a.TABLE_NAME,
 | 
				
			|||||||
       d.BYTES    as DATA_LENGTH,
 | 
					       d.BYTES    as DATA_LENGTH,
 | 
				
			||||||
       0          as INDEX_LENGTH,
 | 
					       0          as INDEX_LENGTH,
 | 
				
			||||||
       a.NUM_ROWS as TABLE_ROWS
 | 
					       a.NUM_ROWS as TABLE_ROWS
 | 
				
			||||||
from all_tables a
 | 
					from ALL_TABLES a
 | 
				
			||||||
         left join ALL_TAB_COMMENTS b on b.TABLE_NAME = a.TABLE_NAME AND b.OWNER = a.OWNER
 | 
					         left join ALL_TAB_COMMENTS b on b.TABLE_NAME = a.TABLE_NAME AND b.OWNER = a.OWNER
 | 
				
			||||||
         left join all_objects c on c.OBJECT_TYPE = 'TABLE' AND c.OWNER = a.OWNER AND c.OBJECT_NAME = a.TABLE_NAME
 | 
					         left join ALL_OBJECTS c on c.OBJECT_TYPE = 'TABLE' AND c.OWNER = a.OWNER AND c.OBJECT_NAME = a.TABLE_NAME
 | 
				
			||||||
         left join dba_segments d on d.SEGMENT_TYPE = 'TABLE' AND d.OWNER = a.OWNER AND d.SEGMENT_NAME = a.TABLE_NAME
 | 
					         left join dba_segments d on d.SEGMENT_TYPE = 'TABLE' AND d.OWNER = a.OWNER AND d.SEGMENT_NAME = a.TABLE_NAME
 | 
				
			||||||
where a.owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
 | 
					where a.owner = (SELECT sys_context('USERENV', 'CURRENT_SCHEMA') FROM dual)
 | 
				
			||||||
ORDER BY a.TABLE_NAME
 | 
					ORDER BY a.TABLE_NAME
 | 
				
			||||||
@@ -55,12 +55,12 @@ SELECT a.TABLE_NAME                                              as TABLE_NAME,
 | 
				
			|||||||
       a.DATA_SCALE                                              as NUM_SCALE,
 | 
					       a.DATA_SCALE                                              as NUM_SCALE,
 | 
				
			||||||
       CASE WHEN d.pri IS NOT NULL THEN 1 ELSE 0 END         as IS_PRIMARY_KEY,
 | 
					       CASE WHEN d.pri IS NOT NULL THEN 1 ELSE 0 END         as IS_PRIMARY_KEY,
 | 
				
			||||||
       CASE WHEN a.IDENTITY_COLUMN = 'YES' THEN 1 ELSE 0 END as IS_IDENTITY
 | 
					       CASE WHEN a.IDENTITY_COLUMN = 'YES' THEN 1 ELSE 0 END as IS_IDENTITY
 | 
				
			||||||
FROM all_tab_columns a
 | 
					FROM ALL_TAB_COLUMNS a
 | 
				
			||||||
         LEFT JOIN all_col_comments b
 | 
					         LEFT JOIN ALL_COL_COMMENTS b
 | 
				
			||||||
                   on a.OWNER = b.OWNER AND a.TABLE_NAME = b.TABLE_NAME AND a.COLUMN_NAME = b.COLUMN_NAME
 | 
					                   on a.OWNER = b.OWNER AND a.TABLE_NAME = b.TABLE_NAME AND a.COLUMN_NAME = b.COLUMN_NAME
 | 
				
			||||||
         LEFT JOIN (select ac.TABLE_NAME, ac.OWNER, cc.COLUMN_NAME, 1 as pri
 | 
					         LEFT JOIN (select ac.TABLE_NAME, ac.OWNER, cc.COLUMN_NAME, 1 as pri
 | 
				
			||||||
                    from all_constraints ac
 | 
					                    from ALL_CONSTRAINTS ac
 | 
				
			||||||
                             join all_cons_columns cc on cc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME AND cc.OWNER = ac.OWNER
 | 
					                             join ALL_CONS_COLUMNS cc on cc.CONSTRAINT_NAME = ac.CONSTRAINT_NAME AND cc.OWNER = ac.OWNER
 | 
				
			||||||
                    where cc.CONSTRAINT_NAME IS NOT NULL
 | 
					                    where cc.CONSTRAINT_NAME IS NOT NULL
 | 
				
			||||||
                      AND ac.CONSTRAINT_TYPE = 'P') d
 | 
					                      AND ac.CONSTRAINT_TYPE = 'P') d
 | 
				
			||||||
                   on d.OWNER = a.OWNER AND d.TABLE_NAME = a.TABLE_NAME AND d.COLUMN_NAME = a.COLUMN_NAME
 | 
					                   on d.OWNER = a.OWNER AND d.TABLE_NAME = a.TABLE_NAME AND d.COLUMN_NAME = a.COLUMN_NAME
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,8 +38,17 @@ func (md *Meta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
 | 
				
			|||||||
			query.Add("database", d.Database)
 | 
								query.Add("database", d.Database)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						params := query.Encode()
 | 
				
			||||||
 | 
						if d.Params != "" {
 | 
				
			||||||
 | 
							if !strings.HasPrefix(d.Params, "&") {
 | 
				
			||||||
 | 
								params = params + "&" + d.Params
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								params = params + d.Params
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const driverName = "mssql"
 | 
						const driverName = "mssql"
 | 
				
			||||||
	dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%d?%s", url.PathEscape(d.Username), url.PathEscape(d.Password), d.Host, d.Port, query.Encode())
 | 
						dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%d?%s", url.PathEscape(d.Username), url.PathEscape(d.Password), d.Host, d.Port, params)
 | 
				
			||||||
	return sql.Open(driverName, dsn)
 | 
						return sql.Open(driverName, dsn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -242,7 +242,7 @@ func (od *OracleDialect) GetSchemas() ([]string, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	schemaNames := make([]string, 0)
 | 
						schemaNames := make([]string, 0)
 | 
				
			||||||
	for _, re := range res {
 | 
						for _, re := range res {
 | 
				
			||||||
		schemaNames = append(schemaNames, anyx.ConvString(re["SCHEMA_NAME"]))
 | 
							schemaNames = append(schemaNames, anyx.ConvString(re["USERNAME"]))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return schemaNames, nil
 | 
						return schemaNames, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,7 +26,7 @@ type PgsqlDialect struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (md *PgsqlDialect) GetDbServer() (*dbi.DbServer, error) {
 | 
					func (md *PgsqlDialect) GetDbServer() (*dbi.DbServer, error) {
 | 
				
			||||||
	_, res, err := md.dc.Query("SHOW server_version")
 | 
						_, res, err := md.dc.Query("SELECT version() as server_version")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,10 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
					func init() {
 | 
				
			||||||
	dbi.Register(dbi.DbTypePostgres, new(PostgresMeta))
 | 
						meta := new(PostgresMeta)
 | 
				
			||||||
 | 
						dbi.Register(dbi.DbTypePostgres, meta)
 | 
				
			||||||
 | 
						dbi.Register(dbi.DbTypeKingbaseEs, meta)
 | 
				
			||||||
 | 
						dbi.Register(dbi.DbTypeVastbase, meta)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gauss := new(PostgresMeta)
 | 
						gauss := new(PostgresMeta)
 | 
				
			||||||
	gauss.Param = "dbtype=gauss"
 | 
						gauss.Param = "dbtype=gauss"
 | 
				
			||||||
@@ -40,16 +43,17 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	db := d.Database
 | 
						db := d.Database
 | 
				
			||||||
	var dbParam string
 | 
						var dbParam string
 | 
				
			||||||
	exsitSchema := false
 | 
						existSchema := false
 | 
				
			||||||
	if db != "" {
 | 
						if db == "" {
 | 
				
			||||||
		// postgres database可以使用db/schema表示,方便连接指定schema, 若不存在schema则使用默认schema
 | 
							db = d.Type.MetaDbName()
 | 
				
			||||||
		ss := strings.Split(db, "/")
 | 
						}
 | 
				
			||||||
		if len(ss) > 1 {
 | 
						// postgres database可以使用db/schema表示,方便连接指定schema, 若不存在schema则使用默认schema
 | 
				
			||||||
			exsitSchema = true
 | 
						ss := strings.Split(db, "/")
 | 
				
			||||||
			dbParam = fmt.Sprintf("dbname=%s search_path=%s", ss[0], ss[len(ss)-1])
 | 
						if len(ss) > 1 {
 | 
				
			||||||
		} else {
 | 
							existSchema = true
 | 
				
			||||||
			dbParam = "dbname=" + db
 | 
							dbParam = fmt.Sprintf("dbname=%s search_path=%s", ss[0], ss[len(ss)-1])
 | 
				
			||||||
		}
 | 
						} else {
 | 
				
			||||||
 | 
							dbParam = "dbname=" + db
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s %s sslmode=disable connect_timeout=8", d.Host, d.Port, d.Username, d.Password, dbParam)
 | 
						dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s %s sslmode=disable connect_timeout=8", d.Host, d.Port, d.Username, d.Password, dbParam)
 | 
				
			||||||
@@ -62,7 +66,7 @@ func (md *PostgresMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
 | 
				
			|||||||
				if strings.HasPrefix(param, "dbname=") {
 | 
									if strings.HasPrefix(param, "dbname=") {
 | 
				
			||||||
					return true
 | 
										return true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if exsitSchema && strings.HasPrefix(param, "search_path") {
 | 
									if existSchema && strings.HasPrefix(param, "search_path") {
 | 
				
			||||||
					return true
 | 
										return true
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return false
 | 
									return false
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user