const memberPlan = require("../management-plan/member-plan"); const managementPlanTask = require("../management-plan/task"); const managementPlan = require("../management-plan"); const dayjs = require("dayjs"); const serviceRecord = require("../service-record"); const api = require("../../api"); const appFunction = require("../app-function"); const utils = require("../utils"); const OrderType = { desc: -1, // 从大到小排序 asc: 1, // 从小到大排序 }; let db = null; let currentCorpId = null; exports.main = async (event, DB) => { db = DB; currentCorpId = event.corpId; switch (event.type) { case "updatePlannedExecutionTime": return await updatePlannedExecutionTime(event); case "getEventsRecords": return await getEventsRecords(event); case "getCustomerTodos": return await getCustomerTodos(event); case "batchUpdateTodo": return await batchUpdateTodo(event); case "getEventsCount": return await getEventsCount(event); case "getTodoById": return await getTodoById(event); case "setTodoExecutor": return await setTodoExecutor(event); case "setTodoStatus": return await setTodoStatus(event); case "createEvents": return await createEvents(event); case "batchAddEvent": return await batchAddEvent(event); case "updateEvent": return await updateEvent(event); case "createTodo": return await createTodo(event); case "updateTaskTodo": return await updateTaskTodo(event); case "updateTaskTodoResult": return await updateTaskTodoResult(event); case "removeTodo": return await removeTodo(event); case "batchUpdateToDoAndManagePlan": return await batchUpdateToDoAndManagePlan(event); case "updateRemindFillEvnet": return await updateRemindFillEvnet(event); case "getTodoEventsByPannedEventId": return await getTodoEventsByPannedEventId(event); case "getMemberIsTodoAndPlan": return await getMemberIsTodoAndPlan(event); case "getCorpToDolist": return await getCorpToDolist(event); default: return { success: false, message: "未找到对应方法", }; } }; const common = require("../../common"); /** * 创建待办单任务 * @param {*} event * @returns * **/ async function createEvents(event) { let params = event.params; // 任务创建时间 params = utils.createTodoEvents(params); params._id = common.generateRandomString(24); // 生成随机字符串作为_id let res = await db.collection("to-do-events").insertOne(params); console.log("创建待办单任务", res); return { success: true, message: "创建成功", data: params._id, }; } /** * 更新任务单 * @param {*} event * @returns */ async function updateEvent(event) { let { params, record } = event; console.log("event", event); try { if (!record) { const { data = [] } = await db .collection("to-do-events") .find({ _id: event.id }) .toArray(); record = data[0]; } if (params.result) record.result = params.result; if (record) { if ( record.eventStatus === "untreated" && ["closed", "treated"].includes(params.eventStatus) ) { params.endTime = new Date().getTime(); await todoCreateServiceRecord(record, params.eventStatus); await toDoEventCompleteUpdateSopTask(record); } await db .collection("to-do-events") .updateOne({ _id: event.id }, { $set: params }); await toDoEventCompleteUpdateManagePlan(record); return { success: true, params, message: "更新成功", }; } else { return { success: false, message: "未查询到对应待办数据", }; } } catch (error) { return { success: false, message: "更新失败", }; } } // 待办完成 更新sop任务状态 async function toDoEventCompleteUpdateSopTask(event) { const { corpId, customerSopTaskId } = event; if (!customerSopTaskId) return; console.log("更新sop任务状态", customerSopTaskId); let res = await appFunction.updateCustomerSopTaskStatus({ corpId, customerSopTaskIds: [customerSopTaskId], executeStatus: "executed", }); console.log("更新sop任务状态res", res); } // 待办完成 更新管理计划状态 async function toDoEventCompleteUpdateManagePlan(event) { let { memberPlanId } = event; console.log("toDoEventCompleteUpdateManagePlan", event); if (!memberPlanId) return true; // 查询是否有未处理的任务 const taskCount = await db .collection("management-plan-task") .find({ memberPlanId, taskStatus: "unexecuted" }) .count(); // 查询是否还有未处理的事件 const memberPlanCount = await db .collection("to-do-events") .find({ memberPlanId, eventStatus: "untreated" }) .count(); console.log("taskCount", taskCount); console.log("memberPlanCount", memberPlanCount); // 如果没有未处理的任务和事件, 则关闭管理计划 if (taskCount === 0 && memberPlanCount === 0) { await db .collection("member-management-plan") .updateOne( { _id: memberPlanId }, { $set: { planExecutStaus: "closed" } } ); return true; } else { return false; } } // 待办完成, 生成服务记录 async function todoCreateServiceRecord(event, eventStatus) { const { taskContent, corpId, executorUserId, customerId, creatorUserId, executeTeamId, eventType, customerName, pannedEventSendFile = "", executionTime = dayjs().valueOf(), externalUserId, pannedEventName, result, } = event; if ( eventStatus === "treated" && eventType !== "remindFiling" && eventType !== "workSchedule" ) { let params = { executeTeamId, creatorUserId, corpId, customerName, executorUserId, customerId, eventType, createTime: new Date().getTime(), taskContent, pannedEventSendFile, executionTime, pannedEventName, result, customerUserId: externalUserId, }; let serviceContent = "已完成"; let followUp = [ "followUpNoShow", "followUpNoDeal", "followUp", "followUpPostSurgery", "followUpPostTreatment", ]; let appointment = [ "appointmentReminder", "followUpReminder", "medicationReminder", ]; let consultation = ["consultationService"]; let eventNotification = ["eventNotification"]; if (followUp.includes(eventType)) { serviceContent = "已回访"; } else if (appointment.includes(eventType)) { serviceContent = "已提醒"; } else if (consultation.includes(eventType)) { serviceContent = "已咨询"; } else if (eventNotification.includes(eventType)) { serviceContent = "已通知"; } params["serviceContent"] = result ? result : serviceContent; await serviceRecord.main({ type: "addServiceRecord", ...params }, db); } } /** * 查询待办 * @param {*} context * @returns */ async function getTodoById(context) { try { const { id: _id, corpId } = context; const data = await db .collection("to-do-events") .find({ _id, corpId }) .toArray(); const record = data && data[0] ? data[0] : null; if (record) return { success: true, message: "查询待办数据成功", data: record }; return { success: false, message: "未查询到待办数据" }; } catch (e) { return { success: false, message: "查询待办数据失败" }; } } async function setTodoStatus(context) { try { const { id: _id, eventStatus, result, userId } = context; const endOfToday = dayjs().endOf("day").valueOf(); if (!["closed", "treated"].includes(eventStatus)) return { success: false, message: "操作失败" }; const data = await db.collection("to-do-events").find({ _id }).toArray(); const record = data[0]; if (record && record.expireTime < endOfToday) { return { success: false, message: "操作失败(该待办已过期)" }; } if (record && record.executorUserId !== userId) { return { success: false, message: "操作失败(执行人不匹配)" }; } if (record && record.eventStatus === "untreated") { const endTime = new Date().getTime(); return await updateEvent({ id: _id, params: { endTime, eventStatus, result }, record, }); } if (record) { return { success: false, message: "操作失败(该待办已被处理或者已过期)" }; } return { success: false, message: "未查到该待办数据" }; } catch (e) { return { success: false, message: "操作失败" }; } } async function setTodoExecutor(context) { try { const { id: _id, executorUserId, corpId } = context; if (!corpId) return { success: false, message: "操作失败(机构id不能为空)" }; const data = await db .collection("to-do-events") .find({ _id, corpId }) .toArray(); const record = data[0]; if (record && record.executorUserId) { return { success: false, message: "操作失败(该待办已被接受)" }; } if (record && !executorUserId) { return { success: false, message: "接收人id不能为空" }; } if (record.eventStatus == "untreated") { await db .collection("to-do-events") .updateOne({ _id }, { $set: { executorUserId } }); return { success: true, message: "操作成功" }; } if (record) { return { success: false, message: "该待办状态不支持当前操作" }; } return { success: false, message: "未查到该待办数据" }; } catch (e) { return { success: false, message: "操作失败" }; } } /** * 获取待办单任务数量 * @param {*} context */ async function getEventsCount(context) { try { const { params = {}, teamId } = context; const currentTime = dayjs().endOf("day").valueOf(); params["createTime"] = { $lte: currentTime }; const { eventStatus, plannedExecutionEndTime, ...rest } = params; if (plannedExecutionEndTime && dayjs(plannedExecutionEndTime).isValid()) { const plannedExecutionTimeEnd = dayjs(plannedExecutionEndTime) .endOf("day") .valueOf(); rest["plannedExecutionTime"] = { $exists: true, $lte: plannedExecutionTimeEnd, }; } if (eventStatus === "untreated") rest.expireTime = { $gte: new Date().getTime() }; if (eventStatus && typeof eventStatus === "string") rest.eventStatus = { $in: eventStatus.split(",") }; if (teamId) rest["executeTeamId"] = teamId; const total = await db.collection("to-do-events").find(rest).count(); return { success: true, message: "获取成功", total: total, }; } catch (error) { return { success: false, message: error, }; } } /** * 获取事件记录 * @param {*} context * @returns */ async function getEventsRecords(context) { const todayStartTime = dayjs().startOf("day").valueOf(); const todayEndTime = dayjs().endOf("day").valueOf(); const { page, pageSize, params = {}, sort, teamId } = context; const { orderBy = "createTime", orderType = "desc" } = sort || {}; const order = { [orderBy]: OrderType[orderType] || OrderType["desc"], }; params["createTime"] = { $lte: todayEndTime }; const { eventStatus, taskContent = "", plannedExecutionTime, plannedExecutionEndTime, eventType, customerName, onlyTodo, ...rest } = params; if (params.eventStatus === "untreated") { rest.expireTime = { $gte: todayStartTime }; } if (eventStatus && typeof eventStatus === "string") { rest.eventStatus = { $in: eventStatus.split(",") }; } if (typeof taskContent === "string" && taskContent.trim()) { rest.taskContent = new RegExp(taskContent.trim(), "i"); } if (plannedExecutionTime && dayjs(plannedExecutionTime).isValid()) { const plannedExecutionTimeStart = dayjs(plannedExecutionTime) .startOf("day") .valueOf(); const plannedExecutionTimeEnd = dayjs(plannedExecutionTime) .endOf("day") .valueOf(); rest["plannedExecutionTime"] = { $gte: plannedExecutionTimeStart, $lte: plannedExecutionTimeEnd, }; } if (plannedExecutionEndTime && dayjs(plannedExecutionEndTime).isValid()) { const plannedExecutionTimeEnd = dayjs(plannedExecutionEndTime) .endOf("day") .valueOf(); rest["plannedExecutionTime"] = { $exists: true, $lte: plannedExecutionTimeEnd, }; } if ( Array.isArray(plannedExecutionEndTime) && plannedExecutionEndTime.length === 2 && plannedExecutionEndTime.every((i) => i && dayjs(i).isValid()) ) { const plannedExecutionTimeStart = dayjs(plannedExecutionEndTime[0]) .startOf("day") .valueOf(); const plannedExecutionTimeEnd = dayjs(plannedExecutionEndTime[1]) .endOf("day") .valueOf(); rest["plannedExecutionTime"] = { $gte: plannedExecutionTimeStart, $lte: plannedExecutionTimeEnd, }; } if (Array.isArray(eventType) && eventType.length) { rest["eventType"] = { $in: eventType }; } if (typeof customerName === "string" && customerName.trim()) { rest["customerName"] = new RegExp(customerName.trim(), "i"); } if (params.type === "common") { if (!teamId) { let teamIds = await getTeamList(rest.executorUserId, rest.corpId); rest["executeTeamId"] = { $in: teamIds }; } rest.executorUserId = ""; delete rest.type; } if (teamId) { rest["executeTeamId"] = teamId; } if (onlyTodo) { rest["executeMethod"] = { $ne: "groupTask" }; } const total = await db.collection("to-do-events").find(rest).count(); const pages = Math.ceil(total / pageSize); const res = await db .collection("to-do-events") .find(rest) .sort(order) .skip((page - 1) * pageSize) .limit(pageSize) .toArray(); return { success: true, message: "获取成功", data: res, total: total, pages: pages, size: pageSize, }; } /** * 获取客户待办事项 * @param {*} ctx * @returns */ async function getCustomerTodos(ctx) { const { corpId, customerId, teamId: executeTeamId, teamIds, page = 1, pageSize = 20, startDate, endDate, eventType, userIds, statusList, } = ctx; if (!corpId) return { success: false, message: "机构id不能为空" }; if (typeof customerId !== "string" || !customerId.trim()) return { success: false, message: "客户id不能为空" }; const query = { corpId, customerId }; if (typeof executeTeamId === "string" && executeTeamId.trim()) { query["executeTeamId"] = executeTeamId; } else if (Array.isArray(teamIds) && teamIds.length) { query["executeTeamId"] = { $in: teamIds }; } const dates = []; if (startDate && dayjs(startDate).isValid()) { dates.push({ $gte: dayjs(startDate).startOf("day").valueOf() }); } if (endDate && dayjs(endDate).isValid()) { dates.push({ $lte: dayjs(endDate).endOf("day").valueOf() }); } if (dates.length) { query["plannedExecutionTime"] = { $and: dates }; } if (Array.isArray(eventType) && eventType.length) { query["eventType"] = { $in: eventType }; } if (Array.isArray(userIds) && userIds.length) { query["executorUserId"] = { $in: userIds }; } const statusQuery = []; if (Array.isArray(statusList) && statusList.length) { statusList.forEach((item) => { if (item === "notStart") { statusQuery.push({ eventStatus: "untreated", plannedExecutionTime: { $lte: dayjs().endOf("day").valueOf() }, }); } else if (item === "processing") { statusQuery.push({ eventStatus: "untreated", plannedExecutionTime: { $lte: dayjs().startOf("day").valueOf() }, expireTime: { $gte: dayjs().endOf("day").valueOf() }, }); } else if (item === "treated") { statusQuery.push({ eventStatus: "treated" }); } else if (item === "cancelled") { statusQuery.push( { eventStatus: "closed" }, { expireTime: { $lte: dayjs().startOf("day").valueOf() } } ); } }); } const params = statusQuery.length === 0 ? query : { $and: [query, { $or: statusQuery }] }; try { const total = await db.collection("to-do-events").find(params).count(); const list = await db .collection("to-do-events") .find(params) .sort({ plannedExecutionTime: -1, createTime: -1 }) .skip((page - 1) * pageSize) .limit(pageSize) .toArray(); return { success: true, message: "获取成功", data: list, total, size: pageSize, }; } catch (e) { return { success: false, message: e.message || "获取失败" }; } } /** * 获取公司待办事项列表 * @param {*} content * @returns */ async function getCorpToDolist(content) { const { corpId, page, pageSize, dates } = content; const todayStartTime = dayjs().startOf("day").valueOf(); const todayEndTime = dayjs().endOf("day").valueOf(); let query = { corpId, createTime: { $lte: todayEndTime }, expireTime: { $gte: todayStartTime }, eventStatus: "untreated", }; if (dates && Array.isArray(dates) && dates.length > 0) { query["createTime"] = { $gte: dayjs(dates[0]).startOf("day").valueOf(), $lte: dayjs(dates[1]).endOf("day").valueOf(), }; } const total = await db.collection("to-do-events").find(query).count(); const pages = Math.ceil(total / pageSize); const res = await db .collection("to-do-events") .find(query) .sort({ createTime: -1 }) .skip((page - 1) * pageSize) .limit(pageSize) .toArray(); return { success: true, message: "获取成功", data: res, total: total, pages: pages, size: pageSize, }; } /** * 批量添加事件 * @param {*} context * @returns */ async function batchAddEvent(context) { try { const { todos = [] } = context; const list = todos .map((i) => utils.createTodoEvents(i)) .map((item) => addTodo(item)); const res = await Promise.all(list); const isSuccess = res.every((i) => i.success); return { success: isSuccess, message: `操作${isSuccess ? "成功" : "失败"}`, fail: res.filter((i) => !i.success), }; } catch (e) { return { success: false, message: "操作失败" }; } } /** * 添加单个待办事项 * @param {*} item * @returns */ async function addTodo(item) { try { item._id = common.generateRandomString(24); await db.collection("to-do-events").insertOne(item); return { success: true, message: "操作成功" }; } catch (e) { return { success: false, message: "操作失败", customName: item.customerName, executorUserId: item.executorUserId, teamId: item.executeTeamId, }; } } async function createTodo(item) { const { params } = item; try { params["createTime"] = dayjs().valueOf(); params["_id"] = common.generateRandomString(24); // 生成随机字符串作为_id const res = await db.collection("to-do-events").insertOne(params); return { success: true, message: "操作成功", id: res.insertedId }; } catch (e) { return { success: false, message: "操作失败" }; } } async function removeTodo(context) { try { const { id, userId, corpId } = context; if (id) { await db .collection("to-do-events") .deleteOne({ _id: id, creatorUserId: userId, corpId }); return { success: true, message: "删除待办成功" }; } else { return { success: false, message: "待办id不能为空" }; } } catch (e) { return { success: false, message: "删除失败" }; } } // 批量修改在执行待办 async function batchUpdateTodo(context) { try { const { customerIds, corpId, params, currentTeamId } = context; if (customerIds && customerIds.length) { let query = { customerId: { $in: customerIds }, corpId, executeTeamId: currentTeamId, eventStatus: "untreated", }; await db.collection("to-do-events").updateMany(query, { $set: params }); return { success: true, message: "修改待办执行人成功" }; } else { return { success: false, message: "客户档案id不能为空" }; } } catch (e) { return { success: false, message: "修改待办执行人失败" }; } } async function batchUpdateToDoAndManagePlan(context) { const { operationType, customerIds, corpId, currentTeamId, executorUserId } = context; let todoQuery = { customerId: { $in: customerIds }, corpId, executeTeamId: currentTeamId, }; let managePlanQuery = { customerId: { $in: customerIds }, corpId, executeTeamId: currentTeamId, }; let managePlanTaskQuery = { customerId: { $in: customerIds }, corpId, executeTeamId: currentTeamId, }; // 更新待办 if (operationType === "closed") { todoQuery["params"] = { eventStatus: "closed" }; managePlanQuery["params"] = { planExecutStaus: "closed" }; managePlanTaskQuery["params"] = { taskStatus: "closed" }; } else if (operationType === "updateExecutor") { todoQuery["params"] = { executorUserId }; managePlanQuery["params"] = { executorUserId }; managePlanTaskQuery["params"] = { executorUserId }; } try { await batchUpdateTodo(todoQuery); // 更新管理计划 await memberPlan.main( { ...managePlanQuery, type: "batchUpdateMemberManagePlan", corpId: currentCorpId, }, db ); // 更新管理计划任务 await managementPlanTask.main( { ...managePlanTaskQuery, type: "batchUpdateManageTask", corpId: currentCorpId, }, db ); return { success: true, message: "操作成功" }; } catch (e) { return { success: false, message: "操作失败" }; } } async function getTeamList(executorUserId, corpId) { const result = await api.getCorpApi({ type: "getTeamBymember", corpUserId: executorUserId, corpId, }); if (result && Array.isArray(result.data) && result.data.length > 0) return result.data.map((item) => item.teamId); else return []; } async function updateRemindFillEvnet(item) { const { toDoEventId } = item; let newDate = new Date().getTime(); try { const event = await db .collection("to-do-events") .findOne({ _id: toDoEventId }); if (event) { const { createTime } = event; if (createTime > newDate) { await db.collection("to-do-events").deleteOne({ _id: toDoEventId }); return { success: false, message: "待办未显示,删除" }; } else { await db .collection("to-do-events") .updateOne( { _id: toDoEventId }, { $set: { eventStatus: "treated", endTime: dayjs().valueOf() } } ); return { success: true, message: "待办已显示,更新成已办" }; } } } catch (error) { return { success: false, message: "更新失败" }; } } async function getTodoEventsByPannedEventId(context) { const { page, pageSize, pannedEventId } = context; try { const total = await db .collection("to-do-events") .countDocuments({ pannedEventId }); const pages = Math.ceil(total / pageSize); const res = await db .collection("to-do-events") .find({ pannedEventId }) .skip((page - 1) * pageSize) .limit(pageSize) .toArray(); return { success: true, message: "获取成功", data: res, total: total, pages: pages, size: pageSize, }; } catch (error) { return { success: false, message: "获取失败" }; } } // 判断客户是否包含待办事项和管理计划 async function getMemberIsTodoAndPlan(context) { const { corpId, memberId, teamId } = context; const params = { corpId, customerId: memberId }; try { if (teamId) params["executeTeamId"] = teamId; const toDoTotal = await db.collection("to-do-events").countDocuments({ ...params, expireTime: { $gte: new Date().getTime() }, eventStatus: "untreated", }); const taskTotal = await db .collection("management-plan-task") .countDocuments({ ...params, taskStatus: "unexecuted" }); return { success: true, message: "获取成功", data: { toDoTotal, taskTotal }, }; } catch (error) { return { success: false, message: error.message }; } } async function updatePlannedExecutionTime(ctx) { const { corpId, id: _id, date } = ctx; if (!corpId || !_id || !date) return { success: false, message: "缺少参数" }; try { if (!dayjs(date).isValid() || dayjs(date).isBefore(dayjs().startOf("day"))) return { success: false, message: "计划执行日期无效" }; const todo = await db.collection("to-do-events").findOne({ _id, corpId }); if (!todo || todo.eventStatus !== "untreated") return { success: false, message: "待办不存在或者已处理" }; await db.collection("to-do-events").updateOne( { _id }, { $set: { plannedExecutionTime: dayjs(date).valueOf(), expireTime: dayjs(date).add(7, "day").valueOf(), }, } ); return { success: true, message: "更新成功" }; } catch (e) { return { success: false, message: e.message }; } } async function updateTaskTodo(ctx) { const { corpId, id: _id, task = {} } = ctx; if ( !corpId || !_id || Object.prototype.toString.call(task) !== "[object Object]" ) return { success: false, message: "缺少参数" }; const { eventType, executeMethod, sendContent, taskContent, fileList, enableSend, executorUserId, planExecutionTime: plannedExecutionTime, } = task; try { const todo = await db.collection("to-do-events").findOne({ _id, corpId }); if ( !todo || todo.eventStatus !== "untreated" || !todo.expireTime || dayjs().isAfter(dayjs(todo.expireTime)) ) { return { success: false, message: "待办不存在或者已处理" }; } const params = {}; if (typeof eventType === "string") params.eventType = eventType; if (typeof executeMethod === "string") params.executeMethod = executeMethod; if (typeof sendContent === "string") params.sendContent = sendContent; if (typeof taskContent === "string") params.taskContent = taskContent; if (Array.isArray(fileList)) params.fileList = fileList; if (typeof enableSend === "boolean") params.enableSend = enableSend; if (typeof executorUserId === "string") params.executorUserId = executorUserId; if (plannedExecutionTime && dayjs(plannedExecutionTime).isValid()) params.plannedExecutionTime = dayjs(plannedExecutionTime).valueOf(); const res = await updateEvent({ params, id: _id, record: {} }); // 如果计划执行时间为今天,且执行方式是群发的,处理群发消息 console.log("=============》", task); await updateGroupmsgTask(task); return res; } catch (e) { return { success: false, message: e.message }; } } /** *如果计划执行时间为今天,且执行方式是待办的,处理待办 * @param {*} ctx * @returns */ async function updateGroupmsgTask({ executeMethod, planExecutionTime, corpId, customerId, customerUserId, sendContent, fileList, executorUserId, taskId, }) { if ( !dayjs(planExecutionTime).isSame(dayjs(), "day") || executeMethod !== "groupTask" ) { return; } const taskList = [ { executeMethod, planExecutionTime, sendContent, fileList, taskId, executorUserId, }, ]; const res = await managementPlan.main({ corpId, customerId, customerUserId, taskList, type: "createGroupmsgTaskByTodo", }); console.log("res", res); } async function updateTaskTodoResult(ctx) { const { corpId, id: _id, result = "" } = ctx; if (!corpId || !_id || typeof result !== "string") return { success: false, message: "参数错误" }; try { const todo = await db.collection("to-do-events").findOne({ _id, corpId }); if (!todo) { return { success: false, message: "待办不存在" }; } const res = await updateEvent({ params: { result }, id: _id, record: {} }); return res; } catch (e) { return { success: false, message: e.message }; } }