fix(kæde): højst 3 beskeder og samlede poster i Kræver handling

notifyProblems sender højst 3 beskeder pr. tick og samler resten i én
("+N manglende led — se fanen Kæder"). Alle kædeproblemer står i én rød post
("Kæder: N manglende led", scoret under rød fuld; klik folder kæderne ud) og
slukkede nødvendige fabrikker i højst én post ("Slukket men nødvendig: X +k").
This commit is contained in:
2026-09-30 15:27:08 +02:00
parent d2a4cf0d23
commit b33f2a3b01
6 changed files with 48 additions and 57 deletions
+25 -44
View File
@@ -279,13 +279,11 @@ end
-- "Kræver handling" fra kæden (ADChain.last): ÉT gult punkt "Kæde: N forslag" (klik -> fanen Kæder), så
-- forslagene ikke fylder listen. Rangeres under alle røde punkter (>= 3000), øverst blandt de gule, over "sælg nu".
ADStorageStats.CHAIN_SCORE = 2000
-- Manglende led: én rød post pr. kæde ("Brød mangler et led: Mel"), højst MAX_CHAIN_PROBLEMS (resten står i
-- fanen Kæder; den sidste viste post får more = antal skjulte). Score CHAIN_PROBLEM_SCORE + alvor (0-99): under
-- "rød tom" (3900-4000: løber tør inden et døgn), over "rød fuld" (3000-3100). Alvor = manglende andel af behovet;
-- kredsløb (kan ikke beregnes) = 99.
ADStorageStats.CHAIN_PROBLEM_SCORE = 3500
ADStorageStats.MAX_CHAIN_PROBLEMS = 2
ADStorageStats.MAX_CHAIN_PROBLEM_ITEMS = 2
-- Manglende led: ALLE kædeproblemer i ÉN rød post ("Kæder: N manglende led", klik -> fanen Kæder med kæderne
-- foldet ud), så en gård med mange kæder (fx fermenteringssiloer) ikke fylder "Kræver handling". N = unikke
-- (kæde, vare). Score CHAIN_PROBLEM_SCORE + alvor (0-99): under "rød fuld" (3000-3100), så lagerets røde poster
-- altid vises først, og over de gule (<= 2000). Alvor = manglende andel af behovet; kredsløb = 99.
ADStorageStats.CHAIN_PROBLEM_SCORE = 2900
local function severity(problems)
local missing, need = 0, 0
@@ -297,50 +295,33 @@ local function severity(problems)
return math.floor(99 * math.min(1, missing / need))
end
local function problemEntry(root, problems, titleOf)
local items, seen = {}, {}
for _, problem in ipairs(problems) do
local title = titleOf(problem.fillType)
if not seen[title] then
seen[title] = true
table.insert(items, title)
end
end
local shown = {}
for index = 1, math.min(#items, ADStorageStats.MAX_CHAIN_PROBLEM_ITEMS) do shown[index] = items[index] end
local itemsText = table.concat(shown, ", ")
if #items > #shown then itemsText = itemsText .. " +" .. tostring(#items - #shown) end
local rootTitle = titleOf(root.name)
return {kind = "chainProblem", level = "red", score = ADStorageStats.CHAIN_PROBLEM_SCORE + severity(problems), rootKey = root.key,
rootTitle = rootTitle, itemsText = itemsText, text = rootTitle .. ": " .. itemsText}
end
local function chainProblemEntries(last)
local titles = last.titles or {}
local titleOf = function(name) return tostring(titles[name] or name) end
local byRoot = {}
local known = {}
for _, root in ipairs(last.chain ~= nil and last.chain.roots or {}) do known[root.key] = true end
local problems, seen, rootKeys, rootSeen = {}, {}, {}, {}
for _, problem in ipairs(last.chain ~= nil and last.chain.problems or {}) do
if problem.rootKey ~= nil then
byRoot[problem.rootKey] = byRoot[problem.rootKey] or {}
table.insert(byRoot[problem.rootKey], problem)
if problem.rootKey ~= nil and known[problem.rootKey] then
table.insert(problems, problem)
seen[tostring(problem.rootKey) .. "|" .. tostring(problem.fillType)] = true
if not rootSeen[problem.rootKey] then
rootSeen[problem.rootKey] = true
table.insert(rootKeys, problem.rootKey)
end
end
end
local entries = {}
for _, root in ipairs(last.chain ~= nil and last.chain.roots or {}) do
if byRoot[root.key] ~= nil then table.insert(entries, problemEntry(root, byRoot[root.key], titleOf)) end
end
entries = ADStorageStats.rankAttention(entries)
local result = {}
for index = 1, math.min(#entries, ADStorageStats.MAX_CHAIN_PROBLEMS) do result[index] = entries[index] end
if #entries > #result then result[#result].more = #entries - #result end
return result
if #problems == 0 then return {} end
local count = 0
for _ in pairs(seen) do count = count + 1 end
table.sort(rootKeys, function(a, b) return tostring(a) < tostring(b) end)
return {{kind = "chainProblem", level = "red", score = ADStorageStats.CHAIN_PROBLEM_SCORE + severity(problems), count = count,
rootKeys = rootKeys, text = string.format("Kæder: %d", count)}}
end
-- "Slukket men nødvendig" (ADChain.last.dependency.offNeeded): én rød post pr. fabrik, højst MAX_DEPENDENCY_ENTRIES
-- (den sidste får more = antal skjulte). Score DEPENDENCY_SCORE + hast (0-99, færre lagerdage = højere; ukendt = 50):
-- over manglende led (3500-3599), under "rød tom" (3900-4000).
-- "Slukket men nødvendig" (ADChain.last.dependency.offNeeded): højst MAX_DEPENDENCY_ENTRIES post (den mest hastende
-- fabrik; more = antal skjulte, vist som "+k"). Score DEPENDENCY_SCORE + hast (0-99, færre lagerdage = højere;
-- ukendt = 50): over "rød fuld" (3000-3100), under "rød tom" (3900-4000).
ADStorageStats.DEPENDENCY_SCORE = 3700
ADStorageStats.MAX_DEPENDENCY_ENTRIES = 2
ADStorageStats.MAX_DEPENDENCY_ENTRIES = 1
local function urgency(days)
if days == nil then return 50 end