feat: 实现20260730优化方案全部功能
- AI文件审查:.docx上传提取文本,支持多种文档类型 - 用工办理工作流:WorkProcess页面+后端API,支持入职/续签/终止等流程 - 企业自建文本库:Templates页面Tab切换,企业模板CRUD+渲染+下载Word - 考勤发布:Attendance发布/取消发布按钮,员工端MyAttendance页面 - 工资条发布:Money发布/定时发送按钮+弹窗,portal端publishStatus过滤 - 合同到期弹窗:Dashboard合同到期预警可点击打开弹窗,支持续签/终止操作 - Prisma schema新增WorkProcess/EnterpriseTemplate/AttendancePublish模型 - 前后端编译验证全部通过
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
import { Router, Response, NextFunction } from 'express'
|
||||
import { authMiddleware, AuthRequest } from '../middleware/auth'
|
||||
import prisma from '../lib/prisma'
|
||||
import { renderTemplate } from '../services/template.service'
|
||||
|
||||
const router = Router()
|
||||
|
||||
// 提取变量名
|
||||
function extractVariables(content: string): string[] {
|
||||
const matches = content.match(/\{\{(\w+)\}\}/g) || []
|
||||
return [...new Set(matches.map(m => m.replace(/\{\{|\}\}/g, '')))]
|
||||
}
|
||||
|
||||
// 列表
|
||||
router.get('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const { category, search } = req.query
|
||||
const where: any = { orgId: req.user!.orgId, status: 'ACTIVE' }
|
||||
if (category) where.category = category
|
||||
if (search) where.name = { contains: String(search) }
|
||||
const items = await (prisma as any).enterpriseTemplate.findMany({
|
||||
where,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
})
|
||||
res.json({ success: true, data: items })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
// 新建
|
||||
router.post('/', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const { name, category, description, content } = req.body
|
||||
if (!name || !category || !content) {
|
||||
return res.status(400).json({ success: false, error: { code: 'MISSING_FIELDS', message: '名称、分类、内容为必填' } })
|
||||
}
|
||||
const variables = extractVariables(content)
|
||||
const template = await (prisma as any).enterpriseTemplate.create({
|
||||
data: {
|
||||
orgId: req.user!.orgId,
|
||||
name,
|
||||
category,
|
||||
description: description || null,
|
||||
content,
|
||||
variables,
|
||||
createdBy: req.user!.id,
|
||||
},
|
||||
})
|
||||
res.json({ success: true, data: template })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
// 详情
|
||||
router.get('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const template = await (prisma as any).enterpriseTemplate.findFirst({
|
||||
where: { id: req.params.id, orgId: req.user!.orgId },
|
||||
})
|
||||
if (!template) {
|
||||
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '模板不存在' } })
|
||||
}
|
||||
res.json({ success: true, data: template })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
// 更新
|
||||
router.put('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const existing = await (prisma as any).enterpriseTemplate.findFirst({
|
||||
where: { id: req.params.id, orgId: req.user!.orgId },
|
||||
})
|
||||
if (!existing) {
|
||||
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '模板不存在' } })
|
||||
}
|
||||
const { name, category, description, content, status } = req.body
|
||||
const variables = content ? extractVariables(content) : existing.variables
|
||||
const updated = await (prisma as any).enterpriseTemplate.update({
|
||||
where: { id: req.params.id },
|
||||
data: {
|
||||
...(name !== undefined && { name }),
|
||||
...(category !== undefined && { category }),
|
||||
...(description !== undefined && { description }),
|
||||
...(content !== undefined && { content, variables }),
|
||||
...(status !== undefined && { status }),
|
||||
},
|
||||
})
|
||||
res.json({ success: true, data: updated })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
// 删除
|
||||
router.delete('/:id', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const existing = await (prisma as any).enterpriseTemplate.findFirst({
|
||||
where: { id: req.params.id, orgId: req.user!.orgId },
|
||||
})
|
||||
if (!existing) {
|
||||
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '模板不存在' } })
|
||||
}
|
||||
await (prisma as any).enterpriseTemplate.delete({ where: { id: req.params.id } })
|
||||
res.json({ success: true, data: { message: '已删除' } })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
// 渲染
|
||||
router.post('/:id/render', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const template = await (prisma as any).enterpriseTemplate.findFirst({
|
||||
where: { id: req.params.id, orgId: req.user!.orgId },
|
||||
})
|
||||
if (!template) {
|
||||
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '模板不存在' } })
|
||||
}
|
||||
const { variables } = req.body as { variables: Record<string, string> }
|
||||
let content = template.content
|
||||
for (const [key, value] of Object.entries(variables || {})) {
|
||||
content = content.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value)
|
||||
}
|
||||
res.json({ success: true, data: { content } })
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
// 下载 Word
|
||||
router.get('/:id/download', authMiddleware, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const template = await (prisma as any).enterpriseTemplate.findFirst({
|
||||
where: { id: req.params.id, orgId: req.user!.orgId },
|
||||
})
|
||||
if (!template) {
|
||||
return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '模板不存在' } })
|
||||
}
|
||||
const encoded = encodeURIComponent(template.name + '.doc')
|
||||
res.setHeader('Content-Type', 'application/msword')
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${encoded}"; filename*=UTF-8''${encoded}`)
|
||||
res.send(template.content)
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user