shenpi_audit.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. 'use strict';
  2. /**
  3. * 版本数据模型
  4. *
  5. * @author CaiAoLin
  6. * @date 2017/10/25
  7. * @version
  8. */
  9. const shenpiConst = require('../const/shenpi');
  10. const auditType = require('../const/audit').auditType;
  11. module.exports = app => {
  12. class ShenpiAudit extends app.BaseService {
  13. /**
  14. * 构造函数
  15. *
  16. * @param {Object} ctx - egg全局变量
  17. * @return {void}
  18. */
  19. constructor(ctx) {
  20. super(ctx);
  21. this.tableName = 'shenpi_audit';
  22. }
  23. async getShenpi(tid, info) {
  24. const spConst = this._.cloneDeep(shenpiConst);
  25. for (const sp of spConst.sp_lc) {
  26. sp.status = info.shenpi ? info.shenpi[sp.code] : shenpiConst.sp_status.sqspr;
  27. if (sp.status === shenpiConst.sp_status.gdspl) {
  28. sp.groupList = await this.ctx.service.shenpiGroup.getGroupList(tid, sp.type) || [];
  29. if (sp.groupList && sp.groupList.length > 0) {
  30. for (const group of sp.groupList) {
  31. if (group.change_type) group.change_type = JSON.parse(group.change_type);
  32. group.auditGroupList = await this.getAuditGroupList(tid, sp.type, sp.status, group.id);
  33. if (group.is_select) sp.auditGroupList = group.auditGroupList;
  34. }
  35. } else {
  36. sp.auditGroupList = await this.getAuditGroupList(tid, sp.type, sp.status);
  37. }
  38. } else if (sp.status === shenpiConst.sp_status.gdzs) {
  39. sp.audit = await this.getAudit(tid, sp.type, sp.status);
  40. }
  41. }
  42. return spConst;
  43. }
  44. async getAudit(tid, type, status) {
  45. const sql = 'SELECT sp.audit_id, sp.audit_type, pa.name FROM ?? AS sp LEFT JOIN ?? AS pa ON sp.audit_id = pa.id' +
  46. ' WHERE sp.tid = ? AND sp.sp_type = ? AND sp.sp_status = ?';
  47. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tid, type, status];
  48. return await this.db.queryOne(sql, sqlParam);
  49. }
  50. async getUnionAudit(tid, type, audit_order) {
  51. const sql = 'SELECT sp.id, sp.audit_id, sp.audit_ledger_id, pa.name, pa.company FROM ?? AS sp LEFT JOIN ?? AS pa ON sp.audit_id = pa.id' +
  52. ' WHERE sp.tid = ? AND sp.sp_type = ? AND sp.sp_status = ? AND audit_order = ?';
  53. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tid, type, shenpiConst.sp_status.gdspl, audit_order];
  54. return await this.db.query(sql, sqlParam);
  55. }
  56. async getAuditList(tid, type, status, group_id = 0) {
  57. const sql = 'SELECT sp.id, sp.audit_id, sp.audit_type, pa.name FROM ?? AS sp LEFT JOIN ?? AS pa ON sp.audit_id = pa.id' +
  58. ' WHERE sp.tid = ? AND sp.sp_type = ? AND sp.sp_status = ? AND sp.sp_group = ? ORDER BY sp.audit_order ASC, sp.id ASC';
  59. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tid, type, status, group_id];
  60. return await this.db.query(sql, sqlParam);
  61. }
  62. async getAuditGroupList(tid, type, status, group_id = 0) {
  63. const sql = 'SELECT sp.audit_id, sp.audit_type, sp.audit_order, sp.sp_group, pa.name FROM ?? AS sp LEFT JOIN ?? AS pa ON sp.audit_id = pa.id' +
  64. ' WHERE sp.tid = ? AND sp.sp_type = ? AND sp.sp_status = ? AND sp.sp_group = ? ORDER BY sp.audit_order ASC, sp.id ASC';
  65. const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tid, type, status, group_id];
  66. const audits = await this.db.query(sql, sqlParam);
  67. const result = [];
  68. for (const a of audits) {
  69. if (a.audit_order > 0) {
  70. if (result[a.audit_order - 1]) {
  71. result[a.audit_order - 1].push(a);
  72. } else {
  73. result.push([a]);
  74. }
  75. } else {
  76. result.push([a]);
  77. }
  78. }
  79. return result;
  80. }
  81. async addAudit(data) {
  82. let result;
  83. const transaction = await this.db.beginTransaction();
  84. try {
  85. if (parseInt(data.code) === shenpiConst.sp_type.stage && parseInt(data.status) === shenpiConst.sp_status.gdspl) {
  86. const options = {
  87. where: {
  88. tid: this.ctx.tender.id,
  89. user_id: data.audit_id,
  90. },
  91. };
  92. const updateData = {
  93. status: 1,
  94. };
  95. await transaction.update(this.ctx.service.ledgerCooperation.tableName, updateData, options);
  96. }
  97. const group = await this.ctx.service.shenpiGroup.getGroupBySelect(this.ctx.tender.id, data.code);
  98. const insertData = {
  99. tid: this.ctx.tender.id,
  100. sp_type: data.code,
  101. sp_status: data.status,
  102. audit_id: data.audit_id,
  103. sp_group: group ? group.id : 0,
  104. };
  105. if (data.audit_type) insertData.audit_type = data.audit_type;
  106. if (data.audit_order) insertData.audit_order = data.audit_order;
  107. result = await transaction.insert(this.tableName, insertData);
  108. await transaction.commit();
  109. } catch (err) {
  110. await transaction.rollback();
  111. throw err;
  112. }
  113. if (result.affectedRows !== 1) throw '添加审批人失败';
  114. data.id = result.insertId;
  115. return data;
  116. }
  117. async removeAudit(data) {
  118. const group = await this.ctx.service.shenpiGroup.getGroupBySelect(this.ctx.tender.id, data.code);
  119. const delData = {
  120. tid: this.ctx.tender.id,
  121. sp_type: data.code,
  122. sp_status: data.status,
  123. audit_id: data.audit_id,
  124. sp_group: group ? group.id : 0,
  125. };
  126. const audit = await this.getDataByCondition(delData);
  127. const conditon = { tid: this.ctx.tender.id, sp_type: data.code, sp_status: data.status };
  128. if (group) conditon.sp_group = group.id;
  129. const allAudit = await this.getAllDataByCondition({ where: conditon });
  130. const sameOrder = allAudit.filter(x => { return x.audit_order === audit.audit_order; });
  131. const updateData = [];
  132. if (sameOrder.length === 1) {
  133. for (const aa of allAudit) {
  134. if (aa.audit_order > audit.audit_order) updateData.push({ id: aa.id, audit_order: aa.audit_order - 1 });
  135. }
  136. }
  137. const transaction = await this.db.beginTransaction();
  138. try {
  139. await transaction.delete(this.tableName, delData);
  140. if (updateData.length > 0) await transaction.updateRows(this.tableName, updateData);
  141. if (parseInt(data.code) === shenpiConst.sp_type.stage && parseInt(data.status) === shenpiConst.sp_status.gdspl) {
  142. const options = {
  143. where: {
  144. tid: this.ctx.tender.id,
  145. user_id: data.audit_id,
  146. },
  147. };
  148. const updateData = {
  149. status: 0,
  150. };
  151. await transaction.update(this.ctx.service.ledgerCooperation.tableName, updateData, options);
  152. }
  153. await transaction.commit();
  154. return true;
  155. } catch (err) {
  156. await transaction.rollback();
  157. throw err;
  158. }
  159. }
  160. async copyAudit2otherTender(data) {
  161. const transaction = await this.db.beginTransaction();
  162. try {
  163. const shenpi_status = parseInt(data.status);
  164. // 1.复制修改当前审批到其他的tender_info里
  165. // 2.删除其他的shenpiAudit
  166. // 3.添加新的shenpiAudit(还要针对该标段是否为原报进行处理)
  167. const tenderInfoUpdateList = [];
  168. const tenders = [];
  169. for (const tid of data.tidList.split(',')) {
  170. // 获取原报
  171. const tender = await this.ctx.service.tender.getDataById(tid);
  172. if (tender) {
  173. tenders.push({ id: parseInt(tid), user_id: tender.user_id });
  174. const shenpiInfo = await this.ctx.service.tenderInfo.getTenderShenpiInfo(tid);
  175. // 把当前期状态复制到其他标段里
  176. if (shenpiInfo[data.code] !== shenpi_status) {
  177. shenpiInfo[data.code] = shenpi_status;
  178. tenderInfoUpdateList.push({ row: { shenpi: JSON.stringify(shenpiInfo) }, where: { tid: parseInt(tid) } });
  179. }
  180. }
  181. }
  182. if (tenderInfoUpdateList.length > 0) await transaction.updateRows(this.ctx.service.tenderInfo.tableName, tenderInfoUpdateList);
  183. const insertList = [];
  184. const needYB = ['ledger', 'revise', 'change'];
  185. const canYB = needYB.indexOf(data.code) !== -1;
  186. let is_group = false;
  187. let groupList = [];
  188. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  189. groupList = await this.ctx.service.shenpiGroup.getGroupList(this.ctx.tender.id, shenpiConst.sp_type[data.code]);
  190. if (groupList.length > 0) {
  191. is_group = true;
  192. for (const g of groupList) {
  193. g.auditList = await this.getAllDataByCondition({ where: { tid: this.ctx.tender.id, sp_type: shenpiConst.sp_type[data.code], sp_status: shenpi_status, sp_group: g.id } });
  194. }
  195. }
  196. }
  197. for (const t of tenders) {
  198. if (shenpi_status !== shenpiConst.sp_status.sqspr) {
  199. if (shenpi_status === shenpiConst.sp_status.gdspl) {
  200. await transaction.delete(this.ctx.service.shenpiGroup.tableName, {
  201. tid: t.id, sp_type: shenpiConst.sp_type[data.code],
  202. });
  203. }
  204. await transaction.delete(this.tableName, { tid: t.id, sp_type: shenpiConst.sp_type[data.code], sp_status: shenpi_status });
  205. if (is_group) {
  206. for (const g of groupList) {
  207. const result = await transaction.insert(this.ctx.service.shenpiGroup.tableName, {
  208. tid: t.id,
  209. sp_type: shenpiConst.sp_type[data.code],
  210. name: g.name,
  211. is_select: g.is_select,
  212. change_type: g.change_type,
  213. create_time: new Date(),
  214. });
  215. for (const s of g.auditList) {
  216. insertList.push({
  217. tid: t.id,
  218. sp_type: shenpiConst.sp_type[data.code],
  219. sp_status: shenpi_status,
  220. audit_id: s.audit_id,
  221. audit_type: s.audit_type,
  222. audit_order: s.audit_order,
  223. sp_group: result.insertId,
  224. });
  225. }
  226. }
  227. } else {
  228. const sourceList = data.auditList.filter(x => { return x.audit_id && (x.audit_id !== t.user_id || canYB); });
  229. sourceList.sort((a, b) => { return a.audit_order - b.audit_order; });
  230. let audit_order = 0, curAuditOrder = 0;
  231. for (const s of sourceList) {
  232. if (s.audit_order !== curAuditOrder) {
  233. curAuditOrder = s.audit_order;
  234. audit_order = audit_order + 1;
  235. }
  236. insertList.push({
  237. tid: t.id,
  238. sp_type: shenpiConst.sp_type[data.code],
  239. sp_status: shenpi_status,
  240. audit_id: s.audit_id,
  241. audit_type: s.audit_type,
  242. audit_order: audit_order,
  243. sp_group: 0,
  244. });
  245. }
  246. }
  247. }
  248. }
  249. // console.log(tenderInfoUpdateList, insertList);
  250. if (insertList.length > 0) await transaction.insert(this.tableName, insertList);
  251. await transaction.commit();
  252. return true;
  253. } catch (err) {
  254. await transaction.rollback();
  255. throw err;
  256. }
  257. }
  258. async copyAudit2otherShenpi(data) {
  259. const transaction = await this.db.beginTransaction();
  260. try {
  261. const shenpi_status = parseInt(data.status);
  262. // 1.修改当前审批到它的tender_info里
  263. // 2.删除相同审批状态的shenpiAudit
  264. // 3.添加新的shenpiAudit(还要针对该标段是否为原报进行处理)
  265. const insertList = [];
  266. const needYB = ['ledger', 'revise', 'change'];
  267. const shenpiInfo = await this.ctx.service.tenderInfo.getTenderShenpiInfo(this.ctx.tender.id);
  268. for (const code of data.shenpiList.split(',')) {
  269. // 把当前审批状态复制到其他标段里
  270. if (shenpiInfo[code] !== shenpi_status) {
  271. shenpiInfo[code] = shenpi_status;
  272. }
  273. if (shenpiInfo[code] !== shenpiConst.sp_status.sqspr) {
  274. if (shenpiInfo[code] === shenpiConst.sp_status.gdspl) {
  275. const group = await this.ctx.service.shenpiGroup.getAllDataByCondition({ where: { tid: this.ctx.tender.id, sp_type: shenpiConst.sp_type[code] } });
  276. if (group && group.length > 0) {
  277. throw '选择同步的流程中存在审批组,无法设置同步';
  278. }
  279. }
  280. await transaction.delete(this.tableName, { tid: this.ctx.tender.id, sp_type: shenpiConst.sp_type[code], sp_status: shenpiInfo[code] });
  281. for (const aid of data.aidList.split(',')) {
  282. if (aid && parseInt(aid) !== this.ctx.tender.data.user_id || (parseInt(aid) === this.ctx.tender.data.user_id && needYB.indexOf(code) !== -1)) {
  283. const insertData = {
  284. tid: this.ctx.tender.id,
  285. sp_type: shenpiConst.sp_type[code],
  286. sp_status: shenpi_status,
  287. audit_id: parseInt(aid),
  288. audit_order: insertList.length + 1,
  289. };
  290. insertList.push(insertData);
  291. }
  292. }
  293. }
  294. }
  295. await transaction.update(this.ctx.service.tenderInfo.tableName,
  296. {
  297. shenpi: JSON.stringify(shenpiInfo),
  298. },
  299. {
  300. where: {
  301. tid: this.ctx.tender.id,
  302. },
  303. });
  304. if (insertList.length > 0) await transaction.insert(this.tableName, insertList);
  305. await transaction.commit();
  306. return true;
  307. } catch (err) {
  308. await transaction.rollback();
  309. throw err;
  310. }
  311. }
  312. async setAuditType(data) {
  313. const conn = await this.db.beginTransaction();
  314. try {
  315. const updateData = { audit_type: data.audit_type };
  316. const group = await this.ctx.service.shenpiGroup.getGroupBySelect(this.ctx.tender.id, data.code);
  317. const condition = {
  318. tid: this.ctx.tender.id,
  319. sp_type: data.code,
  320. sp_status: data.status,
  321. audit_id: data.audit_id,
  322. sp_group: group ? group.id : 0,
  323. };
  324. await conn.update(this.tableName, updateData, { where: condition });
  325. await conn.commit();
  326. } catch (err) {
  327. await conn.rollback();
  328. throw err;
  329. }
  330. }
  331. // 更新审批流程
  332. async updateAuditList(transaction, tenderId, sp_status, sp_type, ids) {
  333. if (sp_status === shenpiConst.sp_status.gdspl) {
  334. const auditList = await this.getAuditList(tenderId, sp_type, sp_status);
  335. const oldIds = this._.map(auditList, 'audit_id');
  336. if (this._.isEqual(ids, oldIds)) {
  337. return;
  338. }
  339. // 更新固定审批流
  340. await transaction.delete(this.tableName, { tid: tenderId, sp_type, sp_status });
  341. const insertDatas = [];
  342. for (const [i, id] of ids.entries()) {
  343. insertDatas.push({
  344. tid: tenderId,
  345. sp_type,
  346. sp_status,
  347. audit_id: id,
  348. audit_order: i + 1,
  349. });
  350. }
  351. await transaction.insert(this.tableName, insertDatas);
  352. if (sp_type === shenpiConst.sp_type.stage) {
  353. // 判断哪些audit_id不存在了,哪些audit_为新增
  354. const exist = this._.difference(ids, oldIds);// 判断新增的
  355. const unExist = this._.difference(oldIds, ids);// 判断已删除的
  356. console.log(ids, oldIds, exist, unExist);
  357. if (exist.length > 0) {
  358. const options = {
  359. where: {
  360. tid: this.ctx.tender.id,
  361. user_id: exist,
  362. },
  363. };
  364. const updateData = {
  365. status: 1,
  366. };
  367. await transaction.update(this.ctx.service.ledgerCooperation.tableName, updateData, options);
  368. }
  369. if (unExist.length > 0) {
  370. const options2 = {
  371. where: {
  372. tid: this.ctx.tender.id,
  373. user_id: unExist,
  374. },
  375. };
  376. const updateData2 = {
  377. status: 0,
  378. };
  379. await transaction.update(this.ctx.service.ledgerCooperation.tableName, updateData2, options2);
  380. }
  381. }
  382. } else if (sp_status === shenpiConst.sp_status.gdzs) {
  383. const audit = await this.getAudit(tenderId, sp_type, sp_status);
  384. if (audit && audit.audit_id !== ids[ids.length - 1]) {
  385. // 更换终审
  386. await transaction.update(this.tableName, { audit_id: ids[ids.length - 1] }, { where: { tid: tenderId, sp_type, sp_status } });
  387. } else if (!audit) {
  388. await transaction.insert(this.tableName, { tid: tenderId, sp_type, sp_status, audit_id: ids[ids.length - 1] });
  389. }
  390. }
  391. }
  392. async updateAuditListWithAuditType(transaction, tenderId, sp_status, sp_type, auditGroup, sp_group = 0) {
  393. const auditList = await this.getAuditList(tenderId, sp_type, sp_status, sp_group);
  394. const newAuditList = [];
  395. for (const group of auditGroup) {
  396. newAuditList.push(...group);
  397. }
  398. let sameAudit = auditList.length === newAuditList.length;
  399. if (sameAudit) {
  400. for (const audit of auditList) {
  401. const newAudit = newAuditList.find(x => { return x.audit_id === audit.aid; });
  402. if (!newAudit || newAudit.audit_order !== audit.audit_order || newAudit.audit_type !== audit.audit_type) {
  403. sameAudit = false;
  404. break;
  405. }
  406. }
  407. }
  408. if (sameAudit) return;
  409. // 更新固定审批流
  410. await transaction.delete(this.tableName, { tid: tenderId, sp_type, sp_status, sp_group });
  411. const insertDatas = [];
  412. for (const a of newAuditList) {
  413. insertDatas.push({
  414. tid: tenderId,
  415. sp_type,
  416. sp_status,
  417. audit_id: a.aid || a.uid || a.audit_id,
  418. audit_order: a.audit_order,
  419. audit_type: a.audit_type,
  420. sp_group,
  421. });
  422. }
  423. await transaction.insert(this.tableName, insertDatas);
  424. }
  425. async getRemoveTenders(tenders) {
  426. const removeTenders = [];
  427. for (const tender of tenders) {
  428. const shenpiInfo = await this.ctx.service.tenderInfo.getTenderShenpiInfo(tender.id);
  429. if (!shenpiInfo) {
  430. removeTenders.push(tender.id);
  431. } else {
  432. tender.shenpiInfo = shenpiInfo;
  433. // 获取所有的固定审批流或固定终审
  434. const shenpiauditList = {};
  435. for (const shenpi in tender.shenpiInfo) {
  436. if (tender.shenpiInfo[shenpi] === shenpiConst.sp_status.gdspl) {
  437. const group = await this.ctx.service.shenpiGroup.getGroupBySelect(tender.id, shenpiConst.sp_type[shenpi]);
  438. const shenpiList = await this.getAuditList(tender.id, shenpiConst.sp_type[shenpi], tender.shenpiInfo[shenpi], group ? group.id : 0);
  439. const shenpiIdList = this._.map(shenpiList, 'audit_id');
  440. shenpiauditList[shenpi] = shenpiIdList.length ? shenpiIdList : null;
  441. } else if (tender.shenpiInfo[shenpi] === shenpiConst.sp_status.gdzs) {
  442. const shenpiInfo = await this.getDataByCondition({ tid: tender.id, sp_type: shenpiConst.sp_type[shenpi], sp_status: tender.shenpiInfo[shenpi] });
  443. shenpiauditList[shenpi] = shenpiInfo && shenpiInfo.audit_id ? [shenpiInfo.audit_id] : null;
  444. }
  445. }
  446. tender.shenpiauditList = shenpiauditList;
  447. }
  448. }
  449. return removeTenders;
  450. }
  451. async noYbShenpiList(uid, shenpiList) {
  452. // 剔除原报及分析审批流中的审批人
  453. const yBIndex = shenpiList.findIndex(x => { return x.audit_id === uid; });
  454. if (yBIndex !== -1) {
  455. const yB = shenpiList[yBIndex];
  456. if (yB.audit_type !== auditType.key.common) {
  457. // 如果是会签或签且人数只有2人,则audit_type变为common
  458. const curSps = shenpiList.filter(x => { return x.audit_order === yB.audit_order; });
  459. if (curSps.length === 1) {
  460. shenpiList.forEach(x => { if (x.audit_order > yB.audit_order) x.audit_order--; });
  461. } else if (curSps.length === 2) {
  462. curSps.forEach(x => { x.audit_type = auditType.key.common; });
  463. }
  464. } else {
  465. // 比它大的audit_order都要-1;
  466. shenpiList.forEach(x => { if (x.audit_order > yB.audit_order) x.audit_order--; });
  467. }
  468. shenpiList.splice(yBIndex, 1);
  469. }
  470. }
  471. async saveUnionAudit(tid, data) {
  472. const orgData = await this.getAllDataByCondition({ where: { id: data.map(x => { return x.id; }) } });
  473. for (const od of orgData) {
  474. if (od.tid !== tid) throw '保存数据错误,请刷新页面后重试';
  475. }
  476. const updateData = data.map(x => { return { id: x.id, audit_ledger_id: x.audit_ledger_id }; });
  477. if (updateData.length > 0) await this.db.updateRows(this.tableName, updateData);
  478. }
  479. }
  480. return ShenpiAudit;
  481. };