ExamStructure.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. <template>
  2. <section class="content" style="margin-top: 20px;">
  3. <div class="box box-info">
  4. <!-- 正文信息 -->
  5. <div class="box-body">
  6. <el-form
  7. :model="formSearch"
  8. :inline="true"
  9. label-position="right"
  10. label-width="100px"
  11. >
  12. <el-form-item label="学校">
  13. <el-select
  14. v-model="formSearch.orgId"
  15. placeholder="请选择"
  16. clearable
  17. @change="loadExamList(formSearch.orgId)"
  18. >
  19. <el-option
  20. v-for="item in orgList"
  21. :label="item.orgName"
  22. :value="item.orgId"
  23. :key="item.orgId"
  24. ></el-option>
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item label="考试">
  28. <el-select
  29. v-model="formSearch.examId"
  30. placeholder="请选择"
  31. @change="searchRecords(1)"
  32. clearable
  33. >
  34. <el-option
  35. v-for="item in examList"
  36. :label="item.examName"
  37. :value="item.examId"
  38. :key="item.examId"
  39. ></el-option>
  40. </el-select>
  41. </el-form-item>
  42. <el-form-item>
  43. <el-button
  44. size="small"
  45. type="primary"
  46. icon="el-icon-search"
  47. @click="searchRecords(1)"
  48. >查询
  49. </el-button>
  50. <el-button
  51. size="small"
  52. type="primary"
  53. icon="el-icon-plus"
  54. :disabled="!hasPermit"
  55. v-show="!checkEmptyNumber(formSearch.orgId)"
  56. @click="openAddStructureDialog"
  57. >新增
  58. </el-button>
  59. </el-form-item>
  60. </el-form>
  61. <!-- 数据列表 -->
  62. <el-table
  63. v-loading="loading"
  64. :data="tableData"
  65. element-loading-text="数据加载中"
  66. style="width:100%;"
  67. border
  68. >
  69. <el-table-column label="学校名称" prop="orgName" />
  70. <el-table-column label="考试名称" prop="examName" />
  71. <el-table-column width="220" label="题数">
  72. <template slot-scope="scope">
  73. 单选:{{ scope.row.questionStructure.singleChoiceTotal }}<br />
  74. 多选:{{ scope.row.questionStructure.multipleChoiceTotal }}<br />
  75. 判断:{{ scope.row.questionStructure.boolQuestionTotal }}
  76. </template>
  77. </el-table-column>
  78. <el-table-column width="200" label="操作" :context="_self">
  79. <template slot-scope="scope">
  80. <el-button
  81. size="mini"
  82. icon="el-icon-menu"
  83. @click="openCloneStructureDialog(scope.row)"
  84. :disabled="!hasPermit"
  85. >复用
  86. </el-button>
  87. <el-button
  88. size="mini"
  89. type="danger"
  90. icon="el-icon-delete"
  91. @click="removeStructure(scope.row)"
  92. :disabled="!hasPermit"
  93. >删除
  94. </el-button>
  95. </template>
  96. </el-table-column>
  97. </el-table>
  98. <!-- 分页 -->
  99. <div class="page pull-right">
  100. <el-pagination
  101. @current-change="handlePager"
  102. :current-page="formSearch.pageNo"
  103. :page-size="formSearch.pageSize"
  104. :total="totalElements"
  105. layout="total, prev, pager, next, jumper"
  106. ></el-pagination>
  107. </div>
  108. </div>
  109. <!-- 新增考试结构弹窗 -->
  110. <el-dialog
  111. title="新增考试结构"
  112. width="400px"
  113. :visible.sync="addStructureDialog"
  114. @close="closeAddStructureDialog"
  115. >
  116. <el-form
  117. :model="addStructureForm"
  118. ref="addStructureForm"
  119. :rules="rules"
  120. label-position="right"
  121. label-width="100px"
  122. >
  123. <el-form-item label="学校名称" prop="orgId">
  124. <el-select
  125. v-model="addStructureForm.orgId"
  126. placeholder="请选择"
  127. :disabled="true"
  128. class="w220"
  129. >
  130. <el-option
  131. v-for="item in orgList"
  132. :label="item.orgName"
  133. :value="item.orgId"
  134. :key="item.orgId"
  135. ></el-option>
  136. </el-select>
  137. </el-form-item>
  138. <el-form-item label="考试名称" prop="examId">
  139. <el-select
  140. v-model="addStructureForm.examId"
  141. placeholder="请选择"
  142. class="w220"
  143. >
  144. <el-option
  145. v-for="item in examList"
  146. :label="item.examName"
  147. :value="item.examId"
  148. :key="item.examId"
  149. ></el-option>
  150. </el-select>
  151. </el-form-item>
  152. <el-form-item label="单选题数量" prop="singleChoiceTotal">
  153. <el-input
  154. v-model="addStructureForm.questionStructure.singleChoiceTotal"
  155. class="w220"
  156. ></el-input>
  157. </el-form-item>
  158. <el-form-item label="多选题数量" prop="multipleChoiceTotal">
  159. <el-input
  160. v-model="addStructureForm.questionStructure.multipleChoiceTotal"
  161. class="w220"
  162. ></el-input>
  163. </el-form-item>
  164. <el-form-item label="判断题数量" prop="boolQuestionTotal">
  165. <el-input
  166. v-model="addStructureForm.questionStructure.boolQuestionTotal"
  167. class="w220"
  168. ></el-input>
  169. </el-form-item>
  170. <div style="text-align: center">
  171. <el-button type="primary" @click="addStructure">确 定</el-button>
  172. <el-button @click="closeAddStructureDialog">取 消</el-button>
  173. </div>
  174. </el-form>
  175. </el-dialog>
  176. <!-- 复用考试结构弹窗 -->
  177. <el-dialog
  178. title="复用考试结构"
  179. width="450px"
  180. :visible.sync="cloneStructureDialog"
  181. @close="closeCloneStructureDialog"
  182. >
  183. <el-form
  184. :model="cloneStructureForm"
  185. ref="cloneStructureForm"
  186. :rules="rules"
  187. label-position="right"
  188. label-width="80px"
  189. >
  190. <el-tabs v-model="sourceTab">
  191. <el-tab-pane label="原结构信息" name="first">
  192. <el-form-item label="学校名称" prop="orgId">
  193. <el-select
  194. v-model="cloneStructureForm.orgId"
  195. placeholder="请选择"
  196. :disabled="true"
  197. class="w220"
  198. >
  199. <el-option
  200. v-for="item in orgList"
  201. :label="item.orgName"
  202. :value="item.orgId"
  203. :key="item.orgId"
  204. ></el-option>
  205. </el-select>
  206. </el-form-item>
  207. <el-form-item label="考试名称" prop="examId">
  208. <el-select
  209. v-model="cloneStructureForm.examId"
  210. placeholder="请选择"
  211. :disabled="true"
  212. class="w220"
  213. >
  214. <el-option
  215. v-for="item in examList"
  216. :label="item.examName"
  217. :value="item.examId"
  218. :key="item.examId"
  219. ></el-option>
  220. </el-select>
  221. </el-form-item>
  222. </el-tab-pane>
  223. </el-tabs>
  224. <el-tabs v-model="targetTab">
  225. <el-tab-pane label="新结构信息" name="first">
  226. <el-form-item label="学校名称" prop="newOrgId">
  227. <el-select
  228. v-model="cloneStructureForm.newOrgId"
  229. @change="loadCloneExamList(cloneStructureForm.newOrgId)"
  230. placeholder="请选择"
  231. class="w220"
  232. >
  233. <el-option
  234. v-for="item in orgList"
  235. :label="item.orgName"
  236. :value="item.orgId"
  237. :key="item.orgId"
  238. ></el-option>
  239. </el-select>
  240. </el-form-item>
  241. <el-form-item label="考试名称" prop="newExamId">
  242. <el-select
  243. v-model="cloneStructureForm.newExamId"
  244. placeholder="请选择"
  245. class="w220"
  246. >
  247. <el-option
  248. v-for="item in cloneExamList"
  249. :label="item.examName"
  250. :value="item.examId"
  251. :key="item.examId"
  252. ></el-option>
  253. </el-select>
  254. </el-form-item>
  255. </el-tab-pane>
  256. </el-tabs>
  257. <div style="text-align: center">
  258. <el-button type="primary" @click="cloneStructure">确 定</el-button>
  259. <el-button @click="closeCloneStructureDialog">取 消</el-button>
  260. </div>
  261. </el-form>
  262. </el-dialog>
  263. </div>
  264. </section>
  265. </template>
  266. <script>
  267. import { PRINT_API } from "@/constants/constants";
  268. import {} from "../constants/constants.js";
  269. import { mapState } from "vuex";
  270. import { checkEmptyNumber } from "../utils/common.js";
  271. export default {
  272. data() {
  273. let validateSingleChoiceTotal = (rule, value, callback) => {
  274. if (
  275. checkEmptyNumber(
  276. this.addStructureForm.questionStructure.singleChoiceTotal
  277. )
  278. ) {
  279. callback(new Error("请输入正确的数值!"));
  280. return;
  281. }
  282. if (this.addStructureForm.questionStructure.singleChoiceTotal > 1000) {
  283. callback(new Error("请输入合理有效的数值!"));
  284. return;
  285. }
  286. callback();
  287. };
  288. let validateMultipleChoiceTotal = (rule, value, callback) => {
  289. if (
  290. checkEmptyNumber(
  291. this.addStructureForm.questionStructure.multipleChoiceTotal
  292. )
  293. ) {
  294. callback(new Error("请输入正确的数值!"));
  295. return;
  296. }
  297. if (this.addStructureForm.questionStructure.multipleChoiceTotal > 1000) {
  298. callback(new Error("请输入合理有效的数值!"));
  299. return;
  300. }
  301. callback();
  302. };
  303. let validateBoolChoiceTotal = (rule, value, callback) => {
  304. if (
  305. checkEmptyNumber(
  306. this.addStructureForm.questionStructure.boolQuestionTotal
  307. )
  308. ) {
  309. callback(new Error("请输入正确的数值!"));
  310. return;
  311. }
  312. if (this.addStructureForm.questionStructure.boolQuestionTotal > 1000) {
  313. callback(new Error("请输入合理有效的数值!"));
  314. return;
  315. }
  316. callback();
  317. };
  318. return {
  319. formSearch: {
  320. orgId: "",
  321. examId: "",
  322. pageNo: 1,
  323. pageSize: 10
  324. },
  325. curUserRole: {},
  326. hasPermit: false,
  327. totalElements: 0,
  328. loading: false,
  329. tableData: [],
  330. orgList: [],
  331. examList: [],
  332. addStructureDialog: false,
  333. addStructureForm: {
  334. examId: "",
  335. examName: "",
  336. orgId: "",
  337. orgName: "",
  338. questionStructure: {
  339. singleChoiceTotal: 0,
  340. multipleChoiceTotal: 0,
  341. boolQuestionTotal: 0
  342. }
  343. },
  344. cloneStructureDialog: false,
  345. cloneExamList: [],
  346. sourceTab: "first",
  347. targetTab: "first",
  348. cloneStructureForm: {
  349. examId: "",
  350. orgId: "",
  351. newExamId: "",
  352. newExamName: "",
  353. newOrgId: "",
  354. newOrgName: ""
  355. },
  356. rules: {
  357. orgId: [
  358. { required: true, message: "学校不能为空!", trigger: "change" }
  359. ],
  360. examId: [
  361. { required: true, message: "考试不能为空!", trigger: "change" }
  362. ],
  363. newOrgId: [
  364. { required: true, message: "学校不能为空!", trigger: "change" }
  365. ],
  366. newExamId: [
  367. { required: true, message: "考试不能为空!", trigger: "change" }
  368. ],
  369. singleChoiceTotal: [
  370. {
  371. required: true,
  372. validator: validateSingleChoiceTotal,
  373. trigger: "change"
  374. }
  375. ],
  376. multipleChoiceTotal: [
  377. {
  378. required: true,
  379. validator: validateMultipleChoiceTotal,
  380. trigger: "change"
  381. }
  382. ],
  383. boolQuestionTotal: [
  384. {
  385. required: true,
  386. validator: validateBoolChoiceTotal,
  387. trigger: "change"
  388. }
  389. ]
  390. }
  391. };
  392. },
  393. methods: {
  394. handlePager(current) {
  395. /* 处理分页 */
  396. this.searchRecords(current);
  397. },
  398. searchRecords(pageNo) {
  399. this.formSearch.pageNo = pageNo;
  400. /* 查询记录列表 */
  401. let orgId = this.formSearch.orgId;
  402. if (checkEmptyNumber(orgId)) {
  403. this.$notify({
  404. title: "提示",
  405. message: "请选择学校!",
  406. type: "warning"
  407. });
  408. return;
  409. }
  410. this.loading = true;
  411. let url = PRINT_API + "/examStructure/list";
  412. this.$http.post(url, this.formSearch).then(
  413. response => {
  414. this.tableData = response.data.content;
  415. this.totalElements = response.data.totalElements;
  416. this.loading = false;
  417. },
  418. error => {
  419. console.log(error);
  420. this.loading = false;
  421. }
  422. );
  423. },
  424. selectDefault() {
  425. if (this.orgList.length > 0) {
  426. let firstOrgId = this.orgList[0].orgId;
  427. this.formSearch.orgId = firstOrgId;
  428. this.loadExamList(firstOrgId);
  429. }
  430. },
  431. loadOrgList() {
  432. /* 查询学校列表 */
  433. let url = PRINT_API + "/printing/project/org/list";
  434. this.$http.post(url).then(
  435. response => {
  436. this.orgList = response.data;
  437. this.selectDefault();
  438. },
  439. error => {
  440. console.log(error.response);
  441. // ignore
  442. }
  443. );
  444. },
  445. loadExamList(orgId) {
  446. /* 查询考试列表 */
  447. this.formSearch.examId = "";
  448. this.examList = [];
  449. this.tableData = [];
  450. if (!checkEmptyNumber(orgId)) {
  451. let url = PRINT_API + "/printing/project/exam/list?orgId=" + orgId;
  452. this.$http.post(url).then(response => {
  453. this.examList = response.data;
  454. if (this.examList.length > 0) {
  455. this.formSearch.examId = this.examList[0].examId;
  456. this.searchRecords(1);
  457. }
  458. });
  459. }
  460. },
  461. loadCloneExamList(orgId) {
  462. /* 查询考试列表 */
  463. this.cloneStructureForm.newExamId = "";
  464. this.cloneExamList = [];
  465. if (!checkEmptyNumber(orgId)) {
  466. let url = PRINT_API + "/printing/project/exam/list?orgId=" + orgId;
  467. this.$http.post(url).then(response => {
  468. this.cloneExamList = response.data;
  469. });
  470. }
  471. },
  472. getOrgNameById(orgList, orgId) {
  473. for (let i = 0; i < orgList.length; i++) {
  474. if (orgList[i].orgId == orgId) {
  475. return orgList[i].orgName;
  476. }
  477. }
  478. return "";
  479. },
  480. getExamNameById(examList, examId) {
  481. for (let i = 0; i < examList.length; i++) {
  482. if (examList[i].examId == examId) {
  483. return examList[i].examName;
  484. }
  485. }
  486. return "";
  487. },
  488. openAddStructureDialog() {
  489. /* 打开考试结构弹窗 */
  490. this.addStructureDialog = true;
  491. this.addStructureForm.orgId = this.formSearch.orgId;
  492. this.addStructureForm.examId = this.formSearch.examId;
  493. this.addStructureForm.questionStructure.singleChoiceTotal = 0;
  494. this.addStructureForm.questionStructure.multipleChoiceTotal = 0;
  495. this.addStructureForm.questionStructure.boolQuestionTotal = 0;
  496. },
  497. closeAddStructureDialog() {
  498. /* 关闭考试结构弹窗 */
  499. this.addStructureDialog = false;
  500. },
  501. addStructure() {
  502. /* 新增考试结构 */
  503. this.$refs.addStructureForm.validate(valid => {
  504. if (!valid) {
  505. return false;
  506. }
  507. this.addStructureForm.orgName = this.getOrgNameById(
  508. this.orgList,
  509. this.addStructureForm.orgId
  510. );
  511. this.addStructureForm.examName = this.getExamNameById(
  512. this.examList,
  513. this.addStructureForm.examId
  514. );
  515. let url = PRINT_API + "/examStructure/save";
  516. this.$http.post(url, this.addStructureForm).then(
  517. () => {
  518. this.$notify({
  519. title: "提示",
  520. message: "考试结构新增成功!",
  521. type: "success"
  522. });
  523. this.addStructureDialog = false;
  524. this.searchRecords(1);
  525. },
  526. error => {
  527. console.log(error.response);
  528. this.$notify({
  529. title: "错误",
  530. type: "error",
  531. message: error.response.data.desc
  532. });
  533. }
  534. );
  535. });
  536. },
  537. openCloneStructureDialog(row) {
  538. /* 打开复用考试结构弹窗 */
  539. this.cloneStructureDialog = true;
  540. this.cloneStructureForm.orgId = row.orgId;
  541. this.cloneStructureForm.examId = row.examId;
  542. this.cloneStructureForm.newOrgId = "";
  543. this.cloneStructureForm.newExamId = "";
  544. },
  545. closeCloneStructureDialog() {
  546. /* 关闭复用考试结构弹窗 */
  547. this.cloneStructureDialog = false;
  548. },
  549. cloneStructure() {
  550. /* 复用考试结构 */
  551. this.$refs.cloneStructureForm.validate(valid => {
  552. if (!valid) {
  553. return false;
  554. }
  555. this.cloneStructureForm.newOrgName = this.getOrgNameById(
  556. this.orgList,
  557. this.cloneStructureForm.newOrgId
  558. );
  559. this.cloneStructureForm.newExamName = this.getExamNameById(
  560. this.cloneExamList,
  561. this.cloneStructureForm.newExamId
  562. );
  563. let url = PRINT_API + "/examStructure/clone";
  564. this.$http.post(url, this.cloneStructureForm).then(
  565. () => {
  566. this.$notify({
  567. title: "提示",
  568. message: "考试结构复用成功!",
  569. type: "success"
  570. });
  571. this.cloneStructureDialog = false;
  572. this.searchRecords(1);
  573. },
  574. error => {
  575. console.log(error.response);
  576. this.$notify({
  577. title: "错误",
  578. type: "error",
  579. message: error.response.data.desc
  580. });
  581. }
  582. );
  583. });
  584. },
  585. removeStructure(row) {
  586. /* 删除考试结构 */
  587. this.$confirm("确定删除当前结构吗?", "提示", {
  588. confirmButtonText: "确定",
  589. cancelButtonText: "取消",
  590. type: "warning"
  591. })
  592. .then(() => {
  593. let url = PRINT_API + "/examStructure/delete/" + row.id;
  594. this.$http.post(url).then(
  595. () => {
  596. this.$notify({
  597. title: "提示",
  598. type: "success",
  599. message: "删除当前结构成功!"
  600. });
  601. this.searchRecords(1);
  602. },
  603. error => {
  604. console.log(error.response);
  605. this.$notify({
  606. title: "错误",
  607. type: "error",
  608. message: error.response.data.desc
  609. });
  610. }
  611. );
  612. })
  613. .catch(() => {
  614. /*ignore*/
  615. });
  616. },
  617. checkEmptyNumber: checkEmptyNumber
  618. },
  619. computed: {
  620. ...mapState({ user: state => state.user })
  621. },
  622. created() {
  623. this.loadOrgList();
  624. this.loadUserRole(this.user);
  625. if (this.curUserRole.isSuperLeader || this.curUserRole.isPM) {
  626. this.hasPermit = true;
  627. } else {
  628. this.hasPermit = false;
  629. }
  630. }
  631. };
  632. </script>
  633. <style scoped>
  634. .page {
  635. margin-top: 10px;
  636. }
  637. .pull-right {
  638. float: right;
  639. }
  640. .pull-left {
  641. float: left;
  642. }
  643. .w220 {
  644. width: 220px;
  645. }
  646. </style>