poi-plugin-koushu-rate 2.0.12 → 2.0.14

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.
Files changed (2) hide show
  1. package/index.js +688 -48
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -17,8 +17,8 @@ const LEVEL_TWO_ROWS = [
17
17
  { range: "★6→7", label: "90%", p: 0.90, source: "phase1" },
18
18
  { range: "★7→8", label: "82%", p: 0.82, source: "phase1" },
19
19
  { range: "★8→9", label: "77%", p: 0.77, source: "phase1" },
20
- { range: "★9→MAX", label: "67%", p: 0.67, source: "phase1" },
21
- { range: "MAX→进化", label: "62%", p: 0.62, source: "upgrade" },
20
+ { range: "★9→max", label: "67%", p: 0.67, source: "phase1" },
21
+ { range: "max→进化", label: "62%", p: 0.62, source: "upgrade" },
22
22
  ];
23
23
 
24
24
  const PLAN_LEVELS_6 = [
@@ -160,10 +160,10 @@ const CSS = `
160
160
  }
161
161
  .kr2-title-row {
162
162
  display: flex;
163
- align-items: center;
164
- justify-content: space-between;
163
+ flex-direction: column;
164
+ align-items: stretch;
165
+ justify-content: flex-start;
165
166
  gap: 12px;
166
- flex-wrap: wrap;
167
167
  }
168
168
  .kr2-title {
169
169
  font-size: 18px;
@@ -202,7 +202,7 @@ const CSS = `
202
202
  display: flex;
203
203
  gap: 6px;
204
204
  flex-wrap: wrap;
205
- margin-top: 0;
205
+ margin-top: 12px;
206
206
  }
207
207
  .kr2-day {
208
208
  padding: 5px 12px;
@@ -224,10 +224,10 @@ const CSS = `
224
224
  .kr2-nav {
225
225
  display: flex;
226
226
  gap: 6px;
227
- margin-top: 12px;
228
- margin-bottom: 20px;
227
+ margin: 0;
229
228
  }
230
229
  .kr2-nav-btn {
230
+ min-width: 110px;
231
231
  padding: 7px 18px;
232
232
  border: 1px solid #5f6b7c;
233
233
  border-radius: 6px;
@@ -235,6 +235,7 @@ const CSS = `
235
235
  color: #f6f7f9;
236
236
  cursor: pointer;
237
237
  font-size: 13px;
238
+ text-align: center;
238
239
  }
239
240
  .kr2-nav-btn:hover {
240
241
  background: #383e47;
@@ -333,6 +334,40 @@ const CSS = `
333
334
  .kr2-plan-table tbody tr:last-child td {
334
335
  border-bottom: 0;
335
336
  }
337
+ .kr2-plan-main-table {
338
+ table-layout: fixed;
339
+ width: 100%;
340
+ }
341
+ .kr2-plan-main-table th,
342
+ .kr2-plan-main-table td {
343
+ vertical-align: middle;
344
+ }
345
+ .kr2-plan-main-table th:nth-child(1),
346
+ .kr2-plan-main-table td:nth-child(1) { width: 40px; }
347
+ .kr2-plan-main-table th:nth-child(2),
348
+ .kr2-plan-main-table td:nth-child(2) { width: 170px; }
349
+ .kr2-plan-main-table th:nth-child(3),
350
+ .kr2-plan-main-table td:nth-child(3) { width: 90px; }
351
+ .kr2-plan-main-table th:nth-child(4),
352
+ .kr2-plan-main-table td:nth-child(4) { width: 190px; }
353
+ .kr2-plan-main-table th:nth-child(5),
354
+ .kr2-plan-main-table td:nth-child(5) { width: 105px; }
355
+ .kr2-plan-main-table th:nth-child(6),
356
+ .kr2-plan-main-table td:nth-child(6) { width: 90px; }
357
+ .kr2-plan-main-table th:nth-child(7),
358
+ .kr2-plan-main-table td:nth-child(7) { width: 90px; }
359
+ .kr2-plan-main-table td.kr2-plan-mat-col {
360
+ white-space: normal;
361
+ word-break: break-word;
362
+ }
363
+ .kr2-plan-target-group {
364
+ display: inline-flex;
365
+ align-items: center;
366
+ justify-content: center;
367
+ gap: 4px;
368
+ flex-wrap: wrap;
369
+ width: 100%;
370
+ }
336
371
  .kr2-plan-current {
337
372
  font-size: 12px;
338
373
  }
@@ -368,7 +403,17 @@ const CSS = `
368
403
  .kr2-plan-table .kr2-plan-name-inner {
369
404
  display: flex;
370
405
  align-items: center;
371
- gap: 8px;
406
+ flex-wrap: wrap;
407
+ gap: 4px 8px;
408
+ }
409
+ .kr2-plan-evo-target-line {
410
+ color: #4fc3f7;
411
+ font-weight: 700;
412
+ white-space: normal;
413
+ word-break: break-word;
414
+ }
415
+ .kr2-plan-evo-target-name {
416
+ color: #4fc3f7;
372
417
  }
373
418
  .kr2-plan-table .kr2-icon {
374
419
  width: 24px;
@@ -443,6 +488,212 @@ const CSS = `
443
488
  color: #d6dce3;
444
489
  margin-bottom: 8px;
445
490
  }
491
+ .kr2-plan-target-btn {
492
+ min-width: 56px;
493
+ height: 24px;
494
+ padding: 0 8px;
495
+ border: 1px solid #5f6b7c;
496
+ border-radius: 4px;
497
+ background: #2f343c;
498
+ color: #f6f7f9;
499
+ font-size: 12px;
500
+ text-align: center;
501
+ cursor: pointer;
502
+ }
503
+ .kr2-plan-target-btn.kr2-plan-target-active {
504
+ background: #2d72d2;
505
+ border-color: #2d72d2;
506
+ color: #fff;
507
+ }
508
+ .kr2-level-max-blue {
509
+ color: #4fc3f7;
510
+ font-weight: 700;
511
+ }
512
+ .kr2-plan-evo-wrap {
513
+ display: inline-block;
514
+ vertical-align: middle;
515
+ }
516
+ .kr2-plan-evo-btn {
517
+ min-width: 56px;
518
+ height: 24px;
519
+ padding: 0 8px;
520
+ border: 1px solid #5f6b7c;
521
+ border-radius: 4px;
522
+ background: #2f343c;
523
+ color: #f6f7f9;
524
+ font-size: 12px;
525
+ text-align: center;
526
+ white-space: nowrap;
527
+ cursor: pointer;
528
+ }
529
+ .kr2-plan-evo-btn:disabled {
530
+ opacity: 0.4;
531
+ cursor: not-allowed;
532
+ }
533
+ .kr2-plan-evo-btn.kr2-plan-evo-active {
534
+ background: #2d72d2;
535
+ border-color: #2d72d2;
536
+ color: #fff;
537
+ }
538
+ .kr2-evo-modal {
539
+ width: 420px;
540
+ max-width: 100%;
541
+ }
542
+ .kr2-evo-scroll {
543
+ max-height: 280px;
544
+ overflow-y: auto;
545
+ display: flex;
546
+ flex-direction: column;
547
+ gap: 6px;
548
+ padding: 12px;
549
+ }
550
+ .kr2-evo-option {
551
+ padding: 8px 10px;
552
+ border: 1px solid #5f6b7c;
553
+ border-radius: 4px;
554
+ background: #2f343c;
555
+ color: #f6f7f9;
556
+ text-align: left;
557
+ font-size: 13px;
558
+ cursor: pointer;
559
+ }
560
+ .kr2-evo-option:hover {
561
+ background: #383e47;
562
+ }
563
+ .kr2-evo-option.kr2-evo-option-active {
564
+ background: #1d3048;
565
+ border-color: #4f9dcc;
566
+ color: #d6e4f5;
567
+ }
568
+
569
+ .kr2-strong {
570
+ margin-top: 12px;
571
+ flex: 1;
572
+ min-height: 60vh;
573
+ overflow-x: hidden;
574
+ overflow-y: auto;
575
+ }
576
+ .kr2-strong-table {
577
+ border-collapse: separate;
578
+ border-spacing: 0;
579
+ }
580
+ .kr2-strong-cat-th {
581
+ position: relative;
582
+ cursor: pointer;
583
+ user-select: none;
584
+ }
585
+ .kr2-strong-cat-title {
586
+ margin-right: 4px;
587
+ }
588
+ .kr2-strong-cat-arrow {
589
+ color: #abb3bf;
590
+ font-size: 11px;
591
+ }
592
+ .kr2-strong-cat-menu {
593
+ position: absolute;
594
+ top: calc(100% + 4px);
595
+ left: 0;
596
+ z-index: 40;
597
+ min-width: 180px;
598
+ background: #252a31;
599
+ border: 1px solid #5f6b7c;
600
+ border-radius: 6px;
601
+ padding: 6px;
602
+ display: flex;
603
+ flex-direction: column;
604
+ gap: 4px;
605
+ }
606
+ .kr2-strong-cat-option {
607
+ display: flex;
608
+ align-items: center;
609
+ gap: 6px;
610
+ color: #f6f7f9;
611
+ font-size: 12px;
612
+ white-space: nowrap;
613
+ cursor: pointer;
614
+ }
615
+ .kr2-strong-cat-option input {
616
+ margin: 0;
617
+ }
618
+
619
+ .kr2-strong-cat {
620
+ white-space: nowrap;
621
+ }
622
+ .kr2-strong-table th,
623
+ .kr2-strong-table td {
624
+ text-align: center;
625
+ border-bottom: 1px solid rgba(255, 255, 255, 0.12);
626
+ }
627
+ .kr2-strong-table tbody tr:last-child td {
628
+ border-bottom: 0;
629
+ }
630
+ .kr2-strong-equip {
631
+ text-align: left !important;
632
+ white-space: normal;
633
+ }
634
+ .kr2-strong-level {
635
+ display: inline-flex;
636
+ align-items: center;
637
+ justify-content: center;
638
+ vertical-align: middle;
639
+ min-width: 30px;
640
+ height: 20px;
641
+ color: #4fc3f7;
642
+ font-weight: 700;
643
+ }
644
+ .kr2-strong-target {
645
+ color: #ffffff;
646
+ font-weight: 700;
647
+ }
648
+ .kr2-strong-stock {
649
+ white-space: normal;
650
+ }
651
+ .kr2-strong-stock-name {
652
+ color: #ffffff;
653
+ font-weight: 700;
654
+ }
655
+ .kr2-strong-stock-ok {
656
+ color: #f6f7f9;
657
+ }
658
+ .kr2-strong-stock-short {
659
+ color: #ff6b6b;
660
+ font-weight: 700;
661
+ }
662
+ .kr2-strong-stock-missing {
663
+ color: #abb3bf;
664
+ }
665
+ .kr2-strong-stock-notfound {
666
+ color: #ff6b6b;
667
+ font-weight: 700;
668
+ }
669
+ .kr2-strong-stock-notfound .kr2-strong-stock-name {
670
+ color: #ff6b6b;
671
+ }
672
+ .kr2-strong-stock-clear {
673
+ color: #4fc3f7;
674
+ font-weight: 700;
675
+ }
676
+ .kr2-strong-clear-row {
677
+ background: rgba(79, 195, 247, 0.14);
678
+ }
679
+ .kr2-strong-owned {
680
+ color: #f6f7f9;
681
+ font-weight: 700;
682
+ }
683
+ .kr2-strong-owned.kr2-strong-stock-short {
684
+ color: #ff6b6b;
685
+ }
686
+ .kr2-strong-owned.kr2-strong-stock-clear {
687
+ color: #4fc3f7;
688
+ }
689
+ .kr2-strong-clear-row td {
690
+ color: #4fc3f7;
691
+ }
692
+ .kr2-strong-clear-row .kr2-strong-target,
693
+ .kr2-strong-clear-row .kr2-strong-stock-name,
694
+ .kr2-strong-clear-row .kr2-strong-owned {
695
+ color: #4fc3f7;
696
+ }
446
697
  .kr2-search {
447
698
  width: 240px;
448
699
  padding: 6px 10px;
@@ -509,20 +760,24 @@ const CSS = `
509
760
  overflow-y: scroll;
510
761
  }
511
762
  .kr2-plan::-webkit-scrollbar,
763
+ .kr2-strong::-webkit-scrollbar,
512
764
  .kr2-list::-webkit-scrollbar {
513
765
  width: 10px;
514
766
  height: 10px;
515
767
  }
516
768
  .kr2-plan::-webkit-scrollbar-track,
769
+ .kr2-strong::-webkit-scrollbar-track,
517
770
  .kr2-list::-webkit-scrollbar-track {
518
771
  background: #1c2127;
519
772
  }
520
773
  .kr2-plan::-webkit-scrollbar-thumb,
774
+ .kr2-strong::-webkit-scrollbar-thumb,
521
775
  .kr2-list::-webkit-scrollbar-thumb {
522
776
  background: #5f6b7c;
523
777
  border-radius: 5px;
524
778
  }
525
779
  .kr2-plan::-webkit-scrollbar-thumb:hover,
780
+ .kr2-strong::-webkit-scrollbar-thumb:hover,
526
781
  .kr2-list::-webkit-scrollbar-thumb:hover {
527
782
  background: #8b95a1;
528
783
  }
@@ -1944,6 +2199,8 @@ function buildRows(staticData, masterEquips, fallbackNames, akashi, recommendati
1944
2199
  upgradesByEquip[key].push(
1945
2200
  Object.assign({}, r, {
1946
2201
  targetName: String(targetMaster.api_name || targetFallback.name || ("装备 " + r.upgrade_id)),
2202
+ targetCategory: String(targetMaster.api_type_name || targetFallback.type || ""),
2203
+ targetBase: baseById[targetId] || null,
1947
2204
  secretaries: secretaries.slice(),
1948
2205
  })
1949
2206
  )
@@ -2168,7 +2425,7 @@ function planInventoryLevels(row, inventoryByEquip) {
2168
2425
  return out
2169
2426
  }
2170
2427
 
2171
- function planCopyCosts(row, target, current) {
2428
+ function planCopyCosts(row, target, current, upgradeId) {
2172
2429
  const levels = target === "max" ? PLAN_LEVELS_MAX : PLAN_LEVELS_6
2173
2430
  const out = { screws: 0, dev: 0, fuel: 0, ammo: 0, steel: 0, bauxite: 0, materials: [] }
2174
2431
  for (const lv of levels) {
@@ -2192,10 +2449,31 @@ function planCopyCosts(row, target, current) {
2192
2449
  out.materials.push({ item: m, count: m.count || 1 })
2193
2450
  }
2194
2451
  }
2452
+ if (upgradeId != null && target === "max") {
2453
+ const upg = (row.upgrades || []).find((u) => String(u.upgrade_id) === String(upgradeId))
2454
+ if (upg) {
2455
+ const rec = buildRecommendation(upg.consume_improvement_min, upg.consume_improvement_max, 0.62)
2456
+ const ensure = rec.tone === "ensure"
2457
+ const expected = Number.isFinite(rec.expected) ? rec.expected : upg.consume_improvement_min / 0.62
2458
+ const screws = ensure ? upg.consume_improvement_max : expected
2459
+ const attempts = ensure ? 1 : expected
2460
+ const dev = ensure ? upg.consume_development_max : upg.consume_development_min * attempts
2461
+ out.screws += screws
2462
+ out.dev += dev
2463
+ const base = upg.targetBase || row.base || {}
2464
+ out.fuel += (base.consume_fuel || 0) * attempts
2465
+ out.ammo += (base.consume_ammo || 0) * attempts
2466
+ out.steel += (base.consume_steel || 0) * attempts
2467
+ out.bauxite += (base.consume_bauxite || 0) * attempts
2468
+ for (const m of upg.materials || []) {
2469
+ out.materials.push({ item: m, count: m.count || 1 })
2470
+ }
2471
+ }
2472
+ }
2195
2473
  return out
2196
2474
  }
2197
2475
 
2198
- function planRowCosts(row, target, qty, inventoryByEquip) {
2476
+ function planRowCosts(row, target, qty, inventoryByEquip, upgradeId) {
2199
2477
  const count = Math.max(1, Math.min(99, Math.round(Number(qty) || 1)))
2200
2478
  let starts = []
2201
2479
  if (count === 1) {
@@ -2206,7 +2484,7 @@ function planRowCosts(row, target, qty, inventoryByEquip) {
2206
2484
  }
2207
2485
  const out = { screws: 0, dev: 0, fuel: 0, ammo: 0, steel: 0, bauxite: 0, materials: [] }
2208
2486
  for (const current of starts) {
2209
- const c = planCopyCosts(row, target, current)
2487
+ const c = planCopyCosts(row, target, current, upgradeId)
2210
2488
  out.screws += c.screws
2211
2489
  out.dev += c.dev
2212
2490
  out.fuel += c.fuel
@@ -2282,11 +2560,80 @@ function planMaterialDevExpected(costs, kcDevData) {
2282
2560
  return total
2283
2561
  }
2284
2562
 
2285
- function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onToggle, onTarget, onQty, onSelectAll, onMaterialClick, kcDevData, includeDevExpected, onToggleIncludeDevExpected }) {
2563
+ class EvolutionButton extends React.Component {
2564
+ state = { open: false, selected: null }
2565
+
2566
+ open = () => {
2567
+ const branches = this.props.branches || []
2568
+ if (branches.length <= 1) {
2569
+ const id = branches[0] ? String(branches[0].upgrade_id) : null
2570
+ if (id == null || !this.props.onSelect) return
2571
+ this.props.onSelect(this.props.rowId, this.props.value === id ? null : id)
2572
+ return
2573
+ }
2574
+ this.setState({ open: true, selected: this.props.value || null })
2575
+ }
2576
+
2577
+ close = () => {
2578
+ if (this.props.onSelect) this.props.onSelect(this.props.rowId, this.state.selected)
2579
+ this.setState({ open: false })
2580
+ }
2581
+
2582
+ render() {
2583
+ const branches = this.props.branches || []
2584
+ if (branches.length === 0) {
2585
+ return React.createElement("button", { type: "button", className: "kr2-plan-evo-btn", disabled: true }, "无进化")
2586
+ }
2587
+ const active = !!this.props.value
2588
+ const selected = branches.find((b) => String(b.upgrade_id) === String(this.props.value))
2589
+ const label = "进化"
2590
+ return React.createElement(
2591
+ "div",
2592
+ { className: "kr2-plan-evo-wrap" },
2593
+ React.createElement("button", { type: "button", className: "kr2-plan-evo-btn" + (active ? " kr2-plan-evo-active" : ""), onClick: this.open }, label),
2594
+ this.state.open
2595
+ ? React.createElement(
2596
+ "div",
2597
+ { className: "kr2-modal-backdrop", onClick: this.close },
2598
+ React.createElement(
2599
+ "div",
2600
+ { className: "kr2-modal kr2-evo-modal", onClick: (e) => e.stopPropagation() },
2601
+ React.createElement(
2602
+ "div",
2603
+ { className: "kr2-modal-head" },
2604
+ React.createElement("div", { className: "kr2-modal-title" }, "选择进化分支"),
2605
+ React.createElement(
2606
+ "div",
2607
+ { className: "kr2-modal-actions" },
2608
+ React.createElement("button", { className: "kr2-button", onClick: this.close }, "关闭")
2609
+ )
2610
+ ),
2611
+ React.createElement(
2612
+ "div",
2613
+ { className: "kr2-evo-scroll" },
2614
+ branches.map((b) =>
2615
+ React.createElement(
2616
+ "button",
2617
+ { key: String(b.upgrade_id), type: "button", className: "kr2-evo-option" + (this.state.selected === String(b.upgrade_id) ? " kr2-evo-option-active" : ""), onClick: () => this.setState({ selected: String(b.upgrade_id) }) },
2618
+ b.targetName
2619
+ )
2620
+ )
2621
+ )
2622
+ )
2623
+ )
2624
+ : null
2625
+ )
2626
+ }
2627
+ }
2628
+
2629
+ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onToggle, onTarget, onQty, onSelectAll, onMaterialClick, kcDevData, includeDevExpected, onToggleIncludeDevExpected, onEvo }) {
2286
2630
  const planRows = rows.map((row) => {
2287
2631
  const sel = (selection || {})[row.id] || { selected: true, target: "max", qty: 1 }
2288
- const costs = planRowCosts(row, sel.target, sel.qty, inventoryByEquip)
2289
- return { row, sel, costs, matDev: planMaterialDevExpected(costs, kcDevData), display: planCurrentDisplay(row, sel, inventoryByEquip) }
2632
+ const evoUpgradeId = sel.evoUpgradeId || null
2633
+ const evoBranch = evoUpgradeId ? (row.upgrades || []).find((u) => String(u.upgrade_id) === String(evoUpgradeId)) : null
2634
+ const target = evoUpgradeId ? "max" : sel.target
2635
+ const costs = planRowCosts(row, target, sel.qty, inventoryByEquip, evoUpgradeId)
2636
+ return { row, sel, costs, matDev: planMaterialDevExpected(costs, kcDevData), display: planCurrentDisplay(row, sel, inventoryByEquip), target, evoUpgradeId, evoBranch }
2290
2637
  })
2291
2638
  const selected = planRows.filter((p) => p.sel.selected)
2292
2639
  const totals = { screws: 0, dev: 0, fuel: 0, ammo: 0, steel: 0, bauxite: 0 }
@@ -2351,7 +2698,7 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
2351
2698
  ),
2352
2699
  React.createElement(
2353
2700
  "table",
2354
- { className: "kr2-table kr2-plan-table" },
2701
+ { className: "kr2-table kr2-plan-table kr2-plan-main-table" },
2355
2702
  React.createElement(
2356
2703
  "thead",
2357
2704
  null,
@@ -2377,22 +2724,17 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
2377
2724
  "tr",
2378
2725
  { key: p.row.id },
2379
2726
  React.createElement("td", null, React.createElement("input", { type: "checkbox", checked: !!p.sel.selected, onChange: () => onToggle(p.row.id) })),
2380
- React.createElement("td", { className: "kr2-plan-name" }, React.createElement("span", { className: "kr2-plan-name-inner" }, React.createElement(SlotitemIcon, { slotitemId: p.row.icon, className: "kr2-icon" }), " ", p.row.name)),
2727
+ React.createElement("td", { className: "kr2-plan-name" }, React.createElement("span", { className: "kr2-plan-name-inner" }, React.createElement(SlotitemIcon, { slotitemId: p.row.icon, className: "kr2-icon" }), " ", p.row.name, p.evoBranch ? React.createElement("span", { className: "kr2-plan-evo-target-line" }, "→ ", React.createElement("span", { className: "kr2-plan-evo-target-name" }, p.evoBranch.targetName)) : null)),
2381
2728
  React.createElement("td", { className: Math.round(Number(p.sel.qty || 1)) === 1 ? "kr2-plan-current" : "kr2-plan-current-stock" }, p.display),
2382
2729
  React.createElement(
2383
2730
  "td",
2384
2731
  null,
2385
2732
  React.createElement(
2386
- "label",
2387
- { style: { marginRight: 8 } },
2388
- React.createElement("input", { type: "radio", name: "plan-" + p.row.id, checked: p.sel.target !== "max", onChange: () => onTarget(p.row.id, "6") }),
2389
- "+6"
2390
- ),
2391
- React.createElement(
2392
- "label",
2393
- null,
2394
- React.createElement("input", { type: "radio", name: "plan-" + p.row.id, checked: p.sel.target === "max", onChange: () => onTarget(p.row.id, "max") }),
2395
- "MAX"
2733
+ "div",
2734
+ { className: "kr2-plan-target-group" },
2735
+ React.createElement("button", { type: "button", className: "kr2-plan-target-btn" + (!p.evoUpgradeId && p.target !== "max" ? " kr2-plan-target-active" : ""), onClick: () => onTarget(p.row.id, "6") }, "+6"),
2736
+ React.createElement("button", { type: "button", className: "kr2-plan-target-btn" + (!p.evoUpgradeId && p.target === "max" ? " kr2-plan-target-active" : ""), onClick: () => onTarget(p.row.id, "max") }, "max"),
2737
+ React.createElement(EvolutionButton, { rowId: p.row.id, branches: p.row.upgrades || [], value: p.evoUpgradeId, onSelect: onEvo })
2396
2738
  )
2397
2739
  ),
2398
2740
  React.createElement(
@@ -2447,6 +2789,179 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
2447
2789
  )
2448
2790
  }
2449
2791
 
2792
+ class StrongPage extends React.Component {
2793
+ catRef = React.createRef()
2794
+ state = {
2795
+ categoryOpen: false,
2796
+ selectedCategories: readStrongCategories(),
2797
+ catPos: null,
2798
+ }
2799
+
2800
+ toggleCategoryOpen = () => {
2801
+ if (this.state.categoryOpen) {
2802
+ this.setState({ categoryOpen: false, catPos: null })
2803
+ return
2804
+ }
2805
+ const el = this.catRef.current
2806
+ if (!el) return
2807
+ const rect = el.getBoundingClientRect()
2808
+ this.setState({
2809
+ categoryOpen: true,
2810
+ catPos: { top: rect.bottom + 4, left: rect.left, width: rect.width },
2811
+ })
2812
+ }
2813
+
2814
+ toggleCategory = (name) => {
2815
+ const all = Array.from(new Set((this.props.rows || []).map((row) => row.category).filter(Boolean)))
2816
+ this.setState((prev) => {
2817
+ let next
2818
+ if (prev.selectedCategories == null) {
2819
+ next = all.filter((c) => c !== name)
2820
+ } else if (prev.selectedCategories.indexOf(name) >= 0) {
2821
+ next = prev.selectedCategories.filter((c) => c !== name)
2822
+ } else {
2823
+ next = prev.selectedCategories.concat([name])
2824
+ }
2825
+ if (next.length === all.length) next = null
2826
+ saveStrongCategories(next)
2827
+ return { selectedCategories: next }
2828
+ })
2829
+ }
2830
+
2831
+ render() {
2832
+ const { rows, inventoryByEquip, selection } = this.props
2833
+ const inventoryLoaded = inventoryByEquip && Object.keys(inventoryByEquip).length > 0
2834
+ const entries = []
2835
+ const levelText = (level) => {
2836
+ const n = Number(level)
2837
+ if (n >= 10) return "max"
2838
+ return "+" + String(n)
2839
+ }
2840
+ const demandMap = {}
2841
+ for (const row of rows || []) {
2842
+ const sel = (selection || {})[row.id] || { selected: true, target: "max", qty: 1 }
2843
+ const qty = Math.max(1, Math.min(99, Math.round(Number(sel.qty) || 1)))
2844
+ const evoUpgradeId = sel.evoUpgradeId || null
2845
+ const evoUpgrade = evoUpgradeId ? (row.upgrades || []).find((u) => String(u.upgrade_id) === String(evoUpgradeId)) : null
2846
+ const displayRow = evoUpgrade
2847
+ ? Object.assign({}, row, { id: row.id + ":evo:" + evoUpgrade.upgrade_id, name: evoUpgrade.targetName, category: evoUpgrade.targetCategory || row.category })
2848
+ : row
2849
+ const targetEquipId = evoUpgrade ? String(evoUpgrade.upgrade_id) : row.id
2850
+ const targetLevelValue = evoUpgrade ? 0 : (sel.target === "max" ? 10 : 6)
2851
+ const bucket = demandMap[targetEquipId] || (demandMap[targetEquipId] = { equipId: targetEquipId, displayRow, demands: {} })
2852
+ bucket.demands[String(targetLevelValue)] = (bucket.demands[String(targetLevelValue)] || 0) + qty
2853
+ }
2854
+ for (const bucket of Object.values(demandMap)) {
2855
+ const inv = (inventoryByEquip || {})[bucket.equipId]
2856
+ const inventoryLevels = []
2857
+ if (inv && inv.levels) {
2858
+ for (const level of Object.keys(inv.levels)) {
2859
+ const count = Math.max(0, Math.round(Number(inv.levels[level]) || 0))
2860
+ if (count > 0) inventoryLevels.push({ level: Number(level), count })
2861
+ }
2862
+ inventoryLevels.sort((a, b) => b.level - a.level)
2863
+ }
2864
+ const remaining = {}
2865
+ for (const lv of inventoryLevels) remaining[String(lv.level)] = lv.count
2866
+ const targetLevels = Object.keys(bucket.demands).map(Number).sort((a, b) => b - a)
2867
+ const allocation = {}
2868
+ const shortfall = {}
2869
+ for (const tl of targetLevels) {
2870
+ let need = bucket.demands[String(tl)] || 0
2871
+ for (const lv of inventoryLevels) {
2872
+ if (need <= 0) break
2873
+ const avail = remaining[String(lv.level)] || 0
2874
+ if (avail <= 0) continue
2875
+ const take = Math.min(need, avail)
2876
+ const key = String(tl) + "|" + String(lv.level)
2877
+ const alloc = allocation[key] || (allocation[key] = { targetLevelValue: tl, inventoryLevel: lv.level, qty: 0, stock: 0 })
2878
+ alloc.qty += take
2879
+ alloc.stock += take
2880
+ remaining[String(lv.level)] = avail - take
2881
+ need -= take
2882
+ }
2883
+ if (need > 0) shortfall[String(tl)] = need
2884
+ }
2885
+ for (const key of Object.keys(allocation)) {
2886
+ const alloc = allocation[key]
2887
+ entries.push({ key: bucket.equipId + ":" + key, row: bucket.displayRow, targetLevel: levelText(alloc.targetLevelValue), targetLevelValue: alloc.targetLevelValue, qty: alloc.qty, inventoryLevel: alloc.inventoryLevel, stock: alloc.stock })
2888
+ }
2889
+ for (const tl of Object.keys(shortfall)) {
2890
+ const value = Number(tl)
2891
+ entries.push({ key: bucket.equipId + ":short:" + tl, row: bucket.displayRow, targetLevel: levelText(value), targetLevelValue: value, qty: shortfall[tl], inventoryLevel: null, stock: inventoryLoaded ? 0 : null, notFound: true })
2892
+ }
2893
+ }
2894
+ for (const item of entries) {
2895
+ item.clear = item.qty > 0 && item.stock != null && item.inventoryLevel === item.targetLevelValue && item.stock >= item.qty
2896
+ item.levelShort = item.inventoryLevel != null && item.inventoryLevel < item.targetLevelValue
2897
+ item.countShort = item.stock != null && item.qty > 0 && item.stock < item.qty
2898
+ item.countEnough = item.stock != null && item.stock >= item.qty
2899
+ }
2900
+ entries.sort((a, b) => (b.clear ? 1 : 0) - (a.clear ? 1 : 0))
2901
+ const categories = Array.from(new Set(entries.map((item) => item.row.category).filter(Boolean))).sort((a, b) => a.localeCompare(b, "zh-Hans-CN"))
2902
+ const selectedCategories = this.state.selectedCategories
2903
+ const visibleEntries = selectedCategories == null ? entries : entries.filter((item) => selectedCategories.indexOf(item.row.category) >= 0)
2904
+ const stockText = (item) => {
2905
+ const nameNode = React.createElement("span", { className: "kr2-strong-stock-name" }, item.row.name)
2906
+ if (item.notFound || item.stock == null) return nameNode
2907
+ const levelPart = levelText(item.inventoryLevel)
2908
+ return React.createElement("span", null, nameNode, " ", levelPart)
2909
+ }
2910
+ const stockClass = (item) => item.notFound || item.stock == null ? "kr2-strong-stock-notfound" : item.clear ? "kr2-strong-stock-clear" : item.levelShort ? "kr2-strong-stock-short" : "kr2-strong-stock-ok"
2911
+ const ownedClass = (item) => item.stock == null ? "kr2-strong-stock-missing" : item.clear || item.countEnough ? "kr2-strong-stock-clear" : item.countShort ? "kr2-strong-stock-short" : "kr2-strong-stock-ok"
2912
+ const catStyle = this.state.catPos ? { position: "fixed", top: this.state.catPos.top, left: this.state.catPos.left, minWidth: Math.max(180, this.state.catPos.width) } : null
2913
+ const categoryHead = React.createElement(
2914
+ "th",
2915
+ { className: "kr2-strong-cat-th", ref: this.catRef, onClick: this.toggleCategoryOpen },
2916
+ React.createElement("span", { className: "kr2-strong-cat-title" }, "装备分类"),
2917
+ React.createElement("span", { className: "kr2-strong-cat-arrow" }, this.state.categoryOpen ? "▲" : "▼"),
2918
+ this.state.categoryOpen
2919
+ ? React.createElement(
2920
+ "div",
2921
+ { className: "kr2-strong-cat-menu", style: catStyle, onClick: (e) => e.stopPropagation() },
2922
+ categories.map((cat) =>
2923
+ React.createElement(
2924
+ "label",
2925
+ { key: cat, className: "kr2-strong-cat-option" },
2926
+ React.createElement("input", { type: "checkbox", checked: selectedCategories == null || selectedCategories.indexOf(cat) >= 0, onChange: () => this.toggleCategory(cat) }),
2927
+ cat
2928
+ )
2929
+ )
2930
+ )
2931
+ : null
2932
+ )
2933
+ return React.createElement(
2934
+ "div",
2935
+ { className: "kr2-strong" },
2936
+ React.createElement(
2937
+ "table",
2938
+ { className: "kr2-table kr2-plan-table kr2-strong-table" },
2939
+ React.createElement(
2940
+ "thead",
2941
+ null,
2942
+ React.createElement("tr", null, categoryHead, React.createElement("th", null, "目标装备"), React.createElement("th", null, "目标数"), React.createElement("th", null, "库存"), React.createElement("th", null, "完成数"))
2943
+ ),
2944
+ React.createElement(
2945
+ "tbody",
2946
+ null,
2947
+ visibleEntries.length === 0
2948
+ ? React.createElement("tr", null, React.createElement("td", { colSpan: 5 }, "无匹配分类"))
2949
+ : visibleEntries.map((item) =>
2950
+ React.createElement(
2951
+ "tr",
2952
+ { key: item.key, className: item.clear ? "kr2-strong-clear-row" : null },
2953
+ React.createElement("td", { className: "kr2-strong-cat" }, item.row.category || "-"),
2954
+ React.createElement("td", { className: "kr2-strong-equip" }, item.row.name, " ", React.createElement("span", { className: "kr2-strong-level" }, item.targetLevel)),
2955
+ React.createElement("td", { className: "kr2-strong-target" }, String(item.qty)),
2956
+ React.createElement("td", { className: "kr2-strong-stock " + stockClass(item) }, stockText(item)),
2957
+ React.createElement("td", { className: "kr2-strong-owned " + ownedClass(item) }, item.stock == null ? "--" : item.clear ? "clear!" : String(item.stock))
2958
+ )
2959
+ )
2960
+ )
2961
+ )
2962
+ )
2963
+ }
2964
+ }
2450
2965
  function RateCell({ range, open, onToggle, tone }) {
2451
2966
  return React.createElement(
2452
2967
  "span",
@@ -2536,12 +3051,15 @@ class LevelTwoTable extends React.Component {
2536
3051
  const phase1 = this.props.phase1
2537
3052
  const upgrades = this.props.upgrades || null
2538
3053
  const rows = []
2539
- const pushRateRow = (step, range, label, key, p, subText, evolTarget) => {
3054
+ const pushRateRow = (step, range, label, key, p, subText, evolTarget, maxBlue) => {
2540
3055
  const normal = step ? step.consume_improvement_min : null
2541
3056
  const certain = step ? step.consume_improvement_max : null
2542
3057
  const rec = buildRecommendation(normal, certain, p)
2543
3058
  const materials = step ? step.materials || [] : []
2544
3059
  const hasMaterials = materials.some((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
3060
+ const rangeNode = maxBlue
3061
+ ? React.createElement("span", null, "★9→", React.createElement("span", { className: "kr2-level-max-blue" }, "max"))
3062
+ : range
2545
3063
  rows.push(
2546
3064
  React.createElement(
2547
3065
  "tr",
@@ -2561,7 +3079,7 @@ class LevelTwoTable extends React.Component {
2561
3079
  ),
2562
3080
  React.createElement("div", { className: "kr2-evol-secretaries" }, subText)
2563
3081
  )
2564
- : range
3082
+ : rangeNode
2565
3083
  ),
2566
3084
  React.createElement("td", null, label),
2567
3085
  React.createElement("td", null, normal == null ? "--" : String(normal)),
@@ -2597,7 +3115,7 @@ class LevelTwoTable extends React.Component {
2597
3115
  return
2598
3116
  }
2599
3117
  const step = rate.source === "phase0" ? phase0 : phase1
2600
- pushRateRow(step, rate.range, rate.label, rate.range, rate.p)
3118
+ pushRateRow(step, rate.range, rate.label, rate.range, rate.p, "", "", rate.range === "★9→max" && !upgrades)
2601
3119
  })
2602
3120
 
2603
3121
  return React.createElement(
@@ -2713,7 +3231,7 @@ function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEqu
2713
3231
  { className: "kr2-level" },
2714
3232
  React.createElement(
2715
3233
  LevelSection,
2716
- { title: "6→MAX", defaultOpen: true, resourceText: "成功率 95 / 90 / 82 / 77 / 67 / 62 %" },
3234
+ { title: "6→max", defaultOpen: true, resourceText: "成功率 95 / 90 / 82 / 77 / 67 / 62 %" },
2717
3235
  React.createElement(LevelTwoTable, { phase0: row.phase0, phase1: row.phase1, upgrades: row.upgrades, onMaterialClick, inventoryByEquip, useItemCounts, onInventoryClick })
2718
3236
  )
2719
3237
  )
@@ -2805,6 +3323,100 @@ function saveFavorites(favorites) {
2805
3323
  saveFavoritesToLocalStorage(favorites)
2806
3324
  }
2807
3325
 
3326
+ const UI_STATE_STORAGE_KEY = "poi-plugin-koushu-rate:ui-state";
3327
+ const FAVORITES_ONLY_STORAGE_KEY = "poi-plugin-koushu-rate:favorites-only";
3328
+ const UI_STATE_FILE_NAME = "ui-state.json";
3329
+
3330
+ function getUiStateFilePath() {
3331
+ try {
3332
+ let remote = null
3333
+ try {
3334
+ remote = require("@electron/remote")
3335
+ } catch (_) {}
3336
+ if (!remote) {
3337
+ try {
3338
+ remote = require("electron").remote
3339
+ } catch (_) {}
3340
+ }
3341
+ const app = remote && (remote.app || (remote.default && remote.default.app))
3342
+ if (app && typeof app.getPath === "function") {
3343
+ return path.join(String(app.getPath("userData")), "poi-plugin-koushu-rate", UI_STATE_FILE_NAME)
3344
+ }
3345
+ } catch (_) {}
3346
+ return null
3347
+ }
3348
+
3349
+ function readUiStateFromLocalStorage() {
3350
+ const out = {}
3351
+ try {
3352
+ const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
3353
+ if (!storage) return out
3354
+ const raw = storage.getItem(UI_STATE_STORAGE_KEY)
3355
+ if (raw) {
3356
+ const parsed = JSON.parse(raw)
3357
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) Object.assign(out, parsed)
3358
+ }
3359
+ const legacy = storage.getItem(FAVORITES_ONLY_STORAGE_KEY)
3360
+ if (legacy != null && out.favoritesOnly == null) out.favoritesOnly = legacy === "1"
3361
+ } catch (_) {}
3362
+ return out
3363
+ }
3364
+
3365
+ function writeUiStateToLocalStorage(state) {
3366
+ try {
3367
+ const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
3368
+ if (storage) storage.setItem(UI_STATE_STORAGE_KEY, JSON.stringify(state || {}))
3369
+ } catch (_) {}
3370
+ }
3371
+
3372
+ function readUiState() {
3373
+ const file = getUiStateFilePath()
3374
+ let fileState = {}
3375
+ if (file) {
3376
+ try {
3377
+ if (fs.existsSync(file)) {
3378
+ const parsed = JSON.parse(fs.readFileSync(file, "utf8"))
3379
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) fileState = parsed
3380
+ }
3381
+ } catch (_) {}
3382
+ }
3383
+ return Object.assign({}, fileState, readUiStateFromLocalStorage())
3384
+ }
3385
+
3386
+ function saveUiState(patch) {
3387
+ const next = Object.assign({}, readUiState(), patch || {})
3388
+ for (const key of ["query", "day", "category", "activeTab"]) delete next[key]
3389
+ const file = getUiStateFilePath()
3390
+ if (file) {
3391
+ try {
3392
+ fs.mkdirSync(path.dirname(file), { recursive: true })
3393
+ fs.writeFileSync(file, JSON.stringify(next, null, 2), "utf8")
3394
+ } catch (_) {}
3395
+ }
3396
+ writeUiStateToLocalStorage(next)
3397
+ try {
3398
+ const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
3399
+ if (storage) storage.setItem(FAVORITES_ONLY_STORAGE_KEY, next.favoritesOnly ? "1" : "0")
3400
+ } catch (_) {}
3401
+ return next
3402
+ }
3403
+
3404
+ function readFavoritesOnly() {
3405
+ return !!readUiState().favoritesOnly
3406
+ }
3407
+
3408
+ function saveFavoritesOnly(value) {
3409
+ saveUiState({ favoritesOnly: !!value })
3410
+ }
3411
+
3412
+ function readStrongCategories() {
3413
+ const value = readUiState().strongCategories
3414
+ return Array.isArray(value) ? value : null
3415
+ }
3416
+
3417
+ function saveStrongCategories(value) {
3418
+ saveUiState({ strongCategories: Array.isArray(value) ? value : null })
3419
+ }
2808
3420
  const PLAN_SELECTION_STORAGE_KEY = "poi-plugin-koushu-rate:plan-selection";
2809
3421
 
2810
3422
  function readPlanSelection() {
@@ -2866,8 +3478,8 @@ class KoushuRateApp extends React.Component {
2866
3478
  useItemCounts: {},
2867
3479
  kcDevData: null,
2868
3480
  favorites: readFavorites(),
2869
- favoritesOnly: false,
2870
- starSort: null,
3481
+ favoritesOnly: readFavoritesOnly(),
3482
+ starSort: readUiState().starSort || null,
2871
3483
  activeTab: "list",
2872
3484
  planSelection: readPlanSelection(),
2873
3485
  includeDevExpected: readPlanIncludeDev(),
@@ -2957,13 +3569,19 @@ class KoushuRateApp extends React.Component {
2957
3569
  }
2958
3570
 
2959
3571
  toggleFavoritesOnly = () => {
2960
- this.setState((prev) => ({ favoritesOnly: !prev.favoritesOnly }))
3572
+ this.setState((prev) => {
3573
+ const favoritesOnly = !prev.favoritesOnly
3574
+ saveFavoritesOnly(favoritesOnly)
3575
+ return { favoritesOnly }
3576
+ })
2961
3577
  }
2962
3578
 
2963
3579
  toggleStarSort = () => {
2964
- this.setState((prev) => ({
2965
- starSort: prev.starSort === "desc" ? "asc" : prev.starSort === "asc" ? null : "desc",
2966
- }))
3580
+ this.setState((prev) => {
3581
+ const starSort = prev.starSort === "desc" ? "asc" : prev.starSort === "asc" ? null : "desc"
3582
+ saveUiState({ starSort })
3583
+ return { starSort }
3584
+ })
2967
3585
  }
2968
3586
 
2969
3587
  toggleCategory = () => {
@@ -3053,7 +3671,18 @@ class KoushuRateApp extends React.Component {
3053
3671
  setPlanTarget = (id, target) => {
3054
3672
  this.setState((prev) => {
3055
3673
  const cur = prev.planSelection[id] || this.planDefaultSel(id)
3056
- const planSelection = Object.assign({}, prev.planSelection, { [id]: Object.assign({}, cur, { target }) })
3674
+ const next = Object.assign({}, cur, { target, evoUpgradeId: null })
3675
+ const planSelection = Object.assign({}, prev.planSelection, { [id]: next })
3676
+ savePlanSelection(planSelection)
3677
+ return { planSelection }
3678
+ })
3679
+ }
3680
+
3681
+ setPlanEvo = (id, upgradeId) => {
3682
+ this.setState((prev) => {
3683
+ const cur = prev.planSelection[id] || this.planDefaultSel(id)
3684
+ const next = Object.assign({}, cur, { target: "max", evoUpgradeId: upgradeId == null ? null : String(upgradeId) })
3685
+ const planSelection = Object.assign({}, prev.planSelection, { [id]: next })
3057
3686
  savePlanSelection(planSelection)
3058
3687
  return { planSelection }
3059
3688
  })
@@ -3161,6 +3790,7 @@ class KoushuRateApp extends React.Component {
3161
3790
  React.createElement(
3162
3791
  "div",
3163
3792
  { className: "kr2-header" },
3793
+
3164
3794
  React.createElement(
3165
3795
  "div",
3166
3796
  { className: "kr2-title-row" },
@@ -3204,7 +3834,14 @@ class KoushuRateApp extends React.Component {
3204
3834
  ),
3205
3835
  React.createElement(
3206
3836
  "div",
3207
- { className: "kr2-toolbar", style: this.state.activeTab === "plan" ? { display: "none" } : null },
3837
+ { className: "kr2-nav" },
3838
+ React.createElement("button", { className: "kr2-nav-btn" + (this.state.activeTab === "list" ? " kr2-nav-active" : ""), onClick: () => this.setActiveTab("list") }, "改修列表"),
3839
+ React.createElement("button", { className: "kr2-nav-btn" + (this.state.activeTab === "plan" ? " kr2-nav-active" : ""), onClick: () => this.setActiveTab("plan") }, "素材计算"),
3840
+ React.createElement("button", { className: "kr2-nav-btn" + (this.state.activeTab === "strong" ? " kr2-nav-active" : ""), onClick: () => this.setActiveTab("strong") }, "我变强了!")
3841
+ ),
3842
+ React.createElement(
3843
+ "div",
3844
+ { className: "kr2-toolbar", style: this.state.activeTab === "plan" || this.state.activeTab === "strong" ? { display: "none" } : null },
3208
3845
  React.createElement("input", {
3209
3846
  className: "kr2-search",
3210
3847
  value: this.state.query,
@@ -3246,15 +3883,10 @@ class KoushuRateApp extends React.Component {
3246
3883
  : null
3247
3884
  )
3248
3885
  ),
3886
+
3249
3887
  React.createElement(
3250
3888
  "div",
3251
- { className: "kr2-nav" },
3252
- React.createElement("button", { className: "kr2-nav-btn" + (this.state.activeTab === "list" ? " kr2-nav-active" : ""), onClick: () => this.setActiveTab("list") }, "改修列表"),
3253
- React.createElement("button", { className: "kr2-nav-btn" + (this.state.activeTab === "plan" ? " kr2-nav-active" : ""), onClick: () => this.setActiveTab("plan") }, "素材计算")
3254
- ),
3255
- React.createElement(
3256
- "div",
3257
- { className: "kr2-days", style: this.state.activeTab === "plan" ? { display: "none" } : null },
3889
+ { className: "kr2-days", style: this.state.activeTab === "plan" || this.state.activeTab === "strong" ? { display: "none" } : null },
3258
3890
  React.createElement(
3259
3891
  "button",
3260
3892
  { className: "kr2-day" + (day === ALL_DAYS_KEY ? " kr2-day-active" : ""), onClick: () => this.setState({ day: ALL_DAYS_KEY }) },
@@ -3279,7 +3911,7 @@ class KoushuRateApp extends React.Component {
3279
3911
  : null,
3280
3912
  React.createElement(
3281
3913
  "div",
3282
- { className: "kr2-list-head", style: this.state.activeTab === "plan" ? { display: "none" } : null },
3914
+ { className: "kr2-list-head", style: this.state.activeTab === "plan" || this.state.activeTab === "strong" ? { display: "none" } : null },
3283
3915
  React.createElement("span", { className: "kr2-head-name" }, "装备"),
3284
3916
  React.createElement("span", { className: "kr2-head-secretary" }, "秘书舰"),
3285
3917
  React.createElement("span", { className: "kr2-head-meta" }, "可改修日期"),
@@ -3296,7 +3928,7 @@ class KoushuRateApp extends React.Component {
3296
3928
  ),
3297
3929
  React.createElement(
3298
3930
  "div",
3299
- { className: "kr2-list", style: this.state.activeTab === "plan" ? { display: "none" } : null },
3931
+ { className: "kr2-list", style: this.state.activeTab === "plan" || this.state.activeTab === "strong" ? { display: "none" } : null },
3300
3932
  rows.length === 0
3301
3933
  ? React.createElement("div", { className: "kr2-empty" }, favoritesOnly ? "还没有收藏装备" : "没有匹配的装备")
3302
3934
  : rows.map((row) =>
@@ -3323,6 +3955,7 @@ class KoushuRateApp extends React.Component {
3323
3955
  selection: this.state.planSelection || {},
3324
3956
  onToggle: this.togglePlanRow,
3325
3957
  onTarget: this.setPlanTarget,
3958
+ onEvo: this.setPlanEvo,
3326
3959
  onQty: this.setPlanQty,
3327
3960
  onSelectAll: this.selectAllPlan,
3328
3961
  onMaterialClick: this.openKcDevPopup,
@@ -3331,6 +3964,13 @@ class KoushuRateApp extends React.Component {
3331
3964
  onToggleIncludeDevExpected: this.toggleIncludeDevExpected,
3332
3965
  })
3333
3966
  : null,
3967
+ this.state.activeTab === "strong"
3968
+ ? React.createElement(StrongPage, {
3969
+ rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
3970
+ inventoryByEquip,
3971
+ selection: this.state.planSelection || {},
3972
+ })
3973
+ : null,
3334
3974
  kcDevPopup
3335
3975
  ? React.createElement(
3336
3976
  "div",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poi-plugin-koushu-rate",
3
- "version": "2.0.12",
3
+ "version": "2.0.14",
4
4
  "description": "全装备改修资材计算与推荐",
5
5
  "main": "index.js",
6
6
  "files": [