iboard/server/routes/news.js
2026-08-06 16:41:47 +08:00

52 lines
1.9 KiB
JavaScript

import { Router } from 'express'
import { prisma } from '../db.js'
import { authRequired } from '../middleware.js'
const router = Router()
router.use(authRequired)
// 新闻列表: 按时间最新优先, cursor 分页
// cursor 格式: "<publishedAt ISO>|<lastId>", 兼容旧版纯时间戳 (不带 |)
// 同秒多条时用 id 兜底, 避免翻页时整批漏掉
router.get('/news', async (req, res, next) => {
try {
const rawLimit = Number(req.query.limit)
const limit = Number.isFinite(rawLimit) && rawLimit >= 1 ? Math.min(Math.floor(rawLimit), 50) : 10
let where = {}
const cursor = req.query.cursor || ''
if (cursor) {
const [ts, idRaw] = cursor.split('|')
const c = new Date(ts)
if (!isNaN(c.getTime())) {
const id = Number(idRaw)
where = id > 0
? { OR: [{ publishedAt: { lt: c } }, { publishedAt: c, id: { lt: id } }] }
: { publishedAt: { lt: c } }
}
}
const items = await prisma.news.findMany({
select: { id: true, title: true, summary: true, source: true, url: true, publishedAt: true, impactRank: true },
where,
orderBy: [{ publishedAt: 'desc' }, { id: 'desc' }],
take: limit,
})
const nextCursor = items.length === limit && items.length > 0
? items[items.length - 1].publishedAt.toISOString() + '|' + items[items.length - 1].id
: null
res.json({ items, nextCursor })
} catch (e) { next(e) }
})
// 新闻详情: 含正文 content
router.get('/news/:id', async (req, res, next) => {
try {
const id = Number(req.params.id)
if (!Number.isInteger(id) || id <= 0) return res.status(400).json({ error: '无效的新闻 id' })
const item = await prisma.news.findUnique({ where: { id } })
if (!item) return res.status(404).json({ error: '新闻不存在' })
res.json({ item })
} catch (e) { next(e) }
})
export default router