chenhj
2026-04-30 8e4c8d6ed7088e0f9e396f324796929cc79778ca
Merge branch 'dev_NEW_pro' of http://114.132.189.42:9002/r/product-inventory-management into dev_NEW_pro
已修改17个文件
1234 ■■■■■ 文件已修改
src/api/productionManagement/productionOrder.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Dialog/FileList.vue 319 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/PIMTable.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue 80 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/afterSalesHandling/index.vue 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/index.vue 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/index.vue 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 85 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/processRoute/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/processRoute/processRouteItem/index.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/workOrderManagement/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/safeQualifications/index.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safeProduction/safetyTrainingAssessment/index.vue 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionOrder.js
@@ -45,6 +45,15 @@
  });
}
// 生产订单-修改
export function updateProductOrder(data) {
  return request({
    url: "/productionOrder/updateOrder",
    method: "post",
    data: data,
  });
}
export function delProductOrder(ids) {
  return request({
    url: `/productionOrder/delete`,
src/components/Dialog/FileList.vue
@@ -5,7 +5,8 @@
             @close="handleClose"
             class="attachment-dialog">
    <!-- 工具栏 -->
    <div class="toolbar">
    <div v-if="editable"
         class="toolbar">
      <el-button type="primary"
                 size="small"
                 @click="handleUpload">
@@ -13,12 +14,11 @@
      </el-button>
    </div>
    <!-- 上传组件弹窗 -->
    <el-dialog
        v-model="uploadDialogVisible"
        title="上传附件"
        width="50%"
        @close="closeUpload">
      <AttachmentUpload v-model:file-list="newFileList"/>
    <el-dialog v-model="uploadDialogVisible"
               title="上传附件"
               width="50%"
               @close="closeUpload">
      <AttachmentUpload v-model:file-list="newFileList" />
      <template #footer>
        <el-button @click="saveUpload">保存</el-button>
        <el-button @click="closeUpload">关闭</el-button>
@@ -32,7 +32,7 @@
                :height="tableData.length > 0 ? 'auto' : '120px'">
        <el-table-column label="附件名称"
                         prop="originalFilename"
                         show-overflow-tooltip/>
                         show-overflow-tooltip />
        <el-table-column v-if="showActions"
                         fixed="right"
                         label="操作"
@@ -46,7 +46,8 @@
                       @click="downloadFile(scope.row.downloadURL)">
              下载
            </el-button>
            <el-button link
            <el-button v-if="editable"
                       link
                       type="danger"
                       size="small"
                       @click="handleDelete(scope.row)">
@@ -60,181 +61,185 @@
</template>
<script setup>
import {ref, computed, getCurrentInstance, onMounted, watch} from "vue";
import AttachmentUpload from "@/components/AttachmentUpload/file/index.vue";
import {
  attachmentList,
  deleteAttachment,
  createAttachment,
} from "@/api/basicData/storageAttachment.js";
  import { ref, computed, getCurrentInstance, onMounted, watch } from "vue";
  import AttachmentUpload from "@/components/AttachmentUpload/file/index.vue";
  import {
    attachmentList,
    deleteAttachment,
    createAttachment,
  } from "@/api/basicData/storageAttachment.js";
const props = defineProps({
  visible: {
    type: Boolean,
    required: true,
  },
  recordType: {
    type: String,
    default: "",
    required: true,
  },
  recordId: {
    type: Number,
    default: 0,
    required: true,
  },
  title: {
    type: String,
    default: "附件",
  },
  width: {
    type: String,
    default: "50%",
  },
  showActions: {
    type: Boolean,
    default: true,
  },
});
  const props = defineProps({
    visible: {
      type: Boolean,
      required: true,
    },
    recordType: {
      type: String,
      default: "",
      required: true,
    },
    recordId: {
      type: Number,
      default: 0,
      required: true,
    },
    title: {
      type: String,
      default: "附件",
    },
    width: {
      type: String,
      default: "50%",
    },
    showActions: {
      type: Boolean,
      default: true,
    },
    editable: {
      type: Boolean,
      default: true,
    },
  });
const emit = defineEmits(["close", "download", "upload", "delete"]);
  const emit = defineEmits(["close", "download", "upload", "delete"]);
const {proxy} = getCurrentInstance();
const tableData = ref([]);
const uploadDialogVisible = ref(false);
const newFileList = ref([]);
  const { proxy } = getCurrentInstance();
  const tableData = ref([]);
  const uploadDialogVisible = ref(false);
  const newFileList = ref([]);
const isShow = computed({
  get() {
    return props.visible;
  },
  set(val) {
    emit("update:visible", val);
  },
});
  const isShow = computed({
    get() {
      return props.visible;
    },
    set(val) {
      emit("update:visible", val);
    },
  });
const handleClose = () => {
  isShow.value = false;
};
  const handleClose = () => {
    isShow.value = false;
  };
const handleUpload = () => {
  uploadDialogVisible.value = true;
};
  const handleUpload = () => {
    uploadDialogVisible.value = true;
  };
const saveUpload = async () => {
  // 检查是否有新上传的文件
  if (newFileList.value.length > 0) {
  const saveUpload = async () => {
    // 检查是否有新上传的文件
    if (newFileList.value.length > 0) {
      try {
        await createAttachment({
          application: "file",
          recordType: props.recordType,
          recordId: props.recordId,
          storageBlobDTOs: [...newFileList.value, ...tableData.value],
        });
        newFileList.value = [];
        // 刷新列表
        setList();
      } catch (error) {
        proxy?.$modal?.msgError("上传失败");
      }
    }
    uploadDialogVisible.value = false;
  };
  const closeUpload = () => {
    newFileList.value = [];
    uploadDialogVisible.value = false;
  };
  const handleDelete = async (row, index) => {
    try {
      await createAttachment({
        application: "file",
        recordType: props.recordType,
        recordId: props.recordId,
        storageBlobDTOs: [...newFileList.value, ...tableData.value],
      });
      newFileList.value = [];
      // 刷新列表
      await deleteAttachment([row.storageAttachmentId]);
      proxy?.$modal?.msgSuccess("删除成功");
      setList();
    } catch (error) {
      proxy?.$modal?.msgError("上传失败");
      proxy?.$modal?.msgError("删除失败");
    }
  }
  uploadDialogVisible.value = false;
};
  };
const closeUpload = () => {
  newFileList.value = [];
  uploadDialogVisible.value = false;
}
  const setList = () => {
    attachmentList({
      recordType: props.recordType,
      recordId: props.recordId,
    }).then(res => {
      if (res && res.data) {
        tableData.value = res.data || [];
      }
    });
  };
const handleDelete = async (row, index) => {
  try {
    await deleteAttachment([row.storageAttachmentId]);
    proxy?.$modal?.msgSuccess("删除成功");
  const downloadFile = url => {
    window.open(url, "_blank");
  };
  onMounted(() => {
    setList();
  } catch (error) {
    proxy?.$modal?.msgError("删除失败");
  }
};
const setList = () => {
  attachmentList({
    recordType: props.recordType,
    recordId: props.recordId,
  }).then(res => {
    if (res && res.data) {
      tableData.value = res.data || [];
    }
  });
};
const downloadFile = (url) => {
  window.open(url, "_blank");
};
onMounted(() => {
  setList();
});
</script>
<style scoped>
.attachment-dialog {
  border-radius: 12px;
}
  .attachment-dialog {
    border-radius: 12px;
  }
.toolbar {
  margin-bottom: 16px;
  text-align: right;
}
  .toolbar {
    margin-bottom: 16px;
    text-align: right;
  }
.table-container {
  max-height: 40vh;
  overflow-y: auto;
  min-height: 120px;
  padding-bottom: 16px;
  box-sizing: border-box;
  will-change: scroll-position;
  transform: translateZ(0);
  -webkit-overflow-scrolling: touch;
}
  .table-container {
    max-height: 40vh;
    overflow-y: auto;
    min-height: 120px;
    padding-bottom: 16px;
    box-sizing: border-box;
    will-change: scroll-position;
    transform: translateZ(0);
    -webkit-overflow-scrolling: touch;
  }
:deep(.el-table) {
  margin-bottom: 0;
}
  :deep(.el-table) {
    margin-bottom: 0;
  }
:deep(.el-table__body-wrapper) {
  overflow-y: auto;
  will-change: transform;
  transform: translateZ(0);
}
  :deep(.el-table__body-wrapper) {
    overflow-y: auto;
    will-change: transform;
    transform: translateZ(0);
  }
:deep(.el-table__body tr) {
  transition: none;
}
  :deep(.el-table__body tr) {
    transition: none;
  }
:deep(.el-dialog__footer) {
  padding-top: 12px;
  border-top: 1px solid #e9ecef;
}
  :deep(.el-dialog__footer) {
    padding-top: 12px;
    border-top: 1px solid #e9ecef;
  }
.attachment-table {
  border-radius: 8px;
}
  .attachment-table {
    border-radius: 8px;
  }
:deep(.el-dialog__header) {
  background-color: #f8f9fa;
  border-bottom: 1px solid #e9ecef;
  padding: 16px 20px;
}
  :deep(.el-dialog__header) {
    background-color: #f8f9fa;
    border-bottom: 1px solid #e9ecef;
    padding: 16px 20px;
  }
:deep(.el-dialog__title) {
  font-size: 16px;
  font-weight: 600;
}
  :deep(.el-dialog__title) {
    font-size: 16px;
    font-weight: 600;
  }
:deep(.el-dialog__body) {
  padding: 16px 20px;
}
  :deep(.el-dialog__body) {
    padding: 16px 20px;
  }
:deep(.el-table__empty-text) {
  color: #999;
}
  :deep(.el-table__empty-text) {
    color: #999;
  }
</style>
src/components/PIMTable/PIMTable.vue
@@ -21,6 +21,7 @@
            class="lims-table">
    <el-table-column align="center"
                     type="selection"
                     :selectable="selectable"
                     width="55"
                     v-if="isSelection" />
    <el-table-column align="center"
@@ -258,6 +259,10 @@
      type: Boolean,
      default: false,
    },
    selectable: {
      type: Function,
      default: () => true,
    },
    isShowPagination: {
      type: Boolean,
      default: true,
src/views/collaborativeApproval/rulesRegulationsManagement/index.vue
@@ -212,14 +212,7 @@
        </el-table-column>
      </el-table>
    </el-dialog>
    <FileListDialog ref="fileListDialogRef"
                    v-model="fileDialogVisible"
                    :show-upload-button="true"
                    :show-delete-button="true"
                    :delete-method="handleAttachmentDelete"
                    :rules-regulations-management-id="currentFileRuleId"
                    :name-column-label="'附件名称'"
                    @upload="handleAttachmentUpload"/>
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="rules_regulations_management" :record-id="recordId"  />
  </div>
</template>
@@ -235,7 +228,7 @@
    addReadingStatus,
    updateReadingStatus,
  } from "@/api/collaborativeApproval/sealManagement.js";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  import {
    listRuleFiles,
    delRuleFile,
@@ -254,14 +247,7 @@
    total: 0,
  });
  // 附件弹窗
  const fileDialogVisible = ref(false);
  const fileListDialogRef = ref(null);
  const currentFileRuleId = ref(null);
  const filePage = reactive({
    current: 1,
    size: 1000,
    total: 0,
  });
  // 规章制度相关
  const showRegulationDialog = ref(false);
  const showRegulationDetailDialog = ref(false);
@@ -564,63 +550,15 @@
    );
  };
  // 附件:查询
  const fetchRuleFiles = async rulesRegulationsManagementId => {
    const params = {
      current: filePage.current,
      size: filePage.size,
      rulesRegulationsManagementId,
    };
    const res = await listRuleFiles(params);
    const records = res?.data?.records || [];
    filePage.total = res?.data?.total || records.length;
    const mapped = records.map(item => ({
      id: item.id,
      name: item.fileName || item.name,
      url: item.fileUrl || item.url,
      raw: item,
    }));
    fileListDialogRef.value?.setList(mapped);
  };
  // 打开附件弹窗
  const openFileDialog = async row => {
    currentFileRuleId.value = row.id;
    fileDialogVisible.value = true;
    await fetchRuleFiles(row.id);
  };
  const recordId =ref(0)
  const fileDialogVisible = ref(false)
  // 刷新附件列表
  const refreshFileList = async () => {
    if (!currentFileRuleId.value) return;
    await fetchRuleFiles(currentFileRuleId.value);
  };
  // 上传附件(由子组件触发)
  const handleAttachmentUpload = async filePayload => {
    if (!currentFileRuleId.value) return;
    const payload = {
      name: filePayload?.fileName || filePayload?.name,
      url: filePayload?.fileUrl || filePayload?.url,
      rulesRegulationsManagementId: currentFileRuleId.value,
    };
    await addRuleFile(payload);
    ElMessage.success("文件上传成功");
    await refreshFileList();
  };
  // 删除附件
  const handleAttachmentDelete = async row => {
    if (!row?.id) return false;
    try {
      await ElMessageBox.confirm("确认删除该附件?", "提示", { type: "warning" });
    } catch {
      return false;
    }
    await delRuleFile([row.id]);
    ElMessage.success("删除成功");
    await refreshFileList();
  };
  // 打开附件弹框
  const openFileDialog = async (row) => {
    recordId.value = row.id
    fileDialogVisible.value = true
  }
  // 获取规章制度列表数据
  const getRegulationList = async () => {
src/views/customerService/afterSalesHandling/index.vue
@@ -102,33 +102,19 @@
            ></PIMTable>
        </div>
        <form-dia ref="formDia" @close="handleQuery"></form-dia>
        <FileListDialog
            ref="fileListRef"
            v-model="fileListDialogVisible"
            title="售后附件"
            :show-upload-button="true"
            :show-delete-button="true"
            :upload-method="handleFileUpload"
            :delete-method="handleFileDelete"
        />
    </div>
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="after_sales_service" :record-id="recordId"  />
  </div>
</template>
<script setup>
import { onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick, defineAsyncComponent} from "vue";
import FormDia from "@/views/customerService/afterSalesHandling/components/formDia.vue";
import FileListDialog from "@/components/Dialog/FileListDialog.vue";
import { ElMessageBox } from "element-plus";
import request from "@/utils/request";
import { getToken } from "@/utils/auth";
import {
    afterSalesServiceListPage,
    afterSalesServiceFileListPage,
    afterSalesServiceFileDel,
} from "@/api/customerService/index.js";
import useUserStore from "@/store/modules/user.js";
const { proxy } = getCurrentInstance();
const userStore = useUserStore()
const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
const data = reactive({
    searchForm: {
@@ -303,144 +289,15 @@
  })
}
// 打开附件弹窗
const recordId =ref(0)
const fileDialogVisible = ref(false)
// 打开附件弹框
const openFilesFormDia = async (row) => {
    currentFileRow.value = row
    try {
        const res = await afterSalesServiceFileListPage({
            afterSalesServiceId: row.id,
            current: 1,
            size: 100,
        })
        if (res.code === 200 && fileListRef.value) {
            const fileList = (res.data?.records || []).map((item) => ({
                name: item.name || item.fileName,
                url: item.url || item.fileUrl,
                id: item.id,
                ...item,
            }))
            fileListRef.value.open(fileList)
            fileListDialogVisible.value = true
        } else {
            fileListRef.value?.open([])
            fileListDialogVisible.value = true
        }
    } catch (error) {
        proxy.$modal.msgError("获取附件列表失败")
        fileListRef.value?.open([])
        fileListDialogVisible.value = true
    }
}
// 上传附件
const handleFileUpload = async () => {
    if (!currentFileRow.value) {
        proxy.$modal.msgWarning("请先选择数据")
        return
    }
    return new Promise((resolve) => {
        const input = document.createElement("input")
        input.type = "file"
        input.style.display = "none"
        input.onchange = async (e) => {
            const file = e.target.files[0]
            if (!file) {
                resolve(null)
                return
            }
            try {
                const formData = new FormData()
                formData.append("file", file)
                formData.append("id", currentFileRow.value.id)
                const uploadRes = await request({
                    url: "/afterSalesService/file/upload",
                    method: "post",
                    data: formData,
                    headers: {
                        "Content-Type": "multipart/form-data",
                        Authorization: `Bearer ${getToken()}`,
                    },
                })
                if (uploadRes.code === 200) {
                    proxy.$modal.msgSuccess("文件上传成功")
                    // 重新获取文件列表
                    const listRes = await afterSalesServiceFileListPage({
                        afterSalesServiceId: currentFileRow.value.id,
                        current: 1,
                        size: 100,
                    })
                    if (listRes.code === 200 && fileListRef.value) {
                        const fileList = (listRes.data?.records || []).map((item) => ({
                            name: item.fileName,
                            url: item.fileUrl,
                            id: item.id,
                            ...item,
                        }))
                        fileListRef.value.setList(fileList)
                    }
                    resolve({ name: file.name, url: "", id: null })
                } else {
                    proxy.$modal.msgError(uploadRes.msg || "文件上传失败")
                    resolve(null)
                }
            } catch (err) {
                proxy.$modal.msgError("文件上传失败")
                resolve(null)
            } finally {
                document.body.removeChild(input)
            }
        }
        document.body.appendChild(input)
        input.click()
    })
}
// 删除附件
const handleFileDelete = async (row) => {
    try {
        // 添加确认对话框
        const confirmResult = await ElMessageBox.confirm(
            '确定要删除这个附件吗?',
            '删除确认',
            {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }
        )
        if (confirmResult === 'confirm') {
            const res = await afterSalesServiceFileDel(row.id)
            if (res.code === 200) {
                proxy.$modal.msgSuccess("删除成功")
                if (currentFileRow.value && fileListRef.value) {
                    const listRes = await afterSalesServiceFileListPage({
                        afterSalesServiceId: currentFileRow.value.id,
                        current: 1,
                        size: 100,
                    })
                    if (listRes.code === 200) {
                        const fileList = (listRes.data?.records || []).map((item) => ({
                            name: item.fileName,
                            url: item.fileUrl,
                            id: item.id,
                            ...item,
                        }))
                        fileListRef.value.setList(fileList)
                    }
                }
            } else {
                proxy.$modal.msgError(res.msg || "删除失败")
                return false
            }
        }
    } catch (error) {
        // 如果用户取消删除,不显示错误信息
        if (error !== 'cancel') {
            proxy.$modal.msgError("删除失败")
        }
        return false
    }
  recordId.value = row.id
  fileDialogVisible.value = true
}
// 查询列表
src/views/financialManagement/expenseManagement/index.vue
@@ -76,27 +76,18 @@
      </PIMTable>
    </div>
    <Modal ref="modalRef" @success="getTableData"></Modal>
    <FileListDialog
      ref="fileListRef"
      v-model="fileListDialogVisible"
      :show-upload-button="true"
      :show-delete-button="true"
      :upload-method="handleUpload"
      :delete-method="handleFileDelete"
    />
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="account_expense" :record-id="recordId"  />
  </div>
</template>
<script setup>
import { usePaginationApi } from "@/hooks/usePaginationApi";
import { listPage, delAccountExpense, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/expenseManagement";
import { onMounted, getCurrentInstance, ref, computed } from "vue";
import { listPage, delAccountExpense } from "@/api/financialManagement/expenseManagement";
import {onMounted, getCurrentInstance, ref, computed, defineAsyncComponent} from "vue";
import Modal from "./Modal.vue";
import { ElMessageBox, ElMessage } from "element-plus";
import dayjs from "dayjs";
import FileListDialog from "@/components/Dialog/FileListDialog.vue";
import request from "@/utils/request";
import { getToken } from "@/utils/auth";
const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
defineOptions({
  name: "支出管理",
@@ -108,9 +99,6 @@
const modalRef = ref();
const { checkout_payment } = proxy.useDict("checkout_payment");
const { expense_types } = proxy.useDict("expense_types");
const fileListRef = ref(null);
const fileListDialogVisible = ref(false);
const currentFileRow = ref(null);
const accountType = ref('支出');
const {
@@ -315,156 +303,16 @@
      proxy.$modal.msg("已取消");
    });
};
// 打开附件弹窗
const recordId =ref(0)
const fileDialogVisible = ref(false)
// 打开附件弹框
const openFilesFormDia = async (row) => {
  currentFileRow.value = row;
  accountType.value = '支出';
  try {
    const res = await fileListPage({
      accountId: row.id,
      accountType: accountType.value,
      current: 1,
      size: 100
    });
    if (res.code === 200 && fileListRef.value) {
      // 将数据转换为 FileListDialog 需要的格式
      const fileList = (res.data?.records || []).map(item => ({
        name: item.name,
        url: item.url,
        id: item.id,
        ...item
      }));
      fileListRef.value.open(fileList);
      fileListDialogVisible.value = true;
    }
  } catch (error) {
    proxy.$modal.msgError("获取附件列表失败");
  }
};
// 上传附件
const handleUpload = async () => {
  if (!currentFileRow.value) {
    proxy.$modal.msgWarning("请先选择数据");
    return null;
  }
  return new Promise((resolve) => {
    // 创建一个隐藏的文件输入元素
    const input = document.createElement('input');
    input.type = 'file';
    input.style.display = 'none';
    input.onchange = async (e) => {
      const file = e.target.files[0];
      if (!file) {
        resolve(null);
        return;
      }
      try {
        // 使用 FormData 上传文件
        const formData = new FormData();
        formData.append('file', file);
        const uploadRes = await request({
          url: '/file/upload',
          method: 'post',
          data: formData,
          headers: {
            'Content-Type': 'multipart/form-data',
            Authorization: `Bearer ${getToken()}`
          }
        });
        if (uploadRes.code === 200) {
          // 保存附件信息
          const fileData = {
            accountId: currentFileRow.value.id,
            accountType: accountType.value,
            name: uploadRes.data.originalName || file.name,
            url: uploadRes.data.tempPath || uploadRes.data.url
          };
          const saveRes = await fileAdd(fileData);
          if (saveRes.code === 200) {
            proxy.$modal.msgSuccess("文件上传成功");
            // 重新加载文件列表
            const listRes = await fileListPage({
              accountId: currentFileRow.value.id,
              accountType: accountType.value,
              current: 1,
              size: 100
            });
            if (listRes.code === 200 && fileListRef.value) {
              const fileList = (listRes.data?.records || []).map(item => ({
                name: item.name,
                url: item.url,
                id: item.id,
                ...item
              }));
              fileListRef.value.setList(fileList);
            }
            // 返回新文件信息
            resolve({
              name: fileData.name,
              url: fileData.url,
              id: saveRes.data?.id
            });
          } else {
            proxy.$modal.msgError(saveRes.msg || "文件保存失败");
            resolve(null);
          }
        } else {
          proxy.$modal.msgError(uploadRes.msg || "文件上传失败");
          resolve(null);
        }
      } catch (error) {
        proxy.$modal.msgError("文件上传失败");
        resolve(null);
      } finally {
        document.body.removeChild(input);
      }
    };
    document.body.appendChild(input);
    input.click();
  });
};
// 删除附件
const handleFileDelete = async (row) => {
  try {
    const res = await fileDel([row.id]);
    if (res.code === 200) {
      proxy.$modal.msgSuccess("删除成功");
      // 重新加载文件列表
      if (currentFileRow.value && fileListRef.value) {
        const listRes = await fileListPage({
          accountId: currentFileRow.value.id,
          accountType: accountType.value,
          current: 1,
          size: 100
        });
        if (listRes.code === 200) {
          const fileList = (listRes.data?.records || []).map(item => ({
            name: item.name,
            url: item.url,
            id: item.id,
            ...item
          }));
          fileListRef.value.setList(fileList);
        }
      }
      return true; // 返回 true 表示删除成功,组件会更新列表
    } else {
      proxy.$modal.msgError(res.msg || "删除失败");
      return false;
    }
  } catch (error) {
    proxy.$modal.msgError("删除失败");
    return false;
  }
};
  recordId.value = row.id
  fileDialogVisible.value = true
}
onMounted(() => {
  getTableData();
src/views/procurementManagement/procurementInvoiceLedger/index.vue
@@ -69,7 +69,7 @@
          <el-button
            type="primary"
            link
            @click="downLoadFile(row)"
            @click="openFileDialog(row)"
          >
            附件
          </el-button>
@@ -83,16 +83,7 @@
        </template>
      </PIMTable>
    </div>
    <FileListDialog
      ref="fileListRef"
      v-model="fileListDialogVisible"
      title="附件列表"
      :showUploadButton="true"
      :showDeleteButton="true"
      :deleteMethod="handleDeleteFile"
      :uploadMethod="handleFileUpload"
      :rulesRegulationsManagementId="currentRowId"
    />
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="ticket_registration" :record-id="recordId"  />
    <EditModal ref="editmodalRef" @success="getTableData"></EditModal>
  </div>
</template>
@@ -113,9 +104,9 @@
import { onMounted } from "vue";
import { ElMessageBox } from "element-plus";
import EditModal from "./Modal/EditModal.vue";
import FileListDialog from '@/components/Dialog/FileListDialog.vue';
import useUserStore from "@/store/modules/user.js";
const userStore = useUserStore();
const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
defineOptions({
  name: "来票台账",
@@ -290,143 +281,15 @@
  onCurrentChange(page);
};
const downLoadFile = row => {
  currentRowId.value = row.id;
  if (fileListRef.value) {
    fileListRef.value.open(row.commonFiles || []);
  }
};
// 打开附件弹窗
const recordId =ref(0)
const fileDialogVisible = ref(false)
// 上传附件(自定义上传方法)
const handleFileUpload = async () => {
  if (!currentRowId.value) {
    proxy.$modal.msgWarning("缺少登记ID,无法保存附件");
    return;
  }
  return new Promise((resolve) => {
    // 创建一个隐藏的文件输入元素
    const input = document.createElement('input');
    input.type = 'file';
    input.style.display = 'none';
    input.onchange = async (e) => {
      const file = e.target.files[0];
      if (!file) {
        resolve(null);
        return;
      }
      try {
        // 使用 FormData 上传文件
        const formData = new FormData();
        formData.append('file', file);
        formData.append('type', '4'); // type 参数,用户未指定具体值,先传空字符串
        formData.append('id', currentRowId.value); // 当前行的 id
        const uploadRes = await request({
          url: '/file/uploadByCommon',
          method: 'post',
          data: formData,
          headers: {
            'Content-Type': 'multipart/form-data',
            Authorization: `Bearer ${getToken()}`
          }
        });
        if (uploadRes.code === 200) {
          proxy.$modal.msgSuccess("附件上传成功");
          // 刷新列表获取最新数据
          await new Promise((resolveRefresh) => {
            // 调用 API 获取最新列表数据
            productRecordPage({
              ...filters,
              current: pagination.currentPage,
              size: pagination.pageSize
            }).then(({ code, data }) => {
              if (code === 200) {
                // 更新数据列表
                dataList.value = data.records;
                pagination.total = data.total;
                // 从外部数据获取 commonFiles
                const currentRow = dataList.value.find(row => row.id === currentRowId.value);
                if (currentRow && fileListRef.value) {
                  // 刷新附件列表,使用从外部获取的最新 commonFiles
                  fileListRef.value.open(currentRow.commonFiles || []);
                }
                resolveRefresh();
              } else {
                resolveRefresh();
              }
            }).catch(() => {
              resolveRefresh();
            });
          });
          resolve({
            name: uploadRes.data?.originalName || file.name,
            url: uploadRes.data?.tempPath || uploadRes.data?.url,
            id: uploadRes.data?.id
          });
        } else {
          proxy.$modal.msgError(uploadRes.msg || "文件上传失败");
          resolve(null);
        }
      } catch (error) {
        console.error("附件上传失败:", error);
        proxy.$modal.msgError("附件上传失败");
        resolve(null);
      } finally {
        document.body.removeChild(input);
      }
    };
    document.body.appendChild(input);
    input.click();
  });
};
// 删除附件
const handleDeleteFile = async (file) => {
  try {
    await delCommonFile([file.id]);
    proxy.$modal.msgSuccess("删除成功");
    // 刷新列表获取最新数据
    await new Promise((resolveRefresh) => {
      // 调用 API 获取最新列表数据
      productRecordPage({
        ...filters,
        current: pagination.currentPage,
        size: pagination.pageSize
      }).then(({ code, data }) => {
        if (code === 200) {
          // 更新数据列表
          dataList.value = data.records;
          pagination.total = data.total;
          // 从外部数据获取 commonFiles
          const currentRow = dataList.value.find(row => row.id === currentRowId.value);
          if (currentRow && fileListRef.value) {
            // 刷新附件列表,使用从外部获取的最新 commonFiles
            fileListRef.value.open(currentRow.commonFiles || []);
          }
          resolveRefresh();
        } else {
          resolveRefresh();
        }
      }).catch(() => {
        resolveRefresh();
      });
    });
    return true;
  } catch (error) {
    proxy.$modal.msgError("删除失败");
    return false;
  }
};
// 打开附件弹框
const openFileDialog = async (row) => {
  recordId.value = row.id
  fileDialogVisible.value = true
}
const openEdit = (row) => {
  editmodalRef.value.open(row);
src/views/procurementManagement/procurementLedger/index.vue
@@ -53,8 +53,7 @@
    <div class="table_list">
      <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
        <el-button type="primary"
                   @click="openForm('add')">新增台账
        </el-button>
                   @click="openForm('add')">新增台账</el-button>
        <el-button type="primary" plain @click="handleImport">导入</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger"
@@ -181,8 +180,7 @@
            </el-button>
            <el-button link
                       type="primary"
                       @click="downLoadFile(scope.row)">附件
            </el-button>
                       @click="openFileDialog(scope.row)">附件</el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -632,51 +630,48 @@
        </el-row>
      </el-form>
    </FormDialog>
    <FileListDialog
        ref="fileListRef"
        v-model="fileListDialogVisible"
        title="附件列表"
    />
    <FileList v-if="fileListDialogVisible"  v-model:visible="fileListDialogVisible" record-type="purchase_ledger" :record-id="recordId"  />
  </div>
</template>
<script setup>
import {getToken} from "@/utils/auth";
import pagination from "@/components/PIMTable/Pagination.vue";
import {
  ref,
  onMounted,
  reactive,
  toRefs,
  getCurrentInstance,
  nextTick,
} from "vue";
import {Search, Delete} from "@element-plus/icons-vue";
import {ElMessageBox, ElMessage} from "element-plus";
import FormDialog from '@/components/Dialog/FormDialog.vue';
import FileListDialog from '@/components/Dialog/FileListDialog.vue';
import {
  getSalesLedgerWithProducts,
  addOrUpdateSalesLedgerProduct,
  delProduct,
  delLedgerFile,
  getProductInfoByContractNo,
} from "@/api/salesManagement/salesLedger.js";
import {
  addOrEditPurchase,
  addPurchaseTemplate,
  updatePurchaseTemplate,
  createPurchaseNo,
  delPurchase,
  getSalesNo,
  purchaseListPage,
  productList,
  getPurchaseById,
  getOptions,
  getPurchaseTemplateList,
  delPurchaseTemplate,
} from "@/api/procurementManagement/procurementLedger.js";
import useFormData from "@/hooks/useFormData.js";
  import { getToken } from "@/utils/auth";
  import pagination from "@/components/PIMTable/Pagination.vue";
  import {
    ref,
    onMounted,
    reactive,
    toRefs,
    getCurrentInstance,
    nextTick,
  } from "vue";
  import { Search, Delete } from "@element-plus/icons-vue";
  import { ElMessageBox, ElMessage } from "element-plus";
  import {
    addOrUpdateSalesLedgerProduct,
    delProduct,
    delLedgerFile,
    getProductInfoByContractNo,
  } from "@/api/salesManagement/salesLedger.js";
  import {
    addOrEditPurchase,
    addPurchaseTemplate,
    updatePurchaseTemplate,
    createPurchaseNo,
    delPurchase,
    getSalesNo,
    purchaseListPage,
    productList,
    getPurchaseById,
    getOptions,
    getPurchaseTemplateList,
    delPurchaseTemplate,
  } from "@/api/procurementManagement/procurementLedger.js";
  import useFormData from "@/hooks/useFormData.js";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
const {proxy} = getCurrentInstance();
const tableData = ref([]);
@@ -1760,6 +1755,12 @@
  }
};
// 打开附件弹框
const openFileDialog = async (row) => {
  recordId.value = row.id
  fileListDialogVisible.value = true
}
// 删除模板
const handleDeleteTemplate = async (item) => {
  if (!item.id) {
src/views/productionManagement/processRoute/index.vue
@@ -61,7 +61,8 @@
  import EditProcess from "@/views/productionManagement/processRoute/Edit.vue";
  import RouteItemForm from "@/views/productionManagement/processRoute/ItemsForm.vue";
  import { listPage, del } from "@/api/productionManagement/processRoute.js";
  import FileList from "@/components/Dialog/FileList.vue";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  import { useRouter } from "vue-router";
  import { ElMessage, ElMessageBox } from "element-plus";
src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -68,7 +68,8 @@
                   style="margin-right: 10px;">
          卡片视图
        </el-button>
        <el-button type="primary"
        <el-button v-if="editable"
                   type="primary"
                   @click="handleAdd">新增</el-button>
      </div>
    </div>
@@ -133,12 +134,12 @@
                     link
                     size="small"
                     @click="handleEdit(scope.row)"
                     :disabled="scope.row.isComplete">编辑</el-button>
                     :disabled="scope.row.isComplete || !editable">编辑</el-button>
          <el-button type="danger"
                     link
                     size="small"
                     @click="handleDelete(scope.row)"
                     :disabled="scope.row.isComplete">删除</el-button>
                     :disabled="scope.row.isComplete || !editable">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
@@ -152,7 +153,8 @@
                     style="margin-right: 10px;">
            表格视图
          </el-button>
          <el-button type="primary"
          <el-button v-if="editable"
                     type="primary"
                     @click="handleAdd">新增</el-button>
        </div>
      </div>
@@ -196,7 +198,7 @@
                         link
                         size="small"
                         @click="handleEdit(item)"
                         :disabled="item.isComplete">编辑</el-button>
                         :disabled="item.isComplete || !editable">编辑</el-button>
              <el-button type="info"
                         link
                         size="small"
@@ -205,7 +207,7 @@
                         link
                         size="small"
                         @click="handleDelete(item)"
                         :disabled="item.isComplete">删除</el-button>
                         :disabled="item.isComplete || !editable">删除</el-button>
            </div>
          </div>
        </div>
@@ -216,7 +218,7 @@
         style="margin-top: 20px;">
      <div class="section-title">BOM 结构</div>
      <div class="section-actions"
           v-if="pageType === 'order'">
           v-if="pageType === 'order' && editable">
        <el-button v-if="!bomDataValue.isEdit"
                   type="primary"
                   @click="bomDataValue.isEdit = true">
@@ -447,7 +449,6 @@
                         @confirm="handleProductSelect"
                         single />
    <!-- 参数列表对话框 -->
    <!-- :editable="!routeInfo.status" -->
    <ProcessParamListDialog v-model="showParamListDialog"
                            :title="`${currentProcess ? (currentProcess.processName || currentProcess.technologyOperationName || currentProcess.operationName) : ''} - 参数列表`"
                            :route-id="routeId"
@@ -455,6 +456,7 @@
                            :process="currentProcess"
                            :page-type="pageType"
                            :param-list="paramList"
                            :editable="editable"
                            @getsyncProcessParamItem="getsyncProcessParamItem"
                            @refresh="refreshParamList" />
  </div>
@@ -509,6 +511,7 @@
  const routeId = computed(() => route.query.id);
  const orderId = computed(() => route.query.orderId);
  const pageType = computed(() => route.query.type);
  const editable = computed(() => route.query.editable !== "false");
  const tableLoading = ref(false);
  const tableData = ref([]);
@@ -878,6 +881,7 @@
  // 初始化拖拽排序
  const initSortable = () => {
    destroySortable();
    if (!editable.value) return;
    if (viewMode.value === "table") {
      // 表格视图的拖拽排序
src/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue
@@ -55,14 +55,15 @@
                             controls-position="right"
                             placeholder="输入实际数量"
                             style="width: 100%;"
                             :disabled="row.returned"
                             :disabled="row.returned || orderRow?.end"
                             @change="val => handleActualQtyChange(row, val)" />
          </template>
        </el-table-column>
      </el-table>
      <template #footer>
        <span class="dialog-footer">
          <el-button type="warning"
          <el-button v-if="!orderRow?.end"
                     type="warning"
                     :loading="materialReturnConfirming"
                     :disabled="!canOpenReturnSummary"
                     @click="openReturnSummaryDialog">
src/views/productionManagement/productionOrder/index.vue
@@ -40,6 +40,8 @@
                       value="3" />
            <el-option label="已取消"
                       value="4" />
            <el-option label="已结束"
                       value="5" />
          </el-select>
        </el-form-item>
        <el-form-item>
@@ -65,6 +67,7 @@
                :tableLoading="tableLoading"
                :row-class-name="tableRowClassName"
                :isSelection="true"
                :selectable="row => !row.endOrder"
                @selection-change="handleSelectionChange"
                @pagination="pagination">
        <template #completionStatus="{ row }">
@@ -210,6 +213,7 @@
    listProcessBom,
    delProductOrder,
    getProductOrderSource,
    updateProductOrder,
  } from "@/api/productionManagement/productionOrder.js";
  import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js";
  import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue";
@@ -243,7 +247,7 @@
      prop: "npsNo",
      width: "150px",
    },
    // 1.待开始、2.进行中、3.已完成、4.已取消
    // 1.待开始、2.进行中、3.已完成、4.已取消、5.已结束
    {
      label: "状态",
      prop: "status",
@@ -256,6 +260,8 @@
          ? "进行中"
          : val === 3
          ? "已完成"
          : val === 5
          ? "已结束"
          : "已取消",
      formatType: val =>
        val === 1
@@ -264,7 +270,9 @@
          ? "warning"
          : val === 3
          ? "success"
          : "danger",
          : val === 5
          ? "danger"
          : "info",
    },
    {
      label: "产品名称",
@@ -319,7 +327,7 @@
      label: "操作",
      align: "center",
      fixed: "right",
      width: 260,
      width: 280,
      operation: [
        {
          name: "工艺路线",
@@ -332,7 +340,7 @@
        {
          name: "绑定工艺路线",
          type: "text",
          showHide: row => !row.processRouteCode,
          showHide: row => !row.processRouteCode && !row.endOrder,
          clickFun: row => {
            openBindRouteDialog(row, "add");
          },
@@ -340,7 +348,7 @@
        {
          name: "更换工艺路线",
          type: "text",
          showHide: row => row.processRouteCode,
          showHide: row => row.processRouteCode && !row.endOrder,
          clickFun: row => {
            openBindRouteDialog(row, "change");
          },
@@ -356,6 +364,7 @@
          name: "领料",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder,
          clickFun: row => {
            openMaterialDialog(row);
          },
@@ -364,6 +373,7 @@
          name: "补料",
          type: "text",
          color: "#5EC7AB",
          showHide: row => !row.endOrder,
          clickFun: row => {
            openMaterialSupplementDialog(row);
          },
@@ -379,7 +389,8 @@
        {
          name: "打印领料单",
          type: "text",
          color: "#409eff",
          color: "#5EC7AB",
          showHide: row => !row.endOrder,
          clickFun: row => {
            handlePrint(row);
          },
@@ -397,6 +408,15 @@
                model: row.model,
              },
            });
          },
        },
        {
          name: "结束订单",
          type: "text",
          color: "red",
          showHide: row => !row.endOrder,
          clickFun: row => {
            handleEndOrder(row);
          },
        },
      ],
@@ -642,6 +662,7 @@
          quantity: row.quantity || 0,
          orderId,
          type: "order",
          editable: !row.endOrder,
        },
      });
    } catch (e) {
@@ -736,6 +757,26 @@
      });
  };
  // 结束订单
  const handleEndOrder = row => {
    ElMessageBox.confirm(`是否确认结束订单:${row.npsNo}?`, "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    })
      .then(() => {
        const params = {
          id: row.id,
          endOrder: true,
        };
        updateProductOrder(params).then(() => {
          proxy.$modal.msgSuccess("结束订单成功");
          getList();
        });
      })
      .catch(() => {});
  };
  const handleConfirmRoute = () => {};
  onMounted(() => {
src/views/productionManagement/workOrderManagement/index.vue
@@ -244,6 +244,7 @@
                    @refresh="getList" />
    <FileList v-if="fileDialogVisible"
              v-model:visible="fileDialogVisible"
              :editable="!currentWorkOrderRow?.endOrder"
              :record-type="'production_operation_task'"
              :record-id="currentWorkOrderId" />
  </div>
@@ -264,7 +265,8 @@
  import QRCode from "qrcode";
  import { getCurrentInstance, reactive, toRefs } from "vue";
  import MaterialDialog from "./components/MaterialDialog.vue";
  import FileList from "@/components/Dialog/FileList.vue";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  import useUserStore from "@/store/modules/user";
  const { proxy } = getCurrentInstance();
  const userStore = useUserStore();
@@ -370,6 +372,7 @@
          clickFun: row => {
            showReportDialog(row);
          },
          showHide: row => !row.endOrder,
          disabled: row => {
            if (row.planQuantity <= 0) return true;
            if (!row.userIds) return false;
@@ -631,9 +634,11 @@
  const printTransferCard = () => {
    window.print();
  };
  const currentWorkOrderRow = ref(null);
  const openWorkOrderFiles = row => {
    currentWorkOrderId.value = row.id;
    currentWorkOrderRow.value = row;
    fileDialogVisible.value = true;
  };
src/views/safeProduction/safeQualifications/index.vue
@@ -110,7 +110,7 @@
            <el-button link
                       type="primary"
                       size="small"
                       @click="downLoadFile(scope.row)">附件</el-button>
                       @click="openFileDialog(scope.row)">附件</el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -203,16 +203,7 @@
      </el-form>
    </FormDialog>
<!-- todo 附件预览相关 -->
    <FileListDialog ref="fileListRef"
                    v-model="fileListDialogVisible"
                    :show-upload-button="true"
                    :show-delete-button="true"
                    :is-show-pagination="true"
                    :page="filePagination"
                    :upload-method="handleUpload"
                    :delete-method="handleFileDelete"
                    @pagination="paginationSearch"
                    title="附件列表" />
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="safe_certification" :record-id="recordId"  />
  </div>
</template>
@@ -223,7 +214,6 @@
  import { ElMessageBox, ElMessage } from "element-plus";
  import useUserStore from "@/store/modules/user";
  import { userListNoPage } from "@/api/system/user.js";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
  import FormDialog from "@/components/Dialog/FormDialog.vue";
  import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
  import {
@@ -238,7 +228,7 @@
  import useFormData from "@/hooks/useFormData.js";
  import request from "@/utils/request";
  import dayjs from "dayjs";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  const userStore = useUserStore();
  const { proxy } = getCurrentInstance();
  const tableData = ref([]);
@@ -524,19 +514,17 @@
    size: 10,
    total: 0,
  });
  const downLoadFile = row => {
    currentFileRow.value = row;
    fileListPage({
      safeCertificationId: row.id,
      current: filePagination.value.current,
      size: filePagination.value.size,
    }).then(res => {
      if (fileListRef.value) {
        fileListRef.value.open(res.data.records);
      }
      filePagination.value.total = res.data.total || 0;
    });
  };
  // 打开附件弹窗
  const recordId =ref(0)
  const fileDialogVisible = ref(false)
  // 打开附件弹框
  const openFileDialog = async (row) => {
    recordId.value = row.id
    fileDialogVisible.value = true
  }
  const currentFactoryName = ref("");
  const getCurrentFactoryName = async () => {
    let res = await userStore.getInfo();
src/views/safeProduction/safetyTrainingAssessment/index.vue
@@ -239,7 +239,7 @@
          <el-descriptions-item label="附件列表:">
            <el-button type="primary"
                       size="small"
                       @click="downLoadFile(endform)">附件列表</el-button>
                       @click="openFileDialog(endform)">附件列表</el-button>
          </el-descriptions-item>
        </el-descriptions>
        <!-- <el-divider style="margin: 20px 0;" /> -->
@@ -359,22 +359,12 @@
      </template>
    </el-dialog>
    <!--  todo 附件预览相关 -->
    <FileListDialog ref="fileListRef"
                    v-model="fileListDialogVisible"
                    :show-upload-button="true"
                    :show-delete-button="true"
                    :is-show-pagination="true"
                    :page="filePagination"
                    :upload-method="handleUpload"
                    :delete-method="handleFileDelete"
                    @pagination="paginationSearch"
                    title="附件列表" />
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="safe_training" :record-id="recordId"  />
  </div>
</template>
<script setup>
  import { Search } from "@element-plus/icons-vue";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
  import {
    onMounted,
    ref,
@@ -403,6 +393,7 @@
  import useUserStore from "@/store/modules/user";
  import dayjs from "dayjs";
  const userStore = useUserStore();
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  // 表单验证规则
  const rules = {
@@ -621,7 +612,7 @@
          name: "附件",
          type: "text",
          clickFun: row => {
            downLoadFile(row);
            openFileDialog(row);
          },
          color: "#007AFF",
        },
@@ -783,27 +774,17 @@
      form.value.principalMobile = selectedUser.phonenumber;
    }
  };
  /**
   * 下载文件
   *
   * @param row 下载文件的相关信息对象
   */
  const fileListRef = ref(null);
  const fileListDialogVisible = ref(false);
  const currentFileRow = ref(null);
  const downLoadFile = row => {
    currentFileRow.value = row;
    safeTrainingFileListPage({
      safeTrainingId: row.id,
      current: filePagination.value.current,
      size: filePagination.value.size,
    }).then(res => {
      if (fileListRef.value) {
        fileListRef.value.open(res.data.records);
        filePagination.value.total = res.data?.total || 0;
      }
    });
  };
  // 打开附件弹窗
  const recordId =ref(0)
  const fileDialogVisible = ref(false)
  // 打开附件弹框
  const openFileDialog = async (row) => {
    recordId.value = row.id
    fileDialogVisible.value = true
  }
  // 上传附件
  const handleUpload = async () => {
    if (!currentFileRow.value) {
src/views/salesManagement/invoiceLedger/index.vue
@@ -44,7 +44,7 @@
        <el-table-column fixed="right" label="操作" width="150" align="center">
          <template #default="scope">
            <el-button link type="primary" @click="openForm(scope.row)">编辑</el-button>
            <el-button link type="primary" @click="downLoadFile(scope.row)">附件</el-button>
            <el-button link type="primary" @click="openFileDialog(scope.row)">附件</el-button>
            <el-button link type="primary" @click="delInvoiceLedger(scope.row)">删除</el-button>
          </template>
        </el-table-column>
@@ -134,7 +134,7 @@
        </div>
      </template>
    </el-dialog>
    <FileListDialog ref="fileListRef" v-model="fileListDialogVisible" />
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="invoice_registration_product" :record-id="recordId"  />
  </div>
</template>
@@ -155,8 +155,8 @@
import useUserStore from "@/store/modules/user.js";
import useFormData from "@/hooks/useFormData";
import dayjs from "dayjs";
import FileListDialog from '@/components/Dialog/FileListDialog.vue';
import { getCurrentDate } from "@/utils/index.js";
const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
const { proxy } = getCurrentInstance();
const tableData = ref([]);
@@ -422,17 +422,14 @@
  getList();
};
//附件相关
const fileListRef = ref(null)
const fileListDialogVisible = ref(false)
//查看附件
const downLoadFile = (row) => {
    invoiceLedgerProductInfo({ id: row.id }).then((res) => {
        if (fileListRef.value) {
            fileListRef.value.open(res.data.fileList)
            fileListDialogVisible.value = true
        }
    });
// 打开附件弹窗
const recordId =ref(0)
const fileDialogVisible = ref(false)
// 打开附件弹框
const openFileDialog = async (row) => {
  recordId.value = row.id
  fileDialogVisible.value = true
}
onMounted(() => {
src/views/salesManagement/salesLedger/index.vue
@@ -231,7 +231,7 @@
                       :disabled="!scope.row.isEdit || scope.row.hasProductionRecord || !canEditLedger(scope.row)">编辑</el-button>
            <el-button link
                       type="primary"
                       @click="downLoadFile(scope.row)">附件</el-button>
                       @click="openFileDialog(scope.row)">附件</el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -740,9 +740,7 @@
    </FormDialog>
<!-- // todo 附件预览相关 -->
    <!-- 附件列表弹窗 -->
    <FileListDialog ref="fileListRef"
                    v-model="fileListDialogVisible"
                    title="附件列表" />
    <FileList v-if="fileDialogVisible"  v-model:visible="fileDialogVisible" record-type="sales_ledger" :record-id="recordId"  />
    <!-- 打印预览弹窗 -->
    <el-dialog v-model="printPreviewVisible"
               title="打印预览"
@@ -904,10 +902,8 @@
  import { onMounted, ref, getCurrentInstance } from "vue";
  import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js";
  import { ElMessageBox, ElMessage } from "element-plus";
  import { UploadFilled, Download } from "@element-plus/icons-vue";
  import useUserStore from "@/store/modules/user";
  import { userListNoPage } from "@/api/system/user.js";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
  import FormDialog from "@/components/Dialog/FormDialog.vue";
  import { getQuotationList } from "@/api/salesManagement/salesQuotation.js";
  import {
@@ -929,6 +925,9 @@
  import { useRouter, useRoute } from "vue-router";
  import { listCustomerPrivatePool } from "@/api/basicData/customerFile.js";
  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
  const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue"));
  const router = useRouter();
  const route = useRoute();
  const userStore = useUserStore();
@@ -2440,20 +2439,15 @@
    return statusStr === "待发货" || statusStr === "审核拒绝";
  };
  /**
   * 下载文件
   *
   * @param row 下载文件的相关信息对象
   */
  const fileListRef = ref(null);
  const fileListDialogVisible = ref(false);
  const downLoadFile = row => {
    getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => {
      if (fileListRef.value) {
        fileListRef.value.open(res.salesLedgerFiles);
      }
    });
  };
  // 打开附件弹窗
  const recordId =ref(0)
  const fileDialogVisible = ref(false)
  // 打开附件弹框
  const openFileDialog = async (row) => {
    recordId.value = row.id
    fileDialogVisible.value = true
  }
  // 打开发货弹框
  const openDeliveryForm = row => {