auditDocumentsMain.vue 49 KB

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