auditNoticeTab.vue 49 KB

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