auditNoticeTab.vue 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  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 == this.document.documentId
  858. )
  859. let documenName =
  860. document.documentTypeName || document.documentName || ''
  861. this.costDocumentTemplateFiles.forEach((item) => {
  862. if (item.pinyin.includes('BeiJianShenDanWei')) {
  863. item.dataValue = unit.unitName
  864. }
  865. if (item.pinyin.includes('ShouSongDaRen')) {
  866. item.dataValue = unit.contactName
  867. }
  868. if (item.pinyin.includes('BeiJianShenDanWeiBanGongDiDian')) {
  869. item.dataValue = unit.address
  870. }
  871. if (item.pinyin.includes('BeiJianShenDanWeiLianXiRenDianHua')) {
  872. item.dataValue = unit.contactMobile
  873. }
  874. if (item.originalText.includes('需要提供材料') && item.dataValue) {
  875. this.dataUploadUrl = item.dataValue
  876. }
  877. // if (item.pinyin.includes('DiGaoNeiRong') && item.dataValue) {
  878. // // 移除所有HTML标签
  879. // item.dataValue = item.dataValue.replace(/<[^>]+>/g, '')
  880. // }
  881. if (
  882. item.pinyin.includes('ShiJian') &&
  883. (item.dataValue == null || item.dataValue == '')
  884. ) {
  885. // 获取当前时间,格式为YYYY年MM月DD日
  886. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  887. } else if (item.pinyin.includes('ShiJian') && item.dataValue) {
  888. item.dataValue = item.dataValue.includes('年')
  889. ? item.dataValue
  890. : moment(item.dataValue).format('YYYY年MM月DD日')
  891. }
  892. if (item.pinyin.includes('RiQi') && item.dataValue) {
  893. item.dataValue = item.dataValue.includes('年')
  894. ? item.dataValue
  895. : moment(item.dataValue).format('YYYY年MM月DD日')
  896. }
  897. // if (item.pinyin.includes('DiGaoNeiRong') && item.dataValue) {
  898. // // 移除所有HTML标签
  899. // item.dataValue = item.dataValue.replace(/<[^>]+>/g, '')
  900. // }
  901. if (documenName.includes('成本监审通知书')) {
  902. if (item.pinyin.includes('DanWeiMingCheng')) {
  903. item.dataValue = unit.unitName
  904. }
  905. if (item.pinyin.includes('FaRenDaiBiao')) {
  906. item.dataValue = unit?.corporateRepresentative || ''
  907. }
  908. if (
  909. item.pinyin.includes(
  910. 'ChengBenJianShenTongZhiShuChuangJianRiQi'
  911. ) &&
  912. (item.dataValue == null || item.dataValue == '')
  913. ) {
  914. // 获取当前时间
  915. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  916. }
  917. if (item.pinyin.includes('ChuangJianRiQi')) {
  918. // 获取当前时间或使用有效日期
  919. item.dataValue =
  920. item.dataValue && !item.dataValue.includes('年')
  921. ? moment(item.dataValue).format('YYYY年MM月DD日')
  922. : moment(new Date()).format('YYYY年MM月DD日')
  923. }
  924. }
  925. if (documenName.includes('成本监审提取资料登记表')) {
  926. if (
  927. item.pinyin.includes('DengJiBiaoShengChengRiQi') &&
  928. (item.dataValue == null || item.dataValue == '')
  929. ) {
  930. // 获取当前时间,格式为YYYY年MM月DD日
  931. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  932. }
  933. }
  934. if (documenName.includes('成本审核初步意见表')) {
  935. if (
  936. item.pinyin.includes('YiJianBiaoShengChengRiQi') &&
  937. (item.dataValue == null || item.dataValue == '')
  938. ) {
  939. // 获取当前时间,格式为YYYY年MM月DD日
  940. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  941. }
  942. }
  943. if (documenName.includes('政府定价成本监审结论报告')) {
  944. if (
  945. item.pinyin.includes('BaoGaoRiQi') &&
  946. (item.dataValue == null || item.dataValue == '')
  947. ) {
  948. // 获取当前时间,格式为YYYY年MM月DD日
  949. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  950. }
  951. if (item.pinyin.includes('JieLunBaoGaoChuangJianRiQi')) {
  952. // 获取当前时间,格式为YYYY年MM月DD日
  953. item.dataValue = moment(new Date()).format('YYYY年MM月DD日')
  954. }
  955. if (item.pinyin.includes('JianShenRenWuFaBuShiJian')) {
  956. let dataValue = this.resCostDocumentTemplateFiles.find(
  957. (item2) => item2.pinyin === 'JianShenRenWuFaBuShiJian'
  958. ).dataValue
  959. item.dataValue = !dataValue.includes('年')
  960. ? moment(dataValue).format('YYYY年MM月DD日')
  961. : dataValue
  962. }
  963. if (
  964. item.pinyin.includes(
  965. 'ChengBenJianShenTongZhiShuShengChengShiJian'
  966. )
  967. ) {
  968. let dataValue = this.resCostDocumentTemplateFiles.find(
  969. (item2) =>
  970. item2.pinyin === 'ChengBenJianShenTongZhiShuShengChengShiJian'
  971. ).dataValue
  972. item.dataValue = !dataValue.includes('年')
  973. ? moment(dataValue).format('YYYY年MM月DD日')
  974. : dataValue
  975. }
  976. if (item.pinyin.includes('ChengBenZiLiaoShangBaoShiJian')) {
  977. let dataValue = this.resCostDocumentTemplateFiles.find(
  978. (item2) => item2.pinyin === 'ChengBenZiLiaoShangBaoShiJian'
  979. ).dataValue
  980. item.dataValue = !dataValue.includes('年')
  981. ? moment(dataValue).format('YYYY年MM月DD日')
  982. : dataValue
  983. }
  984. }
  985. if (documenName.includes('成本审核初步意见告知书')) {
  986. if (
  987. item.pinyin.includes(
  988. 'ChengBenJianShenTongZhiShuChuangJianShiJian'
  989. ) &&
  990. item.dataValue
  991. ) {
  992. // 获取当前时间,格式为YYYY年MM月DD日
  993. item.dataValue = !item.dataValue.includes('年')
  994. ? moment(item.dataValue).format('YYYY年MM月DD日')
  995. : item.dataValue
  996. }
  997. }
  998. // 回显文号
  999. // 获取选中的文号信息
  1000. const selectedDocument = this.selectDocumentWhSelection[0]
  1001. if (selectedDocument) {
  1002. if (
  1003. item.pinyin.includes('WenHao') ||
  1004. item.pinyin.includes('WenJianHao')
  1005. ) {
  1006. item.dataValue = selectedDocument.whNo
  1007. }
  1008. if (item.pinyin.includes('SongDaWenShuMingCheng')) {
  1009. item.dataValue = selectedDocument.whName
  1010. }
  1011. }
  1012. })
  1013. },
  1014. getDocumentData() {
  1015. if (this.document.id === null || this.document.id === '') {
  1016. queryByDocumentIdandWhereValue({
  1017. documentId: this.document.documentId,
  1018. whereValue: this.project.projectId,
  1019. unitId: this.document.enterpriseId,
  1020. // projectId: this.project.projectId,
  1021. }).then((res) => {
  1022. this.formatDaValue(res)
  1023. })
  1024. } else {
  1025. getCostProjectDocumentFile({
  1026. // documentId: this.document.documentId,
  1027. // whereValue: this.project.projectId,
  1028. id: this.document.id,
  1029. }).then((res) => {
  1030. this.formatDaValue(res)
  1031. })
  1032. }
  1033. },
  1034. handleConfirm() {
  1035. switch (this.activeView) {
  1036. case 'table':
  1037. this.handleConfirmSelect()
  1038. break
  1039. case 'form':
  1040. this.handleSaveDocument()
  1041. break
  1042. default:
  1043. break
  1044. }
  1045. },
  1046. handleConfirmSelect() {
  1047. if (this.selectDocumentWhSelection.length !== 1) {
  1048. this.$message.error('请选择一个文号!')
  1049. return
  1050. }
  1051. const selectedDocument = this.selectDocumentWhSelection[0]
  1052. this.document.documentNumber = selectedDocument.whNo
  1053. this.document.documentWhId = selectedDocument.id
  1054. this.costDocumentTemplateFiles.forEach((item) => {
  1055. if (
  1056. item.pinyin.includes('WenHao') ||
  1057. item.pinyin.includes('WenJianHao')
  1058. ) {
  1059. item.dataValue = selectedDocument.whNo
  1060. }
  1061. if (item.pinyin.includes('SongDaWenShuMingCheng')) {
  1062. item.dataValue = selectedDocument.whName
  1063. }
  1064. })
  1065. this.dialogVisible = false
  1066. this.activeView = 'form'
  1067. },
  1068. handleEnterpriseChange() {
  1069. if (this.document.enterpriseId) {
  1070. const unit = this.allUnits.find(
  1071. (item) => item.unitId === this.document.enterpriseId
  1072. )
  1073. this.costDocumentTemplateFiles.forEach((item) => {
  1074. if (item.pinyin.includes('BeiJianShenDanWei')) {
  1075. item.dataValue = unit.unitName
  1076. }
  1077. if (item.pinyin.includes('ShouSongDaRen')) {
  1078. item.dataValue = unit.contactName
  1079. }
  1080. if (item.pinyin.includes('BeiJianShenDanWeiBanGongDiDian')) {
  1081. item.dataValue = unit.address
  1082. }
  1083. if (item.pinyin.includes('BeiJianShenDanWeiLianXiRenDianHua')) {
  1084. item.dataValue = unit.contactMobile
  1085. }
  1086. })
  1087. }
  1088. },
  1089. handleSaveDocument() {
  1090. this.$refs.documentForm.validate((valid) => {
  1091. if (!valid) {
  1092. this.$message.error('请填写必填项!')
  1093. return false
  1094. }
  1095. // 判断this.costDocumentTemplateFiles里面的值是否为空,一次性提示所有为空的值需要填写
  1096. let emptyFields = []
  1097. this.costDocumentTemplateFiles.forEach((item) => {
  1098. if (!item.dataValue && item.originalText !== '需要提供材料') {
  1099. emptyFields.push(item.originalText)
  1100. }
  1101. })
  1102. if (emptyFields.length > 0) {
  1103. this.$message.error(emptyFields.join('、') + '不能为空!')
  1104. return false
  1105. }
  1106. this.loading.saveDocument = true
  1107. if (this.document.id) {
  1108. updateCostProjectDocument({
  1109. ...this.document,
  1110. costProjectDocumentFiles: this.costDocumentTemplateFiles,
  1111. projectId: this.project.projectId,
  1112. electronicDocumentUrl:
  1113. this.document.electronicDocumentUrl || this.fileUrl,
  1114. enterpriseId: this.isMultipleMode
  1115. ? this.document.enterpriseId.join(',')
  1116. : this.document.enterpriseId,
  1117. })
  1118. .then(() => {
  1119. this.loading.saveDocument = false
  1120. this.$message.success('保存成功!')
  1121. this.documentDialogVisible = false
  1122. this.activeView = ''
  1123. this.$emit('refresh', this.project.projectId)
  1124. })
  1125. .catch(() => {
  1126. this.loading.saveDocument = false
  1127. })
  1128. } else {
  1129. addCostProjectDocument({
  1130. ...this.document,
  1131. projectId: this.project.projectId,
  1132. costProjectDocumentFiles: this.costDocumentTemplateFiles || [],
  1133. enterpriseId: this.isMultipleMode
  1134. ? this.document.enterpriseId.join(',')
  1135. : this.document.enterpriseId,
  1136. electronicDocumentUrl: this.fileUrl,
  1137. })
  1138. .then(() => {
  1139. this.loading.saveDocument = false
  1140. this.$message.success('保存成功!')
  1141. this.documentDialogVisible = false
  1142. this.activeView = ''
  1143. this.$emit('refresh', this.project.projectId)
  1144. })
  1145. .catch(() => {
  1146. this.loading.saveDocument = false
  1147. })
  1148. }
  1149. })
  1150. },
  1151. handleCancel() {
  1152. if (this.activeView === 'form') {
  1153. this.documentDialogVisible = false
  1154. } else {
  1155. this.activeView = 'form'
  1156. this.dialogVisible = false
  1157. }
  1158. },
  1159. handleUploadScan(row) {
  1160. let loading = null
  1161. const input = document.createElement('input')
  1162. input.type = 'file'
  1163. input.accept = '.pdf,.doc,.docx,.xls,.xlsx,.csv'
  1164. input.onchange = async (event) => {
  1165. const file = event.target.files[0]
  1166. if (!file) return
  1167. try {
  1168. const maxSize = 50 * 1024 * 1024
  1169. if (file.size > maxSize) {
  1170. this.$message.error('文件大小不能超过50MB!')
  1171. return
  1172. }
  1173. const allowedFormats = [
  1174. '.pdf',
  1175. '.doc',
  1176. '.docx',
  1177. '.xls',
  1178. '.xlsx',
  1179. 'csv',
  1180. ]
  1181. const fileName = file.name.toLowerCase()
  1182. const isValidFormat = allowedFormats.some((format) =>
  1183. fileName.endsWith(format)
  1184. )
  1185. if (!isValidFormat) {
  1186. this.$message.error(
  1187. '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
  1188. )
  1189. return
  1190. }
  1191. loading = this.$baseLoading(1, '文件上传中...')
  1192. const formData = new FormData()
  1193. formData.append('file', file)
  1194. const uploadRes = await uploadFile('/api/file/v1/upload', formData)
  1195. if (!uploadRes || !uploadRes.value) {
  1196. return
  1197. }
  1198. const fileInfo = uploadRes.value
  1199. const updateData = {
  1200. id: row.id,
  1201. scanDocumentUrl: fileInfo?.savePath,
  1202. }
  1203. await updateScan(updateData)
  1204. this.$message.success('文件上传并更新成功!')
  1205. this.$emit('refresh', this.project.projectId)
  1206. } catch (error) {
  1207. this.$message.error('操作失败:' + (error.message || '未知错误'))
  1208. } finally {
  1209. loading && loading.close && loading.close()
  1210. }
  1211. }
  1212. input.click()
  1213. },
  1214. handleEditDocument(row) {
  1215. this.documentDialogTitle = '修改监审通知书'
  1216. this.documentDialogVisible = true
  1217. this.activeView = 'form'
  1218. this.loadOpts()
  1219. getCostProjectDocumentDetail({ id: row.id }).then((res) => {
  1220. this.document = {
  1221. ...this.document,
  1222. ...res.value,
  1223. }
  1224. this.document.enterpriseId = this.isMultipleMode
  1225. ? this.document.enterpriseId.split(',')
  1226. : this.document.enterpriseId
  1227. this.fileUrl = this.document.electronicDocumentUrl
  1228. this.getDocumentData()
  1229. })
  1230. },
  1231. handleDeleteDocument(row) {
  1232. this.$confirm('确认删除该监审通知书?', '提示', {
  1233. confirmButtonText: '确定',
  1234. cancelButtonText: '取消',
  1235. type: 'warning',
  1236. })
  1237. .then(() => {
  1238. deleteCostProjectDocument(row.id)
  1239. .then(() => {
  1240. this.$message.success('删除成功!')
  1241. this.$emit('refresh', this.project.projectId)
  1242. })
  1243. .catch(() => {
  1244. this.$message.error('删除失败!')
  1245. })
  1246. })
  1247. .catch(() => {})
  1248. },
  1249. handleDownloadDocument(row) {
  1250. this.$loading({
  1251. lock: true,
  1252. text: '文件下载中...',
  1253. spinner: 'el-icon-loading',
  1254. background: 'rgba(0, 0, 0, 0.7)',
  1255. })
  1256. downDocument({
  1257. id: row.id,
  1258. })
  1259. .then((res) => {
  1260. this.$loading().close()
  1261. if (!res || !res.state) {
  1262. this.$message.error(
  1263. `下载失败:${res?.message || '未获取到文件数据'}`
  1264. )
  1265. return
  1266. }
  1267. const fileUrl = res.value
  1268. if (!fileUrl) {
  1269. this.$message.error('下载失败:未获取到文件URL')
  1270. return
  1271. }
  1272. let fileName = ''
  1273. const urlParts = fileUrl.split('/')
  1274. let urlFileName = urlParts[urlParts.length - 1]
  1275. if (urlFileName.includes('?')) {
  1276. urlFileName = urlFileName.split('?')[0]
  1277. }
  1278. if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
  1279. fileName = urlFileName
  1280. } else {
  1281. fileName =
  1282. row.documentName ||
  1283. `${row.documentName}_${new Date().getTime()}`
  1284. if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
  1285. fileName += '.pdf'
  1286. }
  1287. }
  1288. const link = document.createElement('a')
  1289. link.style.display = 'none'
  1290. link.href = fileUrl
  1291. link.download = fileName
  1292. document.body.appendChild(link)
  1293. link.click()
  1294. document.body.removeChild(link)
  1295. })
  1296. .catch(() => {
  1297. this.$loading().close()
  1298. })
  1299. },
  1300. handleViewScan(fileUrl) {
  1301. if (!fileUrl) {
  1302. this.$message.error('暂无文件!')
  1303. return
  1304. }
  1305. let _fileUrl = ''
  1306. if (fileUrl.startsWith('http')) {
  1307. _fileUrl = fileUrl
  1308. } else {
  1309. _fileUrl = window.context.form + fileUrl
  1310. }
  1311. // 对文件URL进行Base64编码
  1312. const encodedUrl = encodeURIComponent(Base64.encode(_fileUrl))
  1313. window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
  1314. },
  1315. handleUploadClick(row) {
  1316. let loading = null
  1317. const input = document.createElement('input')
  1318. input.type = 'file'
  1319. input.accept = '.pdf,.doc,.docx,.xls,.xlsx,.csv'
  1320. input.onchange = async (event) => {
  1321. const file = event.target.files[0]
  1322. if (!file) return
  1323. try {
  1324. const maxSize = 50 * 1024 * 1024
  1325. if (file.size > maxSize) {
  1326. this.$message.error('文件大小不能超过50MB!')
  1327. return
  1328. }
  1329. const allowedFormats = [
  1330. '.pdf',
  1331. '.doc',
  1332. '.docx',
  1333. '.xls',
  1334. '.xlsx',
  1335. 'csv',
  1336. ]
  1337. const fileName = file.name.toLowerCase()
  1338. const isValidFormat = allowedFormats.some((format) =>
  1339. fileName.endsWith(format)
  1340. )
  1341. if (!isValidFormat) {
  1342. this.$message.error(
  1343. '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
  1344. )
  1345. return
  1346. }
  1347. loading = this.$baseLoading(1, '文件上传中...')
  1348. const formData = new FormData()
  1349. formData.append('file', file)
  1350. const uploadRes = await uploadFile('/api/file/v1/upload', formData)
  1351. if (!uploadRes || !uploadRes.value) {
  1352. return
  1353. }
  1354. row.dataValue = uploadRes.value.savePath
  1355. this.$message.success('上传成功!')
  1356. } catch (error) {
  1357. this.$message.error('上传失败:' + (error.message || '未知错误'))
  1358. } finally {
  1359. loading && loading.close && loading.close()
  1360. }
  1361. }
  1362. input.click()
  1363. },
  1364. },
  1365. }
  1366. </script>
  1367. <style scoped lang="scss">
  1368. @import '@/styles/costAudit.scss';
  1369. .documents-layout {
  1370. display: flex;
  1371. margin-bottom: 20px;
  1372. flex-wrap: wrap; // 允许在窄屏时换行,左侧列表在上,右侧内容在下
  1373. }
  1374. .documents-type-list {
  1375. // 默认左侧固定宽度,不随容器缩小,避免内容被压缩
  1376. flex: 0 0 240px; // 不增长不收缩,固定240px
  1377. width: 240px;
  1378. min-width: 200px;
  1379. flex-shrink: 0;
  1380. border: 1px solid #ebeef5;
  1381. border-radius: 5px;
  1382. padding: 10px;
  1383. margin-right: 20px;
  1384. }
  1385. .documents-type-list h3 {
  1386. margin-bottom: 10px;
  1387. font-size: 14px;
  1388. font-weight: bold;
  1389. }
  1390. .type-item {
  1391. padding: 5px 0;
  1392. cursor: pointer;
  1393. font-size: 12px;
  1394. }
  1395. .type-item:hover {
  1396. color: $base-color-default;
  1397. }
  1398. .type-item.active {
  1399. color: $base-color-default;
  1400. }
  1401. .documents-content {
  1402. // 右侧区域占据剩余空间,并允许在狭小空间下换行占满
  1403. flex: 1 1 0;
  1404. min-width: 0; // 修复某些浏览器下表格溢出导致的布局问题
  1405. }
  1406. .generate-btn {
  1407. margin-bottom: 10px;
  1408. }
  1409. .cursor-pointer {
  1410. cursor: pointer;
  1411. }
  1412. .mt10 {
  1413. margin-top: 10px;
  1414. }
  1415. .mt20 {
  1416. margin-top: 20px;
  1417. }
  1418. .document-edit-container {
  1419. display: flex;
  1420. .document-params {
  1421. width: 50%;
  1422. }
  1423. .document-preview {
  1424. width: 50%;
  1425. }
  1426. }
  1427. // 响应式:小屏时左侧列表占满一行并堆叠到上方
  1428. @media (max-width: 992px) {
  1429. .documents-type-list {
  1430. flex: 0 0 220px;
  1431. width: 220px;
  1432. }
  1433. }
  1434. @media (max-width: 768px) {
  1435. .documents-type-list {
  1436. flex: 1 1 100%;
  1437. width: 100%;
  1438. min-width: auto;
  1439. margin-right: 0;
  1440. margin-bottom: 12px;
  1441. }
  1442. .documents-content {
  1443. flex: 1 1 100%;
  1444. width: 100%;
  1445. }
  1446. }
  1447. </style>