mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-12-10 01:40:25 +08:00
fix: some issue
This commit is contained in:
@@ -11,7 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@vueuse/core": "^12.7.0",
|
"@vueuse/core": "^12.8.2",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-search": "^0.15.0",
|
"@xterm/addon-search": "^0.15.0",
|
||||||
"@xterm/addon-web-links": "^0.11.0",
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
@@ -59,9 +59,9 @@
|
|||||||
"eslint": "^8.35.0",
|
"eslint": "^8.35.0",
|
||||||
"eslint-plugin-vue": "^9.31.0",
|
"eslint-plugin-vue": "^9.31.0",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"sass": "^1.85.0",
|
"sass": "^1.85.1",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.8.2",
|
||||||
"vite": "^6.2.0",
|
"vite": "^6.2.1",
|
||||||
"vite-plugin-progress": "0.0.7",
|
"vite-plugin-progress": "0.0.7",
|
||||||
"vue-eslint-parser": "^9.4.3"
|
"vue-eslint-parser": "^9.4.3"
|
||||||
},
|
},
|
||||||
|
|||||||
32
frontend/src/views/ops/component/ResourceOpPanel.vue
Normal file
32
frontend/src/views/ops/component/ResourceOpPanel.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<Splitpanes class="default-theme" @resize="handleResize">
|
||||||
|
<Pane :size="leftPaneSize" max-size="30">
|
||||||
|
<slot name="left"></slot>
|
||||||
|
</Pane>
|
||||||
|
|
||||||
|
<Pane>
|
||||||
|
<slot name="right"></slot>
|
||||||
|
</Pane>
|
||||||
|
</Splitpanes>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Pane, Splitpanes } from 'splitpanes';
|
||||||
|
import { useWindowSize } from '@vueuse/core';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['resize']);
|
||||||
|
|
||||||
|
const { width } = useWindowSize();
|
||||||
|
|
||||||
|
console.log(width);
|
||||||
|
|
||||||
|
const leftPaneSize = computed(() => (width.value >= 1600 ? 20 : 25));
|
||||||
|
|
||||||
|
// 处理 resize 事件
|
||||||
|
const handleResize = (event: any) => {
|
||||||
|
emit('resize', event);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss"></style>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="db-sql-exec">
|
<div class="db-sql-exec">
|
||||||
<Splitpanes class="default-theme">
|
<ResourceOpPanel>
|
||||||
<Pane size="20" max-size="30">
|
<template #left>
|
||||||
<tag-tree
|
<tag-tree
|
||||||
:default-expanded-keys="state.defaultExpendKey"
|
:default-expanded-keys="state.defaultExpendKey"
|
||||||
:resource-type="TagResourceTypePath.Db"
|
:resource-type="TagResourceTypePath.Db"
|
||||||
@@ -51,9 +51,9 @@
|
|||||||
<span v-if="data.type.value == SqlExecNodeType.TableMenu && data.params.dbTableSize">{{ ` ${data.params.dbTableSize}` }}</span>
|
<span v-if="data.type.value == SqlExecNodeType.TableMenu && data.params.dbTableSize">{{ ` ${data.params.dbTableSize}` }}</span>
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</Pane>
|
</template>
|
||||||
|
|
||||||
<Pane>
|
<template #right>
|
||||||
<div class="card db-op pd5">
|
<div class="card db-op pd5">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="24" v-if="state.db">
|
<el-col :span="24" v-if="state.db">
|
||||||
@@ -211,8 +211,9 @@
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</template>
|
||||||
</Splitpanes>
|
</ResourceOpPanel>
|
||||||
|
|
||||||
<db-table-op
|
<db-table-op
|
||||||
:title="tableCreateDialog.title"
|
:title="tableCreateDialog.title"
|
||||||
:active-name="tableCreateDialog.activeName"
|
:active-name="tableCreateDialog.activeName"
|
||||||
@@ -247,7 +248,6 @@ import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
|||||||
import { getDbDialect, schemaDbTypes } from './dialect/index';
|
import { getDbDialect, schemaDbTypes } from './dialect/index';
|
||||||
import { sleep } from '@/common/utils/loading';
|
import { sleep } from '@/common/utils/loading';
|
||||||
import { TagResourceTypeEnum, TagResourceTypePath } from '@/common/commonEnum';
|
import { TagResourceTypeEnum, TagResourceTypePath } from '@/common/commonEnum';
|
||||||
import { Pane, Splitpanes } from 'splitpanes';
|
|
||||||
import { useEventListener, useStorage } from '@vueuse/core';
|
import { useEventListener, useStorage } from '@vueuse/core';
|
||||||
import SqlExecBox from '@/views/ops/db/component/sqleditor/SqlExecBox';
|
import SqlExecBox from '@/views/ops/db/component/sqleditor/SqlExecBox';
|
||||||
import { useAutoOpenResource } from '@/store/autoOpenResource';
|
import { useAutoOpenResource } from '@/store/autoOpenResource';
|
||||||
@@ -256,6 +256,7 @@ import { format as sqlFormatter } from 'sql-formatter';
|
|||||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle, useI18nOperateSuccessMsg } from '@/hooks/useI18n';
|
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle, useI18nOperateSuccessMsg } from '@/hooks/useI18n';
|
||||||
|
import ResourceOpPanel from '../component/ResourceOpPanel.vue';
|
||||||
|
|
||||||
const DbTableOp = defineAsyncComponent(() => import('./component/table/DbTableOp.vue'));
|
const DbTableOp = defineAsyncComponent(() => import('./component/table/DbTableOp.vue'));
|
||||||
const DbSqlEditor = defineAsyncComponent(() => import('./component/sqleditor/DbSqlEditor.vue'));
|
const DbSqlEditor = defineAsyncComponent(() => import('./component/sqleditor/DbSqlEditor.vue'));
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
|
|
||||||
<el-dialog width="40%" :title="`${chooseTableName} ${$t('db.column')}`" v-model="columnDialog.visible">
|
<el-dialog width="40%" :title="`${chooseTableName} ${$t('db.column')}`" v-model="columnDialog.visible">
|
||||||
<el-table border stripe :data="columnDialog.columns" size="small">
|
<el-table border stripe :data="columnDialog.columns" size="small">
|
||||||
<el-table-column prop="columnName" :label="$t('common.columnName')" show-overflow-tooltip> </el-table-column>
|
<el-table-column prop="columnName" :label="$t('db.columnName')" show-overflow-tooltip> </el-table-column>
|
||||||
<el-table-column width="120" prop="columnType" :label="$t('common.type')" show-overflow-tooltip> </el-table-column>
|
<el-table-column width="120" prop="columnType" :label="$t('common.type')" show-overflow-tooltip> </el-table-column>
|
||||||
<el-table-column width="80" prop="nullable" :label="$t('db.nullable')" show-overflow-tooltip> </el-table-column>
|
<el-table-column width="80" prop="nullable" :label="$t('db.nullable')" show-overflow-tooltip> </el-table-column>
|
||||||
<el-table-column prop="columnComment" :label="$t('db.comment')" show-overflow-tooltip> </el-table-column>
|
<el-table-column prop="columnComment" :label="$t('db.comment')" show-overflow-tooltip> </el-table-column>
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ const searchItems = [
|
|||||||
const columns = [
|
const columns = [
|
||||||
TableColumn.new('tags[0].tagPath', 'tag.relateTag').isSlot('tagPath').setAddWidth(20),
|
TableColumn.new('tags[0].tagPath', 'tag.relateTag').isSlot('tagPath').setAddWidth(20),
|
||||||
TableColumn.new('name', 'common.name'),
|
TableColumn.new('name', 'common.name'),
|
||||||
TableColumn.new('ipPort', 'Ip:Port').isSlot().setAddWidth(50),
|
TableColumn.new('ipPort', 'Ip:Port').isSlot().setAddWidth(55),
|
||||||
TableColumn.new('authCerts[0].username', 'machine.acName').isSlot('authCert').setAddWidth(10),
|
TableColumn.new('authCerts[0].username', 'machine.acName').isSlot('authCert').setAddWidth(10),
|
||||||
TableColumn.new('status', 'common.status').isSlot().setAddWidth(5),
|
TableColumn.new('status', 'common.status').isSlot().setAddWidth(5),
|
||||||
TableColumn.new('stat', 'machine.runningStat').isSlot().setAddWidth(55),
|
TableColumn.new('stat', 'machine.runningStat').isSlot().setAddWidth(55),
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-all-center">
|
<div class="flex-all-center">
|
||||||
<!-- 文档: https://antoniandre.github.io/splitpanes/ -->
|
<ResourceOpPanel @resized="onResizeTagTree">
|
||||||
<Splitpanes class="default-theme" @resized="onResizeTagTree">
|
<template #left>
|
||||||
<Pane size="20" max-size="30">
|
|
||||||
<tag-tree
|
<tag-tree
|
||||||
class="machine-terminal-tree"
|
class="machine-terminal-tree"
|
||||||
ref="tagTreeRef"
|
ref="tagTreeRef"
|
||||||
@@ -30,9 +29,9 @@
|
|||||||
}}</span>
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</Pane>
|
</template>
|
||||||
|
|
||||||
<Pane>
|
<template #right>
|
||||||
<div class="machine-terminal-tabs card pd5">
|
<div class="machine-terminal-tabs card pd5">
|
||||||
<el-tabs v-if="state.tabs.size > 0" type="card" @tab-remove="onRemoveTab" style="width: 100%" v-model="state.activeTermName" class="h100">
|
<el-tabs v-if="state.tabs.size > 0" type="card" @tab-remove="onRemoveTab" style="width: 100%" v-model="state.activeTermName" class="h100">
|
||||||
<el-tab-pane class="h100" closable v-for="dt in state.tabs.values()" :label="dt.label" :name="dt.key" :key="dt.key">
|
<el-tab-pane class="h100" closable v-for="dt in state.tabs.values()" :label="dt.label" :name="dt.key" :key="dt.key">
|
||||||
@@ -157,8 +156,8 @@
|
|||||||
|
|
||||||
<machine-rec v-model:visible="machineRecDialog.visible" :machineId="machineRecDialog.machineId" :title="machineRecDialog.title" />
|
<machine-rec v-model:visible="machineRecDialog.visible" :machineId="machineRecDialog.machineId" :title="machineRecDialog.title" />
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</template>
|
||||||
</Splitpanes>
|
</ResourceOpPanel>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -171,7 +170,6 @@ import { hasPerms } from '@/components/auth/auth';
|
|||||||
import { TagResourceTypeEnum, TagResourceTypePath } from '@/common/commonEnum';
|
import { TagResourceTypeEnum, TagResourceTypePath } from '@/common/commonEnum';
|
||||||
import { NodeType, TagTreeNode, getTagTypeCodeByPath } from '../component/tag';
|
import { NodeType, TagTreeNode, getTagTypeCodeByPath } from '../component/tag';
|
||||||
import TagTree from '../component/TagTree.vue';
|
import TagTree from '../component/TagTree.vue';
|
||||||
import { Pane, Splitpanes } from 'splitpanes';
|
|
||||||
import { ContextmenuItem } from '@/components/contextmenu/index';
|
import { ContextmenuItem } from '@/components/contextmenu/index';
|
||||||
import TerminalBody from '@/components/terminal/TerminalBody.vue';
|
import TerminalBody from '@/components/terminal/TerminalBody.vue';
|
||||||
import { TerminalStatus, TerminalStatusEnum } from '@/components/terminal/common';
|
import { TerminalStatus, TerminalStatusEnum } from '@/components/terminal/common';
|
||||||
@@ -183,6 +181,7 @@ import { useAutoOpenResource } from '@/store/autoOpenResource';
|
|||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import EnumValue from '@/common/Enum';
|
import EnumValue from '@/common/Enum';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import ResourceOpPanel from '../component/ResourceOpPanel.vue';
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
const ScriptManage = defineAsyncComponent(() => import('./ScriptManage.vue'));
|
const ScriptManage = defineAsyncComponent(() => import('./ScriptManage.vue'));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-all-center">
|
<div class="flex-all-center">
|
||||||
<Splitpanes class="default-theme">
|
<ResourceOpPanel>
|
||||||
<Pane size="20" max-size="30">
|
<template #left>
|
||||||
<tag-tree
|
<tag-tree
|
||||||
ref="tagTreeRef"
|
ref="tagTreeRef"
|
||||||
:default-expanded-keys="state.defaultExpendKey"
|
:default-expanded-keys="state.defaultExpendKey"
|
||||||
@@ -40,9 +40,9 @@
|
|||||||
<span v-if="data.type.value == MongoNodeType.Dbs">{{ formatByteSize(data.params.size) }}</span>
|
<span v-if="data.type.value == MongoNodeType.Dbs">{{ formatByteSize(data.params.size) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</Pane>
|
</template>
|
||||||
|
|
||||||
<Pane>
|
<template #right>
|
||||||
<div class="mongo-data-tab card pd5 w100">
|
<div class="mongo-data-tab card pd5 w100">
|
||||||
<el-row v-if="nowColl">
|
<el-row v-if="nowColl">
|
||||||
<el-descriptions class="w100" :column="10" size="small" border>
|
<el-descriptions class="w100" :column="10" size="small" border>
|
||||||
@@ -121,8 +121,8 @@
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</Pane>
|
</template>
|
||||||
</Splitpanes>
|
</ResourceOpPanel>
|
||||||
|
|
||||||
<el-dialog width="600px" title="find params" v-model="findDialog.visible">
|
<el-dialog width="600px" title="find params" v-model="findDialog.visible">
|
||||||
<el-form label-width="auto">
|
<el-form label-width="auto">
|
||||||
@@ -177,11 +177,11 @@ import TagTree from '../component/TagTree.vue';
|
|||||||
import { formatByteSize } from '@/common/utils/format';
|
import { formatByteSize } from '@/common/utils/format';
|
||||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||||
import { sleep } from '@/common/utils/loading';
|
import { sleep } from '@/common/utils/loading';
|
||||||
import { Splitpanes, Pane } from 'splitpanes';
|
|
||||||
import { useAutoOpenResource } from '@/store/autoOpenResource';
|
import { useAutoOpenResource } from '@/store/autoOpenResource';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useI18nDeleteSuccessMsg, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
import { useI18nDeleteSuccessMsg, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||||
|
import ResourceOpPanel from '../component/ResourceOpPanel.vue';
|
||||||
|
|
||||||
const MonacoEditor = defineAsyncComponent(() => import('@/components/monaco/MonacoEditor.vue'));
|
const MonacoEditor = defineAsyncComponent(() => import('@/components/monaco/MonacoEditor.vue'));
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="redis-data-op flex-all-center">
|
<div class="redis-data-op flex-all-center">
|
||||||
<Splitpanes class="default-theme">
|
<ResourceOpPanel>
|
||||||
<Pane size="20" max-size="30">
|
<template #left>
|
||||||
<tag-tree
|
<tag-tree
|
||||||
ref="tagTreeRef"
|
ref="tagTreeRef"
|
||||||
:default-expanded-keys="state.defaultExpendKey"
|
:default-expanded-keys="state.defaultExpendKey"
|
||||||
@@ -40,122 +40,126 @@
|
|||||||
<span v-if="data.type.value == RedisNodeType.Db">{{ data.params.keys }}</span>
|
<span v-if="data.type.value == RedisNodeType.Db">{{ data.params.keys }}</span>
|
||||||
</template>
|
</template>
|
||||||
</tag-tree>
|
</tag-tree>
|
||||||
</Pane>
|
</template>
|
||||||
|
|
||||||
<Pane min-size="20" size="30">
|
<template #right>
|
||||||
<div class="key-list-vtree card pd5">
|
<Splitpanes class="default-theme">
|
||||||
<el-scrollbar>
|
<Pane size="40" max-size="45">
|
||||||
<el-row>
|
<div class="key-list-vtree card pd5">
|
||||||
<el-col :span="2">
|
<el-scrollbar>
|
||||||
<el-input v-model="state.keySeparator" :placeholder="$t('redis.delimiter')" size="small" class="ml5" />
|
<el-row>
|
||||||
</el-col>
|
<el-col :span="2">
|
||||||
<el-col :span="18">
|
<el-input v-model="state.keySeparator" :placeholder="$t('redis.delimiter')" size="small" class="ml5" />
|
||||||
<el-input
|
</el-col>
|
||||||
@clear="clear"
|
<el-col :span="18">
|
||||||
v-model="scanParam.match"
|
<el-input
|
||||||
@keyup.enter.native="searchKey()"
|
@clear="clear"
|
||||||
:placeholder="$t('redis.keyMatchTips')"
|
v-model="scanParam.match"
|
||||||
clearable
|
@keyup.enter.native="searchKey()"
|
||||||
size="small"
|
:placeholder="$t('redis.keyMatchTips')"
|
||||||
class="ml10"
|
clearable
|
||||||
/>
|
size="small"
|
||||||
</el-col>
|
class="ml10"
|
||||||
<el-col :span="4">
|
/>
|
||||||
<el-button
|
</el-col>
|
||||||
class="ml15"
|
<el-col :span="4">
|
||||||
:disabled="!scanParam.id || !scanParam.db"
|
<el-button
|
||||||
@click="searchKey()"
|
class="ml15"
|
||||||
type="success"
|
:disabled="!scanParam.id || !scanParam.db"
|
||||||
icon="search"
|
@click="searchKey()"
|
||||||
size="small"
|
type="success"
|
||||||
plain
|
icon="search"
|
||||||
></el-button>
|
size="small"
|
||||||
</el-col>
|
plain
|
||||||
</el-row>
|
></el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-row class="mb5 mt5">
|
<el-row class="mb5 mt5">
|
||||||
<el-col :span="19">
|
<el-col :span="19">
|
||||||
<el-button
|
<el-button
|
||||||
class="ml5"
|
class="ml5"
|
||||||
:disabled="!scanParam.id || !scanParam.db"
|
:disabled="!scanParam.id || !scanParam.db"
|
||||||
@click="scan(true)"
|
@click="scan(true)"
|
||||||
type="success"
|
type="success"
|
||||||
icon="more"
|
icon="more"
|
||||||
size="small"
|
size="small"
|
||||||
plain
|
plain
|
||||||
>{{ $t('redis.loadMore') }}</el-button
|
>{{ $t('redis.loadMore') }}</el-button
|
||||||
|
>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
v-auth="'redis:data:save'"
|
||||||
|
:disabled="!scanParam.id || !scanParam.db"
|
||||||
|
@click="showNewKeyDialog"
|
||||||
|
type="primary"
|
||||||
|
icon="plus"
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
>{{ $t('redis.addKey') }}</el-button
|
||||||
|
>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
:disabled="!scanParam.id || !scanParam.db"
|
||||||
|
@click="flushDb"
|
||||||
|
type="danger"
|
||||||
|
plain
|
||||||
|
v-auth="'redis:data:del'"
|
||||||
|
size="small"
|
||||||
|
icon="delete"
|
||||||
|
>flush</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="5">
|
||||||
|
<span style="display: inline-block" class="mt5">keys:{{ state.dbsize }}</span>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-tree
|
||||||
|
ref="keyTreeRef"
|
||||||
|
:highlight-current="true"
|
||||||
|
:data="keyTreeData"
|
||||||
|
:props="treeProps"
|
||||||
|
:indent="8"
|
||||||
|
node-key="key"
|
||||||
|
:auto-expand-parent="false"
|
||||||
|
:default-expanded-keys="Array.from(state.keyTreeExpanded)"
|
||||||
|
@node-click="handleKeyTreeNodeClick"
|
||||||
|
@node-expand="keyTreeNodeExpand"
|
||||||
|
@node-collapse="keyTreeNodeCollapse"
|
||||||
|
@node-contextmenu="rightClickNode"
|
||||||
>
|
>
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<span class="el-dropdown-link key-list-custom-node" :title="node.label">
|
||||||
|
<span v-if="data.type == 1">
|
||||||
|
<SvgIcon :size="15" :name="node.expanded ? 'folder-opened' : 'folder'" />
|
||||||
|
</span>
|
||||||
|
<span :class="'ml5 ' + (data.type == 1 ? 'folder-label' : 'key-label')">
|
||||||
|
{{ node.label }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<el-button
|
<span v-if="!node.isLeaf" class="ml5" style="font-weight: bold"> ({{ data.keyCount }}) </span>
|
||||||
v-auth="'redis:data:save'"
|
</span>
|
||||||
:disabled="!scanParam.id || !scanParam.db"
|
</template>
|
||||||
@click="showNewKeyDialog"
|
</el-tree>
|
||||||
type="primary"
|
</el-scrollbar>
|
||||||
icon="plus"
|
|
||||||
size="small"
|
|
||||||
plain
|
|
||||||
>{{ $t('redis.addKey') }}</el-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<el-button
|
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
|
||||||
:disabled="!scanParam.id || !scanParam.db"
|
</div>
|
||||||
@click="flushDb"
|
</Pane>
|
||||||
type="danger"
|
|
||||||
plain
|
|
||||||
v-auth="'redis:data:del'"
|
|
||||||
size="small"
|
|
||||||
icon="delete"
|
|
||||||
>flush</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="5">
|
|
||||||
<span style="display: inline-block" class="mt5">keys:{{ state.dbsize }}</span>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-tree
|
<Pane min-size="40">
|
||||||
ref="keyTreeRef"
|
<div class="key-detail card pd5">
|
||||||
:highlight-current="true"
|
<el-tabs @tab-remove="removeDataTab" v-model="state.activeName">
|
||||||
:data="keyTreeData"
|
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
||||||
:props="treeProps"
|
<key-detail :redis="redisInst" :key-info="dt.keyInfo" @change-key="searchKey()" @del-key="delKey" />
|
||||||
:indent="8"
|
</el-tab-pane>
|
||||||
node-key="key"
|
</el-tabs>
|
||||||
:auto-expand-parent="false"
|
</div>
|
||||||
:default-expanded-keys="Array.from(state.keyTreeExpanded)"
|
</Pane>
|
||||||
@node-click="handleKeyTreeNodeClick"
|
</Splitpanes>
|
||||||
@node-expand="keyTreeNodeExpand"
|
</template>
|
||||||
@node-collapse="keyTreeNodeCollapse"
|
</ResourceOpPanel>
|
||||||
@node-contextmenu="rightClickNode"
|
|
||||||
>
|
|
||||||
<template #default="{ node, data }">
|
|
||||||
<span class="el-dropdown-link key-list-custom-node" :title="node.label">
|
|
||||||
<span v-if="data.type == 1">
|
|
||||||
<SvgIcon :size="15" :name="node.expanded ? 'folder-opened' : 'folder'" />
|
|
||||||
</span>
|
|
||||||
<span :class="'ml5 ' + (data.type == 1 ? 'folder-label' : 'key-label')">
|
|
||||||
{{ node.label }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span v-if="!node.isLeaf" class="ml5" style="font-weight: bold"> ({{ data.keyCount }}) </span>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-tree>
|
|
||||||
</el-scrollbar>
|
|
||||||
|
|
||||||
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
|
|
||||||
</div>
|
|
||||||
</Pane>
|
|
||||||
|
|
||||||
<Pane min-size="40">
|
|
||||||
<div class="key-detail card pd5">
|
|
||||||
<el-tabs @tab-remove="removeDataTab" v-model="state.activeName">
|
|
||||||
<el-tab-pane closable v-for="dt in state.dataTabs" :key="dt.key" :label="dt.label" :name="dt.key">
|
|
||||||
<key-detail :redis="redisInst" :key-info="dt.keyInfo" @change-key="searchKey()" @del-key="delKey" />
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
</Pane>
|
|
||||||
</Splitpanes>
|
|
||||||
|
|
||||||
<div style="text-align: center; margin-top: 10px"></div>
|
<div style="text-align: center; margin-top: 10px"></div>
|
||||||
|
|
||||||
@@ -204,6 +208,7 @@ import { storeToRefs } from 'pinia';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nFormValidate, useI18nOperateSuccessMsg } from '@/hooks/useI18n';
|
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nFormValidate, useI18nOperateSuccessMsg } from '@/hooks/useI18n';
|
||||||
import { Rules } from '@/common/rule';
|
import { Rules } from '@/common/rule';
|
||||||
|
import ResourceOpPanel from '../component/ResourceOpPanel.vue';
|
||||||
|
|
||||||
const KeyDetail = defineAsyncComponent(() => import('./KeyDetail.vue'));
|
const KeyDetail = defineAsyncComponent(() => import('./KeyDetail.vue'));
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ require (
|
|||||||
github.com/tidwall/gjson v1.18.0
|
github.com/tidwall/gjson v1.18.0
|
||||||
github.com/veops/go-ansiterm v0.0.5
|
github.com/veops/go-ansiterm v0.0.5
|
||||||
go.mongodb.org/mongo-driver v1.16.0 // mongo
|
go.mongodb.org/mongo-driver v1.16.0 // mongo
|
||||||
golang.org/x/crypto v0.35.0 // ssh
|
golang.org/x/crypto v0.36.0 // ssh
|
||||||
golang.org/x/oauth2 v0.26.0
|
golang.org/x/oauth2 v0.26.0
|
||||||
golang.org/x/sync v0.11.0
|
golang.org/x/sync v0.12.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
// gorm
|
// gorm
|
||||||
@@ -93,8 +93,8 @@ require (
|
|||||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect
|
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||||
golang.org/x/image v0.23.0 // indirect
|
golang.org/x/image v0.23.0 // indirect
|
||||||
golang.org/x/net v0.34.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.30.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/text v0.22.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
modernc.org/libc v1.22.5 // indirect
|
modernc.org/libc v1.22.5 // indirect
|
||||||
modernc.org/mathutil v1.5.0 // indirect
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ func (app *dataSyncAppImpl) RunCronJob(ctx context.Context, id uint64) error {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errorx.NewBiz("get column data type... ignore~")
|
return dbi.NewStopWalkQueryError("get column data type... ignore~")
|
||||||
})
|
})
|
||||||
|
|
||||||
updSql = fmt.Sprintf("and %s > %s", task.UpdField, updFieldDataType.DataType.SQLValue(task.UpdFieldVal))
|
updSql = fmt.Sprintf("and %s > %s", task.UpdField, updFieldDataType.DataType.SQLValue(task.UpdFieldVal))
|
||||||
|
|||||||
@@ -333,7 +333,6 @@ func (d *dbSqlExecAppImpl) saveSqlExecLog(dbSqlExecRecord *entity.DbSqlExec, res
|
|||||||
|
|
||||||
func (d *dbSqlExecAppImpl) doSelect(ctx context.Context, sqlExecParam *sqlExecParam) (*dto.DbSqlExecRes, error) {
|
func (d *dbSqlExecAppImpl) doSelect(ctx context.Context, sqlExecParam *sqlExecParam) (*dto.DbSqlExecRes, error) {
|
||||||
maxCount := config.GetDbms().MaxResultSet
|
maxCount := config.GetDbms().MaxResultSet
|
||||||
selectStmt := sqlExecParam.Stmt
|
|
||||||
selectSql := sqlExecParam.Sql
|
selectSql := sqlExecParam.Sql
|
||||||
sqlExecParam.SqlExecRecord.Type = entity.DbSqlExecTypeQuery
|
sqlExecParam.SqlExecRecord.Type = entity.DbSqlExecTypeQuery
|
||||||
|
|
||||||
@@ -343,49 +342,7 @@ func (d *dbSqlExecAppImpl) doSelect(ctx context.Context, sqlExecParam *sqlExecPa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if selectStmt != nil {
|
return d.doQuery(ctx, sqlExecParam.DbConn, selectSql, maxCount)
|
||||||
needCheckLimit := false
|
|
||||||
var limit *sqlstmt.Limit
|
|
||||||
switch stmt := selectStmt.(type) {
|
|
||||||
case *sqlstmt.SimpleSelectStmt:
|
|
||||||
qs := stmt.QuerySpecification
|
|
||||||
limit = qs.Limit
|
|
||||||
if qs.SelectElements != nil && (qs.SelectElements.Star != "" || len(qs.SelectElements.Elements) > 1) {
|
|
||||||
needCheckLimit = true
|
|
||||||
}
|
|
||||||
case *sqlstmt.UnionSelectStmt:
|
|
||||||
limit = stmt.Limit
|
|
||||||
selectSql = selectStmt.GetText()
|
|
||||||
needCheckLimit = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果配置为0,则不校验分页参数
|
|
||||||
if needCheckLimit && maxCount != 0 {
|
|
||||||
if limit == nil {
|
|
||||||
return nil, errorx.NewBizI(ctx, imsg.ErrNoLimitStmt)
|
|
||||||
}
|
|
||||||
if limit.RowCount > maxCount {
|
|
||||||
return nil, errorx.NewBizI(ctx, imsg.ErrLimitInvalid, "count", maxCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if maxCount != 0 {
|
|
||||||
if !strings.Contains(selectSql, "limit") &&
|
|
||||||
// 兼容oracle rownum分页
|
|
||||||
!strings.Contains(selectSql, "rownum") &&
|
|
||||||
// 兼容mssql offset分页
|
|
||||||
!strings.Contains(selectSql, "offset") &&
|
|
||||||
// 兼容mssql top 分页 with result as ({query sql}) select top 100 * from result
|
|
||||||
!strings.Contains(selectSql, " top ") {
|
|
||||||
// 判断是不是count语句
|
|
||||||
if !strings.Contains(selectSql, "count(") {
|
|
||||||
return nil, errorx.NewBizI(ctx, imsg.ErrNoLimitStmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d.doQuery(ctx, sqlExecParam.DbConn, selectSql)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbSqlExecAppImpl) doOtherRead(ctx context.Context, sqlExecParam *sqlExecParam) (*dto.DbSqlExecRes, error) {
|
func (d *dbSqlExecAppImpl) doOtherRead(ctx context.Context, sqlExecParam *sqlExecParam) (*dto.DbSqlExecRes, error) {
|
||||||
@@ -398,7 +355,7 @@ func (d *dbSqlExecAppImpl) doOtherRead(ctx context.Context, sqlExecParam *sqlExe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.doQuery(ctx, sqlExecParam.DbConn, selectSql)
|
return d.doQuery(ctx, sqlExecParam.DbConn, selectSql, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbSqlExecAppImpl) doExecDDL(ctx context.Context, sqlExecParam *sqlExecParam) (*dto.DbSqlExecRes, error) {
|
func (d *dbSqlExecAppImpl) doExecDDL(ctx context.Context, sqlExecParam *sqlExecParam) (*dto.DbSqlExecRes, error) {
|
||||||
@@ -588,11 +545,23 @@ func (d *dbSqlExecAppImpl) doInsert(ctx context.Context, sqlExecParam *sqlExecPa
|
|||||||
return d.doExec(ctx, sqlExecParam.DbConn, sqlExecParam.Sql)
|
return d.doExec(ctx, sqlExecParam.DbConn, sqlExecParam.Sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dbSqlExecAppImpl) doQuery(ctx context.Context, dbConn *dbi.DbConn, sql string) (*dto.DbSqlExecRes, error) {
|
func (d *dbSqlExecAppImpl) doQuery(ctx context.Context, dbConn *dbi.DbConn, sql string, maxRows int) (*dto.DbSqlExecRes, error) {
|
||||||
cols, res, err := dbConn.QueryContext(ctx, sql)
|
res := make([]map[string]any, 0, 16)
|
||||||
|
nowRows := 0
|
||||||
|
cols, err := dbConn.WalkQueryRows(ctx, sql, func(row map[string]any, columns []*dbi.QueryColumn) error {
|
||||||
|
nowRows++
|
||||||
|
// 超过指定的最大查询记录数,则停止查询
|
||||||
|
if maxRows != 0 && nowRows > maxRows {
|
||||||
|
return dbi.NewStopWalkQueryError(fmt.Sprintf("exceed the maximum number of query records %d", maxRows))
|
||||||
|
}
|
||||||
|
res = append(res, row)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &dto.DbSqlExecRes{
|
return &dto.DbSqlExecRes{
|
||||||
Sql: sql,
|
Sql: sql,
|
||||||
Columns: cols,
|
Columns: cols,
|
||||||
|
|||||||
@@ -70,11 +70,7 @@ func (d *DbConn) QueryContext(ctx context.Context, querySql string, args ...any)
|
|||||||
return nil
|
return nil
|
||||||
}, args...)
|
}, args...)
|
||||||
|
|
||||||
if err != nil {
|
return cols, result, err
|
||||||
return nil, nil, wrapSqlError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cols, result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将查询结果映射至struct,可具体参考sqlx库
|
// 将查询结果映射至struct,可具体参考sqlx库
|
||||||
@@ -95,7 +91,15 @@ func (d *DbConn) Query2Struct(execSql string, dest any) error {
|
|||||||
|
|
||||||
// WalkQueryRows 游标方式遍历查询结果集, walkFn返回error不为nil, 则跳出遍历并取消查询
|
// WalkQueryRows 游标方式遍历查询结果集, walkFn返回error不为nil, 则跳出遍历并取消查询
|
||||||
func (d *DbConn) WalkQueryRows(ctx context.Context, querySql string, walkFn WalkQueryRowsFunc, args ...any) ([]*QueryColumn, error) {
|
func (d *DbConn) WalkQueryRows(ctx context.Context, querySql string, walkFn WalkQueryRowsFunc, args ...any) ([]*QueryColumn, error) {
|
||||||
return d.walkQueryRows(ctx, querySql, walkFn, args...)
|
if qcs, err := d.walkQueryRows(ctx, querySql, walkFn, args...); err != nil {
|
||||||
|
// 如果是手动停止 则默认返回当前已遍历查询的数据即可
|
||||||
|
if _, ok := err.(*StopWalkQueryError); ok {
|
||||||
|
return qcs, nil
|
||||||
|
}
|
||||||
|
return qcs, wrapSqlError(err)
|
||||||
|
} else {
|
||||||
|
return qcs, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WalkTableRows 游标方式遍历指定表的结果集, walkFn返回error不为nil, 则跳出遍历并取消查询
|
// WalkTableRows 游标方式遍历指定表的结果集, walkFn返回error不为nil, 则跳出遍历并取消查询
|
||||||
@@ -242,3 +246,18 @@ func wrapSqlError(err error) error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StopWalkQueryError 自定义的停止遍历查询错误类型
|
||||||
|
type StopWalkQueryError struct {
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error 实现 error 接口
|
||||||
|
func (e *StopWalkQueryError) Error() string {
|
||||||
|
return fmt.Sprintf("stop walk query: %s", e.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStopWalkQueryError 创建一个带有reason的StopWalkQueryError
|
||||||
|
func NewStopWalkQueryError(reason string) *StopWalkQueryError {
|
||||||
|
return &StopWalkQueryError{Reason: reason}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,26 +13,31 @@ order by
|
|||||||
n.nspname
|
n.nspname
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
--PGSQL_TABLE_INFO 表详细信息
|
--PGSQL_TABLE_INFO 表详细信息
|
||||||
SELECT
|
SELECT DISTINCT
|
||||||
c.relname AS "tableName",
|
c.relname AS "tableName",
|
||||||
obj_description(c.oid) AS "tableComment",
|
COALESCE(b.description, '') AS "tableComment",
|
||||||
pg_total_relation_size(c.oid) AS "dataLength",
|
pg_total_relation_size(c.oid) AS "dataLength",
|
||||||
pg_indexes_size(c.oid) AS "indexLength",
|
pg_indexes_size(c.oid) AS "indexLength",
|
||||||
psut.n_live_tup AS "tableRows"
|
psut.n_live_tup AS "tableRows"
|
||||||
FROM
|
FROM
|
||||||
pg_class c
|
pg_class c
|
||||||
JOIN
|
LEFT JOIN pg_description b ON c.oid = b.objoid AND b.objsubid = 0
|
||||||
pg_namespace n ON c.relnamespace = n.oid
|
JOIN pg_stat_user_tables psut ON psut.relid = c.oid
|
||||||
JOIN
|
|
||||||
pg_stat_user_tables psut ON psut.relid = c.oid
|
|
||||||
WHERE
|
WHERE
|
||||||
has_table_privilege(c.oid, 'SELECT')
|
c.relkind = 'r'
|
||||||
and n.nspname = current_schema()
|
AND c.relnamespace = (
|
||||||
{{if .tableNames}}
|
SELECT
|
||||||
and c.relname in ({{.tableNames}})
|
oid
|
||||||
{{end}}
|
FROM
|
||||||
|
pg_namespace
|
||||||
|
WHERE
|
||||||
|
nspname = current_schema()
|
||||||
|
{{if .tableNames}}
|
||||||
|
and c.relname in ({{.tableNames}})
|
||||||
|
{{end}}
|
||||||
|
)
|
||||||
ORDER BY
|
ORDER BY
|
||||||
c.relname;
|
c.relname;
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
--PGSQL_INDEX_INFO 表索引信息
|
--PGSQL_INDEX_INFO 表索引信息
|
||||||
SELECT a.indexname AS "indexName",
|
SELECT a.indexname AS "indexName",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
type Db struct {
|
type Db struct {
|
||||||
model.Model
|
model.Model
|
||||||
|
|
||||||
Code string `json:"code" gorm:"size:32;not null;index:idx_code"`
|
Code string `json:"code" gorm:"size:32;not null;index:idx_db_code"`
|
||||||
Name string `json:"name" gorm:"size:255;not null;"`
|
Name string `json:"name" gorm:"size:255;not null;"`
|
||||||
GetDatabaseMode DbGetDatabaseMode `json:"getDatabaseMode" gorm:"comment:库名获取方式(-1.实时获取、1.指定库名)"` // 获取数据库方式
|
GetDatabaseMode DbGetDatabaseMode `json:"getDatabaseMode" gorm:"comment:库名获取方式(-1.实时获取、1.指定库名)"` // 获取数据库方式
|
||||||
Database string `json:"database" gorm:"size:2000;"`
|
Database string `json:"database" gorm:"size:2000;"`
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ var En = map[i18n.MsgId]string{
|
|||||||
|
|
||||||
ErrExistRunFailSql: "There is an execution error in sql",
|
ErrExistRunFailSql: "There is an execution error in sql",
|
||||||
ErrNeedSubmitWorkTicket: "This operation needs to submit a work ticket for approval",
|
ErrNeedSubmitWorkTicket: "This operation needs to submit a work ticket for approval",
|
||||||
ErrNoLimitStmt: "Please complete the paging information before executing",
|
|
||||||
ErrLimitInvalid: "The number of query result sets should be less than the {{.count}} number configured by the system",
|
|
||||||
|
|
||||||
// db transfer
|
// db transfer
|
||||||
LogDtsSave: "dts - Save data transfer task",
|
LogDtsSave: "dts - Save data transfer task",
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ const (
|
|||||||
|
|
||||||
ErrExistRunFailSql
|
ErrExistRunFailSql
|
||||||
ErrNeedSubmitWorkTicket
|
ErrNeedSubmitWorkTicket
|
||||||
ErrNoLimitStmt
|
|
||||||
ErrLimitInvalid
|
|
||||||
|
|
||||||
// db transfer
|
// db transfer
|
||||||
LogDtsSave
|
LogDtsSave
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ var Zh_CN = map[i18n.MsgId]string{
|
|||||||
|
|
||||||
ErrExistRunFailSql: "存在执行错误的sql",
|
ErrExistRunFailSql: "存在执行错误的sql",
|
||||||
ErrNeedSubmitWorkTicket: "该操作需要提交工单审批执行",
|
ErrNeedSubmitWorkTicket: "该操作需要提交工单审批执行",
|
||||||
ErrNoLimitStmt: "请完善分页信息后执行",
|
|
||||||
ErrLimitInvalid: "查询结果集数需小于系统配置的{{.count}}条",
|
|
||||||
|
|
||||||
// db transfer
|
// db transfer
|
||||||
LogDtsSave: "dts-保存数据迁移任务",
|
LogDtsSave: "dts-保存数据迁移任务",
|
||||||
|
|||||||
@@ -47,7 +47,11 @@ func (p *Procdef) MatchCondition(bizType string, param map[string]any) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
res := stringx.TemplateResolve(*p.Condition, collx.Kvs("bizType", bizType, "param", param))
|
res, err := stringx.TemplateResolve(*p.Condition, collx.Kvs("bizType", bizType, "param", param))
|
||||||
|
if err != nil {
|
||||||
|
logx.ErrorTrace("parse condition error", err.Error())
|
||||||
|
return true
|
||||||
|
}
|
||||||
return strings.TrimSpace(res) == "1"
|
return strings.TrimSpace(res) == "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -316,6 +316,12 @@ func (r *resourceAuthCertAppImpl) addAuthCert(ctx context.Context, rac *entity.R
|
|||||||
return errorx.NewBizI(ctx, imsg.ErrAcNameExist, "acName", rac.Name)
|
return errorx.NewBizI(ctx, imsg.ErrAcNameExist, "acName", rac.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if rac.Type == 0 {
|
||||||
|
rac.Type = entity.AuthCertTypePrivate
|
||||||
|
}
|
||||||
|
if rac.CiphertextType == 0 {
|
||||||
|
rac.CiphertextType = entity.AuthCertCiphertextTypePassword
|
||||||
|
}
|
||||||
|
|
||||||
// 公共凭证
|
// 公共凭证
|
||||||
if rac.Type == entity.AuthCertTypePublic {
|
if rac.Type == entity.AuthCertTypePublic {
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import (
|
|||||||
type TagTree struct {
|
type TagTree struct {
|
||||||
model.Model
|
model.Model
|
||||||
|
|
||||||
Type TagType `json:"type" gorm:"not null;default:-1;comment:类型: -1.普通标签; 1机器 2db 3redis 4mongo"` // 类型: -1.普通标签; 其他值则为对应的资源类型
|
Type TagType `json:"type" gorm:"not null;default:-1;comment:类型: -1.普通标签; 1机器 2db 3redis 4mongo"` // 类型: -1.普通标签; 其他值则为对应的资源类型
|
||||||
Code string `json:"code" gorm:"not null;size:50;comment:标识符"` // 标识编码, 若类型不为-1,则为对应资源编码
|
Code string `json:"code" gorm:"not null;size:50;index:idx_tag_code;comment:标识符"` // 标识编码, 若类型不为-1,则为对应资源编码
|
||||||
CodePath string `json:"codePath" gorm:"not null;size:800;comment:标识符路径"` // 标识路径,tag1/tag2/tagType1|tagCode/tagType2|yyycode/,非普通标签类型段含有标签类型
|
CodePath string `json:"codePath" gorm:"not null;size:800;index:idx_tag_code_path,length:255;comment:标识符路径"` // 标识路径,tag1/tag2/tagType1|tagCode/tagType2|yyycode/,非普通标签类型段含有标签类型
|
||||||
Name string `json:"name" gorm:"size:50;comment:名称"` // 名称
|
Name string `json:"name" gorm:"size:50;comment:名称"` // 名称
|
||||||
Remark string `json:"remark" gorm:"size:255;"` // 备注说明
|
Remark string `json:"remark" gorm:"size:255;"` // 备注说明
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagType int8
|
type TagType int8
|
||||||
|
|||||||
@@ -157,6 +157,15 @@ func initRole(tx *gorm.DB) error {
|
|||||||
role.Creator = "admin"
|
role.Creator = "admin"
|
||||||
role.Modifier = "admin"
|
role.Modifier = "admin"
|
||||||
|
|
||||||
|
roleResource := &sysentity.RoleResource{
|
||||||
|
RoleId: role.Id,
|
||||||
|
ResourceId: 1,
|
||||||
|
CreateTime: &now,
|
||||||
|
CreatorId: 1,
|
||||||
|
Creator: "admin",
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.Create(roleResource)
|
||||||
return tx.Create(role).Error
|
return tx.Create(role).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,6 @@ import (
|
|||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 逻辑空字符串(由于gorm更新结构体只更新非零值,所以使用该值最为逻辑空字符串,方便更新结构体)
|
|
||||||
const LogicEmptyStr = "-"
|
|
||||||
|
|
||||||
// 是否为逻辑上空字符串
|
|
||||||
func IsLogicEmpty(str string) bool {
|
|
||||||
return str == "" || str == LogicEmptyStr
|
|
||||||
}
|
|
||||||
|
|
||||||
// 可判断中文
|
// 可判断中文
|
||||||
func Len(str string) int {
|
func Len(str string) int {
|
||||||
return len([]rune(str))
|
return len([]rune(str))
|
||||||
@@ -89,15 +81,18 @@ func UnicodeIndex(str, substr string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 字符串模板解析
|
// 字符串模板解析
|
||||||
func TemplateResolve(temp string, data any) string {
|
func TemplateResolve(temp string, data any) (string, error) {
|
||||||
t, _ := template.New("string-temp").Parse(temp)
|
t, err := template.New("string-temp").Parse(temp)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
var tmplBytes bytes.Buffer
|
var tmplBytes bytes.Buffer
|
||||||
|
|
||||||
err := t.Execute(&tmplBytes, data)
|
err = t.Execute(&tmplBytes, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return "", err
|
||||||
}
|
}
|
||||||
return tmplBytes.String()
|
return tmplBytes.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReverStrTemplate(temp, str string, res map[string]any) {
|
func ReverStrTemplate(temp, str string, res map[string]any) {
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ func TestTemplateResolve(t *testing.T) {
|
|||||||
d := make(map[string]string)
|
d := make(map[string]string)
|
||||||
d["Name"] = "黄先生"
|
d["Name"] = "黄先生"
|
||||||
d["Age"] = "23jlfdsjf"
|
d["Age"] = "23jlfdsjf"
|
||||||
resolve := stringx.TemplateResolve("{{.Name}} is name, and {{.Age}} is age", d)
|
resolve, _ := stringx.TemplateResolve("{{.Name}} is name, and {{.Age}} is age", d)
|
||||||
fmt.Println(resolve)
|
fmt.Println(resolve)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user