EditPaperPendingTrial.vue 82 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625
  1. <template>
  2. <div
  3. v-loading="loading"
  4. class="edit-paper"
  5. element-loading-text="拼命加载中。。。"
  6. >
  7. <div class="edit-header">
  8. <div class="edit-header-top box-justify">
  9. <div class="header-info">
  10. <div class="header-info-item">
  11. <span>课程代码:</span>
  12. <span>{{ paper.course.code }}</span>
  13. </div>
  14. <div class="header-info-item">
  15. <span>课程名称:</span>
  16. <span>{{ paper.course.name }}</span>
  17. </div>
  18. <div class="header-info-item">
  19. <span>试卷名称:</span>
  20. <span>
  21. <el-tooltip class="item" effect="dark" placement="top-start">
  22. <div slot="content">{{ paper.name }}</div>
  23. <el-input
  24. v-model="paper.name"
  25. size="mini"
  26. class="header-info-input"
  27. placeholder="试卷名称"
  28. ></el-input>
  29. </el-tooltip>
  30. </span>
  31. </div>
  32. <div class="header-info-item">
  33. <span>试卷总分:</span>
  34. <span>{{ paper.totalScore }}</span>
  35. </div>
  36. </div>
  37. <div class="header-btns">
  38. <el-dropdown v-show="isShowAuditBtn()">
  39. <el-button type="primary" size="small">
  40. 审核<i class="el-icon-arrow-down el-icon--right"></i>
  41. </el-button>
  42. <el-dropdown-menu slot="dropdown">
  43. <el-dropdown-item>
  44. <el-button
  45. size="mini"
  46. type="success"
  47. @click="auditPaper('PASS')"
  48. >
  49. <i class="el-icon-success"></i>通过
  50. </el-button>
  51. </el-dropdown-item>
  52. <el-dropdown-item>
  53. <el-button
  54. size="mini"
  55. type="danger"
  56. @click="auditPaper('NOT_PASS')"
  57. >
  58. <i class="el-icon-error"></i>不通过
  59. </el-button>
  60. </el-dropdown-item>
  61. </el-dropdown-menu>
  62. </el-dropdown>
  63. <el-button
  64. v-show="isShowEditBtn()"
  65. type="primary"
  66. size="small"
  67. @click="savePaper"
  68. >保存
  69. </el-button>
  70. <el-button
  71. v-show="isShowEditBtn()"
  72. type="danger"
  73. plain
  74. size="small"
  75. @click="deletePaper(paper.id)"
  76. >删除
  77. </el-button>
  78. <el-button
  79. v-if="showCheckDuplicateBtn"
  80. type="primary"
  81. size="small"
  82. plain
  83. @click="checkDuplicate"
  84. >
  85. 进入查重
  86. </el-button>
  87. <el-dropdown v-show="isShowEditBtn()">
  88. <el-button type="primary" size="small" plain>
  89. 更多 <i class="el-icon-more el-icon--right"></i>
  90. </el-button>
  91. <el-dropdown-menu slot="dropdown" class="action-dropdown">
  92. <el-dropdown-item>
  93. <el-button type="primary" plain size="small" @click="openDialog"
  94. >上传音频
  95. </el-button>
  96. </el-dropdown-item>
  97. <el-dropdown-item>
  98. <el-button
  99. size="small"
  100. type="primary"
  101. plain
  102. @click="exportPaperAnswer()"
  103. ><i class="el-icon-download"></i>导出答案</el-button
  104. >
  105. </el-dropdown-item>
  106. <el-dropdown-item>
  107. <el-button
  108. type="primary"
  109. size="small"
  110. plain
  111. @click="openAnswerDialog"
  112. ><i class="el-icon-upload2"></i>导入答案
  113. </el-button>
  114. </el-dropdown-item>
  115. </el-dropdown-menu>
  116. </el-dropdown>
  117. <el-button
  118. size="small"
  119. type="danger"
  120. plain
  121. icon="icon icon-back"
  122. @click="back"
  123. >返回</el-button
  124. >
  125. </div>
  126. </div>
  127. <div class="edit-header-bottom box-justify">
  128. <div>
  129. <el-button type="info" size="small" @click="showBasicDialog">
  130. 基础构成
  131. </el-button>
  132. <el-button type="info" size="small" @click="showTypeDialog">
  133. 题型分布
  134. </el-button>
  135. <el-button type="info" size="small" @click="showBlueDialog">
  136. 蓝图分布
  137. </el-button>
  138. <el-button type="info" size="small" @click="showAuditDialog">
  139. 审核记录
  140. </el-button>
  141. </div>
  142. <div>
  143. <span class="tips-info margin-right-10"
  144. >当前状态:{{ paper.auditStatus | paperAuditStatusFilter }}</span
  145. >
  146. <el-button type="primary" size="small" plain @click="quesTagShowHide">
  147. {{ quesTagShow ? "隐藏" : "显示" }}属性
  148. </el-button>
  149. <el-button
  150. type="primary"
  151. size="small"
  152. plain
  153. @click="quesAnswerShowHide"
  154. >
  155. {{ quesAnswerShow ? "隐藏" : "显示" }}答案
  156. </el-button>
  157. </div>
  158. </div>
  159. </div>
  160. <div class="edit-body">
  161. <div class="edit-part-list">
  162. <div class="edit-part">
  163. <div class="edit-cont">
  164. <div class="edit-cont-title">
  165. <h3>考试说明</h3>
  166. </div>
  167. <div class="edit-cont-action">
  168. <el-button
  169. type="primary"
  170. plain
  171. size="small"
  172. @click="openEditExamPaperRemark"
  173. >编辑</el-button
  174. >
  175. </div>
  176. <div class="edit-cont-body">
  177. <div v-html="paper.examRemark"></div>
  178. </div>
  179. </div>
  180. </div>
  181. </div>
  182. <!-- 循环大题 -->
  183. <div
  184. v-for="(paperDetail, detailIndex) in paper.paperDetails"
  185. v-show="paperDetailShow(paperDetail)"
  186. :key="detailIndex"
  187. class="edit-part-list"
  188. >
  189. <div class="edit-part">
  190. <div
  191. class="edit-cont"
  192. @mouseover="quesMouseOver(paperDetail.id)"
  193. @mouseout="quesMouseOut(paperDetail.id)"
  194. >
  195. <div class="edit-cont-title">
  196. <h3>
  197. <span>{{ paperDetail.cnNum }}</span> <span>.</span>
  198. <span>{{ paperDetail.name }}</span>
  199. <span>
  200. ({{
  201. !paperDetail.title ? "本大题" : paperDetail.title + ","
  202. }}共{{ paperDetail.unitCount }}小题,满分{{
  203. paperDetail.score
  204. }}分)
  205. </span>
  206. </h3>
  207. </div>
  208. <div :id="paperDetail.id" class="edit-cont-action">
  209. <el-button
  210. v-show="parentView == 'gen_paper' && isShowEditBtn()"
  211. size="small"
  212. type="primary"
  213. plain
  214. @click="selectQues(paperDetail.id)"
  215. >选题
  216. </el-button>
  217. <el-button
  218. v-show="isShowEditBtn()"
  219. size="small"
  220. type="primary"
  221. plain
  222. @click="openEditPaperDetail(paperDetail)"
  223. >编辑
  224. </el-button>
  225. <el-button
  226. v-if="showUp(paperDetail)"
  227. v-show="isShowEditBtn()"
  228. size="small"
  229. type="primary"
  230. plain
  231. @click="movePaperDetail(paperDetail, 'up')"
  232. >上移
  233. </el-button>
  234. <el-button
  235. v-if="showDown(paperDetail)"
  236. v-show="isShowEditBtn()"
  237. size="small"
  238. type="primary"
  239. plain
  240. @click="movePaperDetail(paperDetail, 'down')"
  241. >下移
  242. </el-button>
  243. <el-button
  244. v-show="isShowEditBtn()"
  245. size="small"
  246. type="danger"
  247. @click="deletePaperDetail(paperDetail.id)"
  248. >删除
  249. </el-button>
  250. <el-button
  251. v-show="showButtons[detailIndex].up"
  252. size="small"
  253. type="primary"
  254. plain
  255. icon="el-icon-arrow-up"
  256. @click.stop="hideContent(detailIndex)"
  257. ></el-button>
  258. <el-button
  259. v-show="!showButtons[detailIndex].up"
  260. size="small"
  261. icon="el-icon-arrow-down"
  262. type="primary"
  263. plain
  264. @click.stop="showContent(detailIndex)"
  265. ></el-button>
  266. </div>
  267. <div
  268. v-question-audio
  269. class="edit-cont-body"
  270. v-html="paperDetail.description"
  271. ></div>
  272. </div>
  273. <div v-show="quesTagShow" class="edit-property">
  274. <div class="edit-property-box">
  275. <div
  276. v-for="(paperDetailTag, tagIndex) in paperDetail.tags"
  277. :key="tagIndex"
  278. class="edit-property-item"
  279. >
  280. <div class="edit-property-body edit-property-danger">
  281. <div class="edit-property-title">
  282. {{ paperDetailTag.tag }}
  283. </div>
  284. <div class="edit-property-content">
  285. {{ paperDetailTag.content }}
  286. </div>
  287. </div>
  288. </div>
  289. </div>
  290. </div>
  291. </div>
  292. <!-- 循环小题 -->
  293. <div
  294. v-show="showQuestions[detailIndex].is_show"
  295. class="edit-paper-questions"
  296. >
  297. <template
  298. v-for="(paperDetailUnit, unitIndex) in paperDetail.paperDetailUnits"
  299. >
  300. <div
  301. v-show="quesShow(paperDetailUnit.id)"
  302. :key="`question-${unitIndex}`"
  303. :class="[
  304. 'edit-part',
  305. {
  306. 'question-duplicate':
  307. paperDetailUnit.question.checkDuplicateStatus ==
  308. 'TO_BE_DISPOSE',
  309. },
  310. ]"
  311. >
  312. <div
  313. class="edit-cont"
  314. @mouseover="quesMouseOver(paperDetailUnit.id)"
  315. @mouseout="quesMouseOut(paperDetailUnit.id)"
  316. >
  317. <div class="edit-cont-title">
  318. <span>{{ paperDetailUnit.number }}.</span>
  319. <span
  320. v-question-audio
  321. :hasAudio="paperDetailUnit.question.hasAudio"
  322. :questionId="paperDetailUnit.question.id"
  323. v-html="paperDetailUnit.question.quesBody"
  324. ></span>
  325. <span> ({{ paperDetailUnit.score }}分) </span>
  326. </div>
  327. <div :id="paperDetailUnit.id" class="edit-cont-action">
  328. <span class="tips-info">
  329. {{ paperDetailUnit.question.bodyLengthText }}
  330. </span>
  331. <el-button
  332. v-if="
  333. paperDetailUnit.question.checkDuplicateStatus ==
  334. 'TO_BE_DISPOSE'
  335. "
  336. size="small"
  337. type="primary"
  338. plain
  339. @click="checkDuplicateQuestion(paperDetailUnit.question.id)"
  340. >进入查重
  341. </el-button>
  342. <el-button
  343. v-show="isShowEditBtn()"
  344. size="small"
  345. type="primary"
  346. plain
  347. @click="editQues(paperDetailUnit, paperDetailUnit.question)"
  348. >编辑
  349. </el-button>
  350. <el-button
  351. v-if="showUnitUp(paperDetail, paperDetailUnit.id)"
  352. v-show="isShowEditBtn()"
  353. size="small"
  354. type="primary"
  355. plain
  356. @click="
  357. movePaperDetailUnit(
  358. paperDetail.id,
  359. paperDetailUnit.id,
  360. 'up'
  361. )
  362. "
  363. >上移
  364. </el-button>
  365. <el-button
  366. v-if="showUnitDown(paperDetail, paperDetailUnit.id)"
  367. v-show="isShowEditBtn()"
  368. size="small"
  369. type="primary"
  370. plain
  371. @click="
  372. movePaperDetailUnit(
  373. paperDetail.id,
  374. paperDetailUnit.id,
  375. 'down'
  376. )
  377. "
  378. >下移
  379. </el-button>
  380. <el-button
  381. v-show="isShowEditBtn()"
  382. type="danger"
  383. size="small"
  384. @click="deleteQues(paperDetailUnit)"
  385. >删除
  386. </el-button>
  387. <el-button
  388. v-show="
  389. isNested(paperDetailUnit.questionType) &&
  390. showSubButtons[detailIndex + '-' + unitIndex]
  391. "
  392. size="small"
  393. icon="el-icon-arrow-up"
  394. @click.stop="hideSubContent(detailIndex + '-' + unitIndex)"
  395. ></el-button>
  396. <el-button
  397. v-show="
  398. isNested(paperDetailUnit.questionType) &&
  399. !showSubButtons[detailIndex + '-' + unitIndex]
  400. "
  401. size="small"
  402. type="primary"
  403. plain
  404. icon="el-icon-arrow-down"
  405. @click.stop="showSubContent(detailIndex + '-' + unitIndex)"
  406. ></el-button>
  407. </div>
  408. <div class="edit-cont-body">
  409. <div
  410. v-for="(quesOption, optionIndex) in paperDetailUnit.question
  411. .quesOptions"
  412. :key="optionIndex"
  413. class="paper-option"
  414. >
  415. <span>{{ optionIndex | optionOrderWordFilter }}. </span>
  416. <span
  417. v-question-audio
  418. :hasAudio="paperDetailUnit.question.hasAudio"
  419. :questionId="paperDetailUnit.question.id"
  420. v-html="quesOption.optionBody"
  421. ></span>
  422. </div>
  423. <div v-if="!isNested(paperDetailUnit.questionType)">
  424. <div v-show="quesAnswerShow">
  425. <span>答案:</span>
  426. <span v-html="paperDetailUnit.question.quesAnswer"></span>
  427. </div>
  428. </div>
  429. </div>
  430. </div>
  431. <div v-show="quesTagShow" class="edit-property">
  432. <div class="edit-property-box">
  433. <div
  434. v-for="(questionTag, tagIndex) in paperDetailUnit.question
  435. .tags"
  436. :key="tagIndex"
  437. class="edit-property-item"
  438. >
  439. <div class="edit-property-body">
  440. <div class="edit-property-title">
  441. {{ questionTag.tag }}
  442. </div>
  443. <div class="edit-property-content">
  444. {{ questionTag.content }}
  445. </div>
  446. </div>
  447. </div>
  448. </div>
  449. </div>
  450. </div>
  451. <!-- 子题 -->
  452. <div
  453. v-show="showSubQuestions[detailIndex + '-' + unitIndex]"
  454. :key="`question-sub-${unitIndex}`"
  455. class="edit-paper-question-subs"
  456. >
  457. <div
  458. v-for="(subQuestion, subIndex) in paperDetailUnit.question
  459. .subQuestions"
  460. v-show="quesShow(subQuestion.id)"
  461. :key="subIndex"
  462. class="edit-part"
  463. >
  464. <div
  465. class="edit-cont"
  466. @mouseover="
  467. quesMouseOver(
  468. getSubQuesEditId(paperDetailUnit, subQuestion)
  469. )
  470. "
  471. @mouseout="
  472. quesMouseOut(getSubQuesEditId(paperDetailUnit, subQuestion))
  473. "
  474. >
  475. <div
  476. v-show="isShowEditBtn()"
  477. :id="getSubQuesEditId(paperDetailUnit, subQuestion)"
  478. class="edit-cont-action"
  479. >
  480. <el-button
  481. size="small"
  482. type="primary"
  483. plain
  484. @click="editQues(paperDetailUnit, subQuestion)"
  485. >编辑
  486. </el-button>
  487. <el-button
  488. v-if="showUnitSubUp(paperDetailUnit, subQuestion.id)"
  489. size="small"
  490. type="primary"
  491. plain
  492. @click="
  493. movePaperDetailUnitSub(
  494. paperDetailUnit.id,
  495. subQuestion.id,
  496. 'up'
  497. )
  498. "
  499. >上移
  500. </el-button>
  501. <el-button
  502. v-if="showUnitSubDown(paperDetailUnit, subQuestion.id)"
  503. size="small"
  504. type="primary"
  505. plain
  506. @click="
  507. movePaperDetailUnitSub(
  508. paperDetailUnit.id,
  509. subQuestion.id,
  510. 'down'
  511. )
  512. "
  513. >下移
  514. </el-button>
  515. </div>
  516. <div class="edit-cont-title">
  517. <span>{{ subQuestion.subNumber }}. </span>
  518. <span v-question-audio v-html="subQuestion.quesBody"></span>
  519. <span
  520. >({{ paperDetailUnit.subScoreList[subIndex] }}分)</span
  521. >
  522. </div>
  523. <div
  524. v-if="!isMatchingQuestion(paperDetailUnit.questionType)"
  525. class="edit-cont-body"
  526. >
  527. <div
  528. v-for="(
  529. subQuesOption, subOptIndex
  530. ) in subQuestion.quesOptions"
  531. :key="subOptIndex"
  532. class="paper-option"
  533. >
  534. <span>{{ subOptIndex | optionOrderWordFilter }}. </span>
  535. <span
  536. v-question-audio
  537. v-html="subQuesOption.optionBody"
  538. ></span>
  539. </div>
  540. </div>
  541. <div v-show="quesAnswerShow">
  542. <span>答案:</span>
  543. <span v-html="subQuestion.quesAnswer"></span>
  544. </div>
  545. </div>
  546. <div v-show="quesTagShow" class="edit-property">
  547. <div class="edit-property-box">
  548. <div
  549. v-for="(subQuestionTag, tagIndex) in subQuestion.tags"
  550. :key="tagIndex"
  551. class="edit-property-item"
  552. >
  553. <div class="edit-property-body">
  554. <div class="edit-property-title">
  555. {{ subQuestionTag.tag }}
  556. </div>
  557. <div class="edit-property-content">
  558. {{ subQuestionTag.content }}
  559. </div>
  560. </div>
  561. </div>
  562. </div>
  563. </div>
  564. </div>
  565. </div>
  566. </template>
  567. </div>
  568. </div>
  569. </div>
  570. <!-- 编辑大题弹框 -->
  571. <el-dialog
  572. v-loading.body="detailLoading"
  573. width="600px"
  574. title="大题名称编辑"
  575. element-loading-text="保存中。。。"
  576. :visible.sync="paperDatailDialog"
  577. :modal="false"
  578. append-to-body
  579. custom-class="side-dialog"
  580. @close="closeQuesDialog"
  581. >
  582. <el-form :model="editpaperDetail" label-width="80px">
  583. <el-form-item label="大题名称">
  584. <el-input
  585. v-model="editpaperDetail.name"
  586. placeholder="请输入大题名称"
  587. ></el-input>
  588. </el-form-item>
  589. <el-form-item label="大题描述">
  590. <ckeditor
  591. v-model="editpaperDetail.description"
  592. class="area-ckeditor"
  593. ></ckeditor>
  594. </el-form-item>
  595. </el-form>
  596. <div slot="footer">
  597. <el-button type="primary" @click="savePaperDatail(editpaperDetail)"
  598. >保存</el-button
  599. >
  600. <el-button type="danger" plain @click="closePaperDatailDialog()"
  601. >取消</el-button
  602. >
  603. </div>
  604. </el-dialog>
  605. <!-- 编辑试题弹框 -->
  606. <el-dialog
  607. v-loading.body="dialogLoading"
  608. title="试题编辑"
  609. element-loading-text="保存中。。。"
  610. :visible.sync="quesDialog"
  611. :modal="false"
  612. append-to-body
  613. custom-class="side-dialog"
  614. @close="closeQuesDialog"
  615. >
  616. <el-form :model="quesModel" label-position="right" label-width="80px">
  617. <el-row :gutter="10">
  618. <el-col :span="12">
  619. <el-form-item label="题型">
  620. <el-select
  621. v-model="quesModel.questionType"
  622. :disabled="true"
  623. placeholder="请输入题型"
  624. >
  625. <el-option
  626. v-for="item in questionTypes"
  627. :key="item.value"
  628. :label="item.label"
  629. :value="item.value"
  630. >
  631. </el-option>
  632. </el-select>
  633. </el-form-item>
  634. </el-col>
  635. <el-col :span="12">
  636. <el-form-item label="分值">
  637. <el-input-number
  638. v-model="quesModel.score"
  639. placeholder="分值"
  640. :precision="1"
  641. :min="0"
  642. :disabled="isNested(quesModel.questionType)"
  643. ></el-input-number>
  644. </el-form-item>
  645. </el-col>
  646. <el-col :span="12">
  647. <el-form-item label="难度">
  648. <el-select
  649. v-model="quesModel.difficultyDegree"
  650. placeholder="请输入难度"
  651. :disabled="
  652. isNested(quesModel.questionType) ? true : updatePorperty
  653. "
  654. >
  655. <el-option
  656. v-for="item in difficultyDegreeList"
  657. :key="item.value"
  658. :label="item.label"
  659. :value="item.value"
  660. >
  661. </el-option>
  662. </el-select>
  663. </el-form-item>
  664. </el-col>
  665. <el-col :span="12">
  666. <el-form-item label="公开度">
  667. <el-select
  668. v-model="quesModel.publicity"
  669. placeholder="请输入公开度"
  670. :disabled="updatePorperty"
  671. >
  672. <el-option
  673. v-for="item in publicityList"
  674. :key="item.value"
  675. :label="item.label"
  676. :value="item.value"
  677. >
  678. </el-option>
  679. </el-select>
  680. </el-form-item>
  681. </el-col>
  682. <el-col
  683. v-if="quesModel.questionType == 'TEXT_ANSWER_QUESTION'"
  684. :span="12"
  685. >
  686. <el-form-item label="作答类型">
  687. <el-select
  688. v-model="quesModel.answerType"
  689. :disabled="updatePorperty"
  690. >
  691. <el-option
  692. v-for="item in answerTypes"
  693. :key="item.value"
  694. :label="item.label"
  695. :value="item.value"
  696. >
  697. </el-option>
  698. </el-select>
  699. </el-form-item>
  700. </el-col>
  701. <el-col
  702. v-if="quesModel.questionType && !isNested(quesModel.questionType)"
  703. :span="12"
  704. >
  705. <el-form-item label="时长">
  706. <el-input-number
  707. v-model="quesModel.control.maxAnswerTime"
  708. size="small"
  709. :precision="0"
  710. :min="1"
  711. :disabled="updatePorperty"
  712. ></el-input-number>
  713. </el-form-item>
  714. </el-col>
  715. <el-col v-if="isMatchingQuestion(quesModel.questionType)" :span="12">
  716. <el-form-item label="答题模式">
  717. <el-select
  718. v-model="quesModel.quesParam.matchingMode"
  719. :disabled="updatePorperty"
  720. >
  721. <el-option
  722. v-for="item in matchingModes"
  723. :key="item.value"
  724. :label="item.label"
  725. :value="item.value"
  726. >
  727. </el-option>
  728. </el-select>
  729. </el-form-item>
  730. </el-col>
  731. </el-row>
  732. <el-form-item label="属性列表">
  733. <el-tooltip
  734. v-for="(content, propIndex) in quesModel.quesProperties"
  735. :key="propIndex"
  736. placement="top"
  737. >
  738. <div slot="content">
  739. <span v-if="content.firstProperty != null"
  740. >一级属性:{{ content.firstProperty.name }}({{
  741. content.firstProperty.code
  742. }})</span
  743. ><br />
  744. <span v-if="content.secondProperty != null"
  745. >二级属性:{{ content.secondProperty.name }}({{
  746. content.secondProperty.code
  747. }})</span
  748. >
  749. </div>
  750. <span>
  751. <el-tag
  752. :key="content.id"
  753. style="margin-right: 5px"
  754. :closable="!updatePorperty"
  755. type="primary"
  756. effect="dark"
  757. @close="handleClose(content)"
  758. >
  759. {{ content.courseProperty.name }}
  760. </el-tag>
  761. </span>
  762. </el-tooltip>
  763. </el-form-item>
  764. <el-row :gutter="10">
  765. <el-col :span="8">
  766. <el-form-item label="属性名" label-width="80px">
  767. <el-select
  768. v-model="coursePropertyId"
  769. placeholder="属性名"
  770. class="property_with"
  771. :disabled="updatePorperty"
  772. @change="searchFirst"
  773. >
  774. <el-option label="请选择" value=""></el-option>
  775. <el-option
  776. v-for="item in coursePropertyList"
  777. :key="item.id"
  778. :label="item.name"
  779. :value="item.id"
  780. >
  781. </el-option>
  782. </el-select>
  783. </el-form-item>
  784. </el-col>
  785. <el-col :span="6">
  786. <el-form-item label="一级" label-width="48px">
  787. <el-select
  788. v-model="firstPropertyId"
  789. placeholder="一级"
  790. class="property_with"
  791. :disabled="updatePorperty"
  792. @change="searchSecond"
  793. >
  794. <el-option label="请选择" value=""></el-option>
  795. <el-option
  796. v-for="item in firstPropertyList"
  797. :key="item.id"
  798. :label="item.name + '(' + item.code + ')'"
  799. :value="item.id"
  800. >
  801. </el-option>
  802. </el-select>
  803. </el-form-item>
  804. </el-col>
  805. <el-col :span="6">
  806. <el-form-item label="二级" label-width="48px">
  807. <el-select
  808. v-model="secondPropertyId"
  809. placeholder="二级"
  810. class="property_with"
  811. :disabled="updatePorperty"
  812. >
  813. <el-option label="请选择" value=""></el-option>
  814. <el-option
  815. v-for="item in secondPropertyList"
  816. :key="item.id"
  817. :label="item.name + '(' + item.code + ')'"
  818. :value="item.id"
  819. >
  820. </el-option>
  821. </el-select>
  822. </el-form-item>
  823. </el-col>
  824. <el-col :span="4">
  825. <el-form-item label-width="0px">
  826. <el-button
  827. type="primary"
  828. :disabled="updatePorperty"
  829. @click="insertProperty"
  830. ><i class="el-icon-plus"></i>新增属性
  831. </el-button>
  832. </el-form-item>
  833. </el-col>
  834. </el-row>
  835. <!-- end by weiwenhai -->
  836. <el-form-item label="题目">
  837. <ckeditor v-model="quesModel.quesBody"></ckeditor>
  838. </el-form-item>
  839. <el-form-item
  840. v-for="(quesOption, optIndex) in quesModel.quesOptions"
  841. :key="optIndex"
  842. >
  843. <div class="question-edit-option">
  844. <div class="option-check">
  845. <div
  846. v-if="
  847. !quesModel.parentType ||
  848. !isMatchingQuestion(quesModel.parentType) ||
  849. !isInOtherSelect(optIndex, quesModel)
  850. "
  851. >
  852. <el-radio
  853. v-if="quesModel.questionType === 'SINGLE_ANSWER_QUESTION'"
  854. v-model="singleRightAnswer"
  855. :label="optIndex | optionOrderWordFilter"
  856. ></el-radio>
  857. <el-checkbox
  858. v-if="quesModel.questionType === 'MULTIPLE_ANSWER_QUESTION'"
  859. v-model="multipleRightAnswer"
  860. :label="optIndex | optionOrderWordFilter"
  861. ></el-checkbox>
  862. <span v-if="isMatchingQuestion(quesModel.questionType)">{{
  863. optIndex | optionOrderWordFilter
  864. }}</span>
  865. </div>
  866. <div
  867. v-if="
  868. quesModel.parentType &&
  869. isMatchingQuestion(quesModel.parentType) &&
  870. isInOtherSelect(optIndex, quesModel)
  871. "
  872. >
  873. <el-tooltip
  874. class="item"
  875. effect="dark"
  876. :content="otherSelect(optIndex, quesModel)"
  877. placement="top-start"
  878. >
  879. <el-radio
  880. v-if="quesModel.questionType === 'SINGLE_ANSWER_QUESTION'"
  881. v-model="singleRightAnswer"
  882. :disabled="true"
  883. :label="optIndex | optionOrderWordFilter"
  884. ></el-radio>
  885. <el-checkbox
  886. v-if="quesModel.questionType === 'MULTIPLE_ANSWER_QUESTION'"
  887. v-model="multipleRightAnswer"
  888. :disabled="true"
  889. :label="optIndex | optionOrderWordFilter"
  890. ></el-checkbox>
  891. <span v-if="isMatchingQuestion(quesModel.questionType)">{{
  892. optIndex | optionOrderWordFilter
  893. }}</span>
  894. </el-tooltip>
  895. </div>
  896. </div>
  897. <div
  898. v-if="
  899. !quesModel.parentType ||
  900. !isMatchingQuestion(quesModel.parentType)
  901. "
  902. class="option-body"
  903. >
  904. <ckeditor v-model="quesOption.optionBody"></ckeditor>
  905. </div>
  906. <div
  907. v-if="
  908. quesModel.parentType && isMatchingQuestion(quesModel.parentType)
  909. "
  910. class="option-body"
  911. >
  912. <span v-html="quesOption.optionBody"></span>
  913. </div>
  914. <div
  915. v-if="
  916. !quesModel.parentType ||
  917. !isMatchingQuestion(quesModel.parentType)
  918. "
  919. class="option-delete"
  920. >
  921. <el-button
  922. size="mini"
  923. circle
  924. type="danger"
  925. icon="el-icon-delete"
  926. title="删除"
  927. @click.prevent="removeQuesOption(quesOption)"
  928. ></el-button>
  929. </div>
  930. </div>
  931. </el-form-item>
  932. <el-form-item>
  933. <el-button
  934. v-if="
  935. (quesModel.questionType == 'SINGLE_ANSWER_QUESTION' ||
  936. quesModel.questionType == 'MULTIPLE_ANSWER_QUESTION' ||
  937. isMatchingQuestion(quesModel.questionType)) &&
  938. !isMatchingQuestion(quesModel.parentType)
  939. "
  940. type="primary"
  941. @click="addQuesOption"
  942. ><i class="el-icon-plus"></i> 新增选项
  943. </el-button>
  944. </el-form-item>
  945. <!-- 答案 -->
  946. <!-- 填空,简答 -->
  947. <div
  948. v-if="
  949. quesModel.questionType == 'TEXT_ANSWER_QUESTION' ||
  950. quesModel.questionType == 'FILL_BLANK_QUESTION'
  951. "
  952. >
  953. <el-form-item label="答案">
  954. <ckeditor v-model="quesModel.quesAnswer"></ckeditor>
  955. </el-form-item>
  956. </div>
  957. <!-- 单选或多选 -->
  958. <div
  959. v-if="
  960. quesModel.questionType == 'SINGLE_ANSWER_QUESTION' ||
  961. quesModel.questionType == 'MULTIPLE_ANSWER_QUESTION'
  962. "
  963. >
  964. <el-form-item label="答案">
  965. <span v-html="answer"></span>
  966. </el-form-item>
  967. </div>
  968. <!-- 判断 -->
  969. <div v-if="quesModel.questionType == 'BOOL_ANSWER_QUESTION'">
  970. <el-form-item label="答案" prop="quesAnswer">
  971. <el-select v-model="quesModel.quesAnswer" placeholder="请选择">
  972. <el-option
  973. v-for="op in options"
  974. :key="op"
  975. :label="op"
  976. :value="op"
  977. >
  978. </el-option>
  979. </el-select>
  980. </el-form-item>
  981. </div>
  982. </el-form>
  983. <div slot="footer">
  984. <el-button type="primary" @click="savePaperDetailUnit()"
  985. >保存</el-button
  986. >
  987. <el-button type="danger" plain @click="closeQuesDialog">取消</el-button>
  988. </div>
  989. </el-dialog>
  990. <!-- 考试说明弹框 -->
  991. <el-dialog
  992. title="考试说明编辑"
  993. :visible.sync="paperRemarkDialog"
  994. width="600px"
  995. :modal="false"
  996. append-to-body
  997. custom-class="side-dialog"
  998. >
  999. <el-form label-position="top">
  1000. <el-form-item label="考试说明:">
  1001. <ckeditor v-model="examRemark" class="area-ckeditor"></ckeditor>
  1002. </el-form-item>
  1003. </el-form>
  1004. <div slot="footer">
  1005. <el-button type="primary" @click="savePaperRemark">保存</el-button>
  1006. <el-button type="danger" plain @click="closPaperRemark">取消</el-button>
  1007. </div>
  1008. </el-dialog>
  1009. <!-- 上传音频弹框 -->
  1010. <el-dialog
  1011. title="上传音频文件"
  1012. :visible.sync="dialogRadioFile"
  1013. :before-close="closeAudioDialog"
  1014. :modal="false"
  1015. append-to-body
  1016. custom-class="side-dialog"
  1017. >
  1018. <form
  1019. id="radioForm"
  1020. method="post"
  1021. action=""
  1022. enctype="multipart/form-data"
  1023. >
  1024. <input
  1025. id="radioFile"
  1026. name="files"
  1027. type="file"
  1028. value="上传音频文件"
  1029. webkitdirectory
  1030. />
  1031. <el-button type="warning" @click="checkFile">检查文件名</el-button>
  1032. <el-button
  1033. type="info"
  1034. :loading="uploadAudioLoading"
  1035. :disabled="isUpload || uploadAudioLoading"
  1036. @click="uploadAudioFile"
  1037. >
  1038. <span v-show="!uploadAudioLoading">开始上传</span>
  1039. <span v-show="uploadAudioLoading">正在上传中...</span>
  1040. </el-button>
  1041. </form>
  1042. <div v-if="checkResult" style="margin-top: 20px">
  1043. <span>检查结果:</span><br /><br />
  1044. <span v-show="message == 'OK!'" style="color: #13ce66">OK!</span>
  1045. <span v-show="message != 'OK!'" style="color: #ff4949">{{
  1046. message
  1047. }}</span>
  1048. </div>
  1049. </el-dialog>
  1050. <!-- 上传答案文件 -->
  1051. <el-dialog
  1052. title="上传答案文件"
  1053. :visible.sync="dialogAnswerFile"
  1054. :before-close="closeAnswerDialog"
  1055. :modal="false"
  1056. append-to-body
  1057. custom-class="side-dialog"
  1058. >
  1059. <form
  1060. id="answerForm"
  1061. method="post"
  1062. action=""
  1063. enctype="multipart/form-data"
  1064. >
  1065. <input
  1066. id="answerFile"
  1067. name="answerFiles"
  1068. type="file"
  1069. value="上传答案文件"
  1070. accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  1071. />
  1072. <el-button type="primary" @click="downAnswerTemplate">
  1073. <span>下载模板</span>
  1074. </el-button>
  1075. <el-button
  1076. type="primary"
  1077. :loading="uploadAnswerLoading"
  1078. :disabled="uploadAnswerLoading"
  1079. @click="uploadAnswerFile"
  1080. >
  1081. <span v-show="!uploadAnswerLoading">开始上传</span>
  1082. <span v-show="uploadAnswerLoading">正在上传中...</span>
  1083. </el-button>
  1084. </form>
  1085. <div style="margin-top: 20px">
  1086. <span v-show="answerMessage != ''" style="color: #ff4949">{{
  1087. answerMessage
  1088. }}</span>
  1089. </div>
  1090. </el-dialog>
  1091. <!-- 基础构成 -->
  1092. <el-dialog
  1093. title="基础构成"
  1094. width="100%"
  1095. :visible.sync="basicDialog"
  1096. :modal="false"
  1097. append-to-body
  1098. custom-class="side-dialog"
  1099. >
  1100. <PaperBasicComposition
  1101. v-if="basicDialog"
  1102. :paper-id="paperId"
  1103. ></PaperBasicComposition>
  1104. </el-dialog>
  1105. <!-- 题型分布 -->
  1106. <el-dialog
  1107. title="题型分布"
  1108. width="100%"
  1109. :visible.sync="typeDialog"
  1110. :modal="false"
  1111. append-to-body
  1112. custom-class="side-dialog"
  1113. >
  1114. <PaperQuestionType
  1115. v-if="typeDialog"
  1116. :paper-id="paperId"
  1117. ></PaperQuestionType>
  1118. </el-dialog>
  1119. <!-- 蓝图分布 -->
  1120. <el-dialog
  1121. title="蓝图分布"
  1122. width="100%"
  1123. :visible.sync="blueDialog"
  1124. :modal="false"
  1125. append-to-body
  1126. custom-class="side-dialog"
  1127. >
  1128. <PaperBlue
  1129. v-if="blueDialog"
  1130. :paper-id="paperId"
  1131. :course-code="paper.course.code"
  1132. ></PaperBlue>
  1133. </el-dialog>
  1134. <!-- 审核记录 -->
  1135. <el-dialog
  1136. title="审核记录"
  1137. width="700px"
  1138. :visible.sync="auditInfoDialog"
  1139. :modal="false"
  1140. append-to-body
  1141. custom-class="side-dialog"
  1142. >
  1143. <AuditInfo v-if="auditInfoDialog" :paper-id="paperId"></AuditInfo>
  1144. </el-dialog>
  1145. <!-- 审核试卷 -->
  1146. <el-dialog
  1147. title="审核试卷"
  1148. width="700px"
  1149. :visible.sync="auditPaperDialog"
  1150. :modal="false"
  1151. append-to-body
  1152. custom-class="side-dialog"
  1153. >
  1154. <AuditPaper
  1155. v-if="auditPaperDialog"
  1156. :paper-ids="selectedPaperIds"
  1157. :audit-result="auditResult"
  1158. @afterAudit="afterAudit"
  1159. ></AuditPaper>
  1160. </el-dialog>
  1161. </div>
  1162. </template>
  1163. <script>
  1164. import { QUESTION_API } from "@/constants/constants";
  1165. import { isEmptyStr, QUESTION_TYPES } from "../constants/constants";
  1166. import { mapState } from "vuex";
  1167. import ckeditor from "../component/ckeditor.vue";
  1168. import PaperBasicComposition from "./PaperBasicComposition.vue";
  1169. import PaperQuestionType from "./PaperQuestionType.vue";
  1170. import PaperBlue from "./PaperBlue.vue";
  1171. import AuditInfo from "./AuditInfo.vue";
  1172. import AuditPaper from "./AuditPaper.vue";
  1173. export default {
  1174. name: "EditPaperApp",
  1175. components: {
  1176. ckeditor,
  1177. PaperBasicComposition,
  1178. PaperQuestionType,
  1179. PaperBlue,
  1180. AuditInfo,
  1181. AuditPaper,
  1182. },
  1183. data() {
  1184. return {
  1185. showCheckDuplicateBtn: false,
  1186. selectedPaperIds: [],
  1187. auditPaperDialog: false,
  1188. auditResult: "",
  1189. auditInfoDialog: false,
  1190. blueDialog: false,
  1191. typeDialog: false,
  1192. basicDialog: false,
  1193. quesAnswerShow: true,
  1194. quesTagShow: true,
  1195. hValue: "100px",
  1196. wValue: "500px",
  1197. display: "block",
  1198. uploadAction: "",
  1199. fileList: [],
  1200. answerFileList: [],
  1201. paperId: "",
  1202. paperDetailId: "",
  1203. editPaperDetailUnit: "",
  1204. quesDialog: false,
  1205. paperDatailDialog: false,
  1206. paperRemarkDialog: false,
  1207. parentView: "",
  1208. paper: {
  1209. course: {
  1210. code: "",
  1211. name: "",
  1212. },
  1213. examRemark: "",
  1214. },
  1215. loading: false,
  1216. dialogLoading: false,
  1217. detailLoading: false,
  1218. uploadAudioLoading: false,
  1219. uploadAnswerLoading: false,
  1220. questionTypes: QUESTION_TYPES,
  1221. questionType: "",
  1222. quesModel: { quesProperties: [] },
  1223. editpaperDetail: {},
  1224. reduplicateQuestions: [],
  1225. reduplicateGroup: [],
  1226. reduplicateQuesColor: [],
  1227. singleRightAnswer: "", //接收单选答案
  1228. multipleRightAnswer: [], //接收多选答案
  1229. options: ["正确", "错误"],
  1230. duplicateLoading: false,
  1231. dialogRadioFile: false,
  1232. dialogAnswerFile: false,
  1233. isUpload: true,
  1234. isUploadAnswer: true,
  1235. message: "",
  1236. answerMessage: "",
  1237. checkResult: false,
  1238. checkResultAnswer: false,
  1239. fileNameList: [],
  1240. defaultColor: [
  1241. "Red",
  1242. "Blue",
  1243. "LimeGreen",
  1244. "GoldenRod",
  1245. "Black",
  1246. "BlueViolet",
  1247. "Chocolate",
  1248. "DarkCyan",
  1249. "HotPink",
  1250. "Orange",
  1251. "IndianRed",
  1252. "Indigo",
  1253. "Green",
  1254. "Aqua",
  1255. "CadetBlue",
  1256. "SkyBlue",
  1257. "SlateBlue",
  1258. "SlateGray",
  1259. "Tomato",
  1260. "VioletRed",
  1261. ],
  1262. difficultyDegreeList: [
  1263. { label: 0.1, value: 0.1 },
  1264. { label: 0.2, value: 0.2 },
  1265. { label: 0.3, value: 0.3 },
  1266. { label: 0.4, value: 0.4 },
  1267. { label: 0.5, value: 0.5 },
  1268. { label: 0.6, value: 0.6 },
  1269. { label: 0.7, value: 0.7 },
  1270. { label: 0.8, value: 0.8 },
  1271. { label: 0.9, value: 0.9 },
  1272. { label: 1.0, value: 1.0 },
  1273. ],
  1274. publicityList: [
  1275. { label: "公开", value: true },
  1276. { label: "非公开", value: false },
  1277. ],
  1278. answerTypes: [
  1279. { label: "文本", value: "DIVERSIFIED_TEXT" },
  1280. { label: "音频", value: "SINGLE_AUDIO" },
  1281. ],
  1282. matchingTypes: [
  1283. { label: "填词", value: 1 },
  1284. { label: "段落", value: 2 },
  1285. ],
  1286. matchingModes: [
  1287. { label: "单用", value: 1 },
  1288. { label: "复用", value: 2 },
  1289. ],
  1290. coursePropertyList: [],
  1291. coursePropertyId: "", //课程属性名
  1292. firstPropertyList: [], //一级属性集合
  1293. firstPropertyId: "", //一级属性id
  1294. secondPropertyList: [], //二级属性集合
  1295. secondPropertyId: "", //二级属性id
  1296. examRemark: "",
  1297. showQuestions: [],
  1298. showButtons: [],
  1299. showSubQuestions: {},
  1300. showSubButtons: {},
  1301. };
  1302. },
  1303. computed: {
  1304. ...mapState({
  1305. user: (state) => state.user,
  1306. }),
  1307. updatePorperty() {
  1308. return false;
  1309. },
  1310. answer() {
  1311. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  1312. return this.singleRightAnswer;
  1313. } else if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  1314. var obj = this.multipleRightAnswer;
  1315. return obj.sort().toString();
  1316. }
  1317. return this.quesModel.quesAnswer;
  1318. },
  1319. },
  1320. created() {
  1321. let qt = sessionStorage.getItem("quesTagShow");
  1322. if (qt) {
  1323. this.quesTagShow = qt == "true";
  1324. }
  1325. let qa = sessionStorage.getItem("quesAnswerShow");
  1326. if (qa) {
  1327. this.quesAnswerShow = qa == "true";
  1328. }
  1329. document.getElementsByTagName("body")[0].style = "";
  1330. this.paperId = this.$route.params.id;
  1331. this.parentView = this.$route.params.parentView;
  1332. this.initPaper();
  1333. this.uploadAction = QUESTION_API + "/uploadRadio/" + this.paperId;
  1334. this.uploadHeaders = {
  1335. key: this.user.key,
  1336. token: this.user.token,
  1337. };
  1338. },
  1339. methods: {
  1340. showCheckDuplicate() {
  1341. if (this.paper.checkDuplicateStatus == "DISPOSED") {
  1342. this.showCheckDuplicateBtn = false;
  1343. } else if (this.paper.paperDetails) {
  1344. for (let paperDetilData of this.paper.paperDetails) {
  1345. if (paperDetilData.paperDetailUnits) {
  1346. for (let unit of paperDetilData.paperDetailUnits) {
  1347. if (unit.question.checkDuplicateStatus == "TO_BE_DISPOSE") {
  1348. this.showCheckDuplicateBtn = true;
  1349. return;
  1350. }
  1351. }
  1352. }
  1353. }
  1354. this.showCheckDuplicateBtn = false;
  1355. }
  1356. },
  1357. checkDuplicate() {
  1358. this.$router.push({
  1359. name: "check_duplicate_info",
  1360. params: {
  1361. basePaperId: this.paper.id,
  1362. from: "paper",
  1363. },
  1364. });
  1365. },
  1366. checkDuplicateQuestion(questionId) {
  1367. this.$router.push({
  1368. name: "check_duplicate_info",
  1369. params: {
  1370. quesId: questionId,
  1371. basePaperId: this.paper.id,
  1372. from: "paper",
  1373. },
  1374. });
  1375. },
  1376. isShowEditBtn() {
  1377. if (
  1378. this.paper.creationBy == this.user.userId &&
  1379. (this.paper.auditStatus == "WITHDRAW" ||
  1380. this.paper.auditStatus == "NOT_PASS")
  1381. ) {
  1382. return true;
  1383. } else {
  1384. return false;
  1385. }
  1386. },
  1387. afterAudit() {
  1388. this.auditPaperDialog = false;
  1389. this.back();
  1390. },
  1391. auditPaper(pass) {
  1392. this.auditResult = pass;
  1393. this.selectedPaperIds = [];
  1394. this.selectedPaperIds.push(this.paperId);
  1395. this.auditPaperDialog = true;
  1396. },
  1397. isShowAuditBtn() {
  1398. if (
  1399. this.paper.auditStatus != "WITHDRAW" &&
  1400. this.paper.auditStatus != "NOT_PASS" &&
  1401. this.isMyAudit()
  1402. ) {
  1403. return true;
  1404. } else {
  1405. return false;
  1406. }
  1407. },
  1408. isMyAudit() {
  1409. if (
  1410. this.paper.auditStatus == "FIRST_PENDING_TRIAL" &&
  1411. this.user.auditAuthority == "FIRST"
  1412. ) {
  1413. return true;
  1414. }
  1415. if (
  1416. this.paper.auditStatus == "SECOND_PENDING_TRIAL" &&
  1417. this.user.auditAuthority == "SECOND"
  1418. ) {
  1419. return true;
  1420. }
  1421. if (
  1422. this.paper.auditStatus == "THIRD_PENDING_TRIAL" &&
  1423. this.user.auditAuthority == "THIRD"
  1424. ) {
  1425. return true;
  1426. }
  1427. return false;
  1428. },
  1429. showAuditDialog() {
  1430. this.auditInfoDialog = true;
  1431. },
  1432. showBlueDialog() {
  1433. this.blueDialog = true;
  1434. },
  1435. showTypeDialog() {
  1436. this.typeDialog = true;
  1437. },
  1438. showBasicDialog() {
  1439. this.basicDialog = true;
  1440. },
  1441. quesAnswerShowHide() {
  1442. this.quesAnswerShow = !this.quesAnswerShow;
  1443. sessionStorage.setItem("quesAnswerShow", this.quesAnswerShow);
  1444. },
  1445. quesTagShowHide() {
  1446. this.quesTagShow = !this.quesTagShow;
  1447. sessionStorage.setItem("quesTagShow", this.quesTagShow);
  1448. },
  1449. isMatchingQuestion(questionType) {
  1450. if (
  1451. questionType == "PARAGRAPH_MATCHING" ||
  1452. questionType == "BANKED_CLOZE"
  1453. ) {
  1454. return true;
  1455. } else {
  1456. return false;
  1457. }
  1458. },
  1459. isNested(questionType) {
  1460. if (
  1461. questionType == "PARAGRAPH_MATCHING" ||
  1462. questionType == "BANKED_CLOZE" ||
  1463. questionType == "CLOZE" ||
  1464. questionType == "READING_COMPREHENSION" ||
  1465. questionType == "LISTENING_QUESTION"
  1466. ) {
  1467. return true;
  1468. } else {
  1469. return false;
  1470. }
  1471. },
  1472. otherSelect(optIndex, quesModel) {
  1473. return "该选项被第" + quesModel.optionsSelected[optIndex + 1] + "题选用";
  1474. },
  1475. isInOtherSelect(optIndex, quesModel) {
  1476. if (quesModel.parentQuesParam.matchingMode != 1) {
  1477. return false;
  1478. }
  1479. if (!quesModel.optionsSelected) {
  1480. return false;
  1481. }
  1482. if (!quesModel.optionsSelected[optIndex + 1]) {
  1483. return false;
  1484. }
  1485. if (
  1486. quesModel.optionsSelected[optIndex + 1].includes(quesModel.subNumber)
  1487. ) {
  1488. return false;
  1489. }
  1490. return true;
  1491. },
  1492. movePaperDetailUnitSub(unitid, subid, vector) {
  1493. let vectorStr = vector == "up" ? "上移" : "下移";
  1494. this.$alert("您确定" + vectorStr + "吗?", "提示", {
  1495. confirmButtonText: "确定",
  1496. callback: (action) => {
  1497. if (action == "confirm") {
  1498. this.loading = true;
  1499. this.$http
  1500. .put(
  1501. QUESTION_API +
  1502. "/paperDetailUnit/sub/" +
  1503. unitid +
  1504. "/" +
  1505. subid +
  1506. "/" +
  1507. vector
  1508. )
  1509. .then(() => {
  1510. this.initPaper();
  1511. this.loading = true;
  1512. this.$notify({
  1513. message: vectorStr + "成功",
  1514. type: "success",
  1515. });
  1516. this.loading = false;
  1517. });
  1518. }
  1519. },
  1520. });
  1521. },
  1522. showUnitSubDown(unit, subid) {
  1523. if (unit.question.subQuestions.length <= 1) {
  1524. return false;
  1525. }
  1526. if (
  1527. subid !=
  1528. unit.question.subQuestions[unit.question.subQuestions.length - 1].id
  1529. ) {
  1530. return true;
  1531. } else {
  1532. return false;
  1533. }
  1534. },
  1535. showUnitSubUp(unit, subid) {
  1536. if (unit.question.subQuestions.length <= 1) {
  1537. return false;
  1538. }
  1539. if (subid != unit.question.subQuestions[0].id) {
  1540. return true;
  1541. } else {
  1542. return false;
  1543. }
  1544. },
  1545. movePaperDetailUnit(detailId, unitid, vector) {
  1546. let vectorStr = vector == "up" ? "上移" : "下移";
  1547. this.$alert("您确定" + vectorStr + "吗?", "提示", {
  1548. confirmButtonText: "确定",
  1549. callback: (action) => {
  1550. if (action == "confirm") {
  1551. this.loading = true;
  1552. this.$http
  1553. .put(
  1554. QUESTION_API +
  1555. "/paperDetailUnit/" +
  1556. detailId +
  1557. "/" +
  1558. unitid +
  1559. "/" +
  1560. vector
  1561. )
  1562. .then(() => {
  1563. this.initPaper();
  1564. this.loading = true;
  1565. this.$notify({
  1566. message: vectorStr + "成功",
  1567. type: "success",
  1568. });
  1569. this.loading = false;
  1570. });
  1571. }
  1572. },
  1573. });
  1574. },
  1575. showUnitDown(detail, unitid) {
  1576. if (detail.paperDetailUnits.length <= 1) {
  1577. return false;
  1578. }
  1579. if (
  1580. unitid != detail.paperDetailUnits[detail.paperDetailUnits.length - 1].id
  1581. ) {
  1582. return true;
  1583. } else {
  1584. return false;
  1585. }
  1586. },
  1587. showUnitUp(detail, unitid) {
  1588. if (detail.paperDetailUnits.length <= 1) {
  1589. return false;
  1590. }
  1591. if (unitid != detail.paperDetailUnits[0].id) {
  1592. return true;
  1593. } else {
  1594. return false;
  1595. }
  1596. },
  1597. movePaperDetail(detail, vector) {
  1598. let vectorStr = vector == "up" ? "上移" : "下移";
  1599. this.$alert("您确定" + vectorStr + "吗?", "提示", {
  1600. confirmButtonText: "确定",
  1601. callback: (action) => {
  1602. if (action == "confirm") {
  1603. this.loading = true;
  1604. this.$http
  1605. .put(
  1606. QUESTION_API +
  1607. "/paperDetail/" +
  1608. this.paperId +
  1609. "/" +
  1610. detail.id +
  1611. "/" +
  1612. vector
  1613. )
  1614. .then(() => {
  1615. this.initPaper();
  1616. this.loading = true;
  1617. this.$notify({
  1618. message: vectorStr + "成功",
  1619. type: "success",
  1620. });
  1621. this.loading = false;
  1622. });
  1623. }
  1624. },
  1625. });
  1626. },
  1627. showUp(detail) {
  1628. if (this.paper.paperDetails.length <= 1) {
  1629. return false;
  1630. }
  1631. if (detail.id != this.paper.paperDetails[0].id) {
  1632. return true;
  1633. } else {
  1634. return false;
  1635. }
  1636. },
  1637. showDown(detail) {
  1638. if (this.paper.paperDetails.length <= 1) {
  1639. return false;
  1640. }
  1641. if (
  1642. detail.id !=
  1643. this.paper.paperDetails[this.paper.paperDetails.length - 1].id
  1644. ) {
  1645. return true;
  1646. } else {
  1647. return false;
  1648. }
  1649. },
  1650. downAnswerTemplate() {
  1651. var key = this.user.key;
  1652. var token = this.user.token;
  1653. window.open(
  1654. QUESTION_API + "/paper/answer/template?$key=" + key + "&$token=" + token
  1655. );
  1656. },
  1657. openAnswerDialog() {
  1658. this.checkResultAnswer = false;
  1659. this.isUploadAnswer = true;
  1660. if (document.getElementById("answerFile")) {
  1661. document.getElementById("answerFile").value = "";
  1662. }
  1663. this.dialogAnswerFile = true;
  1664. this.answerFileList = [];
  1665. },
  1666. closeAnswerDialog() {
  1667. this.answerMessage = "";
  1668. this.dialogAnswerFile = this.uploadAnswerLoading;
  1669. },
  1670. uploadAnswerFile() {
  1671. this.answerMessage = "";
  1672. var fileList = document.getElementById("answerFile").files;
  1673. if (fileList.length == 0) {
  1674. this.answerMessage = "请选择文件!";
  1675. return;
  1676. }
  1677. let param = new FormData();
  1678. //循环添加到formData中
  1679. for (var i = 0; i < fileList.length; i++) {
  1680. var file = fileList[i];
  1681. param.append("dataFile", file, file.name);
  1682. }
  1683. let config = {
  1684. headers: { "Content-Type": "multipart/form-data" },
  1685. };
  1686. this.uploadAnswerLoading = true;
  1687. this.$http
  1688. .post(
  1689. QUESTION_API + "/paper/answer/import/" + this.paperId,
  1690. param,
  1691. config
  1692. )
  1693. .then(() => {
  1694. this.dialogAnswerFile = false;
  1695. this.uploadAnswerLoading = false;
  1696. this.checkResultAnswer = false;
  1697. this.isUploadAnswer = true;
  1698. document.getElementById("answerFile").value = "";
  1699. this.initPaper();
  1700. })
  1701. .catch((error) => {
  1702. this.answerMessage = error.response.data.desc;
  1703. document.getElementById("answerFile").value = "";
  1704. this.uploadAnswerLoading = false;
  1705. });
  1706. },
  1707. //隐藏大题下的所有小题
  1708. hideContent(index) {
  1709. this.showQuestions[index].is_show = false;
  1710. this.showButtons[index].up = false;
  1711. },
  1712. //展开大题下所有小题
  1713. showContent(index) {
  1714. this.showQuestions[index].is_show = true;
  1715. this.showButtons[index].up = true;
  1716. },
  1717. //隐藏大题下的所有小题
  1718. hideSubContent(index) {
  1719. this.showSubQuestions[index] = false;
  1720. this.showSubButtons[index] = false;
  1721. this.$forceUpdate();
  1722. },
  1723. //展开大题下所有小题
  1724. showSubContent(index) {
  1725. this.showSubQuestions[index] = true;
  1726. this.showSubButtons[index] = true;
  1727. this.$forceUpdate();
  1728. },
  1729. quesMouseOver(index) {
  1730. document.getElementById(index).style.visibility = "visible";
  1731. },
  1732. quesMouseOut(index) {
  1733. document.getElementById(index).style.visibility = "hidden";
  1734. },
  1735. selectQues(id) {
  1736. this.paperDetailId = id;
  1737. var courseCode = this.paper.course.code;
  1738. var courseName = this.paper.course.name;
  1739. this.$router.push({
  1740. path:
  1741. "/select_question/" +
  1742. this.paper.id +
  1743. "/" +
  1744. courseCode +
  1745. "/" +
  1746. encodeURIComponent(courseName) +
  1747. "/" +
  1748. this.paperDetailId +
  1749. "/" +
  1750. this.parentView,
  1751. });
  1752. },
  1753. //打开编辑大题题目弹窗
  1754. openEditPaperDetail(paperDetail) {
  1755. this.paperDatailDialog = true;
  1756. this.editpaperDetail = Object.assign({}, paperDetail); //浅拷贝
  1757. },
  1758. //关闭编辑大题题目弹窗
  1759. closePaperDatailDialog() {
  1760. this.paperDatailDialog = false;
  1761. this.editpaperDetail = {};
  1762. },
  1763. //保存大题题目信息
  1764. savePaperDatail(editpaperDetail) {
  1765. this.detailLoading = true;
  1766. var paperId = this.paper.id;
  1767. this.$http
  1768. .post(QUESTION_API + "/updatePaperDetail/" + paperId, editpaperDetail)
  1769. .then(() => {
  1770. this.$notify({
  1771. message: "保存成功",
  1772. type: "success",
  1773. });
  1774. this.detailLoading = false;
  1775. this.closePaperDatailDialog();
  1776. this.initPaper();
  1777. });
  1778. },
  1779. //初始化试卷
  1780. initPaper() {
  1781. const scrollPosition =
  1782. document.documentElement.scrollTop || document.body.scrollTop;
  1783. this.loading = true;
  1784. this.paper = {
  1785. course: {
  1786. code: "",
  1787. name: "",
  1788. },
  1789. };
  1790. this.$http
  1791. .get(QUESTION_API + "/paper/" + this.paperId)
  1792. .then((response) => {
  1793. this.paper = response.data;
  1794. //查询所有课程属性名
  1795. this.initCourseProperty(this.paper.course.code);
  1796. //将所有小题分为公开和非公开
  1797. if (this.paper.paperDetails && this.paper.paperDetails.length > 0) {
  1798. let dindx = 0;
  1799. for (let paperDetil of this.paper.paperDetails) {
  1800. this.showQuestions.push({ is_show: true });
  1801. this.showButtons.push({ up: true });
  1802. paperDetil.pubCount = 0;
  1803. paperDetil.noPubCount = 0;
  1804. if (
  1805. paperDetil.paperDetailUnits &&
  1806. paperDetil.paperDetailUnits.length > 0
  1807. ) {
  1808. let uindx = 0;
  1809. for (let paperDetilUt of paperDetil.paperDetailUnits) {
  1810. this.showSubQuestions[dindx + "-" + uindx] = true;
  1811. this.showSubButtons[dindx + "-" + uindx] = true;
  1812. if (!this.isNested(paperDetilUt.question.questionType)) {
  1813. //非套题
  1814. if (paperDetilUt.question.publicity) {
  1815. paperDetil.pubCount = paperDetil.pubCount + 1;
  1816. } else {
  1817. paperDetil.noPubCount = paperDetil.noPubCount + 1;
  1818. }
  1819. } else {
  1820. //循环所有子题
  1821. for (let ques of paperDetilUt.question.subQuestions) {
  1822. if (ques.publicity) {
  1823. paperDetil.pubCount = paperDetil.pubCount + 1;
  1824. } else {
  1825. paperDetil.noPubCount = paperDetil.noPubCount + 1;
  1826. }
  1827. }
  1828. }
  1829. uindx++;
  1830. }
  1831. }
  1832. dindx++;
  1833. }
  1834. }
  1835. this.showCheckDuplicate();
  1836. setTimeout(() => {
  1837. document.documentElement.scrollTop = document.body.scrollTop =
  1838. scrollPosition;
  1839. console.log(scrollPosition);
  1840. }, 1000);
  1841. this.loading = false;
  1842. });
  1843. },
  1844. //查询所有课程属性名
  1845. initCourseProperty(courseCode) {
  1846. this.$http
  1847. .get(QUESTION_API + "/courseProperty/enable/" + courseCode)
  1848. .then((response) => {
  1849. this.coursePropertyList = response.data;
  1850. });
  1851. },
  1852. //删除大题
  1853. deletePaperDetail(paperDetailsId) {
  1854. //先判断大题下面是否还有小题
  1855. var count = 0;
  1856. for (var i = 0, imax = this.paper.paperDetails.length; i < imax; i++) {
  1857. if (paperDetailsId == this.paper.paperDetails[i].id) {
  1858. if (this.paper.paperDetails[i].paperDetailUnits) {
  1859. count += this.paper.paperDetails[i].paperDetailUnits.length;
  1860. break;
  1861. }
  1862. }
  1863. }
  1864. if (count == 0) {
  1865. this.$alert("您确定删除吗?", "提示", {
  1866. confirmButtonText: "确定",
  1867. callback: (action) => {
  1868. if (action == "confirm") {
  1869. this.loading = true;
  1870. this.$http
  1871. .delete(
  1872. QUESTION_API +
  1873. "/paperDetail/" +
  1874. this.paperId +
  1875. "/" +
  1876. paperDetailsId
  1877. )
  1878. .then(() => {
  1879. this.initPaper();
  1880. this.loading = true;
  1881. this.$notify({
  1882. message: "删除成功",
  1883. type: "success",
  1884. });
  1885. this.loading = false;
  1886. });
  1887. }
  1888. },
  1889. });
  1890. } else {
  1891. this.$alert("大题下还有小题,不可删除!", "提示", {
  1892. confirmButtonText: "确定",
  1893. callback: () => {},
  1894. });
  1895. }
  1896. },
  1897. quesShow(id) {
  1898. if (this.reduplicateGroup.length < 1) {
  1899. return true;
  1900. }
  1901. for (var i = 0, imax = this.reduplicateGroup.length; i < imax; i++) {
  1902. if (id == this.reduplicateGroup[i]) {
  1903. return true;
  1904. }
  1905. }
  1906. return false;
  1907. },
  1908. //编辑题目
  1909. editQues(paperDetailUnit, question) {
  1910. console.log("question:", question);
  1911. this.coursePropertyId = "";
  1912. this.firstPropertyId = "";
  1913. this.secondPropertyId = "";
  1914. this.editPaperDetailUnit = paperDetailUnit;
  1915. this.quesModel = JSON.parse(JSON.stringify(question)); //深拷贝
  1916. if (!this.quesModel.control) {
  1917. this.quesModel.control = {};
  1918. }
  1919. this.quesModel.score = paperDetailUnit.score;
  1920. //如果是套题下面的小题编辑 ( paperDetailUnit的类型是套题,question的类型不是套题)
  1921. if (
  1922. this.isNested(paperDetailUnit.questionType) &&
  1923. question.questionType != paperDetailUnit.questionType
  1924. ) {
  1925. for (var i = 0; i < paperDetailUnit.question.subQuestions.length; i++) {
  1926. if (
  1927. paperDetailUnit.question.subQuestions[i].id == this.quesModel.id
  1928. ) {
  1929. this.quesModel.score = paperDetailUnit.subScoreList[i];
  1930. this.quesModel.parentType = paperDetailUnit.questionType;
  1931. this.quesModel.optionsSelected = paperDetailUnit.optionsSelected;
  1932. this.quesModel.parentQuesParam = paperDetailUnit.question.quesParam;
  1933. break;
  1934. }
  1935. }
  1936. }
  1937. if (isEmptyStr(this.quesModel.answerType)) {
  1938. this.quesModel.answerType = "DIVERSIFIED_TEXT";
  1939. }
  1940. if (this.quesModel.questionType == "FILL_BLANK_QUESTION") {
  1941. this.quesModel.quesBody = this.quesModel.quesBody.replace(
  1942. /______/g,
  1943. "###"
  1944. );
  1945. }
  1946. if (this.isNested(this.quesModel.questionType)) {
  1947. this.quesModel.quesBody = this.quesModel.quesBody.replace(
  1948. /___([1-9][0-9]*)___/g,
  1949. "##$1##"
  1950. );
  1951. }
  1952. this.assignAnswers(); //给singleRightAnswer或multipleRightAnswer赋值
  1953. this.openQuesDialog();
  1954. },
  1955. //给singleRightAnswer和multipleRightAnswer赋值
  1956. assignAnswers() {
  1957. if (this.quesModel.quesOptions && this.quesModel.quesOptions.length > 0) {
  1958. this.singleRightAnswer = "";
  1959. this.multipleRightAnswer = [];
  1960. for (let i = 0; i < this.quesModel.quesOptions.length; i++) {
  1961. let option = this.quesModel.quesOptions[i];
  1962. if (
  1963. this.quesModel.questionType == "SINGLE_ANSWER_QUESTION" &&
  1964. option.isCorrect == 1
  1965. ) {
  1966. this.singleRightAnswer = String.fromCharCode(65 + i);
  1967. }
  1968. if (
  1969. this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION" &&
  1970. option.isCorrect == 1
  1971. ) {
  1972. this.multipleRightAnswer.push(String.fromCharCode(65 + i));
  1973. }
  1974. }
  1975. }
  1976. },
  1977. //打开修改试题编辑框
  1978. openQuesDialog() {
  1979. this.quesDialog = true;
  1980. },
  1981. //关闭试题编辑框
  1982. closeQuesDialog() {
  1983. this.quesDialog = false;
  1984. this.quesModel = {};
  1985. },
  1986. //删除属性
  1987. handleClose(tag) {
  1988. this.quesModel.quesProperties.splice(
  1989. this.quesModel.quesProperties.indexOf(tag),
  1990. 1
  1991. );
  1992. },
  1993. //查询一级属性
  1994. searchFirst() {
  1995. this.firstPropertyId = "";
  1996. this.secondPropertyId = "";
  1997. this.secondPropertyList = [];
  1998. if (this.coursePropertyId) {
  1999. for (let courseProperty of this.coursePropertyList) {
  2000. if (courseProperty.id == this.coursePropertyId) {
  2001. this.$http
  2002. .get(QUESTION_API + "/property/first/" + courseProperty.id)
  2003. .then((response) => {
  2004. this.firstPropertyList = response.data;
  2005. });
  2006. }
  2007. }
  2008. }
  2009. },
  2010. //查询二级属性
  2011. searchSecond() {
  2012. this.secondPropertyId = "";
  2013. if (this.firstPropertyId) {
  2014. this.$http
  2015. .get(QUESTION_API + "/property/second/" + this.firstPropertyId)
  2016. .then((response) => {
  2017. this.secondPropertyList = response.data;
  2018. });
  2019. }
  2020. },
  2021. //新增属性
  2022. insertProperty() {
  2023. if (!this.checkInsertPro()) {
  2024. return false;
  2025. }
  2026. var quesProperty = {
  2027. id: "",
  2028. courseProperty: {},
  2029. firstProperty: {},
  2030. secondProperty: {},
  2031. };
  2032. if (
  2033. this.quesModel.quesProperties == null ||
  2034. this.quesModel.quesProperties.length == 0
  2035. ) {
  2036. this.quesModel.quesProperties = [];
  2037. }
  2038. if (this.secondPropertyId) {
  2039. quesProperty.id =
  2040. this.coursePropertyId +
  2041. "-" +
  2042. this.firstPropertyId +
  2043. "-" +
  2044. this.secondPropertyId;
  2045. } else {
  2046. quesProperty.id = this.coursePropertyId + "-" + this.firstPropertyId;
  2047. }
  2048. for (let quesPro of this.quesModel.quesProperties) {
  2049. if (quesPro.id == quesProperty.id) {
  2050. this.$notify({
  2051. message: "该属性已存在,请重新选择",
  2052. type: "error",
  2053. });
  2054. return false;
  2055. }
  2056. }
  2057. for (let courseProperty of this.coursePropertyList) {
  2058. if (courseProperty.id == this.coursePropertyId) {
  2059. quesProperty.courseProperty = courseProperty;
  2060. }
  2061. }
  2062. //取到一级属性对象
  2063. for (let property of this.firstPropertyList) {
  2064. if (property.id == this.firstPropertyId) {
  2065. quesProperty.firstProperty = property;
  2066. }
  2067. }
  2068. //判断是否有二级属性
  2069. if (
  2070. this.secondPropertyList != undefined &&
  2071. this.secondPropertyList.length > 0
  2072. ) {
  2073. if (!this.secondPropertyId) {
  2074. this.$notify({
  2075. message: "请选择二级属性",
  2076. type: "error",
  2077. });
  2078. return false;
  2079. }
  2080. }
  2081. //取到二级属性对象
  2082. for (let property of this.secondPropertyList) {
  2083. if (property.id == this.secondPropertyId) {
  2084. quesProperty.secondProperty = property;
  2085. }
  2086. }
  2087. this.quesModel.quesProperties.push(quesProperty);
  2088. this.quesModel = Object.assign({}, this.quesModel);
  2089. //清空下拉框
  2090. this.coursePropertyId = "";
  2091. this.firstPropertyId = "";
  2092. this.secondPropertyId = "";
  2093. this.firstPropertyList = [];
  2094. this.secondPropertyList = [];
  2095. },
  2096. //新增属性验证
  2097. checkInsertPro() {
  2098. if (!this.coursePropertyId) {
  2099. this.$notify({
  2100. message: "请选择属性",
  2101. type: "error",
  2102. });
  2103. return false;
  2104. }
  2105. if (!this.firstPropertyId) {
  2106. this.$notify({
  2107. message: "请选择一级属性",
  2108. type: "error",
  2109. });
  2110. return false;
  2111. }
  2112. return true;
  2113. },
  2114. //删除选项
  2115. removeQuesOption(option) {
  2116. if (this.quesModel.quesOptions.length == 1) {
  2117. this.$notify({
  2118. message: "不能删除最后一个选项",
  2119. type: "error",
  2120. });
  2121. return;
  2122. }
  2123. this.singleRightAnswer = "";
  2124. this.multipleRightAnswer = [];
  2125. let index = this.quesModel.quesOptions.indexOf(option);
  2126. if (index !== -1) {
  2127. this.quesModel.quesOptions.splice(index, 1);
  2128. }
  2129. if (this.quesModel.quesOptions.length > 0) {
  2130. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  2131. var quesOption = this.quesModel.quesOptions[i];
  2132. quesOption["number"] = i + 1;
  2133. if (quesOption.isCorrect == 1) {
  2134. var answerOrderNum = String.fromCharCode(65 + i);
  2135. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  2136. this.singleRightAnswer = answerOrderNum;
  2137. }
  2138. if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  2139. this.multipleRightAnswer.push(answerOrderNum);
  2140. }
  2141. }
  2142. }
  2143. }
  2144. },
  2145. //新增选项
  2146. addQuesOption() {
  2147. this.quesModel.quesOptions.push({
  2148. number: "",
  2149. optionBody: "",
  2150. isCorrect: "",
  2151. });
  2152. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  2153. this.quesModel.quesOptions[i]["number"] = i + 1;
  2154. }
  2155. },
  2156. savePaperDetailUnit() {
  2157. //跟新难度值
  2158. if (this.quesModel.difficultyDegree < 0.4) {
  2159. this.quesModel.difficulty = "难";
  2160. } else if (
  2161. this.quesModel.difficultyDegree > 0.3 &&
  2162. this.quesModel.difficultyDegree < 0.8
  2163. ) {
  2164. this.quesModel.difficulty = "中";
  2165. } else {
  2166. this.quesModel.difficulty = "易";
  2167. }
  2168. this.setRightAnswer();
  2169. if (/^\d+(?=\.{0,1}\d+$|$)/.test(this.quesModel.score)) {
  2170. console.log("正确");
  2171. } else {
  2172. this.$notify({
  2173. message: "分数只能为正数",
  2174. type: "error",
  2175. });
  2176. return;
  2177. }
  2178. if (this.paper.paperType == "GENERATE") {
  2179. this.$confirm(
  2180. "试题内容修改,会影响所有关联试卷,是否确定进行?",
  2181. "提示",
  2182. {
  2183. confirmButtonText: "确定",
  2184. cancelButtonText: "取消",
  2185. type: "warning",
  2186. }
  2187. ).then(() => {
  2188. this.submitPaperDetailUnit();
  2189. });
  2190. } else {
  2191. this.submitPaperDetailUnit();
  2192. }
  2193. },
  2194. submitPaperDetailUnit() {
  2195. let paperDetailUnitExp = {
  2196. id: this.editPaperDetailUnit.id,
  2197. question: this.quesModel,
  2198. score: this.quesModel.score,
  2199. };
  2200. if (
  2201. this.quesModel.quesOptions &&
  2202. this.quesModel.quesOptions.length == 0
  2203. ) {
  2204. this.$confirm("无选项将删除该试题, 是否继续?", "提示", {
  2205. confirmButtonText: "确定",
  2206. cancelButtonText: "取消",
  2207. type: "warning",
  2208. }).then(() => {
  2209. this.dialogLoading = true;
  2210. this.$http
  2211. .delete(
  2212. QUESTION_API +
  2213. "/paper/deleteQuestion/" +
  2214. this.editPaperDetailUnit.id +
  2215. "/" +
  2216. this.quesModel.id
  2217. )
  2218. .then((response) => {
  2219. if (response.data.length > 0) {
  2220. var deleteInfo =
  2221. "该试题被试卷:" +
  2222. response.data.join(" , ") +
  2223. "使用,不能删除";
  2224. this.$notify({
  2225. message: deleteInfo,
  2226. type: "error",
  2227. });
  2228. } else {
  2229. this.$notify({
  2230. message: "保存成功",
  2231. type: "success",
  2232. });
  2233. }
  2234. this.dialogLoading = false;
  2235. });
  2236. });
  2237. } else {
  2238. this.dialogLoading = true;
  2239. //校验音频重复
  2240. let audiomap = new Map();
  2241. let regex = new RegExp(
  2242. '<a id="[^<>]+" name="([^<>]+\\.mp3)"></a>',
  2243. "ig"
  2244. );
  2245. let ret = "";
  2246. let quesBodyStr = paperDetailUnitExp.question.quesBody;
  2247. if (quesBodyStr) {
  2248. while ((ret = regex.exec(quesBodyStr))) {
  2249. if (audiomap.get(ret[1])) {
  2250. this.dialogLoading = false;
  2251. this.$notify({
  2252. type: "error",
  2253. message: "题干中存在相同的音频文件",
  2254. });
  2255. return;
  2256. } else {
  2257. audiomap.set(ret[1], ret[1]);
  2258. }
  2259. }
  2260. }
  2261. let quesAnswerStr = paperDetailUnitExp.question.quesAnswer;
  2262. if (quesAnswerStr) {
  2263. while ((ret = regex.exec(quesAnswerStr))) {
  2264. if (audiomap.get(ret[1])) {
  2265. this.dialogLoading = false;
  2266. this.$notify({
  2267. type: "error",
  2268. message: "答案中存在相同的音频文件",
  2269. });
  2270. return;
  2271. } else {
  2272. audiomap.set(ret[1], ret[1]);
  2273. }
  2274. }
  2275. }
  2276. let quesOptions = paperDetailUnitExp.question.quesOptions;
  2277. if (quesOptions) {
  2278. for (let i = 0; i < quesOptions.length; i++) {
  2279. let quesOptionStr = quesOptions[i].optionBody;
  2280. while ((ret = regex.exec(quesOptionStr))) {
  2281. if (audiomap.get(ret[1])) {
  2282. this.dialogLoading = false;
  2283. this.$notify({
  2284. type: "error",
  2285. message: "选项中存在相同的音频文件",
  2286. });
  2287. return;
  2288. } else {
  2289. audiomap.set(ret[1], ret[1]);
  2290. }
  2291. }
  2292. }
  2293. }
  2294. paperDetailUnitExp.question.quesAnswer = this.answer;
  2295. this.$http
  2296. .put(QUESTION_API + "/paperDetailUnit", paperDetailUnitExp)
  2297. .then(() => {
  2298. this.$notify({
  2299. message: "保存成功",
  2300. type: "success",
  2301. });
  2302. this.dialogLoading = false;
  2303. this.closeQuesDialog();
  2304. this.initPaper();
  2305. })
  2306. .catch((err) => {
  2307. this.dialogLoading = false;
  2308. this.$notify({
  2309. type: "error",
  2310. message: err.response.data.desc,
  2311. });
  2312. });
  2313. }
  2314. },
  2315. //在正确的option上设置isCorrect=1
  2316. setRightAnswer() {
  2317. if (
  2318. !this.quesModel.quesOptions ||
  2319. this.quesModel.quesOptions.length == 0
  2320. ) {
  2321. return false;
  2322. }
  2323. for (var i = 0; i < this.quesModel.quesOptions.length; i++) {
  2324. var option = this.quesModel.quesOptions[i];
  2325. var answerOrderNum = String.fromCharCode(65 + i);
  2326. if (this.quesModel.questionType == "SINGLE_ANSWER_QUESTION") {
  2327. option["isCorrect"] =
  2328. answerOrderNum == this.singleRightAnswer ? 1 : 0;
  2329. }
  2330. if (this.quesModel.questionType == "MULTIPLE_ANSWER_QUESTION") {
  2331. option["isCorrect"] =
  2332. this.multipleRightAnswer.indexOf(answerOrderNum) > -1 ? 1 : 0;
  2333. }
  2334. }
  2335. },
  2336. //删除试题
  2337. deleteQues(paperDetailUnit) {
  2338. let paperDetailUnitId = paperDetailUnit.id;
  2339. if (this.paper.paperType == "GENERATE") {
  2340. this.deleteQues01(paperDetailUnitId);
  2341. } else {
  2342. let questionId = paperDetailUnit.question.id;
  2343. this.deleteQues02(questionId, paperDetailUnitId);
  2344. }
  2345. },
  2346. deleteQues01(paperDetailUnitId) {
  2347. this.$alert("您确定删除吗?", "提示", {
  2348. confirmButtonText: "确定",
  2349. callback: (action) => {
  2350. if (action == "confirm") {
  2351. this.loading = true;
  2352. this.$http
  2353. .delete(QUESTION_API + "/paperDetailUnit/" + paperDetailUnitId)
  2354. .then(() => {
  2355. this.initPaper();
  2356. this.reduplicateGroup = [];
  2357. this.loading = true;
  2358. this.$notify({
  2359. message: "删除成功",
  2360. type: "success",
  2361. });
  2362. this.loading = false;
  2363. });
  2364. }
  2365. },
  2366. });
  2367. },
  2368. deleteQues02(questionId, paperDetailUnitId) {
  2369. this.$alert("您确定删除吗?", "提示", {
  2370. confirmButtonText: "确定",
  2371. callback: (action) => {
  2372. if (action == "confirm") {
  2373. this.loading = true;
  2374. this.$http
  2375. .delete(
  2376. QUESTION_API +
  2377. "/paper/deleteQuestion/" +
  2378. paperDetailUnitId +
  2379. "/" +
  2380. questionId
  2381. )
  2382. .then((response) => {
  2383. if (response.data.length > 0) {
  2384. var deleteInfo =
  2385. "该试题被试卷:" +
  2386. response.data.join(" , ") +
  2387. "使用,不能删除";
  2388. this.$notify({
  2389. message: deleteInfo,
  2390. type: "error",
  2391. });
  2392. } else {
  2393. this.initPaper();
  2394. this.reduplicateGroup = [];
  2395. this.loading = true;
  2396. this.$notify({
  2397. message: "保存成功",
  2398. type: "success",
  2399. });
  2400. }
  2401. this.loading = false;
  2402. });
  2403. }
  2404. },
  2405. });
  2406. },
  2407. exportPaperAnswer() {
  2408. var key = this.user.key;
  2409. var token = this.user.token;
  2410. window.open(
  2411. QUESTION_API +
  2412. "/paper/answer/export/" +
  2413. this.paperId +
  2414. "?$key=" +
  2415. key +
  2416. "&$token=" +
  2417. token
  2418. );
  2419. },
  2420. getSubQuesEditId(paperDetailUnit, subQuestion) {
  2421. return paperDetailUnit.question.id + "_" + subQuestion.subNumber;
  2422. },
  2423. //打开考试说明编辑框
  2424. openEditExamPaperRemark() {
  2425. if (this.paper.examRemark) {
  2426. this.examRemark = this.paper.examRemark;
  2427. } else {
  2428. this.examRemark = "";
  2429. }
  2430. this.paperRemarkDialog = true;
  2431. },
  2432. //保存考试说明
  2433. savePaperRemark() {
  2434. this.paper.examRemark = this.examRemark;
  2435. this.savePaper();
  2436. this.paperRemarkDialog = false;
  2437. },
  2438. //关闭考试说明编辑框
  2439. closPaperRemark() {
  2440. this.examRemark = "";
  2441. this.paperRemarkDialog = false;
  2442. },
  2443. //保存试卷
  2444. savePaper() {
  2445. this.loading = true;
  2446. this.$http
  2447. .put(QUESTION_API + "/paper", this.paper)
  2448. .then(() => {
  2449. this.$notify({
  2450. message: "保存成功",
  2451. type: "success",
  2452. });
  2453. this.loading = false;
  2454. this.initPaper();
  2455. })
  2456. .catch((error) => {
  2457. this.loading = false;
  2458. this.$notify({
  2459. type: "error",
  2460. message: error.response.data.desc,
  2461. });
  2462. });
  2463. },
  2464. //删除试卷
  2465. deletePaper() {
  2466. this.$confirm("确认删除试卷吗?", "提示", {
  2467. type: "warning",
  2468. }).then(() => {
  2469. this.loading = true;
  2470. this.selectedPaperIds = [];
  2471. this.selectedPaperIds.push(this.paper.id);
  2472. this.$http
  2473. .post(
  2474. QUESTION_API + "/paper/audit/delete",
  2475. new URLSearchParams({ paperIds: this.selectedPaperIds })
  2476. )
  2477. .then(
  2478. () => {
  2479. this.$notify({
  2480. message: "删除成功",
  2481. type: "success",
  2482. });
  2483. this.back();
  2484. },
  2485. (error) => {
  2486. this.$notify({
  2487. message: error.response.data.desc,
  2488. type: "error",
  2489. });
  2490. this.loading = false;
  2491. }
  2492. );
  2493. });
  2494. },
  2495. //打开上传音频弹框
  2496. openDialog() {
  2497. this.checkResult = false;
  2498. this.isUpload = true;
  2499. if (document.getElementById("radioFile")) {
  2500. document.getElementById("radioFile").value = "";
  2501. }
  2502. this.dialogRadioFile = true;
  2503. this.fileList = [];
  2504. },
  2505. //关闭音频弹框
  2506. closeAudioDialog() {
  2507. this.dialogRadioFile = this.uploadAudioLoading;
  2508. },
  2509. //返回
  2510. back() {
  2511. if (sessionStorage.getItem("question_back") == "true") {
  2512. this.$router.push({
  2513. path: "/questions/" + this.parentView + "/0",
  2514. });
  2515. } else {
  2516. this.$router.push({
  2517. path: "/questions/" + this.parentView + "/1",
  2518. });
  2519. }
  2520. },
  2521. paperDetailShow(paperDetail) {
  2522. if (this.reduplicateGroup.length == 0) {
  2523. return true;
  2524. }
  2525. let paperDetailUnits = paperDetail.paperDetailUnits;
  2526. for (let i = 0, imax = paperDetailUnits.length; i < imax; i++) {
  2527. for (var j = 0, jmax = this.reduplicateGroup.length; j < jmax; j++) {
  2528. if (paperDetailUnits[i].id == this.reduplicateGroup[j]) {
  2529. return true;
  2530. }
  2531. }
  2532. }
  2533. return false;
  2534. },
  2535. //上传文件检查
  2536. checkFile() {
  2537. this.fileNameList = [];
  2538. //读取选取的文件夹里面的文件
  2539. this.checkResult = true;
  2540. var files = document.getElementById("radioFile").files;
  2541. if (files.length == 0) {
  2542. this.message = "请选择音频文件夹!";
  2543. return;
  2544. }
  2545. var size = 0;
  2546. var isGo = false;
  2547. //取到所有文件的文件名
  2548. for (var i = 0; i < files.length; i++) {
  2549. this.fileNameList.push(files[i].name);
  2550. if (files[i].size > 5 * 1024 * 1024) {
  2551. isGo = true;
  2552. break;
  2553. }
  2554. size = files[i].size + size;
  2555. }
  2556. if (isGo) {
  2557. this.message = "上传单个文件不能超过5M";
  2558. this.isUpload = true;
  2559. }
  2560. if (size > 50 * 1024 * 1024) {
  2561. this.message = "上传文件总和不能超过50M";
  2562. this.isUpload = true;
  2563. return;
  2564. }
  2565. this.$http
  2566. .post(
  2567. QUESTION_API + "/checkRadioFile/" + this.paperId,
  2568. this.fileNameList
  2569. )
  2570. .then((response) => {
  2571. console.log("response:", response);
  2572. this.message = response.data.errorMsg;
  2573. if (this.message == "OK") {
  2574. this.message = "OK!";
  2575. this.isUpload = false;
  2576. } else {
  2577. this.isUpload = true;
  2578. }
  2579. })
  2580. .catch((error) => {
  2581. console.log(error);
  2582. });
  2583. },
  2584. //读取文件
  2585. uploadAudioFile() {
  2586. let param = new FormData();
  2587. var fileList = document.getElementById("radioFile").files;
  2588. //循环添加到formData中
  2589. for (var i = 0; i < fileList.length; i++) {
  2590. var file = fileList[i];
  2591. param.append("files", file, file.name);
  2592. }
  2593. let config = {
  2594. headers: { "Content-Type": "multipart/form-data" },
  2595. };
  2596. this.$http
  2597. .post(QUESTION_API + "/uploadRadio/" + this.paperId, param, config)
  2598. .then(() => {
  2599. this.dialogRadioFile = false;
  2600. this.uploadAudioLoading = false;
  2601. this.checkResult = false;
  2602. this.isUpload = true;
  2603. document.getElementById("radioFile").value = "";
  2604. this.initPaper();
  2605. })
  2606. .catch((error) => {
  2607. this.message = error.response.data.desc;
  2608. this.uploadAudioLoading = false;
  2609. });
  2610. },
  2611. },
  2612. };
  2613. </script>