ApplyContent.vue 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563
  1. <template>
  2. <div class="apply-content task-detail">
  3. <div class="task-body">
  4. <div class="mb-4 tab-btns">
  5. <el-button
  6. v-for="tab in tabs"
  7. :key="tab.val"
  8. size="medium"
  9. :type="curTab == tab.val ? 'primary' : 'default'"
  10. @click="selectMenu(tab.val)"
  11. >{{ tab.name }}
  12. </el-button>
  13. </div>
  14. <table class="table mb-2">
  15. <colgroup>
  16. <col width="100" />
  17. <col width="240" />
  18. <col />
  19. <col v-if="IS_APPLY && !IS_REBUILD" width="80" />
  20. </colgroup>
  21. <tr>
  22. <th>试卷类型</th>
  23. <th>试卷文件</th>
  24. <th>答题卡</th>
  25. <th v-if="IS_APPLY && !IS_REBUILD">操作</th>
  26. </tr>
  27. <tr v-for="(attachment, index) in paperAttachments" :key="index">
  28. <td>
  29. <span>{{ attachment.name }}卷</span>
  30. <span class="color-gray-2" v-if="attachment.isExposed"
  31. >(已曝光)</span
  32. >
  33. </td>
  34. <template v-if="IS_TIKU_TAB">
  35. <td>
  36. <el-button
  37. v-if="!attachment.isExposed && IS_APPLY"
  38. type="text"
  39. class="btn-primary"
  40. @click="toSelect(attachment)"
  41. >
  42. <i
  43. :class="[
  44. 'icon',
  45. attachment.attachmentId ? 'icon-files-act' : 'icon-files',
  46. ]"
  47. ></i
  48. >{{ attachment.filename || "选择试卷" }}
  49. </el-button>
  50. <el-button
  51. v-else
  52. type="text"
  53. class="btn-primary"
  54. @click="downloadPaper(attachment)"
  55. >
  56. <div
  57. :class="{
  58. 'color-primary':
  59. auditLogCache.paper[attachment.attachmentId],
  60. }"
  61. >
  62. <i
  63. class="icon icon-download mr-1"
  64. v-if="attachment.attachmentId"
  65. ></i>
  66. {{ attachment.filename }}
  67. </div>
  68. </el-button>
  69. </td>
  70. <td>
  71. <template v-if="IS_APPLY">
  72. <el-select
  73. v-model="attachment.cardId"
  74. placeholder="请选择"
  75. style="width: 260px; margin-right: 10px"
  76. >
  77. <el-option
  78. v-if="attachment.cardId"
  79. :value="attachment.cardId"
  80. :label="attachment.cardTitle"
  81. >
  82. </el-option>
  83. </el-select>
  84. <el-button
  85. class="btn-primary"
  86. type="text"
  87. :disabled="!attachment.cardId"
  88. @click="toViewCard(attachment)"
  89. >预览</el-button
  90. >
  91. <el-button
  92. v-if="!IS_REBUILD"
  93. class="btn-primary"
  94. type="text"
  95. :disabled="!attachment.cardId"
  96. @click="toEditCard(attachment)"
  97. >编辑</el-button
  98. >
  99. </template>
  100. <el-button
  101. v-else
  102. type="text"
  103. class="btn-primary"
  104. @click="toViewCard(attachment)"
  105. ><i
  106. :class="{
  107. 'color-primary': auditLogCache.card[attachment.cardId],
  108. }"
  109. >{{ attachment.cardTitle || "预览" }}</i
  110. ></el-button
  111. >
  112. </td>
  113. </template>
  114. <template v-else>
  115. <td>
  116. <el-button
  117. v-if="!attachment.isExposed && IS_APPLY"
  118. type="text"
  119. class="btn-primary"
  120. @click="toUpload(attachment)"
  121. >
  122. <i
  123. :class="[
  124. 'icon',
  125. attachment.attachmentId ? 'icon-files-act' : 'icon-files',
  126. ]"
  127. ></i
  128. >{{
  129. attachment.attachmentId
  130. ? attachment.filename
  131. : "点击上传试卷文件"
  132. }}
  133. </el-button>
  134. <el-button
  135. v-else
  136. type="text"
  137. class="btn-primary"
  138. @click="downloadPaper(attachment)"
  139. >
  140. <div
  141. :class="{
  142. 'color-primary':
  143. auditLogCache.paper[attachment.attachmentId],
  144. }"
  145. >
  146. <i
  147. class="icon icon-download mr-1"
  148. v-if="attachment.attachmentId"
  149. ></i>
  150. {{ attachment.filename }}
  151. </div>
  152. </el-button>
  153. </td>
  154. <td>
  155. <template v-if="IS_APPLY">
  156. <el-select
  157. class="mr-2"
  158. v-model="attachment.cardId"
  159. placeholder="请选择"
  160. style="width: 200px"
  161. filterable
  162. @visible-change="
  163. (visible) => cardOptionOpened(visible, attachment)
  164. "
  165. @change="cardChange(attachment)"
  166. >
  167. <el-option
  168. v-for="item in cards"
  169. :key="item.id"
  170. :value="item.id"
  171. :label="item.title"
  172. :disabled="item.disabled"
  173. >
  174. <span
  175. :class="[
  176. item.type === 'GENERIC'
  177. ? 'color-success'
  178. : 'color-primary',
  179. 'mr-1',
  180. {
  181. 'color-danger': item.used,
  182. },
  183. ]"
  184. >[{{ item.type === "GENERIC" ? "通" : "专" }}]</span
  185. >
  186. {{ item.title }}
  187. </el-option>
  188. </el-select>
  189. <span
  190. v-if="attachment.cardId"
  191. :class="[
  192. attachment.cardType === 'GENERIC'
  193. ? 'color-success'
  194. : 'color-primary',
  195. 'mr-1',
  196. {
  197. 'color-danger': attachment.used,
  198. },
  199. ]"
  200. >[{{ attachment.cardType === "GENERIC" ? "通" : "专" }}]</span
  201. >
  202. <el-button
  203. class="btn-primary"
  204. type="text"
  205. :disabled="!attachment.cardId"
  206. @click="toViewCard(attachment)"
  207. >预览</el-button
  208. >
  209. <template v-if="!IS_REBUILD">
  210. <el-button
  211. class="btn-primary"
  212. type="text"
  213. :disabled="
  214. !attachment.cardId ||
  215. (attachment.cardType === 'GENERIC' &&
  216. attachment.createMethod !== 'STANDARD')
  217. "
  218. @click="toCopyCard(attachment)"
  219. >复制</el-button
  220. >
  221. <el-button
  222. class="btn-primary"
  223. type="text"
  224. :disabled="
  225. !attachment.cardId ||
  226. attachment.cardType === 'GENERIC' ||
  227. !(!attachment.used && attachment.createId === user.id)
  228. "
  229. @click="toEditCard(attachment)"
  230. >编辑</el-button
  231. >
  232. <el-button
  233. class="btn-primary"
  234. type="text"
  235. :disabled="!canCreateCard"
  236. @click="toCreateCard(attachment)"
  237. >新建</el-button
  238. >
  239. </template>
  240. </template>
  241. <el-button
  242. v-else
  243. type="text"
  244. class="btn-primary"
  245. @click="toViewCard(attachment)"
  246. >
  247. <i
  248. :class="{
  249. 'color-primary': auditLogCache.card[attachment.cardId],
  250. }"
  251. >
  252. {{ attachment.cardTitle || "预览" }}
  253. </i>
  254. </el-button>
  255. </td>
  256. </template>
  257. <td v-if="IS_APPLY && !IS_REBUILD" class="text-right">
  258. <el-button
  259. v-if="index === paperAttachments.length - 1"
  260. class="btn-primary btn-icon"
  261. type="text"
  262. icon="el-icon-circle-plus"
  263. @click="addAtachment"
  264. ></el-button>
  265. <el-button
  266. v-if="attachment.canDelete"
  267. class="btn-danger btn-icon"
  268. type="text"
  269. icon="el-icon-remove"
  270. @click="deleteAttachment(index)"
  271. ></el-button>
  272. </td>
  273. </tr>
  274. <tr v-if="!paperAttachments.length">
  275. <td colspan="5">
  276. <p class="tips-info text-center">暂无数据</p>
  277. </td>
  278. </tr>
  279. </table>
  280. <el-form v-if="!IS_REBUILD">
  281. <el-form-item label="单次抽卷卷型数量:" label-width="150">
  282. <el-input-number
  283. v-model="curTaskApply.drawCount"
  284. :min="1"
  285. :max="maxFetchCount"
  286. :step="1"
  287. :controls="false"
  288. step-strictly
  289. :disabled="!IS_APPLY || exposedMode"
  290. ></el-input-number>
  291. <!-- :disabled="!IS_APPLY || exposedMode" -->
  292. </el-form-item>
  293. </el-form>
  294. <h4 class="mb-2">附件<span v-if="IS_APPLY">(最多4张)</span>:</h4>
  295. <div class="image-list">
  296. <div
  297. class="image-item"
  298. v-for="(img, index) in paperConfirmAttachments"
  299. :key="index"
  300. >
  301. <img
  302. :src="img.url"
  303. :alt="img.filename"
  304. title="点击查看大图"
  305. @click="toPreview(index)"
  306. />
  307. <div v-if="IS_APPLY" class="image-delete">
  308. <i
  309. class="el-icon-delete-solid"
  310. @click="deletePaperConfirmAttachment(index)"
  311. ></i>
  312. </div>
  313. </div>
  314. <div
  315. v-if="paperConfirmAttachments.length < 4 && IS_APPLY"
  316. class="image-item image-add"
  317. title="上传附件"
  318. @click="toUploadPaperConfirm"
  319. >
  320. <i class="el-icon-plus"></i>
  321. </div>
  322. </div>
  323. <div
  324. v-if="!IS_APPLY && !paperConfirmAttachments.length"
  325. class="image-list-none"
  326. >
  327. 暂无数据
  328. </div>
  329. <h4 class="mb-2">附件说明:</h4>
  330. <el-input
  331. v-if="IS_APPLY"
  332. class="mb-2"
  333. v-model="curTaskApply.remark"
  334. type="textarea"
  335. resize="none"
  336. :rows="2"
  337. :maxlength="100"
  338. clearable
  339. show-word-limit
  340. placeholder="建议不超过100个字"
  341. ></el-input>
  342. <div class="color-gray-2" v-else>
  343. <p v-if="curTaskApply.remark">{{ curTaskApply.remark }}</p>
  344. <p v-else>暂无</p>
  345. </div>
  346. <!-- 作废 -->
  347. <el-alert
  348. v-if="curTaskApply.taskStatus === 'CANCEL'"
  349. class="mt-1"
  350. :title="`已作废,原因:${curTaskApply.cancelRemark || ''}`"
  351. type="error"
  352. :closable="false"
  353. >
  354. </el-alert>
  355. <!-- 入库申请-审核阶段 -->
  356. <!-- audit history -->
  357. <div
  358. v-if="flowHistoryList.length && curTaskApply.flowStatus !== 'START'"
  359. class="task-audit-history flow-timeline"
  360. >
  361. <h4 class="mb-4">审核记录:</h4>
  362. <el-timeline>
  363. <el-timeline-item
  364. v-for="flow in flowHistoryList"
  365. :key="flow.stepKey"
  366. :type="flow.type"
  367. hide-timestamp
  368. size="large"
  369. placement="top"
  370. :class="{ 'timeline-item-stop': flow.nextIsNewFlow }"
  371. >
  372. <div class="flow-item">
  373. <div class="flow-item-content">
  374. <p v-if="flow.createTime" class="flow-item-time">
  375. {{ flow.createTime | timestampFilter }}
  376. </p>
  377. <h4 class="flow-item-title">{{ flow.approveUserName }}</h4>
  378. <p class="flow-item-desc">
  379. <span
  380. v-if="flow.approveOperation"
  381. :class="{
  382. 'color-danger': flow.approveOperation === 'REJECT',
  383. }"
  384. >{{
  385. flow.approveOperation | flowApproveOperationTypeFilter
  386. }}</span
  387. >
  388. <span>{{ flow.approveRemark }}</span>
  389. </p>
  390. <div
  391. v-if="flow.attachments.length"
  392. class="flow-item-attachment"
  393. >
  394. <span>附件:</span>
  395. <more-btn
  396. v-for="item in flow.attachments"
  397. :key="item.name"
  398. type="text"
  399. class="btn-primary"
  400. :data="`${item.name}卷:${item.filename}`"
  401. :show-count="20"
  402. @click="downloadPaper(item)"
  403. ></more-btn>
  404. </div>
  405. <div
  406. v-if="flow.isApproveSetFlowNextNode && approveUsers.length"
  407. class="flow-item-users"
  408. >
  409. <span>审批人:</span>
  410. <el-tag
  411. v-for="user in approveUsers"
  412. :key="user.id"
  413. size="small"
  414. :disable-transitions="false"
  415. >
  416. {{ user.name }}
  417. </el-tag>
  418. </div>
  419. </div>
  420. <div
  421. v-if="
  422. flow.isApproveSetFlowNextNode &&
  423. ((IS_AUDIT && auditModal.approvePass === 'PASS') ||
  424. curTaskApply.flowStatus === 'REJECT' ||
  425. curTaskApply.flowStatus === 'CANCEL')
  426. "
  427. class="flow-item-action"
  428. >
  429. <el-button
  430. class="user-select"
  431. icon="el-icon-plus"
  432. @click="toSelectNextFlowUser"
  433. ></el-button>
  434. <p v-if="!approveUsers.length" class="tips-info tips-error">
  435. 请选择审核人
  436. </p>
  437. </div>
  438. </div>
  439. </el-timeline-item>
  440. </el-timeline>
  441. </div>
  442. <!-- 入库申请-申请阶段 -->
  443. <div
  444. v-if="flowList.length && curTaskApply.flowStatus === 'START'"
  445. class="task-audit-history flow-timeline"
  446. >
  447. <h4 class="mb-4">流程:</h4>
  448. <el-timeline>
  449. <el-timeline-item
  450. v-for="flow in flowList"
  451. :key="flow.taskKey"
  452. :type="flow.type"
  453. >
  454. <div class="flow-item">
  455. <div class="flow-item-content">
  456. <h4 class="flow-item-title">{{ flow.taskName }}</h4>
  457. <p v-if="flow.approveUserNames" class="flow-item-desc">
  458. {{ flow.approveUserNames }}
  459. </p>
  460. <div
  461. v-if="flow.isApproveSetFlowNextNode && approveUsers.length"
  462. class="flow-item-users"
  463. >
  464. <span>审批人:</span>
  465. <el-tag
  466. v-for="user in approveUsers"
  467. :key="user.id"
  468. size="small"
  469. :disable-transitions="false"
  470. >
  471. {{ user.name }}
  472. </el-tag>
  473. </div>
  474. </div>
  475. <div
  476. v-if="flow.isApproveSetFlowNextNode"
  477. class="flow-item-action"
  478. >
  479. <el-button
  480. class="user-select"
  481. icon="el-icon-plus"
  482. @click="toSelectNextFlowUser"
  483. ></el-button>
  484. <p v-if="!approveUsers.length" class="tips-info tips-error">
  485. 请选择审核人
  486. </p>
  487. </div>
  488. </div>
  489. </el-timeline-item>
  490. </el-timeline>
  491. </div>
  492. <!-- audit -->
  493. <div v-if="IS_AUDIT" class="task-audit">
  494. <el-form
  495. ref="auditModalComp"
  496. :model="auditModal"
  497. :rules="auditRules"
  498. label-width="90px"
  499. >
  500. <el-form-item prop="approvePass" label="审批操作:">
  501. <el-radio-group
  502. v-model="auditModal.approvePass"
  503. @change="approvePassChange"
  504. >
  505. <el-radio
  506. v-for="(val, key) in TASK_AUDIT_RESULT"
  507. :key="key"
  508. :label="key"
  509. >{{ val }}</el-radio
  510. >
  511. </el-radio-group>
  512. </el-form-item>
  513. <el-form-item
  514. v-if="auditModal.approvePass === 'REJECT'"
  515. prop="setup"
  516. label="驳回节点:"
  517. >
  518. <el-select
  519. v-model="auditModal.setup"
  520. placeholder="请选择"
  521. style="width: 100%"
  522. >
  523. <el-option
  524. v-for="item in rejectSetupList"
  525. :key="item.taskKey"
  526. :value="item.setup"
  527. :label="item.name"
  528. >
  529. </el-option>
  530. </el-select>
  531. </el-form-item>
  532. <el-form-item
  533. v-if="auditModal.approvePass !== 'EXCHANGE'"
  534. :key="auditModal.approvePass"
  535. prop="remark"
  536. label="审批意见:"
  537. >
  538. <el-input
  539. class="mb-2"
  540. v-model="auditModal.remark"
  541. type="textarea"
  542. resize="none"
  543. :rows="5"
  544. :maxlength="100"
  545. clearable
  546. show-word-limit
  547. placeholder="建议不超过100个字"
  548. ref="ReasonInput"
  549. ></el-input>
  550. </el-form-item>
  551. <el-form-item
  552. v-if="auditModal.approvePass === 'EXCHANGE'"
  553. prop="userId"
  554. label="审批人:"
  555. >
  556. <el-tag
  557. v-for="user in exchangeUsers"
  558. :key="user.id"
  559. :disable-transitions="false"
  560. size="medium"
  561. >
  562. {{ user.name }}
  563. </el-tag>
  564. <el-button
  565. class="ml-2"
  566. size="mini"
  567. type="primary"
  568. @click="toSelectExchangeUser"
  569. >选择用户</el-button
  570. >
  571. </el-form-item>
  572. </el-form>
  573. </div>
  574. </div>
  575. <div class="task-action">
  576. <el-button
  577. v-if="IS_APPLY"
  578. type="primary"
  579. :disabled="isSubmit"
  580. @click="submit"
  581. >确认提交</el-button
  582. >
  583. <!-- <el-button
  584. v-if="IS_APPLY"
  585. type="primary"
  586. :disabled="isSubmit"
  587. @click="toSave"
  588. >暂存</el-button
  589. > -->
  590. <el-button
  591. v-if="IS_AUDIT"
  592. type="primary"
  593. :disabled="isSubmit"
  594. @click="toAuditSubmit"
  595. >确定</el-button
  596. >
  597. <!-- <el-button
  598. v-if="IS_AUDIT_APPLY"
  599. type="primary"
  600. :disabled="isSubmit"
  601. @click="toAuditApply"
  602. >提交</el-button
  603. > -->
  604. <el-button @click="cancel">取消</el-button>
  605. </div>
  606. <!-- upload-paper-dialog -->
  607. <upload-paper-dialog
  608. :paper-attachment="curAttachment"
  609. :upload-type="curUploadType"
  610. @confirm="uploadConfirm"
  611. ref="UploadPaperDialog"
  612. ></upload-paper-dialog>
  613. <!-- image-preview -->
  614. <simple-image-preview
  615. :cur-image="curImage"
  616. @on-prev="toPrevImage"
  617. @on-next="toNextImage"
  618. ref="SimpleImagePreview"
  619. ></simple-image-preview>
  620. <!-- select-user-dialog -->
  621. <select-user-dialog
  622. v-if="IS_AUDIT || IS_NEED_SELECT_APPROVE_USER"
  623. ref="SelectUserDialog"
  624. :user-limit-count="userLimitCount"
  625. :filter-roles="userFilterRoles"
  626. :users="curSelectedUsers"
  627. @modified="userSelected"
  628. ></select-user-dialog>
  629. <!-- ModifyCard -->
  630. <modify-card ref="ModifyCard" @modified="cardModified"></modify-card>
  631. <!-- SelectTikuPaperDialog -->
  632. <select-tiku-paper-dialog
  633. ref="SelectTikuPaperDialog"
  634. :row="curAttachment"
  635. @confirm="tikuPaperSelected"
  636. ></select-tiku-paper-dialog>
  637. <!-- CardBuildDialog -->
  638. <card-build-dialog
  639. ref="CardBuildDialog"
  640. :presetData="cardBuildPresetData"
  641. @confirm="cardBuildConfirm"
  642. ></card-build-dialog>
  643. </div>
  644. </template>
  645. <script>
  646. import UploadPaperDialog from "./UploadPaperDialog";
  647. import SelectTikuPaperDialog from "./createExamAndPrintTask/SelectTikuPaperDialog.vue";
  648. import CardBuildDialog from "../../card/components/CardBuildDialog.vue";
  649. import {
  650. taskApplyDetail,
  651. updateTaskApply,
  652. taskAuditApply,
  653. cardForSelectList,
  654. savePreviewLog,
  655. } from "../api";
  656. import { attachmentPreview } from "../../login/api";
  657. import SimpleImagePreview from "@/components/SimpleImagePreview";
  658. import SelectUserDialog from "../../base/components/SelectUserDialog";
  659. import ModifyCard from "../../card/components/ModifyCard";
  660. import { TASK_AUDIT_RESULT, COMMON_CARD_RULE_ID } from "@/constants/enumerate";
  661. import {
  662. taskFlowDetail,
  663. taskFlowApproverExchange,
  664. taskFlowNodeInfo,
  665. taskFlowApprover,
  666. flowDetailByFlowId,
  667. } from "../../base/api";
  668. import { copyCard } from "../../card/api";
  669. const initTaskApply = {
  670. examId: "",
  671. examTaskId: "",
  672. category: "",
  673. paperNumber: "",
  674. paperType: "A",
  675. paperAttachmentIds: "",
  676. paperConfirmAttachmentIds: "",
  677. cardId: "",
  678. cardRuleId: "",
  679. makeMethod: "",
  680. remark: "",
  681. courseCode: "",
  682. courseName: "",
  683. drawCount: 1,
  684. exposedPaperType: "",
  685. auditContent: [],
  686. // 流程
  687. flowId: "",
  688. flowStatus: "",
  689. setup: null,
  690. // 工作台任务id
  691. flowTaskId: "",
  692. // 题卡状态
  693. status: "",
  694. // 考务规则
  695. review: false,
  696. includePaper: false,
  697. customCard: false,
  698. // 作废
  699. taskStatus: "",
  700. cancelRemark: "",
  701. };
  702. export default {
  703. name: "apply-content",
  704. components: {
  705. UploadPaperDialog,
  706. SimpleImagePreview,
  707. SelectUserDialog,
  708. ModifyCard,
  709. CardBuildDialog,
  710. SelectTikuPaperDialog,
  711. },
  712. props: {
  713. examTask: {
  714. type: Object,
  715. default() {
  716. return {};
  717. },
  718. },
  719. editType: {
  720. type: String,
  721. default: "",
  722. },
  723. },
  724. data() {
  725. return {
  726. isSubmit: false,
  727. tabs: [
  728. {
  729. name: "上传本地试卷",
  730. val: "upload",
  731. },
  732. {
  733. name: "从题库选择试卷",
  734. val: "tiku",
  735. },
  736. ],
  737. curTab: "upload",
  738. user: {},
  739. curTaskApply: { ...initTaskApply },
  740. paperConfirmAttachmentId: { attachmentId: "", filename: "", url: "" },
  741. paperAttachments: [],
  742. paperConfirmAttachments: [],
  743. curAttachment: {},
  744. curUploadType: "paper",
  745. attachmentLimitCount: 26,
  746. abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
  747. cards: [],
  748. task: {},
  749. reason: "",
  750. TASK_AUDIT_RESULT: { ...TASK_AUDIT_RESULT, EXCHANGE: "转他人审批" },
  751. // audit
  752. flowList: [],
  753. flowInfo: {},
  754. auditModal: {
  755. approvePass: "PASS",
  756. setup: "",
  757. remark: "",
  758. userId: "",
  759. },
  760. auditRules: {
  761. approvePass: [
  762. {
  763. required: true,
  764. },
  765. ],
  766. setup: [
  767. {
  768. required: true,
  769. validator: (rule, value, callback) => {
  770. if (this.auditModal.approvePass === "REJECT" && !value) {
  771. callback(new Error(`请选择要驳回到的节点`));
  772. } else {
  773. callback();
  774. }
  775. },
  776. trigger: "change",
  777. },
  778. ],
  779. remark: [
  780. {
  781. required: false,
  782. validator: (rule, value, callback) => {
  783. if (this.auditModal.approvePass === "REJECT" && !value) {
  784. callback(new Error(`请输入审批意见`));
  785. } else {
  786. callback();
  787. }
  788. },
  789. trigger: "change",
  790. },
  791. ],
  792. userId: [
  793. {
  794. required: true,
  795. message: "请选择审批人",
  796. trigger: "change",
  797. },
  798. ],
  799. },
  800. flowHistoryList: [],
  801. rejectSetupList: [], // 可以驳回的节点
  802. exchangeUsers: [],
  803. selectUserType: "exchange", // exchange:转审,approve:下一节点审核
  804. curSelectedUsers: [],
  805. auditLogCache: { paper: {}, card: {} },
  806. // card-build
  807. cardBuildPresetData: {},
  808. // 选择下一节点审批人
  809. IS_NEED_SELECT_APPROVE_USER: false,
  810. nextFlowTaskResult: {}, //下一节点信息
  811. approveUsers: [],
  812. userLimitCount: 1,
  813. userFilterRoles: [],
  814. // image-preview
  815. curImage: {},
  816. curImageIndex: 0,
  817. };
  818. },
  819. computed: {
  820. IS_APPLY() {
  821. return this.editType
  822. ? this.editType === "APPLY"
  823. : this.curTaskApply.setup === 1 || this.curTaskApply.setup === null;
  824. },
  825. IS_PREVIEW() {
  826. return this.editType
  827. ? this.editType === "PREVIEW"
  828. : this.curTaskApply.setup !== null && this.curTaskApply.setup <= 0;
  829. },
  830. IS_AUDIT() {
  831. const IS_COMMON_AUDIT = this.editType
  832. ? this.editType === "AUDIT"
  833. : this.curTaskApply.setup > 1;
  834. return IS_COMMON_AUDIT;
  835. },
  836. FLOW_IS_OVER() {
  837. return ["END", "FINISH"].includes(this.curTaskApply.flowStatus);
  838. },
  839. IS_TIKU_TAB() {
  840. return this.curTab === "tiku";
  841. },
  842. maxFetchCount() {
  843. return this.paperAttachments.length < 1
  844. ? 1
  845. : this.paperAttachments.length;
  846. },
  847. canCreateCard() {
  848. return (
  849. this.curTaskApply.courseCode &&
  850. this.curTaskApply.examId &&
  851. this.curTaskApply.cardRuleId !== COMMON_CARD_RULE_ID
  852. );
  853. },
  854. exposedMode() {
  855. return !!this.curTaskApply.exposedPaperType;
  856. },
  857. IS_REBUILD() {
  858. return this.curTaskApply.category === "REBUILD";
  859. },
  860. },
  861. mounted() {
  862. this.user = this.$ls.get("user", {});
  863. this.initData();
  864. },
  865. methods: {
  866. async initData() {
  867. const data = await taskApplyDetail(
  868. this.examTask.id,
  869. this.examTask.source
  870. );
  871. this.$emit("info-update", {
  872. setup: data.setup,
  873. semesterName: data.semesterName,
  874. examId: data.examId,
  875. examName: data.examName,
  876. examModel: data.examModel,
  877. });
  878. this.curTaskApply = this.$objAssign(initTaskApply, data || {});
  879. this.curTaskApply.examId =
  880. this.curTaskApply.examId || this.examTask.examId;
  881. this.curTaskApply.examTaskId = this.examTask.id;
  882. this.curTaskApply.courseCode = this.examTask.courseCode;
  883. this.curTaskApply.courseName = this.examTask.courseName;
  884. this.curTaskApply.cardRuleId = this.examTask.cardRuleId;
  885. this.curTaskApply.customCard = this.examTask.customCard;
  886. this.curTaskApply.paperNumber = this.examTask.paperNumber;
  887. this.curTaskApply.auditContent = JSON.parse(
  888. this.curTaskApply.auditContent || "[]"
  889. );
  890. this.curTaskApply.includePaper =
  891. data.printContent.indexOf("PAPER") !== -1;
  892. this.paperAttachments = this.curTaskApply.paperAttachmentIds
  893. ? JSON.parse(this.curTaskApply.paperAttachmentIds)
  894. : [];
  895. if (!this.paperAttachments.length) {
  896. this.addAtachment();
  897. }
  898. const pAttachment = this.paperAttachments.some((item) => !!item.paperId);
  899. if (pAttachment) {
  900. this.curTab = "tiku";
  901. this.curTaskApply.uuid = pAttachment.uuid || this.$randomCode(32);
  902. } else {
  903. this.curTab = "upload";
  904. this.curTaskApply.uuid = this.$randomCode(32);
  905. }
  906. const exposedPaperType = data.exposedPaperType || "";
  907. let exposedPaperTypes = exposedPaperType.split(",");
  908. exposedPaperTypes.sort((a, b) => (a > b ? -1 : 1));
  909. const maxExposedPaperType = exposedPaperTypes[0];
  910. let auditLogCache = { paper: {}, card: {} };
  911. this.paperAttachments.forEach((paper) => {
  912. paper.canDelete = maxExposedPaperType
  913. ? paper.name > maxExposedPaperType
  914. : true;
  915. paper.isExposed = exposedPaperTypes.includes(paper.name);
  916. if (
  917. paper.attachmentId &&
  918. this.curTaskApply.auditContent.includes("PAPER")
  919. )
  920. auditLogCache.paper[paper.attachmentId] = false;
  921. if (paper.cardId && this.curTaskApply.auditContent.includes("CARD"))
  922. auditLogCache.card[paper.cardId] = false;
  923. });
  924. this.auditLogCache = auditLogCache;
  925. this.paperConfirmAttachments = this.curTaskApply.paperConfirmAttachmentIds
  926. ? JSON.parse(this.curTaskApply.paperConfirmAttachmentIds)
  927. : [];
  928. if (this.IS_APPLY) this.getCardList();
  929. // flow
  930. if (this.curTaskApply.flowStatus === "START") {
  931. await this.getFlowList();
  932. } else {
  933. await this.getFlowHistory();
  934. if (!this.IS_PREVIEW && this.curTaskApply.review)
  935. this.getCurFlowNodeInfo();
  936. }
  937. // if (this.IS_AUDIT) this.getCurFlowNodeInfo();
  938. },
  939. async selectMenu(tab) {
  940. if (!this.IS_APPLY) return;
  941. const attachment = this.paperAttachments[0];
  942. if (attachment.cardId || attachment.attachmentId) {
  943. const result = await this.$confirm(
  944. "更改类型会清空已设置数据,确定要更改类型?",
  945. "提示",
  946. {
  947. type: "warning",
  948. }
  949. ).catch(() => {});
  950. if (result !== "confirm") return;
  951. this.paperAttachments = [];
  952. this.addAtachment();
  953. }
  954. this.curTab = tab;
  955. },
  956. async getCardList() {
  957. if (!this.curTaskApply.courseCode || !this.curTaskApply.examId) return;
  958. const data = await cardForSelectList({
  959. courseCode: this.curTaskApply.courseCode,
  960. examId: this.curTaskApply.examId,
  961. paperNumber: this.curTaskApply.paperNumber,
  962. });
  963. this.cards = data || [];
  964. if (this.IS_REBUILD) {
  965. this.cards = this.cards.filter((item) => item.type === "GENERIC");
  966. }
  967. },
  968. async getFlowHistory() {
  969. if (!this.curTaskApply.flowId) return;
  970. const data = await taskFlowDetail(this.curTaskApply.flowId).catch(
  971. () => {}
  972. );
  973. if (!data) return;
  974. const FLOW_STATUS = {
  975. SUBMIT: "success",
  976. APPROVE: "success",
  977. EXCHANGE: "success",
  978. REJECT: "danger",
  979. END: "success",
  980. };
  981. let nextFlowId = "";
  982. this.flowHistoryList = data.tfFlowViewLogResultList.map((item, index) => {
  983. const nextItem = data.tfFlowViewLogResultList[index + 1];
  984. nextFlowId = nextItem ? nextItem.flowId : item.flowId;
  985. item.nextIsNewFlow = nextFlowId !== item.flowId;
  986. item.type = FLOW_STATUS[item.approveOperation];
  987. item.attachments = item.paperAttachmentId
  988. ? JSON.parse(item.paperAttachmentId)
  989. : [];
  990. item.isApproveSetFlowNextNode = false;
  991. return item;
  992. });
  993. const flowIsEnd = data.currFlowTaskResult.taskKey === "end";
  994. this.flowHistoryList.push({
  995. type: flowIsEnd ? "success" : "current",
  996. stepKey: this.$randomCode(),
  997. approveSetup: data.currFlowTaskResult.setup, //审批人节点
  998. approveRemark: data.currFlowTaskResult.taskName, //审批信息
  999. approveOperation: flowIsEnd ? "END" : "",
  1000. approveUserName: data.currFlowTaskResult.approveUserNames, //审批人
  1001. createTime: null,
  1002. nextIsNewFlow: false,
  1003. isApproveSetFlowNextNode: false,
  1004. attachments: [],
  1005. });
  1006. },
  1007. async getFlowList() {
  1008. if (!this.curTaskApply.flowId) return;
  1009. const data = await flowDetailByFlowId(this.curTaskApply.flowId);
  1010. if (!data) return;
  1011. const modelType =
  1012. data.flowTaskResultList[0] && data.flowTaskResultList[0].modelType;
  1013. this.flowInfo = {
  1014. customFlowId: data.id,
  1015. version: data.version,
  1016. };
  1017. const nextFlowNodeIndex = 1;
  1018. this.IS_NEED_SELECT_APPROVE_USER = modelType === "APPROVE_SET";
  1019. const flowList = data.flowTaskResultList || [];
  1020. this.flowList = flowList.map((flow, index) => {
  1021. flow.isApproveSetFlowNextNode =
  1022. this.IS_NEED_SELECT_APPROVE_USER && index === nextFlowNodeIndex;
  1023. return flow;
  1024. });
  1025. if (this.flowList.length) {
  1026. this.flowList[0].type = "success";
  1027. }
  1028. this.nextFlowTaskResult = this.flowList[nextFlowNodeIndex];
  1029. },
  1030. async getCurFlowNodeInfo() {
  1031. const data = await taskFlowNodeInfo(this.curTaskApply.flowTaskId);
  1032. this.rejectSetupList = (data && data.rejectSetupList) || [];
  1033. this.rejectSetupList.forEach((item) => {
  1034. item.name = `【${item.taskName}】${item.approveUserNames}`;
  1035. });
  1036. this.nextFlowTaskResult = data.nextFlowTaskResult;
  1037. // 被打回给命题老师之后,命题老师只能通过。
  1038. if (data.setup === 1 && !this.rejectSetupList.length) {
  1039. this.TASK_AUDIT_RESULT = { PASS: "通过" };
  1040. this.auditModal.approvePass = "PASS";
  1041. }
  1042. // 判断发起人自选,不管approveUserNames有没有值,都可以选择下个审核人员
  1043. const { modelType, taskKey } = this.nextFlowTaskResult;
  1044. this.IS_NEED_SELECT_APPROVE_USER =
  1045. modelType === "APPROVE_SET" && taskKey.toLowerCase() !== "end";
  1046. this.flowHistoryList[
  1047. this.flowHistoryList.length - 1
  1048. ].isApproveSetFlowNextNode = this.IS_NEED_SELECT_APPROVE_USER;
  1049. },
  1050. approvePassChange() {
  1051. this.auditRules.remark[0].required =
  1052. this.auditModal.approvePass === "REJECT";
  1053. },
  1054. addAtachment() {
  1055. if (this.paperAttachments.length >= this.attachmentLimitCount) return;
  1056. const name = this.abc[this.paperAttachments.length];
  1057. const newAttachment = {
  1058. name,
  1059. attachmentId: "",
  1060. filename: "",
  1061. paperId: null,
  1062. uuid: null,
  1063. cardId: "",
  1064. cardType: "",
  1065. createMethod: "",
  1066. cardTitle: "",
  1067. pages: 0,
  1068. canDelete: true,
  1069. isExposed: false,
  1070. used: false,
  1071. createId: null,
  1072. };
  1073. this.paperAttachments.push(newAttachment);
  1074. },
  1075. deleteAttachment(index) {
  1076. if (this.paperAttachments.length <= 1) {
  1077. this.$message.error("试卷类型数量不得少于1");
  1078. return;
  1079. }
  1080. this.paperAttachments.splice(index, 1);
  1081. this.paperAttachments.forEach((item, itemIndex) => {
  1082. item.name = this.abc[itemIndex];
  1083. });
  1084. if (
  1085. this.curTaskApply.drawCount &&
  1086. this.curTaskApply.drawCount > this.paperAttachments.length
  1087. ) {
  1088. this.curTaskApply.drawCount = this.paperAttachments.length;
  1089. }
  1090. },
  1091. toUpload(attachment) {
  1092. this.curUploadType = "paper";
  1093. this.curAttachment = {
  1094. ...attachment,
  1095. };
  1096. this.$refs.UploadPaperDialog.open();
  1097. },
  1098. toUploadPaperConfirm() {
  1099. if (this.paperConfirmAttachments.length >= 4) return;
  1100. this.curUploadType = "paperConfirm";
  1101. this.curAttachment = {
  1102. ...this.paperConfirmAttachmentId,
  1103. };
  1104. this.$refs.UploadPaperDialog.open();
  1105. },
  1106. uploadConfirm(attachment, uploadType) {
  1107. if (uploadType === "paper") {
  1108. const index = this.paperAttachments.findIndex(
  1109. (item) => item.name === attachment.name
  1110. );
  1111. this.paperAttachments.splice(index, 1, { ...attachment });
  1112. } else {
  1113. this.paperConfirmAttachments.push(attachment);
  1114. }
  1115. },
  1116. deletePaperConfirmAttachment(index) {
  1117. this.paperConfirmAttachments.splice(index, 1);
  1118. },
  1119. toViewCard(attachment) {
  1120. this.addPreviewLog(attachment, "card");
  1121. window.open(
  1122. this.getRouterPath({
  1123. name: "CardPreview",
  1124. params: {
  1125. cardId: attachment.cardId,
  1126. },
  1127. })
  1128. );
  1129. },
  1130. async toCopyCard(attachment) {
  1131. this.curAttachment = { ...attachment };
  1132. const newCardId = await copyCard(
  1133. attachment.cardId,
  1134. this.curTaskApply.courseCode
  1135. );
  1136. this.cardModified({ id: newCardId });
  1137. },
  1138. toEditCard(attachment) {
  1139. this.curAttachment = { ...attachment };
  1140. this.$ls.set("prepareTcPCard", {
  1141. id: attachment.cardId,
  1142. examTaskId: this.curTaskApply.examTaskId,
  1143. courseCode: this.curTaskApply.courseCode,
  1144. courseName: this.curTaskApply.courseName,
  1145. makeMethod: this.curTaskApply.makeMethod,
  1146. cardRuleId: this.curTaskApply.cardRuleId,
  1147. type: attachment.cardType,
  1148. createMethod: attachment.createMethod,
  1149. });
  1150. this.$refs.ModifyCard.open();
  1151. },
  1152. async cardModified(data) {
  1153. // data: {id,title}
  1154. if (!data.id) return;
  1155. if (this.IS_TIKU_TAB) {
  1156. const aind = this.paperAttachments.findIndex(
  1157. (item) => item.name === this.curAttachment.name
  1158. );
  1159. this.paperAttachments[aind].cardTitle = data.title;
  1160. return;
  1161. }
  1162. await this.getCardList();
  1163. let card = this.cards.find((item) => item.id === data.id);
  1164. const aind = this.paperAttachments.findIndex(
  1165. (item) => item.name === this.curAttachment.name
  1166. );
  1167. if (aind !== -1 && card) {
  1168. this.paperAttachments[aind].cardId = card.id;
  1169. this.paperAttachments[aind].cardType = card.type;
  1170. this.paperAttachments[aind].createMethod = card.createMethod;
  1171. this.paperAttachments[aind].cardTitle = card.title;
  1172. this.paperAttachments[aind].used = card.used;
  1173. this.paperAttachments[aind].createId = card.createId;
  1174. }
  1175. },
  1176. cardChange(attachment) {
  1177. const card = this.cards.find((item) => item.id === attachment.cardId);
  1178. if (card) {
  1179. attachment.cardType = card.type;
  1180. attachment.createMethod = card.createMethod;
  1181. attachment.cardTitle = card.title;
  1182. attachment.used = card.used;
  1183. attachment.createId = card.createId;
  1184. }
  1185. },
  1186. cardOptionOpened(visible, attachment) {
  1187. if (!visible) return;
  1188. // const selectedCardIds = this.paperAttachments.map((item) => item.cardId);
  1189. // this.cards = this.cards.map((card) => {
  1190. // card.disabled =
  1191. // card.id !== attachment.cardId &&
  1192. // selectedCardIds.includes(card.id) &&
  1193. // card.type !== "GENERIC";
  1194. // return card;
  1195. // });
  1196. },
  1197. async toCreateCard(attachment) {
  1198. if (!this.examTask.cardRuleId) {
  1199. this.$message.error("题卡规则缺失!");
  1200. return;
  1201. }
  1202. const res = await this.$prompt("确定要提交当前题卡吗?", "提示", {
  1203. type: "warning",
  1204. showInput: true,
  1205. inputPlaceholder: "请输入题卡名称",
  1206. inputValidator: (val) => {
  1207. if (!val) return "请输入题卡名称!";
  1208. if (val.length > 50) return "题卡名称不得超过50个字符!";
  1209. return true;
  1210. },
  1211. }).catch(() => {});
  1212. if (!res || res.action !== "confirm") return;
  1213. this.curAttachment = { ...attachment };
  1214. // 这里只允许新建标准专卡
  1215. this.$ls.set("prepareTcPCard", {
  1216. courseCode: this.examTask.courseCode,
  1217. courseName: this.examTask.courseName,
  1218. schoolName: this.$ls.get("schoolName"),
  1219. makeMethod: "SELF",
  1220. cardName: res.value,
  1221. cardRuleId: this.examTask.cardRuleId,
  1222. type: "CUSTOM",
  1223. createMethod: "STANDARD",
  1224. });
  1225. this.$refs.ModifyCard.open();
  1226. },
  1227. cancel() {
  1228. this.$emit("cancel");
  1229. },
  1230. async downloadPaper(attachment) {
  1231. if (!attachment.attachmentId) return;
  1232. this.addPreviewLog(attachment, "paper");
  1233. const data = await attachmentPreview(attachment.attachmentId);
  1234. window.open(data.url);
  1235. },
  1236. toSelectNextFlowUser() {
  1237. if (!this.IS_NEED_SELECT_APPROVE_USER) return;
  1238. this.userLimitCount =
  1239. this.nextFlowTaskResult.approveUserCountType === "ONE" ? 1 : 0;
  1240. this.userFilterRoles =
  1241. this.nextFlowTaskResult.approveUserSelectRange === "ROLE"
  1242. ? this.nextFlowTaskResult.approveUserSelectRoles.map(
  1243. (item) => item.id
  1244. )
  1245. : [];
  1246. this.selectUserType = "approve";
  1247. this.curSelectedUsers = this.approveUsers;
  1248. this.$refs.SelectUserDialog.open();
  1249. },
  1250. toSelectExchangeUser() {
  1251. this.userLimitCount = 1;
  1252. this.userFilterRoles = [];
  1253. this.curSelectedUsers = this.exchangeUsers;
  1254. this.selectUserType = "exchange";
  1255. this.$refs.SelectUserDialog.open();
  1256. },
  1257. userSelected(users) {
  1258. if (this.selectUserType === "exchange") {
  1259. this.exchangeUsers = users;
  1260. this.auditModal.userId = users[0].id;
  1261. } else {
  1262. this.approveUsers = users;
  1263. }
  1264. },
  1265. getTaskData() {
  1266. let data = { ...this.curTaskApply };
  1267. data.paperType = this.paperAttachments.map((item) => item.name).join(",");
  1268. data.paperAttachmentIds = JSON.stringify(this.paperAttachments, (k, v) =>
  1269. k === "url" ? undefined : v
  1270. );
  1271. data.paperConfirmAttachmentIds = JSON.stringify(
  1272. this.paperConfirmAttachments
  1273. );
  1274. if (this.IS_NEED_SELECT_APPROVE_USER)
  1275. data.approveUserIds = this.approveUsers.map((item) => item.id);
  1276. return data;
  1277. },
  1278. checkDataValid() {
  1279. if (this.IS_TIKU_TAB) {
  1280. const attachmentValid = !this.paperAttachments.some(
  1281. (item) => !item.cardId
  1282. );
  1283. if (!attachmentValid) {
  1284. this.$message.error("请完成试卷选择!");
  1285. return;
  1286. }
  1287. } else {
  1288. // 设置了入库强制包含试卷时,校验试卷是否上传。
  1289. // 未设置入库强制包含试卷时,若有试卷上传,则需要上传全部。若无试卷上传,则通过。
  1290. if (this.curTaskApply.includePaper) {
  1291. const attachmentValid = !this.paperAttachments.some(
  1292. (item) => !item.attachmentId
  1293. );
  1294. if (!attachmentValid) {
  1295. this.$message.error("请完成试卷文件上传!");
  1296. return;
  1297. }
  1298. } else {
  1299. const hasUploadPaperAttachments = this.paperAttachments.filter(
  1300. (item) => item.attachmentId
  1301. );
  1302. if (
  1303. hasUploadPaperAttachments.length > 0 &&
  1304. hasUploadPaperAttachments.length !== this.paperAttachments.length
  1305. ) {
  1306. this.$message.error("有试卷文件未完成上传!");
  1307. return;
  1308. }
  1309. }
  1310. const cardValid = !this.paperAttachments.some((item) => !item.cardId);
  1311. if (!cardValid) {
  1312. this.$message.error("有试卷类型未选择题卡!");
  1313. return;
  1314. }
  1315. }
  1316. if (this.IS_NEED_SELECT_APPROVE_USER && !this.approveUsers.length) {
  1317. this.$message.error("请设置审核人员!");
  1318. return;
  1319. }
  1320. return true;
  1321. },
  1322. // select-paper
  1323. toSelect(attachment) {
  1324. this.curAttachment = {
  1325. ...attachment,
  1326. courseCode: this.examTask.courseCode,
  1327. };
  1328. this.$refs.SelectTikuPaperDialog.open();
  1329. },
  1330. async tikuPaperSelected(data) {
  1331. this.cardBuildPresetData = {
  1332. examId: this.examTask.examId,
  1333. courseCode: this.examTask.courseCode,
  1334. courseName: this.examTask.courseName,
  1335. schoolName: this.$ls.get("schoolName"),
  1336. makeMethod: "SELF",
  1337. cardName: "",
  1338. cardRuleId: this.examTask.cardRuleId,
  1339. type: "CUSTOM",
  1340. createMethod: "STANDARD",
  1341. paperId: data.id,
  1342. paperName: data.name,
  1343. uuid: this.curTaskApply.uuid,
  1344. };
  1345. this.$refs.CardBuildDialog.open();
  1346. },
  1347. cardBuildConfirm(data) {
  1348. if (!data.success) {
  1349. this.$message.error(data.message);
  1350. return;
  1351. }
  1352. const ind = this.paperAttachments.findIndex(
  1353. (item) => item.name === this.curAttachment.name
  1354. );
  1355. if (ind === -1) return;
  1356. const info = data.data;
  1357. this.curAttachment = { ...this.paperAttachments[ind] };
  1358. this.paperAttachments[ind] = Object.assign(this.paperAttachments[ind], {
  1359. paperId: this.cardBuildPresetData.paperId,
  1360. cardType: this.cardBuildPresetData.type,
  1361. createMethod: this.cardBuildPresetData.createMethod,
  1362. filename: this.cardBuildPresetData.paperName,
  1363. cardId: info.id,
  1364. cardTitle: info.title,
  1365. uuid: info.uuid,
  1366. attachmentId: info.attachmentId,
  1367. });
  1368. },
  1369. async toSave() {
  1370. if (this.isSubmit) return;
  1371. this.isSubmit = true;
  1372. const datas = this.getTaskData();
  1373. datas.operateType = "STAGE";
  1374. const data = await updateTaskApply(datas).catch(() => {});
  1375. this.isSubmit = false;
  1376. if (!data) return;
  1377. this.$message.success("保存成功!");
  1378. },
  1379. async silentSave() {
  1380. const datas = this.getTaskData();
  1381. datas.operateType = "STAGE";
  1382. await updateTaskApply(datas).catch(() => {});
  1383. },
  1384. async submit() {
  1385. if (!this.checkDataValid()) return;
  1386. const result = await this.$confirm(
  1387. "任务确定提交后,则不可更改试卷及答题卡内容,确定提交该任务?",
  1388. "提示",
  1389. {
  1390. type: "warning",
  1391. }
  1392. ).catch(() => {});
  1393. if (result !== "confirm") return;
  1394. const datas = this.getTaskData();
  1395. datas.operateType = "SUBMIT";
  1396. const data = await updateTaskApply(datas).catch(() => {});
  1397. if (!data) return;
  1398. this.$message.success("提交成功!");
  1399. this.$emit("modified");
  1400. },
  1401. async toAuditSubmit() {
  1402. if (this.IS_AUDIT && !this.checkAllFilePreview()) {
  1403. this.$message.error(
  1404. "还有未被查看过的题卡或试卷,请点击试卷及题卡进行查看审核"
  1405. );
  1406. return;
  1407. }
  1408. const valid = await this.$refs.auditModalComp.validate().catch(() => {});
  1409. if (!valid) return;
  1410. if (
  1411. this.auditModal.approvePass === "PASS" &&
  1412. this.IS_NEED_SELECT_APPROVE_USER &&
  1413. !this.approveUsers.length
  1414. ) {
  1415. this.$message.error("请设置审核人员!");
  1416. return;
  1417. }
  1418. const actionName = this.TASK_AUDIT_RESULT[this.auditModal.approvePass];
  1419. const result = await this.$confirm(
  1420. `确定${actionName}该申请吗?`,
  1421. "提示",
  1422. {
  1423. type: "warning",
  1424. }
  1425. ).catch(() => {});
  1426. if (result !== "confirm") return;
  1427. if (this.auditModal.approvePass === "EXCHANGE") {
  1428. let datas = {
  1429. taskId: this.curTaskApply.flowTaskId,
  1430. userId: this.auditModal.userId,
  1431. };
  1432. const data = await taskFlowApproverExchange(datas).catch(() => {});
  1433. if (!data) return;
  1434. } else {
  1435. let datas = { ...this.auditModal };
  1436. datas.taskId = this.curTaskApply.flowTaskId;
  1437. if (
  1438. this.auditModal.approvePass === "PASS" &&
  1439. this.IS_NEED_SELECT_APPROVE_USER
  1440. )
  1441. datas.approveUserIds = this.approveUsers.map((item) => item.id);
  1442. const data = await taskFlowApprover(datas).catch(() => {});
  1443. if (!data) return;
  1444. }
  1445. this.$message.success("审批成功!");
  1446. this.$emit("modified");
  1447. },
  1448. async toAuditApply() {
  1449. const result = await this.$confirm("确定提交该任务吗?", "提示", {
  1450. type: "warning",
  1451. }).catch(() => {});
  1452. if (result !== "confirm") return;
  1453. const datas = {
  1454. examTaskDetail: this.getTaskData(),
  1455. flowTaskId: this.curTaskApply.flowTaskId,
  1456. approvePass: "PASS",
  1457. };
  1458. const data = await taskAuditApply(datas).catch(() => {});
  1459. if (!data) return;
  1460. this.$message.success("审批成功!");
  1461. this.$emit("modified");
  1462. },
  1463. // audit preview log
  1464. async addPreviewLog(attachment, type) {
  1465. if (!this.IS_AUDIT) return;
  1466. const id = type === "paper" ? attachment.attachmentId : attachment.cardId;
  1467. if (!Object.prototype.hasOwnProperty.call(this.auditLogCache[type], id))
  1468. return;
  1469. this.auditLogCache[type][id] = true;
  1470. await savePreviewLog({
  1471. examTaskId: this.curTaskApply.examTaskId,
  1472. paperType: attachment.name,
  1473. type,
  1474. });
  1475. },
  1476. checkAllFilePreview() {
  1477. return (
  1478. !Object.values(this.auditLogCache.paper).some((item) => !item) &&
  1479. !Object.values(this.auditLogCache.card).some((item) => !item)
  1480. );
  1481. },
  1482. // image-preview
  1483. toPreview(index) {
  1484. this.curImageIndex = index;
  1485. this.selectImage(index);
  1486. this.$refs.SimpleImagePreview.open();
  1487. },
  1488. selectImage(index) {
  1489. this.curImage = this.paperConfirmAttachments[index];
  1490. },
  1491. toPrevImage() {
  1492. if (this.curImageIndex === 0) {
  1493. this.curImageIndex = this.paperConfirmAttachments.length - 1;
  1494. } else {
  1495. this.curImageIndex--;
  1496. }
  1497. this.selectImage(this.curImageIndex);
  1498. },
  1499. toNextImage() {
  1500. if (this.curImageIndex === this.paperConfirmAttachments.length - 1) {
  1501. this.curImageIndex = 0;
  1502. } else {
  1503. this.curImageIndex++;
  1504. }
  1505. this.selectImage(this.curImageIndex);
  1506. },
  1507. },
  1508. };
  1509. </script>