paper.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. let configs_count = {}
  2. let config_dialog = 0
  3. define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function ($, undefined, Backend, Table, Form) {
  4. //读取选中的条目
  5. $.jstree.core.prototype.get_all_checked = function (full) {
  6. var obj = this.get_selected(), i, j;
  7. for (i = 0, j = obj.length; i < j; i++) {
  8. obj = obj.concat(this.get_node(obj[i]).parents);
  9. }
  10. obj = $.grep(obj, function (v, i, a) {
  11. return v != '#';
  12. });
  13. obj = obj.filter(function (itm, i, a) {
  14. return i == a.indexOf(itm);
  15. });
  16. return full ? $.map(obj, $.proxy(function (i) {
  17. return this.get_node(i);
  18. }, this)) : obj;
  19. };
  20. var Controller = {
  21. index: function () {
  22. // 初始化表格参数配置
  23. Table.api.init({
  24. extend: {
  25. index_url: 'exam/paper/index' + location.search,
  26. add_url: 'exam/paper/add',
  27. edit_url: 'exam/paper/edit',
  28. del_url: 'exam/paper/del',
  29. multi_url: 'exam/paper/multi',
  30. import_url: 'exam/paper/import',
  31. table: 'exam_paper',
  32. dragsort_url: false,
  33. }
  34. });
  35. var table = $("#table");
  36. //在普通搜索渲染后
  37. table.on('post-common-search.bs.table', function (event, table) {
  38. let form = $("form", table.$commonsearch);
  39. $("input[name='cate_id']", form).addClass("selectpage").data("source", "exam/cate/selectpage").data("params", {"custom[kind]": "QUESTION","isTree":true}).data("orderBy", "sort desc");
  40. // $("input[name='exam_type_id']", form).addClass("selectpage").data("source", "exam_type/index").data("orderBy", "sort desc");
  41. Form.events.cxselect(form);
  42. Form.events.selectpage(form);
  43. });
  44. //当内容渲染完成给编辑按钮添加`data-area`属性,点击列表编辑按钮时全屏
  45. table.on('post-body.bs.table', function (e, settings, json, xhr) {
  46. $(".btn-add").data("area", ["100%", "100%"]);
  47. $(".btn-editone").data("area", ["100%", "100%"]);
  48. });
  49. // 初始化表格
  50. table.bootstrapTable({
  51. url: $.fn.bootstrapTable.defaults.extend.index_url,
  52. pk: 'id',
  53. sortName: 'weigh',
  54. sortOrder: 'desc',
  55. search: false,
  56. showExport: false,//隐藏导出
  57. showToggle: false,//隐藏浏览模式
  58. showColumns: false,//隐藏显示隐藏模式
  59. searchFormVisible: true,//默认显示搜索表单
  60. columns: [
  61. [
  62. {checkbox: true},
  63. {field: 'id', title: __('Id'), operate: false},
  64. // {field: 'cate_id', title: __('Cate_id'), autocomplete: false, visible: false},
  65. // {field: 'cate.name', title: __('Cate_id'), operate: false},
  66. {field: 'title', title: __('Title'), autocomplete: false, operate: 'LIKE'},
  67. {field: 'image', title: __('Image'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.image},
  68. // {field: 'configs', title: __('Configs'), operate: 'LIKE'},
  69. {field: 'quantity', title: __('Quantity'), operate: false},
  70. {field: 'total_score', title: __('Total_score'), operate: false},
  71. // {field: 'pass_score', title: __('Pass_score'), operate: false},
  72. {field: 'limit_count', title: __('Limit_count'), operate: false},
  73. /*{
  74. field: 'mode',
  75. title: __('Mode'),
  76. searchList: {"RANDOM": __('Random'), "FIX": __('Fix')},
  77. formatter: Table.api.formatter.normal
  78. },*/
  79. /*{
  80. field: 'limit_time',
  81. title: __('Limit_time'),
  82. operate: false,
  83. autocomplete: false,
  84. formatter: function (value) {
  85. return Controller.api.formatDuring(value)
  86. }
  87. },*/
  88. /*{
  89. field: 'start_time',
  90. title: __('Start_time'),
  91. operate: 'RANGE',
  92. addclass: 'datetimerange',
  93. autocomplete: false,
  94. formatter: Table.api.formatter.datetime
  95. },*/
  96. /* {
  97. field: 'end_time',
  98. title: __('End_time'),
  99. operate: 'RANGE',
  100. addclass: 'datetimerange',
  101. autocomplete: false,
  102. formatter: Table.api.formatter.datetime
  103. },*/
  104. // {field: 'is_only_room', title: __('Is_only_room'), searchList: {"1":__('Yes'),"0":__('No')}, formatter: Table.api.formatter.toggle},
  105. {
  106. field: 'status',
  107. title: __('Status'),
  108. searchList: {"NORMAL": __('Normal'), "HIDDEN": __('Hidden')},
  109. formatter: Table.api.formatter.status
  110. },
  111. {field: 'weigh', title: __('Weigh'), operate: false},
  112. {
  113. field: 'createtime',
  114. title: __('Createtime'),
  115. operate: 'RANGE',
  116. addclass: 'datetimerange',
  117. autocomplete: false,
  118. formatter: Table.api.formatter.datetime
  119. },
  120. // {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
  121. {
  122. field: 'operate',
  123. title: __('Operate'),
  124. table: table,
  125. buttons:[
  126. /*{
  127. name:'selectuser',
  128. text:'选择用户',
  129. title:'选择用户',
  130. icon:'fa fa-exclamation-circle',
  131. classname:'btn btn-xs btn-info btn-dialog btn-selectuser',
  132. url:'exam/paper/selectuser/id/{ids}?dialog=1',
  133. target:'_self',
  134. },*/
  135. {
  136. name:'grade',
  137. text:'成绩',
  138. title:'成绩',
  139. icon:'fa fa-exclamation-circle',
  140. classname:'btn btn-xs btn-info btn-dialog btn-grade',
  141. url:'exam/grade/index/paper_id/{ids}?dialog=1',
  142. target:'_self',
  143. },
  144. /*{
  145. name:'nograde',
  146. text:'缺考',
  147. title:'缺考',
  148. icon:'fa fa-exclamation-circle',
  149. classname:'btn btn-xs btn-info btn-dialog btn-nograde',
  150. url:'exam/paper/nograde/id/{ids}',
  151. target:'_self',
  152. }*/
  153. ],
  154. events: Table.api.events.operate,
  155. formatter: Table.api.formatter.operate
  156. }
  157. ]
  158. ],
  159. onLoadSuccess:function(){
  160. // 这里就是数据渲染结束后的回调函数
  161. $(".btn-selectuser").data("area", ['80%','80%']);
  162. $(".btn-grade").data("area", ['90%','90%']);
  163. $(".btn-nograde").data("area", ['90%','90%']);
  164. }
  165. });
  166. // 为表格绑定事件
  167. Table.api.bindevent(table);
  168. },
  169. recyclebin: function () {
  170. // 初始化表格参数配置
  171. Table.api.init({
  172. extend: {
  173. 'dragsort_url': ''
  174. }
  175. });
  176. var table = $("#table");
  177. // 初始化表格
  178. table.bootstrapTable({
  179. url: 'exam/paper/recyclebin' + location.search,
  180. pk: 'id',
  181. sortName: 'id',
  182. columns: [
  183. [
  184. {checkbox: true},
  185. {field: 'id', title: __('Id')},
  186. {field: 'title', title: __('Title'), align: 'left'},
  187. {
  188. field: 'deletetime',
  189. title: __('Deletetime'),
  190. operate: 'RANGE',
  191. addclass: 'datetimerange',
  192. formatter: Table.api.formatter.datetime
  193. },
  194. {
  195. field: 'operate',
  196. width: '130px',
  197. title: __('Operate'),
  198. table: table,
  199. events: Table.api.events.operate,
  200. buttons: [
  201. {
  202. name: 'Restore',
  203. text: __('Restore'),
  204. classname: 'btn btn-xs btn-info btn-ajax btn-restoreit',
  205. icon: 'fa fa-rotate-left',
  206. url: 'exam/paper/restore',
  207. refresh: true
  208. },
  209. /*{
  210. name: 'Destroy',
  211. text: __('Destroy'),
  212. classname: 'btn btn-xs btn-danger btn-ajax btn-destroyit',
  213. icon: 'fa fa-times',
  214. url: 'exam/paper/destroy',
  215. refresh: true
  216. }*/
  217. ],
  218. formatter: Table.api.formatter.operate
  219. }
  220. ]
  221. ]
  222. });
  223. // 为表格绑定事件
  224. Table.api.bindevent(table);
  225. },
  226. add: function () {
  227. Controller.api.bindevent()
  228. Controller.api.bindConfigs()
  229. Controller.api.bindTime()
  230. },
  231. selectuser: function () {
  232. Controller.apisu.bindevent();
  233. },
  234. nograde: function () {
  235. Controller.api.bindevent()
  236. },
  237. edit: function () {
  238. Controller.api.bindevent()
  239. Controller.api.bindConfigs()
  240. Controller.api.getCountScore()
  241. Controller.api.renderCountScore()
  242. Controller.api.bindTime()
  243. },
  244. apisu: {
  245. bindevent: function () {
  246. Form.api.bindevent($("form[role=form]"), null, null, function () {
  247. if ($("#treeview").length > 0) {
  248. var r = $("#treeview").jstree("get_all_checked");
  249. $("input[name='row[user_rule]']").val(r.join(','));
  250. }
  251. return true;
  252. });
  253. //渲染权限节点树
  254. //销毁已有的节点树
  255. $("#treeview").jstree("destroy");
  256. Controller.apisu.rendertree(nodeData);
  257. //全选和展开
  258. $(document).on("click", "#checkall", function () {
  259. $("#treeview").jstree($(this).prop("checked") ? "check_all" : "uncheck_all");
  260. });
  261. $(document).on("click", "#expandall", function () {
  262. $("#treeview").jstree($(this).prop("checked") ? "open_all" : "close_all");
  263. });
  264. $("select[name='row[pid]']").trigger("change");
  265. },
  266. rendertree: function (content) {
  267. $("#treeview")
  268. .on('redraw.jstree', function (e) {
  269. $(".layer-footer").attr("domrefresh", Math.random());
  270. })
  271. .jstree({
  272. "themes": {"stripes": true},
  273. "checkbox": {
  274. "keep_selected_style": false,
  275. },
  276. "types": {
  277. "root": {
  278. "icon": "fa fa-folder-open",
  279. },
  280. "menu": {
  281. "icon": "fa fa-folder-open",
  282. },
  283. "file": {
  284. "icon": "fa fa-file-o",
  285. }
  286. },
  287. "plugins": ["checkbox", "types"],
  288. "core": {
  289. 'check_callback': true,
  290. "data": content
  291. }
  292. });
  293. },
  294. },
  295. api: {
  296. bindevent: function () {
  297. Form.api.bindevent($("form[role=form]"), function () {
  298. }, function () {
  299. }, function () {
  300. let mode = $('input[name="row[mode]"]:checked').val()
  301. console.log('submit mode', mode)
  302. if (mode === 'FIX') {
  303. $('#valid').click()
  304. return valid_result;
  305. } else {
  306. let configs = $('#c-configs').val()
  307. console.log('configs', configs)
  308. if (!configs) {
  309. Layer.alert('请选题')
  310. return false
  311. }
  312. let quantity = $('.span_quantity').text()
  313. if (quantity !== $('#c-quantity').val()) {
  314. Layer.alert('试卷出题规则的选取题数与试卷题目数量不一致')
  315. return false
  316. }
  317. let total_score = $('.span_total_score').text()
  318. if (total_score !== $('#c-total_score').val()) {
  319. Layer.alert('试卷出题规则的总分与试卷总分不一致')
  320. return false
  321. }
  322. let limit_time_hour = $('#c-limit_time_hour').val()
  323. let limit_time_minute = $('#c-limit_time_minute').val()
  324. let limit_time = (limit_time_hour ? limit_time_hour : 0) * 3600 + (limit_time_minute ? limit_time_minute : 0) * 60
  325. $('#c-limit_time').val(limit_time)
  326. }
  327. return true
  328. });
  329. },
  330. // 选题模式设置
  331. bindConfigs: function () {
  332. // 选题模式弹窗
  333. $('.btn-configs').click(function () {
  334. let quantity = $('#c-quantity').val()
  335. let total_score = $('#c-total_score').val()
  336. if (!quantity || !total_score) {
  337. Layer.msg('请先设置题目数量和试卷总分')
  338. return false
  339. }
  340. config_dialog = Layer.open({
  341. type: 1,
  342. shade: false,
  343. title: '随机选题配置',
  344. area: ['600px', '600px'],
  345. zIndex: 1,
  346. content: $('#configsDialog'),
  347. cancel: function () {
  348. }
  349. })
  350. })
  351. // 选题库获取题数
  352. $(document).on("change", "#config-cate_id", function () {
  353. Controller.api.getCountScore()
  354. })
  355. // 选取题更改
  356. $('.input_count').change(function () {
  357. let type = $(this).data('type')
  358. let count = $(this).val()
  359. let score = $('.input_' + type + '_score').val()
  360. Controller.api.calcCountScore(type, count, score)
  361. })
  362. // 每题分数更改
  363. $('.input_score').change(function () {
  364. let type = $(this).data('type')
  365. let count = Controller.api.formatVal($('.input_' + type).val())
  366. let score = Controller.api.formatVal($(this).val())
  367. Controller.api.calcCountScore(type, count, score)
  368. })
  369. // 分难度更改
  370. $('.checkbox_difficulty').change(function () {
  371. let type = $(this).data('type')
  372. let value = $(this).is(':checked')
  373. let ul = $('.ul_' + type + '_difficulty')
  374. let input_count = Controller.api.formatVal($('.input_' + type))
  375. let input_score = Controller.api.formatVal($('.input_' + type + '_score'))
  376. let span_score = Controller.api.formatVal($('.span_' + type + '_score'))
  377. if (value) {
  378. ul.removeClass('hide').show()
  379. input_count.attr('disabled', 'disabled')
  380. input_score.attr('disabled', 'disabled')
  381. span_score.hide()
  382. // 触发计算
  383. $(ul.find('.input_count')[0]).trigger('change')
  384. } else {
  385. ul.addClass('hide').hide()
  386. input_count.removeAttr('disabled', 'disabled')
  387. input_score.removeAttr('disabled', 'disabled')
  388. span_score.show()
  389. }
  390. // $('.input_count').trigger('change')
  391. })
  392. // 保存选题配置 TODO 弃用
  393. $('#btnSaveConfig').click(function () {
  394. Controller.api.saveConfig()
  395. })
  396. },
  397. // 保存选题配置
  398. saveConfig() {
  399. let configs = {
  400. cate_ids: $('#config-cate_id').val(),
  401. all: {},
  402. judge: {
  403. difficulty: {}
  404. },
  405. single: {
  406. difficulty: {}
  407. },
  408. multi: {
  409. difficulty: {}
  410. },
  411. fill: {
  412. difficulty: {}
  413. },
  414. short: {
  415. difficulty: {}
  416. },
  417. material: {
  418. difficulty: {}
  419. },
  420. }
  421. // 总
  422. $('#divAll').find('span').each(function (index, ele) {
  423. let key = $(ele).attr('class').replace('span_', '')
  424. configs.all[key] = parseInt(Controller.api.formatVal($(ele).text()))
  425. })
  426. // 题型配置
  427. $('.input_kind_count').each(function (index, ele) {
  428. let type = $(ele).data('type')
  429. configs[type]['count'] = parseInt(Controller.api.formatVal($(ele).val()))
  430. configs[type]['score'] = parseInt(Controller.api.formatVal($(ele).next('span').find('.input_score').val()))
  431. configs[type]['total_score'] = configs[type]['count'] * configs[type]['score']
  432. configs[type]['use_difficulty'] = $(ele).parent().find('.checkbox_difficulty').is(':checked')
  433. })
  434. // 难度配置
  435. $('.ul_difficulty').find('.input_count').each(function (index, ele) {
  436. let type_key = $(ele).data('type').split('_')
  437. let type = type_key[0]
  438. let key = type_key[1]
  439. configs[type].difficulty[key] = {
  440. count: parseInt(Controller.api.formatVal($(ele).val())),
  441. score: parseInt(Controller.api.formatVal($(ele).next('.input_score').val()))
  442. }
  443. configs[type].difficulty[key]['total_score'] = configs[type].difficulty[key].count * configs[type].difficulty[key].score
  444. })
  445. console.log('configs', configs)
  446. $('#c-configs').val(JSON.stringify(configs))
  447. Layer.close(config_dialog)
  448. },
  449. // 根据题库设置题数、分数
  450. getCountScore() {
  451. let cate_ids = $('#config-cate_id').val()
  452. if (cate_ids) {
  453. configs_count = {}
  454. Fast.api.ajax({
  455. url: 'exam/question/getCount',
  456. type: 'post',
  457. data: {cate_ids: cate_ids}
  458. }, function (data, ret) {
  459. configs_count = data
  460. if (!configs_count) {
  461. return false
  462. }
  463. let quantity = $('#c-quantity').val()
  464. let total_score = $('#c-total_score').val()
  465. let sing_score = parseInt(total_score / quantity)
  466. for (let key of Object.keys(configs_count)) {
  467. let value = configs_count[key]
  468. $('.span_' + key + '_total').text(value)
  469. $('.input_' + key).attr('max', value)
  470. $('.input_' + key + '_score').attr('max', sing_score)//.val(sing_score)
  471. }
  472. return false
  473. });
  474. }
  475. },
  476. calcCountScore(type, count, score) {
  477. // 计算题型总分
  478. $('.span_' + type + '_total_score').text(count * score)
  479. // 计算分难度的总分
  480. if (type.indexOf('_') > 0) {
  481. let parent_type = type.split('_')[0]
  482. let ul = $('.ul_' + parent_type + '_difficulty')
  483. let parent_count_input = $('.input_' + parent_type)
  484. let parent_score_span = $('.span_' + parent_type + '_total_score')
  485. let sum_count = 0
  486. let sum_score = 0
  487. ul.find('.input_count').each(function (index, ele) {
  488. let single_score = $(ele).next('input').val()
  489. sum_count += parseInt($(ele).val())
  490. sum_score += parseInt($(ele).val()) * single_score
  491. })
  492. parent_count_input.val(sum_count)
  493. parent_score_span.text(sum_score)
  494. }
  495. // 总题数
  496. let kind_total_count = 0
  497. $('.input_kind_count').each(function (index, ele) {
  498. kind_total_count += parseInt($(ele).val())
  499. })
  500. $('.span_quantity').text(kind_total_count)
  501. // 计算总分
  502. let kind_total_score = 0
  503. $('.span_kind_total_score').each(function (index, ele) {
  504. kind_total_score += parseInt($(ele).text())
  505. })
  506. $('.span_total_score').text(kind_total_score)
  507. // 保存配置
  508. Controller.api.saveConfig()
  509. },
  510. // 根据配置设置题数渲染数据
  511. renderCountScore() {
  512. // 考试时间渲染
  513. const limit_time = $('#c-limit_time').val() ? $('#c-limit_time').val() : 0
  514. if (limit_time) {
  515. let hour = Math.floor(limit_time / 3600)
  516. let minute = Math.floor(limit_time / 60) % 60
  517. $('#c-limit_time_hour').val(hour)
  518. $('#c-limit_time_minute').val(minute)
  519. }
  520. let configs_val = $('#c-configs').val()
  521. console.log('configs_val', configs_val)
  522. const config_json = configs_val && typeof configs_val === 'string' ? JSON.parse(configs_val) : {}
  523. if (config_json && config_json.cate_ids) {
  524. for (const key in config_json) {
  525. if (key === 'all') {
  526. $('.span_quantity').text(config_json.all.quantity)
  527. $('.span_total_score').text(config_json.all.total_score)
  528. } else {
  529. const kind_config = config_json[key]
  530. $('.input_count[data-type="' + key + '"]').val(kind_config['count'])
  531. $('.input_score[data-type="' + key + '"]').val(kind_config['score'])
  532. $('.span_' + key + '_total_score').text(kind_config['total_score'])
  533. if (kind_config['use_difficulty'] === true) {
  534. $('.checkbox_' + key).click()
  535. const difficulty_config = kind_config['difficulty']
  536. for (const k in difficulty_config) {
  537. let difficulty_count = difficulty_config[k].count ? difficulty_config[k].count : 0
  538. let difficulty_score = difficulty_config[k].score ? difficulty_config[k].score : 0
  539. let difficulty_total_score = difficulty_count * difficulty_score
  540. $('.input_' + key + '_' + k).val(difficulty_count)
  541. $('.input_' + key + '_' + k + '_score').val(difficulty_score)
  542. $('.span_' + key + '_' + k + '_total_score').text(difficulty_total_score)
  543. }
  544. }
  545. }
  546. }
  547. // 触发计算
  548. // $($('.ul_judge_difficulty').find('.input_count')[0]).trigger('change')
  549. }
  550. },
  551. // 限定时间事件,59分转小时
  552. bindTime() {
  553. $('#c-limit_time_minute').change(function (ele) {
  554. let minute = $(this).val()
  555. if (minute >= 60) {
  556. $('#c-limit_time_minute').val(0)
  557. let hour_ctrl = $('#c-limit_time_hour')
  558. hour_ctrl.val(parseInt(hour_ctrl.val()) + 1)
  559. }
  560. })
  561. },
  562. // 绑定固定选题配置按钮事件
  563. bindFixButton() {
  564. $('.btn-fix-configs').click(function () {
  565. Fast.api.open('exam/question/select', '选择试题', {
  566. area: ['90%', '90%'],
  567. callback: function (data) {
  568. if (!data) {
  569. return
  570. }
  571. }
  572. })
  573. });
  574. },
  575. // 秒数转时分秒格式
  576. formatDuring (second) {
  577. var hours = parseInt((second % (60 * 60 * 24)) / (60 * 60));
  578. var minutes = parseInt((second % (60 * 60)) / (60));
  579. var seconds = (second % (60));
  580. return hours + "时 " + minutes + "分 " + seconds + "秒";
  581. },
  582. // 获取数字值
  583. formatVal (val) {
  584. return isNaN(val) ? 0 : val
  585. },
  586. }
  587. };
  588. return Controller;
  589. });