quality.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. 'use strict';
  2. /**
  3. * 质量管理 - 工程质量
  4. *
  5. * @author Mai
  6. * @date 2024/7/22
  7. * @version
  8. */
  9. class RuleCheck {
  10. sortCondition(condition) {
  11. const fieldKey = ['gongxu_name', 'yinbi_name', 'file_count', 'file_name'];
  12. condition.forEach(c => { c.fieldKeyIndex = fieldKey.indexOf(c.fieldKey); });
  13. condition.sort((a, b) => { return a.fieldKeyIndex - b.fieldKeyIndex; });
  14. }
  15. fileCountCheck(files, check) {
  16. if (check.operateKey === '>') return files.length > parseInt(check.value);
  17. if (check.operateKey === '=') return files.length === parseInt(check.value);
  18. }
  19. fileNameCheck(files, check) {
  20. const matchName = check.multi ? check.value.split(';') : [check.value];
  21. if (check.operateKey === '=') return files.findIndex(f => { return matchName.indexOf(f.filename) >= 0; }) >= 0;
  22. if (check.operateKey === 'has') return files.findIndex(f => {
  23. return matchName.findIndex(x => { return f.filename.indexOf(x) >= 0; }) >= 0;
  24. }) >= 0;
  25. }
  26. getAllFiles() {
  27. const files = [];
  28. if (this.quality.kaigong) files.push(...this.quality.kaigong.files);
  29. if (this.quality.gongxu) {
  30. for (const gx of this.quality.gongxu.list) {
  31. files.push(...gx.files);
  32. }
  33. }
  34. if (this.quality.pingding) {
  35. files.push(...this.quality.pingding.files);
  36. this.quality.pingding.source_files.forEach(sf => {
  37. if (sf.spec_type === 'add') files.push(sf);
  38. });
  39. }
  40. if (this.quality.jiaogong) files.push(...this.quality.jiaogong.files);
  41. // if (this.quality.yinbi) {
  42. // for (const yb of this.quality.yinbi.list) {
  43. // files.push(...yb.files);
  44. // }
  45. // }
  46. return files;
  47. }
  48. kaigongCheck(check) {
  49. if (!this.quality.kaigong) return false;
  50. switch (check.fieldKey) {
  51. case 'file_count':
  52. return this.fileCountCheck(this.quality.kaigong.files, check);
  53. case 'file_name':
  54. return this.fileNameCheck(this.quality.kaigong.files, check);
  55. default:
  56. return false;
  57. }
  58. }
  59. GongxuNameCheck(check) {
  60. const matchName = check.multi ? check.value.split(';') : [check.value];
  61. if (check.operateKey === '=') {
  62. this.matchGongxu = this.quality.gongxu.list.filter(f => { return matchName.indexOf(f.name) >= 0; });
  63. }
  64. if (check.operateKey === 'has') {
  65. this.matchGongxu = this.quality.gongxu.list.filter(f => {
  66. return matchName.findIndex(x => { return f.name.indexOf(x) >= 0; }) >= 0;
  67. });
  68. }
  69. return this.matchGongxu.length > 0;
  70. }
  71. getGongxuFiles() {
  72. const files = [];
  73. const gongxuList = this.matchGongxu || this.quality.gongxu.list;
  74. for (const gx of gongxuList) {
  75. files.push(...gx.files);
  76. }
  77. return files;
  78. }
  79. gongxuCheck(check) {
  80. switch (check.fieldKey) {
  81. case 'gongxu_name':
  82. return this.GongxuNameCheck(check);
  83. case 'file_count':
  84. return this.fileCountCheck(this.getGongxuFiles(), check);
  85. case 'file_name':
  86. return this.fileNameCheck(this.getGongxuFiles(), check);
  87. default:
  88. return false;
  89. }
  90. }
  91. pingdingCheck(check) {
  92. if (!this.quality.pingding) return false;
  93. const files = [...this.quality.pingding.files, ...this.quality.pingding.source_files];
  94. switch (check.fieldKey) {
  95. case 'file_count':
  96. return this.fileCountCheck(files, check);
  97. case 'file_name':
  98. return this.fileNameCheck(files, check);
  99. default:
  100. return false;
  101. }
  102. }
  103. jiaogongCheck(check) {
  104. if (!this.quality.jiaogong) return false;
  105. switch (check.fieldKey) {
  106. case 'file_count':
  107. return this.fileCountCheck(this.quality.jiaogong.files, check);
  108. case 'file_name':
  109. return this.fileNameCheck(this.quality.jiaogong.files, check);
  110. default:
  111. return false;
  112. }
  113. }
  114. YinbiNameCheck(check) {
  115. const matchName = check.multi ? check.value.split(';') : [check.value];
  116. if (check.operateKey === '=') {
  117. this.matchYinbi = this.quality.yinbi.list.filter(f => { return matchName.indexOf(f.name) >= 0; });
  118. }
  119. if (check.operateKey === '>') {
  120. this.matchYinbi = this.quality.yinbi.list.filter(f => {
  121. return matchName.findIndex(x => { return f.name.indexOf(x) >= 0; }) >= 0;
  122. });
  123. }
  124. return this.matchYinbi.length > 0;
  125. }
  126. getYinbiFiles() {
  127. const files = [];
  128. const yinbiList = this.matchYinbi || this.quality.yinbi.list;
  129. for (const yb of yinbiList) {
  130. files.push(...yb.files);
  131. }
  132. return files;
  133. }
  134. yinbiCheck(check) {
  135. switch (check.fieldKey) {
  136. case 'gongxu_name':
  137. return this.YinbiNameCheck(check);
  138. case 'file_count':
  139. return this.fileCountCheck(this.getYinbiFiles(), check);
  140. case 'file_name':
  141. return this.fileNameCheck(this.getYinbiFiles(), check);
  142. default:
  143. return false;
  144. }
  145. }
  146. allFilesCheck(check) {
  147. const allFiles = this.getAllFiles();
  148. switch (check.fieldKey) {
  149. case 'file_count':
  150. return this.fileCountCheck(allFiles, check);
  151. case 'file_name':
  152. return this.fileNameCheck(allFiles, check);
  153. default:
  154. return false;
  155. }
  156. }
  157. conditionCheck(check) {
  158. switch (check.blockKey) {
  159. case 'kaigong':
  160. return this.kaigongCheck(check);
  161. case 'gongxu':
  162. return this.gongxuCheck(check);
  163. case 'pingding':
  164. return this.pingdingCheck(check);
  165. case 'jiaogong':
  166. return this.jiaogongCheck(check);
  167. case 'yinbi':
  168. return this.yinbiCheck(check);
  169. case 'all':
  170. return this.allFilesCheck(check);
  171. default:
  172. return false;
  173. }
  174. }
  175. calcQualityStatus(quality, group) {
  176. this.quality = quality;
  177. this.group = group;
  178. for (const r of group.rules) {
  179. if (r.condition.length === 0) return false;
  180. if (r.condition.length > 1) this.sortCondition(r.condition);
  181. }
  182. const match = group.rules.filter(r => {
  183. this.matchGongxu = null;
  184. this.matchYinbi = null;
  185. for (const check of r.condition) {
  186. if (!this.conditionCheck(check)) {
  187. return false;
  188. }
  189. }
  190. return true;
  191. });
  192. if (match.length === 0) return null;
  193. const data = {};
  194. for (const m of match) {
  195. for (const s of m.push_status) {
  196. if (!data[s.field] || s.value > data[s.field]) {
  197. data[s.field] = s.value;
  198. }
  199. }
  200. }
  201. return data;
  202. }
  203. }
  204. module.exports = app => {
  205. class Quality extends app.BaseService {
  206. /**
  207. * 构造函数
  208. *
  209. * @param {Object} ctx - egg全局变量
  210. * @return {void}
  211. */
  212. constructor(ctx) {
  213. super(ctx);
  214. this.tableName = 'quality';
  215. this.editableColumns = ['gxby_status', 'gxby_date', 'gxby_limit', 'dagl_status', 'dagl_limit'];
  216. this.blockType = {
  217. kaigong: { key: 'kaigong', name: '开工' },
  218. gongxu: { key: 'gongxu', name: '工序' },
  219. jiaogong: { key: 'jiaogong', name: '中间交工' },
  220. pingding: { key: 'pingding', name: '评定' },
  221. yinbi: { key: 'yinbi', name: '隐蔽工程' },
  222. shiyan: { key: 'shiyan', name: '试验检测' },
  223. waiwei: { key: 'waiwei', name: '外委检测' },
  224. sanfang: { key: 'sanfang', name: '第三方检测' },
  225. };
  226. }
  227. async saveQualityManage(tid, data) {
  228. const quality = await this.getDataByCondition({ tid, rela_type: data.rela_type, rela_id: data.rela_id, rela_name: data.rela_name });
  229. if (quality) {
  230. const updateData = { id: quality.id, group_id: data.group_id, update_uid: this.ctx.session.sessionUser.accountId, };
  231. await this.db.update(this.tableName, updateData);
  232. updateData.rela_id = data.rela_id;
  233. updateData.rela_name = data.rela_name;
  234. return updateData;
  235. } else {
  236. const newQuality = {
  237. id: this.uuid.v4(), tid, rela_type: data.rela_type, rela_id: data.rela_id, rela_name: data.rela_name,
  238. create_uid: this.ctx.session.sessionUser.accountId, update_uid: this.ctx.session.sessionUser.accountId,
  239. group_id: data.group_id,
  240. };
  241. await this.db.insert(this.tableName, newQuality);
  242. return newQuality;
  243. }
  244. }
  245. async saveQuality(quality, filter, data, conn) {
  246. data.update_uid = this.ctx.session.sessionUser.accountId;
  247. data.is_used = 1;
  248. if (quality) {
  249. data.id = quality.id;
  250. if (conn) {
  251. await conn.update(this.tableName, data);
  252. } else {
  253. await this.db.update(this.tableName, data);
  254. }
  255. return data;
  256. } else {
  257. data.id = this.uuid.v4();
  258. data.tid = this.ctx.tender.id;
  259. data.rela_type = filter.rela_type;
  260. data.rela_id = filter.rela_id;
  261. data.rela_name = filter.rela_name;
  262. data.create_uid = this.ctx.session.sessionUser.accountId;
  263. if (conn) {
  264. await conn.insert(this.tableName, data);
  265. } else {
  266. await this.db.insert(this.tableName, data);
  267. }
  268. return data;
  269. }
  270. }
  271. async getQuality(filter) {
  272. if (filter.quality_id) return await this.getDataByCondition({ id: filter.quality_id });
  273. if (filter.rela_type && filter.rela_id) return await this.getDataByCondition({ tid: filter.tid || this.ctx.tender.id, rela_id: filter.rela_id, rela_name: filter.rela_name });
  274. throw '参数错误';
  275. }
  276. async _loadKgData(quality) {
  277. if (!quality.kaigong_time) return;
  278. quality.kaigong = {};
  279. for (const p in quality) {
  280. if (p.indexOf('kaigong_') !== 0) continue;
  281. quality.kaigong[p] = quality[p];
  282. delete quality[p];
  283. }
  284. const files = await this.ctx.service.qualityFile.getBlockFiles(quality, 'kaigong');
  285. quality.kaigong.files = files.filter(f => { return !f.spec_type; });
  286. quality.kaigong.qa_files = files.filter(f => { return f.spec_type === 'qa'; });
  287. // todo 加载开工审批数据
  288. }
  289. async _loadGxData(quality) {
  290. quality.gongxu = {};
  291. // todo 加载工序审批数据
  292. quality.gongxu.list = await this.ctx.service.qualityGongxu.getAllDataByCondition({ where: { quality_id: quality.id }, orders:[['create_time', 'asc']] });
  293. for (const gx of quality.gongxu.list) {
  294. gx.canEdit = gx.user_id === this.ctx.session.sessionUser.accountId;
  295. gx.files = await this.ctx.service.qualityFile.getBlockFiles(quality, 'gongxu', gx.id);
  296. // todo 加载工序步骤审批数据
  297. }
  298. }
  299. async _loadPdData(quality) {
  300. if (!quality.kaigong && quality.gongxu.list.length === 0) return;
  301. quality.pingding = {};
  302. for (const p in quality) {
  303. if (p.indexOf('pingding_') !== 0) continue;
  304. quality.kaigong[p] = quality[p];
  305. delete quality[p];
  306. }
  307. const files = await this.ctx.service.qualityFile.getBlockFiles(quality, 'pingding');
  308. quality.pingding.files = files.filter(f => { return !f.spec_type; });
  309. quality.pingding.source_files = files.filter(f => { return f.spec_type === 'add'; }); // addtional
  310. if (quality.gongxu) {
  311. for (const gx of quality.gongxu.list) {
  312. const qaFiles = gx.files.filter(f => { return f.spec_type === 'qa'; });
  313. for (const f of qaFiles) {
  314. const qaF = JSON.parse(JSON.stringify(f));
  315. qaF.canEdit = false;
  316. quality.pingding.source_files.push(qaF);
  317. }
  318. }
  319. }
  320. // todo 加载评定审批数据
  321. }
  322. async _loadJgData(quality) {
  323. if (!quality.kaigong && quality.gongxu.list.length === 0) return;
  324. quality.jiaogong = {};
  325. for (const p in quality) {
  326. if (p.indexOf('jiaogong_') !== 0) continue;
  327. quality.jiaogong[p] = quality[p];
  328. delete quality[p];
  329. }
  330. quality.jiaogong.files = await this.ctx.service.qualityFile.getBlockFiles(quality, 'jiaogong');
  331. }
  332. async _loadYbData(quality) {
  333. quality.yinbi = {};
  334. quality.yinbi.list = await this.ctx.service.qualityYinbi.getAllDataByCondition({ where: { quality_id: quality.id }, orders:[['create_time', 'asc']] });
  335. for (const yb of quality.yinbi.list) {
  336. yb.canEdit = yb.user_id === this.ctx.session.sessionUser.accountId;
  337. const files = await this.ctx.service.qualityFile.getBlockFiles(quality, 'yinbi', yb.id);
  338. yb.before_files = files.filter(f => { return f.spec_type === 'before'; });
  339. yb.after_files = files.filter(f => { return f.spec_type === 'after'; });
  340. }
  341. }
  342. async loadQualityDetail(quality) {
  343. if (!quality) return;
  344. await this._loadKgData(quality);
  345. await this._loadGxData(quality);
  346. await this._loadPdData(quality);
  347. await this._loadJgData(quality);
  348. await this._loadYbData(quality);
  349. }
  350. async getQualityGroup(quality) {
  351. if (quality.group_id) return quality.group_id;
  352. const ledger = await this.ctx.service.ledger.getDataById(quality.rela_id);
  353. const sql = 'SELECT l.id, l.ledger_id, l.level, q.group_id ' +
  354. ` FROM ${this.tableName} q LEFT JOIN ${this.ctx.service.ledger.tableName} l ON q.rela_id = l.id ` +
  355. ` WHERE q.tid = ${quality.tid} and l.ledger_id in (${ledger.full_path.split('-').join(', ')}) and group_id <> ''` +
  356. ' ORDER BY l.level DESC';
  357. const allQuality = await this.db.query(sql);
  358. return allQuality.length > 0 ? allQuality[0].group_id : '';
  359. }
  360. async checkQualityStatus(quality) {
  361. const groupId = await this.getQualityGroup(quality);
  362. if (!groupId) return null;
  363. const groupRule = await this.ctx.service.qualityRule.getGroupRule(groupId);
  364. if (!groupRule) return null;
  365. const ruleCheck = new RuleCheck();
  366. return ruleCheck.calcQualityStatus(quality, groupRule);
  367. }
  368. async checkQualityStatusAndSave(quality) {
  369. const data = await this.checkQualityStatus(quality);
  370. if (!data) return;
  371. for (const field in data) {
  372. quality[field] = data[field];
  373. }
  374. data.id = quality.id;
  375. await this.db.update(this.tableName, data);
  376. }
  377. async kaigong(filter, name, date) {
  378. const quality = await this.getQuality(filter);
  379. const conn = await this.db.beginTransaction();
  380. try {
  381. const kaigongData = {
  382. kaigong_name: name || '开工工序', kaigong_date: date || this.ctx.moment().format('YYYY-MM-DD'),
  383. kaigong_uid: this.ctx.session.sessionUser.accountId, kaigong_time: new Date(),
  384. };
  385. await this.saveQuality(quality, filter, kaigongData, conn);
  386. await conn.commit();
  387. } catch (err) {
  388. await conn.rollback();
  389. throw err;
  390. }
  391. }
  392. async delKaigong(filter) {
  393. const quality = await this.getQuality(filter);
  394. if (!quality || !quality.kaigong_uid) throw '该工程未开工';
  395. if (quality.kaigong_uid !== this.ctx.session.sessionUser.accountId) throw '开工数据不是您新增的,无权删除';
  396. const conn = await this.db.beginTransaction();
  397. try {
  398. await this.saveQuality(quality, filter, { kaigong_name: '', kaigong_date: '', kaigong_uid: 0, kaigong_time: null }, conn);
  399. await conn.update(this.ctx.service.qualityFile.tableName, { is_deleted: 1 }, { where: { quality_id: quality.id, block_type: 'kaigong' } });
  400. await conn.commit();
  401. } catch (err) {
  402. await conn.rollback();
  403. throw err;
  404. }
  405. }
  406. async pushIncStatus(select) {
  407. const quality = await this.ctx.service.quality.getAllDataByCondition({ where: { tid: this.ctx.tender.id, rela_id: select, is_used: 1 } });
  408. if (quality.length === 0) return 0;
  409. const xmjInsert = [], xmjUpdate = [], posInsert = [], posUpdate = [];
  410. const xmjQuality = [], posQuality = [];
  411. quality.forEach(q => {
  412. if (q.rela_type === 'xmj') {
  413. xmjQuality.push(q);
  414. } else {
  415. posQuality.push(q);
  416. }
  417. });
  418. const xmjExtra = xmjQuality.length > 0 ? await this.ctx.service.ledgerExtra.getAllDataByCondition({ where: { id: xmjQuality.map(x => { return x.rela_id; }) } }) : [];
  419. for (const xq of xmjQuality) {
  420. const xe = xmjExtra.find(x => { return x.id === xq.rela_id; });
  421. const wbs_url = `/3f/zh/info?pid=${this.ctx.session.sessionProject.id}&tid=${xq.tid}&${xq.rela_type}id=${xq.rela_id}`;
  422. if (xe) {
  423. xmjUpdate.push({ id: xe.id, gxby_status: xq.gxby_status, gxby_date: xq.gxby_date, dagl_status: xq.dagl_status, wbs_url });
  424. } else {
  425. xmjInsert.push({ id: xq.rela_id, gxby_status: xq.gxby_status, gxby_date: xq.gxby_date, dagl_status: xq.dagl_status, wbs_url });
  426. }
  427. }
  428. const posExtra = posQuality.length > 0 ? await this.ctx.service.posExtra.getAllDataByCondition({ where: { id: posQuality.map(x => { return x.rela_id; }) } }) : [];
  429. for (const pq of posQuality) {
  430. const pe = posExtra.find(x => { return x.id === pq.rela_id; });
  431. const wbs_url = `/3f/zh/info?pid=${this.ctx.session.sessionProject.id}&tid=${pq.tid}&${pq.rela_type}id=${pq.rela_id}`;
  432. if (pe) {
  433. posUpdate.push({ id: pe.id, gxby_status: pq.gxby_status, gxby_date: pq.gxby_date, dagl_status: pq.dagl_status, wbs_url });
  434. } else {
  435. posInsert.push({ id: pq.rela_id, gxby_status: pq.gxby_status, gxby_date: pq.gxby_date, dagl_status: pq.dagl_status, wbs_url });
  436. }
  437. }
  438. const conn = await this.db.beginTransaction();
  439. try {
  440. if (xmjInsert.length > 0) await conn.insert(this.ctx.service.ledgerExtra.tableName, xmjInsert);
  441. if (xmjUpdate.length > 0) await conn.updateRows(this.ctx.service.ledgerExtra.tableName, xmjUpdate);
  442. if (posInsert.length > 0) await conn.insert(this.ctx.service.posExtra.tableName, posInsert);
  443. if (posUpdate.length > 0) await conn.updateRows(this.ctx.service.posExtra.tableName, posUpdate);
  444. await conn.commit();
  445. } catch (err) {
  446. this.ctx.log(err);
  447. await conn.rollback();
  448. throw '推送状态错误';
  449. }
  450. return xmjInsert.length + xmjUpdate.length + posInsert.length + posUpdate.length;
  451. }
  452. async pushAllStatus() {
  453. const quality = await this.ctx.service.quality.getAllDataByCondition({ where: { tid: this.ctx.tender.id, is_used: 1 } });
  454. if (quality.length === 0) return 0;
  455. const xmjQuality = [], posQuality = [];
  456. quality.forEach(q => {
  457. if (q.rela_type === 'xmj') {
  458. xmjQuality.push(q);
  459. } else {
  460. posQuality.push(q);
  461. }
  462. });
  463. const xmjInsert = [], xmjUpdate = [], posInsert = [], posUpdate = [];
  464. const xmjExtra = await this.ctx.service.ledgerExtra.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
  465. for (const xq of xmjQuality) {
  466. const xe = xmjExtra.find(x => { return x.id === xq.rela_id; });
  467. const wbs_url = `/3f/zh/info?pid=${this.ctx.session.sessionProject.id}&tid=${xq.tid}&${xq.rela_type}id=${xq.rela_id}`;
  468. if (xe) {
  469. xmjUpdate.push({ id: xe.id, gxby_status: xq.gxby_status, gxby_date: xq.gxby_date, dagl_status: xq.dagl_status, wbs_url });
  470. } else {
  471. xmjInsert.push({ id: xq.rela_id, tid: this.ctx.tender.id, gxby_status: xq.gxby_status, gxby_date: xq.gxby_date, dagl_status: xq.dagl_status, wbs_url });
  472. }
  473. }
  474. const posExtra = await this.ctx.service.posExtra.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
  475. for (const pq of posQuality) {
  476. const pe = posExtra.find(x => { return x.id === pq.rela_id; });
  477. const wbs_url = `/3f/zh/info?pid=${this.ctx.session.sessionProject.id}&tid=${pq.tid}&${pq.rela_type}id=${pq.rela_id}`;
  478. if (pe) {
  479. posUpdate.push({ id: pe.id, gxby_status: pq.gxby_status, gxby_date: pq.gxby_date, dagl_status: pq.dagl_status, wbs_url });
  480. } else {
  481. posInsert.push({ id: pq.rela_id, tid: this.ctx.tender.id, gxby_status: pq.gxby_status, gxby_date: pq.gxby_date, dagl_status: pq.dagl_status, wbs_url });
  482. }
  483. }
  484. const conn = await this.db.beginTransaction();
  485. try {
  486. const defaultData = { gxby_status: -1, gxby_date: null, dagl_status: -1 };
  487. await conn.update(this.ctx.service.ledgerExtra.tableName, defaultData, { where: {tid: this.ctx.tender.id } });
  488. await conn.update(this.ctx.service.posExtra.tableName, defaultData, { where: {tid: this.ctx.tender.id } });
  489. if (xmjInsert.length > 0) await conn.insert(this.ctx.service.ledgerExtra.tableName, xmjInsert);
  490. if (xmjUpdate.length > 0) await conn.updateRows(this.ctx.service.ledgerExtra.tableName, xmjUpdate);
  491. if (posInsert.length > 0) await conn.insert(this.ctx.service.posExtra.tableName, posInsert);
  492. if (posUpdate.length > 0) await conn.updateRows(this.ctx.service.posExtra.tableName, posUpdate);
  493. await conn.commit();
  494. } catch (err) {
  495. this.ctx.log(err);
  496. await conn.rollback();
  497. throw '推送状态错误';
  498. }
  499. return xmjInsert.length + xmjUpdate.length + posInsert.length + posUpdate.length;
  500. }
  501. }
  502. return Quality;
  503. };