const utils = require("../utils"); const dayjs = require("dayjs"); const helpers = require("./customer-util"); const sop = require("../sop"); const updateCustomer = require("./update"); const customerQuery = require("./query"); const common = require("../../common"); const appFunction = require("../app-function"); const api = require("../../api"); let db = null; exports.main = async (content, DB) => { db = DB; switch (content.type) { case "autoCreateMember": return await autoCreateMember(content); case "asyncCustomerTag": return await asyncCustomerTag(content); case "update": return await updateMember(content); case "add": return await addMember(content); case "deleteMember": return await deleteMember(content); case "getReferredPeople": return await getReferredPeople(content); case "setAgeToNumber": return await setAgeToNumber(); case "getMember": return await getMember(content); case "getCustomerInSidebar": return await getCustomerInSidebar(content); case "batchImportCustomer": return await batchImportCustomer(content); case "getmemberCountForTeamId": return await getmemberCountForTeamId(content); case "getmemberAndserviceCountForUserId": return await getmemberAndserviceCountForUserId(content); case "getMemberInfo": return await getMemberInfo(content); case "getMemberForTeam": return await getMemberForTeam(content); case "getCorpCustomer": return await getCorpCustomer(content); case "getMemberBytags": return await getMemberBytags(content); case "externalUseridToMember": return await externalUseridToMember(content); case "editExternalContactRemark": return await exports.editExternalContactRemark(content); case "updateCustomerTimeField": return await exports.updateCustomerTimeField(content); case "getCustomerByUnionId": return await exports.getCustomerByUnionId(content); case "getCustomerNamesById": return await exports.getCustomerNamesById(content); case "triggerSoptaskByCustomerId": return await triggerSoptaskByCustomerId(content); case "updateCustomerInHospitalTime": case "pushCustomerTeamId": case "updateCustomerPersonResponsibles": return await updateCustomer.main(content, db); case "getCustomersCount": case "getInHospitalCustomersCount": return await customerQuery.main(content, db); case "addConsumeRecord": return await addConsumeRecord(content); case "updateCustomerReportPeople": return await updateCustomerReportPeople(content); case "getCustomerReportLog": return await getCustomerReportLog(content); } }; /** * 自动建档 * @param {string} corpId 企业微信ID * @param {string} env 环境ID * @param {string} externalUserId 用户userId * @param {string} name 用户姓名 * @param {string} relationship 关系 * @param {Array} tags 标签 * @returns */ /** * 自动建档 * @param {string} corpId 企业微信ID * @param {string} name 用户姓名 * @param {string} externalUserId 用户userId * @param {object} params 其他参数 * @param {string} userId 用户ID * @returns */ async function autoCreateMember({ corpId, name, externalUserId, params, userId, }) { const query = { corpId, externalUserId }; let data = await db.collection("member").find(query).toArray(); if (data.length > 0) return { success: true, message: "该客户已存在", }; if (!name) { let externalUserIdInfo = await api.getWecomApi({ type: "getNameByexternalUserId", externalUserId, corpId, }); let info = externalUserIdInfo.data; if (info && info.name) name = info.name; } // 获取当前客户数据 const teamIds = await getTeamList(userId, corpId); if (teamIds.length === 0) { return { success: false, message: "请先创建团队", }; } const personResponsibles = teamIds.map((i) => { return { corpUserId: userId, teamId: i }; }); console.log(" 外部联系人name", name); const addQuery = { _id: common.generateRandomString(24), corpId, name, externalUserId, relationship: "本人", createTime: new Date().getTime(), creator: "系统自动建档", customerStage: "OMINHOSPITALA", createType: "auto", personResponsibles, teamId: teamIds, ...params, }; await addMember({ params: addQuery }); return { success: true, message: "自动建档成功", }; } /** * 自动化建档 * @param {string} corpId - 企业微信ID */ async function autoCustomerArchives(context, name, qrCodeInfo) { const { ExternalUserID, CorpID, UserID } = context; // 获取到teamId const teamIds = await getTeamList(UserID, CorpID); // 获取二维码数据 // 遍历teamIds建档 // 判断是否已经建档 const archivedCount = await db .collection("member") .find({ corpId: CorpID, externalUserId: ExternalUserID, }) .count(); console.log("已经建档数", archivedCount); if (archivedCount > 0) return; const { tagIds, customerSource } = qrCodeInfo; const personResponsibles = teamIds.map((i) => { return { corpUserId: UserID, teamId: i, }; }); const params = { _id: common.generateRandomString(24), corpId: CorpID, teamId: teamIds, externalUserId: ExternalUserID, relationship: "本人", tagIds, customerSource, name, personResponsibles, createTime: new Date().getTime(), creator: "扫码自动建档", customerStage: "OMINHOSPITALA", createType: "auto", }; console.log("自动建档", params); await db.collection("member").insertOne(params); await addMember({}); } // 根据userId和corpId获取团队列表 async function getTeamList(userId, corpId) { const result = await api.getCorpApi({ type: "getTeamBymember", corpUserId: userId, corpId, }); if (result && Array.isArray(result.data) && result.data.length > 0) return result.data.map((item) => item.teamId); else return []; } /** * * @param {string} corpId - 企业微信ID * @param {string} env - 环境ID * @param {string} externalUserId - 用户userId * @param {string} name - 用户姓名 * @param {Array} tags - 标签 * @returns */ async function asyncCustomerTag({ corpId, externalUserId, tags, name = "", userId, }) { console.log("外部联系人企业微信标签", tags); // 获取 let result = await api.getCorpApi({ type: "getCorpTags", corpId, }); console.log("获取到机构标签getCorpTags", result); let corpAllTag = result.list || []; // 筛选出机构中所有企业微信的标签 let corpWecomTagIds = []; corpAllTag.forEach((item) => { if (item.createType === "corpAsync") { item.tag.forEach((tag) => { corpWecomTagIds.push(tag.id); }); } }); console.log("筛选出机构中所有企业微信的标签", corpWecomTagIds); let data = await db .collection("member") .find({ corpId, externalUserId }) .toArray(); if (data.length === 0) { let params = { tagIds: tags, }; // 给客户自动建档 await autoCreateMember({ corpId, name, externalUserId, userId, params }); } console.log("自动建档的员工", data); // 合并标签 for (let i = 0; i < data.length; i++) { let tag = data[i].tagIds || []; let createType = data[i].createType; // 筛选出客户标签中的企业微信标签 let memberWeComTagIds = tag.filter((item) => corpWecomTagIds.includes(item) ); console.log("筛选出客户标签中的企业微信标签", memberWeComTagIds); let newTagIds = tags; // corpTagIds 比 newTagIds 多的id 是需要删除的 let delTagIds = memberWeComTagIds.filter( (item) => !newTagIds.includes(item) ); // corpTagIds 比 newTagIds 少的id 是需要新增的 let addTagIds = newTagIds.filter( (item) => !memberWeComTagIds.includes(item) ); // 删除标签 tag = tag.filter((item) => !delTagIds.includes(item)); // 新增标签 tag = Array.from(new Set([...tag, ...addTagIds])); console.log("客户标签tagIds", tag); let params = { tagIds: tag, }; if (createType === "auto") params["name"] = name; console.log("更新标签参数", params); await db .collection("member") .updateOne({ _id: data[i]._id }, { $set: params }); } return { success: true, message: "更新标签成功", }; } /** * 合并自动建档 * @param {*} param0 * @returns */ async function asyncAutoCustomerArchives({ corpId, externalUserId, id, createType, }) { if (!externalUserId || createType === "auto") return; let autoCustomer = await db .collection("member") .findOne({ corpId, externalUserId, createType: "auto" }); console.log("获取到自动建档档案", autoCustomer); if (autoCustomer) { // 合并这些字段 let currentCustomer = await db.collection("member").findOne({ _id: id }); let { teamId = [], tagIds = [], personResponsibles = [] } = autoCustomer; let { tagIds: currentTagIds = [], personResponsibles: currentPersonResponsibles = [], customerSource: currentCustomerSource = [], teamId: currentTeamId = [], } = currentCustomer; let newTeamId = Array.from(new Set([...teamId, ...currentTeamId])); // 合并团队 let newTag = Array.from(new Set([...tagIds, ...currentTagIds])); // 合并标签 let newPersonResponsible = personResponsibles || []; currentPersonResponsibles.forEach((item) => { if ( !personResponsibles.find( (i) => i.teamId === item.teamId && i.corpUserId === item.corpUserId ) ) { newPersonResponsible.push(item); } }); await db.collection("member").deleteOne({ _id: autoCustomer._id }); let params = { tagIds: newTag, personResponsibles: newPersonResponsible, customerSource: currentCustomerSource, updateTime: new Date().getTime(), teamId: newTeamId, createType: "manual", }; await db.collection("member").updateOne({ _id: id }, { $set: params }); } } /** * * @param {string} id - 客户id * @param {object} params - 更新参数 * @param {string} env - 环境ID * @param {string} userId - 用户ID * @returns */ async function updateMember({ id, params, userId, corpId, createTeamId, createTeamName, operationType, }) { const member = await db.collection("member").findOne({ _id: id }); if (params.corpId === "undefined" || !params.corpId) { delete params.corpId; } params["updateTime"] = new Date().getTime(); if ("age" in params && params["age"] !== undefined) { params["age"] = parseInt(params["age"]) > 0 ? parseInt(params["age"]) : ""; } if (params.idCard) { const { gender, birthDate, age } = utils.calculateIdCardInfo(params.idCard); params.sex = gender; params.birthday = birthDate; params.age = age; const repeatIdCardCount = await db.collection("member").countDocuments({ idCard: params.idCard, _id: { $ne: id }, }); if (repeatIdCardCount > 0) { return { success: false, message: "已存在相同身份证号档案!", }; } } params.createType = "manual"; if (member.createType === "auto") params.creator = userId || ""; // 自动更新最新的出生日期时间戳 if (member && (params.idCard || params.birthday)) { const mergeData = { ...member, ...params }; const birthdayStamp = helpers.getBirthdayStamp(mergeData); if (birthdayStamp) params["birthdayStamp"] = birthdayStamp; if (!mergeData.birthday && !mergeData.idCard && "birthdayStamp" in member) { params["birthdayStamp"] = undefined; } } await db.collection("member").updateOne({ _id: id }, { $set: params }); // 合并自动建档 const asyncAutoCustomerArchivesTask = asyncAutoCustomerArchives({ corpId, externalUserId: params.externalUserId, id, createType: params.createType, }); // 修改了名字, 同步到企业微信备注名 if (!params.externalUserId && params.unbindExternalUserId) params.externalUserId = params.unbindExternalUserId; let reMarkTask = null; if (params.externalUserId || params.name) { reMarkTask = exports.editExternalContactRemark({ corpId, externalUserId: params.externalUserId, memberId: id, }); } // 触发SOP任务 const query = { ...params, externalUserId: member.externalUserId, personResponsibles: member.personResponsibles, }; if ( params.externalUserId && dayjs().startOf("day").valueOf() < member.createTime ) { query.externalUserId = params.externalUserId; query.createTime = member.createTime; } const sopTask = triggerSoptask({ corpId, params: query, customerId: id, }); // 添加服务记录 const createServiceRecordTask = await createServiceRecordTaskFnc({ corpId, id, userId, member, createTeamId, createTeamName, operationType, params, }); await Promise.all([ asyncAutoCustomerArchivesTask, reMarkTask, sopTask, ...createServiceRecordTask, ]); return { success: true, message: "更新成功", }; } // 创建服务记录 async function createServiceRecordTaskFnc({ corpId, id, userId = "", member, createTeamId, createTeamName, operationType, params, }) { let customerName = params.name || member.name; // 添加服务记录 let query = { eventType: "customerUpdate", customerId: id, executorUserId: userId, executeTeamId: createTeamId, createTeamName, creatorUserId: userId, corpId, customerName: customerName, createTime: dayjs().valueOf(), executionTime: dayjs().valueOf(), customerUserId: member.externalUserId, taskContent: `更新客户档案信息`, }; if (member.createType === "auto") { query.eventType = "remindFiling"; } if (!userId) return []; let addServiceRecordTaskList = []; if (params.teamId && operationType === "adminEditTeam") { let addTeamIds = params.teamId.filter( (item) => !member.teamId.includes(item) ); let removeTeamIds = member.teamId.filter( (item) => !params.teamId.includes(item) ); if (addTeamIds.length > 0) { const teamNames = await getTeamNamesByTeamIds({ corpId, teamIds: addTeamIds, }); query.eventType = "adminAllocateTeams"; query.taskContent = `管理员把${customerName}分配给“${teamNames.join( "、" )}“团队`; query.transferToTeamIds = addTeamIds; addServiceRecordTaskList.push(appFunction.addServiceRecord(query)); } if (removeTeamIds.length > 0) { const teamNames = await getTeamNamesByTeamIds({ corpId, teamIds: removeTeamIds, }); query.eventType = "adminRemoveTeams"; query.removeTeamIds = removeTeamIds; query.taskContent = `管理员解除${customerName}与”${teamNames.join( "、" )}“团队的关联`; addServiceRecordTaskList.push(appFunction.addServiceRecord(query)); } } else { addServiceRecordTaskList = [appFunction.addServiceRecord(query)]; } return addServiceRecordTaskList; } async function getTeamNamesByTeamIds({ corpId, teamIds }) { const teams = await db .collection("team") .find({ corpId, teamId: { $in: teamIds } }) .toArray(); return teams.map((item) => item.name); } /** * 新增成员 * @param {object} params - 成员信息 * @param {string} createTeamId - 创建团队ID * @param {string} createTeamName - 创建团队名称 * @returns {object} 新增结果 */ async function addMember({ params, createTeamId, createTeamName }) { const { corpId, name, teamId, idCard } = params; if (!corpId || corpId === "undefined") { return { success: false, message: "机构Id未传", }; } if (!name) { return { success: false, message: "姓名不能为空", }; } if (idCard) { const { gender, birthDate, age } = utils.calculateIdCardInfo(idCard); params.sex = gender; params.birthday = birthDate; params.age = age; } const limitation = await corpCustomtorLimitation(corpId); if (!limitation) { return { success: false, message: "客户数已达上限", }; } if (params.idCard) { const repeat = await isIdCardRepeat(params.idCard, corpId); if (repeat) return { success: false, message: "您的档案已存在,请勿重复建档!" }; } params["createTime"] = new Date().getTime(); params["customerStage"] = params["customerStage"] || "OMINHOSPITALA"; if (teamId && typeof teamId === "string") { params["teamId"] = [teamId]; } if ("age" in params) { params["age"] = parseInt(params["age"]) > 0 ? parseInt(params["age"]) : ""; } params.inHospitalTimes = []; if (typeof params.teamId === "string") params.teamId = [params.teamId]; const birthdayStamp = helpers.getBirthdayStamp(params); if (birthdayStamp) params["birthdayStamp"] = birthdayStamp; params["_id"] = common.generateRandomString(24); const res = await db.collection("member").insertOne(params); // 合并自动建档 const asyncAutoCustomerArchivesTask = asyncAutoCustomerArchives({ corpId, externalUserId: params.externalUserId, id: res.insertedId, createType: params.createType, }); // 修改了名字, 同步到企业微信备注名 const editRemarkTask = exports.editExternalContactRemark({ corpId, externalUserId: params.externalUserId, }); // 触发SOP任务 const sopTask = triggerSoptask({ corpId, params, customerId: res.insertedId, }); // 添加服务记录 let query = { eventType: "remindFiling", customerId: res.insertedId, executorUserId: params.creator, executeTeamId: createTeamId, createTeamName, creatorUserId: params.creator, corpId, customerName: params.name, createTime: dayjs().valueOf(), taskContent: `&&&${params.creator || ""}&&&新增客户${params.name}`, executionTime: dayjs().valueOf(), customerUserId: params.externalUserId, }; // 采集方式 addMethod 手动录入、扫码加好友自动建档、推送建档链接、网电报备 if (params.createType === "auto") { query.addMethod = "扫码加好友自动建档"; } else if (params.addMethod === "eStoreReport") { query.addMethod = "网电报备"; } else if (params.addMethod === "pushLink") { query.addMethod = "推送建档链接"; } else { query.addMethod = "手动录入"; } query.taskContent = query.taskContent + `,采集方式:${query.addMethod}`; const addServiceRecordTask = params.creator ? appFunction.addServiceRecord(query) : ""; await Promise.all([ asyncAutoCustomerArchivesTask, editRemarkTask, sopTask, addServiceRecordTask, ]); return { success: true, message: "添加成功", data: { id: res.insertedId, }, }; } /** * 触发SOP任务 * @param {object} params - 参数 * @returns {object} 触发结果 */ async function triggerSoptask({ corpId, params, customerId }) { const { personResponsibles } = params; if (!personResponsibles || !corpId) { return { success: false, message: "触发SOP任务失败", }; } const query = { corpId, customerId, archive: params, }; console.log("触发SOP任务参数", query); let res = await sop.main( { type: "triggerSopTask", ...query, }, db ); console.log("触发SOP任务"); } /** * 根据客户ID触发SOP任务 * @param {object} params - 参数 * @returns {object} 触发结果 */ async function triggerSoptaskByCustomerId({ corpId, customerId }) { const { data: [member], } = await db.collection("member").find({ _id: customerId }).toArray(); const query = { corpId, customerId, archive: member, }; console.log("触发SOP任务参数", query); let res = await sop.main( { type: "triggerSopTask", ...query, }, db ); console.log("触发SOP任务", res); } /** * 删除成员 * @param {string} id - 成员id * @param {string} corpId - 企业微信ID * @returns {object} 删除结果 */ async function deleteMember({ id, corpId }) { try { await exports.editExternalContactRemark({ memberId: id, corpId, deleteMemberId: id, }); const res = await db.collection("member").deleteOne({ _id: id }); // 删除成员时, 删除SOP任务 await sop.main({ type: "deleteSopTask", corpId, customerId: id }, db); return { success: true, message: "删除成功", data: res, }; } catch (error) { return { success: false, message: error, }; } } /** * 机构客户数限制 * @param {string} corpId - 企业微信ID * @returns {boolean} 是否超出限制 */ async function corpCustomtorLimitation(corpId) { const memberCount = await db.collection("member").find({ corpId }).count(); const { data } = await api.getCorpApi({ type: "getCorpInfo", corpId }); const corp = data && data[0] ? data[0] : {}; const { package } = corp; if (!package) return false; const { customerCount, giveCustomerCount } = package; return memberCount < customerCount + giveCustomerCount; } /** * 判断身份证是否重复 * @param {string} idCard - 身份证号 * @param {string} corpId - 企业微信ID * @returns {boolean} 是否重复 */ async function isIdCardRepeat(idCard, corpId) { try { const res = await db.collection("member").find({ corpId, idCard }).count(); return res > 0; } catch (e) { return Promise.reject(e.message); } } /** * 获取推荐人信息 * @param {object} ctx - 上下文 * @returns {object} 推荐人信息 */ async function getReferredPeople(ctx) { try { const { id: referenceCustomerId, corpId } = ctx; if (referenceCustomerId && corpId) { const page = typeof ctx.page === "number" && ctx.page % 1 === 0 && ctx.page > 0 ? ctx.page : 1; const pageSize = typeof ctx.pageSize === "number" && ctx.pageSize % 1 === 0 && ctx.pageSize > 0 ? ctx.pageSize : 20; const res = db .collection("member") .find({ referenceCustomerId, corpId, referenceType: "客户" }) .skip((page - 1) * pageSize) .limit(pageSize) .project({ name: true, teamId: true, sex: true, mobile: true }); const data = await res.toArray(); const total = await db .collection("member") .find({ referenceCustomerId, corpId, referenceType: "客户" }) .count(); return { success: true, list: data, pages: Math.ceil(total / pageSize), message: "查询成功", }; } return { success: false, message: "参数错误" }; } catch (e) { return { success: false, message: e.message }; } } // 将年龄字段转换为数字 async function setAgeToNumber() { const batchSize = 100; // 每次处理的文档数量 let totalUpdated = 0; try { while (true) { console.log(`Processing batch...`); // 查询一批符合条件的文档 const queryResult = await db .collection("member") .find({ age: { $regex: "^[0-9]+$", $options: "i" }, }) .limit(batchSize) .project({ _id: true, age: true }) .toArray(); if (queryResult.length === 0) { break; // 没有更多文档需要处理 } const bulkOps = queryResult .map((doc) => { const age = parseInt(doc.age, 10); if (!isNaN(age)) { return { updateOne: { filter: { _id: doc._id }, update: { $set: { age: age } }, }, }; } }) .filter(Boolean); if (bulkOps.length > 0) { const result = await db.collection("member").bulkWrite(bulkOps); totalUpdated += result.modifiedCount; } } return { success: true, message: `${totalUpdated} documents updated.`, }; } catch (err) { return { success: false, error: err, }; } } // 获取成员信息 async function getMember(context) { let { unionid, corpId, corpUserId, params = {}, externalUserIds } = context; if (!corpId || corpId === "undefined") { return { success: false, message: "机构Id未传", }; } try { if (corpUserId) params.teamId = await getTeamList(corpUserId, corpId); if (unionid) params.unionid = unionid; if (externalUserIds) params.externalUserId = { $in: externalUserIds }; if (typeof params.name === "string" && params.name.trim()) { params.name = { $regex: ".*" + params.name.trim() + ".*", $options: "i" }; } const fetchData = async (page, pageSize, db) => { let data = await db .collection("member") .find({ corpId, ...params, }) .skip((page - 1) * pageSize) .limit(pageSize) .sort({ createTime: -1 }) .toArray(); return data; }; const list = await utils.getAllData(fetchData, db); return { success: true, message: "获取成功", data: list, }; } catch (error) { return { success: false, message: error, }; } } // 获取侧边栏客户数据 async function getCustomerInSidebar(context) { let { corpId, teamIds, externalUserId } = context; if (!corpId || corpId === "undefined") { return { success: false, message: "机构Id未传", }; } if (!externalUserId) return { success: false, message: "外部联系人id未传" }; try { const res = await db .collection("member") .find({ corpId, externalUserId, }) .sort({ createTime: -1 }) .limit(100) .project({ externalContactInfo: false, }) .toArray(); return { success: true, message: "获取成功", data: res, }; } catch (error) { return { success: false, message: error, }; } } // 根据团队ID获取客户总数 async function getmemberCountForTeamId(context) { const { time, params } = context; if (time === "THISMONTH") { const { startOfThisMouthTimestamp, endOfThisMouthTimestamp } = getThisMouth(); params["createTime"] = { $gte: startOfThisMouthTimestamp, $lte: endOfThisMouthTimestamp, }; } else if (time === "LASTMONTH") { const { lastMonthStartDateTimestamp, lastMonthEndDateTimestamp } = getlastMonthStartTimeAndEndTime(); params["createTime"] = { $gte: lastMonthStartDateTimestamp, $lte: lastMonthEndDateTimestamp, }; } try { const res = await db.collection("member").find(params).count(); return { success: true, message: "获取成功", data: res, }; } catch (error) { return { success: false, message: error, }; } } // 根据userId 获取客户总数 async function getmemberAndserviceCountForUserId(context) { const { params, teamId } = context; const { corpId, userId, startTime, endTime } = params; try { const memberQuery = { corpId, }; if (teamId) { memberQuery.teamId = teamId; memberQuery.personResponsibles = { $elemMatch: { corpUserId: userId, teamId: teamId, }, }; } else { memberQuery.personResponsibles = { $elemMatch: { corpUserId: userId, }, }; } if (startTime && dayjs(startTime).isValid()) { const startTimestamp = dayjs(startTime).startOf("day").valueOf(); memberQuery.createTime = memberQuery.createTime || {}; memberQuery.createTime.$gte = startTimestamp; } if (endTime && dayjs(endTime).isValid()) { const endTimestamp = dayjs(endTime).endOf("day").valueOf(); memberQuery.createTime = memberQuery.createTime || {}; memberQuery.createTime.$lte = endTimestamp; } const memberTotal = await db.collection("member").find(memberQuery).count(); const serviceQuery = { corpId, executorUserId: userId, eventType: { $ne: "serviceRate" }, }; if (startTime && dayjs(startTime).isValid()) { const startTimestamp = dayjs(startTime).startOf("day").valueOf(); serviceQuery.executionTime = serviceQuery.executionTime || {}; serviceQuery.executionTime.$gte = startTimestamp; } if (endTime && dayjs(endTime).isValid()) { const endTimestamp = dayjs(endTime).endOf("day").valueOf(); serviceQuery.executionTime = serviceQuery.executionTime || {}; serviceQuery.executionTime.$lte = endTimestamp; } if (teamId) { serviceQuery.executeTeamId = teamId; } const serviceTotal = await db .collection("service-record") .find(serviceQuery) .count(); return { success: true, message: "获取成功", data: { memberTotal, serviceTotal, }, }; } catch (error) { return { success: false, message: error.message, }; } } async function getmemberAndserviceCountForUserId(context) { const { params, teamId } = context; const { corpId, userId, startTime, endTime } = params; try { const memberQuery = { corpId, }; if (teamId) { memberQuery.teamId = teamId; memberQuery.personResponsibles = { $elemMatch: { corpUserId: userId, teamId: teamId, }, }; } else { memberQuery.personResponsibles = { $elemMatch: { corpUserId: userId, }, }; } if (startTime && dayjs(startTime).isValid()) { const startTimestamp = dayjs(startTime).startOf("day").valueOf(); memberQuery.createTime = memberQuery.createTime || {}; memberQuery.createTime.$gte = startTimestamp; } if (endTime && dayjs(endTime).isValid()) { const endTimestamp = dayjs(endTime).endOf("day").valueOf(); memberQuery.createTime = memberQuery.createTime || {}; memberQuery.createTime.$lte = endTimestamp; } const memberTotal = await db.collection("member").find(memberQuery).count(); const serviceQuery = { corpId, executorUserId: userId, eventType: { $ne: "serviceRate" }, }; if (startTime && dayjs(startTime).isValid()) { const startTimestamp = dayjs(startTime).startOf("day").valueOf(); serviceQuery.executionTime = serviceQuery.executionTime || {}; serviceQuery.executionTime.$gte = startTimestamp; } if (endTime && dayjs(endTime).isValid()) { const endTimestamp = dayjs(endTime).endOf("day").valueOf(); serviceQuery.executionTime = serviceQuery.executionTime || {}; serviceQuery.executionTime.$lte = endTimestamp; } if (teamId) { serviceQuery.executeTeamId = teamId; } const serviceTotal = await db .collection("service-record") .find(serviceQuery) .count(); return { success: true, message: "获取成功", data: { memberTotal, serviceTotal, }, }; } catch (error) { return { success: false, message: error.message, }; } } // 获取上个月的开始和结束时间戳 function getlastMonthStartTimeAndEndTime() { const currentDate = new Date(); const lastMonthYear = currentDate.getFullYear(); const lastMonth = currentDate.getMonth() - 1; const lastMonthLastDate = new Date(lastMonthYear, lastMonth + 1, 0); const lastMonthStartDate = new Date(lastMonthYear, lastMonth, 1, 0, 0, 0); const lastMonthStartDateTimestamp = lastMonthStartDate.getTime(); const lastMonthEndDate = new Date( lastMonthYear, lastMonth, lastMonthLastDate.getDate(), 23, 59, 59 ); const lastMonthEndDateTimestamp = lastMonthEndDate.getTime(); return { lastMonthStartDateTimestamp, lastMonthEndDateTimestamp, }; } // 获取本月的开始时间戳 function getThisMouth() { const currentDate = new Date(); currentDate.setDate(1); currentDate.setHours(0, 0, 0, 0); const startOfThisMouthTimestamp = currentDate.getTime(); return { startOfThisMouthTimestamp, endOfThisMouthTimestamp: new Date().getTime(), }; } // 根据标签ID获取成员列表 async function getMemberBytags(context) { const { corpId, tagIds, userId } = context; let params = { corpId, tagIds: { $in: tagIds } }; if (userId) params["teamId"] = await getTeamList(userId, corpId); try { const res = await db.collection("member").find(params).toArray(); return { success: true, message: "获取成功", data: res, }; } catch (error) { return { success: false, message: "获取失败", }; } } // 获取企业客户 async function getCorpCustomer(context) { try { let { page, pageSize, type, startCreateTime, endCreateTime, corpUserId, showExternalCustomer, permanent_code, userIds, teamId, accessToken, ...params } = context; const { corpId } = params; // 校验企业ID是否为空 if (!corpId) return { success: false, message: "机构ID不能为空" }; // 根据name进行模糊查询 if (typeof params.name === "string" && params.name.trim()) { params.name = new RegExp(".*" + params.name.trim(), "i"); } // 根据mobile进行模糊查询 if (typeof params.mobile === "string" && params.mobile.trim()) { const pattern = params.mobile.trim().split("").join(".*"); params.mobile = new RegExp(pattern, "i"); } // 如果有teamId进行团队筛选 if (teamId) { if (Array.isArray(teamId)) { params["teamId"] = { $in: teamId }; } else { params["teamId"] = teamId; } } if (showExternalCustomer) { params["externalUserId"] = { $exists: true }; params["personResponsibles"] = { $elemMatch: { corpUserId: { $in: userIds } }, }; } // 如果teamId是'无',设置为无效值 if (teamId === "无") { params.teamId = { $or: [{ $eq: [] }, { $exists: false }, { $eq: "" }] }; } // 如果有tagIds,进行标签筛选 if (Array.isArray(params.tagIds) && params.tagIds.length) { params.tagIds = { $all: params.tagIds }; // 匹配所有指定tagId } // 根据时间范围过滤数据 if (startCreateTime && endCreateTime) { const startTime = dayjs(startCreateTime).startOf("day").valueOf(); const endTime = dayjs(endCreateTime).endOf("day").valueOf(); params["createTime"] = { $gte: startTime, $lte: endTime }; } // 聚合管道 const pipeline = [ { $match: params }, // 过滤条件 { $sort: { createTime: -1 } }, // 按createTime降序排序 { $skip: (page - 1) * pageSize }, // 分页跳过的记录数 { $limit: pageSize }, // 设置分页大小 { $lookup: { from: "member-management-plan", // 关联的集合 localField: "_id", // 当前集合字段 foreignField: "customerId", // 关联集合字段 as: "plans", // 返回的字段名 }, }, { $project: showExternalCustomer ? { _id: 1, name: 1 } : { _id: 1, name: 1, plans: 1 }, // 返回需要的字段 }, ]; // 获取总数的聚合管道 const totalPipeline = [ { $match: params }, { $count: "total" }, // 获取符合条件的总数 ]; // 执行总数查询 const totalResult = await db .collection("member") .aggregate(totalPipeline) .toArray(); const total = totalResult.length ? totalResult[0].total : 0; const pages = Math.ceil(total / pageSize); // 执行数据查询 const memberList = await db .collection("member") .aggregate(pipeline) .toArray(); return { success: true, message: "获取成功", data: memberList, total: total, pages: pages, size: pageSize, }; } catch (error) { return { success: false, message: error.toString(), }; } } // 根据团队ID获取成员列表 async function getMemberForTeam(context) { try { const { page, pageSize, corpId, params: data, teamId } = context; const { startCreateTime, endCreateTime, managementPlanStatus, ...params } = data || {}; if (typeof params.name === "string" && params.name.trim()) { params.name = { $regex: ".*" + params.name.trim() + ".*", $options: "i" }; } if (!teamId || (Array.isArray(teamId) && teamId.length == 0)) { return { success: false, message: "团队ID未传", }; } params["corpId"] = corpId; params["teamId"] = teamId; if (Array.isArray(params.tagIds) && params.tagIds.length) { params.tagIds = { $and: params.tagIds.map((id) => ({ $in: [id] })) }; } if (startCreateTime && endCreateTime) { params["createTime"] = { $and: [ { $gte: dayjs(startCreateTime).valueOf() }, { $lte: dayjs(endCreateTime).valueOf() }, ], }; } if (params.startServiceTime || params.endServiceTime) { params["serviceTime"] = { $and: [ { $gte: params.startServiceTime }, { $lte: params.endServiceTime }, ], }; } if (params["groupIds"] === "no-id") { const groupIds = await getGroupIds(teamId); params["groupIds"] = { $nin: groupIds }; } let planParams = {}; if (managementPlanStatus) { planParams["plan.planExecutStaus"] = managementPlanStatus; } const total = await db.collection("member").find(params).count(); const pages = Math.ceil(total / pageSize); const res = await db .collection("member") .aggregate([ { $match: params }, { $sort: { createTime: -1 } }, { $skip: (page - 1) * pageSize }, { $limit: pageSize }, { $lookup: { from: "member-management-plan", localField: "_id", foreignField: "customerId", as: "plans", }, }, ]) .toArray(); const list = res.map((item) => { item.plans.reverse(); const plan = item.plans.find((plan) => plan.executeTeamId === teamId); delete item.plans; return { ...item, plan: plan || {}, }; }); return { success: true, message: "获取成功", data: list, total: total, pages: pages, size: pageSize, }; } catch (error) { return { success: false, message: error, }; } } // 获取团队的groupIds async function getGroupIds(teamId) { const data = await db.collection("group").find({ teamId }).toArray(); const ids = data.map((item) => item._id); return ids; } // 获取成员信息 async function getMemberInfo(context) { try { const { params } = context; const res = await db .collection("member") .aggregate([ { $match: params }, { $lookup: { from: "member", let: { referenceCustomerId: "$_id" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$referenceCustomerId", "$$referenceCustomerId"], }, { $eq: ["$referenceType", "客户"] }, ], }, }, }, ], as: "referenceCount", }, }, { $addFields: { referenceCount: { $size: "$referenceCount" } } }, ]) .toArray(); return { success: true, message: "获取成功", data: res, }; } catch (error) { return { success: false, message: error, }; } } // 批量导入客户 async function batchImportCustomer(context) { const { params } = context; let baseReatParams = Object.entries(params).reduce((prev, [key, value]) => { if (value) { prev[key] = value; } return prev; }, {}); const { idCard, customerNumber } = baseReatParams; if (!idCard && !customerNumber) return { success: false, message: "身份证号和客户编号不能同时为空" }; let getMemberParams = {}; if (idCard) { getMemberParams["idCard"] = idCard; } else if (!idCard && customerNumber) { getMemberParams["customerNumber"] = customerNumber; } let newCustomerId = ""; let operationType = "add"; try { const customer = await db.collection("member").findOne(getMemberParams); if (customer) { baseReatParams["updateTime"] = new Date().getTime(); operationType = "update"; delete baseReatParams["creator"]; await db .collection("member") .updateOne({ _id: customer._id }, { $set: baseReatParams }); newCustomerId = customer._id; } else { baseReatParams["createTime"] = new Date().getTime(); baseReatParams["_id"] = common.generateRandomString(24); const res = await db.collection("member").insertOne(baseReatParams); newCustomerId = res.insertedId; } return { success: true, data: newCustomerId, operationType, customer, message: "导入成功", }; } catch (error) { return { success: false, message: error, }; } } /** * 根据externalUserId更新unionid * @param {object} context - 上下文 * @returns {object} 更新结果 */ async function externalUseridToMember(context) { const { externalUserId, unionid, corpId, realUnionid } = context; if (!externalUserId || !unionid || !corpId) { return { success: false, message: "参数错误" }; } try { const data = await db .collection("member") .find({ externalUserId, corpId, unionid: { $ne: unionid }, }) .toArray(); if (data.length === 0) return { success: true, message: "无需更新" }; const ids = data.map((item) => item._id); await db .collection("member") .updateMany({ _id: { $in: ids } }, { $set: { unionid, realUnionid } }); return { success: true, message: "更新成功", }; } catch (error) { return { success: false, message: error.message, }; } } /** * 编辑外部联系人备注 * @param {object} context - 上下文 * @returns {object} 编辑结果 */ exports.editExternalContactRemark = async (context) => { if (!context.memberId && !context.externalUserId) { return { success: false, message: "参数错误" }; } if (context.memberId && !context.externalUserId) { const data = await db .collection("member") .find({ _id: context.memberId }) .toArray(); context.externalUserId = data[0].externalUserId; } if (!context.externalUserId) { return { success: false, message: "外部联系人Id未传" }; } const query = { corpId: context.corpId, externalUserId: context.externalUserId, }; if (context.deleteMemberId) { query["_id"] = { $ne: context.deleteMemberId }; } const memberList = await db.collection("member").find(query).toArray(); const list = memberList.map((item) => ({ name: item.name, relationship: item.relationship, })); const res = await api.getWecomApi({ type: "asyncExternalContactRemark", externalUserId: context.externalUserId, corpId: context.corpId, list, }); return res; }; /** * 更新客户的时间字段 * @param {object} context - 上下文 * @returns {object} 更新结果 */ exports.updateCustomerTimeField = async (context) => { const { field, _id, corpId, time } = context; try { if ( typeof field !== "string" || !corpId || !_id || !time || !dayjs(time).isValid() ) { return { success: false, message: "参数错误", }; } const customer = await db .collection("member") .find({ _id, corpId }) .project({ [field]: 1 }) .toArray(); if ( customer.length > 0 && (!customer[0][field] || dayjs(customer[0][field]).isBefore(dayjs(time))) ) { await db .collection("member") .updateOne( { _id, corpId }, { $set: { [field]: dayjs(time).valueOf() } } ); return { success: true, message: "更新成功", }; } return { success: false, message: "客户不存在或者无需更新" }; } catch (error) { return { success: false, message: error.message, }; } }; /** * 根据unionid获取客户 * @param {object} ctx - 上下文 * @returns {object} 客户信息 */ exports.getCustomerByUnionId = async (ctx) => { const { unionid, realUnionid, corpId } = ctx; try { const customer = await db .collection("member") .find({ corpId, unionid: { $in: [unionid, realUnionid] } }) .project({ _id: 1, name: 1 }) .limit(1) .toArray(); return { success: Boolean(customer.length), data: customer[0] }; } catch (e) { return { success: false, message: e.message }; } }; /** * 根据客户ID获取客户名称 * @param {object} ctx - 上下文 * @returns {object} 客户名称列表 */ exports.getCustomerNamesById = async (ctx) => { const { ids, corpId } = ctx; if (!corpId || !Array.isArray(ids) || ids.length === 0) { return { success: false, message: "参数错误" }; } try { const list = await db .collection("member") .find({ corpId, _id: { $in: ids } }) .project({ _id: 1, name: 1 }) .toArray(); return { success: true, data: list }; } catch (e) { return { success: false, message: e.message }; } }; /** * 新增客户消费记录 * @param {object} item - 消费记录信息 * @returns {object} 新增结果 */ async function addConsumeRecord(item) { const { consumeAmount, corpId, customerId } = item; const latestConsumeTime = dayjs().valueOf(); const query = { _id: common.generateRandomString(24), consumeAmount, corpId, customerId, createTime: latestConsumeTime, }; await db.collection("consume-record").insertOne(query); return { success: true, message: "更新成功", }; } /** * 更新客户报备人员 * @param {object} ctx - 上下文 * @returns {object} 更新结果 */ async function updateCustomerReportPeople(ctx) { const { customerId, reportUserId, corpId, updateUserId, reportTimeStamp, personResponsibles, teamId, reportTeamId, } = ctx; if ( !corpId || !customerId || !reportUserId || !updateUserId || !reportTimeStamp || !personResponsibles || !teamId || !reportTeamId || !dayjs(reportTimeStamp).isValid() ) { return { success: false, message: "参数错误" }; } try { const customer = await db .collection("member") .find({ _id: customerId, corpId }) .project({ reportUserId: 1, createTime: 1, reportTimeStamp: 1, reportTeamId: 1, }) .toArray(); if (customer.length === 0) return { success: false, message: "客户不存在" }; const res = await db.collection("member").updateOne( { _id: customerId }, { $set: { reportUserId, reportTimeStamp, personResponsibles, reportTeamId, teamId, }, } ); if (res.modifiedCount === 0) return { success: false, message: "更新失败" }; await db.collection("customer-report-log").insertOne({ _id: common.generateRandomString(24), customerId, corpId, reportUserId, updateUserId, reportTimeStamp, preReportUserId: customer[0].reportUserId, preReportTimeStamp: customer[0].reportTimeStamp || customer[0].createTime, preReportTeamId: customer[0].reportTeamId || "", createTime: Date.now(), }); return { success: true, message: "更新成功" }; } catch (e) { return { success: false, message: e.message }; } } /** * 获取客户报备日志 * @param {object} ctx - 上下文 * @returns {object} 报备日志 */ async function getCustomerReportLog(ctx) { const { customerId, corpId, page = 1, pageSize = 10 } = ctx; if (!corpId || !customerId) return { success: false, message: "参数错误" }; try { const total = await db .collection("customer-report-log") .find({ customerId, corpId }) .count(); const list = await db .collection("customer-report-log") .find({ customerId, corpId }) .sort({ createTime: -1 }) .skip((page - 1) * pageSize) .limit(pageSize) .toArray(); return { success: true, list, total, message: "查询成功" }; } catch (error) { return { success: false, message: error.message }; } }