InfoPrintTask.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. <template>
  2. <div class="info-print-task">
  3. <p v-if="IS_MODEL2" class="tips-info mb-2">
  4. 考试需要命题老师提交具体印刷份数
  5. </p>
  6. <p v-else class="tips-info mb-2">
  7. 考试需要命题老师提交完整的考务数据,每个卷袋表示一个考场,人数字段为应考人数,备份数量为该考场试卷题卡备用数量
  8. </p>
  9. <el-form ref="modalFormComp" label-position="top">
  10. <el-form-item label="考试时间:" required>
  11. <el-date-picker
  12. v-model="createDate"
  13. type="date"
  14. value-format="timestamp"
  15. placeholder="考试日期"
  16. style="width: 150px"
  17. :editable="false"
  18. @change="timeChange"
  19. >
  20. </el-date-picker>
  21. <el-time-picker
  22. is-range
  23. v-model="createTime"
  24. range-separator="至"
  25. start-placeholder="考试开始时间"
  26. end-placeholder="考试结束时间"
  27. placeholder="选择时间范围"
  28. value-format="timestamp"
  29. :editable="false"
  30. @change="timeChange"
  31. >
  32. </el-time-picker>
  33. </el-form-item>
  34. <el-form-item label="考试对象:" required></el-form-item>
  35. </el-form>
  36. <div v-if="IS_MODEL2" class="part-box">
  37. <table class="table">
  38. <colgroup>
  39. <col width="50" />
  40. <col width="50" />
  41. <col width="50" />
  42. <col width="100" />
  43. </colgroup>
  44. <tr>
  45. <th>卷袋序号</th>
  46. <th>印刷份数</th>
  47. <th>备份数量</th>
  48. <th>印刷室</th>
  49. </tr>
  50. <tr>
  51. <td>1</td>
  52. <td>
  53. <el-input-number
  54. v-model="modalForm.printCount"
  55. style="width:80px"
  56. :min="1"
  57. :max="999999"
  58. :step="1"
  59. step-strictly
  60. :controls="false"
  61. ></el-input-number>
  62. </td>
  63. <td>{{ infoExamPrintPlan.backupCount }}</td>
  64. <td>
  65. <el-select
  66. v-model="modalForm.printHouseId"
  67. placeholder="请选择"
  68. filterable
  69. >
  70. <el-option
  71. v-for="room in printHouses"
  72. :key="room.printHouseId"
  73. :value="room.printHouseId"
  74. :label="room.printHouseName"
  75. ></el-option>
  76. </el-select>
  77. </td>
  78. </tr>
  79. </table>
  80. </div>
  81. <div v-else class="part-box">
  82. <div class="box-justify mb-2">
  83. <p>
  84. 共{{ packageInfos.packageCount }}个卷袋,{{
  85. packageInfos.studentCount
  86. }}个考生,共印试卷{{ packageInfos.paperCount }}份(正式{{
  87. packageInfos.paperReleaseCount
  88. }}份,备用{{ packageInfos.paperBackupCount }}份)
  89. </p>
  90. <el-button type="primary" @click="toAdd" :disabled="cannotAdd"
  91. >新增考试对象</el-button
  92. >
  93. </div>
  94. <el-table ref="TableList" :data="tableData" border>
  95. <el-table-column type="index" width="50" label="卷袋序号">
  96. </el-table-column>
  97. <el-table-column prop="className" label="考试对象"> </el-table-column>
  98. <el-table-column prop="studentCount" label="人数" width="60">
  99. </el-table-column>
  100. <el-table-column prop="backupCount" label="备份数量" width="90">
  101. <!-- <template slot-scope="scope">
  102. <el-input-number
  103. v-model="scope.row.backupCount"
  104. style="width:60px"
  105. :min="1"
  106. :max="99999"
  107. :step="1"
  108. step-strictly
  109. :controls="false"
  110. @change="backupCountChange"
  111. ></el-input-number>
  112. </template> -->
  113. </el-table-column>
  114. <el-table-column prop="examPlace" label="考点名称">
  115. <template slot-scope="scope">
  116. <el-input
  117. v-model.trim="scope.row.examPlace"
  118. :maxlength="100"
  119. clearable
  120. ></el-input>
  121. </template>
  122. </el-table-column>
  123. <el-table-column prop="examRoom" label="考场名称">
  124. <template slot-scope="scope">
  125. <el-input
  126. v-model.trim="scope.row.examRoom"
  127. :maxlength="50"
  128. clearable
  129. ></el-input>
  130. </template>
  131. </el-table-column>
  132. <el-table-column prop="printHouseName" label="印刷室">
  133. <template slot-scope="scope">
  134. <el-select
  135. v-model="scope.row.printHouseId"
  136. placeholder="请选择"
  137. filterable
  138. @change="() => printHouseChange(scope.row)"
  139. >
  140. <el-option
  141. v-for="room in printHouses"
  142. :key="room.printHouseId"
  143. :value="room.printHouseId"
  144. :label="room.printHouseName"
  145. ></el-option>
  146. </el-select>
  147. </template>
  148. </el-table-column>
  149. <el-table-column
  150. v-for="item in extendFields"
  151. :key="item.code"
  152. :label="item.name"
  153. >
  154. <div slot-scope="scope">
  155. <el-input
  156. v-model="scope.row.extends[item.code]"
  157. placeholder="请输入"
  158. clearable
  159. ></el-input>
  160. </div>
  161. </el-table-column>
  162. <el-table-column label="操作" width="100">
  163. <template slot-scope="scope">
  164. <el-button
  165. class="btn-danger"
  166. type="text"
  167. @click="toDelete(scope.row)"
  168. >取消</el-button
  169. >
  170. </template>
  171. </el-table-column>
  172. </el-table>
  173. </div>
  174. <!-- ModifyPrintTask -->
  175. <modify-print-task
  176. ref="ModifyPrintTask"
  177. :instance="curRow"
  178. :print-houses="printHouses"
  179. :class-list="unusedClassList"
  180. :extend-fields="extendFields"
  181. @modified="modified"
  182. ></modify-print-task>
  183. </div>
  184. </template>
  185. <script>
  186. import { calcSum, getTimeDatestamp } from "@/plugins/utils";
  187. import { examRuleDetail } from "../../../base/api";
  188. import { listTaskPrintHouse, listTaskApplyClass } from "../../api";
  189. import ModifyPrintTask from "./ModifyPrintTask";
  190. import { mapState, mapMutations } from "vuex";
  191. export default {
  192. name: "info-print-task",
  193. components: { ModifyPrintTask },
  194. data() {
  195. return {
  196. modalForm: {
  197. examStartTime: "",
  198. examEndTime: "",
  199. paperNumber: "",
  200. courseName: "",
  201. courseCode: "",
  202. printCount: 1,
  203. printHouseId: ""
  204. },
  205. tableData: [],
  206. curRow: {},
  207. classList: [],
  208. validClassList: [],
  209. unusedClassList: [],
  210. printHouses: [],
  211. extendFields: [],
  212. packageInfos: {
  213. packageCount: 0,
  214. studentCount: 0,
  215. paperCount: 0,
  216. paperReleaseCount: 0,
  217. paperBackupCount: 0
  218. },
  219. // date-picker
  220. curCreateTime: [],
  221. createDate: "",
  222. createTime: []
  223. };
  224. },
  225. computed: {
  226. ...mapState("exam", [
  227. "infoExamTask",
  228. "infoExamTaskDetail",
  229. "infoPrintTask",
  230. "infoExamPrintPlan"
  231. ]),
  232. cannotAdd() {
  233. return !this.unusedClassList.length;
  234. },
  235. IS_MODEL2() {
  236. return this.infoExamTask.examModel === "MODEL2";
  237. }
  238. },
  239. watch: {
  240. "infoExamTask.courseCode": function(val, oldval) {
  241. if (val !== oldval) this.initData();
  242. },
  243. "infoExamPrintPlan.backupCount": function(val, oldval) {
  244. if (val !== oldval) this.planBackupCountChange();
  245. }
  246. },
  247. mounted() {
  248. this.getExtendFields();
  249. this.getPrintHouses();
  250. const curDate = getTimeDatestamp(Date.now());
  251. const hour = 60 * 60 * 1000;
  252. this.curCreateTime = [curDate + 8 * hour, curDate + 10 * hour];
  253. this.createTime = [...this.curCreateTime];
  254. },
  255. methods: {
  256. ...mapMutations("exam", ["updateTaskInfo"]),
  257. async initData() {
  258. if (this.IS_MODEL2) return;
  259. this.modalForm = Object.assign(this.modalForm, {
  260. paperNumber: this.infoExamTask.paperNumber,
  261. courseName: this.infoExamTask.courseName,
  262. courseCode: this.infoExamTask.courseCode
  263. });
  264. await this.getClassList();
  265. const { examStartTime, examEndTime } = this.infoPrintTask;
  266. if (examStartTime && examEndTime) {
  267. this.createTime = [examStartTime, examEndTime];
  268. this.createDate = getTimeDatestamp(examStartTime);
  269. this.modalForm.examStartTime = this.createTime[0];
  270. this.modalForm.examEndTime = this.createTime[1];
  271. }
  272. this.tableData = [];
  273. this.unusedClassList = [];
  274. this.buildTableData();
  275. this.updatePackageInfos();
  276. this.updeteData();
  277. },
  278. planBackupCountChange() {
  279. this.tableData.forEach(item => {
  280. item.backupCount = this.infoExamPrintPlan.backupCount || 0;
  281. });
  282. this.updatePackageInfos();
  283. },
  284. checkTime() {
  285. if (!this.modalForm.examStartTime || !this.modalForm.examEndTime) {
  286. this.$message.error("请选择考试时间!");
  287. return false;
  288. }
  289. if (this.modalForm.examStartTime >= this.modalForm.examEndTime) {
  290. this.$message.error("考试开始时间必须小于考试结束时间!");
  291. return false;
  292. }
  293. return true;
  294. },
  295. checkData() {
  296. if (!this.checkTime()) return Promise.reject();
  297. if (this.IS_MODEL2) {
  298. if (!this.modalForm.printCount) {
  299. this.$message.error("请输入印刷分数!");
  300. return Promise.reject();
  301. }
  302. if (!this.modalForm.printHouseId) {
  303. this.$message.error("请选择印刷室!");
  304. return Promise.reject();
  305. }
  306. return Promise.resolve(true);
  307. }
  308. if (!this.tableData.length) {
  309. this.$message.error("请添加考试对象!");
  310. return Promise.reject();
  311. }
  312. let errorMsg = [];
  313. this.tableData.forEach(row => {
  314. let errorFields = [];
  315. this.extendFields.forEach(field => {
  316. if (!row.extends[field.code]) {
  317. errorFields.push(field.name);
  318. }
  319. });
  320. if (!row.printHouseId) {
  321. errorFields.push("印刷室");
  322. }
  323. if (errorFields.length) {
  324. errorMsg.push(
  325. `考试对象${row.className}中,${errorFields.join("、")}必须填写`
  326. );
  327. }
  328. });
  329. if (errorMsg.length) {
  330. this.$message.error(errorMsg.join("。"));
  331. return Promise.reject();
  332. }
  333. return Promise.resolve(true);
  334. },
  335. updeteData() {
  336. const tableList = this.tableData.map(row => {
  337. let nrow = { ...row };
  338. let extendFields = this.extendFields.map(field => {
  339. let info = { ...field };
  340. info.value = row.extends[field.code];
  341. return info;
  342. });
  343. nrow.extendFields = JSON.stringify(extendFields);
  344. nrow.examStartTime = this.modalForm.examStartTime;
  345. nrow.examEndTime = this.modalForm.examEndTime;
  346. return nrow;
  347. });
  348. this.updateTaskInfo({
  349. infoPrintTask: {
  350. ...this.modalForm,
  351. list: tableList
  352. }
  353. });
  354. },
  355. updateData() {
  356. this.$emit("data-change", this.getData());
  357. },
  358. buildTableData() {
  359. this.tableData = this.classList.map(clazz => {
  360. let modalFormData = { ...this.modalForm };
  361. delete modalFormData.printHouseId;
  362. let data = {
  363. examPlace: "",
  364. examRoom: "",
  365. classId: clazz.id,
  366. className: clazz.name,
  367. studentCount: clazz.studentCount,
  368. printHouseId: clazz.printHouseId,
  369. printHouseName: clazz.printHouseName,
  370. extendFields: "",
  371. backupCount: this.infoExamPrintPlan.backupCount,
  372. ...modalFormData
  373. };
  374. let extendFieldModal = {};
  375. this.extendFields.forEach(field => {
  376. extendFieldModal[field.code] = "";
  377. });
  378. data.extends = extendFieldModal;
  379. return data;
  380. });
  381. },
  382. updateUnusedClassList() {
  383. let usedClassIds = [];
  384. this.tableData.forEach(row => {
  385. usedClassIds = [...usedClassIds, ...row.classId.split(",")];
  386. });
  387. this.unusedClassList = this.classList.filter(
  388. item => !usedClassIds.includes(item.id)
  389. );
  390. },
  391. updatePackageInfos() {
  392. this.packageInfos.packageCount = this.tableData.length;
  393. this.packageInfos.studentCount = calcSum(
  394. this.tableData.map(item => item.studentCount)
  395. );
  396. this.packageInfos.paperReleaseCount = this.packageInfos.studentCount;
  397. this.packageInfos.paperBackupCount = calcSum(
  398. this.tableData.map(item => item.backupCount || 0)
  399. );
  400. this.packageInfos.paperCount =
  401. this.packageInfos.paperReleaseCount +
  402. this.packageInfos.paperBackupCount;
  403. },
  404. async getExtendFields() {
  405. const examRule = await examRuleDetail();
  406. this.extendFields = examRule.extendFields
  407. ? JSON.parse(examRule.extendFields)
  408. : [];
  409. },
  410. async getPrintHouses() {
  411. this.printHouses = await listTaskPrintHouse();
  412. },
  413. async getClassList() {
  414. this.classList = [];
  415. if (!this.infoExamTask.courseCode) return;
  416. const data = await listTaskApplyClass({
  417. courseCode: this.infoExamTask.courseCode
  418. });
  419. if (!data) return;
  420. this.classList = data.map(item => {
  421. return {
  422. id: item.classId,
  423. name: item.className,
  424. studentCount: item.studentCount,
  425. printHouseId: item.printHouseId,
  426. printHouseName: item.printHouseName
  427. };
  428. });
  429. },
  430. timeChange() {
  431. if (!this.createDate || !this.createTime) {
  432. this.modalForm.examStartTime = null;
  433. this.modalForm.examEndTime = null;
  434. return;
  435. }
  436. const curDate = getTimeDatestamp(this.createDate);
  437. const timeDate = getTimeDatestamp(this.createTime[0]);
  438. this.modalForm.examStartTime = curDate + this.createTime[0] - timeDate;
  439. this.modalForm.examEndTime = curDate + this.createTime[1] - timeDate;
  440. },
  441. backupCountChange() {
  442. this.updatePackageInfos();
  443. },
  444. printHouseChange(row) {
  445. const curHouse = this.printHouses.find(
  446. item => item.printHouseId === row.printHouseId
  447. );
  448. if (curHouse) {
  449. row.printHouseName = curHouse.printHouseName;
  450. }
  451. },
  452. toAdd() {
  453. if (!this.checkTime()) return;
  454. this.curRow = {
  455. examPlace: "",
  456. examRoom: "",
  457. classId: "",
  458. className: "",
  459. studentCount: null,
  460. printHouseId: null,
  461. printHouseName: null,
  462. extendFields: "",
  463. backupCount: this.infoExamPrintPlan.backupCount,
  464. ...this.modalForm
  465. };
  466. let extendFieldModal = {};
  467. this.extendFields.forEach(field => {
  468. extendFieldModal[field.code] = "";
  469. });
  470. this.curRow.extends = extendFieldModal;
  471. this.$refs.ModifyPrintTask.open();
  472. },
  473. toEdit(row) {
  474. this.curRow = { ...row };
  475. this.$refs.ModifyPrintTask.open();
  476. },
  477. toDelete(row) {
  478. this.tableData = this.tableData.filter(
  479. item => item.classId !== row.classId
  480. );
  481. this.updateUnusedClassList();
  482. this.updatePackageInfos();
  483. },
  484. modified(data) {
  485. this.tableData.push(data);
  486. this.updateUnusedClassList();
  487. this.updatePackageInfos();
  488. }
  489. }
  490. };
  491. </script>