poi-plugin-remodel-planner 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,7 +85,8 @@
85
85
  * **切回成本**:改二 ↔ 改二戊 这类可切换形态,会额外显示「从本形态切回上一形态」的成本(25 条)。
86
86
  * **多号机(复制舰)**:起点列会把**每一艘**的等级都列出来(`持有 3 艘:Lv.99 / Lv.85 / Lv.30`),
87
87
  并标出「N 艘已够等级」;如果这个形态**已经改出来过、但还有复制舰够等级**,
88
- 会额外标绿色的「可再改 N 艘」,统计条上也有「多号机可再改 N」标签(点一下=只看这些)。
88
+ 会额外标绿色的「可再改 N 艘」,统计条上也有「多号机可再改 N」标签。
89
+ 这个标签和状态标签一样是**三态**的:点一下=只看这些 → 再点一下=**排除**这些(只看不能再改的)→ 第三下=取消。
89
90
  例:秋月改 Lv99(已改出秋月改二)+ 秋月改 Lv85 → 秋月改二那行显示「已改造 + 可再改 1 艘」。
90
91
  每艘各算一份消耗,所以照着同一行的消耗再备一份资材即可。
91
92
  * 设置面板(插件列表里的小齿轮):自动联网开关、缓存有效期、立刻更新。
@@ -96,8 +97,8 @@ poi.exe 在 `ELECTRON_RUN_AS_NODE=1` 下就是一个完整的 Node 24,所以
96
97
  并且用 **poi 自己的 babel** 现场编译 `.es`(插件在 poi 里也是这么被加载的):
97
98
 
98
99
  ```bat
99
- tests\run-tests.cmd :: 逻辑层单测(14 项,纯函数:字段映射/状态判定/统计/筛选/库存解析/快照自检)
100
- tests\run-smoke.cmd :: 加载+挂载冒烟(真实 require 插件入口 + SSR 渲染页面与设置面板)
100
+ tests\run-tests.cmd :: 逻辑层单测(20 项,纯函数:字段映射/状态判定/统计/筛选/库存解析/快照自检)
101
+ tests\run-smoke.cmd :: 加载+挂载冒烟(真实 require 插件入口 + SSR 渲染页面与设置面板 + 图标存在 + 本机缓存体检)
101
102
  ```
102
103
 
103
104
  目录:
@@ -134,6 +135,10 @@ tests/ 单测与冒烟脚本(不会装到 poi 里)
134
135
 
135
136
  * **道具名 / 数量**:`_remodel_armament` 与 `_remodel_gunmat` 是**同一件道具**(新型砲熕兵装資材)
136
137
  的两个字段名(实测 534 条里从不同时出现),所以**已合并成一项** —— 界面上只会有一个「新型砲熕兵装資材」。
138
+ 合并现在发生在 `buildTable()` 里(所有数据来源的唯一入口),所以**早期版本写下的缓存**
139
+ (`%APPDATA%\poi\poi-plugin-remodel-planner\ship-cache.json` 里还带着 `armament` 键的那些)
140
+ 也照样会被折进来,不会在界面上冒出裸键名「armament」;`materialName()` 另外还认得这个别名兜底。
141
+ 数据文件本身已经有 `schema` 版本号(当前 2),但**不按版本丢弃缓存** —— 断网时启动才不会干等三次镜像超时。
137
142
  * **「现有 N」从哪来**:資源类读 `info.resources`,道具类读 `info.useitems` + `const.$useitems`
138
143
  的名字匹配;匹配不到就用实测确认的兜底 id(2 高速建造材 / 3 開発資材 / 4 改修資材 /
139
144
  58 改装設計図 / **65 試製甲板カタパルト** / 78 戦闘詳報 / 104 工廠資源)。
package/data.es CHANGED
@@ -18,6 +18,14 @@ import snapshot from './assets/remodel-snapshot.json'
18
18
 
19
19
  const CACHE_DIR = 'poi-plugin-remodel-planner'
20
20
  const CACHE_FILE = 'ship-cache.json'
21
+ /**
22
+ * 缓存格式版本(只写不校验,纯记录):
23
+ * 1 → 2:早期缓存的 rows 里带着 `armament`(= gunmat 的另一个字段名)。
24
+ * 现在 buildTable 会把任何来源的 armament 折进 gunmat,所以**老缓存照旧能用**,
25
+ * 这里不按版本丢弃缓存 —— 否则断网时启动要干等三次镜像超时(25 秒 × 3)。
26
+ * 写进文件只是为了将来需要迁移时有个据可查。
27
+ */
28
+ const CACHE_SCHEMA = 2
21
29
  const TIMEOUT_MS = 25000
22
30
 
23
31
  export const MIRRORS = [
@@ -44,7 +52,7 @@ const writeCache = (payload) => {
44
52
  try {
45
53
  const file = cachePath()
46
54
  fs.mkdirSync(path.dirname(file), { recursive: true })
47
- fs.writeFileSync(file, JSON.stringify(payload), 'utf8')
55
+ fs.writeFileSync(file, JSON.stringify({ ...payload, schema: CACHE_SCHEMA }), 'utf8')
48
56
  return true
49
57
  } catch (e) {
50
58
  return false
package/i18n/en-US.json CHANGED
@@ -79,7 +79,7 @@
79
79
  "{{n}} 艘已够等级": "{{n}} of them meets the level",
80
80
  "可再改 {{n}} 艘": "Can remodel {{n}} more",
81
81
  "多号机可再改": "Duplicates ready",
82
- "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)": "Already remodelled once, but another copy meets the level - you can remodel one more",
82
+ "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。": "Already remodelled once, but another copy meets the level - you can remodel one more. Click = only these, click again = exclude them.",
83
83
  "清空状态筛选": "Clear status filter",
84
84
  "点一下=只看它,再点一下=排除它,第三下=取消": "Click = only it, click again = exclude it, third = clear",
85
85
  "现在是:只看它(再点一下=排除它)": "Now: only it (click again = exclude)",
package/i18n/ja-JP.json CHANGED
@@ -79,7 +79,7 @@
79
79
  "{{n}} 艘已够等级": "{{n}} 隻がLv達成",
80
80
  "可再改 {{n}} 艘": "あと {{n}} 隻改装可",
81
81
  "多号机可再改": "複製艦の追加改装",
82
- "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)": "すでに改装済みですが、Lvを満たす複製艦がいます → もう1隻改装できます",
82
+ "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。": "すでに改装済みですが、Lvを満たす複製艦がいます → もう1隻改装できます。クリック=それだけ表示、もう一度=除外。",
83
83
  "清空状态筛选": "状態フィルタを解除",
84
84
  "点一下=只看它,再点一下=排除它,第三下=取消": "1回=それのみ、2回=除外、3回=解除",
85
85
  "现在是:只看它(再点一下=排除它)": "現在:それのみ(もう一度で除外)",
package/i18n/ko-KR.json CHANGED
@@ -79,7 +79,7 @@
79
79
  "{{n}} 艘已够等级": "{{n}}척이 레벨 충족",
80
80
  "可再改 {{n}} 艘": "{{n}}척 더 개장 가능",
81
81
  "多号机可再改": "복제함 추가 개장",
82
- "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)": "이미 개장했지만 레벨을 충족하는 복제함이 있어 한 척 더 개장할 수 있습니다",
82
+ "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。": "이미 개장했지만 레벨을 충족하는 복제함이 있어 한 척 더 개장할 수 있습니다. 클릭=이것만 보기, 다시 클릭=제외.",
83
83
  "清空状态筛选": "상태 필터 해제",
84
84
  "点一下=只看它,再点一下=排除它,第三下=取消": "한 번=그것만, 두 번=제외, 세 번=해제",
85
85
  "现在是:只看它(再点一下=排除它)": "현재: 그것만 (다시=제외)",
package/i18n/zh-CN.json CHANGED
@@ -79,7 +79,7 @@
79
79
  "{{n}} 艘已够等级": "{{n}} 艘已够等级",
80
80
  "可再改 {{n}} 艘": "可再改 {{n}} 艘",
81
81
  "多号机可再改": "多号机可再改",
82
- "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)": "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)",
82
+ "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。": "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。",
83
83
  "清空状态筛选": "清空状态筛选",
84
84
  "点一下=只看它,再点一下=排除它,第三下=取消": "点一下=只看它,再点一下=排除它,第三下=取消",
85
85
  "现在是:只看它(再点一下=排除它)": "现在是:只看它(再点一下=排除它)",
package/i18n/zh-TW.json CHANGED
@@ -79,7 +79,7 @@
79
79
  "{{n}} 艘已够等级": "{{n}} 艘已夠等級",
80
80
  "可再改 {{n}} 艘": "可再改 {{n}} 艘",
81
81
  "多号机可再改": "多號機可再改",
82
- "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)": "已經改出來過,但還有複製艦夠等級 → 可以再改一隻(多號機)",
82
+ "已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。": "已經改出來過,但還有複製艦夠等級 → 可以再改一隻(多號機)。點一下=只看它,再點一下=排除它。",
83
83
  "清空状态筛选": "清空狀態篩選",
84
84
  "点一下=只看它,再点一下=排除它,第三下=取消": "點一下=只看它,再點一下=排除它,第三下=取消",
85
85
  "现在是:只看它(再点一下=排除它)": "現在是:只看它(再點一下=排除它)",
package/index.es CHANGED
@@ -225,15 +225,36 @@ const StatsBar = ({ stats, filter, setFilter, t }) => {
225
225
  </Tooltip>
226
226
  )
227
227
  })}
228
- {stats.again ? (
229
- <Tooltip content={t('已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)')}>
228
+ {(stats.again || filter.againMode) ? (
229
+ <Tooltip
230
+ content={
231
+ filter.againMode === 'in'
232
+ ? t('现在是:只看它(再点一下=排除它)')
233
+ : filter.againMode === 'out'
234
+ ? t('现在是:排除它(再点一下=取消)')
235
+ : t(
236
+ '已经改出来过,但还有复制舰够等级 → 可以再改一只(多号机)。点一下=只看它,再点一下=排除它。',
237
+ )
238
+ }
239
+ >
230
240
  <Tag
231
241
  interactive
232
- minimal={!filter.againOnly}
233
- intent={filter.againOnly ? 'success' : undefined}
234
- onClick={() => setFilter({ ...filter, againOnly: !filter.againOnly })}
242
+ minimal={!filter.againMode}
243
+ intent={filter.againMode === 'in' ? 'success' : filter.againMode === 'out' ? 'danger' : undefined}
244
+ onClick={() =>
245
+ setFilter({
246
+ ...filter,
247
+ againMode: filter.againMode === 'in' ? 'out' : filter.againMode === 'out' ? '' : 'in',
248
+ })
249
+ }
235
250
  >
236
- <Icon icon="duplicate" />
251
+ {filter.againMode === 'in' ? (
252
+ <Icon icon="tick" />
253
+ ) : filter.againMode === 'out' ? (
254
+ <Icon icon="cross" />
255
+ ) : (
256
+ <Icon icon="duplicate" />
257
+ )}
237
258
  {' '}
238
259
  {t('多号机可再改')} <b>{num(stats.again)}</b>
239
260
  </Tag>
package/logic.es CHANGED
@@ -166,8 +166,29 @@ export const namesFromKcwikiShipJson = (raw) => {
166
166
  * byName[full](_full_name,例如 "Akagi Kai Ni E")
167
167
  * extraNames 用来补进基础形态等"不是改造目标"的形态(见 namesFromKcwikiShipJson)。
168
168
  */
169
+ /**
170
+ * 把历史数据里残留的 `armament` 折进 `gunmat`。
171
+ * armament 是「新型砲熕兵装資材」在数据源里的另一个字段名(与 gunmat 互斥出现),
172
+ * 早期版本写下的缓存(ship-cache.json)里还有这个键 —— 不折进来,
173
+ * 界面就会拿 materialName('armament') 找不到名字,把键名原样显示成 "armament"。
174
+ */
175
+ export const normalizeCost = (cost) => {
176
+ if (!cost || typeof cost !== 'object') return cost || {}
177
+ if (!cost.armament) return cost
178
+ const out = { ...cost }
179
+ out.gunmat = posInt(out.gunmat) + posInt(out.armament)
180
+ delete out.armament
181
+ return out
182
+ }
183
+
169
184
  export const buildTable = (input, extraNames) => {
170
- const rows = Array.isArray(input) ? input : rowsFromKcwikiShipJson(input)
185
+ const parsed = Array.isArray(input) ? input : rowsFromKcwikiShipJson(input)
186
+ // 老缓存/老快照可能带着 armament → 在这里统一折一次(所有来源都走这里)
187
+ const rows = parsed.map((row) =>
188
+ row && (row.cost || row.back)
189
+ ? { ...row, cost: normalizeCost(row.cost), back: normalizeCost(row.back) }
190
+ : row,
191
+ )
171
192
  const names =
172
193
  extraNames || (Array.isArray(input) ? null : namesFromKcwikiShipJson(input))
173
194
  const byApiId = {}
@@ -423,7 +444,7 @@ const emptyFilter = {
423
444
  onlyOwned: false,
424
445
  onlyWish: false,
425
446
  onlyReady: false,
426
- againOnly: false,
447
+ againMode: '', // 多号机「可再改」:'' 全部 / 'in' 只看可再改 / 'out' 排除可再改
427
448
  needItems: [],
428
449
  excludeItems: [],
429
450
  levelReady: false,
@@ -458,7 +479,9 @@ export const applyFilter = (entries, filter = emptyFilter) => {
458
479
  if (f.onlyOwned && !e.ownedCount) return false
459
480
  if (f.onlyWish && !e.wish) return false
460
481
  if (f.onlyReady && e.status !== STATUS.READY) return false
461
- if (f.againOnly && !e.again) return false
482
+ // 多号机「可再改」也支持正/反选(点一下只看 → 再点排除 → 第三下取消)
483
+ if (f.againMode === 'in' && !e.again) return false
484
+ if (f.againMode === 'out' && e.again) return false
462
485
  if (f.levelReady && e.ownedCount > 0 && e.lvMissing > 0) return false
463
486
  if (f.needItems.length) {
464
487
  // 多选 = 任选其一:只要需要其中任意一个道具就算命中
package/materials.es CHANGED
@@ -30,7 +30,13 @@ export const MATERIAL_META = {
30
30
  arsenal: { jp: '工廠資源', en: 'Arsenal Resource', kind: 'item' },
31
31
  }
32
32
 
33
- export const materialName = (key) => (MATERIAL_META[key] ? MATERIAL_META[key].jp : key)
33
+ /** 道具键 → 显示名。别名(老缓存里的 armament)也要认得,绝不把键名原样显示出去。 */
34
+ const MATERIAL_ALIASES = { armament: 'gunmat' }
35
+
36
+ export const materialName = (key) => {
37
+ const k = MATERIAL_ALIASES[key] || key
38
+ return MATERIAL_META[k] ? MATERIAL_META[k].jp : key
39
+ }
34
40
 
35
41
  /** 道具名匹配规则(先按游戏主数据里的日文名匹配,匹配不到再用兜底 id) */
36
42
  const ITEM_PATTERNS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poi-plugin-remodel-planner",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "查看全部舰娘的改造需求(等级/资源/设计图/卡特/详报等),按游戏进度自动标记哪些现在就能改、还差什么。",
5
5
  "main": "index.es",
6
6
  "files": [