mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-12-10 01:40:25 +08:00
refactor: 数据库表使用虚拟表替换,提升数据量较大时的渲染速度
This commit is contained in:
@@ -366,7 +366,7 @@ const state = reactive({
|
|||||||
activeName: '',
|
activeName: '',
|
||||||
reloadStatus: false,
|
reloadStatus: false,
|
||||||
tabs,
|
tabs,
|
||||||
dataTabsTableHeight: '600',
|
dataTabsTableHeight: 600,
|
||||||
editorHeight: '600',
|
editorHeight: '600',
|
||||||
tablesOpHeight: '600',
|
tablesOpHeight: '600',
|
||||||
});
|
});
|
||||||
@@ -388,7 +388,7 @@ onBeforeUnmount(() => {
|
|||||||
*/
|
*/
|
||||||
const setHeight = () => {
|
const setHeight = () => {
|
||||||
state.editorHeight = window.innerHeight - 500 + 'px';
|
state.editorHeight = window.innerHeight - 500 + 'px';
|
||||||
state.dataTabsTableHeight = window.innerHeight - 255 + 'px';
|
state.dataTabsTableHeight = window.innerHeight - 255;
|
||||||
state.tablesOpHeight = window.innerHeight - 220 + 'px';
|
state.tablesOpHeight = window.innerHeight - 220 + 'px';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -50,10 +50,7 @@
|
|||||||
|
|
||||||
<div class="mt5">
|
<div class="mt5">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-link v-if="table" @click="onDeleteData()" class="ml5" type="danger" icon="delete" :underline="false"></el-link>
|
|
||||||
|
|
||||||
<span v-if="execRes.data.length > 0">
|
<span v-if="execRes.data.length > 0">
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
<el-link type="success" :underline="false" @click="exportData"><span style="font-size: 12px">导出</span></el-link>
|
<el-link type="success" :underline="false" @click="exportData"><span style="font-size: 12px">导出</span></el-link>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="hasUpdatedFileds">
|
<span v-if="hasUpdatedFileds">
|
||||||
@@ -77,6 +74,7 @@
|
|||||||
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
||||||
@selection-change="onDataSelectionChange"
|
@selection-change="onDataSelectionChange"
|
||||||
@change-updated-field="changeUpdatedField"
|
@change-updated-field="changeUpdatedField"
|
||||||
|
@data-delete="onDeleteData"
|
||||||
></db-table-data>
|
></db-table-data>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,7 +147,7 @@ const state = reactive({
|
|||||||
hasUpdatedFileds: false,
|
hasUpdatedFileds: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { tableDataHeight, execRes, table, loading, hasUpdatedFileds } = toRefs(state);
|
const { tableDataHeight, execRes, loading, hasUpdatedFileds } = toRefs(state);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.editorHeight,
|
() => props.editorHeight,
|
||||||
@@ -529,27 +527,20 @@ const onDataSelectionChange = (datas: []) => {
|
|||||||
state.selectionDatas = datas;
|
state.selectionDatas = datas;
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeUpdatedField = (updatedFields: []) => {
|
const changeUpdatedField = (updatedFields: any) => {
|
||||||
// 如果存在要更新字段,则显示提交和取消按钮
|
// 如果存在要更新字段,则显示提交和取消按钮
|
||||||
state.hasUpdatedFileds = updatedFields && updatedFields.length > 0;
|
state.hasUpdatedFileds = updatedFields && updatedFields.size > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行删除数据事件
|
* 数据删除事件
|
||||||
*/
|
*/
|
||||||
const onDeleteData = async () => {
|
const onDeleteData = async (deleteDatas: any) => {
|
||||||
const deleteDatas = state.selectionDatas;
|
|
||||||
isTrue(deleteDatas && deleteDatas.length > 0, '请先选择要删除的数据');
|
|
||||||
const db = props.dbName;
|
const db = props.dbName;
|
||||||
const dbInst = getNowDbInst();
|
const dbInst = getNowDbInst();
|
||||||
const primaryKey = await dbInst.loadTableColumn(db, state.table);
|
const primaryKey = await dbInst.loadTableColumn(db, state.table);
|
||||||
const primaryKeyColumnName = primaryKey.columnName;
|
const primaryKeyColumnName = primaryKey.columnName;
|
||||||
dbInst.promptExeSql(db, dbInst.genDeleteByPrimaryKeysSql(db, state.table, deleteDatas), null, () => {
|
state.execRes.data = state.execRes.data.filter((d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1));
|
||||||
state.execRes.data = state.execRes.data.filter(
|
|
||||||
(d: any) => !(deleteDatas.findIndex((x: any) => x[primaryKeyColumnName] == d[primaryKeyColumnName]) != -1)
|
|
||||||
);
|
|
||||||
state.selectionDatas = [];
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitUpdateFields = () => {
|
const submitUpdateFields = () => {
|
||||||
@@ -572,10 +563,6 @@ const cancelUpdateFields = () => {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.update_field_active {
|
|
||||||
background-color: var(--el-color-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor-move-resize {
|
.editor-move-resize {
|
||||||
cursor: n-resize;
|
cursor: n-resize;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
|
|||||||
@@ -1,51 +1,122 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="db-table-data mt5" :style="{ height: `${tableHeight}px` }">
|
||||||
<el-table
|
<el-auto-resizer>
|
||||||
@cell-dblclick="(row: any, column: any, cell: any, event: any) => cellClick(row, column, cell)"
|
<template #default="{ height, width }">
|
||||||
@sort-change="(sort: any) => onTableSortChange(sort)"
|
<el-table-v2
|
||||||
@selection-change="onDataSelectionChange"
|
ref="tableRef"
|
||||||
:data="datas"
|
:header-height="32"
|
||||||
size="small"
|
:row-height="32"
|
||||||
:max-height="tableHeight"
|
:row-class="rowClass"
|
||||||
v-loading="loading"
|
:columns="state.columns"
|
||||||
element-loading-text="查询中..."
|
:data="datas"
|
||||||
:empty-text="emptyText"
|
:width="width"
|
||||||
highlight-current-row
|
:height="height"
|
||||||
stripe
|
fixed
|
||||||
border
|
:row-event-handlers="rowEventHandlers"
|
||||||
class="mt5"
|
|
||||||
>
|
|
||||||
<el-table-column v-if="datas.length > 0 && table" type="selection" width="35" />
|
|
||||||
|
|
||||||
<template v-for="(item, index) in columns">
|
|
||||||
<el-table-column
|
|
||||||
min-width="100"
|
|
||||||
:width="DbInst.flexColumnWidth(item.columnName, datas)"
|
|
||||||
align="center"
|
|
||||||
v-if="item.show"
|
|
||||||
:key="index"
|
|
||||||
:prop="item.columnName"
|
|
||||||
:label="item.columnName"
|
|
||||||
show-overflow-tooltip
|
|
||||||
:sortable="sortable"
|
|
||||||
>
|
>
|
||||||
<template #header v-if="showColumnTip">
|
<template #header="{ columns }">
|
||||||
<el-tooltip :show-after="500" raw-content placement="top">
|
<div v-for="(column, i) in columns" :key="i">
|
||||||
<template #content> {{ getColumnTip(item) }} </template>
|
<div
|
||||||
{{ item.columnName }}
|
:style="{
|
||||||
</el-tooltip>
|
width: `${column.width}px`,
|
||||||
|
height: '100%',
|
||||||
|
lineHeight: '32px',
|
||||||
|
textAlign: 'center',
|
||||||
|
borderRight: 'var(--el-table-border)',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<!-- 行号列表头 -->
|
||||||
|
<div v-if="column.key == rowNoColumn.key || !showColumnTip">
|
||||||
|
<el-text tag="b"> {{ column.title }} </el-text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else @contextmenu="headerContextmenuClick($event, column)">
|
||||||
|
<div v-if="showColumnTip" @mouseover="column.showSetting = true" @mouseleave="column.showSetting = false">
|
||||||
|
<el-tooltip :show-after="500" raw-content placement="top">
|
||||||
|
<template #content> {{ getColumnTip(column) }} </template>
|
||||||
|
<el-text tag="b" style="cursor: pointer"> {{ column.title }} </el-text>
|
||||||
|
</el-tooltip>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<SvgIcon
|
||||||
|
color="var(--el-color-primary)"
|
||||||
|
v-if="column.title == nowSortColumn?.columnName"
|
||||||
|
:name="nowSortColumn?.order == 'asc' ? 'top' : 'bottom'"
|
||||||
|
></SvgIcon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<el-text tag="b" style="cursor: pointer"> {{ column.title }} </el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
|
||||||
|
<template #cell="{ rowData, column, rowIndex, columnIndex }">
|
||||||
|
<div style="width: 100%; height: 100%; line-height: 32px">
|
||||||
|
<!-- 行号列 -->
|
||||||
|
<div v-if="column.key == 'tableDataRowNo'">
|
||||||
|
<el-text tag="b" size="small">
|
||||||
|
{{ rowIndex + 1 }}
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据列 -->
|
||||||
|
<div v-else @dblclick="onEnterEditMode($event.target, rowData, column, rowIndex, columnIndex)">
|
||||||
|
<div v-if="canEdit(rowIndex, columnIndex)">
|
||||||
|
<el-input
|
||||||
|
:ref="(el: any) => el?.focus()"
|
||||||
|
@blur="onExitEditMode(rowData, column, rowIndex)"
|
||||||
|
class="w100"
|
||||||
|
input-style="text-align: center"
|
||||||
|
size="small"
|
||||||
|
v-model="rowData[column.dataKey!]"
|
||||||
|
></el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else :class="isUpdated(rowIndex, column.dataKey) ? 'update_field_active' : ''">
|
||||||
|
<el-text :title="rowData[column.dataKey!]" size="small" truncated>
|
||||||
|
{{ rowData[column.dataKey!] }}
|
||||||
|
</el-text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="loading" #overlay>
|
||||||
|
<div class="el-loading-mask" style="display: flex; align-items: center; justify-content: center">
|
||||||
|
<SvgIcon name="loading" color="var(--el-color-primary)" :size="26" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #empty>
|
||||||
|
<div style="text-align: center">
|
||||||
|
<el-empty :description="state.emptyText" :image-size="100" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-v2>
|
||||||
</template>
|
</template>
|
||||||
</el-table>
|
</el-auto-resizer>
|
||||||
|
|
||||||
|
<el-dialog @close="state.genSqlDialog.visible = false" v-model="state.genSqlDialog.visible" :title="state.genSqlDialog.title" width="1000px">
|
||||||
|
<el-input v-model="state.genSqlDialog.sql" type="textarea" rows="20" />
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="headerContextmenuRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, watch, reactive, toRefs } from 'vue';
|
import { ref, onMounted, watch, reactive, toRefs } from 'vue';
|
||||||
import { DbInst, UpdateFieldsMeta, FieldsMeta } from '@/views/ops/db/db';
|
import { ElInput } from 'element-plus';
|
||||||
|
import { DbInst } from '@/views/ops/db/db';
|
||||||
|
import Contextmenu from '@/components/contextmenu/index.vue';
|
||||||
|
import { ContextmenuItem } from '@/components/contextmenu/index';
|
||||||
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
|
|
||||||
const emits = defineEmits(['sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
const emits = defineEmits(['dataDelete', 'sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dbId: {
|
dbId: {
|
||||||
@@ -87,50 +158,348 @@ const props = defineProps({
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: String,
|
type: Number,
|
||||||
default: '600',
|
default: 600,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const headerContextmenuRef = ref();
|
||||||
|
const tableRef = ref();
|
||||||
|
|
||||||
|
const cmHeaderAsc = new ContextmenuItem('asc', '升序').withIcon('top').withOnClick((data: any) => {
|
||||||
|
onTableSortChange({ columnName: data.dataKey, order: 'asc' });
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmHeaderDesc = new ContextmenuItem('desc', '降序').withIcon('bottom').withOnClick((data: any) => {
|
||||||
|
onTableSortChange({ columnName: data.dataKey, order: 'desc' });
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmDataDel = new ContextmenuItem('desc', '删除')
|
||||||
|
.withIcon('delete')
|
||||||
|
.withOnClick(() => onDeleteData())
|
||||||
|
.withHideFunc(() => {
|
||||||
|
return state.table == '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmDataGenInsertSql = new ContextmenuItem('genInsertSql', 'Insert SQL')
|
||||||
|
.withIcon('document')
|
||||||
|
.withOnClick(() => onGenerateInsertSql())
|
||||||
|
.withHideFunc(() => {
|
||||||
|
return state.table == '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmDataGenJson = new ContextmenuItem('genJson', '生成JSON').withIcon('document').withOnClick(() => onGenerateJson());
|
||||||
|
|
||||||
|
class NowUpdateCell {
|
||||||
|
rowIndex: number;
|
||||||
|
colIndex: number;
|
||||||
|
oldValue: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdatedRow {
|
||||||
|
/**
|
||||||
|
* 主键值
|
||||||
|
*/
|
||||||
|
primaryValue: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行数据
|
||||||
|
*/
|
||||||
|
rowData: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改到的列信息, columnName -> tablecelldata
|
||||||
|
*/
|
||||||
|
columnsMap: Map<string, TableCellData> = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TableCellData {
|
||||||
|
/**
|
||||||
|
* 旧值
|
||||||
|
*/
|
||||||
|
oldValue: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nowSortColumn = null as any;
|
||||||
|
|
||||||
|
// 当前正在更新的单元格
|
||||||
|
let nowUpdateCell: NowUpdateCell = null as any;
|
||||||
|
|
||||||
|
// 选中的数据, key->rowIndex value->primaryKeyValue
|
||||||
|
const selectionRowsMap: Map<number, any> = new Map();
|
||||||
|
|
||||||
|
// 更新单元格 key-> rowIndex value -> 更新行
|
||||||
|
const cellUpdateMap: Map<number, UpdatedRow> = new Map();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
dbId: 0, // 当前选中操作的数据库实例
|
dbId: 0, // 当前选中操作的数据库实例
|
||||||
dbType: '',
|
dbType: '',
|
||||||
db: '', // 数据库名
|
db: '', // 数据库名
|
||||||
table: '', // 当前的表名
|
table: '', // 当前的表名
|
||||||
datas: [],
|
datas: [],
|
||||||
columns: [],
|
columns: [] as any,
|
||||||
sortable: false,
|
sortable: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
selectionDatas: [] as any,
|
|
||||||
showColumnTip: false,
|
showColumnTip: false,
|
||||||
tableHeight: '600',
|
tableHeight: 600,
|
||||||
emptyText: '',
|
emptyText: '',
|
||||||
updatedFields: [] as UpdateFieldsMeta[], // 各个tab表被修改的字段信息
|
|
||||||
|
contextmenu: {
|
||||||
|
dropdown: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
items: [] as ContextmenuItem[],
|
||||||
|
},
|
||||||
|
|
||||||
|
genSqlDialog: {
|
||||||
|
title: 'SQL',
|
||||||
|
visible: false,
|
||||||
|
sql: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { tableHeight, datas } = toRefs(state);
|
const { tableHeight, datas } = toRefs(state);
|
||||||
|
|
||||||
watch(props, (newValue: any) => {
|
/**
|
||||||
setState(newValue);
|
* 行号字段列
|
||||||
});
|
*/
|
||||||
|
const rowNoColumn = {
|
||||||
|
title: 'No.',
|
||||||
|
key: 'tableDataRowNo',
|
||||||
|
dataKey: 'tableDataRowNo',
|
||||||
|
width: 45,
|
||||||
|
fixed: true,
|
||||||
|
align: 'center',
|
||||||
|
headerClass: 'table-data-cell',
|
||||||
|
class: 'table-data-cell',
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
(newValue: any) => {
|
||||||
|
setTableData(newValue);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.columns,
|
||||||
|
(newValue: any) => {
|
||||||
|
setTableColumns(newValue);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.table,
|
||||||
|
(newValue: any) => {
|
||||||
|
state.table = newValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.height,
|
||||||
|
(newValue: any) => {
|
||||||
|
state.tableHeight = newValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.loading,
|
||||||
|
(newValue: any) => {
|
||||||
|
state.loading = newValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
console.log('in DbTable mounted');
|
console.log('in DbTable mounted');
|
||||||
setState(props);
|
state.tableHeight = props.height;
|
||||||
});
|
state.sortable = props.sortable as any;
|
||||||
|
state.loading = props.loading;
|
||||||
|
state.showColumnTip = props.showColumnTip;
|
||||||
|
state.emptyText = props.emptyText;
|
||||||
|
|
||||||
const setState = (props: any) => {
|
|
||||||
state.dbId = props.dbId;
|
state.dbId = props.dbId;
|
||||||
state.dbType = props.dbType;
|
state.dbType = props.dbType;
|
||||||
state.db = props.db;
|
state.db = props.db;
|
||||||
state.table = props.table;
|
state.table = props.table;
|
||||||
state.datas = props.data;
|
});
|
||||||
state.tableHeight = props.height;
|
|
||||||
state.sortable = props.sortable;
|
const setTableData = (datas: any) => {
|
||||||
state.loading = props.loading;
|
console.log('set table datas', props);
|
||||||
state.columns = props.columns;
|
tableRef.value.scrollTo({ scrollLeft: 0, scrollTop: 0 });
|
||||||
state.showColumnTip = props.showColumnTip;
|
selectionRowsMap.clear();
|
||||||
state.emptyText = props.emptyText;
|
cellUpdateMap.clear();
|
||||||
|
state.datas = datas;
|
||||||
|
setTableColumns(props.columns);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setTableColumns = (columns: any) => {
|
||||||
|
state.columns = columns.map((x: any) => {
|
||||||
|
const columnName = x.columnName;
|
||||||
|
return {
|
||||||
|
...x,
|
||||||
|
key: columnName,
|
||||||
|
dataKey: columnName,
|
||||||
|
width: DbInst.flexColumnWidth(columnName, state.datas),
|
||||||
|
title: columnName,
|
||||||
|
align: 'center',
|
||||||
|
headerClass: 'table-data-cell',
|
||||||
|
class: 'table-data-cell',
|
||||||
|
sortable: true,
|
||||||
|
hidden: !x.show,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
state.columns.unshift(rowNoColumn);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前单元格是否允许编辑
|
||||||
|
* @param rowIndex ri
|
||||||
|
* @param colIndex ci
|
||||||
|
*/
|
||||||
|
const canEdit = (rowIndex: number, colIndex: number) => {
|
||||||
|
return state.table && nowUpdateCell && nowUpdateCell.rowIndex == rowIndex && nowUpdateCell.colIndex == colIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isUpdated = (rowIndex: number, columnName: string) => {
|
||||||
|
return cellUpdateMap.get(rowIndex)?.columnsMap.get(columnName);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前行是否被选中
|
||||||
|
* @param rowIndex
|
||||||
|
*/
|
||||||
|
const isSelection = (rowIndex: number): boolean => {
|
||||||
|
return selectionRowsMap.get(rowIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选中指定行
|
||||||
|
* @param rowIndex
|
||||||
|
* @param rowData
|
||||||
|
* @param isMultiple 是否允许多选
|
||||||
|
*/
|
||||||
|
const selectionRow = (rowIndex: number, rowData: any, isMultiple = false) => {
|
||||||
|
if (isMultiple) {
|
||||||
|
// 如果重复点击,则取消改选中数据
|
||||||
|
if (selectionRowsMap.get(rowIndex)) {
|
||||||
|
selectionRowsMap.delete(rowIndex);
|
||||||
|
triggerRefresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectionRowsMap.clear();
|
||||||
|
}
|
||||||
|
selectionRowsMap.set(rowIndex, rowData);
|
||||||
|
triggerRefresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 行事件处理
|
||||||
|
*/
|
||||||
|
const rowEventHandlers = {
|
||||||
|
onClick: (e: any) => {
|
||||||
|
const event = e.event;
|
||||||
|
const rowIndex = e.rowIndex;
|
||||||
|
const rowData = e.rowData;
|
||||||
|
// 按住ctrl点击,则新建标签页打开, metaKey对应mac command键
|
||||||
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
selectionRow(rowIndex, rowData, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectionRow(rowIndex, rowData);
|
||||||
|
},
|
||||||
|
onContextmenu: (e: any) => {
|
||||||
|
dataContextmenuClick(e.event, e.rowIndex, e.rowData);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const headerContextmenuClick = (event: any, data: any) => {
|
||||||
|
event.preventDefault(); // 阻止默认的右击菜单行为
|
||||||
|
|
||||||
|
const { clientX, clientY } = event;
|
||||||
|
state.contextmenu.dropdown.x = clientX;
|
||||||
|
state.contextmenu.dropdown.y = clientY;
|
||||||
|
state.contextmenu.items = [cmHeaderAsc, cmHeaderDesc];
|
||||||
|
headerContextmenuRef.value.openContextmenu(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dataContextmenuClick = (event: any, rowIndex: number, data: any) => {
|
||||||
|
event.preventDefault(); // 阻止默认的右击菜单行为
|
||||||
|
|
||||||
|
// 当前行未选中,则单行选中该行
|
||||||
|
if (!isSelection(rowIndex)) {
|
||||||
|
selectionRow(rowIndex, data);
|
||||||
|
}
|
||||||
|
const { clientX, clientY } = event;
|
||||||
|
state.contextmenu.dropdown.x = clientX;
|
||||||
|
state.contextmenu.dropdown.y = clientY;
|
||||||
|
state.contextmenu.items = [cmDataDel, cmDataGenInsertSql, cmDataGenJson];
|
||||||
|
headerContextmenuRef.value.openContextmenu(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEnterEditMode = (el: any, rowData: any, column: any, rowIndex = 0, columnIndex = 0) => {
|
||||||
|
if (!state.table) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerRefresh();
|
||||||
|
|
||||||
|
const oldVal = rowData[column.dataKey];
|
||||||
|
nowUpdateCell = {
|
||||||
|
rowIndex: rowIndex,
|
||||||
|
colIndex: columnIndex,
|
||||||
|
oldValue: oldVal,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const onExitEditMode = (rowData: any, column: any, rowIndex = 0) => {
|
||||||
|
const oldValue = nowUpdateCell.oldValue;
|
||||||
|
const newValue = rowData[column.dataKey];
|
||||||
|
|
||||||
|
// 未改变单元格值
|
||||||
|
if (oldValue == newValue) {
|
||||||
|
nowUpdateCell = null as any;
|
||||||
|
triggerRefresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let updatedRow = cellUpdateMap.get(rowIndex);
|
||||||
|
if (!updatedRow) {
|
||||||
|
updatedRow = new UpdatedRow();
|
||||||
|
updatedRow.rowData = rowData;
|
||||||
|
cellUpdateMap.set(rowIndex, updatedRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
const columnName = column.dataKey;
|
||||||
|
let cellData = updatedRow.columnsMap.get(columnName);
|
||||||
|
if (cellData) {
|
||||||
|
// 多次修改情况,可能又修改回原值,则移除该修改单元格
|
||||||
|
if (cellData.oldValue == newValue) {
|
||||||
|
cellUpdateMap.delete(rowIndex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cellData = new TableCellData();
|
||||||
|
cellData.oldValue = oldValue;
|
||||||
|
updatedRow.columnsMap.set(columnName, cellData);
|
||||||
|
}
|
||||||
|
|
||||||
|
nowUpdateCell = null as any;
|
||||||
|
triggerRefresh();
|
||||||
|
changeUpdatedField();
|
||||||
|
};
|
||||||
|
|
||||||
|
const rowClass = (row: any) => {
|
||||||
|
if (isSelection(row.rowIndex)) {
|
||||||
|
return 'data-selection';
|
||||||
|
}
|
||||||
|
if (row.rowIndex % 2 != 0) {
|
||||||
|
return 'data-spacing';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getColumnTip = (column: any) => {
|
const getColumnTip = (column: any) => {
|
||||||
@@ -138,184 +507,127 @@ const getColumnTip = (column: any) => {
|
|||||||
return `${column.columnType} ${comment ? ' | ' + comment : ''}`;
|
return `${column.columnType} ${comment ? ' | ' + comment : ''}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发响应式实时刷新,否则需要滑动或移动才能使样式实时生效
|
||||||
|
*/
|
||||||
|
const triggerRefresh = () => {
|
||||||
|
// 改变columns等属性值,才能触发slot中的if条件等, 暂不知为啥
|
||||||
|
if (state.columns[0].opTimes) {
|
||||||
|
state.columns[0].opTimes = state.columns[0].opTimes + 1;
|
||||||
|
} else {
|
||||||
|
state.columns[0].opTimes = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表排序字段变更
|
* 表排序字段变更
|
||||||
*/
|
*/
|
||||||
const onTableSortChange = async (sort: any) => {
|
const onTableSortChange = async (sort: any) => {
|
||||||
if (!sort.prop) {
|
nowSortColumn = sort;
|
||||||
return;
|
|
||||||
}
|
|
||||||
cancelUpdateFields();
|
cancelUpdateFields();
|
||||||
emits('sortChange', sort);
|
emits('sortChange', sort);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDataSelectionChange = (datas: []) => {
|
/**
|
||||||
state.selectionDatas = datas;
|
* 执行删除数据事件
|
||||||
emits('selectionChange', datas);
|
*/
|
||||||
|
const onDeleteData = async () => {
|
||||||
|
const deleteDatas = Array.from(selectionRowsMap.values());
|
||||||
|
const db = state.db;
|
||||||
|
const dbInst = getNowDbInst();
|
||||||
|
dbInst.promptExeSql(db, await dbInst.genDeleteByPrimaryKeysSql(db, state.table, deleteDatas as any), null, () => {
|
||||||
|
emits('dataDelete', deleteDatas);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听单元格点击事件
|
const onGenerateInsertSql = async () => {
|
||||||
const cellClick = (row: any, column: any, cell: any) => {
|
const selectionDatas = Array.from(selectionRowsMap.values());
|
||||||
const property = column.property;
|
state.genSqlDialog.sql = await getNowDbInst().genInsertSql(state.db, state.table, selectionDatas);
|
||||||
// 如果当前操作的表名不存在 或者 当前列的property不存在(如多选框),则不允许修改当前单元格内容
|
state.genSqlDialog.title = 'SQL';
|
||||||
if (!state.table || !property) {
|
state.genSqlDialog.visible = true;
|
||||||
return;
|
|
||||||
}
|
|
||||||
let div: HTMLElement = cell.children[0];
|
|
||||||
if (div && div.tagName === 'DIV') {
|
|
||||||
// 转为字符串比较,可能存在数字等
|
|
||||||
let text = (row[property] || row[property] == 0 ? row[property] : '') + '';
|
|
||||||
let input = document.createElement('input');
|
|
||||||
input.setAttribute('value', text);
|
|
||||||
// 将表格width也赋值于输入框,避免输入框长度超过表格长度
|
|
||||||
input.setAttribute('style', 'height:23px;text-align:center;border:none;' + div.getAttribute('style'));
|
|
||||||
cell.replaceChildren(input);
|
|
||||||
input.focus();
|
|
||||||
input.addEventListener('blur', async () => {
|
|
||||||
row[property] = input.value;
|
|
||||||
cell.replaceChildren(div);
|
|
||||||
if (input.value !== text) {
|
|
||||||
let currentUpdatedFields = state.updatedFields;
|
|
||||||
const dbInst = getNowDbInst();
|
|
||||||
// 主键
|
|
||||||
const primaryKey = await dbInst.loadTableColumn(state.db, state.table);
|
|
||||||
const primaryKeyValue = row[primaryKey.columnName];
|
|
||||||
// 更新字段列信息
|
|
||||||
const updateColumn = await dbInst.loadTableColumn(state.db, state.table, property);
|
|
||||||
const newField = {
|
|
||||||
div,
|
|
||||||
row,
|
|
||||||
fieldName: property,
|
|
||||||
fieldType: updateColumn.columnType,
|
|
||||||
oldValue: text,
|
|
||||||
newValue: input.value,
|
|
||||||
} as FieldsMeta;
|
|
||||||
|
|
||||||
// 被修改的字段
|
|
||||||
const primaryKeyFields = currentUpdatedFields.filter((meta) => meta.primaryKey === primaryKeyValue);
|
|
||||||
let hasKey = false;
|
|
||||||
if (primaryKeyFields.length <= 0) {
|
|
||||||
primaryKeyFields[0] = {
|
|
||||||
primaryKey: primaryKeyValue,
|
|
||||||
primaryKeyName: primaryKey.columnName,
|
|
||||||
primaryKeyType: primaryKey.columnType,
|
|
||||||
fields: [newField],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
hasKey = true;
|
|
||||||
let hasField = primaryKeyFields[0].fields.some((a) => {
|
|
||||||
if (a.fieldName === newField.fieldName) {
|
|
||||||
a.newValue = newField.newValue;
|
|
||||||
}
|
|
||||||
return a.fieldName === newField.fieldName;
|
|
||||||
});
|
|
||||||
if (!hasField) {
|
|
||||||
primaryKeyFields[0].fields.push(newField);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let fields = primaryKeyFields[0].fields;
|
|
||||||
|
|
||||||
const fieldsParam = fields.filter((a) => {
|
|
||||||
if (a.fieldName === column.property) {
|
|
||||||
a.newValue = input.value;
|
|
||||||
}
|
|
||||||
return a.fieldName === column.property;
|
|
||||||
});
|
|
||||||
|
|
||||||
const field = (fieldsParam.length > 0 && fieldsParam[0]) || ({} as FieldsMeta);
|
|
||||||
if (field.oldValue === input.value) {
|
|
||||||
// 新值=旧值
|
|
||||||
// 删除数据
|
|
||||||
div.classList.remove('update_field_active');
|
|
||||||
let delIndex: number[] = [];
|
|
||||||
currentUpdatedFields.forEach((a, i) => {
|
|
||||||
if (a.primaryKey === primaryKeyValue) {
|
|
||||||
a.fields = a.fields && a.fields.length > 0 ? a.fields.filter((f) => f.fieldName !== column.property) : [];
|
|
||||||
a.fields.length <= 0 && delIndex.push(i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
delIndex.forEach((i) => delete currentUpdatedFields[i]);
|
|
||||||
currentUpdatedFields = currentUpdatedFields.filter((a) => a);
|
|
||||||
} else {
|
|
||||||
// 新增数据
|
|
||||||
div.classList.add('update_field_active');
|
|
||||||
if (hasKey) {
|
|
||||||
currentUpdatedFields.forEach((value, index, array) => {
|
|
||||||
if (value.primaryKey === primaryKeyValue) {
|
|
||||||
array[index].fields = fields;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
currentUpdatedFields.push({
|
|
||||||
primaryKey: primaryKeyValue,
|
|
||||||
primaryKeyName: primaryKey.columnName,
|
|
||||||
primaryKeyType: primaryKey.columnType,
|
|
||||||
fields,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.updatedFields = currentUpdatedFields;
|
|
||||||
changeUpdatedField();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitUpdateFields = () => {
|
const onGenerateJson = async () => {
|
||||||
const dbInst = DbInst.getInst(state.dbId);
|
const selectionDatas = Array.from(selectionRowsMap.values());
|
||||||
let currentUpdatedFields = state.updatedFields;
|
// 按列字段重新排序对象key
|
||||||
if (currentUpdatedFields.length <= 0) {
|
const jsonObj = [];
|
||||||
|
for (let selectionData of selectionDatas) {
|
||||||
|
let obj = {};
|
||||||
|
for (let column of state.columns) {
|
||||||
|
obj[column.title] = selectionData[column.dataKey];
|
||||||
|
}
|
||||||
|
jsonObj.push(obj);
|
||||||
|
}
|
||||||
|
state.genSqlDialog.sql = JSON.stringify(jsonObj, null, 4);
|
||||||
|
state.genSqlDialog.title = 'JSON';
|
||||||
|
state.genSqlDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitUpdateFields = async () => {
|
||||||
|
const dbInst = getNowDbInst();
|
||||||
|
if (cellUpdateMap.size == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const db = state.db;
|
const db = state.db;
|
||||||
let res = '';
|
let res = '';
|
||||||
let divs: HTMLElement[] = [];
|
|
||||||
currentUpdatedFields.forEach((a) => {
|
for (let updateRow of cellUpdateMap.values()) {
|
||||||
let sql = `UPDATE ${dbInst.wrapName(state.table)} SET `;
|
let sql = `UPDATE ${dbInst.wrapName(state.table)} SET `;
|
||||||
let primaryKey = a.primaryKey;
|
const rowData = updateRow.rowData;
|
||||||
let primaryKeyType = a.primaryKeyType;
|
// 主键列信息
|
||||||
let primaryKeyName = a.primaryKeyName;
|
const primaryKey = await dbInst.loadTableColumn(db, state.table);
|
||||||
a.fields.forEach((f) => {
|
let primaryKeyType = primaryKey.columnType;
|
||||||
sql += ` ${dbInst.wrapName(f.fieldName)} = ${DbInst.wrapColumnValue(f.fieldType, f.newValue)},`;
|
let primaryKeyName = primaryKey.columnName;
|
||||||
// 如果修改的字段是主键
|
let primaryKeyValue = rowData[primaryKeyName];
|
||||||
if (f.fieldName === primaryKeyName) {
|
|
||||||
primaryKey = f.oldValue;
|
for (let k of updateRow.columnsMap.keys()) {
|
||||||
|
const v = updateRow.columnsMap.get(k);
|
||||||
|
if (!v) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
divs.push(f.div);
|
// 更新字段列信息
|
||||||
});
|
const updateColumn = await dbInst.loadTableColumn(db, state.table, k);
|
||||||
|
sql += ` ${dbInst.wrapName(k)} = ${DbInst.wrapColumnValue(updateColumn.columnType, rowData[k])},`;
|
||||||
|
|
||||||
|
// 如果修改的字段是主键
|
||||||
|
if (k === primaryKeyName) {
|
||||||
|
primaryKeyValue = v.oldValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sql = sql.substring(0, sql.length - 1);
|
sql = sql.substring(0, sql.length - 1);
|
||||||
sql += ` WHERE ${dbInst.wrapName(primaryKeyName)} = ${DbInst.wrapColumnValue(primaryKeyType, primaryKey)} ;`;
|
sql += ` WHERE ${dbInst.wrapName(primaryKeyName)} = ${DbInst.wrapColumnValue(primaryKeyType, primaryKeyValue)} ;`;
|
||||||
res += sql;
|
res += sql;
|
||||||
});
|
}
|
||||||
|
|
||||||
dbInst.promptExeSql(
|
dbInst.promptExeSql(
|
||||||
db,
|
db,
|
||||||
res,
|
res,
|
||||||
() => {},
|
() => {},
|
||||||
() => {
|
() => {
|
||||||
currentUpdatedFields = [];
|
triggerRefresh();
|
||||||
divs.forEach((a) => {
|
cellUpdateMap.clear();
|
||||||
a.classList.remove('update_field_active');
|
|
||||||
});
|
|
||||||
state.updatedFields = [];
|
|
||||||
changeUpdatedField();
|
changeUpdatedField();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelUpdateFields = () => {
|
const cancelUpdateFields = () => {
|
||||||
state.updatedFields.forEach((a: any) => {
|
const updateRows = cellUpdateMap.values();
|
||||||
a.fields.forEach((b: any) => {
|
// 恢复原值
|
||||||
b.div.classList.remove('update_field_active');
|
for (let updateRow of updateRows) {
|
||||||
b.row[b.fieldName] = b.oldValue;
|
const rowData = updateRow.rowData;
|
||||||
|
updateRow.columnsMap.forEach((v: TableCellData, k: string) => {
|
||||||
|
rowData[k] = v.oldValue;
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
state.updatedFields = [];
|
cellUpdateMap.clear();
|
||||||
changeUpdatedField();
|
changeUpdatedField();
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeUpdatedField = () => {
|
const changeUpdatedField = () => {
|
||||||
emits('changeUpdatedField', state.updatedFields);
|
emits('changeUpdatedField', cellUpdateMap);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNowDbInst = () => {
|
const getNowDbInst = () => {
|
||||||
@@ -328,8 +640,22 @@ defineExpose({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style>
|
||||||
.update_field_active {
|
.db-table-data {
|
||||||
background-color: var(--el-color-success);
|
.table-data-cell {
|
||||||
|
padding: 0 2px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-right: var(--el-table-border);
|
||||||
|
}
|
||||||
|
.data-selection {
|
||||||
|
background-color: var(--el-color-success-light-8);
|
||||||
|
}
|
||||||
|
.data-spacing {
|
||||||
|
background-color: var(--el-fill-color-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.update_field_active {
|
||||||
|
background-color: var(--el-color-success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -30,19 +30,11 @@
|
|||||||
<el-link @click="onShowAddDataDialog()" type="primary" icon="plus" :underline="false"></el-link>
|
<el-link @click="onShowAddDataDialog()" type="primary" icon="plus" :underline="false"></el-link>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-link @click="onDeleteData()" type="danger" icon="delete" :underline="false"></el-link>
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
|
|
||||||
<el-tooltip :show-after="500" class="box-item" effect="dark" content="commit" placement="top">
|
<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-link @click="onCommit()" type="success" icon="CircleCheck" :underline="false"> </el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-tooltip :show-after="500" class="box-item" effect="dark" content="生成insert sql" placement="top">
|
|
||||||
<el-link @click="onGenerateInsertSql()" type="success" :underline="false">gi</el-link>
|
|
||||||
</el-tooltip>
|
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
|
||||||
|
|
||||||
<el-tooltip :show-after="500" class="box-item" effect="dark" content="导出当前页的csv文件" placement="top">
|
<el-tooltip :show-after="500" class="box-item" effect="dark" content="导出当前页的csv文件" placement="top">
|
||||||
<el-link type="success" :underline="false" @click="exportData"><span class="f12">导出</span></el-link>
|
<el-link type="success" :underline="false" @click="exportData"><span class="f12">导出</span></el-link>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@@ -118,6 +110,7 @@
|
|||||||
@sort-change="(sort: any) => onTableSortChange(sort)"
|
@sort-change="(sort: any) => onTableSortChange(sort)"
|
||||||
@selection-change="onDataSelectionChange"
|
@selection-change="onDataSelectionChange"
|
||||||
@change-updated-field="changeUpdatedField"
|
@change-updated-field="changeUpdatedField"
|
||||||
|
@data-delete="onRefresh"
|
||||||
></db-table-data>
|
></db-table-data>
|
||||||
|
|
||||||
<el-row type="flex" class="mt5" justify="center">
|
<el-row type="flex" class="mt5" justify="center">
|
||||||
@@ -187,10 +180,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog @close="state.genSqlDialog.visible = false" v-model="state.genSqlDialog.visible" title="SQL" width="1000px">
|
|
||||||
<el-input v-model="state.genSqlDialog.sql" type="textarea" rows="20" />
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -221,8 +210,8 @@ const props = defineProps({
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
tableHeight: {
|
tableHeight: {
|
||||||
type: [String],
|
type: [Number],
|
||||||
default: '600',
|
default: 600,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -258,11 +247,7 @@ const state = reactive({
|
|||||||
placeholder: '',
|
placeholder: '',
|
||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
genSqlDialog: {
|
tableHeight: 600,
|
||||||
visible: false,
|
|
||||||
sql: '',
|
|
||||||
},
|
|
||||||
tableHeight: '600',
|
|
||||||
hasUpdatedFileds: false,
|
hasUpdatedFileds: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -446,11 +431,8 @@ const onSelectByCondition = async () => {
|
|||||||
* 表排序字段变更
|
* 表排序字段变更
|
||||||
*/
|
*/
|
||||||
const onTableSortChange = async (sort: any) => {
|
const onTableSortChange = async (sort: any) => {
|
||||||
if (!sort.prop) {
|
const sortType = sort.order == 'desc' ? 'DESC' : 'ASC';
|
||||||
return;
|
state.orderBy = `ORDER BY ${sort.columnName} ${sortType}`;
|
||||||
}
|
|
||||||
const sortType = sort.order == 'descending' ? 'DESC' : 'ASC';
|
|
||||||
state.orderBy = `ORDER BY ${sort.prop} ${sortType}`;
|
|
||||||
await onRefresh();
|
await onRefresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -458,28 +440,9 @@ const onDataSelectionChange = (datas: []) => {
|
|||||||
state.selectionDatas = datas;
|
state.selectionDatas = datas;
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeUpdatedField = (updatedFields: []) => {
|
const changeUpdatedField = (updatedFields: any) => {
|
||||||
// 如果存在要更新字段,则显示提交和取消按钮
|
// 如果存在要更新字段,则显示提交和取消按钮
|
||||||
state.hasUpdatedFileds = updatedFields && updatedFields.length > 0;
|
state.hasUpdatedFileds = updatedFields && updatedFields.size > 0;
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行删除数据事件
|
|
||||||
*/
|
|
||||||
const onDeleteData = async () => {
|
|
||||||
const deleteDatas = state.selectionDatas;
|
|
||||||
isTrue(deleteDatas && deleteDatas.length > 0, '请先选择要删除的数据');
|
|
||||||
const db = props.dbName;
|
|
||||||
const dbInst = getNowDbInst();
|
|
||||||
dbInst.promptExeSql(db, dbInst.genDeleteByPrimaryKeysSql(db, props.tableName, deleteDatas), null, () => {
|
|
||||||
onRefresh();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onGenerateInsertSql = async () => {
|
|
||||||
isTrue(state.selectionDatas && state.selectionDatas.length > 0, '请先选择数据');
|
|
||||||
state.genSqlDialog.sql = getNowDbInst().genInsertSql(props.dbName, props.tableName, state.selectionDatas);
|
|
||||||
state.genSqlDialog.visible = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitUpdateFields = () => {
|
const submitUpdateFields = () => {
|
||||||
@@ -530,8 +493,4 @@ const addRow = async () => {
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss"></style>
|
||||||
.update_field_active {
|
|
||||||
background-color: var(--el-color-success);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -232,11 +232,12 @@ export class DbInst {
|
|||||||
* @param table 表名
|
* @param table 表名
|
||||||
* @param datas 要生成的数据
|
* @param datas 要生成的数据
|
||||||
*/
|
*/
|
||||||
genInsertSql(dbName: string, table: string, datas: any[]): string {
|
async genInsertSql(dbName: string, table: string, datas: any[]) {
|
||||||
if (!datas) {
|
if (!datas) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const columns = this.getDb(dbName).getColumns(table);
|
|
||||||
|
const columns = await this.loadColumns(dbName, table);
|
||||||
const sqls = [];
|
const sqls = [];
|
||||||
for (let data of datas) {
|
for (let data of datas) {
|
||||||
let colNames = [];
|
let colNames = [];
|
||||||
@@ -256,8 +257,8 @@ export class DbInst {
|
|||||||
* @param table 表名
|
* @param table 表名
|
||||||
* @param datas 要删除的记录
|
* @param datas 要删除的记录
|
||||||
*/
|
*/
|
||||||
genDeleteByPrimaryKeysSql(db: string, table: string, datas: any[]) {
|
async genDeleteByPrimaryKeysSql(db: string, table: string, datas: any[]) {
|
||||||
const primaryKey = this.getDb(db).getColumn(table);
|
const primaryKey = await this.loadTableColumn(db, table);
|
||||||
const primaryKeyColumnName = primaryKey.columnName;
|
const primaryKeyColumnName = primaryKey.columnName;
|
||||||
const ids = datas.map((d: any) => `${DbInst.wrapColumnValue(primaryKey.columnType, d[primaryKeyColumnName])}`).join(',');
|
const ids = datas.map((d: any) => `${DbInst.wrapColumnValue(primaryKey.columnType, d[primaryKeyColumnName])}`).join(',');
|
||||||
return `DELETE FROM ${this.wrapName(table)} WHERE ${this.wrapName(primaryKeyColumnName)} IN (${ids})`;
|
return `DELETE FROM ${this.wrapName(table)} WHERE ${this.wrapName(primaryKeyColumnName)} IN (${ids})`;
|
||||||
@@ -389,7 +390,7 @@ export class DbInst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取列名称的长度 加上排序图标长度
|
// 获取列名称的长度 加上排序图标长度
|
||||||
const columnWidth: number = getTextWidth(prop) + 40;
|
const columnWidth: number = getTextWidth(prop) + 23;
|
||||||
// prop为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
|
// prop为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
|
||||||
if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
|
if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
|
||||||
return columnWidth;
|
return columnWidth;
|
||||||
@@ -531,33 +532,6 @@ export class TabInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 修改表字段所需数据 */
|
|
||||||
export type UpdateFieldsMeta = {
|
|
||||||
// 主键值
|
|
||||||
primaryKey: string;
|
|
||||||
// 主键名
|
|
||||||
primaryKeyName: string;
|
|
||||||
// 主键类型
|
|
||||||
primaryKeyType: string;
|
|
||||||
// 新值
|
|
||||||
fields: FieldsMeta[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FieldsMeta = {
|
|
||||||
// 字段所在div
|
|
||||||
div: HTMLElement;
|
|
||||||
// 字段名
|
|
||||||
fieldName: string;
|
|
||||||
// 字段所在的表格行数据
|
|
||||||
row: any;
|
|
||||||
// 字段类型
|
|
||||||
fieldType: string;
|
|
||||||
// 原值
|
|
||||||
oldValue: string;
|
|
||||||
// 新值
|
|
||||||
newValue: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册数据库表、字段等信息提示
|
* 注册数据库表、字段等信息提示
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user