report-config.f7.html 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. <template>
  2. <div class="page" data-name="home-report-config">
  3. <div class="iimt-top-container iimt-hexpand">
  4. <div class="home-patient-data-grid" style="flex-direction: row; width: calc(100% - 32px); padding-bottom: 0px; height: calc(100% - 16px);">
  5. <div class="iimt-frame" style="height: calc(100% - 240px - 180px - 16px);">
  6. <div class="title"><span>{{js "global.tr[global.lang].report.picSettings"}}</span></div>
  7. <div class="content" style="margin-top:8px; flex-direction: col; justify-content: flex-start; align-items: flex-start;">
  8. <div class="flex row" style="width:100%; height:100%;">
  9. <div class="flex row" style="width:35%; height:100%;">
  10. <div class="flex row centerh" style="width: 100%; height: calc(100% - 16px);">
  11. <canvas id="canvas-right" style="margin-right: 32px;">
  12. </canvas>
  13. <div id="thumb-right" class="flex column" style="flex-wrap:nowrap; height:100%; width:120px; justify-content: flex-start; background-color:#eee; overflow-x: hidden; overflow-y: scroll;">
  14. {{#each media}}
  15. {{#js_if "this.side=='right'"}}
  16. {{#js_if "this.metrics.fps"}}
  17. {{#js_if "this.filename.indexOf('.dicom')===-1"}}
  18. <a href="#" @click="selectMedia('{{ID}}', 'right')" class="report-media" id="{{ID}}"><video style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename"}}"></video></a>
  19. {{else}}
  20. <a href="#" @click="selectMedia('{{ID}}', 'right')" class="report-media" id="{{ID}}"><video style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename.replace('.dicom','.mp4')"}}"></video></a>
  21. {{/js_if}}
  22. {{else}}
  23. {{#js_if "this.filename.indexOf('.dicom')===-1"}}
  24. <a href="#" @click="selectMedia('{{ID}}', 'right')" class="report-media" id="{{ID}}"><img style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename"}}"></a>
  25. {{else}}
  26. <a href="#" @click="selectMedia('{{ID}}', 'right')" class="report-media" id="{{ID}}"><img style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename.replace('.dicom','.jpeg')"}}"></a>
  27. {{/js_if}}
  28. {{/js_if}}
  29. {{/js_if}}
  30. {{/each}}
  31. </div>
  32. </div>
  33. </div>
  34. <div class="flex column" style="justify-content: space-around; align-items: center; width:30%; height: 100%;">
  35. <span>{{patient.firstname}} {{patient.lastname}}</span>
  36. <div class="flex column">
  37. <a href="#" @click="report2" class="button iimt-button disabled" style="margin-bottom:16px;" id="report-2">{{js "global.tr[global.lang].report.imtReport"}}</a>
  38. <a href="#" @click="report6" class="button iimt-button" id="report-6">{{js "global.tr[global.lang].report.sixReport"}}</a>
  39. </div>
  40. <div class="flex column" style="align-items: center;">
  41. <span>{{js "global.tr[global.lang].report.abacusSelection"}}</span>
  42. <div class="list no-hairlines-md" style="margin:0;">
  43. <ul>
  44. <li class="item-content item-input">
  45. <div class="item-inner">
  46. <div class="item-input-wrap input-dropdown-wrap">
  47. <select id="abacus">
  48. <option value="PARC" {{js "(lang=='fr')?'selected':''"}}>{{js "global.tr[global.lang].report.PARC"}}</option>
  49. <option value="ARIC_CAUCASIAN" {{js "(lang=='en' && this.patient.race=='white')?'selected':''"}}>{{js "global.tr[global.lang].report.ARIC_CAUCASIAN"}}</option>
  50. <option value="ARIC_AFRICAN" {{js "(lang=='en' && this.patient.race=='african')?'selected':''"}}>{{js "global.tr[global.lang].report.ARIC_AFRICAN"}}</option>
  51. </select>
  52. </div>
  53. </div>
  54. </li>
  55. </ul>
  56. </div>
  57. </div>
  58. </div>
  59. <div class="flex row" style="width:35%; height:100%;">
  60. {{#js_if "this.area!='abdo'"}}
  61. <div class="flex row centerh" style="width: 100%; height: calc(100% - 16px);">
  62. <div id="thumb-left" class="flex column" style="flex-wrap:nowrap; height:100%; width:120px; justify-content: flex-start; background-color:#eee; overflow-x: hidden; overflow-y: scroll;">
  63. {{#each media}}
  64. {{#js_if "this.side=='left'"}}
  65. {{#js_if "this.metrics.fps"}}
  66. {{#js_if "this.filename.indexOf('.dicom')===-1"}}
  67. <a href="#" @click="selectMedia('{{ID}}', 'left')" class="report-media" id="{{ID}}"><video style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename"}}"></video></a>
  68. {{else}}
  69. <a href="#" @click="selectMedia('{{ID}}', 'left')" class="report-media" id="{{ID}}"><video style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename.replace('.dicom','.mp4')"}}"></video></a>
  70. {{/js_if}}
  71. {{else}}
  72. {{#js_if "this.filename.indexOf('.dicom')===-1"}}
  73. <a href="#" @click="selectMedia('{{ID}}', 'left')" class="report-media" id="{{ID}}"><img style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename"}}"></a>
  74. {{else}}
  75. <a href="#" @click="selectMedia('{{ID}}', 'left')" class="report-media" id="{{ID}}"><img style="width:92px; padding:4px;" src="{{js "app.data.config.storageBaseURL+'/media/'+app.data.patient.visitID+'/'+this.filename.replace('.dicom','.jpeg')"}}"></a>
  76. {{/js_if}}
  77. {{/js_if}}
  78. {{/js_if}}
  79. {{/each}}
  80. </div>
  81. <canvas id="canvas-left" style="margin-left: 32px;">
  82. </canvas>
  83. </div>
  84. {{/js_if}}
  85. </div>
  86. </div>
  87. </div>
  88. </div>
  89. <div class="iimt-frame" style="height: 240px;">
  90. <div class="title"><span>{{js "global.tr[global.lang].report.repSettings"}}</span></div>
  91. <div class="content" style="margin-top:8px; flex-direction: col; justify-content: flex-start; align-items: flex-start;">
  92. <div style="width: 100%; height: auto; display: flex; flex-shrink: 1; flex-direction: row;">
  93. <div class="list no-hairlines-md" style="width: 50%; margin:0;">
  94. <ul>
  95. <li class="item-content item-input">
  96. <div class="item-media">
  97. <i class="icon demo-list-icon"></i>
  98. </div>
  99. <div class="item-inner">
  100. <div class="item-title item-label">{{js "global.tr[global.lang].report.indications"}}</div>
  101. <div class="item-input-wrap">
  102. <textarea id="indications" placeholder="{{js "global.tr[global.lang].report.indications"}}" style="height: 70px;"></textarea>
  103. </div>
  104. </div>
  105. </li>
  106. <li class="item-content item-input">
  107. <div class="item-media">
  108. <i class="icon demo-list-icon"></i>
  109. </div>
  110. <div class="item-inner">
  111. <div class="item-title item-label">{{js "global.tr[global.lang].report.clinical"}}</div>
  112. <div class="item-input-wrap">
  113. <textarea id="clinical" placeholder="{{js "global.tr[global.lang].report.clinical"}}" style="height: 70px;"></textarea>
  114. </div>
  115. </div>
  116. </li>
  117. </ul>
  118. </div>
  119. <div class="list no-hairlines-md" style="width: 50%; margin:0;">
  120. <ul>
  121. <li class="item-content item-input">
  122. <div class="item-media">
  123. <i class="icon demo-list-icon"></i>
  124. </div>
  125. <div class="item-inner">
  126. <div class="item-title item-label">{{js "global.tr[global.lang].report.report"}}</div>
  127. <div class="item-input-wrap">
  128. <textarea id="report" placeholder="{{js "global.tr[global.lang].report.report"}}" style="height: 170px;"></textarea>
  129. </div>
  130. </div>
  131. </li>
  132. </div>
  133. </div>
  134. </div>
  135. </div>
  136. <div style="width: 100%; height: calc(164px - 16px); display: flex; flex-shrink: 1; flex-direction: row; margin-top: 16px;">
  137. <div class="iimt-frame" style="height: auto; margin-right:8px;">
  138. <div class="title"><span>{{js "global.tr[global.lang].report.recipients"}}</span></div>
  139. <div class="content" style="margin-top:0px; flex-direction: row; justify-content: flex-start; align-items: flex-start; padding:0px;">
  140. <div class="flex column centerh" style="width:calc(50% - 32px); margin-left:16px; margin-right:16px;">
  141. <div class="list inline-labels no-hairlines-md" style="margin:0;">
  142. <ul>
  143. <li class="item-content item-input">
  144. <div class="item-inner">
  145. <div class="item-input-wrap">
  146. <input type="email" placeholder="{{js "global.tr[global.lang].form.email"}}" id="email-input">
  147. </div>
  148. </div>
  149. </li>
  150. </ul>
  151. </div>
  152. <a href="#" class="button iimt-button" style="width: 100px;" @click="addEmail">{{js "global.tr[global.lang].report.add"}}</a>
  153. </div>
  154. <div class="flex column" style="width:calc(50% - 32px); height:100%; margin-left:16px; margin-right:16px;">
  155. <div class="list simple-list no-hairlines-md" style="margin:0; overflow-y: scroll; height: 140px; overflow-x: hidden;" id="email-list">
  156. <ul>
  157. </ul>
  158. </div>
  159. </div>
  160. </div>
  161. </div>
  162. <div class="iimt-frame" style="height: auto; margin-left:8px; width:500px;">
  163. <div class="title"><span>{{js "global.tr[global.lang].report.generate"}}</span></div>
  164. <div class="content" style="margin-top:8px; flex-direction: row; justify-content: space-around; align-items: center;">
  165. <a href="#" id="downloadLink" class="flex column" style="align-items: center;" @click="downloadReport">
  166. <img src="static/images/PDF.png" style="width:50px; height:50px;">
  167. <span>{{js "global.tr[global.lang].report.download"}}</span>
  168. </a>
  169. <a href="#" id="sendLink" class="flex column" style="align-items: center;" @click="send">
  170. <img src="static/images/send.png" style="width:50px; height:50px;">
  171. <span>{{js "global.tr[global.lang].report.send"}}</span>
  172. </a>
  173. </div>
  174. </div>
  175. </div>
  176. </div>
  177. </div>
  178. </div>
  179. </template>
  180. <script>
  181. export default {
  182. on: {
  183. pageInit: function() {
  184. this.reportType = 2;
  185. this.media6 = {
  186. right: [],
  187. left: []
  188. }
  189. let that = this;
  190. let ch = parseInt($$('#thumb-right').height());
  191. let cw = parseInt(ch * 209 / 466);
  192. let leftLoaded = false, rightLoaded = false;
  193. // canvas right
  194. {
  195. $$('#canvas-right').css({'width': cw+'px'});
  196. $$('#canvas-right').attr('width', cw);
  197. $$('#canvas-right').attr('height', ch);
  198. let ctx = $$('#canvas-right')[0].getContext('2d');
  199. let bkgR = new Image();
  200. bkgR.onload=function() {
  201. ctx.drawImage(bkgR, 0, 0, cw, ch);
  202. for(let i=0; i<that.media.length; i++) {
  203. if(that.media[i].side=='right') {
  204. let src = 'static/images/area_'+that.area+'_'+(that.media[i].side=='right'?'R':(that.media[i].side=='left'?'L':''))+'_'+that.media[i].location+'_alpha.png';
  205. let locImage = new Image();
  206. locImage.onload=function() {
  207. ctx.drawImage(locImage, 0, 0, cw, ch);
  208. }
  209. locImage.src = src;
  210. }
  211. }
  212. rightLoaded = true;
  213. if(leftLoaded) {
  214. that.postInit();
  215. }
  216. }
  217. bkgR.src = 'static/images/area_'+that.area+'_R'+'.png';
  218. }
  219. // canvas left
  220. if(this.area!='abdo')
  221. {
  222. $$('#canvas-left').css({'width': cw+'px'});
  223. $$('#canvas-left').attr('width', cw);
  224. $$('#canvas-left').attr('height', ch);
  225. let ctx = $$('#canvas-left')[0].getContext('2d');
  226. let bkgL = new Image();
  227. bkgL.onload=function() {
  228. ctx.drawImage(bkgL, 0, 0, cw, ch);
  229. for(let i=0; i<that.media.length; i++) {
  230. if(that.media[i].side=='left') {
  231. let src = 'static/images/area_'+that.area+'_'+(that.media[i].side=='right'?'R':(that.media[i].side=='left'?'L':''))+'_'+that.media[i].location+'_alpha.png';
  232. let locImage = new Image();
  233. locImage.onload=function() {
  234. ctx.drawImage(locImage, 0, 0, cw, ch);
  235. }
  236. locImage.src = src;
  237. }
  238. }
  239. leftLoaded = true;
  240. if(rightLoaded) {
  241. that.postInit();
  242. }
  243. }
  244. bkgL.src = 'static/images/area_'+that.area+'_L'+'.png';
  245. }
  246. // emails
  247. for(let i=0; i<this.recipient.length; ++i) {
  248. this.addEmailToList(this.recipient[i].email, this.recipient[i].ID);
  249. }
  250. },
  251. pageBeforeOut: function() {
  252. }
  253. },
  254. methods: {
  255. postInit: function() {
  256. console.log("postInit");
  257. this.foundRightIMTfar = false;
  258. this.foundLeftIMTfar = false;
  259. for(let i=0; i<this.media.length; i++) {
  260. if(this.media[i].side=='left') {
  261. if(!this.foundLeftIMTfar) {
  262. for(let m=0;m<this.media[i].measure.length;m++) {
  263. if(this.media[i].measure[m].type=='imt' && this.media[i].measure[m].computation.nearWall==false) {
  264. this.foundLeftIMTfar=this.media[i].ID;
  265. $$('.report-media[id="'+this.foundLeftIMTfar+'"]').addClass('active');
  266. }
  267. }
  268. }
  269. }
  270. if(this.media[i].side=='right') {
  271. if(!this.foundRightIMTfar) {
  272. for(let m=0;m<this.media[i].measure.length;m++) {
  273. if(this.media[i].measure[m].type=='imt' && this.media[i].measure[m].computation.nearWall==false) {
  274. this.foundRightIMTfar=this.media[i].ID;
  275. $$('.report-media[id="'+this.foundRightIMTfar+'"]').addClass('active');
  276. }
  277. }
  278. }
  279. }
  280. }
  281. console.log("foundRightIMTfar", this.foundRightIMTfar);
  282. console.log("foundLeftIMTfar", this.foundLeftIMTfar);
  283. if(this.reportType == 2 && (!this.foundRightIMTfar || !this.foundLeftIMTfar)) {
  284. this.notReadyNotif();
  285. return;
  286. }
  287. },
  288. notReadyNotif: function() {
  289. app.notification.create({
  290. icon: '<i class="icon material-icons">info</i>',
  291. title: global.tr[global.lang].topLevel.notification.title,
  292. text: global.tr[global.lang].topLevel.warning.report_missing_data,
  293. closeTimeout: 3000,
  294. closeButton: true,
  295. }).open();
  296. },
  297. selectMedia: function(ID, side) {
  298. console.log(ID, side);
  299. if(this.reportType == 2) {
  300. $$('#thumb-'+side+' a').removeClass('active');
  301. if(side=='left') {
  302. this.foundLeftIMTfar=false;
  303. }
  304. else if(side=='right') {
  305. this.foundRightIMTfar=false;
  306. }
  307. for(let i=0; i<this.media.length; i++) {
  308. for(let m=0;m<this.media[i].measure.length;m++) {
  309. if(this.media[i].ID == ID && this.media[i].measure[m].type=='imt' && this.media[i].measure[m].computation.nearWall==false) {
  310. if(this.media[i].side=='left') {
  311. this.foundLeftIMTfar = ID;
  312. $$('.report-media[id="'+ID+'"]').addClass('active');
  313. break;
  314. }
  315. else if(this.media[i].side=='right') {
  316. this.foundRightIMTfar = ID;
  317. $$('.report-media[id="'+ID+'"]').addClass('active');
  318. break;
  319. }
  320. }
  321. }
  322. }
  323. console.log("foundRightIMTfar", this.foundRightIMTfar);
  324. console.log("foundLeftIMTfar", this.foundLeftIMTfar);
  325. if(!this.foundRightIMTfar || !this.foundLeftIMTfar) {
  326. this.notReadyNotif();
  327. return;
  328. }
  329. }
  330. else {
  331. if(side=='right') {
  332. let found = false;
  333. if($$('.report-media[id="'+ID+'"]').hasClass('active')) {
  334. for(let i=0; i<this.media6.right.length; i++) {
  335. if(this.media6.right[i]==ID) {
  336. this.media6.right.splice(i,1);
  337. found = true;
  338. break;
  339. }
  340. }
  341. }
  342. if(!found) {
  343. this.media6.right.push(ID);
  344. }
  345. if(this.media6.right.length==4) {
  346. this.media6.right.splice(0,1);
  347. }
  348. $$('#thumb-right a').removeClass('active');
  349. for(let i=0; i<this.media6.right.length; i++) {
  350. $$('.report-media[id="'+this.media6.right[i]+'"]').addClass('active');
  351. }
  352. }
  353. else if(side=='left') {
  354. let found = false;
  355. if($$('.report-media[id="'+ID+'"]').hasClass('active')) {
  356. for(let i=0; i<this.media6.left.length; i++) {
  357. if(this.media6.left[i]==ID) {
  358. this.media6.left.splice(i,1);
  359. found = true;
  360. break;
  361. }
  362. }
  363. }
  364. if(!found) {
  365. this.media6.left.push(ID);
  366. }
  367. if(this.media6.left.length==4) {
  368. this.media6.left.splice(0,1);
  369. }
  370. $$('#thumb-left a').removeClass('active');
  371. for(let i=0; i<this.media6.left.length; i++) {
  372. $$('.report-media[id="'+this.media6.left[i]+'"]').addClass('active');
  373. }
  374. }
  375. }
  376. },
  377. report2: function() {
  378. $$('#report-2').addClass('disabled');
  379. $$('#report-6').removeClass('disabled');
  380. this.reportType = 2;
  381. $$('#thumb-right a').removeClass('active');
  382. $$('#thumb-left a').removeClass('active');
  383. this.postInit();
  384. },
  385. report6: function() {
  386. this.media6.right = [];
  387. this.media6.left = [];
  388. $$('#report-6').addClass('disabled');
  389. $$('#report-2').removeClass('disabled');
  390. this.reportType = 6;
  391. $$('#thumb-right a').removeClass('active');
  392. $$('#thumb-left a').removeClass('active');
  393. },
  394. addEmail: function() {
  395. let that = this;
  396. let email = $$('#email-input').val();
  397. if(email=='') {
  398. return;
  399. }
  400. let data = {
  401. email: email,
  402. apiKey: ''
  403. };
  404. app.preloader.show();
  405. app.request.post(app.data.config.apiBaseURL + '/report/mail-add/', data, function (data) {
  406. console.log('report/mail-add', data);
  407. app.preloader.hide();
  408. if (data.result == 'ERROR') {
  409. switch (data.reason) {
  410. case 'denied':
  411. app.methods.signout(global.tr[global.lang].topLevel.warning.disconnected);
  412. break;
  413. default:
  414. app.dialog.alert(global.tr[global.lang].topLevel.error.internal_error);
  415. break;
  416. }
  417. }
  418. else {
  419. that.addEmailToList(email, data.ID);
  420. }
  421. }, function (data) {
  422. console.log('error', data);
  423. }, 'json');
  424. },
  425. addEmailToList: function(email, ID) {
  426. $$('#email-list').append(
  427. '<li style="padding:0;" id="email-'+ID+'">'+
  428. '<div class="item-content" style="width: 100%;">'+
  429. '<div class="item-media">'+
  430. '<label class="toggle">'+
  431. '<input class="activeRecipient" type="checkbox" data-email="'+email+'">'+
  432. '<span class="toggle-icon"></span>'+
  433. '</label>'+
  434. '</div>'+
  435. '<div class="item-inner">'+
  436. '<div class="item-title">'+email+'</div>'+
  437. '<div class="item-after"><a href="#" class="button iimt-button" data-email="'+email+'">'+global.tr[global.lang].report.delete+'</a></div>'+
  438. '</div>'+
  439. '</div>'+
  440. '</li>'
  441. );
  442. $$('#email-input').val('');
  443. $$('#email-list li a').on('click', function(e) {
  444. let data = {
  445. ID: ID,
  446. apiKey: ''
  447. };
  448. app.preloader.show();
  449. app.request.post(app.data.config.apiBaseURL + '/report/mail-delete/', data, function (data) {
  450. console.log('report/mail-delete', data);
  451. app.preloader.hide();
  452. if (data.result == 'ERROR') {
  453. switch (data.reason) {
  454. case 'denied':
  455. app.methods.signout(global.tr[global.lang].topLevel.warning.disconnected);
  456. break;
  457. default:
  458. app.dialog.alert(global.tr[global.lang].topLevel.error.internal_error);
  459. break;
  460. }
  461. }
  462. else {
  463. $$('#email-'+ID).remove();
  464. }
  465. }, function (data) {
  466. console.log('error', data);
  467. }, 'json');
  468. });
  469. },
  470. getSelectedMedia: function() {
  471. let mediaList = [];
  472. if(this.reportType == 2) {
  473. mediaList.push(this.foundRightIMTfar);
  474. mediaList.push(this.foundLeftIMTfar);
  475. }
  476. else if(this.reportType == 6) {
  477. mediaList = mediaList.concat(this.media6.right);
  478. mediaList = mediaList.concat(this.media6.left);
  479. }
  480. return mediaList;
  481. },
  482. sendMAIL: function(mediaList, emails) {
  483. let postData = {
  484. emails: emails,
  485. type: this.reportType,
  486. abacus: $$('#abacus').val(),
  487. indications: $$('#indications').val(),
  488. clinical: $$('#clinical').val(),
  489. report: $$('#report').val(),
  490. visitID: app.data.patient.visitID,
  491. mediaList: mediaList,
  492. lang: global.lang,
  493. subject: global.tr[global.lang].report.mailSubject,
  494. message: global.tr[global.lang].report.mailBody,
  495. apiKey: ''
  496. };
  497. app.preloader.show();
  498. app.request.post(app.data.config.apiBaseURL + '/report/pdf-mail/', postData, function (data) {
  499. console.log('report/pdf-mail', data);
  500. app.preloader.hide();
  501. if (data.result == 'ERROR') {
  502. switch (data.reason) {
  503. case 'denied':
  504. app.methods.signout(global.tr[global.lang].topLevel.warning.disconnected);
  505. break;
  506. default:
  507. app.dialog.alert(global.tr[global.lang].topLevel.error.internal_error);
  508. break;
  509. }
  510. }
  511. else {
  512. app.dialog.alert(global.tr[global.lang].topLevel.notification.mail_sent);
  513. }
  514. }, function (data) {
  515. console.log('error', data);
  516. }, 'json');
  517. },
  518. sendPACS: function(mediaList) {
  519. let postData = {
  520. type: this.reportType,
  521. abacus: $$('#abacus').val(),
  522. indications: $$('#indications').val(),
  523. clinical: $$('#clinical').val(),
  524. report: $$('#report').val(),
  525. visitID: app.data.patient.visitID,
  526. mediaList: mediaList,
  527. lang: global.lang,
  528. apiKey: ''
  529. };
  530. app.preloader.show();
  531. app.request.post(app.data.config.apiBaseURL + '/report/pdf-pacs/', postData, function (data) {
  532. console.log('report/pdf-pacs', data);
  533. app.preloader.hide();
  534. if (data.result == 'ERROR') {
  535. switch (data.reason) {
  536. case 'denied':
  537. app.methods.signout(global.tr[global.lang].topLevel.warning.disconnected);
  538. break;
  539. default:
  540. app.dialog.alert(global.tr[global.lang].topLevel.error.internal_error);
  541. break;
  542. }
  543. }
  544. else {
  545. app.dialog.alert(global.tr[global.lang].topLevel.notification.pacs_sent);
  546. }
  547. }, function (data) {
  548. console.log('error', data);
  549. }, 'json');
  550. },
  551. send: function() {
  552. if(this.reportType == 2 && (!this.foundRightIMTfar || !this.foundLeftIMTfar)) {
  553. this.notReadyNotif();
  554. return;
  555. }
  556. if(this.reportType == 6 && !(this.media6.right.length==3 && this.media6.left.length==3)) {
  557. this.notReadyNotif();
  558. return;
  559. }
  560. let mediaList = this.getSelectedMedia();
  561. let that = this;
  562. let buttons = [];
  563. let buttonsAction = [];
  564. if(this.pacs && this.pacs.serverAddress != '') {
  565. buttons.push({text: 'PACS: '+this.pacs.serverAddress});
  566. buttonsAction.push('pacs');
  567. }
  568. let emails = [];
  569. for(let i=0; i<$$('.activeRecipient:checked').length; i++) {
  570. emails.push($$($$('.activeRecipient:checked')[i]).data('email'));
  571. }
  572. let nbrcp = $$('.activeRecipient:checked').length;
  573. if(nbrcp > 0) {
  574. buttons.push({text: 'E-mail: '+nbrcp+' selected'});
  575. buttonsAction.push('email');
  576. }
  577. if(!buttons.length) {
  578. app.dialog.alert(global.tr[global.lang].topLevel.warning.noRecipientNoPacs);
  579. }
  580. else {
  581. if(buttons.length==2) {
  582. buttons.push({text: 'E-mail & PACS'});
  583. buttonsAction.push('both');
  584. }
  585. buttons.push({text: global.tr[global.lang].topLevel.cancel});
  586. app.dialog.create({
  587. title: global.tr[global.lang].report.sendReport,
  588. text: null,
  589. buttons: buttons,
  590. onClick: function (dialog, index) {
  591. if(buttonsAction[index]=='pacs') {
  592. that.sendPACS(mediaList);
  593. }
  594. else if(buttonsAction[index]=='email') {
  595. that.sendMAIL(mediaList, emails);
  596. }
  597. else if(buttonsAction[index]=='both') {
  598. that.sendPACS(mediaList);
  599. that.sendMAIL(mediaList, emails);
  600. }
  601. },
  602. verticalButtons: true,
  603. }).open();
  604. }
  605. },
  606. downloadReport: function() {
  607. if(this.reportType == 2 && (!this.foundRightIMTfar || !this.foundLeftIMTfar)) {
  608. this.notReadyNotif();
  609. return;
  610. }
  611. if(this.reportType == 6 && !(this.media6.right.length==3 && this.media6.left.length==3)) {
  612. this.notReadyNotif();
  613. return;
  614. }
  615. let mediaList = this.getSelectedMedia();
  616. console.log('mediaList', mediaList);
  617. let postData = {
  618. type: this.reportType,
  619. abacus: $$('#abacus').val(),
  620. indications: $$('#indications').val(),
  621. clinical: $$('#clinical').val(),
  622. report: $$('#report').val(),
  623. visitID: app.data.patient.visitID,
  624. mediaList: mediaList,
  625. lang: global.lang,
  626. apiKey: ''
  627. };
  628. app.preloader.show();
  629. app.request.post(app.data.config.apiBaseURL + '/report/pdf-download/', postData, function (data) {
  630. console.log('report/pdf-download', data);
  631. app.preloader.hide();
  632. if (data.result == 'ERROR') {
  633. switch (data.reason) {
  634. case 'denied':
  635. app.methods.signout(global.tr[global.lang].topLevel.warning.disconnected);
  636. break;
  637. default:
  638. app.dialog.alert(global.tr[global.lang].topLevel.error.internal_error);
  639. break;
  640. }
  641. }
  642. else {
  643. //app.dialog.alert(global.tr[global.lang].report.password+'<h3>'+data.password+'</h3>');
  644. // convert data
  645. const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
  646. const byteCharacters = atob(b64Data);
  647. const byteArrays = [];
  648. for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
  649. const slice = byteCharacters.slice(offset, offset + sliceSize);
  650. const byteNumbers = new Array(slice.length);
  651. for (let i = 0; i < slice.length; i++) {
  652. byteNumbers[i] = slice.charCodeAt(i);
  653. }
  654. const byteArray = new Uint8Array(byteNumbers);
  655. byteArrays.push(byteArray);
  656. }
  657. const blob = new Blob(byteArrays, {type: contentType});
  658. return blob;
  659. }
  660. const blob = b64toBlob(data.base64, "application/pdf");
  661. const blobUrl = window.URL.createObjectURL(blob);
  662. // Create an invisible A element
  663. const a = document.createElement("a");
  664. a.style.display = "none";
  665. document.body.appendChild(a);
  666. // Set the HREF to a Blob representation of the data to be downloaded
  667. a.href = blobUrl;/*window.URL.createObjectURL(
  668. new Blob([data], { type })
  669. );*/
  670. // Use download attribute to set set desired file name
  671. a.setAttribute("download", data.filename);
  672. a.setAttribute("class", "link external");
  673. a.setAttribute("target", "_blank");
  674. // Trigger the download by simulating click
  675. a.click();
  676. // Cleanup
  677. window.URL.revokeObjectURL(a.href);
  678. document.body.removeChild(a);
  679. }
  680. }, function (data) {
  681. console.log('error', data);
  682. }, 'json');
  683. }
  684. }
  685. }
  686. </script>