feat: 系统优化Phase2 - 面包屑导航/侧边栏间距/制度公示阅读签收/模板变量中文化/通知类型补全

- 面包屑导航组件,集成至TopNav header
- 侧边栏菜单分组间距增大,分组间分隔线
- 制度公示员工阅读签收:PolicyReadRecord模型、portal路由、管理端阅读统计
- 修复Policies.tsx民主程序推进bug(字段名/API路径/参数)
- 用工文本模板变量名英文转中文显示
- 通知类型TYPE_LABELS补全(RISK_ALERT/SOCIAL_INS/OVERTIME_ALERT/PAYSLIP_READY)
- 通知示例数据补充
- h2标题统一为text-sm font-medium
- 新增run.md
This commit is contained in:
selfrelease
2026-07-26 20:32:38 +08:00
parent 9cb0d1f63b
commit d79e3baa34
71 changed files with 18561 additions and 3230 deletions
+89
View File
@@ -0,0 +1,89 @@
/**
* 批量补齐现有示例数据的证据链
* 运行: npx tsx scripts/seed-evidence.ts
*/
import prisma from '../src/lib/prisma'
import { sha256 } from '../src/lib/crypto'
async function main() {
const orgId = 'cmry97x7l0000trrp5f9jgng5'
const systemUserId = 'system-seed'
let count = 0
// 清除旧的 seed 数据
await prisma.evidenceChain.deleteMany({ where: { createdBy: systemUserId } })
console.log('Cleared old seed evidence chains')
// 1. 员工入职证据链
const employees = await prisma.employee.findMany({ select: { id: true, name: true, hireDate: true, createdAt: true } })
for (const emp of employees) {
const events = [{ action: '员工入职登记', timestamp: emp.createdAt.toISOString(), ip: '127.0.0.1', userAgent: 'system-seed' }]
const hash = sha256(JSON.stringify(events) + orgId + 'ONBOARD' + emp.id)
await prisma.evidenceChain.create({
data: { orgId, category: 'ONBOARD', refId: emp.id, employeeId: emp.id, events: events as any, hash, createdBy: systemUserId, createdAt: emp.createdAt },
}).catch(() => {})
count++
}
console.log('ONBOARD:', employees.length)
// 2. 合同签订证据链
const contracts = await prisma.laborContract.findMany({ select: { id: true, employeeId: true, createdAt: true } })
for (const c of contracts) {
const events = [{ action: '合同签订', timestamp: c.createdAt.toISOString(), ip: '127.0.0.1', userAgent: 'system-seed' }]
const hash = sha256(JSON.stringify(events) + orgId + 'CONTRACT_SIGN' + c.id)
await prisma.evidenceChain.create({
data: { orgId, category: 'CONTRACT_SIGN', refId: c.id, employeeId: c.employeeId, events: events as any, hash, createdBy: systemUserId, createdAt: c.createdAt },
}).catch(() => {})
count++
}
console.log('CONTRACT_SIGN:', contracts.length)
// 3. 工资条确认证据链
const payslips = await prisma.payslip.findMany({ where: { confirmedAt: { not: null } }, select: { id: true, employeeId: true, confirmedAt: true } })
for (const p of payslips) {
const events = [{ action: '工资条确认', timestamp: p.confirmedAt!.toISOString(), ip: '127.0.0.1', userAgent: 'employee-portal' }]
const hash = sha256(JSON.stringify(events) + orgId + 'PAYSLIP_CONFIRM' + p.id)
await prisma.evidenceChain.create({
data: { orgId, category: 'PAYSLIP_CONFIRM', refId: p.id, employeeId: p.employeeId, events: events as any, hash, createdBy: p.employeeId, createdAt: p.confirmedAt! },
}).catch(() => {})
count++
}
console.log('PAYSLIP_CONFIRM:', payslips.length)
// 4. 违纪记录证据链
const disciplinaries = await prisma.disciplinaryRecord.findMany({ select: { id: true, employeeId: true, createdAt: true, violationType: true, severity: true } })
const violationMap: Record<string, string> = { LATE: '迟到', ABSENT: '旷工', INSUBORDINATION: '不服从管理', OTHER: '其他违规' }
for (const d of disciplinaries) {
const desc = violationMap[d.violationType] || d.violationType
const events = [{ action: `违纪记录创建(${desc}`, timestamp: d.createdAt.toISOString(), ip: '127.0.0.1', userAgent: 'system-seed' }]
const hash = sha256(JSON.stringify(events) + orgId + 'DISCIPLINARY' + d.id)
await prisma.evidenceChain.create({
data: { orgId, category: 'DISCIPLINARY', refId: d.id, employeeId: d.employeeId, events: events as any, hash, createdBy: systemUserId, createdAt: d.createdAt },
}).catch(() => {})
count++
}
console.log('DISCIPLINARY:', disciplinaries.length)
// 5. 解聘证据链
const terminations = await prisma.terminationRecord.findMany({ select: { id: true, employeeId: true, createdAt: true, reason: true, status: true } })
const reasonMap: Record<string, string> = { NEGOTIATED: '协商解除', UNILATERAL: '单方解除', EXPIRY: '合同到期', RESIGNATION: '员工辞职', OTHER: '其他' }
const statusMap: Record<string, string> = { DRAFT: '草稿', PENDING_APPROVAL: '待审批', APPROVED: '已审批', EXECUTED: '已执行', CANCELLED: '已撤销' }
for (const t of terminations) {
const reasonText = reasonMap[t.reason] || t.reason
const statusText = statusMap[t.status] || t.status
const events = [{ action: `解聘流程(${reasonText}·${statusText}`, timestamp: t.createdAt.toISOString(), ip: '127.0.0.1', userAgent: 'system-seed' }]
const hash = sha256(JSON.stringify(events) + orgId + 'TERMINATION' + t.id)
await prisma.evidenceChain.create({
data: { orgId, category: 'TERMINATION', refId: t.id, employeeId: t.employeeId, events: events as any, hash, createdBy: systemUserId, createdAt: t.createdAt },
}).catch(() => {})
count++
}
console.log('TERMINATION:', terminations.length)
const total = await prisma.evidenceChain.count()
console.log(`\n总计插入 ${count} 条,数据库现有 ${total} 条证据链`)
await prisma.$disconnect()
}
main().catch(console.error)