PaperApproveTable.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <template>
  2. <el-dialog
  3. class="paper-approve-table"
  4. :visible.sync="modalIsShow"
  5. :close-on-click-modal="false"
  6. :close-on-press-escape="false"
  7. :show-close="false"
  8. append-to-body
  9. fullscreen
  10. @open="initData"
  11. >
  12. <div class="box-justify" slot="title">
  13. <span class="el-dialog__title">试卷审批表</span>
  14. <div>
  15. <el-button type="success" :disabled="loading" @click="toDownload"
  16. >下载</el-button
  17. >
  18. <el-button @click="cancel">取消</el-button>
  19. </div>
  20. </div>
  21. <div class="paper-container" ref="PaperContainer">
  22. <div class="paper-main" v-if="!pages.length">
  23. <div class="paper-a4">
  24. <h1 class="paper-h1" id="paper-head">试卷审批表</h1>
  25. <div class="paper-base" id="paper-base">
  26. <div class="paper-row">
  27. <div class="paper-item">
  28. <span>学院:</span>
  29. <span>{{ basicInfo.collegeName }}</span>
  30. </div>
  31. <div class="paper-item">
  32. <span>教研室(或系):</span>
  33. <span>{{ basicInfo.teachingRoomName }}</span>
  34. </div>
  35. </div>
  36. <div class="paper-row">
  37. <div class="paper-item">
  38. <span>使用学期:</span>
  39. <span>{{ basicInfo.paperName || "" }}</span>
  40. </div>
  41. <div class="paper-item">
  42. <span>课程名称:</span>
  43. <span>{{ basicInfo.courseName }}</span>
  44. </div>
  45. </div>
  46. <div class="paper-row">
  47. <div class="paper-item">
  48. <span>考试时间:</span>
  49. <span>{{ basicInfo.examTime }}</span>
  50. </div>
  51. <div class="paper-item">
  52. <span>拟卷老师:</span>
  53. <span>{{ basicInfo.teacherName }}</span>
  54. </div>
  55. </div>
  56. </div>
  57. <table class="paper-table">
  58. <tr>
  59. <th style="width: 100px;">卷袋编号</th>
  60. <th v-if="hasClassInfo">使用班级</th>
  61. <th style="width: 80px;">人数</th>
  62. <th style="width: 100px;">总印份数</th>
  63. </tr>
  64. <tr v-for="item in examRoomInfoList" :key="item.id" :id="item.id">
  65. <td style="width: 100px;">{{ item.packageCode }}</td>
  66. <td v-if="hasClassInfo">{{ item.clazzNames }}</td>
  67. <td style="width: 80px;">{{ item.studentCount }}</td>
  68. <td style="width: 100px;">{{ item.printCount }}</td>
  69. </tr>
  70. </table>
  71. <table class="paper-table" id="paper-approve">
  72. <tr>
  73. <th>审批部门</th>
  74. <th>审批人</th>
  75. <th>审批时间</th>
  76. <th style="width: 260px;">审批意见</th>
  77. </tr>
  78. <tr v-for="(item, index) in approvalInfoList" :key="index">
  79. <td>{{ item.approveOrgName }}</td>
  80. <td>{{ item.approveName }}</td>
  81. <td>{{ item.time | timestampFilter }}</td>
  82. <td style="width: 260px;">{{ item.remark }}</td>
  83. </tr>
  84. </table>
  85. </div>
  86. </div>
  87. <div class="paper-main" v-else>
  88. <div class="paper-a4" v-for="(page, pindex) in pages" :key="pindex">
  89. <template v-if="pindex === 0">
  90. <h1 class="paper-h1">试卷审批表</h1>
  91. <div class="paper-base">
  92. <div class="paper-row">
  93. <div class="paper-item">
  94. <span>学院:</span>
  95. <span>{{ basicInfo.collegeName }}</span>
  96. </div>
  97. <div class="paper-item">
  98. <span>教研室(或系):</span>
  99. <span>{{ basicInfo.teachingRoomName }}</span>
  100. </div>
  101. </div>
  102. <div class="paper-row">
  103. <div class="paper-item">
  104. <span>使用学期:</span>
  105. <span>{{ basicInfo.paperName || "" }}</span>
  106. </div>
  107. <div class="paper-item">
  108. <span>课程名称:</span>
  109. <span>{{ basicInfo.courseName }}</span>
  110. </div>
  111. </div>
  112. <div class="paper-row">
  113. <div class="paper-item">
  114. <span>考试时间:</span>
  115. <span>{{ basicInfo.examTime }}</span>
  116. </div>
  117. <div class="paper-item">
  118. <span>拟卷老师:</span>
  119. <span>{{ basicInfo.teacherName }}</span>
  120. </div>
  121. </div>
  122. </div>
  123. </template>
  124. <template v-for="(part, tindex) in page">
  125. <table
  126. v-if="part.type === 'room'"
  127. class="paper-table"
  128. :key="tindex"
  129. >
  130. <tr>
  131. <th style="width: 100px;">卷袋编号</th>
  132. <th v-if="hasClassInfo">使用班级</th>
  133. <th style="width: 80px;">人数</th>
  134. <th style="width: 100px;">总印份数</th>
  135. </tr>
  136. <tr v-for="item in examRoomInfoList" :key="item.id" :id="item.id">
  137. <td style="width: 100px;">{{ item.packageCode }}</td>
  138. <td v-if="hasClassInfo">{{ item.clazzNames }}</td>
  139. <td style="width: 80px;">{{ item.studentCount }}</td>
  140. <td style="width: 100px;">{{ item.printCount }}</td>
  141. </tr>
  142. </table>
  143. <table v-else class="paper-table" :key="tindex">
  144. <tr>
  145. <th>审批部门</th>
  146. <th>审批人</th>
  147. <th>审批时间</th>
  148. <th style="width: 260px;">审批意见</th>
  149. </tr>
  150. <tr v-for="(item, index) in approvalInfoList" :key="index">
  151. <td>{{ item.approveOrgName }}</td>
  152. <td>{{ item.approveName }}</td>
  153. <td>{{ item.time | timestampFilter }}</td>
  154. <td style="width: 260px;">{{ item.remark }}</td>
  155. </tr>
  156. </table>
  157. </template>
  158. </div>
  159. </div>
  160. </div>
  161. <div slot="footer"></div>
  162. </el-dialog>
  163. </template>
  164. <script>
  165. import { parseTimeRangeDateAndTime } from "@/plugins/utils";
  166. import { downloadByApi } from "@/plugins/download";
  167. import { examTaskApproveForm, downloadExamTaskApproveForm } from "../api";
  168. export default {
  169. name: "paper-approve-table",
  170. props: {
  171. instance: {
  172. type: Object,
  173. default() {
  174. return {};
  175. }
  176. }
  177. },
  178. data() {
  179. return {
  180. modalIsShow: false,
  181. loading: false,
  182. basicInfo: {},
  183. examRoomInfoList: [],
  184. hasClassInfo: false,
  185. approvalInfoList: [],
  186. pages: []
  187. };
  188. },
  189. methods: {
  190. async initData() {
  191. this.pages = [];
  192. this.basicInfo = {};
  193. this.examRoomInfoList = [];
  194. this.approvalInfoList = [];
  195. const paper = await examTaskApproveForm(this.instance.id);
  196. this.basicInfo = paper.basicInfo;
  197. this.examRoomInfoList = paper.examRoomInfoList.map(item => {
  198. item.id = this.$randomCode();
  199. item.height = 0;
  200. return item;
  201. });
  202. this.hasClassInfo = this.examRoomInfoList.some(item => item.clazzNames);
  203. const levelNames = {
  204. 2: "教研室审批意见",
  205. 3: "二级学院(部)审批意见"
  206. };
  207. this.approvalInfoList = paper.approvalInfoList.map(item => {
  208. item.levelName = levelNames[item.level];
  209. return item;
  210. });
  211. this.approvalInfoList.sort((a, b) => a.level - b.level);
  212. const { date, time } = parseTimeRangeDateAndTime(
  213. this.basicInfo.examStartTime,
  214. this.basicInfo.examEndTime
  215. );
  216. this.basicInfo.examTime = date && time ? `${date} ${time}` : "--";
  217. this.$nextTick(() => {
  218. this.rebuildPaper();
  219. });
  220. },
  221. rebuildPaper() {
  222. const pageHeight = 1043;
  223. const pageLimitHeight = [
  224. pageHeight -
  225. document.getElementById("paper-head").clientHeight -
  226. document.getElementById("paper-base").clientHeight -
  227. 30 -
  228. 37
  229. ];
  230. let pages = [];
  231. let curPage = [];
  232. let curPageLimitHeight = pageHeight;
  233. let curPageHeight = 0;
  234. let roomData = [];
  235. this.examRoomInfoList.forEach(item => {
  236. const curPageNo = pages.length;
  237. curPageLimitHeight = pageLimitHeight[curPageNo] || pageHeight;
  238. const rowHeight = document.getElementById(item.id).clientHeight;
  239. if (rowHeight + curPageHeight <= curPageLimitHeight) {
  240. roomData.push(item);
  241. curPageHeight += rowHeight;
  242. } else {
  243. curPage.push({
  244. type: "room",
  245. data: roomData
  246. });
  247. pages.push(curPage);
  248. curPage = [];
  249. roomData = [];
  250. roomData.push(item);
  251. curPageHeight = rowHeight + 37;
  252. }
  253. });
  254. curPage.push({
  255. type: "room",
  256. data: roomData
  257. });
  258. if (
  259. curPageHeight +
  260. 30 +
  261. document.getElementById("paper-approve").clientHeight >
  262. curPageLimitHeight
  263. ) {
  264. pages.push(curPage);
  265. curPage = [];
  266. }
  267. curPage.push({
  268. type: "approve",
  269. data: this.approvalInfoList
  270. });
  271. pages.push(curPage);
  272. this.pages = pages;
  273. },
  274. cancel() {
  275. this.modalIsShow = false;
  276. },
  277. open() {
  278. this.modalIsShow = true;
  279. },
  280. getHtmlContent() {
  281. const htmlContent = this.$refs.PaperContainer.innerHTML;
  282. const cssContent = `body,div,h1,p,tr,th,td,span{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:rgba(255,255,255,0)}body{font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:14px;color:#1f2230}.paper-main{width:210mm;margin:0 auto;color:#1f2230}.paper-a4{width:210mm;height:297mm;padding:40px;overflow:hidden;page-break-after:always}.paper-h1{font-size:24px;text-align:center;line-height:1;padding-top:20px;padding-bottom:30px}.paper-base{margin-bottom:30px}.paper-row{margin:0 -5px 10px}.paper-item{display:inline-block;vertical-align:top;width:50%;padding:0 5px}.paper-item>span:first-child{float:left;width:96px;text-align:right}.paper-item>span:last-child{display:block;margin-left:96px}.paper-table{width:100%;border-spacing:0;border-collapse:collapse;margin-bottom:40px;text-align:center}.paper-table th{padding:8px;line-height:20px;letter-spacing:1px;border:1px solid #1f2230}.paper-table td{padding:8px;line-height:20px;border:1px solid #1f2230}`;
  283. return `
  284. <!DOCTYPE html>
  285. <html>
  286. <head>
  287. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  288. <meta name="viewport" content="width=device-width,initial-scale=1.0,
  289. maximum-scale=1.0,minimum-scale=1.0, user-scalable=no" "="">
  290. <meta name=" renderer" content="webkit|ie-comp|ie-stand" />
  291. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
  292. <title>试卷审批表</title>
  293. </head>
  294. <style>${cssContent}</style>
  295. <body>${htmlContent}</body>
  296. </html>
  297. `;
  298. },
  299. async toDownload() {
  300. if (this.loading) return;
  301. this.loading = true;
  302. const datas = {
  303. htmlContent: this.getHtmlContent(),
  304. examTaskId: this.instance.id
  305. };
  306. const res = await downloadByApi(() => {
  307. return downloadExamTaskApproveForm(datas);
  308. }, `${this.instance.courseName}-试卷审批表.pdf`).catch(e => {
  309. this.$message.error(e || "下载失败,请重新尝试!");
  310. });
  311. this.downloading = false;
  312. if (!res) return;
  313. this.$message.success("下载成功!");
  314. }
  315. }
  316. };
  317. </script>
  318. <style scoped>
  319. .paper-approve-table .paper-a4 {
  320. box-shadow: 0 0 1px #666;
  321. margin-bottom: 10px;
  322. }
  323. </style>
  324. <style src="@/assets/styles/paper-approve.css" scoped></style>