Загрузка данных
Option Explicit
' ==============================================================================
' 1. АВТОМАТИЧЕСКИЙ ТРИГГЕР
' ==============================================================================
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngToWatch As Range
' Отслеживаем изменения в диапазоне от P (16) до CM (91)
Set rngToWatch = Intersect(Target, Me.Columns("P:CM"))
If Not rngToWatch Is Nothing Then
Dim rw As Range
Dim rowNum As Long
Dim rowsProcessed As Object
Set rowsProcessed = CreateObject("Scripting.Dictionary")
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo SafeExit
For Each rw In rngToWatch.Rows
rowNum = rw.Row
If rowNum >= 4 And Not rowsProcessed.exists(rowNum) Then
rowsProcessed.Add rowNum, True
Call ProcessRowColoring(Me, rowNum)
End If
Next rw
SafeExit:
Application.EnableEvents = True
Application.ScreenUpdating = True
If Err.Number <> 0 Then
MsgBox "Ошибка: " & Err.Description, vbCritical
End If
End If
End Sub
' ==============================================================================
' 2. МАКРОС ДЛЯ РУЧНОГО ЗАПУСКА
' ==============================================================================
Sub ColorAllDeficits()
Dim lastRow As Long
Dim r As Long
lastRow = Me.Cells(Me.Rows.Count, "A").End(xlUp).Row
If lastRow < 4 Then Exit Sub
Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo SafeExit
For r = 4 To lastRow
Call ProcessRowColoring(Me, r)
Next r
SafeExit:
Application.EnableEvents = True
Application.ScreenUpdating = True
If Err.Number <> 0 Then
MsgBox "Ошибка: " & Err.Description, vbCritical
Exit Sub
End If
MsgBox "Раскраска завершена!", vbInformation, "Готово"
End Sub
' ==============================================================================
' 3. ОСНОВНАЯ ЛОГИКА РАСКРАСКИ
' ==============================================================================
Private Sub ProcessRowColoring(ws As Worksheet, r As Long)
Dim valCK As Variant
Dim valCL As Variant
Dim valCM As Variant
Dim defNum As Long
Dim yellowNum As Long
Dim blueNum As Long
Dim countColored As Long
Dim c As Long
Dim colP As Long: colP = 16
Dim colCB As Long: colCB = 80
Dim colCK As Long: colCK = 89
Dim colCL As Long: colCL = 90
Dim colCM As Long: colCM = 91
' Сбрасываем всю старую раскраску в строке перед началом работы
ws.Range(ws.Cells(r, colP), ws.Cells(r, colCK)).Interior.ColorIndex = xlNone
' ПРАВИЛО-ИСКЛЮЧЕНИЕ: Все пустые ячейки красим в зеленый ТОЛЬКО в диапазоне P:CB
For c = colP To colCB
If IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "" Then
ws.Cells(r, c).Interior.Color = RGB(146, 208, 80) ' Зеленый цвет
End If
Next c
valCK = ws.Cells(r, colCK).Value
valCL = ws.Cells(r, colCL).Value
valCM = ws.Cells(r, colCM).Value
' Проверяем валидность значения в CL
yellowNum = 0
If Not IsEmpty(valCL) And Not IsError(valCL) Then
If IsNumeric(valCL) Then
If valCL > 0 Then
' Округление в меньшую сторону
yellowNum = Int(valCL)
End If
End If
End If
' Проверяем валидность значения в CM (синий цвет)
blueNum = 0
If Not IsEmpty(valCM) And Not IsError(valCM) Then
If IsNumeric(valCM) Then
If valCM > 0 Then
' Округление в меньшую сторону
blueNum = Int(valCM)
End If
End If
End If
' Если в CK ошибка или пусто — прерываем окраску
If IsError(valCK) Then Exit Sub
If IsEmpty(valCK) Or Trim(CStr(valCK)) = "" Then Exit Sub
' Если в CK число
If IsNumeric(valCK) Then
' --- СЦЕНАРИЙ А: Дефицит >= 0 - вся строка зеленая (кроме желтых и синих) ---
If valCK >= 0 Then
countColored = 0
' Сначала красим желтым (если есть)
If yellowNum > 0 Then
For c = colCB To colP Step -1
If Not (IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "") Then
If countColored < yellowNum Then
ws.Cells(r, c).Interior.Color = RGB(255, 255, 0) ' Желтый
countColored = countColored + 1
Else
ws.Cells(r, c).Interior.Color = RGB(146, 208, 80) ' Зеленый
End If
End If
Next c
Else
' Если нет желтых - все зеленые
For c = colP To colCB
If Not (IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "") Then
ws.Cells(r, c).Interior.Color = RGB(146, 208, 80) ' Зеленый
End If
Next c
End If
' --- СЦЕНАРИЙ Б: Отрицательный дефицит ---
ElseIf valCK < 0 Then
' Округление в меньшую сторону и модуль
defNum = Abs(Int(valCK))
' Определяем сколько красных и желтых нужно
Dim redNum As Long
redNum = defNum - yellowNum
If redNum < 0 Then redNum = 0
' Красим справа налево: сначала красные, потом желтые, потом зеленые
countColored = 0
Dim redColored As Long
Dim yellowColored As Long
redColored = 0
yellowColored = 0
For c = colCB To colP Step -1
If Not (IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "") Then
If redColored < redNum Then
' Красим красным (самые правые)
ws.Cells(r, c).Interior.Color = RGB(255, 100, 100) ' Красный
redColored = redColored + 1
ElseIf yellowColored < yellowNum Then
' Красим желтым (после красных)
ws.Cells(r, c).Interior.Color = RGB(255, 255, 0) ' Желтый
yellowColored = yellowColored + 1
Else
' Остальные зеленые
ws.Cells(r, c).Interior.Color = RGB(146, 208, 80) ' Зеленый
End If
End If
Next c
End If
End If
' ==============================================================================
' ФИНАЛЬНЫЙ ЭТАП: РАСКРАСКА СИНИМ ЦВЕТОМ (ПОВЕРХ СУЩЕСТВУЮЩИХ)
' ==============================================================================
If blueNum > 0 Then
Call ApplyBlueColoring(ws, r, blueNum, colP, colCB)
End If
End Sub
' ==============================================================================
' 4. ФУНКЦИЯ ДЛЯ ПРИМЕНЕНИЯ СИНЕГО ЦВЕТА
' ==============================================================================
Private Sub ApplyBlueColoring(ws As Worksheet, r As Long, blueNum As Long, colP As Long, colCB As Long)
Dim c As Long
Dim blueColored As Long
Dim currentColor As Long
blueColored = 0
' Проходим слева направо, ищем желтые и красные ячейки
For c = colP To colCB
If blueColored >= blueNum Then Exit For
If Not (IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "") Then
currentColor = ws.Cells(r, c).Interior.Color
' Закрашиваем синим поверх желтого (слева от желтых)
If currentColor = RGB(255, 255, 0) Then ' Желтый
ws.Cells(r, c).Interior.Color = RGB(0, 112, 192) ' Синий
blueColored = blueColored + 1
End If
End If
Next c
' Если еще остались синие, закрашиваем поверх красных (слева от красных)
If blueColored < blueNum Then
For c = colP To colCB
If blueColored >= blueNum Then Exit For
If Not (IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "") Then
currentColor = ws.Cells(r, c).Interior.Color
' Закрашиваем синим поверх красного
If currentColor = RGB(255, 100, 100) Then ' Красный
ws.Cells(r, c).Interior.Color = RGB(0, 112, 192) ' Синий
blueColored = blueColored + 1
End If
End If
Next c
End If
' Если еще остались синие и нет желтых/красных, закрашиваем зеленые справа
If blueColored < blueNum Then
For c = colCB To colP Step -1
If blueColored >= blueNum Then Exit For
If Not (IsEmpty(ws.Cells(r, c)) Or Trim(CStr(ws.Cells(r, c).Value)) = "") Then
currentColor = ws.Cells(r, c).Interior.Color
' Закрашиваем синим поверх зеленого (справа налево)
If currentColor = RGB(146, 208, 80) Then ' Зеленый
ws.Cells(r, c).Interior.Color = RGB(0, 112, 192) ' Синий
blueColored = blueColored + 1
End If
End If
Next c
End If
End Sub