851 lines
26 KiB
JavaScript
851 lines
26 KiB
JavaScript
|
|
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 || "更新失败" };
|
|||
|
|
}
|
|||
|
|
}
|