Commit Graph

43 Commits

Author SHA1 Message Date
kkfluous
1d9f4cb43d feat(scheduling): history view, execute/cancel lifecycle, CSV export, 7d trend
- Add 调度记录 modal: lists notifications by status, supports 标记已执行 (with
  after-mileage + notes) and 取消 for open records
- Add CSV export of filtered suggestions (UTF-8 BOM for Excel); top candidate
  per row picked by same-region > can-qualify preference
- Compute customer 7-day average alongside 30-day baseline in a single query;
  show trend indicator (up/down/flat) next to 客户日均 in list and detail card

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 23:47:31 +08:00
kkfluous
3ef0d4edfa feat(scheduling): persist notifications, batch notify flow, dedup protection
- Add tab_scheduling_notifications table with bootstrap via ensureSchedulingTables()
- Notify endpoint rewritten: dedup by (suggestion_id, candidate_plate), history list, PATCH /:id for execute/cancel lifecycle
- Batch notify endpoint returns success/skipped/failed counts
- Suggestions response now carries notificationId + notificationStatus per candidate (joined from active-notification map)
- UI: select mode with checkboxes, floating action bar, confirmation modal listing each swap; already-notified items are dimmed and skipped
- Detail view badges show sent/executed state, preventing duplicate notify

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 23:43:21 +08:00
kkfluous
31716c6547 refactor(scheduling): shared types, structured reason, cross-region candidates
- Extract shared types to src/shared/scheduling/types.ts (client/server both re-export)
- Convert SchedulingSuggestion.reason from string to structured { lines, conclusion }
- Remove hard region filter; algorithm keeps cross-region candidates with isSameRegion flag
- SuggestionDetail renders same-region vs cross-region sections with a divider
- Close detail modal when selected suggestion no longer exists in data
- Unify estimatedGain definition (strict canQualifyAfterSwap) between algorithm and API layers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 23:36:38 +08:00
kkfluous
335282a2c3 feat(scheduling): add km unit to 客户日均; move 年度考核 to top-right of list item
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 23:24:25 +08:00
kkfluous
dfc32c4485 fix(scheduling): rename 日均→客户日均 to avoid ambiguity
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 23:07:49 +08:00
kkfluous
ceed067807 refactor(scheduling): re-layout list items — left group (dept/manager/customer) + right group (daily/rate)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 23:06:49 +08:00
kkfluous
2f11afc25f fix(scheduling): shorten department name by removing 业务 prefix
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 23:05:40 +08:00
kkfluous
9f781c766a feat(scheduling): rename 完成→年度达标, add sort by 客户日均/年度达标 to list
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 23:03:59 +08:00
kkfluous
8664317852 feat(scheduling): show department and manager in list items and detail card
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 23:02:03 +08:00
kkfluous
c3de4ebaf5 refactor(scheduling): redesign current vehicle card to match candidate card style
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 23:00:22 +08:00
kkfluous
aa9a29fed8 fix(scheduling): use each candidate's own daysLeft for prediction
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Different assessment targets have different end dates. Previously all
candidates used the current vehicle's daysLeft, causing wrong predictions.

Now each inventory vehicle computes its own daysLeft from its assessment
target's current_year_assessment_end_date. predictedAfterSwap uses the
candidate's own daysLeft instead of the current vehicle's.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:58:47 +08:00
kkfluous
a52a77f3a2 feat(scheduling): batch filter as multi-select pills instead of dropdown
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:54:01 +08:00
kkfluous
9012a955b8 feat(scheduling): add 剩余xx天 to candidate header
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:52:50 +08:00
kkfluous
caff78c5f3 fix(scheduling): rename 预估年终 to 考核期结束预估
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:51:37 +08:00
kkfluous
f6f872d2ce fix(scheduling): remove duplicate mileage text, keep only metrics row
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:50:42 +08:00
kkfluous
dbefb90089 feat(scheduling): add metrics row (当前/预估年终/考核) for current vehicle
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:49:43 +08:00
kkfluous
db568c1ebb fix(scheduling): rename 全部批次→全部, reorder metrics to 当前/替换后预计/考核
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:48:26 +08:00
kkfluous
ba6a38973d feat(scheduling): add batch filter and sort controls for candidate list
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Batch dropdown filter (全部批次 / per target name)
- Sort by 替换后预计 (asc/desc toggle)
- Sort by 当前里程 (asc/desc toggle)
- Active sort button highlighted in blue
- Display count shows filtered/total (e.g. "3/12 辆")

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:46:42 +08:00
kkfluous
7aa0d961ce feat(scheduling): show all candidates instead of top 5, update section title
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:44:51 +08:00
kkfluous
4f02a54d38 fix(scheduling): move region to header as pin badge, remove from metrics grid
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:39:31 +08:00
kkfluous
073496cd44 fix(scheduling): reorder candidate metrics to 区域/考核/当前/替换后预计, remove 缺口
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:38:25 +08:00
kkfluous
bea67b6710 fix(scheduling): remove decimals from km display (1,990.2 → 1,990)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:37:14 +08:00
kkfluous
d0984a430b refactor(scheduling): improve reason text, fix classification, polish detail view
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Classification: qualified requires actual completionRate >= 100% (not just predicted)
- Reason text: structured two-column layout (客户日均 | 考核周期剩余)
- Conclusion line in red bold (预估无法达标,需替换 / 已达标,建议换上未达标车辆)
- Remove verbose subtitle from candidate section
- Remove redundant middle line (预估考核期里程 vs 考核里程)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:32:50 +08:00
kkfluous
b3a6beb26b fix(scheduling): update card titles per user request
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:12:19 +08:00
kkfluous
dd03157804 refactor(scheduling): simplify card labels for clarity
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 22:09:27 +08:00
kkfluous
fb89c9beed fix(scheduling): change 辆 to 干预 in suggestion list
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2026-04-16 21:57:35 +08:00
kkfluous
25199b507c refactor(scheduling): simplify SwapPreview layout, remove verbose reason
- Remove type badge, reason section — too verbose
- Two clean white cards connected by arrow (swap diagram)
- Result section: predicted mileage, target, conclusion badge
- Tighter spacing, no redundant labels
- Professional tone, no childish wording

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:45:01 +08:00
kkfluous
6a3a5ba319 feat(scheduling): add full-screen SwapPreview for screenshot sharing
New SwapPreview component replaces direct "发送通知" button:
- Full-screen white background for clean screenshots
- Swap diagram: current vehicle → arrow → replacement vehicle
- Replacement reason section
- Post-swap prediction: predicted mileage, target, conclusion
- "发送替换通知" button at bottom
- Candidate button in detail modal changed to "查看替换方案 →"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:43:18 +08:00
kkfluous
afec75a1cc fix(scheduling): rescue candidates should be close-to-qualifying, not zero-mileage
For rescue_hopeless (换走) scenario, completely rethought candidate logic:

Before: showed biggest-gap candidates (0 mileage) → pointless, customer can't
  drive them to target
After: prioritize candidates where customer's remaining driving can push them
  over the target line (canQualifyAfterSwap), sorted by smallest gap first

Example: customer drives 178km/day × 57 days = ~1万km remaining.
- 粤AGR6869 (缺口 1990km) → 换后 3.8万, 可达标  (shown first)
- 浙FF58720 (缺口 6万km) → 换后 1万, 远不达标 (no longer shown first)

Also updated reason text to explain the math:
"该客户剩余57天还能跑约1万km,足以帮缺口小的车冲线"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:36:53 +08:00
kkfluous
81305be2df feat(scheduling): replace spinner with skeleton loading placeholders
- Full-page skeleton on initial load: card placeholders + list row placeholders
- List skeleton on refresh: 6 rows with pulse animation
- Skeleton blocks match actual layout (color bar, plate, badges, info line)
- Uses Tailwind animate-pulse for smooth loading effect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:30:23 +08:00
kkfluous
64f47d5ad6 fix(scheduling): truncate long customer names, prevent list item wrap
- Customer name in list items: truncate with max-w-[40%]
- Daily km and completion rate: flex-shrink-0 to stay on same line

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:28:30 +08:00
kkfluous
9398688829 feat(scheduling): add department/manager filters, refine color palette
- Add department and manager fields to backend types and suggestions API
- Add department/manager to advanced filter panel
- Refine card colors: orange (换下) / blue (换走) / dark slate (全部)
- Selected card uses solid bg color, inactive uses gradient
- Batch pills use dark slate, confirm button uses dark slate
- Background changed to #F0F4F8 for subtle cool tone

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:28:04 +08:00
kkfluous
48fa3bc73f refactor(scheduling): rewrite terminology to match core business logic
Core story: 里程高的车换下来,里程少的车换上去。

- Summary cards: "里程高·需换下" / "里程低·需换走" / "替换建议"
- List tags: "换下" (amber) / "换走" (blue) with matching color bars
- Detail modal title: "里程高·换下此车" / "里程低·换走此车"
- Candidate section: explains WHY these vehicles are recommended
  - 换下: "以下车辆里程缺口大,换到该高里程客户处可加速达标"
  - 换走: "以下车辆里程已充足,可调给当前客户,将此车换走给高里程客户冲刺"
- Reason text: states current situation + clear action recommendation
  with specific numbers (已跑, 缺口, 日均, 完成率)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:23:35 +08:00
kkfluous
1a5a1c1514 feat(scheduling): add advanced filter panel matching prototype
- Filter icon in list header with active count badge
- Expandable filter panel: plate search, region select, vehicle type select, customer select
- FilterSelect component with search for long option lists
- Active filter tags shown as removable pills below header
- Temp/confirmed filter pattern (edit → confirm/cancel)
- Result count displayed when filters active

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:18:02 +08:00
kkfluous
73080a605d refactor(scheduling): polish overall color scheme and UX
- Modal header: unified dark slate-800 with directional icon (↓ rescue, ↑ release)
- Modal click-outside to close
- Candidate metrics: table-style with bg-slate-50 + dividers, more scannable
- Send button: dark slate instead of blue (avoids color overload)
- Reason section: warm amber accent
- Consistent font sizing and spacing throughout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:13:12 +08:00
kkfluous
6f7555a407 feat(scheduling): make summary cards clickable filters + refine color scheme
- Cards filter suggestions by type (已达标/无望达标/全部)
- Toggle: click active card again to reset to all
- Default: white bg + gray border; active: colored bg + ring
- Batch selector: dark pills instead of blue
- Refresh button moved into list header
- Reset type filter when switching batch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:12:02 +08:00
kkfluous
bcbeb64e28 fix(scheduling): use current year mileage for consistent data display
- Add currentYearMileage to SchedulingVehicleInfo (backend + frontend)
- Compute completionRate as currentYearMileage/yearTarget (year-based)
  instead of using overall completion_rate from DB
- Display "本年已跑" instead of "累计" in detail modal
- Fix reason text to show year completion rate

Before: 累计 4.6万, 考核 3.0万, 完成率 12.1% (mismatched periods)
After:  本年已跑 8.3万, 考核 3.0万, 完成率 275% (consistent year-based)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:08:29 +08:00
kkfluous
6ee811c937 refactor(scheduling): optimize UI for clarity and information density
- Summary cards: white bg + color border, remove icons, more compact
- SuggestionList: replace badge stacking with compact 2-line layout,
  use color bars for priority, fix completion rate format (0.16 → 16.4%)
- SuggestionDetail: bottom-sheet on mobile, compact inline metrics
  instead of grid cards, reduce vertical space per candidate
- Follows ui-ux-pro-max Data-Dense Dashboard guidelines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:04:26 +08:00
kkfluous
495f4bf44f feat(scheduling): add 本年考核 field to candidate cards and rename 年度目标 to 本年考核
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:01:01 +08:00
kkfluous
2e82a30893 feat(scheduling): add SuggestionDetail modal with candidate comparison
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 20:25:58 +08:00
kkfluous
9c005bebc8 feat(scheduling): add SuggestionList component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 20:25:21 +08:00
kkfluous
82ee7f5480 feat(scheduling): add SchedulingModule main entry component
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 20:25:13 +08:00
kkfluous
569b5ea349 feat(scheduling): add frontend types and API client
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 20:20:23 +08:00