From c3c3a8c3d14a2b01f07ba3239bbb156ded359425 Mon Sep 17 00:00:00 2001
From: b2894lxlx <517289602@qq.com>
Date: Wed, 14 Jan 2026 09:56:19 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BC=96=E8=BE=91=E3=80=81?=
=?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E6=B3=95=E6=93=8D=E4=BD=9C=E7=9A=84?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../pwl/pwlProject/components/EditModal.vue | 198 ++++++--
.../pwlProject/components/reportContent.vue | 441 +++++++++++-------
2 files changed, 435 insertions(+), 204 deletions(-)
diff --git a/src/views/pwl/pwlProject/components/EditModal.vue b/src/views/pwl/pwlProject/components/EditModal.vue
index cbb83c4..6cc55c7 100644
--- a/src/views/pwl/pwlProject/components/EditModal.vue
+++ b/src/views/pwl/pwlProject/components/EditModal.vue
@@ -7,26 +7,59 @@
:confirm-loading="loading"
width="600px"
>
+
+
+
编辑行数据
+
+ 同步编辑 {{ displayRecords.length }} 条
+
+
+
+
+
+
+
+
+ #{{ index + 1 }}
+
+
+
+
@@ -44,7 +77,7 @@
class="nested-field-item"
>
@@ -64,12 +97,44 @@ const props = defineProps<{
visible: boolean;
record: any;
fields: any[];
+ records?: any[];
}>();
const emit = defineEmits(['update:visible', 'save']);
const loading = ref(false);
-const formData = ref({});
+const formDataList = ref([]);
+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(() => {
return (props.fields || []).some((field) => {
@@ -81,7 +146,7 @@ const hasWorkPaperIndexField = computed(() => {
const processedFields = computed(() => {
const processed: any[] = [];
- props.fields.forEach(field => {
+ (props.fields || []).forEach(field => {
if (field.children && Array.isArray(field.children)) {
// 处理有子字段的情况(如职务)
processed.push({
@@ -100,49 +165,44 @@ const processedFields = computed(() => {
return processed;
});
-watch(() => props.visible, (visible) => {
- if (visible && props.record) {
- // 深拷贝记录数据
- const recordCopy = JSON.parse(JSON.stringify(props.record));
-
- // 特殊处理workPaperIndex:如果是对象数组,转换为字符串数组
- if (hasWorkPaperIndexField.value && recordCopy.workPaperIndex && Array.isArray(recordCopy.workPaperIndex)) {
- recordCopy.workPaperIndex = recordCopy.workPaperIndex.map(item => {
- if (typeof item === 'object') {
- // 如果是对象,转换为字符串格式:file_id||文件名||url
- return `${item.fileId || ''}||${item.fileName || ''}||${item.fileUrl || ''}`;
- }
- return item;
- }).join('\n');
+watch(
+ () => props.visible,
+ (visible) => {
+ if (visible) {
+ selectedRecordIndex.value = 0;
+ formDataList.value = displayRecords.value.map((rec) =>
+ transformRecordToFormData(rec)
+ );
}
-
- formData.value = recordCopy;
- }
-}, { immediate: true });
+ },
+ { immediate: true }
+);
const handleOk = () => {
- if (!formData.value) {
+ if (!formDataList.value || formDataList.value.length === 0) {
message.warning('没有数据可保存');
return;
}
// 处理workPaperIndex:将字符串转换回对象数组
- const dataToSave = JSON.parse(JSON.stringify(formData.value));
-
- if (hasWorkPaperIndexField.value && dataToSave.workPaperIndex && typeof dataToSave.workPaperIndex === 'string') {
- const lines = dataToSave.workPaperIndex.split('\n').filter(line => line.trim() !== '');
- dataToSave.workPaperIndex = lines.map(line => {
- const parts = line.split('||');
- if (parts.length >= 3) {
- return {
- fileId: parts[0] || '',
- fileName: parts[1] || '',
- fileUrl: parts[2] || ''
- };
- }
- return line;
- });
- }
+ const dataToSave = formDataList.value.map((item) => {
+ const cloned = JSON.parse(JSON.stringify(item || {}));
+ if (hasWorkPaperIndexField.value && cloned.workPaperIndex && typeof cloned.workPaperIndex === 'string') {
+ const lines = cloned.workPaperIndex.split('\n').filter((line: string) => line.trim() !== '');
+ cloned.workPaperIndex = lines.map((line: string) => {
+ const parts = line.split('||');
+ if (parts.length >= 3) {
+ return {
+ fileId: parts[0] || '',
+ fileName: parts[1] || '',
+ fileUrl: parts[2] || ''
+ };
+ }
+ return line;
+ });
+ }
+ return cloned;
+ });
loading.value = true;
emit('save', dataToSave);
@@ -153,6 +213,32 @@ const handleOk = () => {
const handleCancel = () => {
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 || {};
+ }
+});
\ No newline at end of file
+
+.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;
+}
+
diff --git a/src/views/pwl/pwlProject/components/reportContent.vue b/src/views/pwl/pwlProject/components/reportContent.vue
index d4f43ee..cbf5249 100644
--- a/src/views/pwl/pwlProject/components/reportContent.vue
+++ b/src/views/pwl/pwlProject/components/reportContent.vue
@@ -212,15 +212,8 @@
>
- 编辑
- 删除
+ 编辑
+ 删除
导出
导出取证单 row?.key ?? row?.id ?? row?.index"
:data-source="item.data"
>
@@ -497,6 +491,7 @@
@@ -581,6 +576,7 @@
const editingSectionIndex = ref(0);
const editingTableKey = ref('');
const editingFields = ref([]);
+ const editingTargetRows = ref([]);
// ========== 文档选择相关 ==========
const fileModal = ref();
@@ -605,21 +601,21 @@
// ========== 表格选择 ==========
const selectedRowsMap = reactive>({});
- const rowSelections = reactive>(
- {}
- );
+ const selectedRowKeysMap = reactive>({});
const getRowSelection = (
sectionIndex: number
): TableProps['rowSelection'] => {
- if (!rowSelections[sectionIndex]) {
- rowSelections[sectionIndex] = {
- onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
- selectedRowsMap[sectionIndex] = selectedRows;
- }
- };
- }
- return rowSelections[sectionIndex];
+ return {
+ selectedRowKeys: selectedRowKeysMap[sectionIndex] || [],
+ onChange: (
+ selectedRowKeys: (string | number)[],
+ selectedRows: any[]
+ ) => {
+ selectedRowsMap[sectionIndex] = selectedRows;
+ selectedRowKeysMap[sectionIndex] = selectedRowKeys;
+ }
+ };
};
// ========== 历史记录相关 ==========
const showHistory = ref(false);
@@ -718,6 +714,9 @@
section.data = [];
}
+ selectedRowsMap[sectionIndex] = [];
+ selectedRowKeysMap[sectionIndex] = [];
+
message.success(`已切换到:${tableOption.title}`);
};
@@ -1134,10 +1133,16 @@
};
/* 编辑行 */
- const editRow = (record: any, sectionIndex: number) => {
+ const editRow = (sectionIndex: number) => {
const section: any = navigationItems.value[sectionIndex];
if (!section || !section.columns) return;
+ const selectedRows = selectedRowsMap[sectionIndex] || [];
+ if (!selectedRows.length) {
+ message.warning('请先选择要编辑的行');
+ return;
+ }
+
// 获取可编辑的字段(排除操作列)
editingFields.value = section.columns.filter(
(col) =>
@@ -1148,183 +1153,272 @@
col.key !== 'workPaperIndex'
);
- editingRecord.value = { ...record };
+ // 将所有选中的行传递给编辑弹窗
+ editingRecord.value = { ...selectedRows[0] };
+ editingTargetRows.value = selectedRows.map((row: any) => ({ ...row }));
editingSectionIndex.value = sectionIndex;
// 记录当前编辑的表格key
const tableInfo = getTableInfo(sectionIndex);
if (tableInfo) {
editingTableKey.value = tableInfo.tableKey;
+ } else {
+ editingTableKey.value = '';
}
editModalVisible.value = true;
};
/* 保存编辑 */
- const saveEdit = (updatedRecord: any) => {
+ const saveEdit = (updatedRecords: any | any[]) => {
const section: any = navigationItems.value[editingSectionIndex.value];
if (!section || !section.data) return;
- const index = section.data.findIndex(
- (item: any) => item.key === updatedRecord.key
- );
- if (index !== -1) {
- // 保留原有数据的其他字段
- const originalRecord = section.data[index];
- section.data[index] = { ...originalRecord, ...updatedRecord };
+ const targets =
+ editingTargetRows.value && editingTargetRows.value.length
+ ? editingTargetRows.value
+ : editingRecord.value
+ ? [editingRecord.value]
+ : [];
- // 更新对应的响应数据
- if (editingTableKey.value && tableGenerationData[editingTableKey.value]) {
- // 获取当前的响应数据
+ if (!targets.length) {
+ message.warning('未找到需要编辑的行');
+ return;
+ }
+
+ const updatesArray = Array.isArray(updatedRecords)
+ ? updatedRecords
+ : [updatedRecords];
+
+ // 只提取允许编辑的字段,避免把首行的其他值覆盖到所有行
+ const allowedKeys = new Set();
+ 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 = {};
+ 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 =
tableGenerationData[editingTableKey.value].responseData;
- // 如果响应数据存在且包含data数组
- if (
- responseData &&
- responseData.data &&
- Array.isArray(responseData.data)
- ) {
- // 找到对应的原始数据索引
- const dataIndex = (() => {
- const hasValidId =
- updatedRecord.id !== undefined &&
- updatedRecord.id !== null &&
- updatedRecord.id !== '';
+ if (responseData && responseData.data && Array.isArray(responseData.data)) {
+ const rawIndex = findRawIndex(
+ responseData.data,
+ targetRow,
+ uiIndex
+ );
- if (hasValidId) {
- const byId = responseData.data.findIndex(
- (item: any) => item.id === updatedRecord.id
- );
- 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;
- })()
+ if (rawIndex !== -1) {
+ responseData.data[rawIndex] = {
+ ...responseData.data[rawIndex],
+ ...stripResponseFields(appliedFields)
};
-
- // 更新tableGenerationData中的响应数据
- tableGenerationData[editingTableKey.value].responseData =
- responseData;
} else {
- // 如果没找到对应的原始数据,直接将编辑后的数据添加到响应数据中
- // 这可能发生在手动添加行的情况下
- responseData.data.push(
- (() => {
- const { workPaperIndex, key, index, ...rest } = updatedRecord;
- return rest;
- })()
- );
- tableGenerationData[editingTableKey.value].responseData =
- responseData;
+ responseData.data.push(stripResponseFields(appliedFields));
}
+
+ 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;
- editingTableKey.value = ''; // 清空编辑的表格key
+ editingTableKey.value = '';
+ editingTargetRows.value = [];
};
- /* 删除行 */
- const deleteRow = (record: any, sectionIndex: number) => {
+ /* 删除行(多选) */
+ const deleteRow = (sectionIndex: number) => {
const section: any = navigationItems.value[sectionIndex];
if (!section || !section.data) return;
- const uiIndex = section.data.findIndex(
- (item: any) => item.key === record.key
- );
- if (uiIndex === -1) 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;
- }
- }
+ const selectedRows = selectedRowsMap[sectionIndex] || [];
+ if (!selectedRows.length) {
+ message.warning('请先选择要删除的行');
+ return;
}
- // 删除 UI 行
- section.data.splice(uiIndex, 1);
+ const tableInfo = getTableInfo(sectionIndex);
+ 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) => {
const next: any = { ...item, key: index };
if (item && Object.prototype.hasOwnProperty.call(item, 'index')) {
@@ -1337,7 +1431,20 @@
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 = [];
message.success('已清空表格');
+
+ selectedRowsMap[sectionIndex] = [];
+ selectedRowKeysMap[sectionIndex] = [];
}
});
};
@@ -1609,6 +1719,13 @@
// 清空特殊数据
tripleOneData.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];
+ });
}
}
);