financial_system/docs/plans/2026-06-18-monthly-payroll-center.md
2026-06-22 13:23:04 +08:00

30 KiB
Raw Blame History

月度核算中心与实时考勤看板 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 负责纯计算。新增实时考勤和月度核算模块时,复用现有 PayrollCalculatorMonthlySummaryParserDingTalkAttendanceAdapterattendance_recordpayroll_results 等能力,只补齐同步批次、实时预估、月度核算状态和异常记录。

Tech Stack: Python 3 / FastAPI / SQLAlchemy / MySQL / openpyxl / Vue 3 / Pinia / Vue Router / TypeScript / Vite / lucide-vue。


目标业务流

实时考勤看板
  -> 读取在职员工和钉钉 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:

git status --short

Expected: 确认哪些文件已有用户改动。不要回滚任何非本任务改动。

Step 2: 编译当前后端

Run:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: financial_system 编译成功。

Step 3: 构建当前前端

Run:

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 注释:

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 中新增:

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.sqlinit_mysql.sql 中增加建表语句。新增 upgrade_20260618_monthly_payroll_center.sql,包含 CREATE TABLE IF NOT EXISTS,可对已有库安全执行。

Step 4: 编译验证

Run:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 5: Commit

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 增加:

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: 增加菜单

新增菜单:

"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 先注册页面:

{
  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 中增加图标映射:

attendance_realtime: CalendarClock,
monthly_payroll: Calculator,

Step 5: 验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 6: Commit

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:

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 3: Commit

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
  • 查询某日考勤记录。
  • 查询某月薪资预估。

核心方法:

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 4: Commit

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_recordsalary_preview
  • 输出今日考勤列表和汇总。

Step 2: 保持预估语义

返回字段命名使用 estimated_*,页面文案必须展示“预估金额,最终以月度核算锁定结果为准”。

Step 3: 缺少钉钉配置

复用 PayrollApplicationService._dingtalk_settings() 的逻辑,或者抽出公共 helper。缺少 app_key/app_secret 时返回 400提示用户修改 config/app_settings.json

Step 4: 编译验证

Run:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 5: Commit

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:

router = APIRouter(prefix="/api/attendance/realtime", tags=["realtime-attendance"])

Endpoints:

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: 操作日志

同步成功记录:

module=attendance
action=attendance.realtime.sync
target_type=attendance_sync_job

查看成功记录:

module=attendance
action=attendance.realtime.view

Step 4: 注册路由

financial_system/api/app.py 导入并 include_router(realtime_attendance.router)

Step 5: 编译验证

Run:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 6: Commit

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:

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 3: Commit

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 负责:

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 4: Commit

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:

def detect_payroll_exceptions(results: list[PayrollResult]) -> list[PayrollException]:
    ...

异常类型:

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 4: Commit

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: 状态机

状态只保留必要值:

draft       草稿/已导入
calculated  已计算
reviewed    已复核
locked      已锁定
failed      失败

Step 3: 锁定规则

锁定后:

  • 不允许重新计算。
  • 不允许覆盖结果。
  • 允许导出。
  • 操作日志必须记录锁定人。

Step 4: 编译验证

Run:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 5: Commit

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:

router = APIRouter(prefix="/api/payroll/monthly", tags=["monthly-payroll"])

Endpoints:

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: 操作日志

记录以下动作:

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 6: Commit

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: 分组菜单

将菜单视觉分组为:

工作台
实时考勤
月度核算
  工资核算
  计算记录
  提成录入
员工薪资
  员工维护
  薪资档案
  组织架构
报表分析
  工资报表
系统管理
  规则配置
  用户管理
  操作日志

Step 2: 收起侧栏体验

收起时隐藏分组文字,只保留图标;悬停显示 title。保持现在的平滑过渡变量:

--motion-duration: 280ms;
--motion-easing: cubic-bezier(0.22, 1, 0.36, 1);

Step 3: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 4: Commit

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 增加:

export interface RealtimeAttendanceSummary { ... }
export interface TodayAttendanceItem { ... }
export interface RealtimeAttendanceResponse { ... }
export interface MonthlyPayrollRun { ... }
export interface PayrollException { ... }
export interface MonthlyPayrollDetailResponse { ... }

Step 2: 增加 API 方法

Create realtimeAttendance.ts:

export function getTodayAttendance(date: string): Promise<RealtimeAttendanceResponse> { ... }
export function syncRealtimeAttendance(date: string): Promise<RealtimeAttendanceResponse> { ... }

Create monthlyPayroll.ts:

export function listMonthlyRuns(month?: string): Promise<MonthlyPayrollRun[]> { ... }
export function getMonthlyRun(runId: number): Promise<MonthlyPayrollDetailResponse> { ... }
export function calculateMonthlyFromExcel(...): Promise<MonthlyPayrollDetailResponse> { ... }
export function calculateMonthlyFromDingTalk(month: string): Promise<MonthlyPayrollDetailResponse> { ... }
export function lockMonthlyRun(runId: number): Promise<MonthlyPayrollRun> { ... }
export function exportMonthlyRun(runId: number): Promise<void> { ... }

Step 3: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 4: Commit

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: 页面布局

页面结构:

顶部:今日考勤与薪资预估 / 日期选择 / 同步钉钉 / 自动刷新开关
摘要:应到人数、已打卡、未打卡、迟到、请假、预估加班
主表:员工今日考勤
右侧抽屉:员工本月明细

Step 2: 主表字段

员工
部门/岗位
上班打卡
下班打卡
今日状态
迟到分钟
缺卡
请假工时
今日加班
本月剩余加班
本月预估实发

Step 3: 文案

页面必须展示:

预估金额,最终以月度核算锁定结果为准

Step 4: 视觉要求

  • 不使用大面积营销式卡片。
  • 摘要卡片压扁,适合后台扫描。
  • 表格上方保留紧凑筛选栏。
  • 员工明细使用右侧抽屉,不跳页面。

Step 5: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 6: Commit

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 后默认请求今天:

const today = new Date().toISOString().slice(0, 10);
await getTodayAttendance(today);

Step 2: 同步钉钉

点击 同步钉钉 调用:

await syncRealtimeAttendance(selectedDate.value);

同步时按钮显示 loading成功后刷新摘要和表格。

Step 3: 错误处理

钉钉未配置时显示:

钉钉配置缺失,请先在 config/app_settings.json 中配置 app_key 和 app_secret

Step 4: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 5: Commit

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: 页面结构

顶部:月份选择 / 当前状态 / 同步钉钉 / 导入 Excel / 导出 / 锁定
步骤条:数据导入 -> 考勤转换 -> 异常处理 -> 工资计算 -> 复核锁定
摘要条:员工数、应发、实发、扣款、剩余加班
主表:员工工资核算结果
右侧抽屉:员工每日考勤和工资拆分
异常面板:缺薪资档案、缺卡、迟到扣款、未匹配员工

Step 2: 状态文案

draft: 草稿
calculated: 已计算
reviewed: 已复核
locked: 已锁定
failed: 失败

Step 3: 锁定按钮

locked 状态下禁用重新计算和导入,只保留导出。

Step 4: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 5: Commit

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: 默认月份

默认当前月份:

const selectedMonth = ref(new Date().toISOString().slice(0, 7));

Step 2: 加载 run

进入页面或月份变化时加载:

await listMonthlyRuns(selectedMonth.value);

如果已有 run自动打开最新 run否则显示空状态和操作按钮。

Step 3: Excel 导入

导入按钮使用隐藏 file input不让用户填配置路径。

Step 4: 钉钉计算

点击 同步钉钉并计算,后端自动读取在职员工 dingtalk_user_id

Step 5: 锁定确认

锁定前弹窗确认:

锁定后本月工资不能重新计算,只能导出。确认锁定?

Step 6: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 7: Commit

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: 改成经营总览

工作台展示:

今日考勤状态
本月工资预估
本月核算状态
待处理异常
最近同步任务

Step 2: 快捷入口

保留按钮:

进入实时考勤
进入月度核算
提成录入
员工维护

Step 3: 移除假图表

现在 chartBars 是静态假数据。要么接后端报表,要么先移除,避免误导。

Step 4: 构建验证

Run:

cd frontend
npm run build

Expected: PASS。

Step 5: Commit

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 增加模块说明

补充:

实时考勤看板
月度核算中心
薪资预估和正式工资的区别
锁定规则
新增 SQL 升级脚本

Step 2: 更新运行说明

说明后端仍然使用:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python main.py

前端仍然使用:

cd frontend
npm run dev

Step 3: Commit

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:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python -m compileall financial_system

Expected: PASS。

Step 2: 前端构建

Run:

cd frontend
npm run build

Expected: PASS。

Step 3: 启动后端

Run:

/Users/jiaolongyan/miniconda3/envs/Financial_System/bin/python main.py

Expected: 后端启动成功,/health 返回正常。

Step 4: 启动前端

Run:

cd frontend
npm run dev

Expected: 前端启动成功。

Step 5: 浏览器验收

检查:

/attendance/realtime
/payroll/monthly
/dashboard
/system/employees
/system/salary-profiles
/payroll/commissions

验收点:

  • 菜单显示分组合理。
  • 实时考勤能进入,未配置钉钉时提示明确。
  • 月度核算能进入Excel 导入入口存在。
  • 锁定状态不会允许重新计算。
  • 侧栏收起/展开仍然平滑。
  • 控制台无 error/warn。

Step 6: Commit

若修复了验证问题,按实际文件提交:

git add <changed-files>
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 导入。