更新vxetable框架并升级前端组件框架

This commit is contained in:
2026-06-03 11:19:52 +08:00
parent 5b6b23331d
commit 5a2050a736
385 changed files with 19691 additions and 21188 deletions

View File

@@ -1,4 +1,4 @@
<template>
<template>
<el-form ref="formRef" :model="{ tableData }" :rules="rules" class="editable-table-form">
<div
v-if="showAddButton || showDeleteButton || searchFields.length > 0"
@@ -33,22 +33,25 @@
</el-input>
</div>
</div>
<el-table
<vxe-table
ref="tableRef"
:data="filteredTableData"
:border="border"
:border="border ? 'full' : false"
:stripe="stripe"
:max-height="maxHeight || undefined"
:min-height="minHeight || undefined"
:height="!maxHeight && !minHeight ? '100%' : undefined"
:row-key="getRowKey"
:virtualized="useVirtualized"
:row-config="{ keyField: '_etKey' }"
:scroll-x="{ enabled: true }"
:scroll-y="{ enabled: true }"
:show-overflow="true"
v-bind="$attrs"
@selection-change="handleSelectionChange"
@checkbox-change="handleSelectionChange"
@checkbox-all="handleSelectionChange"
class="editable-table-inner"
>
<el-table-column v-if="showSelection" type="selection" width="55" align="center" />
<el-table-column
<vxe-column v-if="showSelection" type="checkbox" width="55" align="center" />
<vxe-column
v-if="showRowActions"
:width="rowActionsColumnWidth"
align="center"
@@ -65,14 +68,14 @@
</div>
<span v-else></span>
</template>
<template #default="scope">
<template #default="{ row, rowIndex }">
<el-button
v-if="showRowAddButton"
type="primary"
link
icon="CirclePlus"
class="action-btn"
@click="handleAdd(scope.$index)"
@click="handleAdd(rowIndex)"
title="增加"
/>
<el-button
@@ -81,38 +84,37 @@
link
icon="Delete"
class="action-btn"
@click="handleDelete(scope.$index)"
@click="handleDelete(rowIndex)"
title="删除"
/>
</template>
</el-table-column>
</vxe-column>
<el-table-column
<vxe-column
v-for="col in filteredColumns"
:key="col.prop"
:prop="col.prop"
:label="col.label"
:field="col.prop"
:title="col.label"
:width="col.width"
:min-width="col.minWidth"
:fixed="col.fixed"
:align="col.align || 'center'"
:formatter="col.formatter"
>
<template #default="scope">
<template #default="{ row, rowIndex }">
<template v-if="col.type === 'input'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:prop="`tableData.${rowIndex}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-input
v-model="scope.row[col.prop]"
v-model="row[col.prop]"
:placeholder="col.placeholder || `请输入${col.label}`"
:disabled="col.disabled"
:clearable="col.clearable !== false"
@blur="col.onBlur && col.onBlur(scope.row, scope.$index)"
@input="col.onInput && col.onInput(scope.row, scope.$index)"
@change="col.onChange && col.onChange(scope.row, scope.$index)"
@blur="col.onBlur && col.onBlur(row, rowIndex)"
@input="col.onInput && col.onInput(row, rowIndex)"
@change="col.onChange && col.onChange(row, rowIndex)"
>
<template v-if="col.suffix" #suffix>{{ col.suffix }}</template>
</el-input>
@@ -121,12 +123,12 @@
<template v-else-if="col.type === 'number'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:prop="`tableData.${rowIndex}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-input-number
v-model="scope.row[col.prop]"
v-model="row[col.prop]"
:placeholder="col.placeholder || `请输入${col.label}`"
:disabled="col.disabled"
:min="col.min"
@@ -134,49 +136,49 @@
:precision="col.precision"
:controls="false"
style="width: 100%"
@change="col.onChange && col.onChange(scope.row, scope.$index)"
@change="col.onChange && col.onChange(row, rowIndex)"
/>
</el-form-item>
</template>
<template v-else-if="col.type === 'select'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:prop="`tableData.${rowIndex}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-select
v-model="scope.row[col.prop]"
v-model="row[col.prop]"
:placeholder="col.placeholder || `请选择${col.label}`"
:disabled="col.disabled"
:clearable="col.clearable !== false"
:filterable="col.filterable"
:multiple="col.multiple"
style="width: 100%"
:class="scope.row.error ? 'error-border' : ''"
:class="row.error ? 'error-border' : ''"
@change="
async (value) => {
const checkBeforeChange = col.extraprops?.checkBeforeChange;
if (checkBeforeChange && typeof checkBeforeChange === 'function') {
const result = await checkBeforeChange(scope.row, scope.$index, value);
const result = await checkBeforeChange(row, rowIndex, value);
if (result === false) {
return;
}
}
if (col.onChange) {
col.onChange(scope.row, scope.$index, value);
col.onChange(row, rowIndex, value);
}
}
"
>
<el-option
v-for="option in typeof col.options === 'function'
? col.options(scope.row, scope.$index)
? col.options(row, rowIndex)
: col.options || []"
:key="option.value"
:label="option.label"
:value="option.value"
@click="option.onClick && option.onClick(scope.row, option)"
@click="option.onClick && option.onClick(row, option)"
/>
</el-select>
</el-form-item>
@@ -184,43 +186,43 @@
<template v-else-if="col.type === 'date'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:prop="`tableData.${rowIndex}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<el-date-picker
v-model="scope.row[col.prop]"
v-model="row[col.prop]"
:type="col.dateType || 'date'"
:placeholder="col.placeholder || `请选择${col.label}`"
:disabled="col.disabled"
:clearable="col.clearable !== false"
:value-format="col.valueFormat || 'YYYY-MM-DD'"
style="width: 100%"
@change="col.onChange && col.onChange(scope.row, scope.$index)"
@change="col.onChange && col.onChange(row, rowIndex)"
/>
</el-form-item>
</template>
<template v-else-if="col.type === 'slot'">
<el-form-item
:prop="`tableData.${scope.$index}.${col.prop}`"
:prop="`tableData.${rowIndex}.${col.prop}`"
:rules="col.rules"
style="margin-bottom: 0"
>
<slot :name="col.slot || col.prop" :row="scope.row" :index="scope.$index" />
<slot :name="col.slot || col.prop" :row="row" :index="rowIndex" />
</el-form-item>
</template>
<template v-else>
<span>{{
col.formatter
? col.formatter(scope.row, scope.column, scope.row[col.prop])
: scope.row[col.prop]
? col.formatter(row, { property: col.prop }, row[col.prop])
: row[col.prop]
}}</span>
</template>
</template>
</el-table-column>
</el-table>
</vxe-column>
</vxe-table>
<div v-if="$slots.footer" class="editable-table-footer">
<slot name="footer" :tableData="tableData" />
</div>
@@ -261,8 +263,8 @@ const emit = defineEmits<{
'toolbar-delete': [rows: Record<string, any>[]];
}>();
const formRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
const tableRef = ref<InstanceType<typeof import('element-plus').ElTable> | null>(null);
const formRef = ref<any>(null);
const tableRef = ref<any>(null);
const selectedRows = ref<Record<string, any>[]>([]);
const searchKeyword = ref('');
@@ -293,13 +295,12 @@ const filteredColumns = computed(() => {
return props.columns.filter((col) => !col.vIf || col.vIf());
});
// 行操作列宽度:同时显示增加+删除则宽一点;只显示一个则缩窄
// 行操作列宽度:同时显示"增加+删除"则宽一点;只显示一个则缩窄
const rowActionsColumnWidth = computed(() => {
const showAdd = !!props.showRowAddButton;
const showDel = !!props.showRowDeleteButton;
if (showAdd && showDel) return 100;
if (showAdd || showDel) return 60;
// 如果两者都不显示,列也不会渲染;这里给个兜底
return 0;
});
@@ -323,7 +324,7 @@ const searchPlaceholder = computed(() => {
return `请输入${fieldLabels[0]}`;
}
return `请输入${fieldLabels.join('')}`;
return `请输入${fieldLabels.join('|')}`;
});
// 根据搜索关键词过滤表格数据
@@ -383,9 +384,9 @@ const handleDelete = (index) => {
}
};
const handleSelectionChange = (selection) => {
selectedRows.value = selection;
emit('selection-change', selection);
const handleSelectionChange = ({ records }: { records: Record<string, any>[] }) => {
selectedRows.value = records;
emit('selection-change', records);
};
// 删除所有选中的行
@@ -418,7 +419,7 @@ const handleDeleteSelected = () => {
// 清空选中状态
if (tableRef.value) {
tableRef.value.clearSelection();
tableRef.value.clearCheckboxRow();
}
selectedRows.value = [];
};
@@ -499,69 +500,20 @@ defineExpose({
display: flex;
gap: 8px;
}
.toolbar-right {
display: flex;
align-items: center;
}
}
:deep(.el-table.editable-table-inner) {
.editable-table-inner {
flex: 1;
display: flex;
flex-direction: column;
.el-table__body-wrapper {
flex: 1;
overflow: auto;
}
.el-table__cell {
position: relative;
overflow: visible;
vertical-align: top;
.cell {
position: relative;
overflow: visible;
}
}
min-height: 0;
}
:deep(.el-table__cell) {
overflow: visible;
vertical-align: top;
.cell {
overflow: visible;
}
}
// 错误信息往下撑开行高不影响上面布局
:deep(.el-form-item) {
margin-bottom: 0;
.el-form-item__error {
position: static;
line-height: 1.5;
padding-top: 4px;
font-size: 12px;
color: var(--el-color-danger);
display: block;
white-space: nowrap;
}
.editable-table-footer {
margin-top: 16px;
padding: 0 4px;
}
.action-btn {
margin: 4px;
:deep(.el-icon) {
font-size: 18px;
}
padding: 2px 4px;
}
}
.editable-table-footer {
flex-shrink: 0;
margin-top: 16px;
}
</style>
</style>