suhp 3 недель назад
Родитель
Сommit
b173eabecc

+ 36 - 0
src/api/audit/dataInduction.js

@@ -45,3 +45,39 @@ export function moveDataInductionWithDetails(data) {
     data: data,
   })
 }
+
+// 新增文件
+export function saveDataInductionFile(data) {
+  return request({
+    url: url + '/api/materialSummary/v1/save',
+    method: 'post',
+    data: data,
+  })
+}
+
+// 保存详情
+export function saveDetailInfo(data) {
+  return request({
+    url: url + '/api/materialSummary/v1/saveDetail',
+    method: 'post',
+    data: data,
+  })
+}
+
+// 删除详情
+export function deleteDetailInfo(id) {
+  return request({
+    url: url + '/api/materialSummary/v1/deleteDetail',
+    method: 'delete',
+    params: { id: id },
+  })
+}
+
+// 获取文件列表
+export function getDetailListByMasterList(masterId) {
+  return request({
+    url: url + '/api/materialSummary/v1/DetailistlByMasterId',
+    method: 'get',
+    params: { masterId: masterId },
+  })
+}

Разница между файлами не показана из-за своего большого размера
+ 55 - 1292
src/views/costAudit/auditInfo/archivesManage/ArchiveDetail.vue


+ 1475 - 0
src/views/costAudit/auditInfo/archivesManage/ArchiveInduction.vue

@@ -0,0 +1,1475 @@
+<template>
+  <div
+    v-if="show"
+    style="padding: 20px; background-color: #f9f9f9; border-radius: 4px"
+  >
+    <div
+      style="
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+      "
+    >
+      <div style="font-size: 16px; font-weight: 500">资料归纳</div>
+      <div>
+        <el-button
+          plain
+          type="success"
+          icon="el-icon-circle-plus"
+          style="margin-right: 10px"
+          @click="openAddMaterialDialog"
+        >
+          添加资料
+        </el-button>
+        <el-button type="primary" @click="$emit('next-step')">下一步</el-button>
+      </div>
+    </div>
+    <div
+      style="
+        margin-top: 20px;
+        padding: 10px;
+        background-color: #fff;
+        border-radius: 4px;
+        font-size: 14px;
+      "
+    >
+      <span style="color: #606266">总资料页数:</span>
+      <span style="color: #f56c6c; font-weight: 500">{{ totalPageCount }}</span>
+    </div>
+    <!-- 资料列表表格 -->
+    <el-table
+      v-loading="loading"
+      :data="archiveData"
+      border
+      style="width: 100%"
+    >
+      <el-table-column type="index" label="序号" width="60" align="center" />
+      <el-table-column
+        prop="materialName"
+        label="资料名称"
+        min-width="300"
+        align="left"
+      />
+      <el-table-column
+        prop="totalPageCount"
+        label="资料页数"
+        width="130"
+        align="center"
+      >
+        <template slot-scope="{ row }">
+          {{ row.totalPageCount || 0 }}
+        </template>
+      </el-table-column>
+      <el-table-column
+        prop="updateTime"
+        label="最后修改时间"
+        width="200"
+        align="center"
+      />
+      <el-table-column label="操作" width="200" align="center" fixed="right">
+        <template slot-scope="{ row }">
+          <el-button type="text" size="small" @click="handleEditMaterial(row)">
+            修改
+          </el-button>
+          <el-button type="text" size="small" @click="$emit('delete', row)">
+            删除
+          </el-button>
+          <el-button type="text" size="small" @click="handleViewFiles(row)">
+            文件列表
+          </el-button>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" width="100" align="center" fixed="right">
+        <template slot-scope="{ row, $index }">
+          <el-button
+            v-if="$index !== 0"
+            type="text"
+            size="small"
+            @click="$emit('move-up', row, $index)"
+          >
+            上移
+          </el-button>
+          <el-button
+            v-if="$index !== archiveData.length - 1"
+            type="text"
+            size="small"
+            @click="$emit('move-down', row, $index)"
+          >
+            下移
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 添加资料弹窗 -->
+    <CostAuditDialog
+      :visible.sync="dataDialogVisible"
+      :title="dataDialogTitle"
+      :show-confirm-btn="false"
+      :show-footer="false"
+      width="80%"
+      @cancel="handleCancel"
+    >
+      <div :class="{ 'view-mode-container': isViewMode }">
+        <el-form
+          ref="dataDialogForm"
+          :model="dataDialogForm"
+          :rules="dataDialogRules"
+          style="width: 100%"
+        >
+          <el-row :gutter="20">
+            <el-col :span="8">
+              <el-form-item label="资料名称" prop="materialName">
+                <el-input
+                  v-model="dataDialogForm.materialName"
+                  placeholder="请输入资料名称"
+                  clearable
+                  :disabled="isViewMode"
+                  @input="handleMaterialNameInput"
+                ></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item label="序号" prop="materialOrderNum">
+                <el-input-number
+                  v-model="dataDialogForm.materialOrderNum"
+                  :min="1"
+                  placeholder="请输入序号"
+                  :disabled="isViewMode"
+                  style="width: 100%"
+                ></el-input-number>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+        <!-- 查询结果列表 -->
+        <div v-if="materialQueryList.length > 0" style="margin-top: 20px">
+          <div style="margin-bottom: 10px; font-weight: 500">
+            查询结果列表(点击行添加)
+          </div>
+          <el-table
+            v-loading="dataDialogLoading"
+            :data="materialQueryList"
+            border
+            style="width: 100%"
+            :row-style="{ cursor: isViewMode ? 'default' : 'pointer' }"
+            @row-click="!isViewMode && handleAddFileFromList"
+          >
+            <el-table-column
+              type="index"
+              label="序号"
+              width="60"
+              align="center"
+            />
+            <el-table-column
+              prop="materialOrderNum"
+              label="序号"
+              width="100"
+              align="center"
+            />
+            <el-table-column
+              prop="materialName"
+              label="资料名称"
+              min-width="200"
+              align="left"
+            />
+            <el-table-column
+              prop="documentName"
+              label="文书名称"
+              min-width="200"
+              align="left"
+            />
+            <el-table-column
+              prop="documentNo"
+              label="文号"
+              width="150"
+              align="center"
+            />
+            <el-table-column
+              prop="auditedUnit"
+              label="被监审单位"
+              min-width="150"
+              align="left"
+            />
+            <el-table-column
+              prop="generateTime"
+              label="生成(上传)时间"
+              width="180"
+              align="center"
+            />
+            <el-table-column
+              prop="fileSource"
+              label="文件来源"
+              width="120"
+              align="center"
+            />
+            <el-table-column
+              label="操作"
+              width="100"
+              align="center"
+              fixed="right"
+            >
+              <template slot-scope="{ row }">
+                <el-button
+                  v-if="!isViewMode"
+                  type="text"
+                  size="small"
+                  style="color: #409eff"
+                  @click.stop="handleAddFileFromList(row)"
+                >
+                  添加
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <!-- 已添加列表 -->
+        <div style="margin-top: 20px">
+          <div style="margin-bottom: 10px; font-weight: 500">
+            已添加列表(共 {{ selectedFileList.length }} 条)
+          </div>
+          <el-table :data="selectedFileList" border style="width: 100%">
+            <el-table-column
+              prop="materialOrderNum"
+              label="序号"
+              width="100"
+              align="center"
+            >
+              <template slot-scope="{ row }">
+                <el-input-number
+                  v-model="row.materialOrderNum"
+                  :min="1"
+                  size="mini"
+                  :disabled="isViewMode"
+                  style="width: 100%"
+                  @change="handleOrderNumChange"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="documentName"
+              label="文书名称"
+              min-width="200"
+              align="left"
+            >
+              <template slot-scope="{ row }">
+                <el-input
+                  v-model="row.documentName"
+                  size="mini"
+                  placeholder="请输入文书名称"
+                  :disabled="isViewMode"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="documentNo"
+              label="文号"
+              width="150"
+              align="center"
+            >
+              <template slot-scope="{ row }">
+                <el-input
+                  v-model="row.documentNo"
+                  size="mini"
+                  placeholder="请输入文号"
+                  :disabled="isViewMode"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="auditedUnit"
+              label="被监审单位"
+              min-width="150"
+              align="left"
+            >
+              <template slot-scope="{ row }">
+                <el-select
+                  v-model="row.auditedUnit"
+                  size="mini"
+                  style="width: 100%"
+                  placeholder="请选择被监审单位"
+                  :disabled="isViewMode"
+                  clearable
+                  filterable
+                  multiple
+                  collapse-tags
+                >
+                  <el-option
+                    v-for="item in allUnits"
+                    :key="item.unitId"
+                    :label="item.unitName"
+                    :value="item.unitId"
+                  ></el-option>
+                </el-select>
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="generateTime"
+              label="生成(上传)时间"
+              width="180"
+              align="center"
+            >
+              <template slot-scope="{ row }">
+                <el-date-picker
+                  v-model="row.generateTime"
+                  type="datetime"
+                  size="mini"
+                  style="width: 100%"
+                  format="yyyy-MM-dd HH:mm"
+                  value-format="yyyy-MM-dd HH:mm"
+                  placeholder="选择时间"
+                  :disabled="isViewMode"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column
+              prop="fileSource"
+              label="文件来源"
+              width="120"
+              align="center"
+            >
+              <template slot-scope="{ row }">
+                <el-select
+                  v-model="row.fileSource"
+                  size="mini"
+                  style="width: 100%"
+                  placeholder="请选择文件来源"
+                  :disabled="isViewMode"
+                  clearable
+                  filterable
+                  allow-create
+                  default-first-option
+                >
+                  <el-option
+                    label="系统生成电子文书"
+                    value="系统生成电子文书"
+                  />
+                  <el-option
+                    label="监审单位反馈文件"
+                    value="监审单位反馈文件"
+                  />
+                  <el-option
+                    label="监管主体上传文件"
+                    value="监管主体上传文件"
+                  />
+                </el-select>
+              </template>
+            </el-table-column>
+            <el-table-column
+              v-if="!isViewMode"
+              label="操作"
+              width="100"
+              align="center"
+              fixed="right"
+            >
+              <template slot-scope="{ row, $index }">
+                <el-button
+                  type="text"
+                  size="small"
+                  style="color: #f56c6c"
+                  @click="handleDeleteFile(row, $index)"
+                >
+                  删除
+                </el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <div slot="footer" style="text-align: right; margin-top: 10px">
+          <el-button
+            v-if="!isViewMode"
+            type="primary"
+            @click="openAddFileDialog"
+          >
+            添加文件
+          </el-button>
+          <el-button
+            v-if="!isViewMode"
+            type="primary"
+            @click="handleSaveDataDialog"
+          >
+            保存
+          </el-button>
+          <el-button v-if="!isViewMode" @click="handleCancel">取消</el-button>
+        </div>
+      </div>
+    </CostAuditDialog>
+
+    <!-- 添加/修改资料弹窗 -->
+    <CostAuditDialog
+      :visible.sync="materialDialogVisible"
+      title="添加/修改资料"
+      :show-confirm-btn="false"
+      :show-footer="true"
+      width="40%"
+      @cancel="materialDialogVisible = false"
+    >
+      <el-form
+        ref="materialForm"
+        :model="materialForm"
+        :rules="materialRules"
+        label-width="100px"
+      >
+        <el-form-item label="资料名称" prop="materialName">
+          <el-input
+            v-model="materialForm.materialName"
+            placeholder="请输入资料名称"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="资料序号" prop="materialOrderNum">
+          <el-input-number
+            v-model="materialForm.materialOrderNum"
+            :min="1"
+            placeholder="请输入资料序号"
+            style="width: 100%"
+          ></el-input-number>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" style="text-align: right">
+        <el-button @click="materialDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleSaveMaterial">确定</el-button>
+      </div>
+    </CostAuditDialog>
+
+    <!-- 文件列表弹窗(使用添加文件弹窗) -->
+    <CostAuditDialog
+      :visible.sync="addFileDialogVisible"
+      title="文件列表"
+      :show-confirm-btn="false"
+      :show-footer="true"
+      width="60%"
+      @cancel="addFileDialogVisible = false"
+    >
+      <el-form
+        ref="addFileForm"
+        :model="addFileForm"
+        :rules="addFileRules"
+        label-width="120px"
+      >
+        <el-form-item label="文书名称" prop="documentName">
+          <el-input
+            v-model="addFileForm.documentName"
+            placeholder="请输入文书名称"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="文号" prop="documentNumber">
+          <el-input
+            v-model="addFileForm.documentNumber"
+            placeholder="请输入文号"
+            clearable
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="被监审单位" prop="auditedUnitName">
+          <el-select
+            v-model="addFileForm.auditedUnitName"
+            placeholder="请选择被监审单位"
+            clearable
+            filterable
+          >
+            <el-option
+              v-for="item in allUnits"
+              :key="item.unitId"
+              :label="item.unitName"
+              :value="item.unitId"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="文件来源" prop="fileSource">
+          <el-select
+            v-model="addFileForm.fileSource"
+            placeholder="请选择文件来源"
+            clearable
+            filterable
+          >
+            <el-option label="系统生成电子文书" value="系统生成电子文书" />
+            <el-option label="监审单位反馈文件" value="监审单位反馈文件" />
+            <el-option label="监管主体上传文件" value="监管主体上传文件" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="上传文件" prop="attachmentUrl">
+          <el-upload
+            action="/api/upload"
+            :on-success="handleUploadSuccess"
+            :auto-upload="true"
+            :limit="1"
+          >
+            <el-button slot="trigger" type="primary">选择文件</el-button>
+            <div
+              slot="tip"
+              style="color: #909399; font-size: 12px; margin-top: 10px"
+            >
+              {{
+                addFileForm.attachmentUrl
+                  ? '已选择文件: ' + addFileForm.attachmentUrl
+                  : '请选择要上传的文件'
+              }}
+            </div>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" style="text-align: right">
+        <el-button @click="addFileDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleAddFile">确定</el-button>
+      </div>
+    </CostAuditDialog>
+
+    <!-- 文件列表弹窗 -->
+    <CostAuditDialog
+      :visible.sync="fileListDialogVisible"
+      title="文件列表"
+      :show-confirm-btn="false"
+      :show-footer="false"
+      width="80%"
+      @cancel="fileListDialogVisible = false"
+    >
+      <!-- 资料信息展示 -->
+      <div
+        v-if="currentEditingMaterial"
+        style="
+          margin-bottom: 20px;
+          padding: 15px;
+          background-color: #f5f7fa;
+          border-radius: 4px;
+        "
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <span style="color: #606266; font-size: 14px; margin-right: 10px">
+              资料名称:
+            </span>
+            <span style="font-weight: 500; font-size: 16px">
+              {{ currentEditingMaterial.materialName }}
+            </span>
+          </el-col>
+          <el-col :span="12">
+            <span style="color: #606266; font-size: 14px; margin-right: 10px">
+              资料序号:
+            </span>
+            <span style="font-weight: 500; font-size: 16px">
+              {{
+                currentEditingMaterial.materialOrderNum ||
+                currentEditingMaterial.orderNum
+              }}
+            </span>
+          </el-col>
+        </el-row>
+      </div>
+
+      <!-- 新增文件按钮 -->
+      <div style="text-align: right; margin-bottom: 15px">
+        <el-button type="primary" plain @click="handleAddNewFile">
+          新增文件
+        </el-button>
+      </div>
+
+      <!-- 文件列表 -->
+      <draggable
+        v-model="fileListData"
+        :options="{ animation: 200, handle: '.drag-handle' }"
+        tag="div"
+        class="file-list-draggable"
+        @change="handleSortFiles"
+      >
+        <div
+          v-for="(row, index) in fileListData"
+          :key="row.id"
+          class="file-list-item"
+          style="
+            padding: 15px;
+            border: 1px solid #dcdfe6;
+            margin-bottom: 10px;
+            border-radius: 4px;
+            background-color: #fff;
+            cursor: move;
+          "
+        >
+          <el-row :gutter="20">
+            <el-col :span="2">
+              <div style="text-align: center">
+                <span
+                  class="drag-handle"
+                  style="cursor: move; color: #909399; font-size: 18px"
+                >
+                  ☰
+                </span>
+                <div style="font-size: 12px; margin-top: 5px">
+                  {{ index + 1 }}
+                </div>
+              </div>
+            </el-col>
+            <el-col :span="6">
+              <div style="font-size: 14px; font-weight: 500">
+                {{ row.documentName }}
+              </div>
+              <div style="font-size: 12px; color: #909399; margin-top: 5px">
+                文书名称
+              </div>
+            </el-col>
+            <el-col :span="4">
+              <div style="font-size: 14px">{{ row.documentNumber }}</div>
+              <div style="font-size: 12px; color: #909399; margin-top: 5px">
+                文号
+              </div>
+            </el-col>
+            <el-col :span="5">
+              <div style="font-size: 14px">{{ row.auditedUnitName }}</div>
+              <div style="font-size: 12px; color: #909399; margin-top: 5px">
+                被监审单位
+              </div>
+            </el-col>
+            <el-col :span="3">
+              <div style="font-size: 14px">{{ row.fileSource }}</div>
+              <div style="font-size: 12px; color: #909399; margin-top: 5px">
+                文件来源
+              </div>
+            </el-col>
+            <el-col :span="2">
+              <div style="font-size: 14px">{{ row.pageCount || 0 }}</div>
+              <div style="font-size: 12px; color: #909399; margin-top: 5px">
+                页数
+              </div>
+            </el-col>
+            <el-col :span="2" style="text-align: right">
+              <el-button
+                type="text"
+                size="small"
+                style="margin-right: 5px"
+                @click="handleEditFile(row)"
+              >
+                修改
+              </el-button>
+              <el-button
+                type="text"
+                size="small"
+                @click="handleDeleteDetailFile(row)"
+              >
+                删除
+              </el-button>
+            </el-col>
+          </el-row>
+        </div>
+      </draggable>
+
+      <div slot="footer" style="text-align: right; margin-top: 20px">
+        <el-button @click="fileListDialogVisible = false">关闭</el-button>
+      </div>
+    </CostAuditDialog>
+
+    <!-- 新增文件弹窗 -->
+    <CostAuditDialog
+      :visible.sync="newFileDialogVisible"
+      :title="isEditingFile ? '修改文件' : '新增文件'"
+      :show-confirm-btn="false"
+      :show-footer="true"
+      width="50%"
+      @cancel="newFileDialogVisible = false"
+    >
+      <el-form
+        ref="newFileForm"
+        :model="newFileForm"
+        :rules="newFileRules"
+        label-width="100px"
+      >
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="文书名称" prop="documentName">
+              <el-input
+                v-model="newFileForm.documentName"
+                placeholder="请输入文书名称"
+                clearable
+              ></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="文号" prop="documentNumber">
+              <el-input
+                v-model="newFileForm.documentNumber"
+                placeholder="请输入文号"
+                clearable
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="被监审单位" prop="auditedUnitName">
+              <el-select
+                v-model="newFileForm.auditedUnitName"
+                placeholder="请选择被监审单位"
+                clearable
+                filterable
+                style="width: 100%"
+              >
+                <el-option
+                  v-for="item in allUnits"
+                  :key="item.unitId"
+                  :label="item.unitName"
+                  :value="item.unitId"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="文件来源" prop="fileSource">
+              <el-select
+                v-model="newFileForm.fileSource"
+                placeholder="请选择文件来源"
+                clearable
+                filterable
+                style="width: 100%"
+              >
+                <el-option label="系统生成电子文书" value="系统生成电子文书" />
+                <el-option label="监审单位反馈文件" value="监审单位反馈文件" />
+                <el-option label="监管主体上传文件" value="监管主体上传文件" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="24">
+            <el-form-item label="上传文件" prop="attachmentUrl">
+              <UploadComponent
+                :upload-mode="'single'"
+                :max-size="50 * 1024 * 1024"
+                :allowed-types="['xlsx', 'xls', 'doc', 'docx', 'pdf']"
+                :files-list="newFilesList"
+                @saveFiles="handleNewFileSaveFiles"
+                @removeFile="handleNewFileRemoveFile"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" style="text-align: right">
+        <el-button @click="newFileDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleSaveNewFile">
+          {{ isEditingFile ? '修改' : '新增' }}
+        </el-button>
+      </div>
+    </CostAuditDialog>
+  </div>
+</template>
+
+<script>
+  import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
+  import UploadComponent from '@/components/costAudit/UploadComponent.vue'
+  import draggable from 'vuedraggable'
+  import {
+    addDataInductionList,
+    saveDataInductionWithDetails,
+    saveDataInductionFile,
+    saveDetailInfo,
+    deleteDetailInfo,
+    getDetailListByMasterList,
+  } from '@/api/audit/dataInduction'
+  import { getAllUnitList } from '@/api/auditEntityManage'
+
+  export default {
+    name: 'ArchiveInduction',
+    components: {
+      CostAuditDialog,
+      UploadComponent,
+      draggable,
+    },
+    filters: {
+      formatDate(value) {
+        if (!value) return ''
+        const date = new Date(value)
+        const year = date.getFullYear()
+        const month = String(date.getMonth() + 1).padStart(2, '0')
+        const day = String(date.getDate()).padStart(2, '0')
+        const hours = String(date.getHours()).padStart(2, '0')
+        const minutes = String(date.getMinutes()).padStart(2, '0')
+        return `${year}-${month}-${day} ${hours}:${minutes}`
+      },
+    },
+    props: {
+      show: {
+        type: Boolean,
+        default: false,
+      },
+      loading: {
+        type: Boolean,
+        default: false,
+      },
+      archiveData: {
+        type: Array,
+        default: () => [],
+      },
+      totalPageCount: {
+        type: Number,
+        default: 0,
+      },
+      taskId: {
+        type: String,
+        default: '',
+      },
+    },
+    data() {
+      return {
+        allUnits: [],
+        dataDialogTitle: '添加资料',
+        dataDialogVisible: false,
+        dataDialogLoading: false,
+        dataDialogForm: { materialName: '', materialOrderNum: 1 },
+        dataDialogRules: {
+          materialName: [
+            { required: true, message: '请输入资料名称', trigger: 'blur' },
+          ],
+          materialOrderNum: [
+            { required: true, message: '请输入序号', trigger: 'blur' },
+          ],
+        },
+        materialQueryList: [],
+        selectedFileList: [],
+        isEditingDataDialog: false,
+        isViewMode: false,
+        currentEditMaterialId: null,
+        materialNameSearchTimer: null,
+        addFileDialogVisible: false,
+        addFileForm: {
+          documentName: '',
+          documentNumber: '',
+          auditedUnitName: '',
+          fileSource: '监管主体上传文件',
+          attachmentUrl: '',
+        },
+        addFileRules: {
+          documentName: [
+            { required: true, message: '请输入文书名称', trigger: 'blur' },
+          ],
+          documentNumber: [
+            { required: true, message: '请输入文号', trigger: 'blur' },
+          ],
+          auditedUnitName: [
+            { required: true, message: '请选择被监审单位', trigger: 'change' },
+          ],
+          attachmentUrl: [
+            { required: true, message: '请上传文件', trigger: 'change' },
+          ],
+        },
+        materialDialogVisible: false,
+        materialForm: {
+          materialName: '',
+          materialOrderNum: 1,
+        },
+        materialRules: {
+          materialName: [
+            { required: true, message: '请输入资料名称', trigger: 'blur' },
+          ],
+          materialOrderNum: [
+            { required: true, message: '请输入资料序号', trigger: 'blur' },
+          ],
+        },
+        currentEditingMaterial: null,
+        // 文件列表相关
+        fileListDialogVisible: false,
+        fileListData: [],
+        fileListLoading: false,
+        newFileDialogVisible: false,
+        newFileForm: {
+          documentName: '',
+          documentNumber: '',
+          auditedUnitName: '',
+          fileSource: '监管主体上传文件',
+          attachmentUrl: '',
+        },
+        newFileRules: {
+          documentName: [
+            { required: true, message: '请输入文书名称', trigger: 'blur' },
+          ],
+          documentNumber: [
+            { required: true, message: '请输入文号', trigger: 'blur' },
+          ],
+          auditedUnitName: [
+            { required: true, message: '请选择被监审单位', trigger: 'change' },
+          ],
+          attachmentUrl: [
+            { required: true, message: '请上传文件', trigger: 'change' },
+          ],
+        },
+        newFilesList: [],
+        isEditingFile: false,
+        editingFileId: null,
+      }
+    },
+    created() {
+      this.loadAllUnits()
+    },
+    methods: {
+      openAddDataDialog() {
+        this.dataDialogForm = { materialName: '', materialOrderNum: 1 }
+        this.materialQueryList = []
+        this.selectedFileList = []
+        this.isEditingDataDialog = false
+        this.isViewMode = false
+        this.currentEditMaterialId = null
+        this.dataDialogTitle = '添加资料'
+        this.dataDialogVisible = true
+      },
+      handleMaterialNameInput() {
+        if (this.materialNameSearchTimer)
+          clearTimeout(this.materialNameSearchTimer)
+        this.materialNameSearchTimer = setTimeout(() => {
+          this.queryMaterialList()
+        }, 500)
+      },
+      async queryMaterialList() {
+        if (
+          !this.dataDialogForm.materialName ||
+          !this.dataDialogForm.materialName.trim()
+        ) {
+          this.materialQueryList = []
+          return
+        }
+        if (!this.taskId) {
+          this.$message.warning('缺少任务信息')
+          return
+        }
+        try {
+          this.dataDialogLoading = true
+          const response = await addDataInductionList({
+            taskId: this.taskId,
+            materialName: this.dataDialogForm.materialName.trim(),
+          })
+          if (response && response.value) {
+            const list = Array.isArray(response.value)
+              ? response.value
+              : response.value.list || []
+            this.materialQueryList = list.map((item) => ({
+              id: item.id,
+              materialOrderNum:
+                item.materialOrderNum ||
+                item.orderNum ||
+                this.dataDialogForm.materialOrderNum,
+              materialName:
+                item.materialName || this.dataDialogForm.materialName,
+              documentName: item.documentName || item.name || '',
+              documentNo: item.documentNo || item.number || '',
+              auditedUnit: item.auditedUnit || item.auditedUnitName || '',
+              generateTime:
+                item.generateTime || item.createTime || item.updateTime || '',
+              fileSource: item.fileSource || item.source || '',
+              originalData: item,
+            }))
+          } else {
+            this.materialQueryList = []
+          }
+        } catch (error) {
+          console.error('查询资料列表失败:', error)
+          this.materialQueryList = []
+        } finally {
+          this.dataDialogLoading = false
+        }
+      },
+      handleAddFileFromList(row) {
+        const newOrderNum =
+          this.selectedFileList.length > 0
+            ? Math.max(
+                ...this.selectedFileList.map(
+                  (item) => item.materialOrderNum || 0
+                )
+              ) + 1
+            : 1
+        let auditedUnitArray = []
+        if (row.auditedUnit) {
+          if (Array.isArray(row.auditedUnit)) {
+            auditedUnitArray = row.auditedUnit
+          } else if (typeof row.auditedUnit === 'string') {
+            const unitItem = this.allUnits.find(
+              (unit) =>
+                unit.unitId === row.auditedUnit ||
+                unit.unitId === String(row.auditedUnit) ||
+                unit.unitName === row.auditedUnit
+            )
+            if (unitItem) auditedUnitArray = [unitItem.unitId]
+          }
+        }
+        this.selectedFileList.push({
+          ...row,
+          materialOrderNum: newOrderNum,
+          auditedUnit: auditedUnitArray,
+        })
+        this.$message.success('添加成功')
+      },
+      openAddMaterialDialog() {
+        this.currentEditingMaterial = null
+        this.materialForm = {
+          materialName: '',
+          materialOrderNum: 1,
+        }
+        this.materialDialogVisible = true
+      },
+      handleEditMaterial(row) {
+        this.currentEditingMaterial = row
+        this.materialForm = {
+          materialName: row.materialName || '',
+          materialOrderNum: row.materialOrderNum || row.orderNum || 1,
+        }
+        this.materialDialogVisible = true
+      },
+      async handleSaveMaterial() {
+        this.$refs.materialForm.validate(async (valid) => {
+          if (!valid) return false
+          try {
+            let params = {
+              taskId: this.taskId,
+              materialName: this.materialForm.materialName,
+              materialOrderNum: this.materialForm.materialOrderNum,
+            }
+            if (this.currentEditingMaterial) {
+              params.id = this.currentEditingMaterial.id
+            }
+            const response = await saveDataInductionFile(params)
+            if (response && response.success !== false) {
+              this.$message.success(response.message || '保存成功')
+              this.materialDialogVisible = false
+              this.$emit('refresh-data')
+            } else {
+              this.$message.error(response.message || '保存失败')
+            }
+          } catch (error) {
+            console.error('保存资料失败:', error)
+            this.$message.error('保存失败')
+          }
+        })
+      },
+      handleViewFiles(row) {
+        this.currentEditingMaterial = row
+        this.fileListDialogVisible = true
+        this.loadFileList(row.id)
+      },
+      async loadFileList(masterId) {
+        try {
+          this.fileListLoading = true
+          const response = await getDetailListByMasterList(masterId)
+          if (response && response.value) {
+            this.fileListData = Array.isArray(response.value)
+              ? response.value
+              : response.value.list || []
+          } else {
+            this.fileListData = []
+          }
+        } catch (error) {
+          console.error('加载文件列表失败:', error)
+          this.fileListData = []
+        } finally {
+          this.fileListLoading = false
+        }
+      },
+      handleAddNewFile() {
+        this.isEditingFile = false
+        this.editingFileId = null
+        this.newFileForm = {
+          documentName: '',
+          documentNumber: '',
+          auditedUnitName: '',
+          fileSource: '监管主体上传文件',
+          attachmentUrl: '',
+        }
+        this.newFilesList = []
+        this.newFileDialogVisible = true
+      },
+      handleNewFileSaveFiles(files) {
+        if (files && files.length > 0) {
+          const fileInfo = files[0]
+          this.newFileForm.attachmentUrl =
+            fileInfo.savePath || fileInfo.url || fileInfo.fileUrl
+        }
+      },
+      handleNewFileRemoveFile(index) {
+        this.newFilesList.splice(index, 1)
+        this.newFileForm.attachmentUrl = ''
+      },
+      async handleSaveNewFile() {
+        this.$refs.newFileForm.validate(async (valid) => {
+          if (!valid) return false
+          try {
+            const params = {
+              masterId: this.currentEditingMaterial.id,
+              taskId: this.taskId,
+              documentName: this.newFileForm.documentName,
+              documentNumber: this.newFileForm.documentNumber,
+              auditedUnitName: this.newFileForm.auditedUnitName,
+              fileSource: this.newFileForm.fileSource,
+              attachmentUrl: this.newFileForm.attachmentUrl,
+            }
+            if (this.isEditingFile) {
+              params.id = this.editingFileId
+            }
+            const response = await saveDetailInfo(params)
+            if (response && response.success !== false) {
+              this.$message.success(
+                response.message ||
+                  (this.isEditingFile ? '文件修改成功' : '文件添加成功')
+              )
+              this.newFileDialogVisible = false
+              this.loadFileList(this.currentEditingMaterial.id)
+            } else {
+              this.$message.error(response.message || '保存失败')
+            }
+          } catch (error) {
+            console.error('保存文件失败:', error)
+            this.$message.error('保存失败')
+          }
+        })
+      },
+      handleEditFile(row) {
+        this.isEditingFile = true
+        this.editingFileId = row.id
+        this.newFileForm = {
+          documentName: row.documentName || '',
+          documentNumber: row.documentNumber || row.documentNo || '',
+          auditedUnitName: row.auditedUnitName || '',
+          fileSource: row.fileSource || '监管主体上传文件',
+          attachmentUrl: row.attachmentUrl || '',
+        }
+        this.newFilesList = row.attachmentUrl
+          ? [{ url: row.attachmentUrl }]
+          : []
+        this.newFileDialogVisible = true
+      },
+      async handleDeleteDetailFile(row) {
+        this.$confirm('确定要删除此文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(async () => {
+            try {
+              const response = await deleteDetailInfo(row.id)
+              if (response && response.success !== false) {
+                this.$message.success(response.message || '删除成功')
+                // 从数组中直接删除,然后执行排序保存
+                const index = this.fileListData.findIndex(
+                  (item) => item.id === row.id
+                )
+                if (index > -1) {
+                  this.fileListData.splice(index, 1)
+                  // 删除后重新排序
+                  await this.handleSortFiles()
+                }
+              } else {
+                this.$message.error(response.message || '删除失败')
+              }
+            } catch (error) {
+              console.error('删除文件失败:', error)
+              this.$message.error('删除失败')
+            }
+          })
+          .catch(() => {})
+      },
+      handleUploadNewFileSuccess(response, file) {
+        // 此方法已经被 handleNewFileSaveFiles 指代
+      },
+      async handleSortFiles() {
+        try {
+          if (!this.fileListData || this.fileListData.length === 0) {
+            return
+          }
+          // 一次性保存所有文件的orderNum
+          const savePromises = this.fileListData.map((row, index) => {
+            const params = {
+              id: row.id,
+              orderNum: index + 1,
+              masterId: this.currentEditingMaterial.id,
+              taskId: this.taskId,
+            }
+            return saveDetailInfo(params)
+          })
+          await Promise.all(savePromises)
+          // 排序成功,不显示提示信息
+          // 不需要重新加载,应为fileListData已经是排序后的结果
+        } catch (error) {
+          console.error('排序失败:', error)
+          this.$message.error('排序失败,请重试')
+          // 失败时重新加载文件列表
+          this.loadFileList(this.currentEditingMaterial.id)
+        }
+      },
+      openAddFileDialog() {
+        this.addFileForm = {
+          documentName: '',
+          documentNumber: '',
+          auditedUnitName: '',
+          fileSource: '监管主体上传文件',
+          attachmentUrl: '',
+        }
+        this.addFileDialogVisible = true
+      },
+      handleAddFile() {
+        this.$refs.addFileForm.validate(async (valid) => {
+          if (!valid) return false
+          try {
+            const params = {
+              masterId: this.currentEditingMaterial.id,
+              taskId: this.taskId,
+              documentName: this.addFileForm.documentName,
+              documentNumber: this.addFileForm.documentNumber,
+              auditedUnitName: this.addFileForm.auditedUnitName,
+              fileSource: this.addFileForm.fileSource,
+              attachmentUrl: this.addFileForm.attachmentUrl,
+            }
+            const response = await saveDataInductionFile(params)
+            if (response && response.success !== false) {
+              this.$message.success(response.message || '文件添加成功')
+              this.addFileDialogVisible = false
+              this.$emit('refresh-data')
+            } else {
+              this.$message.error(response.message || '添加失败')
+            }
+          } catch (error) {
+            console.error('添加文件失败:', error)
+            this.$message.error('添加失败')
+          }
+        })
+      },
+      handleUploadSuccess(response, file) {
+        if (response && response.url) {
+          this.addFileForm.attachmentUrl = response.url
+        }
+      },
+      handleDeleteFile(row, index) {
+        this.$confirm('确定要删除该文件吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        })
+          .then(() => {
+            this.selectedFileList.splice(index, 1)
+            this.$message.success('删除成功')
+          })
+          .catch(() => {
+            this.$message.info('已取消删除')
+          })
+      },
+      async handleSaveDataDialog() {
+        if (!this.selectedFileList || this.selectedFileList.length === 0) {
+          this.$message.warning('请先添加文件')
+          return
+        }
+        if (!this.taskId) {
+          this.$message.warning('缺少任务信息')
+          return
+        }
+        if (
+          !this.dataDialogForm.materialName ||
+          !this.dataDialogForm.materialName.trim()
+        ) {
+          this.$message.warning('请输入资料名称')
+          return
+        }
+        try {
+          this.dataDialogLoading = true
+          const hasMainId =
+            this.currentEditMaterialId !== null &&
+            this.currentEditMaterialId !== undefined
+          const detailList = this.selectedFileList.map((item) => {
+            let generateTimeFormatted = item.generateTime || ''
+            if (generateTimeFormatted) {
+              try {
+                if (typeof generateTimeFormatted === 'string') {
+                  if (
+                    /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(
+                      generateTimeFormatted
+                    )
+                  ) {
+                  } else if (
+                    /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(
+                      generateTimeFormatted
+                    )
+                  ) {
+                    generateTimeFormatted = generateTimeFormatted.substring(
+                      0,
+                      16
+                    )
+                  } else if (generateTimeFormatted.includes('T')) {
+                    generateTimeFormatted = generateTimeFormatted
+                      .replace('T', ' ')
+                      .replace(/\.\d{3}Z?$/, '')
+                      .substring(0, 16)
+                  } else {
+                    const date = new Date(generateTimeFormatted)
+                    if (!isNaN(date.getTime())) {
+                      const year = date.getFullYear()
+                      const month = String(date.getMonth() + 1).padStart(2, '0')
+                      const day = String(date.getDate()).padStart(2, '0')
+                      const hours = String(date.getHours()).padStart(2, '0')
+                      const minutes = String(date.getMinutes()).padStart(2, '0')
+                      generateTimeFormatted = `${year}-${month}-${day} ${hours}:${minutes}`
+                    }
+                  }
+                } else if (generateTimeFormatted instanceof Date) {
+                  const year = generateTimeFormatted.getFullYear()
+                  const month = String(
+                    generateTimeFormatted.getMonth() + 1
+                  ).padStart(2, '0')
+                  const day = String(generateTimeFormatted.getDate()).padStart(
+                    2,
+                    '0'
+                  )
+                  const hours = String(
+                    generateTimeFormatted.getHours()
+                  ).padStart(2, '0')
+                  const minutes = String(
+                    generateTimeFormatted.getMinutes()
+                  ).padStart(2, '0')
+                  generateTimeFormatted = `${year}-${month}-${day} ${hours}:${minutes}`
+                }
+              } catch (error) {
+                console.warn('时间格式转换失败:', error)
+                generateTimeFormatted = ''
+              }
+            }
+            let auditedUnitName = ''
+            if (
+              item.auditedUnit &&
+              Array.isArray(item.auditedUnit) &&
+              item.auditedUnit.length > 0
+            ) {
+              const unitNames = item.auditedUnit
+                .map((unitId) => {
+                  const unitItem = this.allUnits.find(
+                    (unit) =>
+                      unit.unitId === unitId || unit.unitId === String(unitId)
+                  )
+                  return unitItem ? unitItem.unitName : ''
+                })
+                .filter((name) => name)
+              auditedUnitName = unitNames.join(',')
+            } else if (item.auditedUnit && !Array.isArray(item.auditedUnit)) {
+              const unitItem = this.allUnits.find(
+                (unit) =>
+                  unit.unitId === item.auditedUnit ||
+                  unit.unitId === String(item.auditedUnit)
+              )
+              if (unitItem) auditedUnitName = unitItem.unitName
+            }
+            const detailItem = {
+              documentName: item.documentName || '',
+              documentNumber: item.documentNo || '',
+              auditedUnitName: auditedUnitName,
+              generateTime: generateTimeFormatted,
+              fileSource: item.fileSource || '',
+              pageCount: item.pageCount || item.originalData?.pageCount || null,
+              attachmentId:
+                item.attachmentId || item.originalData?.attachmentId || null,
+              orderNum: item.materialOrderNum || null,
+            }
+            if (item.id && hasMainId) detailItem.id = item.id
+            return detailItem
+          })
+          const params = {
+            taskId: this.taskId,
+            materialName: this.dataDialogForm.materialName.trim(),
+            detailList: detailList,
+          }
+          if (!hasMainId) {
+            if (this.dataDialogForm.materialOrderNum)
+              params.materialOrderNum = this.dataDialogForm.materialOrderNum
+          } else {
+            params.id = this.currentEditMaterialId
+          }
+          const response = await saveDataInductionWithDetails(params)
+          if (response && response.success !== false) {
+            this.$message.success(response.message || '保存成功')
+            this.handleCancel()
+            this.$emit('refresh-data')
+          } else {
+            this.$message.error(response.message || '保存失败')
+          }
+        } catch (error) {
+          console.error('保存资料失败:', error)
+        } finally {
+          this.dataDialogLoading = false
+        }
+      },
+      handleCancel() {
+        this.dataDialogVisible = false
+        this.$nextTick(() => {
+          if (this.$refs.dataDialogForm) this.$refs.dataDialogForm.resetFields()
+          this.dataDialogForm = { materialName: '', materialOrderNum: 1 }
+          this.materialQueryList = []
+          this.selectedFileList = []
+          this.isEditingDataDialog = false
+          this.isViewMode = false
+          this.currentEditMaterialId = null
+          this.dataDialogTitle = '添加资料'
+          if (this.materialNameSearchTimer) {
+            clearTimeout(this.materialNameSearchTimer)
+            this.materialNameSearchTimer = null
+          }
+        })
+      },
+      async loadAllUnits() {
+        try {
+          const response = await getAllUnitList()
+          if (response && response.value) {
+            const list = Array.isArray(response.value)
+              ? response.value
+              : response.value.list || []
+            this.allUnits = list.map((item) => ({
+              unitId: item.unitId || item.id,
+              unitName: item.unitName || item.name || '',
+            }))
+          } else {
+            this.allUnits = []
+          }
+        } catch (error) {
+          console.error('加载被监审单位列表失败:', error)
+          this.allUnits = []
+        }
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss">
+  .view-mode-container {
+    pointer-events: none;
+
+    .el-input,
+    .el-input-number,
+    .el-select,
+    .el-date-picker,
+    .el-textarea {
+      pointer-events: none;
+    }
+
+    .el-input__inner,
+    .el-input-number__input-inner,
+    .el-select__input,
+    .el-textarea__inner {
+      background-color: #f5f7fa;
+      border-color: #e4e7ed;
+      color: #909399;
+      cursor: not-allowed;
+    }
+
+    .el-select .el-input.is-disabled .el-input__inner {
+      background-color: #f5f7fa;
+      border-color: #e4e7ed;
+      color: #909399;
+      cursor: not-allowed;
+    }
+
+    .el-date-editor.el-input {
+      .el-input__inner {
+        background-color: #f5f7fa;
+        border-color: #e4e7ed;
+        color: #909399;
+        cursor: not-allowed;
+      }
+    }
+
+    .el-input-number.is-disabled .el-input__inner {
+      background-color: #f5f7fa;
+      border-color: #e4e7ed;
+      color: #909399;
+      cursor: not-allowed;
+    }
+  }
+</style>

+ 55 - 0
src/views/costAudit/auditInfo/archivesManage/ArchivePreview.vue

@@ -0,0 +1,55 @@
+<template>
+  <div
+    v-if="show"
+    style="padding: 20px; background-color: #f9f9f9; border-radius: 4px"
+  >
+    <div
+      style="
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+      "
+    >
+      <div style="font-size: 16px; font-weight: 500">档案预览</div>
+      <div>
+        <el-button style="margin-right: 10px" @click="$emit('prev-step')">
+          上一步
+        </el-button>
+        <el-button type="success" @click="$emit('complete')">完成</el-button>
+      </div>
+    </div>
+    <div class="preview-actions" style="margin-bottom: 20px">
+      <el-button plain type="primary" icon="el-icon-success">保存</el-button>
+      <el-button plain type="primary" icon="el-icon-download">下载</el-button>
+      <el-button plain type="primary" icon="el-icon-refresh">
+        重新生成
+      </el-button>
+    </div>
+    <div
+      style="
+        border: 1px solid #dcdfe6;
+        border-radius: 4px;
+        padding: 20px;
+        background-color: #fff;
+        min-height: 400px;
+      "
+    >
+      <div style="text-align: center; color: #909399">档案预览内容区域</div>
+    </div>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'ArchivePreview',
+    props: {
+      show: {
+        type: Boolean,
+        default: false,
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss"></style>

+ 81 - 0
src/views/costAudit/auditInfo/archivesManage/ArchiveProofread.vue

@@ -0,0 +1,81 @@
+<template>
+  <div
+    v-if="show"
+    style="padding: 20px; background-color: #f9f9f9; border-radius: 4px"
+  >
+    <div
+      style="
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+      "
+    >
+      <div style="font-size: 16px; font-weight: 500">档案目录核对</div>
+      <div>
+        <el-button style="margin-right: 10px" @click="$emit('prev-step')">
+          上一步
+        </el-button>
+        <el-button type="primary" @click="$emit('next-step')">下一步</el-button>
+      </div>
+    </div>
+    <el-table
+      v-loading="loading"
+      :data="proofreadData"
+      border
+      style="width: 100%"
+    >
+      <el-table-column type="index" label="序号" width="60" align="center" />
+      <el-table-column
+        prop="name"
+        label="资料名称"
+        min-width="300"
+        align="left"
+      />
+      <el-table-column
+        prop="pageCount"
+        label="资料页数"
+        width="120"
+        align="center"
+      />
+      <el-table-column
+        prop="startEndPageCount"
+        label="起止页码"
+        width="120"
+        align="center"
+      />
+      <el-table-column label="操作" width="150" align="center" fixed="right">
+        <template slot-scope="{ row }">
+          <el-button type="text" size="small" @click="$emit('view', row)">
+            查看
+          </el-button>
+          <el-button type="text" size="small" @click="$emit('edit', row)">
+            编辑
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: 'ArchiveProofread',
+    props: {
+      show: {
+        type: Boolean,
+        default: false,
+      },
+      loading: {
+        type: Boolean,
+        default: false,
+      },
+      proofreadData: {
+        type: Array,
+        default: () => [],
+      },
+    },
+  }
+</script>
+
+<style scoped lang="scss"></style>

Некоторые файлы не были показаны из-за большого количества измененных файлов