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.
- package/index.js +688 -48
- 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→
|
|
21
|
-
{ range: "
|
|
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
|
-
|
|
164
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2289
|
-
|
|
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
|
-
"
|
|
2387
|
-
{
|
|
2388
|
-
React.createElement("
|
|
2389
|
-
|
|
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
|
-
:
|
|
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→
|
|
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:
|
|
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) =>
|
|
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
|
|
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
|
|
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-
|
|
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-
|
|
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",
|