mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
feat: sql查询支持多tab结果集
This commit is contained in:
@@ -387,7 +387,7 @@ onBeforeUnmount(() => {
|
||||
* 设置editor高度和数据表高度
|
||||
*/
|
||||
const setHeight = () => {
|
||||
state.editorHeight = window.innerHeight - 500 + 'px';
|
||||
state.editorHeight = window.innerHeight - 520 + 'px';
|
||||
state.dataTabsTableHeight = window.innerHeight - 255;
|
||||
state.tablesOpHeight = window.innerHeight - 220 + 'px';
|
||||
};
|
||||
|
||||
@@ -48,37 +48,77 @@
|
||||
</el-icon>
|
||||
</div>
|
||||
|
||||
<div class="mt5">
|
||||
<el-row>
|
||||
<span v-if="hasUpdatedFileds">
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
<el-link type="success" :underline="false" @click="submitUpdateFields()"><span style="font-size: 12px">提交</span></el-link>
|
||||
</span>
|
||||
<span v-if="hasUpdatedFileds">
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
<el-link type="warning" :underline="false" @click="cancelUpdateFields"><span style="font-size: 12px">取消</span></el-link>
|
||||
</span>
|
||||
</el-row>
|
||||
<db-table-data
|
||||
ref="dbTableRef"
|
||||
:db-id="dbId"
|
||||
:db="dbName"
|
||||
:data="execRes.data"
|
||||
:table="state.table"
|
||||
:columns="execRes.tableColumn"
|
||||
:loading="loading"
|
||||
:height="tableDataHeight"
|
||||
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
||||
@selection-change="onDataSelectionChange"
|
||||
@change-updated-field="changeUpdatedField"
|
||||
@data-delete="onDeleteData"
|
||||
></db-table-data>
|
||||
<div class="mt5 sql-exec-res">
|
||||
<el-tabs v-if="state.execResTabs.length > 0" @tab-remove="onRemoveTab" style="width: 100%" v-model="state.activeTab">
|
||||
<el-tab-pane closable v-for="dt in state.execResTabs" :label="dt.label" :name="dt.label" :key="dt.label">
|
||||
<template #label>
|
||||
<el-popover :show-after="1000" placement="top-start" title="执行信息" trigger="hover" :width="300">
|
||||
<template #reference>
|
||||
<div>
|
||||
<span>
|
||||
<span v-if="dt.loading">
|
||||
<SvgIcon class="mb2 is-loading" name="Loading" color="var(--el-color-primary)" />
|
||||
</span>
|
||||
<span v-else>
|
||||
<SvgIcon class="mb2" v-if="!dt.errorMsg" name="CircleCheck" color="var(--el-color-success)" />
|
||||
<SvgIcon class="mb2" v-if="dt.errorMsg" name="CircleClose" color="var(--el-color-error)" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="ml5">
|
||||
{{ dt.label }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #default>
|
||||
<el-descriptions :column="1" size="small">
|
||||
<el-descriptions-item label="耗时 :"> {{ dt.execTime }}ms </el-descriptions-item>
|
||||
<el-descriptions-item label="结果集 :">
|
||||
{{ dt.data?.length }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="SQL :">
|
||||
{{ dt.sql }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<el-row>
|
||||
<span v-if="dt.hasUpdatedFileds" class="mt5">
|
||||
<span>
|
||||
<el-link type="success" :underline="false" @click="submitUpdateFields(dt)"><span style="font-size: 12px">提交</span></el-link>
|
||||
</span>
|
||||
<span>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
<el-link type="warning" :underline="false" @click="cancelUpdateFields(dt)"><span style="font-size: 12px">取消</span></el-link>
|
||||
</span>
|
||||
</span>
|
||||
</el-row>
|
||||
<db-table-data
|
||||
v-if="!dt.errorMsg"
|
||||
:ref="(el) => (dt.dbTableRef = el)"
|
||||
:db-id="dbId"
|
||||
:db="dbName"
|
||||
:data="dt.data"
|
||||
:table="dt.table"
|
||||
:columns="dt.tableColumn"
|
||||
:loading="dt.loading"
|
||||
:height="tableDataHeight"
|
||||
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
||||
@change-updated-field="changeUpdatedField($event, dt)"
|
||||
@data-delete="onDeleteData($event, dt)"
|
||||
></db-table-data>
|
||||
|
||||
<el-result v-else icon="error" title="执行失败" :sub-title="dt.errorMsg"> </el-result>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, nextTick, watch, onMounted, reactive, toRefs, ref, Ref } from 'vue';
|
||||
import { h, nextTick, watch, onMounted, reactive, toRefs, ref } from 'vue';
|
||||
import { getToken } from '@/common/utils/storage';
|
||||
import { notBlank } from '@/common/assert';
|
||||
import { format as sqlFormatter } from 'sql-formatter';
|
||||
@@ -98,6 +138,7 @@ import { buildProgressProps } from '@/components/progress-notify/progress-notify
|
||||
import ProgressNotify from '@/components/progress-notify/progress-notify.vue';
|
||||
import { ElNotification } from 'element-plus';
|
||||
import syssocket from '@/common/syssocket';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
|
||||
const emits = defineEmits(['saveSqlSuccess', 'deleteSqlSuccess']);
|
||||
|
||||
@@ -120,29 +161,57 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
class ExecResTab {
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* 当前结果集对应的sql
|
||||
*/
|
||||
sql: string;
|
||||
|
||||
loading: boolean;
|
||||
|
||||
dbTableRef: any;
|
||||
|
||||
tableColumn: any[] = [];
|
||||
|
||||
data: any[] = [];
|
||||
|
||||
execTime: number;
|
||||
|
||||
/**
|
||||
* 当前单表操作sql关联的表信息
|
||||
*/
|
||||
table: string;
|
||||
|
||||
/**
|
||||
* 是否有更新字段
|
||||
*/
|
||||
hasUpdatedFileds: boolean;
|
||||
|
||||
errorMsg: string;
|
||||
|
||||
constructor(label: string) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
|
||||
const token = getToken();
|
||||
const monacoEditorRef: any = ref(null);
|
||||
const dbTableRef = ref(null) as Ref;
|
||||
|
||||
let monacoEditor: editor.IStandaloneCodeEditor;
|
||||
|
||||
const state = reactive({
|
||||
token,
|
||||
table: '', // 当前单表操作sql的表信息
|
||||
sql: '', // 当前编辑器的sql内容s
|
||||
sqlName: '' as any, // sql模板名称
|
||||
loading: false, // 是否在加载数据
|
||||
execRes: {
|
||||
data: [],
|
||||
tableColumn: [],
|
||||
},
|
||||
selectionDatas: [] as any,
|
||||
execResTabs: [] as ExecResTab[],
|
||||
activeTab: '',
|
||||
editorHeight: '500',
|
||||
tableDataHeight: 255 as any,
|
||||
hasUpdatedFileds: false,
|
||||
});
|
||||
|
||||
const { tableDataHeight, execRes, loading, hasUpdatedFileds } = toRefs(state);
|
||||
const { tableDataHeight } = toRefs(state);
|
||||
|
||||
watch(
|
||||
() => props.editorHeight,
|
||||
@@ -159,6 +228,11 @@ onMounted(async () => {
|
||||
console.log('in query mounted');
|
||||
state.editorHeight = props.editorHeight;
|
||||
|
||||
// 默认新建一个结果集tab
|
||||
const label = '结果1';
|
||||
state.execResTabs.push(new ExecResTab(label));
|
||||
state.activeTab = label;
|
||||
|
||||
state.sqlName = props.sqlName;
|
||||
if (props.sqlName) {
|
||||
const res = await dbApi.getSql.request({ id: props.dbId, type: 1, db: props.dbName, name: props.sqlName });
|
||||
@@ -201,6 +275,34 @@ const initMonacoEditor = () => {
|
||||
},
|
||||
});
|
||||
|
||||
// 注册快捷键:ctrl + R 运行选中的sql
|
||||
monacoEditor.addAction({
|
||||
// An unique identifier of the contributed action.
|
||||
// id: 'run-sql-action' + state.ti.key,
|
||||
id: 'run-sql-action-on-newtab' + getKey(),
|
||||
// A label of the action that will be presented to the user.
|
||||
label: '新标签执行SQL',
|
||||
// A precondition for this action.
|
||||
precondition: undefined,
|
||||
// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
|
||||
keybindingContext: undefined,
|
||||
keybindings: [
|
||||
// chord
|
||||
monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyR, 0),
|
||||
],
|
||||
contextMenuGroupId: 'navigation',
|
||||
contextMenuOrder: 1.6,
|
||||
// Method that will be executed when the action is triggered.
|
||||
// @param editor The editor instance is passed in as a convenience
|
||||
run: async function () {
|
||||
try {
|
||||
await onRunSql(true);
|
||||
} catch (e: any) {
|
||||
e.message && ElMessage.error(e.message);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// 注册快捷键:ctrl + shift + f 格式化sql
|
||||
monacoEditor.addAction({
|
||||
// An unique identifier of the contributed action.
|
||||
@@ -229,6 +331,25 @@ const initMonacoEditor = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const onRemoveTab = (targetName: string) => {
|
||||
let activeTab = state.activeTab;
|
||||
const tabs = [...state.execResTabs];
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
const tabName = tabs[i].label;
|
||||
if (tabName !== targetName) {
|
||||
continue;
|
||||
}
|
||||
const nextTab = tabs[i + 1] || tabs[i - 1];
|
||||
if (nextTab) {
|
||||
activeTab = nextTab.label;
|
||||
} else {
|
||||
activeTab = '';
|
||||
}
|
||||
state.execResTabs.splice(i, 1);
|
||||
state.activeTab = activeTab;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 拖拽改变sql编辑区和查询结果区高度
|
||||
*/
|
||||
@@ -254,7 +375,7 @@ const getKey = () => {
|
||||
/**
|
||||
* 执行sql
|
||||
*/
|
||||
const onRunSql = async () => {
|
||||
const onRunSql = async (newTab = false) => {
|
||||
// 没有选中的文本,则为全部文本
|
||||
let sql = getSql() as string;
|
||||
notBlank(sql && sql.trim(), '请选中需要执行的sql');
|
||||
@@ -285,44 +406,67 @@ const onRunSql = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
let execRes: ExecResTab;
|
||||
let i = 0;
|
||||
let label;
|
||||
// 新tab执行,或者tabs为0,则新建tab执行sql
|
||||
if (newTab || state.execResTabs.length == 0) {
|
||||
label = `结果${state.execResTabs.length + 1}`;
|
||||
execRes = new ExecResTab(label);
|
||||
state.execResTabs.push(execRes);
|
||||
i = state.execResTabs.length - 1;
|
||||
} else {
|
||||
// 不是新建tab执行,则在当前激活的tab上执行sql
|
||||
i = state.execResTabs.findIndex((x) => x.label == state.activeTab);
|
||||
execRes = state.execResTabs[i];
|
||||
label = execRes.label;
|
||||
}
|
||||
|
||||
state.activeTab = label;
|
||||
const startTime = new Date().getTime();
|
||||
try {
|
||||
state.loading = true;
|
||||
execRes.loading = true;
|
||||
execRes.errorMsg = '';
|
||||
execRes.sql = '';
|
||||
|
||||
const colAndData: any = await getNowDbInst().runSql(props.dbName, sql, execRemark);
|
||||
if (!colAndData.res || colAndData.res.length === 0) {
|
||||
ElMessage.warning('未查询到结果集');
|
||||
}
|
||||
state.execRes.data = colAndData.res;
|
||||
// 要实时响应,故需要用索引改变数据才生效
|
||||
state.execResTabs[i].data = colAndData.res;
|
||||
// 兼容表格字段配置
|
||||
state.execRes.tableColumn = colAndData.colNames.map((x: any) => {
|
||||
state.execResTabs[i].tableColumn = colAndData.colNames.map((x: any) => {
|
||||
return {
|
||||
columnName: x,
|
||||
show: true,
|
||||
};
|
||||
});
|
||||
cancelUpdateFields();
|
||||
cancelUpdateFields(execRes);
|
||||
} catch (e: any) {
|
||||
state.execRes.data = [];
|
||||
state.execRes.tableColumn = [];
|
||||
state.table = '';
|
||||
execRes.data = [];
|
||||
execRes.tableColumn = [];
|
||||
execRes.table = '';
|
||||
execRes.errorMsg = e.msg;
|
||||
return;
|
||||
} finally {
|
||||
state.loading = false;
|
||||
state.execResTabs[i].loading = false;
|
||||
execRes.sql = sql;
|
||||
execRes.execTime = new Date().getTime() - startTime;
|
||||
}
|
||||
|
||||
// 即只有以该字符串开头的sql才可修改表数据内容
|
||||
if (sql.startsWith('SELECT *') || sql.startsWith('select *') || sql.startsWith('SELECT\n *')) {
|
||||
state.selectionDatas = [];
|
||||
const tableName = sql.split(/from/i)[1];
|
||||
if (tableName) {
|
||||
const tn = tableName.trim().split(' ')[0].split('\n')[0];
|
||||
state.table = tn;
|
||||
state.table = tn;
|
||||
execRes.table = tn;
|
||||
execRes.table = tn;
|
||||
} else {
|
||||
state.table = '';
|
||||
execRes.table = '';
|
||||
}
|
||||
} else {
|
||||
state.table = '';
|
||||
execRes.table = '';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -505,32 +649,28 @@ const getUploadSqlFileUrl = () => {
|
||||
return `${config.baseApiUrl}/dbs/${props.dbId}/exec-sql-file?db=${props.dbName}&${joinClientParams()}`;
|
||||
};
|
||||
|
||||
const onDataSelectionChange = (datas: []) => {
|
||||
state.selectionDatas = datas;
|
||||
};
|
||||
|
||||
const changeUpdatedField = (updatedFields: any) => {
|
||||
const changeUpdatedField = (updatedFields: any, dt: ExecResTab) => {
|
||||
// 如果存在要更新字段,则显示提交和取消按钮
|
||||
state.hasUpdatedFileds = updatedFields && updatedFields.size > 0;
|
||||
dt.hasUpdatedFileds = updatedFields && updatedFields.size > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* 数据删除事件
|
||||
*/
|
||||
const onDeleteData = async (deleteDatas: any) => {
|
||||
const onDeleteData = async (deleteDatas: any, dt: ExecResTab) => {
|
||||
const db = props.dbName;
|
||||
const dbInst = getNowDbInst();
|
||||
const primaryKey = await dbInst.loadTableColumn(db, state.table);
|
||||
const primaryKey = await dbInst.loadTableColumn(db, dt.table);
|
||||
const primaryKeyColumnName = primaryKey.columnName;
|
||||
state.execRes.data = state.execRes.data.filter((d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1));
|
||||
dt.data = dt.data.filter((d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1));
|
||||
};
|
||||
|
||||
const submitUpdateFields = () => {
|
||||
dbTableRef.value.submitUpdateFields();
|
||||
const submitUpdateFields = (dt: ExecResTab) => {
|
||||
dt?.dbTableRef?.submitUpdateFields();
|
||||
};
|
||||
|
||||
const cancelUpdateFields = () => {
|
||||
dbTableRef.value.cancelUpdateFields();
|
||||
const cancelUpdateFields = (dt: ExecResTab) => {
|
||||
dt?.dbTableRef?.cancelUpdateFields();
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -550,4 +690,17 @@ const cancelUpdateFields = () => {
|
||||
height: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sql-exec-res {
|
||||
.el-tabs__header {
|
||||
margin: 0 0 !important;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
font-size: 12px;
|
||||
height: 20px;
|
||||
margin: 0px;
|
||||
padding: 0 6px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -360,6 +360,7 @@ onMounted(async () => {
|
||||
state.dbType = props.dbType;
|
||||
state.db = props.db;
|
||||
state.table = props.table;
|
||||
setTableData(props.data);
|
||||
});
|
||||
|
||||
const setTableData = (datas: any) => {
|
||||
@@ -386,7 +387,9 @@ const setTableColumns = (columns: any) => {
|
||||
hidden: !x.show,
|
||||
};
|
||||
});
|
||||
state.columns.unshift(rowNoColumn);
|
||||
if (state.columns.length > 0) {
|
||||
state.columns.unshift(rowNoColumn);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
<el-form-item prop="code" label="角色code" required>
|
||||
<el-input :disabled="form.id != null" v-model="form.code" placeholder="COMMON开头则为所有账号共有角色" auto-complete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="status" label="状态" required>
|
||||
<el-select v-model="form.status" placeholder="请选择状态" class="w100">
|
||||
<el-option v-for="item in RoleStatusEnum" :key="item.value" :label="item.label" :value="item.value"> </el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色描述">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入角色描述"></el-input>
|
||||
</el-form-item>
|
||||
@@ -25,6 +30,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, watch } from 'vue';
|
||||
import { roleApi } from '../api';
|
||||
import { RoleStatusEnum } from '../enums';
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
|
||||
@@ -20,12 +20,9 @@
|
||||
>
|
||||
</template>
|
||||
|
||||
<template #showmore="{ data }">
|
||||
<el-link @click.prevent="showResources(data)" type="info">菜单&权限</el-link>
|
||||
</template>
|
||||
|
||||
<template #action="{ data }">
|
||||
<el-button v-if="actionBtns[perms.updateRole]" @click="editRole(data)" type="primary" link>编辑</el-button>
|
||||
<el-button @click="showResources(data)" type="info" link>权限详情</el-button>
|
||||
<el-button v-if="actionBtns[perms.saveRoleResource]" @click="editResource(data)" type="success" link>权限分配</el-button>
|
||||
</template>
|
||||
</page-table>
|
||||
@@ -73,11 +70,10 @@ const columns = ref([
|
||||
TableColumn.new('createTime', '创建时间').isTime(),
|
||||
TableColumn.new('modifier', '更新账号'),
|
||||
TableColumn.new('updateTime', '更新时间').isTime(),
|
||||
TableColumn.new('showmore', '查看更多').isSlot().setMinWidth(150),
|
||||
]);
|
||||
|
||||
const actionBtns = hasPerms([perms.updateRole, perms.saveRoleResource]);
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().setMinWidth(160).fixedRight().alignCenter();
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().setMinWidth(260).fixedRight().alignCenter();
|
||||
|
||||
const state = reactive({
|
||||
query: {
|
||||
@@ -157,7 +153,9 @@ const deleteRole = async (data: any) => {
|
||||
});
|
||||
ElMessage.success('删除成功!');
|
||||
search();
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
};
|
||||
|
||||
const showResources = async (row: any) => {
|
||||
|
||||
@@ -6,6 +6,25 @@
|
||||
<span class="custom-tree-node">
|
||||
<span v-if="data.type == ResourceTypeEnum.Menu.value">{{ node.label }}</span>
|
||||
<span v-if="data.type == ResourceTypeEnum.Permission.value" style="color: #67c23a">{{ node.label }}</span>
|
||||
|
||||
<el-popover :show-after="500" placement="right-start" title="资源分配信息" trigger="hover" :width="200">
|
||||
<template #reference>
|
||||
<el-link style="margin-left: 25px" icon="InfoFilled" type="info" :underline="false" />
|
||||
</template>
|
||||
<template #default>
|
||||
<el-descriptions :column="1" size="small">
|
||||
<el-descriptions-item label="资源名称">
|
||||
{{ data.name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="分配账号">
|
||||
{{ data.creator }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="分配时间">
|
||||
{{ dateFormat(data.createTime) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</template>
|
||||
</el-popover>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
@@ -14,9 +33,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, toRefs, reactive, watch } from 'vue';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
import { toRefs, reactive, watch } from 'vue';
|
||||
import { ResourceTypeEnum } from '../enums';
|
||||
import { dateFormat } from '@/common/utils/date';
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
@@ -33,8 +52,6 @@ const props = defineProps({
|
||||
//定义事件
|
||||
const emit = defineEmits(['update:visible', 'update:resources']);
|
||||
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
@@ -52,26 +69,6 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
const info = (info: any) => {
|
||||
ElMessageBox.alert(
|
||||
'<strong style="margin-right: 18px">资源名称:</strong>' +
|
||||
info.name +
|
||||
' <br/><strong style="margin-right: 18px">分配账号:</strong>' +
|
||||
info.creator +
|
||||
' <br/><strong style="margin-right: 18px">分配时间:</strong>' +
|
||||
proxy.$filters.dateFormat(info.createTime) +
|
||||
'',
|
||||
'分配信息',
|
||||
{
|
||||
type: 'info',
|
||||
dangerouslyUseHTMLString: true,
|
||||
closeOnClickModal: true,
|
||||
showConfirmButton: false,
|
||||
}
|
||||
).catch(() => {});
|
||||
return;
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
emit('update:visible', false);
|
||||
emit('update:resources', []);
|
||||
|
||||
@@ -5,7 +5,7 @@ go 1.21
|
||||
require (
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/glebarez/sqlite v1.9.0
|
||||
github.com/glebarez/sqlite v1.10.0
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.0
|
||||
github.com/go-ldap/ldap/v3 v3.4.5
|
||||
github.com/go-playground/locales v0.14.1
|
||||
|
||||
@@ -30,7 +30,8 @@ func (d *DbConn) SelectData2Struct(execSql string, dest any) error {
|
||||
|
||||
// WalkTableRecord 遍历表记录
|
||||
func (d *DbConn) WalkTableRecord(selectSql string, walk func(record map[string]any, columns []string)) error {
|
||||
return walkTableRecord(d.db, selectSql, walk)
|
||||
_, err := walkTableRecord(d.db, selectSql, walk)
|
||||
return err
|
||||
}
|
||||
|
||||
// 执行 update, insert, delete,建表等sql
|
||||
@@ -66,26 +67,20 @@ func (d *DbConn) Close() {
|
||||
}
|
||||
|
||||
func selectDataByDb(db *sql.DB, selectSql string) ([]string, []map[string]any, error) {
|
||||
// 列名用于前端表头名称按照数据库与查询字段顺序显示
|
||||
var colNames []string
|
||||
result := make([]map[string]any, 0, 16)
|
||||
err := walkTableRecord(db, selectSql, func(record map[string]any, columns []string) {
|
||||
columns, err := walkTableRecord(db, selectSql, func(record map[string]any, columns []string) {
|
||||
result = append(result, record)
|
||||
if colNames == nil {
|
||||
colNames = make([]string, len(columns))
|
||||
copy(colNames, columns)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return colNames, result, nil
|
||||
return columns, result, nil
|
||||
}
|
||||
|
||||
func walkTableRecord(db *sql.DB, selectSql string, walk func(record map[string]any, columns []string)) error {
|
||||
func walkTableRecord(db *sql.DB, selectSql string, walk func(record map[string]any, columns []string)) ([]string, error) {
|
||||
rows, err := db.Query(selectSql)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
// rows对象一定要close掉,如果出错,不关掉则会很迅速的达到设置最大连接数,
|
||||
// 后面的链接过来直接报错或拒绝,实际上也没有起效果
|
||||
@@ -97,7 +92,7 @@ func walkTableRecord(db *sql.DB, selectSql string, walk func(record map[string]a
|
||||
|
||||
colTypes, err := rows.ColumnTypes()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
lenCols := len(colTypes)
|
||||
// 列名用于前端表头名称按照数据库与查询字段顺序显示
|
||||
@@ -115,7 +110,7 @@ func walkTableRecord(db *sql.DB, selectSql string, walk func(record map[string]a
|
||||
for rows.Next() {
|
||||
// 不Scan也会导致等待,该链接实际处于未工作的状态,然后也会导致连接数迅速达到最大
|
||||
if err := rows.Scan(scans...); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
// 每行数据
|
||||
rowData := make(map[string]any, lenCols)
|
||||
@@ -126,7 +121,7 @@ func walkTableRecord(db *sql.DB, selectSql string, walk func(record map[string]a
|
||||
walk(rowData, colNames)
|
||||
}
|
||||
|
||||
return nil
|
||||
return colNames, nil
|
||||
}
|
||||
|
||||
// 将查询的值转为对应列类型的实际值,不全部转为字符串
|
||||
|
||||
Reference in New Issue
Block a user