851 lines
26 KiB
JavaScript
Raw Normal View History

2026-07-27 11:28:33 +08:00
const jwt = require("jsonwebtoken");
const { ObjectId } = require("mongodb");
const utils = require("./account-utils.js");
const api = require("../../api");
const jwtUtils = require("../../utils/jwt-utils");
const tokenStore = require("../../middleware/useTokenStore");
const SECRET_KEY = process.env.CONFIG_JWT_SECRET_KEY || "YOUCAN365";
const TOKEN_EXPIRES = process.env.CONFIG_JWT_EXPIRE_TIME || "1d";
let db = null;
// 自定义默认密码
const defaultPassword = "zytzyy6789";
exports.main = async (event, mongodb, req) => {
db = mongodb;
switch (event.type) {
case "updatePassword":
return await exports.updatePassword(event);
case "login":
return await exports.login(event, req);
case "simpleLogin":
return await exports.simpleLogin(event);
case "loginout":
return await loginout(event, req);
case "loginWithToken":
return await exports.loginWithToken(event);
case "refreshToken":
return await refreshToken(event);
case "getLoginLog":
return await getLoginLog(event);
case "resetPassword":
return await resetPassword(event);
case "getAccountList":
return await getAccountList(event);
case "getAccountOptions":
return await getAccountOptions(event);
case "setAccountState":
return await setAccountState(event);
case "addCorpAccount":
return await addCorpAccount(event);
case "editCorpAccount":
return await editCorpAccount(event);
case "updateAccountDrugStoreId":
return updateAccountDrugStoreId(event);
}
};
function getIp(req) {
return req.headers['x-forwarded-for'] ||
req.headers['x-real-ip'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress ||
'';
}
// 修改密码
exports.updatePassword = async (event) => {
const { corpId, username, oldPassword, newPassword } = event;
try {
// 查询员工账户里的account是否存在
const user = await db.collection("corp-member").findOne(
{ corpId, mobile: username } // 查询条件
);
// 如果不存在,则提示账户不存在
if (!user) {
return {
success: false,
message: "账户不存在",
};
}
const { password = "" } = user || {};
if (
(password && password !== oldPassword) ||
(!password && oldPassword !== defaultPassword)
) {
return {
success: false,
message: "原密码错误",
};
}
// 更新密码
await db.collection("corp-member").updateOne(
{ corpId, mobile: username }, // 查询条件
{ $set: { password: newPassword, updateTime: Date.now() } } // 更新内容
);
return {
success: true,
message: "更新成功",
};
} catch (error) {
return {
success: false,
message: error.message,
};
}
};
exports.simpleLogin = async (event) => {
const { corpId, username, password, fetchPharmacy } = event;
const platform = typeof event.platform === 'string' ? event.platform.trim().toUpperCase() : '';
if (typeof corpId !== 'string' || corpId.trim() === '') {
return { success: false, message: "机构ID不能为空" };
}
if (typeof username !== 'string' || username.trim() === '') {
return { success: false, message: "账号不能为空" };
}
if (typeof password !== 'string' || password.trim() === '') {
return { success: false, message: "密码不能为空" };
}
try {
const user = await db.collection("corp-member").findOne({ corpId, mobile: username });
if (!user) {
return { success: false, message: "账户不存在或者密码不正确" };
}
if (user.accountState !== "enable") {
return { success: false, message: "账户未启用,请联系管理员" };
}
const { password: dbPassword = "" } = user || {};
if (!dbPassword) {
if (password === defaultPassword) {
return { success: false, message: "密码未设置" };
}
return { success: false, message: "默认密码不正确" };
}
if (password !== dbPassword) {
return { success: false, message: "账户不存在或者密码不正确" };
}
if (fetchPharmacy && typeof user.drugStoreId === 'string' && user.drugStoreId.trim()) {
const api = require("../../api");
const res = await api.getInternetHospitalApi({
type: "getDrugStoreList",
storeId: user.drugStoreId,
pageSize: 1,
});
const drugStore = Array.isArray(res.list) && res.list[0] ? res.list[0] : null;
user.drugStore = drugStore;
}
const { password: _password, ...data } = user;
const loginId = new ObjectId().toString();
return {
success: true,
message: "登录成功",
user: { ...data, loginId },
};
} catch (error) {
return { success: false, message: error.message };
}
};
// 登陆账号
exports.login = async (event, req) => {
const { corpId, username, password, fetchPharmacy } = event;
// 规范 platform去空格并转为大写方便后续判断例如 'pc' / 'PC' / ' Pc ' 都视为 PC
const platform = typeof event.platform === 'string' ? event.platform.trim().toUpperCase() : '';
try {
// 查询员工账户里的account是否存在
const user = await db.collection("corp-member").findOne(
{ corpId, mobile: username } // 查询条件
);
// 如果不存在,则提示账户不存在
if (!user) {
return {
success: false,
message: "账户不存在或者密码不正确",
};
}
if (user.accountState !== "enable") {
return { success: false, message: "账户未启用,请联系管理员" };
}
const { password: dbPassword = "" } = user || {};
if (!dbPassword) {
if (password === defaultPassword) {
return {
success: false,
message: "密码未设置",
};
} else {
return {
success: false,
message: "默认密码不正确",
};
}
}
if (password !== dbPassword) {
return {
success: false,
message: "账户不存在或者密码不正确",
};
}
if (fetchPharmacy && typeof user.drugStoreId === 'string' && user.drugStoreId.trim()) {
const api = require("../../api");
const res = await api.getInternetHospitalApi({
type: "getDrugStoreList",
storeId: user.drugStoreId,
pageSize: 1,
});
const drugStore =
Array.isArray(res.list) && res.list[0] ? res.list[0] : null;
user.drugStore = drugStore;
}
const { password: _password, ...data } = user;
const loginId = new ObjectId().toString();
// 使用统一的 JWT 工具生成 token
const tokens = jwtUtils.generateTokens({
userId: user._id.toString(),
platform: platform,
username: user.mobile,
corpId: corpId,
role: user.roleIds || [],
mobile: user.mobile,
drugStoreId: user.drugStoreId || '',
loginId: loginId
});
await addLoginLog(data, loginId, platform, getIp(req), tokens.accessToken);
return {
success: true,
message: "登录成功",
user: { ...data, loginId },
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
expiresIn: tokens.expiresIn,
tokenType: "Bearer",
// 保持向后兼容,同时提供旧的 token 字段
token: tokens.accessToken
};
} catch (error) {
return {
success: false,
message: error.message,
};
}
};
exports.loginWithToken = async function (ctx) {
const { token, corpId: reqCorpId } = ctx;
if (typeof token !== "string" || token.trim() === "") {
return { success: false, message: "token无效" };
}
// 先尝试使用统一的 JWT 验证
let user = await getUserFromToken(token);
// 如果统一验证失败,尝试使用旧的验证方式(向后兼容)
if (!user) {
user = await getUserFromTokenLegacy(token);
}
if (!user) {
return { success: false, message: "登录已失效,请重新登录" };
}
// 支持两种数据结构:新的 userId/username 和旧的 mobile
const mobile = user.username || user.mobile;
const userId = user.userId;
const drugStoreId = user.drugStoreId;
const corpId = user.corpId;
if (!mobile || reqCorpId !== corpId) {
return { success: false, message: "登录已失效,请重新登录" };
}
// 构建查询条件
const query = { corpId, mobile };
if (drugStoreId) {
query.drugStoreId = drugStoreId;
}
const account = await db.collection("corp-member").findOne(query);
if (!account) {
return { success: false, message: "登录已失效,请重新登录" };
}
if (account.accountState !== "enable") {
return { success: false, message: "账户未启用,请联系管理员" };
}
// 获取药店信息
if (drugStoreId) {
const api = require("../../api");
const res = await api.getInternetHospitalApi({
type: "getDrugStoreList",
storeId: drugStoreId,
pageSize: 1,
});
const drugStore =
Array.isArray(res.list) && res.list[0] ? res.list[0] : null;
account.drugStore = drugStore;
}
return { success: true, user: account, message: "登录成功" };
};
async function loginout(ctx) {
try {
const query = {
corpId: typeof ctx.corpId === "string" ? ctx.corpId.trim() : "",
loginId: typeof ctx.loginId === "string" ? ctx.loginId.trim() : "",
userId: typeof ctx.userId === "string" ? ctx.userId.trim() : "",
type: { $in: ["login", "loginout"] },
};
const list = await db.collection("login-log").find(query).toArray();
const login = list.find((item) => item.type === "login");
const logout = list.find((item) => item.type === "loginout");
if (login && !logout) {
const { _id, ...rest } = login;
await db
.collection("login-log")
.insertOne({ ...rest, type: "loginout", createTime: Date.now() });
}
return { success: true, message: "登出成功" };
} catch (e) {
return { success: false, message: e.message };
}
}
// 使用统一的 JWT 验证(新)
function getUserFromToken(token) {
return new Promise((resolve) => {
const secret = process.env.JWT_SECRET || 'your-secret-key';
jwt.verify(token, secret, (err, user) => {
if (err) return resolve(null);
resolve(user);
});
});
}
// 使用旧的 JWT 验证(向后兼容)
function getUserFromTokenLegacy(token) {
return new Promise((resolve) => {
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return resolve(null);
resolve(user);
});
});
}
// Token 刷新功能
async function refreshToken(ctx) {
const { refreshToken } = ctx;
if (!refreshToken) {
return {
success: false,
message: '刷新令牌不能为空'
};
}
const result = jwtUtils.refreshAccessToken(refreshToken);
return {
success: true,
message: 'Token 刷新成功',
accessToken: result.accessToken,
expiresIn: result.expiresIn,
tokenType: 'Bearer'
};
}
async function getLoginLog(ctx) {
const { corpId, accountId, userId } = ctx;
try {
if (corpId && typeof corpId !== "string") {
return { success: false, message: "机构id无效" };
}
if (accountId && typeof accountId !== "string") {
return { success: false, message: "账号id无效" };
}
if (userId && typeof userId !== "string") {
return { success: false, message: "用户id无效" };
}
const query = {
corpId,
accountId,
userId,
};
const page = Number.isInteger(ctx.page) && ctx.page > 0 ? ctx.page : 1;
const pageSize =
Number.isInteger(ctx.pageSize) && ctx.pageSize > 0 ? ctx.pageSize : 10;
const total = await db.collection("login-log").countDocuments(query);
const list = await db
.collection("login-log")
.find(query)
.skip(page * pageSize - pageSize)
.limit(pageSize)
.sort({ createTime: -1 })
.toArray();
return { success: true, data: list, message: "获取登录日志成功", total };
} catch (e) {
return { success: false, message: e.message };
}
}
async function addLoginLog(ctx, loginId, platform, ip, token) {
const { corpId, _id, userid: userId } = ctx;
try {
const { insertedId } = await db
.collection("login-log")
.insertOne({
corpId,
accountId: _id.toString(),
userId,
createTime: Date.now(),
loginId,
type: "login",
ip: typeof ip === "string" ? ip.trim() : "",
platform: ["PC", "MATEPAD"].includes(platform) ? platform : "",
token
});
if (insertedId) {
tokenStore.setToken(_id.toString(), token);
}
return { success: true, message: "添加登录日志成功" };
} catch (e) {
console.log('addLoginLog error:', e)
return { success: false, message: e.message };
}
}
async function resetPassword(ctx) {
// const { corpId, userId, accountId } = ctx;
const corpId = typeof ctx.corpId === "string" ? ctx.corpId.trim() : "";
const userId = typeof ctx.userId === "string" ? ctx.userId.trim() : "";
const accountId =
typeof ctx.accountId === "string" ? ctx.accountId.trim() : "";
if (!corpId || !userId || !accountId) {
return { success: false, message: "参数错误,缺少必要的参数" };
}
try {
const query = { corpId, userid: userId };
if (ObjectId.isValid(accountId)) {
query["$or"] = [{ _id: new ObjectId(accountId) }, { _id: accountId }];
} else {
query._id = accountId; // 如果不是ObjectId则直接使用accountId
}
const res = await db
.collection("corp-member")
.updateOne(query, {
$set: { password: defaultPassword, updateTime: Date.now() },
});
if (res.modifiedCount === 1) {
return {
success: true,
message: "重置密码成功",
password: defaultPassword,
};
}
return {
success: false,
message: "重置密码失败",
};
} catch (error) {
return {
success: false,
message: error.message,
};
}
}
async function addCorpAccount(ctx) {
try {
const { success, message, data } = utils.getAccountData(ctx);
if (!success) {
return { success, message };
}
const { relatedHlwPeople, ...accountData } = data;
if (/\W/.test(accountData.mobile)) {
return { success: false, message: "登录账号不能包含特殊字符" };
}
// 校验 phone 字段是否存在
if (!accountData.phone || typeof accountData.phone !== 'string' || accountData.phone.trim() === '') {
return { success: false, message: "手机号不能为空" };
}
const sameMobile = { corpId: data.corpId, mobile: data.mobile }; // 账号相同
const samePhone = { corpId: data.corpId, phone: data.phone }; // 手机号相同
const sameRelatedPeople = relatedHlwPeople
? [{ corpId: data.corpId, relatedHlwPeople }]
: []; // 关联人员相同
const account = await db
.collection("corp-member")
.findOne(
{ $or: [sameMobile, samePhone, ...sameRelatedPeople] },
{ projection: { mobile: 1, phone: 1, relatedHlwPeople: 1 } }
);
if (account && account.mobile === data.mobile) {
return { success: false, message: "该账号已存在" };
} else if (account && account.phone === data.phone) {
return { success: false, message: "该手机号已被使用" };
} else if (account) {
return { success: false, message: "该人员已关联其他账号" };
}
if (
typeof relatedHlwPeople === "string" &&
relatedHlwPeople.trim() !== ""
) {
const { success, message, data } = await api.getInternetHospitalApi({
type: "getHlwPersonList",
page: 1,
pageSize: 1,
doctorNo: relatedHlwPeople,
});
const doctor = Array.isArray(data) && data[0] ? data[0] : null;
if (!success || !doctor) {
return {
success: false,
message: message || "关联人员信息不正确或者不存在",
};
}
if (["doctor", "pharmacist"].includes(doctor.job)) {
accountData[doctor.job === "doctor" ? "doctorNo" : "workNo"] =
doctor.doctorNo;
}
}
const res = await db.collection("corp-member").insertOne({
...accountData,
relatedHlwPeople,
password: defaultPassword,
createTime: Date.now(),
accountState: "enable",
});
return { success: true, message: "新增账户成功", id: res.insertedId };
} catch (e) {
return { success: false, message: e.message || "新增账户失败" };
}
}
async function editCorpAccount(ctx) {
if (typeof ctx.id !== "string" || ctx.id.trim() === "") {
return { success: false, message: "账号id无效" };
}
try {
const { success, message, data } = utils.getAccountData(ctx, false);
if (!success) {
return { success, message };
}
if (JSON.stringify(data) === "{}") {
return { success: true, message: "没有需要更新的字段" };
}
const record = await db.collection("corp-member").findOne(
{
$or: [
{
corpId: typeof ctx.corpId == "string" ? ctx.corpId : "",
_id: ObjectId.isValid(ctx.id) ? new ObjectId(ctx.id) : ctx.id,
},
{
corpId: typeof ctx.corpId == "string" ? ctx.corpId : "",
_id: ctx.id,
},
],
},
{ projection: { _id: 1, mobile: 1, phone: 1, doctorNo: 1, workNo: 1, corpId: 1 } }
);
if (!record) {
return { success: false, message: "账号不存在" };
}
const { relatedHlwPeople, mobile, userid, ...accountData } = data;
if (/\W/.test(accountData.mobile)) {
return { success: false, message: "登录账号不能包含特殊字符" };
}
if (
record.mobile &&
accountData.mobile &&
accountData.mobile !== record.mobile
) {
return { success: false, message: "登录账号不能修改" };
}
const sameMobile = { corpId: data.corpId, mobile: data.mobile }; // 账号相同
const samePhone = accountData.phone ? { corpId: data.corpId, phone: accountData.phone } : null; // 手机号相同
const sameRelatedPeople =
typeof relatedHlwPeople == "string" && relatedHlwPeople
? [{ corpId: data.corpId, relatedHlwPeople }]
: []; // 关联人员相同
const queryConditions = [sameMobile, ...sameRelatedPeople];
if (samePhone) {
queryConditions.push(samePhone);
}
const account = await db.collection("corp-member").findOne(
{ $or: queryConditions, _id: { $ne: record._id } }, // 排除当前账号
{ projection: { mobile: 1, phone: 1, doctorNo: 1, workNo: 1 } }
);
if (account && account.mobile === data.mobile) {
return { success: false, message: "该账号已存在" };
} else if (account && accountData.phone && account.phone === accountData.phone) {
return { success: false, message: "该手机号已被使用" };
} else if (account) {
return { success: false, message: "该人员已关联其他账号" };
}
if (
typeof relatedHlwPeople === "string" &&
relatedHlwPeople.trim() !== ""
) {
const { success, message, data } = await api.getInternetHospitalApi({
type: "getHlwPersonList",
corpId: record.corpId,
page: 1,
pageSize: 1,
doctorNo: relatedHlwPeople,
});
const doctor = Array.isArray(data) && data[0] ? data[0] : null;
if (!success || !doctor) {
return {
success: false,
message: message || "关联人员信息不正确或者不存在",
};
}
if (record.doctorNo) {
accountData.doctorNo = "";
}
if (record.workNo) {
accountData.workNo = "";
}
if (["doctor", "pharmacist"].includes(doctor.job)) {
accountData[doctor.job === "doctor" ? "doctorNo" : "workNo"] =
doctor.doctorNo;
}
accountData.relatedHlwPeople = relatedHlwPeople;
} else if (relatedHlwPeople === "") {
if (record.doctorNo) {
accountData.doctorNo = "";
}
if (record.workNo) {
accountData.workNo = "";
}
accountData.relatedHlwPeople = "";
}
const res = await db
.collection("corp-member")
.updateOne({ _id: record._id }, { $set: accountData });
if (res.matchedCount === 0) {
return { success: false, message: "修改账户失败" };
}
return { success: true, message: "修改账户成功" };
} catch (e) {
return { success: false, message: e.message || "修改账户失败" };
}
}
async function getAccountList(ctx) {
const page = Number.isInteger(ctx.page) ? ctx.page : 1;
const pageSize = Number.isInteger(ctx.pageSize) ? ctx.pageSize : 10;
try {
const query = { corpId: typeof ctx.corpId === "string" ? ctx.corpId : "" };
if (typeof ctx.roleId === "string" && ctx.roleId.trim() !== "") {
query["roleIds"] = { $in: [ctx.roleId] };
}
if (typeof ctx.name === "string" && ctx.name.trim() !== "") {
query["anotherName"] = { $regex: ctx.name, $options: "i" };
}
if (typeof ctx.mobile === "string" && ctx.mobile.trim() !== "") {
query["mobile"] = { $regex: ctx.mobile.trim(), $options: "i" };
}
if (typeof ctx.accountState === "boolean") {
query["accountState"] = ctx.accountState ? "enable" : "disable";
}
const list = await db
.collection("corp-member")
.aggregate([
{ $match: query },
{ $sort: { createTime: -1, _id: -1 } },
{
$lookup: {
from: "sys-role",
localField: "roleIds",
foreignField: "_id",
pipeline: [{ $project: { roleName: 1, _id: 0 } }],
as: "roles",
},
},
{
$lookup: {
from: "login-log",
let: { accountId: { $toString: "$_id" } },
pipeline: [
{
$match: {
$expr: { $eq: ["$accountId", "$$accountId"] },
type: "login",
},
},
{ $sort: { createTime: -1 } },
{ $limit: 1 },
{ $project: { _id: 0, createTime: 1, ip: 1 } },
],
as: "lastLogin",
},
},
{
$project: {
_id: 1,
anotherName: 1,
mobile: 1,
phone: 1,
accountState: 1,
roles: 1,
roleIds: 1,
lastLogin: 1,
userid: 1,
doctorNo: 1,
workNo: 1,
relatedHlwPeople: 1,
},
},
{ $skip: (page - 1) * pageSize },
{ $limit: pageSize },
])
.toArray();
const total = await db.collection("corp-member").countDocuments(query);
return { success: true, message: "获取成功", list, total };
} catch (e) {
return { success: false, message: e.message || "获取失败" };
}
}
async function setAccountState(ctx) {
const { corpId, accountIds, state } = ctx;
const accountIdList = Array.isArray(accountIds)
? accountIds.filter((i) => typeof i === "string")
: [];
try {
const ids = [];
for (const id of accountIdList) {
if (ObjectId.isValid(id)) {
ids.push(new ObjectId(id), id);
} else if (typeof id === "string" && id.trim() !== "") {
ids.push(id.trim());
}
}
if (typeof state !== "boolean") {
return { success: false, message: "参数错误" };
}
const res = await db
.collection("corp-member")
.updateMany(
{ _id: { $in: ids }, corpId: typeof corpId === "string" ? corpId : "" },
{ $set: { accountState: state ? "enable" : "disable" } }
);
return { success: true, message: "设置成功", data: res };
} catch (e) {
return { success: false, message: e.message || "设置失败" };
}
}
async function getAccountOptions(ctx) {
try {
const query = { corpId: typeof ctx.corpId === "string" ? ctx.corpId : "" };
const list = await db
.collection("corp-member")
.find(query, { projection: { anotherName: 1, _id: 1 } })
.toArray();
return { success: true, message: "获取成功", list };
} catch (e) {
return { success: false, message: e.message || "获取失败" };
}
}
async function updateAccountDrugStoreId(ctx) {
const corpId = typeof ctx.corpId === "string" ? ctx.corpId.trim() : "";
const drugStoreId =
typeof ctx.drugStoreId === "string" ? ctx.drugStoreId.trim() : "";
const oldDrugStoreId =
typeof ctx.oldDrugStoreId === "string" ? ctx.oldDrugStoreId.trim() : "";
const accountId =
typeof ctx.accountId === "string" ? ctx.accountId.trim() : "";
const oldAccountId =
typeof ctx.oldAccountId === "string" ? ctx.oldAccountId.trim() : "";
try {
let account = null;
let oldAccount = null;
if (accountId) {
const query = ObjectId.isValid(accountId)
? {
$or: [
{ corpId, _id: new ObjectId(accountId) },
{ corpId, _id: accountId },
],
}
: { corpId, _id: accountId };
account = await db.collection("corp-member").findOne(query, { _id: 1 });
if (!account) {
return { success: false, message: "关联账号不存在" };
}
}
if (oldAccountId) {
const oldQuery = ObjectId.isValid(oldAccountId)
? {
$or: [
{ corpId, _id: new ObjectId(oldAccountId) },
{ corpId, _id: oldAccountId },
],
}
: { corpId, _id: oldAccountId };
oldAccount = await db
.collection("corp-member")
.findOne(oldQuery, { _id: 1 });
}
if (oldAccount) {
await db
.collection("corp-member")
.updateMany({ _id: oldAccount._id }, { $set: { drugStoreId: "" } });
}
if (oldDrugStoreId && account) {
await db
.collection("corp-member")
.updateMany(
{ corpId, drugStoreId: oldDrugStoreId, _id: { $ne: account._id } },
{ $set: { drugStoreId: "" } }
);
await db
.collection("corp-member")
.updateMany({ _id: account._id }, { $set: { drugStoreId } });
} else if (oldDrugStoreId) {
await db
.collection("corp-member")
.updateMany(
{ corpId, drugStoreId: oldDrugStoreId },
{ $set: { drugStoreId } }
);
} else if (account) {
await db
.collection("corp-member")
.updateMany({ _id: account._id }, { $set: { drugStoreId } });
}
return { success: true, message: "更新成功" };
} catch (e) {
return { success: false, message: e.message || "更新失败" };
}
}