auditNoticeTab.vue 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498
  1. <template>
  2. <!-- 成本审核管理-任务详情-监审文书 直接复用原 auditNoticeTab 代码 -->
  3. <div class="catalog-manage">
  4. <div class="documents-layout">
  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. v-if="!isView"
  23. plain
  24. type="success"
  25. icon="iconfont-5039297 icon-zengjia1"
  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. {{ row.documentName || 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"
  57. type="text"
  58. size="mini"
  59. @click="handleUploadScan(scope.row, 'scanDocumentUrl')"
  60. >
  61. 上传附件
  62. </el-button>
  63. <el-button
  64. type="text"
  65. size="mini"
  66. @click="handleViewScan(scope.row.scanDocumentUrl)"
  67. >
  68. 查看附件
  69. </el-button>
  70. </template>
  71. <template #feedbackDocumentUrl="scope">
  72. <div v-if="getDocumenType(scope.row).includes('送达回证')">
  73. <!-- <span>
  74. {{ scope.row.feedbackDocumentUrl ? '已回传' : '未回传' }}
  75. </span> -->
  76. <el-button
  77. v-if="scope.row.feedbackDocumentUrl"
  78. type="text"
  79. size="mini"
  80. @click="handleViewScan(scope.row.feedbackDocumentUrl)"
  81. >
  82. 查看附件
  83. </el-button>
  84. </div>
  85. </template>
  86. <template #electronicDocumentUrl="scope">
  87. <el-button
  88. type="text"
  89. size="mini"
  90. @click="handleDocView(scope.row)"
  91. >
  92. 查看
  93. </el-button>
  94. <el-button
  95. v-if="!isView && !getDocumenType(scope.row).includes('通知书')"
  96. type="text"
  97. size="mini"
  98. :disabled="true"
  99. @click="handleEditDocument(scope.row)"
  100. >
  101. 修改
  102. </el-button>
  103. <el-button
  104. v-if="!isView"
  105. type="text"
  106. size="mini"
  107. :disabled="true"
  108. @click="handleDeleteDocument(scope.row)"
  109. >
  110. 删除
  111. </el-button>
  112. <el-button
  113. type="text"
  114. size="mini"
  115. @click="handleDownloadDocument(scope.row)"
  116. >
  117. 下载
  118. </el-button>
  119. </template>
  120. </CostAuditTable>
  121. </div>
  122. </div>
  123. <!-- <div style="margin-top: 20px; font-size: 14px" class="table-description">
  124. 说明:此处只能生成各被监审单位的《成本监审通知书》和《送达回证》,同时接收或上传被监审单位的反馈的《送达回证》。
  125. </div> -->
  126. <!-- 编辑监审通知书 -->
  127. <CostAuditDialog
  128. :title="documentDialogTitle"
  129. :visible="documentDialogVisible"
  130. width="82%"
  131. :close-on-click-modal="false"
  132. @cancel="handleCancel"
  133. @confirm="handleConfirm"
  134. >
  135. <div class="document-edit-container">
  136. <!-- 左侧:文书参数设置 -->
  137. <div class="document-params">
  138. <h4>文书参数设置:</h4>
  139. <el-form
  140. ref="documentForm"
  141. v-loading="loading.saveDocument"
  142. :model="document"
  143. label-width="170px"
  144. size="small"
  145. :rules="documentRules"
  146. >
  147. <el-form-item label="选择模板:" prop="documentId">
  148. <el-select
  149. v-model="document.documentId"
  150. placeholder="请选择模板"
  151. style="width: 100%"
  152. @change="handleTemplateChange"
  153. >
  154. <el-option
  155. v-for="item in documentData.documentTypes"
  156. :key="item.id"
  157. :label="item.documentName"
  158. :value="item.id"
  159. ></el-option>
  160. </el-select>
  161. </el-form-item>
  162. <el-form-item label="通知书文号:" prop="documentNumber">
  163. <el-input
  164. v-model="document.documentNumber"
  165. placeholder="请选择通知书文号"
  166. style="width: 74%"
  167. disabled
  168. ></el-input>
  169. <el-button
  170. type="primary"
  171. size="small"
  172. class="ml10"
  173. @click="selectClick"
  174. >
  175. 选择文号
  176. </el-button>
  177. </el-form-item>
  178. <el-form-item label="被监审单位" prop="enterpriseId">
  179. <div style="display: flex; align-items: center; gap: 15px">
  180. <el-select
  181. v-model="document.enterpriseId"
  182. placeholder="请选择被监审单位"
  183. style="width: 100%"
  184. clearable
  185. :multiple="isMultipleMode"
  186. @change="handleEnterpriseChange"
  187. >
  188. <el-option
  189. v-for="item in allUnits"
  190. :key="item.unitId"
  191. :label="item.unitName"
  192. :value="item.unitId"
  193. ></el-option>
  194. </el-select>
  195. </div>
  196. </el-form-item>
  197. <el-form-item label="是否推送被监审单位:" prop="isPushed">
  198. <el-radio-group v-model="document.isPushed">
  199. <el-radio label="1">是</el-radio>
  200. <el-radio label="0">否</el-radio>
  201. </el-radio-group>
  202. </el-form-item>
  203. <!-- 数据内容区域 -->
  204. <div style="margin-top: 20px">
  205. <h4 style="margin-bottom: 10px">数据内容:</h4>
  206. <el-table
  207. :data="costDocumentTemplateFiles"
  208. style="
  209. width: 100%;
  210. border: 1px solid #dcdfe6;
  211. border-radius: 4px;
  212. "
  213. >
  214. <el-table-column
  215. prop="originalText"
  216. label="数据项"
  217. width="120"
  218. align="center"
  219. show-overflow-tooltip
  220. ></el-table-column>
  221. <el-table-column
  222. prop="originalText"
  223. label="描述"
  224. min-width="120"
  225. align="center"
  226. show-overflow-tooltip
  227. ></el-table-column>
  228. <el-table-column
  229. prop="dataValue"
  230. label="数据值"
  231. min-width="150"
  232. align="center"
  233. show-overflow-tooltip
  234. >
  235. <template slot-scope="scope">
  236. <div v-if="scope.row.originalText !== '需要提供材料'">
  237. <el-input
  238. v-if="scope.row.originalText.includes('时间')"
  239. v-model="scope.row.dataValue.split(' ')[0]"
  240. size="small"
  241. placeholder="请输入数据值"
  242. ></el-input>
  243. <el-input
  244. v-else
  245. v-model="scope.row.dataValue"
  246. size="small"
  247. placeholder="请输入数据值"
  248. ></el-input>
  249. </div>
  250. <div v-else>
  251. <el-button
  252. type="text"
  253. size="small"
  254. @click="handleUploadClick(scope.row)"
  255. >
  256. 上传附件
  257. </el-button>
  258. <el-button
  259. v-if="scope.row.dataValue"
  260. type="text"
  261. size="small"
  262. @click="handleViewScan(scope.row.dataValue)"
  263. >
  264. 查看附件
  265. </el-button>
  266. </div>
  267. </template>
  268. </el-table-column>
  269. </el-table>
  270. <div style="margin-top: 10px; font-size: 12px; color: #909399">
  271. 说明:数据内容可以在此处直接修改,修改后的数据将用于生成监审文书。
  272. </div>
  273. </div>
  274. </el-form>
  275. </div>
  276. <!-- 右侧:模板预览和编辑区 -->
  277. <div class="document-preview">
  278. <TemplatePreviewEdit :active-tab="activeTab" :file-url="fileUrl" />
  279. </div>
  280. </div>
  281. </CostAuditDialog>
  282. <!-- 编辑监审通知书 -->
  283. <CostAuditDialog
  284. :title="documentDialogTitle"
  285. :visible="documentDialogVisible"
  286. :width="dialogWidth"
  287. :close-on-click-modal="false"
  288. :z-index="9300"
  289. :show-confirm-btn="false"
  290. cancel-text="关闭"
  291. @cancel="handleCancel"
  292. @confirm="handleConfirm"
  293. >
  294. <div class="document-edit-container">
  295. <!-- 左侧:文书参数设置 -->
  296. <div class="document-params">
  297. <h4>文书参数设置:</h4>
  298. <el-form
  299. v-loading="loading.saveDocument"
  300. :model="document"
  301. label-width="170px"
  302. size="small"
  303. :rules="documentRules"
  304. :disabled="true"
  305. >
  306. <el-form-item label="选择模板:" prop="documentId">
  307. <!-- <el-select
  308. v-model="document.documentId"
  309. placeholder="请选择模板"
  310. style="width: 100%"
  311. @change="handleTemplateChange"
  312. >
  313. <el-option
  314. v-for="item in documentData.documentTypes"
  315. :key="item.id"
  316. :label="item.documentName"
  317. :value="item.id"
  318. ></el-option>
  319. </el-select> -->
  320. {{ getDocumenType(document) }}
  321. </el-form-item>
  322. <el-form-item label="通知书文号:" prop="documentNumber">
  323. {{ document.documentNumber }}
  324. <!-- <el-input
  325. v-model="document.documentNumber"
  326. placeholder="请选择通知书文号"
  327. style="width: 74%"
  328. ></el-input>
  329. <el-button
  330. type="primary"
  331. size="small"
  332. class="ml10"
  333. @click="selectClick"
  334. >
  335. 选择文号
  336. </el-button> -->
  337. </el-form-item>
  338. <el-form-item label="被监审单位:" prop="enterpriseId">
  339. <el-select
  340. v-model="document.enterpriseId"
  341. placeholder="请选择被监审单位"
  342. style="width: 100%"
  343. clearable
  344. >
  345. <el-option
  346. v-for="item in allUnits"
  347. :key="item.unitId"
  348. :label="item.unitName"
  349. :value="item.unitId"
  350. ></el-option>
  351. </el-select>
  352. </el-form-item>
  353. <el-form-item label="是否推送被监审单位:" prop="isPushed">
  354. <!-- 是否推送被监审单位 -->
  355. <el-radio-group v-model="document.isPushed">
  356. <el-radio label="1">是</el-radio>
  357. <el-radio label="0">否</el-radio>
  358. </el-radio-group>
  359. </el-form-item>
  360. <!-- <el-form-item label="被监审单位:">
  361. <el-select
  362. v-model="document.enterpriseId"
  363. placeholder="请选择被监审单位"
  364. style="width: 100%"
  365. clearable
  366. >
  367. <el-option
  368. v-for="item in allUnits"
  369. :key="item.unitId"
  370. :label="item.unitName"
  371. :value="item.unitId"
  372. ></el-option>
  373. </el-select>
  374. </el-form-item> -->
  375. <!-- 数据内容区域 -->
  376. <div style="margin-top: 20px">
  377. <h4 style="margin-bottom: 10px">数据内容:</h4>
  378. <el-table
  379. :data="costDocumentTemplateFiles"
  380. style="
  381. width: 100%;
  382. border: 1px solid #dcdfe6;
  383. border-radius: 4px;
  384. "
  385. >
  386. <el-table-column
  387. prop="originalText"
  388. label="数据项"
  389. width="120"
  390. align="center"
  391. show-overflow-tooltip
  392. ></el-table-column>
  393. <el-table-column
  394. prop="labelValue"
  395. label="标签"
  396. width="100"
  397. align="center"
  398. show-overflow-tooltip
  399. ></el-table-column>
  400. <el-table-column
  401. prop="originalText"
  402. label="描述"
  403. min-width="120"
  404. align="center"
  405. show-overflow-tooltip
  406. ></el-table-column>
  407. <el-table-column
  408. prop="dataValue"
  409. label="数据值"
  410. min-width="150"
  411. align="center"
  412. show-overflow-tooltip
  413. >
  414. <template slot-scope="scope">
  415. <el-input
  416. v-if="scope.row.originalText !== '需要提供材料'"
  417. v-model="scope.row.dataValue"
  418. size="small"
  419. placeholder="请输入数据值"
  420. disabled
  421. ></el-input>
  422. <!-- 否则显示上传按钮 -->
  423. <div v-else>
  424. <!-- <el-button
  425. type="primary"
  426. size="small"
  427. @click="handleUploadClick(scope.row)"
  428. >
  429. 上传附件
  430. </el-button> -->
  431. <el-button
  432. v-if="scope.row.dataValue"
  433. type="primary"
  434. size="small"
  435. :disabled="false"
  436. @click="handleViewScan(scope.row.dataValue)"
  437. >
  438. 查看附件
  439. </el-button>
  440. </div>
  441. </template>
  442. </el-table-column>
  443. </el-table>
  444. <div style="margin-top: 10px; font-size: 12px; color: #909399">
  445. 说明:数据内容不可修改,已在监审文书管理中配置完成,数据值为本次监审项目的相关数据。
  446. </div>
  447. </div>
  448. </el-form>
  449. </div>
  450. <!-- 右侧:模板预览和编辑区 -->
  451. <div class="document-preview">
  452. <!-- 预览/修改标签页 -->
  453. <TemplatePreviewEdit
  454. :active-tab="activeTab"
  455. :file-url="fileUrl"
  456. :is-show-edit="false"
  457. />
  458. </div>
  459. </div>
  460. </CostAuditDialog>
  461. <CostAuditDialog
  462. :title="dialogTitle"
  463. :visible="dialogVisible"
  464. :width="dialogWidth"
  465. :close-on-click-modal="false"
  466. @cancel="handleCancel"
  467. @confirm="handleConfirm"
  468. >
  469. <cost-audit-table
  470. :table-data="selectDocumentWhData"
  471. :columns="selectDocumentWhColumns"
  472. :show-selection="true"
  473. :show-pagination="true"
  474. :pagination="selectDocumentWhPagination"
  475. @pagination-change="selectDocumentWhPaginationChange"
  476. @selection-change="selectDocumentWhSelectionChange"
  477. >
  478. <template #createTime="{ row }">
  479. <div>{{ row.createTime ? row.createTime.split(' ')[0] : '-' }}</div>
  480. <div>{{ row.createTime ? row.createTime.split(' ')[1] : '-' }}</div>
  481. </template>
  482. </cost-audit-table>
  483. </CostAuditDialog>
  484. </div>
  485. </template>
  486. <script>
  487. import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
  488. import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
  489. import TemplatePreviewEdit from '@/components/costAudit/TemplatePreviewEdit.vue'
  490. import { getAllUnitList } from '@/api/auditEntityManage'
  491. import {
  492. getCostProjectDocumentFile,
  493. queryByDocumentIdandWhereValue,
  494. } from '@/api/auditReviewDocManage.js'
  495. import { getData } from '@/api/auditDocNoManage.js'
  496. import {
  497. addCostProjectDocument,
  498. updateCostProjectDocument,
  499. deleteCostProjectDocument,
  500. getCostProjectDocumentDetail,
  501. updateScan,
  502. downDocument,
  503. } from '@/api/taskCustomizedRelease.js'
  504. import { dictMixin, regionMixin } from '@/mixins/useDict'
  505. import { uploadFile } from '@/api/file'
  506. export default {
  507. components: { CostAuditTable, CostAuditDialog, TemplatePreviewEdit },
  508. mixins: [dictMixin, regionMixin],
  509. props: {
  510. project: {
  511. type: Object,
  512. default: () => {},
  513. },
  514. isView: {
  515. type: Boolean,
  516. default: false,
  517. },
  518. documentData: {
  519. type: Object,
  520. default: () => {},
  521. },
  522. },
  523. data() {
  524. return {
  525. isMultipleMode: false,
  526. dictData: {
  527. whGenerateType: [],
  528. },
  529. activeDocumentTypeId: '',
  530. document: {
  531. createBy: '',
  532. createTime: '',
  533. documentAlias: '',
  534. documentId: '',
  535. documentName: '',
  536. documentNumber: '',
  537. documentType: '',
  538. documentWhId: '',
  539. electronicDocumentUrl: '',
  540. enterpriseId: [],
  541. feedbackDocumentUrl: '',
  542. feedbackTime: '',
  543. generateTime: '',
  544. id: '',
  545. isDeleted: '',
  546. isPushed: '',
  547. orderNum: 0,
  548. pkVal: '',
  549. projectId: '',
  550. pushTime: '',
  551. scanDocumentUrl: '',
  552. updateBy: '',
  553. updateTime: '',
  554. },
  555. loading: {
  556. saveDocument: false,
  557. },
  558. activeView: 'list',
  559. activeTab: 'preview',
  560. allUnits: [],
  561. dialogVisible: false,
  562. dialogTitle: '选择文号',
  563. documentDialogVisible: false,
  564. documentDialogTitle: '查看监审通知书',
  565. dialogWidth: '80%',
  566. fileUrl: '',
  567. selectDocumentWhData: [],
  568. selectDocumentWhPagination: {
  569. currentPage: 1,
  570. pageSize: 10,
  571. total: 0,
  572. },
  573. selectDocumentWhSelection: [],
  574. costDocumentTemplateFiles: [],
  575. documentRules: {
  576. enterpriseId: [
  577. {
  578. required: true,
  579. message: '请选择被监审单位',
  580. trigger: 'change',
  581. },
  582. ],
  583. documentId: [
  584. {
  585. required: true,
  586. message: '请选择模板',
  587. trigger: 'change',
  588. },
  589. ],
  590. isPushed: [
  591. {
  592. required: true,
  593. message: '请选择否推送被监审单位',
  594. trigger: 'change',
  595. },
  596. ],
  597. },
  598. dataUploadUrl: [],
  599. resCostDocumentTemplateFiles: [],
  600. }
  601. },
  602. computed: {
  603. selectDocumentWhColumns() {
  604. return [
  605. {
  606. prop: 'whType',
  607. label: '文号分类',
  608. showOverflowTooltip: true,
  609. align: 'center',
  610. formatter: (row) => {
  611. const documentName =
  612. this.documentData.documentTypes.find(
  613. (item) => item.id == row.whType
  614. )?.documentName || '-'
  615. return documentName
  616. },
  617. },
  618. {
  619. prop: 'whName',
  620. label: '文号名称',
  621. showOverflowTooltip: true,
  622. align: 'center',
  623. },
  624. {
  625. prop: 'areaCode',
  626. label: '适用区域',
  627. showOverflowTooltip: true,
  628. align: 'center',
  629. formatter: (row) => this.regionNameMap[row.areaCode] || '-',
  630. },
  631. {
  632. prop: 'generateType',
  633. label: '生成类型',
  634. showOverflowTooltip: true,
  635. align: 'center',
  636. width: 120,
  637. formatter: (row) =>
  638. this.getDictName('whGenerateType', row.generateType),
  639. },
  640. ]
  641. },
  642. },
  643. watch: {
  644. costDocumentTemplateFiles: {
  645. handler(newVal) {
  646. if (newVal.length > 0) {
  647. this.costDocumentTemplateFiles.forEach((item) => {
  648. if (
  649. item.pinyin.includes('ShiJian') &&
  650. (item.dataValue == null || item.dataValue == '')
  651. ) {
  652. const date = new Date()
  653. const year = date.getFullYear()
  654. const month = String(date.getMonth() + 1).padStart(2, '0')
  655. const day = String(date.getDate()).padStart(2, '0')
  656. item.dataValue = `${year}-${month}-${day}`
  657. }
  658. if (
  659. item.originalText.includes('需要提供材料') &&
  660. item.dataValue
  661. ) {
  662. this.dataUploadUrl = item.dataValue
  663. }
  664. })
  665. }
  666. },
  667. deep: true,
  668. },
  669. },
  670. mounted() {
  671. this.loadOpts()
  672. },
  673. methods: {
  674. // 查看监审文书
  675. handleDocView(row) {
  676. this.document = {
  677. ...row,
  678. }
  679. // 从API中获取文件URL
  680. downDocument({
  681. id: row.id,
  682. }).then((res) => {
  683. if (res.state) {
  684. // this.fileUrl = res.value || ''
  685. this.handleViewScan(res.value || '')
  686. } else {
  687. this.$message.error('获取文件URL失败')
  688. }
  689. })
  690. // this.handleTemplateChange()
  691. // this.documentDialogVisible = true
  692. // getCostProjectDocumentFile({
  693. // id: row.id,
  694. // }).then((res) => {
  695. // this.costDocumentTemplateFiles = res.value || []
  696. // })
  697. },
  698. handleDocumentTypeClick(data) {
  699. this.activeDocumentTypeId = data.id
  700. this.$emit('refresh', data)
  701. },
  702. getEnterpriseName(row) {
  703. let enterpriseIds = []
  704. if (Array.isArray(row.enterpriseId)) {
  705. enterpriseIds = row.enterpriseId
  706. } else if (typeof row.enterpriseId === 'string') {
  707. enterpriseIds = row.enterpriseId
  708. .split(',')
  709. .map((id) => id.trim())
  710. .filter((id) => id)
  711. } else if (row.enterpriseId) {
  712. enterpriseIds = [row.enterpriseId]
  713. }
  714. if (enterpriseIds.length > 0) {
  715. return enterpriseIds
  716. .map(
  717. (id) => this.allUnits.find((item) => item.unitId == id)?.unitName
  718. )
  719. .filter((name) => name)
  720. .join(', ')
  721. }
  722. return '-'
  723. },
  724. getDocumenType(row) {
  725. return this.documentData.documentTypes.find(
  726. (item) => item.id == row.documentId
  727. )?.documentName
  728. },
  729. handlePaginationChange({ currentPage, pageSize }) {
  730. this.$emit('paginationChange', { currentPage, pageSize })
  731. },
  732. loadOpts() {
  733. getAllUnitList().then((res) => {
  734. this.allUnits = res.value || []
  735. this.allUnits = this.allUnits.filter((item) => item.status == 1)
  736. if (this.project.auditedUnitId) {
  737. let auditedUnitIds = []
  738. if (Array.isArray(this.project.auditedUnitId)) {
  739. auditedUnitIds = this.project.auditedUnitId
  740. } else if (
  741. typeof this.project.auditedUnitId === 'string' &&
  742. this.project.auditedUnitId.includes(',')
  743. ) {
  744. auditedUnitIds = this.project.auditedUnitId
  745. .split(',')
  746. .map((id) => id.trim())
  747. } else {
  748. auditedUnitIds = [this.project.auditedUnitId]
  749. }
  750. this.allUnits = this.allUnits.filter((item) =>
  751. auditedUnitIds.includes(item.unitId)
  752. )
  753. }
  754. })
  755. },
  756. handleGenerateDocument() {
  757. this.documentDialogTitle = '添加监审通知书'
  758. this.documentDialogVisible = true
  759. this.activeView = 'form'
  760. this.costDocumentTemplateFiles = []
  761. this.document = {
  762. createBy: '',
  763. createTime: '',
  764. documentAlias: '',
  765. documentId: '',
  766. documentName: '',
  767. documentNumber: '',
  768. documentType: '',
  769. documentWhId: '',
  770. electronicDocumentUrl: '',
  771. enterpriseId: this.isMultipleMode ? [] : '',
  772. feedbackDocumentUrl: '',
  773. feedbackTime: '',
  774. generateTime: '',
  775. id: '',
  776. isDeleted: '',
  777. isPushed: '1',
  778. orderNum: this.documentData.list.length + 1,
  779. pkVal: '',
  780. projectId: '',
  781. pushTime: '',
  782. scanDocumentUrl: '',
  783. updateBy: '',
  784. updateTime: '',
  785. }
  786. this.loadOpts()
  787. if (this.activeDocumentTypeId) {
  788. this.document.documentId = this.activeDocumentTypeId
  789. this.handleTemplateChange()
  790. }
  791. },
  792. getDetail() {
  793. getCostProjectDocumentDetail({
  794. projectId: this.project.projectId,
  795. }).then((res) => {
  796. if (res.value) {
  797. this.document = {
  798. ...this.document,
  799. ...res.value,
  800. }
  801. this.loadOpts()
  802. }
  803. })
  804. },
  805. selectClick() {
  806. this.dialogVisible = true
  807. this.activeView = 'table'
  808. this.getWhListData()
  809. },
  810. getWhListData() {
  811. getData({
  812. page: this.selectDocumentWhPagination.currentPage,
  813. pageSize: this.selectDocumentWhPagination.pageSize,
  814. whType: this.document.documentId,
  815. }).then((res) => {
  816. this.selectDocumentWhData = res.rows || []
  817. this.selectDocumentWhPagination.total = res.total || 0
  818. if (this.selectDocumentWhData.length > 0) {
  819. this.fetchRegionNames(this.selectDocumentWhData, 'areaCode')
  820. }
  821. })
  822. },
  823. selectDocumentWhPaginationChange({ currentPage, pageSize }) {
  824. this.selectDocumentWhPagination.currentPage = currentPage
  825. this.selectDocumentWhPagination.pageSize = pageSize
  826. },
  827. selectDocumentWhSelectionChange(selection) {
  828. if (selection.length > 1) {
  829. this.$message.error('只能选择一个文号!')
  830. return
  831. } else {
  832. this.selectDocumentWhSelection = selection
  833. }
  834. },
  835. handleTemplateChange() {
  836. const data = this.documentData.documentTypes.find(
  837. (item) => item.id === this.document.documentId
  838. )
  839. this.fileUrl = data.fileUrl
  840. this.document.documentName = data.documentName
  841. this.document.documentNumber = ''
  842. this.document.documentWhId = ''
  843. this.getDocumentData()
  844. },
  845. formatDaValue(res) {
  846. this.costDocumentTemplateFiles =
  847. JSON.parse(JSON.stringify(res.value || [])) || []
  848. this.resCostDocumentTemplateFiles =
  849. JSON.parse(JSON.stringify(res.value || [])) || []
  850. let unit = this.allUnits.find(
  851. (item) => item.unitId === this.document.enterpriseId
  852. )
  853. this.costDocumentTemplateFiles = this.costDocumentTemplateFiles.filter(
  854. (row) => row.pinyin !== 'ChengBenXiangMu' && row.pinyin !== 'XingCi'
  855. )
  856. let document = this.documentData.documentTypes.find(
  857. (item) => item.id == row.documentId
  858. )
  859. let documenName = document.documentTypeName || documentName || ''
  860. this.costDocumentTemplateFiles.forEach((item) => {
  861. if (item.pinyin.includes('BeiJianShenDanWei')) {
  862. item.dataValue = unit.unitName
  863. }
  864. if (item.pinyin.includes('ShouSongDaRen')) {
  865. item.dataValue = unit.contactName
  866. }
  867. if (item.pinyin.includes('BeiJianShenDanWeiBanGongDiDian')) {
  868. item.dataValue = unit.address
  869. }
  870. if (item.pinyin.includes('BeiJianShenDanWeiLianXiRenDianHua')) {
  871. item.dataValue = unit.contactMobile
  872. }
  873. if (item.originalText.includes('需要提供材料') && item.dataValue) {
  874. this.dataUploadUrl = item.dataValue
  875. }
  876. if (item.pinyin.includes('DiGaoNeiRong') && item.dataValue) {
  877. // 移除所有HTML标签
  878. item.dataValue = item.dataValue.replace(/<[^>]+>/g, '')
  879. }
  880. if (
  881. item.pinyin.includes('ShiJian') &&
  882. (item.dataValue == null || item.dataValue == '')
  883. ) {
  884. // 获取当前时间,格式为YYYY年MM月DD日
  885. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  886. } else if (item.pinyin.includes('ShiJian') && item.dataValue) {
  887. item.dataValue = item.dataValue.includes('年')
  888. ? item.dataValue
  889. : moment(item.dataValue).format('YYYY年MM月DD日')
  890. }
  891. if (item.pinyin.includes('RiQi') && item.dataValue) {
  892. item.dataValue = item.dataValue.includes('年')
  893. ? item.dataValue
  894. : moment(item.dataValue).format('YYYY年MM月DD日')
  895. }
  896. if (item.pinyin.includes('DiGaoNeiRong') && item.dataValue) {
  897. // 移除所有HTML标签
  898. item.dataValue = item.dataValue.replace(/<[^>]+>/g, '')
  899. }
  900. if (documenName.includes('成本监审通知书')) {
  901. if (item.pinyin.includes('DanWeiMingCheng')) {
  902. item.dataValue = unit.unitName
  903. }
  904. if (item.pinyin.includes('FaRenDaiBiao')) {
  905. item.dataValue = unit?.corporateRepresentative || ''
  906. }
  907. if (
  908. item.pinyin.includes(
  909. 'ChengBenJianShenTongZhiShuChuangJianRiQi'
  910. ) &&
  911. (item.dataValue == null || item.dataValue == '')
  912. ) {
  913. // 获取当前时间
  914. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  915. }
  916. if (item.pinyin.includes('ChuangJianRiQi')) {
  917. // 获取当前时间或使用有效日期
  918. item.dataValue =
  919. item.dataValue && !item.dataValue.includes('年')
  920. ? moment(item.dataValue).format('YYYY年MM月DD日')
  921. : moment(new Date()).format('YYYY年MM月DD日')
  922. }
  923. }
  924. if (documenName.includes('成本监审提取资料登记表')) {
  925. if (
  926. item.pinyin.includes('DengJiBiaoShengChengRiQi') &&
  927. (item.dataValue == null || item.dataValue == '')
  928. ) {
  929. // 获取当前时间,格式为YYYY年MM月DD日
  930. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  931. }
  932. }
  933. if (documenName.includes('成本审核初步意见表')) {
  934. if (
  935. item.pinyin.includes('YiJianBiaoShengChengRiQi') &&
  936. (item.dataValue == null || item.dataValue == '')
  937. ) {
  938. // 获取当前时间,格式为YYYY年MM月DD日
  939. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  940. }
  941. }
  942. if (documenName.includes('政府定价成本监审结论报告')) {
  943. if (
  944. item.pinyin.includes('BaoGaoRiQi') &&
  945. (item.dataValue == null || item.dataValue == '')
  946. ) {
  947. // 获取当前时间,格式为YYYY年MM月DD日
  948. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  949. }
  950. if (item.pinyin.includes('JieLunBaoGaoChuangJianRiQi')) {
  951. // 获取当前时间,格式为YYYY年MM月DD日
  952. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  953. }
  954. if (item.pinyin.includes('JianShenRenWuFaBuShiJian')) {
  955. let dataValue = this.resCostDocumentTemplateFiles.find(
  956. (item2) => item2.pinyin === 'JianShenRenWuFaBuShiJian'
  957. ).dataValue
  958. item.dataValue = !dataValue.includes('年')
  959. ? moment(dataValue).format('YYYY年MM月DD日')
  960. : dataValue
  961. }
  962. if (
  963. item.pinyin.includes(
  964. 'ChengBenJianShenTongZhiShuShengChengShiJian'
  965. )
  966. ) {
  967. let dataValue = this.resCostDocumentTemplateFiles.find(
  968. (item2) =>
  969. item2.pinyin === 'ChengBenJianShenTongZhiShuShengChengShiJian'
  970. ).dataValue
  971. item.dataValue = !dataValue.includes('年')
  972. ? moment(dataValue).format('YYYY年MM月DD日')
  973. : dataValue
  974. }
  975. if (item.pinyin.includes('ChengBenZiLiaoShangBaoShiJian')) {
  976. let dataValue = this.resCostDocumentTemplateFiles.find(
  977. (item2) => item2.pinyin === 'ChengBenZiLiaoShangBaoShiJian'
  978. ).dataValue
  979. item.dataValue = !dataValue.includes('年')
  980. ? moment(dataValue).format('YYYY年MM月DD日')
  981. : dataValue
  982. }
  983. }
  984. if (documenName.includes('成本审核初步意见告知书')) {
  985. if (
  986. item.pinyin.includes(
  987. 'ChengBenJianShenTongZhiShuChuangJianShiJian'
  988. ) &&
  989. item.dataValue
  990. ) {
  991. // 获取当前时间,格式为YYYY年MM月DD日
  992. item.dataValue = !item.dataValue.includes('年')
  993. ? moment(item.dataValue).format('YYYY年MM月DD日')
  994. : item.dataValue
  995. }
  996. }
  997. // 回显文号
  998. // 获取选中的文号信息
  999. const selectedDocument = this.selectDocumentWhSelection[0]
  1000. if (selectedDocument) {
  1001. if (
  1002. item.pinyin.includes('WenHao') ||
  1003. item.pinyin.includes('WenJianHao')
  1004. ) {
  1005. item.dataValue = selectedDocument.whNo
  1006. }
  1007. if (item.pinyin.includes('SongDaWenShuMingCheng')) {
  1008. item.dataValue = selectedDocument.whName
  1009. }
  1010. }
  1011. })
  1012. },
  1013. getDocumentData() {
  1014. if (this.document.id === null || this.document.id === '') {
  1015. queryByDocumentIdandWhereValue({
  1016. documentId: this.document.documentId,
  1017. whereValue: this.project.projectId,
  1018. unitId: this.document.enterpriseId,
  1019. // projectId: this.project.projectId,
  1020. }).then((res) => {
  1021. this.formatDaValue(res)
  1022. })
  1023. } else {
  1024. getCostProjectDocumentFile({
  1025. // documentId: this.document.documentId,
  1026. // whereValue: this.project.projectId,
  1027. id: this.document.id,
  1028. }).then((res) => {
  1029. this.formatDaValue(res)
  1030. })
  1031. }
  1032. },
  1033. handleConfirm() {
  1034. switch (this.activeView) {
  1035. case 'table':
  1036. this.handleConfirmSelect()
  1037. break
  1038. case 'form':
  1039. this.handleSaveDocument()
  1040. break
  1041. default:
  1042. break
  1043. }
  1044. },
  1045. handleConfirmSelect() {
  1046. if (this.selectDocumentWhSelection.length !== 1) {
  1047. this.$message.error('请选择一个文号!')
  1048. return
  1049. }
  1050. const selectedDocument = this.selectDocumentWhSelection[0]
  1051. this.document.documentNumber = selectedDocument.whNo
  1052. this.document.documentWhId = selectedDocument.id
  1053. this.costDocumentTemplateFiles.forEach((item) => {
  1054. if (
  1055. item.pinyin.includes('WenHao') ||
  1056. item.pinyin.includes('WenJianHao')
  1057. ) {
  1058. item.dataValue = selectedDocument.whNo
  1059. }
  1060. if (item.pinyin.includes('SongDaWenShuMingCheng')) {
  1061. item.dataValue = selectedDocument.whName
  1062. }
  1063. })
  1064. this.dialogVisible = false
  1065. this.activeView = 'form'
  1066. },
  1067. handleEnterpriseChange() {
  1068. if (this.document.enterpriseId) {
  1069. const unit = this.allUnits.find(
  1070. (item) => item.unitId === this.document.enterpriseId
  1071. )
  1072. this.costDocumentTemplateFiles.forEach((item) => {
  1073. if (item.pinyin.includes('BeiJianShenDanWei')) {
  1074. item.dataValue = unit.unitName
  1075. }
  1076. if (item.pinyin.includes('ShouSongDaRen')) {
  1077. item.dataValue = unit.contactName
  1078. }
  1079. if (item.pinyin.includes('BeiJianShenDanWeiBanGongDiDian')) {
  1080. item.dataValue = unit.address
  1081. }
  1082. if (item.pinyin.includes('BeiJianShenDanWeiLianXiRenDianHua')) {
  1083. item.dataValue = unit.contactMobile
  1084. }
  1085. })
  1086. }
  1087. },
  1088. handleSaveDocument() {
  1089. this.$refs.documentForm.validate((valid) => {
  1090. if (!valid) {
  1091. this.$message.error('请填写必填项!')
  1092. return false
  1093. }
  1094. // 判断this.costDocumentTemplateFiles里面的值是否为空,一次性提示所有为空的值需要填写
  1095. let emptyFields = []
  1096. this.costDocumentTemplateFiles.forEach((item) => {
  1097. if (!item.dataValue && item.originalText !== '需要提供材料') {
  1098. emptyFields.push(item.originalText)
  1099. }
  1100. })
  1101. if (emptyFields.length > 0) {
  1102. this.$message.error(emptyFields.join('、') + '不能为空!')
  1103. return false
  1104. }
  1105. this.loading.saveDocument = true
  1106. if (this.document.id) {
  1107. updateCostProjectDocument({
  1108. ...this.document,
  1109. costProjectDocumentFiles: this.costDocumentTemplateFiles,
  1110. projectId: this.project.projectId,
  1111. electronicDocumentUrl:
  1112. this.document.electronicDocumentUrl || this.fileUrl,
  1113. enterpriseId: this.isMultipleMode
  1114. ? this.document.enterpriseId.join(',')
  1115. : this.document.enterpriseId,
  1116. })
  1117. .then(() => {
  1118. this.loading.saveDocument = false
  1119. this.$message.success('保存成功!')
  1120. this.documentDialogVisible = false
  1121. this.activeView = ''
  1122. this.$emit('refresh', this.project.projectId)
  1123. })
  1124. .catch(() => {
  1125. this.loading.saveDocument = false
  1126. })
  1127. } else {
  1128. addCostProjectDocument({
  1129. ...this.document,
  1130. projectId: this.project.projectId,
  1131. costProjectDocumentFiles: this.costDocumentTemplateFiles || [],
  1132. enterpriseId: this.isMultipleMode
  1133. ? this.document.enterpriseId.join(',')
  1134. : this.document.enterpriseId,
  1135. electronicDocumentUrl: this.fileUrl,
  1136. })
  1137. .then(() => {
  1138. this.loading.saveDocument = false
  1139. this.$message.success('保存成功!')
  1140. this.documentDialogVisible = false
  1141. this.activeView = ''
  1142. this.$emit('refresh', this.project.projectId)
  1143. })
  1144. .catch(() => {
  1145. this.loading.saveDocument = false
  1146. })
  1147. }
  1148. })
  1149. },
  1150. handleCancel() {
  1151. if (this.activeView === 'form') {
  1152. this.documentDialogVisible = false
  1153. } else {
  1154. this.activeView = 'form'
  1155. this.dialogVisible = false
  1156. }
  1157. },
  1158. handleUploadScan(row) {
  1159. let loading = null
  1160. const input = document.createElement('input')
  1161. input.type = 'file'
  1162. input.accept = '.pdf,.doc,.docx,.xls,.xlsx,.csv'
  1163. input.onchange = async (event) => {
  1164. const file = event.target.files[0]
  1165. if (!file) return
  1166. try {
  1167. const maxSize = 50 * 1024 * 1024
  1168. if (file.size > maxSize) {
  1169. this.$message.error('文件大小不能超过50MB!')
  1170. return
  1171. }
  1172. const allowedFormats = [
  1173. '.pdf',
  1174. '.doc',
  1175. '.docx',
  1176. '.xls',
  1177. '.xlsx',
  1178. 'csv',
  1179. ]
  1180. const fileName = file.name.toLowerCase()
  1181. const isValidFormat = allowedFormats.some((format) =>
  1182. fileName.endsWith(format)
  1183. )
  1184. if (!isValidFormat) {
  1185. this.$message.error(
  1186. '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
  1187. )
  1188. return
  1189. }
  1190. loading = this.$baseLoading(1, '文件上传中...')
  1191. const formData = new FormData()
  1192. formData.append('file', file)
  1193. const uploadRes = await uploadFile('/api/file/v1/upload', formData)
  1194. if (!uploadRes || !uploadRes.value) {
  1195. return
  1196. }
  1197. const fileInfo = uploadRes.value
  1198. const updateData = {
  1199. id: row.id,
  1200. scanDocumentUrl: fileInfo?.savePath,
  1201. }
  1202. await updateScan(updateData)
  1203. this.$message.success('文件上传并更新成功!')
  1204. this.$emit('refresh', this.project.projectId)
  1205. } catch (error) {
  1206. this.$message.error('操作失败:' + (error.message || '未知错误'))
  1207. } finally {
  1208. loading && loading.close && loading.close()
  1209. }
  1210. }
  1211. input.click()
  1212. },
  1213. handleEditDocument(row) {
  1214. this.documentDialogTitle = '修改监审通知书'
  1215. this.documentDialogVisible = true
  1216. this.activeView = 'form'
  1217. this.loadOpts()
  1218. getCostProjectDocumentDetail({ id: row.id }).then((res) => {
  1219. this.document = {
  1220. ...this.document,
  1221. ...res.value,
  1222. }
  1223. this.document.enterpriseId = this.isMultipleMode
  1224. ? this.document.enterpriseId.split(',')
  1225. : this.document.enterpriseId
  1226. this.fileUrl = this.document.electronicDocumentUrl
  1227. this.getDocumentData()
  1228. })
  1229. },
  1230. handleDeleteDocument(row) {
  1231. this.$confirm('确认删除该监审通知书?', '提示', {
  1232. confirmButtonText: '确定',
  1233. cancelButtonText: '取消',
  1234. type: 'warning',
  1235. })
  1236. .then(() => {
  1237. deleteCostProjectDocument(row.id)
  1238. .then(() => {
  1239. this.$message.success('删除成功!')
  1240. this.$emit('refresh', this.project.projectId)
  1241. })
  1242. .catch(() => {
  1243. this.$message.error('删除失败!')
  1244. })
  1245. })
  1246. .catch(() => {})
  1247. },
  1248. handleDownloadDocument(row) {
  1249. this.$loading({
  1250. lock: true,
  1251. text: '文件下载中...',
  1252. spinner: 'el-icon-loading',
  1253. background: 'rgba(0, 0, 0, 0.7)',
  1254. })
  1255. downDocument({
  1256. id: row.id,
  1257. })
  1258. .then((res) => {
  1259. this.$loading().close()
  1260. if (!res || !res.state) {
  1261. this.$message.error(
  1262. `下载失败:${res?.message || '未获取到文件数据'}`
  1263. )
  1264. return
  1265. }
  1266. const fileUrl = res.value
  1267. if (!fileUrl) {
  1268. this.$message.error('下载失败:未获取到文件URL')
  1269. return
  1270. }
  1271. let fileName = ''
  1272. const urlParts = fileUrl.split('/')
  1273. let urlFileName = urlParts[urlParts.length - 1]
  1274. if (urlFileName.includes('?')) {
  1275. urlFileName = urlFileName.split('?')[0]
  1276. }
  1277. if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
  1278. fileName = urlFileName
  1279. } else {
  1280. fileName =
  1281. row.documentName ||
  1282. `${row.documentName}_${new Date().getTime()}`
  1283. if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
  1284. fileName += '.pdf'
  1285. }
  1286. }
  1287. const link = document.createElement('a')
  1288. link.style.display = 'none'
  1289. link.href = fileUrl
  1290. link.download = fileName
  1291. document.body.appendChild(link)
  1292. link.click()
  1293. document.body.removeChild(link)
  1294. })
  1295. .catch(() => {
  1296. this.$loading().close()
  1297. })
  1298. },
  1299. handleViewScan(fileUrl) {
  1300. if (!fileUrl) {
  1301. this.$message.error('暂无文件!')
  1302. return
  1303. }
  1304. let _fileUrl = ''
  1305. if (fileUrl.startsWith('http')) {
  1306. _fileUrl = fileUrl
  1307. } else {
  1308. _fileUrl = window.context.form + fileUrl
  1309. }
  1310. // 对文件URL进行Base64编码
  1311. const encodedUrl = encodeURIComponent(Base64.encode(_fileUrl))
  1312. window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
  1313. },
  1314. handleUploadClick(row) {
  1315. let loading = null
  1316. const input = document.createElement('input')
  1317. input.type = 'file'
  1318. input.accept = '.pdf,.doc,.docx,.xls,.xlsx,.csv'
  1319. input.onchange = async (event) => {
  1320. const file = event.target.files[0]
  1321. if (!file) return
  1322. try {
  1323. const maxSize = 50 * 1024 * 1024
  1324. if (file.size > maxSize) {
  1325. this.$message.error('文件大小不能超过50MB!')
  1326. return
  1327. }
  1328. const allowedFormats = [
  1329. '.pdf',
  1330. '.doc',
  1331. '.docx',
  1332. '.xls',
  1333. '.xlsx',
  1334. 'csv',
  1335. ]
  1336. const fileName = file.name.toLowerCase()
  1337. const isValidFormat = allowedFormats.some((format) =>
  1338. fileName.endsWith(format)
  1339. )
  1340. if (!isValidFormat) {
  1341. this.$message.error(
  1342. '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
  1343. )
  1344. return
  1345. }
  1346. loading = this.$baseLoading(1, '文件上传中...')
  1347. const formData = new FormData()
  1348. formData.append('file', file)
  1349. const uploadRes = await uploadFile('/api/file/v1/upload', formData)
  1350. if (!uploadRes || !uploadRes.value) {
  1351. return
  1352. }
  1353. row.dataValue = uploadRes.value.savePath
  1354. this.$message.success('上传成功!')
  1355. } catch (error) {
  1356. this.$message.error('上传失败:' + (error.message || '未知错误'))
  1357. } finally {
  1358. loading && loading.close && loading.close()
  1359. }
  1360. }
  1361. input.click()
  1362. },
  1363. },
  1364. }
  1365. </script>
  1366. <style scoped lang="scss">
  1367. @import '@/styles/costAudit.scss';
  1368. .documents-layout {
  1369. display: flex;
  1370. margin-bottom: 20px;
  1371. flex-wrap: wrap; // 允许在窄屏时换行,左侧列表在上,右侧内容在下
  1372. }
  1373. .documents-type-list {
  1374. // 默认左侧固定宽度,不随容器缩小,避免内容被压缩
  1375. flex: 0 0 240px; // 不增长不收缩,固定240px
  1376. width: 240px;
  1377. min-width: 200px;
  1378. flex-shrink: 0;
  1379. border: 1px solid #ebeef5;
  1380. border-radius: 5px;
  1381. padding: 10px;
  1382. margin-right: 20px;
  1383. }
  1384. .documents-type-list h3 {
  1385. margin-bottom: 10px;
  1386. font-size: 14px;
  1387. font-weight: bold;
  1388. }
  1389. .type-item {
  1390. padding: 5px 0;
  1391. cursor: pointer;
  1392. font-size: 12px;
  1393. }
  1394. .type-item:hover {
  1395. color: $base-color-default;
  1396. }
  1397. .type-item.active {
  1398. color: $base-color-default;
  1399. }
  1400. .documents-content {
  1401. // 右侧区域占据剩余空间,并允许在狭小空间下换行占满
  1402. flex: 1 1 0;
  1403. min-width: 0; // 修复某些浏览器下表格溢出导致的布局问题
  1404. }
  1405. .generate-btn {
  1406. margin-bottom: 10px;
  1407. }
  1408. .cursor-pointer {
  1409. cursor: pointer;
  1410. }
  1411. .mt10 {
  1412. margin-top: 10px;
  1413. }
  1414. .mt20 {
  1415. margin-top: 20px;
  1416. }
  1417. .document-edit-container {
  1418. display: flex;
  1419. .document-params {
  1420. width: 50%;
  1421. }
  1422. .document-preview {
  1423. width: 50%;
  1424. }
  1425. }
  1426. // 响应式:小屏时左侧列表占满一行并堆叠到上方
  1427. @media (max-width: 992px) {
  1428. .documents-type-list {
  1429. flex: 0 0 220px;
  1430. width: 220px;
  1431. }
  1432. }
  1433. @media (max-width: 768px) {
  1434. .documents-type-list {
  1435. flex: 1 1 100%;
  1436. width: 100%;
  1437. min-width: auto;
  1438. margin-right: 0;
  1439. margin-bottom: 12px;
  1440. }
  1441. .documents-content {
  1442. flex: 1 1 100%;
  1443. width: 100%;
  1444. }
  1445. }
  1446. </style>