examScheduling.vue 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. <template>
  2. <el-container>
  3. <el-main v-loading="loading" class="el-main-padding">
  4. <commonFormVue :form="form" :get-exam-condition="getExamCondition">
  5. <el-row v-show="showAllCondition">
  6. <el-col :span="6">
  7. <el-form-item label="完成状态">
  8. <el-select
  9. v-if="
  10. form.examType == '' ||
  11. form.examType == 'ONLINE' ||
  12. form.examType == 'ONLINE_HOMEWORK'
  13. "
  14. v-model="form.finished"
  15. class="form_search_width"
  16. size="small"
  17. clearable
  18. placeholder="全部"
  19. >
  20. <el-option value="1" label="已完成"></el-option>
  21. <el-option value="0" label="未完成"></el-option>
  22. </el-select>
  23. <el-select
  24. v-if="form.examType == 'OFFLINE'"
  25. v-model="form.finished"
  26. class="form_search_width"
  27. size="small"
  28. clearable
  29. placeholder="全部"
  30. >
  31. <el-option value="0" label="未抽题"></el-option>
  32. <el-option value="1" label="已抽题"></el-option>
  33. <el-option value="2" label="已上传"></el-option>
  34. </el-select>
  35. </el-form-item>
  36. </el-col>
  37. <el-col :span="6">
  38. <el-form-item label="采集人">
  39. <el-input
  40. v-model="form.infoCollector"
  41. class="form_search_width"
  42. size="small"
  43. placeholder="采集人"
  44. ></el-input>
  45. </el-form-item>
  46. </el-col>
  47. </el-row>
  48. </commonFormVue>
  49. <el-col :span="24">
  50. <el-button
  51. size="small"
  52. type="primary"
  53. icon="el-icon-search"
  54. @click="search('clickSelectBtn')"
  55. >查询</el-button
  56. >
  57. <el-button
  58. v-if="!showAllCondition"
  59. size="small"
  60. type="primary"
  61. icon="el-icon-more"
  62. @click="showMoreCondition"
  63. >高级查询</el-button
  64. >
  65. <el-button
  66. v-if="showAllCondition"
  67. size="small"
  68. type="primary"
  69. @click="showSimpleCondition"
  70. >简单查询</el-button
  71. >
  72. <el-button
  73. size="small"
  74. icon="el-icon-refresh"
  75. class="margin-bottom-10"
  76. @click="resetForm"
  77. >重置</el-button
  78. >
  79. </el-col>
  80. <el-row>
  81. <el-col
  82. v-show="currentPagePrivileges.EXAM_PARTICULARS_EXPORT"
  83. :span="24"
  84. >
  85. <div class="block-seperator"></div>
  86. <span>操作:</span>
  87. <el-button
  88. type="primary"
  89. size="small"
  90. icon="el-icon-download"
  91. @click="exportData"
  92. >导出</el-button
  93. >
  94. </el-col>
  95. </el-row>
  96. <el-row class="margin-top-10">
  97. <el-col :span="24">
  98. <el-table
  99. ref="multipleTable"
  100. v-loading="tableLoading"
  101. element-loading-text="数据加载中"
  102. :data="tableData"
  103. border
  104. @selection-change="handleSelectionChange"
  105. >
  106. <el-table-column
  107. label="姓名"
  108. prop="studentName"
  109. width="120"
  110. ></el-table-column>
  111. <el-table-column
  112. label="身份证号"
  113. prop="identityNumber"
  114. width="120"
  115. ></el-table-column>
  116. <el-table-column
  117. label="学号"
  118. prop="studentCode"
  119. width="120"
  120. ></el-table-column>
  121. <el-table-column
  122. label="已考次数"
  123. prop="usedNum"
  124. width="90"
  125. ></el-table-column>
  126. <el-table-column
  127. label="学习中心"
  128. prop="orgName"
  129. width="120"
  130. ></el-table-column>
  131. <el-table-column
  132. label="课程"
  133. prop="courseName"
  134. width="120"
  135. ></el-table-column>
  136. <el-table-column
  137. label="课程层次"
  138. prop="courseLevel"
  139. width="90"
  140. ></el-table-column>
  141. <el-table-column label="场次" width="120">
  142. <template slot-scope="scope">
  143. <el-popover trigger="hover" placement="left">
  144. <div style="font-size: 18px; font-family: 新宋体">
  145. <tr>
  146. <td style="color: green">场次序号</td>
  147. <td style="color: purple; padding-left: 20px">
  148. {{ scope.row.examStageOrder }}
  149. </td>
  150. </tr>
  151. <tr>
  152. <td style="color: green">开始时间</td>
  153. <td style="color: purple; padding-left: 20px">
  154. {{ scope.row.startTime }}
  155. </td>
  156. </tr>
  157. <tr>
  158. <td style="color: green">结束时间</td>
  159. <td style="color: purple; padding-left: 20px">
  160. {{ scope.row.endTime }}
  161. </td>
  162. </tr>
  163. </div>
  164. <div slot="reference" class="name-wrapper">
  165. <span>{{ scope.row.examStageOrder }}</span>
  166. </div>
  167. </el-popover>
  168. </template>
  169. </el-table-column>
  170. <el-table-column
  171. label="专业"
  172. prop="specialtyName"
  173. width="90"
  174. ></el-table-column>
  175. <el-table-column
  176. label="年级"
  177. prop="grade"
  178. width="90"
  179. ></el-table-column>
  180. <el-table-column
  181. label="学生电话"
  182. prop="phone"
  183. width="90"
  184. ></el-table-column>
  185. <el-table-column
  186. label="采集人"
  187. prop="infoCollector"
  188. width="90"
  189. ></el-table-column>
  190. <el-table-column
  191. fixed="right"
  192. label="完成状态"
  193. prop="finishedStatus"
  194. width="90"
  195. ></el-table-column>
  196. <el-table-column fixed="right" label="操作" width="120">
  197. <template slot-scope="scope">
  198. <el-row class="operateRow">
  199. <el-col :span="24">
  200. <el-button
  201. v-if="scope.row.examType == 'OFFLINE'"
  202. plain
  203. type="primary"
  204. size="mini"
  205. icon="el-icon-view"
  206. @click="previewPaper(scope.row.examStudentId)"
  207. >查看考题</el-button
  208. >
  209. </el-col>
  210. </el-row>
  211. <el-row class="operateRow">
  212. <el-col :span="24">
  213. <el-button
  214. v-if="scope.row.examType == 'OFFLINE'"
  215. plain
  216. type="primary"
  217. size="mini"
  218. icon="el-icon-download"
  219. @click="exportPaper(scope.row.examStudentId)"
  220. >下载考题</el-button
  221. >
  222. </el-col>
  223. </el-row>
  224. <el-row class="operateRow">
  225. <el-col :span="24">
  226. <el-button
  227. v-if="
  228. scope.row.examType == 'OFFLINE' &&
  229. scope.row.canUploadAttachment
  230. "
  231. plain
  232. type="primary"
  233. size="mini"
  234. icon="el-icon-upload2"
  235. @click="openUploadAnswerDialog(scope.row.examStudentId)"
  236. >上传作答</el-button
  237. >
  238. </el-col>
  239. </el-row>
  240. <el-row class="operateRow">
  241. <el-col :span="24">
  242. <el-button
  243. v-if="
  244. scope.row.examType == 'OFFLINE' &&
  245. scope.row.offlineFiles
  246. "
  247. plain
  248. type="primary"
  249. size="mini"
  250. icon="el-icon-download"
  251. @click="downloadAnswer(scope.row.offlineFiles)"
  252. >下载作答</el-button
  253. >
  254. </el-col>
  255. </el-row>
  256. </template>
  257. </el-table-column>
  258. </el-table>
  259. <div class="page pull-right">
  260. <el-pagination
  261. :current-page.sync="form.pageNo"
  262. :page-sizes="[10, 20, 50, 100, 200, 300]"
  263. :page-size="form.pageSize"
  264. layout="total, sizes, prev, pager, next, jumper"
  265. :total="total"
  266. @size-change="handleSizeChange"
  267. @current-change="handleCurrentChange"
  268. ></el-pagination>
  269. </div>
  270. </el-col>
  271. </el-row>
  272. <div>
  273. <el-dialog
  274. v-loading="uploadAnswerDialogLoading"
  275. title="上传作答"
  276. :visible.sync="uploadAnswerDialogVisible"
  277. >
  278. <el-form>
  279. <el-form-item label="选择文件类型">
  280. <el-radio-group v-model="fileType" @change="handleFileTypeChange">
  281. <el-radio v-show="optZipVisible" label="zip">ZIP</el-radio>
  282. <el-radio v-show="optPdfVisible" label="pdf">PDF</el-radio>
  283. <el-radio v-show="optImageVisible" label="image"
  284. >图片(jpg、jpeg、png)</el-radio
  285. >
  286. </el-radio-group>
  287. </el-form-item>
  288. <el-form-item label="选择文件">
  289. <div
  290. v-show="fileType == 'image'"
  291. style="width: 580px; padding-left: 80px"
  292. >
  293. <el-upload
  294. ref="upload"
  295. :class="{ disabled: uploadDisabled }"
  296. action
  297. :limit="fileLimit"
  298. :http-request="customUpload"
  299. :before-upload="beforeFileUpload"
  300. :on-success="handleSuccess"
  301. :file-list="fileList"
  302. :auto-upload="false"
  303. :accept="accept"
  304. :on-change="handleChange"
  305. multiple
  306. list-type="picture-card"
  307. >
  308. <i slot="default" class="el-icon-plus"></i>
  309. <div slot="file" slot-scope="{ file }">
  310. <img
  311. class="el-upload-list__item-thumbnail"
  312. :src="file.url"
  313. alt
  314. />
  315. <span class="el-upload-list__item-actions">
  316. <span
  317. class="el-upload-list__item-preview"
  318. @click="handlePictureCardPreview(file)"
  319. >
  320. <i class="el-icon-zoom-in"></i>
  321. </span>
  322. <span
  323. v-if="!disabled"
  324. class="el-upload-list__item-delete"
  325. @click="handleRemove(file)"
  326. >
  327. <i class="el-icon-delete"></i>
  328. </span>
  329. </span>
  330. </div>
  331. </el-upload>
  332. <div style="width: 580px">
  333. 温馨提示:仅支持JPG,JPEG和PNG文件,单个图片大小请不要超过5M,图片数量最多6张!
  334. </div>
  335. </div>
  336. <div v-show="fileType != 'image'">
  337. <input
  338. id="importFile"
  339. ref="offlineFileInput"
  340. type="file"
  341. :accept="accept"
  342. :class="{ offline_file: offlineAnswerFile }"
  343. @change="uploadAnswerChange"
  344. />
  345. <div>温馨提示:仅支持pdf和zip文件,文件大小请不要超过30M!</div>
  346. </div>
  347. </el-form-item>
  348. <div class="dialog-footer">
  349. <el-button @click="cancelUpload">取 消</el-button>
  350. <el-button
  351. v-show="fileType != 'image'"
  352. :disabled="!offlineAnswerFile"
  353. type="primary"
  354. @click="doUploadAnswer"
  355. >确 定</el-button
  356. >
  357. <el-button
  358. v-show="fileType == 'image'"
  359. :disabled="batchSubmitUploadDisabled"
  360. type="primary"
  361. @click="batchSubmitUpload"
  362. >确 定</el-button
  363. >
  364. </div>
  365. </el-form>
  366. </el-dialog>
  367. <el-dialog :append-to-body="true" :visible.sync="dialogVisible">
  368. <img width="100%" :src="dialogImageUrl" alt />
  369. </el-dialog>
  370. <el-dialog title="图片作答" :visible.sync="downloadImageDialogVisible">
  371. <el-form>
  372. <el-form-item label="作答结果">
  373. <div style="width: 580px; padding-left: 80px">
  374. <el-upload
  375. :class="{ disabled: true }"
  376. action
  377. :limit="6"
  378. :file-list="imageAnswerFileList"
  379. multiple
  380. list-type="picture-card"
  381. :disabled="true"
  382. >
  383. <i slot="default" class="el-icon-plus"></i>
  384. <div slot="file" slot-scope="{ file }">
  385. <img
  386. class="el-upload-list__item-thumbnail"
  387. :src="file.url"
  388. :alt="file.name"
  389. />
  390. <span class="el-upload-list__item-actions">
  391. <span
  392. class="el-upload-list__item-preview"
  393. @click="handlePictureCardPreview(file)"
  394. >
  395. <i class="el-icon-zoom-in"></i>
  396. </span>
  397. <span
  398. class="el-upload-list__item-delete"
  399. @click="handleDownload(file)"
  400. >
  401. <i class="el-icon-download"></i>
  402. </span>
  403. </span>
  404. </div>
  405. </el-upload>
  406. </div>
  407. </el-form-item>
  408. <div class="dialog-footer">
  409. <el-button
  410. type="primary"
  411. @click="downloadImageDialogVisible = false"
  412. >确 定</el-button
  413. >
  414. </div>
  415. </el-form>
  416. </el-dialog>
  417. </div>
  418. </el-main>
  419. </el-container>
  420. </template>
  421. <script>
  422. import { mapState } from "vuex";
  423. import commonFormVue from "../component/commonForm.vue";
  424. import pagePrivilege from "../mixin/pagePrivilege.js";
  425. // import MD5 from "js-md5";
  426. import SparkMD5 from "spark-md5";
  427. export default {
  428. components: { commonFormVue },
  429. mixins: [pagePrivilege],
  430. data() {
  431. return {
  432. dialogImageUrl: "",
  433. dialogVisible: false,
  434. disabled: false,
  435. loading: false,
  436. uploadAnswerDialogLoading: false,
  437. uploadAnswerDialogVisible: false,
  438. total: 0,
  439. tableLoading: false,
  440. showAllCondition: false,
  441. fileType: "zip",
  442. accept: "application/zip",
  443. fileList: [],
  444. downloadImageDialogVisible: false,
  445. imageAnswerFileList: [],
  446. fileLimit: 6,
  447. form: {
  448. examRecordDataId: null,
  449. hasStranger: null,
  450. courseId: null,
  451. courseLevel: null,
  452. examId: null,
  453. faceSuccessPercentLower: null,
  454. faceSuccessPercentUpper: null,
  455. livenessSuccessPercentLower: null,
  456. livenessSuccessPercentUpper: null,
  457. identityNumber: null,
  458. orgId: null,
  459. studentCode: null,
  460. studentName: null,
  461. isWarn: null,
  462. pageNo: 1,
  463. pageSize: 10,
  464. examType: "",
  465. ORG_FIND_ALL: false, //查询所有机构
  466. examStageId: null,
  467. },
  468. getExamCondition: {
  469. params: {
  470. name: "",
  471. examTypes: "ONLINE#OFFLINE#ONLINE_HOMEWORK",
  472. },
  473. filterCondition: "",
  474. },
  475. tableData: [],
  476. exportUrl:
  477. "/api/ecs_oe_admin/exam/student/examScheduling/list/export/async",
  478. exportFileName: "考试进度详情",
  479. currentOfflineExamRecordDataId: "",
  480. offlineAnswerFile: "",
  481. currentPagePrivileges: {
  482. EXAM_PARTICULARS_EXPORT: false, //导出
  483. },
  484. summary: "",
  485. summaryList: [],
  486. md5Size: 0,
  487. optZipVisible: false,
  488. optPdfVisible: false,
  489. optImageVisible: false,
  490. };
  491. },
  492. computed: {
  493. ...mapState({ user: (state) => state.user }),
  494. batchSubmitUploadDisabled() {
  495. return this.fileList.length == 0 || this.fileList.length != this.md5Size;
  496. },
  497. //计算是否显示图片上传框
  498. uploadDisabled() {
  499. return this.fileList.length >= this.fileLimit;
  500. },
  501. },
  502. created() {
  503. if (this.form.examId) {
  504. this.getUploadFileType();
  505. }
  506. },
  507. methods: {
  508. exportData() {
  509. if (!this.form.examId) {
  510. this.$notify({
  511. title: "警告",
  512. message: "请选择考试",
  513. type: "warning",
  514. duration: 1000,
  515. });
  516. return false;
  517. }
  518. this.$confirm("确定执行导出?", "提示", {
  519. confirmButtonText: "确定",
  520. cancelButtonText: "取消",
  521. type: "warning",
  522. }).then(() => {
  523. this.$http
  524. .get(this.exportUrl, {
  525. params: {
  526. query: this.form,
  527. },
  528. })
  529. .then(() => {
  530. this.$notify({
  531. type: "success",
  532. message: "正在后台导出中,请稍后到“导出任务列表”中下载!",
  533. });
  534. })
  535. .catch((error) => {
  536. this.$notify({
  537. type: "error",
  538. message: error.response.data.desc,
  539. });
  540. });
  541. });
  542. },
  543. cancelUpload() {
  544. this.uploadAnswerDialogVisible = false;
  545. this.removeImgs();
  546. },
  547. handleChange(file, fileList) {
  548. this.fileList = fileList;
  549. this.calcSummary(this.fileList);
  550. },
  551. getFileMD5(dataFile, callback) {
  552. var fileReader = new FileReader();
  553. var spark = new SparkMD5(); //创建md5对象(基于SparkMD5)
  554. if (dataFile.size > 1024 * 1024 * 10) {
  555. var data1 = dataFile.slice(0, 1024 * 1024 * 10); //将文件进行分块 file.slice(start,length)
  556. fileReader.readAsBinaryString(data1); //将文件读取为二进制码
  557. } else {
  558. fileReader.readAsBinaryString(dataFile);
  559. }
  560. //文件读取完毕之后的处理
  561. //a639e28526d1809745b46bf1189594fe 6d9efe0c593b1383482feb229318e03a
  562. fileReader.onload = function (e) {
  563. spark.appendBinary(e.target.result);
  564. var md5 = spark.end();
  565. console.log(md5);
  566. callback(md5);
  567. };
  568. },
  569. handleRemove(file) {
  570. let index = this.fileList.findIndex((p) => p.uid == file.uid);
  571. this.fileList.splice(index, 1);
  572. this.calcSummary(this.fileList);
  573. },
  574. calcSummary(fileList) {
  575. var summaryList = [];
  576. var md5Size = 0;
  577. for (let i = 0; i < fileList.length; i++) {
  578. let f = fileList[i];
  579. this.getFileMD5(f.raw, (md5) => {
  580. summaryList.push({ index: i, summary: md5 });
  581. md5Size++;
  582. this.summaryList = summaryList;
  583. this.md5Size = md5Size;
  584. });
  585. }
  586. },
  587. handlePictureCardPreview(file) {
  588. this.dialogImageUrl = file.url;
  589. this.dialogVisible = true;
  590. },
  591. handleDownload(file) {
  592. window.open(file.url);
  593. console.log(file);
  594. },
  595. removeImgs() {
  596. this.fileList = [];
  597. this.$refs.upload.clearFiles();
  598. },
  599. resetForm() {
  600. this.form = {
  601. examRecordDataId: null,
  602. hasStranger: null,
  603. courseId: null,
  604. courseLevel: null,
  605. examId: null,
  606. faceSuccessPercentLower: null,
  607. faceSuccessPercentUpper: null,
  608. livenessSuccessPercentLower: null,
  609. livenessSuccessPercentUpper: null,
  610. identityNumber: null,
  611. orgId: this.form.ORG_FIND_ALL ? null : this.form.orgId,
  612. studentCode: null,
  613. studentName: null,
  614. isWarn: null,
  615. pageNo: 1,
  616. pageSize: 10,
  617. examType: "",
  618. ORG_FIND_ALL: this.form.ORG_FIND_ALL,
  619. examStageId: null,
  620. };
  621. },
  622. showMoreCondition() {
  623. this.showAllCondition = true;
  624. },
  625. showSimpleCondition() {
  626. this.$notify({
  627. title: "提示",
  628. message: "高级查询条件值已重置",
  629. type: "info",
  630. duration: 2000,
  631. });
  632. this.resetForm();
  633. this.showAllCondition = false;
  634. },
  635. search(type) {
  636. if (!this.form.examId) {
  637. this.$notify({
  638. title: "警告",
  639. message: "请选择考试",
  640. type: "warning",
  641. duration: 2000,
  642. });
  643. return false;
  644. }
  645. if (type && type == "clickSelectBtn") {
  646. this.form.pageNo = 1;
  647. }
  648. this.tableLoading = true;
  649. this.$http
  650. .post("/api/ecs_oe_admin/exam/student/examScheduling/list", this.form)
  651. .then((response) => {
  652. if (response.data) {
  653. var dataList = response.data.content;
  654. this.tableData = dataList;
  655. this.total = response.data.totalElements;
  656. } else {
  657. this.tableData = [];
  658. }
  659. this.tableLoading = false;
  660. });
  661. this.getUploadFileType();
  662. },
  663. selectable(row) {
  664. return row.isWarn;
  665. },
  666. handleSelectionChange(val) {
  667. this.multipleSelection = val;
  668. },
  669. /**
  670. * pagesize改变时触发
  671. */
  672. handleSizeChange(val) {
  673. this.form.pageSize = val;
  674. this.search();
  675. },
  676. /**
  677. * 当前页改变时触发
  678. */
  679. handleCurrentChange() {
  680. this.search();
  681. },
  682. previewPaper(examStudentId) {
  683. this.$http
  684. .get("/api/ecs_oe_admin/exam/record/select/byExamStudentId", {
  685. params: { examStudentId: examStudentId },
  686. })
  687. .then((response) => {
  688. if (response.data) {
  689. var examRecordList = response.data;
  690. if (examRecordList && examRecordList.length > 0) {
  691. window.open(
  692. "/admin/preview_paper/" + examRecordList[0].basePaperId
  693. );
  694. } else {
  695. this.$notify({
  696. title: "提示",
  697. message: "该考生未参加考试",
  698. type: "error",
  699. duration: 2000,
  700. });
  701. }
  702. }
  703. });
  704. },
  705. exportPaper(examStudentId) {
  706. this.loading = true;
  707. this.$http
  708. .get("/api/ecs_oe_admin/exam/record/select/byExamStudentId", {
  709. params: { examStudentId: examStudentId },
  710. })
  711. .then((response) => {
  712. if (response.data) {
  713. var examRecordList = response.data;
  714. if (examRecordList && examRecordList.length > 0) {
  715. var basePaperId = examRecordList[0].basePaperId;
  716. this.$http
  717. .get(
  718. "/api/ecs_ques/paper/export/" +
  719. basePaperId +
  720. "/PAPER/offLine",
  721. {
  722. responseType: "arraybuffer",
  723. filename: "utf-8",
  724. }
  725. )
  726. .then((response) => {
  727. if (response.data && response.data.byteLength > 0) {
  728. var blob = new Blob([response.data], {
  729. type: "application/zip",
  730. });
  731. var url = URL.createObjectURL(blob);
  732. var fileName = response.headers["content-disposition"]
  733. .split(";")[1]
  734. .replace("filename=", "");
  735. var a = document.createElement("a");
  736. a.href = url;
  737. a.download = decodeURI(fileName);
  738. a.target = "_blank";
  739. a.click();
  740. URL.revokeObjectURL(url);
  741. } else {
  742. this.$notify({
  743. title: "提示",
  744. message: "无相关文件",
  745. type: "error",
  746. duration: 2000,
  747. });
  748. }
  749. this.loading = false;
  750. })
  751. .catch(() => {
  752. this.loading = false;
  753. });
  754. } else {
  755. this.loading = false;
  756. this.$notify({
  757. title: "提示",
  758. message: "该考生未参加考试",
  759. type: "error",
  760. duration: 2000,
  761. });
  762. }
  763. }
  764. });
  765. },
  766. openUploadAnswerDialog(examStudentId) {
  767. this.fileList = [];
  768. this.imageAnswerFileList = [];
  769. // this.offlineAnswerFile = "";
  770. this.cleanOfflineFile();
  771. this.$http
  772. .get("/api/ecs_oe_admin/exam/record/data/findByExamStudentId", {
  773. params: { examStudentId: examStudentId },
  774. })
  775. .then((response) => {
  776. var examRecordDataList = response.data;
  777. if (examRecordDataList.length == 0) {
  778. this.$notify({
  779. title: "提示",
  780. message: "该考生未参加考试",
  781. type: "error",
  782. duration: 2000,
  783. });
  784. } else {
  785. this.uploadAnswerDialogVisible = true;
  786. this.currentOfflineExamStudentId = examStudentId;
  787. this.currentOfflineExamRecordDataId = examRecordDataList[0].id;
  788. }
  789. });
  790. },
  791. uploadAnswerChange(event) {
  792. if (event.target.files.length > 0) {
  793. this.offlineAnswerFile = event.target.files[0];
  794. } else {
  795. this.offlineAnswerFile = "";
  796. }
  797. },
  798. doUploadAnswer() {
  799. var index = this.offlineAnswerFile.name.lastIndexOf(".");
  800. var fileNameLength = this.offlineAnswerFile.name.length;
  801. var fileSuffix = this.offlineAnswerFile.name
  802. .substring(index + 1, fileNameLength)
  803. .toUpperCase();
  804. this.$http
  805. .get(
  806. "/api/ecs_exam_work/exam/property/" +
  807. this.form.examId +
  808. "/OFFLINE_UPLOAD_FILE_TYPE"
  809. )
  810. .then((response) => {
  811. var allowfileSuffixs = response.data;
  812. if (!allowfileSuffixs || allowfileSuffixs.length == 0) {
  813. this.$notify({
  814. title: "提示",
  815. message: "当前考试设置不允许上传附件",
  816. type: "error",
  817. duration: 2000,
  818. });
  819. return false;
  820. }
  821. if (allowfileSuffixs.toString().indexOf(fileSuffix) < 0) {
  822. this.$notify({
  823. title: "提示",
  824. message:
  825. "当前考试允许上传文件格式为:" + allowfileSuffixs.toString(),
  826. type: "error",
  827. duration: 2000,
  828. });
  829. return false;
  830. }
  831. this.uploadAnswerDialogLoading = true;
  832. let config = {
  833. headers: { "Content-Type": "multipart/form-data" },
  834. };
  835. let param = new FormData();
  836. param.append("file", this.offlineAnswerFile);
  837. param.append("examRecordDataId", this.currentOfflineExamRecordDataId);
  838. this.$http
  839. .post("/api/ecs_oe_admin/offlineExam/submitPaper", param, config)
  840. .then(() => {
  841. this.$notify({
  842. title: "提示",
  843. message: "上传成功",
  844. type: "success",
  845. duration: 2000,
  846. });
  847. this.uploadAnswerDialogVisible = false;
  848. this.uploadAnswerDialogLoading = false;
  849. this.$refs.offlineFileInput.value = "";
  850. this.offlineAnswerFile = "";
  851. this.search();
  852. })
  853. .catch((e) => {
  854. let errMsg = "上传失败";
  855. if (e.response) {
  856. errMsg = e.response.data.desc;
  857. }
  858. this.$notify({
  859. title: "提示",
  860. message: errMsg,
  861. type: "error",
  862. duration: 2000,
  863. });
  864. this.uploadAnswerDialogLoading = false;
  865. this.$refs.offlineFileInput.value = "";
  866. this.offlineAnswerFile = "";
  867. });
  868. });
  869. },
  870. //获取支持的文件上传类型
  871. getUploadFileType() {
  872. this.$http
  873. .get(
  874. "/api/ecs_exam_work/exam/property/" +
  875. this.form.examId +
  876. "/OFFLINE_UPLOAD_FILE_TYPE"
  877. )
  878. .then((response) => {
  879. var allowfileSuffixs = response.data;
  880. if (!allowfileSuffixs || allowfileSuffixs.length == 0) {
  881. return false;
  882. }
  883. if (allowfileSuffixs.some((p) => p.toUpperCase() == "ZIP")) {
  884. this.optZipVisible = true;
  885. }
  886. if (allowfileSuffixs.some((p) => p.toUpperCase() == "PDF")) {
  887. this.optPdfVisible = true;
  888. }
  889. if (allowfileSuffixs.some((p) => p.toUpperCase() == "IMAGE")) {
  890. this.optImageVisible = true;
  891. }
  892. });
  893. },
  894. beforeUpload(file) {
  895. var index = file.name.lastIndexOf(".");
  896. var fileNameLength = file.name.length;
  897. var fileSuffix = file.name
  898. .substring(index + 1, fileNameLength)
  899. .toUpperCase();
  900. this.$http
  901. .get(
  902. "/api/ecs_exam_work/exam/property/" +
  903. this.form.examId +
  904. "/OFFLINE_UPLOAD_FILE_TYPE"
  905. )
  906. .then((response) => {
  907. var allowfileSuffixs = response.data;
  908. if (!allowfileSuffixs || allowfileSuffixs.length == 0) {
  909. this.$notify({
  910. title: "提示",
  911. message: "当前考试设置不允许上传附件",
  912. type: "error",
  913. duration: 2000,
  914. });
  915. return false;
  916. }
  917. if (allowfileSuffixs.toString().indexOf(fileSuffix) < 0) {
  918. this.$notify({
  919. title: "提示",
  920. message:
  921. "当前考试允许上传文件格式为:" + allowfileSuffixs.toString(),
  922. type: "error",
  923. duration: 2000,
  924. });
  925. return false;
  926. }
  927. this.offlineAnswerFile = file;
  928. });
  929. this.uploadData = {
  930. examRecordDataId: this.currentOfflineExamRecordDataId,
  931. summary: this.summary,
  932. };
  933. console.log(this.uploadData);
  934. let promise = new Promise((resolve) => {
  935. this.$nextTick(function () {
  936. resolve(true);
  937. });
  938. });
  939. return promise; //通过返回一个promis对象解决
  940. },
  941. submitUpload() {
  942. this.uploadAnswerDialogLoading = true;
  943. let config = {
  944. headers: { "Content-Type": "multipart/form-data" },
  945. };
  946. let param = new FormData();
  947. param.append("file", this.offlineAnswerFile);
  948. param.append("examRecordDataId", this.currentOfflineExamRecordDataId);
  949. param.append("fileType", this.fileType);
  950. this.$http
  951. .post("/api/ecs_oe_admin/offlineExam/submitPaper", param, config)
  952. .then(() => {
  953. this.$notify({
  954. title: "提示",
  955. message: "上传成功",
  956. type: "success",
  957. duration: 2000,
  958. });
  959. this.uploadAnswerDialogVisible = false;
  960. this.$refs.offlineFileInput.value = "";
  961. this.offlineAnswerFile = "";
  962. this.search();
  963. })
  964. .catch((e) => {
  965. let errMsg = "上传失败";
  966. if (e.response) {
  967. errMsg = e.response.data.desc;
  968. }
  969. this.$notify({
  970. title: "提示",
  971. message: errMsg,
  972. type: "error",
  973. duration: 2000,
  974. });
  975. this.uploadAnswerDialogLoading = false;
  976. this.$refs.offlineFileInput.value = "";
  977. this.offlineAnswerFile = "";
  978. });
  979. },
  980. cleanOfflineFile() {
  981. if (this.$refs.offlineFileInput) {
  982. this.$refs.offlineFileInput.value = "";
  983. }
  984. this.offlineAnswerFile = "";
  985. },
  986. downloadAnswer(files) {
  987. if (files && files.length > 0) {
  988. if (files[0].fileType != "image") {
  989. window.open(files[0].offlineFileUrl);
  990. return;
  991. }
  992. this.imageAnswerFileList = [];
  993. for (let f of files) {
  994. this.imageAnswerFileList.push({
  995. url: f.offlineFileUrl,
  996. name: f.offlineFileName,
  997. });
  998. }
  999. this.downloadImageDialogVisible = true;
  1000. }
  1001. },
  1002. handleFileTypeChange(ft) {
  1003. switch (ft) {
  1004. case "zip":
  1005. this.accept = "application/zip";
  1006. break;
  1007. case "pdf":
  1008. this.accept = "application/pdf";
  1009. break;
  1010. case "image":
  1011. this.accept = "image/jpeg,image/png";
  1012. break;
  1013. }
  1014. },
  1015. batchSubmitUpload() {
  1016. this.$refs.upload.submit();
  1017. let params = new FormData();
  1018. params.append("examRecordDataId", this.currentOfflineExamRecordDataId);
  1019. params.append("fileType", this.fileType);
  1020. for (let f of this.fileList) {
  1021. params.append("fileArray", f.raw);
  1022. }
  1023. //先对文件md5进行排序(按索引正序排列)
  1024. this.summaryList.sort((a, b) => a.index - b.index);
  1025. let summaries = [];
  1026. for (let s of this.summaryList) {
  1027. summaries.push(s.summary);
  1028. }
  1029. params.append("fileMd5Array", summaries);
  1030. let config = {
  1031. headers: { "Content-Type": "multipart/form-data" },
  1032. };
  1033. this.$http
  1034. .post("/api/ecs_oe_admin/offlineExam/batchSubmitPaper", params, config)
  1035. .then(() => {
  1036. this.$notify({
  1037. title: "提示",
  1038. message: "上传成功",
  1039. type: "success",
  1040. duration: 2000,
  1041. });
  1042. this.uploadAnswerDialogVisible = false;
  1043. this.removeImgs();
  1044. this.offlineAnswerFile = "";
  1045. this.search();
  1046. })
  1047. .catch((e) => {
  1048. let errMsg = "上传失败";
  1049. if (e.response) {
  1050. errMsg = e.response.data.desc;
  1051. }
  1052. this.$notify({
  1053. title: "提示",
  1054. message: errMsg,
  1055. type: "error",
  1056. duration: 2000,
  1057. });
  1058. this.uploadAnswerDialogLoading = false;
  1059. this.offlineAnswerFile = "";
  1060. });
  1061. },
  1062. beforeFileUpload(file) {
  1063. const isLt5M = file.size / 1024 / 1024 <= 5;
  1064. if (!isLt5M) {
  1065. this.$message.error("上传的单个数据文件大小不能超过5MB!");
  1066. let index = this.fileList.findIndex((p) => p.uid == file.uid);
  1067. this.fileList.splice(index, 1);
  1068. this.calcSummary(this.fileList);
  1069. }
  1070. return isLt5M;
  1071. },
  1072. handleSuccess(response, file, fileList) {
  1073. console.log(response);
  1074. console.log(file);
  1075. console.log(fileList);
  1076. this.$message.success("上传成功");
  1077. },
  1078. customUpload(file) {
  1079. console.log(file);
  1080. return false;
  1081. },
  1082. },
  1083. };
  1084. </script>
  1085. <style scoped>
  1086. .offline_file {
  1087. color: blue;
  1088. }
  1089. .disabled .el-upload--picture-card {
  1090. display: none !important;
  1091. }
  1092. </style>
  1093. <style scoped src="../style/common.css"></style>