poi-plugin-koushu-rate 2.0.17 → 2.0.19
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/data/equipment_rarity.json +175 -0
- package/index.js +669 -222
- package/package.json +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
{
|
|
2
|
+
"source": "用户装备拆解指南 2026-08-25(合并稀有/次级稀有)",
|
|
3
|
+
"rare": [
|
|
4
|
+
"10.5cm連装砲",
|
|
5
|
+
"10cm連装高角砲(砲架)",
|
|
6
|
+
"12.7cm単装高角砲(後期型)",
|
|
7
|
+
"12.7cm連装高角砲(後期型)",
|
|
8
|
+
"12.7cm連装砲C型改二",
|
|
9
|
+
"12.7cm連装砲D型改二",
|
|
10
|
+
"120mm/50 連装砲",
|
|
11
|
+
"12cm30連装噴進砲",
|
|
12
|
+
"12cm単装高角砲",
|
|
13
|
+
"12cm単装高角砲E型",
|
|
14
|
+
"13.8cm連装砲",
|
|
15
|
+
"130mm B-13連装砲",
|
|
16
|
+
"13号対空電探",
|
|
17
|
+
"13号対空電探改",
|
|
18
|
+
"13号対空電探改(後期型)",
|
|
19
|
+
"14cm連装砲改",
|
|
20
|
+
"15.2cm連装砲改",
|
|
21
|
+
"15.2cm三連装砲",
|
|
22
|
+
"15cm連装副砲",
|
|
23
|
+
"16inch Mk.I連装砲",
|
|
24
|
+
"16inch Mk.I三連装砲",
|
|
25
|
+
"16inch Mk.V連装砲",
|
|
26
|
+
"16inch三連装砲 Mk.6",
|
|
27
|
+
"16inch三連装砲 Mk.6 mod.2",
|
|
28
|
+
"16inch三連装砲 Mk.7",
|
|
29
|
+
"20.3cm(3号)連装砲",
|
|
30
|
+
"203mm/53 連装砲",
|
|
31
|
+
"20連装7inch UP Rocket Launchers",
|
|
32
|
+
"22号対水上電探改四",
|
|
33
|
+
"25mm三連装機銃",
|
|
34
|
+
"25mm三連装機銃 集中配備",
|
|
35
|
+
"2cm 四連装FlaK 38",
|
|
36
|
+
"3.7cm FlaK M42",
|
|
37
|
+
"30.5cm三連装砲改",
|
|
38
|
+
"32号対水上電探",
|
|
39
|
+
"33号対水上電探",
|
|
40
|
+
"35.6cm連装砲(ダズル迷彩)",
|
|
41
|
+
"35.6cm連装砲改",
|
|
42
|
+
"38.1cm Mk.I連装砲",
|
|
43
|
+
"381mm/50 三連装砲",
|
|
44
|
+
"381mm/50 三連装砲改",
|
|
45
|
+
"38cm連装砲",
|
|
46
|
+
"38cm連装砲改",
|
|
47
|
+
"38cm四連装砲",
|
|
48
|
+
"38cm四連装砲改",
|
|
49
|
+
"42号対空電探",
|
|
50
|
+
"46cm三連装砲",
|
|
51
|
+
"46cm三連装砲改",
|
|
52
|
+
"533mm 三連装魚雷",
|
|
53
|
+
"533mm五連装魚雷(初期型)",
|
|
54
|
+
"53cm連装魚雷",
|
|
55
|
+
"5inch 単装高角砲群",
|
|
56
|
+
"5inch単装砲 Mk.30",
|
|
57
|
+
"5inch連装砲 Mk.28 mod.2",
|
|
58
|
+
"61cm三連装(酸素)魚雷",
|
|
59
|
+
"61cm五連装(酸素)魚雷",
|
|
60
|
+
"6inch Mk.XXIII三連装砲",
|
|
61
|
+
"6inch三連装速射砲 Mk.16 mod.2",
|
|
62
|
+
"8cm高角砲",
|
|
63
|
+
"8inch三連装砲 Mk.9",
|
|
64
|
+
"90mm単装高角砲",
|
|
65
|
+
"94式高射装置",
|
|
66
|
+
"彩雲",
|
|
67
|
+
"大発動艇(八九式中戦車&陸戦隊)",
|
|
68
|
+
"二式12cm迫撃砲改",
|
|
69
|
+
"二式爆雷",
|
|
70
|
+
"二式大艇",
|
|
71
|
+
"二式複戦 屠龍",
|
|
72
|
+
"二式複戦 屠龍 丙型",
|
|
73
|
+
"二式艦上偵察機",
|
|
74
|
+
"発煙装置(煙幕)",
|
|
75
|
+
"彗星(六〇一空)",
|
|
76
|
+
"艦艇修理施設",
|
|
77
|
+
"艦載型 四式20cm対地噴進砲",
|
|
78
|
+
"九八式水上偵察機(夜偵)",
|
|
79
|
+
"九九式艦爆(江草隊)",
|
|
80
|
+
"九九式艦爆(熟練)",
|
|
81
|
+
"九九式艦爆二二型",
|
|
82
|
+
"九六式艦戦改",
|
|
83
|
+
"九六式陸攻",
|
|
84
|
+
"九七式艦攻(九三一空)",
|
|
85
|
+
"九七式艦攻(熟練)",
|
|
86
|
+
"九七式艦攻(友永隊)",
|
|
87
|
+
"九七式艦攻改 試製三号戊型(空六号電探改装備機)",
|
|
88
|
+
"九一式徹甲弾",
|
|
89
|
+
"烈風 一一型",
|
|
90
|
+
"零式艦戦21型(熟練)",
|
|
91
|
+
"零式艦戦32型(熟練)",
|
|
92
|
+
"零式艦戦62型(爆戦)",
|
|
93
|
+
"零式艦戦63型(爆戦)",
|
|
94
|
+
"零式水上偵察機11型乙",
|
|
95
|
+
"零式小型水上機",
|
|
96
|
+
"零戦52型丙(六〇一空)",
|
|
97
|
+
"流星(六〇一空)",
|
|
98
|
+
"流星改",
|
|
99
|
+
"流星改(熟練)",
|
|
100
|
+
"毘式40mm連装機銃",
|
|
101
|
+
"秋刀魚の缶詰",
|
|
102
|
+
"瑞雲12型",
|
|
103
|
+
"瑞雲12型(六三四空)",
|
|
104
|
+
"三式爆雷投射機 集中配備",
|
|
105
|
+
"三式弾",
|
|
106
|
+
"試製35.6cm三連装砲",
|
|
107
|
+
"試製41cm三連装砲",
|
|
108
|
+
"試製46cm連装砲",
|
|
109
|
+
"試製51cm連装砲",
|
|
110
|
+
"試製烈風 後期型",
|
|
111
|
+
"試製晴嵐",
|
|
112
|
+
"試製FaT仕様九五式酸素魚雷改",
|
|
113
|
+
"熟練甲板要員",
|
|
114
|
+
"熟練見張員",
|
|
115
|
+
"四式水中聴音機",
|
|
116
|
+
"天山(六〇一空)",
|
|
117
|
+
"天山一二型甲",
|
|
118
|
+
"通信装置&要員",
|
|
119
|
+
"新型高温高圧缶",
|
|
120
|
+
"洋上補給",
|
|
121
|
+
"一式陸攻",
|
|
122
|
+
"一式陸攻 二二型甲",
|
|
123
|
+
"一式戦 隼II型",
|
|
124
|
+
"増設バルジ(大型艦)",
|
|
125
|
+
"増設バルジ(中型艦)",
|
|
126
|
+
"戦闘糧食",
|
|
127
|
+
"戦闘糧食(特別なおにぎり)",
|
|
128
|
+
"照明弾",
|
|
129
|
+
"紫電二一型 紫電改",
|
|
130
|
+
"紫電改二",
|
|
131
|
+
"紫電一一型",
|
|
132
|
+
"Ar196改",
|
|
133
|
+
"Bf109T改",
|
|
134
|
+
"Bofors 40mm四連装機関砲",
|
|
135
|
+
"Bofors15.2cm連装砲 Model1930",
|
|
136
|
+
"F4F-3",
|
|
137
|
+
"F4F-4",
|
|
138
|
+
"F4U-1D",
|
|
139
|
+
"F6F-3",
|
|
140
|
+
"FM-2",
|
|
141
|
+
"Fulmar",
|
|
142
|
+
"FuMO25 レーダー",
|
|
143
|
+
"Fw190T改",
|
|
144
|
+
"GFCS Mk.37",
|
|
145
|
+
"Ju87C改",
|
|
146
|
+
"OS2U",
|
|
147
|
+
"OTO 152mm三連装速射砲",
|
|
148
|
+
"QF 2ポンド8連装ポンポン砲",
|
|
149
|
+
"QF 4.7inch砲 Mk.XII改",
|
|
150
|
+
"Re.2001 G改",
|
|
151
|
+
"Re.2001 OR改",
|
|
152
|
+
"Ro.44水上戦闘機",
|
|
153
|
+
"S9 Osprey",
|
|
154
|
+
"SB2C-3",
|
|
155
|
+
"SBD",
|
|
156
|
+
"SG レーダー(初期型)",
|
|
157
|
+
"SKC34 20.3cm連装砲",
|
|
158
|
+
"Skua",
|
|
159
|
+
"SKレーダー",
|
|
160
|
+
"SM.79",
|
|
161
|
+
"SOC Seagull",
|
|
162
|
+
"Spitfire Mk.I",
|
|
163
|
+
"Spitfire Mk.V",
|
|
164
|
+
"Swordfish",
|
|
165
|
+
"Swordfish Mk.II(熟練)",
|
|
166
|
+
"Swordfish Mk.II改(水偵型)",
|
|
167
|
+
"TBD",
|
|
168
|
+
"TBF",
|
|
169
|
+
"Type124 ASDIC",
|
|
170
|
+
"Type144/147 ASDIC",
|
|
171
|
+
"オ号観測機改",
|
|
172
|
+
"プリエーゼ式水中防御隔壁"
|
|
173
|
+
],
|
|
174
|
+
"secondary": []
|
|
175
|
+
}
|
package/index.js
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
const React = require("react");
|
|
2
2
|
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const { WindowEnv } = require("views/components/etc/window-env");
|
|
5
|
-
const { SlotitemIcon, MaterialIcon } = require("views/components/etc/icon");
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { WindowEnv } = require("views/components/etc/window-env");
|
|
5
|
+
const { SlotitemIcon, MaterialIcon } = require("views/components/etc/icon");
|
|
6
|
+
|
|
7
|
+
function readPluginVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const info = require("./package.json")
|
|
10
|
+
return String((info && info.version) || "0.0.0")
|
|
11
|
+
} catch (_) {
|
|
12
|
+
return "0.0.0"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PLUGIN_VERSION = readPluginVersion()
|
|
17
|
+
const HELP_PAGE_REVISION = "1"
|
|
18
|
+
const HELP_VERSION = PLUGIN_VERSION + "." + HELP_PAGE_REVISION
|
|
19
|
+
const HELP_UPDATE_NOTES = {
|
|
20
|
+
"2.0.17": [
|
|
21
|
+
"新增使用说明页与更新提示。",
|
|
22
|
+
"新增稀有素材消耗提示。",
|
|
23
|
+
"素材计算新增排序与开发资材期望统计。",
|
|
24
|
+
"“我变强了!”新增完成度、库存合并与进化目标标记。",
|
|
25
|
+
],
|
|
26
|
+
"2.0.18": [
|
|
27
|
+
"新增稀有素材消耗提示;",
|
|
28
|
+
"优化了装备进化在我变强了页中的显示逻辑,现在会和进化后的改修计划分开统计,以方便检查阶段性目标的完成情况;",
|
|
29
|
+
"优化了我变强了页中的目标/已有装备的显示,现在不会自动拆分已完成的装备单独置顶显示了;",
|
|
30
|
+
"在改修列表页新增了改修计划的显示(装备名称的下方)。",
|
|
31
|
+
],
|
|
32
|
+
"2.0.19": [
|
|
33
|
+
"“我变强了”页中,完成数与目标数相等并置顶时,完成数列改为显示 clear!。",
|
|
34
|
+
],
|
|
35
|
+
}
|
|
36
|
+
const CURRENT_HELP_UPDATE_NOTES = HELP_UPDATE_NOTES[PLUGIN_VERSION] || ["本次更新暂无详细说明。"]
|
|
37
|
+
|
|
38
|
+
const LEVEL_ONE_ROWS = [
|
|
8
39
|
{ range: "★0→1", p: 1.0 },
|
|
9
40
|
{ range: "★1→2", p: 1.0 },
|
|
10
41
|
{ range: "★2→3", p: 1.0 },
|
|
@@ -37,10 +68,33 @@ const PLAN_LEVELS_MAX = PLAN_LEVELS_6.concat([
|
|
|
37
68
|
]);
|
|
38
69
|
|
|
39
70
|
const WEEKDAY_KEYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
|
|
40
|
-
const WEEKDAY_LABELS = { monday: "周一", tuesday: "周二", wednesday: "周三", thursday: "周四", friday: "周五", saturday: "周六", sunday: "周日" };
|
|
41
|
-
const ALL_DAYS_KEY = "all";
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
const WEEKDAY_LABELS = { monday: "周一", tuesday: "周二", wednesday: "周三", thursday: "周四", friday: "周五", saturday: "周六", sunday: "周日" };
|
|
72
|
+
const ALL_DAYS_KEY = "all";
|
|
73
|
+
const RARE_MATERIAL_KEYS = new Set([
|
|
74
|
+
"新型砲熕兵装資材",
|
|
75
|
+
"新型兵装資材",
|
|
76
|
+
"戦闘詳報",
|
|
77
|
+
"勲章",
|
|
78
|
+
"ネ式エンジン",
|
|
79
|
+
"熟練搭乗員",
|
|
80
|
+
"海外艦最新技術",
|
|
81
|
+
"新型航空兵装資材",
|
|
82
|
+
"工廠資源",
|
|
83
|
+
"新型噴進装備開発資材",
|
|
84
|
+
"潜水艦補給物資",
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
let RARE_EQUIP_NAMES = null
|
|
88
|
+
let SECONDARY_EQUIP_NAMES = null
|
|
89
|
+
function getRareEquipSets() {
|
|
90
|
+
if (RARE_EQUIP_NAMES) return { rare: RARE_EQUIP_NAMES, secondary: SECONDARY_EQUIP_NAMES }
|
|
91
|
+
const data = loadJson("equipment_rarity.json") || {}
|
|
92
|
+
RARE_EQUIP_NAMES = new Set(data.rare || [])
|
|
93
|
+
SECONDARY_EQUIP_NAMES = new Set(data.secondary || [])
|
|
94
|
+
return { rare: RARE_EQUIP_NAMES, secondary: SECONDARY_EQUIP_NAMES }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function japanWeekdayKey() {
|
|
44
98
|
const japanNow = new Date(Date.now() + 9 * 60 * 60 * 1000)
|
|
45
99
|
return ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"][japanNow.getUTCDay()]
|
|
46
100
|
}
|
|
@@ -158,17 +212,36 @@ const CSS = `
|
|
|
158
212
|
padding: 12px 14px 20px;
|
|
159
213
|
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
|
160
214
|
}
|
|
161
|
-
.kr2-title-row {
|
|
162
|
-
display: flex;
|
|
163
|
-
flex-direction: column;
|
|
164
|
-
align-items: stretch;
|
|
165
|
-
justify-content: flex-start;
|
|
166
|
-
gap: 12px;
|
|
167
|
-
}
|
|
168
|
-
.kr2-title {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
215
|
+
.kr2-title-row {
|
|
216
|
+
display: flex;
|
|
217
|
+
flex-direction: column;
|
|
218
|
+
align-items: stretch;
|
|
219
|
+
justify-content: flex-start;
|
|
220
|
+
gap: 12px;
|
|
221
|
+
}
|
|
222
|
+
.kr2-title-line {
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
gap: 10px;
|
|
226
|
+
flex-wrap: wrap;
|
|
227
|
+
}
|
|
228
|
+
.kr2-title {
|
|
229
|
+
font-size: 18px;
|
|
230
|
+
font-weight: 800;
|
|
231
|
+
}
|
|
232
|
+
.kr2-help-btn {
|
|
233
|
+
padding: 4px 10px;
|
|
234
|
+
border: 1px solid #5f6b7c;
|
|
235
|
+
border-radius: 4px;
|
|
236
|
+
background: #2f343c;
|
|
237
|
+
color: #8abbff;
|
|
238
|
+
font-size: 12px;
|
|
239
|
+
cursor: pointer;
|
|
240
|
+
}
|
|
241
|
+
.kr2-help-btn:hover {
|
|
242
|
+
background: #383e47;
|
|
243
|
+
color: #a8c8ff;
|
|
244
|
+
}
|
|
172
245
|
.kr2-title-note {
|
|
173
246
|
margin-top: 2px;
|
|
174
247
|
font-size: 18px;
|
|
@@ -570,17 +643,41 @@ const CSS = `
|
|
|
570
643
|
color: #d6e4f5;
|
|
571
644
|
}
|
|
572
645
|
|
|
573
|
-
.kr2-strong {
|
|
574
|
-
margin-top: 12px;
|
|
575
|
-
flex: 1;
|
|
646
|
+
.kr2-strong {
|
|
647
|
+
margin-top: 12px;
|
|
648
|
+
flex: 1;
|
|
576
649
|
min-height: 60vh;
|
|
577
650
|
overflow-x: hidden;
|
|
578
651
|
overflow-y: auto;
|
|
579
652
|
}
|
|
580
|
-
.kr2-strong-table {
|
|
581
|
-
border-collapse: separate;
|
|
582
|
-
border-spacing: 0;
|
|
583
|
-
|
|
653
|
+
.kr2-table.kr2-strong-table {
|
|
654
|
+
border-collapse: separate;
|
|
655
|
+
border-spacing: 0;
|
|
656
|
+
table-layout: fixed;
|
|
657
|
+
width: 100%;
|
|
658
|
+
}
|
|
659
|
+
.kr2-strong-table th:nth-child(1),
|
|
660
|
+
.kr2-strong-table td:nth-child(1) {
|
|
661
|
+
width: 100px;
|
|
662
|
+
}
|
|
663
|
+
.kr2-strong-table th:nth-child(2),
|
|
664
|
+
.kr2-strong-table td:nth-child(2) {
|
|
665
|
+
width: 32%;
|
|
666
|
+
}
|
|
667
|
+
.kr2-strong-table th:nth-child(4),
|
|
668
|
+
.kr2-strong-table td:nth-child(4) {
|
|
669
|
+
width: 48px;
|
|
670
|
+
padding-left: 2px !important;
|
|
671
|
+
padding-right: 2px !important;
|
|
672
|
+
white-space: nowrap;
|
|
673
|
+
}
|
|
674
|
+
.kr2-strong-table th:nth-child(5),
|
|
675
|
+
.kr2-strong-table td:nth-child(5) {
|
|
676
|
+
width: 64px;
|
|
677
|
+
padding-left: 2px !important;
|
|
678
|
+
padding-right: 2px !important;
|
|
679
|
+
white-space: nowrap;
|
|
680
|
+
}
|
|
584
681
|
.kr2-strong-cat-th {
|
|
585
682
|
position: relative;
|
|
586
683
|
cursor: pointer;
|
|
@@ -631,9 +728,10 @@ const CSS = `
|
|
|
631
728
|
.kr2-strong-table tbody tr:last-child td {
|
|
632
729
|
border-bottom: 0;
|
|
633
730
|
}
|
|
634
|
-
.kr2-strong-equip {
|
|
635
|
-
text-align:
|
|
636
|
-
white-space: normal;
|
|
731
|
+
.kr2-strong-equip {
|
|
732
|
+
text-align: center !important;
|
|
733
|
+
white-space: normal;
|
|
734
|
+
font-weight: 700;
|
|
637
735
|
}
|
|
638
736
|
.kr2-strong-level {
|
|
639
737
|
display: inline-flex;
|
|
@@ -649,10 +747,20 @@ const CSS = `
|
|
|
649
747
|
color: #ffffff;
|
|
650
748
|
font-weight: 700;
|
|
651
749
|
}
|
|
652
|
-
.kr2-strong-stock {
|
|
653
|
-
white-space: normal;
|
|
654
|
-
|
|
655
|
-
|
|
750
|
+
.kr2-strong-stock {
|
|
751
|
+
white-space: normal;
|
|
752
|
+
text-align: center !important;
|
|
753
|
+
}
|
|
754
|
+
.kr2-strong-stock-th {
|
|
755
|
+
text-align: center !important;
|
|
756
|
+
}
|
|
757
|
+
.kr2-strong-stock-line {
|
|
758
|
+
display: block;
|
|
759
|
+
}
|
|
760
|
+
.kr2-strong-stock-line + .kr2-strong-stock-line {
|
|
761
|
+
margin-top: 2px;
|
|
762
|
+
}
|
|
763
|
+
.kr2-strong-stock-name {
|
|
656
764
|
color: #ffffff;
|
|
657
765
|
font-weight: 700;
|
|
658
766
|
}
|
|
@@ -687,10 +795,28 @@ const CSS = `
|
|
|
687
795
|
.kr2-strong-owned.kr2-strong-stock-short {
|
|
688
796
|
color: #ff6b6b;
|
|
689
797
|
}
|
|
690
|
-
.kr2-strong-owned.kr2-strong-stock-clear {
|
|
691
|
-
color: #4fc3f7;
|
|
692
|
-
}
|
|
693
|
-
.kr2-strong-
|
|
798
|
+
.kr2-strong-owned.kr2-strong-stock-clear {
|
|
799
|
+
color: #4fc3f7;
|
|
800
|
+
}
|
|
801
|
+
.kr2-strong-owned-line {
|
|
802
|
+
display: block;
|
|
803
|
+
}
|
|
804
|
+
.kr2-strong-owned-line + .kr2-strong-owned-line {
|
|
805
|
+
margin-top: 2px;
|
|
806
|
+
}
|
|
807
|
+
.kr2-strong-owned-line-clear {
|
|
808
|
+
color: #4fc3f7;
|
|
809
|
+
}
|
|
810
|
+
.kr2-strong-owned-line-short {
|
|
811
|
+
color: #ff6b6b;
|
|
812
|
+
}
|
|
813
|
+
.kr2-strong-owned-line-missing {
|
|
814
|
+
color: #abb3bf;
|
|
815
|
+
}
|
|
816
|
+
.kr2-strong-completion-done {
|
|
817
|
+
color: #4fc3f7;
|
|
818
|
+
}
|
|
819
|
+
.kr2-strong-clear-row td {
|
|
694
820
|
color: #4fc3f7;
|
|
695
821
|
}
|
|
696
822
|
.kr2-strong-clear-row .kr2-strong-target,
|
|
@@ -866,12 +992,18 @@ const CSS = `
|
|
|
866
992
|
color: #abb3bf;
|
|
867
993
|
cursor: default;
|
|
868
994
|
}
|
|
869
|
-
.kr2-row-not-improveable .kr2-name,
|
|
870
|
-
.kr2-row-not-improveable .kr2-secretary,
|
|
871
|
-
.kr2-row-not-improveable .kr2-meta {
|
|
872
|
-
color: #abb3bf;
|
|
873
|
-
}
|
|
874
|
-
.kr2-
|
|
995
|
+
.kr2-row-not-improveable .kr2-name,
|
|
996
|
+
.kr2-row-not-improveable .kr2-secretary,
|
|
997
|
+
.kr2-row-not-improveable .kr2-meta {
|
|
998
|
+
color: #abb3bf;
|
|
999
|
+
}
|
|
1000
|
+
.kr2-row-clear {
|
|
1001
|
+
background: rgba(79, 195, 247, 0.14);
|
|
1002
|
+
}
|
|
1003
|
+
.kr2-row-clear:hover {
|
|
1004
|
+
background: rgba(79, 195, 247, 0.2);
|
|
1005
|
+
}
|
|
1006
|
+
.kr2-reco-empty {
|
|
875
1007
|
min-height: 34px;
|
|
876
1008
|
}
|
|
877
1009
|
.kr2-not-improveable-group {
|
|
@@ -961,14 +1093,35 @@ const CSS = `
|
|
|
961
1093
|
font-size: 9px;
|
|
962
1094
|
line-height: 1.2;
|
|
963
1095
|
}
|
|
964
|
-
.kr2-name {
|
|
965
|
-
flex: 1 1 0;
|
|
966
|
-
min-width: 0;
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
1096
|
+
.kr2-name-cell {
|
|
1097
|
+
flex: 1 1 0;
|
|
1098
|
+
min-width: 0;
|
|
1099
|
+
display: flex;
|
|
1100
|
+
flex-direction: column;
|
|
1101
|
+
justify-content: center;
|
|
1102
|
+
gap: 1px;
|
|
1103
|
+
}
|
|
1104
|
+
.kr2-name {
|
|
1105
|
+
font-weight: 600;
|
|
1106
|
+
white-space: nowrap;
|
|
1107
|
+
overflow: hidden;
|
|
1108
|
+
text-overflow: ellipsis;
|
|
1109
|
+
}
|
|
1110
|
+
.kr2-name-completion {
|
|
1111
|
+
font-size: 11px;
|
|
1112
|
+
line-height: 1.2;
|
|
1113
|
+
white-space: nowrap;
|
|
1114
|
+
font-weight: 400;
|
|
1115
|
+
}
|
|
1116
|
+
.kr2-name-completion-incomplete {
|
|
1117
|
+
color: #ff6b6b;
|
|
1118
|
+
}
|
|
1119
|
+
.kr2-name-completion-done-active {
|
|
1120
|
+
color: #4fc3f7;
|
|
1121
|
+
}
|
|
1122
|
+
.kr2-name-completion-clear {
|
|
1123
|
+
color: #4fc3f7;
|
|
1124
|
+
}
|
|
972
1125
|
.kr2-secretary {
|
|
973
1126
|
flex: 1 1 0;
|
|
974
1127
|
min-width: 0;
|
|
@@ -1117,7 +1270,17 @@ const CSS = `
|
|
|
1117
1270
|
align-items: flex-end;
|
|
1118
1271
|
gap: 6px;
|
|
1119
1272
|
}
|
|
1120
|
-
.kr2-
|
|
1273
|
+
.kr2-rare-warning {
|
|
1274
|
+
color: #ff6b6b;
|
|
1275
|
+
font-size: 11px;
|
|
1276
|
+
white-space: nowrap;
|
|
1277
|
+
}
|
|
1278
|
+
.kr2-rare-warning-secondary {
|
|
1279
|
+
color: #ffb3b3;
|
|
1280
|
+
font-size: 11px;
|
|
1281
|
+
white-space: nowrap;
|
|
1282
|
+
}
|
|
1283
|
+
.kr2-material-list {
|
|
1121
1284
|
display: flex;
|
|
1122
1285
|
flex-direction: column;
|
|
1123
1286
|
align-items: flex-end;
|
|
@@ -1235,11 +1398,64 @@ const CSS = `
|
|
|
1235
1398
|
font-size: 12px;
|
|
1236
1399
|
margin-top: 2px;
|
|
1237
1400
|
}
|
|
1238
|
-
.kr2-modal-actions {
|
|
1239
|
-
display: flex;
|
|
1240
|
-
gap: 8px;
|
|
1241
|
-
}
|
|
1242
|
-
.kr2-
|
|
1401
|
+
.kr2-modal-actions {
|
|
1402
|
+
display: flex;
|
|
1403
|
+
gap: 8px;
|
|
1404
|
+
}
|
|
1405
|
+
.kr2-modal-close {
|
|
1406
|
+
width: 30px;
|
|
1407
|
+
height: 30px;
|
|
1408
|
+
padding: 0;
|
|
1409
|
+
display: flex;
|
|
1410
|
+
align-items: center;
|
|
1411
|
+
justify-content: center;
|
|
1412
|
+
border: 1px solid #5f6b7c;
|
|
1413
|
+
border-radius: 4px;
|
|
1414
|
+
background: #2f343c;
|
|
1415
|
+
color: #f6f7f9;
|
|
1416
|
+
font-size: 18px;
|
|
1417
|
+
line-height: 1;
|
|
1418
|
+
cursor: pointer;
|
|
1419
|
+
}
|
|
1420
|
+
.kr2-modal-close:hover {
|
|
1421
|
+
background: #383e47;
|
|
1422
|
+
color: #fff;
|
|
1423
|
+
}
|
|
1424
|
+
.kr2-help-modal {
|
|
1425
|
+
width: 720px;
|
|
1426
|
+
}
|
|
1427
|
+
.kr2-help-body {
|
|
1428
|
+
flex: 1;
|
|
1429
|
+
min-height: 0;
|
|
1430
|
+
overflow-y: auto;
|
|
1431
|
+
padding: 14px 16px 18px;
|
|
1432
|
+
}
|
|
1433
|
+
.kr2-help-lead {
|
|
1434
|
+
margin-bottom: 10px;
|
|
1435
|
+
color: #8abbff;
|
|
1436
|
+
font-size: 14px;
|
|
1437
|
+
font-weight: 800;
|
|
1438
|
+
}
|
|
1439
|
+
.kr2-help-section + .kr2-help-section {
|
|
1440
|
+
margin-top: 14px;
|
|
1441
|
+
}
|
|
1442
|
+
.kr2-help-section-title {
|
|
1443
|
+
margin-bottom: 6px;
|
|
1444
|
+
color: #8abbff;
|
|
1445
|
+
font-size: 14px;
|
|
1446
|
+
font-weight: 800;
|
|
1447
|
+
}
|
|
1448
|
+
.kr2-help-list {
|
|
1449
|
+
margin: 0;
|
|
1450
|
+
padding-left: 20px;
|
|
1451
|
+
color: #d6d9de;
|
|
1452
|
+
font-size: 13px;
|
|
1453
|
+
line-height: 1.7;
|
|
1454
|
+
}
|
|
1455
|
+
.kr2-help-list li + li {
|
|
1456
|
+
margin-top: 2px;
|
|
1457
|
+
}
|
|
1458
|
+
.kr2-dev-scroll {
|
|
1243
1459
|
flex: 1;
|
|
1244
1460
|
min-height: 0;
|
|
1245
1461
|
overflow-y: auto;
|
|
@@ -2365,7 +2581,20 @@ function buildRecommendation(normal, certain, p) {
|
|
|
2365
2581
|
return { expected, text: "相同", tone: "same" }
|
|
2366
2582
|
}
|
|
2367
2583
|
|
|
2368
|
-
function
|
|
2584
|
+
function classifyRareMaterial(materials, kcDevData) {
|
|
2585
|
+
const sets = getRareEquipSets()
|
|
2586
|
+
let hasSecondary = false
|
|
2587
|
+
for (const item of materials || []) {
|
|
2588
|
+
if (!item) continue
|
|
2589
|
+
if (item.item_material_key != null && RARE_MATERIAL_KEYS.has(String(item.item_material_key))) return "rare"
|
|
2590
|
+
const name = String(item.item_name || "")
|
|
2591
|
+
if (sets.rare.has(name)) return "rare"
|
|
2592
|
+
if (sets.secondary.has(name)) hasSecondary = true
|
|
2593
|
+
}
|
|
2594
|
+
return hasSecondary ? "secondary" : null
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
function MaterialDetail({ materials, onMaterialClick, inventoryByEquip, onInventoryClick, useItemCounts }) {
|
|
2369
2598
|
const items = (materials || []).filter((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
|
|
2370
2599
|
if (items.length === 0) {
|
|
2371
2600
|
return React.createElement("div", { className: "kr2-material-empty" }, "无消耗装备")
|
|
@@ -2877,7 +3106,143 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2877
3106
|
)
|
|
2878
3107
|
}
|
|
2879
3108
|
|
|
2880
|
-
|
|
3109
|
+
function formatStrongLevel(level) {
|
|
3110
|
+
const n = Number(level)
|
|
3111
|
+
if (n >= 10) return "max"
|
|
3112
|
+
return "+" + String(n)
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
function buildStrongEntries(rows, inventoryByEquip, selection) {
|
|
3116
|
+
const inventoryLoaded = inventoryByEquip && Object.keys(inventoryByEquip).length > 0
|
|
3117
|
+
const entries = []
|
|
3118
|
+
const demandMap = {}
|
|
3119
|
+
for (const row of rows || []) {
|
|
3120
|
+
const sel = (selection || {})[row.id] || { selected: true, target: "max", qty: 1 }
|
|
3121
|
+
const qty = Math.max(1, Math.min(99, Math.round(Number(sel.qty) || 1)))
|
|
3122
|
+
const evoUpgradeId = sel.evoUpgradeId || null
|
|
3123
|
+
const evoUpgrade = evoUpgradeId ? (row.upgrades || []).find((u) => String(u.upgrade_id) === String(evoUpgradeId)) : null
|
|
3124
|
+
const displayRow = evoUpgrade
|
|
3125
|
+
? Object.assign({}, row, { id: row.id + ":evo:" + evoUpgrade.upgrade_id, name: evoUpgrade.targetName, category: evoUpgrade.targetCategory || row.category })
|
|
3126
|
+
: row
|
|
3127
|
+
const targetEquipId = evoUpgrade ? String(evoUpgrade.upgrade_id) : row.id
|
|
3128
|
+
const targetLevelValue = evoUpgrade ? 0 : (row.improveable === false ? 0 : (sel.target === "max" ? 10 : 6))
|
|
3129
|
+
const bucket = demandMap[targetEquipId] || (demandMap[targetEquipId] = { equipId: targetEquipId, displayRow, sourceRowIds: [], sourceRowIdsByLevel: {}, demands: {}, evolvedLevels: {} })
|
|
3130
|
+
if (bucket.sourceRowIds.indexOf(row.id) < 0) bucket.sourceRowIds.push(row.id)
|
|
3131
|
+
const levelKey = String(targetLevelValue)
|
|
3132
|
+
const levelSources = bucket.sourceRowIdsByLevel[levelKey] || (bucket.sourceRowIdsByLevel[levelKey] = [])
|
|
3133
|
+
if (levelSources.indexOf(row.id) < 0) levelSources.push(row.id)
|
|
3134
|
+
if (evoUpgrade) bucket.evolvedLevels[String(targetLevelValue)] = true
|
|
3135
|
+
bucket.demands[String(targetLevelValue)] = (bucket.demands[String(targetLevelValue)] || 0) + qty
|
|
3136
|
+
}
|
|
3137
|
+
for (const bucket of Object.values(demandMap)) {
|
|
3138
|
+
const inv = (inventoryByEquip || {})[bucket.equipId]
|
|
3139
|
+
const inventoryLevels = []
|
|
3140
|
+
if (inv && inv.levels) {
|
|
3141
|
+
for (const level of Object.keys(inv.levels)) {
|
|
3142
|
+
const count = Math.max(0, Math.round(Number(inv.levels[level]) || 0))
|
|
3143
|
+
if (count > 0) inventoryLevels.push({ level: Number(level), count })
|
|
3144
|
+
}
|
|
3145
|
+
inventoryLevels.sort((a, b) => b.level - a.level)
|
|
3146
|
+
}
|
|
3147
|
+
const remaining = {}
|
|
3148
|
+
for (const lv of inventoryLevels) remaining[String(lv.level)] = lv.count
|
|
3149
|
+
const targetLevels = Object.keys(bucket.demands).map(Number).sort((a, b) => b - a)
|
|
3150
|
+
const allocation = {}
|
|
3151
|
+
const shortfall = {}
|
|
3152
|
+
for (const tl of targetLevels) {
|
|
3153
|
+
let need = bucket.demands[String(tl)] || 0
|
|
3154
|
+
for (const lv of inventoryLevels) {
|
|
3155
|
+
if (need <= 0) break
|
|
3156
|
+
const avail = remaining[String(lv.level)] || 0
|
|
3157
|
+
if (avail <= 0) continue
|
|
3158
|
+
const take = Math.min(need, avail)
|
|
3159
|
+
const key = String(tl) + "|" + String(lv.level)
|
|
3160
|
+
const alloc = allocation[key] || (allocation[key] = { targetLevelValue: tl, inventoryLevel: lv.level, qty: 0, stock: 0 })
|
|
3161
|
+
alloc.qty += take
|
|
3162
|
+
alloc.stock += take
|
|
3163
|
+
remaining[String(lv.level)] = avail - take
|
|
3164
|
+
need -= take
|
|
3165
|
+
}
|
|
3166
|
+
if (need > 0) shortfall[String(tl)] = need
|
|
3167
|
+
}
|
|
3168
|
+
for (const key of Object.keys(allocation)) {
|
|
3169
|
+
const alloc = allocation[key]
|
|
3170
|
+
entries.push({ key: bucket.equipId + ":" + key, row: bucket.displayRow, sourceRowIds: bucket.sourceRowIdsByLevel[String(alloc.targetLevelValue)] || bucket.sourceRowIds, evolved: !!bucket.evolvedLevels[String(alloc.targetLevelValue)], targetLevel: formatStrongLevel(alloc.targetLevelValue), targetLevelValue: alloc.targetLevelValue, qty: alloc.qty, inventoryLevel: alloc.inventoryLevel, stock: alloc.stock })
|
|
3171
|
+
}
|
|
3172
|
+
for (const tl of Object.keys(shortfall)) {
|
|
3173
|
+
const value = Number(tl)
|
|
3174
|
+
entries.push({ key: bucket.equipId + ":short:" + tl, row: bucket.displayRow, sourceRowIds: bucket.sourceRowIdsByLevel[String(value)] || bucket.sourceRowIds, evolved: !!bucket.evolvedLevels[String(value)], targetLevel: formatStrongLevel(value), targetLevelValue: value, qty: shortfall[tl], inventoryLevel: null, stock: inventoryLoaded ? 0 : null, notFound: true })
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
for (const item of entries) {
|
|
3178
|
+
item.clear = item.qty > 0 && item.stock != null && item.inventoryLevel >= item.targetLevelValue && item.stock >= item.qty
|
|
3179
|
+
item.completed = item.clear ? item.qty : 0
|
|
3180
|
+
item.levelShort = item.inventoryLevel != null && item.inventoryLevel < item.targetLevelValue
|
|
3181
|
+
item.countShort = item.stock != null && item.qty > 0 && item.stock < item.qty
|
|
3182
|
+
item.countEnough = item.stock != null && item.stock >= item.qty
|
|
3183
|
+
}
|
|
3184
|
+
const levelRank = (item) => item.inventoryLevel == null ? -1 : item.inventoryLevel
|
|
3185
|
+
entries.sort((a, b) => {
|
|
3186
|
+
const ac = a.clear ? 1 : 0
|
|
3187
|
+
const bc = b.clear ? 1 : 0
|
|
3188
|
+
if (ac !== bc) return bc - ac
|
|
3189
|
+
if (a.clear) return b.qty - a.qty || levelRank(b) - levelRank(a)
|
|
3190
|
+
const sa = a.stock == null ? -1 : a.stock
|
|
3191
|
+
const sb = b.stock == null ? -1 : b.stock
|
|
3192
|
+
return sb - sa || b.qty - a.qty || levelRank(b) - levelRank(a)
|
|
3193
|
+
})
|
|
3194
|
+
return { entries, inventoryLoaded }
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
function buildStrongGroups(entries) {
|
|
3198
|
+
const groupsByKey = {}
|
|
3199
|
+
for (const item of entries || []) {
|
|
3200
|
+
const key = item.row.id + "|" + String(item.targetLevelValue)
|
|
3201
|
+
const group = groupsByKey[key] || (groupsByKey[key] = {
|
|
3202
|
+
key,
|
|
3203
|
+
row: item.row,
|
|
3204
|
+
targetLevel: item.targetLevel,
|
|
3205
|
+
targetLevelValue: item.targetLevelValue,
|
|
3206
|
+
items: [],
|
|
3207
|
+
sourceRowIds: [],
|
|
3208
|
+
qty: 0,
|
|
3209
|
+
completed: 0,
|
|
3210
|
+
stock: 0,
|
|
3211
|
+
stockLoaded: false,
|
|
3212
|
+
maxInventoryLevel: -1,
|
|
3213
|
+
evolved: false,
|
|
3214
|
+
})
|
|
3215
|
+
group.items.push(item)
|
|
3216
|
+
group.qty += item.qty
|
|
3217
|
+
group.completed += item.completed || 0
|
|
3218
|
+
if (item.stock != null) {
|
|
3219
|
+
group.stock += item.stock
|
|
3220
|
+
group.stockLoaded = true
|
|
3221
|
+
}
|
|
3222
|
+
if (item.inventoryLevel != null) group.maxInventoryLevel = Math.max(group.maxInventoryLevel, item.inventoryLevel)
|
|
3223
|
+
if (item.evolved) group.evolved = true
|
|
3224
|
+
for (const rowId of item.sourceRowIds || []) {
|
|
3225
|
+
if (group.sourceRowIds.indexOf(rowId) < 0) group.sourceRowIds.push(rowId)
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
const groups = Object.keys(groupsByKey).map((key) => groupsByKey[key])
|
|
3229
|
+
for (const group of groups) {
|
|
3230
|
+
group.items.sort((a, b) => (b.inventoryLevel == null ? -1 : b.inventoryLevel) - (a.inventoryLevel == null ? -1 : a.inventoryLevel))
|
|
3231
|
+
group.clear = group.qty > 0 && group.completed >= group.qty
|
|
3232
|
+
}
|
|
3233
|
+
groups.sort((a, b) => {
|
|
3234
|
+
const ac = a.clear ? 1 : 0
|
|
3235
|
+
const bc = b.clear ? 1 : 0
|
|
3236
|
+
if (ac !== bc) return bc - ac
|
|
3237
|
+
if (a.clear) return b.qty - a.qty || b.maxInventoryLevel - a.maxInventoryLevel
|
|
3238
|
+
const sa = a.stockLoaded ? a.stock : -1
|
|
3239
|
+
const sb = b.stockLoaded ? b.stock : -1
|
|
3240
|
+
return sb - sa || b.qty - a.qty || b.maxInventoryLevel - a.maxInventoryLevel
|
|
3241
|
+
})
|
|
3242
|
+
return groups
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
class StrongPage extends React.Component {
|
|
2881
3246
|
catRef = React.createRef()
|
|
2882
3247
|
state = {
|
|
2883
3248
|
categoryOpen: false,
|
|
@@ -2916,96 +3281,28 @@ class StrongPage extends React.Component {
|
|
|
2916
3281
|
})
|
|
2917
3282
|
}
|
|
2918
3283
|
|
|
2919
|
-
render() {
|
|
2920
|
-
const { rows, inventoryByEquip, selection } = this.props
|
|
2921
|
-
const
|
|
2922
|
-
const
|
|
2923
|
-
const
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
const
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
}
|
|
2942
|
-
for (const bucket of Object.values(demandMap)) {
|
|
2943
|
-
const inv = (inventoryByEquip || {})[bucket.equipId]
|
|
2944
|
-
const inventoryLevels = []
|
|
2945
|
-
if (inv && inv.levels) {
|
|
2946
|
-
for (const level of Object.keys(inv.levels)) {
|
|
2947
|
-
const count = Math.max(0, Math.round(Number(inv.levels[level]) || 0))
|
|
2948
|
-
if (count > 0) inventoryLevels.push({ level: Number(level), count })
|
|
2949
|
-
}
|
|
2950
|
-
inventoryLevels.sort((a, b) => b.level - a.level)
|
|
2951
|
-
}
|
|
2952
|
-
const remaining = {}
|
|
2953
|
-
for (const lv of inventoryLevels) remaining[String(lv.level)] = lv.count
|
|
2954
|
-
const targetLevels = Object.keys(bucket.demands).map(Number).sort((a, b) => b - a)
|
|
2955
|
-
const allocation = {}
|
|
2956
|
-
const shortfall = {}
|
|
2957
|
-
for (const tl of targetLevels) {
|
|
2958
|
-
let need = bucket.demands[String(tl)] || 0
|
|
2959
|
-
for (const lv of inventoryLevels) {
|
|
2960
|
-
if (need <= 0) break
|
|
2961
|
-
const avail = remaining[String(lv.level)] || 0
|
|
2962
|
-
if (avail <= 0) continue
|
|
2963
|
-
const take = Math.min(need, avail)
|
|
2964
|
-
const key = String(tl) + "|" + String(lv.level)
|
|
2965
|
-
const alloc = allocation[key] || (allocation[key] = { targetLevelValue: tl, inventoryLevel: lv.level, qty: 0, stock: 0 })
|
|
2966
|
-
alloc.qty += take
|
|
2967
|
-
alloc.stock += take
|
|
2968
|
-
remaining[String(lv.level)] = avail - take
|
|
2969
|
-
need -= take
|
|
2970
|
-
}
|
|
2971
|
-
if (need > 0) shortfall[String(tl)] = need
|
|
2972
|
-
}
|
|
2973
|
-
for (const key of Object.keys(allocation)) {
|
|
2974
|
-
const alloc = allocation[key]
|
|
2975
|
-
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 })
|
|
2976
|
-
}
|
|
2977
|
-
for (const tl of Object.keys(shortfall)) {
|
|
2978
|
-
const value = Number(tl)
|
|
2979
|
-
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 })
|
|
2980
|
-
}
|
|
2981
|
-
}
|
|
2982
|
-
for (const item of entries) {
|
|
2983
|
-
item.clear = item.qty > 0 && item.stock != null && item.inventoryLevel === item.targetLevelValue && item.stock >= item.qty
|
|
2984
|
-
item.levelShort = item.inventoryLevel != null && item.inventoryLevel < item.targetLevelValue
|
|
2985
|
-
item.countShort = item.stock != null && item.qty > 0 && item.stock < item.qty
|
|
2986
|
-
item.countEnough = item.stock != null && item.stock >= item.qty
|
|
2987
|
-
}
|
|
2988
|
-
const levelRank = (item) => item.inventoryLevel == null ? -1 : item.inventoryLevel
|
|
2989
|
-
entries.sort((a, b) => {
|
|
2990
|
-
const ac = a.clear ? 1 : 0
|
|
2991
|
-
const bc = b.clear ? 1 : 0
|
|
2992
|
-
if (ac !== bc) return bc - ac
|
|
2993
|
-
if (a.clear) return b.qty - a.qty || levelRank(b) - levelRank(a)
|
|
2994
|
-
const sa = a.stock == null ? -1 : a.stock
|
|
2995
|
-
const sb = b.stock == null ? -1 : b.stock
|
|
2996
|
-
return sb - sa || b.qty - a.qty || levelRank(b) - levelRank(a)
|
|
2997
|
-
})
|
|
2998
|
-
const categories = Array.from(new Set(entries.map((item) => item.row.category).filter(Boolean))).sort((a, b) => a.localeCompare(b, "zh-Hans-CN"))
|
|
2999
|
-
const selectedCategories = this.state.selectedCategories
|
|
3000
|
-
const visibleEntries = selectedCategories == null ? entries : entries.filter((item) => selectedCategories.indexOf(item.row.category) >= 0)
|
|
3001
|
-
const stockText = (item) => {
|
|
3002
|
-
const nameNode = React.createElement("span", { className: "kr2-strong-stock-name" }, item.row.name)
|
|
3003
|
-
if (item.notFound || item.stock == null) return nameNode
|
|
3004
|
-
const levelPart = levelText(item.inventoryLevel)
|
|
3005
|
-
return React.createElement("span", null, nameNode, " ", levelPart)
|
|
3006
|
-
}
|
|
3007
|
-
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"
|
|
3008
|
-
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"
|
|
3284
|
+
render() {
|
|
3285
|
+
const { rows, inventoryByEquip, selection } = this.props
|
|
3286
|
+
const { entries } = buildStrongEntries(rows, inventoryByEquip, selection)
|
|
3287
|
+
const groups = buildStrongGroups(entries)
|
|
3288
|
+
const categories = Array.from(new Set(groups.map((group) => group.row.category).filter(Boolean))).sort((a, b) => a.localeCompare(b, "zh-Hans-CN"))
|
|
3289
|
+
const selectedCategories = this.state.selectedCategories
|
|
3290
|
+
const visibleGroups = selectedCategories == null ? groups : groups.filter((group) => selectedCategories.indexOf(group.row.category) >= 0)
|
|
3291
|
+
const stockText = (item) => {
|
|
3292
|
+
const nameNode = React.createElement("span", { className: "kr2-strong-stock-name" }, item.row.name)
|
|
3293
|
+
if (item.notFound || item.stock == null) return nameNode
|
|
3294
|
+
const levelPart = formatStrongLevel(item.inventoryLevel)
|
|
3295
|
+
return React.createElement("span", null, nameNode, " ", levelPart)
|
|
3296
|
+
}
|
|
3297
|
+
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"
|
|
3298
|
+
const groupOwnedClass = (group) => !group.stockLoaded ? "kr2-strong-stock-missing" : group.clear ? "kr2-strong-stock-clear" : "kr2-strong-stock-short"
|
|
3299
|
+
const completionLineClass = (item, group) => "kr2-strong-owned-line " + (item.stock == null ? "kr2-strong-owned-line-missing" : group.qty > 0 && (item.completed || 0) >= group.qty ? "kr2-strong-owned-line-clear" : "kr2-strong-owned-line-short")
|
|
3300
|
+
const completionLineText = (item, group) => {
|
|
3301
|
+
if (item.stock == null) return "--"
|
|
3302
|
+
const completed = item.completed || 0
|
|
3303
|
+
if (group.qty > 0 && completed >= group.qty) return String(completed)
|
|
3304
|
+
return completed > 0 ? React.createElement("span", { className: "kr2-strong-completion-done" }, String(completed)) : String(completed)
|
|
3305
|
+
}
|
|
3009
3306
|
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
|
|
3010
3307
|
const categoryHead = React.createElement(
|
|
3011
3308
|
"th",
|
|
@@ -3036,24 +3333,30 @@ class StrongPage extends React.Component {
|
|
|
3036
3333
|
React.createElement(
|
|
3037
3334
|
"thead",
|
|
3038
3335
|
null,
|
|
3039
|
-
React.createElement("tr", null, categoryHead, React.createElement("th", null, "目标装备"), React.createElement("th",
|
|
3336
|
+
React.createElement("tr", null, categoryHead, React.createElement("th", null, "目标装备"), React.createElement("th", { className: "kr2-strong-stock-th" }, "库存装备"), React.createElement("th", null, "完成数"), React.createElement("th", null, "目标数"))
|
|
3040
3337
|
),
|
|
3041
3338
|
React.createElement(
|
|
3042
3339
|
"tbody",
|
|
3043
3340
|
null,
|
|
3044
|
-
|
|
3045
|
-
? React.createElement("tr", null, React.createElement("td", { colSpan: 5 }, "无匹配分类"))
|
|
3046
|
-
:
|
|
3047
|
-
React.createElement(
|
|
3048
|
-
"tr",
|
|
3049
|
-
{ key:
|
|
3050
|
-
React.createElement("td", { className: "kr2-strong-cat" },
|
|
3051
|
-
React.createElement(
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3341
|
+
visibleGroups.length === 0
|
|
3342
|
+
? React.createElement("tr", null, React.createElement("td", { colSpan: 5 }, "无匹配分类"))
|
|
3343
|
+
: visibleGroups.map((group) =>
|
|
3344
|
+
React.createElement(
|
|
3345
|
+
"tr",
|
|
3346
|
+
{ key: group.key, className: group.clear ? "kr2-strong-clear-row" : null },
|
|
3347
|
+
React.createElement("td", { className: "kr2-strong-cat" }, group.row.category || "-"),
|
|
3348
|
+
React.createElement(
|
|
3349
|
+
"td",
|
|
3350
|
+
{ className: "kr2-strong-equip" },
|
|
3351
|
+
group.row.name + (group.evolved ? "(进化)" : ""),
|
|
3352
|
+
!group.evolved && group.row.improveable !== false ? " " : null,
|
|
3353
|
+
!group.evolved && group.row.improveable !== false ? React.createElement("span", { className: "kr2-strong-level" }, group.targetLevel) : null
|
|
3354
|
+
),
|
|
3355
|
+
React.createElement("td", { className: "kr2-strong-stock" }, group.items.map((item) => React.createElement("div", { key: item.key, className: "kr2-strong-stock-line " + stockClass(item), "data-level": item.inventoryLevel == null ? "" : String(item.inventoryLevel) }, stockText(item)))),
|
|
3356
|
+
React.createElement("td", { className: "kr2-strong-owned " + groupOwnedClass(group), "data-completed": String(group.completed || 0), "data-stock": group.stockLoaded ? String(group.stock) : "", "data-level": String(group.maxInventoryLevel) }, group.clear ? "clear!" : group.items.map((item) => React.createElement("div", { key: item.key, className: completionLineClass(item, group), "data-level": item.inventoryLevel == null ? "" : String(item.inventoryLevel) }, completionLineText(item, group)))),
|
|
3357
|
+
React.createElement("td", { className: "kr2-strong-target", "data-target": String(group.qty) }, String(group.qty))
|
|
3358
|
+
)
|
|
3359
|
+
)
|
|
3057
3360
|
)
|
|
3058
3361
|
)
|
|
3059
3362
|
)
|
|
@@ -3087,7 +3390,8 @@ class LevelOneTable extends React.Component {
|
|
|
3087
3390
|
const normal = phase.consume_improvement_min
|
|
3088
3391
|
const materials = phase.materials || []
|
|
3089
3392
|
const hasMaterials = materials.some((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
|
|
3090
|
-
const
|
|
3393
|
+
const rareWarning = null
|
|
3394
|
+
const rows = []
|
|
3091
3395
|
LEVEL_ONE_ROWS.forEach((rate) => {
|
|
3092
3396
|
const key = rate.range
|
|
3093
3397
|
rows.push(
|
|
@@ -3106,7 +3410,8 @@ class LevelOneTable extends React.Component {
|
|
|
3106
3410
|
"div",
|
|
3107
3411
|
{ className: "kr2-material-cell" },
|
|
3108
3412
|
React.createElement(RateCell, { range: "素材详情", open: !!this.state.open[key], onToggle: () => this.toggle(key) }),
|
|
3109
|
-
|
|
3413
|
+
rareWarning,
|
|
3414
|
+
!!this.state.open[key]
|
|
3110
3415
|
? React.createElement(MaterialDetail, { materials, onMaterialClick: this.props.onMaterialClick, inventoryByEquip: this.props.inventoryByEquip, useItemCounts: this.props.useItemCounts, onInventoryClick: this.props.onInventoryClick })
|
|
3111
3416
|
: null
|
|
3112
3417
|
)
|
|
@@ -3156,7 +3461,9 @@ class LevelTwoTable extends React.Component {
|
|
|
3156
3461
|
const rec = buildRecommendation(normal, certain, p)
|
|
3157
3462
|
const materials = step ? step.materials || [] : []
|
|
3158
3463
|
const hasMaterials = materials.some((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
|
|
3159
|
-
const
|
|
3464
|
+
const rareTier = rec.tone === "save" ? classifyRareMaterial(materials, kcDevData) : null
|
|
3465
|
+
const rareWarning = rareTier === "rare" ? React.createElement("div", { className: "kr2-rare-warning" }, "稀有素材消耗注意!") : rareTier === "secondary" ? React.createElement("div", { className: "kr2-rare-warning-secondary" }, "次级稀有素材消耗注意!") : null
|
|
3466
|
+
const rangeNode = maxBlue
|
|
3160
3467
|
? React.createElement("span", null, "★9→", React.createElement("span", { className: "kr2-level-max-blue" }, "max"))
|
|
3161
3468
|
: range
|
|
3162
3469
|
rows.push(
|
|
@@ -3192,7 +3499,8 @@ class LevelTwoTable extends React.Component {
|
|
|
3192
3499
|
"div",
|
|
3193
3500
|
{ className: "kr2-material-cell" },
|
|
3194
3501
|
React.createElement(RateCell, { range: rec.text, open: !!this.state.open[key], onToggle: () => this.toggle(key), tone: rec.tone }),
|
|
3195
|
-
|
|
3502
|
+
rareWarning,
|
|
3503
|
+
!!this.state.open[key]
|
|
3196
3504
|
? React.createElement(MaterialDetail, { materials, onMaterialClick: this.props.onMaterialClick, inventoryByEquip: this.props.inventoryByEquip, useItemCounts: this.props.useItemCounts, onInventoryClick: this.props.onInventoryClick })
|
|
3197
3505
|
: null
|
|
3198
3506
|
)
|
|
@@ -3270,13 +3578,14 @@ class LevelSection extends React.Component {
|
|
|
3270
3578
|
}
|
|
3271
3579
|
}
|
|
3272
3580
|
|
|
3273
|
-
function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEquip, useItemCounts, onInventoryClick, isFavorite, onFavoriteClick, secretaryText, kcDevData }) {
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3581
|
+
function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEquip, useItemCounts, onInventoryClick, isFavorite, onFavoriteClick, secretaryText, kcDevData, completion }) {
|
|
3582
|
+
const clear = !!(completion && completion.target > 0 && completion.completed >= completion.target)
|
|
3583
|
+
return React.createElement(
|
|
3584
|
+
"div",
|
|
3585
|
+
null,
|
|
3586
|
+
React.createElement(
|
|
3587
|
+
"div",
|
|
3588
|
+
{ className: "kr2-row" + (row.improveable === false ? " kr2-row-not-improveable" : "") + (clear ? " kr2-row-clear" : ""), onClick: row.improveable === false ? null : onToggle },
|
|
3280
3589
|
React.createElement(
|
|
3281
3590
|
"button",
|
|
3282
3591
|
{ className: "kr2-fav-btn" + (isFavorite ? " kr2-fav-active" : ""), onClick: (e) => { e.stopPropagation(); onFavoriteClick && onFavoriteClick(row.id) }, title: isFavorite ? "取消收藏" : "收藏" },
|
|
@@ -3288,7 +3597,24 @@ function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEqu
|
|
|
3288
3597
|
React.createElement(SlotitemIcon, { slotitemId: row.icon, className: "kr2-icon" }),
|
|
3289
3598
|
React.createElement("span", { className: "kr2-arrow" }, row.improveable === false ? "" : expanded ? "▼" : "▶")
|
|
3290
3599
|
),
|
|
3291
|
-
React.createElement(
|
|
3600
|
+
React.createElement(
|
|
3601
|
+
"span",
|
|
3602
|
+
{ className: "kr2-name-cell" },
|
|
3603
|
+
React.createElement("span", { className: "kr2-name" }, row.name),
|
|
3604
|
+
completion
|
|
3605
|
+
? clear
|
|
3606
|
+
? React.createElement("span", { className: "kr2-name-completion kr2-name-completion-clear" }, "(", String(completion.completed), "/", String(completion.target), ")clear!")
|
|
3607
|
+
: React.createElement(
|
|
3608
|
+
"span",
|
|
3609
|
+
{ className: "kr2-name-completion kr2-name-completion-incomplete" },
|
|
3610
|
+
"完成数(",
|
|
3611
|
+
React.createElement("span", { className: "kr2-name-completion-done" + (completion.completed > 0 ? " kr2-name-completion-done-active" : "") }, String(completion.completed)),
|
|
3612
|
+
"/",
|
|
3613
|
+
String(completion.target),
|
|
3614
|
+
")"
|
|
3615
|
+
)
|
|
3616
|
+
: null
|
|
3617
|
+
),
|
|
3292
3618
|
React.createElement("span", { className: "kr2-secretary" }, row.improveable === false ? "" : (secretaryText || "-")),
|
|
3293
3619
|
React.createElement(
|
|
3294
3620
|
"span",
|
|
@@ -3552,14 +3878,96 @@ function readPlanIncludeDev() {
|
|
|
3552
3878
|
}
|
|
3553
3879
|
}
|
|
3554
3880
|
|
|
3555
|
-
function savePlanIncludeDev(value) {
|
|
3556
|
-
try {
|
|
3557
|
-
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
3558
|
-
if (storage) storage.setItem(PLAN_INCLUDE_DEV_STORAGE_KEY, value ? "1" : "0")
|
|
3559
|
-
} catch (_) {}
|
|
3560
|
-
}
|
|
3561
|
-
|
|
3562
|
-
|
|
3881
|
+
function savePlanIncludeDev(value) {
|
|
3882
|
+
try {
|
|
3883
|
+
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
3884
|
+
if (storage) storage.setItem(PLAN_INCLUDE_DEV_STORAGE_KEY, value ? "1" : "0")
|
|
3885
|
+
} catch (_) {}
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
function HelpModal({ onClose, updateNotes }) {
|
|
3889
|
+
const sections = []
|
|
3890
|
+
if (updateNotes && updateNotes.length) sections.push({ title: PLUGIN_VERSION + "更新", items: updateNotes })
|
|
3891
|
+
sections.push(
|
|
3892
|
+
{
|
|
3893
|
+
title: "1.改修列表",
|
|
3894
|
+
items: [
|
|
3895
|
+
"显示每日改修装备,打开插件时默认自动跳转到当前星期数;",
|
|
3896
|
+
"装备行上最右侧为改修推荐星级,数据参考nga梦美改修2.0贴(插件版头有网站链接),点击表头可以按照星级排序;",
|
|
3897
|
+
"点击对应装备行可展开详细改修数据,默认只展开6-10级的改修(也可手动点开查看),最右侧确保推荐是按照螺丝期望自动计算的,未考虑稀有素材和紫菜的消耗情况(请注意甄别);",
|
|
3898
|
+
"点击装备行最左侧的星星可以收藏该装备,点亮插件右上角的收藏按钮会隐藏其他未收藏的装备;",
|
|
3899
|
+
"点击确保推荐列中的“推荐确保”/“不确保”按钮会显示消耗素材情况以及库存素材数量(默认不统计带有星级的素材),点击素材会弹出装备开发配方列表,点击库存可查看已拥有的素材详情(主要是查看星级);",
|
|
3900
|
+
],
|
|
3901
|
+
},
|
|
3902
|
+
{
|
|
3903
|
+
title: "2.素材计算",
|
|
3904
|
+
items: [
|
|
3905
|
+
"只有在改修列表中点击收藏的装备才会显示在该页中;",
|
|
3906
|
+
"为了让插件看起来更加简洁,改修目标只设置了+6、max和进化三个选项,输入目标数量后,插件会自动计算所需的素材汇总情况;",
|
|
3907
|
+
"勾选“统计素材开发的紫菜消耗期望”会计算当所有改修素材均来自开发时所预计消耗的紫菜数量(图一乐功能);",
|
|
3908
|
+
"可对开发资材、螺丝以及素材汇总中的需求、库存和紫菜开发期望进行排序;",
|
|
3909
|
+
],
|
|
3910
|
+
},
|
|
3911
|
+
{
|
|
3912
|
+
title: "3.我变强了!",
|
|
3913
|
+
items: [
|
|
3914
|
+
"所有收藏的装备均会在该页中显示(无论在素材计算页中是否勾选),插件会自动计算目标装备与库存装备的星级、数量差异,并默认倒序排列;",
|
|
3915
|
+
"已完成的装备会自动置顶并显示clear!;",
|
|
3916
|
+
"计划的完成情况会同步显示在改修列表页的装备行上;",
|
|
3917
|
+
"注意在素材计算页选择“进化”的装备会和进化后的同名装备分开计算,用来锚定阶段性目标。",
|
|
3918
|
+
],
|
|
3919
|
+
},
|
|
3920
|
+
{
|
|
3921
|
+
title: "其他常规功能",
|
|
3922
|
+
items: [
|
|
3923
|
+
"模糊搜索,搜索栏支持输入简体中文;",
|
|
3924
|
+
"可在插件版头按照装备大类进行筛选;",
|
|
3925
|
+
"插件也加入了不可改修装备,同样可以收藏,并正常显示在我变强了页中。",
|
|
3926
|
+
],
|
|
3927
|
+
},
|
|
3928
|
+
)
|
|
3929
|
+
const updateSection = sections[0] && sections[0].title === PLUGIN_VERSION + "更新" ? sections[0] : null
|
|
3930
|
+
const guideSections = updateSection ? sections.slice(1) : sections
|
|
3931
|
+
const renderSection = (section, key) =>
|
|
3932
|
+
React.createElement(
|
|
3933
|
+
"section",
|
|
3934
|
+
{ key, className: "kr2-help-section" },
|
|
3935
|
+
React.createElement("div", { className: "kr2-help-section-title" }, section.title),
|
|
3936
|
+
React.createElement(
|
|
3937
|
+
"ul",
|
|
3938
|
+
{ className: "kr2-help-list" },
|
|
3939
|
+
section.items.map((text, itemIndex) => React.createElement("li", { key: itemIndex }, text))
|
|
3940
|
+
)
|
|
3941
|
+
)
|
|
3942
|
+
return React.createElement(
|
|
3943
|
+
"div",
|
|
3944
|
+
{ className: "kr2-modal-backdrop", onClick: onClose },
|
|
3945
|
+
React.createElement(
|
|
3946
|
+
"div",
|
|
3947
|
+
{ className: "kr2-modal kr2-help-modal", role: "dialog", "aria-modal": "true", "aria-label": "使用说明", onClick: (e) => e.stopPropagation() },
|
|
3948
|
+
React.createElement(
|
|
3949
|
+
"div",
|
|
3950
|
+
{ className: "kr2-modal-head" },
|
|
3951
|
+
React.createElement(
|
|
3952
|
+
"div",
|
|
3953
|
+
null,
|
|
3954
|
+
React.createElement("div", { className: "kr2-modal-title" }, "使用说明"),
|
|
3955
|
+
React.createElement("div", { className: "kr2-modal-sub" }, "螺丝计算器 v" + PLUGIN_VERSION)
|
|
3956
|
+
),
|
|
3957
|
+
React.createElement("button", { type: "button", className: "kr2-modal-close", onClick: onClose, title: "关闭", "aria-label": "关闭使用说明" }, "×")
|
|
3958
|
+
),
|
|
3959
|
+
React.createElement(
|
|
3960
|
+
"div",
|
|
3961
|
+
{ className: "kr2-help-body" },
|
|
3962
|
+
updateSection ? renderSection(updateSection, "update") : null,
|
|
3963
|
+
React.createElement("div", { className: "kr2-help-lead" }, "功能主页"),
|
|
3964
|
+
guideSections.map((section, index) => renderSection(section, index))
|
|
3965
|
+
)
|
|
3966
|
+
)
|
|
3967
|
+
)
|
|
3968
|
+
}
|
|
3969
|
+
|
|
3970
|
+
class KoushuRateApp extends React.Component {
|
|
3563
3971
|
state = {
|
|
3564
3972
|
query: "",
|
|
3565
3973
|
day: japanWeekdayKey(),
|
|
@@ -3583,13 +3991,22 @@ class KoushuRateApp extends React.Component {
|
|
|
3583
3991
|
starSort: readUiState().starSort || null,
|
|
3584
3992
|
activeTab: "list",
|
|
3585
3993
|
improveableOpen: true,
|
|
3586
|
-
nonImproveableOpen: false,
|
|
3587
|
-
planSelection: readPlanSelection(),
|
|
3588
|
-
includeDevExpected: readPlanIncludeDev(),
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3994
|
+
nonImproveableOpen: false,
|
|
3995
|
+
planSelection: readPlanSelection(),
|
|
3996
|
+
includeDevExpected: readPlanIncludeDev(),
|
|
3997
|
+
helpOpen: false,
|
|
3998
|
+
}
|
|
3999
|
+
|
|
4000
|
+
componentDidMount() {
|
|
4001
|
+
const uiState = readUiState()
|
|
4002
|
+
const legacyVersion = uiState.helpVersion ? String(uiState.helpVersion).split(".").slice(0, 3).join(".") : ""
|
|
4003
|
+
const seenVersion = String(uiState.pluginVersion || legacyVersion || "").trim()
|
|
4004
|
+
const firstInstall = !seenVersion
|
|
4005
|
+
const isUpdate = !!seenVersion && seenVersion !== PLUGIN_VERSION
|
|
4006
|
+
if (firstInstall || isUpdate) {
|
|
4007
|
+
this.setState({ helpOpen: true })
|
|
4008
|
+
}
|
|
4009
|
+
this.refresh()
|
|
3593
4010
|
this.checkAkashiUpdate(false)
|
|
3594
4011
|
refreshKcDevData().catch(() => {})
|
|
3595
4012
|
this.loadKcDevExpectations()
|
|
@@ -3597,11 +4014,20 @@ class KoushuRateApp extends React.Component {
|
|
|
3597
4014
|
this.inventoryTimer = setInterval(() => this.refreshInventory(), 1000)
|
|
3598
4015
|
}
|
|
3599
4016
|
|
|
3600
|
-
componentWillUnmount() {
|
|
3601
|
-
if (this.inventoryTimer) clearInterval(this.inventoryTimer)
|
|
3602
|
-
}
|
|
3603
|
-
|
|
3604
|
-
|
|
4017
|
+
componentWillUnmount() {
|
|
4018
|
+
if (this.inventoryTimer) clearInterval(this.inventoryTimer)
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
openHelp = () => {
|
|
4022
|
+
this.setState({ helpOpen: true })
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4025
|
+
closeHelp = () => {
|
|
4026
|
+
saveUiState({ helpVersion: HELP_VERSION, pluginVersion: PLUGIN_VERSION })
|
|
4027
|
+
this.setState({ helpOpen: false })
|
|
4028
|
+
}
|
|
4029
|
+
|
|
4030
|
+
loadKcDevExpectations = () => {
|
|
3605
4031
|
loadKcDevData(false)
|
|
3606
4032
|
.then((data) => this.setState({ kcDevData: data }))
|
|
3607
4033
|
.catch(() => {})
|
|
@@ -3847,8 +4273,9 @@ class KoushuRateApp extends React.Component {
|
|
|
3847
4273
|
if (ib >= 0) return 1
|
|
3848
4274
|
return a.localeCompare(b, "zh-Hans-CN")
|
|
3849
4275
|
})
|
|
3850
|
-
const kcDevPopup = this.state.kcDevPopup
|
|
3851
|
-
const inventoryPopup = this.state.inventoryPopup
|
|
4276
|
+
const kcDevPopup = this.state.kcDevPopup
|
|
4277
|
+
const inventoryPopup = this.state.inventoryPopup
|
|
4278
|
+
const helpOpen = this.state.helpOpen
|
|
3852
4279
|
const kcDevSort = (kcDevPopup && kcDevPopup.sort) || { key: "rate", dir: "desc" }
|
|
3853
4280
|
const kcDevFormulas = kcDevPopup && Array.isArray(kcDevPopup.formulas) ? kcDevPopup.formulas.slice() : []
|
|
3854
4281
|
if (kcDevSort.key === "rate" || kcDevSort.key === "failRate") {
|
|
@@ -3857,10 +4284,21 @@ class KoushuRateApp extends React.Component {
|
|
|
3857
4284
|
return kcDevSort.dir === "asc" ? diff : -diff
|
|
3858
4285
|
})
|
|
3859
4286
|
}
|
|
3860
|
-
const inventoryByEquip = this.state.inventoryByEquip || {}
|
|
3861
|
-
const useItemCounts = this.state.useItemCounts || {}
|
|
3862
|
-
const favoritesOnly = !!this.state.favoritesOnly
|
|
3863
|
-
|
|
4287
|
+
const inventoryByEquip = this.state.inventoryByEquip || {}
|
|
4288
|
+
const useItemCounts = this.state.useItemCounts || {}
|
|
4289
|
+
const favoritesOnly = !!this.state.favoritesOnly
|
|
4290
|
+
const planSelection = this.state.planSelection || {}
|
|
4291
|
+
const favoriteRows = this.state.rows.filter((row) => !!this.state.favorites[row.id])
|
|
4292
|
+
const strongSummary = {}
|
|
4293
|
+
for (const item of buildStrongEntries(favoriteRows, inventoryByEquip, planSelection).entries) {
|
|
4294
|
+
const rowIds = item.sourceRowIds && item.sourceRowIds.length ? item.sourceRowIds : [item.row.id]
|
|
4295
|
+
for (const rowId of rowIds) {
|
|
4296
|
+
const summary = strongSummary[rowId] || (strongSummary[rowId] = { completed: 0, target: 0 })
|
|
4297
|
+
summary.completed += item.completed || 0
|
|
4298
|
+
summary.target += item.qty
|
|
4299
|
+
}
|
|
4300
|
+
}
|
|
4301
|
+
let rows = this.state.rows.filter((row) => {
|
|
3864
4302
|
if (favoritesOnly && !this.state.favorites[row.id]) return false
|
|
3865
4303
|
if (row.improveable !== false && day !== ALL_DAYS_KEY && (row.days || []).indexOf(day) < 0) return false
|
|
3866
4304
|
if (category !== "all" && row.category !== category) return false
|
|
@@ -3899,9 +4337,10 @@ class KoushuRateApp extends React.Component {
|
|
|
3899
4337
|
onInventoryClick: this.openInventoryPopup,
|
|
3900
4338
|
isFavorite: !!this.state.favorites[row.id],
|
|
3901
4339
|
onFavoriteClick: this.toggleFavorite,
|
|
3902
|
-
secretaryText: secretaryText(row.secretaries, day),
|
|
3903
|
-
kcDevData: this.state.kcDevData,
|
|
3904
|
-
|
|
4340
|
+
secretaryText: secretaryText(row.secretaries, day),
|
|
4341
|
+
kcDevData: this.state.kcDevData,
|
|
4342
|
+
completion: strongSummary[row.id],
|
|
4343
|
+
})
|
|
3905
4344
|
|
|
3906
4345
|
return React.createElement(
|
|
3907
4346
|
"div",
|
|
@@ -3914,11 +4353,16 @@ class KoushuRateApp extends React.Component {
|
|
|
3914
4353
|
React.createElement(
|
|
3915
4354
|
"div",
|
|
3916
4355
|
{ className: "kr2-title-row" },
|
|
3917
|
-
React.createElement(
|
|
3918
|
-
"div",
|
|
3919
|
-
null,
|
|
3920
|
-
React.createElement(
|
|
3921
|
-
|
|
4356
|
+
React.createElement(
|
|
4357
|
+
"div",
|
|
4358
|
+
null,
|
|
4359
|
+
React.createElement(
|
|
4360
|
+
"div",
|
|
4361
|
+
{ className: "kr2-title-line" },
|
|
4362
|
+
React.createElement("div", { className: "kr2-title" }, "螺丝计算器"),
|
|
4363
|
+
React.createElement("button", { type: "button", className: "kr2-help-btn", onClick: this.openHelp }, "使用说明")
|
|
4364
|
+
),
|
|
4365
|
+
React.createElement(
|
|
3922
4366
|
"div",
|
|
3923
4367
|
{ className: "kr2-title-note" },
|
|
3924
4368
|
"螺丝确保仅供参考,稀有素材消耗请酌情考虑~(∠・ω< )⌒★"
|
|
@@ -4084,10 +4528,10 @@ class KoushuRateApp extends React.Component {
|
|
|
4084
4528
|
),
|
|
4085
4529
|
this.state.activeTab === "plan"
|
|
4086
4530
|
? React.createElement(PlanningPage, {
|
|
4087
|
-
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4088
|
-
inventoryByEquip,
|
|
4089
|
-
useItemCounts,
|
|
4090
|
-
selection:
|
|
4531
|
+
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4532
|
+
inventoryByEquip,
|
|
4533
|
+
useItemCounts,
|
|
4534
|
+
selection: planSelection,
|
|
4091
4535
|
onToggle: this.togglePlanRow,
|
|
4092
4536
|
onTarget: this.setPlanTarget,
|
|
4093
4537
|
onEvo: this.setPlanEvo,
|
|
@@ -4099,14 +4543,17 @@ class KoushuRateApp extends React.Component {
|
|
|
4099
4543
|
onToggleIncludeDevExpected: this.toggleIncludeDevExpected,
|
|
4100
4544
|
})
|
|
4101
4545
|
: null,
|
|
4102
|
-
this.state.activeTab === "strong"
|
|
4103
|
-
? React.createElement(StrongPage, {
|
|
4104
|
-
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4105
|
-
inventoryByEquip,
|
|
4106
|
-
selection:
|
|
4107
|
-
})
|
|
4108
|
-
: null,
|
|
4109
|
-
|
|
4546
|
+
this.state.activeTab === "strong"
|
|
4547
|
+
? React.createElement(StrongPage, {
|
|
4548
|
+
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4549
|
+
inventoryByEquip,
|
|
4550
|
+
selection: planSelection,
|
|
4551
|
+
})
|
|
4552
|
+
: null,
|
|
4553
|
+
helpOpen
|
|
4554
|
+
? React.createElement(HelpModal, { onClose: this.closeHelp, updateNotes: CURRENT_HELP_UPDATE_NOTES })
|
|
4555
|
+
: null,
|
|
4556
|
+
kcDevPopup
|
|
4110
4557
|
? React.createElement(
|
|
4111
4558
|
"div",
|
|
4112
4559
|
{ className: "kr2-modal-backdrop", onClick: this.closeKcDevPopup },
|