wap_controller.js 69 KB

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