338 lines
10 KiB
JavaScript
338 lines
10 KiB
JavaScript
|
|
const stats = require("./stats");
|
||
|
|
const cate = require("./article-cate");
|
||
|
|
const utils = require("./utils");
|
||
|
|
const common = require("../../common");
|
||
|
|
const { getDatabase } = require("../../mongodb");
|
||
|
|
const { ObjectId } = require("mongodb");
|
||
|
|
|
||
|
|
let db = null;
|
||
|
|
let articleDB = null;
|
||
|
|
let articleCateDB = null;
|
||
|
|
|
||
|
|
exports.main = async (content, mongodb) => {
|
||
|
|
db = mongodb;
|
||
|
|
articleDB = db.collection("article");
|
||
|
|
articleCateDB = db.collection("article-cate");
|
||
|
|
switch (content.type) {
|
||
|
|
case "getArticleCates":
|
||
|
|
return await exports.getArticleCates(content);
|
||
|
|
case "removeArticleCate":
|
||
|
|
return await exports.removeArticleCate(content);
|
||
|
|
case "setArticle":
|
||
|
|
return await exports.setArticle(content);
|
||
|
|
case "setArticleCate":
|
||
|
|
return await exports.setArticleCate(content);
|
||
|
|
case "getArticle":
|
||
|
|
return await exports.getArticle(content);
|
||
|
|
case "getArticleList":
|
||
|
|
return await exports.getArticleList(content);
|
||
|
|
case "getArticleByIds":
|
||
|
|
return await exports.getArticleByIds(content);
|
||
|
|
case "removeArticle":
|
||
|
|
return await exports.removeArticle(content);
|
||
|
|
case "toggleArticleStatus":
|
||
|
|
return await exports.toggleArticleStatus(content);
|
||
|
|
case "toggleArticleTop":
|
||
|
|
return await exports.toggleArticleTop(content);
|
||
|
|
case "getArticleStatus":
|
||
|
|
return await exports.getArticleStatus(content);
|
||
|
|
case "addArticleSendRecord":
|
||
|
|
case "addArticleReadRecord":
|
||
|
|
case "getArticleStats":
|
||
|
|
case "getArticleTrend":
|
||
|
|
case "getSendDetail":
|
||
|
|
case "getReadDetail":
|
||
|
|
case "getArticleListReadStats":
|
||
|
|
case "getArticleCount":
|
||
|
|
return await stats.main(content, db);
|
||
|
|
case "initCorpArticleCate":
|
||
|
|
case "addArticleCate":
|
||
|
|
case "updateArticleCate":
|
||
|
|
case "deleteArticleCate":
|
||
|
|
case "getArticleCateList":
|
||
|
|
case "sortArticleCate":
|
||
|
|
return await cate.main(content, db);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.setArticle = async (context) => {
|
||
|
|
const { _id, userId } = context;
|
||
|
|
const { success, message, ...article } = utils.formatArticle(context);
|
||
|
|
if (!success) {
|
||
|
|
return { success: false, message };
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const time = new Date().getTime();
|
||
|
|
if (_id) {
|
||
|
|
await articleDB.updateOne(
|
||
|
|
{ _id },
|
||
|
|
{ $set: { ...article, updateUserId: userId, updateTime: time } }
|
||
|
|
);
|
||
|
|
return { success: true, message: "更新文章成功" };
|
||
|
|
} else {
|
||
|
|
await articleDB.insertOne({
|
||
|
|
_id: common.generateRandomString(24),
|
||
|
|
...article,
|
||
|
|
userId,
|
||
|
|
createTime: time,
|
||
|
|
enable: true,
|
||
|
|
isTop: false,
|
||
|
|
topTime: 0,
|
||
|
|
});
|
||
|
|
return { success: true, message: "新增文章成功" };
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: `${_id ? "更新" : "新增"}文章失败` };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.setArticleCate = async (context) => {
|
||
|
|
const { _id, corpId, cateId } = context;
|
||
|
|
if (!corpId) return { success: false, message: "机构id不能为空" };
|
||
|
|
try {
|
||
|
|
const time = new Date().getTime();
|
||
|
|
const article = await articleDB.findOne({ _id, corpId });
|
||
|
|
if (!article) return { success: false, message: "文章不存在" };
|
||
|
|
const { success, message } = await cate.main({
|
||
|
|
type: "ifCateExist",
|
||
|
|
corpId,
|
||
|
|
cateId,
|
||
|
|
}, db);
|
||
|
|
if (!success) return { success, message };
|
||
|
|
await articleDB.updateOne({ _id }, { $set: { cateId, updateTime: time } });
|
||
|
|
return { success: true, message: "更新文章分类成功" };
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: e.message };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.getArticle = async (context) => {
|
||
|
|
try {
|
||
|
|
const { corpId, id: _id } = context;
|
||
|
|
const article = await articleDB.findOne({ corpId, _id });
|
||
|
|
if (article) {
|
||
|
|
return { success: true, message: "查询文章成功", data: article };
|
||
|
|
}
|
||
|
|
return { success: false, message: "未查询到文章" };
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: "查询文章失败" };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.getArticleList = async (context) => {
|
||
|
|
try {
|
||
|
|
const {
|
||
|
|
corpId,
|
||
|
|
cateId,
|
||
|
|
title,
|
||
|
|
enable,
|
||
|
|
page,
|
||
|
|
pageSize,
|
||
|
|
cateIds,
|
||
|
|
showCount = false,
|
||
|
|
} = context;
|
||
|
|
const query = { corpId };
|
||
|
|
if (cateId) query.cateId = cateId;
|
||
|
|
if (cateIds) query.cateId = { $in: cateIds };
|
||
|
|
if (typeof enable === "boolean") query.enable = enable;
|
||
|
|
if (typeof title === "string" && title.trim()) {
|
||
|
|
query.title = { $regex: ".*" + title.trim() + ".*", $options: "i" };
|
||
|
|
}
|
||
|
|
const total = await articleDB.countDocuments(query);
|
||
|
|
const list = await articleDB
|
||
|
|
.find(query)
|
||
|
|
.sort({ topTime: -1, createTime: -1 })
|
||
|
|
.skip((page - 1) * pageSize)
|
||
|
|
.limit(pageSize)
|
||
|
|
.project({
|
||
|
|
_id: 1,
|
||
|
|
title: 1,
|
||
|
|
link: 1,
|
||
|
|
enable: 1,
|
||
|
|
createTime: 1,
|
||
|
|
summary: 1,
|
||
|
|
userId: 1,
|
||
|
|
cateId: 1,
|
||
|
|
isTop: 1,
|
||
|
|
topTime: 1,
|
||
|
|
cover: 1,
|
||
|
|
})
|
||
|
|
.toArray();
|
||
|
|
|
||
|
|
if (list.length > 0) {
|
||
|
|
// 获取创建人名称
|
||
|
|
const userIds = [...new Set(list.map(item => item.userId).filter(id => id))];
|
||
|
|
if (userIds.length > 0) {
|
||
|
|
try {
|
||
|
|
const corpDB = await getDatabase("corp");
|
||
|
|
const objectIds = userIds.map(id => {
|
||
|
|
try { return new ObjectId(id); } catch (e) { return null; }
|
||
|
|
}).filter(id => id);
|
||
|
|
|
||
|
|
const users = await corpDB.collection("corp-member").find({
|
||
|
|
$or: [
|
||
|
|
{ _id: { $in: objectIds } },
|
||
|
|
{ userid: { $in: userIds } }
|
||
|
|
]
|
||
|
|
}).project({ _id: 1, userid: 1, anotherName: 1, mobile: 1 }).toArray();
|
||
|
|
|
||
|
|
const userMap = {};
|
||
|
|
users.forEach(u => {
|
||
|
|
const name = u.anotherName || u.mobile;
|
||
|
|
if (u._id) userMap[u._id.toString()] = name;
|
||
|
|
if (u.userid) userMap[u.userid] = name;
|
||
|
|
});
|
||
|
|
|
||
|
|
list.forEach(item => {
|
||
|
|
if (item.userId) {
|
||
|
|
item.userName = userMap[item.userId] || item.userId;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
} catch (err) {
|
||
|
|
console.error("Fetch user names failed:", err);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (showCount && list.length > 0) {
|
||
|
|
const { read = {}, send = {} } = await stats.getArticleListStats(
|
||
|
|
corpId,
|
||
|
|
list.map((item) => item._id)
|
||
|
|
);
|
||
|
|
list.forEach((item) => {
|
||
|
|
item.read = read[item._id] || 0;
|
||
|
|
item.send = send[item._id] || 0;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return { success: true, message: "获取文章成功", list, total };
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: "查询文章失败" };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.getArticleByIds = async (context) => {
|
||
|
|
const { corpId, ids } = context;
|
||
|
|
if (!corpId) {
|
||
|
|
return { success: false, message: "机构id不能为空" };
|
||
|
|
}
|
||
|
|
if (!ids) {
|
||
|
|
return { success: false, message: "文章id不能为空" };
|
||
|
|
}
|
||
|
|
if (typeof ids !== "string") {
|
||
|
|
return { success: false, message: "文章id格式不正确" };
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
const idList = ids.split(",");
|
||
|
|
if (idList.length === 0)
|
||
|
|
return { success: true, message: "获取文章成功", list: [] };
|
||
|
|
const query = { corpId, _id: { $in: idList }, enable: true };
|
||
|
|
const list = await articleDB
|
||
|
|
.find(query)
|
||
|
|
.project({
|
||
|
|
_id: 1,
|
||
|
|
title: 1,
|
||
|
|
cover: 1,
|
||
|
|
summary: 1,
|
||
|
|
link: 1,
|
||
|
|
keyword: 1,
|
||
|
|
})
|
||
|
|
.toArray();
|
||
|
|
return { success: true, message: "获取文章成功", list };
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: "查询文章失败" };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.getArticleCates = async (context) => {
|
||
|
|
try {
|
||
|
|
const { corpId, name } = context;
|
||
|
|
const query = { corpId };
|
||
|
|
if (typeof name === "string" && name.trim()) {
|
||
|
|
query.name = { $regex: ".*" + name.trim() + ".*", $options: "i" };
|
||
|
|
}
|
||
|
|
const list = await articleCateDB.find(query).toArray();
|
||
|
|
return { success: true, message: "获取文章分类成功", list };
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: "获取文章分类失败" };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.removeArticleCate = async (context) => {
|
||
|
|
try {
|
||
|
|
const { corpId, id } = context;
|
||
|
|
if (id) {
|
||
|
|
await articleDB.deleteMany({ cateId: id });
|
||
|
|
await articleCateDB.deleteOne({ corpId, _id: id });
|
||
|
|
return { success: true, message: "删除文章分类成功" };
|
||
|
|
} else {
|
||
|
|
return { success: false, message: "文章分类id不能为空" };
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: "删除文章分类失败" };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.removeArticle = async (context) => {
|
||
|
|
try {
|
||
|
|
const { corpId, _id } = context;
|
||
|
|
if (_id) {
|
||
|
|
await articleDB.deleteOne({ corpId, _id });
|
||
|
|
return { success: true, message: "删除文章成功" };
|
||
|
|
} else {
|
||
|
|
return { success: false, message: "文章分类id不能为空" };
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: "删除文章失败" };
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.toggleArticleStatus = async (context) => {
|
||
|
|
const { _id, enable } = context;
|
||
|
|
try {
|
||
|
|
await articleDB.updateOne({ _id }, { $set: { enable: Boolean(enable) } });
|
||
|
|
return {
|
||
|
|
success: true,
|
||
|
|
message: Boolean(enable) ? "启用文章成功" : "停用文章成功",
|
||
|
|
};
|
||
|
|
} catch (e) {
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
message: Boolean(enable) ? "启用文章失败" : "停用文章失败",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.toggleArticleTop = async (context) => {
|
||
|
|
const { _id, isTop } = context;
|
||
|
|
if (!_id) return { success: false, message: "文章id不能为空" };
|
||
|
|
const topFlag = Boolean(isTop);
|
||
|
|
const updateDoc = { isTop: topFlag, topTime: topFlag ? Date.now() : 0 };
|
||
|
|
try {
|
||
|
|
await articleDB.updateOne({ _id }, { $set: updateDoc });
|
||
|
|
return {
|
||
|
|
success: true,
|
||
|
|
message: topFlag ? "置顶文章成功" : "取消置顶成功",
|
||
|
|
};
|
||
|
|
} catch (e) {
|
||
|
|
return {
|
||
|
|
success: false,
|
||
|
|
message: topFlag ? "置顶文章失败" : "取消置顶失败",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
exports.getArticleStatus = async (context) => {
|
||
|
|
const { corpId, ids } = context;
|
||
|
|
if (!corpId || !Array.isArray(ids) || ids.length === 0)
|
||
|
|
return { success: false, message: "参数错误" };
|
||
|
|
try {
|
||
|
|
const list = await articleDB
|
||
|
|
.find({ corpId, _id: { $in: ids } })
|
||
|
|
.project({ enable: 1 })
|
||
|
|
.toArray();
|
||
|
|
return { success: true, message: "获取文章状态成功", list };
|
||
|
|
} catch (e) {
|
||
|
|
return { success: false, message: e.message || "获取文章状态失败" };
|
||
|
|
}
|
||
|
|
};
|