poi-plugin-koushu-rate 2.0.17 → 2.0.18
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 +666 -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,38 @@
|
|
|
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
|
+
}
|
|
33
|
+
const CURRENT_HELP_UPDATE_NOTES = HELP_UPDATE_NOTES[PLUGIN_VERSION] || ["本次更新暂无详细说明。"]
|
|
34
|
+
|
|
35
|
+
const LEVEL_ONE_ROWS = [
|
|
8
36
|
{ range: "★0→1", p: 1.0 },
|
|
9
37
|
{ range: "★1→2", p: 1.0 },
|
|
10
38
|
{ range: "★2→3", p: 1.0 },
|
|
@@ -37,10 +65,33 @@ const PLAN_LEVELS_MAX = PLAN_LEVELS_6.concat([
|
|
|
37
65
|
]);
|
|
38
66
|
|
|
39
67
|
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
|
-
|
|
68
|
+
const WEEKDAY_LABELS = { monday: "周一", tuesday: "周二", wednesday: "周三", thursday: "周四", friday: "周五", saturday: "周六", sunday: "周日" };
|
|
69
|
+
const ALL_DAYS_KEY = "all";
|
|
70
|
+
const RARE_MATERIAL_KEYS = new Set([
|
|
71
|
+
"新型砲熕兵装資材",
|
|
72
|
+
"新型兵装資材",
|
|
73
|
+
"戦闘詳報",
|
|
74
|
+
"勲章",
|
|
75
|
+
"ネ式エンジン",
|
|
76
|
+
"熟練搭乗員",
|
|
77
|
+
"海外艦最新技術",
|
|
78
|
+
"新型航空兵装資材",
|
|
79
|
+
"工廠資源",
|
|
80
|
+
"新型噴進装備開発資材",
|
|
81
|
+
"潜水艦補給物資",
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
let RARE_EQUIP_NAMES = null
|
|
85
|
+
let SECONDARY_EQUIP_NAMES = null
|
|
86
|
+
function getRareEquipSets() {
|
|
87
|
+
if (RARE_EQUIP_NAMES) return { rare: RARE_EQUIP_NAMES, secondary: SECONDARY_EQUIP_NAMES }
|
|
88
|
+
const data = loadJson("equipment_rarity.json") || {}
|
|
89
|
+
RARE_EQUIP_NAMES = new Set(data.rare || [])
|
|
90
|
+
SECONDARY_EQUIP_NAMES = new Set(data.secondary || [])
|
|
91
|
+
return { rare: RARE_EQUIP_NAMES, secondary: SECONDARY_EQUIP_NAMES }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function japanWeekdayKey() {
|
|
44
95
|
const japanNow = new Date(Date.now() + 9 * 60 * 60 * 1000)
|
|
45
96
|
return ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"][japanNow.getUTCDay()]
|
|
46
97
|
}
|
|
@@ -158,17 +209,36 @@ const CSS = `
|
|
|
158
209
|
padding: 12px 14px 20px;
|
|
159
210
|
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
|
160
211
|
}
|
|
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
|
-
|
|
212
|
+
.kr2-title-row {
|
|
213
|
+
display: flex;
|
|
214
|
+
flex-direction: column;
|
|
215
|
+
align-items: stretch;
|
|
216
|
+
justify-content: flex-start;
|
|
217
|
+
gap: 12px;
|
|
218
|
+
}
|
|
219
|
+
.kr2-title-line {
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
gap: 10px;
|
|
223
|
+
flex-wrap: wrap;
|
|
224
|
+
}
|
|
225
|
+
.kr2-title {
|
|
226
|
+
font-size: 18px;
|
|
227
|
+
font-weight: 800;
|
|
228
|
+
}
|
|
229
|
+
.kr2-help-btn {
|
|
230
|
+
padding: 4px 10px;
|
|
231
|
+
border: 1px solid #5f6b7c;
|
|
232
|
+
border-radius: 4px;
|
|
233
|
+
background: #2f343c;
|
|
234
|
+
color: #8abbff;
|
|
235
|
+
font-size: 12px;
|
|
236
|
+
cursor: pointer;
|
|
237
|
+
}
|
|
238
|
+
.kr2-help-btn:hover {
|
|
239
|
+
background: #383e47;
|
|
240
|
+
color: #a8c8ff;
|
|
241
|
+
}
|
|
172
242
|
.kr2-title-note {
|
|
173
243
|
margin-top: 2px;
|
|
174
244
|
font-size: 18px;
|
|
@@ -570,17 +640,41 @@ const CSS = `
|
|
|
570
640
|
color: #d6e4f5;
|
|
571
641
|
}
|
|
572
642
|
|
|
573
|
-
.kr2-strong {
|
|
574
|
-
margin-top: 12px;
|
|
575
|
-
flex: 1;
|
|
643
|
+
.kr2-strong {
|
|
644
|
+
margin-top: 12px;
|
|
645
|
+
flex: 1;
|
|
576
646
|
min-height: 60vh;
|
|
577
647
|
overflow-x: hidden;
|
|
578
648
|
overflow-y: auto;
|
|
579
649
|
}
|
|
580
|
-
.kr2-strong-table {
|
|
581
|
-
border-collapse: separate;
|
|
582
|
-
border-spacing: 0;
|
|
583
|
-
|
|
650
|
+
.kr2-table.kr2-strong-table {
|
|
651
|
+
border-collapse: separate;
|
|
652
|
+
border-spacing: 0;
|
|
653
|
+
table-layout: fixed;
|
|
654
|
+
width: 100%;
|
|
655
|
+
}
|
|
656
|
+
.kr2-strong-table th:nth-child(1),
|
|
657
|
+
.kr2-strong-table td:nth-child(1) {
|
|
658
|
+
width: 100px;
|
|
659
|
+
}
|
|
660
|
+
.kr2-strong-table th:nth-child(2),
|
|
661
|
+
.kr2-strong-table td:nth-child(2) {
|
|
662
|
+
width: 32%;
|
|
663
|
+
}
|
|
664
|
+
.kr2-strong-table th:nth-child(4),
|
|
665
|
+
.kr2-strong-table td:nth-child(4) {
|
|
666
|
+
width: 48px;
|
|
667
|
+
padding-left: 2px !important;
|
|
668
|
+
padding-right: 2px !important;
|
|
669
|
+
white-space: nowrap;
|
|
670
|
+
}
|
|
671
|
+
.kr2-strong-table th:nth-child(5),
|
|
672
|
+
.kr2-strong-table td:nth-child(5) {
|
|
673
|
+
width: 64px;
|
|
674
|
+
padding-left: 2px !important;
|
|
675
|
+
padding-right: 2px !important;
|
|
676
|
+
white-space: nowrap;
|
|
677
|
+
}
|
|
584
678
|
.kr2-strong-cat-th {
|
|
585
679
|
position: relative;
|
|
586
680
|
cursor: pointer;
|
|
@@ -631,9 +725,10 @@ const CSS = `
|
|
|
631
725
|
.kr2-strong-table tbody tr:last-child td {
|
|
632
726
|
border-bottom: 0;
|
|
633
727
|
}
|
|
634
|
-
.kr2-strong-equip {
|
|
635
|
-
text-align:
|
|
636
|
-
white-space: normal;
|
|
728
|
+
.kr2-strong-equip {
|
|
729
|
+
text-align: center !important;
|
|
730
|
+
white-space: normal;
|
|
731
|
+
font-weight: 700;
|
|
637
732
|
}
|
|
638
733
|
.kr2-strong-level {
|
|
639
734
|
display: inline-flex;
|
|
@@ -649,10 +744,20 @@ const CSS = `
|
|
|
649
744
|
color: #ffffff;
|
|
650
745
|
font-weight: 700;
|
|
651
746
|
}
|
|
652
|
-
.kr2-strong-stock {
|
|
653
|
-
white-space: normal;
|
|
654
|
-
|
|
655
|
-
|
|
747
|
+
.kr2-strong-stock {
|
|
748
|
+
white-space: normal;
|
|
749
|
+
text-align: center !important;
|
|
750
|
+
}
|
|
751
|
+
.kr2-strong-stock-th {
|
|
752
|
+
text-align: center !important;
|
|
753
|
+
}
|
|
754
|
+
.kr2-strong-stock-line {
|
|
755
|
+
display: block;
|
|
756
|
+
}
|
|
757
|
+
.kr2-strong-stock-line + .kr2-strong-stock-line {
|
|
758
|
+
margin-top: 2px;
|
|
759
|
+
}
|
|
760
|
+
.kr2-strong-stock-name {
|
|
656
761
|
color: #ffffff;
|
|
657
762
|
font-weight: 700;
|
|
658
763
|
}
|
|
@@ -687,10 +792,28 @@ const CSS = `
|
|
|
687
792
|
.kr2-strong-owned.kr2-strong-stock-short {
|
|
688
793
|
color: #ff6b6b;
|
|
689
794
|
}
|
|
690
|
-
.kr2-strong-owned.kr2-strong-stock-clear {
|
|
691
|
-
color: #4fc3f7;
|
|
692
|
-
}
|
|
693
|
-
.kr2-strong-
|
|
795
|
+
.kr2-strong-owned.kr2-strong-stock-clear {
|
|
796
|
+
color: #4fc3f7;
|
|
797
|
+
}
|
|
798
|
+
.kr2-strong-owned-line {
|
|
799
|
+
display: block;
|
|
800
|
+
}
|
|
801
|
+
.kr2-strong-owned-line + .kr2-strong-owned-line {
|
|
802
|
+
margin-top: 2px;
|
|
803
|
+
}
|
|
804
|
+
.kr2-strong-owned-line-clear {
|
|
805
|
+
color: #4fc3f7;
|
|
806
|
+
}
|
|
807
|
+
.kr2-strong-owned-line-short {
|
|
808
|
+
color: #ff6b6b;
|
|
809
|
+
}
|
|
810
|
+
.kr2-strong-owned-line-missing {
|
|
811
|
+
color: #abb3bf;
|
|
812
|
+
}
|
|
813
|
+
.kr2-strong-completion-done {
|
|
814
|
+
color: #4fc3f7;
|
|
815
|
+
}
|
|
816
|
+
.kr2-strong-clear-row td {
|
|
694
817
|
color: #4fc3f7;
|
|
695
818
|
}
|
|
696
819
|
.kr2-strong-clear-row .kr2-strong-target,
|
|
@@ -866,12 +989,18 @@ const CSS = `
|
|
|
866
989
|
color: #abb3bf;
|
|
867
990
|
cursor: default;
|
|
868
991
|
}
|
|
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-
|
|
992
|
+
.kr2-row-not-improveable .kr2-name,
|
|
993
|
+
.kr2-row-not-improveable .kr2-secretary,
|
|
994
|
+
.kr2-row-not-improveable .kr2-meta {
|
|
995
|
+
color: #abb3bf;
|
|
996
|
+
}
|
|
997
|
+
.kr2-row-clear {
|
|
998
|
+
background: rgba(79, 195, 247, 0.14);
|
|
999
|
+
}
|
|
1000
|
+
.kr2-row-clear:hover {
|
|
1001
|
+
background: rgba(79, 195, 247, 0.2);
|
|
1002
|
+
}
|
|
1003
|
+
.kr2-reco-empty {
|
|
875
1004
|
min-height: 34px;
|
|
876
1005
|
}
|
|
877
1006
|
.kr2-not-improveable-group {
|
|
@@ -961,14 +1090,35 @@ const CSS = `
|
|
|
961
1090
|
font-size: 9px;
|
|
962
1091
|
line-height: 1.2;
|
|
963
1092
|
}
|
|
964
|
-
.kr2-name {
|
|
965
|
-
flex: 1 1 0;
|
|
966
|
-
min-width: 0;
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
1093
|
+
.kr2-name-cell {
|
|
1094
|
+
flex: 1 1 0;
|
|
1095
|
+
min-width: 0;
|
|
1096
|
+
display: flex;
|
|
1097
|
+
flex-direction: column;
|
|
1098
|
+
justify-content: center;
|
|
1099
|
+
gap: 1px;
|
|
1100
|
+
}
|
|
1101
|
+
.kr2-name {
|
|
1102
|
+
font-weight: 600;
|
|
1103
|
+
white-space: nowrap;
|
|
1104
|
+
overflow: hidden;
|
|
1105
|
+
text-overflow: ellipsis;
|
|
1106
|
+
}
|
|
1107
|
+
.kr2-name-completion {
|
|
1108
|
+
font-size: 11px;
|
|
1109
|
+
line-height: 1.2;
|
|
1110
|
+
white-space: nowrap;
|
|
1111
|
+
font-weight: 400;
|
|
1112
|
+
}
|
|
1113
|
+
.kr2-name-completion-incomplete {
|
|
1114
|
+
color: #ff6b6b;
|
|
1115
|
+
}
|
|
1116
|
+
.kr2-name-completion-done-active {
|
|
1117
|
+
color: #4fc3f7;
|
|
1118
|
+
}
|
|
1119
|
+
.kr2-name-completion-clear {
|
|
1120
|
+
color: #4fc3f7;
|
|
1121
|
+
}
|
|
972
1122
|
.kr2-secretary {
|
|
973
1123
|
flex: 1 1 0;
|
|
974
1124
|
min-width: 0;
|
|
@@ -1117,7 +1267,17 @@ const CSS = `
|
|
|
1117
1267
|
align-items: flex-end;
|
|
1118
1268
|
gap: 6px;
|
|
1119
1269
|
}
|
|
1120
|
-
.kr2-
|
|
1270
|
+
.kr2-rare-warning {
|
|
1271
|
+
color: #ff6b6b;
|
|
1272
|
+
font-size: 11px;
|
|
1273
|
+
white-space: nowrap;
|
|
1274
|
+
}
|
|
1275
|
+
.kr2-rare-warning-secondary {
|
|
1276
|
+
color: #ffb3b3;
|
|
1277
|
+
font-size: 11px;
|
|
1278
|
+
white-space: nowrap;
|
|
1279
|
+
}
|
|
1280
|
+
.kr2-material-list {
|
|
1121
1281
|
display: flex;
|
|
1122
1282
|
flex-direction: column;
|
|
1123
1283
|
align-items: flex-end;
|
|
@@ -1235,11 +1395,64 @@ const CSS = `
|
|
|
1235
1395
|
font-size: 12px;
|
|
1236
1396
|
margin-top: 2px;
|
|
1237
1397
|
}
|
|
1238
|
-
.kr2-modal-actions {
|
|
1239
|
-
display: flex;
|
|
1240
|
-
gap: 8px;
|
|
1241
|
-
}
|
|
1242
|
-
.kr2-
|
|
1398
|
+
.kr2-modal-actions {
|
|
1399
|
+
display: flex;
|
|
1400
|
+
gap: 8px;
|
|
1401
|
+
}
|
|
1402
|
+
.kr2-modal-close {
|
|
1403
|
+
width: 30px;
|
|
1404
|
+
height: 30px;
|
|
1405
|
+
padding: 0;
|
|
1406
|
+
display: flex;
|
|
1407
|
+
align-items: center;
|
|
1408
|
+
justify-content: center;
|
|
1409
|
+
border: 1px solid #5f6b7c;
|
|
1410
|
+
border-radius: 4px;
|
|
1411
|
+
background: #2f343c;
|
|
1412
|
+
color: #f6f7f9;
|
|
1413
|
+
font-size: 18px;
|
|
1414
|
+
line-height: 1;
|
|
1415
|
+
cursor: pointer;
|
|
1416
|
+
}
|
|
1417
|
+
.kr2-modal-close:hover {
|
|
1418
|
+
background: #383e47;
|
|
1419
|
+
color: #fff;
|
|
1420
|
+
}
|
|
1421
|
+
.kr2-help-modal {
|
|
1422
|
+
width: 720px;
|
|
1423
|
+
}
|
|
1424
|
+
.kr2-help-body {
|
|
1425
|
+
flex: 1;
|
|
1426
|
+
min-height: 0;
|
|
1427
|
+
overflow-y: auto;
|
|
1428
|
+
padding: 14px 16px 18px;
|
|
1429
|
+
}
|
|
1430
|
+
.kr2-help-lead {
|
|
1431
|
+
margin-bottom: 10px;
|
|
1432
|
+
color: #8abbff;
|
|
1433
|
+
font-size: 14px;
|
|
1434
|
+
font-weight: 800;
|
|
1435
|
+
}
|
|
1436
|
+
.kr2-help-section + .kr2-help-section {
|
|
1437
|
+
margin-top: 14px;
|
|
1438
|
+
}
|
|
1439
|
+
.kr2-help-section-title {
|
|
1440
|
+
margin-bottom: 6px;
|
|
1441
|
+
color: #8abbff;
|
|
1442
|
+
font-size: 14px;
|
|
1443
|
+
font-weight: 800;
|
|
1444
|
+
}
|
|
1445
|
+
.kr2-help-list {
|
|
1446
|
+
margin: 0;
|
|
1447
|
+
padding-left: 20px;
|
|
1448
|
+
color: #d6d9de;
|
|
1449
|
+
font-size: 13px;
|
|
1450
|
+
line-height: 1.7;
|
|
1451
|
+
}
|
|
1452
|
+
.kr2-help-list li + li {
|
|
1453
|
+
margin-top: 2px;
|
|
1454
|
+
}
|
|
1455
|
+
.kr2-dev-scroll {
|
|
1243
1456
|
flex: 1;
|
|
1244
1457
|
min-height: 0;
|
|
1245
1458
|
overflow-y: auto;
|
|
@@ -2365,7 +2578,20 @@ function buildRecommendation(normal, certain, p) {
|
|
|
2365
2578
|
return { expected, text: "相同", tone: "same" }
|
|
2366
2579
|
}
|
|
2367
2580
|
|
|
2368
|
-
function
|
|
2581
|
+
function classifyRareMaterial(materials, kcDevData) {
|
|
2582
|
+
const sets = getRareEquipSets()
|
|
2583
|
+
let hasSecondary = false
|
|
2584
|
+
for (const item of materials || []) {
|
|
2585
|
+
if (!item) continue
|
|
2586
|
+
if (item.item_material_key != null && RARE_MATERIAL_KEYS.has(String(item.item_material_key))) return "rare"
|
|
2587
|
+
const name = String(item.item_name || "")
|
|
2588
|
+
if (sets.rare.has(name)) return "rare"
|
|
2589
|
+
if (sets.secondary.has(name)) hasSecondary = true
|
|
2590
|
+
}
|
|
2591
|
+
return hasSecondary ? "secondary" : null
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
function MaterialDetail({ materials, onMaterialClick, inventoryByEquip, onInventoryClick, useItemCounts }) {
|
|
2369
2595
|
const items = (materials || []).filter((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
|
|
2370
2596
|
if (items.length === 0) {
|
|
2371
2597
|
return React.createElement("div", { className: "kr2-material-empty" }, "无消耗装备")
|
|
@@ -2877,7 +3103,143 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2877
3103
|
)
|
|
2878
3104
|
}
|
|
2879
3105
|
|
|
2880
|
-
|
|
3106
|
+
function formatStrongLevel(level) {
|
|
3107
|
+
const n = Number(level)
|
|
3108
|
+
if (n >= 10) return "max"
|
|
3109
|
+
return "+" + String(n)
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
function buildStrongEntries(rows, inventoryByEquip, selection) {
|
|
3113
|
+
const inventoryLoaded = inventoryByEquip && Object.keys(inventoryByEquip).length > 0
|
|
3114
|
+
const entries = []
|
|
3115
|
+
const demandMap = {}
|
|
3116
|
+
for (const row of rows || []) {
|
|
3117
|
+
const sel = (selection || {})[row.id] || { selected: true, target: "max", qty: 1 }
|
|
3118
|
+
const qty = Math.max(1, Math.min(99, Math.round(Number(sel.qty) || 1)))
|
|
3119
|
+
const evoUpgradeId = sel.evoUpgradeId || null
|
|
3120
|
+
const evoUpgrade = evoUpgradeId ? (row.upgrades || []).find((u) => String(u.upgrade_id) === String(evoUpgradeId)) : null
|
|
3121
|
+
const displayRow = evoUpgrade
|
|
3122
|
+
? Object.assign({}, row, { id: row.id + ":evo:" + evoUpgrade.upgrade_id, name: evoUpgrade.targetName, category: evoUpgrade.targetCategory || row.category })
|
|
3123
|
+
: row
|
|
3124
|
+
const targetEquipId = evoUpgrade ? String(evoUpgrade.upgrade_id) : row.id
|
|
3125
|
+
const targetLevelValue = evoUpgrade ? 0 : (row.improveable === false ? 0 : (sel.target === "max" ? 10 : 6))
|
|
3126
|
+
const bucket = demandMap[targetEquipId] || (demandMap[targetEquipId] = { equipId: targetEquipId, displayRow, sourceRowIds: [], sourceRowIdsByLevel: {}, demands: {}, evolvedLevels: {} })
|
|
3127
|
+
if (bucket.sourceRowIds.indexOf(row.id) < 0) bucket.sourceRowIds.push(row.id)
|
|
3128
|
+
const levelKey = String(targetLevelValue)
|
|
3129
|
+
const levelSources = bucket.sourceRowIdsByLevel[levelKey] || (bucket.sourceRowIdsByLevel[levelKey] = [])
|
|
3130
|
+
if (levelSources.indexOf(row.id) < 0) levelSources.push(row.id)
|
|
3131
|
+
if (evoUpgrade) bucket.evolvedLevels[String(targetLevelValue)] = true
|
|
3132
|
+
bucket.demands[String(targetLevelValue)] = (bucket.demands[String(targetLevelValue)] || 0) + qty
|
|
3133
|
+
}
|
|
3134
|
+
for (const bucket of Object.values(demandMap)) {
|
|
3135
|
+
const inv = (inventoryByEquip || {})[bucket.equipId]
|
|
3136
|
+
const inventoryLevels = []
|
|
3137
|
+
if (inv && inv.levels) {
|
|
3138
|
+
for (const level of Object.keys(inv.levels)) {
|
|
3139
|
+
const count = Math.max(0, Math.round(Number(inv.levels[level]) || 0))
|
|
3140
|
+
if (count > 0) inventoryLevels.push({ level: Number(level), count })
|
|
3141
|
+
}
|
|
3142
|
+
inventoryLevels.sort((a, b) => b.level - a.level)
|
|
3143
|
+
}
|
|
3144
|
+
const remaining = {}
|
|
3145
|
+
for (const lv of inventoryLevels) remaining[String(lv.level)] = lv.count
|
|
3146
|
+
const targetLevels = Object.keys(bucket.demands).map(Number).sort((a, b) => b - a)
|
|
3147
|
+
const allocation = {}
|
|
3148
|
+
const shortfall = {}
|
|
3149
|
+
for (const tl of targetLevels) {
|
|
3150
|
+
let need = bucket.demands[String(tl)] || 0
|
|
3151
|
+
for (const lv of inventoryLevels) {
|
|
3152
|
+
if (need <= 0) break
|
|
3153
|
+
const avail = remaining[String(lv.level)] || 0
|
|
3154
|
+
if (avail <= 0) continue
|
|
3155
|
+
const take = Math.min(need, avail)
|
|
3156
|
+
const key = String(tl) + "|" + String(lv.level)
|
|
3157
|
+
const alloc = allocation[key] || (allocation[key] = { targetLevelValue: tl, inventoryLevel: lv.level, qty: 0, stock: 0 })
|
|
3158
|
+
alloc.qty += take
|
|
3159
|
+
alloc.stock += take
|
|
3160
|
+
remaining[String(lv.level)] = avail - take
|
|
3161
|
+
need -= take
|
|
3162
|
+
}
|
|
3163
|
+
if (need > 0) shortfall[String(tl)] = need
|
|
3164
|
+
}
|
|
3165
|
+
for (const key of Object.keys(allocation)) {
|
|
3166
|
+
const alloc = allocation[key]
|
|
3167
|
+
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 })
|
|
3168
|
+
}
|
|
3169
|
+
for (const tl of Object.keys(shortfall)) {
|
|
3170
|
+
const value = Number(tl)
|
|
3171
|
+
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 })
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
for (const item of entries) {
|
|
3175
|
+
item.clear = item.qty > 0 && item.stock != null && item.inventoryLevel >= item.targetLevelValue && item.stock >= item.qty
|
|
3176
|
+
item.completed = item.clear ? item.qty : 0
|
|
3177
|
+
item.levelShort = item.inventoryLevel != null && item.inventoryLevel < item.targetLevelValue
|
|
3178
|
+
item.countShort = item.stock != null && item.qty > 0 && item.stock < item.qty
|
|
3179
|
+
item.countEnough = item.stock != null && item.stock >= item.qty
|
|
3180
|
+
}
|
|
3181
|
+
const levelRank = (item) => item.inventoryLevel == null ? -1 : item.inventoryLevel
|
|
3182
|
+
entries.sort((a, b) => {
|
|
3183
|
+
const ac = a.clear ? 1 : 0
|
|
3184
|
+
const bc = b.clear ? 1 : 0
|
|
3185
|
+
if (ac !== bc) return bc - ac
|
|
3186
|
+
if (a.clear) return b.qty - a.qty || levelRank(b) - levelRank(a)
|
|
3187
|
+
const sa = a.stock == null ? -1 : a.stock
|
|
3188
|
+
const sb = b.stock == null ? -1 : b.stock
|
|
3189
|
+
return sb - sa || b.qty - a.qty || levelRank(b) - levelRank(a)
|
|
3190
|
+
})
|
|
3191
|
+
return { entries, inventoryLoaded }
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
function buildStrongGroups(entries) {
|
|
3195
|
+
const groupsByKey = {}
|
|
3196
|
+
for (const item of entries || []) {
|
|
3197
|
+
const key = item.row.id + "|" + String(item.targetLevelValue)
|
|
3198
|
+
const group = groupsByKey[key] || (groupsByKey[key] = {
|
|
3199
|
+
key,
|
|
3200
|
+
row: item.row,
|
|
3201
|
+
targetLevel: item.targetLevel,
|
|
3202
|
+
targetLevelValue: item.targetLevelValue,
|
|
3203
|
+
items: [],
|
|
3204
|
+
sourceRowIds: [],
|
|
3205
|
+
qty: 0,
|
|
3206
|
+
completed: 0,
|
|
3207
|
+
stock: 0,
|
|
3208
|
+
stockLoaded: false,
|
|
3209
|
+
maxInventoryLevel: -1,
|
|
3210
|
+
evolved: false,
|
|
3211
|
+
})
|
|
3212
|
+
group.items.push(item)
|
|
3213
|
+
group.qty += item.qty
|
|
3214
|
+
group.completed += item.completed || 0
|
|
3215
|
+
if (item.stock != null) {
|
|
3216
|
+
group.stock += item.stock
|
|
3217
|
+
group.stockLoaded = true
|
|
3218
|
+
}
|
|
3219
|
+
if (item.inventoryLevel != null) group.maxInventoryLevel = Math.max(group.maxInventoryLevel, item.inventoryLevel)
|
|
3220
|
+
if (item.evolved) group.evolved = true
|
|
3221
|
+
for (const rowId of item.sourceRowIds || []) {
|
|
3222
|
+
if (group.sourceRowIds.indexOf(rowId) < 0) group.sourceRowIds.push(rowId)
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
const groups = Object.keys(groupsByKey).map((key) => groupsByKey[key])
|
|
3226
|
+
for (const group of groups) {
|
|
3227
|
+
group.items.sort((a, b) => (b.inventoryLevel == null ? -1 : b.inventoryLevel) - (a.inventoryLevel == null ? -1 : a.inventoryLevel))
|
|
3228
|
+
group.clear = group.qty > 0 && group.completed >= group.qty
|
|
3229
|
+
}
|
|
3230
|
+
groups.sort((a, b) => {
|
|
3231
|
+
const ac = a.clear ? 1 : 0
|
|
3232
|
+
const bc = b.clear ? 1 : 0
|
|
3233
|
+
if (ac !== bc) return bc - ac
|
|
3234
|
+
if (a.clear) return b.qty - a.qty || b.maxInventoryLevel - a.maxInventoryLevel
|
|
3235
|
+
const sa = a.stockLoaded ? a.stock : -1
|
|
3236
|
+
const sb = b.stockLoaded ? b.stock : -1
|
|
3237
|
+
return sb - sa || b.qty - a.qty || b.maxInventoryLevel - a.maxInventoryLevel
|
|
3238
|
+
})
|
|
3239
|
+
return groups
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
class StrongPage extends React.Component {
|
|
2881
3243
|
catRef = React.createRef()
|
|
2882
3244
|
state = {
|
|
2883
3245
|
categoryOpen: false,
|
|
@@ -2916,96 +3278,28 @@ class StrongPage extends React.Component {
|
|
|
2916
3278
|
})
|
|
2917
3279
|
}
|
|
2918
3280
|
|
|
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"
|
|
3281
|
+
render() {
|
|
3282
|
+
const { rows, inventoryByEquip, selection } = this.props
|
|
3283
|
+
const { entries } = buildStrongEntries(rows, inventoryByEquip, selection)
|
|
3284
|
+
const groups = buildStrongGroups(entries)
|
|
3285
|
+
const categories = Array.from(new Set(groups.map((group) => group.row.category).filter(Boolean))).sort((a, b) => a.localeCompare(b, "zh-Hans-CN"))
|
|
3286
|
+
const selectedCategories = this.state.selectedCategories
|
|
3287
|
+
const visibleGroups = selectedCategories == null ? groups : groups.filter((group) => selectedCategories.indexOf(group.row.category) >= 0)
|
|
3288
|
+
const stockText = (item) => {
|
|
3289
|
+
const nameNode = React.createElement("span", { className: "kr2-strong-stock-name" }, item.row.name)
|
|
3290
|
+
if (item.notFound || item.stock == null) return nameNode
|
|
3291
|
+
const levelPart = formatStrongLevel(item.inventoryLevel)
|
|
3292
|
+
return React.createElement("span", null, nameNode, " ", levelPart)
|
|
3293
|
+
}
|
|
3294
|
+
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"
|
|
3295
|
+
const groupOwnedClass = (group) => !group.stockLoaded ? "kr2-strong-stock-missing" : group.clear ? "kr2-strong-stock-clear" : "kr2-strong-stock-short"
|
|
3296
|
+
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")
|
|
3297
|
+
const completionLineText = (item, group) => {
|
|
3298
|
+
if (item.stock == null) return "--"
|
|
3299
|
+
const completed = item.completed || 0
|
|
3300
|
+
if (group.qty > 0 && completed >= group.qty) return String(completed)
|
|
3301
|
+
return completed > 0 ? React.createElement("span", { className: "kr2-strong-completion-done" }, String(completed)) : String(completed)
|
|
3302
|
+
}
|
|
3009
3303
|
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
3304
|
const categoryHead = React.createElement(
|
|
3011
3305
|
"th",
|
|
@@ -3036,24 +3330,30 @@ class StrongPage extends React.Component {
|
|
|
3036
3330
|
React.createElement(
|
|
3037
3331
|
"thead",
|
|
3038
3332
|
null,
|
|
3039
|
-
React.createElement("tr", null, categoryHead, React.createElement("th", null, "目标装备"), React.createElement("th",
|
|
3333
|
+
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
3334
|
),
|
|
3041
3335
|
React.createElement(
|
|
3042
3336
|
"tbody",
|
|
3043
3337
|
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
|
-
|
|
3338
|
+
visibleGroups.length === 0
|
|
3339
|
+
? React.createElement("tr", null, React.createElement("td", { colSpan: 5 }, "无匹配分类"))
|
|
3340
|
+
: visibleGroups.map((group) =>
|
|
3341
|
+
React.createElement(
|
|
3342
|
+
"tr",
|
|
3343
|
+
{ key: group.key, className: group.clear ? "kr2-strong-clear-row" : null },
|
|
3344
|
+
React.createElement("td", { className: "kr2-strong-cat" }, group.row.category || "-"),
|
|
3345
|
+
React.createElement(
|
|
3346
|
+
"td",
|
|
3347
|
+
{ className: "kr2-strong-equip" },
|
|
3348
|
+
group.row.name + (group.evolved ? "(进化)" : ""),
|
|
3349
|
+
!group.evolved && group.row.improveable !== false ? " " : null,
|
|
3350
|
+
!group.evolved && group.row.improveable !== false ? React.createElement("span", { className: "kr2-strong-level" }, group.targetLevel) : null
|
|
3351
|
+
),
|
|
3352
|
+
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)))),
|
|
3353
|
+
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.items.map((item) => React.createElement("div", { key: item.key, className: completionLineClass(item, group), "data-level": item.inventoryLevel == null ? "" : String(item.inventoryLevel) }, completionLineText(item, group)))),
|
|
3354
|
+
React.createElement("td", { className: "kr2-strong-target", "data-target": String(group.qty) }, String(group.qty))
|
|
3355
|
+
)
|
|
3356
|
+
)
|
|
3057
3357
|
)
|
|
3058
3358
|
)
|
|
3059
3359
|
)
|
|
@@ -3087,7 +3387,8 @@ class LevelOneTable extends React.Component {
|
|
|
3087
3387
|
const normal = phase.consume_improvement_min
|
|
3088
3388
|
const materials = phase.materials || []
|
|
3089
3389
|
const hasMaterials = materials.some((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
|
|
3090
|
-
const
|
|
3390
|
+
const rareWarning = null
|
|
3391
|
+
const rows = []
|
|
3091
3392
|
LEVEL_ONE_ROWS.forEach((rate) => {
|
|
3092
3393
|
const key = rate.range
|
|
3093
3394
|
rows.push(
|
|
@@ -3106,7 +3407,8 @@ class LevelOneTable extends React.Component {
|
|
|
3106
3407
|
"div",
|
|
3107
3408
|
{ className: "kr2-material-cell" },
|
|
3108
3409
|
React.createElement(RateCell, { range: "素材详情", open: !!this.state.open[key], onToggle: () => this.toggle(key) }),
|
|
3109
|
-
|
|
3410
|
+
rareWarning,
|
|
3411
|
+
!!this.state.open[key]
|
|
3110
3412
|
? React.createElement(MaterialDetail, { materials, onMaterialClick: this.props.onMaterialClick, inventoryByEquip: this.props.inventoryByEquip, useItemCounts: this.props.useItemCounts, onInventoryClick: this.props.onInventoryClick })
|
|
3111
3413
|
: null
|
|
3112
3414
|
)
|
|
@@ -3156,7 +3458,9 @@ class LevelTwoTable extends React.Component {
|
|
|
3156
3458
|
const rec = buildRecommendation(normal, certain, p)
|
|
3157
3459
|
const materials = step ? step.materials || [] : []
|
|
3158
3460
|
const hasMaterials = materials.some((item) => item && (item.item_name || item.item_material_key || item.item_equipment_id != null))
|
|
3159
|
-
const
|
|
3461
|
+
const rareTier = rec.tone === "save" ? classifyRareMaterial(materials, kcDevData) : null
|
|
3462
|
+
const rareWarning = rareTier === "rare" ? React.createElement("div", { className: "kr2-rare-warning" }, "稀有素材消耗注意!") : rareTier === "secondary" ? React.createElement("div", { className: "kr2-rare-warning-secondary" }, "次级稀有素材消耗注意!") : null
|
|
3463
|
+
const rangeNode = maxBlue
|
|
3160
3464
|
? React.createElement("span", null, "★9→", React.createElement("span", { className: "kr2-level-max-blue" }, "max"))
|
|
3161
3465
|
: range
|
|
3162
3466
|
rows.push(
|
|
@@ -3192,7 +3496,8 @@ class LevelTwoTable extends React.Component {
|
|
|
3192
3496
|
"div",
|
|
3193
3497
|
{ className: "kr2-material-cell" },
|
|
3194
3498
|
React.createElement(RateCell, { range: rec.text, open: !!this.state.open[key], onToggle: () => this.toggle(key), tone: rec.tone }),
|
|
3195
|
-
|
|
3499
|
+
rareWarning,
|
|
3500
|
+
!!this.state.open[key]
|
|
3196
3501
|
? React.createElement(MaterialDetail, { materials, onMaterialClick: this.props.onMaterialClick, inventoryByEquip: this.props.inventoryByEquip, useItemCounts: this.props.useItemCounts, onInventoryClick: this.props.onInventoryClick })
|
|
3197
3502
|
: null
|
|
3198
3503
|
)
|
|
@@ -3270,13 +3575,14 @@ class LevelSection extends React.Component {
|
|
|
3270
3575
|
}
|
|
3271
3576
|
}
|
|
3272
3577
|
|
|
3273
|
-
function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEquip, useItemCounts, onInventoryClick, isFavorite, onFavoriteClick, secretaryText, kcDevData }) {
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3578
|
+
function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEquip, useItemCounts, onInventoryClick, isFavorite, onFavoriteClick, secretaryText, kcDevData, completion }) {
|
|
3579
|
+
const clear = !!(completion && completion.target > 0 && completion.completed >= completion.target)
|
|
3580
|
+
return React.createElement(
|
|
3581
|
+
"div",
|
|
3582
|
+
null,
|
|
3583
|
+
React.createElement(
|
|
3584
|
+
"div",
|
|
3585
|
+
{ className: "kr2-row" + (row.improveable === false ? " kr2-row-not-improveable" : "") + (clear ? " kr2-row-clear" : ""), onClick: row.improveable === false ? null : onToggle },
|
|
3280
3586
|
React.createElement(
|
|
3281
3587
|
"button",
|
|
3282
3588
|
{ className: "kr2-fav-btn" + (isFavorite ? " kr2-fav-active" : ""), onClick: (e) => { e.stopPropagation(); onFavoriteClick && onFavoriteClick(row.id) }, title: isFavorite ? "取消收藏" : "收藏" },
|
|
@@ -3288,7 +3594,24 @@ function EquipmentRow({ row, expanded, onToggle, onMaterialClick, inventoryByEqu
|
|
|
3288
3594
|
React.createElement(SlotitemIcon, { slotitemId: row.icon, className: "kr2-icon" }),
|
|
3289
3595
|
React.createElement("span", { className: "kr2-arrow" }, row.improveable === false ? "" : expanded ? "▼" : "▶")
|
|
3290
3596
|
),
|
|
3291
|
-
React.createElement(
|
|
3597
|
+
React.createElement(
|
|
3598
|
+
"span",
|
|
3599
|
+
{ className: "kr2-name-cell" },
|
|
3600
|
+
React.createElement("span", { className: "kr2-name" }, row.name),
|
|
3601
|
+
completion
|
|
3602
|
+
? clear
|
|
3603
|
+
? React.createElement("span", { className: "kr2-name-completion kr2-name-completion-clear" }, "(", String(completion.completed), "/", String(completion.target), ")clear!")
|
|
3604
|
+
: React.createElement(
|
|
3605
|
+
"span",
|
|
3606
|
+
{ className: "kr2-name-completion kr2-name-completion-incomplete" },
|
|
3607
|
+
"完成数(",
|
|
3608
|
+
React.createElement("span", { className: "kr2-name-completion-done" + (completion.completed > 0 ? " kr2-name-completion-done-active" : "") }, String(completion.completed)),
|
|
3609
|
+
"/",
|
|
3610
|
+
String(completion.target),
|
|
3611
|
+
")"
|
|
3612
|
+
)
|
|
3613
|
+
: null
|
|
3614
|
+
),
|
|
3292
3615
|
React.createElement("span", { className: "kr2-secretary" }, row.improveable === false ? "" : (secretaryText || "-")),
|
|
3293
3616
|
React.createElement(
|
|
3294
3617
|
"span",
|
|
@@ -3552,14 +3875,96 @@ function readPlanIncludeDev() {
|
|
|
3552
3875
|
}
|
|
3553
3876
|
}
|
|
3554
3877
|
|
|
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
|
-
|
|
3878
|
+
function savePlanIncludeDev(value) {
|
|
3879
|
+
try {
|
|
3880
|
+
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
3881
|
+
if (storage) storage.setItem(PLAN_INCLUDE_DEV_STORAGE_KEY, value ? "1" : "0")
|
|
3882
|
+
} catch (_) {}
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
function HelpModal({ onClose, updateNotes }) {
|
|
3886
|
+
const sections = []
|
|
3887
|
+
if (updateNotes && updateNotes.length) sections.push({ title: PLUGIN_VERSION + "更新", items: updateNotes })
|
|
3888
|
+
sections.push(
|
|
3889
|
+
{
|
|
3890
|
+
title: "1.改修列表",
|
|
3891
|
+
items: [
|
|
3892
|
+
"显示每日改修装备,打开插件时默认自动跳转到当前星期数;",
|
|
3893
|
+
"装备行上最右侧为改修推荐星级,数据参考nga梦美改修2.0贴(插件版头有网站链接),点击表头可以按照星级排序;",
|
|
3894
|
+
"点击对应装备行可展开详细改修数据,默认只展开6-10级的改修(也可手动点开查看),最右侧确保推荐是按照螺丝期望自动计算的,未考虑稀有素材和紫菜的消耗情况(请注意甄别);",
|
|
3895
|
+
"点击装备行最左侧的星星可以收藏该装备,点亮插件右上角的收藏按钮会隐藏其他未收藏的装备;",
|
|
3896
|
+
"点击确保推荐列中的“推荐确保”/“不确保”按钮会显示消耗素材情况以及库存素材数量(默认不统计带有星级的素材),点击素材会弹出装备开发配方列表,点击库存可查看已拥有的素材详情(主要是查看星级);",
|
|
3897
|
+
],
|
|
3898
|
+
},
|
|
3899
|
+
{
|
|
3900
|
+
title: "2.素材计算",
|
|
3901
|
+
items: [
|
|
3902
|
+
"只有在改修列表中点击收藏的装备才会显示在该页中;",
|
|
3903
|
+
"为了让插件看起来更加简洁,改修目标只设置了+6、max和进化三个选项,输入目标数量后,插件会自动计算所需的素材汇总情况;",
|
|
3904
|
+
"勾选“统计素材开发的紫菜消耗期望”会计算当所有改修素材均来自开发时所预计消耗的紫菜数量(图一乐功能);",
|
|
3905
|
+
"可对开发资材、螺丝以及素材汇总中的需求、库存和紫菜开发期望进行排序;",
|
|
3906
|
+
],
|
|
3907
|
+
},
|
|
3908
|
+
{
|
|
3909
|
+
title: "3.我变强了!",
|
|
3910
|
+
items: [
|
|
3911
|
+
"所有收藏的装备均会在该页中显示(无论在素材计算页中是否勾选),插件会自动计算目标装备与库存装备的星级、数量差异,并默认倒序排列;",
|
|
3912
|
+
"已完成的装备会自动置顶并显示clear!;",
|
|
3913
|
+
"计划的完成情况会同步显示在改修列表页的装备行上;",
|
|
3914
|
+
"注意在素材计算页选择“进化”的装备会和进化后的同名装备分开计算,用来锚定阶段性目标。",
|
|
3915
|
+
],
|
|
3916
|
+
},
|
|
3917
|
+
{
|
|
3918
|
+
title: "其他常规功能",
|
|
3919
|
+
items: [
|
|
3920
|
+
"模糊搜索,搜索栏支持输入简体中文;",
|
|
3921
|
+
"可在插件版头按照装备大类进行筛选;",
|
|
3922
|
+
"插件也加入了不可改修装备,同样可以收藏,并正常显示在我变强了页中。",
|
|
3923
|
+
],
|
|
3924
|
+
},
|
|
3925
|
+
)
|
|
3926
|
+
const updateSection = sections[0] && sections[0].title === PLUGIN_VERSION + "更新" ? sections[0] : null
|
|
3927
|
+
const guideSections = updateSection ? sections.slice(1) : sections
|
|
3928
|
+
const renderSection = (section, key) =>
|
|
3929
|
+
React.createElement(
|
|
3930
|
+
"section",
|
|
3931
|
+
{ key, className: "kr2-help-section" },
|
|
3932
|
+
React.createElement("div", { className: "kr2-help-section-title" }, section.title),
|
|
3933
|
+
React.createElement(
|
|
3934
|
+
"ul",
|
|
3935
|
+
{ className: "kr2-help-list" },
|
|
3936
|
+
section.items.map((text, itemIndex) => React.createElement("li", { key: itemIndex }, text))
|
|
3937
|
+
)
|
|
3938
|
+
)
|
|
3939
|
+
return React.createElement(
|
|
3940
|
+
"div",
|
|
3941
|
+
{ className: "kr2-modal-backdrop", onClick: onClose },
|
|
3942
|
+
React.createElement(
|
|
3943
|
+
"div",
|
|
3944
|
+
{ className: "kr2-modal kr2-help-modal", role: "dialog", "aria-modal": "true", "aria-label": "使用说明", onClick: (e) => e.stopPropagation() },
|
|
3945
|
+
React.createElement(
|
|
3946
|
+
"div",
|
|
3947
|
+
{ className: "kr2-modal-head" },
|
|
3948
|
+
React.createElement(
|
|
3949
|
+
"div",
|
|
3950
|
+
null,
|
|
3951
|
+
React.createElement("div", { className: "kr2-modal-title" }, "使用说明"),
|
|
3952
|
+
React.createElement("div", { className: "kr2-modal-sub" }, "螺丝计算器 v" + PLUGIN_VERSION)
|
|
3953
|
+
),
|
|
3954
|
+
React.createElement("button", { type: "button", className: "kr2-modal-close", onClick: onClose, title: "关闭", "aria-label": "关闭使用说明" }, "×")
|
|
3955
|
+
),
|
|
3956
|
+
React.createElement(
|
|
3957
|
+
"div",
|
|
3958
|
+
{ className: "kr2-help-body" },
|
|
3959
|
+
updateSection ? renderSection(updateSection, "update") : null,
|
|
3960
|
+
React.createElement("div", { className: "kr2-help-lead" }, "功能主页"),
|
|
3961
|
+
guideSections.map((section, index) => renderSection(section, index))
|
|
3962
|
+
)
|
|
3963
|
+
)
|
|
3964
|
+
)
|
|
3965
|
+
}
|
|
3966
|
+
|
|
3967
|
+
class KoushuRateApp extends React.Component {
|
|
3563
3968
|
state = {
|
|
3564
3969
|
query: "",
|
|
3565
3970
|
day: japanWeekdayKey(),
|
|
@@ -3583,13 +3988,22 @@ class KoushuRateApp extends React.Component {
|
|
|
3583
3988
|
starSort: readUiState().starSort || null,
|
|
3584
3989
|
activeTab: "list",
|
|
3585
3990
|
improveableOpen: true,
|
|
3586
|
-
nonImproveableOpen: false,
|
|
3587
|
-
planSelection: readPlanSelection(),
|
|
3588
|
-
includeDevExpected: readPlanIncludeDev(),
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3991
|
+
nonImproveableOpen: false,
|
|
3992
|
+
planSelection: readPlanSelection(),
|
|
3993
|
+
includeDevExpected: readPlanIncludeDev(),
|
|
3994
|
+
helpOpen: false,
|
|
3995
|
+
}
|
|
3996
|
+
|
|
3997
|
+
componentDidMount() {
|
|
3998
|
+
const uiState = readUiState()
|
|
3999
|
+
const legacyVersion = uiState.helpVersion ? String(uiState.helpVersion).split(".").slice(0, 3).join(".") : ""
|
|
4000
|
+
const seenVersion = String(uiState.pluginVersion || legacyVersion || "").trim()
|
|
4001
|
+
const firstInstall = !seenVersion
|
|
4002
|
+
const isUpdate = !!seenVersion && seenVersion !== PLUGIN_VERSION
|
|
4003
|
+
if (firstInstall || isUpdate) {
|
|
4004
|
+
this.setState({ helpOpen: true })
|
|
4005
|
+
}
|
|
4006
|
+
this.refresh()
|
|
3593
4007
|
this.checkAkashiUpdate(false)
|
|
3594
4008
|
refreshKcDevData().catch(() => {})
|
|
3595
4009
|
this.loadKcDevExpectations()
|
|
@@ -3597,11 +4011,20 @@ class KoushuRateApp extends React.Component {
|
|
|
3597
4011
|
this.inventoryTimer = setInterval(() => this.refreshInventory(), 1000)
|
|
3598
4012
|
}
|
|
3599
4013
|
|
|
3600
|
-
componentWillUnmount() {
|
|
3601
|
-
if (this.inventoryTimer) clearInterval(this.inventoryTimer)
|
|
3602
|
-
}
|
|
3603
|
-
|
|
3604
|
-
|
|
4014
|
+
componentWillUnmount() {
|
|
4015
|
+
if (this.inventoryTimer) clearInterval(this.inventoryTimer)
|
|
4016
|
+
}
|
|
4017
|
+
|
|
4018
|
+
openHelp = () => {
|
|
4019
|
+
this.setState({ helpOpen: true })
|
|
4020
|
+
}
|
|
4021
|
+
|
|
4022
|
+
closeHelp = () => {
|
|
4023
|
+
saveUiState({ helpVersion: HELP_VERSION, pluginVersion: PLUGIN_VERSION })
|
|
4024
|
+
this.setState({ helpOpen: false })
|
|
4025
|
+
}
|
|
4026
|
+
|
|
4027
|
+
loadKcDevExpectations = () => {
|
|
3605
4028
|
loadKcDevData(false)
|
|
3606
4029
|
.then((data) => this.setState({ kcDevData: data }))
|
|
3607
4030
|
.catch(() => {})
|
|
@@ -3847,8 +4270,9 @@ class KoushuRateApp extends React.Component {
|
|
|
3847
4270
|
if (ib >= 0) return 1
|
|
3848
4271
|
return a.localeCompare(b, "zh-Hans-CN")
|
|
3849
4272
|
})
|
|
3850
|
-
const kcDevPopup = this.state.kcDevPopup
|
|
3851
|
-
const inventoryPopup = this.state.inventoryPopup
|
|
4273
|
+
const kcDevPopup = this.state.kcDevPopup
|
|
4274
|
+
const inventoryPopup = this.state.inventoryPopup
|
|
4275
|
+
const helpOpen = this.state.helpOpen
|
|
3852
4276
|
const kcDevSort = (kcDevPopup && kcDevPopup.sort) || { key: "rate", dir: "desc" }
|
|
3853
4277
|
const kcDevFormulas = kcDevPopup && Array.isArray(kcDevPopup.formulas) ? kcDevPopup.formulas.slice() : []
|
|
3854
4278
|
if (kcDevSort.key === "rate" || kcDevSort.key === "failRate") {
|
|
@@ -3857,10 +4281,21 @@ class KoushuRateApp extends React.Component {
|
|
|
3857
4281
|
return kcDevSort.dir === "asc" ? diff : -diff
|
|
3858
4282
|
})
|
|
3859
4283
|
}
|
|
3860
|
-
const inventoryByEquip = this.state.inventoryByEquip || {}
|
|
3861
|
-
const useItemCounts = this.state.useItemCounts || {}
|
|
3862
|
-
const favoritesOnly = !!this.state.favoritesOnly
|
|
3863
|
-
|
|
4284
|
+
const inventoryByEquip = this.state.inventoryByEquip || {}
|
|
4285
|
+
const useItemCounts = this.state.useItemCounts || {}
|
|
4286
|
+
const favoritesOnly = !!this.state.favoritesOnly
|
|
4287
|
+
const planSelection = this.state.planSelection || {}
|
|
4288
|
+
const favoriteRows = this.state.rows.filter((row) => !!this.state.favorites[row.id])
|
|
4289
|
+
const strongSummary = {}
|
|
4290
|
+
for (const item of buildStrongEntries(favoriteRows, inventoryByEquip, planSelection).entries) {
|
|
4291
|
+
const rowIds = item.sourceRowIds && item.sourceRowIds.length ? item.sourceRowIds : [item.row.id]
|
|
4292
|
+
for (const rowId of rowIds) {
|
|
4293
|
+
const summary = strongSummary[rowId] || (strongSummary[rowId] = { completed: 0, target: 0 })
|
|
4294
|
+
summary.completed += item.completed || 0
|
|
4295
|
+
summary.target += item.qty
|
|
4296
|
+
}
|
|
4297
|
+
}
|
|
4298
|
+
let rows = this.state.rows.filter((row) => {
|
|
3864
4299
|
if (favoritesOnly && !this.state.favorites[row.id]) return false
|
|
3865
4300
|
if (row.improveable !== false && day !== ALL_DAYS_KEY && (row.days || []).indexOf(day) < 0) return false
|
|
3866
4301
|
if (category !== "all" && row.category !== category) return false
|
|
@@ -3899,9 +4334,10 @@ class KoushuRateApp extends React.Component {
|
|
|
3899
4334
|
onInventoryClick: this.openInventoryPopup,
|
|
3900
4335
|
isFavorite: !!this.state.favorites[row.id],
|
|
3901
4336
|
onFavoriteClick: this.toggleFavorite,
|
|
3902
|
-
secretaryText: secretaryText(row.secretaries, day),
|
|
3903
|
-
kcDevData: this.state.kcDevData,
|
|
3904
|
-
|
|
4337
|
+
secretaryText: secretaryText(row.secretaries, day),
|
|
4338
|
+
kcDevData: this.state.kcDevData,
|
|
4339
|
+
completion: strongSummary[row.id],
|
|
4340
|
+
})
|
|
3905
4341
|
|
|
3906
4342
|
return React.createElement(
|
|
3907
4343
|
"div",
|
|
@@ -3914,11 +4350,16 @@ class KoushuRateApp extends React.Component {
|
|
|
3914
4350
|
React.createElement(
|
|
3915
4351
|
"div",
|
|
3916
4352
|
{ className: "kr2-title-row" },
|
|
3917
|
-
React.createElement(
|
|
3918
|
-
"div",
|
|
3919
|
-
null,
|
|
3920
|
-
React.createElement(
|
|
3921
|
-
|
|
4353
|
+
React.createElement(
|
|
4354
|
+
"div",
|
|
4355
|
+
null,
|
|
4356
|
+
React.createElement(
|
|
4357
|
+
"div",
|
|
4358
|
+
{ className: "kr2-title-line" },
|
|
4359
|
+
React.createElement("div", { className: "kr2-title" }, "螺丝计算器"),
|
|
4360
|
+
React.createElement("button", { type: "button", className: "kr2-help-btn", onClick: this.openHelp }, "使用说明")
|
|
4361
|
+
),
|
|
4362
|
+
React.createElement(
|
|
3922
4363
|
"div",
|
|
3923
4364
|
{ className: "kr2-title-note" },
|
|
3924
4365
|
"螺丝确保仅供参考,稀有素材消耗请酌情考虑~(∠・ω< )⌒★"
|
|
@@ -4084,10 +4525,10 @@ class KoushuRateApp extends React.Component {
|
|
|
4084
4525
|
),
|
|
4085
4526
|
this.state.activeTab === "plan"
|
|
4086
4527
|
? React.createElement(PlanningPage, {
|
|
4087
|
-
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4088
|
-
inventoryByEquip,
|
|
4089
|
-
useItemCounts,
|
|
4090
|
-
selection:
|
|
4528
|
+
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4529
|
+
inventoryByEquip,
|
|
4530
|
+
useItemCounts,
|
|
4531
|
+
selection: planSelection,
|
|
4091
4532
|
onToggle: this.togglePlanRow,
|
|
4092
4533
|
onTarget: this.setPlanTarget,
|
|
4093
4534
|
onEvo: this.setPlanEvo,
|
|
@@ -4099,14 +4540,17 @@ class KoushuRateApp extends React.Component {
|
|
|
4099
4540
|
onToggleIncludeDevExpected: this.toggleIncludeDevExpected,
|
|
4100
4541
|
})
|
|
4101
4542
|
: 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
|
-
|
|
4543
|
+
this.state.activeTab === "strong"
|
|
4544
|
+
? React.createElement(StrongPage, {
|
|
4545
|
+
rows: this.state.rows.filter((row) => !!this.state.favorites[row.id]),
|
|
4546
|
+
inventoryByEquip,
|
|
4547
|
+
selection: planSelection,
|
|
4548
|
+
})
|
|
4549
|
+
: null,
|
|
4550
|
+
helpOpen
|
|
4551
|
+
? React.createElement(HelpModal, { onClose: this.closeHelp, updateNotes: CURRENT_HELP_UPDATE_NOTES })
|
|
4552
|
+
: null,
|
|
4553
|
+
kcDevPopup
|
|
4110
4554
|
? React.createElement(
|
|
4111
4555
|
"div",
|
|
4112
4556
|
{ className: "kr2-modal-backdrop", onClick: this.closeKcDevPopup },
|