ModifyTaskPaper.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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. </el-option>
  136. </el-select>
  137. <el-button
  138. class="btn-primary"
  139. type="text"
  140. :disabled="!attachment.cardId"
  141. @click="toViewCard(attachment)"
  142. >预览</el-button
  143. >
  144. <el-button
  145. class="btn-primary"
  146. type="text"
  147. :disabled="
  148. !attachment.cardId ||
  149. (attachment.cardType === 'GENERIC' &&
  150. attachment.createMethod !== 'STANDARD')
  151. "
  152. @click="toCopyCard(attachment)"
  153. >复制</el-button
  154. >
  155. <el-button
  156. class="btn-primary"
  157. type="text"
  158. :disabled="
  159. !attachment.cardId || attachment.cardType === 'GENERIC'
  160. "
  161. @click="toEditCard(attachment)"
  162. >编辑</el-button
  163. >
  164. <el-button
  165. class="btn-primary"
  166. type="text"
  167. :disabled="!canCreateCard"
  168. @click="toCreateCard(attachment)"
  169. >新建</el-button
  170. >
  171. </template>
  172. <el-button
  173. v-else
  174. type="text"
  175. class="btn-primary"
  176. @click="toViewCard(attachment)"
  177. >
  178. {{ attachment.cardTitle || "预览" }}
  179. </el-button>
  180. </td>
  181. <td v-if="IS_EDIT">
  182. <el-button
  183. v-if="attachment.canDelete"
  184. class="btn-danger"
  185. type="text"
  186. @click="deleteAttachment(index)"
  187. >删除</el-button
  188. >
  189. </td>
  190. </tr>
  191. </table>
  192. <el-form>
  193. <el-form-item label="单次抽卷卷型数量:" label-width="150">
  194. <el-input-number
  195. v-model="curTaskApply.drawCount"
  196. :min="1"
  197. :max="maxFetchCount"
  198. :step="1"
  199. step-strictly
  200. :controls="false"
  201. :disabled="!IS_EDIT || exposedMode"
  202. ></el-input-number>
  203. </el-form-item>
  204. </el-form>
  205. </div>
  206. <div slot="footer">
  207. <el-button
  208. v-if="IS_EDIT"
  209. type="primary"
  210. :disabled="isSubmit"
  211. @click="submit"
  212. >确认提交</el-button
  213. >
  214. <el-button @click="cancel">取消</el-button>
  215. </div>
  216. </el-dialog>
  217. <!-- upload-paper-dialog -->
  218. <upload-paper-dialog
  219. :paper-attachment="curAttachment"
  220. :upload-type="curUploadType"
  221. @confirm="uploadConfirm"
  222. ref="UploadPaperDialog"
  223. ></upload-paper-dialog>
  224. <!-- ModifyCard -->
  225. <modify-card ref="ModifyCard" @modified="cardModified"></modify-card>
  226. </div>
  227. </template>
  228. <script>
  229. import UploadPaperDialog from "./UploadPaperDialog";
  230. import ModifyCard from "../../card/components/ModifyCard";
  231. import { taskApplyDetail, taskPaperApplyEdit, cardForSelectList } from "../api";
  232. import { attachmentPreview } from "../../login/api";
  233. import { COMMON_CARD_RULE_ID } from "@/constants/enumerate";
  234. import { copyCard } from "../../card/api";
  235. const initTaskApply = {
  236. examId: "",
  237. examTaskId: "",
  238. paperType: "A",
  239. paperAttachmentIds: "",
  240. cardId: "",
  241. cardRuleId: "",
  242. makeMethod: "",
  243. courseCode: "",
  244. courseName: "",
  245. drawCount: 1,
  246. exposedPaperType: "",
  247. // 题卡状态
  248. status: "",
  249. // 考务规则
  250. includePaper: false,
  251. customCard: false
  252. };
  253. export default {
  254. name: "modify-task-paper",
  255. components: { UploadPaperDialog, ModifyCard },
  256. props: {
  257. instance: {
  258. type: Object,
  259. default() {
  260. return {};
  261. }
  262. },
  263. editType: {
  264. type: String,
  265. default: "PREVIEW",
  266. validator: val => ["EDIT", "PREVIEW"].includes(val)
  267. }
  268. },
  269. computed: {
  270. title() {
  271. const names = {
  272. EDIT: "申请编辑卷库",
  273. PREVIEW: "卷库详情"
  274. };
  275. return names[this.editType];
  276. },
  277. IS_PREVIEW() {
  278. return this.editType === "PREVIEW";
  279. },
  280. IS_EDIT() {
  281. return this.editType === "EDIT";
  282. },
  283. CAN_EDIT_CARD() {
  284. return this.editType === "EDIT" && !this.instance.exposedPaperType;
  285. },
  286. maxFetchCount() {
  287. return this.paperAttachments.length < 1
  288. ? 1
  289. : this.paperAttachments.length;
  290. },
  291. canCreateCard() {
  292. return (
  293. this.curTaskApply.courseCode &&
  294. this.curTaskApply.examId &&
  295. this.curTaskApply.cardRuleId !== COMMON_CARD_RULE_ID
  296. );
  297. },
  298. exposedMode() {
  299. return !!this.curTaskApply.exposedPaperType;
  300. }
  301. },
  302. data() {
  303. return {
  304. isSubmit: false,
  305. modalIsShow: false,
  306. curTaskApply: { ...initTaskApply },
  307. paperAttachments: [],
  308. curAttachment: {},
  309. curUploadType: "paper",
  310. abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
  311. cards: []
  312. };
  313. },
  314. methods: {
  315. async getCardList() {
  316. if (!this.curTaskApply.courseCode || !this.curTaskApply.examId) return;
  317. const data = await cardForSelectList({
  318. courseCode: this.curTaskApply.courseCode,
  319. examId: this.curTaskApply.examId,
  320. paperNumber: this.instance.paperNumber
  321. });
  322. this.cards = data || [];
  323. },
  324. async visibleChange() {
  325. const data = await taskApplyDetail(this.instance.id);
  326. this.curTaskApply = this.$objAssign(initTaskApply, data || {});
  327. this.curTaskApply.courseCode = this.instance.courseCode;
  328. this.curTaskApply.courseName = this.instance.courseName;
  329. this.curTaskApply.cardRuleId = this.instance.cardRuleId;
  330. this.curTaskApply.includePaper =
  331. data.printContent.indexOf("PAPER") !== -1;
  332. this.paperAttachments = data.paperAttachmentIds
  333. ? JSON.parse(data.paperAttachmentIds)
  334. : [];
  335. const exposedPaperType = data.exposedPaperType || "";
  336. let exposedPaperTypes = exposedPaperType.split(",");
  337. exposedPaperTypes.sort((a, b) => (a > b ? -1 : 1));
  338. const maxExposedPaperType = exposedPaperTypes[0];
  339. this.paperAttachments.forEach(paper => {
  340. paper.canDelete = maxExposedPaperType
  341. ? paper.name > maxExposedPaperType
  342. : true;
  343. paper.isExposed = exposedPaperTypes.includes(paper.name);
  344. });
  345. this.$nextTick(() => {
  346. if (this.CAN_EDIT_CARD) {
  347. this.getCardList();
  348. }
  349. });
  350. },
  351. cancel() {
  352. this.modalIsShow = false;
  353. },
  354. open() {
  355. this.modalIsShow = true;
  356. },
  357. addAtachment() {
  358. if (this.paperAttachments.length >= this.abc.length) return;
  359. const name = this.abc[this.paperAttachments.length];
  360. const newAttachment = {
  361. name,
  362. attachmentId: "",
  363. filename: "",
  364. cardId: "",
  365. cardType: "",
  366. createMethod: "",
  367. cardTitle: "",
  368. pages: 0,
  369. canDelete: true,
  370. isExposed: false
  371. };
  372. this.paperAttachments.push(newAttachment);
  373. },
  374. deleteAttachment(index) {
  375. if (this.paperAttachments.length <= 1) {
  376. this.$message.error("试卷类型数量不得少于1");
  377. return;
  378. }
  379. this.paperAttachments.splice(index, 1);
  380. this.paperAttachments.forEach((item, itemIndex) => {
  381. item.name = this.abc[itemIndex];
  382. });
  383. if (
  384. this.curTaskApply.drawCount &&
  385. this.curTaskApply.drawCount > this.paperAttachments.length
  386. ) {
  387. this.curTaskApply.drawCount = this.paperAttachments.length;
  388. }
  389. },
  390. toUpload(attachment) {
  391. this.curUploadType = "paper";
  392. this.curAttachment = {
  393. ...attachment
  394. };
  395. this.$refs.UploadPaperDialog.open();
  396. },
  397. uploadConfirm(attachment, uploadType) {
  398. if (uploadType === "paper") {
  399. const index = this.paperAttachments.findIndex(
  400. item => item.name === attachment.name
  401. );
  402. this.paperAttachments.splice(index, 1, { ...attachment });
  403. }
  404. },
  405. async downloadPaper(attachment) {
  406. if (!attachment.attachmentId) return;
  407. const data = await attachmentPreview(attachment.attachmentId);
  408. window.open(data.url);
  409. },
  410. toViewCard(attachment) {
  411. window.open(
  412. this.getRouterPath({
  413. name: "CardPreview",
  414. params: {
  415. cardId: attachment.cardId,
  416. viewType: "view"
  417. }
  418. })
  419. );
  420. },
  421. async toCopyCard(attachment) {
  422. this.curAttachment = { ...attachment };
  423. const newCardId = await copyCard(
  424. attachment.cardId,
  425. this.curTaskApply.courseCode
  426. );
  427. this.cardModified(newCardId);
  428. },
  429. toEditCard(attachment) {
  430. this.curAttachment = { ...attachment };
  431. this.$ls.set("prepareTcPCard", {
  432. id: attachment.cardId,
  433. examTaskId: this.curTaskApply.examTaskId,
  434. courseCode: this.curTaskApply.courseCode,
  435. courseName: this.curTaskApply.courseName,
  436. makeMethod: this.curTaskApply.makeMethod,
  437. cardRuleId: this.curTaskApply.cardRuleId,
  438. paperType: this.paperAttachments.map(item => item.name).join(","),
  439. type: attachment.cardType,
  440. createMethod: attachment.createMethod
  441. });
  442. this.$refs.ModifyCard.open();
  443. },
  444. async cardModified(cardId) {
  445. if (!cardId) return;
  446. await this.getCardList();
  447. let card = this.cards.find(item => item.id === cardId);
  448. const aind = this.paperAttachments.findIndex(
  449. item => item.name === this.curAttachment.name
  450. );
  451. if (aind !== -1 && card) {
  452. this.paperAttachments[aind].cardId = card.id;
  453. this.paperAttachments[aind].cardType = card.type;
  454. this.paperAttachments[aind].createMethod = card.createMethod;
  455. this.paperAttachments[aind].cardTitle = card.title;
  456. }
  457. },
  458. toCreateCard(attachment) {
  459. if (!this.curTaskApply.cardRuleId) {
  460. this.$message.error("题卡规则缺失!");
  461. return;
  462. }
  463. this.curAttachment = { ...attachment };
  464. // 这里只允许新建标准专卡
  465. this.$ls.set("prepareTcPCard", {
  466. courseCode: this.curTaskApply.courseCode,
  467. courseName: this.curTaskApply.courseName,
  468. schoolName: this.$ls.get("schoolName"),
  469. makeMethod: "SELF",
  470. cardRuleId: this.curTaskApply.cardRuleId,
  471. type: "CUSTOM",
  472. createMethod: "STANDARD"
  473. });
  474. this.$refs.ModifyCard.open();
  475. },
  476. cardChange(attachment) {
  477. const card = this.cards.find(item => item.id === attachment.cardId);
  478. if (card) {
  479. attachment.cardType = card.type;
  480. attachment.createMethod = card.createMethod;
  481. attachment.cardTitle = card.title;
  482. }
  483. },
  484. cardOptionOpened(visible, attachment) {
  485. if (!visible) return;
  486. const selectedCardIds = this.paperAttachments.map(item => item.cardId);
  487. this.cards = this.cards.map(card => {
  488. card.disabled =
  489. card.id !== attachment.cardId &&
  490. selectedCardIds.includes(card.id) &&
  491. card.type !== "GENERIC";
  492. return card;
  493. });
  494. },
  495. checkDataValid() {
  496. // 设置了入库强制包含试卷时,校验试卷是否上传。
  497. // 未设置入库强制包含试卷时,若有试卷上传,则需要上传全部。若无试卷上传,则通过。
  498. if (this.curTaskApply.includePaper) {
  499. const attachmentValid = !this.paperAttachments.some(
  500. item => !item.attachmentId
  501. );
  502. if (!attachmentValid) {
  503. this.$message.error("请完成试卷文件上传!");
  504. return Promise.reject();
  505. }
  506. } else {
  507. const hasUploadPaperAttachments = this.paperAttachments.filter(
  508. item => item.attachmentId
  509. );
  510. if (
  511. hasUploadPaperAttachments.length > 0 &&
  512. hasUploadPaperAttachments.length !== this.paperAttachments.length
  513. ) {
  514. this.$message.error("有试卷文件未完成上传!");
  515. return Promise.reject();
  516. }
  517. }
  518. const cardValid = !this.paperAttachments.some(item => !item.cardId);
  519. if (!cardValid) {
  520. this.$message.error("有试卷类型未选择题卡!");
  521. return;
  522. }
  523. return true;
  524. },
  525. async submit() {
  526. if (!this.checkDataValid()) return;
  527. this.$confirm("确定要提交申请修改当前任务吗?", "提示", {
  528. type: "warning"
  529. })
  530. .then(async () => {
  531. const datas = {
  532. examTaskId: this.curTaskApply.examTaskId,
  533. paperType: this.paperAttachments.map(item => item.name).join(","),
  534. paperAttachmentIds: JSON.stringify(this.paperAttachments)
  535. };
  536. const data = await taskPaperApplyEdit(datas).catch(() => {});
  537. if (!data) return;
  538. this.$message.success("提交成功!");
  539. this.$emit("modified");
  540. this.cancel();
  541. })
  542. .catch(() => {});
  543. }
  544. }
  545. };
  546. </script>