addPage.vue 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589
  1. <!-- 新建考试 -->
  2. <template>
  3. <div class="page-container examinationArrange-addPage">
  4. <div class="page-container-top-max-big-box">
  5. <p class="top-1-p">{{newData.id ? '编辑考试' : '新建考试'}}</p>
  6. <p class="top-2-p" @click="backPage()">返回</p>
  7. <p class="top-3-p" v-if="newData.id&&!showType" @click="resetButton()">重置</p>
  8. <p class="top-4-p" v-if="!showType" @click="submitButton()">保存</p>
  9. </div>
  10. <div class="content-box">
  11. <div class="layout-box">
  12. <!-- 左侧导航 -->
  13. <div class="side-nav">
  14. <div
  15. v-for="tab in tabs"
  16. :key="tab.key"
  17. class="nav-item"
  18. :class="{ active: activeTab === tab.key }"
  19. @click="activeTab = tab.key"
  20. >{{ tab.label }}
  21. </div>
  22. </div>
  23. <!-- 右侧内容 -->
  24. <div class="tab-content scrollbar-box">
  25. <el-form :model="newData" ref="basicForm" label-width="120px" :rules="rules">
  26. <!-- ==================== 基本设置 ==================== -->
  27. <div v-show="activeTab === 'basic'">
  28. <div class="section-block">
  29. <div class="flex-row-box">
  30. <el-form-item label="考试类型" prop="examTypeId">
  31. <el-select :disabled="showType" v-model="newData.examTypeId" placeholder="考试类型" @change="examChange" style="width:200px;">
  32. <el-option v-for="item in optionExamType" :key="item.id" :label="item.examTypeName"
  33. :value="item.id"/>
  34. </el-select>
  35. </el-form-item>
  36. <el-form-item label="安全分类" v-if="!placementTest" :prop="placementTest?'disciplineTypeId':''">
  37. <el-select :disabled="showType" v-model="newData.disciplineTypeId" placeholder="安全分类" style="width:200px;">
  38. <el-option v-for="item in tableList" :key="item.id"
  39. :label="item.disciplineName"
  40. :value="item.id"/>
  41. </el-select>
  42. </el-form-item>
  43. <el-form-item label="安全分类" v-if="placementTest" :prop="placementTest?'disciplineTypeId':''">
  44. <el-select :disabled="showType" v-model="newData.disciplineTypeId" placeholder="安全分类" style="width:200px;">
  45. <el-option v-for="item in tableList2" :key="item.id"
  46. :label="item.disciplineName"
  47. :value="item.id"/>
  48. </el-select>
  49. </el-form-item>
  50. <el-form-item label="风险等级" prop="riskLevelId" v-if="placementTest">
  51. <el-select :disabled="showType" v-model="newData.riskLevelId" placeholder="请选择" style="width:200px;">
  52. <el-option v-for="item in optionRiskLevel" :key="item.levelId" :label="item.titleName"
  53. :value="item.levelId"/>
  54. </el-select>
  55. </el-form-item>
  56. </div>
  57. <el-form-item label="考试名称" prop="examName">
  58. <el-input :disabled="showType" v-model="newData.examName" placeholder="请输入课程名称" style="width:600px;"/>
  59. </el-form-item>
  60. <el-form-item label="答卷次数" prop="attemptLimit">
  61. <div class="stepper-row">
  62. <div class="number-stepper">
  63. <el-input-number
  64. :disabled="answerUnlimited||showType"
  65. class="form-input-number"
  66. style="width:160px"
  67. :min="1"
  68. :max="9999"
  69. :step="1" :precision="0" step-strictly
  70. v-model="newData.attemptLimit"
  71. >
  72. </el-input-number>
  73. </div>
  74. <span class="unit-text">次</span>
  75. <el-checkbox :disabled="showType" v-model="answerUnlimited" :label="true" style="margin-left:20px;">无限制</el-checkbox>
  76. </div>
  77. </el-form-item>
  78. <el-form-item label="是否共享">
  79. <div class="switch-row">
  80. <el-switch :disabled="showType" v-model="newData.shareStatus" :active-value="1" :inactive-value="0"
  81. active-color="#0183FB" inactive-color="#AAAAAA"
  82. />
  83. <p class="tip-text" style="margin:2px 0 0 10px;">共享开启,全校所有学院单位都可见</p>
  84. </div>
  85. </el-form-item>
  86. <el-form-item label="启用" prop="enableStatus">
  87. <el-switch :disabled="showType" v-model="newData.enableStatus" :active-value="1" :inactive-value="0"
  88. active-color="#0183FB" inactive-color="#AAAAAA"
  89. />
  90. </el-form-item>
  91. <el-form-item label="考卷" prop="paperId">
  92. <div class="paper-select-row">
  93. <p class="checkButton-p" @click="openPaperDrawer" v-if="!showType">选择试卷</p>
  94. <div class="selected-tag" v-if="newData.paperName">
  95. <span>{{ newData.paperName }}</span>
  96. <!--<i class="el-icon-close" @click="newData.paperId = null; newData.paperName = ''"></i>-->
  97. </div>
  98. </div>
  99. </el-form-item>
  100. </div>
  101. <div class="section-divider"></div>
  102. <div class="section-block">
  103. <div class="flex-row-box">
  104. <el-form-item label="考试时间" prop="examTimeRange">
  105. <el-date-picker
  106. :disabled="showType"
  107. popper-class="examinationArrange-addPage-date-picker"
  108. v-model="newData.examTimeRange"
  109. type="datetimerange"
  110. range-separator="至"
  111. format="yyyy-MM-dd HH:mm"
  112. value-format="yyyy-MM-dd HH:mm"
  113. start-placeholder="开始日期"
  114. end-placeholder="结束日期"
  115. :picker-options="pickerOptions"
  116. />
  117. </el-form-item>
  118. <el-form-item label="考试时长" prop="answerDuration">
  119. <div class="stepper-row">
  120. <div class="number-stepper">
  121. <div class="number-stepper">
  122. <el-input-number
  123. :disabled="showType"
  124. class="form-input-number"
  125. style="width:160px"
  126. :min="0"
  127. :max="9999"
  128. :step="1" :precision="0" step-strictly
  129. v-model="newData.answerDuration"
  130. >
  131. </el-input-number>
  132. </div>
  133. </div>
  134. <span class="unit-text">分钟</span>
  135. <span class="tip-text" style="margin-left:12px;">限制答卷最大时长</span>
  136. </div>
  137. </el-form-item>
  138. </div>
  139. <el-form-item label="考试范围" prop="scopeType" v-if="!yzyhTest">
  140. <div class="scope-btn-group">
  141. <button
  142. v-for="item in scopeOptions"
  143. :key="item.value"
  144. class="scope-btn"
  145. v-show="!showType || newData.scopeType === item.value"
  146. :class="{ active: newData.scopeType === item.value }"
  147. @click.prevent="newData.scopeType = item.value"
  148. >
  149. <i v-if="newData.scopeType === item.value" class="el-icon-check"
  150. style="color:#0183fa;margin-right:4px;"
  151. ></i>
  152. {{ item.label }}
  153. </button>
  154. <p class="checkButton-p" @click="openExamScopeDrawer"
  155. v-if="(newData.scopeType == '2' || newData.scopeType == '3')&&!showType"
  156. >选择</p>
  157. </div>
  158. <!-- 考试范围表格(非全校时显示) -->
  159. <div v-if="newData.scopeType != '1'" class="scope-table-box">
  160. <div class="scope-table-header" v-if="newData.scopeType == '2'">已选取:{{ scopeList.length }}组</div>
  161. <div class="scope-table-header" v-if="newData.scopeType == '3'">已选取:{{ userList.length }}人</div>
  162. <el-table v-if="newData.scopeType == '2'" border class="table-box" :data="scopeList" size="small"
  163. style="width:100%;">
  164. <el-table-column label="学院" prop="deptName">
  165. <template slot-scope="scope">
  166. {{scope.row.deptName?scope.row.deptName:'-'}}
  167. </template>
  168. </el-table-column>
  169. <el-table-column label="专业" prop="disciplineName" width="200">
  170. <template slot-scope="scope">
  171. {{scope.row.disciplineName?scope.row.disciplineName:'-'}}
  172. </template>
  173. </el-table-column>
  174. <el-table-column label="角色" prop="roleName" width="180">
  175. <template slot-scope="scope">
  176. {{scope.row.roleName?scope.row.roleName:'-'}}
  177. </template>
  178. </el-table-column>
  179. <el-table-column label="学年" prop="academicYear" width="180">
  180. <template slot-scope="scope">
  181. {{scope.row.academicYear?scope.row.academicYear:'-'}}
  182. </template>
  183. </el-table-column>
  184. <el-table-column label="操作" width="140" align="center" v-if="!showType">
  185. <template slot-scope="{ $index }">
  186. <div class="table-button-box">
  187. <p class="table-button-null"></p>
  188. <p class="table-button-p"
  189. @click="scopeList.splice($index, 1)"
  190. >移除</p>
  191. <p class="table-button-null"></p>
  192. </div>
  193. </template>
  194. </el-table-column>
  195. </el-table>
  196. <el-table v-if="newData.scopeType == '3'" border class="table-box" :data="userList" size="small"
  197. style="width:100%;">
  198. <el-table-column label="姓名" prop="userName" width="200">
  199. <template slot-scope="scope">
  200. {{scope.row.userName?scope.row.userName:'-'}}
  201. </template>
  202. </el-table-column>
  203. <el-table-column label="学工号" prop="account">
  204. <template slot-scope="scope">
  205. {{scope.row.account?scope.row.account:'-'}}
  206. </template>
  207. </el-table-column>
  208. <el-table-column label="专业" prop="majorName" width="200">
  209. <template slot-scope="scope">
  210. {{scope.row.majorName?scope.row.majorName:'-'}}
  211. </template>
  212. </el-table-column>
  213. <el-table-column label="学院" prop="deptName" width="180">
  214. <template slot-scope="scope">
  215. {{scope.row.deptName?scope.row.deptName:'-'}}
  216. </template>
  217. </el-table-column>
  218. <el-table-column label="学年" prop="gradeNumber" width="180">
  219. <template slot-scope="scope">
  220. {{scope.row.gradeNumber?scope.row.gradeNumber:'-'}}
  221. </template>
  222. </el-table-column>
  223. <el-table-column label="操作" width="140" align="center">
  224. <template slot-scope="{ $index }">
  225. <div class="table-button-box">
  226. <p class="table-button-null"></p>
  227. <p class="table-button-p" v-if="!showType"
  228. @click="userList.splice($index, 1)"
  229. >移除</p>
  230. <p class="table-button-null"></p>
  231. </div>
  232. </template>
  233. </el-table-column>
  234. </el-table>
  235. </div>
  236. </el-form-item>
  237. <el-form-item label="考试范围" prop="targetUserType" v-if="yzyhTest">
  238. <div class="scope-btn-group">
  239. <button
  240. v-for="item in scopeOptionsB"
  241. :key="item.value"
  242. class="scope-btn"
  243. v-show="!showType || newData.targetUserType === item.value"
  244. :class="{ active: newData.targetUserType === item.value }"
  245. @click.prevent="newData.targetUserType = item.value"
  246. >
  247. <i v-if="newData.targetUserType === item.value" class="el-icon-check"
  248. style="color:#0183fa;margin-right:4px;"
  249. ></i>
  250. {{ item.label }}
  251. </button>
  252. </div>
  253. </el-form-item>
  254. </div>
  255. </div>
  256. <!-- ==================== 考前配置 ==================== -->
  257. <div v-show="activeTab === 'preExam'">
  258. <div class="section-block">
  259. <el-form-item label="学时要求" prop="studyHoursRequirementEnabled">
  260. <div class="switch-row" style="display: flex">
  261. <el-switch :disabled="showType" v-model="newData.studyHoursRequirementEnabled" :active-value="1" :inactive-value="0"
  262. active-color="#0183FB" inactive-color="#AAAAAA"
  263. />
  264. <div class="number-stepper" v-if="(!yzyhTest&&!placementTest)&&newData.studyHoursRequirementEnabled == 1" style="margin-left:12px;height:40px;">
  265. <el-input-number
  266. :disabled="showType"
  267. class="form-input-number"
  268. style="width:160px;margin-left:8px;"
  269. :min="0"
  270. :max="9999"
  271. :step="1" :precision="1" step-strictly
  272. v-model="newData.studyHoursRequirement"
  273. >
  274. </el-input-number>
  275. </div>
  276. <span v-if="(!yzyhTest&&!placementTest)&&newData.studyHoursRequirementEnabled == 1" class="unit-text" style="margin-top:2px;"
  277. >学时</span>
  278. <span class="tip-text" style="margin-left:12px;">开启后,需完成相应学时才能参加考试</span>
  279. <el-cascader
  280. :disabled="showType"
  281. v-if="(!yzyhTest&&!placementTest)&&newData.studyHoursRequirementEnabled == 1"
  282. style="width: 600px;margin-left:20px;"
  283. v-model="newData.knowledgePointIds"
  284. :options="optionListC"
  285. :props="{
  286. multiple:true,
  287. emitPath:false,
  288. checkStrictly: true,
  289. value: 'id',
  290. label: 'knowledgePointName',
  291. children: 'children',
  292. }"
  293. :show-all-levels="false"
  294. filterable
  295. placeholder="知识点"
  296. ></el-cascader>
  297. </div>
  298. <!--应知应会 学时要求-->
  299. <div class="yzyh-max-big-box" v-if="yzyhTest&&newData.studyHoursRequirementEnabled == 1">
  300. <div class="yzyh-title-box">
  301. <p>用户类别</p>
  302. <p>学时要求配置</p>
  303. </div>
  304. <div v-if="this.newData.targetUserType == 2" class="yzyh-input-max-box">
  305. <p class="yzyh-title-p">研究生</p>
  306. <div class="yzyh-text-box">
  307. <p>新生(无需进入实验室的)</p>
  308. <p>非新生</p>
  309. </div>
  310. <div class="yzyh-input-big-box">
  311. <div class="yzyh-input-box">
  312. <el-input-number
  313. :disabled="showType"
  314. class="form-input-number"
  315. style="width:200px;margin-top:20px;"
  316. :min="0"
  317. :max="9999"
  318. :step="1" :precision="0" step-strictly
  319. v-model="newData.mandatoryStudyHoursConfig.freshmanNoLabHours"
  320. >
  321. </el-input-number>
  322. </div>
  323. <div class="yzyh-input-box">
  324. <p class="yzyh-text-p">Ⅰ级{{hourData.level1Hour}}学时 / Ⅱ级{{hourData.level2Hour}}学时 / Ⅲ级{{hourData.level3Hour}}学时 / Ⅳ级{{hourData.level4Hour}}学时</p>
  325. </div>
  326. </div>
  327. </div>
  328. <div v-if="this.newData.targetUserType == 2" class="yzyh-input-max-box">
  329. <p class="yzyh-title-p">本科生</p>
  330. <div class="yzyh-text-box">
  331. <p>非新生</p>
  332. </div>
  333. <div class="yzyh-input-big-box">
  334. <div class="yzyh-input-box">
  335. <el-input-number
  336. :disabled="showType"
  337. class="form-input-number"
  338. style="width:200px;margin-top:20px;"
  339. :min="0"
  340. :max="9999"
  341. :step="1" :precision="0" step-strictly
  342. v-model="newData.mandatoryStudyHoursConfig.undergraduateHours"
  343. >
  344. </el-input-number>
  345. </div>
  346. </div>
  347. </div>
  348. <div v-if="this.newData.targetUserType == 1" class="yzyh-input-max-box">
  349. <p class="yzyh-title-p">教职工</p>
  350. <div class="yzyh-text-box">
  351. <p>新入职</p>
  352. <p>非新入职</p>
  353. </div>
  354. <div class="yzyh-input-big-box">
  355. <div class="yzyh-input-box">
  356. <el-input-number
  357. :disabled="showType"
  358. class="form-input-number"
  359. style="width:200px;margin-top:20px;"
  360. :min="0"
  361. :max="9999"
  362. :step="1" :precision="0" step-strictly
  363. v-model="newData.mandatoryStudyHoursConfig.staffNewHours"
  364. >
  365. </el-input-number>
  366. </div>
  367. <div class="yzyh-input-box">
  368. <el-input-number
  369. :disabled="showType"
  370. class="form-input-number"
  371. style="width:200px;margin-top:20px;"
  372. :min="0"
  373. :max="9999"
  374. :step="1" :precision="0" step-strictly
  375. v-model="newData.mandatoryStudyHoursConfig.staffNonNewHours"
  376. >
  377. </el-input-number>
  378. </div>
  379. </div>
  380. </div>
  381. </div>
  382. </el-form-item>
  383. <el-form-item label="考前学习" prop="preCourseEnabled">
  384. <div class="switch-row">
  385. <el-switch :disabled="showType" v-model="newData.preCourseEnabled" :active-value="1" :inactive-value="0"
  386. active-color="#0183FB" inactive-color="#AAAAAA"
  387. />
  388. <p class="checkButton-p" style="margin-left:20px;" v-if="newData.preCourseEnabled == 1&&!showType"
  389. @click="openCourseDrawer"
  390. >选择课程</p>
  391. <div class="tip-text" style="margin-left:20px;">开启后,需完成学习才能参加考试</div>
  392. </div>
  393. <div class="selected-tag" v-if="newData.preCourseEnabled==1&&newData.preCourseId"
  394. style="margin-top:8px;max-width:400px;"
  395. >
  396. <span>{{ newData.courseName }}</span>
  397. <!--<i class="el-icon-close" @click="newData.preCourseId = null; newData.courseName = ''"></i>-->
  398. </div>
  399. </el-form-item>
  400. <el-form-item label="模拟练习" prop="mockEnabled">
  401. <div class="switch-row">
  402. <el-switch :disabled="showType" v-model="newData.mockEnabled" :active-value="1" :inactive-value="0"
  403. active-color="#0183FB" inactive-color="#AAAAAA"
  404. />
  405. <el-checkbox
  406. :disabled="showType"
  407. v-if="newData.mockEnabled == 1"
  408. v-model="newData.mockMode"
  409. true-label="1"
  410. false-label="2"
  411. style="margin-left:20px;">
  412. 复用试卷
  413. </el-checkbox>
  414. <p class="checkButton-p" v-if="newData.mockEnabled == 1&&newData.mockMode == 2&&!showType"
  415. style="margin-left:20px;" @click="openMockPaperDrawer"
  416. >选择试卷</p>
  417. <span class="tip-text" style="margin-left:20px;">开启后,需完成模拟练习任务才能参加考试</span>
  418. </div>
  419. <div class="mock-stat-bar"
  420. v-if="newData.mockPaperId&&newData.mockEnabled == 1&&newData.mockMode == 2"
  421. >
  422. <span style="margin-right:20px;"><b>{{ newData.mockPaperName}}</b></span>
  423. <span>总题目数:<b>{{ newData.mockTotalCount || 0 }}</b></span>
  424. <span style="margin-left:20px;">总分:<b>{{ newData.mockTotalScore || 0 }}</b></span>
  425. <span style="margin-left:20px;">及格分:<b>{{ newData.mockPassScore || 0 }}</b></span>
  426. <!--<i class="el-icon-close" @click="newData.mockPaperId = null;newData.mockPaperName = '';newData.mockTotalCount = 0;newData.mockTotalScore = 0;newData.mockPassScore = 0"></i>-->
  427. </div>
  428. </el-form-item>
  429. <el-form-item label="考试承诺书" prop="commitmentEnabled">
  430. <div class="switch-row">
  431. <el-switch :disabled="showType" v-model="newData.commitmentEnabled" :active-value="1" :inactive-value="0"
  432. active-color="#0183FB" inactive-color="#AAAAAA"
  433. />
  434. <span class="tip-text" style="margin-left:20px;">开启后,考生需要阅读考试承诺内容并做出承诺才可开始考试</span>
  435. <span style="margin-left:30px;font-weight:600;color:#333;">承诺书打印</span>
  436. <el-switch :disabled="showType" v-model="newData.commitmentPrintEnabled" :active-value="1" :inactive-value="0"
  437. active-color="#0183FB" inactive-color="#AAAAAA" style="margin-left:12px;"
  438. />
  439. </div>
  440. <div class="editor-box" v-if="newData.commitmentEnabled == 1" style="margin-top:12px;">
  441. <tinymce-text
  442. :disabled="showType"
  443. v-model="newData.commitmentContent"
  444. :height="500"
  445. :max-length="1000"
  446. :upload-url="editorUploadUrl"
  447. :upload-headers="editorUploadHeaders"
  448. />
  449. </div>
  450. </el-form-item>
  451. </div>
  452. </div>
  453. <!-- ==================== 防作弊 ==================== -->
  454. <div v-show="activeTab === 'antiCheat'">
  455. <div class="section-block">
  456. <!--<el-form-item label="图形弹窗校验" prop="popupVerifyEnabled">-->
  457. <!--<div class="switch-row">-->
  458. <!--<el-switch :disabled="showType" v-model="newData.popupVerifyEnabled" :active-value="1" :inactive-value="0"-->
  459. <!--active-color="#0183FB" inactive-color="#AAAAAA"-->
  460. <!--/>-->
  461. <!--<template v-if="newData.popupVerifyEnabled==1">-->
  462. <!--<p class="tip-text" style="margin-left:12px;">开启后,每隔</p>-->
  463. <!--<div class="number-stepper" style="margin-left:8px;">-->
  464. <!--<el-input-number-->
  465. <!--:disabled="showType"-->
  466. <!--class="form-input-number"-->
  467. <!--style="width:160px;"-->
  468. <!--:min="0"-->
  469. <!--:max="9999"-->
  470. <!--:step="1" :precision="0" step-strictly-->
  471. <!--v-model="newData.popupIntervalMinutes"-->
  472. <!--&gt;-->
  473. <!--</el-input-number>-->
  474. <!--</div>-->
  475. <!--<span class="tip-text" style="margin-left:8px;">分钟,提醒弹窗验证</span>-->
  476. <!--</template>-->
  477. <!--<span class="tip-text" style="margin-left:12px;" v-else>开启后,每隔 N 分钟,提醒弹窗验证</span>-->
  478. <!--</div>-->
  479. <!--</el-form-item>-->
  480. <el-form-item label="人脸识别校验">
  481. <div class="anti-cheat-group">
  482. <div class="switch-row" style="margin-bottom:12px;">
  483. <el-switch :disabled="showType" v-model="newData.preFaceVerifyEnabled" :active-value="1" :inactive-value="0"
  484. active-color="#0183FB" inactive-color="#AAAAAA"
  485. />
  486. <span class="tip-text" style="margin-left:12px;">开启后,考试前需要进行人脸识别(仅学习考试一体机)</span>
  487. </div>
  488. <div class="switch-row">
  489. <el-switch :disabled="showType" v-model="newData.postFaceVerifyEnabled" :active-value="1" :inactive-value="0"
  490. active-color="#0183FB" inactive-color="#AAAAAA"
  491. />
  492. <span class="tip-text" style="margin-left:12px;">开启后,考试后需要进行人脸识别(仅学习考试一体机)</span>
  493. </div>
  494. </div>
  495. </el-form-item>
  496. <el-form-item label="摄像头抓拍">
  497. <div class="switch-row">
  498. <el-switch :disabled="showType" v-model="newData.cameraCaptureEnabled" :active-value="1" :inactive-value="0"
  499. active-color="#0183FB" inactive-color="#AAAAAA"
  500. />
  501. <span class="tip-text" style="margin-left:12px;">开启后,考试过程中摄像头随机抓拍(仅学习考试一体机)</span>
  502. </div>
  503. </el-form-item>
  504. </div>
  505. </div>
  506. <!-- ==================== 获得证书 ==================== -->
  507. <div v-show="activeTab === 'certificate'">
  508. <div class="section-block">
  509. <el-form-item label="获得证书" prop="certificateEnabled">
  510. <div class="switch-row">
  511. <el-switch :disabled="showType" v-model="newData.certificateEnabled" :active-value="1" :inactive-value="0"
  512. active-color="#0183FB" inactive-color="#AAAAAA"
  513. />
  514. <p v-if="newData.certificateEnabled==1&&!showType" class="checkButton-p" style="margin-left:20px;"
  515. @click="openCertTemplateDrawer"
  516. >选择模板</p>
  517. </div>
  518. <div class="mock-stat-bar" style="padding:0 20px;"
  519. v-if="newData.certificateTemplateId&&newData.certificateEnabled == 1">
  520. <span style="margin-right:20px;"><b>{{ newData.certificateTemplateName}}</b></span>
  521. <!--<i class="el-icon-close" @click="newData.certificateTemplateId = null;newData.certificateTemplateName = '';"></i>-->
  522. </div>
  523. </el-form-item>
  524. <el-form-item label="证书打印" v-if="newData.certificateEnabled == 1">
  525. <el-switch :disabled="showType" v-model="newData.certificatePrintEnabled" :active-value="1" :inactive-value="0"
  526. active-color="#0183FB" inactive-color="#AAAAAA"
  527. />
  528. </el-form-item>
  529. <el-form-item label="证书有效期" prop="certificateValidMonths" v-if="newData.certificateEnabled == 1">
  530. <div class="stepper-row">
  531. <div class="number-stepper">
  532. <el-input-number
  533. :disabled="showType"
  534. class="form-input-number"
  535. style="width:160px;"
  536. :min="0"
  537. :max="9999"
  538. :step="1" :precision="0" step-strictly
  539. v-model="newData.certificateValidMonths"
  540. >
  541. </el-input-number>
  542. </div>
  543. <span class="unit-text">个月</span>
  544. </div>
  545. </el-form-item>
  546. <el-form-item label="证书复审周期" prop="certificateReviewMonths" v-if="newData.certificateEnabled == 1">
  547. <div class="stepper-row">
  548. <div class="number-stepper">
  549. <el-input-number
  550. :disabled="showType"
  551. class="form-input-number"
  552. style="width:160px;"
  553. :min="0"
  554. :max="9999"
  555. :step="1" :precision="0" step-strictly
  556. v-model="newData.certificateReviewMonths"
  557. >
  558. </el-input-number>
  559. </div>
  560. <span class="unit-text">个月</span>
  561. </div>
  562. </el-form-item>
  563. </div>
  564. </div>
  565. </el-form>
  566. </div>
  567. </div>
  568. </div>
  569. <el-drawer
  570. size="100%"
  571. custom-class="examinationArrange-addPage-drawer"
  572. :append-to-body="true"
  573. :title="drawerTitle"
  574. ref="drawer"
  575. :visible.sync="drawer"
  576. direction="rtl"
  577. >
  578. <!--选择试卷/选择试题-->
  579. <selectTestPaper v-if="(drawerType === 1 || drawerType === 5)&&drawer"></selectTestPaper>
  580. <!--选择课程-->
  581. <selectCourse v-if="drawerType === 2&&drawer"></selectCourse>
  582. <!--选择用户-->
  583. <selectUser v-if="drawerType === 3&&drawer"></selectUser>
  584. <!--选择范围-->
  585. <selectScope v-if="drawerType === 4&&drawer"></selectScope>
  586. <!--选择证书-->
  587. <selectCertificate v-if="drawerType === 6&&drawer"></selectCertificate>
  588. </el-drawer>
  589. </div>
  590. </template>
  591. <script>
  592. import { getToken } from '@/utils/auth'
  593. import tinymceText from '@/components/tinymceContainer/tinymceText.vue'
  594. import selectTestPaper from './selectTestPaper.vue'
  595. import selectCourse from './selectCourse.vue'
  596. import selectUser from './selectUser.vue'
  597. import selectScope from './selectScope.vue'
  598. import selectCertificate from './selectCertificate.vue'
  599. import {
  600. examElExamAdd,examElExamEdit,examElExamDetail,examElKnowledgePointTreeList,examElDisciplineTypeList,
  601. examElExamTypeList, laboratoryLevelConfigGetLevelTitleList,examElConfigMasterInitMinHour
  602. } from '@/api/safetyEducationExaminationNew/index'
  603. export default {
  604. name: 'addPage',
  605. components: {
  606. tinymceText,
  607. selectTestPaper,
  608. selectCourse,
  609. selectUser,
  610. selectScope,
  611. selectCertificate
  612. },
  613. props: {
  614. propsData: {}
  615. },
  616. data() {
  617. const validateData0 = (rule, value, callback) => {
  618. if (this.newData.scopeType == 2 && !this.scopeList[0]) {
  619. callback(new Error('请添加考试范围-范围组'))
  620. }else if(this.newData.scopeType == 3 && !this.userList[0]){
  621. callback(new Error('请添加考试范围-考生'))
  622. } else {
  623. callback()
  624. }
  625. }
  626. const validateData = (rule, value, callback) => {
  627. if (value == 0) {
  628. callback(new Error('总分数不能为0'))
  629. } else {
  630. callback()
  631. }
  632. }
  633. const validateData1 = (rule, value, callback) => {
  634. if(this.newData.targetUserType==2){
  635. if (this.newData.studyHoursRequirementEnabled == 1 && !this.yzyhTest && !this.placementTest && this.newData.studyHoursRequirement == 0) {
  636. callback(new Error('学时要求不能为0'))
  637. }else if (this.newData.studyHoursRequirementEnabled == 1 && this.yzyhTest && this.newData.mandatoryStudyHoursConfig.freshmanNoLabHours == 0) {
  638. callback(new Error('研究生-新生的学时要求不能为0'))
  639. } else {
  640. callback()
  641. }
  642. }else if(this.newData.targetUserType==1){
  643. if (this.newData.studyHoursRequirementEnabled == 1 && this.yzyhTest && this.newData.mandatoryStudyHoursConfig.staffNewHours == 0) {
  644. callback(new Error('教职工-新入职的学时要求不能为0'))
  645. } else {
  646. callback()
  647. }
  648. }
  649. }
  650. const validateData2 = (rule, value, callback) => {
  651. if (this.newData.preCourseEnabled == 1 && !this.newData.preCourseId) {
  652. callback(new Error('请选择考前学习课程'))
  653. } else {
  654. callback()
  655. }
  656. }
  657. const validateData3 = (rule, value, callback) => {
  658. if (this.newData.mockEnabled == 1 && this.newData.mockMode == 2 && !this.newData.mockPaperId) {
  659. callback(new Error('请选择模拟练习试卷'))
  660. } else {
  661. callback()
  662. }
  663. }
  664. const validateData4 = (rule, value, callback) => {
  665. if (this.newData.commitmentEnabled == 1 && !this.newData.commitmentContent) {
  666. callback(new Error('请输入考试承诺书内容'))
  667. } else {
  668. callback()
  669. }
  670. }
  671. // const validateData5 = (rule, value, callback) => {
  672. // if (this.newData.popupVerifyEnabled == 1 && this.newData.popupIntervalMinutes == 0) {
  673. // callback(new Error('图形弹窗校验间隔不能为0'))
  674. // } else {
  675. // callback()
  676. // }
  677. // }
  678. const validateData6 = (rule, value, callback) => {
  679. if (this.newData.certificateEnabled == 1 && !this.newData.certificateTemplateId) {
  680. callback(new Error('请选择证书'))
  681. } else {
  682. callback()
  683. }
  684. }
  685. const validateData7 = (rule, value, callback) => {
  686. if (this.newData.certificateEnabled == 1 && this.newData.certificateValidMonths == 0) {
  687. callback(new Error('证书有效期不能为0'))
  688. } else {
  689. callback()
  690. }
  691. }
  692. const validateData8 = (rule, value, callback) => {
  693. if (this.newData.certificateEnabled == 1 && this.newData.certificateReviewMonths == 0) {
  694. callback(new Error('证书复审周期不能为0'))
  695. } else {
  696. callback()
  697. }
  698. }
  699. return {
  700. //日期选择范围限制
  701. pickerOptions: {
  702. disabledDate(time) {
  703. return time.getTime() < Date.now() - 8.64e7;
  704. }
  705. },
  706. editorUploadUrl: this.uploadUrl(),
  707. editorUploadHeaders: {
  708. Authorization: getToken()
  709. },
  710. activeTab: 'basic',
  711. tabs: [
  712. { key: 'basic', label: '基本设置' },
  713. { key: 'preExam', label: '考前配置' },
  714. { key: 'antiCheat', label: '防作弊' },
  715. { key: 'certificate', label: '获得证书' }
  716. ],
  717. scopeOptions: [
  718. { label: '全校', value: 1 },
  719. { label: '考试范围', value: 2 },
  720. { label: '指定考生', value: 3 }
  721. ],
  722. scopeOptionsB: [
  723. { label: '学生', value: 2 },
  724. { label: '教职工', value: 1 },
  725. ],
  726. optionListC:[],
  727. optionExamType: [],
  728. tableList: [],
  729. tableList2: [],
  730. optionRiskLevel: [],
  731. scopeList: [],
  732. userList: [],
  733. //是否是分级考试
  734. placementTest: false,
  735. //是否是应知应会考试
  736. yzyhTest:false,
  737. //答卷次数限制
  738. answerUnlimited: false,
  739. //应知应会学时要求数据
  740. hourData:{
  741. level1Hour:0,
  742. level2Hour:0,
  743. level3Hour:0,
  744. level4Hour:0,
  745. },
  746. newData: {
  747. examTypeId: null,
  748. disciplineTypeId: null,
  749. riskLevelId: null,
  750. examName: '',
  751. attemptLimit: 1,
  752. shareStatus: 0,
  753. enableStatus: 0,
  754. paperId: null,
  755. paperName: '',
  756. examTimeRange: null,
  757. answerDuration: 0,
  758. scopeType: 1,
  759. targetUserType: 2,
  760. studyHoursRequirementEnabled: 0,
  761. studyHoursRequirement: 0,
  762. knowledgePointIds:[],
  763. preCourseEnabled: 0,
  764. preCourseId: null,
  765. courseName: '',
  766. mockEnabled: 0,
  767. mockMode: 2,
  768. mockPaperId: null,
  769. mockPaperName: '',
  770. mockTotalCount: 0,
  771. mockTotalScore: 0,
  772. mockPassScore: 0,
  773. commitmentEnabled: 0,
  774. commitmentPrintEnabled: 0,
  775. commitmentContent: '',
  776. // popupVerifyEnabled: 0,
  777. // popupIntervalMinutes: 0,
  778. preFaceVerifyEnabled: 0,
  779. postFaceVerifyEnabled: 0,
  780. cameraCaptureEnabled: 0,
  781. certificateEnabled: 0,
  782. certificateTemplateId: null,
  783. certificateTemplateName: '',
  784. certificatePrintEnabled: 0,
  785. certificateValidMonths: 0,
  786. certificateReviewMonths: 0,
  787. mandatoryStudyHoursConfig:{
  788. freshmanNoLabHours:0,
  789. undergraduateHours:0,
  790. staffNewHours:0,
  791. staffNonNewHours:0,
  792. }
  793. },
  794. rules: {
  795. examTypeId: [
  796. { required: true, message: '请选择考试类型', trigger: 'change' }
  797. ],
  798. disciplineTypeId: [
  799. { required: true, message: '请选择安全分类', trigger: 'change' }
  800. ],
  801. riskLevelId: [
  802. { required: true, message: '请选择风险等级', trigger: 'change' }
  803. ],
  804. examName: [
  805. { required: true, message: '请输入考试名称', trigger: 'change' }
  806. ],
  807. attemptLimit: [
  808. { required: true, message: '请输入答卷次数', trigger: 'change' }
  809. ],
  810. paperId: [
  811. { required: true, message: '请选择考卷', trigger: 'change' }
  812. ],
  813. enableStatus: [
  814. { required: true, message: '请选择启用停用', trigger: 'change' }
  815. ],
  816. answerDuration: [
  817. { required: true, message: '请选择考试时长', trigger: 'change' },
  818. { validator: validateData, trigger: 'blur' }
  819. ],
  820. scopeType: [
  821. { required: true, message: '请选择考试范围', trigger: 'change' },
  822. { validator: validateData0, trigger: 'blur' }
  823. ],
  824. targetUserType: [
  825. { required: true, message: '请选择考试范围', trigger: 'change' },
  826. { validator: validateData0, trigger: 'blur' }
  827. ],
  828. examTimeRange: [
  829. { required: true, message: '请选择考试时间', trigger: 'change' }
  830. ],
  831. studyHoursRequirementEnabled: [
  832. { required: true, message: '请输入学时要求', trigger: 'change' },
  833. { validator: validateData1, trigger: 'blur' }
  834. ],
  835. preCourseEnabled: [
  836. { required: true, message: '请选择考前学习课程', trigger: 'change' },
  837. { validator: validateData2, trigger: 'blur' }
  838. ],
  839. mockEnabled: [
  840. { required: true, message: '请选择模拟练习试卷', trigger: 'change' },
  841. { validator: validateData3, trigger: 'blur' }
  842. ],
  843. commitmentEnabled: [
  844. { required: true, message: '请输入考试承诺书内容', trigger: 'change' },
  845. { validator: validateData4, trigger: 'blur' }
  846. ],
  847. // popupVerifyEnabled: [
  848. // { required: true, message: '请输入图形弹窗校验间隔', trigger: 'change' },
  849. // { validator: validateData5, trigger: 'blur' }
  850. // ],
  851. certificateEnabled: [
  852. { required: true, message: '请选择证书', trigger: 'change' },
  853. { validator: validateData6, trigger: 'blur' }
  854. ],
  855. certificateValidMonths: [
  856. { required: true, message: '证书有效期不能为0', trigger: 'change' },
  857. { validator: validateData7, trigger: 'blur' }
  858. ],
  859. certificateReviewMonths: [
  860. { required: true, message: '证书复审周期不能为0', trigger: 'change' },
  861. { validator: validateData8, trigger: 'blur' }
  862. ],
  863. },
  864. //弹窗相关
  865. drawerTitle: '',
  866. drawerType: '',
  867. drawer: false,
  868. showType:false,
  869. }
  870. },
  871. watch: {
  872. 'newData.knowledgePointIds': {
  873. handler(newVal, oldVal) {
  874. // 假设最多只能选 2 个
  875. if (newVal && newVal.length > 10) {
  876. this.msgError('最多选择10个知识点')
  877. this.$nextTick(() => {
  878. // 将值回退到上一次的状态
  879. this.newData.knowledgePointIds = oldVal;
  880. });
  881. }
  882. },
  883. deep: true, // 关键:必须开启深度监听
  884. immediate: false // 初始化时不触发,防止默认值超限误报
  885. }
  886. },
  887. mounted() {
  888. this.initialize();
  889. this.examElExamTypeList();
  890. this.laboratoryLevelConfigGetLevelTitleList();
  891. this.examElConfigMasterInitMinHour();
  892. this.examElKnowledgePointTreeList();
  893. this.examElDisciplineTypeList();
  894. },
  895. methods: {
  896. initialize() {
  897. if (this.propsData.id) {
  898. if(this.propsData.showType){
  899. this.$set(this,'showType',true);
  900. }
  901. examElExamDetail({id:this.propsData.id}).then(response => {
  902. if(response.data.attemptLimit == 0){
  903. this.$set(this,'answerUnlimited',true);
  904. }
  905. let obj = {
  906. id:this.propsData.id,
  907. examTypeId: response.data.examTypeId,
  908. disciplineTypeId: response.data.disciplineTypeId,
  909. riskLevelId: response.data.riskLevelId,
  910. examName: response.data.examName,
  911. attemptLimit: response.data.attemptLimit,
  912. shareStatus: response.data.shareStatus,
  913. enableStatus: response.data.enableStatus,
  914. paperId: response.data.paperId,
  915. paperName: response.data.paperName,
  916. examTimeRange: [response.data.startTime.replace("T", "0"),response.data.endTime.replace("T", "0")],
  917. answerDuration: response.data.answerDuration,
  918. scopeType:response.data.scopeType,
  919. targetUserType:response.data.targetUserType?response.data.targetUserType:2,
  920. studyHoursRequirementEnabled: response.data.studyHoursRequirementEnabled,
  921. studyHoursRequirement: response.data.studyHoursRequirement,
  922. knowledgePointIds: response.data.knowledgePointIds,
  923. preCourseEnabled: response.data.preCourseEnabled,
  924. preCourseId: response.data.preCourseEnabled?response.data.preCourseId:null,
  925. courseName: response.data.preCourseEnabled?response.data.courseName:'',
  926. mockEnabled: response.data.mockEnabled,
  927. mockMode: response.data.mockMode,
  928. mockPaperId: response.data.mockEnabled==1&&response.data.mockMode==2?response.data.mockPaperId:null,
  929. mockPaperName: response.data.mockEnabled==1&&response.data.mockMode==2?response.data.mockPaperName:'',
  930. mockTotalCount: response.data.mockEnabled==1&&response.data.mockMode==2?response.data.mockQuestionCount:0,
  931. mockTotalScore: response.data.mockEnabled==1&&response.data.mockMode==2?response.data.mockTotalScore:0,
  932. mockPassScore: response.data.mockEnabled==1&&response.data.mockMode==2?response.data.mockPassScore:0,
  933. commitmentEnabled: response.data.commitmentEnabled,
  934. commitmentPrintEnabled: response.data.commitmentPrintEnabled,
  935. commitmentContent: response.data.commitmentEnabled==1?response.data.commitmentContent:'',
  936. // popupVerifyEnabled: response.data.popupVerifyEnabled,
  937. // popupIntervalMinutes: response.data.popupIntervalMinutes,
  938. preFaceVerifyEnabled: response.data.preFaceVerifyEnabled,
  939. postFaceVerifyEnabled: response.data.postFaceVerifyEnabled,
  940. cameraCaptureEnabled: response.data.cameraCaptureEnabled,
  941. certificateEnabled: response.data.certificateEnabled,
  942. certificateTemplateId: response.data.certificateEnabled==1?response.data.certificateTemplateId:null,
  943. certificateTemplateName: response.data.certificateEnabled==1?response.data.certificateTemplateName:'',
  944. certificatePrintEnabled: response.data.certificateEnabled==1?response.data.certificatePrintEnabled:0,
  945. certificateValidMonths: response.data.certificateEnabled==1?response.data.certificateValidMonths:0,
  946. certificateReviewMonths: response.data.certificateEnabled==1?response.data.certificateReviewMonths:0,
  947. mandatoryStudyHoursConfig: response.data.mandatoryStudyHoursConfig,
  948. };
  949. this.$set(this,'scopeList',response.data.ruleScopeItems?response.data.ruleScopeItems:[]);
  950. this.$set(this,'userList',response.data.designatedCandidates?response.data.designatedCandidates:[]);
  951. this.$set(this,'newData',obj);
  952. this.examChange();
  953. })
  954. }
  955. },
  956. backPage() {
  957. this.$parent.tableButton(6)
  958. },
  959. resetButton() {
  960. this.initialize();
  961. },
  962. submitButton() {
  963. let self = this;
  964. this.$refs.basicForm.validate((valid, fields) => {
  965. if (!valid) {
  966. const firstErrorField = Object.keys(fields)[0]
  967. const tabFieldMap = [
  968. { tab: 'basic', list: ['examTypeId','disciplineTypeId','riskLevelId','examName','attemptLimit','paperId','enableStatus','answerDuration','scopeType','examTimeRange'] },
  969. { tab: 'preExam', list: ['studyHoursRequirementEnabled','preCourseEnabled','mockEnabled','commitmentEnabled'] },
  970. // { tab: 'antiCheat', list: ['popupVerifyEnabled'] },
  971. { tab: 'certificate', list: ['certificateEnabled','certificateValidMonths','certificateReviewMonths'] }
  972. ]
  973. const matchedTab = tabFieldMap.find(item => item.list.includes(firstErrorField))
  974. this.activeTab = matchedTab ? matchedTab.tab : 'basic'
  975. } else {
  976. this.$confirm('是否确认保存?', "提示", {
  977. confirmButtonText: "确定",
  978. cancelButtonText: "取消",
  979. type: "warning"
  980. }).then(function() {
  981. }).then(() => {
  982. self.dataIntegration();
  983. }).catch(() => {});
  984. }
  985. })
  986. },
  987. //提交
  988. dataIntegration(){
  989. let self = this;
  990. let obj = {
  991. examTypeId:this.newData.examTypeId,
  992. disciplineTypeId:this.newData.disciplineTypeId,
  993. riskLevelId:this.placementTest?this.newData.riskLevelId:'',
  994. examName:this.newData.examName,
  995. attemptLimit:this.answerUnlimited?0:this.newData.attemptLimit,
  996. shareStatus:this.newData.shareStatus,
  997. enableStatus:this.newData.enableStatus,
  998. paperId:this.newData.paperId,
  999. startTime:this.newData.examTimeRange[0].replace(" ", "T"),
  1000. endTime:this.newData.examTimeRange[1].replace(" ", "T"),
  1001. answerDuration:this.newData.answerDuration,
  1002. scopeType:this.newData.scopeType,
  1003. targetUserType:this.yzyhTest?this.newData.targetUserType:'',
  1004. ruleScopeItems:this.newData.scopeType==2?this.scopeList:[],
  1005. designatedCandidates:this.newData.scopeType==3?this.userList:[],
  1006. studyHoursRequirementEnabled:this.newData.studyHoursRequirementEnabled,
  1007. studyHoursRequirement:this.newData.studyHoursRequirementEnabled == 1&&(!this.yzyhTest&&!this.placementTest)?this.newData.studyHoursRequirement:0,
  1008. mandatoryStudyHoursConfig:this.newData.studyHoursRequirementEnabled == 1&&this.yzyhTest?{
  1009. freshmanNoLabHours:this.newData.targetUserType==2?this.newData.mandatoryStudyHoursConfig.freshmanNoLabHours:0,
  1010. undergraduateHours:this.newData.targetUserType==2?this.newData.mandatoryStudyHoursConfig.undergraduateHours:0,
  1011. staffNewHours:this.newData.targetUserType==1?this.newData.mandatoryStudyHoursConfig.staffNewHours:0,
  1012. staffNonNewHours:this.newData.targetUserType==1?this.newData.mandatoryStudyHoursConfig.staffNonNewHours:0,
  1013. }:{
  1014. freshmanNoLabHours:0,
  1015. undergraduateHours:0,
  1016. staffNewHours:0,
  1017. staffNonNewHours:0,
  1018. },
  1019. knowledgePointIds:this.newData.studyHoursRequirementEnabled == 1&&(!this.yzyhTest&&!this.placementTest)?this.newData.knowledgePointIds:[],
  1020. preCourseEnabled:this.newData.preCourseEnabled,
  1021. preCourseId:this.newData.preCourseEnabled == 1?this.newData.preCourseId:'',
  1022. mockEnabled:this.newData.mockEnabled,
  1023. mockMode:this.newData.mockEnabled == 1&&this.newData.mockMode == 1?this.newData.mockMode:2,
  1024. mockPaperId:this.newData.mockEnabled == 1&&this.newData.mockMode == 2?this.newData.mockPaperId:'',
  1025. commitmentEnabled:this.newData.commitmentEnabled,
  1026. commitmentPrintEnabled:this.newData.commitmentPrintEnabled,
  1027. commitmentContent:this.newData.commitmentEnabled == 1 ? this.newData.commitmentContent:'',
  1028. // popupVerifyEnabled:this.newData.popupVerifyEnabled,
  1029. // popupIntervalMinutes:this.newData.popupVerifyEnabled == 1?this.newData.popupIntervalMinutes:0,
  1030. preFaceVerifyEnabled:this.newData.preFaceVerifyEnabled,
  1031. postFaceVerifyEnabled:this.newData.postFaceVerifyEnabled,
  1032. cameraCaptureEnabled:this.newData.cameraCaptureEnabled,
  1033. certificateEnabled:this.newData.certificateEnabled,
  1034. certificateTemplateId:this.newData.certificateEnabled == 1?this.newData.certificateTemplateId:'',
  1035. certificatePrintEnabled:this.newData.certificateEnabled == 1?this.newData.certificatePrintEnabled:0,
  1036. certificateValidMonths:this.newData.certificateEnabled == 1?this.newData.certificateValidMonths:0,
  1037. certificateReviewMonths:this.newData.certificateEnabled == 1?this.newData.certificateReviewMonths:0,
  1038. };
  1039. if(this.newData.id){
  1040. obj.id = this.newData.id;
  1041. this.examElExamEdit(obj);
  1042. }else{
  1043. this.examElExamAdd(obj);
  1044. }
  1045. },
  1046. examElExamAdd(obj){
  1047. examElExamAdd(obj).then(response => {
  1048. this.msgSuccess(response.message);
  1049. this.$parent.tableButton(6);
  1050. })
  1051. },
  1052. examElExamEdit(obj){
  1053. examElExamEdit(obj).then(response => {
  1054. this.msgSuccess(response.message);
  1055. this.$parent.tableButton(6);
  1056. })
  1057. },
  1058. openPaperDrawer() {
  1059. // TODO: 打开选择试卷弹窗
  1060. this.$set(this, 'drawerTitle', '选择试卷')
  1061. this.$set(this, 'drawerType', 1)
  1062. this.$set(this, 'drawer', true)
  1063. },
  1064. openCourseDrawer() {
  1065. // TODO: 打开选择课程弹窗
  1066. this.$set(this, 'drawerTitle', '选择课程')
  1067. this.$set(this, 'drawerType', 2)
  1068. this.$set(this, 'drawer', true)
  1069. },
  1070. openExamScopeDrawer() {
  1071. if (this.newData.scopeType == '2') {
  1072. // TODO: 打开选择范围弹窗
  1073. this.$set(this, 'drawerTitle', '选择范围')
  1074. this.$set(this, 'drawerType', 4)
  1075. this.$set(this, 'drawer', true)
  1076. } else if (this.newData.scopeType == '3') {
  1077. // TODO: 打开选择用户弹窗
  1078. this.$set(this, 'drawerTitle', '选择用户')
  1079. this.$set(this, 'drawerType', 3)
  1080. this.$set(this, 'drawer', true)
  1081. }
  1082. },
  1083. openMockPaperDrawer() {
  1084. // TODO: 打开选择试题弹窗
  1085. this.$set(this, 'drawerTitle', '选择试卷')
  1086. this.$set(this, 'drawerType', 5)
  1087. this.$set(this, 'drawer', true)
  1088. },
  1089. openCertTemplateDrawer() {
  1090. // TODO: 打开选择证书模板弹窗
  1091. this.$set(this, 'drawerTitle', '选择证书')
  1092. this.$set(this, 'drawerType', 6)
  1093. this.$set(this, 'drawer', true)
  1094. },
  1095. //弹窗关闭
  1096. drawerOffButton(data) {
  1097. if (this.drawerType == 1) {
  1098. //选择试卷
  1099. this.$set(this.newData, 'paperId', data.id)
  1100. this.$set(this.newData, 'paperName', data.name)
  1101. }else if(this.drawerType == 2){
  1102. //选择课程
  1103. this.$set(this.newData, 'preCourseId', data.id)
  1104. this.$set(this.newData, 'courseName', data.name)
  1105. }else if(this.drawerType == 3){
  1106. //选择用户
  1107. let obj = this.mergeAndDeduplicate(this.userList,data);
  1108. if(obj.filteredCount>0){
  1109. this.msgSuccess('已过滤 '+obj.filteredCount+' 条相同数据');
  1110. }
  1111. this.$set(this,'userList',obj.data);
  1112. }else if(this.drawerType == 4){
  1113. //选择范围
  1114. let obj = this.mergeAndDeduplicate(this.scopeList,data);
  1115. if(obj.filteredCount>0){
  1116. this.msgSuccess('已过滤 '+obj.filteredCount+' 条相同数据');
  1117. }
  1118. this.$set(this,'scopeList',obj.data);
  1119. }else if(this.drawerType == 5){
  1120. //选择模拟试卷
  1121. this.$set(this.newData, 'mockPaperId', data.id)
  1122. this.$set(this.newData, 'mockPaperName', data.name)
  1123. this.$set(this.newData, 'mockTotalCount', data.totalScore)
  1124. this.$set(this.newData, 'mockTotalScore', data.passScore)
  1125. this.$set(this.newData, 'mockPassScore', data.questionCount)
  1126. }else if(this.drawerType == 6){
  1127. //选择证书
  1128. this.$set(this.newData, 'certificateTemplateId', data.id)
  1129. this.$set(this.newData, 'certificateTemplateName', data.name)
  1130. }
  1131. this.$refs.drawer.closeDrawer()
  1132. },
  1133. //数据拼接过滤
  1134. mergeAndDeduplicate(arr1, arr2) {
  1135. const combinedArr = [...arr1, ...arr2];
  1136. const totalLength = combinedArr.length;
  1137. const uniqueArr = combinedArr.filter((item, index, self) => {
  1138. const firstIndex = self.findIndex(otherItem => {
  1139. return JSON.stringify(item) === JSON.stringify(otherItem);
  1140. });
  1141. return index === firstIndex;
  1142. });
  1143. const filteredCount = totalLength - uniqueArr.length;
  1144. return {
  1145. data: uniqueArr,
  1146. filteredCount: filteredCount
  1147. };
  1148. },
  1149. //考试类型选中
  1150. examChange() {
  1151. let self = this
  1152. for (let i = 0; i < self.optionExamType.length; i++) {
  1153. if (self.optionExamType[i].id == self.newData.examTypeId) {
  1154. if (self.optionExamType[i].examTypeCode == 'CLASSIFIED') {
  1155. self.$set(this, 'placementTest', true)
  1156. let num = 0;
  1157. for(let o=0;o<self.tableList2.length;o++){
  1158. if(self.newData.disciplineTypeId == self.tableList2[o].id){
  1159. num++
  1160. }
  1161. }
  1162. if(num == 0){
  1163. self.$set(self.newData,'disciplineTypeId',null);
  1164. }
  1165. } else {
  1166. self.$set(this, 'placementTest', false)
  1167. let num = 0;
  1168. for(let o=0;o<self.tableList.length;o++){
  1169. if(self.newData.disciplineTypeId == self.tableList[o].id){
  1170. num++
  1171. }
  1172. }
  1173. if(num == 0){
  1174. self.$set(self.newData,'disciplineTypeId',null);
  1175. }
  1176. }
  1177. if (self.optionExamType[i].examTypeCode == 'yzyh') {
  1178. self.$set(this.newData, 'scopeType', 1)
  1179. if(!this.newData.targetUserType){
  1180. self.$set(this.newData, 'targetUserType', 2)
  1181. }
  1182. self.$set(this, 'yzyhTest', true)
  1183. } else {
  1184. self.$set(this, 'yzyhTest', false)
  1185. }
  1186. }
  1187. }
  1188. },
  1189. //查询全部考试类型
  1190. examElExamTypeList() {
  1191. examElExamTypeList({}).then(response => {
  1192. let userInfo = JSON.parse(localStorage.getItem('user'));
  1193. let schoolId = process.env.VUE_APP_SCHOOL_ID;
  1194. if(userInfo.position == schoolId ){
  1195. this.$set(this, 'optionExamType', response.data)
  1196. } else {
  1197. let list = [];
  1198. for(let i=0;i<response.data.length;i++){
  1199. if(response.data[i].examTypeCode != 'CLASSIFIED' && response.data[i].examTypeCode != 'yzyh' && response.data[i].examTypeCode != 'STUDENT'){
  1200. list.push(response.data[i])
  1201. }
  1202. }
  1203. this.$set(this, 'optionExamType', list)
  1204. }
  1205. })
  1206. },
  1207. //查询全部考试类型
  1208. examElConfigMasterInitMinHour() {
  1209. examElConfigMasterInitMinHour({}).then(response => {
  1210. this.$set(this, 'hourData', response.data)
  1211. })
  1212. },
  1213. //查询全部考试类型
  1214. laboratoryLevelConfigGetLevelTitleList() {
  1215. laboratoryLevelConfigGetLevelTitleList({}).then(response => {
  1216. this.$set(this, 'optionRiskLevel', response.data)
  1217. })
  1218. },
  1219. //知识点
  1220. examElKnowledgePointTreeList(){
  1221. examElKnowledgePointTreeList({}).then(response => {
  1222. const list = response.data || [];
  1223. this.formatTreeData(list);
  1224. this.$set(this, 'optionListC', list);
  1225. });
  1226. },
  1227. //类型选项卡数据
  1228. examElDisciplineTypeList(){
  1229. examElDisciplineTypeList({}).then(response => {
  1230. const validCodes = ['CHEMISTRY', 'BIOLOGY', 'RADIATION', 'MECHANICAL_ELECTRICAL', 'OTHER'];
  1231. let list = response.data.filter(item => validCodes.includes(item.disciplineTypeCode));
  1232. this.$set(this, 'tableList', response.data)
  1233. this.$set(this, 'tableList2', list)
  1234. })
  1235. },
  1236. }
  1237. }
  1238. </script>
  1239. <style scoped lang="scss">
  1240. .examinationArrange-addPage {
  1241. .content-box {
  1242. flex: 1;
  1243. display: flex;
  1244. overflow: hidden;
  1245. }
  1246. .layout-box {
  1247. display: flex;
  1248. width: 100%;
  1249. height: 100%;
  1250. }
  1251. .side-nav {
  1252. width: 140px;
  1253. flex-shrink: 0;
  1254. border-right: 1px solid #e8e8e8;
  1255. padding: 24px 0;
  1256. background: #fff;
  1257. .nav-item {
  1258. padding: 14px 24px;
  1259. font-size: 14px;
  1260. color: #555;
  1261. cursor: pointer;
  1262. transition: all 0.15s;
  1263. &:hover {
  1264. color: #0183fa;
  1265. }
  1266. &.active {
  1267. color: #0183fa;
  1268. font-weight: 600;
  1269. background: #f0f7ff;
  1270. border-right: 3px solid #0183fa;
  1271. }
  1272. }
  1273. }
  1274. .tab-content {
  1275. flex: 1;
  1276. overflow-y: auto;
  1277. padding: 24px 32px;
  1278. }
  1279. .section-block {
  1280. padding-bottom: 8px;
  1281. }
  1282. .yzyh-max-big-box{
  1283. width:720px;
  1284. margin-top:20px;
  1285. .yzyh-title-box{
  1286. display: flex;
  1287. background-color: #F2F2F2;
  1288. border:1px solid #D7D7D7;
  1289. p{
  1290. line-height:40px;
  1291. padding:0 20px;
  1292. }
  1293. p:nth-child(1){
  1294. width:500px;
  1295. }
  1296. p:nth-child(2){
  1297. width:220px;
  1298. }
  1299. }
  1300. .yzyh-input-max-box:nth-child(2){
  1301. .yzyh-title-p{
  1302. line-height:160px;
  1303. }
  1304. }
  1305. .yzyh-input-max-box:nth-child(3){
  1306. .yzyh-title-p{
  1307. line-height:80px;
  1308. }
  1309. }
  1310. .yzyh-input-max-box:nth-child(4){
  1311. .yzyh-title-p{
  1312. line-height:160px;
  1313. }
  1314. }
  1315. .yzyh-input-max-box{
  1316. display: flex;
  1317. border-bottom:1px solid #D7D7D7;
  1318. .yzyh-title-p{
  1319. width:200px;
  1320. padding:0 20px;
  1321. border-left:1px solid #D7D7D7;
  1322. }
  1323. .yzyh-text-box{
  1324. width:300px;
  1325. p{
  1326. padding:0 20px;
  1327. line-height:80px;
  1328. border-left:1px solid #D7D7D7;
  1329. }
  1330. p:nth-child(1){
  1331. }
  1332. p:nth-child(2){
  1333. border-top:1px solid #D7D7D7;
  1334. }
  1335. }
  1336. .yzyh-input-big-box{
  1337. width:220px;
  1338. border-right:1px solid #D7D7D7;
  1339. .yzyh-input-box{
  1340. height:80px;
  1341. .yzyh-text-p{
  1342. color:#666;
  1343. line-height:40px;
  1344. background-color:#F4F6FA;
  1345. margin:20px 20px 20px 0;
  1346. padding:0 10px;
  1347. border-radius:4px;
  1348. margin-left:-180px;
  1349. text-align: center;
  1350. }
  1351. }
  1352. .yzyh-input-box:nth-child(2){
  1353. border-top:1px solid #D7D7D7;
  1354. }
  1355. }
  1356. }
  1357. }
  1358. .section-divider {
  1359. height: 1px;
  1360. background: #e8e8e8;
  1361. margin: 16px 0 24px;
  1362. }
  1363. .flex-row-box {
  1364. display: flex;
  1365. flex-wrap: wrap;
  1366. gap: 0 60px;
  1367. }
  1368. .stepper-row {
  1369. display: flex;
  1370. align-items: center;
  1371. }
  1372. .number-stepper {
  1373. display: inline-flex;
  1374. align-items: center;
  1375. border-radius: 4px;
  1376. overflow: hidden;
  1377. .stepper-btn {
  1378. width: 32px;
  1379. height: 32px;
  1380. background: #f5f7fa;
  1381. border: none;
  1382. cursor: pointer;
  1383. font-size: 16px;
  1384. color: #333;
  1385. &:hover {
  1386. background: #e6f0fe;
  1387. }
  1388. }
  1389. .stepper-val {
  1390. min-width: 44px;
  1391. text-align: center;
  1392. font-size: 14px;
  1393. padding: 0 4px;
  1394. }
  1395. }
  1396. .unit-text {
  1397. margin-left: 8px;
  1398. color: #333;
  1399. white-space: nowrap;
  1400. font-size: 14px;
  1401. }
  1402. .tip-text {
  1403. color: #999;
  1404. font-size: 13px;
  1405. }
  1406. .paper-select-row {
  1407. display: flex;
  1408. align-items: center;
  1409. gap: 12px;
  1410. flex-wrap: wrap;
  1411. }
  1412. .checkButton-p {
  1413. background-color: #0183fa;
  1414. color: #ffffff;
  1415. line-height: 40px;
  1416. border-radius: 4px;
  1417. text-align: center;
  1418. width: 80px;
  1419. cursor: pointer;
  1420. }
  1421. .selected-tag {
  1422. display: inline-flex;
  1423. align-items: center;
  1424. background: #e6f4ff;
  1425. border: 1px solid #91caff;
  1426. border-radius: 4px;
  1427. padding: 2px 12px;
  1428. color: #0183fa;
  1429. font-size: 13px;
  1430. min-width: 200px;
  1431. max-width: 500px;
  1432. span {
  1433. flex: 1;
  1434. }
  1435. i {
  1436. margin-left: 8px;
  1437. cursor: pointer;
  1438. &:hover {
  1439. color: #e74c3c;
  1440. }
  1441. }
  1442. }
  1443. .scope-btn-group {
  1444. display: flex;
  1445. gap: 8px;
  1446. margin-bottom: 12px;
  1447. .scope-btn {
  1448. padding: 7px 20px;
  1449. border: 1px solid #dcdfe6;
  1450. border-radius: 4px;
  1451. background: #fff;
  1452. cursor: pointer;
  1453. font-size: 14px;
  1454. color: #333;
  1455. display: flex;
  1456. align-items: center;
  1457. transition: all 0.15s;
  1458. &:hover {
  1459. border-color: #0183fa;
  1460. color: #0183fa;
  1461. }
  1462. &.active {
  1463. border-color: #0183fa;
  1464. color: #0183fa;
  1465. background: #f0f7ff;
  1466. }
  1467. }
  1468. }
  1469. .scope-table-box {
  1470. /*border: 1px solid #e8e8e8;*/
  1471. border-radius: 4px;
  1472. overflow: hidden;
  1473. height: 400px;
  1474. display: flex;
  1475. flex-direction: column;
  1476. .scope-table-header {
  1477. background: #f5f5f5;
  1478. padding: 4px 16px;
  1479. font-size: 13px;
  1480. color: #555;
  1481. border: 1px solid #e8e8e8;
  1482. border-bottom: none;
  1483. }
  1484. }
  1485. .switch-row {
  1486. display: flex;
  1487. /*align-items: center;*/
  1488. /*flex-wrap: wrap;*/
  1489. .el-switch {
  1490. margin-top: 10px;
  1491. }
  1492. .tip-text {
  1493. margin-top: 2px;
  1494. }
  1495. }
  1496. .anti-cheat-group {
  1497. display: flex;
  1498. flex-direction: column;
  1499. }
  1500. .mock-stat-bar {
  1501. background: #e6f4ff;
  1502. border: 1px solid #91caff;
  1503. border-radius: 4px;
  1504. padding: 10px 16px;
  1505. margin-top: 10px;
  1506. font-size: 13px;
  1507. color: #333;
  1508. display: inline-block;
  1509. b {
  1510. color: #0183fa;
  1511. font-weight: 600;
  1512. }
  1513. }
  1514. .editor-box {
  1515. max-width: 1030px;
  1516. }
  1517. }
  1518. </style>
  1519. <style lang="scss">
  1520. .examinationArrange-addPage-date-picker {
  1521. .el-input--small {
  1522. width: 144px !important;
  1523. }
  1524. .el-time-panel__content::after, .el-time-panel__content::before{
  1525. top:45%!important;
  1526. }
  1527. }
  1528. .examinationArrange-addPage-drawer {
  1529. .el-drawer__body {
  1530. padding: 0;
  1531. }
  1532. .el-drawer__header {
  1533. margin: 0;
  1534. }
  1535. }
  1536. </style>