poi-plugin-koushu-rate 2.0.8 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +132 -14
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -341,13 +341,22 @@ const CSS = `
|
|
|
341
341
|
}
|
|
342
342
|
.kr2-plan-bar-left {
|
|
343
343
|
display: flex;
|
|
344
|
-
align-items:
|
|
344
|
+
align-items: flex-end;
|
|
345
345
|
gap: 10px;
|
|
346
346
|
}
|
|
347
347
|
.kr2-plan-total-label {
|
|
348
348
|
font-size: 12px;
|
|
349
349
|
color: #abb3bf;
|
|
350
350
|
}
|
|
351
|
+
.kr2-plan-dev-toggle {
|
|
352
|
+
display: inline-flex;
|
|
353
|
+
align-items: center;
|
|
354
|
+
gap: 4px;
|
|
355
|
+
font-size: 14px;
|
|
356
|
+
color: #ffd54f;
|
|
357
|
+
cursor: pointer;
|
|
358
|
+
white-space: nowrap;
|
|
359
|
+
}
|
|
351
360
|
.kr2-plan-table td.kr2-plan-mat-col,
|
|
352
361
|
.kr2-plan-table td.kr2-plan-consumed {
|
|
353
362
|
text-align: left;
|
|
@@ -1590,12 +1599,30 @@ function kcDevRecipes(data, equipId) {
|
|
|
1590
1599
|
}
|
|
1591
1600
|
out.sort((a, b) => {
|
|
1592
1601
|
if (a.rate !== b.rate) return b.rate - a.rate
|
|
1602
|
+
if (a.failRate !== b.failRate) return b.failRate - a.failRate
|
|
1593
1603
|
if (Math.abs(a.total - b.total) > 1) return a.total - b.total
|
|
1594
|
-
return
|
|
1604
|
+
return 0
|
|
1595
1605
|
})
|
|
1596
1606
|
return out
|
|
1597
1607
|
}
|
|
1598
1608
|
|
|
1609
|
+
let kcDevBestCache = {}
|
|
1610
|
+
let kcDevBestCacheKey = ""
|
|
1611
|
+
function kcDevBestFormula(data, equipId) {
|
|
1612
|
+
if (!data) return null
|
|
1613
|
+
const dataKey = String(data.updatedAt || data.generatedAt || "bundled")
|
|
1614
|
+
if (kcDevBestCacheKey !== dataKey) {
|
|
1615
|
+
kcDevBestCache = {}
|
|
1616
|
+
kcDevBestCacheKey = dataKey
|
|
1617
|
+
}
|
|
1618
|
+
const key = String(equipId)
|
|
1619
|
+
if (Object.prototype.hasOwnProperty.call(kcDevBestCache, key)) return kcDevBestCache[key]
|
|
1620
|
+
const bestList = kcDevRecipes(data, key).slice().sort((a, b) => b.rate - a.rate || a.failRate - b.failRate || (Math.abs(a.total - b.total) > 1 ? a.total - b.total : 0))
|
|
1621
|
+
const best = bestList.length ? bestList[0] : null
|
|
1622
|
+
kcDevBestCache[key] = best
|
|
1623
|
+
return best
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1599
1626
|
function openExternalUrl(url) {
|
|
1600
1627
|
try {
|
|
1601
1628
|
let remote = null
|
|
@@ -2198,17 +2225,38 @@ function planFormatScrews(n) {
|
|
|
2198
2225
|
return v.toFixed(1)
|
|
2199
2226
|
}
|
|
2200
2227
|
|
|
2201
|
-
function
|
|
2228
|
+
function planDevExpectedValue(item, count, kcDevData) {
|
|
2229
|
+
if (!item || item.item_equipment_id == null || !kcDevData) return 0
|
|
2230
|
+
const best = kcDevBestFormula(kcDevData, item.item_equipment_id)
|
|
2231
|
+
if (!best || !Number.isFinite(best.rate) || best.rate <= 0) return 0
|
|
2232
|
+
const qty = Number(count) > 0 ? Number(count) : 1
|
|
2233
|
+
return qty * (100 / best.rate)
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
function planDevExpectedText(item, count, kcDevData) {
|
|
2237
|
+
const v = planDevExpectedValue(item, count, kcDevData)
|
|
2238
|
+
return v > 0 ? planFormatScrews(v) : "--"
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
function planMaterialDevExpected(costs, kcDevData) {
|
|
2242
|
+
let total = 0
|
|
2243
|
+
for (const m of costs.materials || []) total += planDevExpectedValue(m.item, m.count, kcDevData)
|
|
2244
|
+
return total
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onToggle, onTarget, onQty, onSelectAll, onMaterialClick, kcDevData, includeDevExpected, onToggleIncludeDevExpected }) {
|
|
2202
2248
|
const planRows = rows.map((row) => {
|
|
2203
2249
|
const sel = (selection || {})[row.id] || { selected: true, target: "max", qty: 1 }
|
|
2204
|
-
|
|
2250
|
+
const costs = planRowCosts(row, sel.target, sel.qty, inventoryByEquip)
|
|
2251
|
+
return { row, sel, costs, matDev: planMaterialDevExpected(costs, kcDevData), display: planCurrentDisplay(row, sel, inventoryByEquip) }
|
|
2205
2252
|
})
|
|
2206
2253
|
const selected = planRows.filter((p) => p.sel.selected)
|
|
2207
2254
|
const totals = { screws: 0, dev: 0, fuel: 0, ammo: 0, steel: 0, bauxite: 0 }
|
|
2208
2255
|
const materialMap = {}
|
|
2256
|
+
const includeDev = !!includeDevExpected
|
|
2209
2257
|
for (const p of selected) {
|
|
2210
2258
|
totals.screws += p.costs.screws
|
|
2211
|
-
totals.dev += p.costs.dev
|
|
2259
|
+
totals.dev += p.costs.dev + (includeDev ? p.matDev : 0)
|
|
2212
2260
|
totals.fuel += p.costs.fuel
|
|
2213
2261
|
totals.ammo += p.costs.ammo
|
|
2214
2262
|
totals.steel += p.costs.steel
|
|
@@ -2241,7 +2289,8 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2241
2289
|
"div",
|
|
2242
2290
|
{ className: "kr2-plan-bar-left" },
|
|
2243
2291
|
React.createElement("span", { className: "kr2-plan-total-label" }, "总资源消耗"),
|
|
2244
|
-
React.createElement("span", { className: "kr2-status" }, "已选 " + selected.length + " / " + planRows.length + " 件收藏装备")
|
|
2292
|
+
React.createElement("span", { className: "kr2-status" }, "已选 " + selected.length + " / " + planRows.length + " 件收藏装备"),
|
|
2293
|
+
React.createElement("label", { className: "kr2-plan-dev-toggle" }, React.createElement("input", { type: "checkbox", checked: !!includeDevExpected, onChange: onToggleIncludeDevExpected }), "统计素材开发的紫菜消耗期望")
|
|
2245
2294
|
),
|
|
2246
2295
|
React.createElement(
|
|
2247
2296
|
"div",
|
|
@@ -2276,7 +2325,7 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2276
2325
|
React.createElement("th", null, "当前"),
|
|
2277
2326
|
React.createElement("th", null, "目标"),
|
|
2278
2327
|
React.createElement("th", null, "目标数量"),
|
|
2279
|
-
React.createElement("th", null, "
|
|
2328
|
+
React.createElement("th", null, "开发资材"),
|
|
2280
2329
|
React.createElement("th", null, "螺丝"),
|
|
2281
2330
|
React.createElement("th", null, "素材")
|
|
2282
2331
|
)
|
|
@@ -2319,7 +2368,7 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2319
2368
|
React.createElement("button", { type: "button", className: "kr2-plan-qty-btn", onClick: () => onQty(p.row.id, Number(p.sel.qty || 1) + 1) }, "+")
|
|
2320
2369
|
)
|
|
2321
2370
|
),
|
|
2322
|
-
React.createElement("td", null, planFormatNumber(p.costs.dev)),
|
|
2371
|
+
React.createElement("td", null, planFormatNumber(p.costs.dev + (includeDev ? p.matDev : 0))),
|
|
2323
2372
|
React.createElement("td", null, planFormatScrews(p.costs.screws)),
|
|
2324
2373
|
React.createElement("td", { className: "kr2-plan-mat-col" }, matText)
|
|
2325
2374
|
)
|
|
@@ -2336,13 +2385,13 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2336
2385
|
React.createElement(
|
|
2337
2386
|
"thead",
|
|
2338
2387
|
null,
|
|
2339
|
-
React.createElement("tr", null, React.createElement("th", { className: "kr2-plan-mat-th" }, "素材名称"), React.createElement("th", null, "需求"), React.createElement("th", null, "库存"), React.createElement("th", { className: "kr2-plan-mat-th" }, "消耗于装备"))
|
|
2388
|
+
React.createElement("tr", null, React.createElement("th", { className: "kr2-plan-mat-th" }, "素材名称"), React.createElement("th", null, "需求"), React.createElement("th", null, "库存"), React.createElement("th", null, "紫菜开发期望"), React.createElement("th", { className: "kr2-plan-mat-th" }, "消耗于装备"))
|
|
2340
2389
|
),
|
|
2341
2390
|
React.createElement(
|
|
2342
2391
|
"tbody",
|
|
2343
2392
|
null,
|
|
2344
2393
|
materialList.length === 0
|
|
2345
|
-
? React.createElement("tr", null, React.createElement("td", { colSpan:
|
|
2394
|
+
? React.createElement("tr", null, React.createElement("td", { colSpan: 5 }, "暂无素材需求"))
|
|
2346
2395
|
: materialList.map((m) =>
|
|
2347
2396
|
React.createElement(
|
|
2348
2397
|
"tr",
|
|
@@ -2350,6 +2399,7 @@ function PlanningPage({ rows, inventoryByEquip, useItemCounts, selection, onTogg
|
|
|
2350
2399
|
React.createElement("td", { className: "kr2-plan-name" }, React.createElement("button", { className: "kr2-plan-mat-btn", onClick: () => onMaterialClick && onMaterialClick(m.item) }, m.name)),
|
|
2351
2400
|
React.createElement("td", null, String(m.required)),
|
|
2352
2401
|
React.createElement("td", { className: stockClass(m.stock, m.required) }, m.stock == null ? "--" : String(m.stock)),
|
|
2402
|
+
React.createElement("td", null, planDevExpectedText(m.item, m.required, kcDevData)),
|
|
2353
2403
|
React.createElement("td", { className: "kr2-plan-consumed" }, m.equips.join("、"))
|
|
2354
2404
|
)
|
|
2355
2405
|
)
|
|
@@ -2628,6 +2678,47 @@ function saveFavorites(favorites) {
|
|
|
2628
2678
|
} catch (_) {}
|
|
2629
2679
|
}
|
|
2630
2680
|
|
|
2681
|
+
const PLAN_SELECTION_STORAGE_KEY = "poi-plugin-koushu-rate:plan-selection";
|
|
2682
|
+
|
|
2683
|
+
function readPlanSelection() {
|
|
2684
|
+
try {
|
|
2685
|
+
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
2686
|
+
if (!storage) return {}
|
|
2687
|
+
const raw = storage.getItem(PLAN_SELECTION_STORAGE_KEY)
|
|
2688
|
+
if (!raw) return {}
|
|
2689
|
+
const parsed = JSON.parse(raw)
|
|
2690
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {}
|
|
2691
|
+
} catch (_) {
|
|
2692
|
+
return {}
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2696
|
+
function savePlanSelection(selection) {
|
|
2697
|
+
try {
|
|
2698
|
+
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
2699
|
+
if (storage) storage.setItem(PLAN_SELECTION_STORAGE_KEY, JSON.stringify(selection || {}))
|
|
2700
|
+
} catch (_) {}
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2703
|
+
const PLAN_INCLUDE_DEV_STORAGE_KEY = "poi-plugin-koushu-rate:plan-include-dev";
|
|
2704
|
+
|
|
2705
|
+
function readPlanIncludeDev() {
|
|
2706
|
+
try {
|
|
2707
|
+
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
2708
|
+
if (!storage) return false
|
|
2709
|
+
return storage.getItem(PLAN_INCLUDE_DEV_STORAGE_KEY) === "1"
|
|
2710
|
+
} catch (_) {
|
|
2711
|
+
return false
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
function savePlanIncludeDev(value) {
|
|
2716
|
+
try {
|
|
2717
|
+
const storage = typeof localStorage !== "undefined" ? localStorage : (typeof window !== "undefined" ? window.localStorage : null)
|
|
2718
|
+
if (storage) storage.setItem(PLAN_INCLUDE_DEV_STORAGE_KEY, value ? "1" : "0")
|
|
2719
|
+
} catch (_) {}
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2631
2722
|
class KoushuRateApp extends React.Component {
|
|
2632
2723
|
state = {
|
|
2633
2724
|
query: "",
|
|
@@ -2646,17 +2737,20 @@ class KoushuRateApp extends React.Component {
|
|
|
2646
2737
|
inventoryPopup: null,
|
|
2647
2738
|
inventoryByEquip: {},
|
|
2648
2739
|
useItemCounts: {},
|
|
2740
|
+
kcDevData: null,
|
|
2649
2741
|
favorites: readFavorites(),
|
|
2650
2742
|
favoritesOnly: false,
|
|
2651
2743
|
starSort: null,
|
|
2652
2744
|
activeTab: "list",
|
|
2653
|
-
planSelection:
|
|
2745
|
+
planSelection: readPlanSelection(),
|
|
2746
|
+
includeDevExpected: readPlanIncludeDev(),
|
|
2654
2747
|
}
|
|
2655
2748
|
|
|
2656
2749
|
componentDidMount() {
|
|
2657
2750
|
this.refresh()
|
|
2658
2751
|
this.checkAkashiUpdate(false)
|
|
2659
2752
|
refreshKcDevData().catch(() => {})
|
|
2753
|
+
this.loadKcDevExpectations()
|
|
2660
2754
|
this.refreshInventory()
|
|
2661
2755
|
this.inventoryTimer = setInterval(() => this.refreshInventory(), 1000)
|
|
2662
2756
|
}
|
|
@@ -2665,6 +2759,12 @@ class KoushuRateApp extends React.Component {
|
|
|
2665
2759
|
if (this.inventoryTimer) clearInterval(this.inventoryTimer)
|
|
2666
2760
|
}
|
|
2667
2761
|
|
|
2762
|
+
loadKcDevExpectations = () => {
|
|
2763
|
+
loadKcDevData(false)
|
|
2764
|
+
.then((data) => this.setState({ kcDevData: data }))
|
|
2765
|
+
.catch(() => {})
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2668
2768
|
refreshInventory = () => {
|
|
2669
2769
|
const nextEquips = getEquipInventory(getInventoryEquips(this.props.envWindow))
|
|
2670
2770
|
const nextUseItems = getUseItemCounts(this.props.envWindow)
|
|
@@ -2817,14 +2917,18 @@ class KoushuRateApp extends React.Component {
|
|
|
2817
2917
|
togglePlanRow = (id) => {
|
|
2818
2918
|
this.setState((prev) => {
|
|
2819
2919
|
const cur = prev.planSelection[id] || this.planDefaultSel(id)
|
|
2820
|
-
|
|
2920
|
+
const planSelection = Object.assign({}, prev.planSelection, { [id]: Object.assign({}, cur, { selected: !cur.selected }) })
|
|
2921
|
+
savePlanSelection(planSelection)
|
|
2922
|
+
return { planSelection }
|
|
2821
2923
|
})
|
|
2822
2924
|
}
|
|
2823
2925
|
|
|
2824
2926
|
setPlanTarget = (id, target) => {
|
|
2825
2927
|
this.setState((prev) => {
|
|
2826
2928
|
const cur = prev.planSelection[id] || this.planDefaultSel(id)
|
|
2827
|
-
|
|
2929
|
+
const planSelection = Object.assign({}, prev.planSelection, { [id]: Object.assign({}, cur, { target }) })
|
|
2930
|
+
savePlanSelection(planSelection)
|
|
2931
|
+
return { planSelection }
|
|
2828
2932
|
})
|
|
2829
2933
|
}
|
|
2830
2934
|
|
|
@@ -2832,7 +2936,9 @@ class KoushuRateApp extends React.Component {
|
|
|
2832
2936
|
const n = Math.max(1, Math.min(99, Math.round(Number(qty) || 1)))
|
|
2833
2937
|
this.setState((prev) => {
|
|
2834
2938
|
const cur = prev.planSelection[id] || this.planDefaultSel(id)
|
|
2835
|
-
|
|
2939
|
+
const planSelection = Object.assign({}, prev.planSelection, { [id]: Object.assign({}, cur, { qty: n }) })
|
|
2940
|
+
savePlanSelection(planSelection)
|
|
2941
|
+
return { planSelection }
|
|
2836
2942
|
})
|
|
2837
2943
|
}
|
|
2838
2944
|
|
|
@@ -2844,10 +2950,19 @@ class KoushuRateApp extends React.Component {
|
|
|
2844
2950
|
const cur = planSelection[row.id] || this.planDefaultSel(row.id)
|
|
2845
2951
|
planSelection[row.id] = Object.assign({}, cur, { selected })
|
|
2846
2952
|
}
|
|
2953
|
+
savePlanSelection(planSelection)
|
|
2847
2954
|
return { planSelection }
|
|
2848
2955
|
})
|
|
2849
2956
|
}
|
|
2850
2957
|
|
|
2958
|
+
toggleIncludeDevExpected = () => {
|
|
2959
|
+
this.setState((prev) => {
|
|
2960
|
+
const includeDevExpected = !prev.includeDevExpected
|
|
2961
|
+
savePlanIncludeDev(includeDevExpected)
|
|
2962
|
+
return { includeDevExpected }
|
|
2963
|
+
})
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2851
2966
|
setKcDevSort = (key) => {
|
|
2852
2967
|
this.setState((prev) => {
|
|
2853
2968
|
const popup = prev.kcDevPopup
|
|
@@ -3084,6 +3199,9 @@ class KoushuRateApp extends React.Component {
|
|
|
3084
3199
|
onQty: this.setPlanQty,
|
|
3085
3200
|
onSelectAll: this.selectAllPlan,
|
|
3086
3201
|
onMaterialClick: this.openKcDevPopup,
|
|
3202
|
+
kcDevData: this.state.kcDevData,
|
|
3203
|
+
includeDevExpected: !!this.state.includeDevExpected,
|
|
3204
|
+
onToggleIncludeDevExpected: this.toggleIncludeDevExpected,
|
|
3087
3205
|
})
|
|
3088
3206
|
: null,
|
|
3089
3207
|
kcDevPopup
|