wap_controller.js 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. 'use strict';
  2. /**
  3. * 登录页面控制器
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/11/15
  7. * @version
  8. */
  9. const URL = require('url');
  10. const maintainConst = require('../const/maintain');
  11. const auditConst = require('../const/audit');
  12. const tenderConst = require('../const/tender');
  13. const changeConst = require('../const/change');
  14. const advanceConst = require('../const/advance');
  15. const materialConst = require('../const/material');
  16. const shenpiConst = require('../const/shenpi');
  17. const codeRuleConst = require('../const/code_rule');
  18. const fs = require('fs');
  19. const path = require('path');
  20. const sendToWormhole = require('stream-wormhole');
  21. const moment = require('moment');
  22. const auditType = require('../const/audit').auditType;
  23. const AiInspect = require('../lib/ai_inspect');
  24. const uuid = require('node-uuid');
  25. const nlsToken = require('../lib/nls_token');
  26. const streamToArray = require('stream-to-array');
  27. const PermissionCheck = require('../const/account_permission').PermissionCheck;
  28. module.exports = app => {
  29. class WapController extends app.BaseController {
  30. /**
  31. * 登录页面
  32. *
  33. * @param {Object} ctx - egg全局页面
  34. * @return {void}
  35. */
  36. async index(ctx) {
  37. if (!ctx.helper.isMobile(ctx.request.header['user-agent'])) {
  38. ctx.redirect('/');
  39. return;
  40. }
  41. const errorMessage = ctx.session.loginError;
  42. // 显示完删除
  43. ctx.session.loginError = null;
  44. // 获取系统维护信息
  45. const maintainData = await ctx.service.maintain.getDataById(1);
  46. if (!ctx.app.config.is_debug) {
  47. await ctx.service.maintain.syncMaintainData();
  48. }
  49. let projectData = '';
  50. if (ctx.session.wapTenderID) {
  51. const tenderData = await ctx.service.tender.getDataById(ctx.session.wapTenderID);
  52. if (tenderData) projectData = await ctx.service.project.getDataById(tenderData.project_id);
  53. }
  54. const renderData = {
  55. maintainData,
  56. maintainConst,
  57. errorMessage,
  58. projectData,
  59. };
  60. await ctx.render('wap/login.ejs', renderData);
  61. }
  62. /**
  63. * 登录操作
  64. *
  65. * @param {Object} ctx - egg全局变量
  66. * @return {void}
  67. */
  68. async login(ctx) {
  69. let loginType = ctx.request.body.type;
  70. try {
  71. loginType = parseInt(loginType);
  72. const result = await ctx.service.projectAccount.accountLogin(ctx.request.body, loginType);
  73. if (!result) {
  74. throw '用户名或密码错误';
  75. }
  76. if (result === 2) {
  77. // 判断是否有设置停用提示,有则展示
  78. const msg = await ctx.service.projectStopmsg.getMsg(ctx.session.sessionProject.id);
  79. throw msg;
  80. }
  81. // 调用 rotateCsrfSecret 刷新用户的 CSRF token
  82. ctx.rotateCsrfSecret();
  83. // 判断是否已经有对应用户信息,没有则跳转初始化页面
  84. const needBoot = await ctx.service.customer.isNeedBoot(ctx.request.body);
  85. const url = needBoot ? '/boot' : '/wap/dashboard';
  86. const query = URL.parse(ctx.request.header.referer, true).query;
  87. let referer = '';
  88. if (ctx.session.wapTenderID) {
  89. referer = query.referer ? query.referer + '#shenpi' : url;
  90. ctx.session.wapTenderID = null;
  91. }
  92. ctx.redirect(referer ? referer : url);
  93. } catch (error) {
  94. this.log(error);
  95. ctx.session.loginError = error;
  96. ctx.redirect('/wap');
  97. }
  98. }
  99. /**
  100. * 退出登录
  101. *
  102. * @param {Object} ctx - egg全局变量
  103. * @return {void}
  104. */
  105. async logout(ctx) {
  106. // 删除session并跳转
  107. ctx.session = null;
  108. ctx.redirect('/wap');
  109. }
  110. /**
  111. * 待办页
  112. *
  113. * @param {Object} ctx - egg全局变量
  114. * @return {void}
  115. */
  116. async dashboard(ctx) {
  117. // 获取待审批的期
  118. const auditStages = await ctx.service.stageAudit.getAuditStageByWap(ctx.session.sessionUser.accountId);
  119. const subProjects = [];
  120. for (const audit of auditStages) {
  121. if (audit.status !== auditConst.stage.status.uncheck) {
  122. const isLastage = await ctx.service.stage.isLastStage(audit.tid, audit.id);
  123. if (isLastage) await this.ctx.service.stage.checkStageGatherData(audit);
  124. }
  125. audit.gather_tp = ctx.helper.sum([audit.contract_tp, audit.qc_tp, audit.pc_tp]);
  126. audit.end_contract_tp = ctx.helper.sum([audit.contract_tp, audit.pre_contract_tp, audit.contract_pc_tp]);
  127. audit.end_qc_tp = ctx.helper.sum([audit.qc_tp, audit.pre_qc_tp, audit.qc_pc_tp]);
  128. audit.pre_gather_tp = ctx.helper.add(audit.pre_contract_tp, audit.pre_qc_tp);
  129. audit.end_gather_tp = ctx.helper.add(audit.gather_tp, audit.pre_gather_tp);
  130. let sp = null;
  131. if (audit.spid) {
  132. if (ctx.helper._.findIndex(subProjects, { id: audit.spid }) !== -1) {
  133. sp = ctx.helper._.find(subProjects, { id: audit.spid });
  134. } else {
  135. sp = await ctx.service.subProject.getDataById(audit.spid);
  136. subProjects.push(sp);
  137. }
  138. }
  139. if (sp) {
  140. const pageShow = JSON.parse(sp.page_show);
  141. audit.closeWapYfSf = pageShow.closeWapYfSf || 0;
  142. } else {
  143. audit.closeWapYfSf = 0;
  144. }
  145. }
  146. // 获取待审批的变更期
  147. const auditChanges = await ctx.service.changeAudit.getAuditChangeByWap(ctx.session.sessionUser.accountId);
  148. // 获取待审批的变更立项
  149. const auditChangeProjects = [];
  150. const changeProjects = await ctx.service.changeProjectAudit.getAuditChangeProjectByWap(ctx.session.sessionUser.accountId);
  151. for (const cp of changeProjects) {
  152. let sp = null;
  153. if (cp.spid) {
  154. if (ctx.helper._.findIndex(subProjects, { id: cp.spid }) !== -1) {
  155. sp = ctx.helper._.find(subProjects, { id: cp.spid });
  156. } else {
  157. sp = await ctx.service.subProject.getDataById(cp.spid);
  158. subProjects.push(sp);
  159. }
  160. }
  161. if (sp) {
  162. const pageShow = JSON.parse(sp.page_show);
  163. if (pageShow.openChangeProject) {
  164. auditChangeProjects.push(cp);
  165. }
  166. }
  167. }
  168. // 获取待审批的变更申请
  169. const auditChangeApplys = [];
  170. const changeApplys = await ctx.service.changeApplyAudit.getAuditChangeApplyByWap(ctx.session.sessionUser.accountId);
  171. for (const ca of changeApplys) {
  172. let sp = null;
  173. if (ca.spid) {
  174. if (ctx.helper._.findIndex(subProjects, { id: ca.spid }) !== -1) {
  175. sp = ctx.helper._.find(subProjects, { id: ca.spid });
  176. } else {
  177. sp = await ctx.service.subProject.getDataById(ca.spid);
  178. subProjects.push(sp);
  179. }
  180. }
  181. if (sp) {
  182. const pageShow = JSON.parse(sp.page_show);
  183. if (pageShow.openChangeApply) {
  184. auditChangeApplys.push(ca);
  185. }
  186. }
  187. }
  188. // 获取待审批的变更方案
  189. const auditChangePlans = [];
  190. const changePlans = await ctx.service.changePlanAudit.getAuditChangePlanByWap(ctx.session.sessionUser.accountId);
  191. for (const cp of changePlans) {
  192. let sp = null;
  193. if (cp.spid) {
  194. if (ctx.helper._.findIndex(subProjects, { id: cp.spid }) !== -1) {
  195. sp = ctx.helper._.find(subProjects, { id: cp.spid });
  196. } else {
  197. sp = await ctx.service.subProject.getDataById(cp.spid);
  198. subProjects.push(sp);
  199. }
  200. }
  201. if (sp) {
  202. const pageShow = JSON.parse(sp.page_show);
  203. if (pageShow.openChangePlan) {
  204. auditChangePlans.push(cp);
  205. }
  206. } else {
  207. auditChangePlans.push(cp);
  208. }
  209. }
  210. // 获取待审批的台账修订
  211. const auditRevise = await ctx.service.reviseAudit.getAuditReviseByWap(ctx.session.sessionUser.accountId);
  212. for (const revise of auditRevise) {
  213. const yb_audit = await ctx.service.projectAccount.getAccountInfoById(revise.audit_id);
  214. revise.yb_name = yb_audit.name;
  215. }
  216. // 获取待审批的预付款
  217. const auditAdvance = await ctx.service.advanceAudit.getAuditAdvanceByWap(ctx.session.sessionUser.accountId);
  218. const materialList = await ctx.service.materialAudit.getAuditMaterialByWap(ctx.session.sessionUser.accountId);
  219. const auditMaterials = [];
  220. for (const audit of materialList) {
  221. audit.decimal = audit.decimal ? JSON.parse(audit.decimal) : materialConst.decimal;
  222. let sp = null;
  223. if (audit.spid) {
  224. if (ctx.helper._.findIndex(subProjects, { id: audit.spid }) !== -1) {
  225. sp = ctx.helper._.find(subProjects, { id: audit.spid });
  226. } else {
  227. sp = await ctx.service.subProject.getDataById(audit.spid);
  228. subProjects.push(sp);
  229. }
  230. }
  231. if (sp) {
  232. const pageShow = JSON.parse(sp.page_show);
  233. if (pageShow.openMaterial) {
  234. auditMaterials.push(audit);
  235. }
  236. }
  237. }
  238. // 获取待审批的质量巡检单
  239. const auditQualityInspections = [];
  240. const qualityInspectionList = await ctx.service.qualityInspectionAudit.getAuditInspectionByWap(ctx.session.sessionUser.accountId);
  241. for (const audit of qualityInspectionList) {
  242. let sp = null;
  243. if (audit.spid) {
  244. if (ctx.helper._.findIndex(subProjects, { id: audit.spid }) !== -1) {
  245. sp = ctx.helper._.find(subProjects, { id: audit.spid });
  246. } else {
  247. sp = await ctx.service.subProject.getDataById(audit.spid);
  248. subProjects.push(sp);
  249. }
  250. }
  251. if (sp) {
  252. const pageShow = JSON.parse(sp.page_show);
  253. if (pageShow.qualityInspection) {
  254. auditQualityInspections.push(audit);
  255. }
  256. }
  257. }
  258. const auditSafeInspections = [];
  259. const safeInspectionList = await ctx.service.safeInspectionAudit.getAuditInspectionByWap(ctx.session.sessionUser.accountId);
  260. for (const audit of safeInspectionList) {
  261. let sp = null;
  262. if (audit.spid) {
  263. if (ctx.helper._.findIndex(subProjects, { id: audit.spid }) !== -1) {
  264. sp = ctx.helper._.find(subProjects, { id: audit.spid });
  265. } else {
  266. sp = await ctx.service.subProject.getDataById(audit.spid);
  267. subProjects.push(sp);
  268. }
  269. }
  270. if (sp) {
  271. const pageShow = JSON.parse(sp.page_show);
  272. if (pageShow.safeInspection) {
  273. auditSafeInspections.push(audit);
  274. }
  275. }
  276. }
  277. const renderData = {
  278. auditStages,
  279. auditChanges,
  280. auditChangeProjects,
  281. auditChangeApplys,
  282. auditChangePlans,
  283. auditMaterials,
  284. auditRevise,
  285. auditAdvance,
  286. auditQualityInspections,
  287. auditSafeInspections,
  288. changeConst,
  289. advanceConst,
  290. tpUnit: 2,
  291. };
  292. await ctx.render('wap/dashboard.ejs', renderData);
  293. }
  294. async subproj(ctx) {
  295. try {
  296. const renderData = {
  297. jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.subProject.wap),
  298. };
  299. renderData.projectList = await ctx.service.subProject.getSubProject(ctx.session.sessionProject.id, ctx.session.sessionUser.accountId, ctx.session.sessionUser.is_admin);
  300. renderData.tenderList = await ctx.service.tender.getManageTenderList(ctx.session.sessionProject.id);
  301. await ctx.render('wap/sub_proj.ejs', renderData);
  302. } catch (err) {
  303. ctx.log(err);
  304. ctx.session.postError = err.toString();
  305. ctx.redirect('/wap/dashboard');
  306. }
  307. }
  308. /**
  309. * 标段列表页
  310. *
  311. * @param {Object} ctx - egg全局变量
  312. * @return {void}
  313. */
  314. async list(ctx) {
  315. try {
  316. // 获取用户新建标段权利
  317. const type = ctx.params.type || '';
  318. let tenderList = '';
  319. const accountInfo = await this.ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
  320. const userPermission = accountInfo !== undefined && accountInfo.permission !== '' ? JSON.parse(accountInfo.permission) : null;
  321. if (type) {
  322. if (type === 'safe' && !ctx.subProject.page_show.safeInspection) throw '该功能已关闭';
  323. if (type === 'quality' && !ctx.subProject.page_show.qualityInspection) throw '该功能已关闭';
  324. const permission = type === 'quality' ? 'inspection' : type === 'safe' ? 'safe_inspection' : '';
  325. if (!permission) throw '参数错误';
  326. tenderList = await ctx.service.tender.getSpecList(ctx.service.tenderPermission, permission, ctx.session.sessionUser.is_admin ? 'all' : '');
  327. } else {
  328. tenderList = await this.ctx.service.tender.getBuildList('', userPermission);
  329. }
  330. for (const t of tenderList) {
  331. await this.ctx.service.tenderCache.loadTenderCache(t, this.ctx.session.sessionUser.accountId);
  332. }
  333. const categoryData = await this.ctx.service.category.getAllCategory(ctx.subProject);
  334. const valuations = await this.ctx.service.valuation.getProjectValidValuation(this.ctx.session.sessionProject.id);
  335. const renderData = {
  336. tenderList,
  337. categoryData,
  338. auditConst,
  339. userPermission,
  340. valuations,
  341. uid: this.ctx.session.sessionUser.accountId,
  342. pid: this.ctx.session.sessionProject.id,
  343. type,
  344. };
  345. await ctx.render('wap/list.ejs', renderData);
  346. } catch (err) {
  347. this.log(err);
  348. this.ctx.redirect('/wap/dashboard');
  349. }
  350. }
  351. /**
  352. * 标段详细页
  353. *
  354. * @param {Object} ctx - egg全局变量
  355. * @return {void}
  356. */
  357. async tender(ctx) {
  358. try {
  359. const tender = ctx.tender.data;
  360. if (tender.user_id === this.ctx.session.sessionUser.accountId && (
  361. tender.ledger_status === auditConst.ledger.status.checkNo || tender.ledger_status === auditConst.ledger.status.uncheck)) {
  362. const sum = await this.ctx.service.ledger.addUp({tender_id: tender.id/*, is_leaf: true*/});
  363. tender.total_price = sum.total_price;
  364. tender.deal_tp = sum.deal_tp;
  365. }
  366. const [change_tp, change_p_tp, change_n_tp, change_valuation_tp, change_unvaluation_tp] = await ctx.service.change.getChangeTp(ctx.tender.id);
  367. tender.change_tp = change_tp;
  368. tender.change_p_tp = change_p_tp;
  369. tender.change_n_tp = change_n_tp;
  370. tender.change_valuation_tp = change_valuation_tp;
  371. tender.change_unvaluation_tp = change_unvaluation_tp;
  372. const stages = await ctx.service.stage.getValidStages(ctx.tender.id);
  373. const lastStage = stages.length > 0 ? stages[0] : null; //await ctx.service.stage.getLastestStage(ctx.tender.id);
  374. if (lastStage) {
  375. await this.ctx.service.stage.checkStageGatherData(lastStage);
  376. tender.gather_tp = ctx.helper.sum([lastStage.contract_tp, lastStage.qc_tp, lastStage.pc_tp]);
  377. tender.end_contract_tp = ctx.helper.sum([lastStage.contract_tp, lastStage.pre_contract_tp, lastStage.contract_pc_tp]);
  378. tender.end_qc_tp = ctx.helper.sum([lastStage.qc_tp, lastStage.pre_qc_tp, lastStage.qc_pc_tp]);
  379. tender.pre_gather_tp = ctx.helper.add(lastStage.pre_contract_tp, lastStage.pre_qc_tp);
  380. tender.end_gather_tp = ctx.helper.add(tender.gather_tp, tender.pre_gather_tp);
  381. tender.yf_tp = lastStage.yf_tp;
  382. tender.qc_ratio = ctx.helper.mul(ctx.helper.div(tender.end_qc_tp, ctx.tender.info.deal_param.contractPrice, 2), 100);
  383. tender.sum = ctx.helper.add(tender.total_price, tender.change_tp);
  384. tender.pre_ratio = ctx.helper.mul(ctx.helper.div(tender.pre_gather_tp, tender.sum, 2), 100);
  385. tender.cur_ratio = ctx.helper.mul(ctx.helper.div(tender.gather_tp, tender.sum, 2), 100);
  386. tender.other_tp = ctx.helper.sub(ctx.helper.sub(tender.sum, tender.pre_gather_tp), tender.gather_tp);
  387. tender.other_ratio = Math.max(0, 100 - tender.pre_ratio - tender.cur_ratio);
  388. }
  389. const monthProgress = [];
  390. for (const s of stages) {
  391. if (s.s_time) {
  392. let progress = monthProgress.find(function(x) {
  393. return x.month === s.s_time;
  394. });
  395. if (!progress) {
  396. progress = { month: s.s_time };
  397. monthProgress.push(progress);
  398. }
  399. progress.tp = ctx.helper.add(ctx.helper.add(progress.tp, s.contract_tp), s.qc_tp);
  400. }
  401. }
  402. monthProgress.sort(function(x, y) {
  403. return Date.parse(x.month) - Date.parse(y.month);
  404. });
  405. let sum = 0;
  406. for (const p of monthProgress) {
  407. p.ratio = ctx.helper.mul(ctx.helper.div(p.tp, tender.sum, 4), 100);
  408. sum = ctx.helper.add(sum, p.tp);
  409. p.end_tp = sum;
  410. p.end_ratio = ctx.helper.mul(ctx.helper.div(p.end_tp, tender.sum, 4), 100);
  411. }
  412. // 台账修订列表
  413. const revises = await ctx.service.ledgerRevise.getReviseList(ctx.tender.id);
  414. for (const lr of revises) {
  415. if (lr.valid) {
  416. lr.curAuditor = await ctx.service.reviseAudit.getAuditorByStatus(lr.id, lr.status, lr.times);
  417. }
  418. }
  419. // 预付款期数获取
  420. const advanceList = [];
  421. for (const t of advanceConst.typeCol) {
  422. const advance = await ctx.service.advance.getLastestAdvance(ctx.tender.id, t.type, true);
  423. advanceList.push(advance);
  424. }
  425. // 材料调差
  426. const materials = await ctx.service.material.getValidMaterials(ctx.tender.id);
  427. let openMaterialTax = ctx.subProject.page_show.openMaterialTax;
  428. const tenderMsg = await ctx.service.tender.getTender(ctx.tender.id, ['material_col_show']);
  429. const material_col_show = tenderMsg.material_col_show ? JSON.parse(tenderMsg.material_col_show) : ctx.helper._.cloneDeep(tenderConst.materialColShow);
  430. let allMaterialTax = true;
  431. for (const s of materials) {
  432. if (!s.final_auditor_str || s.status !== auditConst.material.status.checked) {
  433. // 根据期状态返回展示用户
  434. s.curAuditors = await ctx.service.materialAudit.getAuditorsByStatus(s.id, s.status, s.times);
  435. if (s.status === auditConst.material.status.checked && s.curAuditors.length > 0) {
  436. const final_auditor_str = (s.curAuditors[0].audit_type === auditType.key.common)
  437. ? `${s.curAuditors[0].name}${(s.curAuditors[0].role ? '-' + s.curAuditors[0].role : '')}`
  438. : ctx.helper.transFormToChinese(s.curAuditors[0].audit_order) + '审';
  439. await ctx.service.material.defaultUpdate({ id: s.id, final_auditor_str });
  440. }
  441. }
  442. if (allMaterialTax && s.material_tax === 0) {
  443. allMaterialTax = false;
  444. }
  445. if (!openMaterialTax && s.material_tax === 1) {
  446. openMaterialTax = 1;
  447. }
  448. s.decimal = s.decimal ? JSON.parse(s.decimal) : materialConst.decimal;
  449. }
  450. const renderData = {
  451. tender,
  452. stages,
  453. revises,
  454. advanceList,
  455. materials,
  456. openMaterialTax,
  457. allMaterialTax,
  458. materialColShow: material_col_show,
  459. auditConst: auditConst.stage,
  460. auditReviseConst: auditConst.revise,
  461. auditMaterialConst: auditConst.material,
  462. advanceConst,
  463. tpUnit: ctx.tender.info.decimal.tp,
  464. monthProgress,
  465. stagesEcharts: JSON.parse(JSON.stringify(stages)).reverse(),
  466. auditType: auditConst.auditType,
  467. };
  468. if (stages.length > 0) {
  469. for (const s of stages) {
  470. // s.curAuditor = null;
  471. // 根据期状态返回展示用户
  472. s.curAuditors = await ctx.service.stageAudit.getAuditorsByStatus(s.id, s.status, s.times);
  473. if (s.status === auditConst.stage.status.checkNoPre) {
  474. s.curAuditors2 = await ctx.service.stageAudit.getAuditorsByStatus(s.id, auditConst.stage.status.checking);
  475. }
  476. }
  477. renderData.stage = stages[0];
  478. const times = renderData.stage.status === auditConst.stage.status.checkNo ? renderData.stage.times - 1 : renderData.stage.times;
  479. renderData.stage.user = await ctx.service.projectAccount.getAccountInfoById(renderData.stage.user_id);
  480. renderData.stage.auditors = await ctx.service.stageAudit.getAuditors(renderData.stage.id, times);
  481. // 获取审批流程中左边列表
  482. renderData.stage.auditors2 = await ctx.service.stageAudit.getAuditGroupByList(renderData.stage.id, times);
  483. }
  484. await ctx.render('wap/tender.ejs', renderData);
  485. } catch (err) {
  486. this.log(err);
  487. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  488. }
  489. }
  490. /**
  491. * 期审批详细页
  492. *
  493. * @param {Object} ctx - egg全局变量
  494. * @return {void}
  495. */
  496. async stage(ctx) {
  497. try {
  498. const tender = ctx.tender.data;
  499. // const stages = await ctx.service.stage.getValidStages(ctx.tender.id);
  500. // const lastStage = stages.length > 0 ? stages[0] : null;
  501. // if (lastStage) {
  502. // await this.ctx.service.stage.checkStageGatherData(lastStage);
  503. // }
  504. const stage = ctx.stage;
  505. if (stage) {
  506. if (stage.status !== auditConst.stage.status.checked) await this.ctx.service.stage.checkStageGatherData(stage);
  507. stage.tp = this.ctx.helper.sum([stage.contract_tp, stage.qc_tp, stage.pc_tp]);
  508. stage.pre_tp = this.ctx.helper.add(stage.pre_contract_tp, stage.pre_qc_tp);
  509. stage.end_tp = this.ctx.helper.add(stage.pre_tp, stage.tp);
  510. }
  511. await ctx.service.stage.loadStageAuditViewData(stage);
  512. const renderData = {
  513. moment,
  514. tender,
  515. stage,
  516. auditConst: auditConst.stage,
  517. auditType,
  518. };
  519. // const times = renderData.stage.status === auditConst.stage.status.checkNo ? renderData.stage.times - 1 : renderData.stage.times;
  520. // renderData.stage.user = await ctx.service.projectAccount.getAccountInfoById(renderData.stage.user_id);
  521. // renderData.stage.auditors = await ctx.service.stageAudit.getAuditors(renderData.stage.id, times);
  522. // // 获取审批流程中左边列表
  523. // renderData.stage.auditors2 = await ctx.service.stageAudit.getAuditGroupByList(renderData.stage.id, times);
  524. renderData.stage.lastAuditors = await ctx.service.stageAudit.getAuditorsByStatus(stage.id, stage.status, stage.times);
  525. await ctx.render('wap/shenpi_stage.ejs', renderData);
  526. } catch (err) {
  527. this.log(err);
  528. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  529. }
  530. }
  531. /**
  532. * 调差期审批详细页
  533. *
  534. * @param {Object} ctx - egg全局变量
  535. * @return {void}
  536. */
  537. async material(ctx) {
  538. try {
  539. const tender = ctx.tender.data;
  540. const material = ctx.material;
  541. await ctx.service.material.loadMaterialAuditViewData(material);
  542. const renderData = {
  543. moment,
  544. tender,
  545. material,
  546. auditConst: auditConst.material,
  547. auditType,
  548. };
  549. renderData.material.m_tax_tp = renderData.material.m_tax_tp ? renderData.material.m_tax_tp : renderData.material.m_tp;
  550. renderData.pre_tp_hs = await ctx.service.material.getPreTpHs(ctx.tender.id, ctx.material.order, ctx.material.decimal.tp);
  551. renderData.ex_pre_tp_hs = await ctx.service.material.getExPreTpHs(ctx.tender.id, ctx.material.order, ctx.material.decimal.tp);
  552. renderData.months = ctx.material.months ? ctx.material.months.split(',') : [];
  553. renderData.material.lastAuditors = await ctx.service.materialAudit.getAuditorsByStatus(material.id, material.status, material.times);
  554. renderData.old_had_tax = await ctx.service.material.getOldMaterialTax(ctx.tender.id, ctx.material.order);
  555. await ctx.render('wap/shenpi_material.ejs', renderData);
  556. } catch (err) {
  557. this.log(err);
  558. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  559. }
  560. }
  561. /**
  562. * 工程变更列表页
  563. *
  564. * @param {Object} ctx - egg全局变量
  565. * @return {void}
  566. */
  567. async changeIndex(ctx) {
  568. try {
  569. // 变更令列表
  570. const changes = await ctx.service.change.getListByStatus(ctx.tender.id, 0, 0);
  571. for (const c of changes) {
  572. c.showApprovalBtn = false;
  573. c.curAuditors = await ctx.service.changeAudit.getAuditorsByStatus(c.cid, c.status, c.times);
  574. if (c.status === auditConst.change.status.checkNoPre) {
  575. c.curAuditors2 = await ctx.service.changeAudit.getAuditorsByStatus(c.cid, auditConst.change.status.checking, c.times);
  576. const curAudit = c.curAuditors2.find(function(x) {
  577. return x.uid === ctx.session.sessionUser.accountId;
  578. });
  579. if (curAudit && curAudit.status === auditConst.change.status.checking) {
  580. c.showApprovalBtn = true;
  581. }
  582. } else {
  583. const curAudit = c.curAuditors.find(function(x) {
  584. return x.uid === ctx.session.sessionUser.accountId;
  585. });
  586. if (curAudit && curAudit.status === auditConst.change.status.checking) {
  587. c.showApprovalBtn = true;
  588. }
  589. }
  590. }
  591. // 变更立项列表
  592. let changeProjects = [];
  593. if (ctx.subProject.page_show.openChangeProject) {
  594. changeProjects = await ctx.service.changeProject.getListByStatus(ctx.tender.id, 0, 0);
  595. for (const c of changeProjects) {
  596. c.showApprovalBtn = false;
  597. c.curAuditors = await ctx.service.changeProjectAudit.getAuditorsByStatus(c.id, c.status, c.times);
  598. const curAudit = c.curAuditors.find(function(x) {
  599. return x.aid === ctx.session.sessionUser.accountId;
  600. });
  601. if (curAudit && curAudit.status === auditConst.changeProject.status.checking) {
  602. c.showApprovalBtn = true;
  603. }
  604. }
  605. }
  606. // 变更申请列表
  607. let changeApplys = [];
  608. if (ctx.subProject.page_show.openChangeApply) {
  609. changeApplys = await ctx.service.changeApply.getListByStatus(ctx.tender.id, 0, 0);
  610. for (const c of changeApplys) {
  611. c.showApprovalBtn = false;
  612. c.curAuditors = await ctx.service.changeApplyAudit.getAuditorsByStatus(c.id, c.status, c.times);
  613. const curAudit = c.curAuditors.find(function(x) {
  614. return x.aid === ctx.session.sessionUser.accountId;
  615. });
  616. if (curAudit && curAudit.status === auditConst.changeApply.status.checking) {
  617. c.showApprovalBtn = true;
  618. }
  619. }
  620. }
  621. // 变更方案列表
  622. let changePlans = [];
  623. if (ctx.subProject.page_show.openChangePlan) {
  624. changePlans = await ctx.service.changePlan.getListByStatus(ctx.tender.id, 0, 0);
  625. for (const c of changePlans) {
  626. c.showApprovalBtn = false;
  627. c.curAuditors = await ctx.service.changePlanAudit.getAuditorsByStatus(c.id, c.status, c.times);
  628. const curAudit = c.curAuditors.find(function(x) {
  629. return x.aid === ctx.session.sessionUser.accountId;
  630. });
  631. if (curAudit && curAudit.status === auditConst.changePlan.status.checking) {
  632. c.showApprovalBtn = true;
  633. }
  634. }
  635. }
  636. const renderData = {
  637. tender: ctx.tender,
  638. changes,
  639. changeProjects,
  640. changeApplys,
  641. changePlans,
  642. auditChangeConst: auditConst.change,
  643. auditChangeProjectConst: auditConst.changeProject,
  644. auditChangeApplyConst: auditConst.changeApply,
  645. auditChangePlanConst: auditConst.changePlan,
  646. changeConst,
  647. tpUnit: ctx.tender.info.decimal.tp,
  648. auditType: auditConst.auditType,
  649. };
  650. await ctx.render('wap/shenpi_change_index.ejs', renderData);
  651. } catch (err) {
  652. this.log(err);
  653. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  654. }
  655. }
  656. /**
  657. * 变更审批详细页
  658. *
  659. * @param {Object} ctx - egg全局变量
  660. * @return {void}
  661. */
  662. async change(ctx) {
  663. try {
  664. const tender = ctx.tender.data;
  665. const change = ctx.change;
  666. const times = change.status !== auditConst.change.status.checkNo && change.status !== auditConst.change.status.revise ? change.times : change.times - 1;
  667. const auditList = await ctx.service.changeAudit.getListOrderByTimes(change.cid, times);
  668. const auditGroupList = await ctx.service.changeAudit.getListGroupByTimes(change.cid, times);
  669. await ctx.service.change.loadChangeAuditViewData(ctx.change);
  670. const renderData = {
  671. moment,
  672. tender,
  673. change,
  674. auditList,
  675. auditGroupList,
  676. auditConst: auditConst.change,
  677. changeConst,
  678. tpUnit: ctx.tender.info.decimal.tp,
  679. auditType,
  680. };
  681. await ctx.render('wap/shenpi_change.ejs', renderData);
  682. } catch (err) {
  683. this.log(err);
  684. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  685. }
  686. }
  687. /**
  688. * 变更立项审批详细页
  689. *
  690. * @param {Object} ctx - egg全局变量
  691. * @return {void}
  692. */
  693. async changeProject(ctx) {
  694. try {
  695. const tender = ctx.tender.data;
  696. const change = ctx.change;
  697. await ctx.service.changeProject.loadChangeAuditViewData(ctx.change);
  698. const renderData = {
  699. moment,
  700. tender,
  701. change,
  702. auditConst: auditConst.changeProject,
  703. changeConst,
  704. tpUnit: ctx.tender.info.decimal.tp,
  705. auditType,
  706. };
  707. await ctx.render('wap/shenpi_change_project.ejs', renderData);
  708. } catch (err) {
  709. this.log(err);
  710. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  711. }
  712. }
  713. /**
  714. * 变更申请审批详细页
  715. *
  716. * @param {Object} ctx - egg全局变量
  717. * @return {void}
  718. */
  719. async changeApply(ctx) {
  720. try {
  721. const tender = ctx.tender.data;
  722. const change = ctx.change;
  723. await ctx.service.changeApply.loadChangeAuditViewData(ctx.change);
  724. const renderData = {
  725. moment,
  726. tender,
  727. change,
  728. auditConst: auditConst.changeApply,
  729. changeConst,
  730. tpUnit: ctx.tender.info.decimal.tp,
  731. auditType,
  732. };
  733. await ctx.render('wap/shenpi_change_apply.ejs', renderData);
  734. } catch (err) {
  735. this.log(err);
  736. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  737. }
  738. }
  739. /**
  740. * 变更方案审批详细页
  741. *
  742. * @param {Object} ctx - egg全局变量
  743. * @return {void}
  744. */
  745. async changePlan(ctx) {
  746. try {
  747. const tender = ctx.tender.data;
  748. const change = ctx.change;
  749. await ctx.service.changePlan.loadChangeAuditViewData(ctx.change);
  750. const renderData = {
  751. moment,
  752. tender,
  753. change,
  754. auditConst: auditConst.changeApply,
  755. changeConst,
  756. tpUnit: ctx.tender.info.decimal.tp,
  757. auditType,
  758. };
  759. await ctx.render('wap/shenpi_change_plan.ejs', renderData);
  760. } catch (err) {
  761. this.log(err);
  762. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  763. }
  764. }
  765. /**
  766. * 修订审批详细页
  767. *
  768. * @param {Object} ctx - egg全局变量
  769. * @return {void}
  770. */
  771. async revise(ctx) {
  772. try {
  773. const tender = ctx.tender.data;
  774. const revise = await ctx.service.ledgerRevise.getDataByCondition({ id: ctx.params.rid });
  775. revise.user = await ctx.service.projectAccount.getAccountInfoById(revise.uid);
  776. const times = revise.status === auditConst.revise.status.checkNo ? revise.times - 1 : revise.times;
  777. revise.curAuditor = await ctx.service.reviseAudit.getAuditorByStatus(revise.id, revise.status, times);
  778. revise.auditors = await ctx.service.reviseAudit.getAuditors(revise.id, times);
  779. console.log(times, revise.auditors);
  780. const renderData = {
  781. tender,
  782. revise,
  783. auditConst: auditConst.revise,
  784. };
  785. await ctx.render('wap/shenpi_revise.ejs', renderData);
  786. } catch (err) {
  787. this.log(err);
  788. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  789. }
  790. }
  791. /**
  792. * 预付款列表页
  793. *
  794. * @param {Object} ctx - egg全局变量
  795. * @return {void}
  796. */
  797. async advance(ctx) {
  798. try {
  799. const tender = ctx.tender.data;
  800. const { decimal } = ctx.tender.info;
  801. this.decimal = decimal.pay ? decimal.payTp : decimal.tp;
  802. const advancePayTotalList = [];
  803. const advanceList = [];
  804. for (const t of advanceConst.typeCol) {
  805. const advancePayTotal = ctx.tender.info.deal_param[t.key + 'Advance'];
  806. advancePayTotalList.push(advancePayTotal);
  807. const advances = await ctx.service.advance.getAdvanceList(ctx.tender.id, t.type, this.decimal, advancePayTotal);
  808. advanceList.push(advances);
  809. }
  810. const renderData = {
  811. tender,
  812. advancePayTotalList,
  813. advanceList,
  814. auditConst: auditConst.advance,
  815. advanceConst,
  816. };
  817. await ctx.render('wap/shenpi_advance.ejs', renderData);
  818. } catch (err) {
  819. this.log(err);
  820. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/list');
  821. }
  822. }
  823. /**
  824. * 预付款详情页 GET
  825. * @param {Object} ctx 全局上下文
  826. */
  827. async advanceDetail(ctx) {
  828. try {
  829. const tender = ctx.tender.data;
  830. ctx.advance.advancePayTotal = ctx.tender.info.deal_param[ advanceConst.typeCol[ctx.advance.type].key + 'Advance'];
  831. const times = ctx.advance.status === auditConst.advance.status.checkNo ? ctx.advance.times - 1 : ctx.advance.times;
  832. if (ctx.advance.status === auditConst.advance.status.checkNo) {
  833. ctx.advance.curAuditor = await ctx.service.advanceAudit.getAuditorByStatus(ctx.advance.id, ctx.advance.status, times);
  834. ctx.advance.auditors = await ctx.service.advanceAudit.getAuditors(ctx.advance.id, times);
  835. }
  836. // 获取审批流程中左边列表
  837. ctx.advance.auditors2 = await ctx.service.advanceAudit.getAuditGroupByList(ctx.advance.id, times);
  838. const renderData = {
  839. tender,
  840. advance: ctx.advance,
  841. auditConst: auditConst.advance,
  842. advanceConst,
  843. };
  844. await ctx.render('wap/shenpi_advance_detail.ejs', renderData);
  845. } catch (error) {
  846. this.log(error);
  847. ctx.redirect('/wap/tender/' + ctx.tender.id + '/advance');
  848. }
  849. }
  850. /**
  851. * 变更令审批
  852. * @param {Object} ctx - egg全局变量
  853. * @return {void}
  854. */
  855. async changeApproval(ctx) {
  856. try {
  857. const cid = ctx.request.body.change_id;
  858. const changeData = await ctx.service.change.getDataByCondition({ cid });
  859. if (!changeData) {
  860. throw '变更令数据错误';
  861. }
  862. // 判断是否到你审批,如果不是则无法审批
  863. const curAuditor = await ctx.service.changeAudit.getCurAuditors(changeData.cid, changeData.times);
  864. if (!curAuditor || (curAuditor && ctx.helper._.findIndex(curAuditor, { uid: ctx.session.sessionUser.accountId }) === -1)) {
  865. throw '该变更令当前您无权操作';
  866. }
  867. const readySettle = await ctx.service.settle.getReadySettle(changeData.tid);
  868. if (readySettle && readySettle.settle_order !== ctx.tender.data.settle_order) {
  869. throw '结算数据发生变化,请刷新页面再提交';
  870. }
  871. const status = parseInt(ctx.request.body.status);
  872. const pid = this.ctx.session.sessionProject.id;
  873. let result = false;
  874. switch (status) {
  875. case 3:// 审批通过
  876. result = await ctx.service.change.approvalSuccess(pid, ctx.request.body, changeData);
  877. break;
  878. // case 4:// 审批终止
  879. // result = await ctx.service.change.approvalStop(ctx.request.body);
  880. // break;
  881. case 5:// 审批退回到原报人
  882. result = await ctx.service.change.approvalCheckNo(pid, ctx.request.body, changeData);
  883. break;
  884. case 6:// 审批退回到上一个审批人
  885. result = await ctx.service.change.approvalCheckNoPre(pid, ctx.request.body, changeData);
  886. break;
  887. default:break;
  888. }
  889. if (!result) {
  890. throw '审批失败';
  891. }
  892. ctx.redirect(ctx.request.header.referer);
  893. } catch (err) {
  894. console.log(err);
  895. ctx.redirect(ctx.request.header.referer);
  896. }
  897. }
  898. /**
  899. * 收方单附件上传页
  900. * @param {Object} ctx - egg全局变量
  901. * @return {void}
  902. */
  903. async shoufangUpload(ctx) {
  904. try {
  905. const tid = parseInt(ctx.query.tid) || 0;
  906. const order = parseInt(ctx.query.order) || 0;
  907. const sfid = parseInt(ctx.query.sfid) || 0;
  908. if (!tid || !order || !sfid) {
  909. throw '参数有误';
  910. }
  911. const tender = await ctx.service.tender.getDataById(tid);
  912. if (!tender) {
  913. throw '该标段不存在';
  914. }
  915. const sfInfo = await ctx.service.stageShoufang.getDataByCondition({ id: sfid, tid, order });
  916. if (!sfInfo) {
  917. throw '该收方单不存在';
  918. }
  919. // 查找对应的台账或计量单元名称
  920. const ledger = await ctx.service.ledger.getData(tid);
  921. const ledgerInfo = ctx.helper._.find(ledger, { id: sfInfo.lid });
  922. let name = ledgerInfo.b_code;
  923. if (sfInfo.pid) {
  924. const pos = await ctx.service.pos.getPosData({ tid });
  925. const posInfo = ctx.helper._.find(pos, { lid: sfInfo.lid, id: sfInfo.pid });
  926. name += ' / ' + posInfo.name;
  927. }
  928. const renderData = {
  929. tender,
  930. order,
  931. name,
  932. sfid,
  933. whiteList: this.ctx.app.config.multipart.whitelist,
  934. };
  935. await ctx.render('wap/shoufangupload.ejs', renderData);
  936. } catch (error) {
  937. this.log(error);
  938. ctx.redirect('/wap/login');
  939. }
  940. }
  941. /**
  942. * 上传附件
  943. * @param {Object} ctx - egg全局变量
  944. * @return {void}
  945. */
  946. async shoufangUpFile(ctx) {
  947. const responseData = {
  948. err: 0,
  949. msg: '',
  950. data: [],
  951. };
  952. let stream;
  953. try {
  954. const parts = ctx.multipart({ autoFields: true });
  955. const files = [];
  956. let index = 0;
  957. while ((stream = await parts()) !== undefined) {
  958. // 判断是否存在
  959. const sfInfo = await ctx.service.stageShoufang.getDataById(parts.field.sfid);
  960. if (!sfInfo) {
  961. throw '该清单 / 计量单元下不存在收方单';
  962. }
  963. // 判断用户是否选择上传文件
  964. if (!stream.filename) {
  965. throw '请选择上传的文件!';
  966. }
  967. // const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD');
  968. // 判断文件夹是否存在,不存在则直接创建文件夹
  969. // if (!fs.existsSync(path.join(this.app.baseDir, dirName))) {
  970. // await fs.mkdirSync(path.join(this.app.baseDir, dirName));
  971. // }
  972. const fileInfo = path.parse(stream.filename);
  973. const now_time = new Date();
  974. const create_time = Date.parse(now_time) / 1000;
  975. const filepath = `app/public/upload/${sfInfo.tid}/stage/shoufang/fujian_${create_time + index.toString() + fileInfo.ext}`;
  976. // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, filepath));
  977. await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream);
  978. // console.log(await fs.existsSync(path.resolve(this.app.baseDir, 'app', filepath)));
  979. // const fileInfo = path.parse(stream.filename);
  980. // const fileName = 'stage' + create_time + '_' + index + fileInfo.ext;
  981. // 保存文件
  982. // await ctx.helper.saveStreamFile(stream, path.resolve(this.app.baseDir, dirName, fileName));
  983. if (stream) {
  984. await sendToWormhole(stream);
  985. }
  986. // 保存数据到att表
  987. const fileData = {
  988. tid: sfInfo.tid,
  989. sid: sfInfo.sid,
  990. sfid: sfInfo.id,
  991. in_time: now_time,
  992. filename: fileInfo.name,
  993. fileext: fileInfo.ext,
  994. filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size,
  995. filepath,
  996. };
  997. // if (ctx.reUploadPermission) {
  998. // fileData.re_upload = 1;
  999. // }
  1000. const result = await ctx.service.stageShoufangAtt.save(fileData);
  1001. if (!result) {
  1002. throw '导入数据库保存失败';
  1003. }
  1004. const attData = await ctx.service.stageShoufangAtt.getDataByFid(result.insertId);
  1005. attData.in_time = moment(create_time * 1000).format('YYYY-MM-DD');
  1006. files.length !== 0 ? files.unshift(attData) : files.push(attData);
  1007. ++index;
  1008. }
  1009. responseData.data = files;
  1010. } catch (err) {
  1011. this.log(err);
  1012. // 失败需要消耗掉stream 以防卡死
  1013. if (stream) {
  1014. await sendToWormhole(stream);
  1015. }
  1016. this.setMessage(err.toString(), this.messageType.ERROR);
  1017. responseData.err = 1;
  1018. responseData.msg = err.toString();
  1019. }
  1020. ctx.body = responseData;
  1021. }
  1022. /**
  1023. * 删除附件
  1024. * @param {Object} ctx - egg全局变量
  1025. * @return {void}
  1026. */
  1027. async shoufangDeleteFile(ctx) {
  1028. const responseData = {
  1029. err: 0,
  1030. msg: '',
  1031. data: '',
  1032. };
  1033. try {
  1034. const data = JSON.parse(ctx.request.body.data);
  1035. const fileInfo = await ctx.service.stageShoufangAtt.getDataById(data.id);
  1036. if (!fileInfo || !Object.keys(fileInfo).length) {
  1037. throw '该文件不存在';
  1038. }
  1039. if (fileInfo !== undefined && fileInfo !== '') {
  1040. // 先删除文件
  1041. // await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath));
  1042. await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath);
  1043. // 再删除数据库
  1044. await ctx.service.stageShoufangAtt.deleteById(data.id);
  1045. responseData.data = '';
  1046. } else {
  1047. throw '不存在该文件';
  1048. }
  1049. } catch (err) {
  1050. responseData.err = 1;
  1051. responseData.msg = err;
  1052. }
  1053. ctx.body = responseData;
  1054. }
  1055. /**
  1056. * 编辑附件
  1057. * @param {Object} ctx - egg全局变量
  1058. * @return {void}
  1059. */
  1060. async shoufangEditFile(ctx) {
  1061. const responseData = {
  1062. err: 0,
  1063. msg: '',
  1064. data: '',
  1065. };
  1066. try {
  1067. const data = JSON.parse(ctx.request.body.data);
  1068. const fileInfo = await ctx.service.stageShoufangAtt.getDataById(data.id);
  1069. if (!fileInfo || !Object.keys(fileInfo).length) {
  1070. throw '该文件不存在';
  1071. }
  1072. await ctx.service.stageShoufangAtt.edit(data);
  1073. } catch (err) {
  1074. responseData.err = 1;
  1075. responseData.msg = err;
  1076. }
  1077. ctx.body = responseData;
  1078. }
  1079. /**
  1080. * 下载附件
  1081. * @param {Object} ctx - egg全局变量
  1082. * @return {void}
  1083. */
  1084. async messageDownloadFile(ctx) {
  1085. const id = ctx.params.fid;
  1086. if (id) {
  1087. try {
  1088. const fileInfo = await ctx.service.messageAtt.getDataById(id);
  1089. if (fileInfo !== undefined && fileInfo !== '') {
  1090. // const fileName = path.join(this.app.baseDir, fileInfo.filepath);
  1091. // 解决中文无法下载问题
  1092. const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
  1093. let disposition = '';
  1094. if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
  1095. disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext);
  1096. } else if (userAgent.indexOf('firefox') >= 0) {
  1097. disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"';
  1098. } else {
  1099. /* safari等其他非主流浏览器只能自求多福了 */
  1100. disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary');
  1101. }
  1102. ctx.response.set({
  1103. 'Content-Type': 'application/octet-stream',
  1104. 'Content-Disposition': disposition,
  1105. 'Content-Length': fileInfo.filesize,
  1106. });
  1107. // ctx.body = await fs.createReadStream(fileName);
  1108. ctx.body = await ctx.helper.ossFileGet(fileInfo.filepath);
  1109. } else {
  1110. throw '不存在该文件';
  1111. }
  1112. } catch (err) {
  1113. this.log(err);
  1114. this.setMessage(err.toString(), this.messageType.ERROR);
  1115. }
  1116. }
  1117. }
  1118. /**
  1119. * 下载附件
  1120. * @param {Object} ctx - egg全局变量
  1121. * @return {void}
  1122. */
  1123. async shoufangDownloadFile(ctx) {
  1124. const id = ctx.params.fid;
  1125. if (id) {
  1126. try {
  1127. const fileInfo = await ctx.service.stageShoufangAtt.getDataById(id);
  1128. if (fileInfo !== undefined && fileInfo !== '') {
  1129. // const fileName = path.join(this.app.baseDir, fileInfo.filepath);
  1130. // 解决中文无法下载问题
  1131. const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase();
  1132. let disposition = '';
  1133. if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) {
  1134. disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext);
  1135. } else if (userAgent.indexOf('firefox') >= 0) {
  1136. disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"';
  1137. } else {
  1138. /* safari等其他非主流浏览器只能自求多福了 */
  1139. disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary');
  1140. }
  1141. ctx.response.set({
  1142. 'Content-Type': 'application/octet-stream',
  1143. 'Content-Disposition': disposition,
  1144. 'Content-Length': fileInfo.filesize,
  1145. });
  1146. // ctx.body = await fs.createReadStream(fileName);
  1147. ctx.body = await ctx.helper.ossFileGet(fileInfo.filepath);
  1148. } else {
  1149. throw '不存在该文件';
  1150. }
  1151. } catch (err) {
  1152. this.log(err);
  1153. this.setMessage(err.toString(), this.messageType.ERROR);
  1154. }
  1155. }
  1156. }
  1157. async msg(ctx) {
  1158. try {
  1159. const msgId = parseInt(ctx.params.id) || 0;
  1160. if (!msgId) {
  1161. throw '参数有误';
  1162. }
  1163. const msgInfo = await ctx.service.message.getDataById(msgId);
  1164. const files = await ctx.service.messageAtt.getAtt(msgId);
  1165. if (!msgInfo) {
  1166. throw '项目通知不存在';
  1167. }
  1168. if (msgInfo && msgInfo.type === 1 && msgInfo.project_id !== ctx.session.sessionProject.id) {
  1169. throw '非该项目通知无权查看';
  1170. }
  1171. if (msgInfo) {
  1172. msgInfo.content = JSON.parse(JSON.stringify(msgInfo.content).replace(/\\r\\n/g, '<br>').replace(/\\"/g, '&#34;').replace(/'/g, '&#39;').replace(/\\t/g, '&#9;'));
  1173. }
  1174. const renderData = {
  1175. msgInfo,
  1176. moment,
  1177. files,
  1178. };
  1179. await ctx.render('wap/msg.ejs', renderData);
  1180. } catch (error) {
  1181. console.log(error);
  1182. this.log(error);
  1183. ctx.redirect('/wap/dashboard');
  1184. }
  1185. }
  1186. /**
  1187. * 巡检列表页
  1188. *
  1189. * @param {Object} ctx - egg全局变量
  1190. * @return {void}
  1191. */
  1192. async inspection(ctx) {
  1193. try {
  1194. const type = ctx.params.type || '';
  1195. if (type !== 'safe' && type !== 'quality') {
  1196. throw '参数有误';
  1197. }
  1198. const tableName = type + 'Inspection';
  1199. // 变更令列表
  1200. const inspections = await ctx.service[tableName].getListByStatus(ctx.tender.id, 0, 0);
  1201. for (const c of inspections) {
  1202. c.showApprovalBtn = false;
  1203. c.curAuditors = await ctx.service[tableName + 'Audit'].getAuditorsByStatus(c.id, c.status, c.times);
  1204. if ((c.status === auditConst.inspection.status.uncheck || c.status === auditConst.inspection.status.checkNo) && c.uid === ctx.session.sessionUser.accountId) {
  1205. c.showApprovalBtn = true;
  1206. } else if (c.status === auditConst.inspection.status.checkNoPre) {
  1207. c.curAuditors2 = await ctx.service[tableName + 'Audit'].getAuditorsByStatus(c.id, auditConst.inspection.status.checking, c.times);
  1208. const curAudit = c.curAuditors2.find(function(x) {
  1209. return x.aid === ctx.session.sessionUser.accountId;
  1210. });
  1211. if (curAudit && (curAudit.status === auditConst.inspection.status.checking || curAudit.status === auditConst.inspection.status.rectification)) {
  1212. c.showApprovalBtn = true;
  1213. }
  1214. } else {
  1215. const curAudit = c.curAuditors.find(function(x) {
  1216. return x.aid === ctx.session.sessionUser.accountId;
  1217. });
  1218. if (curAudit && (curAudit.status === auditConst.inspection.status.checking || curAudit.status === auditConst.inspection.status.rectification)) {
  1219. c.showApprovalBtn = true;
  1220. }
  1221. }
  1222. }
  1223. const renderData = {
  1224. tender: ctx.tender.data,
  1225. inspections,
  1226. auditInspectionConst: auditConst.inspection,
  1227. auditType: auditConst.auditType,
  1228. type,
  1229. moment,
  1230. permission: type === 'quality' ? ctx.permission.inspection : ctx.permission.safe_inspection,
  1231. };
  1232. await ctx.render('wap/shenpi_inspection_index.ejs', renderData);
  1233. } catch (err) {
  1234. console.log(err);
  1235. this.log(err);
  1236. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/' + ctx.params.type + '/inspection');
  1237. }
  1238. }
  1239. /**
  1240. * 巡检审批详细页
  1241. *
  1242. * @param {Object} ctx - egg全局变量
  1243. * @return {void}
  1244. */
  1245. async qualityInspectionInformation(ctx) {
  1246. const type = 'quality';
  1247. await this._inspectionInformation(ctx, type);
  1248. }
  1249. async safeInspectionInformation(ctx) {
  1250. const type = 'safe';
  1251. await this._inspectionInformation(ctx, type);
  1252. }
  1253. async _inspectionInformation(ctx, type) {
  1254. try {
  1255. const whiteList = this.ctx.app.config.multipart.whitelist;
  1256. const tender = ctx.tender.data;
  1257. const inspection = ctx.inspection;
  1258. await ctx.service[type + 'Inspection'].loadAuditViewData(ctx.inspection);
  1259. // 获取附件列表
  1260. const fileList = await ctx.service[type + 'InspectionAtt'].getAllAtt(ctx.tender.id, ctx.inspection.id);
  1261. const renderData = {
  1262. moment,
  1263. tender,
  1264. inspection,
  1265. fileList,
  1266. whiteList,
  1267. deleteFilePermission: PermissionCheck.delFile(this.ctx.session.sessionUser.permission),
  1268. auditConst: auditConst.inspection,
  1269. shenpiConst,
  1270. tpUnit: ctx.tender.info.decimal.tp,
  1271. auditType,
  1272. type,
  1273. preUrl: `/sp/${ctx.subProject.id}/${type}/tender/${ctx.tender.id}/inspection/${ctx.inspection.id}/information`,
  1274. };
  1275. const accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject);
  1276. renderData.accountList = accountList;
  1277. const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
  1278. renderData.accountGroup = unitList.map(item => {
  1279. const groupList = accountList.filter(item1 => item1.company === item.name);
  1280. return { groupName: item.name, groupList };
  1281. }).filter(x => { return x.groupList.length > 0; });
  1282. await ctx.render('wap/shenpi_inspection.ejs', renderData);
  1283. } catch (err) {
  1284. this.log(err);
  1285. ctx.redirect('/wap/sp/' + ctx.subProject.id + '/' + type + '/inspection');
  1286. }
  1287. }
  1288. async inspectionAdd(ctx) {
  1289. const type = ctx.params.type || '';
  1290. if (type !== 'safe' && type !== 'quality') {
  1291. throw '参数有误';
  1292. }
  1293. const tenderData = await ctx.service.tender.getDataById(ctx.tender.id);
  1294. const codeType = type === 'quality' ? codeRuleConst.ruleString[codeRuleConst.ruleType.inspection] : codeRuleConst.ruleString[codeRuleConst.ruleType.safe_inspection];
  1295. const c_code_rules = tenderData.c_code_rules !== null ? JSON.parse(tenderData.c_code_rules) : null;
  1296. const cCodeRule = c_code_rules && c_code_rules[codeType + '_rule'] ? c_code_rules[codeType + '_rule'] : [
  1297. { rule_type: 2, text: (type === 'quality' ? '质量' : '安全') + '巡检' + moment().format('YYYYMMDD') },
  1298. { rule_type: 4, format: 3, start: 1 },
  1299. ];
  1300. const cConnector = c_code_rules && c_code_rules[codeType + '_connector'] ? c_code_rules[codeType + '_connector'] : 3;
  1301. const changeCount = await ctx.service[type + 'Inspection'].count({ tid: ctx.tender.id });
  1302. const code = [];
  1303. for (const rule of cCodeRule) {
  1304. switch (rule.rule_type) {
  1305. case codeRuleConst.measure.ruleType.dealCode:
  1306. code.push(ctx.tender.info.deal_info.dealCode);
  1307. break;
  1308. case codeRuleConst.measure.ruleType.tenderName:
  1309. code.push(tenderData.name);
  1310. break;
  1311. case codeRuleConst.measure.ruleType.text:
  1312. code.push(rule.text);
  1313. break;
  1314. case codeRuleConst.measure.ruleType.inDate:
  1315. code.push(moment().format('YYYY'));
  1316. break;
  1317. case codeRuleConst.measure.ruleType.addNo:
  1318. let s = '0000000000';
  1319. const count = rule.start + changeCount;
  1320. s = s + count;
  1321. code.push(s.substr(s.length - rule.format));
  1322. break;
  1323. default: break;
  1324. }
  1325. }
  1326. const newCode = code.join(cConnector !== null && parseInt(cConnector) !== 3 ? codeRuleConst.measure.connectorString[cConnector] : '');
  1327. const renderData = {
  1328. newCode,
  1329. tender: ctx.tender.data,
  1330. type,
  1331. };
  1332. await ctx.render('wap/inspection.ejs', renderData);
  1333. }
  1334. /**
  1335. * 新增变更申请 (Post)
  1336. *
  1337. * @param {Object} ctx - egg全局变量
  1338. * @return {void}
  1339. */
  1340. async inspectionSave(ctx) {
  1341. try {
  1342. const type = ctx.params.type || '';
  1343. if (type !== 'safe' && type !== 'quality') {
  1344. throw '参数有误';
  1345. }
  1346. const data = JSON.parse(ctx.request.body.data);
  1347. const reponseData = {
  1348. err: 0, msg: '', data: {},
  1349. };
  1350. switch (data.type) {
  1351. case 'addByWap':
  1352. if (!data.insert || !data.insert.code || data.insert.code === '') {
  1353. throw '巡检编号不能为空';
  1354. }
  1355. if (!data.insert.check_item) {
  1356. throw '检查项不能为空';
  1357. }
  1358. reponseData.data = await ctx.service[type + 'Inspection'].addByWap(ctx.tender.id, data.insert);
  1359. break;
  1360. default:throw '参数有误';
  1361. }
  1362. ctx.body = reponseData;
  1363. } catch (err) {
  1364. this.log(err);
  1365. ctx.body = { err: 1, msg: err.toString() };
  1366. }
  1367. }
  1368. async inspectionAiAsk(ctx) {
  1369. const responseData = {
  1370. err: 0,
  1371. msg: '',
  1372. data: '',
  1373. };
  1374. try {
  1375. const { user_input, conversationId } = JSON.parse(ctx.request.body.data);
  1376. if (!user_input) {
  1377. throw '参数有误';
  1378. }
  1379. const ai = new AiInspect({
  1380. chatflowId: conversationId,
  1381. });
  1382. const result = await ai.ask(user_input);
  1383. let answerText = result.answer || '';
  1384. let jsonPart = null;
  1385. const jsonMatch = answerText.match(/\{[\s\S]*\}/);
  1386. if (jsonMatch) {
  1387. jsonPart = JSON.parse(jsonMatch[0]);
  1388. answerText = answerText.replace(jsonMatch[0], '').trim();
  1389. }
  1390. responseData.data = {
  1391. answer_text: answerText,
  1392. answer_json: jsonPart,
  1393. conversation_id: result.conversation_id || '',
  1394. };
  1395. } catch (error) {
  1396. responseData.err = 1;
  1397. responseData.msg = error.message ? error.message : error;
  1398. }
  1399. ctx.body = responseData;
  1400. }
  1401. async voiceToken(ctx) {
  1402. const responseData = {
  1403. err: 0,
  1404. msg: '',
  1405. data: '',
  1406. };
  1407. try {
  1408. const token = await nlsToken.getToken();
  1409. responseData.data = token;
  1410. } catch (error) {
  1411. responseData.err = 1;
  1412. responseData.msg = error.message ? error.message : error;
  1413. }
  1414. ctx.body = responseData;
  1415. }
  1416. async voiceOneShot(ctx) {
  1417. const responseData = {
  1418. err: 0,
  1419. msg: '',
  1420. data: '',
  1421. };
  1422. const stream = await ctx.getFileStream();
  1423. try {
  1424. // 读取字节流
  1425. const parts = await streamToArray(stream);
  1426. // 转化为buffer
  1427. const buffer = Buffer.concat(parts);
  1428. if (!buffer || buffer.length === 0) {
  1429. throw '音频数据为空';
  1430. }
  1431. // 调用 service 执行一句话识别
  1432. const nls_token = new nlsToken(this.ctx);
  1433. const token = await nls_token.getToken();
  1434. const text = await nls_token.oneShotRecognition(token, buffer);
  1435. console.log(text);
  1436. if (stream) {
  1437. await sendToWormhole(stream);
  1438. }
  1439. responseData.data = text;
  1440. } catch (error) {
  1441. if (stream) {
  1442. await sendToWormhole(stream);
  1443. }
  1444. responseData.err = 1;
  1445. responseData.msg = error.message ? error.message : error;
  1446. }
  1447. ctx.body = responseData;
  1448. }
  1449. }
  1450. return WapController;
  1451. };