dashboard_controller.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. 'use strict';
  2. /**
  3. * 控制面板
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/11/23
  7. * @version
  8. */
  9. const auditConst = require('../const/audit');
  10. const officeList = require('../const/cld_office').list;
  11. const maintainConst = require('../const/maintain');
  12. const typeColMap = require('../const/advance').typeColMap;
  13. const moment = require('moment');
  14. const fs = require('fs');
  15. const path = require('path');
  16. const sendToWormhole = require('stream-wormhole');
  17. module.exports = app => {
  18. class DashboardController extends app.BaseController {
  19. /**
  20. * 控制面板页面
  21. *
  22. * @param {Object} ctx - egg全局变量
  23. * @return {void}
  24. */
  25. async index(ctx) {
  26. const auditTenders = await ctx.service.ledgerAudit.getAuditTender(ctx.session.sessionUser.accountId);
  27. const auditStages = await ctx.service.stageAudit.getAuditStage(ctx.session.sessionUser.accountId);
  28. const auditChanges = await ctx.service.changeAudit.getAuditChange(ctx.session.sessionUser.accountId);
  29. const auditRevise = await ctx.service.reviseAudit.getAuditRevise(ctx.session.sessionUser.accountId);
  30. const auditMaterial = ctx.session.sessionProject.page_show.openMaterial ? await ctx.service.materialAudit.getAuditMaterial(ctx.session.sessionUser.accountId) : [];
  31. const auditAdvance = await ctx.service.advanceAudit.getAuditAdvance(ctx.session.sessionUser.accountId);
  32. const auditChangeProject = ctx.session.sessionProject.page_show.openChangeProject ? await ctx.service.changeProjectAudit.getAuditChangeProject(ctx.session.sessionUser.accountId) : [];
  33. const auditChangeApply = ctx.session.sessionProject.page_show.openChangeApply ? await ctx.service.changeApplyAudit.getAuditChangeApply(ctx.session.sessionUser.accountId) : [];
  34. const auditChangePlan = ctx.session.sessionProject.page_show.openChangePlan ? await ctx.service.changePlanAudit.getAuditChangePlan(ctx.session.sessionUser.accountId) : [];
  35. const auditPayments = ctx.session.sessionProject.page_show.openPayment ? await ctx.service.paymentDetailAudit.getAuditPayment(ctx.session.sessionUser.accountId) : [];
  36. const auditStageAss = await ctx.service.stageAuditAss.getAuditStageAss(ctx.session.sessionUser.accountId);
  37. const auditFinancials = ctx.session.sessionProject.page_show.openFinancial ? await ctx.service.financialPayAudit.getAuditFinancial(ctx.session.sessionUser.accountId) : [];
  38. const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
  39. const noticeList = await ctx.service.noticePush.getNotice(ctx.session.sessionProject.id, pa.id);
  40. const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
  41. // 获取销售人员数据
  42. const salesmanData = await ctx.service.manager.getDataById(projectData.manager_id);
  43. const officeName = officeList[salesmanData.office];
  44. // 获取版本信息
  45. const versionList = await ctx.service.version.getAllDataByCondition({ orders: [['id', 'desc']], limit: 5, offset: 0 });
  46. // 获取项目通知
  47. const msgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id);
  48. const userPermission = pa !== undefined && pa.permission !== '' ? JSON.parse(pa.permission) : null;
  49. const userMsgPermission = userPermission !== null && userPermission.project_msg !== undefined && parseInt(userPermission.project_msg) === 1;
  50. // 获取系统通知
  51. const sysMsgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, 1, 0, 2);
  52. // 获取系统维护信息
  53. const maintainData = await ctx.service.maintain.getDataById(1);
  54. // 获取各个审批的次数及最后的审批时间
  55. const shenpi_count = [
  56. { count: await ctx.service.advanceAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '预付款' },
  57. { count: await ctx.service.ledgerAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '台账审批' },
  58. { count: await ctx.service.reviseAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '台账修订' },
  59. { count: await ctx.service.stageAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '计量审批' },
  60. { count: await ctx.service.changeAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更审批' },
  61. ];
  62. if (ctx.session.sessionProject.page_show.openChangeProject) shenpi_count.push({ count: await ctx.service.changeProjectAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更立项' });
  63. if (ctx.session.sessionProject.page_show.openChangeApply) shenpi_count.push({ count: await ctx.service.changeApplyAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更申请' });
  64. if (ctx.session.sessionProject.page_show.openChangePlan) shenpi_count.push({ count: await ctx.service.changePlanAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更方案' });
  65. if (ctx.session.sessionProject.page_show.openMaterial) shenpi_count.push({ count: await ctx.service.materialAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '材料调差' });
  66. if (ctx.session.sessionProject.page_show.openFinancial) shenpi_count.push({ count: await ctx.service.financialPayAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '资金支付' });
  67. // shenpi_count.push({ count: await ctx.service.advanceAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '预付款' });
  68. const total_count = ctx.app._.sumBy(shenpi_count, 'count');
  69. const shenpi_lastime = [
  70. await ctx.service.advanceAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
  71. await ctx.service.ledgerAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
  72. await ctx.service.reviseAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
  73. await ctx.service.stageAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
  74. await ctx.service.changeAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
  75. ctx.session.sessionProject.page_show.openChangeProject ? await ctx.service.changeProjectAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
  76. ctx.session.sessionProject.page_show.openChangeApply ? await ctx.service.changeApplyAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
  77. ctx.session.sessionProject.page_show.openChangePlan ? await ctx.service.changePlanAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
  78. ctx.session.sessionProject.page_show.openMaterial ? await ctx.service.materialAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
  79. ctx.session.sessionProject.page_show.openFinancial ? await ctx.service.financialPayAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
  80. ];
  81. const last_time = ctx.app._.max(shenpi_lastime);
  82. // console.log(ctx.app._.max(shenpi_lastime), ctx.helper.calcDayNum(last_time));
  83. const renderData = {
  84. auditTenders,
  85. auditStages,
  86. auditChanges,
  87. auditRevise,
  88. auditMaterial,
  89. auditAdvance,
  90. auditChangeProject,
  91. auditChangeApply,
  92. auditChangePlan,
  93. auditPayments,
  94. auditStageAss,
  95. auditFinancials,
  96. shenpi_count,
  97. total_count,
  98. last_day: ctx.helper.calcDayNum(last_time),
  99. role: pa.role,
  100. authMobile: pa.auth_mobile,
  101. acLedger: auditConst.ledger,
  102. acStage: auditConst.stage,
  103. acChange: auditConst.change,
  104. acRevise: auditConst.revise,
  105. acMaterial: auditConst.material,
  106. acAdvance: auditConst.advance,
  107. acChangeProject: auditConst.changeProject,
  108. acChangeApply: auditConst.changeApply,
  109. acChangePlan: auditConst.changeApply,
  110. acFinancial: auditConst.financial,
  111. noticeList,
  112. pushType: auditConst.pushType,
  113. projectData,
  114. salesmanData,
  115. officeName,
  116. versionList: JSON.parse(JSON.stringify(versionList).replace(/\\r\\n/g, '<br>').replace(/\\"/g, '&#34;').replace(/'/g, '&#39;').replace(/\\t/g, '&#9;')),
  117. msgList: JSON.parse(JSON.stringify(msgList).replace(/\\r\\n/g, '<br>').replace(/\\"/g, '&#34;').replace(/'/g, '&#39;').replace(/\\t/g, '&#9;')),
  118. sysMsgList: JSON.parse(JSON.stringify(sysMsgList).replace(/\\r\\n/g, '<br>').replace(/\\"/g, '&#34;').replace(/'/g, '&#39;').replace(/\\t/g, '&#9;')),
  119. userMsgPermission,
  120. uid: ctx.session.sessionUser.accountId,
  121. maintainData,
  122. maintainConst,
  123. typeColMap,
  124. };
  125. await this.layout('dashboard/index.ejs', renderData, 'dashboard/modal.ejs');
  126. await ctx.service.projectAccount.defaultUpdate({
  127. id: this.ctx.session.sessionUser.accountId,
  128. last_notice: new Date(),
  129. });
  130. }
  131. /**
  132. * 控制面板-通知页面
  133. *
  134. * @param {Object} ctx - egg全局变量
  135. * @return {void}
  136. */
  137. async msg(ctx) {
  138. try {
  139. const page = ctx.page;
  140. const msgId = parseInt(ctx.params.id) || 0;
  141. let msgInfo = msgId ? await ctx.service.message.getDataById(msgId) : null;
  142. const type = msgInfo ? msgInfo.type : ctx.request.query.type ? parseInt(ctx.request.query.type) : 1;
  143. if (msgInfo && msgInfo.type === 1 && msgInfo.project_id !== ctx.session.sessionProject.id) {
  144. throw '非该项目通知无权查看';
  145. }
  146. if (msgInfo) {
  147. msgInfo.content = JSON.parse(JSON.stringify(msgInfo.content).replace(/\\r\\n/g, '<br>').replace(/\\"/g, '&#34;').replace(/'/g, '&#39;').replace(/\\t/g, '&#9;'));
  148. msgInfo.files = await this.ctx.service.messageAtt.getAtt(msgInfo.id);
  149. }
  150. const total = type === 1 ?
  151. await ctx.service.message.count({ project_id: ctx.session.sessionProject.id, type }) :
  152. await ctx.service.message.count({ status: 1, type });
  153. const limit = 5;
  154. const offset = limit * (this.ctx.page - 1);
  155. const msgList = await ctx.service.message.getMsgList(ctx.session.sessionProject.id, limit, offset, type);
  156. const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
  157. const userPermission = pa !== undefined && pa.permission !== '' ? JSON.parse(pa.permission) : null;
  158. const userMsgPermission = userPermission !== null && userPermission.project_msg !== undefined && parseInt(userPermission.project_msg) === 1;
  159. if (!msgId) {
  160. msgInfo = msgList[0];
  161. }
  162. // 分页相关
  163. const pageInfo = {
  164. page,
  165. total: Math.ceil(total / limit),
  166. queryData: JSON.stringify(ctx.urlInfo.query),
  167. };
  168. const renderData = {
  169. msgInfo,
  170. uid: ctx.session.sessionUser.accountId,
  171. type,
  172. pageInfo,
  173. userMsgPermission,
  174. msgList: JSON.parse(JSON.stringify(msgList).replace(/\\r\\n/g, '<br>').replace(/\\"/g, '&#34;').replace(/'/g, '&#39;').replace(/\\t/g, '&#9;')),
  175. };
  176. await this.layout('dashboard/msg.ejs', renderData);
  177. } catch (error) {
  178. console.log(error);
  179. this.log(error);
  180. ctx.session.postError = error.toString();
  181. ctx.redirect('/dashboard');
  182. }
  183. }
  184. /**
  185. * 控制面板-通知添加和编辑页面
  186. *
  187. * @param {Object} ctx - egg全局变量
  188. * @return {void}
  189. */
  190. async msgAdd(ctx) {
  191. let id = ctx.params.id;
  192. id = parseInt(id);
  193. try {
  194. if (isNaN(id) || id < 0) {
  195. throw '参数错误';
  196. }
  197. const rule = ctx.service.message.rule();
  198. const jsValidator = await this.jsValidator.convert(rule).build();
  199. const msgInfo = id === 0 ? {} : await ctx.service.message.getDataById(id);
  200. const files = await ctx.service.messageAtt.getAtt(id);
  201. const renderData = {
  202. jsValidator,
  203. msgInfo,
  204. files,
  205. whiteList: ctx.app.config.multipart.whitelist,
  206. moment,
  207. };
  208. await this.layout('dashboard/msg_add.ejs', renderData, 'dashboard/msg_modal.ejs');
  209. } catch (error) {
  210. console.log(error);
  211. // this.setMessage(error.toString(), this.messageType.ERROR);
  212. ctx.redirect(ctx.request.header.referer);
  213. }
  214. }
  215. /**
  216. * 控制面板-通知保存
  217. *
  218. * @param {Object} ctx - egg全局变量
  219. * @return {void}
  220. */
  221. async msgSet(ctx) {
  222. try {
  223. let id = ctx.params.id;
  224. id = parseInt(id);
  225. if (isNaN(id) || id < 0) {
  226. throw '参数错误';
  227. }
  228. const rule = ctx.service.message.rule();
  229. ctx.helper.validate(rule);
  230. const result = await ctx.service.message.save(id, ctx.request.body, ctx.session.sessionUser, ctx.session.sessionProject.id);
  231. if (result) {
  232. // 新增的项目通知会发送微信模版消息通知客户
  233. if (id === 0) {
  234. // 获取该项目所有的openid,发送信息
  235. const wechats = await ctx.service.projectAccount.getOpenIdListByPid(ctx.session.sessionProject.id);
  236. if (wechats.length > 0) {
  237. const msgInfo = await ctx.service.message.getDataById(result);
  238. const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
  239. // 绑定成功通知
  240. const templateId = 'VKUo4us4lt2dQY0EaaJxcui2jkjmriN3A0K7i4kpZwY';
  241. const url = ctx.protocol + '://' + ctx.host + '/wx/url2wap?project=' + ctx.session.sessionProject.code + '&url=' + ctx.protocol + '://' + ctx.host + '/wap/dashboard/msg/' + msgInfo.id;
  242. const msgData = {
  243. thing21: {
  244. value: ctx.helper.contentChange(projectData.name),
  245. },
  246. thing2: {
  247. value: ctx.helper.contentChange(msgInfo.title),
  248. },
  249. thing8: {
  250. value: msgInfo.creator,
  251. },
  252. time3: {
  253. value: moment(msgInfo.release_time * 1000).format('YYYY-MM-DD'),
  254. },
  255. };
  256. for (const wx of wechats) {
  257. const result = await app.wechat.api.sendTemplate(wx.wx_openid, templateId, url, '', msgData);
  258. }
  259. }
  260. }
  261. ctx.redirect('/dashboard/msg');
  262. }
  263. } catch (error) {
  264. console.log(error);
  265. ctx.redirect(ctx.request.header.referer);
  266. }
  267. }
  268. /**
  269. * 控制面板-通知删除
  270. *
  271. * @param {Object} ctx - egg全局变量
  272. * @return {void}
  273. */
  274. async msgDelete(ctx) {
  275. try {
  276. let id = ctx.params.id;
  277. id = parseInt(id);
  278. if (isNaN(id) || id <= 0) {
  279. throw '参数错误';
  280. }
  281. const msgInfo = await ctx.service.message.getDataById(id);
  282. if (!msgInfo || msgInfo.create_uid !== ctx.session.sessionUser.accountId) {
  283. throw '通知不存在或无权限操作';
  284. }
  285. const result = await ctx.service.message.deleteMsg(msgInfo.id);
  286. if (result) {
  287. ctx.redirect('/dashboard/msg');
  288. }
  289. } catch (error) {
  290. console.log(error);
  291. ctx.redirect(ctx.request.header.referer);
  292. }
  293. }
  294. /**
  295. * 将推送记录设置为已读
  296. * @param {Object} ctx 上下文
  297. */
  298. async pushSet(ctx) {
  299. try {
  300. const { id } = JSON.parse(ctx.request.body.data);
  301. const data = await ctx.service.noticePush.set(id);
  302. ctx.body = { err: 0, msg: '' };
  303. } catch (err) {
  304. this.log(err);
  305. ctx.body = { err: 1, msg: err.toString(), data: null };
  306. }
  307. }
  308. /**
  309. * 上传附件
  310. * @param {*} ctx 上下文
  311. */
  312. async msgUploadFile(ctx) {
  313. let stream;
  314. try {
  315. const responseData = { err: 0, msg: '', data: {} };
  316. const mid = ctx.params.id || 0;
  317. if (!mid) throw '参数有误';
  318. const parts = this.ctx.multipart({
  319. autoFields: true,
  320. });
  321. const files = [];
  322. const create_time = Date.parse(new Date()) / 1000;
  323. let idx = 0;
  324. while ((stream = await parts()) !== undefined) {
  325. if (!stream.filename) {
  326. // 如果没有传入直接返回
  327. return;
  328. }
  329. const fileInfo = path.parse(stream.filename);
  330. const filepath = `app/public/upload/message/fujian_${create_time + idx.toString() + fileInfo.ext}`;
  331. await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
  332. files.push({ filepath, name: stream.filename, ext: fileInfo.ext });
  333. ++idx;
  334. stream && (await sendToWormhole(stream));
  335. }
  336. const in_time = new Date();
  337. const payload = files.map(file => {
  338. let idx;
  339. if (Array.isArray(parts.field.name)) {
  340. idx = parts.field.name.findIndex(name => name === file.name);
  341. } else {
  342. idx = 'isString';
  343. }
  344. const newFile = {
  345. project_id: ctx.session.sessionProject.id,
  346. mid,
  347. uid: ctx.session.sessionUser.accountId,
  348. filename: file.name,
  349. fileext: file.ext,
  350. filesize: ctx.helper.bytesToSize(idx === 'isString' ? parts.field.size : parts.field.size[idx]),
  351. filepath: file.filepath,
  352. upload_time: in_time,
  353. };
  354. return newFile;
  355. });
  356. // 执行文件信息写入数据库
  357. await ctx.service.messageAtt.saveFileMsgToDb(payload);
  358. // 将最新的当前标段的所有文件信息返回
  359. responseData.data = await ctx.service.messageAtt.getAtt(mid);
  360. ctx.body = responseData;
  361. } catch (err) {
  362. stream && (await sendToWormhole(stream));
  363. this.log(err);
  364. ctx.body = { err: 1, msg: err.toString(), data: null };
  365. }
  366. }
  367. /**
  368. * 删除附件
  369. * @param {Ojbect} ctx 上下文
  370. */
  371. async msgDeleteFile(ctx) {
  372. try {
  373. const mid = ctx.params.id || 0;
  374. const responseData = { err: 0, msg: '', data: {} };
  375. const data = JSON.parse(ctx.request.body.data);
  376. const fileInfo = await ctx.service.messageAtt.getDataById(data.id);
  377. if (fileInfo) {
  378. // 先删除文件
  379. // await fs.unlinkSync(path.resolve(this.app.baseDir, './app', fileInfo.filepath));
  380. await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
  381. // 再删除数据库
  382. await ctx.service.messageAtt.delete(data.id);
  383. } else {
  384. throw '不存在该文件';
  385. }
  386. responseData.data = await ctx.service.messageAtt.getAtt(mid);
  387. ctx.body = responseData;
  388. } catch (err) {
  389. this.log(err);
  390. ctx.body = { err: 1, msg: err.toString(), data: null };
  391. }
  392. }
  393. }
  394. return DashboardController;
  395. };