|
@@ -1,6 +1,6 @@
|
|
import {IApiProcessor, ICachedData, IMethodParams, IRequest} from "@core/Defined";
|
|
import {IApiProcessor, ICachedData, IMethodParams, IRequest} from "@core/Defined";
|
|
import DataCURD from "@core/DataCURD";
|
|
import DataCURD from "@core/DataCURD";
|
|
-import {Op, WhereOptions} from "sequelize";
|
|
|
|
|
|
+import {Op, QueryTypes, WhereOptions} from "sequelize";
|
|
import {PrjInfo} from "@core-models/PrjInfo";
|
|
import {PrjInfo} from "@core-models/PrjInfo";
|
|
import dayjs from "dayjs";
|
|
import dayjs from "dayjs";
|
|
import {PrjLogger} from "@src/utils/prj_logger";
|
|
import {PrjLogger} from "@src/utils/prj_logger";
|
|
@@ -21,6 +21,8 @@ import {BpmnWork} from "@core-models/BpmnWork";
|
|
import {FlowEngine} from "@src/bpmn/flow_engine";
|
|
import {FlowEngine} from "@src/bpmn/flow_engine";
|
|
import {PrjPhaseDefine} from "@core-models/PrjPhaseDefine";
|
|
import {PrjPhaseDefine} from "@core-models/PrjPhaseDefine";
|
|
import {WorkItemStatus} from "@src/utils/define";
|
|
import {WorkItemStatus} from "@src/utils/define";
|
|
|
|
+import {BizCustomer} from "@core-models/BizCustomer";
|
|
|
|
+import {AcsDomain} from "@core-models/AcsDomain";
|
|
|
|
|
|
interface IData {
|
|
interface IData {
|
|
/**
|
|
/**
|
|
@@ -73,11 +75,13 @@ function permission_guard(content: IRequest, cached_data: ICachedData): Promise<
|
|
return reject(Resp.gen_err(Resp.ResourceNotFound, '项目不存在。'));
|
|
return reject(Resp.gen_err(Resp.ResourceNotFound, '项目不存在。'));
|
|
let phase = await PrjPhaseDefine.findOne({where: {id: prj.phase_id}, raw: true});
|
|
let phase = await PrjPhaseDefine.findOne({where: {id: prj.phase_id}, raw: true});
|
|
if (!phase) return reject(Resp.gen_err(Resp.ResourceNotFound, '项目状态信息出错,id: ' + prj.id));
|
|
if (!phase) return reject(Resp.gen_err(Resp.ResourceNotFound, '项目状态信息出错,id: ' + prj.id));
|
|
|
|
+ // 缓存项目阶段的order_index
|
|
|
|
+ cached_data.phase_order_index = phase.order_index;
|
|
|
|
|
|
let is_privileged_account = await is_project_privileged_account(cached_data.user_id);
|
|
let is_privileged_account = await is_project_privileged_account(cached_data.user_id);
|
|
|
|
|
|
- if (phase.order_index >= 20 ) {
|
|
|
|
- if (data.type_id !== undefined && prj.type_id !== data.type_id) {
|
|
|
|
|
|
+ if (phase.order_index >= 20) {
|
|
|
|
+ if (data.type_id !== undefined && prj.type_id !== data.type_id) {
|
|
return reject(Resp.gen_err(Resp.Forbidden, '项目立项后不允许修改项目类型。'))
|
|
return reject(Resp.gen_err(Resp.Forbidden, '项目立项后不允许修改项目类型。'))
|
|
}
|
|
}
|
|
if (!is_privileged_account) {
|
|
if (!is_privileged_account) {
|
|
@@ -89,17 +93,17 @@ function permission_guard(content: IRequest, cached_data: ICachedData): Promise<
|
|
/// 只有项目特权人员才可以修改项目负责人
|
|
/// 只有项目特权人员才可以修改项目负责人
|
|
if (data.leader_id && data.leader_id !== prj.leader_id) {
|
|
if (data.leader_id && data.leader_id !== prj.leader_id) {
|
|
if (!is_privileged_account) {
|
|
if (!is_privileged_account) {
|
|
- return reject(Resp.gen_err(Resp.Forbidden, '您没有权限修改项目负责人,请确认您是特权人员。'));
|
|
|
|
|
|
+ return reject(Resp.gen_err(Resp.Forbidden, '您没有权限修改项目负责人,请确认您是特权人员。'));
|
|
}
|
|
}
|
|
// 新的项目负责人必须是项目组成员
|
|
// 新的项目负责人必须是项目组成员
|
|
if (!await is_project_member(data.leader_id, prj.id)) {
|
|
if (!await is_project_member(data.leader_id, prj.id)) {
|
|
- return reject(Resp.gen_err(Resp.Forbidden, '新的项目负责人必须是项目组成员。'));
|
|
|
|
|
|
+ return reject(Resp.gen_err(Resp.Forbidden, '新的项目负责人必须是项目组成员。'));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!await is_project_modifiable(cached_data.user_id, prj.id))
|
|
if (!await is_project_modifiable(cached_data.user_id, prj.id))
|
|
return reject(Resp.gen_err(Resp.Forbidden, '您没有权限修改本项目的信息,请确认您是项目负责人或特权人员。'));
|
|
return reject(Resp.gen_err(Resp.Forbidden, '您没有权限修改本项目的信息,请确认您是项目负责人或特权人员。'));
|
|
if (data.deliver_at) {
|
|
if (data.deliver_at) {
|
|
- data.deliver_at += ' 23:59:59';
|
|
|
|
|
|
+ data.deliver_at = dayjs(data.deliver_at).format('YYYY-MM-DD 23:59:59');
|
|
}
|
|
}
|
|
let task = await PrjPlanTask.findOne({where: {prj_id: prj.id, end_at: {[Op.gt]: data.deliver_at}}, raw: true});
|
|
let task = await PrjPlanTask.findOne({where: {prj_id: prj.id, end_at: {[Op.gt]: data.deliver_at}}, raw: true});
|
|
if (task) {
|
|
if (task) {
|
|
@@ -130,7 +134,7 @@ async function before_respond(content: IRequest, params: IMethodParams, cached_d
|
|
await PrjLogger.updated({
|
|
await PrjLogger.updated({
|
|
creator_id: cached_data.user_id,
|
|
creator_id: cached_data.user_id,
|
|
creator_name: cached_data.user_name,
|
|
creator_name: cached_data.user_name,
|
|
- content: '项目信息',
|
|
|
|
|
|
+ content: cached_data.modified_info,
|
|
prj_id: data.id
|
|
prj_id: data.id
|
|
});
|
|
});
|
|
return result;
|
|
return result;
|
|
@@ -139,7 +143,7 @@ async function before_respond(content: IRequest, params: IMethodParams, cached_d
|
|
function modify(content: IRequest, params: IMethodParams, cached_data: ICachedData): Promise<any> {
|
|
function modify(content: IRequest, params: IMethodParams, cached_data: ICachedData): Promise<any> {
|
|
return new Promise<any>(async (resolve, reject) => {
|
|
return new Promise<any>(async (resolve, reject) => {
|
|
let data = <IData>content.data;
|
|
let data = <IData>content.data;
|
|
-
|
|
|
|
|
|
+ let modified = '';
|
|
let t = await PrjInfo.sequelize!.transaction();
|
|
let t = await PrjInfo.sequelize!.transaction();
|
|
try {
|
|
try {
|
|
let prj = await PrjInfo.findOne({where: {id: data.id}, raw: true, transaction: t});
|
|
let prj = await PrjInfo.findOne({where: {id: data.id}, raw: true, transaction: t});
|
|
@@ -155,15 +159,25 @@ function modify(content: IRequest, params: IMethodParams, cached_data: ICachedDa
|
|
throw Resp.gen_err(Resp.ResourceNotFound, '新选中的项目负责人不存在.');
|
|
throw Resp.gen_err(Resp.ResourceNotFound, '新选中的项目负责人不存在.');
|
|
}
|
|
}
|
|
let [_count, flow_cases] = await BpmnCase.update({creator_id: data.leader_id},
|
|
let [_count, flow_cases] = await BpmnCase.update({creator_id: data.leader_id},
|
|
- {where: {prj_id: prj.id, task_id: {[Op.is]: null}, completed_at: {[Op.is]: null}}, transaction: t, returning: true});
|
|
|
|
|
|
+ {
|
|
|
|
+ where: {prj_id: prj.id, task_id: {[Op.is]: null}, completed_at: {[Op.is]: null}},
|
|
|
|
+ transaction: t,
|
|
|
|
+ returning: true
|
|
|
|
+ });
|
|
await BpmnWork.update({assigned_to: data.leader_id},
|
|
await BpmnWork.update({assigned_to: data.leader_id},
|
|
- {where: {prj_id: prj.id, task_id: {[Op.is]: null}, status: {[Op.lt]: WorkItemStatus.completed}}, transaction: t, returning: false});
|
|
|
|
|
|
+ {
|
|
|
|
+ where: {prj_id: prj.id, task_id: {[Op.is]: null}, status: {[Op.lt]: WorkItemStatus.completed}},
|
|
|
|
+ transaction: t,
|
|
|
|
+ returning: false
|
|
|
|
+ });
|
|
if (flow_cases && flow_cases.length > 0) {
|
|
if (flow_cases && flow_cases.length > 0) {
|
|
for (let flow_case of flow_cases) {
|
|
for (let flow_case of flow_cases) {
|
|
let engine = FlowEngine.case_engine_map.get(flow_case.id);
|
|
let engine = FlowEngine.case_engine_map.get(flow_case.id);
|
|
if (engine) engine.owner = data.leader_id;
|
|
if (engine) engine.owner = data.leader_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ let old_leader = await AcsUserInfo.findOne({where: {id: prj.leader_id}, raw: true, transaction: t});
|
|
|
|
+ modified += PrjLogger.gen_modified_content('项目负责人', old_leader!.name, new_leader.name);
|
|
}
|
|
}
|
|
|
|
|
|
let contract_id = prj.contract_id;
|
|
let contract_id = prj.contract_id;
|
|
@@ -211,7 +225,87 @@ function modify(content: IRequest, params: IMethodParams, cached_data: ICachedDa
|
|
size: contract.pdf_size
|
|
size: contract.pdf_size
|
|
}, {transaction: t});
|
|
}, {transaction: t});
|
|
}
|
|
}
|
|
|
|
+ let old_contract = await BizContractInfo.findOne({
|
|
|
|
+ where: {id: data.contract_id},
|
|
|
|
+ raw: true,
|
|
|
|
+ transaction: t
|
|
|
|
+ });
|
|
|
|
+ modified += PrjLogger.gen_modified_content('项目合同', old_contract ? old_contract.name : '无', contract.name);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //如果项目已立项,要详细记录变化内容,立项前的项目信息修改不用记录
|
|
|
|
+ if (cached_data.phase_order_index >= 20) {
|
|
|
|
+ let sql = `
|
|
|
|
+ select prj.id, prj.name,
|
|
|
|
+ prj.type_id, CONCAT_WS('/', pidtype.name, ptype.name) as type_name,
|
|
|
|
+ prj.region_id, region.name as region_name,
|
|
|
|
+ prj.leader_id, leader.name as leader_name,
|
|
|
|
+ prj.bizman_id, bizman.name as bizman_name,
|
|
|
|
+ prj.customer_id, customer.name as customer_name,
|
|
|
|
+ prj.region_id, region.name as region_name,
|
|
|
|
+ prj.contract_id, contract.name as contract_name,
|
|
|
|
+ prj.intro,
|
|
|
|
+ TO_CHAR(prj.deliver_at, 'yyyy-MM-dd') as deliver_at
|
|
|
|
+ from ${PrjInfo.table_name} prj
|
|
|
|
+ left join ${AcsDomain.table_name} ptype on prj.type_id = ptype.id
|
|
|
|
+ left join ${AcsDomain.table_name} pidtype on ptype.pid = pidtype.id
|
|
|
|
+ left join ${AcsUserInfo.table_name} bizman on bizman.id = prj.bizman_id
|
|
|
|
+ left join ${AcsUserInfo.table_name} leader on leader.id = prj.leader_id
|
|
|
|
+ left join ${BizCustomer.table_name} customer on customer.id = prj.customer_id
|
|
|
|
+ left join ${AcsDomain.table_name} region on prj.region_id = region.id
|
|
|
|
+ left join ${BizContractInfo.table_name} contract on contract.id = prj.contract_id
|
|
|
|
+ where prj.id = :prj_id
|
|
|
|
+ `;
|
|
|
|
+ let record: any = await PrjInfo.sequelize!.query(sql, {
|
|
|
|
+ type: QueryTypes.SELECT,
|
|
|
|
+ raw: true,
|
|
|
|
+ transaction: t,
|
|
|
|
+ replacements: {prj_id: data.id}
|
|
|
|
+ });
|
|
|
|
+ if (!record || record.length === 0) {
|
|
|
|
+ throw Resp.gen_err(Resp.ResourceNotFound, '项目已被其他用户删除。');
|
|
|
|
+ }
|
|
|
|
+ let old_info = record[0];
|
|
|
|
+ modified += PrjLogger.gen_modified_content('项目名称', old_info.name, data.name);
|
|
|
|
+ if (data.type_id && data.type_id !== prj.type_id) {
|
|
|
|
+ sql = `
|
|
|
|
+ select CONCAT_WS('/', pidtype.name, ptype.name) as type_name
|
|
|
|
+ from ${AcsDomain.table_name} ptype
|
|
|
|
+ left join ${AcsDomain.table_name} pidtype on ptype.pid = pidtype.id
|
|
|
|
+ where ptype.id = :type_id
|
|
|
|
+ `
|
|
|
|
+ let type_name: any = await PrjInfo.sequelize!.query(sql, {
|
|
|
|
+ type: QueryTypes.SELECT,
|
|
|
|
+ raw: true,
|
|
|
|
+ transaction: t,
|
|
|
|
+ replacements: {type_id: data.type_id}
|
|
|
|
+ });
|
|
|
|
+ modified += PrjLogger.gen_modified_content('项目类型', old_info.type_name, type_name ? type_name[0].type_name : undefined);
|
|
|
|
+ }
|
|
|
|
+ if (data.customer_id && data.customer_id !== prj.customer_id) {
|
|
|
|
+ let customer = await BizCustomer.findOne({where: {id: data.customer_id}, transaction: t});
|
|
|
|
+ modified += PrjLogger.gen_modified_content('客户', old_info.customer_name, customer ? customer.name : undefined);
|
|
|
|
+ }
|
|
|
|
+ if (data.region_id && data.region_id !== prj.region_id) {
|
|
|
|
+ let region = await AcsDomain.findOne({where: {id: data.region_id}, transaction: t});
|
|
|
|
+ modified += PrjLogger.gen_modified_content('项目区域', old_info.region_name, region ? region.name : undefined);
|
|
|
|
+ }
|
|
|
|
+ if (data.bizman_id && data.bizman_id !== prj.bizman_id) {
|
|
|
|
+ let bizman = await AcsUserInfo.findOne({where: {id: data.bizman_id}, transaction: t});
|
|
|
|
+ modified += PrjLogger.gen_modified_content('商务负责人', old_info.bizman_name, bizman ? bizman.name : undefined);
|
|
|
|
+ }
|
|
|
|
+ if (data.intro && data.intro !== prj.intro) {
|
|
|
|
+ modified += PrjLogger.gen_modified_content('项目简介', old_info.intro, data.intro);
|
|
|
|
+ }
|
|
|
|
+ if (data.deliver_at && data.deliver_at !== old_info.deliver_at) {
|
|
|
|
+ modified += PrjLogger.gen_modified_content('交付日期', old_info.deliver_at, dayjs(data.deliver_at).format('YYYY-MM-DD'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cached_data.modified_info = modified;
|
|
|
|
+ } else {
|
|
|
|
+ cached_data.modified_info = '';
|
|
}
|
|
}
|
|
|
|
+
|
|
let result = await DataCURD.internal_update_row(content, {
|
|
let result = await DataCURD.internal_update_row(content, {
|
|
model: PrjInfo,
|
|
model: PrjInfo,
|
|
where: get_where,
|
|
where: get_where,
|
|
@@ -334,7 +428,7 @@ const v1_0: IApiProcessor = {
|
|
"token"
|
|
"token"
|
|
]
|
|
]
|
|
},
|
|
},
|
|
- method: modify,//DataCURD.internal_update_row,
|
|
|
|
|
|
+ method: modify,
|
|
on_before_respond: before_respond,
|
|
on_before_respond: before_respond,
|
|
method_params: {
|
|
method_params: {
|
|
model: PrjInfo,
|
|
model: PrjInfo,
|