practiceExam.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. <template>
  2. <div>
  3. <LinkTitlesCustom
  4. :currentPaths="['考试管理', '考试信息', '练习考试设置']"
  5. />
  6. <section class="content">
  7. <div class="box box-info">
  8. <!-- 正文信息 -->
  9. <div class="box-body">
  10. <el-form
  11. :inline="true"
  12. :rules="rules"
  13. ref="form"
  14. :model="form"
  15. label-position="right"
  16. inline-message
  17. >
  18. <div style="margin-bottom: 10px">
  19. <el-button type="primary" size="small" @click="saveExam"
  20. >保 存</el-button
  21. >
  22. <el-button
  23. type="primary"
  24. size="small"
  25. @click="back"
  26. icon="el-icon-arrow-left"
  27. >返 回</el-button
  28. >
  29. </div>
  30. <el-tabs type="border-card" v-model="activeName">
  31. <!-- 基础信息 -->
  32. <el-tab-pane label="基础信息" name="tab1">
  33. <el-row v-if="examId != 'add'">
  34. <el-form-item
  35. label="ID"
  36. prop="id"
  37. :label-width="style.label_width_tab1"
  38. >
  39. <el-input
  40. v-model="form.id"
  41. class="input"
  42. :disabled="true"
  43. maxlength="20"
  44. ></el-input>
  45. </el-form-item>
  46. </el-row>
  47. <el-row v-if="examId != 'add'">
  48. <el-form-item
  49. label="考试编码"
  50. placeholder="请输入考试编码"
  51. prop="code"
  52. :label-width="style.label_width_tab1"
  53. >
  54. <el-input
  55. v-model="form.code"
  56. class="input"
  57. :disabled="examId != 'add'"
  58. maxlength="20"
  59. ></el-input>
  60. </el-form-item>
  61. </el-row>
  62. <el-row>
  63. <el-form-item
  64. label="考试名称"
  65. :label-width="style.label_width_tab1"
  66. placeholder="请输入考试名称"
  67. prop="name"
  68. >
  69. <el-input
  70. maxlength="20"
  71. v-model="form.name"
  72. class="input"
  73. ></el-input>
  74. </el-form-item>
  75. </el-row>
  76. <el-row>
  77. <el-form-item
  78. label="考试类型"
  79. :label-width="style.label_width_tab1"
  80. >
  81. <el-select
  82. class="input"
  83. :disabled="true"
  84. v-model="form.examType"
  85. placeholder="请选择"
  86. >
  87. <el-option
  88. v-for="item in examTypeList"
  89. :key="item.value"
  90. :label="item.label"
  91. :value="item.value"
  92. >
  93. </el-option>
  94. </el-select>
  95. </el-form-item>
  96. </el-row>
  97. <el-row>
  98. <el-form-item
  99. label="状态"
  100. :label-width="style.label_width_tab1"
  101. >
  102. <el-radio-group v-model="form.enable" class="input">
  103. <el-radio label="true">启用</el-radio>
  104. <el-radio label="false">禁用</el-radio>
  105. </el-radio-group>
  106. </el-form-item>
  107. </el-row>
  108. <el-row>
  109. <el-form-item
  110. label="考试时间"
  111. prop="examDatetimeRange"
  112. :label-width="style.label_width_tab1"
  113. >
  114. <el-date-picker
  115. class="input"
  116. v-model="examDatetimeRange"
  117. type="datetimerange"
  118. range-separator="至"
  119. start-placeholder="开始日期"
  120. end-placeholder="结束日期"
  121. value-format="yyyy-MM-dd HH:mm:ss"
  122. :clearable="false"
  123. >
  124. </el-date-picker>
  125. </el-form-item>
  126. </el-row>
  127. </el-tab-pane>
  128. <!-- 控制设置 -->
  129. <el-tab-pane label="控制设置" name="tab2">
  130. <el-row>
  131. <el-form-item
  132. label="考试时长"
  133. prop="duration"
  134. :label-width="style.label_width_tab2"
  135. >
  136. <el-input
  137. maxlength="20"
  138. class="input"
  139. v-model.trim.number="form.duration"
  140. auto-complete="off"
  141. ><template slot="append"
  142. >分钟</template
  143. ></el-input
  144. >
  145. </el-form-item>
  146. </el-row>
  147. <el-row>
  148. <el-form-item
  149. label="考试次数"
  150. prop="examTimes"
  151. :label-width="style.label_width_tab2"
  152. >
  153. <el-input
  154. maxlength="20"
  155. class="input"
  156. v-model.trim.number="form.examTimes"
  157. auto-complete="off"
  158. ><template slot="append"
  159. >次</template
  160. ></el-input
  161. >
  162. </el-form-item>
  163. </el-row>
  164. <el-row>
  165. <el-form-item
  166. label="交卷冻结时间"
  167. prop="FREEZE_TIME"
  168. :label-width="style.label_width_tab2"
  169. >
  170. <el-input
  171. maxlength="20"
  172. class="input"
  173. v-model.trim.number="form.properties.FREEZE_TIME"
  174. auto-complete="off"
  175. ><template slot="append"
  176. >分钟</template
  177. ></el-input
  178. >
  179. </el-form-item>
  180. </el-row>
  181. <el-row>
  182. <el-form-item
  183. label="断点续考时间"
  184. prop="EXAM_RECONNECT_TIME"
  185. :label-width="style.label_width_tab2"
  186. >
  187. <el-input
  188. maxlength="20"
  189. class="input"
  190. v-model.trim.number="form.properties.EXAM_RECONNECT_TIME"
  191. auto-complete="off"
  192. ><template slot="append"
  193. >分钟</template
  194. ></el-input
  195. >
  196. </el-form-item>
  197. </el-row>
  198. </el-tab-pane>
  199. <el-tab-pane label="显示设置" name="tab3">
  200. <el-row v-if="show_ckeditor">
  201. <el-form-item
  202. label="考前说明"
  203. :label-width="style.label_width_tab3"
  204. >
  205. <ckeditor
  206. v-model="form.properties.BEFORE_EXAM_REMARK"
  207. ></ckeditor>
  208. </el-form-item>
  209. </el-row>
  210. <el-row>
  211. <el-form-item
  212. label="客观题成绩显示"
  213. :label-width="style.label_width_tab3"
  214. >
  215. <el-radio-group
  216. v-model="form.properties.IS_OBJ_SCORE_VIEW"
  217. class="input"
  218. >
  219. <el-radio label="true">开启</el-radio>
  220. <el-radio label="false">关闭</el-radio>
  221. </el-radio-group>
  222. </el-form-item>
  223. </el-row>
  224. <el-row>
  225. <el-form-item
  226. label="练习模式"
  227. :label-width="style.label_width_tab3"
  228. >
  229. <el-radio-group
  230. v-model="form.properties.PRACTICE_TYPE"
  231. class="input"
  232. >
  233. <el-radio label="IN_PRACTICE">边答边显示答案</el-radio>
  234. <el-radio label="AFTER_PRACTICE"
  235. >结束统一显示答案</el-radio
  236. >
  237. <el-radio label="NO_ANSWER">不显示答案</el-radio>
  238. </el-radio-group>
  239. </el-form-item>
  240. </el-row>
  241. </el-tab-pane>
  242. </el-tabs>
  243. </el-form>
  244. </div>
  245. </div>
  246. </section>
  247. </div>
  248. </template>
  249. <script>
  250. import { EXAM_TYPE, EXAM_WORK_API } from "@/constants/constants.js";
  251. import moment from "moment";
  252. import ckeditor from "@/components/ckeditor.vue";
  253. import LinkTitlesCustom from "@/components/LinkTitlesCustom.vue";
  254. let _this = null;
  255. let validateCode = (rule, value, callback) => {
  256. let code = _this.form.code;
  257. if (code == "") {
  258. callback(new Error("请输入考试编码"));
  259. if (!_this.toActiveName) {
  260. _this.toActiveName = "tab1";
  261. _this.activeName = "tab1";
  262. }
  263. } else {
  264. callback();
  265. }
  266. };
  267. let validateName = (rule, value, callback) => {
  268. let name = _this.form.name;
  269. if (name == "") {
  270. callback(new Error("请输入考试名称"));
  271. if (!_this.toActiveName) {
  272. _this.toActiveName = "tab1";
  273. _this.activeName = "tab1";
  274. }
  275. } else {
  276. callback();
  277. }
  278. };
  279. let validateExamDatetimeRange = (rule, value, callback) => {
  280. let examDatetimeRange = _this.examDatetimeRange;
  281. if (!examDatetimeRange) {
  282. callback(new Error("请输入考试时间"));
  283. if (!_this.toActiveName) {
  284. _this.toActiveName = "tab1";
  285. _this.activeName = "tab1";
  286. }
  287. } else {
  288. callback();
  289. }
  290. };
  291. let validateDuration = (rule, value, callback) => {
  292. let duration = _this.form.duration;
  293. if (duration === "") {
  294. callback(new Error("请输入考试时长"));
  295. if (!_this.toActiveName) {
  296. _this.toActiveName = "tab2";
  297. _this.activeName = "tab2";
  298. }
  299. } else if (0 > duration || !duration.toString().match(/^[1-9]\d*|0$/)) {
  300. callback(new Error("只能是非负整数"));
  301. if (!_this.toActiveName) {
  302. _this.toActiveName = "tab2";
  303. _this.activeName = "tab2";
  304. }
  305. } else {
  306. callback();
  307. }
  308. };
  309. let validateExamTimes = (rule, value, callback) => {
  310. let examTimes = _this.form.examTimes;
  311. if (examTimes === "") {
  312. callback(new Error("请输入考试次数"));
  313. if (!_this.toActiveName) {
  314. _this.toActiveName = "tab2";
  315. _this.activeName = "tab2";
  316. }
  317. } else if (0 >= examTimes || !examTimes.toString().match(/^[1-9]\d*$/)) {
  318. callback(new Error("只能是正整数"));
  319. if (!_this.toActiveName) {
  320. _this.toActiveName = "tab2";
  321. _this.activeName = "tab2";
  322. }
  323. } else {
  324. callback();
  325. }
  326. };
  327. let validateFreezeTime = (rule, value, callback) => {
  328. let freezeTime = _this.form.properties.FREEZE_TIME;
  329. let duration = _this.form.duration;
  330. if (freezeTime === "") {
  331. callback(new Error("请输入交卷冻结时长"));
  332. if (!_this.toActiveName) {
  333. _this.toActiveName = "tab2";
  334. _this.activeName = "tab2";
  335. }
  336. } else if (0 > freezeTime || !freezeTime.toString().match(/^[1-9]\d*|0$/)) {
  337. callback(new Error("只能是非负整数"));
  338. if (!_this.toActiveName) {
  339. _this.toActiveName = "tab2";
  340. _this.activeName = "tab2";
  341. }
  342. } else if (duration != "" && parseInt(freezeTime) > parseInt(duration)) {
  343. callback(new Error("交卷冻结时长不能大于考试时长"));
  344. if (!_this.toActiveName) {
  345. _this.toActiveName = "tab2";
  346. _this.activeName = "tab2";
  347. }
  348. } else {
  349. callback();
  350. }
  351. };
  352. let validateExamReconnectTime = (rule, value, callback) => {
  353. let examReconnectTime = _this.form.properties.EXAM_RECONNECT_TIME;
  354. if (examReconnectTime === "") {
  355. callback(new Error("请输入断点续考时间"));
  356. if (!_this.toActiveName) {
  357. _this.toActiveName = "tab2";
  358. _this.activeName = "tab2";
  359. }
  360. } else if (
  361. 0 >= examReconnectTime ||
  362. !examReconnectTime.toString().match(/^[1-9]\d*$/)
  363. ) {
  364. callback(new Error("只能是正整数"));
  365. if (!_this.toActiveName) {
  366. _this.toActiveName = "tab2";
  367. _this.activeName = "tab2";
  368. }
  369. } else {
  370. callback();
  371. }
  372. };
  373. export default {
  374. components: {
  375. ckeditor,
  376. LinkTitlesCustom
  377. },
  378. data() {
  379. return {
  380. style: {
  381. label_width_tab1: "80px",
  382. label_width_tab2: "110px",
  383. label_width_tab3: "120px"
  384. },
  385. activeName: "tab1",
  386. toActiveName: null,
  387. examDatetimeRange: [],
  388. show_ckeditor: false,
  389. form: {
  390. started: false,
  391. name: "",
  392. examType: "PRACTICE",
  393. examTimes: 1,
  394. beginTime: null,
  395. endTime: null,
  396. duration: 120,
  397. enable: "true",
  398. properties: {
  399. FREEZE_TIME: 0,
  400. EXAM_RECONNECT_TIME: 30,
  401. BEFORE_EXAM_REMARK: "",
  402. AFTER_EXAM_REMARK: "",
  403. IS_OBJ_SCORE_VIEW: "true",
  404. PRACTICE_TYPE: "IN_PRACTICE"
  405. }
  406. },
  407. examTypeList: EXAM_TYPE,
  408. examId: "",
  409. rules: {
  410. code: [{ required: true, validator: validateCode, trigger: "blur" }],
  411. name: [{ required: true, validator: validateName, trigger: "blur" }],
  412. examDatetimeRange: [
  413. {
  414. required: true,
  415. validator: validateExamDatetimeRange,
  416. trigger: "blur"
  417. }
  418. ],
  419. duration: [
  420. { required: true, validator: validateDuration, trigger: "blur" }
  421. ],
  422. examTimes: [
  423. { required: true, validator: validateExamTimes, trigger: "blur" }
  424. ],
  425. FREEZE_TIME: [
  426. { required: true, validator: validateFreezeTime, trigger: "blur" }
  427. ],
  428. EXAM_RECONNECT_TIME: [
  429. {
  430. required: true,
  431. validator: validateExamReconnectTime,
  432. trigger: "blur"
  433. }
  434. ]
  435. }
  436. };
  437. },
  438. methods: {
  439. init() {
  440. if (this.examId != "add") {
  441. let url = EXAM_WORK_API + "/exam/" + this.examId;
  442. this.$httpWithMsg.get(url).then(response => {
  443. let body = response.data;
  444. body.properties = this.form.properties;
  445. this.form = Object.assign(this.form, response.data);
  446. this.form.enable = this.form.enable ? "true" : "false";
  447. this.examDatetimeRange = [this.form.beginTime, this.form.endTime];
  448. console.log("getOnlineExam(); form: ", this.form);
  449. let url = EXAM_WORK_API + "/exam/allProperties/" + this.examId;
  450. this.$httpWithMsg.get(url).then(response => {
  451. this.form.properties = Object.assign(
  452. this.form.properties,
  453. response.data
  454. );
  455. this.form.properties.IS_OBJ_SCORE_VIEW =
  456. this.form.properties.IS_OBJ_SCORE_VIEW == "true" ? true : false;
  457. this.show_ckeditor = true;
  458. });
  459. });
  460. } else {
  461. let now = moment().format("YYYY-MM-DD HH:mm:ss");
  462. this.examDatetimeRange = [now, now];
  463. this.show_ckeditor = true;
  464. }
  465. },
  466. saveExam: function() {
  467. this.toActiveName = null;
  468. this.form.beginTime = this.examDatetimeRange[0];
  469. this.form.endTime = this.examDatetimeRange[1];
  470. console.log(this.form);
  471. let url = EXAM_WORK_API + "/exam";
  472. this.$refs.form.validate(valid => {
  473. if (valid) {
  474. if (this.examId != "add") {
  475. this.$httpWithMsg.put(url, this.form).then(response => {
  476. if (200 != response.status) {
  477. this.$notify({
  478. type: "error",
  479. message: response.body.desc
  480. });
  481. return;
  482. }
  483. this.$notify({
  484. type: "success",
  485. message: "保存成功"
  486. });
  487. });
  488. } else {
  489. this.form.code = this.form.name;
  490. this.$httpWithMsg.post(url, this.form).then(response => {
  491. console.log(response);
  492. this.$notify({
  493. type: "success",
  494. message: "新增成功"
  495. });
  496. this.examId = response.data.id;
  497. this.form.id = this.examId;
  498. this.$router.push({
  499. path: "/examwork/practiceExam/" + response.data.id
  500. });
  501. });
  502. }
  503. } else {
  504. return false;
  505. }
  506. });
  507. },
  508. back() {
  509. this.$router.push({ path: "/examwork/examInfo" });
  510. }
  511. },
  512. created() {
  513. _this = this;
  514. this.examId = this.$route.params.id;
  515. this.init();
  516. }
  517. };
  518. </script>
  519. <style scoped>
  520. .input {
  521. width: 440px;
  522. }
  523. .input >>> .el-input__inner {
  524. -webkit-appearance: button;
  525. }
  526. </style>