mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-04 00:10:25 +08:00
feat: 数据库支持编辑行数据
This commit is contained in:
@@ -71,7 +71,7 @@
|
|||||||
<el-descriptions-item label-align="right">
|
<el-descriptions-item label-align="right">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div>
|
<div>
|
||||||
<SvgIcon :name="getDbDialect(nowDbInst.type).getInfo().icon" :size="18" />
|
<SvgIcon :name="nowDbInst.getDialect().getInfo().icon" :size="18" />
|
||||||
实例
|
实例
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ import { buildProgressProps } from '@/components/progress-notify/progress-notify
|
|||||||
import ProgressNotify from '@/components/progress-notify/progress-notify.vue';
|
import ProgressNotify from '@/components/progress-notify/progress-notify.vue';
|
||||||
import syssocket from '@/common/syssocket';
|
import syssocket from '@/common/syssocket';
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
import { getDbDialect } from '../../dialect';
|
|
||||||
import { Pane, Splitpanes } from 'splitpanes';
|
import { Pane, Splitpanes } from 'splitpanes';
|
||||||
|
|
||||||
const emits = defineEmits(['saveSqlSuccess']);
|
const emits = defineEmits(['saveSqlSuccess']);
|
||||||
@@ -453,7 +452,7 @@ const formatSql = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatDialect = getDbDialect(getNowDbInst().type).getInfo().formatSqlDialect;
|
const formatDialect = getNowDbInst().getDialect().getInfo().formatSqlDialect;
|
||||||
|
|
||||||
let sql = monacoEditor.getModel()?.getValueInRange(selection);
|
let sql = monacoEditor.getModel()?.getValueInRange(selection);
|
||||||
// 有选中sql则格式化并替换选中sql, 否则格式化编辑器所有内容
|
// 有选中sql则格式化并替换选中sql, 否则格式化编辑器所有内容
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@blur="handleBlur"
|
@blur="handleBlur"
|
||||||
:class="`w100 mb4 ${showEditorIcon ? 'string-input-container-show-icon' : ''}`"
|
:class="`w100 mb4 ${showEditorIcon ? 'string-input-container-show-icon' : ''}`"
|
||||||
input-style="text-align: center; height: 26px;"
|
|
||||||
size="small"
|
size="small"
|
||||||
v-model="itemValue"
|
v-model="itemValue"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@@ -20,7 +19,6 @@
|
|||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@blur="handleBlur"
|
@blur="handleBlur"
|
||||||
class="w100 mb4"
|
class="w100 mb4"
|
||||||
input-style="text-align: center; height: 26px;"
|
|
||||||
size="small"
|
size="small"
|
||||||
v-model.number="itemValue"
|
v-model.number="itemValue"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@@ -185,9 +183,6 @@ const getEditorLangByValue = (value: any) => {
|
|||||||
.el-input__prefix {
|
.el-input__prefix {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.el-input__inner {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-time-picker-popper {
|
.edit-time-picker-popper {
|
||||||
|
|||||||
@@ -137,13 +137,25 @@
|
|||||||
<el-input v-model="state.genTxtDialog.txt" type="textarea" rows="20" />
|
<el-input v-model="state.genTxtDialog.txt" type="textarea" rows="20" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<DbTableDataForm
|
||||||
|
v-if="state.tableDataFormDialog.visible"
|
||||||
|
:db-inst="getNowDbInst()"
|
||||||
|
:db-name="db"
|
||||||
|
:columns="columns!"
|
||||||
|
:title="state.tableDataFormDialog.title"
|
||||||
|
:table-name="table"
|
||||||
|
v-model:visible="state.tableDataFormDialog.visible"
|
||||||
|
v-model="state.tableDataFormDialog.data"
|
||||||
|
@submit-success="emits('changeUpdatedField')"
|
||||||
|
/>
|
||||||
|
|
||||||
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
|
<contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onBeforeUnmount, onMounted, reactive, ref, toRefs, watch } from 'vue';
|
import { onBeforeUnmount, onMounted, reactive, ref, toRefs, watch } from 'vue';
|
||||||
import { ElInput } from 'element-plus';
|
import { ElInput, ElMessage } from 'element-plus';
|
||||||
import { copyToClipboard } from '@/common/utils/string';
|
import { copyToClipboard } from '@/common/utils/string';
|
||||||
import { DbInst } from '@/views/ops/db/db';
|
import { DbInst } from '@/views/ops/db/db';
|
||||||
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
|
||||||
@@ -153,6 +165,7 @@ import { dateStrFormat } from '@/common/utils/date';
|
|||||||
import { useIntervalFn, useStorage } from '@vueuse/core';
|
import { useIntervalFn, useStorage } from '@vueuse/core';
|
||||||
import { ColumnTypeSubscript, compatibleMysql, DataType, DbDialect, getDbDialect } from '../../dialect/index';
|
import { ColumnTypeSubscript, compatibleMysql, DataType, DbDialect, getDbDialect } from '../../dialect/index';
|
||||||
import ColumnFormItem from './ColumnFormItem.vue';
|
import ColumnFormItem from './ColumnFormItem.vue';
|
||||||
|
import DbTableDataForm from './DbTableDataForm.vue';
|
||||||
|
|
||||||
const emits = defineEmits(['dataDelete', 'sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
const emits = defineEmits(['dataDelete', 'sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
||||||
|
|
||||||
@@ -246,6 +259,13 @@ const cmDataDel = new ContextmenuItem('deleteData', '删除')
|
|||||||
return state.table == '';
|
return state.table == '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const cmDataEdit = new ContextmenuItem('editData', '编辑行')
|
||||||
|
.withIcon('edit')
|
||||||
|
.withOnClick(() => onEditRowData())
|
||||||
|
.withHideFunc(() => {
|
||||||
|
return state.table == '';
|
||||||
|
});
|
||||||
|
|
||||||
const cmDataGenInsertSql = new ContextmenuItem('genInsertSql', 'Insert SQL')
|
const cmDataGenInsertSql = new ContextmenuItem('genInsertSql', 'Insert SQL')
|
||||||
.withIcon('tickets')
|
.withIcon('tickets')
|
||||||
.withOnClick(() => onGenerateInsertSql())
|
.withOnClick(() => onGenerateInsertSql())
|
||||||
@@ -332,7 +352,11 @@ const state = reactive({
|
|||||||
},
|
},
|
||||||
items: [] as ContextmenuItem[],
|
items: [] as ContextmenuItem[],
|
||||||
},
|
},
|
||||||
|
tableDataFormDialog: {
|
||||||
|
data: {},
|
||||||
|
title: '',
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
genTxtDialog: {
|
genTxtDialog: {
|
||||||
title: 'SQL',
|
title: 'SQL',
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -443,7 +467,7 @@ const formatDataValues = (datas: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setTableData = (datas: any) => {
|
const setTableData = (datas: any) => {
|
||||||
tableRef.value.scrollTo({ scrollLeft: 0, scrollTop: 0 });
|
tableRef.value?.scrollTo({ scrollLeft: 0, scrollTop: 0 });
|
||||||
selectionRowsMap.clear();
|
selectionRowsMap.clear();
|
||||||
cellUpdateMap.clear();
|
cellUpdateMap.clear();
|
||||||
formatDataValues(datas);
|
formatDataValues(datas);
|
||||||
@@ -575,7 +599,7 @@ const dataContextmenuClick = (event: any, rowIndex: number, column: any, data: a
|
|||||||
const { clientX, clientY } = event;
|
const { clientX, clientY } = event;
|
||||||
state.contextmenu.dropdown.x = clientX;
|
state.contextmenu.dropdown.x = clientX;
|
||||||
state.contextmenu.dropdown.y = clientY;
|
state.contextmenu.dropdown.y = clientY;
|
||||||
state.contextmenu.items = [cmDataCopyCell, cmDataDel, cmDataGenInsertSql, cmDataGenJson, cmDataExportCsv, cmDataExportSql];
|
state.contextmenu.items = [cmDataCopyCell, cmDataDel, cmDataEdit, cmDataGenInsertSql, cmDataGenJson, cmDataExportCsv, cmDataExportSql];
|
||||||
contextmenuRef.value.openContextmenu({ column, rowData: data });
|
contextmenuRef.value.openContextmenu({ column, rowData: data });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -600,6 +624,18 @@ const onDeleteData = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onEditRowData = () => {
|
||||||
|
const selectionDatas = Array.from(selectionRowsMap.values());
|
||||||
|
if (selectionDatas.length > 1) {
|
||||||
|
ElMessage.warning('只能编辑一行数据');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const data = selectionDatas[0];
|
||||||
|
state.tableDataFormDialog.data = data;
|
||||||
|
state.tableDataFormDialog.title = `编辑表'${props.table}'数据`;
|
||||||
|
state.tableDataFormDialog.visible = true;
|
||||||
|
};
|
||||||
|
|
||||||
const onGenerateInsertSql = async () => {
|
const onGenerateInsertSql = async () => {
|
||||||
const selectionDatas = Array.from(selectionRowsMap.values());
|
const selectionDatas = Array.from(selectionRowsMap.values());
|
||||||
state.genTxtDialog.txt = await getNowDbInst().genInsertSql(state.db, state.table, selectionDatas);
|
state.genTxtDialog.txt = await getNowDbInst().genInsertSql(state.db, state.table, selectionDatas);
|
||||||
@@ -713,40 +749,21 @@ const submitUpdateFields = async () => {
|
|||||||
|
|
||||||
const db = state.db;
|
const db = state.db;
|
||||||
let res = '';
|
let res = '';
|
||||||
const dbDialect = getDbDialect(dbInst.type);
|
|
||||||
let schema = '';
|
|
||||||
let dbArr = db.split('/');
|
|
||||||
if (dbArr.length == 2) {
|
|
||||||
schema = dbInst.wrapName(dbArr[1]) + '.';
|
|
||||||
}
|
|
||||||
for (let updateRow of cellUpdateMap.values()) {
|
for (let updateRow of cellUpdateMap.values()) {
|
||||||
let sql = `UPDATE ${schema}${dbInst.wrapName(state.table)} SET `;
|
const rowData = { ...updateRow.rowData };
|
||||||
const rowData = updateRow.rowData;
|
let updateColumnValue = {};
|
||||||
// 主键列信息
|
|
||||||
const primaryKey = await dbInst.loadTableColumn(db, state.table);
|
|
||||||
let primaryKeyType = primaryKey.columnType;
|
|
||||||
let primaryKeyName = primaryKey.columnName;
|
|
||||||
let primaryKeyValue = rowData[primaryKeyName];
|
|
||||||
|
|
||||||
for (let k of updateRow.columnsMap.keys()) {
|
for (let k of updateRow.columnsMap.keys()) {
|
||||||
const v = updateRow.columnsMap.get(k);
|
const v = updateRow.columnsMap.get(k);
|
||||||
if (!v) {
|
if (!v) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 更新字段列信息
|
updateColumnValue[k] = rowData[k];
|
||||||
const updateColumn = await dbInst.loadTableColumn(db, state.table, k);
|
// 将更新的字段对应的原始数据还原(主要应对可能更新修改了主键等)
|
||||||
|
rowData[k] = v.oldValue;
|
||||||
sql += ` ${dbInst.wrapName(k)} = ${DbInst.wrapColumnValue(updateColumn.columnType, rowData[k], dbDialect)},`;
|
|
||||||
|
|
||||||
// 如果修改的字段是主键
|
|
||||||
if (k === primaryKeyName) {
|
|
||||||
primaryKeyValue = v.oldValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
res += await dbInst.genUpdateSql(db, state.table, updateColumnValue, rowData);
|
||||||
sql = sql.substring(0, sql.length - 1);
|
|
||||||
sql += ` WHERE ${dbInst.wrapName(primaryKeyName)} = ${DbInst.wrapColumnValue(primaryKeyType, primaryKeyValue)} ;`;
|
|
||||||
res += sql;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dbInst.promptExeSql(
|
dbInst.promptExeSql(
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="visible" :title="title" :destroy-on-close="true" width="600px">
|
||||||
|
<el-form ref="dataForm" :model="modelValue" :show-message="false" label-width="auto" size="small">
|
||||||
|
<el-form-item
|
||||||
|
v-for="column in columns"
|
||||||
|
:key="column.columnName"
|
||||||
|
class="w100 mb5"
|
||||||
|
:prop="column.columnName"
|
||||||
|
:required="column.nullable != 'YES' && !column.isPrimaryKey && !column.isIdentity"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
{{ column.columnName }}
|
||||||
|
<el-tooltip :content="`${column.columnType} | ${column.columnComment}`" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<question-filled />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<ColumnFormItem
|
||||||
|
v-model="modelValue[`${column.columnName}`]"
|
||||||
|
:data-type="dbInst.getDialect().getDataType(column.columnType)"
|
||||||
|
:placeholder="`${column.columnType} ${column.columnComment}`"
|
||||||
|
:column-name="column.columnName"
|
||||||
|
:disabled="column.isIdentity"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="closeDialog">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirm">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import ColumnFormItem from './ColumnFormItem.vue';
|
||||||
|
import { DbInst } from '../../db';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
export interface ColumnFormItemProps {
|
||||||
|
dbInst: DbInst;
|
||||||
|
dbName: string;
|
||||||
|
tableName: string;
|
||||||
|
columns: any[];
|
||||||
|
title?: string; // dialog title
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<ColumnFormItemProps>(), {
|
||||||
|
title: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const modelValue = defineModel<any>('modelValue');
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible', {
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['submitSuccess']);
|
||||||
|
|
||||||
|
const dataForm: any = ref(null);
|
||||||
|
|
||||||
|
let oldValue = null as any;
|
||||||
|
|
||||||
|
watch(visible, (newValue) => {
|
||||||
|
// 空对象则为insert操作,无需记录旧值
|
||||||
|
if (newValue && Object.keys(modelValue.value).length > 0) {
|
||||||
|
oldValue = Object.assign({}, modelValue.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const closeDialog = () => {
|
||||||
|
visible.value = false;
|
||||||
|
modelValue.value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirm = async () => {
|
||||||
|
dataForm.value.validate(async (valid: boolean) => {
|
||||||
|
if (!valid) {
|
||||||
|
ElMessage.error('请正确填写数据信息');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbInst = props.dbInst;
|
||||||
|
const data = modelValue.value;
|
||||||
|
const db = props.dbName;
|
||||||
|
const tableName = props.tableName;
|
||||||
|
|
||||||
|
let sql = '';
|
||||||
|
if (oldValue) {
|
||||||
|
const updateColumnValue = {};
|
||||||
|
Object.keys(oldValue).forEach((key) => {
|
||||||
|
// 如果新旧值不相等,则为需要更新的字段
|
||||||
|
if (oldValue[key] !== modelValue.value[key]) {
|
||||||
|
updateColumnValue[key] = modelValue.value[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sql = await dbInst.genUpdateSql(db, tableName, updateColumnValue, oldValue);
|
||||||
|
} else {
|
||||||
|
sql = await dbInst.genInsertSql(db, tableName, [data], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbInst.promptExeSql(db, sql, null, () => {
|
||||||
|
closeDialog();
|
||||||
|
emit('submitSuccess');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss"></style>
|
||||||
@@ -234,32 +234,16 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog v-model="addDataDialog.visible" :title="addDataDialog.title" :destroy-on-close="true" width="600px">
|
<DbTableDataForm
|
||||||
<el-form ref="dataForm" :model="addDataDialog.data" :show-message="false" label-width="auto" size="small">
|
:db-inst="getNowDbInst()"
|
||||||
<el-form-item
|
:db-name="dbName"
|
||||||
v-for="column in columns"
|
:columns="columns"
|
||||||
:key="column.columnName"
|
:title="addDataDialog.title"
|
||||||
class="w100 mb5"
|
:table-name="tableName"
|
||||||
:prop="column.columnName"
|
v-model:visible="addDataDialog.visible"
|
||||||
:label="column.columnName"
|
v-model="addDataDialog.data"
|
||||||
:required="column.nullable != 'YES' && !column.isPrimaryKey && !column.isIdentity"
|
@submit-success="onRefresh"
|
||||||
>
|
/>
|
||||||
<ColumnFormItem
|
|
||||||
v-model="addDataDialog.data[`${column.columnName}`]"
|
|
||||||
:data-type="dbDialect.getDataType(column.columnType)"
|
|
||||||
:placeholder="`${column.columnType} ${column.columnComment}`"
|
|
||||||
:column-name="column.columnName"
|
|
||||||
:disabled="column.isIdentity"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<span class="dialog-footer">
|
|
||||||
<el-button @click="closeAddDataDialog">取消</el-button>
|
|
||||||
<el-button type="primary" @click="addRow">确定</el-button>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -269,11 +253,11 @@ import { ElMessage } from 'element-plus';
|
|||||||
|
|
||||||
import { DbInst } from '@/views/ops/db/db';
|
import { DbInst } from '@/views/ops/db/db';
|
||||||
import DbTableData from './DbTableData.vue';
|
import DbTableData from './DbTableData.vue';
|
||||||
import { DbDialect, getDbDialect } from '@/views/ops/db/dialect';
|
import { DbDialect } from '@/views/ops/db/dialect';
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
import ColumnFormItem from './ColumnFormItem.vue';
|
|
||||||
import { useEventListener, useStorage } from '@vueuse/core';
|
import { useEventListener, useStorage } from '@vueuse/core';
|
||||||
import { copyToClipboard } from '@/common/utils/string';
|
import { copyToClipboard } from '@/common/utils/string';
|
||||||
|
import DbTableDataForm from './DbTableDataForm.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dbId: {
|
dbId: {
|
||||||
@@ -294,7 +278,6 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataForm: any = ref(null);
|
|
||||||
const dbTableRef: Ref = ref(null);
|
const dbTableRef: Ref = ref(null);
|
||||||
const condInputRef: Ref = ref(null);
|
const condInputRef: Ref = ref(null);
|
||||||
const columnNameSearchInputRef: Ref = ref(null);
|
const columnNameSearchInputRef: Ref = ref(null);
|
||||||
@@ -341,7 +324,6 @@ const state = reactive({
|
|||||||
addDataDialog: {
|
addDataDialog: {
|
||||||
data: {},
|
data: {},
|
||||||
title: '',
|
title: '',
|
||||||
placeholder: '',
|
|
||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
tableHeight: '600px',
|
tableHeight: '600px',
|
||||||
@@ -349,7 +331,7 @@ const state = reactive({
|
|||||||
dbDialect: {} as DbDialect,
|
dbDialect: {} as DbDialect,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { datas, condition, loading, columns, pageNum, pageSize, pageSizes, sql, hasUpdatedFileds, conditionDialog, addDataDialog, dbDialect } = toRefs(state);
|
const { datas, condition, loading, columns, pageNum, pageSize, pageSizes, sql, hasUpdatedFileds, conditionDialog, addDataDialog } = toRefs(state);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.tableHeight,
|
() => props.tableHeight,
|
||||||
@@ -367,7 +349,7 @@ onMounted(async () => {
|
|||||||
state.tableHeight = props.tableHeight;
|
state.tableHeight = props.tableHeight;
|
||||||
await onRefresh();
|
await onRefresh();
|
||||||
|
|
||||||
state.dbDialect = getDbDialect(getNowDbInst().type);
|
state.dbDialect = getNowDbInst().getDialect();
|
||||||
useEventListener('click', handlerWindowClick);
|
useEventListener('click', handlerWindowClick);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -601,46 +583,6 @@ const onShowAddDataDialog = async () => {
|
|||||||
state.addDataDialog.title = `添加'${props.tableName}'表数据`;
|
state.addDataDialog.title = `添加'${props.tableName}'表数据`;
|
||||||
state.addDataDialog.visible = true;
|
state.addDataDialog.visible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeAddDataDialog = () => {
|
|
||||||
state.addDataDialog.visible = false;
|
|
||||||
state.addDataDialog.data = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 添加新数据行
|
|
||||||
const addRow = async () => {
|
|
||||||
dataForm.value.validate(async (valid: boolean) => {
|
|
||||||
if (valid) {
|
|
||||||
const dbInst = getNowDbInst();
|
|
||||||
const data = state.addDataDialog.data;
|
|
||||||
// key: 字段名,value: 字段名提示
|
|
||||||
let obj: any = {};
|
|
||||||
for (let item of state.columns) {
|
|
||||||
const value = data[item.columnName];
|
|
||||||
if (!value) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
obj[`${dbInst.wrapName(item.columnName)}`] = DbInst.wrapValueByType(value);
|
|
||||||
}
|
|
||||||
let columnNames = Object.keys(obj).join(',');
|
|
||||||
let values = Object.values(obj).join(',');
|
|
||||||
// 获取schema
|
|
||||||
let schema = '';
|
|
||||||
let arr = props.dbName?.split('/');
|
|
||||||
if (arr && arr.length > 1) {
|
|
||||||
schema = dbInst.wrapName(arr[1]) + '.';
|
|
||||||
}
|
|
||||||
let sql = `INSERT INTO ${schema}${dbInst.wrapName(props.tableName)} (${columnNames}) VALUES (${values});`;
|
|
||||||
dbInst.promptExeSql(props.dbName, sql, null, () => {
|
|
||||||
closeAddDataDialog();
|
|
||||||
onRefresh();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
ElMessage.error('请正确填写数据信息');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ export class DbInst {
|
|||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取数据库实例方言
|
||||||
|
getDialect(): DbDialect {
|
||||||
|
return getDbDialect(this.type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载数据库表信息
|
* 加载数据库表信息
|
||||||
* @param dbName 数据库名
|
* @param dbName 数据库名
|
||||||
@@ -257,7 +262,7 @@ export class DbInst {
|
|||||||
* @param table 表名
|
* @param table 表名
|
||||||
* @param datas 要生成的数据
|
* @param datas 要生成的数据
|
||||||
*/
|
*/
|
||||||
async genInsertSql(dbName: string, table: string, datas: any[]) {
|
async genInsertSql(dbName: string, table: string, datas: any[], skipNull = false) {
|
||||||
if (!datas) {
|
if (!datas) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -269,6 +274,9 @@ export class DbInst {
|
|||||||
let values = [];
|
let values = [];
|
||||||
for (let column of columns) {
|
for (let column of columns) {
|
||||||
const colName = column.columnName;
|
const colName = column.columnName;
|
||||||
|
if (skipNull && data[colName] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
colNames.push(this.wrapName(colName));
|
colNames.push(this.wrapName(colName));
|
||||||
values.push(DbInst.wrapValueByType(data[colName]));
|
values.push(DbInst.wrapValueByType(data[colName]));
|
||||||
}
|
}
|
||||||
@@ -277,6 +285,38 @@ export class DbInst {
|
|||||||
return sqls.join(';\n') + ';';
|
return sqls.join(';\n') + ';';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成根据主键更新语句
|
||||||
|
* @param dbName 数据库名
|
||||||
|
* @param table 表名
|
||||||
|
* @param columnValue 要更新的列以及对应的值 field->columnName; value->columnValue
|
||||||
|
* @param rowData 表的一行完整数据(需要获取主键信息)
|
||||||
|
*/
|
||||||
|
async genUpdateSql(dbName: string, table: string, columnValue: {}, rowData: {}) {
|
||||||
|
let schema = '';
|
||||||
|
let dbArr = dbName.split('/');
|
||||||
|
if (dbArr.length == 2) {
|
||||||
|
schema = this.wrapName(dbArr[1]) + '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
let sql = `UPDATE ${schema}${this.wrapName(table)} SET `;
|
||||||
|
// 主键列信息
|
||||||
|
const primaryKey = await this.loadTableColumn(dbName, table);
|
||||||
|
let primaryKeyType = primaryKey.columnType;
|
||||||
|
let primaryKeyName = primaryKey.columnName;
|
||||||
|
let primaryKeyValue = rowData[primaryKeyName];
|
||||||
|
const dialect = this.getDialect();
|
||||||
|
for (let k of Object.keys(columnValue)) {
|
||||||
|
const v = columnValue[k];
|
||||||
|
// 更新字段列信息
|
||||||
|
const updateColumn = await this.loadTableColumn(dbName, table, k);
|
||||||
|
sql += ` ${this.wrapName(k)} = ${DbInst.wrapColumnValue(updateColumn.columnType, v, dialect)},`;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = sql.substring(0, sql.length - 1);
|
||||||
|
return (sql += ` WHERE ${this.wrapName(primaryKeyName)} = ${DbInst.wrapColumnValue(primaryKeyType, primaryKeyValue)} ;`);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成根据主键删除的sql语句
|
* 生成根据主键删除的sql语句
|
||||||
* @param table 表名
|
* @param table 表名
|
||||||
@@ -297,7 +337,7 @@ export class DbInst {
|
|||||||
sql,
|
sql,
|
||||||
dbId: this.id,
|
dbId: this.id,
|
||||||
db,
|
db,
|
||||||
dbType: getDbDialect(this.type).getInfo().formatSqlDialect,
|
dbType: this.getDialect().getInfo().formatSqlDialect,
|
||||||
runSuccessCallback: successFunc,
|
runSuccessCallback: successFunc,
|
||||||
cancelCallback: cancelFunc,
|
cancelCallback: cancelFunc,
|
||||||
});
|
});
|
||||||
@@ -310,7 +350,7 @@ export class DbInst {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
wrapName = (name: string) => {
|
wrapName = (name: string) => {
|
||||||
return getDbDialect(this.type).quoteIdentifier(name);
|
return this.getDialect().quoteIdentifier(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ class PostgresqlDialect implements DbDialect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars,no-unused-vars
|
||||||
wrapStrValue(value: string, type: string): string {
|
wrapStrValue(columnType: string, value: string): string {
|
||||||
return `'${value}'`;
|
return `'${value}'`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user