profile.vue only rendered fan level digit, hiding the fact that
fans level up via accumulated exhibition hours (6h/level, cap 20),
not login/task experience. Users saw "LV X" without "X more
hours to next level", so upgrades felt invisible.
- backend: surface exhibition_hours / next_level_hours on
CurrentIdentityDTO via a new loadLevelProgress helper in
user_controller (read-only, no proto regen, no service
surface change). Full-level responses set next_level_hours =
exhibition_hours so the client can derive progress=1.
- frontend: split level-box into base track + gold fill + text
overlay; width bound to progressRatio with 0.4s transition.
Adds "距 LV X+1 还差 N 小时" hint and MAX indicator for
full-level users.