2026-07-27 11:28:33 +08:00

1775 lines
48 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 };
}
}