Compare commits

...

2 Commits

Author SHA1 Message Date
2f122d0a96 docs: 更新 DEV.md — 后端 API 响应格式规范
- 统一响应格式 { code: 0, data: ... }
- 错误码规范说明
2026-06-08 11:30:58 +08:00
d681dc67a3 fix: 后端 API 响应格式统一 — config 和 feedback 路由
- config.ts: 响应格式改为 { code: 0, data: ... }
- feedback.ts: 响应格式改为 { code: 0, data: ... }
- 修复前端 request 函数因响应格式不标准导致的请求失败
2026-06-08 11:30:38 +08:00
3 changed files with 37 additions and 14 deletions

23
DEV.md
View File

@@ -52,6 +52,29 @@ request('/config', { method: 'PUT', data })
**原因**`request` 函数签名是 `request<T>(options: RequestOptions): Promise<T>`,第一个参数是 options 对象,不支持分开传 url 和 options。
### 后端 API 响应格式
**所有后端路由必须返回统一格式**
```typescript
// 成功
res.json({ code: 0, data: ... })
// 失败
res.status(400).json({ code: 40001, message: '错误信息' })
res.status(403).json({ code: 40300, message: '无权限' })
res.status(500).json({ code: 50000, message: '服务器错误' })
```
**错误码规范**
- `0` — 成功
- `40001` — 参数错误
- `40300` — 权限不足
- `40400` — 资源不存在
- `50000` — 服务器错误
**原因**:前端 `request` 函数检查 `data.code === 0` 判断成功,不返回标准格式会导致前端误判为失败。
### 页面数据加载模式
```typescript

View File

@@ -12,10 +12,10 @@ router.get('/', async (_req, res) => {
for (const row of rows as any[]) {
config[row.config_key] = row.config_value
}
res.json(config)
res.json({ code: 0, data: config })
} catch (error) {
console.error('Get config error:', error)
res.status(500).json({ error: '获取配置失败' })
res.status(500).json({ code: 50000, message: '获取配置失败' })
}
})
@@ -43,10 +43,10 @@ router.put('/', authMiddleware, async (req, res) => {
)
}
res.json({ success: true })
res.json({ code: 0 })
} catch (error) {
console.error('Update config error:', error)
res.status(500).json({ error: '更新配置失败' })
res.status(500).json({ code: 50000, message: '更新配置失败' })
}
})

View File

@@ -11,7 +11,7 @@ router.post('/', authMiddleware, async (req, res) => {
const { type, content, contact } = req.body
if (!content || !content.trim()) {
return res.status(400).json({ error: '请填写反馈内容' })
return res.status(400).json({ code: 40001, message: '请填写反馈内容' })
}
const validTypes = ['bug', 'feature', 'ux', 'other']
@@ -22,10 +22,10 @@ router.post('/', authMiddleware, async (req, res) => {
[userId, feedbackType, content.trim(), contact || '']
)
res.json({ success: true })
res.json({ code: 0 })
} catch (error) {
console.error('Submit feedback error:', error)
res.status(500).json({ error: '提交失败' })
res.status(500).json({ code: 50000, message: '提交失败' })
}
})
@@ -37,7 +37,7 @@ router.get('/', authMiddleware, async (req, res) => {
const user = (users as any[])[0]
if (!user || user.role !== 'admin') {
return res.status(403).json({ error: '无权限' })
return res.status(403).json({ code: 40300, message: '无权限' })
}
const page = Math.max(1, parseInt(req.query.page as string) || 1)
@@ -69,10 +69,10 @@ router.get('/', authMiddleware, async (req, res) => {
[...params, pageSize, offset]
)
res.json({ list: rows, total, page, pageSize })
res.json({ code: 0, data: { list: rows, total, page, pageSize } })
} catch (error) {
console.error('Get feedback list error:', error)
res.status(500).json({ error: '获取失败' })
res.status(500).json({ code: 50000, message: '获取失败' })
}
})
@@ -84,7 +84,7 @@ router.put('/:id/status', authMiddleware, async (req, res) => {
const user = (users as any[])[0]
if (!user || user.role !== 'admin') {
return res.status(403).json({ error: '无权限' })
return res.status(403).json({ code: 40300, message: '无权限' })
}
const { id } = req.params
@@ -92,7 +92,7 @@ router.put('/:id/status', authMiddleware, async (req, res) => {
const validStatuses = ['pending', 'processed', 'ignored']
if (!validStatuses.includes(status)) {
return res.status(400).json({ error: '无效的状态' })
return res.status(400).json({ code: 40001, message: '无效的状态' })
}
// 查询反馈信息(用于发送通知)
@@ -129,10 +129,10 @@ router.put('/:id/status', authMiddleware, async (req, res) => {
)
}
res.json({ success: true })
res.json({ code: 0 })
} catch (error) {
console.error('Update feedback status error:', error)
res.status(500).json({ error: '更新失败' })
res.status(500).json({ code: 50000, message: '更新失败' })
}
})