1775 lines
48 KiB
JavaScript
Raw Normal View History

2026-07-27 11:28:33 +08:00
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 };
}
}