1331 lines
36 KiB
JavaScript
1331 lines
36 KiB
JavaScript
const dayjs = require("dayjs");
|
|
const cate = require("./sop-cate.js");
|
|
const medicalRecord = require("../medical-record");
|
|
const corpGroup = require("../corp-group");
|
|
const utils = require("../utils.js");
|
|
const appFunction = require("../app-function");
|
|
const common = require("../../common.js");
|
|
const e = require("connect-timeout");
|
|
let db = null;
|
|
exports.main = async (content, DB) => {
|
|
db = DB;
|
|
switch (content.type) {
|
|
case "getSopTaskList":
|
|
return await exports.getSopTaskList(content);
|
|
case "getSopTask":
|
|
return await exports.getSopTask(content);
|
|
case "updateSopTask":
|
|
return await exports.updateSopTask(content);
|
|
case "updateSopTaskField":
|
|
return await exports.updateSopTaskField(content);
|
|
case "removeSopTask":
|
|
return await exports.removeSopTask(content);
|
|
case "executeSopTask":
|
|
return await exports.executeSopTask(content);
|
|
case "getSopFilterRule":
|
|
return await exports.getSopFilterRule(content);
|
|
case "createSopTask":
|
|
return await exports.createSopTask(content);
|
|
case "updateSopTaskExecuteUser":
|
|
return await exports.updateSopTaskExecuteUser(content);
|
|
case "triggerSopTask":
|
|
return await exports.triggerSopTask(content);
|
|
case "removeCustomerSopTask":
|
|
return await exports.removeCustomerSopTask(content);
|
|
case "getCustomerSopTask":
|
|
return await exports.getCustomerSopTask(content);
|
|
case "createCustomerSopTask":
|
|
return await exports.createCustomerSopTask(content);
|
|
case "customerSopTaskTrigger":
|
|
return await exports.customerSopTaskTrigger(content);
|
|
case "customerSopTaskAutoGroup":
|
|
return await customerSopTaskAutoGroup(content);
|
|
case "addSopCate":
|
|
case "updateSopCate":
|
|
case "deleteSopCate":
|
|
case "getSopCateList":
|
|
case "sortSopCate":
|
|
return await cate.main(content, db);
|
|
default:
|
|
return {
|
|
success: false,
|
|
message: "未找到方法",
|
|
};
|
|
}
|
|
};
|
|
|
|
exports.getSopTask = async (content) => {
|
|
const { corpId, sopTaskId } = content;
|
|
if (!corpId || !sopTaskId) return { success: false, message: "参数错误" };
|
|
|
|
const result = await db
|
|
.collection("sop-tasks")
|
|
.findOne({ _id: sopTaskId, corpId });
|
|
return {
|
|
success: Boolean(result),
|
|
message: `获取sop任务${Boolean(result) ? "成功" : "失败"}`,
|
|
timeStamp: Date.now(),
|
|
data: result,
|
|
};
|
|
};
|
|
|
|
exports.getSopTaskList = async (content) => {
|
|
const {
|
|
corpId,
|
|
sopName,
|
|
page = 1,
|
|
pageSize = 10,
|
|
eventType,
|
|
sopExecuteStatus,
|
|
classIds,
|
|
} = content;
|
|
|
|
let query = { corpId };
|
|
if (classIds)
|
|
query.classId = { $in: Array.isArray(classIds) ? classIds : [] };
|
|
if (sopName) query.sopName = { $regex: sopName, $options: "i" };
|
|
if (eventType) query.eventType = eventType;
|
|
if (sopExecuteStatus === "executing") {
|
|
query.executeStartTime = { $lte: Date.now() };
|
|
query.$or = [
|
|
{ executeEndTime: { $gte: Date.now() } },
|
|
{ executeEndTime: { $eq: "" } },
|
|
];
|
|
query.sopEnableStatus = "enable";
|
|
} else if (sopExecuteStatus === "unexecuted") {
|
|
query.executeStartTime = { $gte: Date.now() };
|
|
} else if (sopExecuteStatus === "closed") {
|
|
query.executeEndTime = { $lte: Date.now() };
|
|
}
|
|
|
|
const total = await db.collection("sop-tasks").countDocuments(query);
|
|
const pages = Math.ceil(total / pageSize);
|
|
const data = await db
|
|
.collection("sop-tasks")
|
|
.find(query)
|
|
.sort({ createTime: -1 })
|
|
.skip((page - 1) * pageSize)
|
|
.limit(pageSize)
|
|
.toArray();
|
|
|
|
return {
|
|
success: true,
|
|
total,
|
|
pages,
|
|
size: pageSize,
|
|
timeStamp: Date.now(),
|
|
message: "获取sop任务列表成功",
|
|
list: data,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* 更新sop任务
|
|
* @param {*} content
|
|
* @returns
|
|
*/
|
|
exports.updateSopTask = async (content) => {
|
|
let { corpId, sopTaskId, ...rest } = content;
|
|
const { executeTeams, executeJobs } = rest;
|
|
|
|
// 根据 executeTeams 和 executeJobs 获取执行人员
|
|
if (executeTeams || executeJobs) {
|
|
const teamIds = executeTeams.map((item) => item.teamId);
|
|
rest.executeUserIds = await appFunction.getCorpMemberByTeamsAndJobs({
|
|
corpId,
|
|
teamIds,
|
|
jobs: executeJobs,
|
|
});
|
|
}
|
|
|
|
try {
|
|
const res = await db
|
|
.collection("sop-tasks")
|
|
.updateOne({ _id: sopTaskId }, { $set: rest });
|
|
return {
|
|
success: true,
|
|
message: "更新sop任务成功",
|
|
res,
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
message: "更新sop任务失败",
|
|
};
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 创建sop任务
|
|
* @param {string} corpId 机构id
|
|
* @param {string} createUserId 创建人
|
|
* @param {string} sopName sop名称
|
|
* @param {string} sopContent sop内容
|
|
* @param {string} classId 分类id
|
|
* @param {string} eventType 事件类型
|
|
* @param {string} executeMethod 执行方式 groupmsg-群发 todo-待办 tag-标签
|
|
* @param {string} sendContent 发送内容
|
|
* @param {string} fileList 发送文件
|
|
* @param {string} creatorUserId 创建人
|
|
* @param {string} executeStartTime 开始执行时间
|
|
* @param {string} executeEndTime 结束执行时间
|
|
* @param {string} executeTeams 执行团队
|
|
* @param {string} executeJobs 执行职位
|
|
* @param {array} filterConditions 筛选条件
|
|
* @param {number} triggerInterval 间隔时间
|
|
* @param {string} sopEnableStatus sop启用状态 enable-启用 disable-禁用
|
|
* @returns
|
|
*/
|
|
exports.createSopTask = async (content) => {
|
|
const {
|
|
corpId,
|
|
createUserId,
|
|
sopName,
|
|
eventType,
|
|
sopContent,
|
|
classId,
|
|
executeTeams,
|
|
executeJobs,
|
|
executeStartTime,
|
|
executeEndTime = "",
|
|
filterConditions,
|
|
executeMethod,
|
|
sendContent,
|
|
fileList,
|
|
creatorUserId,
|
|
triggerInterval,
|
|
sopEnableStatus = "enable",
|
|
newTagIds,
|
|
removeTagIds,
|
|
executeType,
|
|
enableSendContent,
|
|
groups,
|
|
archiveLink,
|
|
} = content;
|
|
|
|
// 根据 executeTeams 和 executeJobs 获取执行人员
|
|
const teamIds = executeTeams.map((item) => item.teamId);
|
|
const executeUserIds = await appFunction.getCorpMemberByTeamsAndJobs({
|
|
corpId,
|
|
teamIds,
|
|
jobs: executeJobs,
|
|
});
|
|
|
|
try {
|
|
await db.collection("sop-tasks").insertOne({
|
|
_id: common.generateRandomString(24),
|
|
corpId,
|
|
createUserId,
|
|
sopName,
|
|
eventType,
|
|
sopContent,
|
|
classId,
|
|
executeTeams,
|
|
executeJobs,
|
|
executeStartTime:
|
|
executeStartTime && dayjs(executeStartTime).isValid()
|
|
? dayjs(executeStartTime).valueOf()
|
|
: Date.now(), // 未设置开始执行时间 默认立即执行
|
|
executeEndTime:
|
|
executeEndTime && dayjs(executeEndTime).isValid()
|
|
? dayjs(executeEndTime).valueOf()
|
|
: "", // 未设置结束执行时间 默认永久执行
|
|
filterConditions,
|
|
executeMethod,
|
|
sendContent,
|
|
fileList,
|
|
executeUserIds,
|
|
creatorUserId,
|
|
triggerInterval,
|
|
sopEnableStatus,
|
|
newTagIds,
|
|
removeTagIds,
|
|
executeType,
|
|
enableSendContent,
|
|
groups,
|
|
archiveLink,
|
|
createTime: dayjs().valueOf(),
|
|
});
|
|
return {
|
|
success: true,
|
|
message: "创建sop任务成功",
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
message: error.message,
|
|
};
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 删除sop任务
|
|
* @param {*} content
|
|
* @returns
|
|
*/
|
|
exports.removeSopTask = async (content) => {
|
|
const { sopTaskId } = content;
|
|
await db.collection("sop-tasks").deleteOne({ _id: sopTaskId });
|
|
return {
|
|
success: true,
|
|
message: "删除sop任务成功",
|
|
};
|
|
};
|
|
|
|
/**
|
|
* 获取sop筛选规则
|
|
*/
|
|
exports.getSopFilterRule = async (content) => {
|
|
const { corpId } = content;
|
|
const data = await db
|
|
.collection("sop-filter-conditions")
|
|
.find({ corpId: { $in: [corpId, "default"] } })
|
|
.toArray();
|
|
if (data.length === 0) {
|
|
return {
|
|
success: false,
|
|
message: "未找到筛选规则",
|
|
};
|
|
} else if (data.length === 1) {
|
|
return {
|
|
success: true,
|
|
data: data[0],
|
|
message: "获取筛选规则成功",
|
|
};
|
|
} else {
|
|
const defaultRule = data.find((item) => item.corpId === corpId);
|
|
return {
|
|
success: true,
|
|
data: defaultRule || data[0],
|
|
message: "获取筛选规则成功",
|
|
};
|
|
}
|
|
};
|
|
/**
|
|
* 更新sop任务的执行人员
|
|
*/
|
|
exports.updateSopTaskExecuteUser = async (content) => {
|
|
const { corpId, teamId } = content;
|
|
|
|
// 获取本机构的所有sop任务
|
|
const taskList = await db
|
|
.collection("sop-tasks")
|
|
.find({
|
|
corpId,
|
|
executeTeams: { $elemMatch: { teamId } },
|
|
})
|
|
.project({
|
|
_id: 1,
|
|
executeTeams: 1,
|
|
executeJobs: 1,
|
|
executeUserIds: 1,
|
|
})
|
|
.toArray();
|
|
|
|
for (let task of taskList) {
|
|
const { executeTeams, executeJobs, _id } = task;
|
|
const teamIds = executeTeams.map((item) => item.teamId);
|
|
const executeUserIds = await appFunction.getCorpMemberByTeamsAndJobs({
|
|
corpId,
|
|
teamIds,
|
|
jobs: executeJobs,
|
|
});
|
|
await db
|
|
.collection("sop-tasks")
|
|
.updateOne({ _id }, { $set: { executeUserIds } });
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
message: "更新执行人员成功",
|
|
};
|
|
};
|
|
|
|
/**
|
|
* 触发sop任务
|
|
*/
|
|
exports.triggerSopTask = async (content) => {
|
|
let {
|
|
corpId,
|
|
customerId,
|
|
medicalRecord = {},
|
|
archive = {},
|
|
healthIndicators,
|
|
} = content;
|
|
console.log("触发sop任务", content);
|
|
if (!customerId) return;
|
|
const archiveSopIndicators = [
|
|
"age",
|
|
"createTime",
|
|
"birthday",
|
|
"tagIds",
|
|
"intentedProject",
|
|
"customerSource",
|
|
"diagnosis",
|
|
"physicalExaminationTemplate",
|
|
];
|
|
const medicalIndicators = [
|
|
"outpatientDiagnosis",
|
|
"inhospitalDiagnosis",
|
|
"physicalExaminationTemplate",
|
|
"visitTime",
|
|
"inhosDate",
|
|
"outhosDate",
|
|
"operationDate",
|
|
];
|
|
const medicalKeys = Object.keys(medicalRecord);
|
|
const archiveKeys = Object.keys(archive);
|
|
if (
|
|
medicalKeys.length > 0 &&
|
|
!medicalIndicators.some((item) => medicalIndicators.includes(item))
|
|
)
|
|
return;
|
|
if (
|
|
archiveKeys.length > 0 &&
|
|
!archiveSopIndicators.some((item) => archiveKeys.includes(item))
|
|
)
|
|
return;
|
|
const archiveData = await db
|
|
.collection("member")
|
|
.find({ corpId, _id: customerId })
|
|
.toArray();
|
|
archive = archiveData[0];
|
|
let executeSopTaskRes = await this.executeSopTask({
|
|
corpId,
|
|
customerId,
|
|
medicalRecord,
|
|
archive,
|
|
healthIndicators,
|
|
});
|
|
return {
|
|
success: true,
|
|
message: "触发sop任务成功",
|
|
executeSopTaskRes,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* 获取客户健康指标
|
|
*/
|
|
async function customerHealthIndicators({
|
|
corpId,
|
|
memberId,
|
|
healthFilterConditions,
|
|
healthIndicators = {},
|
|
}) {
|
|
if (
|
|
Object.keys(healthIndicators).length === 0 &&
|
|
Object.keys(healthFilterConditions).length > 0 &&
|
|
!healthFilterConditions["healthIndexUpdate"] &&
|
|
healthFilterConditions["healthIndexUpdate"] !== 0
|
|
) {
|
|
const { success, list } = await medicalRecord.main(
|
|
{
|
|
corpId,
|
|
memberId,
|
|
type: "getHealthIndicators",
|
|
},
|
|
db
|
|
);
|
|
if (success && list) {
|
|
for (let item of list) {
|
|
healthIndicators[item.type] = item.value;
|
|
}
|
|
}
|
|
}
|
|
return healthIndicators;
|
|
}
|
|
|
|
/**
|
|
* 执行sop任务
|
|
*/
|
|
exports.executeSopTask = async (content) => {
|
|
let {
|
|
corpId,
|
|
customerId,
|
|
medicalRecord,
|
|
archive = {},
|
|
healthIndicators,
|
|
} = content;
|
|
const {
|
|
externalUserId: customerUserId,
|
|
personResponsibles,
|
|
name: customerName,
|
|
} = archive;
|
|
console.log("archive", archive);
|
|
if (!personResponsibles || personResponsibles.length === 0)
|
|
return { success: false, message: "未找到责任人" };
|
|
const sopTaskQuery = {
|
|
corpId,
|
|
executeStartTime: { $lte: dayjs().valueOf() },
|
|
$or: [
|
|
{ executeEndTime: { $gte: dayjs().valueOf() } },
|
|
{ executeEndTime: "" },
|
|
{ executeEndTime: null },
|
|
{ executeEndTime: { $exists: false } },
|
|
],
|
|
sopEnableStatus: { $ne: "disable" },
|
|
};
|
|
|
|
const sopTask = await db
|
|
.collection("sop-tasks")
|
|
.find(sopTaskQuery)
|
|
.limit(1000)
|
|
.toArray();
|
|
if (!Array.isArray(sopTask) || sopTask.length === 0) return;
|
|
for (let i of sopTask) {
|
|
// 如果执行人员为空,则跳过
|
|
let newHealthIndicators = {};
|
|
if (i.executeUserIds.length === 0) continue;
|
|
const {
|
|
executeUserIds,
|
|
executeTeams,
|
|
filterConditions = [],
|
|
eventType,
|
|
_id: sopTaskId,
|
|
sendContent,
|
|
fileList,
|
|
executeMethod,
|
|
triggerInterval,
|
|
sopContent,
|
|
newTagIds,
|
|
removeTagIds,
|
|
sopName,
|
|
groups,
|
|
} = i;
|
|
if (executeMethod === "groupmsg" && !customerUserId) continue;
|
|
const executeTeamIds = executeTeams.map((item) => item.teamId);
|
|
const item = personResponsibles.find(
|
|
(item) =>
|
|
executeUserIds.includes(item.corpUserId) &&
|
|
executeTeamIds.includes(item.teamId)
|
|
);
|
|
console.log(
|
|
"item",
|
|
item,
|
|
personResponsibles,
|
|
executeUserIds,
|
|
executeTeamIds
|
|
);
|
|
// 如果执行人员不是当前客户的责任人,则跳过
|
|
if (!item) continue;
|
|
const executeUserId = item.corpUserId;
|
|
const executeTeamId = item.teamId;
|
|
const executeTeamName = executeTeams.find(
|
|
(item) => item.teamId === executeTeamId
|
|
).name;
|
|
// 匹配筛选条件
|
|
if (filterConditions.length === 0) continue;
|
|
console.log("filterConditions", filterConditions);
|
|
const conditions = parseFilterConditions(filterConditions);
|
|
const {
|
|
archiveFilterConditions = {},
|
|
medicalFilterConditions = {},
|
|
healthFilterConditions = {},
|
|
} = conditions;
|
|
console.log("conditions", conditions);
|
|
newHealthIndicators = await customerHealthIndicators({
|
|
corpId,
|
|
memberId: customerId,
|
|
healthFilterConditions,
|
|
healthIndicators,
|
|
});
|
|
let { isMatch, executeTime, key } = matchFilterConditions({
|
|
archiveFilterConditions,
|
|
medicalFilterConditions,
|
|
healthFilterConditions,
|
|
medicalRecord,
|
|
archive,
|
|
healthIndicators: newHealthIndicators,
|
|
});
|
|
|
|
console.log("isMatch", isMatch, executeTime, key);
|
|
if (!isMatch) continue;
|
|
// 创建sop任务
|
|
await exports.createCustomerSopTask({
|
|
corpId,
|
|
eventType,
|
|
executeMethod,
|
|
sendContent,
|
|
fileList,
|
|
executeUserId,
|
|
executeTeamId,
|
|
executeTeamName,
|
|
customerId,
|
|
customerName,
|
|
customerUserId,
|
|
sopTaskId,
|
|
executeTime,
|
|
newTagIds,
|
|
removeTagIds,
|
|
triggerInterval,
|
|
sopContent,
|
|
sopName,
|
|
groups,
|
|
});
|
|
}
|
|
};
|
|
function matchFilterConditions({
|
|
archiveFilterConditions = {},
|
|
medicalFilterConditions = {},
|
|
healthFilterConditions = {},
|
|
medicalRecord = {},
|
|
archive = {},
|
|
healthIndicators,
|
|
}) {
|
|
let isMatch = true;
|
|
let executeTime = "";
|
|
// 档案模版字段时间类型的字段
|
|
const medicalTimeType = [
|
|
"visitTime",
|
|
"inhosDate",
|
|
"outhosDate",
|
|
"operationDate",
|
|
"inspectTime",
|
|
];
|
|
if (Object.keys(archiveFilterConditions).length !== 0) {
|
|
// 判断archiveFilterConditions是否为空
|
|
for (let key in archiveFilterConditions) {
|
|
const filterItem = archiveFilterConditions[key];
|
|
if (archiveFilterConditions.hasOwnProperty(key)) {
|
|
// 判断年龄是否在范围内
|
|
if (key === "age") {
|
|
const { min, max } = filterItem;
|
|
const age = parseInt(archive.age, 10);
|
|
if (isNaN(age) || age < min || age > max) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
}
|
|
// 判断是否是创建时间
|
|
// 没有更新时间 则证明这条数据是建档数据
|
|
if (key === "createTimeAfter" && !archive.updateTime) {
|
|
console.log("createTimeAfter", archive, filterItem);
|
|
if (
|
|
!archive.createTime ||
|
|
archive.createTime < dayjs().startOf("day").valueOf()
|
|
) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
} else {
|
|
executeTime = dayjs()
|
|
.add(archiveFilterConditions[key], "day")
|
|
.valueOf();
|
|
}
|
|
}
|
|
// 判断生日获取执行时间
|
|
if (key === "birthday" && typeof filterItem === "number") {
|
|
if (!archive.birthday) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
executeTime = dayjs().subtract(filterItem, "day").valueOf();
|
|
// executeTime 与当天年、月比较
|
|
}
|
|
// 判断性别是否匹配
|
|
const sexObj = {
|
|
male: "男",
|
|
female: "女",
|
|
};
|
|
if (
|
|
key === "sex" &&
|
|
(!filterItem || sexObj[filterItem] !== archive.sex)
|
|
) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
// 判断是否包含标签
|
|
const tagIds = archive.tagIds;
|
|
const includeTag = archiveFilterConditions.includeTag;
|
|
const includeTagType = archiveFilterConditions.includeTagType;
|
|
const excludeTagType = archiveFilterConditions.excludeTagType;
|
|
const excludeTag = archiveFilterConditions.excludeTag;
|
|
if (
|
|
key === "includeTag" &&
|
|
(!tagIds ||
|
|
(tagIds &&
|
|
includeTagType === "or" &&
|
|
!tagIds.some((item) => includeTag.includes(item))) ||
|
|
(tagIds &&
|
|
includeTagType === "and" &&
|
|
!includeTag.every((tag) => tagIds.includes(tag))))
|
|
) {
|
|
return { isMatch: false, key };
|
|
}
|
|
if (
|
|
key === "excludeTag" &&
|
|
Array.isArray(excludeTag) &&
|
|
((tagIds &&
|
|
excludeTagType === "or" &&
|
|
tagIds.some((item) => excludeTag.includes(item))) ||
|
|
(tagIds &&
|
|
excludeTagType === "and" &&
|
|
excludeTag.every((tag) => tagIds.includes(tag))))
|
|
) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
// 判断是否是创建时间
|
|
if (key === "createTimeAfter") {
|
|
if (!archive.createTime) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
executeTime = dayjs(archive.createTime)
|
|
.add(filterItem, "day")
|
|
.valueOf();
|
|
}
|
|
// 判断是否是意向项目
|
|
if (
|
|
key === "intentedProject" &&
|
|
(!archive.intentedProject ||
|
|
!archiveFilterConditions.intentedProject.includes(
|
|
archive.intentedProject
|
|
))
|
|
) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
// 判断是否是客户来源
|
|
if (
|
|
key === "customerSource" &&
|
|
(!archive.customerSource ||
|
|
!archive.customerSource.some((item) =>
|
|
archiveFilterConditions.customerSource.includes(item)
|
|
))
|
|
) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 判断medicalFilterConditions是否为空
|
|
if (Object.keys(medicalFilterConditions).length !== 0) {
|
|
// 获取最新的就诊记录包含所有字段
|
|
for (let key in medicalFilterConditions) {
|
|
if (medicalFilterConditions.hasOwnProperty(key)) {
|
|
console.log("key", key);
|
|
const recordItem = medicalRecord[key]; // 就诊记录的字段
|
|
const medicalFilterItem = medicalFilterConditions[key]; // 筛选条件的字段
|
|
if (medicalTimeType.includes(key)) {
|
|
executeTime = dayjs(recordItem)
|
|
.add(medicalFilterItem, "day")
|
|
.valueOf();
|
|
}
|
|
if (
|
|
!recordItem ||
|
|
(typeof medicalFilterItem === "string" &&
|
|
medicalFilterItem !== recordItem) ||
|
|
(Array.isArray(medicalFilterItem) &&
|
|
Array.isArray(recordItem) &&
|
|
!recordItem.some((item) => medicalFilterItem.includes(item)))
|
|
) {
|
|
return {
|
|
isMatch: false,
|
|
key,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (Object.keys(healthFilterConditions).length !== 0) {
|
|
// 获取最新的健康指标包含所有字段
|
|
// 如果健康指标没有更新时间,则立马更新
|
|
// if (!healthFilterConditions['healthIndexUpdate']) executeTime = dayjs().valueOf();
|
|
for (let item in healthFilterConditions) {
|
|
if (healthFilterConditions.hasOwnProperty(item)) {
|
|
// 获取健康指标的字段
|
|
const value = healthFilterConditions[item];
|
|
if (item === "healthIndexUpdate") {
|
|
executeTime = dayjs().add(value, "day").valueOf();
|
|
continue;
|
|
}
|
|
const healthFilterKeys = Object.keys(value);
|
|
const healthItemKeys = Object.keys(healthIndicators);
|
|
const incloudKeys = healthFilterKeys.filter((item) =>
|
|
healthItemKeys.includes(item)
|
|
);
|
|
if (incloudKeys.length === 0) {
|
|
return { isMatch: false, key: "incloudKeys" };
|
|
}
|
|
let isMatch = false;
|
|
// 获取健康指标的值
|
|
for (let key in value) {
|
|
const healthFilterItem = value[key];
|
|
const healthItem = healthIndicators[key];
|
|
if (
|
|
healthItem &&
|
|
((isObject(healthFilterItem) &&
|
|
healthItem >= healthFilterItem.min &&
|
|
healthItem <= healthFilterItem.max) ||
|
|
(Array.isArray(healthFilterItem) &&
|
|
Array.isArray(healthItem) &&
|
|
healthItem.some((item) => healthFilterItem.includes(item))))
|
|
) {
|
|
isMatch = true;
|
|
}
|
|
}
|
|
if (!isMatch) return { isMatch: false };
|
|
}
|
|
}
|
|
}
|
|
// 如果执行时间存在且小于当天 则不执行
|
|
if (executeTime && dayjs(executeTime).isBefore(dayjs().startOf("day"))) {
|
|
console.log("执行时间小于当天, 不执行");
|
|
isMatch = false;
|
|
}
|
|
return {
|
|
isMatch,
|
|
executeTime,
|
|
};
|
|
}
|
|
|
|
function parseFilterConditions(filterConditionsArray) {
|
|
const filterConditions = {
|
|
archiveFilterConditions: {},
|
|
medicalFilterConditions: {},
|
|
healthFilterConditions: {},
|
|
};
|
|
filterConditionsArray.forEach((condition, index) => {
|
|
const { theme, value, condition: cond } = condition;
|
|
switch (theme) {
|
|
case "includeTag":
|
|
filterConditions.archiveFilterConditions["includeTag"] = value;
|
|
filterConditions.archiveFilterConditions["includeTagType"] = cond;
|
|
break;
|
|
case "excludeTag":
|
|
filterConditions.archiveFilterConditions["excludeTag"] = value;
|
|
filterConditions.archiveFilterConditions["excludeTagType"] = cond;
|
|
break;
|
|
case "sex":
|
|
filterConditions.archiveFilterConditions["sex"] = cond;
|
|
break;
|
|
case "birthdayTheme":
|
|
case "intentedProject":
|
|
case "customerSource":
|
|
case "age":
|
|
case "notArriveTheme":
|
|
filterConditions.archiveFilterConditions[cond] = value;
|
|
break;
|
|
case "outpatientTheme":
|
|
case "inhospitalTheme":
|
|
case "operationTheme":
|
|
case "physicalExaminationTheme":
|
|
filterConditions.medicalFilterConditions[cond] = value;
|
|
break;
|
|
case "healthIndexTheme":
|
|
// 健康指标
|
|
if (cond === "healthIndexAbnormal") {
|
|
let conditions = {};
|
|
if (Array.isArray(value)) {
|
|
value.forEach((item) => {
|
|
const { condition, key, type, value: v } = item;
|
|
conditions[condition] = v;
|
|
});
|
|
}
|
|
filterConditions.healthFilterConditions[index] = conditions;
|
|
//健康指标更新时间
|
|
} else {
|
|
filterConditions.healthFilterConditions[cond] = value;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
return filterConditions;
|
|
}
|
|
|
|
function isObject(value) {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
}
|
|
|
|
/**
|
|
* 执行sop任务
|
|
* @param {string} corpId 机构id
|
|
* @param {string} eventType 事件类型
|
|
* @param {string} executeMethod 执行方法
|
|
* @param {string} sendContent 发送内容
|
|
* @param {string} fileList 发送文件
|
|
* @param {string} executeUserId 执行人
|
|
* @param {string} executeTeamId 执行团队id
|
|
* @param {string} executeTeamName 执行团队名称
|
|
* @param {string} creatorUserId 创建人
|
|
* @param {string} customerId 客户id
|
|
* @param {string} customerName 客户姓名
|
|
* @param {string} customerUserId 客户用户id
|
|
* @param {string} sopTaskId sop任务id
|
|
* @param {string} executeTime 执行时间
|
|
* @param {number} triggerInterval 触发限制
|
|
* @returns
|
|
*/
|
|
exports.createCustomerSopTask = async (content) => {
|
|
let {
|
|
corpId,
|
|
eventType,
|
|
executeMethod,
|
|
sendContent,
|
|
fileList,
|
|
executeUserId,
|
|
executeTeamId,
|
|
executeTeamName,
|
|
creatorUserId,
|
|
customerId,
|
|
customerName,
|
|
customerUserId,
|
|
sopTaskId,
|
|
executeTime,
|
|
triggerInterval,
|
|
newTagIds,
|
|
removeTagIds,
|
|
sopContent,
|
|
sopName,
|
|
groups,
|
|
} = content;
|
|
if (executeTime && !triggerInterval) triggerInterval = -1;
|
|
let { data } = await this.getCustomerSopTask({
|
|
corpId,
|
|
customerId,
|
|
sopTaskId,
|
|
getType: "All",
|
|
});
|
|
console.log("data", data);
|
|
const today = dayjs().endOf("day").valueOf();
|
|
let taskData = data[0];
|
|
if (taskData && taskData.triggerInterval && taskData.triggerInterval != -1) {
|
|
if (!taskData.triggerInterval)
|
|
return { success: false, message: "任务已执行" };
|
|
let interval = dayjs(taskData.executeTime)
|
|
.add(taskData.triggerInterval, "day")
|
|
.valueOf();
|
|
if (today < interval)
|
|
return { success: false, message: "任务还未过间隔时间,不生成" };
|
|
}
|
|
let params = {
|
|
_id: common.generateRandomString(24),
|
|
corpId,
|
|
eventType,
|
|
executeMethod,
|
|
sendContent,
|
|
fileList,
|
|
executeUserId,
|
|
executeTeamId,
|
|
executeTeamName,
|
|
creatorUserId,
|
|
customerId,
|
|
customerName,
|
|
customerUserId,
|
|
sopTaskId,
|
|
executeTime,
|
|
triggerInterval,
|
|
sopContent,
|
|
executeStatus: "init",
|
|
sopName,
|
|
createTime: dayjs().valueOf(),
|
|
};
|
|
// 执行任务
|
|
// 根据执行方式执行任务
|
|
// 标签
|
|
if (
|
|
executeMethod === "tag" &&
|
|
(!executeTime || (executeTime && dayjs(executeTime).isSame(dayjs(), "day")))
|
|
) {
|
|
await customerSopTaskAutoTag({ customerId, newTagIds, removeTagIds });
|
|
params.executeStatus = "executed";
|
|
}
|
|
if (
|
|
executeMethod === "enterGroup" &&
|
|
(!executeTime || (executeTime && dayjs(executeTime).isSame(dayjs(), "day")))
|
|
) {
|
|
const { success, targetGroupId, message } = await customerSopTaskAutoGroup({
|
|
customerId,
|
|
groups,
|
|
executeUserId,
|
|
corpId,
|
|
executeTime,
|
|
executeTeamId,
|
|
executeTeamName,
|
|
});
|
|
params.executeStatus = "executed";
|
|
params.groupId = targetGroupId;
|
|
if (!success) {
|
|
params.failReason = message;
|
|
}
|
|
}
|
|
if (
|
|
executeMethod === "groupmsg" &&
|
|
(!executeTime || (executeTime && dayjs(executeTime).isSame(dayjs(), "day")))
|
|
) {
|
|
await createGroupmsgTask({
|
|
executeUserId,
|
|
customers: [customerId],
|
|
sendContent,
|
|
fileList,
|
|
sopTaskId,
|
|
executeTeamIds: [executeTeamId],
|
|
externalUserIds: [customerUserId],
|
|
customerSopTaskIds: [sopTaskId],
|
|
corpId,
|
|
sopName,
|
|
});
|
|
// 生成群发消息, 未执行
|
|
params.executeStatus = "unexecuted";
|
|
}
|
|
if (
|
|
executeMethod === "todo" &&
|
|
(!executeTime || (executeTime && dayjs(executeTime).isSame(dayjs(), "day")))
|
|
) {
|
|
await customerSopTaskCreateTodo([params]);
|
|
// 生成代码, 未执行
|
|
params.executeStatus = "unexecuted";
|
|
}
|
|
if (
|
|
!executeTime ||
|
|
(executeTime && !dayjs(executeTime).isSame(dayjs(), "day"))
|
|
) {
|
|
params.executeTime = dayjs().add(1, "day").valueOf();
|
|
}
|
|
|
|
console.log("传入时间params", params);
|
|
await db.collection("sop-customer-task").insertOne(params);
|
|
return {
|
|
success: true,
|
|
message: "创建sop任务成功",
|
|
};
|
|
};
|
|
|
|
exports.removeCustomerSopTask = async (content) => {
|
|
const { corpId, customerId } = content;
|
|
await db
|
|
.collection("sop-customer-task")
|
|
.deleteMany({ corpId, customerId, executeStatus: "unexecuted" });
|
|
return {
|
|
success: true,
|
|
message: "删除sop任务成功",
|
|
};
|
|
};
|
|
|
|
exports.getCustomerSopTask = async (content) => {
|
|
const {
|
|
corpId,
|
|
customerId,
|
|
sopTaskId,
|
|
executeUserId,
|
|
executeStatus,
|
|
dates,
|
|
page = 1,
|
|
pageSize = 10,
|
|
getType = "",
|
|
} = content;
|
|
let query = {
|
|
corpId,
|
|
sopTaskId,
|
|
};
|
|
if (executeUserId) query.executeUserId = executeUserId;
|
|
if (executeStatus) query.executeStatus = executeStatus;
|
|
if (customerId) query.customerId = customerId;
|
|
if (dates && dates.length > 0) {
|
|
let dateStart = dayjs(dates[0]).startOf("day").valueOf();
|
|
let dateEnd = dayjs(dates[1]).endOf("day").valueOf();
|
|
query.createTime = { $gte: dateStart, $lte: dateEnd };
|
|
}
|
|
if (getType !== "All") query.executeStatus = { $ne: "init" };
|
|
const total = await db.collection("sop-customer-task").countDocuments(query);
|
|
const pages = Math.ceil(total / pageSize);
|
|
const data = await db
|
|
.collection("sop-customer-task")
|
|
.find(query)
|
|
.sort({ createTime: -1 })
|
|
.skip((page - 1) * pageSize)
|
|
.limit(pageSize)
|
|
.toArray();
|
|
|
|
return {
|
|
success: true,
|
|
message: "获取sop任务成功",
|
|
total,
|
|
pages,
|
|
data,
|
|
};
|
|
};
|
|
|
|
exports.updateSopTaskField = async (ctx) => {
|
|
if (!ctx.corpId || !ctx.id) return { success: false, message: "更新失败" };
|
|
try {
|
|
const task = await db
|
|
.collection("sop-tasks")
|
|
.findOne({ corpId: ctx.corpId, _id: ctx.id });
|
|
if (!task) return { success: false, message: "未找到sop任务" };
|
|
|
|
let payload = null;
|
|
if (ctx.action === "stop") payload = { sopEnableStatus: "disable" };
|
|
else if (ctx.action === "startRightNow")
|
|
payload = { sopEnableStatus: "enable", executeStartTime: Date.now() };
|
|
else if (ctx.action === "start") payload = { sopEnableStatus: "enable" };
|
|
|
|
if (payload) {
|
|
await db
|
|
.collection("sop-tasks")
|
|
.updateOne({ _id: ctx.id }, { $set: payload });
|
|
return { success: true, message: "更新成功" };
|
|
}
|
|
return { success: false, message: "更新失败" };
|
|
} catch (e) {
|
|
return { success: false, message: e.message || "更新失败" };
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 档案sop任务触发
|
|
* @param {*} content
|
|
*/
|
|
exports.customerSopTaskTrigger = async () => {
|
|
const fetchData = async (page, pageSize, db) => {
|
|
return await db
|
|
.collection("sop-customer-task")
|
|
.find({
|
|
executeStatus: "init",
|
|
executeTime: {
|
|
$gte: dayjs().startOf("day").valueOf(),
|
|
$lte: dayjs().endOf("day").valueOf(),
|
|
},
|
|
})
|
|
.skip((page - 1) * pageSize)
|
|
.limit(pageSize)
|
|
.toArray();
|
|
};
|
|
const list = await utils.getAllData(fetchData, db);
|
|
let toDoList = list.filter((i) => i.executeMethod === "todo");
|
|
let groupMsgList = list.filter((i) => i.executeMethod === "groupmsg");
|
|
let tagList = list.filter((i) => i.executeMethod === "tag");
|
|
let enterGroupList = list.filter((i) => i.executeMethod === "enterGroup");
|
|
if (toDoList.length > 0) await customerSopTaskCreateTodo(toDoList);
|
|
if (groupMsgList.length > 0)
|
|
await customerSopTaskCreateGroupMsg(groupMsgList);
|
|
if (tagList.length > 0) {
|
|
for (let item of tagList) {
|
|
await customerSopTaskAutoTag(item);
|
|
}
|
|
}
|
|
if (enterGroupList.length > 0) {
|
|
for (let item of enterGroupList) {
|
|
await customerSopTaskAutoGroup(item);
|
|
}
|
|
}
|
|
const ids = list.map((i) => i._id);
|
|
await db
|
|
.collection("sop-customer-task")
|
|
.updateMany(
|
|
{ _id: { $in: ids } },
|
|
{ $set: { executeStatus: "unexecuted" } }
|
|
);
|
|
return { success: true, message: "触发sop任务成功" };
|
|
};
|
|
|
|
// 获取待办类型的sop任务
|
|
async function customerSopTaskCreateTodo(list) {
|
|
for (let item of list) {
|
|
let {
|
|
triggerInterval,
|
|
executeMethod,
|
|
_id,
|
|
executeUserId,
|
|
executeStatus,
|
|
executeTeamId,
|
|
executeTime,
|
|
sopContent,
|
|
executeTeamName,
|
|
sendContent,
|
|
sopName,
|
|
fileList,
|
|
...rest
|
|
} = item;
|
|
rest.createTime = dayjs().valueOf();
|
|
rest.creatorUserId = "system";
|
|
rest.isFeedback = false;
|
|
rest.eventStatus = "untreated";
|
|
rest.customerSopTaskId = _id;
|
|
rest.executorUserId = executeUserId;
|
|
rest.executeTeamId = executeTeamId;
|
|
rest.plannedExecutionTime = executeTime;
|
|
rest.planName = sopName;
|
|
rest.taskContent = sopName + sopContent;
|
|
rest.executeTeamName = executeTeamName;
|
|
rest.sendContent = sendContent;
|
|
rest.executeMethod = "todo";
|
|
rest.pannedEventSendFile = getTodoSendFile(fileList);
|
|
rest.expireTime = dayjs().add(7, "day").endOf("day").valueOf();
|
|
await db.collection("to-do-events").insertOne({
|
|
_id: common.generateRandomString(24),
|
|
...rest,
|
|
});
|
|
}
|
|
}
|
|
|
|
// 生成群发任务
|
|
async function customerSopTaskCreateGroupMsg(list) {
|
|
if (list.length === 0) return;
|
|
let newObj = groupBySopTaskIdAndExecuteUserId(list);
|
|
for (const key in newObj) {
|
|
if (newObj.hasOwnProperty(key)) {
|
|
const array = newObj[key];
|
|
const customers = array.map((i) => i.customerId);
|
|
const customerSopTaskIds = array.map((i) => i._id);
|
|
const executeTeamIds = [...new Set(array.map((i) => i.executeTeamId))];
|
|
const externalUserIds = [...new Set(array.map((i) => i.customerUserId))];
|
|
const {
|
|
sendContent,
|
|
executeUserId,
|
|
fileList,
|
|
sopTaskId,
|
|
corpId,
|
|
sopName,
|
|
} = array[0];
|
|
await createGroupmsgTask({
|
|
executeUserId,
|
|
customers,
|
|
sendContent,
|
|
fileList,
|
|
sopTaskId,
|
|
executeTeamIds,
|
|
customerSopTaskIds,
|
|
corpId,
|
|
externalUserIds,
|
|
sopName,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
async function createGroupmsgTask({
|
|
executeUserId,
|
|
customers,
|
|
sendContent,
|
|
fileList,
|
|
sopTaskId,
|
|
executeTeamIds,
|
|
customerSopTaskIds,
|
|
corpId,
|
|
externalUserIds,
|
|
sopName,
|
|
}) {
|
|
const params = {
|
|
sendType: "MESSAGE",
|
|
executor: executeUserId,
|
|
customers,
|
|
content: sendContent,
|
|
attachments: common.getAttachments(fileList, sopTaskId, executeUserId),
|
|
startTaskDate: dayjs().valueOf(),
|
|
endTaskDate: dayjs().add(3, "day").endOf("day").valueOf(),
|
|
sendSource: "MINE",
|
|
teamIds: executeTeamIds,
|
|
creator: "system",
|
|
createSounrce: "MINE",
|
|
executeStatus: "doing",
|
|
sopTaskId,
|
|
customerSopTaskIds,
|
|
corpId,
|
|
externalUserIds,
|
|
taskName: sopName,
|
|
};
|
|
await appFunction.createGroupmsgTask({ params, corpId });
|
|
}
|
|
function groupBySopTaskIdAndExecuteUserId(list) {
|
|
return list.reduce((acc, item) => {
|
|
const key = `${item.sopTaskId}-${item.executeUserId}`;
|
|
if (!acc[key]) {
|
|
acc[key] = [];
|
|
}
|
|
acc[key].push(item);
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
function getTodoSendFile(fileList) {
|
|
let file = Array.isArray(fileList) && fileList[0] ? fileList[0].file : {};
|
|
if (!file) return {};
|
|
let { name, type, url, surveryId } = file;
|
|
let query = { name, type, url };
|
|
if (surveryId) query.surveryId = surveryId;
|
|
return query;
|
|
}
|
|
|
|
// 自动打标签
|
|
async function customerSopTaskAutoTag({ customerId, newTagIds, removeTagIds }) {
|
|
if (!customerId) return;
|
|
let customerData = await db.collection("member").findOne({ _id: customerId });
|
|
if (!customerData) return;
|
|
let { tagIds = [] } = customerData;
|
|
|
|
if (Array.isArray(newTagIds) && newTagIds.length > 0)
|
|
tagIds = [...new Set([...tagIds, ...newTagIds])];
|
|
|
|
if (Array.isArray(removeTagIds) && removeTagIds.length > 0)
|
|
tagIds = tagIds.filter((i) => !removeTagIds.includes(i));
|
|
|
|
await db
|
|
.collection("member")
|
|
.updateOne({ _id: customerId }, { $set: { tagIds } });
|
|
}
|
|
|
|
// 自动进入分组
|
|
async function customerSopTaskAutoGroup({
|
|
groups,
|
|
corpId,
|
|
customerId,
|
|
executeTime,
|
|
executeUserId,
|
|
executeTeamId,
|
|
executeTeamName,
|
|
}) {
|
|
if (!Array.isArray(groups) || groups.length === 0) return;
|
|
let selectedGroupId = "";
|
|
if (groups.length === 1) {
|
|
selectedGroupId = groups[0].groupId;
|
|
} else {
|
|
const randomValue = Math.floor(Math.random() * 101);
|
|
for (const { groupId, percent } of groups) {
|
|
if (randomValue < percent) {
|
|
selectedGroupId = groupId;
|
|
break;
|
|
}
|
|
}
|
|
if (!selectedGroupId) {
|
|
selectedGroupId = groups[groups.length - 1].groupId;
|
|
}
|
|
}
|
|
let res = await corpGroup.main(
|
|
{
|
|
type: "customerEnterGroup",
|
|
corpId,
|
|
customerId,
|
|
targetGroupId: selectedGroupId,
|
|
executeTeamId,
|
|
executeTeamName,
|
|
executeUserId,
|
|
planExecutionTime: executeTime,
|
|
},
|
|
db
|
|
);
|
|
return {
|
|
...res,
|
|
targetGroupId: selectedGroupId,
|
|
};
|
|
}
|