feat(records): 训练勋章 UI 改造

- 勋章图标从 emoji 改为矢量 SVG 线性图标(utils/icons.js 新增 bolt/moon/diamond 路径及 white 变体)
- 命名改为累计语义(一周累计/半月累计/月度累计/双月累计/百日累计),并标注"非连续打卡"
- 进度条改回等距节点,解锁时填充正好抵达节点、满级满格
- 新增单枚解锁庆祝:持久化已见解锁集合,进入页面弹 toast + 节点 pop 动画
- 已解锁节点常驻显示勋章名 + 右上角 ✓ 角标,直观体现"已拥有"
- utils/storage.js 新增 totalDays(累计去重训练日),为勋章统计提供数据源
This commit is contained in:
2026-07-28 16:25:55 +08:00
parent 75bad477b1
commit c5ae332cbe
6 changed files with 316 additions and 5 deletions
+11
View File
@@ -56,6 +56,12 @@ const PATHS = {
// Trophy (record celebrations) — Material emoji-events
trophy: '<path d="M19 5h-2V3H7v2H5c-1.1 0-2 .9-2 2v1c0 2.55 1.92 4.63 4.39 4.94.63 1.5 1.98 2.63 3.61 2.96V19H7v2h10v-2h-4v-3.1c1.63-.33 2.98-1.46 3.61-2.96C19.08 12.63 21 10.55 21 8V7c0-1.1-.9-2-2-2zM5 8V7h2v3.82C5.84 10.4 5 9.3 5 8zm14 0c0 1.3-.84 2.4-2 2.82V7h2v1z" fill-rule="evenodd"/>',
trophyFill: '<path d="M19 5h-2V3H7v2H5c-1.1 0-2 .9-2 2v1c0 2.55 1.92 4.63 4.39 4.94.63 1.5 1.98 2.63 3.61 2.96V19H7v2h10v-2h-4v-3.1c1.63-.33 2.98-1.46 3.61-2.96C19.08 12.63 21 10.55 21 8V7c0-1.1-.9-2-2-2zM5 8V7h2v3.82C5.84 10.4 5 9.3 5 8zm14 0c0 1.3-.84 2.4-2 2.82V7h2v1z"/>',
// Badge icons (training milestone medals) — replace the old emoji set.
// Single-color fills; a gray <name> (locked) and white <name>White
// (unlocked, sits on the theme-color disc) variant are both built.
bolt: '<path d="M13 2L4 14h6l-1 8 9-12h-6l1-8z"/>',
moon: '<path d="M12 21a9 9 0 1 1 9-9 7 7 0 0 0-9 9z"/>',
diamond: '<path d="M7 2h10l4 7-11 13L3 9l4-7z"/>',
// Party popper (first-time celebrations) — Material celebration
party: '<path d="M2 22l14-5-9-9-5 14zm12.53-9.47l1.41-1.41 2.83 2.83-1.41 1.41-2.83-2.83zm.53-6.53L16.47 4.59l1.41-1.41 1.41 1.41-1.41 1.42zM21 11h-3v-2h3v2zm-5.65-4.35L14.24 5.54 15.65 4.1l1.11 1.11-1.41 1.44zM13 3V0h2v3h-2zM8.35 5.65l-1.41-1.44L8.06 3.1l1.41 1.41 1.12 1.14z" fill-rule="evenodd"/>',
partyFill: '<path d="M2 22l14-5-9-9-5 14zm12.53-9.47l1.41-1.41 2.83 2.83-1.41 1.41-2.83-2.83zm.53-6.53L16.47 4.59l1.41-1.41 1.41 1.41-1.41 1.42zM21 11h-3v-2h3v2zm-5.65-4.35L14.24 5.54 15.65 4.1l1.11 1.11-1.41 1.44zM13 3V0h2v3h-2zM8.35 5.65l-1.41-1.44L8.06 3.1l1.41 1.41 1.12 1.14z"/>',
@@ -154,6 +160,11 @@ const build = (theme) => {
out.playWhite = _svg(PATHS.playFill, '#FFFFFF')
out.sparkleWhite = _svg(PATHS.sparkleFill, '#FFFFFF')
out.checkWhite = _svg(PATHS.check, '#FFFFFF')
// Badge white variants — sit on the theme-color (filled) node disc.
out.boltWhite = _svg(PATHS.bolt, '#FFFFFF')
out.moonWhite = _svg(PATHS.moon, '#FFFFFF')
out.diamondWhite = _svg(PATHS.diamond, '#FFFFFF')
out.crownWhite = _svg(PATHS.crown, '#FFFFFF')
return out
}
+5 -1
View File
@@ -154,15 +154,19 @@ const getTotalStats = () => {
let totalDuration = 0
let totalSessions = 0
let maxDuration = 0
// 累计训练天数:有训练记录的不同日期数(一天多次只算 1 天)。
// 用于记录页里程碑勋章,只增不减(删记录才会减)。
const days = new Set()
Object.keys(records).forEach((key) => {
records[key].forEach((r) => {
const d = Number(r && r.duration) || 0
totalDuration += d
totalSessions++
if (d > maxDuration) maxDuration = d
if (r && r.date) days.add(dateOnly(r.date))
})
})
return { totalDuration, totalSessions, maxDuration }
return { totalDuration, totalSessions, maxDuration, totalDays: days.size }
}
const getSettings = () => {