ArchiveProofread.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. <template>
  2. <div style="padding: 20px; background-color: #f9f9f9; border-radius: 4px">
  3. <div
  4. style="
  5. display: flex;
  6. justify-content: space-between;
  7. align-items: center;
  8. margin-bottom: 20px;
  9. "
  10. >
  11. <div style="font-size: 16px; font-weight: 500">档案目录核对</div>
  12. <div>
  13. <el-button style="margin-right: 10px" @click="handlePrevStep">
  14. 上一步
  15. </el-button>
  16. <el-button type="primary" @click="handleNextStep">下一步</el-button>
  17. </div>
  18. </div>
  19. <el-table
  20. v-loading="loading"
  21. :data="proofreadData"
  22. border
  23. style="width: 100%"
  24. >
  25. <el-table-column type="index" label="序号" width="60" align="center">
  26. <template slot-scope="{ row }">
  27. {{ row.orderNum }}
  28. </template>
  29. </el-table-column>
  30. <el-table-column
  31. prop="materialName"
  32. label="资料名称"
  33. min-width="300"
  34. align="left"
  35. />
  36. <el-table-column
  37. prop="pageCount"
  38. label="资料页数"
  39. width="120"
  40. align="center"
  41. />
  42. <el-table-column
  43. prop="pageRange"
  44. label="起止页码"
  45. width="120"
  46. align="center"
  47. />
  48. <el-table-column label="操作" width="200" align="center" fixed="right">
  49. <template slot-scope="{ row }">
  50. <el-button
  51. v-if="row.canGenerate === '1' && row.documentType === 1"
  52. type="text"
  53. size="small"
  54. @click="handleGenerate(row)"
  55. >
  56. 编辑生成
  57. </el-button>
  58. <el-button
  59. v-if="row.documentType === 0"
  60. type="text"
  61. size="small"
  62. @click="handleViewFiles(row)"
  63. >
  64. 查看
  65. </el-button>
  66. <el-button
  67. v-if="row.documentType === 2"
  68. type="text"
  69. size="small"
  70. @click="handleViewCatalog(row)"
  71. >
  72. 编辑生成
  73. </el-button>
  74. <el-button
  75. v-if="row.documentType === 3"
  76. type="text"
  77. size="small"
  78. @click="handleViewCatalog(row)"
  79. >
  80. 编辑生成
  81. </el-button>
  82. <el-button
  83. v-if="[1, 2, 3].includes(row.documentType) && row.attachmentUrl"
  84. type="text"
  85. size="small"
  86. @click="handlePreviewFile(row)"
  87. >
  88. 查看
  89. </el-button>
  90. </template>
  91. </el-table-column>
  92. </el-table>
  93. <!-- 文件列表弹窗(只读模式) -->
  94. <CostAuditDialog
  95. :visible.sync="fileListDialogVisible"
  96. title="文件列表"
  97. :show-confirm-btn="false"
  98. :show-footer="false"
  99. width="80%"
  100. @cancel="fileListDialogVisible = false"
  101. >
  102. <!-- 资料信息展示 -->
  103. <div
  104. v-if="currentViewingMaterial"
  105. style="
  106. margin-bottom: 20px;
  107. padding: 15px;
  108. background-color: #f5f7fa;
  109. border-radius: 4px;
  110. "
  111. >
  112. <el-row :gutter="20">
  113. <el-col :span="12">
  114. <span style="color: #606266; font-size: 14px; margin-right: 10px">
  115. 资料名称:
  116. </span>
  117. <span style="font-weight: 500; font-size: 16px">
  118. {{ currentViewingMaterial.materialName }}
  119. </span>
  120. </el-col>
  121. <el-col :span="12">
  122. <span style="color: #606266; font-size: 14px; margin-right: 10px">
  123. 资料序号:
  124. </span>
  125. <span style="font-weight: 500; font-size: 16px">
  126. {{
  127. currentViewingMaterial.materialOrderNum ||
  128. currentViewingMaterial.orderNum
  129. }}
  130. </span>
  131. </el-col>
  132. </el-row>
  133. </div>
  134. <!-- 文件列表(只读模式,使用表格展示) -->
  135. <el-table
  136. v-loading="fileListLoading"
  137. :data="fileListData"
  138. border
  139. style="width: 100%"
  140. >
  141. <el-table-column type="index" label="序号" width="60" align="center" />
  142. <el-table-column
  143. prop="documentName"
  144. label="文书名称"
  145. min-width="200"
  146. align="left"
  147. />
  148. <el-table-column
  149. prop="documentNumber"
  150. label="文号"
  151. width="200"
  152. align="center"
  153. />
  154. <el-table-column
  155. prop="auditedUnitName"
  156. label="被监审单位"
  157. min-width="150"
  158. align="left"
  159. />
  160. <el-table-column
  161. prop="fileSource"
  162. label="文件来源"
  163. width="150"
  164. align="center"
  165. />
  166. <el-table-column
  167. prop="pageCount"
  168. label="页数"
  169. width="100"
  170. align="center"
  171. >
  172. <template slot-scope="{ row }">
  173. {{ row.pageCount || 0 }}
  174. </template>
  175. </el-table-column>
  176. <el-table-column label="操作" width="120" align="center" fixed="right">
  177. <template slot-scope="{ row }">
  178. <el-button
  179. v-if="row.attachmentUrl"
  180. type="text"
  181. size="small"
  182. @click="handlePreviewFile(row)"
  183. >
  184. 查看文件
  185. </el-button>
  186. </template>
  187. </el-table-column>
  188. </el-table>
  189. <div slot="footer" style="text-align: right; margin-top: 20px">
  190. <el-button @click="fileListDialogVisible = false">关闭</el-button>
  191. </div>
  192. </CostAuditDialog>
  193. <!-- 卷内目录弹窗 -->
  194. <CostAuditDialog
  195. :visible.sync="catalogDialogVisible"
  196. title="卷内目录"
  197. :show-confirm-btn="false"
  198. :show-footer="true"
  199. width="60%"
  200. @cancel="handleCancelCatalog"
  201. >
  202. <!-- 目录表格(只读) -->
  203. <el-table
  204. v-loading="catalogLoading"
  205. :data="catalogData"
  206. border
  207. style="width: 100%"
  208. >
  209. <el-table-column type="index" label="序号" width="100" align="center" />
  210. <el-table-column
  211. prop="materialName"
  212. label="资料名称"
  213. min-width="300"
  214. align="left"
  215. />
  216. <el-table-column
  217. prop="pageRange"
  218. label="开始页码-结束页码"
  219. width="200"
  220. align="center"
  221. />
  222. <!-- <el-table-column
  223. prop="remark"
  224. label="备注"
  225. min-width="200"
  226. align="left"
  227. /> -->
  228. </el-table>
  229. <div slot="footer" style="text-align: right">
  230. <el-button @click="handleCancelCatalog">关闭</el-button>
  231. <el-button type="primary" @click="handleGenerateCatalog">
  232. 生成
  233. </el-button>
  234. </div>
  235. </CostAuditDialog>
  236. <!-- 生成文书弹窗 -->
  237. <CostAuditDialog
  238. :visible.sync="generateDialogVisible"
  239. :title="generateDialogTitle"
  240. :show-confirm-btn="false"
  241. :show-footer="true"
  242. width="50%"
  243. @cancel="handleCancelGenerate"
  244. >
  245. <el-form
  246. ref="generateForm"
  247. :model="generateForm"
  248. :rules="generateRules"
  249. label-width="120px"
  250. >
  251. <el-row :gutter="20">
  252. <el-col :span="12">
  253. <el-form-item label="保管期限" prop="retentionPeriod">
  254. <el-input-number
  255. v-model="generateForm.retentionPeriod"
  256. :min="1"
  257. :controls="false"
  258. placeholder="请输入保管期限"
  259. style="width: 100%"
  260. ></el-input-number>
  261. </el-form-item>
  262. </el-col>
  263. <el-col :span="12">
  264. <el-form-item label="卷宗号" prop="archiveNo">
  265. <el-input
  266. v-model="generateForm.archiveNo"
  267. placeholder="请输入卷宗号"
  268. clearable
  269. ></el-input>
  270. </el-form-item>
  271. </el-col>
  272. </el-row>
  273. </el-form>
  274. <div slot="footer" style="text-align: right">
  275. <el-button @click="handleCancelGenerate">取消</el-button>
  276. <el-button type="primary" @click="handleConfirmGenerate">
  277. 确定
  278. </el-button>
  279. </div>
  280. </CostAuditDialog>
  281. <!-- 卷宗封底说明弹窗 (documentType=3) -->
  282. <CostAuditDialog
  283. :visible.sync="coverRemarkDialogVisible"
  284. title="卷宗封底说明"
  285. :show-confirm-btn="false"
  286. :show-footer="true"
  287. width="50%"
  288. @cancel="handleCancelCoverRemark"
  289. >
  290. <el-form
  291. ref="coverRemarkForm"
  292. :model="coverRemarkForm"
  293. :rules="coverRemarkRules"
  294. label-width="120px"
  295. >
  296. <el-form-item label="封底说明" prop="remark">
  297. <el-input
  298. v-model="coverRemarkForm.remark"
  299. type="textarea"
  300. :rows="6"
  301. placeholder="请输入卷宗封底说明内容"
  302. maxlength="1000"
  303. show-word-limit
  304. ></el-input>
  305. </el-form-item>
  306. </el-form>
  307. <div slot="footer" style="text-align: right">
  308. <el-button @click="handleCancelCoverRemark">取消</el-button>
  309. <el-button type="primary" @click="handleConfirmCoverRemark">
  310. 确定
  311. </el-button>
  312. </div>
  313. </CostAuditDialog>
  314. </div>
  315. </template>
  316. <script>
  317. import {
  318. getArchiveProofreadList,
  319. saveArchiveDocument,
  320. } from '@/api/audit/dataProofread'
  321. import { getDetailListByMasterList } from '@/api/audit/dataInduction'
  322. import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
  323. export default {
  324. name: 'ArchiveProofread',
  325. components: {
  326. CostAuditDialog,
  327. },
  328. props: {
  329. taskId: {
  330. type: String,
  331. default: '',
  332. },
  333. },
  334. data() {
  335. return {
  336. loading: false,
  337. proofreadData: [],
  338. // 文件列表弹窗相关
  339. fileListDialogVisible: false,
  340. fileListData: [],
  341. fileListLoading: false,
  342. currentViewingMaterial: null,
  343. // 卷内目录弹窗相关
  344. catalogDialogVisible: false,
  345. catalogData: [],
  346. catalogLoading: false,
  347. currentCatalogRow: null,
  348. // 生成文书弹窗相关
  349. generateDialogVisible: false,
  350. generateDialogTitle: '生成文书',
  351. generateForm: {
  352. id: '',
  353. taskId: '',
  354. documentType: null,
  355. retentionPeriod: null,
  356. archiveNo: '',
  357. },
  358. generateRules: {
  359. retentionPeriod: [
  360. { required: true, message: '请输入保管期限', trigger: 'blur' },
  361. ],
  362. archiveNo: [
  363. { required: true, message: '请输入卷宗号', trigger: 'blur' },
  364. ],
  365. },
  366. currentGenerateRow: null,
  367. // 卷宗封底说明弹窗相关 (documentType=3)
  368. coverRemarkDialogVisible: false,
  369. coverRemarkForm: {
  370. id: '',
  371. taskId: '',
  372. documentType: 3,
  373. remark: '',
  374. },
  375. coverRemarkRules: {
  376. remark: [
  377. { required: true, message: '请输入封底说明内容', trigger: 'blur' },
  378. ],
  379. },
  380. currentCoverRemarkRow: null,
  381. }
  382. },
  383. watch: {
  384. taskId: {
  385. handler(newVal) {
  386. if (newVal) {
  387. this.loadProofreadData()
  388. }
  389. },
  390. immediate: true,
  391. },
  392. },
  393. methods: {
  394. async loadProofreadData() {
  395. if (!this.taskId) return
  396. try {
  397. this.loading = true
  398. const response = await getArchiveProofreadList({
  399. taskId: this.taskId,
  400. })
  401. if (response && response.value) {
  402. this.proofreadData = Array.isArray(response.value)
  403. ? response.value
  404. : response.value.list || []
  405. } else {
  406. this.proofreadData = []
  407. }
  408. } catch (error) {
  409. console.error('加载卷宗校对列表失败:', error)
  410. this.proofreadData = []
  411. this.$message.error('数据加载失败')
  412. } finally {
  413. this.loading = false
  414. }
  415. },
  416. handleGenerate(row) {
  417. // 处理生成操作
  418. this.currentGenerateRow = row
  419. // 根据 documentType 设置弹窗标题
  420. const titleMap = {
  421. 1: '生成案卷封面',
  422. 2: '生成卷内目录',
  423. 3: '生成案卷封底',
  424. }
  425. this.generateDialogTitle = titleMap[row.documentType] || '生成文书'
  426. // 重置表单数据
  427. this.generateForm = {
  428. id: row.id || '',
  429. taskId: this.taskId,
  430. documentType: row.documentType,
  431. retentionPeriod: row.retentionPeriod || null,
  432. archiveNo: row.archiveNo || '',
  433. }
  434. this.generateDialogVisible = true
  435. },
  436. handleEdit(row) {
  437. // 处理编辑操作
  438. this.$emit('edit', row)
  439. },
  440. handleViewFiles(row) {
  441. // 处理查看文件列表操作
  442. this.currentViewingMaterial = row
  443. this.fileListDialogVisible = true
  444. // 兼容不同的ID字段名称
  445. const masterId = row.relatedId
  446. if (!masterId) {
  447. this.$message.warning('无法获取资料ID')
  448. console.warn('资料数据缺少ID字段:', row)
  449. return
  450. }
  451. this.loadFileList(masterId)
  452. },
  453. handlePreviewFile(row) {
  454. // 预览文件(documentType = 1 或 3)
  455. if (!row.attachmentUrl) {
  456. this.$message.warning('文件地址为空')
  457. return
  458. }
  459. // 在新窗口打开文件预览
  460. window.open(row.attachmentUrl, '_blank')
  461. },
  462. handleViewCatalog(row) {
  463. // 查看卷内目录(documentType = 2)或卷宗封底说明(documentType = 3)
  464. if (row.documentType === 2) {
  465. this.currentCatalogRow = row
  466. this.catalogDialogVisible = true
  467. this.loadCatalogData()
  468. } else if (row.documentType === 3) {
  469. // 处理 documentType=3 的情况,打开卷宗封底说明弹窗
  470. this.currentCoverRemarkRow = row
  471. // 设置表单数据
  472. this.coverRemarkForm = {
  473. id: row.id || '',
  474. taskId: this.taskId,
  475. documentType: 3,
  476. remark: row.remark || '',
  477. }
  478. this.coverRemarkDialogVisible = true
  479. }
  480. },
  481. async loadCatalogData() {
  482. try {
  483. this.catalogLoading = true
  484. console.log('开始加载卷内目录数据')
  485. const response = await getArchiveProofreadList({
  486. taskId: this.taskId,
  487. })
  488. console.log('卷内目录响应:', response)
  489. if (response && response.value) {
  490. this.catalogData = Array.isArray(response.value)
  491. ? response.value
  492. : response.value.list || []
  493. // 过滤掉前两条记录
  494. if (this.catalogData.length > 2) {
  495. this.catalogData = this.catalogData.slice(2)
  496. } else {
  497. this.catalogData = []
  498. }
  499. console.log('卷内目录数据:', this.catalogData)
  500. } else {
  501. this.catalogData = []
  502. console.warn('卷内目录响应数据为空')
  503. }
  504. } catch (error) {
  505. console.error('加载卷内目录失败:', error)
  506. this.catalogData = []
  507. this.$message.error(
  508. '数据加载失败: ' + (error.message || '请检查网络连接')
  509. )
  510. } finally {
  511. this.catalogLoading = false
  512. }
  513. },
  514. handleCancelCatalog() {
  515. // 关闭卷内目录弹窗
  516. this.catalogDialogVisible = false
  517. this.currentCatalogRow = null
  518. this.catalogData = []
  519. },
  520. async handleGenerateCatalog() {
  521. // 生成卷内目录,调用 documentType=2 的保存接口
  522. try {
  523. this.catalogLoading = true
  524. const submitData = {
  525. taskId: this.taskId,
  526. documentType: 2, // 卷内目录
  527. }
  528. // 如果当前行有ID,说明是编辑
  529. if (this.currentCatalogRow && this.currentCatalogRow.id) {
  530. submitData.id = this.currentCatalogRow.id
  531. }
  532. console.log('生成卷内目录数据:', submitData)
  533. // 调用保存文书的API接口
  534. const response = await saveArchiveDocument(submitData)
  535. if (response && response.success !== false) {
  536. this.$message.success(response.message || '生成成功')
  537. this.catalogDialogVisible = false
  538. this.loadProofreadData() // 重新加载列表
  539. } else {
  540. this.$message.error(response.message || '生成失败')
  541. }
  542. } catch (error) {
  543. console.error('生成卷内目录失败:', error)
  544. this.$message.error(
  545. '生成失败:' + (error.message || '请检查网络连接')
  546. )
  547. } finally {
  548. this.catalogLoading = false
  549. }
  550. },
  551. async loadFileList(masterId) {
  552. if (!masterId) {
  553. console.error('加载文件列表失败: masterId 为空')
  554. return
  555. }
  556. try {
  557. this.fileListLoading = true
  558. console.log('开始加载文件列表, masterId:', masterId)
  559. const response = await getDetailListByMasterList(masterId)
  560. console.log('文件列表响应:', response)
  561. if (response && response.value) {
  562. this.fileListData = Array.isArray(response.value)
  563. ? response.value
  564. : response.value.list || []
  565. console.log('文件列表数据:', this.fileListData)
  566. } else {
  567. this.fileListData = []
  568. console.warn('文件列表响应数据为空')
  569. }
  570. } catch (error) {
  571. console.error('加载文件列表失败:', error)
  572. this.fileListData = []
  573. this.$message.error(
  574. '文件列表加载失败: ' + (error.message || '请检查网络连接')
  575. )
  576. } finally {
  577. this.fileListLoading = false
  578. }
  579. },
  580. handlePrevStep() {
  581. // 处理上一步操作
  582. this.$emit('prev-step')
  583. },
  584. handleNextStep() {
  585. // 检查卷宗封面、卷内目录和案卷封底是否有文件数据
  586. let missingFiles = []
  587. // 查找各类型的文档
  588. const coverFile = this.proofreadData.find(
  589. (item) => item.documentType === 1
  590. ) // 卷宗封面
  591. const catalogFile = this.proofreadData.find(
  592. (item) => item.documentType === 2
  593. ) // 卷内目录
  594. const bottomFile = this.proofreadData.find(
  595. (item) => item.documentType === 3
  596. ) // 案卷封底
  597. // 检查各文件是否存在且有附件
  598. if (!coverFile || !coverFile.attachmentUrl) {
  599. missingFiles.push('卷宗封面')
  600. }
  601. if (!catalogFile || !catalogFile.attachmentUrl) {
  602. missingFiles.push('卷内目录')
  603. }
  604. if (!bottomFile || !bottomFile.attachmentUrl) {
  605. missingFiles.push('案卷封底')
  606. }
  607. // 如果有缺失的文件,提示用户
  608. if (missingFiles.length > 0) {
  609. this.$message.warning(`以下文件未生成:${missingFiles.join('、')}`)
  610. return
  611. }
  612. // 如果所有文件都已生成,则继续下一步
  613. this.$emit('next-step')
  614. },
  615. handleCancelGenerate() {
  616. // 取消生成
  617. this.generateDialogVisible = false
  618. this.currentGenerateRow = null
  619. this.$nextTick(() => {
  620. if (this.$refs.generateForm) {
  621. this.$refs.generateForm.resetFields()
  622. }
  623. })
  624. },
  625. handleCancelCoverRemark() {
  626. // 取消卷宗封底说明
  627. this.coverRemarkDialogVisible = false
  628. this.currentCoverRemarkRow = null
  629. this.$nextTick(() => {
  630. if (this.$refs.coverRemarkForm) {
  631. this.$refs.coverRemarkForm.resetFields()
  632. }
  633. })
  634. },
  635. async handleConfirmCoverRemark() {
  636. // 确认卷宗封底说明
  637. this.$refs.coverRemarkForm.validate(async (valid) => {
  638. if (!valid) return false
  639. try {
  640. // 准备提交数据
  641. const submitData = {
  642. taskId: this.coverRemarkForm.taskId,
  643. documentType: this.coverRemarkForm.documentType,
  644. remark: this.coverRemarkForm.remark,
  645. }
  646. // 如果有ID,说明是编辑
  647. if (this.coverRemarkForm.id) {
  648. submitData.id = this.coverRemarkForm.id
  649. }
  650. console.log('生成卷宗封底说明数据:', submitData)
  651. // 调用保存文书的API接口(与documentType=1和documentType=2相同的方法)
  652. const response = await saveArchiveDocument(submitData)
  653. if (response && response.success !== false) {
  654. this.$message.success(response.message || '生成成功')
  655. this.coverRemarkDialogVisible = false
  656. this.loadProofreadData() // 重新加载列表
  657. } else {
  658. this.$message.error(response.message || '生成失败')
  659. }
  660. } catch (error) {
  661. console.error('生成卷宗封底说明失败:', error)
  662. this.$message.error(
  663. '生成失败:' + (error.message || '请检查网络连接')
  664. )
  665. }
  666. })
  667. },
  668. async handleConfirmGenerate() {
  669. // 确认生成
  670. this.$refs.generateForm.validate(async (valid) => {
  671. if (!valid) return false
  672. try {
  673. // 准备提交数据
  674. const submitData = {
  675. taskId: this.generateForm.taskId,
  676. documentType: this.generateForm.documentType,
  677. retentionPeriod: this.generateForm.retentionPeriod,
  678. archiveNo: this.generateForm.archiveNo,
  679. }
  680. // 如果有ID,说明是编辑
  681. if (this.generateForm.id) {
  682. submitData.id = this.generateForm.id
  683. }
  684. console.log('生成文书数据:', submitData)
  685. // 调用生成文书的API接口
  686. const response = await saveArchiveDocument(submitData)
  687. if (response && response.success !== false) {
  688. this.$message.success(response.message || '生成成功')
  689. this.generateDialogVisible = false
  690. this.loadProofreadData() // 重新加载列表
  691. } else {
  692. this.$message.error(response.message || '生成失败')
  693. }
  694. } catch (error) {
  695. console.error('生成文书失败:', error)
  696. this.$message.error(
  697. '生成失败:' + (error.message || '请检查网络连接')
  698. )
  699. }
  700. })
  701. },
  702. },
  703. }
  704. </script>
  705. <style scoped lang="scss"></style>