extend.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <script>
  2. var valid_result = false
  3. {notempty name="row"}
  4. var row = {:json_encode($row, 256)};
  5. {else/}
  6. var row = {};
  7. {/notempty}
  8. var app = new Vue({
  9. el: '#app',
  10. data: {
  11. title: '',
  12. kind: 'SINGLE',
  13. // 填空题
  14. fillOptions: [],
  15. showTitleEditor: true,
  16. showTitleFill: true,
  17. // 简答题
  18. shortOptions: [],
  19. // 简答题分数设置
  20. shortScoreDialogVisible: false,
  21. shortScoreConfig: [],
  22. shortScoreIndex: 0,
  23. // 材料题
  24. materialQuestions: [],
  25. materialSummary: {
  26. // 总分数及题数
  27. total_score: 0,
  28. total_quantity: 0,
  29. // 各类题目的分数及题数
  30. judge_quantity: 0,
  31. judge_score: 0,
  32. single_quantity: 0,
  33. single_score: 0,
  34. multi_quantity: 0,
  35. multi_score: 0,
  36. fill_quantity: 0,
  37. fill_score: 0,
  38. short_quantity: 0,
  39. short_score: 0,
  40. },
  41. // 是否属于材料题的子题
  42. isMaterialChild: 0,
  43. },
  44. created() {
  45. // 编辑时初始化数据
  46. if (row) {
  47. this.title = row.title
  48. this.kind = row.kind
  49. this.isMaterialChild = row.is_material_child
  50. this.hideMaterial()
  51. // this.changeIsMaterialChild({target: {value: row.is_material_child}})
  52. console.log('row.answer', row.answer)
  53. switch (row.kind) {
  54. // 填空题
  55. case 'FILL':
  56. this.fillOptions = JSON.parse(row.answer)
  57. console.log('fillOptions', this.fillOptions)
  58. break
  59. // 简答题
  60. case 'SHORT':
  61. let shortAnswer = JSON.parse(row.answer)
  62. this.shortOptions = shortAnswer.config
  63. $('#c-short_answer').html(shortAnswer.answer)
  64. console.log('shortOptions', this.shortOptions)
  65. break
  66. // 材料题
  67. case 'MATERIAL':
  68. let material_questions = row.material_questions ? row.material_questions : []
  69. for (let i = 0; i < material_questions.length; i++) {
  70. if (material_questions[i].question) {
  71. material_questions[i].id = material_questions[i].question.id
  72. material_questions[i].kind = material_questions[i].question.kind
  73. material_questions[i].title = material_questions[i].question.title
  74. material_questions[i].cates = material_questions[i].question.cates
  75. }
  76. }
  77. this.materialQuestions = material_questions
  78. this.statisticsMaterialSummary()
  79. console.log('materialQuestions', this.materialQuestions)
  80. break
  81. default:
  82. break
  83. }
  84. this.hideTitle(row.kind)
  85. } else {
  86. // $('#c-title2').hide()
  87. this.showTitleFill = false
  88. }
  89. },
  90. methods: {
  91. // 修改是否属于材料题的子题
  92. changeIsMaterialChild(e) {
  93. console.log('changeKind', e.target.value)
  94. this.isMaterialChild = e.target.value
  95. this.hideMaterial()
  96. },
  97. // 修改题型
  98. changeKind(e) {
  99. console.log('changeKind', e.target.value)
  100. this.kind = e.target.value
  101. this.hideMaterial()
  102. this.hideTitle(this.kind)
  103. },
  104. // 隐藏材料题子题相关的内容
  105. hideMaterial() {
  106. if (this.isMaterialChild == 1) {
  107. $('label[for="row[kind]-MATERIAL"]').hide()
  108. $('.is_material_child').show()
  109. } else {
  110. $('label[for="row[kind]-MATERIAL"]').show()
  111. $('.is_material_child').hide()
  112. }
  113. if (this.kind == 'MATERIAL') {
  114. $('#is_material_child').hide()
  115. } else {
  116. $('#is_material_child').show()
  117. }
  118. },
  119. // 隐藏题目
  120. hideTitle(kind) {
  121. if (kind == 'FILL') {
  122. this.showTitleEditor = false
  123. this.showTitleFill = true
  124. $('#c-title1').hide()
  125. $('#c-title2').show()
  126. } else {
  127. this.showTitleEditor = true
  128. this.showTitleFill = false
  129. $('#c-title1').show()
  130. $('#c-title2').hide()
  131. }
  132. console.log('hideTitle', kind, this.showTitleEditor, this.showTitleFill)
  133. },
  134. // 填空题 - 插入填空位
  135. addFillOptions() {
  136. this.fillOptions.push({
  137. answers: [''],
  138. })
  139. this.title = this.title == undefined ? '' : this.title
  140. this.title += '______'// 6个_
  141. },
  142. // 填空题 - 填空位添加答案
  143. addFillAnswer(index) {
  144. this.fillOptions[index].answers.push('')
  145. },
  146. // 填空题 - 填空位删除答案
  147. deleteFillAnswer(index, key) {
  148. if (this.fillOptions[index].answers.length === 1) {
  149. this.fillOptions.splice(index, 1)
  150. } else {
  151. this.fillOptions[index].answers.splice(key, 1)
  152. }
  153. },
  154. // 修改题目
  155. changeTitle(e) {
  156. console.log('changeTitle e', e, this.title)
  157. },
  158. // 简答题 - 插入答案
  159. addShortOptions() {
  160. this.shortOptions.push({
  161. answer: '',
  162. score: 1,
  163. })
  164. },
  165. // 简答题 - 删除答案
  166. deleteShortAnswer(index) {
  167. this.shortOptions.splice(index, 1)
  168. },
  169. // 材料题 - 选择题目
  170. selectMaterialQuestion() {
  171. Fast.api.open('exam/question/select?kind=JUDGE,SINGLE,MULTI,FILL,SHORT', '选择题目', {
  172. callback: (data) => {
  173. console.log('selectMaterialQuestions', data)
  174. for (let i = 0; i < data.length; i++) {
  175. // 材料题不允许选择材料题
  176. if (data[i].kind == 'MATERIAL') {
  177. data.splice(i, 1)
  178. continue;
  179. }
  180. data[i].score = 1
  181. }
  182. // 排除已经存在的试题
  183. for (let i = 0; i < this.materialQuestions.length; i++) {
  184. for (let j = 0; j < data.length; j++) {
  185. if (this.materialQuestions[i].id == data[j].id) {
  186. data.splice(j, 1)
  187. }
  188. }
  189. }
  190. // 合并数组
  191. this.materialQuestions = this.materialQuestions.concat(data)
  192. // 统计题目信息
  193. this.statisticsMaterialSummary()
  194. }
  195. })
  196. },
  197. // 材料题 - 修改分数
  198. scoreChange(index) {
  199. console.log('scoreChange', index)
  200. // 统计题目信息
  201. this.statisticsMaterialSummary()
  202. },
  203. // 材料题 - 打开简答题关键词分数设置
  204. openShortScoreDialog(row, index) {
  205. let answer = row.answer
  206. if (typeof answer == 'string') {
  207. answer = JSON.parse(answer)
  208. }
  209. console.log('openShortScoreDialog', row, index, answer)
  210. this.shortScoreConfig = [...answer.config]
  211. this.shortScoreIndex = index
  212. this.shortScoreDialogVisible = true
  213. },
  214. // 材料题 - 提交简答题关键词分数设置
  215. shortScoreSubmit() {
  216. console.log('shortScoreSubmit', this.shortScoreConfig, this.materialQuestions[this.shortScoreIndex])
  217. let answer = this.materialQuestions[this.shortScoreIndex].answer
  218. if (typeof answer == 'string') {
  219. answer = JSON.parse(answer)
  220. }
  221. answer.config = this.shortScoreConfig
  222. this.materialQuestions[this.shortScoreIndex].answer = answer
  223. this.shortScoreConfig = null
  224. this.shortScoreIndex = 0
  225. this.shortScoreDialogVisible = false
  226. // 统计题目信息
  227. this.statisticsMaterialSummary()
  228. },
  229. // 材料题 - 删除试题
  230. deleteQuestion(index) {
  231. console.log('deleteQuestion', index)
  232. this.materialQuestions.splice(index, 1)
  233. // 统计题目信息
  234. this.statisticsMaterialSummary()
  235. },
  236. // 材料题 - 统计材料题的分数及题数
  237. statisticsMaterialSummary() {
  238. let summary = {
  239. // 总分数及题数
  240. total_score: 0,
  241. total_quantity: 0,
  242. // 各类题目的分数及题数
  243. judge_quantity: 0,
  244. judge_score: 0,
  245. single_quantity: 0,
  246. single_score: 0,
  247. multi_quantity: 0,
  248. multi_score: 0,
  249. fill_quantity: 0,
  250. fill_score: 0,
  251. short_quantity: 0,
  252. short_score: 0,
  253. }
  254. for (let i = 0; i < this.materialQuestions.length; i++) {
  255. let question = this.materialQuestions[i]
  256. summary.total_score += question.score ? question.score : 1
  257. summary.total_quantity += 1
  258. switch (question.kind) {
  259. case 'JUDGE':
  260. summary.judge_quantity += 1
  261. summary.judge_score += question.score ? question.score : 1
  262. break
  263. case 'SINGLE':
  264. summary.single_quantity += 1
  265. summary.single_score += question.score ? question.score : 1
  266. break
  267. case 'MULTI':
  268. summary.multi_quantity += 1
  269. summary.multi_score += question.score ? question.score : 1
  270. break
  271. case 'FILL':
  272. summary.fill_quantity += 1
  273. summary.fill_score += question.score ? question.score : 1
  274. break
  275. case 'SHORT':
  276. summary.short_quantity += 1
  277. summary.short_score += question.score ? question.score : 1
  278. break
  279. }
  280. }
  281. this.materialSummary = summary
  282. },
  283. // 验证
  284. valid() {
  285. console.log('trigger valid', this.kind)
  286. switch (this.kind) {
  287. case 'FILL':
  288. console.log('this.fillOptions', this.fillOptions)
  289. for (let i = 0; i < this.fillOptions.length; i++) {
  290. let option = this.fillOptions[i]
  291. for (let j = 0; j < option.answers.length; j++) {
  292. let answer = option.answers[j]
  293. console.log('answer', answer)
  294. if (answer.length == 0) {
  295. Fast.api.msg('填空位(' + (i + 1) + ')的第' + (j + 1) + '个答案不能为空')
  296. console.log('填空位(' + (i + 1) + ')的第' + (j + 1) + '个答案不能为空')
  297. valid_result = false
  298. return false
  299. }
  300. }
  301. }
  302. // $('#options_extend').val(encodeURI(JSON.stringify(this.fillOptions)))
  303. valid_result = true
  304. return true
  305. // 材料题
  306. case 'MATERIAL':
  307. console.log('this.materialQuestions', this.materialQuestions)
  308. // if (this.materialQuestions.length == 0) {
  309. // console.log('材料题的子题目不能为空')
  310. // valid_result = false
  311. // return false
  312. // }
  313. for (let i = 0; i < this.materialQuestions.length; i++) {
  314. let question = this.materialQuestions[i]
  315. if (question.kind == 'SHORT') {
  316. let answer = question.answer
  317. if (typeof answer == 'string') {
  318. answer = JSON.parse(answer)
  319. }
  320. if (answer.config.length == 0) {
  321. Fast.api.msg('简答题的关键词分数不能为空')
  322. console.log('简答题的关键词分数不能为空')
  323. valid_result = false
  324. return false
  325. }
  326. }
  327. }
  328. // 将试题信息转换为JSON字符串
  329. let questions = []
  330. for (let i = 0; i < this.materialQuestions.length; i++) {
  331. let question = this.materialQuestions[i]
  332. questions.push({
  333. id: question.id,
  334. score: question.score,
  335. answer: question.answer,
  336. answer_config: question.answer_config ? question.answer_config : null,
  337. })
  338. }
  339. $('#c-material_questions').val(JSON.stringify(questions))
  340. valid_result = true
  341. return true
  342. default:
  343. valid_result = true
  344. return true
  345. }
  346. }
  347. }
  348. })
  349. </script>
  350. <style>
  351. .sp_results {
  352. min-width: 600px;
  353. }
  354. </style>