修复编辑、删除无法操作的问题
This commit is contained in:
@@ -7,26 +7,59 @@
|
|||||||
:confirm-loading="loading"
|
:confirm-loading="loading"
|
||||||
width="600px"
|
width="600px"
|
||||||
>
|
>
|
||||||
|
<template #title>
|
||||||
|
<div class="modal-title">
|
||||||
|
<span>编辑行数据</span>
|
||||||
|
<a-tag v-if="displayRecords.length > 1" color="blue" class="ml-2">
|
||||||
|
同步编辑 {{ displayRecords.length }} 条
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<a-alert
|
||||||
|
v-if="displayRecords.length > 1"
|
||||||
|
type="info"
|
||||||
|
show-icon
|
||||||
|
style="margin-bottom: 12px"
|
||||||
|
:message="`已选择 ${displayRecords.length} 条记录,将把当前修改同步到这些记录`"
|
||||||
|
/>
|
||||||
|
<a-list
|
||||||
|
v-if="displayRecords.length > 1"
|
||||||
|
size="small"
|
||||||
|
bordered
|
||||||
|
:data-source="displayRecords"
|
||||||
|
style="margin-bottom: 12px; max-height: 160px; overflow-y: auto"
|
||||||
|
>
|
||||||
|
<template #renderItem="{ item, index }">
|
||||||
|
<a-list-item
|
||||||
|
:class="['record-item', { active: index === selectedRecordIndex }]"
|
||||||
|
@click="selectRecord(index)"
|
||||||
|
>
|
||||||
|
<span class="record-label">#{{ index + 1 }}</span>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
|
||||||
<a-form layout="vertical">
|
<a-form layout="vertical">
|
||||||
<template v-for="field in processedFields" :key="field.key">
|
<template v-for="field in processedFields" :key="field.key">
|
||||||
<a-form-item :label="field.title" v-if="!field.children">
|
<a-form-item :label="field.title" v-if="!field.children">
|
||||||
<template v-if="field.type === 'textarea'">
|
<template v-if="field.type === 'textarea'">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="formData[field.dataIndex]"
|
v-model:value="activeFormData[field.dataIndex]"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
:placeholder="`请输入${field.title}`"
|
:placeholder="`请输入${field.title}`"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="field.dataIndex === 'workPaperIndex'">
|
<template v-else-if="field.dataIndex === 'workPaperIndex'">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="formData[field.dataIndex]"
|
v-model:value="activeFormData[field.dataIndex]"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
:placeholder="'每行一个文件,格式为:file_id||文件名||url'"
|
:placeholder="'每行一个文件,格式为:file_id||文件名||url'"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData[field.dataIndex]"
|
v-model:value="activeFormData[field.dataIndex]"
|
||||||
:placeholder="`请输入${field.title}`"
|
:placeholder="`请输入${field.title}`"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -44,7 +77,7 @@
|
|||||||
class="nested-field-item"
|
class="nested-field-item"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData[childField.dataIndex]"
|
v-model:value="activeFormData[childField.dataIndex]"
|
||||||
:placeholder="`请输入${childField.title}`"
|
:placeholder="`请输入${childField.title}`"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -64,12 +97,44 @@ const props = defineProps<{
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
record: any;
|
record: any;
|
||||||
fields: any[];
|
fields: any[];
|
||||||
|
records?: any[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'save']);
|
const emit = defineEmits(['update:visible', 'save']);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const formData = ref({});
|
const formDataList = ref<any[]>([]);
|
||||||
|
const selectedRecordIndex = ref(0);
|
||||||
|
|
||||||
|
const displayRecords = computed(() => {
|
||||||
|
if (props.records && Array.isArray(props.records) && props.records.length) {
|
||||||
|
return props.records;
|
||||||
|
}
|
||||||
|
if (props.record) return [props.record];
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
const transformRecordToFormData = (record: any) => {
|
||||||
|
if (!record) return {};
|
||||||
|
const recordCopy = JSON.parse(JSON.stringify(record));
|
||||||
|
|
||||||
|
if (
|
||||||
|
hasWorkPaperIndexField.value &&
|
||||||
|
recordCopy.workPaperIndex &&
|
||||||
|
Array.isArray(recordCopy.workPaperIndex)
|
||||||
|
) {
|
||||||
|
recordCopy.workPaperIndex = recordCopy.workPaperIndex
|
||||||
|
.map((item: any) => {
|
||||||
|
if (typeof item === 'object') {
|
||||||
|
return `${item.fileId || ''}||${item.fileName || ''}||${item.fileUrl || ''}`;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordCopy;
|
||||||
|
};
|
||||||
|
|
||||||
const hasWorkPaperIndexField = computed(() => {
|
const hasWorkPaperIndexField = computed(() => {
|
||||||
return (props.fields || []).some((field) => {
|
return (props.fields || []).some((field) => {
|
||||||
@@ -81,7 +146,7 @@ const hasWorkPaperIndexField = computed(() => {
|
|||||||
const processedFields = computed(() => {
|
const processedFields = computed(() => {
|
||||||
const processed: any[] = [];
|
const processed: any[] = [];
|
||||||
|
|
||||||
props.fields.forEach(field => {
|
(props.fields || []).forEach(field => {
|
||||||
if (field.children && Array.isArray(field.children)) {
|
if (field.children && Array.isArray(field.children)) {
|
||||||
// 处理有子字段的情况(如职务)
|
// 处理有子字段的情况(如职务)
|
||||||
processed.push({
|
processed.push({
|
||||||
@@ -100,49 +165,44 @@ const processedFields = computed(() => {
|
|||||||
return processed;
|
return processed;
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.visible, (visible) => {
|
watch(
|
||||||
if (visible && props.record) {
|
() => props.visible,
|
||||||
// 深拷贝记录数据
|
(visible) => {
|
||||||
const recordCopy = JSON.parse(JSON.stringify(props.record));
|
if (visible) {
|
||||||
|
selectedRecordIndex.value = 0;
|
||||||
// 特殊处理workPaperIndex:如果是对象数组,转换为字符串数组
|
formDataList.value = displayRecords.value.map((rec) =>
|
||||||
if (hasWorkPaperIndexField.value && recordCopy.workPaperIndex && Array.isArray(recordCopy.workPaperIndex)) {
|
transformRecordToFormData(rec)
|
||||||
recordCopy.workPaperIndex = recordCopy.workPaperIndex.map(item => {
|
);
|
||||||
if (typeof item === 'object') {
|
|
||||||
// 如果是对象,转换为字符串格式:file_id||文件名||url
|
|
||||||
return `${item.fileId || ''}||${item.fileName || ''}||${item.fileUrl || ''}`;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}).join('\n');
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
formData.value = recordCopy;
|
{ immediate: true }
|
||||||
}
|
);
|
||||||
}, { immediate: true });
|
|
||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
if (!formData.value) {
|
if (!formDataList.value || formDataList.value.length === 0) {
|
||||||
message.warning('没有数据可保存');
|
message.warning('没有数据可保存');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理workPaperIndex:将字符串转换回对象数组
|
// 处理workPaperIndex:将字符串转换回对象数组
|
||||||
const dataToSave = JSON.parse(JSON.stringify(formData.value));
|
const dataToSave = formDataList.value.map((item) => {
|
||||||
|
const cloned = JSON.parse(JSON.stringify(item || {}));
|
||||||
if (hasWorkPaperIndexField.value && dataToSave.workPaperIndex && typeof dataToSave.workPaperIndex === 'string') {
|
if (hasWorkPaperIndexField.value && cloned.workPaperIndex && typeof cloned.workPaperIndex === 'string') {
|
||||||
const lines = dataToSave.workPaperIndex.split('\n').filter(line => line.trim() !== '');
|
const lines = cloned.workPaperIndex.split('\n').filter((line: string) => line.trim() !== '');
|
||||||
dataToSave.workPaperIndex = lines.map(line => {
|
cloned.workPaperIndex = lines.map((line: string) => {
|
||||||
const parts = line.split('||');
|
const parts = line.split('||');
|
||||||
if (parts.length >= 3) {
|
if (parts.length >= 3) {
|
||||||
return {
|
return {
|
||||||
fileId: parts[0] || '',
|
fileId: parts[0] || '',
|
||||||
fileName: parts[1] || '',
|
fileName: parts[1] || '',
|
||||||
fileUrl: parts[2] || ''
|
fileUrl: parts[2] || ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return cloned;
|
||||||
|
});
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
emit('save', dataToSave);
|
emit('save', dataToSave);
|
||||||
@@ -153,6 +213,32 @@ const handleOk = () => {
|
|||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
emit('update:visible', false);
|
emit('update:visible', false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectRecord = (index: number) => {
|
||||||
|
if (index < 0 || index >= displayRecords.value.length) return;
|
||||||
|
selectedRecordIndex.value = index;
|
||||||
|
if (!formDataList.value[index]) {
|
||||||
|
formDataList.value[index] = transformRecordToFormData(
|
||||||
|
displayRecords.value[index]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeFormData = computed({
|
||||||
|
get() {
|
||||||
|
if (!displayRecords.value.length) return {};
|
||||||
|
if (!formDataList.value[selectedRecordIndex.value]) {
|
||||||
|
formDataList.value[selectedRecordIndex.value] = transformRecordToFormData(
|
||||||
|
displayRecords.value[selectedRecordIndex.value]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return formDataList.value[selectedRecordIndex.value] || {};
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
if (!displayRecords.value.length) return;
|
||||||
|
formDataList.value[selectedRecordIndex.value] = val || {};
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -179,4 +265,32 @@ const handleCancel = () => {
|
|||||||
.nested-field-item {
|
.nested-field-item {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
.modal-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 36px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-text {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-item {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-item:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-item.active {
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -212,15 +212,8 @@
|
|||||||
>
|
>
|
||||||
<div class="flex justify-start items-center">
|
<div class="flex justify-start items-center">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" @click.native="editRow(record, index)"
|
<a-button type="primary" @click.native="editRow(index)">编辑</a-button>
|
||||||
>编辑</a-button
|
<a-button type="primary" danger @click.native="deleteRow(index)">删除</a-button>
|
||||||
>
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
danger
|
|
||||||
@click.native="deleteRow(record, index)"
|
|
||||||
>删除</a-button
|
|
||||||
>
|
|
||||||
<a-button>导出</a-button>
|
<a-button>导出</a-button>
|
||||||
<a-button @click="openEvidenceModal(index)"
|
<a-button @click="openEvidenceModal(index)"
|
||||||
>导出取证单</a-button
|
>导出取证单</a-button
|
||||||
@@ -264,6 +257,7 @@
|
|||||||
:scroll="{ y: 500, x: 1000 }"
|
:scroll="{ y: 500, x: 1000 }"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
bordered
|
bordered
|
||||||
|
:row-key="(row) => row?.key ?? row?.id ?? row?.index"
|
||||||
:data-source="item.data"
|
:data-source="item.data"
|
||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
@@ -497,6 +491,7 @@
|
|||||||
<EditModal
|
<EditModal
|
||||||
v-model:visible="editModalVisible"
|
v-model:visible="editModalVisible"
|
||||||
:record="editingRecord"
|
:record="editingRecord"
|
||||||
|
:records="editingTargetRows"
|
||||||
:fields="editingFields"
|
:fields="editingFields"
|
||||||
@save="saveEdit"
|
@save="saveEdit"
|
||||||
/>
|
/>
|
||||||
@@ -581,6 +576,7 @@
|
|||||||
const editingSectionIndex = ref(0);
|
const editingSectionIndex = ref(0);
|
||||||
const editingTableKey = ref('');
|
const editingTableKey = ref('');
|
||||||
const editingFields = ref<any[]>([]);
|
const editingFields = ref<any[]>([]);
|
||||||
|
const editingTargetRows = ref<any[]>([]);
|
||||||
|
|
||||||
// ========== 文档选择相关 ==========
|
// ========== 文档选择相关 ==========
|
||||||
const fileModal = ref();
|
const fileModal = ref();
|
||||||
@@ -605,21 +601,21 @@
|
|||||||
|
|
||||||
// ========== 表格选择 ==========
|
// ========== 表格选择 ==========
|
||||||
const selectedRowsMap = reactive<Record<number, any[]>>({});
|
const selectedRowsMap = reactive<Record<number, any[]>>({});
|
||||||
const rowSelections = reactive<Record<number, TableProps['rowSelection']>>(
|
const selectedRowKeysMap = reactive<Record<number, (string | number)[]>>({});
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
const getRowSelection = (
|
const getRowSelection = (
|
||||||
sectionIndex: number
|
sectionIndex: number
|
||||||
): TableProps['rowSelection'] => {
|
): TableProps['rowSelection'] => {
|
||||||
if (!rowSelections[sectionIndex]) {
|
return {
|
||||||
rowSelections[sectionIndex] = {
|
selectedRowKeys: selectedRowKeysMap[sectionIndex] || [],
|
||||||
onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
|
onChange: (
|
||||||
selectedRowsMap[sectionIndex] = selectedRows;
|
selectedRowKeys: (string | number)[],
|
||||||
}
|
selectedRows: any[]
|
||||||
};
|
) => {
|
||||||
}
|
selectedRowsMap[sectionIndex] = selectedRows;
|
||||||
return rowSelections[sectionIndex];
|
selectedRowKeysMap[sectionIndex] = selectedRowKeys;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
// ========== 历史记录相关 ==========
|
// ========== 历史记录相关 ==========
|
||||||
const showHistory = ref(false);
|
const showHistory = ref(false);
|
||||||
@@ -718,6 +714,9 @@
|
|||||||
section.data = [];
|
section.data = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedRowsMap[sectionIndex] = [];
|
||||||
|
selectedRowKeysMap[sectionIndex] = [];
|
||||||
|
|
||||||
message.success(`已切换到:${tableOption.title}`);
|
message.success(`已切换到:${tableOption.title}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1134,10 +1133,16 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 编辑行 */
|
/* 编辑行 */
|
||||||
const editRow = (record: any, sectionIndex: number) => {
|
const editRow = (sectionIndex: number) => {
|
||||||
const section: any = navigationItems.value[sectionIndex];
|
const section: any = navigationItems.value[sectionIndex];
|
||||||
if (!section || !section.columns) return;
|
if (!section || !section.columns) return;
|
||||||
|
|
||||||
|
const selectedRows = selectedRowsMap[sectionIndex] || [];
|
||||||
|
if (!selectedRows.length) {
|
||||||
|
message.warning('请先选择要编辑的行');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取可编辑的字段(排除操作列)
|
// 获取可编辑的字段(排除操作列)
|
||||||
editingFields.value = section.columns.filter(
|
editingFields.value = section.columns.filter(
|
||||||
(col) =>
|
(col) =>
|
||||||
@@ -1148,183 +1153,272 @@
|
|||||||
col.key !== 'workPaperIndex'
|
col.key !== 'workPaperIndex'
|
||||||
);
|
);
|
||||||
|
|
||||||
editingRecord.value = { ...record };
|
// 将所有选中的行传递给编辑弹窗
|
||||||
|
editingRecord.value = { ...selectedRows[0] };
|
||||||
|
editingTargetRows.value = selectedRows.map((row: any) => ({ ...row }));
|
||||||
editingSectionIndex.value = sectionIndex;
|
editingSectionIndex.value = sectionIndex;
|
||||||
|
|
||||||
// 记录当前编辑的表格key
|
// 记录当前编辑的表格key
|
||||||
const tableInfo = getTableInfo(sectionIndex);
|
const tableInfo = getTableInfo(sectionIndex);
|
||||||
if (tableInfo) {
|
if (tableInfo) {
|
||||||
editingTableKey.value = tableInfo.tableKey;
|
editingTableKey.value = tableInfo.tableKey;
|
||||||
|
} else {
|
||||||
|
editingTableKey.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
editModalVisible.value = true;
|
editModalVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 保存编辑 */
|
/* 保存编辑 */
|
||||||
const saveEdit = (updatedRecord: any) => {
|
const saveEdit = (updatedRecords: any | any[]) => {
|
||||||
const section: any = navigationItems.value[editingSectionIndex.value];
|
const section: any = navigationItems.value[editingSectionIndex.value];
|
||||||
if (!section || !section.data) return;
|
if (!section || !section.data) return;
|
||||||
|
|
||||||
const index = section.data.findIndex(
|
const targets =
|
||||||
(item: any) => item.key === updatedRecord.key
|
editingTargetRows.value && editingTargetRows.value.length
|
||||||
);
|
? editingTargetRows.value
|
||||||
if (index !== -1) {
|
: editingRecord.value
|
||||||
// 保留原有数据的其他字段
|
? [editingRecord.value]
|
||||||
const originalRecord = section.data[index];
|
: [];
|
||||||
section.data[index] = { ...originalRecord, ...updatedRecord };
|
|
||||||
|
|
||||||
// 更新对应的响应数据
|
if (!targets.length) {
|
||||||
if (editingTableKey.value && tableGenerationData[editingTableKey.value]) {
|
message.warning('未找到需要编辑的行');
|
||||||
// 获取当前的响应数据
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatesArray = Array.isArray(updatedRecords)
|
||||||
|
? updatedRecords
|
||||||
|
: [updatedRecords];
|
||||||
|
|
||||||
|
// 只提取允许编辑的字段,避免把首行的其他值覆盖到所有行
|
||||||
|
const allowedKeys = new Set<string>();
|
||||||
|
const collectKeys = (field: any) => {
|
||||||
|
if (field?.dataIndex) allowedKeys.add(field.dataIndex);
|
||||||
|
if (field?.children && Array.isArray(field.children)) {
|
||||||
|
field.children.forEach((child: any) => collectKeys(child));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
editingFields.value.forEach((field: any) => collectKeys(field));
|
||||||
|
|
||||||
|
const buildApplyFields = (source: any) => {
|
||||||
|
const applied: Record<string, any> = {};
|
||||||
|
allowedKeys.forEach((key) => {
|
||||||
|
if (key === 'key' || key === 'index') return;
|
||||||
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||||||
|
applied[key] = source[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return applied;
|
||||||
|
};
|
||||||
|
|
||||||
|
const stripResponseFields = (data: any) => {
|
||||||
|
const { workPaperIndex, key, index, ...rest } = data;
|
||||||
|
return rest;
|
||||||
|
};
|
||||||
|
|
||||||
|
const findRawIndex = (
|
||||||
|
responseList: any[],
|
||||||
|
targetRow: any,
|
||||||
|
fallbackUiIndex: number
|
||||||
|
) => {
|
||||||
|
const hasValidId =
|
||||||
|
targetRow?.id !== undefined &&
|
||||||
|
targetRow?.id !== null &&
|
||||||
|
targetRow?.id !== '';
|
||||||
|
|
||||||
|
if (hasValidId) {
|
||||||
|
const byId = responseList.findIndex(
|
||||||
|
(item: any) => item.id === targetRow.id
|
||||||
|
);
|
||||||
|
if (byId !== -1) return byId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof targetRow?.key === 'number' &&
|
||||||
|
targetRow.key >= 0 &&
|
||||||
|
targetRow.key < responseList.length
|
||||||
|
) {
|
||||||
|
return targetRow.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetRow?.key !== undefined && targetRow?.key !== null) {
|
||||||
|
const byKey = responseList.findIndex(
|
||||||
|
(item: any) => item.key !== undefined && item.key === targetRow.key
|
||||||
|
);
|
||||||
|
if (byKey !== -1) return byKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
fallbackUiIndex !== -1 &&
|
||||||
|
fallbackUiIndex >= 0 &&
|
||||||
|
fallbackUiIndex < responseList.length
|
||||||
|
) {
|
||||||
|
return fallbackUiIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let hasApplied = false;
|
||||||
|
|
||||||
|
targets.forEach((targetRow: any, idx: number) => {
|
||||||
|
const updateSource = updatesArray[idx] || updatesArray[0] || {};
|
||||||
|
const appliedFields = buildApplyFields(updateSource);
|
||||||
|
|
||||||
|
if (Object.keys(appliedFields).length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasApplied = true;
|
||||||
|
|
||||||
|
const uiIndex = section.data.findIndex(
|
||||||
|
(item: any) => item.key === targetRow.key
|
||||||
|
);
|
||||||
|
|
||||||
|
if (uiIndex !== -1) {
|
||||||
|
const originalRecord = section.data[uiIndex];
|
||||||
|
const merged = { ...originalRecord, ...appliedFields };
|
||||||
|
merged.key = originalRecord.key;
|
||||||
|
if (Object.prototype.hasOwnProperty.call(originalRecord, 'index')) {
|
||||||
|
merged.index = originalRecord.index;
|
||||||
|
}
|
||||||
|
section.data.splice(uiIndex, 1, merged);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
editingTableKey.value &&
|
||||||
|
tableGenerationData[editingTableKey.value]
|
||||||
|
) {
|
||||||
const responseData =
|
const responseData =
|
||||||
tableGenerationData[editingTableKey.value].responseData;
|
tableGenerationData[editingTableKey.value].responseData;
|
||||||
|
|
||||||
// 如果响应数据存在且包含data数组
|
if (responseData && responseData.data && Array.isArray(responseData.data)) {
|
||||||
if (
|
const rawIndex = findRawIndex(
|
||||||
responseData &&
|
responseData.data,
|
||||||
responseData.data &&
|
targetRow,
|
||||||
Array.isArray(responseData.data)
|
uiIndex
|
||||||
) {
|
);
|
||||||
// 找到对应的原始数据索引
|
|
||||||
const dataIndex = (() => {
|
|
||||||
const hasValidId =
|
|
||||||
updatedRecord.id !== undefined &&
|
|
||||||
updatedRecord.id !== null &&
|
|
||||||
updatedRecord.id !== '';
|
|
||||||
|
|
||||||
if (hasValidId) {
|
if (rawIndex !== -1) {
|
||||||
const byId = responseData.data.findIndex(
|
responseData.data[rawIndex] = {
|
||||||
(item: any) => item.id === updatedRecord.id
|
...responseData.data[rawIndex],
|
||||||
);
|
...stripResponseFields(appliedFields)
|
||||||
if (byId !== -1) return byId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认 key 由 mapper 使用 index 生成,后端原始数据通常没有 key
|
|
||||||
if (
|
|
||||||
typeof updatedRecord.key === 'number' &&
|
|
||||||
updatedRecord.key >= 0 &&
|
|
||||||
updatedRecord.key < responseData.data.length
|
|
||||||
) {
|
|
||||||
return updatedRecord.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasKey =
|
|
||||||
updatedRecord.key !== undefined && updatedRecord.key !== null;
|
|
||||||
if (hasKey) {
|
|
||||||
const byKey = responseData.data.findIndex(
|
|
||||||
(item: any) =>
|
|
||||||
item.key !== undefined && item.key === updatedRecord.key
|
|
||||||
);
|
|
||||||
if (byKey !== -1) return byKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (dataIndex !== -1) {
|
|
||||||
// 更新原始响应数据中的对应记录
|
|
||||||
responseData.data[dataIndex] = {
|
|
||||||
...responseData.data[dataIndex],
|
|
||||||
...(() => {
|
|
||||||
const { workPaperIndex, key, index, ...rest } = updatedRecord;
|
|
||||||
return rest;
|
|
||||||
})()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新tableGenerationData中的响应数据
|
|
||||||
tableGenerationData[editingTableKey.value].responseData =
|
|
||||||
responseData;
|
|
||||||
} else {
|
} else {
|
||||||
// 如果没找到对应的原始数据,直接将编辑后的数据添加到响应数据中
|
responseData.data.push(stripResponseFields(appliedFields));
|
||||||
// 这可能发生在手动添加行的情况下
|
|
||||||
responseData.data.push(
|
|
||||||
(() => {
|
|
||||||
const { workPaperIndex, key, index, ...rest } = updatedRecord;
|
|
||||||
return rest;
|
|
||||||
})()
|
|
||||||
);
|
|
||||||
tableGenerationData[editingTableKey.value].responseData =
|
|
||||||
responseData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tableGenerationData[editingTableKey.value].responseData =
|
||||||
|
responseData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
message.success('编辑成功');
|
if (editingTableKey.value) {
|
||||||
|
tableData[editingTableKey.value] = section.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentSelections = selectedRowsMap[editingSectionIndex.value] || [];
|
||||||
|
selectedRowsMap[editingSectionIndex.value] = currentSelections
|
||||||
|
.map(
|
||||||
|
(row: any) =>
|
||||||
|
section.data.find((item: any) => item.key === row.key) || row
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasApplied) {
|
||||||
|
message.warning('没有可应用的字段');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
message.success('编辑成功');
|
||||||
editModalVisible.value = false;
|
editModalVisible.value = false;
|
||||||
editingTableKey.value = ''; // 清空编辑的表格key
|
editingTableKey.value = '';
|
||||||
|
editingTargetRows.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 删除行 */
|
/* 删除行(多选) */
|
||||||
const deleteRow = (record: any, sectionIndex: number) => {
|
const deleteRow = (sectionIndex: number) => {
|
||||||
const section: any = navigationItems.value[sectionIndex];
|
const section: any = navigationItems.value[sectionIndex];
|
||||||
if (!section || !section.data) return;
|
if (!section || !section.data) return;
|
||||||
|
|
||||||
const uiIndex = section.data.findIndex(
|
const selectedRows = selectedRowsMap[sectionIndex] || [];
|
||||||
(item: any) => item.key === record.key
|
if (!selectedRows.length) {
|
||||||
);
|
message.warning('请先选择要删除的行');
|
||||||
if (uiIndex === -1) return;
|
return;
|
||||||
|
|
||||||
// 同步删除原始 responseData(删除前就计算 rawIndex,避免 key 重排导致错位)
|
|
||||||
const tableInfo = getTableInfo(sectionIndex);
|
|
||||||
if (
|
|
||||||
tableInfo &&
|
|
||||||
tableInfo.tableKey &&
|
|
||||||
tableGenerationData[tableInfo.tableKey]
|
|
||||||
) {
|
|
||||||
const responseData = tableGenerationData[tableInfo.tableKey].responseData;
|
|
||||||
if (
|
|
||||||
responseData &&
|
|
||||||
responseData.data &&
|
|
||||||
Array.isArray(responseData.data)
|
|
||||||
) {
|
|
||||||
const rawIndex = (() => {
|
|
||||||
const hasValidId =
|
|
||||||
record?.id !== undefined &&
|
|
||||||
record?.id !== null &&
|
|
||||||
record?.id !== '';
|
|
||||||
if (hasValidId) {
|
|
||||||
const byId = responseData.data.findIndex(
|
|
||||||
(item: any) => item.id === record.id
|
|
||||||
);
|
|
||||||
if (byId !== -1) return byId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认 key 由 mapper 使用 index 生成
|
|
||||||
if (
|
|
||||||
typeof record.key === 'number' &&
|
|
||||||
record.key >= 0 &&
|
|
||||||
record.key < responseData.data.length
|
|
||||||
) {
|
|
||||||
return record.key;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasKey = record?.key !== undefined && record?.key !== null;
|
|
||||||
if (hasKey) {
|
|
||||||
const byKey = responseData.data.findIndex(
|
|
||||||
(item: any) => item.key !== undefined && item.key === record.key
|
|
||||||
);
|
|
||||||
if (byKey !== -1) return byKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最后兜底:使用 UI 索引
|
|
||||||
if (uiIndex >= 0 && uiIndex < responseData.data.length)
|
|
||||||
return uiIndex;
|
|
||||||
return -1;
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (rawIndex !== -1) {
|
|
||||||
responseData.data.splice(rawIndex, 1);
|
|
||||||
tableGenerationData[tableInfo.tableKey].responseData = responseData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除 UI 行
|
const tableInfo = getTableInfo(sectionIndex);
|
||||||
section.data.splice(uiIndex, 1);
|
const responseData =
|
||||||
|
tableInfo &&
|
||||||
|
tableInfo.tableKey &&
|
||||||
|
tableGenerationData[tableInfo.tableKey] &&
|
||||||
|
tableGenerationData[tableInfo.tableKey].responseData &&
|
||||||
|
tableGenerationData[tableInfo.tableKey].responseData.data &&
|
||||||
|
Array.isArray(tableGenerationData[tableInfo.tableKey].responseData.data)
|
||||||
|
? tableGenerationData[tableInfo.tableKey].responseData
|
||||||
|
: null;
|
||||||
|
|
||||||
// 删除后重排 key/index,保证后续编辑/保存按 key(索引) 能正确匹配
|
const findRawIndex = (
|
||||||
|
responseList: any[],
|
||||||
|
targetRow: any,
|
||||||
|
fallbackUiIndex: number
|
||||||
|
) => {
|
||||||
|
const hasValidId =
|
||||||
|
targetRow?.id !== undefined &&
|
||||||
|
targetRow?.id !== null &&
|
||||||
|
targetRow?.id !== '';
|
||||||
|
if (hasValidId) {
|
||||||
|
const byId = responseList.findIndex((item: any) => item.id === targetRow.id);
|
||||||
|
if (byId !== -1) return byId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof targetRow?.key === 'number' &&
|
||||||
|
targetRow.key >= 0 &&
|
||||||
|
targetRow.key < responseList.length
|
||||||
|
) {
|
||||||
|
return targetRow.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetRow?.key !== undefined && targetRow?.key !== null) {
|
||||||
|
const byKey = responseList.findIndex(
|
||||||
|
(item: any) => item.key !== undefined && item.key === targetRow.key
|
||||||
|
);
|
||||||
|
if (byKey !== -1) return byKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
fallbackUiIndex !== -1 &&
|
||||||
|
fallbackUiIndex >= 0 &&
|
||||||
|
fallbackUiIndex < responseList.length
|
||||||
|
) {
|
||||||
|
return fallbackUiIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uiIndexesToDelete: number[] = [];
|
||||||
|
const rawIndexesToDelete: number[] = [];
|
||||||
|
|
||||||
|
selectedRows.forEach((row: any) => {
|
||||||
|
const uiIndex = section.data.findIndex((item: any) => item.key === row.key);
|
||||||
|
if (uiIndex !== -1) uiIndexesToDelete.push(uiIndex);
|
||||||
|
|
||||||
|
if (responseData) {
|
||||||
|
const rawIndex = findRawIndex(responseData.data, row, uiIndex);
|
||||||
|
if (rawIndex !== -1) rawIndexesToDelete.push(rawIndex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const uniqueUiIndexes = Array.from(new Set(uiIndexesToDelete)).sort(
|
||||||
|
(a, b) => b - a
|
||||||
|
);
|
||||||
|
uniqueUiIndexes.forEach((idx) => {
|
||||||
|
section.data.splice(idx, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除后重排 key/index,保证后续操作按 key(索引) 能正确匹配
|
||||||
section.data = section.data.map((item: any, index: number) => {
|
section.data = section.data.map((item: any, index: number) => {
|
||||||
const next: any = { ...item, key: index };
|
const next: any = { ...item, key: index };
|
||||||
if (item && Object.prototype.hasOwnProperty.call(item, 'index')) {
|
if (item && Object.prototype.hasOwnProperty.call(item, 'index')) {
|
||||||
@@ -1337,7 +1431,20 @@
|
|||||||
tableData[tableInfo.tableKey] = section.data;
|
tableData[tableInfo.tableKey] = section.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.success('删除成功');
|
if (responseData && tableInfo && tableInfo.tableKey) {
|
||||||
|
const uniqueRawIndexes = Array.from(new Set(rawIndexesToDelete)).sort(
|
||||||
|
(a, b) => b - a
|
||||||
|
);
|
||||||
|
uniqueRawIndexes.forEach((idx) => {
|
||||||
|
responseData.data.splice(idx, 1);
|
||||||
|
});
|
||||||
|
tableGenerationData[tableInfo.tableKey].responseData = responseData;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedRowsMap[sectionIndex] = [];
|
||||||
|
selectedRowKeysMap[sectionIndex] = [];
|
||||||
|
|
||||||
|
message.success(`已删除${uniqueUiIndexes.length || selectedRows.length}条记录`);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 保存当前表格到历史记录 */
|
/* 保存当前表格到历史记录 */
|
||||||
@@ -1471,6 +1578,9 @@
|
|||||||
|
|
||||||
section.data = [];
|
section.data = [];
|
||||||
message.success('已清空表格');
|
message.success('已清空表格');
|
||||||
|
|
||||||
|
selectedRowsMap[sectionIndex] = [];
|
||||||
|
selectedRowKeysMap[sectionIndex] = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1609,6 +1719,13 @@
|
|||||||
// 清空特殊数据
|
// 清空特殊数据
|
||||||
tripleOneData.value = null;
|
tripleOneData.value = null;
|
||||||
stateAssetsData.value = null;
|
stateAssetsData.value = null;
|
||||||
|
// 清空选中行
|
||||||
|
Object.keys(selectedRowsMap).forEach((key) => {
|
||||||
|
delete selectedRowsMap[key as any];
|
||||||
|
});
|
||||||
|
Object.keys(selectedRowKeysMap).forEach((key) => {
|
||||||
|
delete selectedRowKeysMap[key as any];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user