record.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. 'use strict';
  2. const Const = require("../const");
  3. const RoleNames = Const.RoleNames;
  4. const VehicleNames = Const.VehicleNames;
  5. const WeaponNames = Const.WeaponNames;
  6. const MapNames = Const.MapNames;
  7. const StatisName = Const.StatisName;
  8. const Excel = require("exceljs");
  9. const path = require("path");
  10. const await = require("await-stream-ready/lib/await");
  11. const Service = require('egg').Service;
  12. class RecordService extends Service {
  13. async create(teacherId, templateId, title) {
  14. let mysql = this.app.mysql;
  15. let ret = await mysql.query(`insert into train_records (teacher_id, title, template_id,start_time, state) values (?,?,?,now(), 0)`, [teacherId, title, templateId]);
  16. console.log( ret );
  17. return {id: ret.insertId};
  18. }
  19. //开始训练的时候,调用更新
  20. async update(data) {
  21. let mysql = this.app.mysql;
  22. console.log( data );
  23. data.state = 1;
  24. let ret = await mysql.update("train_records", data, {where:{id: data.id}});
  25. //更新参训用户表
  26. let config = data.config;
  27. try {
  28. config = JSON.parse( config );
  29. let role = config.role;
  30. if( role ) {
  31. await mysql.query("delete from train_records_users where rid=?", [data.id]);
  32. let n = role.length;
  33. for( let i=0; i<n; i++) {
  34. if( role[i].user != -1) {
  35. await mysql.insert("train_records_users", {uid:role[i].user, rid: data.id, add_time:mysql.literals.now });
  36. }
  37. }
  38. }
  39. } catch (error) {
  40. }
  41. return ret;
  42. }
  43. //完成或取消的时候调用
  44. async complete( data )
  45. {
  46. let mysql = this.app.mysql;
  47. console.log( data );
  48. let ok = data.ok;
  49. let ret = null;
  50. if( ok == '1') { //完成
  51. ret = await mysql.query("update train_records set end_time=now(), duration=timestampdiff(second, start_time, now()), state=2 where id=?", [data.id]);
  52. } else if(ok == '2') { //删除
  53. ret = await mysql.query("delete from train_records where id=?", [data.id]);
  54. } else { //取消
  55. ret = await mysql.query("update train_records set end_time=now(), duration=timestampdiff(second, start_time, now()),state=3 where id=?", [data.id]);
  56. }
  57. return ret;
  58. }
  59. async playbackList( query )
  60. {
  61. console.log( query );
  62. let size = 8;
  63. let page = query.page;
  64. if( page == undefined || page == null || page == '') page = 0;
  65. page = parseInt( page );
  66. let mysql = this.app.mysql;
  67. let ret = await mysql.query("select r.id, r.title, DATE_FORMAT(r.start_time,'%Y-%m-%d') as start_time, r.playback, t.subject from train_records as r left join train_templates as t on t.id = r.template_id order by r.start_time desc limit ?,?", [page*size, size]);
  68. let total = await mysql.query("select count(*) as count from train_records");
  69. total = total[0].count;
  70. return {
  71. total: total,
  72. size: 8,
  73. pages: Math.ceil(total / 8),
  74. list:ret
  75. };
  76. }
  77. async addPlayback( body )
  78. {
  79. console.log("add playback", body);
  80. let {id, playback} = body;
  81. if( !id || !playback) throw "参数不合法";
  82. let mysql = this.app.mysql;
  83. let ret = await mysql.query(`update train_records set playback=? where id=?`, [playback, id]);
  84. return ret;
  85. }
  86. async adminList(query) {
  87. let mysql = this.app.mysql;
  88. let pageNo = query.pageNo;
  89. let pageSize = query.pageSize;
  90. pageNo = parseInt( pageNo );
  91. pageSize = parseInt( pageSize );
  92. let name = query.title;
  93. let teacher_id = query.teacher_id;
  94. let ret = {records:[], total: 0, };
  95. let where = name ? `where title like '%${name}%'`: "";
  96. if( teacher_id != undefined ) {
  97. where = where?where + ` and teacher_id=${teacher_id}` : `where teacher_id=${teacher_id}`;
  98. }
  99. let sql = `select r.id, r.title,r.state, date_format(r.start_time,'%Y-%m-%d %H:%m:%s') as start_time,
  100. date_format(r.end_time,'%Y-%m-%d %H:%m:%s') as end_time, users.name as teacher_name, r.duration, r.playback, t.subject from train_records as r left join users on users.id=r.teacher_id left join train_templates as t on t.id = r.template_id ${where}`
  101. let total = await mysql.query(`select count(id) as count from train_records ${where}`);
  102. ret.total = total[0].count;
  103. let data = await mysql.query( `${sql} order by id desc limit ${(pageNo-1)*pageSize},${pageSize}`);
  104. ret.records = data;
  105. return ret;
  106. }
  107. async detail( query ) {
  108. let {id } = query;
  109. if( !id) throw "参数不合法";
  110. let mysql = this.app.mysql;
  111. let ret = await mysql.query(`select r.id,r.state, r.title, t.subject, date_format(r.start_time,'%Y-%m-%d %H:%m:%s') as start_time, date_format(r.end_time,'%Y-%m-%d %H:%m:%s') as end_time,
  112. r.config, r.teacher_id, users.name as teacher_name, r.duration, r.playback from train_records as r left join users on r.teacher_id=users.id left join train_templates t on t.id=r.template_id where r.id=?`, [id]);
  113. ret = ret[0];
  114. let config = {scene:{}, ai:[], objective:[],role:[]};
  115. if( ret.config ) {
  116. try {
  117. config = JSON.parse(ret.config);
  118. let roles = config.role;
  119. if( roles ) {
  120. let n = roles.length;
  121. for(let i=0; i<n; i++) {
  122. let u = roles[i];
  123. if( u.user != -1) {
  124. let userInfo = await mysql.query("select id, name from users where id=" + u.user);
  125. userInfo = userInfo[0];
  126. if( userInfo ) {
  127. u.name = userInfo.name;
  128. }
  129. //日志数量
  130. let logs = await mysql.query(`SELECT COUNT(id) AS nu FROM train_records_logs WHERE rid=${id} AND uid=${u.user}`)
  131. u.logs = logs[0].nu;
  132. //飞行日志数量
  133. let flys = await mysql.query(`SELECT COUNT(id) AS nu FROM train_records_fly WHERE rid=${id} AND uid=${u.user}`)
  134. u.flys = flys[0].nu;
  135. //发送文书数据
  136. let messages = await mysql.query(`SELECT COUNT(id) AS nu FROM train_records_message WHERE rid=${id} AND \`from\`=${u.user}`)
  137. u.messages = messages[0].nu;
  138. }
  139. }
  140. }
  141. } catch (error) {
  142. config = {scene:{}, ai:[], objective:[],role:[]};
  143. }
  144. }
  145. ret.config = config;
  146. return ret;
  147. }
  148. async getUserRecord(query){
  149. let uid = query.uid;
  150. let rid = query.rid;
  151. if( !rid ) throw "ID为空";
  152. if( !uid ) {//根据token获取用户信息
  153. let u = await this.ctx.getLoginedUser();
  154. if( !u ) throw "用户ID为空";
  155. if( u.type == 2 ) {
  156. uid = u.id;
  157. }
  158. }
  159. if(!uid ) throw "用户ID为空";
  160. let mysql = this.app.mysql;
  161. let ret = {};
  162. //用户信息
  163. let info = await mysql.query("select realname, avatar, code from users where id=?", [uid]);
  164. info = info[0];
  165. ret.user = {
  166. ...info
  167. }
  168. ret.base = [];
  169. //训练信息
  170. let record = await mysql.query(`select r.id, r.title, date_format(r.start_time,'%Y-%m-%d %H:%m:%s') as start_time, date_format(r.end_time,'%Y-%m-%d %H:%m:%s') as end_time,
  171. r.config, r.duration,t.subject from train_records as r left join train_templates as t on r.template_id=t.id where r.id=?`, [rid]);
  172. record = record[0];
  173. ret.base.push({name:"训练任务",value: record.title});
  174. // ret.base.push({name:"训练开始时间",value: record.start_time});
  175. ret.base.push({name:"训练持续时间",value: Math.ceil(record.duration / 60)+"分钟" });
  176. ret.base.push({name:"训练科目",value: record.subject});
  177. ret.weapon = [];
  178. let comment = await mysql.query("select comment from train_records_users where uid=? and rid=?", [uid, rid]);
  179. comment = comment[0];
  180. ret.comment = comment;
  181. ret.uid = uid;
  182. try {
  183. let config = JSON.parse(record.config);
  184. console.log("---", config);
  185. ret.base.push({name:"训练地图", value: MapNames[ parseInt(config.scene.id) ] });
  186. let role = config.role;
  187. let n = role.length;
  188. while( n-- ) {
  189. let r = role[n];
  190. if( r.user == uid ) {
  191. ret.base.push({name:"所属小队",value: r.team>0 ? ("小队" + r.team):"..." });
  192. ret.base.push({name:"所属小组",value: r.group>0 ?("小队" + r.group):"..." });
  193. ret.base.push({name:"角色",value: RoleNames[parseInt(r.role)] });
  194. if( r.vehicleid != -1) {
  195. ret.base.push({name:"直升机型号",value: VehicleNames[ parseInt(r.vehicleid) ] });
  196. }
  197. //装备信息
  198. if( r.weapon ) {
  199. r.weapon.forEach(element => {
  200. ret.weapon.push({name: WeaponNames[element.id], value: "x"+element.quantity})
  201. });
  202. }
  203. break;
  204. }
  205. }
  206. } catch (error) {
  207. console.error( error );
  208. }
  209. //训练成绩
  210. ret.task = [];
  211. let taskInfo = await mysql.query("select state, value from train_records_result where rid=? and uid=?", [rid, uid]);
  212. taskInfo.forEach( e=>{
  213. let v = e.value;
  214. if( e.state == 4 || e.state == 5 || e.state ==6 || e.state == 12 ) {
  215. v = Math.ceil( v / 60 ) + "分钟";
  216. }
  217. ret.task.push({name: StatisName[e.state], value: v});
  218. });
  219. return ret;
  220. }
  221. //删除记录
  222. async delete(id)
  223. {
  224. let mysql = this.app.mysql;
  225. //删除文书
  226. console.log("delete id", id);
  227. let ret = await mysql.query("delete from train_records_message where rid=?",[id]);
  228. //删除日志
  229. await mysql.query("delete from train_records_logs where rid=?",[id]);
  230. //删除飞行日志
  231. await mysql.query("delete from train_records_fly where rid=?",[id]);
  232. await mysql.query("delete from train_records where id=?",[id]);
  233. return true;
  234. }
  235. //获取用户训练记录
  236. async getUserRecordList(query) {
  237. let user = this.ctx.state.admin;
  238. console.log("getUserRecordList", user);
  239. let uid = user.id;
  240. let type = user.type;
  241. if( type != 2 ) return {total:0, records:[]};
  242. let name = query.name;
  243. let where = name ? `where r.title like '%${name}%' and u.uid=${uid} order by r.id desc`: `where u.uid= ${uid} order by r.id desc`;
  244. let select = `r.id, r.title,r.state, date_format(r.start_time,'%Y-%m-%d %H:%m:%s') as start_time,
  245. date_format(r.end_time,'%Y-%m-%d %H:%m:%s') as end_time, users.name as teacher_name, r.duration, r.playback, t.subject`
  246. let table= `train_records as r join train_records_users as u on u.rid=r.id left join users on users.id=r.teacher_id left join train_templates as t on t.id = r.template_id`
  247. return await this.ctx.pageSelect(query, table, select, where);
  248. }
  249. async exportXls(query) {
  250. console.log("exportXls==>", query );
  251. let sql = `select r.id, r.title,r.state, date_format(r.start_time,'%Y-%m-%d %H:%m:%s') as start_time,
  252. date_format(r.end_time,'%Y-%m-%d %H:%m:%s') as end_time, users.name as teacher_name, r.duration, r.playback, t.subject from train_records as r left join users on users.id=r.teacher_id left join train_templates as t on t.id = r.template_id`
  253. if( query.selections ) { //导出指定的内容,否则导出所有
  254. sql += ` where r.id in (${query.selections})`;
  255. }
  256. let mysql = this.app.mysql;
  257. let ret = await mysql.query( sql );
  258. let workbook = new Excel.Workbook();
  259. let sheet = workbook.addWorksheet("训练记录列表", {
  260. // views: [{xSplit:1, ySplit:1}],
  261. pageSetup:{pageSize:9, orientation:'portrait', fitToPage:true, showGridLines:true, horizontalCentered:true},
  262. headerFooter:{
  263. firstHeader:"舰航仿真模拟训练记录列表",
  264. firstFooter:"舰航仿真模拟训练记录列表",
  265. oddFooter:"第 &P 页,共 &N页"
  266. }
  267. });
  268. let style = {alignment: {vertical:'middle', horizontal:'center'}};
  269. let columns = [
  270. {
  271. style,
  272. header: '#ID',
  273. key: 'id',
  274. },{
  275. style,
  276. header: '训练名称',
  277. key: 'title',
  278. width:20,
  279. },{
  280. style,
  281. width:20,
  282. header: '科目',
  283. key: 'subject',
  284. },{
  285. style,
  286. width:15,
  287. header: '时长',
  288. key: 'duration',
  289. },{
  290. style,
  291. width:10,
  292. header: '状态',
  293. key: 'state',
  294. },{
  295. style,
  296. width:20,
  297. header: '开始时间',
  298. key: 'start_time',
  299. },{
  300. style,
  301. width:20,
  302. header: '结束时间',
  303. key: 'end_time',
  304. }
  305. ];
  306. sheet.columns = columns;
  307. let StatNames = ["创建" ,"开始", "完成", "取消"];
  308. let rows = ret.map(item=>{
  309. let state = item.state;
  310. item.state = StatNames[state];
  311. let duration = item.duration;
  312. if( duration ) {
  313. item.duration = Math.ceil( duration / 60 ) + "分钟";
  314. } else {
  315. item.duration = "0 分钟";
  316. }
  317. return item;
  318. });
  319. sheet.addRows( rows );
  320. return await workbook.xlsx.writeBuffer();
  321. }
  322. async itemExportXls(query) {
  323. let data = await this.detail( query )
  324. let workbook = new Excel.Workbook();
  325. let sheet = workbook.addWorksheet("训练详情", {
  326. // views: [{xSplit:1, ySplit:1}],
  327. pageSetup:{pageSize:9, orientation:'portrait', fitToPage:true, showGridLines:false, horizontalCentered:true},
  328. headerFooter:{
  329. firstHeader:"舰航仿真模拟训练详情",
  330. firstFooter:"舰航仿真模拟训练详情",
  331. oddFooter:"第 &P 页,共 &N页"
  332. }
  333. });
  334. let style = {alignment: {vertical:'middle', horizontal:'center'}};
  335. // console.log( data.config.role );
  336. sheet.getColumn(1).width = 12;
  337. sheet.getColumn(5).width = 12;
  338. //第一行
  339. let row = sheet.getRow(1);
  340. row.getCell(1).value = "训练配置";
  341. row.getCell(1).style = {alignment: {vertical:'middle', horizontal:'center'}, font: {size:14, color:{rgba:'1890FFFF'}}};
  342. row.height = 25
  343. row.style = {alignment: {vertical:'middle', horizontal:'center'}};
  344. //训练配置数据
  345. row = sheet.getRow(2);
  346. row.height = 20
  347. sheet.mergeCells('B2:D2');
  348. row.getCell(1).value = "训练名字:"
  349. let cell = row.getCell(2);
  350. cell.value = data.title;
  351. row.getCell(5).value = "科目名字:";
  352. cell = row.getCell(6);
  353. cell.value = data.subject;
  354. sheet.mergeCells('F2:H2');
  355. let scene = data.config.scene;
  356. sheet.mergeCells('B3:D3');
  357. sheet.mergeCells('F3:H3');
  358. row = sheet.getRow(3);
  359. row.height = 20
  360. row.getCell(1).value = "训练地图:";
  361. row.getCell(2).value = Const.MapNames[ parseInt(scene.id) ];
  362. row.getCell(5).value = "初始天气:";
  363. row.getCell(6).value = Const.Weathers[ parseInt(scene.weather)];
  364. sheet.mergeCells('B4:D4');
  365. row = sheet.getRow(4);
  366. row.height = 20
  367. row.getCell(1).value = "初始时间:";
  368. row.getCell(2).value = Const.Times[ [14,21].indexOf(scene.time) ];
  369. row = sheet.getRow(5);
  370. row.height = 20
  371. row.getCell(1).value = "训练标准:";
  372. sheet.mergeCells('B5:H5');
  373. let items = data.config.objective.map(item=>{ return `${item.key}:${item.val}`})
  374. let over = false;
  375. let currRow = 5
  376. while( !over )
  377. {
  378. let curr = [];
  379. if( items.length > 4) {
  380. curr = items.slice(0, 4);
  381. items = items.slice(4);
  382. if( items.length == 0 ) over = true;
  383. } else {
  384. curr = items;
  385. over = true;
  386. }
  387. if( curr.length != 0) {
  388. row.getCell(2).value = curr.join(" ");
  389. } else {
  390. over = true;
  391. }
  392. if( !over ) {
  393. currRow +=1;
  394. row = sheet.getRow( currRow );
  395. row.height = 20
  396. }
  397. }
  398. //参训情况
  399. currRow +=1;
  400. row = sheet.getRow(currRow);
  401. row.height = 25
  402. row.getCell(1).value = "参训情况";
  403. row.getCell(1).style = {alignment: {vertical:'middle', horizontal:'center'}, font: {size:14, color:{rgba:'1890FFFF'}}};
  404. currRow +=1;
  405. row = sheet.getRow(currRow);
  406. row.height = 22
  407. row.getCell(1).value = "#"
  408. row.getCell(1).border = {
  409. top: {style:'thin'},
  410. left: {style:'thin'},
  411. bottom: {style:'thin'},
  412. right: {style:'thin'}
  413. };
  414. row.getCell(2).value = "姓名"
  415. row.getCell(2).border = {
  416. top: {style:'thin'},
  417. bottom: {style:'thin'},
  418. right: {style:'thin'}
  419. };
  420. row.getCell(3).value = "角色"
  421. row.getCell(3).border = {
  422. top: {style:'thin'},
  423. bottom: {style:'thin'},
  424. right: {style:'thin'}
  425. };
  426. row.getCell(4).value = "飞机型号"
  427. row.getCell(4).border = {
  428. top: {style:'thin'},
  429. bottom: {style:'thin'},
  430. right: {style:'thin'}
  431. };
  432. row.getCell(5).value = "所属小队"
  433. row.getCell(5).border = {
  434. top: {style:'thin'},
  435. bottom: {style:'thin'},
  436. right: {style:'thin'}
  437. };
  438. row.getCell(6).value = "所属小组"
  439. row.getCell(6).border = {
  440. top: {style:'thin'},
  441. bottom: {style:'thin'},
  442. right: {style:'thin'}
  443. };
  444. row.getCell(7).value = "日志数"
  445. row.getCell(7).border = {
  446. top: {style:'thin'},
  447. bottom: {style:'thin'},
  448. right: {style:'thin'}
  449. };
  450. row.getCell(8).value = "飞行记录"
  451. row.getCell(8).border = {
  452. top: {style:'thin'},
  453. bottom: {style:'thin'},
  454. right: {style:'thin'}
  455. };
  456. row.getCell(9).value = "发送文书"
  457. row.getCell(9).border = {
  458. top: {style:'thin'},
  459. bottom: {style:'thin'},
  460. right: {style:'thin'}
  461. };
  462. let users = data.config.role.filter(item=>item.user != -1);
  463. let ulen = users.length;
  464. for(let i=0; i<ulen; i++) {
  465. currRow +=1;
  466. let u = users[i];
  467. row = sheet.getRow( currRow );
  468. row.getCell(1).value = (i+1) + "";
  469. row.getCell(1).border = {
  470. left: {style:'thin'},
  471. bottom: {style:'thin'},
  472. right: {style:'thin'}
  473. };
  474. row.getCell(2).value = u.name;
  475. row.getCell(2).border = {
  476. bottom: {style:'thin'},
  477. right: {style:'thin'}
  478. };
  479. row.getCell(3).value = Const.RoleNames[ u.role ];
  480. row.getCell(3).border = {
  481. bottom: {style:'thin'},
  482. right: {style:'thin'}
  483. };
  484. row.getCell(4).value = u.vehicleid != -1? ( Const.VehicleNames[u.vehicleid] + `(${u.num})` ) : "--";
  485. row.getCell(4).border = {
  486. bottom: {style:'thin'},
  487. right: {style:'thin'}
  488. };
  489. row.getCell(6).value = u.group != -1 ? ("小组"+u.group) : "--";
  490. row.getCell(6).border = {
  491. bottom: {style:'thin'},
  492. right: {style:'thin'}
  493. };
  494. row.getCell(5).value = u.team != -1 ? ("小队"+u.team) : "--";
  495. row.getCell(5).border = {
  496. bottom: {style:'thin'},
  497. right: {style:'thin'}
  498. };
  499. row.getCell(7).value = u.logs;
  500. row.getCell(7).border = {
  501. bottom: {style:'thin'},
  502. right: {style:'thin'}
  503. };
  504. row.getCell(8).value = u.flys;
  505. row.getCell(8).border = {
  506. bottom: {style:'thin'},
  507. right: {style:'thin'}
  508. };
  509. row.getCell(9).value = u.messages;
  510. row.getCell(9).border = {
  511. bottom: {style:'thin'},
  512. right: {style:'thin'}
  513. };
  514. }
  515. //训练状态
  516. //参训情况
  517. currRow +=1;
  518. row = sheet.getRow( currRow );
  519. row.height = 25
  520. row.getCell(1).value = "训练状态";
  521. row.getCell(1).style = {alignment: {vertical:'middle', horizontal:'center'}, font: {size:14, color:{rgba:'1890FFFF'}}};
  522. currRow +=1;
  523. row = sheet.getRow(currRow);
  524. row.height = 20
  525. sheet.mergeCells(`B${currRow}:D${currRow}`);
  526. row.getCell(1).value = "开始时间:"
  527. cell = row.getCell(2);
  528. cell.value = data.start_time;
  529. row.getCell(5).value = "结束时间:";
  530. cell = row.getCell(6);
  531. cell.value = data.end_time;
  532. sheet.mergeCells(`F${currRow}:H${currRow}`);
  533. currRow +=1;
  534. row = sheet.getRow(currRow);
  535. row.height = 20
  536. sheet.mergeCells(`B${currRow}:D${currRow}`);
  537. row.getCell(1).value = "持续时间:"
  538. cell = row.getCell(2);
  539. let duration = data.duration;
  540. if( !duration ) duration = 0;
  541. cell.value = duration + 's';
  542. row.getCell(5).value = "任务状态:";
  543. cell = row.getCell(6);
  544. let state = "未开始";
  545. if( data.state == 1) state = "训练中";
  546. else if( data == 2 ) state = "已结束";
  547. cell.value = state;
  548. sheet.mergeCells(`F${currRow}:H${currRow}`);
  549. return await workbook.xlsx.writeBuffer();
  550. }
  551. }
  552. module.exports = RecordService;