mark-control.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. function MarkControl(option) {
  2. this.option = option;
  3. this.maxPrefetchCount = parseInt(option.prefetchCount);
  4. this.maxPrefetchCount = this.maxPrefetchCount != undefined && this.maxPrefetchCount > 2 ? this.maxPrefetchCount : 2;
  5. this.container = option.container;
  6. this.context = {
  7. imageServer: option.imageServer,
  8. staticServer: option.staticServer,
  9. isFinish: false,
  10. prefetching: false,
  11. prefetchTask: []
  12. };
  13. //初始化容器结构
  14. this.initContainer();
  15. //初始化事件监听
  16. this.initTriggers(option);
  17. //初始化功能模块
  18. this.initModules(option);
  19. //初始化成功回调方法
  20. //console.log('MarkControl init success!');
  21. //if (option.success != undefined && typeof(option.success) == 'function') {
  22. // option.success();
  23. //}
  24. }
  25. MarkControl.prototype.initContainer = function() {
  26. var height = this.option.height;
  27. if (height == undefined) {
  28. height = $(window).height();
  29. }
  30. this.container = getDom(this.main_row_dom, this).appendTo(this.container);
  31. if (this.option.enableSidear != false) {
  32. this.container.sidebar = getDom(this.sidebar_dom, this).appendTo(this.container);
  33. this.container.sidebar.css('max-height', height);
  34. }
  35. this.container.center = getDom(this.center_dom, this).appendTo(this.container);
  36. this.container.header = getDom(this.center_header_dom, this).appendTo(this.container.center).find('.header');
  37. this.container.centerContent = getDom(this.center_content_dom, this).appendTo(this.container.center);
  38. this.container.imageContent = getDom(this.image_content_dom, this).appendTo(this.container.centerContent);
  39. this.container.height(height);
  40. this.container.centerContent.css('height', height - this.container.header.parent().height());
  41. this.initHeaderAndAssistant();
  42. }
  43. MarkControl.prototype.initHeaderAndAssistant = function() {
  44. var self = this;
  45. this.container.header.find('#mark-user-name').html(this.option.userName);
  46. if (this.option.logoutTitle != undefined) {
  47. this.container.header.find('#logout-title').html(this.option.logoutTitle);
  48. }
  49. this.container.header.find('#logout-link').click(function() {
  50. self.trigger('logout.link.click');
  51. return true;
  52. })
  53. this.container.assistant = getDom(this.assistant_dom, this).appendTo(this.container);
  54. this.container.assistant.positionSet = false;
  55. this.container.assistantButton = this.container.header.find('#assistant-button');
  56. this.container.assistantButton.click(this, function(event) {
  57. if (self.container.assistant.positionSet == false) {
  58. self.container.assistant.offset({
  59. top: self.container.assistantButton.position().top + self.container.assistantButton.height() + 5,
  60. left: self.container.assistantButton.position().left - 85
  61. });
  62. self.container.assistant.positionSet = true;
  63. }
  64. self.container.assistant.toggle();
  65. });
  66. }
  67. MarkControl.prototype.initMarkFunction = function() {
  68. var functionList = this.container.assistant.functionList;
  69. if (functionList == undefined) {
  70. functionList = getDom(this.mark_function_dom, this).appendTo(this.container.assistant).find('#function-list');
  71. this.container.assistant.functionList = functionList;
  72. }
  73. }
  74. //增加某个事件的监听方法
  75. MarkControl.prototype.on = function(eventName, caller, callback, async) {
  76. if (eventName && callback && eventName.length > 0 && typeof(callback) == 'function') {
  77. if (async) {
  78. this.container.bind(eventName, callback);
  79. } else {
  80. if (this.triggers[eventName] == undefined) {
  81. this.triggers[eventName] = new Array();
  82. }
  83. this.triggers[eventName].push({
  84. caller: caller,
  85. callback: callback
  86. });
  87. }
  88. }
  89. }
  90. //触发某个事件,并传递事件相关内容
  91. MarkControl.prototype.trigger = function(eventName, eventObject) {
  92. var result = true;
  93. if (eventName && eventName.length > 0) {
  94. var array = this.triggers[eventName];
  95. if (array != undefined && array.length > 0) {
  96. var event = {
  97. name: eventName
  98. }
  99. for (var i in array) {
  100. result = result & array[i].callback.call(array[i].caller, event, this.context, eventObject);
  101. }
  102. }
  103. this.container.trigger(eventName, this.context, eventObject);
  104. }
  105. return result;
  106. }
  107. //初始化事件监听
  108. MarkControl.prototype.initTriggers = function(option) {
  109. if (this.triggers == undefined) {
  110. this.triggers = {};
  111. }
  112. if (option != undefined && option.on != undefined) {
  113. for (var name in option.on) {
  114. this.on(name, option.on[name]);
  115. }
  116. }
  117. var self = this;
  118. this.on('view.sidebar.open', this, function(event, context, eventObject) {
  119. this.container.assistant.hide();
  120. if (this.container.center.hasClass('span12')) {
  121. this.container.center.removeClass('span12');
  122. this.container.center.addClass('span7');
  123. } else if (this.container.center.hasClass('span10')) {
  124. this.container.center.removeClass('span10');
  125. this.container.center.addClass('span5');
  126. }
  127. this.trigger('center.width.change');
  128. });
  129. this.on('view.sidebar.close', this, function(event, context, eventObject) {
  130. this.container.assistant.hide();
  131. if (this.container.center.hasClass('span7')) {
  132. this.container.center.removeClass('span7');
  133. this.container.center.addClass('span12');
  134. } else if (this.container.center.hasClass('span5')) {
  135. this.container.center.removeClass('span5');
  136. this.container.center.addClass('span10');
  137. }
  138. this.trigger('center.width.change');
  139. });
  140. this.on('mark.sidebar.open', this, function(event, context, eventObject) {
  141. this.container.assistant.hide();
  142. if (this.container.center.hasClass('span12')) {
  143. this.container.center.removeClass('span12');
  144. this.container.center.addClass('span10');
  145. } else if (this.container.center.hasClass('span7')) {
  146. this.container.center.removeClass('span7');
  147. this.container.center.addClass('span5');
  148. }
  149. this.trigger('center.width.change');
  150. });
  151. this.on('mark.sidebar.close', this, function(event, context, eventObject) {
  152. this.container.assistant.hide();
  153. if (this.container.center.hasClass('span10')) {
  154. this.container.center.removeClass('span10');
  155. this.container.center.addClass('span12');
  156. } else if (this.container.center.hasClass('span5')) {
  157. this.container.center.removeClass('span5');
  158. this.container.center.addClass('span7');
  159. }
  160. this.trigger('center.width.change');
  161. });
  162. this.on('task.get.finish', this, function(event, context, eventObject) {
  163. context.prefetchCallback = undefined;
  164. });
  165. this.on('task.get.none', this, function(event, context, eventObject) {
  166. self.getStatus();
  167. if (context.task == undefined && self.option.clearUrl != undefined) {
  168. $.post(self.option.clearUrl, {}, function() {});
  169. }
  170. context.prefetchCallback = function() {
  171. context.prefetchCallback = undefined;
  172. if (self.context.task == undefined && self.context.prefetchTask.length > 0) {
  173. self.getTask();
  174. }
  175. }
  176. });
  177. this.on('task.prefetch.success', this, function(event, context, eventObject) {
  178. if (context.prefetchCallback != undefined) {
  179. context.prefetchCallback();
  180. }
  181. setTimeout(function() {
  182. self.prefetch();
  183. }, 500);
  184. });
  185. this.on('task.prefetch.error', this, function(event, context, eventObject) {
  186. setTimeout(function() {
  187. self.prefetch();
  188. }, 500);
  189. });
  190. this.on('task.prefetch.none', this, function(event, context, eventObject) {
  191. if (context.prefetchCallback != undefined) {
  192. context.prefetchCallback();
  193. }
  194. if (context.isFinish != true) {
  195. setTimeout(function() {
  196. self.prefetch();
  197. }, 1000);
  198. }
  199. });
  200. this.on('task.prefetch.finish', this, function(event, context, eventObject) {
  201. self.getTask();
  202. });
  203. this.on('task.submit.before', this, function(event, context, eventObject) {
  204. context.submitting = true;
  205. });
  206. this.on('task.submit.success', this, function(event, context, eventObject) {
  207. context.submitting = false;
  208. context.task = undefined;
  209. self.getTask();
  210. });
  211. this.on('task.submit.error', this, function(event, context, eventObject) {
  212. context.submitting = false;
  213. });
  214. this.on('task.pass.success', this, function(event, context, eventObject) {
  215. if (context.task != undefined && self.option.clearUrl != undefined) {
  216. $.post(self.option.clearUrl, {
  217. libraryId: context.task.libraryId
  218. });
  219. }
  220. context.task = undefined;
  221. self.getTask();
  222. });
  223. this.on('task.load.finish', this, function(event, context, eventObject) {
  224. var timestamp = new Date().getTime();
  225. context.task.spent = timestamp;
  226. });
  227. this.on('task.submit.forceSpecialTag', this, function(event, context, eventObject) {
  228. });
  229. $(document).keypress(this, function(event) {
  230. if (self.context.listenKeyboard != false) {
  231. return self.trigger('key.press', event);
  232. }
  233. });
  234. $(document).keydown(this, function(event) {
  235. if (self.context.listenKeyboard != false) {
  236. return self.trigger('key.down', event);
  237. }
  238. });
  239. $(document).keyup(this, function(event) {
  240. if (self.context.listenKeyboard != false) {
  241. return self.trigger('key.up', event);
  242. }
  243. });
  244. window.onbeforeunload = function(e) {
  245. if (self.option.clearUrl != undefined) {
  246. $.post(self.option.clearUrl);
  247. }
  248. }
  249. }
  250. //初始化功能模块
  251. MarkControl.prototype.initModules = function(option) {
  252. if (this.modules == undefined) {
  253. this.modules = {};
  254. }
  255. var names = [];
  256. var options = [];
  257. for (var name in this.defaultModules) {
  258. names.push(name);
  259. options[name] = this.defaultModules[name];
  260. }
  261. if (option.modules != undefined) {
  262. for (var name in option.modules) {
  263. if (options[name] == undefined) {
  264. names.push(name);
  265. options[name] = {};
  266. }
  267. $.extend(options[name], option.modules[name]);
  268. }
  269. }
  270. this.initModule(names, options, this.option.success);
  271. //initModule(this, names, 0, options);
  272. }
  273. //指定初始化某个名称的模块
  274. MarkControl.prototype.initModule = function(names, options, success) {
  275. for (var i in names) {
  276. var name = names[i];
  277. var option = options[name];
  278. var moduleInit = name.replace(/-/g, '_');
  279. if (option == undefined || typeof(option) != 'object') {
  280. option = {};
  281. }
  282. option.markControl = this;
  283. eval('this.modules[name]=' + moduleInit + '(option, function(){})');
  284. }
  285. if (success != undefined && typeof(success) == 'function') {
  286. success();
  287. }
  288. }
  289. function initModuleAsync(markControl, names, index, option) {
  290. if (index < names.length) {
  291. var name = names[index];
  292. var moduleOption = option[name];
  293. var moduleUrl = 'modules/' + name + '.js';
  294. var moduleInit = name.replace(/-/g, '_');
  295. var modules = markControl.modules;
  296. if (modules[name] == undefined) {
  297. if (typeof(moduleOption) != 'object') {
  298. moduleOption = {};
  299. }
  300. moduleOption.markControl = markControl;
  301. $.getScript(moduleUrl, function() {
  302. var success = function() {
  303. initModule(markControl, names, index + 1, option);
  304. }
  305. eval('modules[name]=' + moduleInit + '(moduleOption, success)');
  306. });
  307. } else {
  308. initModule(markControl, names, index + 1, option);
  309. }
  310. } else {
  311. if (markControl.option.success != undefined && typeof(markControl.option.success) == 'function') {
  312. markControl.option.success();
  313. }
  314. }
  315. }
  316. MarkControl.prototype.start = function(taskOption) {
  317. taskOption.markControl = this;
  318. var markControl = this;
  319. taskOption.success = function() {
  320. markControl.context.prefetchCallback = function() {
  321. markControl.context.prefetchCallback = undefined;
  322. markControl.getTask();
  323. }
  324. markControl.context.statusCallback = function() {
  325. markControl.context.statusCallback = undefined;
  326. markControl.prefetch();
  327. }
  328. markControl.getStatus();
  329. };
  330. taskOption.error = function(message) {
  331. alert('初始化失败,请刷新页面重新加载');
  332. };
  333. this.taskControl = new TaskControl(taskOption);
  334. this.taskControl.init();
  335. }
  336. //task预加载
  337. MarkControl.prototype.prefetch = function() {
  338. var taskControl = this.taskControl;
  339. var markControl = this;
  340. var context = this.context;
  341. var imageBuilder = this.modules['image-builder'];
  342. if (context.isFinish != true) {
  343. if (taskControl.isFinish()) {
  344. context.isFinish = true;
  345. } else if (context.prefetchTask.length >= markControl.maxPrefetchCount) {
  346. markControl.trigger('task.prefetch.success');
  347. } else if (context.prefetching == false) {
  348. context.prefetching = true;
  349. markControl.trigger('task.prefetch.before');
  350. taskControl.fetch(function(task) {
  351. if (imageBuilder != undefined) {
  352. imageBuilder.build(task, function(error) {
  353. if (error) {
  354. context.prefetching = false;
  355. markControl.trigger('task.prefetch.error');
  356. } else {
  357. context.prefetchTask.push(task);
  358. context.prefetchStatus = undefined;
  359. context.prefetching = false;
  360. markControl.trigger('task.prefetch.success');
  361. }
  362. });
  363. } else {
  364. context.prefetchTask.push(task);
  365. context.prefetchStatus = undefined;
  366. context.prefetching = false;
  367. markControl.trigger('task.prefetch.success');
  368. }
  369. }, function(task) {
  370. context.prefetchStatus = task.message;
  371. context.prefetching = false;
  372. markControl.trigger('task.prefetch.none');
  373. }, function() {
  374. context.prefetching = false;
  375. markControl.trigger('task.prefetch.none');
  376. });
  377. }
  378. } else {
  379. markControl.trigger('task.prefetch.finish');
  380. }
  381. }
  382. MarkControl.prototype.getStatus = function() {
  383. if (this.taskControl == undefined) {
  384. return;
  385. }
  386. var self = this;
  387. this.taskControl.status(function(status) {
  388. self.context.status = status;
  389. if (status != undefined) {
  390. self.context.isFinish = status.blockTotalCount > 0 && status.blockTotalCount == (status.blockMarkedCount + status.blockExceptionCount);
  391. }
  392. if (self.context.statusCallback != undefined) {
  393. self.context.statusCallback();
  394. }
  395. self.trigger('mark.status.change', status);
  396. })
  397. }
  398. MarkControl.prototype.getTask = function() {
  399. if (this.taskControl == undefined) {
  400. return;
  401. }
  402. var markControl = this;
  403. var context = this.context;
  404. markControl.trigger('task.get.before');
  405. if (context.isFinish == true) {
  406. markControl.trigger('task.get.finish');
  407. return;
  408. } else if (context.task != undefined) {
  409. markControl.trigger('task.get.success');
  410. return;
  411. } else if (context.waitTask != undefined) {
  412. //优先选择因回评等操作处于等待状态的任务
  413. context.task = context.waitTask;
  414. context.waitTask = undefined;
  415. markControl.trigger('task.get.success');
  416. } else if (context.prefetchTask.length > 0) {
  417. //判断是否有任务已预加载完毕
  418. context.task = context.prefetchTask.shift();
  419. markControl.trigger('task.get.success');
  420. } else if (context.prefetchStatus != undefined) {
  421. //判断是否有在无预加载任务的情况下的消息提示
  422. markControl.trigger('task.get.none', context.prefetchStatus);
  423. } else {
  424. markControl.trigger('task.get.none');
  425. }
  426. }
  427. MarkControl.prototype.getHistory = function(data) {
  428. if (this.taskControl == undefined) {
  429. return;
  430. }
  431. this.taskControl.history(data, function(result) {
  432. data.result = result;
  433. this.option.markControl.trigger('history.get.success', data);
  434. }, function(message) {
  435. data.message = message;
  436. this.option.markControl.trigger('history.get.error', data);
  437. });
  438. }
  439. MarkControl.prototype.setTask = function(task) {
  440. var imageBuilder = this.modules['image-builder'];
  441. var self = this;
  442. if (this.context.task != undefined && !this.context.task.previous && this.context.waitTask == undefined) {
  443. this.context.waitTask = this.context.task;
  444. }
  445. this.trigger('task.get.before');
  446. if (imageBuilder != undefined && task != undefined) {
  447. imageBuilder.build(task, function(error) {
  448. self.context.task = task;
  449. self.trigger('task.get.success');
  450. });
  451. } else {
  452. self.context.task = task;
  453. if (task != undefined) {
  454. this.trigger('task.get.success');
  455. }
  456. }
  457. }
  458. MarkControl.prototype.submitTask = function(submitUrl) {
  459. var task = this.context.task;
  460. var markControl = this;
  461. var submitUrl = submitUrl != undefined && submitUrl.length > 0 ? submitUrl : this.option.submitUrl;
  462. if (task != undefined && this.context.submitting != true) {
  463. task.markStepList = undefined;
  464. task.pictureUrls = undefined;
  465. task.sheetUrls = undefined;
  466. task.imageData = undefined;
  467. task.markFinish = undefined;
  468. task.markTime = undefined;
  469. var timestamp = new Date().getTime();
  470. task.spent = timestamp - task.spent;
  471. this.trigger('task.submit.before');
  472. //开启强制标记
  473. if(this.option.forceSpecialTag===true){
  474. console.log(task);
  475. if(task.tagList==undefined ||task.tagList==null ||task.tagList.length <= 0){
  476. return;
  477. }
  478. }
  479. if (this.taskControl != undefined) {
  480. //已定义任务引擎
  481. this.taskControl.submit(task, function(status) {
  482. if (status != undefined && status.valid == true) {
  483. markControl.context.status = status;
  484. markControl.trigger('mark.status.change', status);
  485. }
  486. //markControl.context.task = undefined;
  487. markControl.trigger('task.submit.success');
  488. markControl.trigger('mark.specialTag.success');
  489. //markControl.getTask();
  490. }, function(message) {
  491. markControl.trigger('task.submit.error', message);
  492. });
  493. } else if (submitUrl != undefined && submitUrl.length > 0) {
  494. //未定义任务引擎,依赖定义/传入的提交地址
  495. $.ajax({
  496. url: submitUrl,
  497. type: 'POST',
  498. data: task,
  499. success: function(result) {
  500. if (result.success == true) {
  501. //markControl.context.task = undefined;
  502. markControl.trigger('task.submit.success');
  503. //markControl.getTask();
  504. } else {
  505. markControl.trigger('task.submit.error', result.message);
  506. }
  507. },
  508. error: function(message) {
  509. markControl.trigger('task.submit.error', message);
  510. }
  511. });
  512. } else {
  513. markControl.trigger('task.submit.success');
  514. //markControl.getTask();
  515. }
  516. }
  517. }
  518. //默认要初始化的模块名称
  519. MarkControl.prototype.defaultModules = {
  520. 'image-builder': {}
  521. };
  522. MarkControl.prototype.main_row_dom = '<div class="row-fluid" style="background-image:url({staticServer}/mark-new/images/background.jpg)"></div>';
  523. MarkControl.prototype.sidebar_dom = '<div class="mark-sidebar span2 hide"></div>';
  524. MarkControl.prototype.center_dom = '<div class="center-content span12"></div>';
  525. MarkControl.prototype.center_header_dom = '<div class="row-fluid"><div class="header"><p class="tips">\
  526. <em><a href="/mark/index?mode=track" class="btn">切换到轨迹模式</a>\
  527. <a href="javascript:void(0)" id="assistant-button" class="btn"><i class="icon-wrench"></i> 小助手</a></em>\
  528. <a class="useinfo" href="#"><i class="icon-user icon-white"></i><i id="mark-user-name"></i></a>\
  529. <a class="logout" id="logout-link" href="{logoutUrl}"><i class="icon-off icon-white"></i> <i id="logout-title">退出</i></a>\
  530. </p></div></div>';
  531. MarkControl.prototype.center_content_dom = '<div class="row-fluid"></div>';
  532. MarkControl.prototype.image_content_dom = '<div class="image-content span12"></div>';
  533. MarkControl.prototype.assistant_dom = '<div class="popover bottom assistant"><div class="arrow"></div></div>';
  534. MarkControl.prototype.mark_function_dom = '<h3 class="popover-title">评卷功能</h3>\
  535. <div class="popover-content"><p id="function-list" class="popover-list">\
  536. </p></div>';
  537. //其他通用方法
  538. String.prototype.startWith = function(prefix) {
  539. return this.indexOf(prefix) === 0;
  540. }
  541. String.prototype.endWith = function(suffix) {
  542. return this.match(suffix + "$") == suffix;
  543. };
  544. //日期格式化
  545. Date.prototype.format = function(fmt) { //author: meizz
  546. var o = {
  547. "M+": this.getMonth() + 1, //月份
  548. "d+": this.getDate(), //日
  549. "h+": this.getHours(), //小时
  550. "m+": this.getMinutes(), //分
  551. "s+": this.getSeconds(), //秒
  552. "q+": Math.floor((this.getMonth() + 3) / 3), //季度
  553. "S": this.getMilliseconds() //毫秒
  554. };
  555. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  556. for (var k in o) {
  557. if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  558. }
  559. return fmt;
  560. }
  561. function getDom(content, markControl) {
  562. if (markControl != undefined && markControl.option.staticServer != undefined) {
  563. content = content.replace(/{staticServer}/g, markControl.option.staticServer);
  564. }
  565. if (markControl != undefined && markControl.option.logoutUrl != undefined) {
  566. content = content.replace(/{logoutUrl}/g, markControl.option.logoutUrl);
  567. }
  568. return $(content);
  569. }
  570. function isArray(obj) {
  571. return obj != undefined && Object.prototype.toString.call(obj) === '[object Array]';
  572. }