fix: 修复数据库表数据横向滚动后切换tab导致表头错位&数据取消居中显示

This commit is contained in:
meilin.huang
2024-05-31 12:12:40 +08:00
parent d85bbff270
commit 4814793546
15 changed files with 118 additions and 32 deletions

View File

@@ -10,7 +10,7 @@
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@vueuse/core": "^10.9.0",
"@vueuse/core": "^10.10.0",
"asciinema-player": "^3.7.1",
"axios": "^1.6.2",
"clipboard": "^2.0.11",
@@ -22,8 +22,8 @@
"jsencrypt": "^3.3.2",
"lodash": "^4.17.21",
"mitt": "^3.0.1",
"monaco-editor": "^0.48.0",
"monaco-sql-languages": "^0.11.0",
"monaco-editor": "^0.49.0",
"monaco-sql-languages": "^0.12.0",
"monaco-themes": "^0.4.4",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",

View File

@@ -15,7 +15,7 @@ const config = {
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
// 系统版本
version: 'v1.8.6',
version: 'v1.8.7',
};
export default config;

View File

@@ -177,6 +177,7 @@
:db-name="dt.db"
:table-name="dt.params.table"
:table-height="state.dataTabsTableHeight"
:ref="(el: any) => (dt.componentRef = el)"
></db-table-data-op>
<db-sql-editor
@@ -185,6 +186,7 @@
:db-name="dt.db"
:sql-name="dt.params.sqlName"
@save-sql-success="reloadSqls"
:ref="(el: any) => (dt.componentRef = el)"
>
</db-sql-editor>
@@ -579,7 +581,7 @@ const loadTableData = async (db: any, dbName: string, tableName: string) => {
}
changeDb(db, dbName);
const key = `${db.id}:\`${dbName}\`.${tableName}`;
const key = `tableData:${db.id}.${dbName}.${tableName}`;
let tab = state.tabs.get(key);
state.activeName = key;
// 如果存在该表tab则直接返回
@@ -614,7 +616,7 @@ const addQueryTab = async (db: any, dbName: string, sqlName: string = '') => {
// 存在sql模板名则该模板名只允许一个tab
if (sqlName) {
label = `查询-${sqlName}`;
key = `查询:${dbId}:${dbName}.${sqlName}`;
key = `query:${dbId}.${dbName}.${sqlName}`;
} else {
let count = 1;
state.tabs.forEach((v) => {
@@ -623,7 +625,7 @@ const addQueryTab = async (db: any, dbName: string, sqlName: string = '') => {
}
});
label = `新查询-${count}`;
key = `新查询${count}:${dbId}:${dbName}`;
key = `query:${count}.${dbId}.${dbName}`;
}
state.activeName = key;
let tab = state.tabs.get(key);
@@ -660,7 +662,7 @@ const addTablesOpTab = async (db: any) => {
changeDb(db, dbName);
const dbId = db.id;
let key = `表操作:${dbId}:${dbName}.tablesOp`;
let key = `tablesOp:${dbId}.${dbName}`;
state.activeName = key;
let tab = state.tabs.get(key);
@@ -691,15 +693,22 @@ const onRemoveTab = (targetName: string) => {
if (tabName !== targetName) {
continue;
}
state.tabs.delete(targetName);
if (activeName != targetName) {
break;
}
// 如果删除的tab是当前激活的tab则切换到前一个或后一个tab
const nextTab = tabNames[i + 1] || tabNames[i - 1];
if (nextTab) {
activeName = nextTab;
} else {
activeName = '';
}
state.tabs.delete(targetName);
state.activeName = activeName;
onTabChange();
break;
}
};
@@ -719,6 +728,9 @@ const onTabChange = () => {
registerDbCompletionItemProvider(nowTab.dbId, nowTab.db, nowTab.params.dbs, nowDbInst.value.type);
}
// 激活当前tab需要调用DbTableData组件的active否则表头与数据会出现错位暂不知为啥先这样处理
nowTab?.componentRef?.active();
if (dbConfig.value.locationTreeNode) {
locationNowTreeNode(nowTab);
}

View File

@@ -23,8 +23,11 @@ export const dbApi = {
if (process.env.NODE_ENV === 'development') {
console.log(param.sql);
}
// 非base64编码sql则进行base64编码refreshToken时会重复调用该方法故简单判断下
if (!Base64.isValid(param.sql)) {
param.sql = Base64.encode(param.sql);
}
}
return param;
}),
// 保存sql

View File

@@ -52,7 +52,7 @@
<Pane :size="100 - state.editorSize">
<div class="mt5 sql-exec-res h100">
<el-tabs class="h100 w100" v-if="state.execResTabs.length > 0" @tab-remove="onRemoveTab" v-model="state.activeTab">
<el-tabs class="h100 w100" v-if="state.execResTabs.length > 0" @tab-remove="onRemoveTab" @tab-change="active" v-model="state.activeTab">
<el-tab-pane class="h100" closable v-for="dt in state.execResTabs" :label="dt.id" :name="dt.id" :key="dt.id">
<template #label>
<el-popover :show-after="1000" placement="top-start" title="执行信息" trigger="hover" :width="300">
@@ -700,6 +700,19 @@ const initMonacoEditor = () => {
},
});
};
const active = () => {
const resTab = state.execResTabs[state.activeTab - 1];
if (!resTab || !resTab.dbTableRef) {
return;
}
resTab.dbTableRef?.active();
};
defineExpose({
active,
});
</script>
<style lang="scss">

View File

@@ -152,6 +152,10 @@ const getEditorLangByValue = (value: any) => {
<style lang="scss">
.string-input-container {
position: relative;
.el-input__wrapper {
padding: 1px 3px;
}
}
.string-input-container-show-icon {
.el-input__inner {
@@ -174,6 +178,10 @@ const getEditorLangByValue = (value: any) => {
.el-input__prefix {
display: none;
}
.el-input__wrapper {
padding: 1px 3px;
}
}
.edit-time-picker-popper {

View File

@@ -15,6 +15,7 @@
fixed
class="table"
:row-event-handlers="rowEventHandlers"
@scroll="onTableScroll"
>
<template #header="{ columns }">
<div v-for="(column, i) in columns" :key="i">
@@ -59,9 +60,7 @@
</div>
<div v-else class="header-column-title">
<b class="el-text">
{{ column.title }}
</b>
<b class="el-text"> {{ column.title }} </b>
</div>
<!-- 字段列右部分内容 -->
@@ -96,7 +95,7 @@
/>
</div>
<div v-else :class="isUpdated(rowIndex, column.dataKey) ? 'update_field_active' : ''">
<div v-else :class="isUpdated(rowIndex, column.dataKey) ? 'update_field_active ml2 mr2' : 'ml2 mr2'">
<span v-if="rowData[column.dataKey!] === null" style="color: var(--el-color-info-light-5)"> NULL </span>
<span v-else :title="rowData[column.dataKey!]" class="el-text el-text--small is-truncated">
@@ -486,7 +485,7 @@ const setTableColumns = (columns: any) => {
dataKey: columnName,
width: DbInst.flexColumnWidth(columnName, state.datas),
title: columnName,
align: 'center',
align: x.dataType == DataType.Number ? 'right' : 'left',
headerClass: 'table-column',
class: 'table-column',
sortable: true,
@@ -841,11 +840,23 @@ const triggerRefresh = () => {
}
};
const scrollLeftValue = ref(0);
const onTableScroll = (param: any) => {
scrollLeftValue.value = param.scrollLeft;
};
/**
* 激活表格,恢复滚动位置,否则会造成表头与数据单元格错位(暂不知为啥,先这样解决)
*/
const active = () => {
setTimeout(() => tableRef.value.scrollToLeft(scrollLeftValue.value));
};
const getNowDbInst = () => {
return DbInst.getInst(state.dbId);
};
defineExpose({
active,
submitUpdateFields,
cancelUpdateFields,
});

View File

@@ -48,6 +48,21 @@
<el-tooltip :show-after="500" class="box-item" effect="dark" content="commit" placement="top">
<el-link @click="onCommit()" type="success" icon="CircleCheck" :underline="false"> </el-link>
</el-tooltip>
<el-divider direction="vertical" border-style="dashed" />
<!-- 表数据展示配置 -->
<el-popover
popper-style="max-height: 550px; overflow: auto; max-width: 450px"
placement="bottom"
width="auto"
title="展示配置"
trigger="click"
>
<el-checkbox v-model="dbConfig.showColumnComment" label="显示字段备注" :true-value="true" :false-value="false" size="small" />
<template #reference>
<el-link type="primary" icon="setting" :underline="false"></el-link>
</template>
</el-popover>
<el-divider direction="vertical" border-style="dashed" />
@@ -243,7 +258,7 @@ import { DbInst } from '@/views/ops/db/db';
import DbTableData from './DbTableData.vue';
import { DbDialect } from '@/views/ops/db/dialect';
import SvgIcon from '@/components/svgIcon/index.vue';
import { useEventListener } from '@vueuse/core';
import { useEventListener, useStorage } from '@vueuse/core';
import { copyToClipboard } from '@/common/utils/string';
import DbTableDataForm from './DbTableDataForm.vue';
@@ -273,6 +288,8 @@ const condDialogInputRef: Ref = ref(null);
const defaultPageSize = DbInst.DefaultLimit;
const dbConfig = useStorage('dbConfig', { showColumnComment: false });
const state = reactive({
datas: [],
sql: '', // 当前数据tab执行的sql
@@ -605,6 +622,10 @@ const onShowAddDataDialog = async () => {
state.addDataDialog.title = `添加'${props.tableName}'表数据`;
state.addDataDialog.visible = true;
};
defineExpose({
active: () => dbTableRef.value.active(),
});
</script>
<style lang="scss">

View File

@@ -450,8 +450,8 @@ export class DbInst {
return;
}
// 获取列名称的长度 加上排序图标长度、abc为字段类型简称占位符
const columnWidth: number = getTextWidth(prop + 'abc') + 23;
// 获取列名称的长度 加上排序图标长度、abc为字段类型简称占位符、排序图标等
const columnWidth: number = getTextWidth(prop + 'abc') + 10;
// prop为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
return columnWidth;
@@ -471,7 +471,7 @@ export class DbInst {
maxWidthText = nowText;
}
}
const contentWidth: number = getTextWidth(maxWidthText) + 15;
const contentWidth: number = getTextWidth(maxWidthText) + 3;
const flexWidth: number = contentWidth > columnWidth ? contentWidth : columnWidth;
return flexWidth > 500 ? 500 : flexWidth;
};
@@ -601,6 +601,11 @@ export class TabInfo {
*/
params: any;
/**
* 组件ref
*/
componentRef: any;
getNowDbInst() {
return DbInst.getInst(this.dbId);
}

View File

@@ -71,9 +71,9 @@ export enum DataType {
/** 列数据类型角标 */
export const ColumnTypeSubscript = {
/** 字符串 */
string: 'abc',
string: 'ab',
/** 数字 */
number: '123',
number: '12',
/** 日期 */
date: 'icon-clock',
/** 时间 */

View File

@@ -497,20 +497,27 @@ const onRemoveTab = (targetName: string) => {
if (tabName !== targetName) {
continue;
}
state.tabs.delete(targetName);
let info = state.tabs.get(targetName);
if (info) {
terminalRefs[info.key]?.close();
}
if (activeTermName != targetName) {
break;
}
// 如果删除的tab是当前激活的tab则切换到前一个或后一个tab
const nextTab = tabNames[i + 1] || tabNames[i - 1];
if (nextTab) {
activeTermName = nextTab;
} else {
activeTermName = '';
}
let info = state.tabs.get(targetName);
if (info) {
terminalRefs[info.key]?.close();
}
state.tabs.delete(targetName);
state.activeTermName = activeTermName;
// onTabChange();
break;
}
};

View File

@@ -28,7 +28,7 @@ require (
github.com/pquerna/otp v1.4.0
github.com/redis/go-redis/v9 v9.5.1
github.com/robfig/cron/v3 v3.0.1 //
github.com/sijms/go-ora/v2 v2.8.17
github.com/sijms/go-ora/v2 v2.8.19
github.com/stretchr/testify v1.9.0
github.com/veops/go-ansiterm v0.0.5
go.mongodb.org/mongo-driver v1.15.0 // mongo

View File

@@ -297,7 +297,7 @@ func (d *dbAppImpl) DumpDb(ctx context.Context, reqParam *dto.DumpDb) error {
// 生成insert sql数据在索引前加速insert
if reqParam.DumpData {
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表记录: %s \n-- ----------------------------\n", tableName))
writer.WriteString(fmt.Sprintf("\n-- ----------------------------\n-- 表数据: %s \n-- ----------------------------\n", tableName))
dumpHelper.BeforeInsert(writer, quoteTableName)
// 获取列信息

View File

@@ -26,7 +26,7 @@ type ResourceAuthCert interface {
// GetAuthCert 根据授权凭证名称获取授权凭证
GetAuthCert(authCertName string) (*entity.ResourceAuthCert, error)
// GetResourceAuthCert 获取资源授权凭证,默认获取特权账号,若没有则返回第一个
// GetResourceAuthCert 获取资源授权凭证,优先获取默认账号,若不存在默认账号则返回特权账号,都不存在则返回第一个
GetResourceAuthCert(resourceType entity.TagType, resourceCode string) (*entity.ResourceAuthCert, error)
// FillAuthCertByAcs 根据授权凭证列表填充资源的授权凭证信息
@@ -224,6 +224,12 @@ func (r *resourceAuthCertAppImpl) GetResourceAuthCert(resourceType entity.TagTyp
return nil, errorx.NewBiz("该资源不存在授权凭证账号")
}
for _, resourceAuthCert := range resourceAuthCerts {
if resourceAuthCert.Type == entity.AuthCertTypePrivateDefault {
return r.decryptAuthCert(resourceAuthCert)
}
}
for _, resourceAuthCert := range resourceAuthCerts {
if resourceAuthCert.Type == entity.AuthCertTypePrivileged {
return r.decryptAuthCert(resourceAuthCert)

View File

@@ -4,7 +4,7 @@ import "fmt"
const (
AppName = "mayfly-go"
Version = "v1.8.6"
Version = "v1.8.7"
)
func GetAppInfo() string {