diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e97fcc..440cc63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ - PC 选将 overlay 不再在顶栏头像下显示定位图标;仍保留网格「克/搭/补」与阵容分析条。 +## [0.6.15] - 2026-07-31 + +### Added + +- 物品详情下方展示近一年该物品的版本改动时间线(与英雄「改动」同源 `patches` 数据;无改动则不显示)。 + ## [0.6.14] - 2026-07-31 ### Changed diff --git a/web/export_relations_site.py b/web/export_relations_site.py index c7d6499..80d956a 100644 --- a/web/export_relations_site.py +++ b/web/export_relations_site.py @@ -55,7 +55,7 @@ from shared.paths import ( from seo_prerender import DEFAULT_SITE_ORIGIN, write_seo_bundle from serve_relations import WEB_DIR, build_payload -SITE_VERSION = "0.6.14" +SITE_VERSION = "0.6.15" DEFAULT_OSS_BASE = "https://climperor.oss-cn-shanghai.aliyuncs.com" diff --git a/web/frontend/app.js b/web/frontend/app.js index 4b95d18..45a8585 100644 --- a/web/frontend/app.js +++ b/web/frontend/app.js @@ -3590,6 +3590,9 @@ function renderItemDetail() { render(); }, }); + + const patchPanel = buildItemPatchChangesPanel(meta.key); + if (patchPanel) root.appendChild(patchPanel); } // Stat-icon labels for patch hero_notes (icon field). Attr values map to the @@ -3772,6 +3775,62 @@ function buildPatchChangesPanel(heroKey) { return wrap; } +/** Match shop/item key against a patch items or neutral_items entry via lookup. */ +function patchItemEntryForKey(entries, itemKey, lookup) { + if (!itemKey || !entries?.length) return null; + const itemsLookup = (lookup && lookup.items) || {}; + for (const entry of entries) { + if (!entry || entry.is_general_note || entry.ability_id === -1) continue; + const meta = itemsLookup[String(entry.ability_id)]; + if (meta && meta.key === itemKey) return entry; + } + return null; +} + +/** Recent patch notes for one item (shop detail). Null when none in window. */ +function buildItemPatchChangesPanel(itemKey) { + const patches = state.data.patches || []; + const details = state.data.patch_details || {}; + const lookup = state.data.patch_lookup || { items: {}, abilities: {}, heroes: {} }; + if (!itemKey || !patches.length) return null; + + const blocks = []; + for (const p of patches) { + const det = details[p.version]; + if (!det) continue; + const entry = + patchItemEntryForKey(det.items, itemKey, lookup) || + patchItemEntryForKey(det.neutral_items, itemKey, lookup); + if (!entry) continue; + const notesHtml = renderNotesList(entry.ability_notes); + if (!notesHtml) continue; + const patchDate = + formatAbsoluteTime(p.date || p.timestamp, { dateOnly: true }) || + p.date || + ""; + blocks.push( + `
` + + `
${escapeHtml(p.version)}` + + `${escapeHtml(patchDate)}
` + + notesHtml + + `
` + ); + } + if (!blocks.length) return null; + + const section = document.createElement("div"); + section.className = "item-detail-patches"; + const label = document.createElement("div"); + label.className = "craft-label"; + label.textContent = "改动"; + section.appendChild(label); + const wrap = document.createElement("div"); + wrap.className = "patch-changes item-patch-changes"; + wrap.innerHTML = blocks.join(""); + section.appendChild(wrap); + return section; +} + function ensureDefaultPatch() { const patches = state.data?.patches || []; if (!patches.length) return; diff --git a/web/frontend/config.js b/web/frontend/config.js index eb89843..c011163 100644 --- a/web/frontend/config.js +++ b/web/frontend/config.js @@ -1,5 +1,5 @@ /* Local defaults; production export overwrites via export_relations_site.py. */ -var SITE_VERSION = "0.6.14"; +var SITE_VERSION = "0.6.15"; var SITE_ORIGIN = ""; var ABILITY_VIDEO_BASE = ""; var STATIC_ASSET_BASE = ""; diff --git a/web/frontend/index.html b/web/frontend/index.html index b5314b2..ac78087 100644 --- a/web/frontend/index.html +++ b/web/frontend/index.html @@ -43,8 +43,8 @@ } - - + +

DOTA2 上分帝

@@ -240,8 +240,8 @@ - - - + + + diff --git a/web/frontend/style.css b/web/frontend/style.css index 4a3c3cd..979786d 100644 --- a/web/frontend/style.css +++ b/web/frontend/style.css @@ -2639,16 +2639,31 @@ body:has(#items-view:not(.hidden)) { flex: 1 1 auto; } .item-detail-recipe, -.item-detail-upgrades { +.item-detail-upgrades, +.item-detail-patches { margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--line); } .item-detail-recipe .craft-label, -.item-detail-upgrades .craft-label { +.item-detail-upgrades .craft-label, +.item-detail-patches .craft-label { display: block; margin: 0 0 8px; } +.item-detail-box .item-patch-changes { + max-width: 100%; + margin: 0; + padding: 0; + gap: 12px; +} +.item-detail-box .patch-change-ver { + font-size: var(--fs-body-sm); +} +.item-detail-box .patch-notes { + font-size: var(--fs-label); + line-height: 1.45; +} .shop-col-headers { width: 100%; display: grid;