替代 Excel 和纸质表单,一键搭建符合马来西亚劳动法的请假审批与考勤打卡系统
* Preview is for reference only. Actual results may vary depending on the AI model, variable values, and tools used.
你是一位资深全栈开发工程师,精通 Next.js 16、Tailwind CSS 4 和 Supabase。请为 {company_name} 搭建一个完整的【员工请假与考勤管理系统】,公司目前有 {num_employees} 位员工。
---
## 一、技术栈
- 前端:Next.js 16 (App Router) + TypeScript + Tailwind CSS 4
- UI 组件:shadcn/ui(主色调 {primary_color})
- 后端/数据库:Supabase (Postgres + Auth + RLS + Storage)
- 部署:Vercel
- 时区:Asia/Kuala_Lumpur (UTC+8)
---
## 二、数据模型(Supabase Postgres)
### employees 表
- id (uuid, PK)
- auth_user_id (uuid, FK -> auth.users)
- employee_code (text, unique) -- 例如 EMP001
- full_name (text)
- email (text)
- department (text)
- position (text)
- join_date (date)
- manager_id (uuid, FK -> employees.id, nullable)
- role (enum: employee / manager / hr_admin)
- status (enum: active / inactive / probation)
- state (text) -- 马来西亚州属,影响公共假期
- created_at (timestamptz)
### leave_types 表
- id (uuid, PK)
- name_zh (text) -- 年假、病假、紧急假、无薪假
- name_en (text) -- Annual Leave, Medical Leave, Emergency Leave, Unpaid Leave
- code (text, unique) -- AL, MC, EL, UL
- default_days (int) -- 默认天数
- requires_attachment (boolean) -- MC 需要上传医疗证明
- is_paid (boolean)
- sort_order (int)
### leave_entitlements 表
- id (uuid, PK)
- employee_id (uuid, FK)
- leave_type_id (uuid, FK)
- year (int)
- entitled_days (numeric(4,1)) -- 总额度
- carried_forward (numeric(4,1)) -- 上年结转
- used_days (numeric(4,1)) -- 已用
- pending_days (numeric(4,1)) -- 审批中
- balance (numeric(4,1), generated) -- entitled + carried_forward - used - pending
- UNIQUE(employee_id, leave_type_id, year)
### leave_requests 表
- id (uuid, PK)
- employee_id (uuid, FK)
- leave_type_id (uuid, FK)
- start_date (date)
- end_date (date)
- half_day (enum: null / morning / afternoon) -- 半天假
- total_days (numeric(4,1))
- reason (text)
- attachment_url (text, nullable) -- MC 上传路径
- status (enum: pending / approved / rejected / cancelled)
- approved_by (uuid, FK -> employees.id, nullable)
- approved_at (timestamptz, nullable)
- rejection_reason (text, nullable)
- created_at (timestamptz)
- updated_at (timestamptz)
### attendance_records 表
- id (uuid, PK)
- employee_id (uuid, FK)
- date (date)
- clock_in (timestamptz, nullable)
- clock_out (timestamptz, nullable)
- clock_in_lat (numeric(10,7), nullable)
- clock_in_lng (numeric(10,7), nullable)
- clock_out_lat (numeric(10,7), nullable)
- clock_out_lng (numeric(10,7), nullable)
- work_hours (numeric(4,2), generated) -- 自动计算
- overtime_hours (numeric(4,2), default 0)
- status (enum: present / absent / late / half_day / on_leave / holiday)
- notes (text, nullable)
- UNIQUE(employee_id, date)
### public_holidays 表
- id (uuid, PK)
- name_zh (text)
- name_en (text)
- date (date)
- state (text, nullable) -- null 表示全国,否则指定州属
- year (int)
- is_replacement (boolean, default false)
### overtime_records 表
- id (uuid, PK)
- employee_id (uuid, FK)
- date (date)
- start_time (timestamptz)
- end_time (timestamptz)
- total_hours (numeric(4,2))
- rate_multiplier (numeric(3,1)) -- 1.5x 工作日, 2.0x 休息日, 3.0x 公共假期
- status (enum: pending / approved / rejected)
- approved_by (uuid, FK, nullable)
- created_at (timestamptz)
### 索引要求
- leave_requests: (employee_id), (status), (start_date, end_date)
- attendance_records: (employee_id, date), (date)
- leave_entitlements: (employee_id, year)
- public_holidays: (date, state), (year)
- employees: (manager_id), (auth_user_id)
### RLS 策略
- employees: 本人可读自己记录;manager 可读下属;hr_admin 全读写
- leave_requests: 本人可读写自己的申请;manager 可读写下属申请(审批);hr_admin 全读写
- attendance_records: 本人可读自己;本人可 INSERT 打卡;hr_admin 全读写
- public_holidays: anon 和 authenticated 都可读
---
## 三、业务逻辑
### 1. 年假额度计算(依据马来西亚 Employment Act 1955)
```
服务年资 < 2 年: {annual_leave_days} 天(最低 8 天)
服务年资 2-5 年: {annual_leave_days} + 4 天(最低 12 天)
服务年资 > 5 年: {annual_leave_days} + 8 天(最低 16 天)
病假额度: {mc_days} 天(无需住院),住院可额外 60 天
紧急假: 2 天/年
无薪假: 无上限,需审批
```
### 2. 年假结转政策
- 未用年假可结转到下一年
- 结转上限:5 天
- 结转假期须在 Q1(3月31日前)用完,否则作废
- 系统自动在每年1月1日生成新年度额度
### 3. 请假审批流程
```
员工提交 -> 直属经理审批 -> 系统自动更新余额
-> 如被拒绝,退回余额
-> 员工可取消 pending 状态的申请
```
- MC 超过 2 天须上传医疗证明(Supabase Storage)
- 紧急假可事后补申请(48小时内)
- 审批后自动发送通知(可用 Supabase Edge Function + email)
### 4. 考勤规则
- 工作时间:{operating_hours}
- 迟到定义:超过上班时间 15 分钟
- GPS 打卡(可选):记录经纬度,可配置办公室范围(500米内)
- 每日只能打卡一次上班、一次下班
- 忘记打卡须由 HR 手动补录
- 加班计算:超过标准 8 小时的部分
### 5. 加班费率(Employment Act)
- 工作日加班:1.5 倍
- 休息日工作:2.0 倍
- 公共假期工作:3.0 倍
### 6. 公共假期(2025 马来西亚联邦法定 11 天)
预设以下联邦公共假期,并允许 HR 添加州属假期:
- 元旦 (1月1日)
- 开斋节 (2天)
- 劳动节 (5月1日)
- 最高元首诞辰 (6月第一个周一)
- 马来西亚日 (9月16日)
- 哈芝节
- 回历新年
- 屠妖节
- 圣诞节 (12月25日)
- 农历新年 (2天)
州属假期由 HR 自行配置(如 Selangor 大宝森节、Thaipusam 等)
---
## 四、页面结构与 UI/UX
### 4.1 员工端(移动优先设计)
#### /dashboard — 员工主页
- 假期余额卡片(年假、病假各一张,圆环进度条显示已用/总额)
- 本月考勤概览(出勤天数、迟到次数、加班时数)
- 快捷操作:打卡、申请假期
- 最近请假记录(最新3条)
#### /leave/apply — 申请假期
- 表单:假期类型(下拉)、起止日期(日历选择器)、半天选项、原因
- 实时显示:扣除天数(自动排除周末和公共假期)、剩余余额
- MC 类型自动显示文件上传区域
- 提交前确认弹窗
#### /leave/history — 假期记录
- 按年度筛选
- 状态标签:待审批(黄)、已批准(绿)、已拒绝(红)、已取消(灰)
- 点击可查看详情和审批备注
#### /attendance — 打卡页面
- 大按钮打卡(上班/下班状态自动切换)
- 当前时间显示(实时更新)
- GPS 位置显示(如开启)
- 本月打卡日历视图(绿=正常、红=缺勤、黄=迟到、蓝=请假)
#### /leave/calendar — 团队假期日历
- 月视图日历
- 显示同部门同事的请假情况
- 颜色区分假期类型
- 方便员工选择不冲突的请假日期
### 4.2 经理端
#### /manager/approvals — 审批中心
- 待审批列表(按提交时间排序)
- 每条显示:员工姓名、假期类型、日期、天数、原因
- 一键批准 / 拒绝(拒绝须填写理由)
- 批量审批功能
- 团队假期日历(快速查看冲突)
#### /manager/team — 团队概览
- 团队成员列表
- 每人显示:假期余额、本月出勤率、加班时数
- 点击进入员工详情
### 4.3 HR 管理端
#### /admin/employees — 员工管理
- 员工列表(搜索、筛选部门/状态)
- 新增/编辑员工信息
- 手动调整假期额度
- 手动补录考勤
#### /admin/holidays — 公共假期管理
- 按年度管理公共假期
- 添加联邦/州属假期
- 支持替代假期设置
#### /admin/reports — 报表中心
- 月度考勤报告(全公司 / 按部门)
- 假期使用统计
- 加班统计
- 导出 CSV(payroll integration-ready 格式)
- 列:员工编号、姓名、工作天数、迟到次数、加班时数、假期天数(按类型)
- 年度假期余额总表
#### /admin/settings — 系统设置
- 工作时间配置
- GPS 打卡开关和范围设置
- 结转政策配置
- 加班费率配置
---
## 五、示例种子数据
请生成以下 5 位马来西亚员工的测试数据:
| 编号 | 姓名 | 部门 | 职位 | 入职日期 | 角色 | 州属 |
|------|------|------|------|----------|------|------|
| EMP001 | 陈伟明 (Tan Wei Ming) | 运营部 | 运营总监 | 2020-03-15 | hr_admin | Selangor |
| EMP002 | Siti Nurhaliza | 市场部 | 市场经理 | 2022-06-01 | manager | Selangor |
| EMP003 | Rajesh Kumar | 技术部 | 高级开发 | 2023-01-10 | employee | KL |
| EMP004 | 林美玲 (Lim Mei Ling) | 市场部 | 市场专员 | 2024-08-20 | employee | Selangor |
| EMP005 | Ahmad bin Ismail | 运营部 | 仓库主管 | 2019-11-01 | manager | Johor |
汇报关系:EMP003 -> EMP005, EMP004 -> EMP002, EMP002 -> EMP001, EMP005 -> EMP001
并生成:
- 每位员工 2025 年度的假期额度(根据年资自动计算)
- 2-3 条请假记录(混合 approved / pending / rejected)
- 本月 5 天考勤打卡记录
- 2025 年马来西亚联邦公共假期数据
---
## 六、关键实现细节
1. 使用 Supabase Auth 管理登录,通过 employees.role 控制权限
2. 请假天数计算须排除周末(六日)和公共假期(根据员工州属)
3. 半天假算 0.5 天
4. 所有时间使用 Asia/Kuala_Lumpur 时区
5. 移动端优先 — 员工主要用手机打卡和请假
6. 使用 Supabase Realtime 实现审批实时通知
7. 文件上传(MC 证明)使用 Supabase Storage,限制 5MB,仅 PDF/JPG/PNG
8. 报表导出 CSV 须兼容中文字符(UTF-8 BOM)
9. 数据库使用 Postgres function 计算 work_hours 和 balance
10. 所有金额和天数显示保留一位小数