const db = uniCloud.database(); const _ = db.command; const uniID = require('uni-id-common'); const ARTICLE_DB = 'uni-cms-articles'; module.exports = { _before: function () { // 通用预处理器 this.uniID = uniID.createInstance({ context: this.getClientInfo() }); }, /** 校验登录并返回 payload */ async _requireLogin() { const payload = await this.uniID.checkToken(this.getUniIdToken()); if (payload.errCode) throw new Error('登录状态失效,请重新登录'); return payload; }, /** * 读取文章详情 * 只返回已发布文章;作者与管理员可读自己的草稿 */ async getDetail(query) { try { const id = query && query.id; if (!id) return { code: 400, msg: '缺少文章 id' }; const res = await db.collection(ARTICLE_DB).doc(id).get(); const article = res.data && res.data[0]; if (!article) return { code: 404, msg: '文章不存在' }; if (article.article_status !== 1) { const payload = await this.uniID.checkToken(this.getUniIdToken()); const owner = !payload.errCode && article.user_id === payload.uid; const admin = !payload.errCode && (payload.role || []).includes('admin'); if (!owner && !admin) { return { code: 403, msg: '无权查看该文章' }; } } return { code: 200, data: article }; } catch (e) { return { code: 500, msg: e.message }; } }, /** * 是否已投过票:以登录态为准,不再采信客户端传入的 user_id */ async isSelectVote(query) { try { const payload = await this._requireLogin(); const vote_id = query && query.vote_id; if (!vote_id) return { code: 400, msg: '缺少 vote_id' }; const res = await db.collection("cms-vote") .where({ user_id: payload.uid, vote_id: vote_id }) .count(); return { code: 200, isSelectVote: res.total > 0 }; } catch (e) { return { code: 500, msg: e.message }; } }, /** * 当前登录用户对某文章的点赞/收藏状态 */ async getInfo(query) { try { const payload = await this._requireLogin(); const article_id = query && query.article_id; if (!article_id) return { code: 400, msg: '缺少 article_id' }; const [likeRes, collectRes] = await Promise.all([ db.collection("cms-articles-like").where({ user_id: payload.uid, article_id }).count(), db.collection("cms-articles-collect").where({ user_id: payload.uid, article_id }).count() ]); return { code: 200, isLike: likeRes.total > 0, isCollect: collectRes.total > 0 }; } catch (e) { console.log(e.message); return { code: 500, msg: e.message }; } }, /** * 按 id 读取公开文章字段。 * 原实现用了未定义变量 dbCollectionName 且硬编码文档 id,调用必然抛错。 */ async get(query) { try { const id = query && (query.id || query._id); if (!id) return { code: 400, msg: '缺少文章 id' }; const res = await db.collection(ARTICLE_DB).doc(id).field( "_id,user_id,category_id,title,content,excerpt,article_status,thumbnail,publish_date" ).get(); const article = res.data && res.data[0]; if (!article) return { code: 404, msg: '文章不存在' }; if (article.article_status !== 1) { const payload = await this.uniID.checkToken(this.getUniIdToken()); const owner = !payload.errCode && article.user_id === payload.uid; const admin = !payload.errCode && (payload.role || []).includes('admin'); if (!owner && !admin) return { code: 403, msg: '无权查看该文章' }; } return { code: 200, data: article }; } catch (e) { return { code: 500, msg: e.message }; } }, /** * 某篇文章的阅读记录(详情页用于展示"谁看过") * 只有文章作者(或管理员)能看,普通读者不返回任何数据。 */ async getCmsArticleLog(query) { try { const payload = await this._requireLogin(); const article_id = query && query.article_id; if (!article_id) return { code: 400, msg: '缺少 article_id' }; const articleRes = await db.collection(ARTICLE_DB).doc(article_id).field({ user_id: true }).get(); const article = articleRes.data && articleRes.data[0]; if (!article) return { code: 404, msg: '文章不存在' }; const isAdmin = (payload.role || []).includes('admin'); if (article.user_id !== payload.uid && !isAdmin) { return { code: 403, msg: '只有作者可以查看阅读记录' }; } const page = Math.max(1, Number(query.page) || 1); const pageSize = Math.min(50, Math.max(1, Number(query.page_size) || 21)); // 浏览日志的读权限是"仅本人",这里用云函数的管理连接跨用户查询 const logsRes = await db.collection('cms-articles-log') .where({ article_id }) .orderBy('last_view_time', 'desc') .skip((page - 1) * pageSize) .limit(pageSize) .field('article_id, user_id, first_view_time, last_view_time') .get(); const uids = [...new Set(logsRes.data.map((l) => l.user_id).filter(Boolean))]; const usersRes = uids.length ? await db.collection('uni-id-users').where({ _id: _.in(uids) }).field('_id,avatar_file').get() : { data: [] }; const userMap = new Map(usersRes.data.map((u) => [u._id, u])); return { code: 200, cmsArticleLog: logsRes.data.map((log) => ({ ...log, user_id: [userMap.get(log.user_id) || { _id: log.user_id, avatar_file: {} }] })) }; } catch (e) { console.log(e.message); return { code: 500, msg: e.message }; } } }