# 月度核算中心与实时考勤看板 Implementation Plan > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** 将当前薪酬考勤系统从“多个功能页分散操作”升级为“实时考勤看板 + 月度核算中心”的主流程系统,支持钉钉实时同步、Excel 导入、考勤标准化、薪资预估、月度工资复核、锁定和导出。 **Architecture:** 后端继续沿用 FastAPI 分层架构:router 只处理 HTTP 和权限,schema 只定义请求响应,service 负责编排,repository 负责 ORM 读写,domain 负责纯计算。新增实时考勤和月度核算模块时,复用现有 `PayrollCalculator`、`MonthlySummaryParser`、`DingTalkAttendanceAdapter`、`attendance_record`、`payroll_results` 等能力,只补齐同步批次、实时预估、月度核算状态和异常记录。 **Tech Stack:** Python 3 / FastAPI / SQLAlchemy / MySQL / openpyxl / Vue 3 / Pinia / Vue Router / TypeScript / Vite / lucide-vue。 --- ## 目标业务流 ```text 实时考勤看板 -> 读取在职员工和钉钉 userId -> 同步今天或本月至今的钉钉打卡 -> 标准化为每日考勤 -> 展示今日打卡、迟到、缺卡、请假、加班和本月薪资预估 月度核算中心 -> 选择工资月份 -> 同步钉钉或导入 Excel -> 标准化考勤 -> 生成异常清单 -> 计算工资 -> 复核员工明细 -> 锁定本月工资 -> 导出工资表和报表 ``` ## 阶段 0:开发前保护 ### Task 0.1: 建立当前基线 **Files:** - Read: `README.md` - Read: `financial_system/database/orm.py` - Read: `financial_system/services/payroll_service.py` - Read: `financial_system/api/routers/payroll.py` - Read: `frontend/src/router/index.ts` - Read: `frontend/src/components/SidebarNav.vue` - Read: `frontend/src/views/PayrollView.vue` **Step 1: 查看工作区状态** Run: ```bash git status --short ``` Expected: 确认哪些文件已有用户改动。不要回滚任何非本任务改动。 **Step 2: 编译当前后端** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: `financial_system` 编译成功。 **Step 3: 构建当前前端** Run: ```bash cd frontend npm run build ``` Expected: Vite build 通过。 **Step 4: Commit** 本任务只做基线验证,不需要 commit。 --- ## 阶段 1:数据库模型与 SQL ### Task 1.1: 增加实时同步和月度核算 ORM **Files:** - Modify: `financial_system/database/orm.py` - Modify: `financial_system/database/sql/schema.sql` - Modify: `financial_system/database/sql/init_mysql.sql` - Create: `financial_system/database/sql/upgrade_20260618_monthly_payroll_center.sql` **Step 1: 设计新增表** 新增 4 张表,所有表和字段都必须有 MySQL 注释: ```text attendance_sync_jobs id source_type sync_mode attendance_date salary_month start_date end_date status employee_count record_count error_message created_by created_at updated_at salary_preview id sync_job_id employee_id employee_no employee_name department position salary_month attendance_days actual_work_hours punch_overtime_hours leave_hours remaining_overtime_hours late_deduction missing_card_deduction commission_amount overtime_pay estimated_gross_salary estimated_net_salary status note created_at updated_at monthly_payroll_runs id salary_month source_type source_job_id status employee_count gross_total net_total deduction_total overtime_total locked_by locked_at created_by created_at updated_at payroll_exceptions id run_id sync_job_id employee_id employee_no employee_name salary_month exception_type severity message status created_at resolved_at ``` **Step 2: 修改 ORM** 在 `financial_system/database/orm.py` 中新增: ```python class AttendanceSyncJobORM(Base): """钉钉或 Excel 考勤同步批次,用于实时看板和月度核算追踪。""" __tablename__ = "attendance_sync_jobs" ... class SalaryPreviewORM(Base): """本月进行中的薪资预估结果,不作为最终工资发放依据。""" __tablename__ = "salary_preview" ... class MonthlyPayrollRunORM(Base): """月度正式核算批次,支持复核、锁定和导出。""" __tablename__ = "monthly_payroll_runs" ... class PayrollExceptionORM(Base): """核算异常记录,例如缺员工、缺薪资档案、缺卡、请假无法识别。""" __tablename__ = "payroll_exceptions" ... ``` 字段类型沿用现有风格:金额用 `Float`,月份用 `String(7)`,状态用 `String(32)`,时间用 `DateTime`。 **Step 3: 更新 SQL** 在 `schema.sql` 和 `init_mysql.sql` 中增加建表语句。新增 `upgrade_20260618_monthly_payroll_center.sql`,包含 `CREATE TABLE IF NOT EXISTS`,可对已有库安全执行。 **Step 4: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 5: Commit** ```bash git add financial_system/database/orm.py financial_system/database/sql/schema.sql financial_system/database/sql/init_mysql.sql financial_system/database/sql/upgrade_20260618_monthly_payroll_center.sql git commit -m "feat: add monthly payroll center tables" ``` --- ### Task 1.2: 增加权限和菜单 **Files:** - Modify: `financial_system/core/permissions.py` - Modify: `frontend/src/router/index.ts` - Modify: `frontend/src/components/SidebarNav.vue` **Step 1: 增加权限码** 在 `financial_system/core/permissions.py` 增加: ```python PERMISSION_ATTENDANCE_REALTIME_VIEW = "attendance:realtime:view" PERMISSION_ATTENDANCE_REALTIME_SYNC = "attendance:realtime:sync" PERMISSION_MONTHLY_PAYROLL_VIEW = "monthly_payroll:view" PERMISSION_MONTHLY_PAYROLL_CALCULATE = "monthly_payroll:calculate" PERMISSION_MONTHLY_PAYROLL_LOCK = "monthly_payroll:lock" PERMISSION_MONTHLY_PAYROLL_EXPORT = "monthly_payroll:export" ``` **Step 2: 增加菜单** 新增菜单: ```python "attendance_realtime": MenuPermission( code="attendance_realtime", name="实时考勤", path="/attendance/realtime", ), "monthly_payroll": MenuPermission( code="monthly_payroll", name="月度核算", path="/payroll/monthly", ), ``` 超级用户和管理者可见两个菜单;查看权限至少可见 `实时考勤` 和报表,是否能看月度工资按业务需要决定,默认仅查看 `实时考勤`。 **Step 3: 前端路由占位** 在 `frontend/src/router/index.ts` 先注册页面: ```typescript { path: "attendance/realtime", name: "attendance-realtime", component: RealtimeAttendanceView, meta: { permission: "attendance:realtime:view" }, }, { path: "payroll/monthly", name: "monthly-payroll", component: MonthlyPayrollView, meta: { permission: "monthly_payroll:view" }, }, ``` **Step 4: 侧边栏图标** 在 `frontend/src/components/SidebarNav.vue` 中增加图标映射: ```typescript attendance_realtime: CalendarClock, monthly_payroll: Calculator, ``` **Step 5: 验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 6: Commit** ```bash git add financial_system/core/permissions.py frontend/src/router/index.ts frontend/src/components/SidebarNav.vue git commit -m "feat: add realtime attendance and monthly payroll menus" ``` --- ## 阶段 2:后端实时考勤看板 ### Task 2.1: 增加实时考勤 schema **Files:** - Create: `financial_system/api/schemas/realtime_attendance.py` - Modify: `financial_system/api/schemas/__init__.py` **Step 1: 编写 schema** Create `financial_system/api/schemas/realtime_attendance.py`: ```python from __future__ import annotations from datetime import date, datetime from pydantic import BaseModel class RealtimeAttendanceSyncRequest(BaseModel): attendance_date: date include_salary_preview: bool = True class TodayAttendanceItem(BaseModel): employee_id: int | None employee_no: str employee_name: str department: str position: str first_punch: str last_punch: str attendance_status: str late_minutes: int missing_card_count: int leave_hours: float today_overtime_hours: float month_remaining_overtime_hours: float estimated_net_salary: float | None note: str class RealtimeAttendanceSummary(BaseModel): attendance_date: date employee_total: int checked_in_count: int unchecked_count: int late_count: int leave_count: int missing_card_count: int estimated_overtime_count: int estimated_net_total: float class RealtimeAttendanceResponse(BaseModel): sync_job_id: str | None synced_at: datetime | None summary: RealtimeAttendanceSummary items: list[TodayAttendanceItem] ``` **Step 2: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 3: Commit** ```bash git add financial_system/api/schemas/realtime_attendance.py financial_system/api/schemas/__init__.py git commit -m "feat: add realtime attendance schemas" ``` --- ### Task 2.2: 增加实时考勤 Repository **Files:** - Create: `financial_system/repositories/realtime_attendance_repository.py` - Modify: `financial_system/repositories/__init__.py` **Step 1: 实现 repository** Repository 负责: - 查询在职员工和钉钉 userId。 - 创建 `attendance_sync_jobs`。 - 保存 `attendance_record`。 - 保存 `salary_preview`。 - 查询某日考勤记录。 - 查询某月薪资预估。 核心方法: ```python class RealtimeAttendanceRepository: def list_active_employees_with_dingtalk(self) -> list[EmployeeORM]: ... def create_sync_job(...) -> AttendanceSyncJobORM: ... def mark_sync_completed(...) -> None: ... def mark_sync_failed(...) -> None: ... def replace_attendance_records(...) -> None: ... def replace_salary_previews(...) -> None: ... def list_today_records(...) -> list[AttendanceRecordORM]: ... def list_salary_previews(...) -> list[SalaryPreviewORM]: ... ``` **Step 2: 注意幂等** 同一天多次同步时,应按 `source_type=dingtalk + work_date + employee_id` 替换当天记录,避免列表越来越多。 **Step 3: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 4: Commit** ```bash git add financial_system/repositories/realtime_attendance_repository.py financial_system/repositories/__init__.py git commit -m "feat: add realtime attendance repository" ``` --- ### Task 2.3: 增加实时薪资预估服务 **Files:** - Create: `financial_system/services/realtime_attendance_service.py` - Modify: `financial_system/services/__init__.py` - Modify: `financial_system/api/dependencies.py` **Step 1: 实现服务职责** `RealtimeAttendanceService` 负责: - 从数据库拿在职员工。 - 自动收集员工 `dingtalk_user_id`,不再让用户手填。 - 调用 `DingTalkClient.list_attendance_records`。 - 使用 `DingTalkAttendanceAdapter` 转成 `EmployeeAttendance`。 - 使用 `PayrollCalculator` 计算本月薪资预估。 - 写入 `attendance_record` 和 `salary_preview`。 - 输出今日考勤列表和汇总。 **Step 2: 保持预估语义** 返回字段命名使用 `estimated_*`,页面文案必须展示“预估金额,最终以月度核算锁定结果为准”。 **Step 3: 缺少钉钉配置** 复用 `PayrollApplicationService._dingtalk_settings()` 的逻辑,或者抽出公共 helper。缺少 `app_key/app_secret` 时返回 400,提示用户修改 `config/app_settings.json`。 **Step 4: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 5: Commit** ```bash git add financial_system/services/realtime_attendance_service.py financial_system/services/__init__.py financial_system/api/dependencies.py git commit -m "feat: add realtime attendance service" ``` --- ### Task 2.4: 增加实时考勤 API **Files:** - Create: `financial_system/api/routers/realtime_attendance.py` - Modify: `financial_system/api/app.py` **Step 1: 新增路由** Create router prefix: ```python router = APIRouter(prefix="/api/attendance/realtime", tags=["realtime-attendance"]) ``` Endpoints: ```text GET /api/attendance/realtime/today?date=YYYY-MM-DD POST /api/attendance/realtime/sync ``` **Step 2: 权限** - `GET today` 使用 `PERMISSION_ATTENDANCE_REALTIME_VIEW` - `POST sync` 使用 `PERMISSION_ATTENDANCE_REALTIME_SYNC` **Step 3: 操作日志** 同步成功记录: ```text module=attendance action=attendance.realtime.sync target_type=attendance_sync_job ``` 查看成功记录: ```text module=attendance action=attendance.realtime.view ``` **Step 4: 注册路由** 在 `financial_system/api/app.py` 导入并 `include_router(realtime_attendance.router)`。 **Step 5: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 6: Commit** ```bash git add financial_system/api/routers/realtime_attendance.py financial_system/api/app.py git commit -m "feat: add realtime attendance api" ``` --- ## 阶段 3:后端月度核算中心 ### Task 3.1: 增加月度核算 schema **Files:** - Create: `financial_system/api/schemas/monthly_payroll.py` - Modify: `financial_system/api/schemas/__init__.py` **Step 1: 定义请求响应** Create: ```python class MonthlyPayrollCreateRequest(BaseModel): salary_month: str source_type: str export_excel: bool = True class MonthlyPayrollImportExcelResponse(BaseModel): run_id: int status: str employee_count: int exception_count: int class MonthlyPayrollRunResponse(BaseModel): id: int salary_month: str source_type: str status: str employee_count: int gross_total: float net_total: float deduction_total: float overtime_total: float locked_by: str locked_at: datetime | None created_at: datetime updated_at: datetime class MonthlyPayrollDetailResponse(BaseModel): run: MonthlyPayrollRunResponse results: list[PayrollResultItem] exceptions: list[PayrollExceptionItem] ``` `PayrollResultItem` 可复用现有 `financial_system/api/schemas/payroll.py` 中的结果 schema,避免重复字段。 **Step 2: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 3: Commit** ```bash git add financial_system/api/schemas/monthly_payroll.py financial_system/api/schemas/__init__.py git commit -m "feat: add monthly payroll schemas" ``` --- ### Task 3.2: 增加月度核算 Repository **Files:** - Create: `financial_system/repositories/monthly_payroll_repository.py` - Modify: `financial_system/repositories/__init__.py` **Step 1: 实现方法** Repository 负责: ```python class MonthlyPayrollRepository: def create_run(...) -> MonthlyPayrollRunORM: ... def get_run(run_id: int) -> MonthlyPayrollRunORM | None: ... def get_run_by_month(salary_month: str) -> MonthlyPayrollRunORM | None: ... def update_run_totals(...) -> None: ... def lock_run(...) -> None: ... def replace_exceptions(...) -> None: ... def list_exceptions(...) -> list[PayrollExceptionORM]: ... ``` **Step 2: 锁定保护** 如果 `monthly_payroll_runs.status == "locked"`,任何重新计算或覆盖结果都必须拒绝。 **Step 3: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 4: Commit** ```bash git add financial_system/repositories/monthly_payroll_repository.py financial_system/repositories/__init__.py git commit -m "feat: add monthly payroll repository" ``` --- ### Task 3.3: 增加异常识别规则 **Files:** - Create: `financial_system/domain/payroll_exceptions.py` **Step 1: 实现纯函数** Create: ```python def detect_payroll_exceptions(results: list[PayrollResult]) -> list[PayrollException]: ... ``` 异常类型: ```text missing_salary_profile missing_employee_match missing_dingtalk_user_id missing_card late_penalty negative_remaining_overtime empty_attendance ``` **Step 2: 规则建议** - `base_pay is None` -> `missing_salary_profile` - `missing_card_count > 0` -> `missing_card` - `penalized_late_count > 0` -> `late_penalty` - `remaining_overtime_hours < 0` -> `negative_remaining_overtime` - `attendance_days == 0` -> `empty_attendance` **Step 3: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 4: Commit** ```bash git add financial_system/domain/payroll_exceptions.py git commit -m "feat: add payroll exception detection" ``` --- ### Task 3.4: 增加月度核算服务 **Files:** - Create: `financial_system/services/monthly_payroll_service.py` - Modify: `financial_system/services/__init__.py` - Modify: `financial_system/api/dependencies.py` **Step 1: 服务职责** `MonthlyPayrollService` 负责: - Excel 导入并创建月度 run。 - 钉钉全量同步并创建月度 run。 - 复用 `PayrollApplicationService` 或直接复用 parser/calculator。 - 生成工资结果。 - 生成异常记录。 - 更新 run 汇总金额。 - 锁定工资。 - 导出工资文件。 **Step 2: 状态机** 状态只保留必要值: ```text draft 草稿/已导入 calculated 已计算 reviewed 已复核 locked 已锁定 failed 失败 ``` **Step 3: 锁定规则** 锁定后: - 不允许重新计算。 - 不允许覆盖结果。 - 允许导出。 - 操作日志必须记录锁定人。 **Step 4: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 5: Commit** ```bash git add financial_system/services/monthly_payroll_service.py financial_system/services/__init__.py financial_system/api/dependencies.py git commit -m "feat: add monthly payroll service" ``` --- ### Task 3.5: 增加月度核算 API **Files:** - Create: `financial_system/api/routers/monthly_payroll.py` - Modify: `financial_system/api/app.py` **Step 1: 新增路由** Create router prefix: ```python router = APIRouter(prefix="/api/payroll/monthly", tags=["monthly-payroll"]) ``` Endpoints: ```text GET /api/payroll/monthly/runs?month=YYYY-MM GET /api/payroll/monthly/runs/{run_id} POST /api/payroll/monthly/excel POST /api/payroll/monthly/dingtalk POST /api/payroll/monthly/runs/{run_id}/recalculate POST /api/payroll/monthly/runs/{run_id}/lock GET /api/payroll/monthly/runs/{run_id}/export ``` **Step 2: 权限** - 查看:`PERMISSION_MONTHLY_PAYROLL_VIEW` - 计算:`PERMISSION_MONTHLY_PAYROLL_CALCULATE` - 锁定:`PERMISSION_MONTHLY_PAYROLL_LOCK` - 导出:`PERMISSION_MONTHLY_PAYROLL_EXPORT` **Step 3: 操作日志** 记录以下动作: ```text monthly_payroll.view monthly_payroll.excel.import monthly_payroll.dingtalk.calculate monthly_payroll.recalculate monthly_payroll.lock monthly_payroll.export ``` **Step 4: 注册路由** 在 `financial_system/api/app.py` 导入并 include。 **Step 5: 编译验证** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 6: Commit** ```bash git add financial_system/api/routers/monthly_payroll.py financial_system/api/app.py git commit -m "feat: add monthly payroll api" ``` --- ## 阶段 4:前端信息架构和 API ### Task 4.1: 重组菜单展示 **Files:** - Modify: `frontend/src/components/SidebarNav.vue` - Modify: `frontend/src/assets/styles.css` **Step 1: 分组菜单** 将菜单视觉分组为: ```text 工作台 实时考勤 月度核算 工资核算 计算记录 提成录入 员工薪资 员工维护 薪资档案 组织架构 报表分析 工资报表 系统管理 规则配置 用户管理 操作日志 ``` **Step 2: 收起侧栏体验** 收起时隐藏分组文字,只保留图标;悬停显示 `title`。保持现在的平滑过渡变量: ```css --motion-duration: 280ms; --motion-easing: cubic-bezier(0.22, 1, 0.36, 1); ``` **Step 3: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 4: Commit** ```bash git add frontend/src/components/SidebarNav.vue frontend/src/assets/styles.css git commit -m "feat: group sidebar navigation" ``` --- ### Task 4.2: 增加前端 API 类型 **Files:** - Modify: `frontend/src/api/types.ts` - Create: `frontend/src/api/realtimeAttendance.ts` - Create: `frontend/src/api/monthlyPayroll.ts` **Step 1: 增加类型** 在 `types.ts` 增加: ```typescript export interface RealtimeAttendanceSummary { ... } export interface TodayAttendanceItem { ... } export interface RealtimeAttendanceResponse { ... } export interface MonthlyPayrollRun { ... } export interface PayrollException { ... } export interface MonthlyPayrollDetailResponse { ... } ``` **Step 2: 增加 API 方法** Create `realtimeAttendance.ts`: ```typescript export function getTodayAttendance(date: string): Promise { ... } export function syncRealtimeAttendance(date: string): Promise { ... } ``` Create `monthlyPayroll.ts`: ```typescript export function listMonthlyRuns(month?: string): Promise { ... } export function getMonthlyRun(runId: number): Promise { ... } export function calculateMonthlyFromExcel(...): Promise { ... } export function calculateMonthlyFromDingTalk(month: string): Promise { ... } export function lockMonthlyRun(runId: number): Promise { ... } export function exportMonthlyRun(runId: number): Promise { ... } ``` **Step 3: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 4: Commit** ```bash git add frontend/src/api/types.ts frontend/src/api/realtimeAttendance.ts frontend/src/api/monthlyPayroll.ts git commit -m "feat: add realtime and monthly payroll api clients" ``` --- ## 阶段 5:实时考勤页面 ### Task 5.1: 创建实时考勤页面 **Files:** - Create: `frontend/src/views/RealtimeAttendanceView.vue` - Modify: `frontend/src/router/index.ts` **Step 1: 页面布局** 页面结构: ```text 顶部:今日考勤与薪资预估 / 日期选择 / 同步钉钉 / 自动刷新开关 摘要:应到人数、已打卡、未打卡、迟到、请假、预估加班 主表:员工今日考勤 右侧抽屉:员工本月明细 ``` **Step 2: 主表字段** ```text 员工 部门/岗位 上班打卡 下班打卡 今日状态 迟到分钟 缺卡 请假工时 今日加班 本月剩余加班 本月预估实发 ``` **Step 3: 文案** 页面必须展示: ```text 预估金额,最终以月度核算锁定结果为准 ``` **Step 4: 视觉要求** - 不使用大面积营销式卡片。 - 摘要卡片压扁,适合后台扫描。 - 表格上方保留紧凑筛选栏。 - 员工明细使用右侧抽屉,不跳页面。 **Step 5: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 6: Commit** ```bash git add frontend/src/views/RealtimeAttendanceView.vue frontend/src/router/index.ts git commit -m "feat: add realtime attendance view" ``` --- ### Task 5.2: 接入实时考勤页面数据 **Files:** - Modify: `frontend/src/views/RealtimeAttendanceView.vue` **Step 1: 加载数据** 页面 mounted 后默认请求今天: ```typescript const today = new Date().toISOString().slice(0, 10); await getTodayAttendance(today); ``` **Step 2: 同步钉钉** 点击 `同步钉钉` 调用: ```typescript await syncRealtimeAttendance(selectedDate.value); ``` 同步时按钮显示 loading,成功后刷新摘要和表格。 **Step 3: 错误处理** 钉钉未配置时显示: ```text 钉钉配置缺失,请先在 config/app_settings.json 中配置 app_key 和 app_secret ``` **Step 4: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 5: Commit** ```bash git add frontend/src/views/RealtimeAttendanceView.vue git commit -m "feat: connect realtime attendance data" ``` --- ## 阶段 6:月度核算中心页面 ### Task 6.1: 创建月度核算中心页面 **Files:** - Create: `frontend/src/views/MonthlyPayrollView.vue` - Modify: `frontend/src/router/index.ts` **Step 1: 页面结构** ```text 顶部:月份选择 / 当前状态 / 同步钉钉 / 导入 Excel / 导出 / 锁定 步骤条:数据导入 -> 考勤转换 -> 异常处理 -> 工资计算 -> 复核锁定 摘要条:员工数、应发、实发、扣款、剩余加班 主表:员工工资核算结果 右侧抽屉:员工每日考勤和工资拆分 异常面板:缺薪资档案、缺卡、迟到扣款、未匹配员工 ``` **Step 2: 状态文案** ```text draft: 草稿 calculated: 已计算 reviewed: 已复核 locked: 已锁定 failed: 失败 ``` **Step 3: 锁定按钮** `locked` 状态下禁用重新计算和导入,只保留导出。 **Step 4: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 5: Commit** ```bash git add frontend/src/views/MonthlyPayrollView.vue frontend/src/router/index.ts git commit -m "feat: add monthly payroll center view" ``` --- ### Task 6.2: 接入月度核算 API **Files:** - Modify: `frontend/src/views/MonthlyPayrollView.vue` **Step 1: 默认月份** 默认当前月份: ```typescript const selectedMonth = ref(new Date().toISOString().slice(0, 7)); ``` **Step 2: 加载 run** 进入页面或月份变化时加载: ```typescript await listMonthlyRuns(selectedMonth.value); ``` 如果已有 run,自动打开最新 run;否则显示空状态和操作按钮。 **Step 3: Excel 导入** 导入按钮使用隐藏 file input,不让用户填配置路径。 **Step 4: 钉钉计算** 点击 `同步钉钉并计算`,后端自动读取在职员工 `dingtalk_user_id`。 **Step 5: 锁定确认** 锁定前弹窗确认: ```text 锁定后本月工资不能重新计算,只能导出。确认锁定? ``` **Step 6: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 7: Commit** ```bash git add frontend/src/views/MonthlyPayrollView.vue git commit -m "feat: connect monthly payroll center api" ``` --- ## 阶段 7:工作台改造 ### Task 7.1: 工作台改为流程总览 **Files:** - Modify: `frontend/src/views/DashboardView.vue` - Modify: `frontend/src/assets/styles.css` **Step 1: 改成经营总览** 工作台展示: ```text 今日考勤状态 本月工资预估 本月核算状态 待处理异常 最近同步任务 ``` **Step 2: 快捷入口** 保留按钮: ```text 进入实时考勤 进入月度核算 提成录入 员工维护 ``` **Step 3: 移除假图表** 现在 `chartBars` 是静态假数据。要么接后端报表,要么先移除,避免误导。 **Step 4: 构建验证** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 5: Commit** ```bash git add frontend/src/views/DashboardView.vue frontend/src/assets/styles.css git commit -m "feat: redesign dashboard around payroll workflow" ``` --- ## 阶段 8:文档与验证 ### Task 8.1: 更新 README **Files:** - Modify: `README.md` - Modify: `frontend/README.md` **Step 1: README 增加模块说明** 补充: ```text 实时考勤看板 月度核算中心 薪资预估和正式工资的区别 锁定规则 新增 SQL 升级脚本 ``` **Step 2: 更新运行说明** 说明后端仍然使用: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python main.py ``` 前端仍然使用: ```bash cd frontend npm run dev ``` **Step 3: Commit** ```bash git add README.md frontend/README.md git commit -m "docs: update payroll center documentation" ``` --- ### Task 8.2: 全量验证 **Files:** - No source edits unless verification fails. **Step 1: 后端编译** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system ``` Expected: PASS。 **Step 2: 前端构建** Run: ```bash cd frontend npm run build ``` Expected: PASS。 **Step 3: 启动后端** Run: ```bash /Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python main.py ``` Expected: 后端启动成功,`/health` 返回正常。 **Step 4: 启动前端** Run: ```bash cd frontend npm run dev ``` Expected: 前端启动成功。 **Step 5: 浏览器验收** 检查: ```text /attendance/realtime /payroll/monthly /dashboard /system/employees /system/salary-profiles /payroll/commissions ``` 验收点: - 菜单显示分组合理。 - 实时考勤能进入,未配置钉钉时提示明确。 - 月度核算能进入,Excel 导入入口存在。 - 锁定状态不会允许重新计算。 - 侧栏收起/展开仍然平滑。 - 控制台无 error/warn。 **Step 6: Commit** 若修复了验证问题,按实际文件提交: ```bash git add git commit -m "fix: stabilize payroll center flow" ``` --- ## 实施顺序建议 优先级从高到低: 1. 阶段 1:数据库和菜单权限。 2. 阶段 2:实时考勤后端。 3. 阶段 5:实时考勤前端。 4. 阶段 3:月度核算后端。 5. 阶段 6:月度核算前端。 6. 阶段 7:工作台改造。 7. 阶段 8:文档和全量验证。 这样可以先让你看到“今天打卡和实时薪资预估”的效果,再继续完善月底正式核算。 ## 风险点 - 钉钉接口真实字段可能和当前 `DingTalkAttendanceAdapter` 的假设不完全一致,需要用真实返回样例校准。 - 实时薪资只能作为预估,不能覆盖正式工资结果。 - 包月员工的“本月预估工资”要确认是否按自然日、工作日进度、还是直接展示已产生工资。 - 计件员工如果没有每日计件数据,只能显示已录入计件金额,不能凭考勤自动估算。 - 锁定工资后是否允许管理员解锁,需要单独确认。当前计划默认不提供解锁。 ## 后续可选增强 - 自动同步定时任务:每天 09:30、12:00、18:30 同步钉钉。 - 异常提醒:缺卡、迟到、未绑定钉钉 userId 自动出现在工作台。 - 工资条:锁定后生成员工工资条。 - 审批流:人事核算、财务复核、老板确认。 - 导入计件数据:为计件员工增加单独的产量录入或 Excel 导入。