let dayjs = require("dayjs"); let utils = require("../utils.js"); const api = require("../../api"); let db = null; exports.main = async (content, DB) => { db = DB; switch (content.type) { case "getCustomerStatistics": return await exports.getCustomerStatistics(content); case "getServiceAndmemberTotalByTeamId": return await exports.getServiceAndmemberTotalByTeamId(content); case "getServiceAndmemberTotalByUserId": return await exports.getServiceAndmemberTotalByUserId(content); case "getServiceTrendByTeamId": return await exports.getServiceTrendByTeamId(content); case "getMemberTrendByTeamId": return await exports.getMemberTrendByTeamId(content); case "getUsersMemberByTeamId": return await exports.getUsersMemberByTeamId(content); case "getTeamsServiceAndMemberCount": return await getTeamsServiceAndMemberCount(content); case "getStaffServiceAndMemberCount": return await getStaffServiceAndMemberCount(content); case "getCustomerSourceCountSort": return await getCustomerSourceCountSort(content); case "getCustomerGroupCountSort": return await getCustomerGroupCountSort(content); case "getCusomterAndServiceCount": return await getCusomterAndServiceCount(content); case "getStaffRate": return await getStaffRate(content); case "getScoreRateTrend": return await getScoreRateTrend(content); case "getTeamCustmerCount": return await getTeamCustmerCount(content); } }; // 获取客户数和服务数 async function getCusomterAndServiceCount(content) { const { corpId } = content; const todayStartTime = dayjs().startOf("day").valueOf(); const todayEndTime = dayjs().endOf("day").valueOf(); // 获取客户总数 const customerTotalCount = await db .collection("member") .find({ corpId }) .count(); const serviceTotalCount = await db .collection("service-record") .find({ corpId, eventType: { $ne: "serviceRate" } }) .count(); let todayCustomerCount = await db .collection("member") .find({ corpId, createTime: { $gte: todayStartTime, $lt: todayEndTime }, }) .count(); let todayServiceCount = await db .collection("service-record") .find({ corpId, eventType: { $ne: "serviceRate" }, createTime: { $gte: todayStartTime, $lt: todayEndTime }, }) .count(); return { success: true, message: "获取成功", customerTotalCount, serviceTotalCount, todayCustomerCount, todayServiceCount, }; } // 分组客户数据统计 async function getCustomerGroupCountSort(content) { const { corpId } = content; const data = await db .collection("member") .aggregate([ { $match: { corpId } }, { $group: { _id: "$groupIds", count: { $sum: 1 } } }, ]) .toArray(); const result = data.reduce((acc, item) => { if (Array.isArray(item._id)) { item._id.forEach((id) => { acc[id] = (acc[id] || 0) + item.count; }); } else if (item._id) { acc[item._id] = (acc[item._id] || 0) + item.count; } return acc; }, {}); let list = Object.entries(result).map(([groupId, count]) => ({ groupId, count, })); const ids = list.map((item) => item.groupId); let res = await db .collection("group") .find({ _id: { $in: ids } }) .limit(1000) .toArray(); list = list.map((item) => { let group = res.find((i) => i._id === item.groupId); if (!group) { return { ...item, groupName: "未知", }; } else { return { ...item, groupName: group.groupName, parentGroupId: group.parentGroupId, }; } }); list = list.filter((i) => i.groupName !== "未知"); let mergedList = []; list.forEach((item) => { if (!item.parentGroupId) { mergedList.push(item); return; } let existingItem = mergedList.find( (el) => el.parentGroupId === item.parentGroupId ); if (existingItem) { existingItem.count += item.count; } else { mergedList.push(item); } }); mergedList.sort((a, b) => b.count - a.count); let countAfterFive = 0; if (mergedList.length > 5) { for (let i = 5; i < mergedList.length; i++) { countAfterFive += mergedList[i].count; } mergedList = mergedList.slice(0, 5); mergedList.push({ groupName: "其他", count: countAfterFive, }); } return { success: true, message: "获取成功", list: mergedList, }; } // 获取获取客户来源的客户数据 async function getCustomerSourceCountSort(content) { const { corpId, sources = [] } = content; const PAGE_SIZE = 1000; // 每页查询的记录数,可以根据实际情况调整 let page = 0; let hasMoreData = true; let allData = []; while (hasMoreData) { const data = await db .collection("member") .aggregate([ { $match: { corpId } }, { $skip: page * PAGE_SIZE }, { $limit: PAGE_SIZE }, { $group: { _id: "$customerSource", count: { $sum: 1 } } }, ]) .toArray(); if (data.length > 0) { allData = allData.concat(data); page++; } else { hasMoreData = false; // 如果没有更多数据,停止查询 } } // 处理数据 const result = allData.reduce((acc, item) => { if (Array.isArray(item._id)) { item._id.forEach((id) => { acc[id] = (acc[id] || 0) + item.count; }); } else if (item._id) { acc[item._id] = (acc[item._id] || 0) + item.count; } return acc; }, {}); // 获取未知来源的数据 let unknowSourceCount = allData.find((i) => !i._id) ? allData.find((i) => !i._id).count : 0; let list = Object.entries(result) .map(([sourceName, count]) => ({ sourceName, count, })) .filter((i) => sources.some((item) => item === i.sourceName)); list.sort((a, b) => b.count - a.count); if (list.length > 5) { // 5名之后相加 let countAfterFive = 0; for (let i = 5; i < list.length; i++) { countAfterFive += list[i].count; } list = list.slice(0, 5); list.push({ sourceName: "其他", count: countAfterFive, }); } list.push({ sourceName: "未知", count: unknowSourceCount, }); return { success: true, message: "获取成功", data: allData, list, }; } //获取团队服务和客户总数 async function getTeamsServiceAndMemberCount(context) { try { const { corpId, dates } = context; let teamList = await getCorpTeams(corpId); teamList = teamList.map((item) => { return { ...item, corpId, dates, }; }); const handler = async (item) => { let { data } = await exports.getServiceAndmemberTotalByTeamId(item); let { averageScore } = await getStaffRate(item); return { ...data, satisfaction: averageScore, }; }; let list = await utils.processInBatches(teamList, handler, 10); return { success: true, message: "获取成功", list, }; } catch (e) { return { success: false, message: e.message }; } } // 获取满意度评分趋势 async function getScoreRateTrend(context) { const { corpId, dates } = context; const { startTime, lastTime } = getStartAndEndTime(dates); let params = { corpId, }; if (dates && Array.isArray(dates) && dates.length !== 0) { params["createTime"] = { $gte: startTime, $lte: lastTime }; } // 已评价的总数 let ratedTotalCount = await db .collection("corp-rate-records") .find({ ...params, rate: { $exists: true } }) .count(); // 未评价的总数 let unratedTotalCount = await db .collection("corp-rate-records") .find({ ...params, rate: { $exists: false }, expireTime: { $lte: new Date().getTime() }, }) .count(); const getRateCount = async (rate) => { return await db .collection("corp-rate-records") .find({ ...params, rate }) .count(); }; let arrCount = Promise.all([ getRateCount(5), getRateCount(4), getRateCount(3), getRateCount(2), getRateCount(1), ]); let [ fiveStarCount, fourStarCount, threeStarCount, twoStarCount, oneStareCount, ] = await arrCount; return { success: true, message: "获取成功", count: { total: ratedTotalCount + unratedTotalCount, fiveStarCount: fiveStarCount + unratedTotalCount, fourStarCount, threeStarCount, twoStarCount, oneStareCount, }, }; } // 获取员工服务满意度评分 async function getStaffRate(context) { const { corpId, dates, userId, teamId } = context; const { startTime, lastTime } = getStartAndEndTime(dates); const rateQuery = { corpId, teamId }; if (userId) rateQuery.userId = userId; if (dates && Array.isArray(dates) && dates.length !== 0) { rateQuery["createTime"] = { $gte: startTime, $lte: lastTime }; } // 获取 4 5星评价的条数 const goodRateCout = await api.getKnowledgeBaseApi({ type: "getRateRecordCount", params: { ...rateQuery, rate: { $in: [4, 5] } }, corpId, }); // 获取 1 2 3星评价的条数 const notGoodRateCout = await api.getKnowledgeBaseApi({ type: "getRateRecordCount", params: { ...rateQuery, rate: { $in: [1, 2, 3] } }, corpId, }); // 获取超时未评价的条数 (超时未评价默认好评) const unratedCount = await api.getKnowledgeBaseApi({ type: "getRateRecordCount", params: { ...rateQuery, rate: { $exists: false }, expireTime: { $lte: new Date().getTime() }, }, corpId, }); const rate = (goodRateCout + unratedCount) / Math.max(goodRateCout + notGoodRateCout + unratedCount, 1); const percent = (rate * 100).toFixed(2); return { success: true, message: "获取成功", averageScore: percent, }; } async function getStaffServiceAndMemberCount(context) { const { corpId, dates } = context; let staffList = await getCorpStaffs(corpId); staffList = staffList.map((item) => { return { userId: item.userid, corpId, dates, }; }); const handler = async (item) => { let { data } = await exports.getServiceAndmemberTotalByUserId(item); let { averageScore } = await getStaffRate(item); return { ...data, satisfaction: averageScore, }; }; let list = await utils.processInBatches(staffList, handler, 10); return { success: true, message: "获取成功", list, }; } exports.getServiceAndmemberTotalByTeamId = async (context) => { const { corpId, teamId, dates, name } = context; const { startTime, lastTime } = getStartAndEndTime(dates); let memberParmas = { corpId, teamId, }; let serviceParams = { corpId, executeTeamId: teamId, eventType: { $ne: "serviceRate" }, }; let registrationParams = { teamId, }; if (Array.isArray(dates) && dates.length !== 0) { memberParmas["createTime"] = { $gte: startTime, $lte: lastTime }; serviceParams["executionTime"] = { $gte: startTime, $lte: lastTime }; registrationParams["createTime"] = { $gte: startTime, $lte: lastTime }; } try { let memberCount = await db.collection("member").find(memberParmas).count(); let serviceCount = await db .collection("service-record") .find(serviceParams) .count(); let visitCount = await db .collection("registration") .find(registrationParams) .count(); return { success: true, message: "获取成功", data: { memberCount, serviceCount, visitCount, teamName: name, }, }; } catch { return { success: false, message: "获取失败", }; } }; exports.getServiceAndmemberTotalByUserId = async (context) => { const { corpId, userId, dates } = context; const { startTime, lastTime } = getStartAndEndTime(dates); try { let memberParams = { corpId, personResponsibles: { $elemMatch: { corpUserId: userId } }, }; let serviceParams = { corpId, executorUserId: userId, eventType: { $ne: "serviceRate" }, }; if (Array.isArray(dates) && dates.length !== 0) { memberParams["createTime"] = { $gte: startTime, $lte: lastTime }; serviceParams["executionTime"] = { $gte: startTime, $lte: lastTime }; } let memberCount = await db.collection("member").find(memberParams).count(); let serviceCount = await db .collection("service-record") .find(serviceParams) .count(); let res = await db .collection("member") .find(memberParams) .project({ name: 1, _id: 1, personResponsibles: 1, }) .toArray(); return { success: true, message: "获取成功", data: { memberCount, serviceCount, userId, res, }, }; } catch { return { success: false, message: "获取失败", }; } }; // 获取所有团队 async function getCorpTeams(corpId) { const fetchData = async (page, pageSize, db) => { const { list = [] } = await api.getCorpApi({ type: "getCorpTeams", corpId, pageSize, page, fields: { name: 1, teamId: 1 }, showCustomerCount: false, }); return Array.isArray(list) ? list : []; }; const list = await utils.getAllData(fetchData, db); return list; } // 获取所有成员 async function getCorpStaffs(corpId) { const fetchData = async (page, pageSize, db) => { const { data } = await api.getCorpApi({ type: 'getCorpMember', page, pageSize, params: { corpId, open_userid: { $exists: true } } }) const list = Array.isArray(data) ? data.map(i => ({ userid: i.userid })).filter(i => i.userid) : []; return list; }; const list = await utils.getAllData(fetchData, db); return list; } exports.getCustomerStatistics = async (content) => { const { corpId } = content; // 校验 corpId 是否存在 if (!corpId) { return { success: false, message: "机构id不能为空", }; } try { // 获取今日的起始和结束时间戳 const todayStartTime = dayjs().startOf("day").valueOf(); const todayEndTime = dayjs().endOf("day").valueOf(); // 使用聚合管道来进行多个统计查询 const result = await db .collection("member") .aggregate([ { $match: { corpId }, }, { $facet: { // 获取客户总数 totalCount: [{ $count: "total" }], // 获取已加好友数 friendCount: [ { $match: { externalUserId: { $ne: "", $exists: true } } }, { $count: "total" }, ], // 获取未加好友数 noFriendCount: [ { $match: { $or: [ { externalUserId: { $eq: "" } }, { externalUserId: { $exists: false } }, ], }, }, { $count: "total" }, ], // 获取今日新增客户数 todayAddCustomerCount: [ { $match: { createTime: { $gte: todayStartTime, $lt: todayEndTime }, }, }, { $count: "total" }, ], // 获取今日新增好友数 todayAddFriendCount: [ { $match: { externalUserId: { $ne: "", $exists: true }, createTime: { $gte: todayStartTime, $lt: todayEndTime }, }, }, { $count: "total" }, ], // 获取今日未加好友数 todayNoFriendCount: [ { $match: { $or: [ { externalUserId: { $eq: "" } }, { externalUserId: { $exists: false } }, ], createTime: { $gte: todayStartTime, $lt: todayEndTime }, }, }, { $count: "total" }, ], }, }, { $project: { customerTotalCount: { $arrayElemAt: ["$totalCount.total", 0] }, friendCount: { $arrayElemAt: ["$friendCount.total", 0] }, noFriendCount: { $arrayElemAt: ["$noFriendCount.total", 0] }, todayAddCustomerCount: { $arrayElemAt: ["$todayAddCustomerCount.total", 0], }, todayAddFriendCount: { $arrayElemAt: ["$todayAddFriendCount.total", 0], }, todayNoFriendCount: { $arrayElemAt: ["$todayNoFriendCount.total", 0], }, }, }, ]) .toArray(); // 处理返回的数据,将缺失的字段赋值为 0 const stats = result[0] || {}; return { success: true, message: "获取成功", data: { customerTotalCount: stats.customerTotalCount || 0, friendCount: stats.friendCount || 0, noFriendCount: stats.noFriendCount || 0, todayAddCustomerCount: stats.todayAddCustomerCount || 0, todayAddFriendCount: stats.todayAddFriendCount || 0, todayNoFriendCount: stats.todayNoFriendCount || 0, }, }; } catch (error) { return { success: false, message: "获取失败", }; } }; function getStartAndEndTime(dates) { if (!dates || dates.length === 0) { return { startTime: "", lastTime: "", }; } let t_1 = dates[0]; let t_2 = dates[1]; return { startTime: t_1 && new Date(t_1).setHours(0, 0, 0, 0), lastTime: t_2 && new Date(t_2).setHours(23, 59, 59, 999), }; } exports.getMemberTrendByTeamId = async (context) => { const { corpId, teamId, dates, userId, dataType = "increaseCount" } = context; const { startTime, lastTime } = getStartAndEndTime(dates); let params = { createTime: { $gte: startTime, $lte: lastTime }, }; try { let result = {}; if (dataType === "increaseCount") { if (userId) { params["personResponsibles"] = { $elemMatch: { corpUserId: userId, teamId: teamId }, }; } params["corpId"] = corpId; params["teamId"] = teamId; result = await db .collection("member") .aggregate([ { $match: params }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: { $toDate: "$createTime" }, }, }, count: { $sum: 1 }, }, }, ]) .toArray(); } else if (dataType === "visitCount") { params["teamId"] = teamId; result = await db .collection("registration") .aggregate([ { $match: params }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: { $toDate: "$createTime" }, }, }, count: { $sum: 1 }, }, }, ]) .toArray(); } else if (dataType === "peopleCount") { params["corpId"] = corpId; params["executeTeamId"] = teamId; if (userId) params["creatorUserId"] = userId; result = await db .collection("service-record") .aggregate([ { $match: params }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: { $toDate: "$createTime" }, }, }, count: { $sum: 1 }, }, }, ]) .toArray(); } let list = result; let filledArray = fillDateGaps(list, dates[0], dates[1]); return { success: true, message: "获取成功", data: filledArray, }; } catch (error) { return { success: false, message: "获取失败", }; } }; exports.getServiceTrendByTeamId = async (context) => { const { corpId, teamId, userId, dates } = context; const { startTime, lastTime } = getStartAndEndTime(dates); let params = { corpId, executeTeamId: teamId, createTime: { $gte: startTime, $lte: lastTime }, }; if (userId) { params["executorUserId"] = userId; } try { const result = await db .collection("service-record") .aggregate([ { $match: params }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: { $toDate: "$createTime" }, }, }, count: { $sum: 1 }, }, }, ]) .toArray(); let list = result; let filledArray = fillDateGaps(list, dates[0], dates[1]); return { success: true, message: "获取成功", data: filledArray, params, }; } catch (error) { return { success: false, message: "获取失败", }; } }; // 获取团队成员客户数 exports.getUsersMemberByTeamId = async (context) => { try { const { memberList } = context; let counts = []; let arr = memberList.map((i) => { return getServiceAndMemberCount(context, i); }); for (let i = 0; i < arr.length; i += 10) { const promiseArr = arr.slice(i, i + 10); const list = await Promise.all(promiseArr); counts = counts.concat(list); } return { success: true, message: "获取成功", data: counts, }; } catch (error) { return { success: false, message: "获取失败", }; } }; async function getServiceAndMemberCount(context, userId) { const { corpId, teamId, dates } = context; const { startTime, lastTime } = getStartAndEndTime(dates); const query = { teamId, personResponsibles: { $elemMatch: { corpUserId: userId, teamId } }, createTime: { $gte: startTime, $lte: lastTime }, }; let servicQuery = { corpId, createTime: { $gte: startTime, $lte: lastTime }, executorUserId: userId, executeTeamId: teamId, eventType: { $ne: "serviceRate" }, }; const customerCount = await db .collection("member") .find({ ...query, corpId }) .count(); const visitCount = await db.collection("registration").find(query).count(); const serviceCount = await db .collection("service-record") .find(servicQuery) .count(); return { userId, customerCount, visitCount, serviceCount, }; } // 填充日期间隔 function fillDateGaps(arr, start, end) { let startDate = new Date(start); let endDate = new Date(end); let dateCounts = {}; arr.forEach((item) => { dateCounts[item._id] = item.count; }); while (startDate <= endDate) { let dateString = startDate.toISOString().split("T")[0]; if (!dateCounts[dateString]) { dateCounts[dateString] = 0; } startDate.setDate(startDate.getDate() + 1); } let datesArray = Object.entries(dateCounts).map(([dateString, count]) => { return { _id: dateString, count: count }; }); datesArray.sort((a, b) => new Date(a._id) - new Date(b._id)); return datesArray; } async function getTeamCustmerCount(ctx) { const { corpId, teamIds } = ctx; if (!corpId || !Array.isArray(teamIds) || teamIds.length === 0) { return []; } try { const customerCounts = await db .collection("member") .aggregate([ { $match: { teamId: { $in: teamIds } } }, // 查找 teamId 数组中包含任意 teamId 的文档 { $unwind: "$teamId" }, // 展开 teamId 数组,每个 teamId 成为一个单独的文档 { $match: { teamId: { $in: teamIds } } }, // 再次匹配这些 teamId 是否在目标队列中 { $group: { _id: "$teamId", // 根据 teamId 聚合 count: { $sum: 1 }, // 计算每个 teamId 的数量 }, }, ]) .toArray(); return customerCounts; } catch (e) { return []; } }