feat(attendance): add anomaly alert banner showing consecutive absences and frequent lates

This commit is contained in:
2026-07-06 14:27:21 +08:00
parent da69545f74
commit beeb8cb905
2 changed files with 111 additions and 17 deletions

View File

@@ -0,0 +1,98 @@
# 列表页筛选补全 + 考勤预警 + 同步对接
> **For agentic workers:** Use subagent-driven-development. Steps use checkbox syntax.
**Goal:** Add missing filter dropdowns to 7 list pages, implement attendance anomaly detection, and wire up real DingTalk/WeCom sync API calls.
**Architecture:** Frontend: add Ant Design `<Select>` + `<DatePicker>` components to existing filter bars. Backend: add anomaly detection query to AttendanceService, implement sync stubs.
**Tech Stack:** React 19 + Ant Design 6 + NestJS 11 + TypeORM
## Global Constraints
- Follow existing filter patterns (Input.Search + Select + Space wrap)
- Each filter change resets to page 1
- Status filter options must match entity `status` field values
- Sync stubs must check env vars before attempting API calls
---
### Task 1: Students Page — Status + Tenant Filter
**Files:**
- Modify: `apps/admin/src/pages/Students/index.tsx`
- [ ] Add `filterStatus` state + `<Select>` dropdown (active/graduated/withdrawn/archived)
- [ ] Add `filterTenantId` state + `<Select>` dropdown (loaded from `/tenants`)
- [ ] Wire `fetchData()` to pass `status` + `tenantId` query params
- [ ] Verify: select status → list filters, select tenant → list filters
---
### Task 2: Rooms Page — Status Filter
**Files:**
- Modify: `apps/admin/src/pages/Rooms/index.tsx`
- [ ] Add `filterStatus` + `<Select>` (available/in_use/maintenance/archived)
- [ ] Wire to API query param
---
### Task 3: Occupancies Page — Status + Date Range
**Files:**
- Modify: `apps/admin/src/pages/Occupancies/index.tsx`
- [ ] Add `filterStatus` (checked_in/checked_out)
- [ ] Add `<RangePicker>` for check-in date range
- [ ] Wire to API params
---
### Task 4: Remaining Pages — Status Filters
**Files:**
- Modify: `apps/admin/src/pages/Classrooms/index.tsx` — status dropdown
- Modify: `apps/admin/src/pages/Expenses/index.tsx` — status filter
- Modify: `apps/admin/src/pages/Tenants/index.tsx` — status dropdown
- [ ] Each page: add `<Select>` with appropriate status options
- [ ] Wire to API params
---
### Task 5: Bills Page — Expense Type Filter
**Files:**
- Modify: `apps/admin/src/pages/Bills/index.tsx`
- [ ] Add `filterExpenseType` + `<Select>` with water/electricity/cleaning/rent/other
- [ ] Wire to API
---
### Task 6: Attendance Anomaly Detection
**Files:**
- Modify: `apps/server/src/attendance/attendance.service.ts` — add `getAnomalies()` method
- Modify: `apps/server/src/attendance/attendance.controller.ts` — add `GET /attendance-records/anomalies`
- Modify: `apps/admin/src/pages/Attendance/index.tsx` — add Alert banner
- [ ] Backend: `getAnomalies()` queries students with ≥3 consecutive absences or ≥5 lates in 7 days
- [ ] Backend: returns `{ studentId, studentName, type: 'consecutive_absence'|'frequent_late', count, dateRange }`
- [ ] Frontend: `<Alert>` banner at top of page showing anomaly count
- [ ] Frontend: click to filter records for that student
---
### Task 7: Sync Stubs → Real Implementation
**Files:**
- Modify: `apps/server/src/sync/sync.service.ts`
- [ ] Check `process.env.DINGTALK_APP_KEY` before attempting ding sync
- [ ] Check `process.env.WECOM_CORP_ID` before attempting wecom sync
- [ ] Log actionable messages: "DingTalk not configured, set DINGTALK_APP_KEY"
- [ ] If configured, attempt real API calls with proper error handling
- [ ] Record sync counts in SyncLog