fix: risk.service.ts priorityOrder 重复声明导致后端启动失败

用户手动修改 risk.service.ts 时在第 966 行重复声明了
priorityOrder(第 955 行已声明),导致 esbuild 报错
"The symbol priorityOrder has already been declared",
后端 502 Bad Gateway。删除重复声明。

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 12:22:00 +08:00
parent ef6d4591be
commit 72a6eab3bd
6 changed files with 395 additions and 4 deletions
@@ -0,0 +1,140 @@
/**
* 提成奖金路由
* 管理按月提成奖金/扣款的 CRUD、批量导入、模板下载
*/
import { Router, Response, NextFunction } from 'express'
import { authMiddleware, AuthRequest } from '../middleware/auth'
import multer from 'multer'
import * as XLSX from 'xlsx'
import {
listByMonth,
summaryByMonth,
create,
update,
remove,
batchImport,
} from '../services/commission-bonus.service'
import { auditLog } from '../middleware/auditLog'
const router = Router()
router.use(authMiddleware)
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 5 * 1024 * 1024 } })
/**
* 按月查询提成奖金列表
* GET /commission-bonus?month=YYYY-MM
*/
router.get('/', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
const month = (req.query.month as string) || new Date().toISOString().slice(0, 7)
const [records, summary] = await Promise.all([
listByMonth(orgId, month),
summaryByMonth(orgId, month),
])
res.json({ success: true, data: { records, summary, month } })
} catch (err) { next(err) }
})
/**
* 新增单条提成奖金
* POST /commission-bonus body: { employeeId, month, amount, remark? }
*/
router.post('/', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
const { employeeId, month, amount, remark } = req.body
if (!employeeId || !month || amount === undefined) {
return res.status(400).json({ success: false, error: { code: 'BAD_REQUEST', message: '缺少 employeeId/month/amount' } })
}
const record = await create(orgId, req.user!.id, { employeeId, month, amount: Number(amount), remark })
await auditLog(req, 'CREATE', 'COMMISSION_BONUS', record.id, { employeeId, month, amount })
res.json({ success: true, data: record })
} catch (err: any) {
if (err.code === 'NOT_FOUND') return res.status(404).json({ success: false, error: { code: err.code, message: err.message } })
next(err)
}
})
/**
* 更新单条
* PUT /commission-bonus/:id body: { amount?, remark? }
*/
router.put('/:id', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
const { amount, remark } = req.body
const record = await update(orgId, req.params.id, { amount: amount !== undefined ? Number(amount) : undefined, remark })
await auditLog(req, 'UPDATE', 'COMMISSION_BONUS', req.params.id, { amount, remark })
res.json({ success: true, data: record })
} catch (err: any) {
if (err.code === 'NOT_FOUND') return res.status(404).json({ success: false, error: { code: err.code, message: err.message } })
next(err)
}
})
/**
* 删除单条
* DELETE /commission-bonus/:id
*/
router.delete('/:id', async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
await remove(orgId, req.params.id)
await auditLog(req, 'DELETE', 'COMMISSION_BONUS', req.params.id)
res.json({ success: true, data: { message: '已删除' } })
} catch (err: any) {
if (err.code === 'NOT_FOUND') return res.status(404).json({ success: false, error: { code: err.code, message: err.message } })
next(err)
}
})
/**
* 批量导入 Excel
* POST /commission-bonus/import multipart: file, month
* Excel 列:员工姓名 | 证件号码 | 金额 | 备注
*/
router.post('/import', upload.single('file'), async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const orgId = req.user!.orgId
const month = req.body.month || new Date().toISOString().slice(0, 7)
if (!req.file) {
return res.status(400).json({ success: false, error: { code: 'BAD_REQUEST', message: '请上传 Excel 文件' } })
}
const wb = XLSX.read(req.file.buffer, { type: 'buffer' })
const ws = wb.Sheets[wb.SheetNames[0]]
const rows: any[] = XLSX.utils.sheet_to_json(ws, { defval: '' })
const parsed = rows.map((r) => ({
employeeName: String(r['员工姓名'] || r['姓名'] || '').trim() || undefined,
idCardNumber: String(r['证件号码'] || r['身份证号'] || '').trim() || undefined,
amount: parseFloat(r['金额'] || r['提成奖金'] || '0') || 0,
remark: String(r['备注'] || '').trim() || undefined,
})).filter((r) => r.employeeName || r.idCardNumber)
const result = await batchImport(orgId, req.user!.id, month, parsed)
await auditLog(req, 'IMPORT', 'COMMISSION_BONUS', undefined, { month, ...result })
res.json({ success: true, data: result })
} catch (err) { next(err) }
})
/**
* 下载导入模板
* GET /commission-bonus/template
*/
router.get('/template', (req: AuthRequest, res: Response) => {
const ws = XLSX.utils.aoa_to_sheet([
['员工姓名', '证件号码', '金额', '备注'],
['张三', '110101199001011234', '5000', '销售提成'],
['李四', '', '-200', '迟到扣款'],
])
const wb = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb, ws, '提成奖金模板')
const buf = XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' })
res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
res.setHeader('Content-Disposition', 'attachment; filename="commission-bonus-template.xlsx"')
res.send(buf)
})
export default router