ModifyTaskPaper.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  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 { examRuleDetail } from "../../base/api";
  234. import { COMMON_CARD_RULE_ID } from "@/constants/enumerate";
  235. import { copyCard } from "../../card/api";
  236. const initTaskApply = {
  237. examId: "",
  238. examTaskId: "",
  239. paperType: "A",
  240. paperAttachmentIds: "",
  241. cardId: "",
  242. cardRuleId: "",
  243. makeMethod: "",
  244. courseCode: "",
  245. courseName: "",
  246. drawCount: 1,
  247. exposedPaperType: "",
  248. // 题卡状态
  249. status: "",
  250. // 考务规则
  251. includePaper: false,
  252. customCard: false
  253. };
  254. export default {
  255. name: "modify-task-paper",
  256. components: { UploadPaperDialog, ModifyCard },
  257. props: {
  258. instance: {
  259. type: Object,
  260. default() {
  261. return {};
  262. }
  263. },
  264. editType: {
  265. type: String,
  266. default: "PREVIEW",
  267. validator: val => ["EDIT", "PREVIEW"].includes(val)
  268. }
  269. },
  270. computed: {
  271. title() {
  272. const names = {
  273. EDIT: "申请编辑卷库",
  274. PREVIEW: "卷库详情"
  275. };
  276. return names[this.editType];
  277. },
  278. IS_PREVIEW() {
  279. return this.editType === "PREVIEW";
  280. },
  281. IS_EDIT() {
  282. return this.editType === "EDIT";
  283. },
  284. CAN_EDIT_CARD() {
  285. return this.editType === "EDIT" && !this.instance.exposedPaperType;
  286. },
  287. maxFetchCount() {
  288. return this.paperAttachments.length < 1
  289. ? 1
  290. : this.paperAttachments.length;
  291. },
  292. canCreateCard() {
  293. return (
  294. this.curTaskApply.courseCode &&
  295. this.curTaskApply.examId &&
  296. this.curTaskApply.cardRuleId !== COMMON_CARD_RULE_ID
  297. );
  298. },
  299. exposedMode() {
  300. return !!this.curTaskApply.exposedPaperType;
  301. }
  302. },
  303. data() {
  304. return {
  305. isSubmit: false,
  306. modalIsShow: false,
  307. curTaskApply: { ...initTaskApply },
  308. paperAttachments: [],
  309. curAttachment: {},
  310. curUploadType: "paper",
  311. abc: "abcdefghijklmnopqrstuvwxyz".toUpperCase(),
  312. includePaper: false,
  313. cards: []
  314. };
  315. },
  316. created() {
  317. this.getExamRule();
  318. },
  319. methods: {
  320. async getExamRule() {
  321. const examRule = await examRuleDetail();
  322. this.includePaper = examRule && examRule.includePaper;
  323. },
  324. async getCardList() {
  325. if (!this.curTaskApply.courseCode || !this.curTaskApply.examId) return;
  326. const data = await cardForSelectList({
  327. courseCode: this.curTaskApply.courseCode,
  328. examId: this.curTaskApply.examId
  329. });
  330. this.cards = data || [];
  331. },
  332. async visibleChange() {
  333. const data = await taskApplyDetail(this.instance.id);
  334. this.curTaskApply = this.$objAssign(initTaskApply, data || {});
  335. this.curTaskApply.courseCode = this.instance.courseCode;
  336. this.curTaskApply.courseName = this.instance.courseName;
  337. this.curTaskApply.cardRuleId = this.instance.cardRuleId;
  338. this.curTaskApply.includePaper = this.includePaper;
  339. this.paperAttachments = data.paperAttachmentIds
  340. ? JSON.parse(data.paperAttachmentIds)
  341. : [];
  342. const exposedPaperType = data.exposedPaperType || "";
  343. let exposedPaperTypes = exposedPaperType.split(",");
  344. exposedPaperTypes.sort((a, b) => (a > b ? -1 : 1));
  345. const maxExposedPaperType = exposedPaperTypes[0];
  346. this.paperAttachments.forEach(paper => {
  347. paper.canDelete = maxExposedPaperType
  348. ? paper.name > maxExposedPaperType
  349. : true;
  350. paper.isExposed = exposedPaperTypes.includes(paper.name);
  351. });
  352. this.$nextTick(() => {
  353. if (this.CAN_EDIT_CARD) {
  354. this.getCardList();
  355. }
  356. });
  357. },
  358. cancel() {
  359. this.modalIsShow = false;
  360. },
  361. open() {
  362. this.modalIsShow = true;
  363. },
  364. addAtachment() {
  365. if (this.paperAttachments.length >= this.abc.length) return;
  366. const name = this.abc[this.paperAttachments.length];
  367. const newAttachment = {
  368. name,
  369. attachmentId: "",
  370. filename: "",
  371. cardId: "",
  372. cardType: "",
  373. createMethod: "",
  374. cardTitle: "",
  375. pages: 0,
  376. canDelete: true,
  377. isExposed: false
  378. };
  379. this.paperAttachments.push(newAttachment);
  380. },
  381. deleteAttachment(index) {
  382. if (this.paperAttachments.length <= 1) {
  383. this.$message.error("试卷类型数量不得少于1");
  384. return;
  385. }
  386. this.paperAttachments.splice(index, 1);
  387. this.paperAttachments.forEach((item, itemIndex) => {
  388. item.name = this.abc[itemIndex];
  389. });
  390. if (
  391. this.curTaskApply.drawCount &&
  392. this.curTaskApply.drawCount > this.paperAttachments.length
  393. ) {
  394. this.curTaskApply.drawCount = this.paperAttachments.length;
  395. }
  396. },
  397. toUpload(attachment) {
  398. this.curUploadType = "paper";
  399. this.curAttachment = {
  400. ...attachment
  401. };
  402. this.$refs.UploadPaperDialog.open();
  403. },
  404. uploadConfirm(attachment, uploadType) {
  405. if (uploadType === "paper") {
  406. const index = this.paperAttachments.findIndex(
  407. item => item.name === attachment.name
  408. );
  409. this.paperAttachments.splice(index, 1, { ...attachment });
  410. }
  411. },
  412. async downloadPaper(attachment) {
  413. if (!attachment.attachmentId) return;
  414. const data = await attachmentPreview(attachment.attachmentId);
  415. window.open(data.url);
  416. },
  417. toViewCard(attachment) {
  418. window.open(
  419. this.getRouterPath({
  420. name: "CardPreview",
  421. params: {
  422. cardId: attachment.cardId,
  423. viewType: "view"
  424. }
  425. })
  426. );
  427. },
  428. async toCopyCard(attachment) {
  429. this.curAttachment = { ...attachment };
  430. const newCardId = await copyCard(
  431. attachment.cardId,
  432. this.curTaskApply.courseCode
  433. );
  434. this.cardModified(newCardId);
  435. },
  436. toEditCard(attachment) {
  437. this.curAttachment = { ...attachment };
  438. this.$ls.set("prepareTcPCard", {
  439. id: attachment.cardId,
  440. examTaskId: this.curTaskApply.examTaskId,
  441. courseCode: this.curTaskApply.courseCode,
  442. courseName: this.curTaskApply.courseName,
  443. makeMethod: this.curTaskApply.makeMethod,
  444. cardRuleId: this.curTaskApply.cardRuleId,
  445. paperType: this.paperAttachments.map(item => item.name).join(","),
  446. type: attachment.cardType,
  447. createMethod: attachment.createMethod
  448. });
  449. this.$refs.ModifyCard.open();
  450. },
  451. async cardModified(cardId) {
  452. if (!cardId) return;
  453. await this.getCardList();
  454. let card = this.cards.find(item => item.id === cardId);
  455. const aind = this.paperAttachments.findIndex(
  456. item => item.name === this.curAttachment.name
  457. );
  458. if (aind !== -1 && card) {
  459. this.paperAttachments[aind].cardId = card.id;
  460. this.paperAttachments[aind].cardType = card.type;
  461. this.paperAttachments[aind].createMethod = card.createMethod;
  462. this.paperAttachments[aind].cardTitle = card.title;
  463. }
  464. },
  465. toCreateCard(attachment) {
  466. if (!this.curTaskApply.cardRuleId) {
  467. this.$message.error("题卡规则缺失!");
  468. return;
  469. }
  470. this.curAttachment = { ...attachment };
  471. // 这里只允许新建标准专卡
  472. this.$ls.set("prepareTcPCard", {
  473. courseCode: this.curTaskApply.courseCode,
  474. courseName: this.curTaskApply.courseName,
  475. schoolName: this.$ls.get("schoolName"),
  476. makeMethod: "SELF",
  477. cardRuleId: this.curTaskApply.cardRuleId,
  478. type: "CUSTOM",
  479. createMethod: "STANDARD"
  480. });
  481. this.$refs.ModifyCard.open();
  482. },
  483. cardChange(attachment) {
  484. const card = this.cards.find(item => item.id === attachment.cardId);
  485. if (card) {
  486. attachment.cardType = card.type;
  487. attachment.createMethod = card.createMethod;
  488. attachment.cardTitle = card.title;
  489. }
  490. },
  491. cardOptionOpened(visible, attachment) {
  492. if (!visible) return;
  493. const selectedCardIds = this.paperAttachments.map(item => item.cardId);
  494. this.cards = this.cards.map(card => {
  495. card.disabled =
  496. card.id !== attachment.cardId && selectedCardIds.includes(card.id);
  497. return card;
  498. });
  499. },
  500. checkDataValid() {
  501. const attachmentValid = !this.paperAttachments.some(
  502. item => !item.attachmentId
  503. );
  504. // 设置了入库强制包含试卷时,校验试卷是否上传。
  505. if (this.curTaskApply.includePaper && !attachmentValid) {
  506. this.$message.error("请完成试卷文件上传!");
  507. return;
  508. }
  509. const cardValid = !this.paperAttachments.some(item => !item.cardId);
  510. if (!cardValid) {
  511. this.$message.error("有试卷类型未选择题卡!");
  512. return;
  513. }
  514. return true;
  515. },
  516. async submit() {
  517. if (!this.checkDataValid()) return;
  518. this.$confirm("确定要提交申请修改当前任务吗?", "提示", {
  519. type: "warning"
  520. })
  521. .then(async () => {
  522. const datas = {
  523. examTaskId: this.curTaskApply.examTaskId,
  524. paperType: this.paperAttachments.map(item => item.name).join(","),
  525. paperAttachmentIds: JSON.stringify(this.paperAttachments)
  526. };
  527. const data = await taskPaperApplyEdit(datas).catch(() => {});
  528. if (!data) return;
  529. this.$message.success("提交成功!");
  530. this.$emit("modified");
  531. this.cancel();
  532. })
  533. .catch(() => {});
  534. }
  535. }
  536. };
  537. </script>