feat: 统一页面布局与字体样式
This commit is contained in:
+9
-1
@@ -9,7 +9,15 @@ import { apiLimiter } from './middleware/rateLimit'
|
||||
const app = express()
|
||||
|
||||
app.use(helmet())
|
||||
app.use(compression())
|
||||
app.use(compression({
|
||||
filter: (req, res) => {
|
||||
// SSE 流式响应不压缩,避免缓冲导致前端一次性收到所有数据
|
||||
if (req.headers['accept'] === 'text/event-stream' || res.getHeader('Content-Type') === 'text/event-stream') {
|
||||
return false
|
||||
}
|
||||
return compression.filter(req, res)
|
||||
},
|
||||
}))
|
||||
app.use(
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import app from './app'
|
||||
|
||||
const PORT = process.env.PORT || 3000
|
||||
const PORT = Number(process.env.PORT) || 3000
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on http://localhost:${PORT}`)
|
||||
app.listen(PORT, '::', () => {
|
||||
console.log(`Server running on http://[::]:${PORT}`)
|
||||
})
|
||||
|
||||
@@ -109,12 +109,18 @@ router.post('/chat-stream', authMiddleware, async (req: AuthRequest, res, next)
|
||||
res.setHeader('Content-Type', 'text/event-stream')
|
||||
res.setHeader('Cache-Control', 'no-cache')
|
||||
res.setHeader('Connection', 'keep-alive')
|
||||
res.setHeader('X-Accel-Buffering', 'no')
|
||||
res.flushHeaders()
|
||||
let usageRecorded = false
|
||||
try {
|
||||
for await (const delta of chatStream(messages, orgContext)) {
|
||||
res.write(`data: ${JSON.stringify({ delta })}\n\n`)
|
||||
if (typeof (res as any).flush === 'function') (res as any).flush()
|
||||
}
|
||||
res.write('data: [DONE]\n\n')
|
||||
} catch (streamErr: any) {
|
||||
res.write(`data: ${JSON.stringify({ error: streamErr.message || 'AI 服务异常' })}\n\n`)
|
||||
res.write('data: [DONE]\n\n')
|
||||
} finally {
|
||||
if (!usageRecorded) {
|
||||
await recordUsage(req.user!.orgId, req.user!.id, 'chat')
|
||||
|
||||
@@ -205,7 +205,7 @@ router.get('/:id/evidence-chain', authMiddleware, async (req: AuthRequest, res,
|
||||
employee.contracts.forEach((c) => {
|
||||
evidence.push({
|
||||
category: '劳动关系',
|
||||
title: `劳动合同(${c.contractType === 'FIXED' ? '固定期限' : c.contractType === 'UNFIXED' ? '无固定期限' : '未签订'})`,
|
||||
title: `合同(${({ FIXED: '固定期限', UNFIXED: '无固定期限', LABOR: '劳务协议', INTERNSHIP: '实习协议', UNSIGNED: '未签订' } as Record<string, string>)[c.contractType] || '未签订'})`,
|
||||
date: c.signDate ? c.signDate.toISOString().slice(0, 10) : c.startDate.toISOString().slice(0, 10),
|
||||
description: `合同期限:${c.startDate.toISOString().slice(0, 10)} 至 ${c.endDate ? c.endDate.toISOString().slice(0, 10) : '无固定期限'},试用期${c.probationMonths}个月,试用期工资¥${c.probationSalary}。`,
|
||||
evidenceType: 'CONTRACT',
|
||||
@@ -788,4 +788,16 @@ router.get('/contracts/expiring', authMiddleware, async (req: AuthRequest, res,
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
// 合同类型列表(供前端动态获取)
|
||||
router.get('/contract-types', authMiddleware, (_req: AuthRequest, res) => {
|
||||
const types = [
|
||||
{ value: 'FIXED', label: '劳动合同-固定期', hasEndDate: true },
|
||||
{ value: 'UNFIXED', label: '劳动合同-无固定期', hasEndDate: false },
|
||||
{ value: 'LABOR', label: '劳务协议', hasEndDate: false },
|
||||
{ value: 'INTERNSHIP', label: '实习协议', hasEndDate: false },
|
||||
{ value: 'UNSIGNED', label: '未签合同', hasEndDate: false },
|
||||
]
|
||||
res.json({ success: true, data: types })
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -26,7 +26,14 @@ export function getContractStatus(contract: {
|
||||
hireDate: Date
|
||||
}): { status: string; statusText: string; riskLevel: 'high' | 'medium' | 'low' | 'safe' } {
|
||||
const today = new Date()
|
||||
const typeLabel = contract.contractType === 'FIXED' ? '固定期限' : contract.contractType === 'UNFIXED' ? '无固定期限' : ''
|
||||
const typeLabelMap: Record<string, string> = {
|
||||
FIXED: '固定期限',
|
||||
UNFIXED: '无固定期限',
|
||||
LABOR: '劳务协议',
|
||||
INTERNSHIP: '实习协议',
|
||||
UNSIGNED: '',
|
||||
}
|
||||
const typeLabel = typeLabelMap[contract.contractType] || ''
|
||||
|
||||
if (!contract.signDate || contract.contractType === 'UNSIGNED') {
|
||||
const days = daysBetween(today, contract.hireDate)
|
||||
|
||||
Reference in New Issue
Block a user