auditNoticeTab.vue 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. <template>
  2. <div class="catalog-manage">
  3. <div class="documents-layout">
  4. <!--成本审核管理-任务详情-监审文书 -->
  5. <!-- 左侧文书类型列表 -->
  6. <div class="documents-type-list">
  7. <h3>监审文书类型:</h3>
  8. <div
  9. v-for="type in documentData.documentTypes"
  10. :key="type.id"
  11. class="type-item"
  12. :class="{ active: activeDocumentTypeId === type.id }"
  13. @click="handleDocumentTypeClick(type)"
  14. >
  15. {{ type.documentName }}
  16. </div>
  17. </div>
  18. <!-- 右侧文书列表表格 -->
  19. <div class="documents-content">
  20. <!-- <div class="operation-bar">
  21. <el-button
  22. plain
  23. type="success"
  24. icon="el-icon-circle-plus"
  25. :disabled="isView"
  26. @click="handleGenerateDocument"
  27. >
  28. 生成文书
  29. </el-button>
  30. </div> -->
  31. <CostAuditTable
  32. :table-data="documentData.list"
  33. :columns="documentData.documentColumns"
  34. :show-index="true"
  35. :show-pagination="true"
  36. :show-action-column="true"
  37. :pagination="documentData.pagination"
  38. @pagination-change="handlePaginationChange"
  39. >
  40. <template #documentId="{ row }">
  41. {{ getDocumenType(row) }}
  42. </template>
  43. <template #enterpriseId="{ row }">
  44. {{ getEnterpriseName(row) }}
  45. </template>
  46. <template #generateTime="{ row }">
  47. <div>
  48. {{ row.generateTime ? row.generateTime.split(' ')[0] : '' }}
  49. </div>
  50. <div>
  51. {{ row.generateTime ? row.generateTime.split(' ')[1] : '' }}
  52. </div>
  53. </template>
  54. <template #scanDocumentUrl="scope">
  55. <el-button
  56. v-if="!isView && getDocumenType(scope.row).includes('送达回证')"
  57. type="text"
  58. size="mini"
  59. :disabled="isView"
  60. @click="handleUploadScan(scope.row, 'scanDocumentUrl')"
  61. >
  62. 上传附件
  63. </el-button>
  64. <el-button
  65. type="text"
  66. size="mini"
  67. @click="
  68. handleViewScan(scope.row.scanDocumentUrl, 'scanDocumentUrl')
  69. "
  70. >
  71. 查看附件
  72. </el-button>
  73. </template>
  74. <template #feedbackDocumentUrl="scope">
  75. <!-- <el-button
  76. type="text"
  77. size="mini"
  78. :disabled="isView"
  79. @click="handleUploadScan(scope.row, 'feedbackDocumentUrl')"
  80. >
  81. 上传附件
  82. </el-button> -->
  83. <div v-if="getDocumenType(scope.row).includes('送达回证')">
  84. <el-button
  85. v-if="scope.row.feedbackDocumentUrl"
  86. type="text"
  87. size="mini"
  88. @click="
  89. handleViewScan(
  90. scope.row.feedbackDocumentUrl,
  91. 'feedbackDocumentUrl'
  92. )
  93. "
  94. >
  95. 查看附件
  96. </el-button>
  97. </div>
  98. </template>
  99. <template #electronicDocumentUrl="scope">
  100. <!-- 查看 -->
  101. <el-button
  102. type="text"
  103. size="mini"
  104. @click="handleDocView(scope.row)"
  105. >
  106. 查看
  107. </el-button>
  108. <!-- <el-button
  109. type="text"
  110. size="mini"
  111. :disabled="isView"
  112. @click="handleEditDocument(scope.row)"
  113. >
  114. 修改
  115. </el-button> -->
  116. <!-- <el-button
  117. type="text"
  118. size="mini"
  119. :disabled="isView"
  120. @click="handleSignDocument(scope.row)"
  121. >
  122. 签章
  123. </el-button> -->
  124. <!-- <el-button
  125. type="text"
  126. size="mini"
  127. :disabled="isView"
  128. @click="handleDeleteDocument(scope.row)"
  129. >
  130. 删除
  131. </el-button> -->
  132. <el-button
  133. type="text"
  134. size="mini"
  135. @click="handleDownloadDocument(scope.row)"
  136. >
  137. 下载
  138. </el-button>
  139. </template>
  140. </CostAuditTable>
  141. </div>
  142. </div>
  143. <!-- <div style="margin-top: 20px; font-size: 14px" class="table-description">
  144. 说明:此处只能生成各被监审单位的《成本监审通知书》和《送达回证》,同时接收或上传被监审单位的反馈的《送达回证》。
  145. </div> -->
  146. <!-- 编辑监审通知书 -->
  147. <CostAuditDialog
  148. :title="documentDialogTitle"
  149. :visible="documentDialogVisible"
  150. :width="dialogWidth"
  151. :close-on-click-modal="false"
  152. :z-index="9300"
  153. :show-confirm-btn="false"
  154. cancel-text="关闭"
  155. @cancel="handleCancel"
  156. @confirm="handleConfirm"
  157. >
  158. <div class="document-edit-container">
  159. <!-- 左侧:文书参数设置 -->
  160. <div class="document-params">
  161. <h4>文书参数设置:</h4>
  162. <el-form
  163. v-loading="loading.saveDocument"
  164. :model="document"
  165. label-width="170px"
  166. size="small"
  167. :rules="documentRules"
  168. :disabled="true"
  169. >
  170. <el-form-item label="选择模板:" prop="documentId">
  171. <!-- <el-select
  172. v-model="document.documentId"
  173. placeholder="请选择模板"
  174. style="width: 100%"
  175. @change="handleTemplateChange"
  176. >
  177. <el-option
  178. v-for="item in documentData.documentTypes"
  179. :key="item.id"
  180. :label="item.documentName"
  181. :value="item.id"
  182. ></el-option>
  183. </el-select> -->
  184. {{ getDocumenType(document) }}
  185. </el-form-item>
  186. <el-form-item label="通知书文号:" prop="documentNumber">
  187. {{ document.documentNumber }}
  188. <!-- <el-input
  189. v-model="document.documentNumber"
  190. placeholder="请选择通知书文号"
  191. style="width: 74%"
  192. ></el-input>
  193. <el-button
  194. type="primary"
  195. size="small"
  196. class="ml10"
  197. @click="selectClick"
  198. >
  199. 选择文号
  200. </el-button> -->
  201. </el-form-item>
  202. <el-form-item label="被监审单位:" prop="enterpriseId">
  203. <el-select
  204. v-model="document.enterpriseId"
  205. placeholder="请选择被监审单位"
  206. style="width: 100%"
  207. clearable
  208. >
  209. <el-option
  210. v-for="item in allUnits"
  211. :key="item.unitId"
  212. :label="item.unitName"
  213. :value="item.unitId"
  214. ></el-option>
  215. </el-select>
  216. </el-form-item>
  217. <el-form-item label="是否推送被监审单位:" prop="isPushed">
  218. <!-- 是否推送被监审单位 -->
  219. <el-radio-group v-model="document.isPushed">
  220. <el-radio label="1">是</el-radio>
  221. <el-radio label="0">否</el-radio>
  222. </el-radio-group>
  223. </el-form-item>
  224. <!-- <el-form-item label="被监审单位:">
  225. <el-select
  226. v-model="document.enterpriseId"
  227. placeholder="请选择被监审单位"
  228. style="width: 100%"
  229. clearable
  230. >
  231. <el-option
  232. v-for="item in allUnits"
  233. :key="item.unitId"
  234. :label="item.unitName"
  235. :value="item.unitId"
  236. ></el-option>
  237. </el-select>
  238. </el-form-item> -->
  239. <!-- 数据内容区域 -->
  240. <div style="margin-top: 20px">
  241. <h4 style="margin-bottom: 10px">数据内容:</h4>
  242. <el-table
  243. :data="costDocumentTemplateFiles"
  244. style="
  245. width: 100%;
  246. border: 1px solid #dcdfe6;
  247. border-radius: 4px;
  248. "
  249. >
  250. <el-table-column
  251. prop="originalText"
  252. label="数据项"
  253. width="120"
  254. align="center"
  255. show-overflow-tooltip
  256. ></el-table-column>
  257. <el-table-column
  258. prop="labelValue"
  259. label="标签"
  260. width="100"
  261. align="center"
  262. show-overflow-tooltip
  263. ></el-table-column>
  264. <el-table-column
  265. prop="originalText"
  266. label="描述"
  267. min-width="120"
  268. align="center"
  269. show-overflow-tooltip
  270. ></el-table-column>
  271. <el-table-column
  272. prop="dataValue"
  273. label="数据值"
  274. min-width="150"
  275. align="center"
  276. show-overflow-tooltip
  277. >
  278. <template slot-scope="scope">
  279. <el-input
  280. v-if="scope.row.originalText !== '需要提供材料'"
  281. v-model="scope.row.dataValue"
  282. size="small"
  283. placeholder="请输入数据值"
  284. disabled
  285. ></el-input>
  286. <!-- 否则显示上传按钮 -->
  287. <div v-else>
  288. <!-- <el-button
  289. type="primary"
  290. size="small"
  291. @click="handleUploadClick(scope.row)"
  292. >
  293. 上传附件
  294. </el-button> -->
  295. <el-button
  296. type="primary"
  297. size="small"
  298. :disabled="false"
  299. @click="handleViewScan(scope.row.dataValue)"
  300. >
  301. 查看附件
  302. </el-button>
  303. </div>
  304. </template>
  305. </el-table-column>
  306. </el-table>
  307. <div style="margin-top: 10px; font-size: 12px; color: #909399">
  308. 说明:数据内容不可修改,已在监审文书管理中配置完成,数据值为本次监审项目的相关数据。
  309. </div>
  310. </div>
  311. </el-form>
  312. </div>
  313. <!-- 右侧:模板预览和编辑区 -->
  314. <div class="document-preview">
  315. <!-- 预览/修改标签页 -->
  316. <TemplatePreviewEdit
  317. :active-tab="activeTab"
  318. :file-url="fileUrl"
  319. :is-show-edit="false"
  320. />
  321. </div>
  322. </div>
  323. </CostAuditDialog>
  324. <CostAuditDialog
  325. :title="dialogTitle"
  326. :visible="dialogVisible"
  327. :width="dialogWidth"
  328. :close-on-click-modal="false"
  329. @cancel="handleCancel"
  330. @confirm="handleConfirm"
  331. >
  332. <cost-audit-table
  333. :table-data="selectDocumentWhData"
  334. :columns="selectDocumentWhColumns"
  335. :show-selection="true"
  336. :show-pagination="true"
  337. :pagination="selectDocumentWhPagination"
  338. @pagination-change="selectDocumentWhPaginationChange"
  339. @selection-change="selectDocumentWhSelectionChange"
  340. >
  341. <!-- 创建时间自定义单元格 -->
  342. <template #createTime="{ row }">
  343. <div>{{ row.createTime ? row.createTime.split(' ')[0] : '-' }}</div>
  344. <div>{{ row.createTime ? row.createTime.split(' ')[1] : '-' }}</div>
  345. </template>
  346. </cost-audit-table>
  347. </CostAuditDialog>
  348. </div>
  349. </template>
  350. <script>
  351. // import { taskMixin } from './index.js'
  352. import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
  353. import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
  354. import TemplatePreviewEdit from '@/components/costAudit/TemplatePreviewEdit.vue'
  355. import { getAllUnitList } from '@/api/auditEntityManage'
  356. import {
  357. getWhCateList,
  358. queryByDocumentId,
  359. getCostProjectDocumentFile,
  360. } from '@/api/auditReviewDocManage.js'
  361. import { getData } from '@/api/auditDocNoManage.js'
  362. import {
  363. addCostProjectDocument,
  364. updateCostProjectDocument,
  365. deleteCostProjectDocument,
  366. } from '@/api/taskCustomizedRelease.js'
  367. import { dictMixin, regionMixin } from '@/mixins/useDict'
  368. import { uploadFile } from '@/api/file'
  369. export default {
  370. components: { CostAuditTable, CostAuditDialog, TemplatePreviewEdit },
  371. mixins: [dictMixin, regionMixin],
  372. props: {
  373. // 父组件传递的参数
  374. project: {
  375. type: Object,
  376. default: () => {},
  377. },
  378. isView: {
  379. type: Boolean,
  380. default: false,
  381. },
  382. documentData: {
  383. type: Object,
  384. default: () => {},
  385. },
  386. },
  387. data() {
  388. return {
  389. dictData: {
  390. whGenerateType: [],
  391. },
  392. activeDocumentTypeId: '',
  393. document: {
  394. documentId: '',
  395. documentWhId: '',
  396. documentNumber: '',
  397. enterpriseId: [],
  398. dataList: [],
  399. isPushed: '1',
  400. },
  401. loading: {
  402. saveDocument: false,
  403. },
  404. activeView: 'list', // list edit
  405. activeTab: 'preview', // 当前标签页,preview:预览,edit:修改
  406. // 所有单位列表
  407. allUnits: [],
  408. dialogVisible: false,
  409. dialogTitle: '选择文号',
  410. documentDialogVisible: false,
  411. documentDialogTitle: '编辑监审通知书',
  412. dialogWidth: '70%',
  413. fileUrl: '',
  414. selectDocumentWhData: [],
  415. selectDocumentWhPagination: {
  416. currentPage: 1,
  417. pageSize: 10,
  418. total: 0,
  419. },
  420. selectDocumentWhSelection: [],
  421. costDocumentTemplateFiles: [],
  422. documentRules: {
  423. // documentNumber: [
  424. // {
  425. // required: true,
  426. // message: '请选择通知书文号',
  427. // trigger: 'change',
  428. // },
  429. // ],
  430. enterpriseId: [
  431. {
  432. required: true,
  433. message: '请选择被监审单位',
  434. trigger: 'change',
  435. },
  436. ],
  437. documentId: [
  438. {
  439. required: true,
  440. message: '请选择模板',
  441. trigger: 'change',
  442. },
  443. ],
  444. isPushed: [
  445. {
  446. required: true,
  447. message: '请选择否推送被监审单位',
  448. trigger: 'change',
  449. },
  450. ],
  451. },
  452. }
  453. },
  454. computed: {
  455. selectDocumentWhColumns() {
  456. return [
  457. {
  458. prop: 'whType',
  459. label: '文号分类',
  460. showOverflowTooltip: true,
  461. align: 'center',
  462. formatter: (row) => {
  463. let documentName =
  464. this.documentData.documentTypes.find(
  465. (item) => item.id == row.whType
  466. )?.documentName || '-'
  467. return documentName
  468. },
  469. },
  470. {
  471. prop: 'whName',
  472. label: '文号名称',
  473. showOverflowTooltip: true,
  474. align: 'center',
  475. },
  476. {
  477. prop: 'areaCode',
  478. label: '适用区域',
  479. showOverflowTooltip: true,
  480. align: 'center',
  481. formatter: (row) => this.regionNameMap[row.areaCode] || '-',
  482. },
  483. {
  484. prop: 'generateType',
  485. label: '生成类型',
  486. showOverflowTooltip: true,
  487. align: 'center',
  488. width: 120,
  489. formatter: (row) =>
  490. this.getDictName('whGenerateType', row.generateType),
  491. },
  492. ]
  493. },
  494. },
  495. watch: {},
  496. mounted() {
  497. this.loadOpts()
  498. },
  499. methods: {
  500. // 查看监审文书
  501. handleDocView(row) {
  502. this.document = {
  503. ...row,
  504. }
  505. // 从API中获取文件URL
  506. downDocument({
  507. id: row.id,
  508. }).then((res) => {
  509. if (res.state) {
  510. // this.fileUrl = res.value || ''
  511. this.handleViewScan(res.value || '')
  512. } else {
  513. this.$message.error('获取文件URL失败')
  514. }
  515. })
  516. // this.handleTemplateChange()
  517. // this.documentDialogVisible = true
  518. // getCostProjectDocumentFile({
  519. // id: row.id,
  520. // }).then((res) => {
  521. // this.costDocumentTemplateFiles = res.value || []
  522. // })
  523. },
  524. handleDocumentTypeClick(data) {
  525. this.activeDocumentTypeId = data.id
  526. this.$emit('refresh', data)
  527. },
  528. getEnterpriseName(row) {
  529. // 处理enterpriseId,无论是数组还是逗号分隔的字符串
  530. let enterpriseIds = []
  531. if (Array.isArray(row.enterpriseId)) {
  532. enterpriseIds = row.enterpriseId
  533. } else if (typeof row.enterpriseId === 'string') {
  534. // 处理逗号分隔的字符串
  535. enterpriseIds = row.enterpriseId
  536. .split(',')
  537. .map((id) => id.trim())
  538. .filter((id) => id)
  539. } else if (row.enterpriseId) {
  540. // 处理其他可能的非空值
  541. enterpriseIds = [row.enterpriseId]
  542. }
  543. if (enterpriseIds.length > 0) {
  544. // 返回多个企业名称,用逗号分隔
  545. return enterpriseIds
  546. .map(
  547. (id) => this.allUnits.find((item) => item.unitId == id)?.unitName
  548. )
  549. .filter((name) => name)
  550. .join(', ')
  551. }
  552. return '-'
  553. },
  554. getDocumenType(row) {
  555. return this.documentData.documentTypes.find(
  556. (item) => item.id == row.documentId
  557. )?.documentName
  558. },
  559. handlePaginationChange({ currentPage, pageSize }) {
  560. this.$emit('paginationChange', { currentPage, pageSize })
  561. },
  562. // 加载选项数据
  563. loadOpts() {
  564. // 加载所有单位列表
  565. getAllUnitList().then((res) => {
  566. this.allUnits = res.value || []
  567. // 过滤掉状态为停用的数据
  568. this.allUnits = this.allUnits.filter((item) => item.status == 1)
  569. })
  570. },
  571. // 生成文书
  572. handleGenerateDocument() {
  573. this.documentDialogVisible = true
  574. this.activeView = 'form'
  575. this.document = {
  576. documentId: '',
  577. documentWhId: '',
  578. documentNumber: '',
  579. enterpriseId: [],
  580. isPushed: '1', // 默认设置为'1'(是)
  581. }
  582. if (this.activeDocumentTypeId) {
  583. this.document.documentId = this.activeDocumentTypeId
  584. }
  585. this.costProjectDocumentFiles = []
  586. },
  587. selectClick() {
  588. this.dialogVisible = true
  589. this.activeView = 'table'
  590. this.getWhListData()
  591. },
  592. getWhListData() {
  593. getData({
  594. pageNum: this.selectDocumentWhPagination.currentPage,
  595. pageSize: this.selectDocumentWhPagination.pageSize,
  596. whType: this.document.documentId,
  597. }).then((res) => {
  598. this.selectDocumentWhData = res.value.records || []
  599. this.selectDocumentWhPagination.total = res.value.total || 0
  600. })
  601. },
  602. selectDocumentWhPaginationChange({ currentPage, pageSize }) {
  603. this.selectDocumentWhPagination.currentPage = currentPage
  604. this.selectDocumentWhPagination.pageSize = pageSize
  605. },
  606. selectDocumentWhSelectionChange(selection) {
  607. if (selection.length > 1) {
  608. this.$message.error('只能选择一个文号!')
  609. return
  610. } else {
  611. this.selectDocumentWhSelection = selection
  612. }
  613. },
  614. handleTemplateChange() {
  615. this.fileUrl = this.documentData.documentTypes.find(
  616. (item) => item.id === this.document.documentId
  617. ).fileUrl
  618. this.getDocumentData(this.document.documentId)
  619. },
  620. getDocumentData(documentId) {
  621. if (documentId) {
  622. queryByDocumentId({ documentId }).then((res) => {
  623. this.costDocumentTemplateFiles = res.value || []
  624. })
  625. }
  626. },
  627. handleConfirm() {
  628. switch (this.activeView) {
  629. case 'table':
  630. this.handleConfirmSelect()
  631. break
  632. case 'form':
  633. this.handleSaveDocument()
  634. break
  635. default:
  636. break
  637. }
  638. },
  639. handleConfirmSelect() {
  640. if (this.selectDocumentWhSelection.length !== 1) {
  641. this.$message.error('请选择一个文号!')
  642. return
  643. }
  644. this.document.documentNumber = this.selectDocumentWhSelection[0].whNo
  645. this.document.documentWhId = this.selectDocumentWhSelection[0].id // 假设这是正确的字段名
  646. this.dialogVisible = false
  647. this.activeView = 'form'
  648. },
  649. // 保存文档
  650. handleSaveDocument() {
  651. // 验证是否选择了企业
  652. if (
  653. !this.document.enterpriseId ||
  654. this.document.enterpriseId.length === 0
  655. ) {
  656. this.$message.error('请至少选择一个被监审单位!')
  657. return
  658. }
  659. this.loading.saveDocument = true
  660. if (this.document.id) {
  661. updateCostProjectDocument({
  662. id: this.document.id,
  663. // documentAlias: this.document.documentAlias,
  664. documentId: this.document.documentId,
  665. documentNumber: this.document.documentNumber,
  666. documentWhId: this.document.documentWhId,
  667. costProjectDocumentFiles: this.costDocumentTemplateFiles,
  668. isPushed: this.document.isPushed, // 添加isPushed字段
  669. projectId: this.project.projectId,
  670. // electronicDocumentUrl: '',
  671. enterpriseId: this.document.enterpriseId.join(','), // 保存时转换为逗号分隔的字符串
  672. // feedbackDocumentUrl: '',
  673. // feedbackTime: '',
  674. // generateTime: '',
  675. })
  676. .then((res) => {
  677. this.loading.saveDocument = false
  678. this.$message.success('保存成功!')
  679. this.documentDialogVisible = false
  680. this.activeView = ''
  681. this.$emit('refresh', this.project.projectId)
  682. })
  683. .catch((err) => {
  684. this.loading.saveDocument = false
  685. })
  686. } else {
  687. // 处理多选逻辑,如果选择了多个单位,为每个单位创建一个文档记录
  688. const promises = this.document.enterpriseId.map((enterpriseId) => {
  689. return addCostProjectDocument({
  690. // documentAlias: this.document.documentAlias,
  691. projectId: this.project.projectId,
  692. documentId: this.document.documentId,
  693. documentNumber: this.document.documentNumber,
  694. documentWhId: this.document.documentWhId,
  695. costProjectDocumentFiles: this.costDocumentTemplateFiles || [],
  696. enterpriseId: enterpriseId,
  697. // electronicDocumentUrl: '',
  698. // feedbackDocumentUrl: '',
  699. // feedbackTime: '',
  700. // generateTime: '',
  701. isPushed: this.document.isPushed, // 使用isPushed,如果不存在则使用isPushed
  702. // orderNum: 0,
  703. // pushTime: '',
  704. // scanDocumentUrl: '',
  705. })
  706. })
  707. Promise.all(promises)
  708. .then(() => {
  709. this.loading.saveDocument = false
  710. this.$message.success('保存成功!')
  711. this.documentDialogVisible = false
  712. this.activeView = ''
  713. this.$emit('refresh', this.project.projectId)
  714. })
  715. .catch((err) => {
  716. this.loading.saveDocument = false
  717. })
  718. }
  719. },
  720. // 处理取消
  721. handleCancel() {
  722. if (this.activeView === 'form') {
  723. this.documentDialogVisible = false
  724. } else {
  725. this.activeView = 'form'
  726. this.dialogVisible = false
  727. }
  728. },
  729. // 上传扫描件
  730. handleUploadScan(row, type) {
  731. let loading = null
  732. // 第一步:创建文件选择器
  733. const input = document.createElement('input')
  734. input.type = 'file'
  735. input.accept = '.pdf,.doc,.docx,.xls,.xlsx,.csv' // 允许的文件类型
  736. input.onchange = async (event) => {
  737. const file = event.target.files[0]
  738. if (!file) return
  739. try {
  740. // 校验文件大小(50MB)
  741. const maxSize = 50 * 1024 * 1024 // 50MB
  742. if (file.size > maxSize) {
  743. this.$message.error('文件大小不能超过50MB!')
  744. return
  745. }
  746. // 校验文件格式
  747. const allowedFormats = [
  748. '.pdf',
  749. '.doc',
  750. '.docx',
  751. '.xls',
  752. '.xlsx',
  753. 'csv',
  754. ]
  755. const fileName = file.name.toLowerCase()
  756. const isValidFormat = allowedFormats.some((format) =>
  757. fileName.endsWith(format)
  758. )
  759. if (!isValidFormat) {
  760. this.$message.error(
  761. '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
  762. )
  763. return
  764. }
  765. // 显示遮罩层
  766. loading = this.$baseLoading(1, '文件上传中...')
  767. // 第三步:创建FormData并上传文件
  768. const formData = new FormData()
  769. formData.append('file', file)
  770. // 先调用上传API
  771. const uploadRes = await uploadFile('/api/file/v1/upload', formData)
  772. // 第四步:检查上传结果
  773. if (!uploadRes || !uploadRes.value) {
  774. // this.$message.error('文件上传失败!');
  775. return
  776. }
  777. // 第五步:文件上传成功后,再更新数据
  778. const fileInfo = uploadRes.value
  779. // 创建更新数据对象
  780. const updateData = {
  781. ...row,
  782. scanDocumentUrl: fileInfo?.savePath, // 更新扫描件URL
  783. }
  784. // 第六步:调用更新API
  785. await updateCostProjectDocument(updateData)
  786. // 第七步:更新成功,显示提示并刷新
  787. this.$message.success('文件上传成功并更新数据!')
  788. this.$emit('refresh', this.project.projectId) // 通知父组件刷新
  789. } catch (error) {
  790. // 错误处理
  791. console.log('操作失败:' + (error.message || '未知错误'))
  792. // this.$message.error('操作失败:' + (error.message || '未知错误'))
  793. } finally {
  794. // 关闭遮罩层
  795. loading.close()
  796. }
  797. }
  798. // 触发文件选择
  799. input.click()
  800. },
  801. // 查看扫描件
  802. handleViewScan(fileUrl, type) {
  803. if (!fileUrl) {
  804. this.$message.error('暂无文件!')
  805. return
  806. }
  807. let _fileUrl = ''
  808. if (fileUrl.startsWith('http')) {
  809. _fileUrl = fileUrl
  810. } else {
  811. fileUrl = window.context.form + fileUrl
  812. }
  813. // 对文件URL进行Base64编码
  814. const encodedUrl = encodeURIComponent(Base64.encode(_fileUrl))
  815. // 构建 kkFileView 预览URL
  816. // onlinePreview - 在线预览
  817. // onlinePreview?type=pdf - 强制使用PDF模式预览
  818. window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
  819. },
  820. // 编辑文档
  821. handleEditDocument(row) {
  822. this.documentDialogVisible = true
  823. this.activeView = 'form'
  824. this.loadOpts()
  825. // 确保enterpriseId是数组格式,处理可能的逗号分隔字符串
  826. const enterpriseId = row.enterpriseId
  827. ? Array.isArray(row.enterpriseId)
  828. ? row.enterpriseId
  829. : typeof row.enterpriseId === 'string'
  830. ? row.enterpriseId
  831. .split(',')
  832. .map((id) => id.trim())
  833. .filter((id) => id) // 将逗号分隔字符串转换为数组
  834. : [row.enterpriseId]
  835. : []
  836. this.document = {
  837. ...row,
  838. documentId: Number(row.documentId),
  839. enterpriseId,
  840. // 确保isPushed有值,如果row中没有,设置默认值'1'
  841. isPushed: row.isPushed !== undefined ? row.isPushed : '1',
  842. }
  843. this.fileUrl = this.documentData.documentTypes.find(
  844. (item) => item.id === this.document.documentId
  845. ).fileUrl
  846. this.getDocumentData(this.document.documentId)
  847. },
  848. // 签章
  849. handleSignDocument(row) {},
  850. // 删除文档
  851. handleDeleteDocument(row) {
  852. this.$confirm('确定要删除该数据吗?', '提示', {
  853. confirmButtonText: '确定',
  854. cancelButtonText: '取消',
  855. type: 'warning',
  856. }).then(() => {
  857. deleteCostProjectDocument(row.id).then((res) => {
  858. this.$message.success('删除成功!')
  859. this.$emit('refresh', this.project.projectId)
  860. })
  861. })
  862. },
  863. // 下载文档
  864. handleDownloadDocument(row) {},
  865. },
  866. }
  867. </script>
  868. <style lang="scss" scoped>
  869. @import '@/styles/costAudit.scss';
  870. .documents-layout {
  871. display: flex;
  872. margin-bottom: 20px;
  873. }
  874. .documents-type-list {
  875. width: 200px;
  876. border: 1px solid #ebeef5;
  877. border-radius: 5px;
  878. padding: 10px;
  879. margin-right: 20px;
  880. }
  881. .documents-type-list h3 {
  882. margin-bottom: 10px;
  883. font-size: 14px;
  884. font-weight: bold;
  885. }
  886. .type-item {
  887. padding: 5px 0;
  888. cursor: pointer;
  889. font-size: 12px;
  890. }
  891. .type-item:hover {
  892. color: $base-color-default;
  893. }
  894. .type-item.active {
  895. color: $base-color-default;
  896. }
  897. .documents-content {
  898. flex: 1;
  899. }
  900. .generate-btn {
  901. margin-bottom: 10px;
  902. }
  903. .cursor-pointer {
  904. cursor: pointer;
  905. }
  906. .mt10 {
  907. margin-top: 10px;
  908. }
  909. .mt20 {
  910. margin-top: 20px;
  911. }
  912. .document-edit-container {
  913. display: flex;
  914. .document-params {
  915. width: 50%;
  916. }
  917. .document-preview {
  918. width: 50%;
  919. }
  920. }
  921. </style>