修改架构,移动端优先。
save
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import { Router } from 'express'
|
||||
import { authRequired } from '../middleware.js'
|
||||
import { listArticles, getArticle } from '../articles.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.use(authRequired)
|
||||
|
||||
router.get('/articles', (_req, res) => {
|
||||
res.json({ articles: listArticles() })
|
||||
})
|
||||
|
||||
router.get('/articles/:slug', (req, res) => {
|
||||
const article = getArticle(req.params.slug)
|
||||
if (!article) return res.status(404).json({ error: '文章不存在' })
|
||||
res.json({ article })
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Router } from 'express'
|
||||
import crypto from 'node:crypto'
|
||||
import { prisma } from '../db.js'
|
||||
import { authRequired, signToken } from '../middleware.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
// 校验密码: 接受 scrypt$salt$hash 格式
|
||||
function verifyPassword(plain, stored) {
|
||||
if (!stored || !stored.startsWith('scrypt$')) return false
|
||||
const parts = stored.split('$')
|
||||
if (parts.length !== 3) return false
|
||||
const [, salt, hash] = parts
|
||||
const computed = crypto.scryptSync(plain, salt, 64).toString('hex')
|
||||
// 常数时间比较
|
||||
const a = Buffer.from(computed, 'hex')
|
||||
const b = Buffer.from(hash, 'hex')
|
||||
if (a.length !== b.length) return false
|
||||
return crypto.timingSafeEqual(a, b)
|
||||
}
|
||||
|
||||
router.post('/login', async (req, res) => {
|
||||
const { email, password } = req.body || {}
|
||||
if (!email || !password) return res.status(400).json({ error: '邮箱或密码不能为空' })
|
||||
const user = await prisma.user.findUnique({ where: { email: String(email).toLowerCase() } })
|
||||
if (!user) return res.status(401).json({ error: '邮箱或密码错误' })
|
||||
if (!verifyPassword(String(password), user.password)) {
|
||||
return res.status(401).json({ error: '邮箱或密码错误' })
|
||||
}
|
||||
const payload = { sub: user.id, email: user.email, name: user.name }
|
||||
const token = signToken(payload)
|
||||
res.json({ token, user: { id: user.id, name: user.name, email: user.email, createdAt: user.createdAt } })
|
||||
})
|
||||
|
||||
router.get('/me', authRequired, async (req, res) => {
|
||||
const user = await prisma.user.findUnique({ where: { id: req.user.sub } })
|
||||
if (!user) return res.status(401).json({ error: '用户不存在' })
|
||||
res.json({ user: { id: user.id, name: user.name, email: user.email, createdAt: user.createdAt } })
|
||||
})
|
||||
|
||||
router.post('/logout', (_req, res) => {
|
||||
// JWT 无状态, 前端清 token 即可; 这里返回 200 让前端不用特判
|
||||
res.json({ ok: true })
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,30 @@
|
||||
import { Router } from 'express'
|
||||
import { prisma } from '../db.js'
|
||||
import { authRequired } from '../middleware.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.use(authRequired)
|
||||
|
||||
router.get('/indicators', async (_req, res, next) => {
|
||||
try {
|
||||
const rows = await prisma.indicator.findMany({ orderBy: [{ groupName: 'asc' }, { name: 'asc' }] })
|
||||
res.json({ indicators: rows })
|
||||
} catch (e) { next(e) }
|
||||
})
|
||||
|
||||
router.get('/strategies', async (_req, res, next) => {
|
||||
try {
|
||||
const rows = await prisma.strategy.findMany({ orderBy: { name: 'asc' } })
|
||||
res.json({ strategies: rows })
|
||||
} catch (e) { next(e) }
|
||||
})
|
||||
|
||||
router.get('/sow', async (_req, res, next) => {
|
||||
try {
|
||||
const rows = await prisma.econ_SowInventory.findMany({ orderBy: { month: 'asc' } })
|
||||
res.json({ rows })
|
||||
} catch (e) { next(e) }
|
||||
})
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user