|
@@ -7,10 +7,11 @@
|
|
|
* @date 2024/7/22
|
|
* @date 2024/7/22
|
|
|
* @version
|
|
* @version
|
|
|
*/
|
|
*/
|
|
|
-const auditConst = require('../const/audit').inspection;
|
|
|
|
|
|
|
+const auditConst = require('../const/quality_inspection');
|
|
|
const pushType = require('../const/audit').pushType;
|
|
const pushType = require('../const/audit').pushType;
|
|
|
const auditType = require('../const/audit').auditType;
|
|
const auditType = require('../const/audit').auditType;
|
|
|
const shenpiConst = require('../const/shenpi');
|
|
const shenpiConst = require('../const/shenpi');
|
|
|
|
|
+const moment = require('moment');
|
|
|
module.exports = app => {
|
|
module.exports = app => {
|
|
|
|
|
|
|
|
class QualityInspectionAudit extends app.BaseService {
|
|
class QualityInspectionAudit extends app.BaseService {
|
|
@@ -34,12 +35,13 @@ module.exports = app => {
|
|
|
* @return {Promise<*>}
|
|
* @return {Promise<*>}
|
|
|
*/
|
|
*/
|
|
|
async getAuditors(inspectionId, times = 1, order_sort = 'asc') {
|
|
async getAuditors(inspectionId, times = 1, order_sort = 'asc') {
|
|
|
- const sql = 'SELECT la.id, la.tid, la.aid, la.times, la.order, la.status, la.opinion, la.is_rectification, la.is_old, la.begin_time, la.end_time, la.audit_type, la.audit_order,' +
|
|
|
|
|
|
|
+ const direction = order_sort === 'desc' ? 'DESC' : 'ASC';
|
|
|
|
|
+ const sql = 'SELECT la.id, la.tid, la.aid, la.times, la.order, la.status, la.opinion, la.is_rectification, la.is_old, la.begin_time, la.end_time, la.audit_type, la.audit_order, la.flow_stage, la.stage_round, la.rectification_item, la.rectification_date,' +
|
|
|
' pa.name, pa.company, pa.role, pa.mobile, pa.telephone, pa.sign_path' +
|
|
' pa.name, pa.company, pa.role, pa.mobile, pa.telephone, pa.sign_path' +
|
|
|
- ` FROM ${this.tableName} la LEFT JOIN ${this.ctx.service.projectAccount.tableName} pa ON la.aid = pa.id` +
|
|
|
|
|
|
|
+ ' FROM ?? la LEFT JOIN ?? pa ON la.aid = pa.id' +
|
|
|
' WHERE la.qiid = ? AND la.times = ?' +
|
|
' WHERE la.qiid = ? AND la.times = ?' +
|
|
|
- ' ORDER BY la.order ' + order_sort;
|
|
|
|
|
- const sqlParam = [inspectionId, times];
|
|
|
|
|
|
|
+ ' ORDER BY la.order ' + direction;
|
|
|
|
|
+ const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, inspectionId, times];
|
|
|
const result = await this.db.query(sql, sqlParam);
|
|
const result = await this.db.query(sql, sqlParam);
|
|
|
const max_sort = this._.max(result.map(x => { return x.audit_order; }));
|
|
const max_sort = this._.max(result.map(x => { return x.audit_order; }));
|
|
|
for (const i in result) {
|
|
for (const i in result) {
|
|
@@ -58,6 +60,11 @@ module.exports = app => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async getAuditorsByStatus(qiId, status, times = 1) {
|
|
async getAuditorsByStatus(qiId, status, times = 1) {
|
|
|
|
|
+ const inspection = await this.ctx.service.qualityInspection.getDataById(qiId);
|
|
|
|
|
+ if (inspection && inspection.flow_version === 1) {
|
|
|
|
|
+ const auditors = await this.getAuditors(qiId, inspection.times);
|
|
|
|
|
+ return auditors.filter(x => !x.is_old && x.flow_stage === inspection.flow_stage && x.stage_round === inspection.stage_round && [2, 12].includes(x.status) && [2, 6, 12].includes(inspection.status));
|
|
|
|
|
+ }
|
|
|
let auditor = [];
|
|
let auditor = [];
|
|
|
let sql = '';
|
|
let sql = '';
|
|
|
let sqlParam = '';
|
|
let sqlParam = '';
|
|
@@ -221,21 +228,23 @@ module.exports = app => {
|
|
|
* @return {Promise<*>}
|
|
* @return {Promise<*>}
|
|
|
*/
|
|
*/
|
|
|
async getAuditInspection(auditorId, spid = '') {
|
|
async getAuditInspection(auditorId, spid = '') {
|
|
|
- const spSql = spid ? ' and t.`spid` = "' + spid + '"' : '';
|
|
|
|
|
|
|
+ const spSql = spid ? ' AND t.spid = ?' : '';
|
|
|
const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`tid`, ma.`qiid`,' +
|
|
const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`tid`, ma.`qiid`,' +
|
|
|
- ' m.`code` As `mcode`, m.`status` As `mstatus`,' +
|
|
|
|
|
|
|
+ ' m.`code` As `mcode`, m.`status` As `mstatus`, m.flow_version, m.flow_stage,' +
|
|
|
' t.`name`, t.`project_id`, t.`type`, t.`user_id`, t.`spid` ' +
|
|
' t.`name`, t.`project_id`, t.`type`, t.`user_id`, t.`spid` ' +
|
|
|
' FROM ?? AS ma' +
|
|
' FROM ?? AS ma' +
|
|
|
' LEFT JOIN ?? AS m On ma.qiid = m.id' +
|
|
' LEFT JOIN ?? AS m On ma.qiid = m.id' +
|
|
|
' LEFT JOIN ?? As t On m.tid = t.id' +
|
|
' LEFT JOIN ?? As t On m.tid = t.id' +
|
|
|
- ' WHERE ((ma.`aid` = ? and (ma.`status` = ? OR ma.`status` = ?)) OR (m.`uid` = ? and ma.`status` = ? and m.`status` = ? and ma.`times` = (m.`times`-1)))' + spSql +
|
|
|
|
|
|
|
+ ' WHERE ((ma.`aid` = ? and (ma.`status` = ? OR ma.`status` = ?) AND ma.times = m.times AND ma.is_old = 0 AND m.status IN (2, 6, 12) AND (m.flow_version = 0 OR (ma.flow_stage = m.flow_stage AND ma.stage_round = m.stage_round))) OR (m.`uid` = ? and ma.`status` = ? and m.`status` = ? and ma.`times` = (m.`times`-1)))' + spSql +
|
|
|
' ORDER BY ma.`begin_time` DESC';
|
|
' ORDER BY ma.`begin_time` DESC';
|
|
|
const sqlParam = [this.tableName, this.ctx.service.qualityInspection.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking, auditConst.status.rectification, auditorId, auditConst.status.checkNo, auditConst.status.checkNo];
|
|
const sqlParam = [this.tableName, this.ctx.service.qualityInspection.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking, auditConst.status.rectification, auditorId, auditConst.status.checkNo, auditConst.status.checkNo];
|
|
|
|
|
+ if (spid) sqlParam.push(spid);
|
|
|
const result = await this.db.query(sql, sqlParam);
|
|
const result = await this.db.query(sql, sqlParam);
|
|
|
// 过滤result中存在重复sid的值, 保留最新的一条
|
|
// 过滤result中存在重复sid的值, 保留最新的一条
|
|
|
const filterResult = [];
|
|
const filterResult = [];
|
|
|
const qiidArr = [];
|
|
const qiidArr = [];
|
|
|
for (const r of result) {
|
|
for (const r of result) {
|
|
|
|
|
+ this.ctx.service.qualityInspection.setFlowLabel(r);
|
|
|
if (qiidArr.indexOf(r.qiid) === -1) {
|
|
if (qiidArr.indexOf(r.qiid) === -1) {
|
|
|
filterResult.push(r);
|
|
filterResult.push(r);
|
|
|
qiidArr.push(r.qiid);
|
|
qiidArr.push(r.qiid);
|
|
@@ -252,14 +261,14 @@ module.exports = app => {
|
|
|
*/
|
|
*/
|
|
|
async getAuditInspectionByWap(auditorId) {
|
|
async getAuditInspectionByWap(auditorId) {
|
|
|
const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`tid`, ma.`qiid`,' +
|
|
const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`tid`, ma.`qiid`,' +
|
|
|
- ' m.`code` As `mcode`, m.`status` As `mstatus`, m.`check_item`, m.`check_date`,' +
|
|
|
|
|
|
|
+ ' m.`code` As `mcode`, m.`status` As `mstatus`, m.flow_version, m.flow_stage, m.`check_item`, m.`check_date`,' +
|
|
|
' t.id As t_id, t.`name` As t_name, t.`project_id` As t_pid, t.`type` As t_type, t.`user_id` As t_uid, t.`status` As t_status, t.`spid`, ' +
|
|
' t.id As t_id, t.`name` As t_name, t.`project_id` As t_pid, t.`type` As t_type, t.`user_id` As t_uid, t.`status` As t_status, t.`spid`, ' +
|
|
|
' ti.`deal_info`' +
|
|
' ti.`deal_info`' +
|
|
|
' FROM ?? AS ma' +
|
|
' FROM ?? AS ma' +
|
|
|
' LEFT JOIN ?? AS m On ma.qiid = m.id' +
|
|
' LEFT JOIN ?? AS m On ma.qiid = m.id' +
|
|
|
' LEFT JOIN ?? As t On m.tid = t.id' +
|
|
' LEFT JOIN ?? As t On m.tid = t.id' +
|
|
|
' LEFT JOIN ?? As ti On m.tid = ti.tid' +
|
|
' LEFT JOIN ?? As ti On m.tid = ti.tid' +
|
|
|
- ' WHERE ma.`aid` = ? and (ma.`status` = ? OR ma.`status` = ?)' +
|
|
|
|
|
|
|
+ ' WHERE ma.`aid` = ? and (ma.`status` = ? OR ma.`status` = ?) AND ma.times = m.times AND ma.is_old = 0 AND m.status IN (2, 6, 12) AND (m.flow_version = 0 OR (ma.flow_stage = m.flow_stage AND ma.stage_round = m.stage_round))' +
|
|
|
' ORDER BY ma.`begin_time` DESC';
|
|
' ORDER BY ma.`begin_time` DESC';
|
|
|
const sqlParam = [this.tableName, this.ctx.service.qualityInspection.tableName, this.ctx.service.tender.tableName, this.ctx.service.tenderInfo.tableName, auditorId, auditConst.status.checking, auditConst.status.rectification];
|
|
const sqlParam = [this.tableName, this.ctx.service.qualityInspection.tableName, this.ctx.service.tender.tableName, this.ctx.service.tenderInfo.tableName, auditorId, auditConst.status.checking, auditConst.status.rectification];
|
|
|
const result = await this.db.query(sql, sqlParam);
|
|
const result = await this.db.query(sql, sqlParam);
|
|
@@ -267,6 +276,7 @@ module.exports = app => {
|
|
|
const filterResult = [];
|
|
const filterResult = [];
|
|
|
const qiidArr = [];
|
|
const qiidArr = [];
|
|
|
for (const r of result) {
|
|
for (const r of result) {
|
|
|
|
|
+ this.ctx.service.qualityInspection.setFlowLabel(r);
|
|
|
if (qiidArr.indexOf(r.qiid) === -1) {
|
|
if (qiidArr.indexOf(r.qiid) === -1) {
|
|
|
filterResult.push(r);
|
|
filterResult.push(r);
|
|
|
qiidArr.push(r.qiid);
|
|
qiidArr.push(r.qiid);
|
|
@@ -357,6 +367,7 @@ module.exports = app => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async updateNewAuditList(inspection, newList) {
|
|
async updateNewAuditList(inspection, newList) {
|
|
|
|
|
+ if (inspection.flow_version === 1) return this.syncFlowReport(inspection, newList);
|
|
|
const transaction = await this.db.beginTransaction();
|
|
const transaction = await this.db.beginTransaction();
|
|
|
try {
|
|
try {
|
|
|
// 先删除旧的审批流,再添加新的
|
|
// 先删除旧的审批流,再添加新的
|
|
@@ -395,6 +406,12 @@ module.exports = app => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async updateLastAudit(inspection, auditList, lastId) {
|
|
async updateLastAudit(inspection, auditList, lastId) {
|
|
|
|
|
+ if (inspection.flow_version === 1) {
|
|
|
|
|
+ const list = auditList.filter(x => x.aid !== lastId).map(x => ({ audit_id: x.aid, audit_type: x.audit_type, audit_order: x.audit_order }));
|
|
|
|
|
+ const order = list.length ? Math.max(...list.map(x => x.audit_order)) + 1 : 1;
|
|
|
|
|
+ list.push({ audit_id: lastId, audit_type: auditType.key.common, audit_order: order });
|
|
|
|
|
+ return this.syncFlowReport(inspection, list);
|
|
|
|
|
+ }
|
|
|
const transaction = await this.db.beginTransaction();
|
|
const transaction = await this.db.beginTransaction();
|
|
|
try {
|
|
try {
|
|
|
// 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
|
|
// 先判断auditList里的aid是否与lastId相同,相同则删除并重新更新order
|
|
@@ -550,20 +567,12 @@ module.exports = app => {
|
|
|
* @return {Promise<*>}
|
|
* @return {Promise<*>}
|
|
|
*/
|
|
*/
|
|
|
async getDonesByAudit(auditorId, spid = '') {
|
|
async getDonesByAudit(auditorId, spid = '') {
|
|
|
- const spSql = spid ? ' and t.`spid` = "' + spid + '"' : '';
|
|
|
|
|
- const status = [auditConst.status.checked, auditConst.status.checkNo, auditConst.status.checkNoPre, auditConst.status.checkStop];
|
|
|
|
|
- const sql =
|
|
|
|
|
- 'SELECT la.`status`, la.`end_time` as `shenpi_time`, la.`qiid`, t.`id`, m.`code` As `code`, t.`name`, t.`spid` ' +
|
|
|
|
|
- ' FROM ?? AS la Left Join ?? AS t ON la.`tid` = t.`id` LEFT JOIN ?? AS m ON la.`qiid` = m.`id`' +
|
|
|
|
|
- ' WHERE la.`aid` = ? AND la.`status` in (' + this.ctx.helper.getInArrStrSqlFilter(status) + ')' + spSql +
|
|
|
|
|
- ' ORDER BY la.`end_time` DESC';
|
|
|
|
|
- const sqlParam = [
|
|
|
|
|
- this.tableName,
|
|
|
|
|
- this.ctx.service.tender.tableName,
|
|
|
|
|
- this.ctx.service.qualityInspection.tableName,
|
|
|
|
|
- auditorId,
|
|
|
|
|
- ];
|
|
|
|
|
- return await this.db.query(sql, sqlParam);
|
|
|
|
|
|
|
+ const sql = 'SELECT la.status, la.flow_stage, la.end_time AS shenpi_time, la.qiid, t.id, m.code, t.name, t.spid FROM ?? la LEFT JOIN ?? t ON la.tid = t.id LEFT JOIN ?? m ON la.qiid = m.id WHERE la.aid = ? AND la.status IN (?, ?, ?, ?)' + (spid ? ' AND t.spid = ?' : '') + ' ORDER BY la.end_time DESC';
|
|
|
|
|
+ const sqlParam = [this.tableName, this.ctx.service.tender.tableName, this.ctx.service.qualityInspection.tableName, auditorId, 3, 5, 6, 4];
|
|
|
|
|
+ if (spid) sqlParam.push(spid);
|
|
|
|
|
+ const records = await this.db.query(sql, sqlParam);
|
|
|
|
|
+ for (const record of records) record.stage_name = record.flow_stage ? auditConst.stageString[record.flow_stage] : '';
|
|
|
|
|
+ return records;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -575,7 +584,8 @@ module.exports = app => {
|
|
|
* @return {Promise<*>}
|
|
* @return {Promise<*>}
|
|
|
*/
|
|
*/
|
|
|
async copyPreAuditors(transaction, preInspection, newInspection) {
|
|
async copyPreAuditors(transaction, preInspection, newInspection) {
|
|
|
- const auditList = await this.getUniqAuditor(preInspection.id, preInspection.times); // 全部参与的审批人
|
|
|
|
|
|
|
+ const previous = await this.getAuditors(preInspection.id, preInspection.times);
|
|
|
|
|
+ const auditList = this._.uniqBy(previous.filter(x => !x.is_old && !x.is_rectification && (preInspection.flow_version !== 1 || x.flow_stage === 1)), x => x.aid + ':' + x.audit_order);
|
|
|
const newAuditors = [];
|
|
const newAuditors = [];
|
|
|
for (const x of auditList) {
|
|
for (const x of auditList) {
|
|
|
if (x.audit_order !== 0 && x.is_rectification === 0) {
|
|
if (x.audit_order !== 0 && x.is_rectification === 0) {
|
|
@@ -583,6 +593,7 @@ module.exports = app => {
|
|
|
tid: preInspection.tid, qiid: newInspection.id, aid: x.aid,
|
|
tid: preInspection.tid, qiid: newInspection.id, aid: x.aid,
|
|
|
times: 1, order: x.audit_order, status: auditConst.status.uncheck,
|
|
times: 1, order: x.audit_order, status: auditConst.status.uncheck,
|
|
|
audit_type: x.audit_type, audit_order: x.audit_order,
|
|
audit_type: x.audit_type, audit_order: x.audit_order,
|
|
|
|
|
+ flow_stage: newInspection.flow_version === 1 ? 1 : 0, stage_round: 1,
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1272,6 +1283,284 @@ module.exports = app => {
|
|
|
}
|
|
}
|
|
|
return content.length ? JSON.stringify(content[0]) : '';
|
|
return content.length ? JSON.stringify(content[0]) : '';
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ async lockFlow(transaction, id) {
|
|
|
|
|
+ const sql = 'SELECT * FROM ?? WHERE id = ? FOR UPDATE';
|
|
|
|
|
+ const sqlParam = [this.ctx.service.qualityInspection.tableName, id];
|
|
|
|
|
+ const rows = await transaction.query(sql, sqlParam);
|
|
|
|
|
+ if (!rows.length || rows[0].tid !== this.ctx.tender.id) throw '巡检不存在';
|
|
|
|
|
+ return rows[0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async prepareDraftFlow(inspection) {
|
|
|
|
|
+ // 已上报的历史单继续使用旧流程,仅转换尚未上报的草稿。
|
|
|
|
|
+ if (inspection.flow_version === 1 || inspection.status !== 1 || inspection.uid !== this.ctx.session.sessionUser.accountId || this.ctx.url.indexOf('/wap/') === 0) return;
|
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
|
+ try {
|
|
|
|
|
+ const current = await this.lockFlow(transaction, inspection.id);
|
|
|
|
|
+ if (!current.flow_version && current.status === 1 && current.uid === this.ctx.session.sessionUser.accountId) {
|
|
|
|
|
+ const changes = { flow_version: 1, flow_stage: 1, stage_round: 1, need_rectification: 1 };
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, changes, { where: { id: current.id } });
|
|
|
|
|
+ await transaction.update(this.tableName, { flow_stage: 1, stage_round: 1 }, { where: { qiid: current.id, times: current.times, is_rectification: 0 } });
|
|
|
|
|
+ Object.assign(current, changes);
|
|
|
|
|
+ }
|
|
|
|
|
+ Object.assign(inspection, current);
|
|
|
|
|
+ await transaction.commit();
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ await transaction.rollback();
|
|
|
|
|
+ throw err;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async syncFlowReport(inspection, list) {
|
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
|
+ try {
|
|
|
|
|
+ const current = await this.lockFlow(transaction, inspection.id);
|
|
|
|
|
+ if (current.flow_version !== 1 || ![1, 5].includes(current.status)) throw '流程已上报,请刷新页面';
|
|
|
|
|
+ await transaction.delete(this.tableName, { qiid: current.id, times: current.times, flow_stage: 1, is_old: 0 });
|
|
|
|
|
+ const records = list.map(x => this.flowRecord(current, {
|
|
|
|
|
+ aid: x.audit_id, flow_stage: 1, order: x.audit_order, audit_order: x.audit_order, audit_type: x.audit_type,
|
|
|
|
|
+ }));
|
|
|
|
|
+ if (records.length) {
|
|
|
|
|
+ await transaction.insert(this.tableName, records);
|
|
|
|
|
+ await this.grantFlowPermission(transaction, records.map(x => x.aid));
|
|
|
|
|
+ }
|
|
|
|
|
+ await transaction.commit();
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ await transaction.rollback();
|
|
|
|
|
+ throw err;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ flowRecord(inspection, record) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ tid: inspection.tid, qiid: inspection.id, times: inspection.times,
|
|
|
|
|
+ aid: record.aid, flow_stage: record.flow_stage, stage_round: inspection.stage_round,
|
|
|
|
|
+ order: record.order, audit_order: record.audit_order, audit_type: record.audit_type || 1,
|
|
|
|
|
+ status: 1, is_old: 0, is_rectification: record.flow_stage === 2 ? 1 : 0,
|
|
|
|
|
+ begin_time: null, end_time: null, opinion: '', rectification_item: '', rectification_date: null,
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async grantFlowPermission(transaction, ids) {
|
|
|
|
|
+ const existing = await this.ctx.service.tenderPermission.getPartsPermission(this.ctx.tender.id, ['inspection']);
|
|
|
|
|
+ const missing = this._.uniq(ids).filter(id => !existing.some(x => x.uid === id));
|
|
|
|
|
+ if (missing.length) {
|
|
|
|
|
+ await this.ctx.service.tenderPermission.saveOnePermission(this.ctx.tender.id, missing, missing.map(uid => ({ uid, inspection: ['1'] })), ['inspection'], transaction);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async activateFlow(transaction, inspection, stage) {
|
|
|
|
|
+ const records = await transaction.select(this.tableName, { where: { qiid: inspection.id, times: inspection.times, flow_stage: stage, stage_round: inspection.stage_round, is_old: 0, status: 1 }, orders: [['order', 'asc']] });
|
|
|
|
|
+ if (!records.length) throw '请先设置' + auditConst.stageString[stage] + '人员';
|
|
|
|
|
+ const active = stage === 2 ? records : records.filter(x => x.order === records[0].order);
|
|
|
|
|
+ const status = stage === 2 ? 12 : 2;
|
|
|
|
|
+ const begin_time = new Date();
|
|
|
|
|
+ await transaction.updateRows(this.tableName, active.map(x => ({ id: x.id, status, begin_time })));
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, { id: inspection.id, flow_stage: stage, stage_round: inspection.stage_round, status });
|
|
|
|
|
+ Object.assign(inspection, { flow_stage: stage, status });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async processFlow(inspection, data) {
|
|
|
|
|
+ const transaction = await this.db.beginTransaction();
|
|
|
|
|
+ try {
|
|
|
|
|
+ const current = await this.lockFlow(transaction, inspection.id);
|
|
|
|
|
+ if (current.flow_version !== 1) throw '流程已变更,请刷新页面';
|
|
|
|
|
+ if (Number(data.times) !== current.times || Number(data.stage_round) !== current.stage_round || Number(data.flow_stage) !== current.flow_stage) throw '流程已更新,请刷新后操作';
|
|
|
|
|
+ const uid = this.ctx.session.sessionUser.accountId;
|
|
|
|
|
+ const ownerEdit = current.uid === uid && [1, 5].includes(current.status);
|
|
|
|
|
+ const records = await transaction.select(this.tableName, { where: { qiid: current.id, times: current.times, is_old: 0 }, orders: [['order', 'asc'], ['id', 'asc']] });
|
|
|
|
|
+ const active = records.filter(x => x.flow_stage === current.flow_stage && x.stage_round === current.stage_round && [2, 12].includes(x.status));
|
|
|
|
|
+ const self = [2, 6, 12].includes(current.status) ? active.find(x => x.aid === uid) : null;
|
|
|
|
|
+ const report = records.filter(x => x.flow_stage === 1);
|
|
|
|
|
+ const rectifiers = records.filter(x => x.flow_stage === 2 && x.stage_round === current.stage_round);
|
|
|
|
|
+ const reply = records.filter(x => x.flow_stage === 3 && x.stage_round === current.stage_round);
|
|
|
|
|
+ switch (data.type) {
|
|
|
|
|
+ case 'update-field': {
|
|
|
|
|
+ if (!ownerEdit) throw '当前状态不可修改巡检内容';
|
|
|
|
|
+ const update = data.update || {};
|
|
|
|
|
+ const fields = ['id', 'code', 'check_item', 'check_situation', 'action', 'check_date', 'inspector'];
|
|
|
|
|
+ if (Number(update.id) !== current.id || Object.keys(update).some(x => !fields.includes(x))) throw '参数有误';
|
|
|
|
|
+ for (const key of ['code', 'check_item', 'check_date']) {
|
|
|
|
|
+ if (update[key] !== undefined && !String(update[key]).trim()) throw '巡检编号、检查项和检查日期不能为空';
|
|
|
|
|
+ }
|
|
|
|
|
+ for (const key of ['code', 'check_item', 'check_situation', 'action', 'inspector']) {
|
|
|
|
|
+ if (update[key] !== undefined && (typeof update[key] !== 'string' || update[key].length > (['code', 'inspector'].includes(key) ? 255 : 1000))) throw '字段内容过长或格式错误';
|
|
|
|
|
+ }
|
|
|
|
|
+ if (update.check_date !== undefined) {
|
|
|
|
|
+ if (typeof update.check_date !== 'string' || !moment(update.check_date, 'YYYY-MM-DD', true).isValid()) throw '检查日期格式错误';
|
|
|
|
|
+ }
|
|
|
|
|
+ if (update.code !== undefined && update.code !== current.code) {
|
|
|
|
|
+ const other = await transaction.get(this.ctx.service.qualityInspection.tableName, { tid: current.tid, code: update.code });
|
|
|
|
|
+ if (other && other.id !== current.id) throw '该巡检编号已存在';
|
|
|
|
|
+ }
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, Object.assign({}, update, { id: current.id }));
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case 'flow-need-rectification':
|
|
|
|
|
+ throw '请刷新页面,是否整改需随上报一起提交';
|
|
|
|
|
+ case 'flow-add-audit':
|
|
|
|
|
+ case 'flow-del-audit': {
|
|
|
|
|
+ const stage = Number(data.target_stage);
|
|
|
|
|
+ const canAssign = current.flow_stage === 1 && self && current.need_rectification === 1;
|
|
|
|
|
+ if (!([1, 3].includes(stage) && ownerEdit || stage === 2 && canAssign)) throw '您无权设置该阶段人员';
|
|
|
|
|
+ // 草稿可先配置批复人,是否启用整改、批复以上报时的选择为准。
|
|
|
|
|
+ const mode = this.ctx.tender.info.shenpi.inspection;
|
|
|
|
|
+ if (stage === 1 && mode === shenpiConst.sp_status.gdspl) throw '固定上报流程不可修改';
|
|
|
|
|
+ const stageRecords = records.filter(x => x.flow_stage === stage && x.stage_round === current.stage_round);
|
|
|
|
|
+ const id = Number(data.auditorId);
|
|
|
|
|
+ if (!Number.isInteger(id) || id <= 0) throw '请选择有效用户';
|
|
|
|
|
+ if (data.type === 'flow-add-audit') {
|
|
|
|
|
+ if (stage === 1 && id === current.uid) throw '上报审批人不能是上报人本人';
|
|
|
|
|
+ if (stageRecords.some(x => x.aid === id)) throw '该人员已存在';
|
|
|
|
|
+ const users = await this.ctx.service.projectAccount.getAllSubProjectAccount(this.ctx.subProject);
|
|
|
|
|
+ if (!users.some(x => x.id === id)) throw '该用户不在当前项目中';
|
|
|
|
|
+ let order = stage === 2 ? 1 : stageRecords.reduce((n, x) => Math.max(n, x.order), 0) + 1;
|
|
|
|
|
+ if (stage === 1 && mode === shenpiConst.sp_status.gdzs && stageRecords.length) {
|
|
|
|
|
+ const last = stageRecords[stageRecords.length - 1];
|
|
|
|
|
+ order = last.order;
|
|
|
|
|
+ await transaction.update(this.tableName, { id: last.id, order: order + 1, audit_order: order + 1 });
|
|
|
|
|
+ }
|
|
|
|
|
+ await transaction.insert(this.tableName, this.flowRecord(current, { aid: id, flow_stage: stage, order, audit_order: order, audit_type: stage === 2 ? 2 : 1 }));
|
|
|
|
|
+ await this.grantFlowPermission(transaction, [id]);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const target = stageRecords.find(x => x.aid === id);
|
|
|
|
|
+ if (!target) throw '该人员不存在';
|
|
|
|
|
+ if (stage === 1 && mode === shenpiConst.sp_status.gdzs && target.order === Math.max(...stageRecords.map(x => x.order))) throw '固定终审人不可移除';
|
|
|
|
|
+ await transaction.delete(this.tableName, { id: target.id });
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case 'start-inspection':
|
|
|
|
|
+ if (!ownerEdit) throw '当前不可上报';
|
|
|
|
|
+ if (![0, 1].includes(data.need_rectification)) throw '请选择是否整改';
|
|
|
|
|
+ if (!current.code || !current.check_item || !current.check_date) throw '请完善巡检信息';
|
|
|
|
|
+ if (!report.length) throw '请设置上报审批人';
|
|
|
|
|
+ if (data.need_rectification && !reply.length) throw '请设置批复审批人';
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, { id: current.id, need_rectification: data.need_rectification });
|
|
|
|
|
+ current.need_rectification = data.need_rectification;
|
|
|
|
|
+ await this.activateFlow(transaction, current, 1);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'del-inspection': {
|
|
|
|
|
+ if (!ownerEdit) throw '当前不可删除';
|
|
|
|
|
+ const files = await transaction.select(this.ctx.service.qualityInspectionAtt.tableName, { where: { qiid: current.id } });
|
|
|
|
|
+ if (files.length) await this.ctx.helper.delFiles(files);
|
|
|
|
|
+ await transaction.delete(this.tableName, { qiid: current.id });
|
|
|
|
|
+ await transaction.delete(this.ctx.service.qualityInspectionAtt.tableName, { qiid: current.id });
|
|
|
|
|
+ await transaction.delete(this.ctx.service.qualityInspection.tableName, { id: current.id });
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case 'flow-save-rectification':
|
|
|
|
|
+ case 'flow-complete-rectification': {
|
|
|
|
|
+ if (!self || current.flow_stage !== 2 || self.status !== 12 || Number(data.auditId) !== self.id) throw '您没有待处理的整改任务';
|
|
|
|
|
+ const item = typeof data.rectification_item === 'string' ? data.rectification_item.trim() : '';
|
|
|
|
|
+ const date = data.rectification_date || null;
|
|
|
|
|
+ const opinion = typeof data.opinion === 'string' ? data.opinion.trim() : '';
|
|
|
|
|
+ if (item.length > 1000 || opinion.length > 1000) throw '整改内容和意见最多1000字';
|
|
|
|
|
+ if (date && (typeof date !== 'string' || !moment(date, 'YYYY-MM-DD', true).isValid())) throw '整改日期格式错误';
|
|
|
|
|
+ const done = data.type === 'flow-complete-rectification';
|
|
|
|
|
+ if (done && (!item || !date)) throw '请填写整改内容和整改日期';
|
|
|
|
|
+ const update = { id: self.id, rectification_item: item, rectification_date: date, opinion };
|
|
|
|
|
+ if (done) Object.assign(update, { status: 3, end_time: new Date() });
|
|
|
|
|
+ await transaction.update(this.tableName, update);
|
|
|
|
|
+ // 所有提交都先锁巡检主记录,再检查本轮其他人的结果。
|
|
|
|
|
+ if (done && rectifiers.every(x => x.id === self.id || x.status === 3)) await this.activateFlow(transaction, current, 3);
|
|
|
|
|
+ if (done) await this.noticeFlow(transaction, current, records, 3, opinion, 2);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case 'flow-check': {
|
|
|
|
|
+ if (!self || ![1, 3].includes(current.flow_stage) || self.status !== 2 || Number(data.auditId) !== self.id) throw '您没有待处理的审批任务';
|
|
|
|
|
+ const result = Number(data.checkType);
|
|
|
|
|
+ const opinion = typeof data.opinion === 'string' ? data.opinion.trim() : '';
|
|
|
|
|
+ if (![3, 4, 5, 6].includes(result) || opinion.length > 1000) throw '审批参数有误';
|
|
|
|
|
+ if (result !== 3 && !opinion) throw '请填写退回或关闭原因';
|
|
|
|
|
+ const phase = current.flow_stage;
|
|
|
|
|
+ if (result === 3) {
|
|
|
|
|
+ const phaseRecords = records.filter(x => x.flow_stage === phase && x.stage_round === current.stage_round);
|
|
|
|
|
+ const group = phaseRecords.filter(x => x.order === self.order);
|
|
|
|
|
+ const advance = self.audit_type !== auditType.key.and || group.every(x => x.id === self.id || x.status === 3);
|
|
|
|
|
+ const later = phaseRecords.filter(x => x.order > self.order && x.status === 1);
|
|
|
|
|
+ if (advance && !later.length && phase === 1 && current.need_rectification && !rectifiers.length) throw '请先指派至少一名整改人';
|
|
|
|
|
+ await transaction.update(this.tableName, { id: self.id, status: 3, opinion, end_time: new Date() });
|
|
|
|
|
+ if (advance) {
|
|
|
|
|
+ const skipped = group.filter(x => x.id !== self.id && x.status === 2);
|
|
|
|
|
+ if (skipped.length) await transaction.updateRows(this.tableName, skipped.map(x => ({ id: x.id, status: 8, end_time: new Date() })));
|
|
|
|
|
+ if (later.length) {
|
|
|
|
|
+ await this.activateFlow(transaction, current, phase);
|
|
|
|
|
+ } else if (phase === 1 && current.need_rectification) {
|
|
|
|
|
+ await this.activateFlow(transaction, current, 2);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, { id: current.id, status: 3 });
|
|
|
|
|
+ current.status = 3;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await this.returnFlow(transaction, current, records, self, result, opinion);
|
|
|
|
|
+ }
|
|
|
|
|
+ await this.noticeFlow(transaction, current, records, result, opinion, phase);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ default: throw '无效的新流程操作';
|
|
|
|
|
+ }
|
|
|
|
|
+ await transaction.commit();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ await transaction.rollback();
|
|
|
|
|
+ throw err;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async returnFlow(transaction, inspection, records, self, result, opinion) {
|
|
|
|
|
+ const time = new Date();
|
|
|
|
|
+ await transaction.update(this.tableName, { id: self.id, status: result, opinion, end_time: time });
|
|
|
|
|
+ const active = records.filter(x => x.id !== self.id && [2, 12].includes(x.status));
|
|
|
|
|
+ if (active.length) await transaction.updateRows(this.tableName, active.map(x => ({ id: x.id, status: 8, end_time: time })));
|
|
|
|
|
+ if (result === 4) {
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, { id: inspection.id, status: 4 });
|
|
|
|
|
+ inspection.status = 4;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (inspection.flow_stage === 3) {
|
|
|
|
|
+ // 批复退回:原轮次保留,所有整改人同时开始新一轮整改。
|
|
|
|
|
+ const previous = records.filter(x => [2, 3].includes(x.flow_stage) && x.stage_round === inspection.stage_round);
|
|
|
|
|
+ inspection.stage_round += 1;
|
|
|
|
|
+ const copies = previous.map(x => this.flowRecord(inspection, x));
|
|
|
|
|
+ if (copies.length) await transaction.insert(this.tableName, copies);
|
|
|
|
|
+ await this.activateFlow(transaction, inspection, 2);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (result === 5) {
|
|
|
|
|
+ const templates = records.filter(x => x.flow_stage === 1 || x.flow_stage === 3 && x.stage_round === inspection.stage_round);
|
|
|
|
|
+ inspection.times += 1;
|
|
|
|
|
+ inspection.stage_round = 1;
|
|
|
|
|
+ const copies = templates.map(x => this.flowRecord(inspection, x));
|
|
|
|
|
+ if (copies.length) await transaction.insert(this.tableName, copies);
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, { id: inspection.id, times: inspection.times, stage_round: 1, flow_stage: 1, status: 5 });
|
|
|
|
|
+ inspection.status = 5;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const report = records.filter(x => x.flow_stage === 1);
|
|
|
|
|
+ const earlier = report.filter(x => x.audit_order < self.audit_order);
|
|
|
|
|
+ if (!earlier.length) throw '当前为首个上报审批节点,请退回上报人';
|
|
|
|
|
+ const target = Math.max(...earlier.map(x => x.audit_order));
|
|
|
|
|
+ const replaced = report.filter(x => x.audit_order >= target);
|
|
|
|
|
+ await transaction.updateRows(this.tableName, replaced.map(x => ({ id: x.id, is_old: 1 })));
|
|
|
|
|
+ const maxOrder = Math.max(...report.map(x => x.order));
|
|
|
|
|
+ const orders = this._.uniq(replaced.map(x => x.audit_order)).sort((a, b) => a - b);
|
|
|
|
|
+ const copies = replaced.map(x => this.flowRecord(inspection, Object.assign({}, x, { order: maxOrder + orders.indexOf(x.audit_order) + 1 })));
|
|
|
|
|
+ await transaction.insert(this.tableName, copies);
|
|
|
|
|
+ await this.activateFlow(transaction, inspection, 1);
|
|
|
|
|
+ await transaction.update(this.ctx.service.qualityInspection.tableName, { id: inspection.id, status: 6 });
|
|
|
|
|
+ inspection.status = 6;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async noticeFlow(transaction, inspection, records, result, opinion, stage) {
|
|
|
|
|
+ const content = JSON.parse(await this.getNoticeContent(this.ctx.session.sessionProject.id, inspection.tid, inspection.id, this.ctx.session.sessionUser.accountId, opinion) || '{}');
|
|
|
|
|
+ content.flow_stage = stage;
|
|
|
|
|
+ content.stage_name = auditConst.stageString[stage];
|
|
|
|
|
+ const users = this._.uniq([inspection.uid].concat(records.map(x => x.aid)));
|
|
|
|
|
+ await transaction.insert('zh_notice', users.map(uid => ({ pid: this.ctx.session.sessionProject.id, tid: inspection.tid, type: pushType.inspection, uid, status: result, content: JSON.stringify(content) })));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return QualityInspectionAudit;
|
|
return QualityInspectionAudit;
|