feat(P15B-1,P15B-6): 完成请假V1闭环

这个提交包含在:
2026-03-07 08:11:24 +08:00
父节点 03c5a78485
当前提交 4ba311199d
共修改 23 个文件,包含 3202 行新增和 308 行删除
+95
查看文件
@@ -105,6 +105,43 @@ const DEFAULT_LEAVE_WORKFLOW_DEFINITION = {
],
};
const DEFAULT_LEAVE_TYPES = [
{
code: "annual_leave",
name: "年假",
description: "按自然日+半天粒度扣减。",
enabled: true,
requires_attachment: false,
attachment_mime_types: null,
sort_order: 10,
annual_quota_days: "15.0",
policy_description: "默认年度授予 15 天。",
},
{
code: "sick_leave",
name: "病假",
description: "病假需上传诊断或病历附件。",
enabled: true,
requires_attachment: true,
attachment_mime_types: ["application/pdf", "image/jpeg", "image/png"],
sort_order: 20,
annual_quota_days: "10.0",
policy_description: "默认年度授予 10 天。",
},
{
code: "personal_leave",
name: "事假",
description: "事假默认走经理审批。",
enabled: true,
requires_attachment: false,
attachment_mime_types: null,
sort_order: 30,
annual_quota_days: "5.0",
policy_description: "默认年度授予 5 天。",
},
];
async function seedExpenseTypes(prisma) {
const now = new Date();
const allTypes = [
@@ -179,6 +216,61 @@ async function seedDocumentSequence(prisma) {
});
}
async function seedLeaveTypes(prisma) {
const now = new Date();
for (const item of DEFAULT_LEAVE_TYPES) {
const leaveType = await prisma.leaveType.upsert({
where: { code: item.code },
update: {
name: item.name,
description: item.description,
enabled: item.enabled,
requires_attachment: item.requires_attachment,
attachment_mime_types: item.attachment_mime_types,
sort_order: item.sort_order,
updated_at: now,
updated_by: null,
},
create: {
code: item.code,
name: item.name,
description: item.description,
enabled: item.enabled,
requires_attachment: item.requires_attachment,
attachment_mime_types: item.attachment_mime_types,
sort_order: item.sort_order,
created_at: now,
created_by: null,
updated_at: now,
updated_by: null,
},
select: { id: true },
});
await prisma.leavePolicy.upsert({
where: { leave_type_id: leaveType.id },
update: {
annual_quota_days: item.annual_quota_days,
enabled: item.enabled,
description: item.policy_description,
updated_at: now,
updated_by: null,
},
create: {
leave_type_id: leaveType.id,
annual_quota_days: item.annual_quota_days,
enabled: item.enabled,
description: item.policy_description,
created_at: now,
created_by: null,
updated_at: now,
updated_by: null,
},
});
}
}
async function seedWorkflowDefinition(prisma) {
await prisma.workflowDefinition.updateMany({
where: {
@@ -254,6 +346,7 @@ async function main() {
await seedApprovalRules(prisma);
await seedDocumentSequence(prisma);
await seedWorkflowDefinition(prisma);
await seedLeaveTypes(prisma);
// eslint-disable-next-line no-console
console.log("Seeded config data:");
@@ -267,6 +360,8 @@ async function main() {
console.log("- workflow definition: reimbursement v1 (1-step role=ceo)");
// eslint-disable-next-line no-console
console.log("- workflow definition: leave v1 (1-step department_manager)");
// eslint-disable-next-line no-console
console.log(`- leave types: ${DEFAULT_LEAVE_TYPES.length} seeded with default policies`);
} finally {
await prisma.$disconnect();
await pool.end();