diff --git a/css/styles.css b/css/styles.css index 3025f15..d826ee4 100644 --- a/css/styles.css +++ b/css/styles.css @@ -1,48 +1,74 @@ -.page-header { - padding: var(--space-6) 0; - border-bottom: 2px solid var(--color-accent); - margin-bottom: var(--space-6); -} - -.page-header-title { - font-size: 1.75rem; - font-weight: 600; - margin: 0; -} - -.page-header-subtitle { +.text-muted { color: var(--color-text-muted); - margin: var(--space-1) 0 0; } .text-center { text-align: center; } -.dl-row-highlight { - font-weight: 600; - border-top: 1px solid var(--color-border); - padding-top: var(--space-2); - margin-top: var(--space-2); +/* Metric card accent */ +.metric-card-accent { + border-color: var(--color-accent); + background: var(--color-surface-elevated); } +.metric-card-accent .metric-card-value { + color: var(--color-accent); +} + +/* Payout cell in table */ +.payout-cell { + font-weight: 600; + white-space: nowrap; +} + +/* Artist table alignment */ #artists-table td, #artists-table th { vertical-align: middle; } -.checkbox-inline { - display: flex; - align-items: center; - gap: var(--space-2); - flex-wrap: wrap; +/* Card title with icon */ +.card-title i.ph { + color: var(--color-accent); + margin-right: var(--space-1); } -.checkbox-inline .checkbox { - margin: 0; +/* Page header override */ +.page-header { + border-bottom: 2px solid var(--color-accent); + margin-bottom: var(--space-6); } -.payout-cell { - font-weight: 600; - white-space: nowrap; +/* Alert margin */ +.alert.mt-4 { + margin-top: var(--space-4); +} + +/* Form grid tweak for compact cards */ +.card .form-grid { + margin-top: var(--space-2); +} + +/* Section spacing with cards */ +.section .card { + margin-bottom: 0; +} + +/* Summary row */ +.row.g-4 { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--space-4); +} + +/* Badge inside label */ +.label .badge { + margin-left: var(--space-1); + vertical-align: middle; +} + +/* Compact action card */ +.action-card { + max-width: 600px; } diff --git a/docs/calculations.md b/docs/calculations.md new file mode 100644 index 0000000..c6a019d --- /dev/null +++ b/docs/calculations.md @@ -0,0 +1,130 @@ +# Как работают расчёты в Mardis Calc + +## Общая формула + +``` +S = Pz + Tz + (Lz * Nl) + Rom + Rop + Rot + Rok + (Na * Z) +``` + +## Переменные + +| Переменная | Описание | +|-----------|----------| +| S | Общая сумма за шоу | +| Pz | Стоимость пиротехники | +| Tz | Стоимость титана | +| Lz | Стоимость одного литра керосина | +| Nl | Количество литров керосина | +| Rom | Роялти организации (10%) | +| Rop | Роялти постановщика (5%) | +| Rot | Роялти техника (5%) | +| Rok | Роялти комиссионера (10%) | +| Na | Количество артистов | +| Z | Зарплата одного артиста | + +## База для роялти + +Роялти считаются **не от общей суммы**, а от чистой суммы после вычета материальных расходов: + +``` +Материальные расходы = Pz + Tz + (Lz * Nl) +Base = S - Материальные расходы +``` + +``` +Rom = Base * 10% +Rop = Base * 5% +Rot = Base * 5% +Rok = Base * 10% +``` + +Rom — это фиксированный расход в бюджет команды, а не выплата конкретному человеку. Он не назначается артистам. + +## Соотношение между S, Na и Z + +Из формулы можно вывести ключевое соотношение: + +``` +S = Материальные расходы + Всего роялти + Зарплаты артистов +S = Материалы + 30% * Base + Na * Z +S = Материалы + 30% * (S - Материалы) + Na * Z +0.70 * S = 0.70 * Материалы + Na * Z +S = Материалы + (Na * Z) / 0.70 +``` + +## Автоматический расчёт + +Калькулятор позволяет оставить **ровно одно** поле пустым — оно будет вычислено автоматически. + +### Как вычисляется каждая переменная + +- **S** (общая сумма): `S = Материалы + (Na * Z) / 0.70` +- **Z** (зарплата артиста): `Z = 0.70 * (S - Материалы) / Na` +- **Pz** (пиротехника): `Pz = S - Тз - (Lz * Nl) - (Na * Z) / 0.70` +- **Tz** (титан): `Tz = S - Pz - (Lz * Nl) - (Na * Z) / 0.70` +- **Lz** (цена керосина): `Lz = (S - Pz - Tz - (Na * Z) / 0.70) / Nl` +- **Nl** (литры керосина): `Nl = (S - Pz - Tz - (Na * Z) / 0.70) / Lz` + +### Правило пересчёта при изменении состава + +Если вы изменяете количество артистов (добавляете или удаляете), калькулятор проверяет, какое поле было вычислено автоматически: + +- Если **Z** было авто-вычислено, а **S** введено вручную → пересчитывается **Z** под новое количество артистов +- Если **S** было авто-вычислено, а **Z** введено вручную → пересчитывается **S** +- Если оба поля введены вручную → показывается предупреждение, что сумма может не сходиться + +Чтобы сбросить авто-вычисление для поля, просто введите в него значение вручную. + +## Выплаты артистам + +Каждый добавленный артист может получать: + +- **Зарплату артиста (Z)** — если отмечена роль «Артист». Выплачивается каждому артисту полностью. +- **Роялти постановщика (Rop)** — если отмечена роль «Постановщик». Выплачивается полностью каждому назначенному постановщику. +- **Роялти техника (Rot)** — если отмечена роль «Техник». Выплачивается полностью каждому назначенному технику. +- **Роялти комиссионера (Rok)** — если отмечена роль «Комиссионер». Выплачивается полностью каждому назначенному комиссионеру. + +**Важно:** роялти не делятся между людьми. Если два человека выполняют роль постановщика — каждый получает полный Rop. + +**Выплата = Z (если артист) + Rop (если постановщик) + Rot (если техник) + Rok (если комиссионер)** + +## Пример + +Дано: +- Pz = 1000, Tz = 500, Lz = 50, Nl = 20 +- Na = 5 артистов +- Z = ? +- S = 25000 + +Расчёт: +``` +Материалы = 1000 + 500 + 50*20 = 2500 +Base = 25000 - 2500 = 22500 +Rom = 2250, Rop = 1125, Rot = 1125, Rok = 2250 +Z = 0.70 * (25000 - 2500) / 5 = 3150 +``` + +Проверка: +``` +S = 2500 + 5625 + 5*3150 = 2500 + 5625 + 15750 = 23875 +``` + +Стоп, это не 25000. Давайте пересчитаем через правильную формулу: + +``` +S = Материалы + (Na * Z) / 0.70 +25000 = 2500 + (5 * Z) / 0.70 +22500 = (5 * Z) / 0.70 +Z = 22500 * 0.70 / 5 = 3150 +``` + +Всего роялти = Rom + Rop + Rot + Rok = 2250 + 1125 + 1125 + 2250 = 6750 (30% от Base = 30% от 22500 = 6750) + +Зарплаты = 5 * 3150 = 15750 +Итого: 2500 (материалы) + 6750 (роялти) + 15750 (зарплаты) = 25000 + +Правильно! + +## Округление + +Все значения округляются до 2 знаков после запятой (копеек). diff --git a/index.html b/index.html index c9316b5..9ee08e4 100644 --- a/index.html +++ b/index.html @@ -10,173 +10,237 @@
-
-

Параметры шоу

-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
+ + -
-
- Роялти (автоматический расчёт) + +
+
+
+

Параметры шоу

+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + +
+
+
+

+ Роялти + авто +

+

Рассчитываются от чистой суммы (S − материальные расходы). Rom — фиксированный расход в бюджет команды.

+
+
+
-
+
- -
+
-

Артисты и роли

-
-
- -
-

Итоговый расчёт

-
-
-
Материальные расходы
-
0.00
-
-
-
Чистая сумма (Base)
-
0.00
-
-
-
Всего роялти
-
0.00
-
-
-
Зарплаты артистов
-
0.00
-
-
-
Общая сумма (S)
-
0.00
+
+ + + + + + + + + + + + + + + + + + +
Участники шоу
АртистАртист (Z)Постановщик (Rop)Техник (Rot)Комиссионер (Rok)Выплата
Нет добавленных артистов
+
+
-

Действия

-
- - - - +

Итоговый расчёт

+
+
+
+
+

Материальные расходы

+ +
+

0.00

+
+
+ +
+
+
+

Чистая сумма (Base)

+ +
+

0.00

+
+
+ +
+
+
+

Всего роялти

+ +
+

0.00

+
+
+ +
+
+
+

Зарплаты артистов

+ +
+

0.00

+
+
+ +
+
+
+

Общая сумма (S)

+ +
+

0.00

+
+
+
+
+ + +
+
+
+ Данные +

Импорт / Экспорт расчёта

+

Сохраните текущий расчёт в файл или загрузите ранее сохранённый.

+
+ + + +
+
diff --git a/js/app.js b/js/app.js index 42bfe81..1a97621 100644 --- a/js/app.js +++ b/js/app.js @@ -228,10 +228,12 @@ function showMessage(text, type) { messageEl.textContent = text; - messageEl.className = 'input-info mt-4'; - if (type === 'error') messageEl.classList.add('error'); - if (type === 'warning') messageEl.classList.add('warning'); - if (type === 'success') messageEl.classList.add('success'); + messageEl.hidden = false; + messageEl.className = 'alert mt-4'; + if (type === 'error') messageEl.classList.add('alert-error'); + else if (type === 'warning') messageEl.classList.add('alert-warning'); + else if (type === 'success') messageEl.classList.add('alert-success'); + else messageEl.classList.add('alert-info'); } function updateComputed(s, materials, base, royalties, salaries, counts) { @@ -475,6 +477,7 @@ }); document.getElementById('btn-export').addEventListener('click', exportState); + document.getElementById('btn-export-action').addEventListener('click', exportState); document.getElementById('btn-reset').addEventListener('click', resetAll); const importTrigger = document.getElementById('btn-import-trigger');