ModifyTaskPaper.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. <template>
  2. <div class="modify-task-paper">
  3. <el-dialog
  4. class="task-detail"
  5. :visible.sync="modalIsShow"
  6. :title="title"
  7. top="10vh"
  8. width="900px"
  9. :close-on-click-modal="false"
  10. :close-on-press-escape="false"
  11. append-to-body
  12. @open="visibleChange"
  13. >
  14. <div class="part-box part-box-pad part-box-border">
  15. <el-form class="form-info" label-width="100px">
  16. <el-row>
  17. <el-col :span="12">
  18. <el-form-item label="试卷编号:">
  19. <span>{{ instance.paperNumber }}</span>
  20. </el-form-item>
  21. </el-col>
  22. <el-col :span="12">
  23. <el-form-item label="课程(代码):">
  24. <span>
  25. {{ instance.courseName }}({{ instance.courseCode }})
  26. </span>
  27. </el-form-item>
  28. </el-col>
  29. </el-row>
  30. <el-row>
  31. <el-col :span="12">
  32. <el-form-item label="卷型:">
  33. <span>{{ instance.paperType }}</span>
  34. </el-form-item>
  35. </el-col>
  36. <el-col :span="12">
  37. <el-form-item label="命题老师:">
  38. <span>{{ instance.userName }}</span>
  39. </el-form-item>
  40. </el-col>
  41. </el-row>
  42. <el-row>
  43. <el-col :span="12">
  44. <el-form-item label="已曝光:">
  45. <span>{{
  46. instance.exposedPaperType | defaultFieldFilter
  47. }}</span>
  48. </el-form-item>
  49. </el-col>
  50. <el-col :span="12">
  51. <el-form-item label="未曝光:">
  52. <span>{{
  53. instance.unexposedPaperType | defaultFieldFilter
  54. }}</span>
  55. </el-form-item>
  56. </el-col>
  57. </el-row>
  58. </el-form>
  59. </div>
  60. <div>
  61. <div v-if="IS_EDIT" class="mb-2 text-right">
  62. <el-button
  63. type="info"
  64. icon="el-icon-circle-plus-outline"
  65. @click="addAtachment"
  66. >增加卷型</el-button
  67. >
  68. </div>
  69. <table class="table">
  70. <tr>
  71. <th>试卷类型</th>
  72. <th>试卷文件</th>
  73. <th>答题卡</th>
  74. <th v-if="IS_EDIT">操作</th>
  75. </tr>
  76. <tr v-for="(attachment, index) in paperAttachments" :key="index">
  77. <td>
  78. <span>{{ attachment.name }}卷</span>
  79. <span class="color-gray-2" v-if="attachment.isExposed"
  80. >(已曝光)</span
  81. >
  82. </td>
  83. <td>
  84. <el-button
  85. v-if="!attachment.isExposed && IS_EDIT"
  86. type="text"
  87. class="btn-primary"
  88. @click="toUpload(attachment)"
  89. >
  90. <i
  91. :class="[
  92. 'icon',
  93. attachment.attachmentId ? 'icon-files-act' : 'icon-files',
  94. ]"
  95. ></i
  96. >{{
  97. attachment.attachmentId
  98. ? attachment.filename
  99. : "点击上传试卷文件"
  100. }}
  101. </el-button>
  102. <el-button
  103. v-else
  104. type="text"
  105. class="btn-primary"
  106. @click="downloadPaper(attachment)"
  107. >
  108. <i
  109. class="icon icon-download mr-1"
  110. v-if="attachment.attachmentId"
  111. ></i>
  112. <i>{{ attachment.filename }}</i>
  113. </el-button>
  114. </td>
  115. <td>
  116. <template v-if="CAN_EDIT_CARD">
  117. <el-select
  118. class="mr-2"
  119. v-model="attachment.cardId"
  120. placeholder="请选择"
  121. style="width: 200px"
  122. filterable
  123. @visible-change="
  124. (visible) => cardOptionOpened(visible, attachment)
  125. "
  126. @change="cardChange(attachment)"
  127. >
  128. <el-option
  129. v-for="item in cards"
  130. :key="item.id"
  131. :value="item.id"
  132. :label="item.title"
  133. :disabled="item.disabled"
  134. >
  135. <span
  136. :class="[
  137. item.type === 'GENERIC'
  138. ? 'color-success'
  139. : 'color-primary',
  140. 'mr-1',
  141. {
  142. 'color-danger': item.used,
  143. },
  144. ]"
  145. >[{{ item.type === "GENERIC" ? "通" : "专" }}]</span
  146. >
  147. {{ item.title }}
  148. </el-option>
  149. </el-select>
  150. <span
  151. v-if="attachment.cardId"
  152. :class="[
  153. attachment.cardType === 'GENERIC'
  154. ? 'color-success'
  155. : 'color-primary',
  156. 'mr-1',
  157. {
  158. 'color-danger': attachment.used,
  159. },
  160. ]"
  161. >[{{ attachment.cardType === "GENERIC" ? "通" : "专" }}]</span
  162. >
  163. <el-button
  164. class="btn-primary"
  165. type="text"
  166. :disabled="!attachment.cardId"
  167. @click="toViewCard(attachment)"
  168. >预览</el-button
  169. >
  170. <el-button
  171. class="btn-primary"
  172. type="text"
  173. :disabled="
  174. !attachment.cardId ||
  175. (attachment.cardType === 'GENERIC' &&
  176. attachment.createMethod !== 'STANDARD')
  177. "
  178. @click="toCopyCard(attachment)"
  179. >复制</el-button
  180. >
  181. <el-button
  182. class="btn-primary"
  183. type="text"
  184. :disabled="
  185. !attachment.cardId ||
  186. attachment.cardType === 'GENERIC' ||
  187. !(!attachment.used && attachment.createId === user.id) ||
  188. !(
  189. attachment.used &&
  190. attachment.savedCardId &&
  191. attachment.savedCardId === attachment.cardId
  192. )
  193. "
  194. @click="toEditCard(attachment)"
  195. >编辑</el-button
  196. >
  197. <el-button
  198. class="btn-primary"
  199. type="text"
  200. :disabled="!canCreateCard"
  201. @click="toCreateCard(attachment)"
  202. >新建</el-button
  203. >
  204. </template>
  205. <el-button
  206. v-else
  207. type="text"
  208. class="btn-primary"
  209. @click="toViewCard(attachment)"
  210. >
  211. {{ attachment.cardTitle || "预览" }}
  212. </el-button>
  213. </td>
  214. <td v-if="IS_EDIT">
  215. <el-button
  216. v-if="attachment.canDelete"
  217. class="btn-danger"
  218. type="text"
  219. @click="deleteAttachment(index)"
  220. >删除</el-button
  221. >
  222. </td>
  223. </tr>
  224. </table>
  225. <el-form>
  226. <el-form-item label="单次抽卷卷型数量:" label-width="150">
  227. <el-input-number
  228. v-model="curTaskApply.drawCount"
  229. :min="1"
  230. :max="maxFetchCount"
  231. :step="1"
  232. step-strictly
  233. :controls="false"
  234. :disabled="!IS_EDIT || exposedMode"
  235. ></el-input-number>
  236. </el-form-item>
  237. </el-form>
  238. </div>
  239. <div slot="footer">
  240. <el-button
  241. v-if="IS_EDIT"
  242. type="primary"
  243. :disabled="isSubmit"
  244. @click="submit"
  245. >确认提交</el-button
  246. >
  247. <el-button @click="cancel">取消</el-button>
  248. </div>
  249. </el-dialog>
  250. <!-- upload-paper-dialog -->
  251. <upload-paper-dialog
  252. :paper-attachment="curAttachment"
  253. :upload-type="curUploadType"
  254. @confirm="uploadConfirm"
  255. ref="UploadPaperDialog"
  256. ></upload-paper-dialog>
  257. <!-- ModifyCard -->
  258. <modify-card ref="ModifyCard" @modified="cardModified"></modify-card>
  259. <!-- card-preview-dialog -->
  260. <card-preview-dialog
  261. ref="CardPreviewDialog"
  262. :card-id="curAttachment.cardId"
  263. ></card-preview-dialog>
  264. </div>
  265. </template>
  266. <script>
  267. import UploadPaperDialog from "./UploadPaperDialog";
  268. import ModifyCard from "../../card/components/ModifyCard";
  269. import CardPreviewDialog from "../../card/components/CardPreviewDialog.vue";
  270. import { taskApplyDetail, taskPaperApplyEdit, cardForSelectList } from "../api";
  271. import { attachmentPreview } from "../../login/api";
  272. import { COMMON_CARD_RULE_ID } from "@/constants/enumerate";
  273. import { copyCard } from "../../card/api";
  274. const initTaskApply = {
  275. examId: "",
  276. examTaskId: "",
  277. paperType: "A",
  278. paperAttachmentIds: "",
  279. cardId: "",
  280. cardRuleId: "",
  281. makeMethod: "",
  282. courseCode: "",
  283. courseName: "",
  284. drawCount: 1,
  285. exposedPaperType: "",
  286. // 题卡状态
  287. status: "",
  288. // 考务规则
  289. includePaper: false,
  290. customCard: false,
  291. };
  292. export default {
  293. name: "modify-task-paper",
  294. components: { UploadPaperDialog, ModifyCard, CardPreviewDialog },
  295. props: {
  296. instance: {
  297. type: Object,
  298. default() {
  299. return {};
  300. },
  301. },
  302. editType: {
  303. type: String,
  304. default: "PREVIEW",
  305. validator: (val) => ["EDIT", "PREVIEW"].includes(val),
  306. },
  307. },
  308. computed: {
  309. title() {
  310. const names = {
  311. EDIT: "申请编辑卷库",
  312. PREVIEW: "卷库详情",
  313. };
  314. return names[this.editType];
  315. },
  316. IS_PREVIEW() {
  317. return this.editType === "PREVIEW";
  318. },
  319. IS_EDIT() {
  320. return this.editType === "EDIT";
  321. },
  322. CAN_EDIT_CARD() {
  323. return this.editType === "EDIT" && !this.instance.exposedPaperType;
  324. },
  325. maxFetchCount() {
  326. return this.paperAttachments.length < 1
  327. ? 1
  328. : this.paperAttachments.length;
  329. },
  330. canCreateCard() {
  331. return (
  332. this.curTaskApply.courseCode &&
  333. this.curTaskApply.examId &&
  334. this.curTaskApply.cardRuleId !== COMMON_CARD_RULE_ID
  335. );
  336. },
  337. exposedMode() {
  338. return !!this.curTaskApply.exposedPaperType;
  339. },
  340. },
  341. data() {
  342. return {
  343. isSubmit: false,
  344. modalIsShow: false,
  345. curTaskApply: { ...initTaskApply },
  346. paperAttachments: [],
  347. curAttachment: {},
  348. curUploadType: "paper",
  349. abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
  350. cards: [],
  351. user: this.$ls.get("user", {}),
  352. };
  353. },
  354. methods: {
  355. async getCardList() {
  356. if (!this.curTaskApply.courseCode || !this.curTaskApply.examId) return;
  357. const data = await cardForSelectList({
  358. courseCode: this.curTaskApply.courseCode,
  359. examId: this.curTaskApply.examId,
  360. paperNumber: this.instance.paperNumber,
  361. });
  362. this.cards = data || [];
  363. },
  364. async visibleChange() {
  365. const data = await taskApplyDetail(this.instance.id);
  366. this.curTaskApply = this.$objAssign(initTaskApply, data || {});
  367. this.curTaskApply.courseCode = this.instance.courseCode;
  368. this.curTaskApply.courseName = this.instance.courseName;
  369. this.curTaskApply.cardRuleId = this.instance.cardRuleId;
  370. this.curTaskApply.includePaper =
  371. data.printContent.indexOf("PAPER") !== -1;
  372. this.paperAttachments = data.paperAttachmentIds
  373. ? JSON.parse(data.paperAttachmentIds)
  374. : [];
  375. const exposedPaperType = data.exposedPaperType || "";
  376. let exposedPaperTypes = exposedPaperType.split(",");
  377. exposedPaperTypes.sort((a, b) => (a > b ? -1 : 1));
  378. const maxExposedPaperType = exposedPaperTypes[0];
  379. this.paperAttachments.forEach((paper) => {
  380. paper.canDelete = maxExposedPaperType
  381. ? paper.name > maxExposedPaperType
  382. : true;
  383. paper.isExposed = exposedPaperTypes.includes(paper.name);
  384. paper.savedCardId = paper.cardId;
  385. });
  386. this.$nextTick(() => {
  387. if (this.CAN_EDIT_CARD) {
  388. this.getCardList();
  389. }
  390. });
  391. },
  392. cancel() {
  393. this.modalIsShow = false;
  394. },
  395. open() {
  396. this.modalIsShow = true;
  397. },
  398. addAtachment() {
  399. if (this.paperAttachments.length >= this.abc.length) return;
  400. const name = this.abc[this.paperAttachments.length];
  401. const newAttachment = {
  402. name,
  403. attachmentId: "",
  404. filename: "",
  405. savedCardId: null,
  406. cardId: "",
  407. cardType: "",
  408. createMethod: "",
  409. cardTitle: "",
  410. pages: 0,
  411. canDelete: true,
  412. isExposed: false,
  413. used: false,
  414. createId: null,
  415. };
  416. this.paperAttachments.push(newAttachment);
  417. },
  418. deleteAttachment(index) {
  419. if (this.paperAttachments.length <= 1) {
  420. this.$message.error("试卷类型数量不得少于1");
  421. return;
  422. }
  423. this.paperAttachments.splice(index, 1);
  424. this.paperAttachments.forEach((item, itemIndex) => {
  425. item.name = this.abc[itemIndex];
  426. });
  427. if (
  428. this.curTaskApply.drawCount &&
  429. this.curTaskApply.drawCount > this.paperAttachments.length
  430. ) {
  431. this.curTaskApply.drawCount = this.paperAttachments.length;
  432. }
  433. },
  434. toUpload(attachment) {
  435. this.curUploadType = "paper";
  436. this.curAttachment = {
  437. ...attachment,
  438. };
  439. this.$refs.UploadPaperDialog.open();
  440. },
  441. uploadConfirm(attachment, uploadType) {
  442. if (uploadType === "paper") {
  443. const index = this.paperAttachments.findIndex(
  444. (item) => item.name === attachment.name
  445. );
  446. this.paperAttachments.splice(index, 1, { ...attachment });
  447. }
  448. },
  449. async downloadPaper(attachment) {
  450. if (!attachment.attachmentId) return;
  451. const data = await attachmentPreview(attachment.attachmentId);
  452. window.open(data.url);
  453. },
  454. toViewCard(attachment) {
  455. this.curAttachment = { ...attachment };
  456. this.$refs.CardPreviewDialog.open();
  457. },
  458. async toCopyCard(attachment) {
  459. this.curAttachment = { ...attachment };
  460. const newCardId = await copyCard(
  461. attachment.cardId,
  462. this.curTaskApply.courseCode
  463. );
  464. this.cardModified(newCardId);
  465. },
  466. toEditCard(attachment) {
  467. this.curAttachment = { ...attachment };
  468. this.$ls.set("prepareTcPCard", {
  469. id: attachment.cardId,
  470. examTaskId: this.curTaskApply.examTaskId,
  471. courseCode: this.curTaskApply.courseCode,
  472. courseName: this.curTaskApply.courseName,
  473. makeMethod: this.curTaskApply.makeMethod,
  474. cardRuleId: this.curTaskApply.cardRuleId,
  475. paperType: this.paperAttachments.map((item) => item.name).join(","),
  476. type: attachment.cardType,
  477. createMethod: attachment.createMethod,
  478. });
  479. this.$refs.ModifyCard.open();
  480. },
  481. async cardModified(cardId) {
  482. if (!cardId) return;
  483. await this.getCardList();
  484. let card = this.cards.find((item) => item.id === cardId);
  485. const aind = this.paperAttachments.findIndex(
  486. (item) => item.name === this.curAttachment.name
  487. );
  488. if (aind !== -1 && card) {
  489. this.paperAttachments[aind].cardId = card.id;
  490. this.paperAttachments[aind].cardType = card.type;
  491. this.paperAttachments[aind].createMethod = card.createMethod;
  492. this.paperAttachments[aind].cardTitle = card.title;
  493. this.paperAttachments[aind].used = card.used;
  494. this.paperAttachments[aind].createId = card.createId;
  495. }
  496. },
  497. toCreateCard(attachment) {
  498. if (!this.curTaskApply.cardRuleId) {
  499. this.$message.error("题卡规则缺失!");
  500. return;
  501. }
  502. this.curAttachment = { ...attachment };
  503. // 这里只允许新建标准专卡
  504. this.$ls.set("prepareTcPCard", {
  505. courseCode: this.curTaskApply.courseCode,
  506. courseName: this.curTaskApply.courseName,
  507. schoolName: this.$ls.get("schoolName"),
  508. makeMethod: "SELF",
  509. cardRuleId: this.curTaskApply.cardRuleId,
  510. type: "CUSTOM",
  511. createMethod: "STANDARD",
  512. });
  513. this.$refs.ModifyCard.open();
  514. },
  515. cardChange(attachment) {
  516. const card = this.cards.find((item) => item.id === attachment.cardId);
  517. if (card) {
  518. attachment.cardType = card.type;
  519. attachment.createMethod = card.createMethod;
  520. attachment.cardTitle = card.title;
  521. attachment.used = card.used;
  522. attachment.createId = card.createId;
  523. }
  524. },
  525. cardOptionOpened(visible, attachment) {
  526. if (!visible) return;
  527. // const selectedCardIds = this.paperAttachments.map((item) => item.cardId);
  528. // this.cards = this.cards.map((card) => {
  529. // card.disabled =
  530. // card.id !== attachment.cardId &&
  531. // selectedCardIds.includes(card.id) &&
  532. // card.type !== "GENERIC";
  533. // return card;
  534. // });
  535. },
  536. checkDataValid() {
  537. // 设置了入库强制包含试卷时,校验试卷是否上传。
  538. // 未设置入库强制包含试卷时,若有试卷上传,则需要上传全部。若无试卷上传,则通过。
  539. if (this.curTaskApply.includePaper) {
  540. const attachmentValid = !this.paperAttachments.some(
  541. (item) => !item.attachmentId
  542. );
  543. if (!attachmentValid) {
  544. this.$message.error("请完成试卷文件上传!");
  545. return;
  546. }
  547. } else {
  548. const hasUploadPaperAttachments = this.paperAttachments.filter(
  549. (item) => item.attachmentId
  550. );
  551. if (
  552. hasUploadPaperAttachments.length > 0 &&
  553. hasUploadPaperAttachments.length !== this.paperAttachments.length
  554. ) {
  555. this.$message.error("有试卷文件未完成上传!");
  556. return;
  557. }
  558. }
  559. let cardValid = !this.paperAttachments.some((item) => !item.cardId);
  560. if (!cardValid) {
  561. this.$message.error("有试卷类型未选择题卡!");
  562. return;
  563. }
  564. // const usedCards = this.paperAttachments
  565. // .filter((item) => item.cardId && item.used)
  566. // .map((item) => item.name);
  567. // if (usedCards.length) {
  568. // this.$message.error(`${usedCards.join()}卷选择的题卡已经被使用过!`);
  569. // return;
  570. // }
  571. return true;
  572. },
  573. async submit() {
  574. if (!this.checkDataValid()) return;
  575. this.$confirm("确定要提交申请修改当前任务吗?", "提示", {
  576. type: "warning",
  577. })
  578. .then(async () => {
  579. const datas = {
  580. examTaskId: this.curTaskApply.examTaskId,
  581. drawCount: this.curTaskApply.drawCount,
  582. paperType: this.paperAttachments.map((item) => item.name).join(","),
  583. paperAttachmentIds: JSON.stringify(this.paperAttachments),
  584. };
  585. const data = await taskPaperApplyEdit(datas).catch(() => {});
  586. if (!data) return;
  587. this.$message.success("提交成功!");
  588. this.$emit("modified");
  589. this.cancel();
  590. })
  591. .catch(() => {});
  592. },
  593. },
  594. };
  595. </script>