// ФЕНИКС · Терминал
// Исходник восстановлен 22.08.2026 из сборки v57 после потери рабочей копии.
// Имена внутренних переменных пока машинные — переименовываются по мере правок.
import React, { useState, useEffect, useMemo, useRef, useCallback, useContext } from "react";
import ReactDOM from "react-dom/client";
import { createPortal } from "react-dom";
import { createClient } from "@supabase/supabase-js";
import "./style.css";
const S = React;
const nt = React;
const _n = {
  createPortal,
};
const Wl = createClient;
const tl = ReactDOM.createRoot;
const A = Wl(
    "https://xrdrhvwadumcglbkbswb.supabase.co",
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InhyZHJodndhZHVtY2dsYmtic3diIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODQyMDA1MTQsImV4cCI6MjA5OTc3NjUxNH0.gFAdRYQFX0DAM2gRyk3J9MGQjDHfCxnllLGXS-k_J4M",
  ),
  Ot = ["reg_cp", "reg_ctr", "reg_ord", "reg_req", "reg_tr", "reg_cult", "reg_cont"],
  wt = {
    manager: {
      label: "Менеджер",
      tabs: [
        "manager",
        "kpp",
        "lab",
        "scale",
        "container",
        "transship",
        "batches",
        "dispatcher",
        "reg_cp",
        "reg_ctr",
        "reg_ord",
        "reg_req",
        "reg_tr",
        "reg_cult",
        "reg_cont",
        "reports",
        "docs",
        "audit",
      ],
    },
    kpp: {
      label: "КПП",
      tabs: ["kpp", "dispatcher", ...Ot, "chief"],
    },
    scale: {
      label: "Весовая",
      tabs: ["scale", ...Ot, "chief"],
    },
    lab: {
      label: "Лаборатория",
      tabs: ["lab", ...Ot, "chief"],
    },
    container: {
      label: "Приёмка контейнеров",
      tabs: ["container", "batches", "docs", ...Ot, "chief"],
    },
    dispatcher: {
      label: "Диспетчер",
      tabs: ["dispatcher", ...Ot, "chief"],
    },
    transship: {
      label: "Перевалка",
      tabs: ["transship", "batches", ...Ot, "chief"],
    },
    chief: {
      label: "Управляющий",
      tabs: [
        "chief",
        "manager",
        "kpp",
        "lab",
        "scale",
        "container",
        "transship",
        "batches",
        "dispatcher",
        "reg_cp",
        "reg_ctr",
        "reg_ord",
        "reg_req",
        "reg_tr",
        "reg_cult",
        "reg_cont",
        "reports",
        "docs",
        "users",
        "settings",
        "devices",
        "audit",
      ],
    },
  },
  nn = {
    Пшеница: "1001 99 000 0",
    Ячмень: "1003 90 000 0",
    Горох: "0713 10 900 0",
    Нут: "0713 20 000 0",
    Чечевица: "0713 40 000 0",
    "Чечевица Зелёная": "0713 40 000 0",
    "Чечевица Красная": "0713 40 000 0",
    Лен: "1204 00 900 0",
    Кориандр: "0909 21 000 0",
    "Рыжик масличный": "1207 99 960 0",
    Горчица: "1207 50 900 0",
    Просо: "1008 29 000 0",
    Овёс: "1004 90 000 0",
    Кукуруза: "1005 90 000 0",
    Соя: "1201 90 000 0",
    Подсолнечник: "1206 00 990 0",
    Сафлор: "1207 60 000 0",
  },
  ln = (t) =>
    String(t || "")
      .trim()
      .toLowerCase()
      .replace(/ё/g, "е")
      .replace(/\s+/g, " ");
let Is = null,
  rn = [];
const ti = (t) => {
    const n = {},
      s = [];
    for (const l of t || []) {
      const i = String(l.culture || "").trim();
      if (!i) continue;
      s.push(i);
      const u = String(l.hs_code || "").trim();
      u && (n[ln(i)] = u);
    }
    ((Is = n), (rn = s));
  },
  ts = async () => {
    try {
      const { data: t, error: n } = await A.from("term_culture_norms").select("culture, hs_code").order("culture");
      if (n) throw n;
      return (ti(t || []), t || []);
    } catch {
      return [];
    }
  },
  Es = (t) => {
    const n = ln(t);
    if (!n) return "";
    if (Is && Is[n]) return Is[n];
    const s = Object.keys(nn).find((l) => ln(l) === n);
    return s ? nn[s] : "";
  },
  an = (t) => String(t || "").replace(/\D+/g, "").length === 10,
  Ln = (t) => {
    const n = String(t || "").replace(/\D+/g, "");
    return n.length === 10 ? `${n.slice(0, 4)} ${n.slice(4, 6)} ${n.slice(6, 9)} ${n.slice(9)}` : String(t || "").trim();
  },
  Ft = () => (rn.length ? rn : Object.keys(nn)),
  si = [0, 22],
  ni = (t) => (t == null || t === "" ? "—" : `${+t} %`),
  sl = (t) => {
    const n = [
        [0, "0 % — без НДС"],
        [22, "22 % — основная ставка"],
      ],
      s = t == null || t === "" ? null : +t;
    return s != null && !si.includes(s) ? [...n, [s, `${s} % — как в договоре`]] : n;
  },
  jn = [
    "Турция",
    "Египет",
    "Индия",
    "Китай",
    "ОАЭ",
    "Саудовская Аравия",
    "Пакистан",
    "Бангладеш",
    "Иран",
    "Израиль",
    "Ливия",
    "Алжир",
    "Марокко",
    "Тунис",
    "Иордания",
    "Ирак",
    "Судан",
    "Вьетнам",
    "Индонезия",
    "Испания",
    "Италия",
    "Греция",
    "Грузия",
    "Азербайджан",
    "Армения",
    "Казахстан",
    "Узбекистан",
    "Абхазия",
    "Австралия",
    "Австрия",
    "Албания",
    "Ангола",
    "Аргентина",
    "Афганистан",
    "Бахрейн",
    "Беларусь",
    "Бельгия",
    "Бенин",
    "Болгария",
    "Боливия",
    "Босния и Герцеговина",
    "Бразилия",
    "Буркина-Фасо",
    "Бурунди",
    "Великобритания",
    "Венгрия",
    "Венесуэла",
    "Габон",
    "Гаити",
    "Гана",
    "Гватемала",
    "Гвинея",
    "Германия",
    "Гонконг",
    "Дания",
    "Джибути",
    "Доминиканская Республика",
    "Замбия",
    "Зимбабве",
    "Ирландия",
    "Йемен",
    "Камбоджа",
    "Камерун",
    "Канада",
    "Катар",
    "Кения",
    "Кипр",
    "Киргизия",
    "Колумбия",
    "Конго",
    "Корея (Республика)",
    "Коста-Рика",
    "Кот-д’Ивуар",
    "Куба",
    "Кувейт",
    "Латвия",
    "Ливан",
    "Литва",
    "Маврикий",
    "Мавритания",
    "Мадагаскар",
    "Малайзия",
    "Мали",
    "Мальта",
    "Мексика",
    "Мозамбик",
    "Молдова",
    "Монголия",
    "Мьянма",
    "Намибия",
    "Непал",
    "Нигер",
    "Нигерия",
    "Нидерланды",
    "Никарагуа",
    "Новая Зеландия",
    "Норвегия",
    "Оман",
    "Панама",
    "Парагвай",
    "Перу",
    "Польша",
    "Португалия",
    "Россия",
    "Руанда",
    "Румыния",
    "Северная Македония",
    "Сенегал",
    "Сербия",
    "Сингапур",
    "Сирия",
    "Словакия",
    "Словения",
    "Сомали",
    "США",
    "Таджикистан",
    "Таиланд",
    "Танзания",
    "Туркменистан",
    "Уганда",
    "Украина",
    "Уругвай",
    "Филиппины",
    "Финляндия",
    "Франция",
    "Хорватия",
    "Черногория",
    "Чехия",
    "Чили",
    "Швейцария",
    "Швеция",
    "Шри-Ланка",
    "Эквадор",
    "Эстония",
    "Эфиопия",
    "ЮАР",
    "Япония",
  ],
  li = ["Оборудование+Стикеровка", "Оборудование", "Стикеровка", "Лейблы", "Времянки", "Чистка (бюллер)", "Чистка (сортекс)", "Фасовка"],
  vt = {
    formed: "Сформирована · ждёт досмотр",
    inspect: "На досмотре РСХН",
    fumig: "На фумигации",
    ready: "Готова · выпуск через КПП",
    departed: "Убыла в порт",
  },
  ii = {
    A: "А",
    B: "В",
    C: "С",
    E: "Е",
    H: "Н",
    K: "К",
    M: "М",
    O: "О",
    P: "Р",
    T: "Т",
    X: "Х",
    Y: "У",
  },
  De = (t) =>
    String(t || "")
      .toUpperCase()
      .replace(/\s+/g, "")
      .replace(/[-–—]/g, "")
      .replace(/[ABCEHKMOPTXY]/g, (n) => ii[n] || n),
  Fs = "АВЕКМНОРСТУХ",
  nl = new RegExp(`^[${Fs}]\\d{3}[${Fs}]{2}\\d{2,3}$`),
  ri = new RegExp(`^[${Fs}]{2}\\d{4}\\d{2,3}$`),
  xs = (t) => nl.test(De(t)),
  zs = (t) => {
    const n = De(t);
    return ri.test(n) || nl.test(n);
  },
  Dt = (t, n) => {
    const s = De(t);
    if (!s || (n ? zs(s) : xs(s))) return "";
    if (/[A-Z]/.test(s)) return "в номере латинские буквы — набери русскими";
    if (/[^А-Я0-9]/.test(s)) return "в номере лишние знаки — только буквы и цифры";
    const l = [...s].filter((i) => /[А-Я]/.test(i) && !Fs.includes(i));
    return l.length
      ? `буквы ${[...new Set(l)].join(", ")} на номерных знаках не используются`
      : n
        ? "формат прицепа: две буквы, четыре цифры и регион — например АВ123477"
        : "формат машины: буква, три цифры, две буквы и регион — например О854ВВ126";
  },
  ai = {
    а: "a",
    б: "b",
    в: "v",
    г: "g",
    д: "d",
    е: "e",
    ё: "e",
    ж: "zh",
    з: "z",
    и: "i",
    й: "y",
    к: "k",
    л: "l",
    м: "m",
    н: "n",
    о: "o",
    п: "p",
    р: "r",
    с: "s",
    т: "t",
    у: "u",
    ф: "f",
    х: "h",
    ц: "c",
    ч: "ch",
    ш: "sh",
    щ: "sch",
    ъ: "",
    ы: "y",
    ь: "",
    э: "e",
    ю: "yu",
    я: "ya",
  },
  ll = (t) =>
    String(t ?? "")
      .split("")
      .map((n) => {
        const s = n.toLowerCase(),
          l = ai[s];
        return l === void 0 ? n : n === s ? l : l ? l[0].toUpperCase() + l.slice(1) : "";
      })
      .join(""),
  st = (...t) => {
    const n = (u) =>
        String(u ?? "")
          .replace(/[«»"'`]/g, "")
          .replace(/[\\/:*?<>|]+/g, "-")
          .replace(/[.,;]+/g, "")
          .replace(/\s*[·—–]\s*/g, "-")
          .replace(/\s+/g, "-")
          .replace(/-{2,}/g, "-")
          .replace(/^-|-$/g, "")
          .trim(),
      s = new Date(),
      l = `${s.getFullYear()}-${String(s.getMonth() + 1).padStart(2, "0")}-${String(s.getDate()).padStart(2, "0")}`;
    return `${
      ll(t.map(n).filter(Boolean).join("_"))
        .replace(/[^-\w.]+/g, "")
        .slice(0, 120)
        .replace(/_$/, "") || "Document"
    }_${l}.pdf`;
  },
  gn = (t) => {
    let n = String(t || "")
      .replace(/\.0$/, "")
      .replace(/[^\d+]/g, "");
    return (/^8\d{10}$/.test(n) && (n = "+7" + n.slice(1)), /^7\d{10}$/.test(n) && (n = "+" + n), n);
  },
  tn = (t, n) => {
    const s = String(t || "").replace(/\D+/g, "");
    return n ? s.slice(0, n) : s;
  },
  St = (t) =>
    String(t || "")
      .replace(/\s+/g, " ")
      .trim()
      .replace(/^(ООО|ОАО|ЗАО|ПАО|АО|ИП|НАО)\s+"([^"]+)"$/i, (n, s, l) => s.toUpperCase() + " «" + l + "»")
      .replace(/"([^"]+)"/g, "«$1»"),
  il = (t) => {
    const n = String(t || "").replace(/\D/g, ""),
      s = (l) => (l.reduce((i, u, o) => i + u * +n[o], 0) % 11) % 10;
    return n.length === 10
      ? s([2, 4, 10, 3, 5, 9, 4, 6, 8]) === +n[9]
      : n.length === 12
        ? s([7, 2, 4, 10, 3, 5, 9, 4, 6, 8]) === +n[10] && s([3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8]) === +n[11]
        : !1;
  },
  cn = (t, n) => {
    const s = String(t || "").replace(/\D/g, ""),
      l = String(n || "").replace(/\D/g, "");
    if (s.length !== 20 || l.length !== 9) return !0;
    const i = /^0000/.test(l.slice(-3)) ? "0" + l.slice(4, 6) : l.slice(-3),
      u = (s.startsWith("301") || s.startsWith("30101") ? "0" + l.slice(4, 6) : i) + s,
      o = [7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1, 3, 7, 1];
    let x = 0;
    for (let N = 0; N < 23; N++) x += (o[N] * +u[N]) % 10;
    return x % 10 === 0;
  };
function ci(t) {
  const n = String(t || "").replace(/\u00a0/g, " "),
    s = (z, _ = 1) => {
      const h = n.match(z);
      return h ? h[_].trim() : "";
    },
    l = (z) => (s(z) || "").replace(/\D/g, ""),
    i = s(/((?:ООО|ОАО|ЗАО|ПАО|АО|НАО|ИП)\s*[«"][^»"]+[»"])/i) || s(/^\s*([^\n]{4,90})\n/),
    u = l(/ИНН[^0-9]{0,12}(\d{10,12})/i),
    o = l(/КПП[^0-9]{0,12}(\d{9})/i),
    x = l(/ОГРН(?:ИП)?[^0-9]{0,12}(\d{13,15})/i),
    N = l(/БИК[^0-9]{0,12}(\d{9})/i),
    b = l(/(?:р\/с|расч[её]тный сч[её]т|счет|счёт)[^0-9]{0,14}(\d{20})/i) || (n.match(/\b(40\d{18})\b/) || [])[1] || "",
    j = l(/(?:к\/с|корр[^0-9]{0,14})(\d{20})/i) || (n.match(/\b(30101\d{15})\b/) || [])[1] || "",
    g = s(/(?:банк|в банке)[^A-Za-zА-Яа-я]{0,4}([^\n,;]{4,80})/i),
    d = s(/(?:директор|руководитель|генеральный директор)[^A-Za-zА-Яа-я]{0,4}([А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё.]+(?:\s+[А-ЯЁ][а-яё.]+)?)/i),
    M = s(/(?:адрес|юридический адрес)[^0-9А-Яа-я]{0,4}([^\n]{10,150})/i) || s(/(\d{6},\s*[^\n]{10,150})/);
  return {
    name: St(i),
    inn: u,
    kpp: o,
    ogrn: x,
    bik: N,
    rs: b,
    ks: j,
    bank: St(g),
    director: d,
    addr: M.trim(),
  };
}
const zt = (t) => {
    try {
      localStorage.removeItem("term9." + t);
    } catch {}
  },
  An = (t) =>
    String(t || "")
      .toLowerCase()
      .replace(/ё/g, "е")
      .replace(/\b(\d+|[ivx]+)\s*(класс[а-я]*|сорт[а-я]*|кл\.?|тип[а-я]*)\b/g, " ")
      .replace(/[^a-zа-я0-9]+/g, " ")
      .trim(),
  _s = (t, n) => {
    const s = An(t),
      l = An(n);
    return !s || !l || s === l ? !0 : s.startsWith(l) || l.startsWith(s);
  },
  Ks = (t) => !!(t && (t.mix_id || t.mix_group || t.mix_with || t.mix_param || t.lab_result1 === "mix" || t.lab_result1 === "clean_mix")),
  js = (t) =>
    Ks(t)
      ? [t.mix_group, t.mix_with ? "с " + t.mix_with : null, t.mix_param, t.site ? "площадка " + t.site : null].filter(Boolean).join(" · ")
      : null,
  oi = {
    lab_ok: "Собран · ждёт перевалку",
    ts_ok: "Перевалка выполнена · машины на тару",
    weighed: "Взвешен · к затарке",
    packed: "Затарен в контейнеры",
    closed: "Закрыт",
    formed: "Собран · ждёт перевалку",
  },
  ue = async (t, n = "запись", s = !1) => {
    const { data: l, error: i } = await (typeof t.select == "function" ? t.select() : t);
    if (i) throw i;
    if (!s && (!l || (Array.isArray(l) && !l.length)))
      throw new Error(`Не удалось сохранить (${n}): нет прав на эту операцию или запись изменилась. Обнови страницу и попробуй ещё раз.`);
    return l || [];
  },
  pn = async () => {
    try {
      const { data: t } = await A.auth.getSession(),
        n = t && t.session && t.session.access_token;
      n && A.realtime && A.realtime.setAuth && (await A.realtime.setAuth(n));
    } catch {}
  },
  je = async (t, n, s, l, i) => {
    const { error: u } = await A.from("term_audit").insert({
      entity: t,
      entity_id: n == null ? null : Number(n),
      action: s,
      details: l || null,
      by_id: (i == null ? void 0 : i.id) || null,
      by_name: (i == null ? void 0 : i.name) || null,
    });
    if (u)
      throw (
        console.error("audit:", u),
        new Error(
          `Операция выполнена, но запись в журнал изменений не прошла (${u.message}). Сообщи управляющему: следа от этого действия в журнале нет.`,
        )
      );
  },
  Rt = {
    vgm_method: "METHOD-2",
    scale_calib_date: "19 февраля 2026",
    scale_calib_until: "2027-02-19",
    scale_details: 'Весы автомобильные ВА "СХТ", мод. ВА СХТ 2-80-20-3-0, 66276-16 (ТВ-003/05 Н №48186)',
    vgm_declarant: "",
    weigh_place: "ООО «Зерновой Оператор» · ст. Раевская",
    truck_gross_max: "60000",
    truck_gross_min: "5000",
    truck_tare_max: "25000",
    truck_tare_min: "3000",
    cont_tare_min: "5000",
    cont_tare_max: "25000",
    plan_dev_pct: "10",
    tonnage_date: "tare_at",
    dotare_warn: "500",
    dotare_max: "5000",
    call_limit: "5",
    stuck_unload_h: "4",
    stuck_lab_h: "2",
    stuck_tare_h: "6",
    stuck_cont_d: "30",
    feed_audit_all: "да",
    digest_on: "да",
    autologout_min: "0",
    ts_step: "да",
  },
  di = {
    vgm_method: "Метод взвешивания в VGM",
    scale_calib_date: "Дата поверки весов (текст в документе)",
    scale_calib_until: "Поверка действует до (для напоминания)",
    scale_details: "Средство взвешивания (текст в документе)",
    vgm_declarant: "Исполнитель VGM (Фамилия И.О. / NAME)",
    weigh_place: "Место взвешивания (текст в документе)",
    truck_gross_min: "Зерновоз: брутто минимум, кг",
    truck_gross_max: "Зерновоз: брутто максимум, кг",
    truck_tare_min: "Зерновоз: тара минимум, кг",
    truck_tare_max: "Зерновоз: тара максимум, кг",
    cont_tare_min: "Контейнер: тара а/т минимум, кг",
    cont_tare_max: "Контейнер: тара а/т максимум, кг",
    plan_dev_pct: "Допустимое отклонение факта от плана, %",
    tonnage_date: "Дата признания тоннажа",
    dotare_warn: "Дотарка: с какого веса предупреждать, кг (можно продавить подтверждением)",
    dotare_max: "Дотарка: предел, кг (больше — не принимается)",
    call_limit: "Сколько машин можно держать вызванными с отстойника",
    stuck_lab_h: "Просрочка: сколько часов машина может ждать лабораторию",
    stuck_unload_h: "Просрочка: сколько часов машина может стоять на выгрузке",
    stuck_tare_h: "Просрочка: сколько часов машина может ждать тару после услуги",
    stuck_cont_d: "Просрочка: сколько дней контейнер может стоять на терминале",
    feed_audit_all: "Показывать исключения (откаты, продавленные проверки) всем отделам в ленте: да / нет",
    digest_on: "Утренний дайджест в чат («да»/«нет», 07:00 по Новороссийску)",
    autologout_min: "Автовыход после бездействия, минут (0 — выключен; для общих компьютеров КПП и весовой)",
    ts_step: "Перевалка как отдельный шаг процесса («нет» — весовая снимает тару сразу после выгрузки, услуга отмечается сама)",
  };
async function hi() {
  try {
    const { data: t, error: n } = await A.from("term_settings").select("key, value");
    if (n) throw n;
    const s = {
      ...Rt,
    };
    for (const l of t || []) l.value != null && (s[l.key] = l.value);
    return s;
  } catch {
    return {
      ...Rt,
    };
  }
}
const ui = (() => {
    const t = {};
    let n = 10;
    for (let s = 0; s < 26; s++) (n % 11 === 0 && n++, (t[String.fromCharCode(65 + s)] = n), n++);
    return t;
  })(),
  ss = (t) => {
    const n = String(t || "")
      .toUpperCase()
      .replace(/\s+/g, "");
    if (!/^[A-Z]{4}\d{7}$/.test(n)) return !1;
    let s = 0;
    for (let l = 0; l < 10; l++) {
      const i = n[l],
        u = l < 4 ? ui[i] : +i;
      s += u * Math.pow(2, l);
    }
    return (s % 11) % 10 === +n[10];
  },
  qe = (t) => (t == null || t === "" ? null : Math.round(Number(t) * 1e3)),
  Ue = (t) =>
    t == null
      ? "—"
      : new Date(t).toLocaleTimeString("ru-RU", {
          hour: "2-digit",
          minute: "2-digit",
        }),
  he = (t) =>
    t == null
      ? "—"
      : new Date(t).toLocaleString("ru-RU", {
          day: "2-digit",
          month: "2-digit",
          hour: "2-digit",
          minute: "2-digit",
        }),
  q = (t) => (t == null ? "—" : Number(t).toLocaleString("ru-RU")),
  hs = 3 * 3600 * 1e3,
  Nt = (t, n) =>
    n != null
      ? [new Date(Date.UTC(+t, +n - 1, 1) - hs).toISOString(), new Date(Date.UTC(+t, +n, 1) - hs).toISOString()]
      : [new Date(Date.UTC(+t, 0, 1) - hs).toISOString(), new Date(Date.UTC(+t + 1, 0, 1) - hs).toISOString()],
  mi = (t) => {
    const [n, s, l] = String(t || "")
      .split("-")
      .map(Number);
    if (!n || !s || !l) return Nt(new Date().getFullYear());
    const i = new Date(Date.UTC(n, s - 1, l) - hs);
    return [i.toISOString(), new Date(i.getTime() + 864e5).toISOString()];
  },
  on = (() => {
    try {
      const t = window.location.hash.replace(/^#/, "");
      if (!t || !t.includes("v=")) return {};
      const n = {};
      return (
        new URLSearchParams(t).forEach((s, l) => {
          n[l] = s;
        }),
        n
      );
    } catch {
      return {};
    }
  })(),
  ut = (t, n) => (on.v !== t ? null : (on[n] ?? null)),
  Bn = (t, n) => {
    const s = new URLSearchParams({
      v: t,
    });
    for (const [l, i] of Object.entries(n || {})) i != null && String(i).trim() !== "" && s.set(l, String(i));
    return window.location.origin + window.location.pathname + "#" + s.toString();
  },
  te = (t) => {
    const n = parseFloat(
      String(t ?? "")
        .replace(",", ".")
        .replace(/\s/g, ""),
    );
    return isNaN(n) ? null : n;
  },
  dn = ["Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"],
  gs = "term-files";
function xi(t, n = 1600, s = 0.85) {
  return new Promise((l, i) => {
    const u = new Image();
    ((u.onload = () => {
      const o = Math.min(1, n / Math.max(u.width, u.height)),
        x = document.createElement("canvas");
      ((x.width = Math.max(1, Math.round(u.width * o))),
        (x.height = Math.max(1, Math.round(u.height * o))),
        x.getContext("2d").drawImage(u, 0, 0, x.width, x.height),
        URL.revokeObjectURL(u.src),
        x.toBlob((N) => (N ? l(N) : i(new Error("не удалось сжать фото"))), "image/jpeg", s));
    }),
      (u.onerror = () => {
        (URL.revokeObjectURL(u.src), i(new Error("не удалось прочитать изображение")));
      }),
      (u.src = URL.createObjectURL(t)));
  });
}
async function rl(t, n, s, l) {
  let i = s,
    u = s.name || "файл",
    o = s.type || "application/octet-stream";
  if (/^image\//.test(o) && s.size > 350 * 1024)
    try {
      ((i = await xi(s)), (o = "image/jpeg"), (u = u.replace(/\.\w+$/, "") + ".jpg"));
    } catch {
      i = s;
    }
  const x = (u.match(/\.(\w{1,8})$/) || [])[1] || "bin",
    N = `${t}/${n}/${Date.now()}_${Math.random().toString(36).slice(2, 8)}.${x.toLowerCase()}`,
    { error: b } = await A.storage.from(gs).upload(N, i, {
      contentType: o,
      upsert: !1,
    });
  if (b) throw b;
  const { data: j, error: g } = await A.from("term_files")
    .insert({
      entity: t,
      entity_id: n,
      name: u,
      path: N,
      mime: o,
      size_kb: Math.round((i.size || 0) / 102.4) / 10,
      uploaded_by: l,
    })
    .select();
  if (g)
    throw (
      await A.storage
        .from(gs)
        .remove([N])
        .catch(() => {}),
      g
    );
  return j[0];
}
async function fn(t, n = 3600) {
  const { data: s } = await A.storage.from(gs).createSignedUrl(t, n);
  return s ? s.signedUrl : null;
}
const Pn = {
    Заявки: "заявок",
    Зерновозы: "зерновозов",
    Контейнеры: "контейнеров",
    Контрагенты: "контрагентов",
    Поручения: "поручений",
    Погрузки: "погрузок",
    Договоры: "договоров",
    Культуры: "культур",
    Затарки: "затарок",
    Партии: "партий",
    Замесы: "замесов",
  },
  bn = (t, n) => {
    const s = new Date(),
      l = `${s.getFullYear()}-${String(s.getMonth() + 1).padStart(2, "0")}-${String(s.getDate()).padStart(2, "0")}`,
      i = String(t || "Выгрузка"),
      u = Pn[i] ? "Реестр-" + Pn[i] : /журнал|реестр|отчёт|отчет/i.test(i) ? i : "Выгрузка-" + i.toLowerCase();
    return `FENIX_${ll(u.replace(/[_\s]+/g, "-")).replace(/[^-\w.]+/g, "")}_${l}.${n}`;
  };
async function Ze(t, n) {
  const s = await import("exceljs"),
    l = s.default || s,
    i = new l.Workbook();
  i.creator = "ФЕНИКС · Терминал";
  for (const N of n) {
    const b = i.addWorksheet(String(N.name).slice(0, 31), {
      views: [
        {
          state: "frozen",
          ySplit: 2,
        },
      ],
    });
    b.columns = N.cols.map((d) => ({
      width: d.w || 14,
    }));
    const j = b.addRow([N.title || N.name]);
    ((j.height = 26),
      b.mergeCells(1, 1, 1, N.cols.length),
      Object.assign(j.getCell(1), {
        font: {
          name: "Calibri",
          size: 13,
          bold: !0,
          color: {
            argb: "FF111111",
          },
        },
        alignment: {
          vertical: "middle",
        },
      }));
    const g = b.addRow(N.cols.map((d) => d.h));
    ((g.height = 22),
      g.eachCell((d) => {
        ((d.font = {
          name: "Calibri",
          size: 9,
          bold: !0,
          color: {
            argb: "FFFFFFFF",
          },
        }),
          (d.fill = {
            type: "pattern",
            pattern: "solid",
            fgColor: {
              argb: "FF161616",
            },
          }),
          (d.alignment = {
            vertical: "middle",
            horizontal: "center",
            wrapText: !0,
          }),
          (d.border = {
            bottom: {
              style: "thick",
              color: {
                argb: "FFC2F24A",
              },
            },
          }));
      }),
      (N.rows || []).forEach((d, M) => {
        const z = d.map((h, w) => (h == null || h === "" ? null : N.cols[w] && N.cols[w].num ? (te(h) ?? String(h)) : h));
        b.addRow(z).eachCell(
          {
            includeEmpty: !0,
          },
          (h, w) => {
            ((h.font = {
              name: "Calibri",
              size: 10,
            }),
              M % 2 &&
                (h.fill = {
                  type: "pattern",
                  pattern: "solid",
                  fgColor: {
                    argb: "FFF4F6EC",
                  },
                }),
              (h.border = {
                bottom: {
                  style: "hair",
                  color: {
                    argb: "FFDDDDDD",
                  },
                },
              }));
            const p = N.cols[w - 1];
            p &&
              p.num &&
              typeof h.value == "number" &&
              ((h.numFmt = p.int ? "#,##0" : "#,##0.00"),
              (h.alignment = {
                horizontal: "right",
              }));
          },
        );
      }),
      (b.autoFilter = {
        from: {
          row: 2,
          column: 1,
        },
        to: {
          row: 2,
          column: N.cols.length,
        },
      }));
  }
  const u = await i.xlsx.writeBuffer(),
    o = new Blob([u], {
      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    }),
    x = Object.assign(document.createElement("a"), {
      href: URL.createObjectURL(o),
      download: bn(t, "xlsx"),
    });
  (x.click(), setTimeout(() => URL.revokeObjectURL(x.href), 4e3));
}
const kt = {
    nameRu: "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ЗЕРНОВОЙ ОПЕРАТОР»",
    nameShort: "ООО «ЗЕРНОВОЙ ОПЕРАТОР»",
    requisites: "ИНН/КПП 2315243025/231501001, ОГРН 1262300005098",
    addrRu: "353920, КРАСНОДАРСКИЙ КРАЙ, Г.О. ГОРОД НОВОРОССИЙСК, Г НОВОРОССИЙСК, ПР-КТ ДЗЕРЖИНСКОГО, Д. 156Б",
    addrEn:
      'LLC " GRAIN OPERATOR ", INN/KPP 2315243025/231501001, STATE REGISTRATION NUMBER 1262300005098, 353920, KRASNODAR KRAI, G.O. NOVOROSSIYSK, G NOVOROSSIYSK, PR-KT DZERZHINSKOGO, D. 156B',
    email: "terminal@raevkahills.ru",
    weighPlace: "ООО «Зерновой Оператор»",
    weighAddr: `353983, Краснодарский край, станица Раевская, ул. Раевская, склад ООО "Зерновой Оператор"
353983, KRANSODARSKY REGION, RAEVSKAYA VILLAGE, RAEVSKAYA STR., "GRAIN OPERATOR" LLC WAREHOUSE`,
    scales:
      'Весы автомобильные ВА "СХТ", мод. ВА СХТ 2-80-20-3-0, 66276-16 (ТВ-003/05 Н №48186)/ Automobile scale ВА "СХТ", model ВА СХТ 2-80-20-3-0, 66276-16 (ТВ-003/05 Н №48186)',
  },
  qs = {
    "20DC": 31.08,
    "20HC": 37.4,
    "40DC": 67.7,
    "40HC": 76.4,
    "40RE": 67.3,
  },
  al = (t, n) => {
    const s = String(t || "").trim() + String(n || "").trim();
    if (qs[s] != null) return qs[s];
    const l = String(t || "").trim();
    if (!l) return "";
    const i = l === "20" || l === "20'" ? "20DC" : l === "40" || l === "40'" ? "40HC" : null;
    return i && qs[i] != null ? qs[i] : "";
  },
  Qt = {
    top: {
      style: "thin",
    },
    bottom: {
      style: "thin",
    },
    left: {
      style: "thin",
    },
    right: {
      style: "thin",
    },
  },
  cl = async (t, n) => {
    const s = await t.xlsx.writeBuffer(),
      l = new Blob([s], {
        type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      }),
      i = Object.assign(document.createElement("a"), {
        href: URL.createObjectURL(l),
        download: bn(n, "xlsx"),
      });
    (i.click(), setTimeout(() => URL.revokeObjectURL(i.href), 4e3));
  };
async function _i({ aktNo: t, aktDate: n, client: s, cargo: l, addr: i, dtNo: u, booking: o, zatDate: x, rows: N }) {
  const b = await import("exceljs"),
    j = b.default || b,
    g = new j.Workbook(),
    d = g.addWorksheet("Акт", {
      pageSetup: {
        orientation: "landscape",
        fitToPage: !0,
        fitToWidth: 1,
      },
    });
  d.columns = [
    {
      width: 5,
    },
    {
      width: 6,
    },
    {
      width: 12,
    },
    {
      width: 17,
    },
    {
      width: 13,
    },
    {
      width: 12,
    },
    {
      width: 14,
    },
    {
      width: 14,
    },
    {
      width: 16,
    },
    {
      width: 14,
    },
    {
      width: 9,
    },
  ];
  const M = (y, $, m = {}) => {
    const v = d.getCell(y);
    return (
      (v.value = $),
      (v.font = {
        name: "Calibri",
        size: m.sz || 11,
        bold: !!m.b,
      }),
      (v.alignment = {
        vertical: "middle",
        horizontal: m.h || "left",
        wrapText: !0,
      }),
      v
    );
  };
  (d.mergeCells("B1:J1"),
    M("B1", `${kt.nameShort.replace("«", '"').replace("»", '"')} по поручению ${s || ""}`, {
      b: 1,
    }),
    d.mergeCells("B2:J2"),
    M("B2", `АКТ №${t || ""} от ${n || ""}`, {
      b: 1,
      h: "center",
      sz: 13,
    }),
    d.mergeCells("B3:J3"),
    M("B3", "Перетарки груза из автомобиля в контейнер", {
      h: "center",
    }),
    d.mergeCells("B4:J4"),
    M("B4", `Настоящим акт подтверждает, что груз «${(l || "").toUpperCase()}» предназначенный к отгрузке на экспорт в адрес ${i || ""}`),
    d.mergeCells("B5:J5"),
    M("B5", 'Перетарен в контейнеры и перевешен на весах автомобильных ВА "СХТ", мод. ВА СХТ 2-80-20-3-0, 66276-16 (ТВ-003/05 Н №48186)'),
    d.mergeCells("B6:J6"),
    M("B6", `дата затарки ${x || n || ""}`),
    d.mergeCells("B7:J7"),
    M("B7", `ДТ № ${u || ""}`),
    d.mergeCells("B8:J8"),
    M("B8", `БУКИНГ ${o || ""}`, {
      b: 1,
    }));
  const z = [
      "№",
      "Склад",
      "Погружено в контейнер",
      "Тип конт., фут",
      "Линия",
      "Вес нетто, кг",
      "Вес брутто, кг",
      "Тара контейнера, кг",
      "№ пломбы",
      "CU m3",
    ],
    _ = 10;
  (z.forEach((y, $) => {
    const m = d.getCell(_, $ + 2);
    ((m.value = y),
      (m.font = {
        name: "Calibri",
        size: 10,
        bold: !0,
      }),
      (m.alignment = {
        vertical: "middle",
        horizontal: "center",
        wrapText: !0,
      }),
      (m.border = Qt));
  }),
    (d.getRow(_).height = 28));
  let h = _ + 1,
    w = 0,
    p = 0;
  (N.forEach((y, $) => {
    ([$ + 1, y.sklad, y.cont, y.type, y.line, y.net, y.gross, y.tare, y.seal, y.cum].forEach((v, U) => {
      const Z = d.getCell(h, U + 2);
      ((Z.value = v ?? ""),
        (Z.font = {
          name: "Calibri",
          size: 10,
        }),
        (Z.alignment = {
          vertical: "middle",
          horizontal: U === 0 || U >= 3 ? "center" : "left",
        }),
        (Z.border = Qt),
        [5, 6, 7].includes(U) && (Z.numFmt = "#,##0"));
    }),
      (w += +y.net || 0),
      (p += +y.gross || 0),
      h++);
  }),
    d.mergeCells(`B${h}:F${h}`),
    M(`B${h}`, "Всего:", {
      b: 1,
      h: "right",
    }));
  const F = d.getCell(h, 7);
  ((F.value = w),
    (F.font = {
      bold: !0,
    }),
    (F.numFmt = "#,##0"),
    (F.border = Qt));
  const C = d.getCell(h, 8);
  ((C.value = p),
    (C.font = {
      bold: !0,
    }),
    (C.numFmt = "#,##0"),
    (C.border = Qt),
    [2, 3, 4, 5, 6, 9, 10, 11].forEach((y) => {
      d.getCell(h, y).border = Qt;
    }),
    (h += 2),
    d.mergeCells(`C${h}:F${h}`),
    M(`C${h}`, `представитель  ${kt.nameShort}`),
    M(`H${h}`, "_________________"),
    await cl(g, `Акт_затарки_${o || t || ""}`));
}
async function ji({ certNo: t, certDate: n, calibDate: s, declarant: l, method: i, rows: u }) {
  const o = await import("exceljs"),
    x = o.default || o,
    N = new x.Workbook(),
    b = N.addWorksheet("VGM", {
      pageSetup: {
        orientation: "portrait",
        fitToPage: !0,
        fitToWidth: 1,
      },
    });
  b.columns = [
    {
      width: 7,
    },
    {
      width: 34,
    },
    {
      width: 26,
    },
    {
      width: 26,
    },
    {
      width: 20,
    },
  ];
  const j = (z, _, h = {}) => {
    const w = b.getCell(z);
    return (
      (w.value = _),
      (w.font = {
        name: "Calibri",
        size: h.sz || 10,
        bold: !!h.b,
      }),
      (w.alignment = {
        vertical: "middle",
        horizontal: h.h || "left",
        wrapText: !0,
      }),
      h.bd && (w.border = Qt),
      w
    );
  };
  (b.mergeCells("A1:E1"),
    j(
      "A1",
      kt.nameRu +
        `
` +
        kt.requisites +
        `
` +
        kt.addrRu,
      {
        h: "center",
        sz: 9,
      },
    ),
    b.mergeCells("A2:E2"),
    j("A2", kt.addrEn, {
      h: "center",
      sz: 8,
    }),
    b.mergeCells("A3:E3"),
    j("A3", "E-mail:  " + kt.email, {
      h: "center",
      sz: 9,
    }),
    b.mergeCells("A5:E5"),
    j("A5", "СЕРТИФИКАТ О ПОДТВЕРЖДЕНИИ МАССЫ БРУТТО КОНТЕЙНЕРА", {
      b: 1,
      h: "center",
      sz: 12,
    }),
    b.mergeCells("A6:E6"),
    j("A6", "CERTIFICATE OF VERIFIED GROSS MASS OF CONTAINER", {
      b: 1,
      h: "center",
      sz: 11,
    }));
  const g = [
    ["Номер Сертификата / Certificate No.", t || ""],
    ["Дата взвешивания и выдачи сертификата / Date of issue (weighing)", n || ""],
    ["Место взвешивания / Place of weighing", kt.weighPlace],
    ["Адрес предприятия / Address", kt.weighAddr],
    ["Средство взвешивания / Weighing scale details", kt.scales],
    ["Свидетельство о поверке · дата / Calibration date", s || ""],
    ["Метод взвешивания / Method of weighing", i || "METHOD-2"],
  ];
  let d = 8;
  (g.forEach(([z, _]) => {
    (b.mergeCells(`A${d}:B${d}`),
      j(`A${d}`, z, {
        b: 1,
        bd: 1,
        sz: 9,
      }),
      b.mergeCells(`C${d}:E${d}`),
      j(`C${d}`, _, {
        bd: 1,
        sz: 9,
      }),
      (b.getRow(d).height = Math.max(18, Math.ceil(String(_).length / 62) * 13)),
      d++);
  }),
    d++);
  const M = [
    "№ п/п",
    `Идентификационный номер контейнера /
Container Number`,
    `Подтвержденная масса брутто контейнера, кг /
Verified gross mass, kgs`,
    `Пломба контейнера /
Seal number`,
  ];
  (j(`A${d}`, M[0], {
    b: 1,
    bd: 1,
    h: "center",
    sz: 9,
  }),
    j(`B${d}`, M[1], {
      b: 1,
      bd: 1,
      h: "center",
      sz: 9,
    }),
    b.mergeCells(`C${d}:D${d}`),
    j(`C${d}`, M[2], {
      b: 1,
      bd: 1,
      h: "center",
      sz: 9,
    }),
    j(`E${d}`, M[3], {
      b: 1,
      bd: 1,
      h: "center",
      sz: 9,
    }),
    (b.getRow(d).height = 30),
    d++,
    u.forEach((z, _) => {
      (j(`A${d}`, _ + 1, {
        bd: 1,
        h: "center",
      }),
        j(`B${d}`, z.cont, {
          bd: 1,
          h: "center",
        }),
        b.mergeCells(`C${d}:D${d}`));
      const h = j(`C${d}`, z.vgm, {
        bd: 1,
        h: "center",
      });
      ((h.numFmt = "#,##0.00"),
        j(`E${d}`, z.seal || "", {
          bd: 1,
          h: "center",
        }),
        d++);
    }),
    d++,
    b.mergeCells(`A${d}:E${d}`),
    j(
      `A${d}`,
      `ДЕКЛАРАЦИЯ: Масса брутто контейнера подтверждена в соответствии с требованиями конвенции СОЛАС.
DECLARATION: Gross weight of the container is confirmed in accordance with the requirements of SOLAS convention`,
      {
        sz: 9,
      },
    ),
    (b.getRow(d).height = 30),
    (d += 2),
    b.mergeCells(`A${d}:B${d}`),
    j(`A${d}`, "Фамилия исполнителя / Name of declarant", {
      b: 1,
    }),
    b.mergeCells(`C${d}:D${d}`),
    j(`C${d}`, l || ""),
    d++,
    b.mergeCells(`A${d}:B${d}`),
    j(`A${d}`, "Подпись исполнителя / Signature of declarant", {
      b: 1,
    }),
    b.mergeCells(`C${d}:D${d}`),
    j(`C${d}`, "_________________"),
    await cl(N, `VGM_${(t || "").replace(/[^\w-]+/g, "_") || "сертификат"}`));
}
function ns(t, n, s) {
  const l = (x) => {
      let N = x == null ? "" : String(x);
      return (/^[=+\-@]/.test(N) && (N = "'" + N), /[;"\n]/.test(N) ? '"' + N.replace(/"/g, '""') + '"' : N);
    },
    i = [n.map(l).join(";"), ...s.map((x) => x.map(l).join(";"))].join(`\r
`),
    u = new Blob(["\uFEFF" + i], {
      type: "text/csv;charset=utf-8;",
    }),
    o = Object.assign(document.createElement("a"), {
      href: URL.createObjectURL(u),
      download: bn(t, "csv"),
    });
  (o.click(), setTimeout(() => URL.revokeObjectURL(o.href), 3e3));
}
const gi = [
    ["wait", "Ожидание"],
    ["lab", "Лаборатория"],
    ["gross", "Весовая · брутто"],
    ["ts", "Выгрузка и перевалка"],
    ["tare", "Весовая · тара"],
    ["out", "Выезд"],
    ["stop", "Отказ и отмены"],
  ],
  pi = {
    wait: "new",
    lab: "in",
    gross: "lab_ok",
    ts: "gross",
    tare: "ts_ok",
    out: "left",
    stop: "lab_no",
  },
  fi = {
    unload: "выгрузка",
    clean: "очистка",
    mix: "замес",
    clean_mix: "очистка и замес",
  };
function Ae(t, n) {
  const s = (l, i, u, o) => ({
    g: l,
    k: i,
    t: u,
    c: o || pi[l],
  });
  if (t.cancelled_at) return s("stop", "cancel", "Заезд отменён", "cancel");
  if (t.out_at) return s("out", "left", "Убыл с терминала");
  if (t.lab_status === "rejected") return s("stop", "lab_no", "Отказ лаборатории · к выезду");
  if (t.tare_kg != null) return s("out", "tare", "Взвешен порожним · к выезду", "tare");
  if (t.gross_kg != null) {
    if (t.ts_at) {
      const l = (n && n.need) || [],
        i = t.extra_done || [];
      return l.length && l.some((u) => !i.includes(u))
        ? s("tare", "ts_extra", "Услуга оказана · ждёт доп. услуги")
        : s("tare", "ts_ok", "Услуга оказана · ждёт тару");
    }
    return t.site ? s("ts", "ts_site", "Площадка " + t.site + " · идёт выгрузка") : s("ts", "unload", "Взвешен гружёным · на выгрузку");
  }
  if (t.lab_status === "passed") {
    const l = fi[t.lab_result1];
    return s("gross", "ok_" + (t.lab_result1 || "x"), l ? `Одобрен (${l}) · ждёт брутто` : "Одобрен · ждёт брутто");
  }
  return t.in_at ? s("lab", "in", "На терминале · очередь лаборатории") : s("wait", "new", "Ожидается");
}
const bi = [
  ["new", "Ожидается · в пути", "wait"],
  ["t2", "Отстойник (Т2) · ждёт вызова", "wait"],
  ["called", "Вызван на терминал", "wait"],
  ["in", "На терминале · очередь лаборатории", "lab"],
  ["ok_unload", "Одобрен (выгрузка) · ждёт брутто", "gross"],
  ["ok_clean", "Одобрен (очистка) · ждёт брутто", "gross"],
  ["ok_mix", "Одобрен (замес) · ждёт брутто", "gross"],
  ["ok_clean_mix", "Одобрен (очистка и замес) · ждёт брутто", "gross"],
  ["ok_x", "Одобрен · ждёт брутто", "gross"],
  ["unload", "Взвешен гружёным · на выгрузку", "ts"],
  ["ts_site", "Площадка назначена · идёт выгрузка", "ts"],
  ["ts_ok", "Услуга оказана · ждёт тару", "tare"],
  ["ts_extra", "Услуга оказана · ждёт доп. услуги", "tare"],
  ["tare", "Взвешен порожним · к выезду", "out"],
  ["left", "Убыл с терминала", "out"],
  ["lab_no", "Отказ лаборатории · к выезду", "stop"],
  ["cancel", "Заезд отменён", "stop"],
];
function et(t) {
  return t.deleted_at
    ? {
        g: "stop",
        k: "del",
        t: "Удалена (в истории)",
        c: "cancel",
      }
    : t.status === "cancelled"
      ? {
          g: "stop",
          k: "req_no",
          t: "Отменена",
          c: "lab_no",
        }
      : t.status === "done"
        ? {
            g: "out",
            k: "req_done",
            t: "Завершена",
            c: "left",
          }
        : t.status === "arrived"
          ? {
              g: "lab",
              k: "req_in",
              t: "На терминале",
              c: "lab_ok",
            }
          : t.t2_called_at
            ? {
                g: "wait",
                k: "called",
                t: "Вызвана на терминал",
                c: "called",
              }
            : t.t2_at
              ? {
                  g: "wait",
                  k: "t2",
                  t: "Отстойник (Т2) · ждёт вызова",
                  c: "t2",
                }
              : {
                  g: "wait",
                  k: "new",
                  t: "Ожидается · в пути",
                  c: "new",
                };
}
const kn = [
  ["expected", "Ожидается к приезду", "exp"],
  ["arrived", "Заехал · ждёт приёмку", "in"],
  ["ready", "Принят · свободен под затарку", "ready"],
  ["to_load", "Под затаркой", "to_load"],
  ["loaded_free", "Гружёный · ждёт партию", "loaded"],
  ["b_formed", "В партии · ждёт досмотр", "loaded"],
  ["b_insp", "На досмотре РСХН", "inspected"],
  ["b_fumig", "Досмотр пройден · ждёт фумигацию", "inspected"],
  ["b_ready", "Готов к выпуску", "fumigated"],
  ["b_departed", "Партия убыла в порт", "dispatched"],
  ["temp", "Времянка · хранение остатка", "temp"],
  ["repair", "В ремонте", "repair"],
  ["washing", "На мойке", "washing"],
  ["out_full", "Убыл гружёным", "dispatched"],
  ["out_empty", "Убыл порожним", "dispatched"],
];
function ki(t, n, s) {
  if (!t)
    return {
      err: "Времянка не выбрана",
    };
  const l = t.temp_kg != null && String(t.temp_kg) !== "" ? +t.temp_kg : null,
    i = n == null || String(n).trim() === "" ? l : +n;
  if (i == null || Number.isNaN(i))
    return {
      err: `Во времянке ${t.container_no} остаток не известен — укажи, сколько килограммов берём`,
    };
  if (!(i > 0))
    return {
      err: "Сколько берём из времянки: нужно число больше нуля",
    };
  if (l != null && i > l + 1)
    return {
      err: `Во времянке ${t.container_no} остаток ${q(l)} кг, а берём ${q(i)} кг`,
    };
  const u = l != null ? Math.max(0, l - i) : null,
    o = u != null && u <= 1,
    x = o
      ? {
          temp_kg: 0,
          state: "ready",
          temp_closed_at: s || new Date().toISOString(),
          cargo: null,
        }
      : {
          temp_kg: u,
        };
  return {
    take: i,
    have: l,
    left: u,
    closed: o,
    patch: x,
  };
}
function Mt(t, n) {
  const s = (i, u, o) => ({
    k: i,
    t: u,
    c: "st-" + (o || i),
  });
  if (!t) return s("none", "—", "arrived");
  if (t.out_at || t.state === "dispatched")
    return t.empty_out ? s("out_empty", "Убыл порожним", "dispatched") : s("out_full", "Убыл гружёным", "dispatched");
  if (t.state === "expected")
    return s("expected", t.eta_date ? `Ожидается ${String(t.eta_date).split("-").reverse().join(".")}` : "Ожидается к приезду", "exp");
  if (t.state === "temp")
    return s(
      "temp",
      t.temp_kg != null && +t.temp_kg > 0 ? `Времянка · остаток ${q(Math.round(+t.temp_kg))} кг` : "Времянка · хранение остатка",
      "temp",
    );
  if (t.state === "repair") return s("repair", "В ремонте", "repair");
  if (t.state === "washing") return s("washing", "На мойке", "washing");
  if (t.state === "arrived") return s("arrived", "Заехал · ждёт приёмку", "arrived");
  if (t.state === "ready") return s("ready", "Принят · свободен под затарку", "ready");
  if (t.state === "to_load") return s("to_load", "Под затаркой", "to_load");
  if (!t.batch_id || !n) return s("loaded_free", "Гружёный · ждёт партию", "loaded");
  const l = {
    formed: ["b_formed", "В партии · ждёт досмотр", "loaded"],
    inspect: ["b_insp", "На досмотре РСХН", "inspected"],
    fumig: ["b_fumig", "Досмотр пройден · ждёт фумигацию", "inspected"],
    ready: ["b_ready", "Готов к выпуску", "fumigated"],
    departed: ["b_departed", "Партия убыла в порт", "dispatched"],
  }[n.status];
  return l ? s(l[0], l[1], l[2]) : s("loaded_free", "Гружёный · ждёт партию", "loaded");
}
function wi(t, n) {
  const s = n || [],
    l = s.filter((i) => i.out_at).length;
  return t.status === "departed"
    ? {
        k: "departed",
        t: "Убыла в порт",
        c: "left",
      }
    : s.length
      ? t.status === "ready"
        ? l === 0
          ? {
              k: "ready",
              t: "Готова · выпуск через КПП",
              c: "ts_ok",
            }
          : l < s.length
            ? {
                k: "part_out",
                t: "Частично выпущена",
                c: "gross",
              }
            : {
                k: "all_out",
                t: "Все выпущены · отметить убытие",
                c: "tare",
              }
        : {
            k: t.status,
            t: vt[t.status] || t.status,
            c: t.status === "formed" ? "in" : "lab_ok",
          }
      : {
          k: "empty",
          t: "Пустая — удалить",
          c: "cancel",
        };
}
function vs(t, n) {
  const s = n || {};
  return t.status === "closed"
    ? {
        k: "closed",
        t: "Закрыт",
        c: "left",
      }
    : t.status === "packed"
      ? {
          k: "packed",
          t: "Затарен в контейнеры",
          c: "left",
        }
      : t.status === "weighed"
        ? s.packed > 0
          ? {
              k: "part_packed",
              t: "Затарен частично",
              c: "gross",
            }
          : {
              k: "weighed",
              t: "Взвешен · к затарке",
              c: "tare",
            }
        : t.status === "ts_ok"
          ? {
              k: "ts_ok",
              t: "Перевалка выполнена · машины на тару",
              c: "ts_ok",
            }
          : s.pending > 0
            ? {
                k: "collect",
                t: "Собирается · ждёт остальных",
                c: "in",
              }
            : {
                k: "lab_ok",
                t: "Собран · ждёт перевалку",
                c: "lab_ok",
              };
}
const vi = {
    plate: "Камера ГРЗ",
    container: "Камера номеров контейнеров",
    weight: "Весы",
  },
  Vn = "https://xrdrhvwadumcglbkbswb.supabase.co/functions/v1/ingest-device";
function wn(t, n) {
  if (((t = String(t || "")), (n = String(n || "")), t === n)) return 0;
  if (!t.length || !n.length) return Math.max(t.length, n.length);
  let s = Array.from(
    {
      length: n.length + 1,
    },
    (l, i) => i,
  );
  for (let l = 1; l <= t.length; l++) {
    const i = [l];
    for (let u = 1; u <= n.length; u++) i[u] = Math.min(s[u] + 1, i[u - 1] + 1, s[u - 1] + (t[l - 1] === n[u - 1] ? 0 : 1));
    s = i;
  }
  return s[n.length];
}
function Ni(t, n, s, l = 2) {
  const i = String(t || "");
  if (!i) return [];
  const u = [];
  for (const o of n || []) {
    let x = 99;
    for (const N of (s(o) || []).filter(Boolean)) {
      const b = wn(i, String(N));
      b < x && (x = b);
    }
    x <= l &&
      u.push({
        row: o,
        d: x,
      });
  }
  return u.sort((o, x) => o.d - x.d).slice(0, 8);
}
const ol = (t, n = 15) => !!(t != null && t.last_seen) && Date.now() - new Date(t.last_seen) < n * 6e4,
  dl = (t) => (t != null && t.last_seen ? Math.round((Date.now() - new Date(t.last_seen)) / 6e4) : null);
async function Rs(t, n, s, l) {
  if (!(t != null && t.id)) return;
  const { error: i } = await A.from("term_device_events")
    .update({
      status: "used",
      entity: n,
      entity_id: s || null,
      used_by: (l == null ? void 0 : l.id) || null,
      used_at: new Date().toISOString(),
    })
    .eq("id", t.id);
  if (i) throw new Error(`Показание устройства не отмечено использованным (${i.message}) — оно останется в списке новых`);
}
async function hl(t, n) {
  if (!(t != null && t.id)) return;
  const { error: s } = await A.from("term_device_events")
    .update({
      status: "ignored",
      used_by: (n == null ? void 0 : n.id) || null,
      used_at: new Date().toISOString(),
    })
    .eq("id", t.id);
  if (s) throw new Error(`Показание устройства не отмечено пропущенным (${s.message}) — оно останется в списке новых`);
}
const Ls = (t) => (t != null && t.at ? Math.round((Date.now() - new Date(t.at)) / 6e4) : null),
  _t = ["Движение", "ЗПК верхняя", "ЗПК нижняя"],
  As = ["Движение", "ЗПК верхняя", "ЗПК нижняя", "Склад"],
  ls = [
    ["mp", "Масличная примесь, %"],
    ["dark", "Тёмные, %"],
    ["dmg", "Повреждённые, %"],
    ["sprout", "Проросшие, %"],
    ["color", "Др. цвета, %"],
    ["water", "Повр. водой, %"],
    ["infest", "Заражённость"],
    ["bleach", "Обесцвеченные, %"],
    ["mar", "Маранность, %"],
  ],
  Le = {
    unload: "Выгрузка",
    clean: "Очистка",
    mix: "Замес",
    clean_mix: "Очистка+Замес",
  },
  us = ["20", "40"],
  ms = ["HC", "DC"],
  ul = {
    expected: "Ожидается к приезду",
    arrived: "Заехал · ждёт приёмку",
    ready: "Принят · свободен под затарку",
    repair: "В ремонте",
    washing: "На мойке",
    to_load: "Под затаркой",
    temp: "Времянка (хранение остатка)",
    loaded: "Гружёный",
    inspected: "Досмотр РСХН пройден",
    fumigated: "Фумигация пройдена",
    dispatched: "Убыл с терминала",
  },
  Lt = (t, n) => (t ? Math.max(0, Math.round(((n ? new Date(n) : new Date()) - new Date(t)) / 864e5)) : null),
  ml = (t) => {
    const n = t.term_line_containers || {},
      s = (n.size || "") + (n.height || ""),
      l = t.net_final_kg ?? t.net_kg,
      i = n.cont_tare_kg,
      u = l != null && i != null ? +l + +i : null;
    return {
      sklad: t.site || n.site || "Склад",
      cont: n.container_no,
      type: s,
      line: n.line || "",
      net: l,
      gross: u,
      tare: i,
      seal: t.seal_no || n.seal_no || "",
      cum: al(n.size, n.height),
      vgm: u,
      is_temp: !!t.is_temp,
      booking: n.booking || "",
      client: n.client || "",
      culture: t.culture || "",
    };
  };
async function vn({ kind: t, no: n, date: s, booking: l, batchId: i, cargo: u, client: o, rows: x, me: N }) {
  var z, _;
  const b = (x || []).reduce((h, w) => h + (+w.net || 0), 0),
    j = (x || []).map((h) => ({
      cont: h.cont,
      net: h.net,
      vgm: h.vgm,
      seal: h.seal,
    })),
    { data: g, error: d } = await A.from("term_docs")
      .select("id, rows_n, total_net_kg, payload, created_at, by_name")
      .eq("kind", t)
      .ilike("doc_no", n)
      .limit(1);
  if (d)
    throw new Error(
      `Не удалось проверить номер ${n} по журналу документов (${d.message}). Выпуск остановлен: без этой проверки под одним номером могут уйти два разных документа.`,
    );
  if (g && g.length) {
    const h = g[0],
      w = ($) => [$.cont, Math.round(+$.net || 0), Math.round(+$.vgm || 0), ($.seal || "").trim()].join("|"),
      p = (((z = h.payload) == null ? void 0 : z.containers) || []).map(w).sort(),
      F = j.map(w).sort();
    if (!(h.rows_n === j.length && Math.abs((+h.total_net_kg || 0) - b) < 1 && JSON.stringify(p) === JSON.stringify(F))) {
      const $ = (((_ = h.payload) == null ? void 0 : _.containers) || [])
          .map((U) => U.cont)
          .sort()
          .join(","),
        m = j
          .map((U) => U.cont)
          .sort()
          .join(","),
        v = $ !== m ? "другой набор контейнеров" : "те же контейнеры, но изменились массы или пломбы";
      throw new Error(
        `Документ ${t === "vgm" ? "VGM" : "акт затарки"} №${n} уже выпущен ${new Date(h.created_at).toLocaleString("ru-RU")} (${h.by_name || ""}), и сейчас состав другой: ${v}. Было контейнеров ${h.rows_n} на ${Math.round(h.total_net_kg || 0)} кг. Возьми другой номер — иначе на один номер будет два разных документа.`,
      );
    }
    const { error: y } = await A.from("term_docs").insert({
      kind: t,
      doc_no: n + " (копия " + new Date().toLocaleString("ru-RU") + ")",
      doc_date: s || null,
      booking: l || null,
      batch_id: i || null,
      cargo: u || null,
      client: o || null,
      rows_n: j.length,
      total_net_kg: b,
      payload: {
        containers: j,
        copy_of: h.id,
      },
      by_id: (N == null ? void 0 : N.id) || null,
      by_name: (N == null ? void 0 : N.name) || null,
    });
    if (y)
      throw new Error(
        `Повторная печать не записалась в журнал документов (${y.message}). Журнал перестанет показывать, сколько экземпляров ушло наружу.`,
      );
    return "copy";
  }
  const { error: M } = await A.from("term_docs").insert({
    kind: t,
    doc_no: n,
    doc_date: s || null,
    booking: l || null,
    batch_id: i || null,
    cargo: u || null,
    client: o || null,
    rows_n: j.length,
    total_net_kg: b,
    payload: {
      containers: j,
    },
    by_id: (N == null ? void 0 : N.id) || null,
    by_name: (N == null ? void 0 : N.name) || null,
  });
  if (M) throw /duplicate|unique/i.test(M.message || "") ? new Error(`Документ №${n} только что выпустил другой сотрудник — обнови страницу.`) : M;
  return "new";
}
const xl = () => typeof navigator < "u" && "serial" in navigator,
  yi = (t) => {
    const s = String(t || "")
      .replace(/[\u00a0]/g, " ")
      .replace(/(\d)[ ](?=\d{3}(\D|$))/g, "$1")
      .replace(/,(?=\D|$)/g, " ")
      .match(/-?\d+(?:[.,]\d+)?/g);
    if (!s || !s.length) return null;
    const l = Math.round(Number(String(s[s.length - 1]).replace(",", ".")));
    return isFinite(l) ? l : null;
  };
function Si({ baudRate: t = 9600, minRead: n = 500, stableN: s = 3, onWeight: l, onState: i }) {
  let u = null,
    o = null,
    x = !1,
    N = "",
    b = [],
    j = null;
  const g = (z, _) => i && i(z, _);
  return {
    connect: async () => {
      if (!xl()) throw new Error("Браузер не умеет читать весы. Открой систему в Chrome на том компьютере, к которому подключены весы.");
      ((u = await navigator.serial.requestPort()),
        await u.open({
          baudRate: Number(t) || 9600,
        }),
        g("on"),
        (x = !1));
      const z = new TextDecoderStream();
      return (
        u.readable.pipeTo(z.writable).catch(() => {}),
        (o = z.readable.getReader()),
        (async () => {
          try {
            for (; !x;) {
              const { value: _, done: h } = await o.read();
              if (h) break;
              N += _;
              const w = N.split(/[\r\n]+/);
              N = w.pop() || "";
              for (const p of w) {
                const F = yi(p);
                if (F == null || Math.abs(F) < Number(n)) continue;
                (b.push(F), b.length > Number(s) && b.shift());
                const C = b.length >= Number(s) && b.every((y) => y === b[0]);
                ((j = F),
                  l &&
                    l({
                      weight: F,
                      stable: C,
                      raw: p.trim(),
                    }));
              }
            }
          } catch (_) {
            g("err", String(_.message || _));
          }
        })(),
        !0
      );
    },
    disconnect: async () => {
      x = !0;
      try {
        o && (await o.cancel());
      } catch {}
      try {
        u && (await u.close());
      } catch {}
      ((u = null), (o = null), (b = []), (j = null), g("off"));
    },
    get current() {
      return j;
    },
  };
}
const Et = ({ c: t, b: n, bm: s }) => {
    const l = Mt(t, n || (s ? s[t.batch_id] : null));
    return <span className={"stage " + l.c}>{l.t}</span>;
  },
  $i = {
    expected: ["in", "Ожидается"],
    arrived: ["lab_ok", "На терминале"],
    done: ["left", "Завершена"],
    cancelled: ["lab_no", "Отменена"],
    open: ["in", "Открыта"],
    closed: ["left", "Закрыта"],
  };
function hn() {
  try {
    Object.keys(sessionStorage)
      .filter((t) => t.startsWith("c9."))
      .forEach((t) => sessionStorage.removeItem(t));
  } catch {}
}
function ne(t, n = [], s = 3e4, l = null) {
  const [i, u] = S.useState(() => {
      if (!l) return null;
      try {
        const j = sessionStorage.getItem("c9." + l);
        return j ? JSON.parse(j) : null;
      } catch {
        return null;
      }
    }),
    [o, x] = S.useState(null),
    N = S.useRef(""),
    b = S.useCallback(async (j) => {
      if (!(!j && document.hidden))
        try {
          x(null);
          const g = await t(),
            d = JSON.stringify(g);
          if (d !== N.current && ((N.current = d), u(g), l))
            try {
              d.length < 4e5 && sessionStorage.setItem("c9." + l, d);
            } catch {}
        } catch (g) {
          x(String(g.message || g));
        }
    }, n);
  return (
    S.useEffect(() => {
      if ((b(!0), !s)) return;
      const j = setInterval(b, s),
        g = () => {
          document.hidden || b();
        };
      return (
        document.addEventListener("visibilitychange", g),
        () => {
          (clearInterval(j), document.removeEventListener("visibilitychange", g));
        }
      );
    }, [b, s]),
    [i, b, o]
  );
}
function Te(t, n, s) {
  const [l, i] = S.useState(() => {
      if (s != null) return s;
      try {
        const o = localStorage.getItem("term9." + t);
        return o != null ? JSON.parse(o) : n;
      } catch {
        return n;
      }
    }),
    u = S.useCallback(
      (o) =>
        i((x) => {
          const N = typeof o == "function" ? o(x) : o;
          try {
            localStorage.setItem("term9." + t, JSON.stringify(N));
          } catch {}
          return N;
        }),
      [t],
    );
  return [l, u];
}
const Y = async (t) => {
  const { data: n, error: s } = await t;
  if (s) throw s;
  return n;
};
function rt() {
  const [t, n] = S.useState({
    k: null,
    d: 1,
  });
  return {
    TH: ({ k: i, children: u, right: o }) => (
      <th
        className={"sortth" + (o ? " right" : "") + (t.k === i ? " on" : "")}
        onClick={() =>
          n((x) =>
            x.k === i
              ? x.d === 1
                ? {
                    k: i,
                    d: -1,
                  }
                : {
                    k: null,
                    d: 1,
                  }
              : {
                  k: i,
                  d: 1,
                },
          )
        }
      >
        {u}
        <span className="s-ar">{t.k === i ? (t.d === 1 ? "▲" : "▼") : "⇅"}</span>
      </th>
    ),
    apply: (i, u) => {
      if (!t.k || !i || !u[t.k]) return i;
      const o = u[t.k];
      return [...i].sort((x, N) => {
        const b = o(x),
          j = o(N);
        return b == null && j == null
          ? 0
          : b == null
            ? 1
            : j == null
              ? -1
              : typeof b == "number" && typeof j == "number"
                ? (b - j) * t.d
                : String(b).localeCompare(String(j), "ru", {
                    numeric: !0,
                  }) * t.d;
      });
    },
  };
}
const Ve = (t) => {
    const n = t ? new Date(t) : new Date();
    return `${n.getFullYear()}-${String(n.getMonth() + 1).padStart(2, "0")}-${String(n.getDate()).padStart(2, "0")}`;
  },
  Ns = (t) => Ve(t).split("-").reverse().join(".");
function X({ label: t, children: n }) {
  return (
    <div className="fld">
      <label>{t}</label>
      {n}
    </div>
  );
}
const qt = {
    me: null,
  },
  Ci = {
    cp: ["manager", "chief"],
    ctr: ["manager", "chief"],
    ord: ["manager", "chief"],
    req: ["manager", "chief"],
    vis: ["kpp", "scale", "lab", "transship", "manager", "chief"],
    cont: ["kpp", "container", "scale", "dispatcher", "manager", "transship", "chief"],
  },
  mt = (t) => {
    var n;
    return (Ci[t] || []).includes((n = qt.me) == null ? void 0 : n.role);
  },
  Mi = " · только просмотр: правку ведёт отдел, который отвечает за эти данные",
  ot = {
    S: Rt,
  },
  _l = nt.createContext(Rt),
  Js = () => nt.useContext(_l),
  Oe = (t, n) => {
    const s = Number(t == null ? void 0 : t[n]);
    return isFinite(s) ? s : Number(Rt[n]);
  },
  it = {
    set: new Set(),
    list: [],
    make: {},
    short: {},
    gen: 0,
    subs: new Set(),
  },
  Ei = () => {
    (it.gen++,
      it.subs.forEach((t) => {
        try {
          t(it.gen);
        } catch {}
      }));
  };
function Nn() {
  const [, t] = S.useState(it.gen);
  return (
    S.useEffect(() => {
      const n = (s) => t(s);
      return (it.subs.add(n), () => it.subs.delete(n));
    }, []),
    it
  );
}
const Bs = (t) => {
    const n = De(t);
    return n ? (it.set.has(n) ? n : (/^\d{3}$/.test(n) && it.short[n]) || "") : "";
  },
  qi = (t) => !!Bs(t),
  CXt = ({ v: t, dash: n = "—" }) => {
    if ((Nn(), !t)) return <>{n}</>;
    const s = Bs(t);
    if (!s) return <>{t}</>;
    const l = it.make[s] || "",
      i = s !== De(t);
    return (
      <span className="veh9own" title={`машина терминала${i ? ` · ${s}` : ""}${l ? " · " + l : ""}`}>
        {t}
      </span>
    );
  },
  $t = () => {
    var t;
    return (
      String(((t = ot.S) == null ? void 0 : t.ts_step) ?? Rt.ts_step)
        .trim()
        .toLowerCase() !== "нет"
    );
  };
function CYn({ warns: t, on: n, setOn: s }) {
  return t.length ? (
    <div className="ovr9">
      {t.map((l, i) => (
        <div className="ovr-l">⚠ {l}</div>
      ))}
      <label className="fkey">
        <input type="checkbox" checked={n} onChange={(l) => s(l.target.checked)} /> вижу отклонение, подтверждаю ввод под свою ответственность
      </label>
    </div>
  ) : null;
}
function Gt({ v: t, dash: n, small: s }) {
  if (!Ks(t)) return n ? <span className="faint">—</span> : null;
  const l = js(t);
  return (
    <span className="mixtag" title={"Замес" + (l ? ": " + l : "")}>
      ⇄ Замес{t.mix_group ? " " + t.mix_group : ""}
      {t.mix_with ? <span className="mx-w"> · с {t.mix_with}</span> : null}
      {t.mix_param ? <span className="mx-p"> · {t.mix_param}</span> : null}
      {t.site ? <span className="mx-s"> · {t.site}</span> : null}
    </span>
  );
}
function CFe({ err: t, ok: n }) {
  return t ? <div className="err">Ошибка: {t}</div> : n ? <div className="ok">{n}</div> : null;
}
const Se = (t, n, s, l = "", i) => (
    <input
      style={
        i
          ? {
              width: i,
              minWidth: i,
            }
          : void 0
      }
      placeholder={l}
      value={t[s] ?? ""}
      onChange={(u) =>
        n((o) => ({
          ...o,
          [s]: u.target.value,
        }))
      }
    />
  ),
  is = (t, n, s, l, i, u = 96, o) => (
    <input
      list={o}
      style={{
        background: "var(--panel-2)",
        border: "1px solid var(--line-2)",
        borderRadius: 6,
        color: "var(--text)",
        font: "inherit",
        fontSize: 12,
        padding: "5px 8px",
        width: u,
      }}
      placeholder={i}
      value={(t[s] || {})[l] || ""}
      onChange={(x) =>
        n((N) => ({
          ...N,
          [s]: {
            ...(N[s] || {}),
            [l]: x.target.value,
          },
        }))
      }
    />
  );
function CPe({ value: t, onChange: n, options: s, w: l, ph: i = "— выбрать —" }) {
  const [u, o] = S.useState(!1),
    [x, N] = S.useState(null),
    [b, j] = S.useState(""),
    g = S.useRef(null),
    d = S.useRef(null),
    M = () => {
      const F = g.current.getBoundingClientRect(),
        C = window.innerHeight - F.bottom,
        y = C < 240 && F.top > C;
      (N({
        left: Math.min(F.left, Math.max(8, window.innerWidth - 390)),
        width: F.width,
        top: y ? null : F.bottom + 4,
        bottom: y ? window.innerHeight - F.top + 4 : null,
        maxH: Math.max(120, Math.min(250, (y ? F.top : C) - 14)),
      }),
        j(""),
        o(!0));
    };
  S.useEffect(() => {
    if (!u) return;
    const F = ($) => {
        (g.current && g.current.contains($.target)) || (d.current && d.current.contains($.target)) || o(!1);
      },
      C = ($) => {
        (d.current && d.current.contains($.target)) || o(!1);
      },
      y = () => o(!1);
    return (
      document.addEventListener("mousedown", F),
      document.addEventListener("scroll", C, !0),
      window.addEventListener("resize", y),
      () => {
        (document.removeEventListener("mousedown", F), document.removeEventListener("scroll", C, !0), window.removeEventListener("resize", y));
      }
    );
  }, [u]);
  const z = (s || []).map((F) => (Array.isArray(F) ? F : [F, F])),
    _ = z.find((F) => String(F[0]) === String(t ?? "")) || null,
    h = z.length > 12,
    w = (b || "").trim().toLowerCase(),
    p = w ? z.filter((F) => String(F[1]).toLowerCase().includes(w) || String(F[0]).toLowerCase().includes(w)) : z;
  return (
    <div
      className="sel"
      ref={g}
      style={
        l
          ? {
              width: l,
              minWidth: l,
            }
          : void 0
      }
    >
      <button
        type="button"
        className={"sel-btn" + (u ? " open" : "")}
        onClick={(F) => {
          (F.stopPropagation(), u ? o(!1) : M());
        }}
      >
        <span className={_ ? "" : "sel-ph"}>{_ ? _[1] : i}</span>
        <i className="sel-car">▾</i>
      </button>
      {u &&
        x &&
        _n.createPortal(
          <div
            ref={d}
            className="sel-list fx"
            onMouseDown={(F) => F.stopPropagation()}
            style={{
              left: x.left,
              minWidth: Math.max(x.width, 150),
              top: x.top ?? "auto",
              bottom: x.bottom ?? "auto",
              maxHeight: x.maxH,
            }}
          >
            {h && (
              <div className="sel-find">
                <input
                  autoFocus={window.innerWidth > 760}
                  value={b}
                  onChange={(F) => j(F.target.value)}
                  placeholder={`поиск среди ${z.length}…`}
                  onKeyDown={(F) => {
                    (F.key === "Enter" && p.length === 1 && (n(String(p[0][0])), o(!1)), F.key === "Escape" && o(!1));
                  }}
                />
              </div>
            )}
            {!w && (
              <div
                className={"sel-opt" + (_ ? "" : " on")}
                onClick={() => {
                  (n(""), o(!1));
                }}
              >
                —
              </div>
            )}
            {p.map((F) => (
              <div
                className={"sel-opt" + (_ && String(F[0]) === String(_[0]) ? " on" : "")}
                onClick={() => {
                  (n(String(F[0])), o(!1));
                }}
              >
                {F[1]}
              </div>
            ))}
            {h && !p.length && <div className="sel-opt faint">ничего не найдено</div>}
          </div>,
          document.body,
        )}
    </div>
  );
}
const Ti = {
    key: ["M21 2l-2 2", "M11.4 11.6a5.5 5.5 0 1 1-7.8 7.8 5.5 5.5 0 0 1 7.8-7.8z", "M11.4 11.6L15.5 7.5", "M15.5 7.5l3 3L22 7l-3-3"],
    clip: ["M21.4 11.1l-9.2 9.2a6 6 0 0 1-8.5-8.5l9.2-9.2a4 4 0 0 1 5.7 5.7l-9.2 9.2a2 2 0 0 1-2.8-2.9l8.5-8.5"],
    link: ["M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.8 1.7", "M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.8-1.7"],
    ok: ["M20 6L9 17l-5-5"],
    save: ["M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z", "M17 21v-8H7v8", "M7 3v5h8"],
  },
  Sn = ({ n: t, s: n = 14 }) => (
    <svg
      viewBox="0 0 24 24"
      width={n}
      height={n}
      fill="none"
      stroke="currentColor"
      strokeWidth="1.7"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      {(Ti[t] || []).map((s, l) => (
        <path d={s} />
      ))}
    </svg>
  ),
  Ye = ({ onClick: t, title: n = "Изменить запись" }) => (
    <button
      className="btn sec sm icon"
      title={n}
      onClick={(s) => {
        (s.stopPropagation(), t());
      }}
    >
      ✎
    </button>
  );
function Je({ make: t, label: n = "⇩ Excel" }) {
  const [s, l] = S.useState(!1);
  return (
    <button
      className="btn sec sm"
      disabled={s}
      onClick={async (i) => {
        (i.stopPropagation(), l(!0));
        try {
          await t();
        } catch (u) {
          (console.error(u), alert("Ошибка экспорта: " + (u.message || u)));
        }
        l(!1);
      }}
    >
      {s ? "…" : n}
    </button>
  );
}
function Hn({ data: t, fmt: n = (l) => q(Math.round(l)), unit: s = "" }) {
  const l = Math.max(1, ...t.map((i) => +i.v || 0));
  return (
    <div className="bars">
      {t.map((i, u) => (
        <div className="bcol">
          <div className="btip">
            <span className="tt-l">{i.tip || i.l}</span>
            <span className="tt-v">
              <i className="tt-dot" />
              {n(i.v)}
              {s}
            </span>
          </div>
          <span className="bval">{i.v ? n(i.v) : ""}</span>
          <div
            className="bar"
            style={{
              height: Math.max(2, Math.round(((+i.v || 0) / l) * 100)) + "%",
            }}
          />
          <span className="blab">{i.l}</span>
        </div>
      ))}
    </div>
  );
}
function Ps({ data: t, fmt: n = (l) => q(Math.round(l)), unit: s = "" }) {
  const l = Math.max(1, ...t.map((i) => +i.v || 0));
  return t.length ? (
    <div>
      {t.map((i, u) => (
        <div className="hrow">
          <div className="btip">
            <span className="tt-l">{i.tip || i.l}</span>
            <span className="tt-v">
              <i className="tt-dot" />
              {n(i.v)}
              {s}
            </span>
          </div>
          <span className="hlab" title={i.l}>
            {i.l}
          </span>
          <div className="htrack">
            <div
              className="hfill"
              style={{
                width: Math.max(1.5, ((+i.v || 0) / l) * 100) + "%",
              }}
            />
          </div>
          <span className="hval">
            {n(i.v)}
            {s}
          </span>
        </div>
      ))}
    </div>
  ) : (
    <p
      className="p-sub"
      style={{
        margin: 0,
      }}
    >
      данных пока нет
    </p>
  );
}
function Tt({ items: t, val: n, onSel: s }) {
  return (
    <div className="chips">
      {t.map((l) => (
        <button className={"chip" + (n === l.k ? " on" : "")} onClick={() => s && s(n === l.k ? null : l.k)}>
          {l.t} <b>{l.n}</b>
        </button>
      ))}
    </div>
  );
}
function ys() {
  const [t] = ne(
    () =>
      Y(
        A.from("term_batches")
          .select("id, batch_no, status")
          .order("id", {
            ascending: !1,
          })
          .limit(2e3),
      ),
    [],
    6e4,
    "bmap9",
  );
  return S.useMemo(() => Object.fromEntries((t || []).map((n) => [n.id, n])), [t]);
}
const tt = (t, n) => Mt(t, n ? n[t.batch_id] : null).t,
  Fe = (t) => [...new Set(t.filter((n) => n != null && String(n).trim() !== "").map((n) => String(n).trim()))].slice(0, 300),
  CJt = ({ id: t, items: n }) => (
    <datalist id={t}>
      {n.map((s) => (
        <option value={s} />
      ))}
    </datalist>
  ),
  cs = (t, n, s) => {
    if (!t || !String(t).trim()) return null;
    const l = String(t).replace(/\D/g, "");
    if (!n.includes(l.length)) throw new Error(`${s}: ожидается ${n.join(" или ")} цифр (введено ${l.length})`);
    return l;
  };
function Ss({ title: t, hint: n, onClose: s, onSave: l, onClear: i, busy: u, err: o, warn: x, children: N }) {
  return (
    <div
      className="modal-bg"
      onMouseDown={(b) => {
        b.target === b.currentTarget && s();
      }}
    >
      <div
        className="modal"
        style={{
          width: 470,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">{t}</h2>
          <button className="btn sec sm" onClick={s}>
            ✕
          </button>
        </div>
        {n && (
          <p
            className="p-sub"
            style={{
              marginBottom: 0,
            }}
          >
            {n}
          </p>
        )}
        <div className="m-body">
          <div className="fcol">{N}</div>
        </div>
        <div className="m-foot">
          <button className="btn" disabled={u} onClick={l}>
            {u ? "Сохранение…" : "Сохранить"}
          </button>
          {i && (
            <button className="btn sec sm" onClick={i}>
              Очистить форму
            </button>
          )}
          <span
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            черновик сохраняется автоматически — ввод не потеряется
          </span>
        </div>
        {x && <div className="warn9">⚠ {x}</div>}
        <CFe err={o} />
      </div>
    </div>
  );
}
const CGt = ({ n: t, onClick: n, title: s = "Вложения: файлы и фото" }) => (
  <button
    className={"btn sec sm icon clip" + (t ? " has" : "")}
    title={s}
    onClick={(l) => {
      (l.stopPropagation(), n());
    }}
  >
    <Sn n="clip" />
    {t ? <b>{t}</b> : null}
  </button>
);
function Oi(t, n) {
  const [s, l] = ne(
      () =>
        Y(
          A.from("term_files").select("*").eq("entity", t).eq("entity_id", n).order("id", {
            ascending: !1,
          }),
        ),
      [t, n],
      2e4,
    ),
    [i, u] = S.useState({});
  return (
    S.useEffect(() => {
      let o = !1;
      return (
        (s || [])
          .filter((x) => /^image\//.test(x.mime || "") && !i[x.id])
          .forEach(async (x) => {
            const N = await fn(x.path);
            N &&
              !o &&
              u((b) => ({
                ...b,
                [x.id]: N,
              }));
          }),
        () => {
          o = !0;
        }
      );
    }, [s]),
    {
      files: s || [],
      urls: i,
      reload: l,
    }
  );
}
function Bt({ me: t, entity: n, id: s, canAdd: l = !0 }) {
  const { files: i, urls: u, reload: o } = Oi(n, s),
    [x, N] = S.useState(!1),
    [b, j] = S.useState(null),
    g = async (h) => {
      if (!(!h || !h.length)) {
        (N(!0), j(null));
        try {
          for (const w of Array.from(h)) {
            if (w.size > Vs * 1024 * 1024) throw new Error(`Файл «${w.name}» больше ${Vs} МБ — сожми или загрузи частями`);
            await rl(n, s, w, t.id);
          }
          o();
        } catch (w) {
          j(String(w.message || w));
        }
        N(!1);
      }
    },
    d = async (h) => {
      const w = u[h.id] || (await fn(h.path));
      w && window.open(w, "_blank");
    },
    M = async (h) => {
      if (window.confirm(`Удалить файл «${h.name}»?`))
        try {
          const { data: w, error: p } = await A.from("term_files").delete().eq("id", h.id).select("id");
          if (p) throw p;
          if (!w || !w.length) throw new Error("Удалить может автор файла или управляющий");
          (A.storage
            .from(gs)
            .remove([h.path])
            .catch(() => {}),
            o());
        } catch (w) {
          j(String(w.message || w));
        }
    },
    z = i.filter((h) => /^image\//.test(h.mime || "")),
    _ = i.filter((h) => !/^image\//.test(h.mime || ""));
  return (
    <div className="fblock">
      {l && (
        <div
          className="row"
          style={{
            gap: 6,
            alignItems: "center",
          }}
        >
          <label
            className="btn sm"
            style={{
              cursor: "pointer",
            }}
          >
            📷 Фото с камеры
            <input
              type="file"
              accept="image/*"
              capture="environment"
              style={{
                display: "none",
              }}
              onChange={(h) => {
                (g(h.target.files), (h.target.value = ""));
              }}
            />
          </label>
          <label
            className="btn sec sm"
            style={{
              cursor: "pointer",
            }}
          >
            + Файлы
            <input
              type="file"
              multiple={!0}
              style={{
                display: "none",
              }}
              onChange={(h) => {
                (g(h.target.files), (h.target.value = ""));
              }}
            />
          </label>
          {x && (
            <span
              className="p-sub"
              style={{
                margin: 0,
              }}
            >
              загрузка…
            </span>
          )}
        </div>
      )}
      <CFe err={b} />
      {z.length > 0 && (
        <div className="fgal">
          {z.map((h) => (
            <div className="fimg" title={h.name}>
              <div className="fimg-in" onClick={() => d(h)}>
                {u[h.id] ? <img src={u[h.id]} alt={h.name} loading="lazy" /> : <span className="faint">…</span>}
              </div>
              <button className="fdel" title="Удалить фото" onClick={() => M(h)}>
                ✕
              </button>
            </div>
          ))}
        </div>
      )}
      {_.length > 0 && (
        <table
          style={{
            marginTop: 8,
          }}
        >
          <thead>
            <tr>
              <th>Файл</th>
              <th className="right">Размер, КБ</th>
              <th>Когда</th>
              <th />
            </tr>
          </thead>
          <tbody>
            {_.map((h) => (
              <tr>
                <td className="rowx" onClick={() => d(h)}>
                  <b>📄 {h.name}</b>
                </td>
                <td className="right">{h.size_kb ?? "—"}</td>
                <td className="nowrap">{he(h.created_at)}</td>
                <td>
                  <button className="btn danger sm icon" title="Удалить" onClick={() => M(h)}>
                    ✕
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
      {!i.length && (
        <p
          className="p-sub"
          style={{
            margin: "8px 0 0",
          }}
        >
          вложений пока нет · фото сжимаются автоматически
        </p>
      )}
    </div>
  );
}
function Kt({ me: t, entity: n, id: s, title: l, onClose: i, canAdd: u = !0 }) {
  return (
    <div
      className="modal-bg"
      onMouseDown={(o) => {
        o.target === o.currentTarget && i();
      }}
    >
      <div
        className="modal"
        style={{
          width: 620,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">📎 {l}</h2>
          <button className="btn sec sm" onClick={i}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <Bt me={t} entity={n} id={s} canAdd={u} />
        </div>
      </div>
    </div>
  );
}
function Di(t, n, s) {
  const l = [],
    i = (o) => (s[o] !== void 0 ? s[o] : n[o]),
    u = (o) => {
      const x = i(o);
      return x == null || x === "" ? null : +x;
    };
  if (t === "term_truck_visits" || t === "term_container_loads") {
    const o = u("gross_kg"),
      x = u("tare_kg");
    o != null &&
      x != null &&
      x >= o &&
      l.push(
        t === "term_container_loads"
          ? `Тара ${q(x)} кг больше брутто ${q(o)} кг — нетто выйдет отрицательным. Если зерно ЗАБИРАЛИ из контейнера, это растарка: закрой правку и нажми «Дотарка / растарка» на строке затарки (или в панели «Времянки на площадке»), тогда остаток пересчитается сам.`
          : `Тара ${q(x)} кг больше брутто ${q(o)} кг — нетто выйдет отрицательным. Проверь, не переставлены ли цифры местами.`,
      );
  }
  return l;
}
function Ii(t, n, s) {
  const l = [],
    i = (o) => (s[o] !== void 0 ? s[o] : n[o]),
    u = (o) => {
      const x = i(o);
      return x == null || x === "" ? null : +x;
    };
  if (t === "term_orders") {
    const o = (x, N, b, j, g = "") => {
      const d = u(x);
      d != null && (d < b || d > j) && l.push(`${N}: ${d}${g} вне разумных границ (${b}–${j}${g})`);
    };
    (o("vat_pct", "НДС", 0, 30, "%"),
      o("rate_per_t", "Ставка", 0.01, 1e5, " $/т"),
      o("load_norm_t", "Норма загрузки", 8, 35, " т"),
      o("volume_t", "Объём", 0.1, 1e6, " т"));
  }
  if (t === "term_contracts") {
    const o = i("contract_date");
    (o && o > Hs() && l.push(`дата договора ${String(o).split("-").reverse().join(".")} — в будущем`),
      o && o < "2015-01-01" && l.push(`дата договора ${String(o).split("-").reverse().join(".")} — раньше 2015 года, проверь год`));
  }
  if (t === "term_truck_visits" || t === "term_container_loads") {
    const o = u("gross_kg"),
      x = u("tare_kg");
    (o != null &&
      x != null &&
      x >= o &&
      l.push(
        `тара ${q(x)} кг не может быть больше или равна брутто ${q(o)} кг — нетто получится отрицательным${t === "term_container_loads" ? "; забор зерна из контейнера оформляется растаркой, а не затаркой" : ""}`,
      ),
      o != null && o <= 0 && l.push("брутто должно быть больше нуля"),
      x != null && x <= 0 && l.push("тара должна быть больше нуля"));
  }
  if (
    (t === "term_truck_visits" &&
      (u("gross_kg") != null && u("gross_kg") > Oe(ot.S, "truck_gross_max") && l.push(`брутто выше предела ${q(Oe(ot.S, "truck_gross_max"))} кг`),
      u("lab_moisture") != null && (u("lab_moisture") < 0 || u("lab_moisture") > 100) && l.push("влажность вне диапазона 0–100%"),
      u("lab_impurity") != null && (u("lab_impurity") < 0 || u("lab_impurity") > 100) && l.push("сорность вне диапазона 0–100%"),
      i("lab_status") === "pending" &&
        (n.tare_kg != null || n.gross_kg != null) &&
        l.push("машина уже взвешена — возврат в очередь лаборатории сделает запись противоречивой"),
      i("lab_status") === "passed" && !i("lab_result1") && l.push("«Одобрен» без «Результата 1» — перевалка не поймёт, какую услугу оказывать")),
    t === "term_requests")
  ) {
    const o = u("planned_tonnes");
    (o != null && o * 1e3 > Oe(ot.S, "truck_gross_max") && l.push(`вес плана ${q(o * 1e3)} кг больше предельного брутто зерновоза`),
      o != null && o <= 0 && l.push("вес плана должен быть больше нуля"));
  }
  if (
    ((t === "term_requests" || t === "term_truck_visits") &&
      (i("vehicle_no") && !xs(i("vehicle_no")) && l.push(`номер машины ${De(i("vehicle_no"))}: ${Dt(i("vehicle_no"))}`),
      i("trailer_no") && !zs(i("trailer_no")) && l.push(`номер прицепа ${De(i("trailer_no"))}: ${Dt(i("trailer_no"), 1)}`)),
    t === "term_counterparties")
  ) {
    const o = String(i("inn") || "").replace(/\D/g, "");
    o && !il(o) && l.push(`ИНН ${o} не проходит контрольную сумму`);
    const x = String(i("settle_account") || "").replace(/\D/g, "");
    (x && x.length !== 20 && l.push(`р/с введён не полностью: ${x.length} цифр из 20 — контрольный ключ по такому счёту не проверить`),
      i("settle_account") && i("bik") && !cn(i("settle_account"), i("bik")) && l.push("р/с не сходится с БИК по контрольному ключу"));
  }
  if (t === "term_line_containers") {
    i("container_no") && !ss(i("container_no")) && l.push(`номер контейнера ${i("container_no")} не проходит проверку ISO 6346`);
    const o = u("payload_kg"),
      x = u("max_gross_kg"),
      N = u("cont_tare_kg");
    o != null &&
      x != null &&
      N != null &&
      Math.abs(x - N - o) > 500 &&
      l.push(`паспорт не сходится: макс. гросс ${q(x)} − тара ${q(N)} ≠ payload ${q(o)}`);
  }
  return l;
}
function CAt({ title: t, fields: n, row: s, table: l, onClose: i, onDone: u }) {
  const [o, x] = S.useState(() =>
      Object.fromEntries(
        n.map(($) => [
          $.k,
          $.type === "bool" ? (s[$.k] ? "1" : "0") : $.type === "kg" ? (s[$.k] == null ? "" : Math.round(s[$.k] * 1e3)) : (s[$.k] ?? ""),
        ]),
      ),
    ),
    { list: N } = fs("surveyor"),
    { list: b } = fs("line"),
    j = n.some(($) => ["client", "supplier", "pc"].includes($.dict)),
    [g] = ne(
      () => (j ? Y(A.from("term_requests").select("client, supplier, purchase_contract").limit(3e3)) : Promise.resolve([])),
      [j],
      12e4,
      "hist.req",
    ),
    d = S.useCallback(
      ($) => {
        if ($.opts) return $.opts;
        if (!$.dict) return null;
        const m = g || [],
          v =
            $.dict === "surveyor"
              ? N
              : $.dict === "line"
                ? b
                : $.dict === "cargo"
                  ? Ft()
                  : $.dict === "country"
                    ? jn
                    : $.dict === "client"
                      ? m.map((U) => U.client)
                      : $.dict === "supplier"
                        ? m.map((U) => U.supplier)
                        : $.dict === "pc"
                          ? m.map((U) => U.purchase_contract)
                          : [];
        return Fe([...v, s[$.k]]).map((U) => [U, U]);
      },
      [N, b, g, s],
    ),
    [M, z] = S.useState(!1),
    [_, h] = S.useState(null),
    [w, p] = S.useState(!1),
    F = S.useMemo(() => {
      const $ = {};
      for (const m of n) {
        const v = o[m.k];
        $[m.k] =
          v === "" || v == null
            ? null
            : m.type === "num"
              ? te(String(v))
              : m.type === "kg"
                ? te(String(v)) == null
                  ? null
                  : te(String(v)) / 1e3
                : m.type === "bool"
                  ? v === "1" || v === !0 || v === "true"
                  : v;
      }
      return $;
    }, [o, n]),
    C = S.useMemo(() => Ii(l, s, F), [l, s, F]),
    y = async () => {
      var $;
      (z(!0), h(null));
      try {
        const m = {};
        for (const D of n) {
          let E = o[D.k];
          if (E === "" || E == null) m[D.k] = null;
          else if (D.type === "num") {
            if (((m[D.k] = te(String(E))), m[D.k] == null)) throw new Error(`«${D.t}» — нужно число`);
          } else if (D.type === "bool") m[D.k] = E === "1" || E === !0 || E === "true";
          else if (D.type === "kg") {
            const a = te(String(E));
            if (a == null) throw new Error(`«${D.t}» — нужно число`);
            m[D.k] = a / 1e3;
          } else m[D.k] = typeof E == "string" ? E.trim() : E;
          if (D.req && m[D.k] == null) throw new Error(`Поле «${D.t}» обязательно`);
        }
        const v = Di(l, s, m);
        if (v.length) throw new Error(v.join(" "));
        if (C.length && !w) throw new Error("Есть замечания — проверь значения или отметь подтверждение внизу");
        if (l === "term_container_loads" || l === "term_truck_visits") {
          const D = new Date().toISOString();
          for (const [E, a, f] of [
            ["gross_kg", "gross_at", "gross_by"],
            ["tare_kg", "tare_at", "tare_by"],
          ])
            E in m &&
              (m[E] != null && s[E] == null && (s[a] == null && (m[a] = D), s[f] == null && (m[f] = (($ = qt.me) == null ? void 0 : $.id) ?? null)),
              m[E] == null && s[E] != null && ((m[a] = null), (m[f] = null)));
        }
        const { data: U, error: Z } = await A.from(l).update(m).eq("id", s.id).select("id");
        if (Z) throw Z;
        if (!U || !U.length) throw new Error("Нет прав на изменение этой записи");
        const I = {};
        for (const D of n) {
          const E = s[D.k] ?? null,
            a = m[D.k] ?? null;
          String(E) !== String(a) &&
            (I[D.t] =
              D.type === "kg"
                ? {
                    было: E == null ? null : Math.round(E * 1e3),
                    стало: a == null ? null : Math.round(a * 1e3),
                  }
                : {
                    было: E,
                    стало: a,
                  });
        }
        (Object.keys(I).length &&
          (await je(
            l.replace("term_", ""),
            s.id,
            "edit",
            {
              ...I,
              продавлено: C.length ? C : void 0,
            },
            qt.me,
          )),
          u(),
          i());
      } catch (m) {
        (h(String(m.message || m)), z(!1));
      }
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={($) => {
        $.target === $.currentTarget && i();
      }}
    >
      <div
        className="modal"
        style={{
          width: 470,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">{t}</h2>
          <button className="btn sec sm" onClick={i}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <div className="fcol">
            {n.map(($) => (
              <X label={$.t + ($.req ? " *" : "")}>
                {d($) ? (
                  <CPe
                    value={o[$.k] ?? ""}
                    onChange={(m) =>
                      x((v) => ({
                        ...v,
                        [$.k]: m,
                      }))
                    }
                    options={d($)}
                    w={$.w || 170}
                    ph="—"
                  />
                ) : (
                  <input
                    className="g-in"
                    type={$.type === "date" ? "date" : "text"}
                    style={{
                      width: $.w || 170,
                    }}
                    value={o[$.k] ?? ""}
                    onChange={(m) =>
                      x((v) => ({
                        ...v,
                        [$.k]: m.target.value,
                      }))
                    }
                  />
                )}
              </X>
            ))}
          </div>
        </div>
        <div
          className="m-body"
          style={{
            paddingTop: 0,
          }}
        >
          <CYn warns={C} on={w} setOn={p} />
        </div>
        <div className="m-foot">
          <button className="btn" disabled={M || (C.length > 0 && !w)} onClick={y}>
            {M ? "Сохранение…" : "Сохранить изменения"}
          </button>
          <CFe err={_} />
        </div>
      </div>
    </div>
  );
}
const Vs = 25;
function C$n({ pend: t, setPend: n }) {
  return (
    <X label={`Вложения · ${t.length ? "выбрано " + t.length : "файлы и фото"}`}>
      <span
        className="row"
        style={{
          gap: 6,
          alignItems: "center",
        }}
      >
        <label
          className="btn sec sm"
          style={{
            cursor: "pointer",
          }}
        >
          📎 Выбрать файлы
          <input
            type="file"
            multiple={!0}
            style={{
              display: "none",
            }}
            onChange={(s) => {
              (n((l) => [...l, ...Array.from(s.target.files)]), (s.target.value = ""));
            }}
          />
        </label>
        <label
          className="btn sec sm"
          style={{
            cursor: "pointer",
          }}
        >
          📷 Фото
          <input
            type="file"
            accept="image/*"
            capture="environment"
            style={{
              display: "none",
            }}
            onChange={(s) => {
              (n((l) => [...l, ...Array.from(s.target.files)]), (s.target.value = ""));
            }}
          />
        </label>
        {t.length > 0 && (
          <button className="btn danger sm" onClick={() => n([])}>
            сбросить
          </button>
        )}
      </span>
      {t.length > 0 && (
        <span
          className="p-sub"
          style={{
            margin: "4px 0 0",
          }}
        >
          {t
            .map((s) => s.name)
            .join(" · ")
            .slice(0, 120)}
        </span>
      )}
    </X>
  );
}
const Cn = async (t, n, s, l) => {
  const i = [];
  for (const u of s)
    try {
      if (u.size > Vs * 1024 * 1024) throw new Error(`больше ${Vs} МБ`);
      await rl(t, n, u, l);
    } catch (o) {
      (console.error("вложение:", o), i.push(`${u.name}: ${o.message || o}`));
    }
  i.length &&
    alert(
      `Не удалось приложить файлы:
` +
        i.join(`
`) +
        `

Запись сохранена — приложи файлы ещё раз через скрепку.`,
    );
};
function Fi({ v: t, onClose: n, onDone: s }) {
  var j;
  const [l, i] = S.useState(() => ({
      ...(t.lab_extra || {}),
    })),
    [u, o] = S.useState(!1),
    [x, N] = S.useState(null),
    b = async () => {
      var g;
      (o(!0), N(null));
      try {
        const d = {};
        for (const [_, h] of ls) {
          const w = (l[_] ?? "").toString().trim();
          if (w === "") continue;
          const p = te(w);
          if (p == null) throw new Error(`«${h}» — нужно число (введено «${w}»)`);
          if (p < 0 || p > 100) throw new Error(`«${h}»: значение ${p} вне диапазона 0–100%`);
          d[_] = p;
        }
        ((l.note || "").trim() && (d.note = l.note.trim()),
          Object.keys(d).length && ((d._by = ((g = qt.me) == null ? void 0 : g.name) || ""), (d._at = new Date().toISOString())));
        const { data: M, error: z } = await A.from("term_truck_visits")
          .update({
            lab_extra: Object.keys(d).length ? d : null,
          })
          .eq("id", t.id)
          .select("id");
        if (z) throw z;
        if (!M.length) throw new Error("Нет прав на изменение");
        (await je(
          "visit",
          t.id,
          "lab_extra",
          {
            машина: t.vehicle_no,
            показателей: Object.keys(d).filter((_) => !_.startsWith("_")).length,
          },
          qt.me,
        ),
          s(),
          n());
      } catch (d) {
        (N(String(d.message || d)), o(!1));
      }
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={(g) => {
        g.target === g.currentTarget && n();
      }}
    >
      <div
        className="modal"
        style={{
          width: 470,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Доп. показатели · {t.vehicle_no}</h2>
          <button className="btn sec sm" onClick={n}>
            ✕
          </button>
        </div>
        <p
          className="p-sub"
          style={{
            marginBottom: 0,
          }}
        >
          заполняются по необходимости для культуры · пустые не сохраняются
        </p>
        <div className="m-body">
          <div className="fcol">
            {ls.map(([g, d]) => (
              <X label={d}>
                <input
                  value={l[g] ?? ""}
                  onChange={(M) =>
                    i((z) => ({
                      ...z,
                      [g]: M.target.value,
                    }))
                  }
                />
              </X>
            ))}
            {(j = t.lab_extra) != null && j._by ? (
              <p
                className="p-sub"
                style={{
                  margin: 0,
                }}
              >
                последнее изменение: {t.lab_extra._by} · {he(t.lab_extra._at)}
              </p>
            ) : null}
            <X label="Примечание">
              <input
                value={l.note ?? ""}
                onChange={(g) =>
                  i((d) => ({
                    ...d,
                    note: g.target.value,
                  }))
                }
              />
            </X>
          </div>
        </div>
        <div className="m-foot">
          <button className="btn" disabled={u} onClick={b}>
            {u ? "Сохранение…" : "Сохранить показатели"}
          </button>
          <CFe err={x} />
        </div>
      </div>
    </div>
  );
}
function CZi({ load: t, onClose: n, onDone: s }) {
  var M;
  const [l, i] = ne(() => Y(A.from("term_load_allocs").select("*").eq("load_id", t.id).order("id")), [t.id], 0),
    [u, o] = S.useState({}),
    [x, N] = S.useState(null),
    b = t.net_final_kg ?? t.net_kg,
    j = (l || []).reduce((z, _) => z + (+_.weight_kg || 0), 0),
    g = async () => {
      try {
        const z = (u.c || "").trim();
        if (!z) throw new Error("Укажи контракт продажи / партию");
        const _ = te(u.w);
        if (_ == null || _ <= 0) throw new Error("Укажи вес распределения, кг");
        if (b != null && j + _ > +b + 1)
          throw new Error(`Распределено будет ${q(j + _)} кг при нетто ${q(b)} кг — больше, чем в контейнере. Уменьши вес.`);
        const h = te(u.w);
        (await Y(
          A.from("term_load_allocs").insert({
            load_id: t.id,
            contract: z,
            weight_kg: h,
            marker: (u.m || "").trim() || null,
          }),
          "ins",
        ),
          o({}),
          N(null),
          i(),
          s && s());
      } catch (z) {
        N(String(z.message || z));
      }
    },
    d = async (z) => {
      try {
        (await ue(A.from("term_load_allocs").delete().eq("id", z.id), "распределение по контрактам"), i(), s && s());
      } catch (_) {
        N(String(_.message || _));
      }
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={(z) => {
        z.target === z.currentTarget && n();
      }}
    >
      <div
        className="modal"
        style={{
          width: 560,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Партии · {((M = t.term_line_containers) == null ? void 0 : M.container_no) || "контейнер"}</h2>
          <button className="btn sec sm" onClick={n}>
            ✕
          </button>
        </div>
        <p
          className="p-sub"
          style={{
            marginBottom: 0,
          }}
        >
          распределение веса затарки по контрактам продажи · нетто {q(b)} кг · распределено {q(j)} кг{b != null && j > +b ? " — больше нетто!" : ""}
        </p>
        <div
          className="row"
          style={{
            marginTop: 10,
            gap: 6,
          }}
        >
          <X label="Контракт / партия *">{Se(u, o, "c", "RHL00…", 150)}</X>
          <X label="Вес, кг">{Se(u, o, "w", "", 110)}</X>
          <X label="Маркер">{Se(u, o, "m", "Т", 70)}</X>
          <button className="btn sm" onClick={g}>
            + Добавить
          </button>
        </div>
        <CFe err={x} />
        <div className="m-body">
          <table>
            <thead>
              <tr>
                <th>Контракт</th>
                <th className="right">Вес, кг</th>
                <th>Маркер</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {(l || []).map((z) => (
                <tr>
                  <td>
                    <b>{z.contract}</b>
                  </td>
                  <td className="right">{q(z.weight_kg)}</td>
                  <td>{z.marker || "—"}</td>
                  <td>
                    <Jt onClick={() => d(z)} />
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}
function Un({ load: t, cont: n, onClose: s, onDone: l, me: i }) {
  const u = t ? t.term_line_containers || {} : n || {},
    o = (t && +t.dotare_kg) || 0,
    [x, N] = S.useState(t ? "add" : "take"),
    [b, j] = S.useState(""),
    [g, d] = S.useState(""),
    [M, z] = S.useState(""),
    [_, h] = S.useState(""),
    [w, p] = S.useState(!1),
    [F, C] = S.useState(!1),
    [y, $] = S.useState(null),
    m = ot.S || {},
    v = Oe(m, "dotare_warn"),
    U = Oe(m, "dotare_max"),
    Z = u,
    I = te(String(b)),
    D = te(String(g)),
    E = I != null && D != null ? Math.abs(D - I) : (te(String(M)) ?? null),
    a = E == null ? null : x === "take" ? -E : E,
    f = t ? (+t.net_kg || 0) + o : +u.temp_kg || 0,
    P = a == null ? f : f + a,
    T = async () => {
      if (E == null) {
        $("Введи тару и брутто машины — или впиши вес операции вручную");
        return;
      }
      if (E <= 0) {
        $("Вес операции должен быть больше нуля");
        return;
      }
      if (U > 0 && E > U) {
        $(`${x === "take" ? "Растарка" : "Дотарка"} ${q(E)} кг больше предела ${q(U)} кг. Предел меняется в настройках терминала.`);
        return;
      }
      const H = [];
      if (
        (v > 0 && E > v && H.push(`${x === "take" ? "растарка" : "дотарка"} ${q(E)} кг выше обычной (${q(v)} кг)`),
        P < 0 && H.push(`в контейнере останется ${q(P)} кг — забрали больше, чем в нём было (${q(f)} кг)`),
        x === "add" && Z.payload_kg != null && P > +Z.payload_kg && H.push(`перегруз: станет ${q(P)} кг при полезной нагрузке ${q(Z.payload_kg)} кг`),
        H.length && !w)
      ) {
        $(`${H.join("; ")}. Проверь ввод — или отметь «подтверждаю».`);
        return;
      }
      (C(!0), $(null));
      try {
        const Q = {
          контейнер: Z.container_no,
          вес: E,
          "было в контейнере": f,
          стало: P,
          "по взвешиваниям": I != null && D != null ? `тара ${I} · брутто ${D}` : void 0,
          продавлено: H.length ? H : void 0,
        };
        if (t) {
          const ae = {
              dotare_kg: o + a,
            },
            { data: me, error: L } = await A.from("term_container_loads").update(ae).eq("id", t.id).select("id");
          if (L) throw L;
          if (!me.length) throw new Error("Нет прав");
          (t.is_temp &&
            t.container_id &&
            (await ue(
              A.from("term_line_containers")
                .update({
                  temp_kg: Math.max(0, P),
                })
                .eq("id", t.container_id),
              "остаток времянки",
            )),
            await je("load", t.id, x === "take" ? "rastarka" : "dotarka", Q, i || qt.me));
        } else {
          const ae = {
            temp_kg: Math.max(0, P),
            state: "temp",
          };
          (!u.cargo && (_ || "").trim() && (ae.cargo = _.trim()),
            await ue(A.from("term_line_containers").update(ae).eq("id", u.id), "остаток времянки " + (u.container_no || "")),
            await je(
              "container",
              u.id,
              x === "take" ? "rastarka" : "dotarka",
              {
                ...Q,
                "без приходной затарки": !0,
              },
              i || qt.me,
            ));
        }
        (l(), s());
      } catch (Q) {
        ($(String(Q.message || Q)), C(!1));
      }
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={(H) => {
        H.target === H.currentTarget && s();
      }}
    >
      <div
        className="modal"
        style={{
          minWidth: 420,
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Дотарка / растарка · {Z.container_no || ""}</h2>
          <button className="btn sec sm" onClick={s}>
            ✕
          </button>
        </div>
        <p
          className="p-sub"
          style={{
            marginBottom: 0,
          }}
        >
          вес операции считает система: тара и брутто той машины, что досыпала или забрала · «нетто финал» показывает, сколько в контейнере сейчас ·
          пороги — в настройках терминала
        </p>
        <div className="m-body">
          <div className="fcol">
            {t ? null : (
              <div
                className="ordinfo"
                style={{
                  marginTop: 0,
                }}
              >
                У контейнера нет приходной затарки в системе — операция ляжет прямо в остаток карточки и в журнал изменений.
              </div>
            )}
            <X label="Операция">
              <CPe
                value={x}
                onChange={N}
                w={260}
                ph="—"
                options={[
                  ["add", "Дотарка — досыпали в контейнер"],
                  ["take", "Растарка — забрали из контейнера"],
                ]}
              />
            </X>
            {!t && !u.cargo ? (
              <X label="Культура во времянке">
                <Wt w={220} ph="— культура —" options={Ft()} addTitle="Культуры нет в списке" addPrompt="Культура:" value={_} onChange={h} />
              </X>
            ) : null}
            <div
              className="row"
              style={{
                gap: 8,
              }}
            >
              <X label="Тара машины, кг">
                <input
                  className="g-in"
                  inputMode="numeric"
                  style={{
                    width: 120,
                  }}
                  value={b}
                  onChange={(H) => j(H.target.value)}
                />
              </X>
              <X label="Брутто машины, кг">
                <input
                  className="g-in"
                  inputMode="numeric"
                  style={{
                    width: 120,
                  }}
                  value={g}
                  onChange={(H) => d(H.target.value)}
                />
              </X>
            </div>
            {(I == null || D == null) && (
              <X label="…или вес операции вручную, кг">
                <input
                  className="g-in"
                  inputMode="numeric"
                  style={{
                    width: 160,
                  }}
                  value={M}
                  onChange={(H) => z(H.target.value)}
                />
              </X>
            )}
            <div className="ordinfo">
              Вес операции: <b>{E == null ? "—" : q(a)}</b> кг · было в контейнере <b>{q(f)}</b> кг · станет <b>{q(P)}</b> кг
              {o ? (
                <div
                  className="faint"
                  style={{
                    fontSize: 11,
                  }}
                >
                  ранее уже учтено дотарок/растарок на {q(o)} кг
                </div>
              ) : null}
            </div>
            <div
              className="faint"
              style={{
                fontSize: 11,
              }}
            >
              обычная операция до {q(v)} кг · предел {q(U)} кг
            </div>
            <label className="fkey">
              <input type="checkbox" checked={w} onChange={(H) => p(H.target.checked)} /> подтверждаю отклонение
            </label>
          </div>
        </div>
        <div className="m-foot">
          <button className="btn" disabled={F} onClick={T}>
            {F ? "…" : "Сохранить"}
          </button>
          <CFe err={y} />
        </div>
      </div>
    </div>
  );
}
function Mn({ title: t, onClose: n, file: s, children: l }) {
  return (
    <CDt title={t} onClose={n} file={s}>
      <div className="pdoc">{l}</div>
    </CDt>
  );
}
function CJl({ c: t, load: n }) {
  const s = t.cont_tare_kg,
    l = n ? (n.net_final_kg ?? n.net_kg) : null,
    i = l != null && s != null ? +l + +s : null;
  return (
    <>
      <C_e done={!0} title={`Справка о подтверждённой массе контейнера (VGM) · ${t.container_no}`}>
        <div className="dgrid">
          <R l="Контейнер" v={t.container_no} />
          <R l="Тип" v={t.size ? `${t.size}' ${t.height || ""}` : null} />
          <R l="Линия" v={t.line} />
          <R l="Букинг" v={t.booking} />
          <R l="Клиент" v={t.client || (n == null ? void 0 : n.culture)} />
          <R l="Груз" v={t.cargo || (n == null ? void 0 : n.culture)} />
          <R l="Пломба" v={t.seal_no} />
          <R l="Тара контейнера (табличка), кг" v={q(s)} />
          <R l="Нетто груза, кг" v={q(l)} />
          <R l="Метод" v="Метод 2 (расчётный)" />
        </div>
      </C_e>
      <C_e done={!0} title={`VGM · ${i != null ? q(i) + " кг" : "нет данных"}`}>
        <div className="dgrid">
          <R l="Дата взвешивания" v={n ? he(n.gross_at) : "—"} />
          <R l="Подпись ответственного" v="__________________" />
        </div>
      </C_e>
    </>
  );
}
function Ri({ c: t, load: n, onClose: s }) {
  return (
    <Mn title={`Справка VGM · ${t.container_no}`} onClose={s} file={st("VGM", t.container_no, t.line, t.booking ? "букинг-" + t.booking : "")}>
      <CJl c={t} load={n} />
    </Mn>
  );
}
function Li({ b: t, items: n, onClose: s }) {
  return (
    <Mn
      title={`Справки VGM · партия ${t.batch_no} · ${n.length} конт.`}
      onClose={s}
      file={st("VGM", "партия-" + t.batch_no, t.booking ? "букинг-" + t.booking : "", n.length + "-конт")}
    >
      {n.map(({ c: l, load: i }, u) => (
        <div className={u < n.length - 1 ? "pbreak" : void 0}>
          <CJl c={l} load={i} />
        </div>
      ))}
    </Mn>
  );
}
const Ai = [
  [
    "1. Общие положения",
    [
      "1.1. Настоящая Инструкция устанавливает единый порядок допуска, движения и регистрации сторонних автотранспортных средств, доставляющих сельскохозяйственную продукцию на территорию терминала.",
      "1.2. Инструкция обязательна для исполнения: водителями стороннего автотранспорта; сотрудниками охраны (проходной); операторами приёмки и диспетчерами; ответственными лицами производственных зон терминала.",
      "1.3. Заезд, перемещение и выгрузка сторонних автомобилей на территории терминала допускаются исключительно при соблюдении требований настоящей Инструкции.",
    ],
  ],
  [
    "2. Прибытие водителя и регистрация на стоянке «Зерновой Оператор № 2» (Объездная, ст. Раевская, г.о. Новороссийск · координаты 44.839771, 37.585578)",
    [
      "2.1. При прибытии на стоянку водитель должен позвонить по телефону +7 988 387-47-28 для регистрации.",
      "2.2. Водитель сообщает по телефону: вид сельскохозяйственной культуры; государственный регистрационный номер транспортного средства и прицепа (при наличии); фамилию, имя, отчество водителя.",
      "2.3. Сотрудник терминала: фиксирует сведения в Журнале регистрации автотранспорта; проверяет наличие разрешения на приём заявленной культуры; при необходимости подтверждает допуск приёмки.",
      "2.4. После подтверждения допуска водитель едет на терминал (ул. Раевская, 2): выдаётся временный пропуск на въезд; доводится маршрут движения по территории; указывается зона ожидания либо зона выгрузки.",
    ],
  ],
  [
    "3. Въезд на территорию и движение по маршруту",
    [
      "3.1. Въезд на территорию терминала осуществляется строго по временному пропуску.",
      "3.2. Водитель обязан: следовать исключительно по указанному маршруту движения; соблюдать установленный скоростной режим; выполнять указания сотрудников терминала.",
      "3.3. На территории терминала запрещается: самовольное изменение маршрута движения; заезд в производственные и технологические зоны без разрешения; выход из кабины транспортного средства без указания ответственного лица.",
    ],
  ],
  [
    "4. Регистрация на выгрузку",
    [
      "4.1. По прибытии в зону выгрузки водитель обязан остановить транспортное средство в указанном месте и передать временный пропуск оператору или ответственному лицу зоны.",
      "4.2. Оператор приёмки: сверяет сведения о грузе (культура, грузоотправитель); регистрирует транспортное средство в Журнале выгрузки; определяет очерёдность выгрузки.",
      "4.3. До получения разрешения на выгрузку водитель обязан находиться в кабине транспортного средства либо в зоне ожидания.",
    ],
  ],
  [
    "5. Процесс выгрузки",
    [
      "5.1. Выгрузка осуществляется исключительно по команде оператора приёмки или ответственного сотрудника терминала.",
      "5.2. Во время выгрузки водитель обязан: соблюдать требования охраны труда и промышленной безопасности; выполнять указания персонала терминала; не вмешиваться в работу технологического оборудования.",
      "5.3. При выявлении несоответствий по грузу (культура, качество, засорённость и иные параметры) выгрузка может быть приостановлена либо отменена до принятия решения ответственным лицом.",
    ],
  ],
  [
    "6. Выезд с территории терминала",
    [
      "6.1. По завершении выгрузки водитель обязан: вернуть временный пропуск сотруднику охраны; получить разрешение на выезд с территории терминала.",
      "6.2. Выезд осуществляется по установленному маршруту без остановок в производственных зонах.",
    ],
  ],
  [
    "7. Ответственность",
    [
      "7.1. Водители, нарушившие требования настоящей Инструкции, могут быть отстранены от выгрузки и лишены допуска на территорию терминала.",
      "7.2. Сотрудники терминала несут ответственность за соблюдение настоящей Инструкции в рамках своих должностных обязанностей.",
    ],
  ],
];
function Bi({ r: t, onClose: n, onSaved: s }) {
  const [l, i] = S.useState({
      no: String(t.id || ""),
      unload: "",
      pass: "",
    }),
    [u, o] = S.useState(() => new Date()),
    x = (d) => d.toLocaleDateString("ru-RU"),
    N = (d) =>
      d.toLocaleTimeString("ru-RU", {
        hour: "2-digit",
        minute: "2-digit",
      }),
    b = t.t2_at ? new Date(t.t2_at) : null,
    j = async () => {
      (o(new Date()),
        await Y(
          A.rpc("term_req_op", {
            p_id: t.id,
            p_op: "pass",
            p_a: (l.no || "").trim(),
            p_b: (l.unload || "").trim(),
            p_c: (l.pass || "").trim(),
          }),
        ),
        s && s(),
        await new Promise((d) => setTimeout(d, 80)));
    };
  return (
    <CDt
      title={`Автопропуск · ${t.vehicle_no || ""}`}
      onClose={n}
      pages=".pdoc"
      beforePdf={j}
      file={st("Автопропуск", t.vehicle_no, t.client, l.no ? "№" + l.no : "")}
    >
      <div
        className="row no-print"
        style={{
          gap: 8,
          marginBottom: 10,
        }}
      >
        <X label="№ пропуска">
          <input
            style={{
              width: 90,
              minWidth: 90,
            }}
            value={l.no}
            onChange={(d) =>
              i((M) => ({
                ...M,
                no: d.target.value,
              }))
            }
          />
        </X>
        <X label="Вид выгрузки">
          <CPe
            value={l.unload}
            onChange={(d) =>
              i((M) => ({
                ...M,
                unload: d,
              }))
            }
            options={["Боковая", "Задняя", "Самосвал", "Бок", "Мешки"]}
            w={140}
            ph="—"
          />
        </X>
        <X label="Паспорт / клиент">
          <input
            style={{
              width: 320,
              minWidth: 200,
            }}
            placeholder="серия, №, кем и когда выдан"
            value={l.pass}
            onChange={(d) =>
              i((M) => ({
                ...M,
                pass: d.target.value,
              }))
            }
          />
        </X>
      </div>
      <div className="pdoc pass9">
        <div className="plogo9">
          <img src="/logo-side.png" alt="ФЕНИКС" />
        </div>
        <div className="ph1">ЗЕРНОВОЙ ОПЕРАТОР</div>
        <div className="ph2">ДОКУМЕНТЫ - ТТН И ПРОПУСК ЗАНЕСТИ НА ВЕСОВУЮ</div>
        <div className="ph3">ВРЕМЕННЫЙ АВТОПРОПУСК № {l.no || "__"}</div>
        <div className="pgrid">
          <div className="prow p2">
            <div className="pl">Хозяйство</div>
            <div className="pv">{t.supplier || ""}</div>
          </div>
          <div className="prow p2">
            <div className="pl">ФИО / Тел</div>
            <div className="pv">{[t.driver, t.driver_phone].filter(Boolean).join(" / ")}</div>
          </div>
          <div className="prow p2">
            <div className="pl">ГОС № / Прицеп</div>
            <div className="pv">{[t.vehicle_no, t.trailer_no].filter(Boolean).join(" / ")}</div>
          </div>
          <div className="prow p2">
            <div className="pl">Груз / Вес, т</div>
            <div className="pv">
              {[t.culture, t.planned_tonnes != null ? String(t.planned_tonnes).replace(".", ",") + " т" : null].filter(Boolean).join(" / ")}
            </div>
          </div>
          <div className="prow p2">
            <div className="pl">Вид выгрузки</div>
            <div className="pv">{l.unload}</div>
          </div>
          <div className="prow">
            <div className="pl">Дата прихода {b ? "(отстойник Т2)" : ""}</div>
            <div className="pv">{x(b || u)}</div>
            <div className="pt">Время · {N(b || u)}</div>
          </div>
          <div className="prow tall">
            <div className="pl">Дата заезда Зерновой 1</div>
            <div className="pv">{x(u)}</div>
            <div className="pt">Время · {N(u)}</div>
          </div>
          <div className="prow tall">
            <div className="pl">Отметка о выезде Зерновой 1</div>
            <div className="pv" />
            <div className="pt">Время</div>
          </div>
          <div className="prow p2">
            <div className="pl">Паспорт / клиент</div>
            <div
              className="pv"
              style={{
                fontWeight: 500,
              }}
            >
              {l.pass}
            </div>
          </div>
        </div>
        <div className="pmemo">{`Памятка для водителей транспортных средств, въезжающих на территорию ООО «Зерновой Оператор»

Запрещается:
- нахождение несовершеннолетних лиц на территории;
- проносить или провозить оружие, боеприпасы, взрывчатые и ядовитые вещества, наркотические средства;
- проносить, провозить и распивать спиртные напитки;
- передвигаться со скоростью более 10 км/ч. Соблюдать правила дорожного движения;
- передвигаться по территории без технологической необходимости и покидать транспортное средство;
- самостоятельно посещать зоны погрузки;
- заходить на площадки хранения новых автомобилей;
- передвигаться по платформе без технологической необходимости.

Правила поведения при выгрузке:
- на автомобильной платформе могут находиться только персонал, задействованный на технологической операции;
- без разрешения оператора не разблокировать устройство запора откидного борта;
- не находиться на трапах автомобильной платформы напротив борта с разблокированным запором откидного борта;
- не разблокировать устройство запора откидного борта без надобности.

При открытии борта работники находятся со стороны торцов борта во избежание удара падающим бортом.

В случае нарушения установленного порядка пребывания на территории ООО «Зерновой Оператор» действие пропуска может быть приостановлено.`}</div>
        <div className="pfoot">
          <div className="pl">ФИО</div>
          <div className="pstamp">
            Пропуск сформирован: {x(u)}, {N(u)}
          </div>
          <div className="pl pbl">Подпись</div>
        </div>
      </div>
      <div className="pdoc pass9 pinstr">
        <div className="plogo9 sm">
          <img src="/logo-side.png" alt="ФЕНИКС" />
        </div>
        <div className="pi-t">ИНСТРУКЦИЯ</div>
        <div className="pi-s">
          по заезду сторонних автомобилей с сельскохозяйственной продукцией на территорию терминала и регистрации на выгрузку
        </div>
        {Ai.map(([d, M]) => (
          <div className="pi-sec">
            <div className="pi-h">{d}</div>
            {M.map((z, _) => (
              <div className="pi-p">{z}</div>
            ))}
          </div>
        ))}
        <div className="pi-f">ООО «Зерновой Оператор» · терминал, ул. Раевская, 2 · регистрация на стоянке № 2: +7 988 387-47-28</div>
      </div>
    </CDt>
  );
}
function Pi({ v: t, onClose: n }) {
  return (
    <Mn title={`ТТН (зерно) · ${t.vehicle_no}`} onClose={n} file={st("ТТН", t.vehicle_no, t.client, t.culture)}>
      <C_e done={!0} title="Товарно-транспортная накладная · зерно">
        <div className="dgrid">
          <R l="Дата" v={he(t.in_at)} />
          <R l="Грузоотправитель" v={t.supplier} />
          <R l="Грузополучатель" v={t.client} />
          <R l="Контракт закупки" v={t.purchase_contract} />
          <R l="Культура" v={t.culture} />
        </div>
      </C_e>
      <C_e done={!0} title="Транспорт">
        <div className="dgrid">
          <R l="Автомобиль" v={t.vehicle_no} />
          <R l="Прицеп" v={t.trailer_no} />
          <R l="Водитель" v={t.driver} />
          <R l="Телефон" v={t.driver_phone} />
        </div>
      </C_e>
      <C_e done={!0} title="Взвешивание">
        <div className="dgrid">
          <R l="Брутто, кг" v={q(t.gross_kg)} />
          <R l="Тара, кг" v={q(t.tare_kg)} />
          <R l="Нетто, кг" v={q(t.net_kg)} />
          <R l="Место выгрузки" v={t.unload_place} />
        </div>
      </C_e>
      <C_e done={!0} title="Подписи">
        <div className="dgrid">
          <R l="Сдал (водитель)" v="__________________" />
          <R l="Принял (весовая)" v="__________________" />
        </div>
        <p
          className="p-sub"
          style={{
            margin: "8px 0 0",
          }}
        >
          упрощённая печатная форма системы · для госформы СП-31 приложите образец — приведём 1:1
        </p>
      </C_e>
    </Mn>
  );
}
const gl = nt.createContext(!1);
function CDt({ title: t, badge: n, onClose: s, pages: l, beforePdf: i, wide: u, cls: o, file: x, foot: N, children: b }) {
  const j = S.useRef(null),
    [g, d] = S.useState(!1),
    [M, z] = S.useState(!1),
    _ = async () => {
      d(!0);
      try {
        (z(!0), await new Promise((I) => setTimeout(I, 60)), i && (await i()));
        const [h, w] = await Promise.all([import("html2canvas"), import("jspdf")]),
          p = h.default || h,
          F = w.jsPDF || (w.default && w.default.jsPDF) || w.default,
          C = j.current,
          y = new F("p", "mm", "a4"),
          $ = 210,
          m = 297,
          v = 8,
          U = $ - v * 2,
          Z = m - v * 2;
        C.classList.add("snap");
        try {
          if (l) {
            const I = [...C.querySelectorAll(l)];
            for (let D = 0; D < I.length; D++) {
              const E = await p(I[D], {
                backgroundColor: "#ffffff",
                scale: 2,
                useCORS: !0,
                windowWidth: Math.max(C.scrollWidth, 720),
              });
              D > 0 && y.addPage();
              const a = Math.min(U / E.width, Z / E.height);
              y.addImage(E.toDataURL("image/jpeg", 0.92), "JPEG", v, v, E.width * a, E.height * a);
            }
          } else {
            const I = await p(C, {
                backgroundColor: "#ffffff",
                scale: 2,
                useCORS: !0,
                windowWidth: Math.max(C.scrollWidth, 720),
              }),
              D = U / I.width,
              E = Math.floor((m - v * 2) / D);
            let a = 0,
              f = 0;
            for (; a < I.height;) {
              const P = Math.min(E, I.height - a),
                T = document.createElement("canvas");
              ((T.width = I.width),
                (T.height = P),
                T.getContext("2d").drawImage(I, 0, a, I.width, P, 0, 0, I.width, P),
                f > 0 && y.addPage(),
                y.addImage(T.toDataURL("image/jpeg", 0.92), "JPEG", v, v, U, P * D),
                (a += P),
                f++);
            }
          }
        } finally {
          C.classList.remove("snap");
        }
        y.save(x || st(t));
      } catch (h) {
        (console.error(h), alert("Ошибка PDF: " + (h.message || h)));
      }
      (z(!1), d(!1));
    };
  return (
    <div
      className="modal-bg doc9"
      onMouseDown={(h) => {
        h.target === h.currentTarget && s();
      }}
    >
      <div
        className={"modal" + (u ? " wide9" : "") + (o ? " " + o : "")}
        ref={j}
        style={{
          width: 700,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <span
            className="row"
            style={{
              gap: 10,
              alignItems: "center",
              minWidth: 0,
            }}
          >
            <img className="pdf-logo" src="/logo-side.png" alt="ФЕНИКС" />
            <h2 className="p-title mt0">
              {t} {n}
            </h2>
          </span>
          <span
            className="row no-print"
            style={{
              gap: 6,
            }}
          >
            <button className="btn sec sm" disabled={g} onClick={_}>
              {g ? "Готовлю…" : "⇩ PDF"}
            </button>
            <button className="btn sec sm" onClick={s}>
              ✕
            </button>
          </span>
        </div>
        <div
          className="m-body"
          style={{
            paddingRight: 4,
          }}
        >
          <gl.Provider value={M}>{b}</gl.Provider>
        </div>
        {N ? (
          <div
            className="m-body no-print"
            style={{
              paddingTop: 0,
            }}
          >
            {N}
          </div>
        ) : null}
      </div>
    </div>
  );
}
function Vi() {
  const [t] = ne(
    () => {
      const n = ot.S || {};
      return Y(
        A.rpc("term_stuck", {
          p_lab_h: +Oe(n, "stuck_lab_h") || 2,
          p_unload_h: +Oe(n, "stuck_unload_h") || 4,
          p_tare_h: +Oe(n, "stuck_tare_h") || 6,
          p_cont_d: +Oe(n, "stuck_cont_d") || 30,
          p_cap: 0,
        }),
      );
    },
    [],
    12e4,
    "stuck9",
  );
  return S.useMemo(() => {
    const n = {};
    for (const s of t || []) {
      const l = s.kind + ":" + s.entity_id;
      (n[l] = n[l] || []).push(s);
    }
    return n;
  }, [t]);
}
const Hi = (t) => {
    const n = Math.max(0, +t || 0);
    if (n < 90) return `${Math.round(n)} мин`;
    const s = n / 60;
    return s < 48 ? `${Math.round(s)} ч` : `${Math.round(s / 24)} дн`;
  },
  Ys = ({ kind: t, id: n }) => {
    const l = Vi()[t + ":" + n] || [];
    return l.length ? (
      <div className="stuck9">
        <div className="s9-t">⚠ Просрочено · {l.length === 1 ? "одна причина" : `причин ${l.length}`}</div>
        {l.map((i, u) => (
          <div className="s9-r">
            <b>{i.what}</b>
            <span>
              {Hi(i.mins)}
              {i.extra ? " · " + i.extra : ""}
            </span>
          </div>
        ))}
      </div>
    ) : null;
  },
  C_e = ({ done: t, skip: n, title: s, extra: l, children: i }) => (
    <div className={"dsec" + (t ? " done" : "") + (n ? " skip" : "")}>
      <div className="t">
        <span className="dot9" />
        {s}
        {l ? <span className="t-x">{l}</span> : null}
      </div>
      {i}
    </div>
  ),
  R = ({ l: t, v: n }) => {
    const s = n === "" || n == null ? "—" : n;
    return (
      <div className="dv">
        <span>{t}</span>
        <b>{s}</b>
      </div>
    );
  };
function Ui({ v: t, me: n, onSaved: s }) {
  const [l, i] = S.useState(() => ({
      m: t.lab_moisture ?? "",
      i: t.lab_impurity ?? "",
      b: t.lab_broken ?? "",
      g: t.lab_grain_adm ?? "",
      rt: t.lab_result_text ?? "",
      note: (t.lab_extra || {}).note ?? "",
      r1: t.lab_result1 || "",
      st: t.lab_status || "pending",
      ex: Object.fromEntries(ls.map(([p]) => [p, (t.lab_extra || {})[p] ?? ""])),
    })),
    [u, o] = S.useState(!1),
    [x, N] = S.useState(!1),
    [b, j] = S.useState(null),
    [g] = ne(() => Y(A.from("term_culture_norms").select("*")), [], 3e5, "norms"),
    d = (g || []).find(
      (p) =>
        (p.culture || "").trim().toLowerCase() ===
        String(t.culture || "")
          .trim()
          .toLowerCase(),
    ),
    M = (p, F) =>
      i((C) => ({
        ...C,
        [p]: F,
      })),
    z = (p, F) =>
      i((C) => ({
        ...C,
        ex: {
          ...C.ex,
          [p]: F,
        },
      })),
    _ = S.useMemo(() => {
      const p = [];
      for (const [F, C] of [
        [te(l.m), "Влажность"],
        [te(l.i), "Сорность"],
        [te(l.b), "Колотые/битые"],
        [te(l.g), "Зерновая примесь"],
      ])
        F != null && (F < 0 || F > 100) && p.push(`${C}: значение вне 0–100%`);
      return (
        l.st === "passed" &&
          (l.r1 || p.push("не выбран путь груза (результат 1)"),
          te(l.m) == null && te(l.i) == null && te(l.b) == null && te(l.g) == null && p.push("не введён ни один показатель качества"),
          d &&
            (te(l.m) != null &&
              d.moisture_max != null &&
              te(l.m) > +d.moisture_max &&
              p.push(`влажность ${te(l.m)}% выше нормы для «${t.culture}» (${d.moisture_max}%)`),
            te(l.i) != null && d.impurity_max != null && te(l.i) > +d.impurity_max && p.push(`сорность ${te(l.i)}% выше нормы (${d.impurity_max}%)`),
            te(l.b) != null && d.broken_max != null && te(l.b) > +d.broken_max && p.push(`колотые/битые ${te(l.b)}% выше нормы (${d.broken_max}%)`),
            te(l.g) != null &&
              d.grain_adm_max != null &&
              te(l.g) > +d.grain_adm_max &&
              p.push(`зерновая примесь ${te(l.g)}% выше нормы (${d.grain_adm_max}%)`))),
        l.st === "rejected" && !(l.rt || "").trim() && p.push("отказ без текста причины"),
        p
      );
    }, [l, d, t.culture]),
    h = () => {
      if (!d) {
        j({
          err: `Для культуры «${t.culture || "—"}» нормы не заданы — их ведёт лаборатория в настройках`,
        });
        return;
      }
      i((p) => ({
        ...p,
        m: String(d.moisture_max ?? ""),
        i: String(d.impurity_max ?? ""),
        b: String(d.broken_max ?? ""),
        g: String(d.grain_adm_max ?? ""),
      }));
    },
    w = async () => {
      if (_.length && !u) {
        j({
          err: `${_.join("; ")}. Проверь ввод — или отметь «подтверждаю».`,
        });
        return;
      }
      (N(!0), j(null));
      try {
        const p = {};
        for (const [y] of ls) {
          const $ = String(l.ex[y] ?? "").trim();
          $ && (p[y] = $);
        }
        (l.note || "").trim() && (p.note = (l.note || "").trim());
        const F = {
          lab_status: l.st,
          lab_moisture: te(l.m),
          lab_impurity: te(l.i),
          lab_broken: te(l.b),
          lab_grain_adm: te(l.g),
          lab_result_text: (l.rt || "").trim() || null,
          lab_extra: Object.keys(p).length ? p : null,
          lab_result1: (l.st === "passed" && l.r1) || null,
        };
        (l.st === "passed" || l.st === "rejected"
          ? ((F.lab_at = new Date().toISOString()), (F.lab_by = n.id))
          : ((F.lab_at = null), (F.lab_by = null)),
          await ue(A.from("term_truck_visits").update(F).eq("id", t.id), "машина " + t.vehicle_no));
        const C = {};
        for (const [y, $] of [
          ["lab_status", "Решение"],
          ["lab_moisture", "Влажность"],
          ["lab_impurity", "Сорность"],
          ["lab_broken", "Колотые/битые"],
          ["lab_grain_adm", "Зерновая примесь"],
          ["lab_result1", "Путь груза"],
          ["lab_result_text", "Показатели (текст)"],
        ])
          String(t[y] ?? "") !== String(F[y] ?? "") &&
            (C[$] = {
              было: t[y] ?? null,
              стало: F[y] ?? null,
            });
        (JSON.stringify(t.lab_extra || {}) !== JSON.stringify(p) &&
          (C["Доп. показатели"] = {
            было: t.lab_extra || null,
            стало: Object.keys(p).length ? p : null,
          }),
          await je(
            "visit",
            t.id,
            "lab_card_save",
            {
              машина: t.vehicle_no,
              ...C,
              продавлено: _.length ? _ : void 0,
            },
            n,
          ),
          j({
            ok: "Результаты сохранены",
          }),
          N(!1),
          s && s());
      } catch (p) {
        (j({
          err: String(p.message || p),
        }),
          N(!1));
      }
    };
  return (
    <div
      className="dsec no-print"
      style={{
        marginTop: 10,
      }}
    >
      <div className="t">
        <span className="dot9" />
        Лаборатория · внести результаты
      </div>
      <p
        className="p-sub"
        style={{
          margin: "0 0 6px",
        }}
      >
        пустое поле означает «не мерили» · нормы для «{t.culture || "—"}»:{" "}
        {d
          ? `влажность ≤${d.moisture_max ?? "—"} · сорность ≤${d.impurity_max ?? "—"} · кол/бит ≤${d.broken_max ?? "—"} · зерновая ≤${d.grain_adm_max ?? "—"}`
          : "не заданы"}
      </p>
      <div
        className="row"
        style={{
          gap: 8,
        }}
      >
        <X label="Решение">
          <CPe
            value={l.st}
            onChange={(p) => M("st", p)}
            w={150}
            ph="—"
            options={[
              ["pending", "В очереди"],
              ["passed", "Одобрен"],
              ["rejected", "Отказ"],
            ]}
          />
        </X>
        {l.st === "passed" && (
          <X label="Путь груза">
            <CPe value={l.r1} onChange={(p) => M("r1", p)} w={160} ph="— выбрать —" options={Object.entries(Le)} />
          </X>
        )}
        <X label="Влажность, %">
          <input
            className="g-in"
            inputMode="decimal"
            style={{
              width: 90,
            }}
            value={l.m}
            onChange={(p) => M("m", p.target.value)}
          />
        </X>
        <X label="Сорность, %">
          <input
            className="g-in"
            inputMode="decimal"
            style={{
              width: 90,
            }}
            value={l.i}
            onChange={(p) => M("i", p.target.value)}
          />
        </X>
        <X label="Колотые/битые, %">
          <input
            className="g-in"
            inputMode="decimal"
            style={{
              width: 90,
            }}
            value={l.b}
            onChange={(p) => M("b", p.target.value)}
          />
        </X>
        <X label="Зерновая примесь, %">
          <input
            className="g-in"
            inputMode="decimal"
            style={{
              width: 90,
            }}
            value={l.g}
            onChange={(p) => M("g", p.target.value)}
          />
        </X>
        <button className="btn sec sm" onClick={h} title="Подставить значения «в норме» по культуре">
          ≡ по норме
        </button>
      </div>
      <div
        className="row"
        style={{
          gap: 8,
          marginTop: 6,
        }}
      >
        {ls.map(([p, F]) => (
          <X label={F}>
            <input
              className="g-in"
              inputMode="decimal"
              style={{
                width: 82,
              }}
              value={l.ex[p]}
              onChange={(C) => z(p, C.target.value)}
            />
          </X>
        ))}
      </div>
      <div
        className="row"
        style={{
          gap: 8,
          marginTop: 6,
        }}
      >
        <X label="Показатели (текст)">
          <input
            className="g-in"
            style={{
              width: 320,
            }}
            value={l.rt}
            onChange={(p) => M("rt", p.target.value)}
          />
        </X>
        <X label="Примечание лаборатории">
          <input
            className="g-in"
            style={{
              width: 320,
            }}
            value={l.note}
            onChange={(p) => M("note", p.target.value)}
          />
        </X>
      </div>
      <CYn warns={_} on={u} setOn={o} />
      <div className="m-foot">
        <button className="btn" disabled={x || (_.length > 0 && !u)} onClick={w}>
          {x ? "Сохраняю…" : "Сохранить результаты"}
        </button>
        <CFe {...(b || {})} />
      </div>
    </div>
  );
}
function Zs({ v: t, req: n, who: s, me: l, onClose: i, onSaved: u }) {
  var d, M, z;
  const o = n == null ? void 0 : n.term_orders,
    x = (o == null ? void 0 : o.extra_services) || [],
    N = ["lab", "manager", "chief"].includes(l == null ? void 0 : l.role) && !t.out_at && !t.cancelled_at,
    b = Ae(t, {
      need: x,
    }),
    [j] = ne(
      () =>
        t.mix_id
          ? Y(A.from("term_mixes").select("id, mix_no, culture, param, site, status, machines, ext_partner").eq("id", t.mix_id).limit(1))
          : Promise.resolve([]),
      [t.mix_id],
      0,
    ),
    g = (j || [])[0];
  return (
    <CDt
      title={`Зерновоз ${t.vehicle_no} · процесс №${t.id}`}
      badge={<span className={"stage " + b.c}>{b.t}</span>}
      onClose={i}
      file={st("Зерновоз", t.vehicle_no, t.client, t.culture, "процесс-" + t.id)}
    >
      <Ys kind="visit" id={t.id} />
      <C_e done={!!n} skip={!n} title="Менеджер · Заявка" extra={n ? `№${n.id}` : "без заявки"}>
        {n ? (
          <div className="dgrid">
            <R
              l="Организация"
              v={n.client || ((M = (d = o == null ? void 0 : o.term_contracts) == null ? void 0 : d.term_counterparties) == null ? void 0 : M.name)}
            />
            <R l="Поручение" v={o == null ? void 0 : o.order_no} />
            <R l="Договор" v={(z = o == null ? void 0 : o.term_contracts) == null ? void 0 : z.contract_no} />
            <R l="Культура" v={n.culture} />
            <R l="Вес план, кг" v={n.planned_tonnes != null ? q(qe(n.planned_tonnes)) : null} />
            <R l="Дата прихода (план)" v={n.arrive_date} />
            <R l="Водитель" v={n.driver} />
            <R l="Контакт водителя" v={n.driver_phone} />
            <R l="Контракт закупочный" v={n.purchase_contract} />
            <R l="Отправитель (поставщик)" v={n.supplier} />
          </div>
        ) : (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            машина заведена без предварительной заявки
          </p>
        )}
      </C_e>
      <C_e done={!!t.in_at} title="КПП · Заезд" extra={he(t.in_at)}>
        <div className="dgrid">
          <R l="Машина / прицеп" v={t.vehicle_no + (t.trailer_no ? " / " + t.trailer_no : "")} />
          <R l="Водитель" v={t.driver} />
          <R l="Контакт водителя" v={t.driver_phone} />
          <R l="Организация" v={t.client} />
          <R l="Культура" v={t.culture} />
          <R l="Поставщик" v={t.supplier} />
          <R l="Контракт закупочный" v={t.purchase_contract} />
          <R l="Очередность выгрузки" v={t.priority} />
          <R l="ТТН у водителя" v={t.ttn_ok == null ? null : t.ttn_ok ? "есть" : "нет"} />
          <R l="№ пропуска" v={t.pass_no} />
          <R l="Оформил" v={s(t.in_by)} />
        </div>
        {t.cancelled_at ? (
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
              color: "var(--bad)",
            }}
          >
            заезд отменён {he(t.cancelled_at)} · {s(t.cancelled_by)}
          </p>
        ) : null}
      </C_e>
      {n && (n.t2_at || n.t2_called_at) ? (
        <C_e done={!0} title="Отстойник (Т2)" extra={he(n.t2_at)}>
          <div className="dgrid">
            <R l="Поставлен на отстойник" v={he(n.t2_at)} />
            <R l="Вызван на терминал" v={n.t2_called_at ? he(n.t2_called_at) : "ещё не вызывали"} />
            <R
              l="Простой на отстойнике"
              v={
                n.t2_at
                  ? (() => {
                      const _ = n.t2_called_at || t.in_at;
                      if (!_) return null;
                      const h = Math.round(((new Date(_) - new Date(n.t2_at)) / 36e5) * 10) / 10;
                      return h >= 0 ? h + " ч" : null;
                    })()
                  : null
              }
            />
          </div>
        </C_e>
      ) : null}
      <C_e done={t.lab_status === "passed" || t.lab_status === "rejected"} title="Лаборатория · проверка качества" extra={he(t.lab_at)}>
        <div className="dgrid">
          <R l="Решение" v={t.lab_status === "passed" ? "Одобрен" : t.lab_status === "rejected" ? "Отказ" : "в очереди"} />
          <R l="Результат 1 (путь груза)" v={t.lab_result1 ? Le[t.lab_result1] : null} />
          <R l="Влажность, %" v={t.lab_moisture} />
          <R l="Сорность, %" v={t.lab_impurity} />
          <R l="Колотые/битые, %" v={t.lab_broken} />
          <R l="Зерновая примесь, %" v={t.lab_grain_adm} />
          <R l="Показатели (текст)" v={t.lab_result_text} />
          <R l="Примечания" v={t.lab_notes} />
          <R l="Лаборант" v={s(t.lab_by)} />
          {t.lab_extra &&
            Object.entries(t.lab_extra).map(([_, h]) => {
              const w = _ === "note" ? "Прим. (доп.)" : (ls.find((p) => p[0] === _) || [, _])[1];
              return <R l={w} v={h} />;
            })}
        </div>
      </C_e>
      <C_e done={!!t.ts_at} skip={t.lab_status === "rejected"} title="Перевалка · услуга по решению лаборатории" extra={he(t.ts_at)}>
        <div className="dgrid">
          <R l="Площадка" v={t.site} />
          <R l="Оказанная услуга" v={t.ts_service || (t.lab_result1 ? Le[t.lab_result1] : null)} />
          <R l="Услуга отмечена" v={t.ts_at ? he(t.ts_at) : "ещё не отмечена"} />
          <R l="Отметил" v={s(t.ts_by)} />
          {x.length ? <R l="Доп. услуги поручения" v={x.join(", ")} /> : null}
          {x.length ? <R l="Из них оказано" v={(t.extra_done || []).length ? (t.extra_done || []).join(", ") : "ни одной"} /> : null}
          {x.length && x.some((_) => !(t.extra_done || []).includes(_)) ? (
            <R l="Не отмечено" v={x.filter((_) => !(t.extra_done || []).includes(_)).join(", ")} />
          ) : null}
        </div>
      </C_e>
      {t.mix_id || Ks(t) ? (
        <C_e done={!!t.mix_id} title="Замес" extra={g ? g.mix_no : "замес ещё не собран"}>
          {t.mix_id ? (
            <div className="dgrid">
              <R l="Номер замеса" v={g == null ? void 0 : g.mix_no} />
              <R l="Состояние замеса" v={g ? vs(g).t : null} />
              <R l="Культура замеса" v={g == null ? void 0 : g.culture} />
              <R l="Параметр смешивания" v={(g == null ? void 0 : g.param) || t.mix_param} />
              <R l="Площадка замеса" v={g == null ? void 0 : g.site} />
              <R
                l="С кем в замесе"
                v={
                  g
                    ? (g.machines || [])
                        .filter((_) => _ !== t.vehicle_no)
                        .concat(g.ext_partner ? [g.ext_partner] : [])
                        .join(", ")
                    : t.mix_with
                }
              />
            </div>
          ) : (
            <p
              className="p-sub"
              style={{
                margin: 0,
              }}
            >
              лаборатория назначила машине замес, но сам замес ещё не собран — машина ждёт вторую
            </p>
          )}
        </C_e>
      ) : null}
      <C_e done={t.gross_kg != null} title="Весовая · Брутто" extra={he(t.gross_at)}>
        <div className="dgrid">
          <R l="Брутто, кг" v={q(t.gross_kg)} />
          <R l="Место выгрузки" v={t.unload_place} />
          <R l="Весовщик" v={s(t.gross_by)} />
        </div>
      </C_e>
      <C_e done={!!t.unload_at} title="Выгрузка" extra={he(t.unload_at)}>
        <div className="dgrid">
          <R l="Отметил" v={s(t.unload_by)} />
        </div>
      </C_e>
      <C_e done={t.tare_kg != null} title="Весовая · Тара → Нетто" extra={he(t.tare_at)}>
        <div className="dgrid">
          <R l="Тара, кг" v={q(t.tare_kg)} />
          <R l="Нетто, кг" v={q(t.net_kg)} />
          {t.net_kg != null && t.planned_tonnes != null && (
            <R
              l="Отклонение от плана, кг"
              v={(t.net_kg - t.planned_tonnes * 1e3 >= 0 ? "+" : "") + q(Math.round(t.net_kg - t.planned_tonnes * 1e3))}
            />
          )}
          <R l="Весовщик" v={s(t.tare_by)} />
        </div>
      </C_e>
      <C_e done={!!t.out_at} title="КПП · Выезд" extra={he(t.out_at)}>
        <div className="dgrid">
          <R l="Выпустил" v={s(t.out_by)} />
        </div>
      </C_e>
      <C_e done={!0} title="Вложения · фото и документы">
        <Bt me={l} entity="visit" id={t.id} canAdd={l && ["kpp", "scale", "lab", "transship", "manager", "chief"].includes(l.role)} />
      </C_e>
      {N ? <Ui v={t} me={l} onSaved={u} /> : null}
    </CDt>
  );
}
const Wi = ["container", "transship", "dispatcher", "manager", "chief"];
function Gi({ c: t, me: n, now: s, onSet: l }) {
  const [i, u] = S.useState(""),
    [o, x] = S.useState(null),
    [N, b] = S.useState(!1);
  if (!(n && Wi.includes(n.role)))
    return s == null ? (
      <p
        className="p-sub"
        style={{
          margin: "8px 0 0",
        }}
      >
        Остаток не известен: времянку завели до того, как система начала вести вес. Его может записать перевалка, приёмка, диспетчер или руководитель.
      </p>
    ) : null;
  const g = async () => {
    const d = te(i);
    if (d == null || d < 0) {
      x({
        err: "Остаток, кг: нужно число (0 — времянка пуста)",
      });
      return;
    }
    if (d > 4e4) {
      x({
        err: "Остаток больше 40 000 кг — проверь цифру",
      });
      return;
    }
    b(!0);
    try {
      (await ue(
        A.from("term_line_containers")
          .update({
            temp_kg: d,
          })
          .eq("id", t.id),
        "времянка " + t.container_no,
      ),
        await je(
          "container",
          t.id,
          "temp_set",
          {
            контейнер: t.container_no,
            "остаток по замеру, кг": d,
            было: s ?? "не известен",
          },
          n,
        ),
        l(d),
        u(""),
        x({
          ok: `Остаток записан: ${q(d)} кг`,
        }));
    } catch (M) {
      x({
        err: String(M.message || M),
      });
    }
    b(!1);
  };
  return (
    <div
      style={{
        marginTop: 10,
      }}
    >
      {s == null && (
        <p
          className="p-sub"
          style={{
            margin: "0 0 6px",
          }}
        >
          Остаток не известен: времянку завели до того, как система начала вести вес. Взвесь или замерь и запиши — дальше система считает остаток
          сама.
        </p>
      )}
      <div
        className="row"
        style={{
          gap: 6,
          alignItems: "flex-end",
        }}
      >
        <X label="Остаток по факту, кг">
          <input
            value={i}
            onChange={(d) => u(d.target.value)}
            placeholder={s != null ? String(s) : "например 4200"}
            style={{
              width: 130,
            }}
          />
        </X>
        <button className="btn sec sm" disabled={N} onClick={g}>
          {N ? "Пишу…" : "Записать остаток"}
        </button>
      </div>
      <CFe {...(o || {})} />
    </div>
  );
}
function CPl({ c: t, loads: n, who: s, me: l, onClose: i }) {
  const u = ys(),
    o = t.state === "temp" || !!t.temp_closed_at,
    [x] = ne(
      () =>
        o
          ? Y(A.from("term_mixes").select("id, mix_no, culture, site, status, temp_kg").eq("temp_container_id", t.id).order("id"))
          : Promise.resolve([]),
      [t.id, o],
      0,
    ),
    N = x || [],
    b = (n || []).filter((w) => w.is_temp).slice(-1)[0],
    j = b ? +b.net_final_kg || +b.net_kg || 0 : null,
    g = N.reduce((w, p) => w + (+p.temp_kg || 0), 0),
    d = t.state === "temp",
    M = o || N.length > 0,
    [z, _] = S.useState(null),
    h = z ?? (t.temp_kg != null ? +t.temp_kg : null);
  return (
    <CDt
      title={`Контейнер ${t.container_no} · №${t.id}`}
      badge={<Et c={t} bm={u} />}
      onClose={i}
      file={st("Контейнер", t.container_no, t.line, t.booking ? "букинг-" + t.booking : "", t.cargo)}
    >
      <Ys kind="cont" id={t.id} />
      {t.state === "expected" || t.exp_at || t.off_list ? (
        <C_e done={!!t.exp_at} skip={!t.exp_at && !!t.off_list} title="Диспетчеры · реестр порта" extra={t.exp_at ? he(t.exp_at) : "заявки не было"}>
          <div className="dgrid">
            <R l="Заявлен к приезду" v={t.exp_at ? he(t.exp_at) : "нет — контейнер приехал вне реестра"} />
            <R l="Дата подачи (план)" v={t.eta_date ? String(t.eta_date).split("-").reverse().join(".") : null} />
            <R l="№ релиза / открепления" v={t.release_no} />
            <R l="Терминал порта" v={t.port_terminal} />
            <R l="Очерёдность вывоза" v={t.port_order} />
            <R l="Машина по реестру" v={t.in_vehicle_no} />
            <R l="Водитель по реестру" v={t.driver} />
            <R l="Откуда строка" v={t.exp_src} />
            <R l="Завёл" v={t.exp_by ? s(t.exp_by) : null} />
          </div>
          {t.off_list ? (
            <p
              className="p-sub"
              style={{
                margin: "8px 0 0",
                color: "var(--warn)",
              }}
            >
              ⚠ контейнера не было в списке от порта — свести реестр с портом
            </p>
          ) : null}
        </C_e>
      ) : null}
      <C_e done={!!t.in_at} title="КПП · Заезд порожнего" extra={t.in_at ? he(t.in_at) : "ещё не заезжал"}>
        <div className="dgrid">
          <R l="Тип" v={t.size ? `${t.size}' ${t.height || ""}` : null} />
          <R l="Линия" v={t.line} />
          <R l="Клиент (кому линия выдала)" v={t.client} />
          <R l="Букинг" v={t.booking} />
          <R l="Площадка" v={t.site} />
          <R l="Груз" v={t.cargo} />
          <R l="Дней на терминале" v={Lt(t.in_at, t.out_at)} />
          <R l="Оформил" v={s(t.in_by)} />
        </div>
      </C_e>
      <C_e done={!!t.accept_at} title="Приёмка · осмотр" extra={he(t.accept_at)}>
        <div className="dgrid">
          <R
            l="Состояние"
            v={t.accept_condition === "clean" ? "Чистый — принят" : t.accept_condition === "repair" ? "В ремонт" : t.accept_condition}
          />
          <R l="Сюрвейер" v={t.surveyor} />
          <R l="Характер повреждений" v={t.damage_note} />
          <R l="Сумма ремонта, ₽" v={t.repair_cost != null ? q(t.repair_cost) : null} />
          <R l="Примечания" v={t.notes} />
          <R l="Принял" v={s(t.accept_by)} />
        </div>
      </C_e>
      <C_e done={t.cont_tare_kg != null || t.payload_kg != null} title="Паспорт контейнера (табличка)">
        <div className="dgrid">
          <R l="Вес контейнера, кг" v={q(t.cont_tare_kg)} />
          <R l="Max gross, кг" v={q(t.max_gross_kg)} />
          <R l="Payload, кг" v={q(t.payload_kg)} />
        </div>
      </C_e>
      {n.length ? (
        n.map((w) => (
          <C_e done={w.gross_kg != null} title={`Погрузка (перетарка) №${w.id}`} extra={he(w.gross_at || w.tare_at)}>
            <div className="dgrid">
              <R l="Машина (а/т)" v={w.vehicle_no ? <CXt v={w.vehicle_no} /> : null} />
              <R l="Поручение" v={w.order_name} />
              <R l="Культура" v={w.culture} />
              <R l="Тара, кг" v={q(w.tare_kg)} />
              <R l="Брутто, кг" v={q(w.gross_kg)} />
              <R l="Нетто, кг" v={q(w.net_kg)} />
              {w.dotare_kg != null && <R l="Дотарь, кг" v={q(w.dotare_kg)} />}
              {w.dotare_kg != null && +w.dotare_kg != 0 ? (
                <R l={+w.dotare_kg < 0 ? "Растарено, кг" : "Дотарено, кг"} v={q(Math.abs(w.dotare_kg))} />
              ) : null}
              <R l="Нетто финал (в контейнере), кг" v={q(w.net_final_kg ?? w.net_kg)} />
              {w.is_temp ? <R l="Назначение" v="Времянка (хранение остатка)" /> : null}
              <R l="Пломба" v={w.seal_no} />
              <R l="Тару взвесил" v={s(w.tare_by)} />
              <R l="Брутто взвесил" v={s(w.gross_by)} />
            </div>
          </C_e>
        ))
      ) : (
        <C_e skip={!0} title="Погрузка (перетарка)">
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            погрузок не было
          </p>
        </C_e>
      )}
      {M ? (
        <C_e
          done={!d}
          title="Времянка · остаток груза"
          extra={d ? (h != null ? `в контейнере ${q(Math.round(h))} кг` : "остаток не известен") : "разобрана " + he(t.temp_closed_at)}
        >
          <div className="dgrid">
            <R l="Культура" v={t.cargo} />
            <R l="Заложено во времянку, кг" v={j ? q(Math.round(j)) : null} />
            <R l="Забрано в замесы, кг" v={g ? q(Math.round(g)) : N.length ? "—" : "0"} />
            <R l="Остаток сейчас, кг" v={d ? (h != null ? q(Math.round(h)) : "не известен") : "0 · контейнер свободен"} />
            <R l="Дата закрытия времянки" v={t.temp_closed_at ? he(t.temp_closed_at) : null} />
          </div>
          <p
            className="p-sub"
            style={{
              margin: "8px 0 6px",
            }}
          >
            Куда ушёл остаток
          </p>
          <CPt
            head={[
              "Замес",
              "Культура",
              "Площадка",
              {
                t: "Взято, кг",
                r: 1,
              },
              "Статус",
            ]}
            empty="из времянки пока ничего не брали"
            rows={N.map((w) => ({
              k: w.id,
              c: [
                <b>{w.mix_no || "№" + w.id}</b>,
                w.culture || "—",
                w.site || "—",
                w.temp_kg != null ? q(Math.round(+w.temp_kg)) : "—",
                oi[w.status] || w.status || "—",
              ],
            }))}
          />
          {d && <Gi c={t} me={l} now={h} onSet={_} />}
        </C_e>
      ) : null}
      <C_e done={!!t.out_at} title="КПП · Выезд" extra={he(t.out_at)}>
        <div className="dgrid">
          <R l="Машина вывоза" v={t.out_vehicle_no ? <CXt v={t.out_vehicle_no} /> : null} />
          <R l="Пломба" v={t.seal_no} />
          <R l="Пломба сверена" v={t.out_at ? (t.seal_checked ? "да" : "нет") : null} />
          <R l="Выпустил" v={s(t.out_by)} />
        </div>
      </C_e>
      <C_e done={!0} title="Вложения · фото и документы">
        <Bt
          me={l}
          entity="container"
          id={t.id}
          canAdd={l && ["kpp", "container", "scale", "dispatcher", "transship", "manager", "chief"].includes(l.role)}
        />
      </C_e>
    </CDt>
  );
}
function Ki() {
  const [t, n] = S.useState(""),
    [s, l] = S.useState(""),
    [i, u] = S.useState(null),
    [o, x] = S.useState(!1),
    N = async (b) => {
      (b.preventDefault(), x(!0), u(null));
      const { error: j } = await A.auth.signInWithPassword({
        email: t.trim(),
        password: s,
      });
      (j && u(j.message === "Invalid login credentials" ? "Неверный логин или пароль" : j.message), x(!1));
    };
  return (
    <div className="login">
      <form className="card" onSubmit={N}>
        <div className="brand">
          <img
            src="/logo-side.png"
            alt="ФЕНИКС"
            style={{
              width: 170,
            }}
          />
          <small>
            Терминал
            <br />
            Управленческий учёт
          </small>
        </div>
        <X label="Логин (email)">
          <input value={t} onChange={(b) => n(b.target.value)} autoFocus={!0} autoComplete="username" />
        </X>
        <X label="Пароль">
          <input type="password" value={s} onChange={(b) => l(b.target.value)} autoComplete="current-password" />
        </X>
        <button
          className="btn"
          style={{
            width: "100%",
            marginTop: 6,
          }}
          disabled={o}
        >
          {o ? "Вход…" : "Войти"}
        </button>
        <CFe err={i} />
      </form>
    </div>
  );
}
const es = (t, n) => {
    if (t == null || String(t).trim() === "") return null;
    const s = te(t);
    if (s == null) throw new Error(`${n}: нужно число`);
    return s;
  },
  os = (t, n, s, l, i = "") => {
    if (t == null) return null;
    if (t < s || t > l) throw new Error(`${n}: ${t}${i} вне разумных границ (${s}–${l}${i}). Проверь ввод.`);
    return t;
  },
  fl = (t, n, { future: s = !1, from: l = "2015-01-01" } = {}) => {
    const i = (t || "").trim();
    if (!i) return null;
    if (!/^\d{4}-\d{2}-\d{2}$/.test(i)) throw new Error(`${n}: дата в формате ДД.ММ.ГГГГ`);
    const u = new Date(i + "T00:00:00");
    if (isNaN(+u)) throw new Error(`${n}: такой даты не существует`);
    if (i < l) throw new Error(`${n}: ${i.split("-").reverse().join(".")} — раньше ${l.split("-").reverse().join(".")}. Проверь год.`);
    if (!s) {
      const o = new Date();
      if ((o.setDate(o.getDate() + 1), u > o)) throw new Error(`${n}: ${i.split("-").reverse().join(".")} — дата в будущем. Проверь год.`);
    }
    return i;
  },
  Hs = () => new Date().toISOString().slice(0, 10),
  Ji = {
    term_counterparties: "counterparty",
    term_contracts: "contract",
    term_orders: "order",
    term_requests: "request",
    term_truck_visits: "visit",
    term_line_containers: "container",
    term_container_loads: "load",
  },
  ps = async (t, n) => {
    const s = Ji[t];
    if (!s) return 0;
    try {
      const l = await Y(A.from("term_files").select("id, path").eq("entity", s).eq("entity_id", n));
      if (!l || !l.length) return 0;
      const i = l.map((o) => o.path).filter(Boolean);
      i.length && (await A.storage.from(gs).remove(i));
      const { error: u } = await A.from("term_files").delete().eq("entity", s).eq("entity_id", n);
      if (u) throw new Error(`вложения не удалились: ${u.message}`);
      return l.length;
    } catch (l) {
      throw new Error(String(l.message || l));
    }
  },
  En = async (t, n, s, l, i, u) => {
    if (window.confirm(`Удалить ${s}? Действие необратимо.`))
      try {
        const o = await ps(t, n),
          { data: x, error: N } = await A.from(t).delete().eq("id", n).select("id");
        if (N) throw N;
        if (!x || !x.length) throw new Error("Нет прав на удаление этой записи");
        (u({
          ok: o ? `Запись удалена вместе с вложениями (${o})` : "Запись удалена",
        }),
          i());
      } catch (o) {
        const x = String(o.message || o);
        u({
          err: /foreign key|violates|23503/i.test(x) ? `Нельзя удалить: ${l}` : x,
        });
      }
  },
  lt = (t) =>
    !t.target.closest(
      "input, button, select, textarea, label, a, .sel, .sel-list, .sel-opt, .sel-btn, .bchip, .mixtag, .t2chip, .svcchips, .clip, .stage",
    ),
  Ts = {
    visit: "v",
    container: "c",
    mix: "m",
    load: "l",
  },
  Jt = ({ onClick: t }) => (
    <button
      className="btn danger sm icon"
      title="Удалить"
      onClick={(n) => {
        (n.stopPropagation(), t());
      }}
    >
      ✕
    </button>
  );
function Wt({ options: t, value: n, onChange: s, w: l, ph: i, addTitle: u, addPrompt: o, note: x }) {
  const N = S.useMemo(() => {
      const j = (t || []).filter(Boolean),
        g = n && j.some((d) => String(d).toLowerCase() === String(n).toLowerCase());
      return (n && !g ? [n, ...j] : j).map((d) => [d, d]);
    }, [t, n]),
    b = () => {
      const j = (window.prompt(o || "Своё значение:", n || "") || "").trim();
      if (!j) return;
      const g = (t || []).find((d) => String(d).toLowerCase().replace(/ё/g, "е") === j.toLowerCase().replace(/ё/g, "е"));
      s(g || j);
    };
  return (
    <span
      className="row"
      style={{
        gap: 5,
        alignItems: "center",
      }}
    >
      <CPe value={n || ""} onChange={s} options={N} w={l} ph={i} />
      {u ? (
        <button type="button" className="btn sec sm icon" title={u} onClick={b}>
          +
        </button>
      ) : null}
      {x ? (
        <span
          className="faint"
          style={{
            fontSize: 10,
          }}
        >
          {x}
        </span>
      ) : null}
    </span>
  );
}
const Wn = {
    line: "линию",
    surveyor: "сюрвейера",
  },
  Yi = [];
function fs(t) {
  const [n, s] = ne(() => Y(A.from("term_dict").select("id, name, note").eq("kind", t).order("name")), [t], 12e4, "dict." + t),
    l = n || Yi;
  return {
    list: S.useMemo(() => l.map((u) => u.name), [l]),
    rows: l,
    reload: s,
  };
}
function CUn() {
  const t = Nn();
  return <CJt id="trucks9" items={t.list} />;
}
function It({ kind: t, value: n, onChange: s, w: l, me: i, ph: u }) {
  const { list: o, reload: x } = fs(t),
    N = S.useMemo(() => {
      const j = [...o];
      return (n && !j.includes(n) && j.unshift(n), j.map((g) => [g, g]));
    }, [o, n]),
    b = async () => {
      const j = (window.prompt(`Новая ${Wn[t] || ""} — как записывать в документах:`, "") || "").trim();
      if (!j) return;
      const g = o.find((M) => M.toLowerCase().replace(/ё/g, "е") === j.toLowerCase().replace(/ё/g, "е"));
      if (g) {
        s(g);
        return;
      }
      const d = o.find((M) => wn(M.toLowerCase(), j.toLowerCase()) <= 2);
      if (
        d &&
        !window.confirm(`«${j}» похоже на «${d}», которое уже есть в справочнике.

Всё равно завести «${j}» как новое?`)
      ) {
        s(d);
        return;
      }
      try {
        (await ue(
          A.from("term_dict").insert({
            kind: t,
            name: j,
            created_by: (i == null ? void 0 : i.id) || null,
          }),
          "справочник",
        ),
          await je(
            "dict",
            null,
            "create",
            {
              вид: t === "line" ? "линия" : "сюрвейер",
              значение: j,
            },
            i,
          ),
          s(j),
          x());
      } catch (M) {
        window.alert("Не добавилось: " + (M.message || M));
      }
    };
  return (
    <span
      className="row"
      style={{
        gap: 4,
        alignItems: "center",
      }}
    >
      <CPe value={n || ""} onChange={s} options={N} w={l || 150} ph={u || "—"} />
      <button type="button" className="btn sec sm icon" title={`Добавить ${Wn[t] || ""} в справочник`} onClick={b}>
        +
      </button>
    </span>
  );
}
const Gn = (t) =>
  String(t ?? "")
    .toLowerCase()
    .replace(/ё/g, "е");
function Pt(t, n) {
  const [s, l] = S.useState(n || ""),
    i = S.useRef(null),
    u = S.useMemo(() => Gn(s).split(/\s+/).filter(Boolean), [s]),
    o = S.useMemo(
      () =>
        (...g) => {
          if (!u.length) return !0;
          const d = Gn(g.filter((M) => M != null && M !== "").join("  "));
          return u.every((M) => d.includes(M));
        },
      [u],
    ),
    x = S.useRef(null),
    [N, b] = S.useState(!1);
  S.useEffect(() => {
    if (!u.length) {
      b(!1);
      return;
    }
    const g = setTimeout(() => {
      const d = x.current && (x.current.closest(".panel") || x.current.closest(".main"));
      b(!!d && d.querySelectorAll("tbody tr").length === 0);
    }, 300);
    return () => clearTimeout(g);
  }, [u, s]);
  const j = (
    <span className="find9" ref={x}>
      <input
        className="srch9"
        value={s}
        onChange={(g) => l(g.target.value)}
        placeholder={t || "поиск…"}
        onKeyDown={(g) => {
          g.key === "Enter" && i.current && (g.preventDefault(), i.current());
        }}
      />
      {s ? (
        <button className="find9x" title="Очистить поиск" onClick={() => l("")}>
          ✕
        </button>
      ) : null}
      {N ? <span className="find9no">ничего не найдено</span> : null}
    </span>
  );
  return {
    on: u.length > 0,
    test: o,
    Find: j,
    q: s,
    clear: () => l(""),
    enterRef: i,
  };
}
function Yt({ win: t, params: n }) {
  const [s, l] = S.useState(!1);
  return (
    <button
      className="btn sec sm icon"
      title="Скопировать ссылку на этот раздел с текущим отбором"
      onClick={async () => {
        try {
          await navigator.clipboard.writeText(Bn(t, n));
        } catch {
          window.prompt("Скопируй ссылку:", Bn(t, n));
        }
        (l(!0), setTimeout(() => l(!1), 1600));
      }}
    >
      <Sn n={s ? "ok" : "link"} />
    </button>
  );
}
const Vt = (t, n, s) => (t.on && n !== s ? `${n} из ${s}` : String(s)),
  Zi = ["manager", "chief"],
  sn = (t) => !!t && Zi.includes(t.role),
  Xi = async (t, n, s, l, i) => {
    const u = t.length;
    if (!u) return;
    if (u > 300) {
      i({
        err: `За раз можно удалить не больше 300 контейнеров, в отборе ${u}. Сузь отбор.`,
      });
      return;
    }
    const o = window.prompt(
      `Удалить из базы ${u} контейнер(ов) текущего отбора вместе с их затарками и вложениями? Действие необратимо.

Чтобы подтвердить, впиши число ${u}:`,
      "",
    );
    if (String(o || "").trim() !== String(u)) {
      o !== null &&
        i({
          err: "Число не совпало — ничего не удалено",
        });
      return;
    }
    (s(!0),
      i({
        ok: `Удаляю ${u}…`,
      }));
    let x = 0;
    const N = [];
    try {
      for (const b of t) {
        const j = await Qi(b, n);
        j.ok ? x++ : N.push(`${b.container_no} — ${j.why}`);
      }
      i(
        N.length
          ? {
              err: `Удалено ${x} из ${u}. Не удалось: ${N.slice(0, 8).join("; ")}${N.length > 8 ? ` и ещё ${N.length - 8}` : ""}`,
            }
          : {
              ok: `Удалено контейнеров: ${x} — все записи есть в журнале изменений`,
            },
      );
    } catch (b) {
      i({
        err: `Удалено ${x} из ${u}, дальше сорвалось: ${b.message || b}`,
      });
    }
    (s(!1), l());
  },
  Qi = async (t, n) => {
    try {
      const s = await Y(A.from("term_mixes").select("id, mix_no").eq("temp_container_id", t.id));
      if ((s || []).length)
        return {
          ok: !1,
          why: `учтён во времянке замеса ${(s || []).map((o) => o.mix_no || "№" + o.id).join(", ")}`,
        };
      const l = (await Y(A.from("term_container_loads").select("id, gross_kg").eq("container_id", t.id))) || [];
      (await je(
        "container",
        t.id,
        "delete",
        {
          контейнер: t.container_no,
          тип: (t.size || "") + (t.height || ""),
          линия: t.line,
          заезд: t.in_at,
          затарок: l.length,
          "из них закрытых": l.filter((o) => o.gross_kg != null).length,
          "массовое удаление": !0,
        },
        n,
      ),
        await ps("term_line_containers", t.id));
      for (const o of l) (await ps("term_container_loads", o.id), await ue(A.from("term_container_loads").delete().eq("id", o.id), "затарка"));
      const { data: i, error: u } = await A.from("term_line_containers").delete().eq("id", t.id).select("id");
      if (u) throw u;
      return !i || !i.length
        ? {
            ok: !1,
            why: "нет прав",
          }
        : {
            ok: !0,
          };
    } catch (s) {
      return {
        ok: !1,
        why: String(s.message || s).slice(0, 80),
      };
    }
  },
  er = async (t, n, s, l) => {
    try {
      const [i, u, o] = await Promise.all([
          Y(A.from("term_container_loads").select("id, vehicle_no, net_kg, gross_kg, is_temp").eq("container_id", t.id)),
          Y(A.from("term_mixes").select("id, mix_no, temp_kg").eq("temp_container_id", t.id)),
          t.batch_id ? Y(A.from("term_batches").select("id, batch_no, status").eq("id", t.batch_id).limit(1)) : Promise.resolve([]),
        ]),
        x = i || [],
        N = u || [],
        b = (o || [])[0];
      if (N.length) {
        l({
          err: `Контейнер ${t.container_no} учтён во времянке замеса ${N.map((h) => h.mix_no || "№" + h.id).join(", ")}. Сначала разберись с замесом — расформируй его или убери времянку, потом удаляй контейнер.`,
        });
        return;
      }
      const j = x.filter((h) => h.gross_kg != null),
        g = [];
      (j.length &&
        g.push(
          `${j.length} закрыт${j.length === 1 ? "ую затарку" : "ых затарок"} (${j.map((h) => q(h.net_final_kg ?? h.net_kg) + " кг").join(", ")})`,
        ),
        x.length - j.length && g.push(`${x.length - j.length} незакрытую затарку`));
      const d = await Y(A.from("term_files").select("id").eq("entity", "container").eq("entity_id", t.id));
      (d || []).length && g.push(`${d.length} вложени${d.length === 1 ? "е" : "й"}`);
      const M = [
        `Удалить контейнер ${t.container_no} (№${t.id}) из базы? Действие необратимо.`,
        g.length
          ? `
Вместе с ним будет удалено: ${g.join(", ")}.`
          : "",
        b
          ? `
Контейнер числится в партии ${b.batch_no} — партия станет меньше на одну позицию.`
          : "",
        j.length
          ? `
Это уже учтённый груз: цифры уйдут из отчётов и актов.`
          : "",
      ]
        .filter(Boolean)
        .join("");
      if (!window.confirm(M)) return;
      (await je(
        "container",
        t.id,
        "delete",
        {
          контейнер: t.container_no,
          тип: (t.size || "") + (t.height || ""),
          линия: t.line,
          статус: tt(t, {}),
          заезд: t.in_at,
          затарок: x.length,
          "из них закрытых": j.length,
          партия: b ? b.batch_no : void 0,
          вложений: (d || []).length || void 0,
        },
        n,
      ),
        await ps("term_line_containers", t.id));
      for (const h of x)
        (await ps("term_container_loads", h.id), await ue(A.from("term_container_loads").delete().eq("id", h.id), "затарка №" + h.id));
      const { data: z, error: _ } = await A.from("term_line_containers").delete().eq("id", t.id).select("id");
      if (_) throw _;
      if (!z || !z.length) throw new Error("Нет прав на удаление контейнеров — это может менеджер или управляющий");
      (l({
        ok: `Контейнер ${t.container_no} удалён${x.length ? ` вместе с затарками (${x.length})` : ""} — запись есть в журнале изменений`,
      }),
        s());
    } catch (i) {
      const u = String(i.message || i);
      l({
        err: /foreign key|violates|23503/i.test(u) ? `Нельзя удалить ${t.container_no}: на него ещё что-то ссылается (${u})` : u,
      });
    }
  };
function $s(t) {
  const [n, s, l] = ne(() => Y(A.from("term_counterparties").select("*").order("name")), [], 6e4, "cps"),
    [i, u, o] = ne(
      () =>
        Y(
          A.from("term_contracts").select("*, term_counterparties(name)").order("id", {
            ascending: !1,
          }),
        ),
      [],
      6e4,
      "ctrs",
    ),
    [x, N, b] = ne(
      () =>
        Y(
          A.from("term_orders").select("*, term_contracts(contract_no, contract_date, term_counterparties(name))").order("id", {
            ascending: !1,
          }),
        ),
      [],
      6e4,
      "ords",
    ),
    [j, g, d] = ne(
      () =>
        Y(
          A.from("term_requests")
            .select("*, term_orders(order_no, cargo, term_contracts(contract_no, term_counterparties(name)))")
            .order("id", {
              ascending: !1,
            })
            .limit(500),
        ),
      [],
      3e4,
    ),
    [M, z] = ne(() => Y(A.from("term_files").select("id, entity, entity_id").in("entity", ["contract", "order", "request"]).limit(5e3)), [], 6e4);
  return {
    me: t,
    cps: n || [],
    ctrs: i || [],
    ords: x || [],
    reqs: j || [],
    reload: () => {
      (s(), u(), N(), g());
    },
    freload: z,
    fcnt: (_, h) => (M || []).reduce((w, p) => w + (p.entity === _ && p.entity_id === h ? 1 : 0), 0),
    err: l || o || b || d,
  };
}
function tr({ me: t }) {
  const [n, s] = Te("mgr.tab", "req"),
    l = $s(t);
  return (
    <>
      <div className="tabs">
        {[
          ["req", "Заявки"],
          ["ord", "Поручения"],
          ["ctr", "Договоры"],
          ["cp", "Контрагенты"],
        ].map(([i, u]) => (
          <button className={"tab" + (n === i ? " on" : "")} onClick={() => s(i)}>
            {u}
          </button>
        ))}
      </div>
      {n === "cp" && <CBl D={l} />}
      {n === "ctr" && <CKl D={l} />}
      {n === "ord" && <CWl D={l} />}
      {n === "req" && <C$l D={l} />}
    </>
  );
}
function CSr({ D: t, onClose: n }) {
  const [s, l] = Te("draft.cp", {}),
    [i, u] = S.useState(!1),
    [o, x] = S.useState(null),
    [N, b] = S.useState(null),
    j = (_, h) => (w) =>
      l((p) => ({
        ...p,
        [_]: tn(w.target.value, h),
      })),
    g = (_, h, w, p) => (
      <input
        inputMode="numeric"
        style={{
          width: w,
          minWidth: w,
        }}
        placeholder=""
        value={s[_] ?? ""}
        onChange={j(_, h)}
      />
    ),
    d = (_) => {
      const h = tn(_.target.value, 9);
      l((w) => {
        const p = {
          ...w,
          bik: h,
        };
        if (h.length === 9) {
          const F = t.cps.find((C) => (C.bik || "") === h && (C.bank_name || C.corr_account));
          F && (w.bank || (p.bank = F.bank_name || ""), w.ks || (p.ks = F.corr_account || ""));
        }
        return p;
      });
    },
    M = (_) => {
      if (!String(_ || "").trim()) return;
      const h = ci(_),
        w = [];
      (l((p) => {
        const F = {
            ...p,
          },
          C = (y, $, m) => {
            $ && !String(F[y] || "").trim() && ((F[y] = $), w.push(m));
          };
        return (
          C("name", h.name, "наименование"),
          C("inn", h.inn, "ИНН"),
          C("kpp", h.kpp, "КПП"),
          C("ogrn", h.ogrn, "ОГРН"),
          C("director", h.director, "директор"),
          C("addr", h.addr, "адрес"),
          C("bank", h.bank, "банк"),
          C("ks", h.ks, "к/с"),
          C("rs", h.rs, "р/с"),
          C("bik", h.bik, "БИК"),
          F
        );
      }),
        b(w.length ? "Распознано: " + w.join(", ") : "В тексте не нашлось реквизитов — заполни поля вручную"));
    },
    z = async () => {
      try {
        const _ = St(s.name);
        if (!_) throw new Error("Наименование организации обязательно");
        const h = t.cps.find(($) => St($.name).toLowerCase() === _.toLowerCase());
        if (h) throw new Error(`Такой контрагент уже есть в реестре («${h.name}»)`);
        const w = cs(s.inn, [10, 12], "ИНН");
        if (w) {
          if (!il(w)) throw new Error(`ИНН ${w} не проходит проверку контрольной суммы — проверь цифры`);
          const $ = t.cps.find((m) => (m.inn || "") === w);
          if ($) throw new Error(`ИНН ${w} уже занят: «${$.name}»`);
        }
        const p = cs(s.ogrn, [13, 15], "ОГРН"),
          F = cs(s.bik, [9], "БИК"),
          C = cs(s.ks, [20], "К/с"),
          y = cs(s.rs, [20], "Р/с");
        if (y && F && !cn(y, F)) throw new Error("Р/с не сходится с БИК по контрольному ключу — проверь номер счёта");
        if (C && !/^301/.test(C)) throw new Error("К/с должен начинаться с 301 — проверь номер");
        (u(!0),
          x(null),
          await ue(
            A.from("term_counterparties").insert({
              name: _,
              inn: w,
              kpp: tn(s.kpp, 9) || null,
              ogrn: p,
              director: St(s.director) || null,
              legal_address: (s.addr || "").replace(/\s+/g, " ").trim() || null,
              bank_name: St(s.bank) || null,
              corr_account: C,
              settle_account: y,
              bik: F,
            }),
            "контрагент",
          ),
          l({}),
          zt("draft.cp"),
          t.reload(),
          n());
      } catch (_) {
        (x(String(_.message || _)), u(!1));
      }
    };
  return (
    <Ss
      title="Новый контрагент"
      hint="вставь карточку предприятия в первое поле — реквизиты распознаются автоматически · цифровые поля принимают только цифры · ИНН и Р/с проверяются по контрольным суммам"
      onClose={n}
      onSave={z}
      onClear={() => {
        (l({}), zt("draft.cp"), b(null));
      }}
      busy={i}
      err={o}
    >
      <X label="Умная вставка · вставь реквизиты текстом (ИНН, ОГРН, банк, счета, адрес)">
        <textarea
          className="smartpaste"
          rows={3}
          placeholder={`ООО «Ромашка», ИНН 7707083893, КПП 770701001, ОГРН 1027700132195,
123456, г. Москва, ул. Ленина, 1, банк ПАО Сбербанк, БИК 044525225,
к/с 30101810400000000225, р/с 40702810…`}
          onChange={(_) => M(_.target.value)}
        />
      </X>
      {N && <p className="ordinfo">{N}</p>}
      <X label="Наименование организации *">
        <input
          style={{
            width: 300,
            minWidth: 300,
          }}
          value={s.name ?? ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              name: _.target.value,
            }))
          }
          onBlur={(_) =>
            l((h) => ({
              ...h,
              name: St(_.target.value),
            }))
          }
        />
      </X>
      <X label="ИНН · 10 или 12 цифр">{g("inn", 12, 140)}</X>
      <X label="КПП · 9 цифр">{g("kpp", 9, 120)}</X>
      <X label="ОГРН · 13 или 15 цифр">{g("ogrn", 15, 160)}</X>
      <X label="Директор">
        <input
          style={{
            width: 200,
            minWidth: 200,
          }}
          value={s.director ?? ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              director: _.target.value,
            }))
          }
          onBlur={(_) =>
            l((h) => ({
              ...h,
              director: St(_.target.value),
            }))
          }
        />
      </X>
      <X label="Юридический адрес">
        <input
          style={{
            width: 330,
            minWidth: 330,
          }}
          value={s.addr ?? ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              addr: _.target.value,
            }))
          }
          onBlur={(_) =>
            l((h) => ({
              ...h,
              addr: (_.target.value || "").replace(/\s+/g, " ").trim(),
            }))
          }
        />
      </X>
      <X label="БИК · 9 цифр (подтянет банк и к/с)">
        <input
          inputMode="numeric"
          style={{
            width: 130,
            minWidth: 130,
          }}
          value={s.bik ?? ""}
          onChange={d}
        />
      </X>
      <X label="Банк">
        <input
          list="dl-bank"
          style={{
            width: 230,
            minWidth: 230,
          }}
          value={s.bank ?? ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              bank: _.target.value,
            }))
          }
          onBlur={(_) =>
            l((h) => ({
              ...h,
              bank: St(_.target.value),
            }))
          }
        />
      </X>
      <CJt id="dl-bank" items={Fe(t.cps.map((_) => _.bank_name))} />
      <X label="К/с · 20 цифр (начинается с 301)">{g("ks", 20, 210)}</X>
      <X label="Р/с · 20 цифр">{g("rs", 20, 210)}</X>
      {(s.rs || "").length === 20 && (s.bik || "").length === 9 && (
        <p className="ordinfo">{cn(s.rs, s.bik) ? "✓ Р/с сходится с БИК по контрольному ключу" : "⚠ Р/с не сходится с БИК — проверь номер счёта"}</p>
      )}
    </Ss>
  );
}
function CNr({ D: t, onClose: n }) {
  const [s, l] = Te("draft.ctr", {}),
    [i, u] = S.useState([]),
    [o, x] = S.useState(!1),
    [N, b] = S.useState(null),
    j = async () => {
      try {
        if (!s.cp) throw new Error("Выбери контрагента — организация подтянется из реестра");
        const d = (s.no || "").trim();
        if (!d) throw new Error("Номер договора обязателен");
        if (t.ctrs.find((_) => _.counterparty_id === +s.cp && (_.contract_no || "").trim().toLowerCase() === d.toLowerCase()))
          throw new Error(`У этого контрагента уже есть договор «${d}»`);
        (x(!0), b(null), fl(s.dt, "Дата договора"));
        const z = await Y(
          A.from("term_contracts")
            .insert({
              counterparty_id: +s.cp,
              contract_no: d,
              contract_date: s.dt || null,
            })
            .select("id"),
        );
        (await Cn("contract", z[0].id, i, t.me.id), l({}), zt("draft.ctr"), u([]), t.reload(), t.freload(), n());
      } catch (d) {
        (b(String(d.message || d)), x(!1));
      }
    },
    g = (d) => {
      const M = String(d || ""),
        z = (M.match(/№\s*([^\s,;]+)/) || M.match(/договор[а-я]*\s+([A-ZА-Я0-9/-]{3,})/i) || [])[1],
        _ = M.match(/(\d{2})[./](\d{2})[./](\d{4})/),
        h = t.cps.find((w) => w.name && M.toLowerCase().includes(String(w.name).toLowerCase().replace(/[«»"]/g, "").slice(0, 12).toLowerCase()));
      l((w) => ({
        ...w,
        no: w.no || z || "",
        dt: w.dt || (_ ? `${_[3]}-${_[2]}-${_[1]}` : ""),
        cp: w.cp || (h ? String(h.id) : ""),
      }));
    };
  return (
    <Ss
      title="Новый договор"
      hint="организация выбирается из реестра контрагентов · дубль номера у одного контрагента не пропускается"
      onClose={n}
      onSave={j}
      onClear={() => {
        (l({}), zt("draft.ctr"));
      }}
      busy={o}
      err={N}
    >
      <X label="Умная вставка · вставь текст с реквизитами (№ и дата распознаются)">
        <textarea className="smartpaste" rows={2} placeholder="например: Договор № RHL-24/07 от 12.08.2026 …" onChange={(d) => g(d.target.value)} />
      </X>
      <X label="Контрагент *">
        <CPe
          value={s.cp || ""}
          onChange={(d) =>
            l((M) => ({
              ...M,
              cp: d,
            }))
          }
          options={t.cps.map((d) => [d.id, d.name])}
          w={280}
        />
      </X>
      <X label="Номер договора *">{Se(s, l, "no", "", 170)}</X>
      <X label="Дата договора">
        <input
          type="date"
          value={s.dt || ""}
          onChange={(d) =>
            l((M) => ({
              ...M,
              dt: d.target.value,
            }))
          }
        />
      </X>
      <C$n pend={i} setPend={u} />
    </Ss>
  );
}
function CLr({ D: t, onClose: n }) {
  var z;
  const [s, l] = Te("draft.ord", {}),
    [i, u] = S.useState([]),
    [o, x] = S.useState(!1),
    [N, b] = S.useState(null),
    j = t.ctrs.find((_) => String(_.id) === String(s.ctr)),
    g = Fe([...t.ords.map((_) => _.cargo), ...t.reqs.map((_) => _.culture)]),
    d = Fe(t.ords.map((_) => _.tnved)),
    M = async () => {
      try {
        if (!j) throw new Error("Выбери договор — организация подтянется автоматически");
        const _ = (s.no || "").trim();
        if (!_) throw new Error("Номер поручения обязателен");
        if (t.ords.find((m) => m.contract_id === j.id && (m.order_no || "").trim().toLowerCase() === _.toLowerCase()))
          throw new Error(`По договору ${j.contract_no} уже есть поручение «${_}»`);
        const w = es(s.vol, "Объём"),
          p = es(s.cn, "Кол-во контейнеров"),
          F = es(s.norm, "Норма загрузки"),
          C = es(s.rate, "Ставка");
        if (s.vat == null || String(s.vat).trim() === "") throw new Error("Выбери ставку НДС: 0 % или 22 %");
        const y = es(s.vat, "НДС");
        if (C != null && C <= 0) throw new Error("Ставка должна быть больше нуля");
        if (w != null && w <= 0) throw new Error("Объём должен быть больше нуля");
        (os(y, "НДС", 0, 30, "%"),
          os(C, "Ставка", 0.01, 1e5, " $/т"),
          os(F, "Норма загрузки", 8, 35, " т"),
          os(w, "Объём", 0.1, 1e6, " т"),
          os(p, "Кол-во контейнеров", 1, 1e4),
          fl(s.until, "Ставка действует до", {
            future: !0,
          }),
          x(!0),
          b(null));
        const $ = await Y(
          A.from("term_orders")
            .insert({
              contract_id: j.id,
              order_no: _,
              cargo: (s.cargo || "").trim() || null,
              tnved: (s.tnved || "").trim() || null,
              volume_t: w,
              containers_n: p,
              container_type: (s.ctype || "").trim() || "40'HC",
              load_norm_t: F,
              rate_per_t: C,
              vat_pct: y,
              rate_valid_until: s.until || null,
              load_instruction: (s.instr || "").trim() || null,
              dest_country: (s.dest || "").trim() || null,
              survey: (s.srv || "").trim() || null,
              extra_services: (s.svc || []).length ? s.svc : null,
            })
            .select("id"),
        );
        (await Cn("order", $[0].id, i, t.me.id), l({}), zt("draft.ord"), u([]), t.reload(), t.freload(), n());
      } catch (_) {
        (b(String(_.message || _)), x(!1));
      }
    };
  return (
    <Ss
      title="Новое поручение"
      hint="организация и договор подтягиваются из выбранного договора · ставка НДС выбирается из списка (0 % или 22 %) · код ТН ВЭД подставляется из справочника культур · тип контейнеров по умолчанию 40'HC"
      onClose={n}
      onSave={M}
      onClear={() => {
        (l({}), zt("draft.ord"));
      }}
      busy={o}
      err={N}
    >
      <CJt id="dl-tnved" items={d} />
      <X label="Договор *">
        <CPe
          value={s.ctr || ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              ctr: _,
            }))
          }
          options={t.ctrs.map((_) => {
            var h;
            return [_.id, `${(h = _.term_counterparties) == null ? void 0 : h.name} · дог. ${_.contract_no}`];
          })}
          w={300}
        />
      </X>
      <X label="Номер поручения *">{Se(s, l, "no", "", 150)}</X>
      <X label="Наименование груза">
        <Wt
          w={210}
          ph="— выбери груз —"
          options={[...new Set([...Ft(), ...g])]}
          value={s.cargo}
          addTitle="Груз, которого нет в списке"
          addPrompt="Наименование груза (как писать в документах):"
          onChange={(_) =>
            l((h) => ({
              ...h,
              cargo: _,
              tnved: (h.tnved || "").trim() ? h.tnved : Es(_),
            }))
          }
        />
      </X>
      <X label={"Код ТН ВЭД" + (Es(s.cargo) && !(s.tnved || "").trim() ? " · авто" : "")}>
        <input
          list="dl-tnved"
          style={{
            width: 140,
            minWidth: 140,
          }}
          placeholder={Es(s.cargo)}
          value={s.tnved ?? ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              tnved: _.target.value,
            }))
          }
        />
      </X>
      {(s.cargo || "").trim() && !Es(s.cargo) && !(s.tnved || "").trim() && (
        <p
          className="p-sub"
          style={{
            margin: 0,
            color: "var(--warn)",
          }}
        >
          для «{s.cargo}» кода в справочнике нет — впиши ТН ВЭД вручную, а управляющий добавит культуру в «Настройки терминала»
        </p>
      )}
      {(s.tnved || "").trim() && !an(s.tnved) && (
        <p
          className="p-sub"
          style={{
            margin: 0,
            color: "var(--warn)",
          }}
        >
          код ТН ВЭД обычно из 10 цифр — проверь: «{s.tnved}»
        </p>
      )}
      <X label="Страна назначения">
        <Wt
          w={200}
          ph="— выбери страну —"
          options={jn}
          value={s.dest}
          addTitle="Страны нет в списке"
          addPrompt="Страна назначения:"
          onChange={(_) =>
            l((h) => ({
              ...h,
              dest: _,
            }))
          }
        />
      </X>
      <X label="Сюрвей">
        <It
          kind="surveyor"
          me={t.me}
          value={s.srv || ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              srv: _,
            }))
          }
          w={200}
          ph="— выбери сюрвейера —"
        />
      </X>
      <X label="Доп. услуги (видят лаборатория, весовая, перевалка, досмотр и фумигация)">
        <div className="svcchips">
          {li.map((_) => {
            const h = (s.svc || []).includes(_);
            return (
              <button
                type="button"
                className={"chip" + (h ? " on" : "")}
                onClick={() =>
                  l((w) => ({
                    ...w,
                    svc: h ? (w.svc || []).filter((p) => p !== _) : [...(w.svc || []), _],
                  }))
                }
              >
                {_}
              </button>
            );
          })}
        </div>
      </X>
      <X label="Объём, т">{Se(s, l, "vol", "", 100)}</X>
      <X label="Кол-во контейнеров">{Se(s, l, "cn", "", 100)}</X>
      <X label="Тип контейнеров">{Se(s, l, "ctype", "40'HC", 110)}</X>
      <X label="Норма загрузки, т">{Se(s, l, "norm", "", 110)}</X>
      <X label="Ставка за перевалку, $/т">{Se(s, l, "rate", "", 130)}</X>
      <X label="Ставка НДС *">
        <CPe
          value={s.vat ?? ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              vat: _,
            }))
          }
          options={sl(s.vat)}
          w={200}
          ph="— выбери ставку —"
        />
      </X>
      <X label="Ставка действует до">
        <input
          type="date"
          value={s.until || ""}
          onChange={(_) =>
            l((h) => ({
              ...h,
              until: _.target.value,
            }))
          }
        />
      </X>
      <X label="Инструкция на затарку (сюрвейер · стоп-листы линий · партии)">{Se(s, l, "instr", "", 320)}</X>
      <C$n pend={i} setPend={u} />
      {j && (
        <p className="ordinfo">
          Организация: <b>{(z = j.term_counterparties) == null ? void 0 : z.name}</b> · договор <b>{j.contract_no}</b>
          {j.contract_date ? ` от ${j.contract_date}` : ""}
        </p>
      )}
    </Ss>
  );
}
function CIr({ D: t, onClose: n }) {
  var Z, I, D;
  const [s, l] = Te("draft.req", {}),
    [i, u] = S.useState([]),
    [o, x] = S.useState(!1),
    [N, b] = S.useState(null),
    j = t.ords.find((E) => String(E.id) === String(s.ord)),
    g = S.useMemo(() => {
      const E = {};
      return (
        t.reqs.forEach((a) => {
          const f = (a.vehicle_no || "").toUpperCase();
          f && !E[f] && (E[f] = a);
        }),
        E
      );
    }, [t.reqs]),
    d = Fe(t.reqs.map((E) => E.vehicle_no)),
    M = Fe(t.reqs.map((E) => E.driver)),
    z = Fe(t.reqs.map((E) => E.supplier)),
    _ = Fe(t.reqs.map((E) => E.purchase_contract)),
    h = (E) => {
      const a = E.toUpperCase().replace(/\s+/g, "");
      l((f) => {
        const P = g[a];
        return P
          ? {
              ...f,
              veh: a,
              trl: f.trl || P.trailer_no || "",
              drv: f.drv || P.driver || "",
              ph: f.ph || P.driver_phone || "",
              sup: f.sup || P.supplier || "",
              pc: f.pc || P.purchase_contract || "",
            }
          : {
              ...f,
              veh: a,
            };
      });
    },
    w = te(s.tons),
    p = w == null ? null : w / 1e3,
    [F, C] = S.useState(null);
  S.useEffect(() => {
    if (!j) {
      C(null);
      return;
    }
    let E = !1;
    return (
      Y(
        A.rpc("term_order_planned_kg", {
          p_order: j.id,
        }),
      )
        .then((a) => {
          E || C(+a || 0);
        })
        .catch(() => {}),
      () => {
        E = !0;
      }
    );
  }, [j && j.id]);
  const y =
      F != null
        ? F / 1e3
        : j
          ? t.reqs.filter((E) => E.order_id === j.id && E.status !== "cancelled" && !E.deleted_at).reduce((E, a) => E + (+a.planned_tonnes || 0), 0)
          : 0,
    [$, m] = S.useState(!1);
  let v = null;
  j && j.volume_t != null && p != null && y + p > +j.volume_t
    ? (v = `по поручению ${j.order_no} уже запланировано ${q(qe(y))} кг из ${q(qe(+j.volume_t))} кг — с этой заявкой станет ${q(qe(y + p))} кг (превышение объёма)`)
    : j && (s.cult || "").trim() && !_s(s.cult, j.cargo)
      ? (v = `культура «${s.cult}» не совпадает с грузом поручения ${j.order_no} («${j.cargo || "—"}»)`)
      : s.adate && s.adate < Hs() && (v = "дата прихода в прошлом — проверь дату");
  const U = async () => {
    var E, a;
    try {
      if (!j) throw new Error("Выбери поручение — организация, договор и груз подтянутся из него");
      const f = De(s.veh);
      if (!f) throw new Error("Укажи номер машины");
      if (!xs(f) && !$) throw new Error(`Номер машины «${f}» — ${Dt(f)}. Исправь или отметь «номер нестандартный» внизу формы.`);
      const P = De(s.trl);
      if (P && !zs(P) && !$) throw new Error(`Номер прицепа «${P}» — ${Dt(P, 1)}. Исправь или отметь «номер нестандартный» внизу формы.`);
      if ((s.cult || "").trim() && !_s(s.cult, j.cargo))
        throw new Error(
          `Культура «${s.cult}» не совпадает с грузом поручения ${j.order_no} («${j.cargo || "—"}»). Исправь культуру или выбери другое поручение.`,
        );
      if (j.volume_t != null && p != null && y + p > +j.volume_t && !$)
        throw new Error(
          `Превышение объёма поручения ${j.order_no}: запланировано ${q(qe(y))} из ${q(qe(+j.volume_t))} кг, с этой заявкой станет ${q(qe(y + p))} кг. Отметь «подтверждаю превышение» внизу формы или уменьши вес.`,
        );
      const T = es(s.tons, "Вес (план), кг");
      if (T != null && T <= 0) throw new Error("Вес должен быть больше нуля");
      if (T != null && T < 500) throw new Error("Вес вводится в килограммах — проверь значение (похоже на тонны)");
      (x(!0), b(null));
      const H = await Y(
        A.from("term_requests")
          .insert({
            order_id: j.id,
            client: ((a = (E = j.term_contracts) == null ? void 0 : E.term_counterparties) == null ? void 0 : a.name) || null,
            culture: (s.cult || "").trim() || j.cargo || null,
            vehicle_no: f,
            trailer_no: De(s.trl) || null,
            planned_tonnes: T == null ? null : T / 1e3,
            arrive_date: s.adate || null,
            driver: (s.drv || "").trim() || null,
            driver_phone: gn(s.ph) || null,
            purchase_contract: (s.pc || "").trim() || null,
            supplier: (s.sup || "").trim() || null,
            status: "expected",
            created_by: t.me.id,
            priority: (s.prio || "").trim() || null,
          })
          .select("id"),
      );
      (await Cn("request", H[0].id, i, t.me.id),
        j.volume_t != null &&
          p != null &&
          y + p > +j.volume_t &&
          (await je(
            "request",
            H[0].id,
            "volume_override",
            {
              поручение: j.order_no,
              план: qe(y),
              объём: qe(+j.volume_t),
              заявка: T,
            },
            t.me,
          )),
        l({
          ord: s.ord,
        }),
        zt("draft.req"),
        u([]),
        t.reload(),
        t.freload(),
        n());
    } catch (f) {
      (b(String(f.message || f)), x(!1));
    }
  };
  return (
    <Ss
      title="Новая заявка · машина под поручение"
      hint="выбери поручение — остальное подтянется · знакомая машина автозаполнит прицеп, водителя, контакт и поставщика из прошлых заявок"
      onClose={n}
      onSave={U}
      onClear={() => {
        (l({}), zt("draft.req"));
      }}
      busy={o}
      err={N}
      warn={v}
    >
      <CJt id="dl-veh" items={d} />
      <CJt id="dl-drv" items={M} />
      <CJt id="dl-sup" items={z} />
      <CJt id="dl-pc" items={_} />
      <X label="Поручение *">
        <CPe
          value={s.ord || ""}
          onChange={(E) =>
            l((a) => {
              const f = t.ords.find((P) => String(P.id) === String(E));
              return {
                ...a,
                ord: E,
                cult: (a.cult || "").trim() ? a.cult : (f == null ? void 0 : f.cargo) || "",
              };
            })
          }
          options={t.ords.map((E) => {
            var a, f;
            return [
              E.id,
              `${(f = (a = E.term_contracts) == null ? void 0 : a.term_counterparties) == null ? void 0 : f.name} · ${E.order_no} · ${E.cargo || ""}`,
            ];
          })}
          w={320}
        />
      </X>
      <X label="Культура (из поручения)">
        <Wt
          w={200}
          ph={(j == null ? void 0 : j.cargo) || "— выбери культуру —"}
          options={Fe([...(j != null && j.cargo ? [j.cargo] : []), ...Ft(), ...t.ords.map((E) => E.cargo)])}
          value={s.cult}
          addTitle="Культуры нет в списке"
          addPrompt="Культура (как писать в документах):"
          onChange={(E) =>
            l((a) => ({
              ...a,
              cult: E,
            }))
          }
        />
      </X>
      <X label="Машина (госномер) *">
        <input
          list="dl-veh"
          style={{
            width: 150,
            minWidth: 150,
          }}
          placeholder="О854ВВ126"
          value={s.veh ?? ""}
          onChange={(E) => h(De(E.target.value))}
        />
      </X>
      {Dt(s.veh) && (
        <p
          className="p-sub"
          style={{
            margin: 0,
            color: "var(--warn)",
          }}
        >
          номер машины: {Dt(s.veh)}
        </p>
      )}
      <X label="Прицеп">
        <input
          style={{
            width: 150,
            minWidth: 150,
          }}
          placeholder="АВ123477"
          value={s.trl ?? ""}
          onChange={(E) =>
            l((a) => ({
              ...a,
              trl: De(E.target.value),
            }))
          }
        />
      </X>
      {Dt(s.trl, 1) && (
        <p
          className="p-sub"
          style={{
            margin: 0,
            color: "var(--warn)",
          }}
        >
          номер прицепа: {Dt(s.trl, 1)}
        </p>
      )}
      <X label="Вес (план), кг">{Se(s, l, "tons", "например 45000", 120)}</X>
      <X label="Дата прихода (план)">
        <input
          type="date"
          value={s.adate || ""}
          onChange={(E) =>
            l((a) => ({
              ...a,
              adate: E.target.value,
            }))
          }
        />
      </X>
      <X label="ФИО водителя">
        <input
          list="dl-drv"
          style={{
            width: 200,
            minWidth: 200,
          }}
          value={s.drv ?? ""}
          onChange={(E) =>
            l((a) => ({
              ...a,
              drv: E.target.value,
            }))
          }
        />
      </X>
      <X label="Контакт водителя">{Se(s, l, "ph", "+7 …", 150)}</X>
      <X label="Контракт закупочный">
        <Wt
          w={210}
          ph="— выбери контракт —"
          options={_}
          value={s.pc}
          addTitle="Новый закупочный контракт"
          addPrompt="Номер закупочного контракта:"
          onChange={(E) =>
            l((a) => ({
              ...a,
              pc: E,
            }))
          }
        />
      </X>
      <X label="Отправитель (поставщик)">
        <Wt
          w={230}
          ph="— выбери поставщика —"
          options={z}
          value={s.sup}
          addTitle="Новый поставщик"
          addPrompt="Отправитель (поставщик):"
          onChange={(E) =>
            l((a) => ({
              ...a,
              sup: E,
            }))
          }
        />
      </X>
      <X label="Очередность выгрузки (1, 2, 3… / 1н — ночь)">{Se(s, l, "prio", "", 140)}</X>
      <C$n pend={i} setPend={u} />
      {j && (
        <p className="ordinfo">
          Организация: <b>{(I = (Z = j.term_contracts) == null ? void 0 : Z.term_counterparties) == null ? void 0 : I.name}</b> · договор{" "}
          <b>{(D = j.term_contracts) == null ? void 0 : D.contract_no}</b> · груз <b>{j.cargo || "—"}</b>
          {j.volume_t != null ? (
            <>
              {" "}
              · запланировано <b>{q(qe(y))}</b> из <b>{q(qe(+j.volume_t))}</b> кг
            </>
          ) : null}
        </p>
      )}
      {v && /превышение объёма/i.test(v) && (
        <label className="fkey">
          <input type="checkbox" checked={$} onChange={(E) => m(E.target.checked)} /> подтверждаю превышение объёма поручения
        </label>
      )}
      {((s.veh || "").trim() && !xs(s.veh)) || ((s.trl || "").trim() && !zs(s.trl)) ? (
        <label className="fkey">
          <input type="checkbox" checked={$} onChange={(E) => m(E.target.checked)} /> номер нестандартный (иностранный или спецтехника) — сохранить
          как есть
        </label>
      ) : null}
    </Ss>
  );
}
function CRr({ D: t, onClose: n }) {
  const [s, l] = S.useState(null),
    [i, u] = S.useState(""),
    [o, x] = S.useState(!1),
    [N, b] = S.useState(null),
    [j, g] = S.useState(null),
    [d, M] = S.useState(!1),
    [z, _] = S.useState("auto"),
    h = (E) => (E == null ? null : Math.round(z === "t" ? E * 1e3 : z === "kg" || E > 500 ? E : E * 1e3)),
    w = t.ords.find((E) => String(E.id) === String(i)),
    p = S.useMemo(() => (!w || !s ? [] : s.filter((E) => !_s(E.cult, w.cargo))), [s, w]),
    F = S.useMemo(() => [...new Set(p.map((E) => E.cult || "(пусто)"))], [p]),
    C = S.useMemo(() => {
      if (!s) return [];
      const E = new Map(),
        a = [];
      for (const f of s) {
        const P = f.veh + "|" + (f.adate || "");
        E.has(P) ? a.push(f) : E.set(P, f);
      }
      return a;
    }, [s]),
    y = S.useMemo(() => {
      if (!s || !w) return [];
      const E = new Set(t.reqs.filter((a) => !a.deleted_at).map((a) => De(a.vehicle_no) + "|" + (a.arrive_date || "")));
      return s.filter((a) => E.has(a.veh + "|" + (a.adate || "")));
    }, [s, w, t.reqs]),
    [$, m] = S.useState(null);
  S.useEffect(() => {
    if (!w) {
      m(null);
      return;
    }
    let E = !1;
    return (
      Y(
        A.rpc("term_order_planned_kg", {
          p_order: w.id,
        }),
      )
        .then((a) => {
          E || m(+a || 0);
        })
        .catch(() => {}),
      () => {
        E = !0;
      }
    );
  }, [w && w.id]);
  const v = S.useMemo(() => (s || []).reduce((E, a) => E + (h(a.w0) || 0), 0), [s, z]),
    U = w && w.volume_t != null && $ != null && $ + v > +w.volume_t * 1e3,
    Z = S.useMemo(() => (s ? t.ords.filter((E) => s.every((a) => _s(a.cult, E.cargo))) : []), [s, t.ords]),
    I = async (E) => {
      (b(null), l(null));
      try {
        const a = (await import("exceljs")).default || (await import("exceljs")),
          f = new a.Workbook();
        await f.xlsx.load(await E.arrayBuffer());
        const P = f.worksheets[0],
          T = [];
        let H = null;
        if (
          (P.eachRow((Q) => {
            const ae = [];
            Q.eachCell(
              {
                includeEmpty: !0,
              },
              (K, le) => {
                ae[le - 1] = K.value;
              },
            );
            const me = (K) => {
              const le = ae[K];
              return le == null
                ? ""
                : typeof le == "object" && le.richText
                  ? le.richText.map(($e) => $e.text).join("")
                  : le instanceof Date
                    ? le.toISOString().slice(0, 10)
                    : String(le).trim();
            };
            if (!H) {
              const K = ae.map((le) => String(le || "").toLowerCase());
              K.some((le) => le.includes("контракт")) &&
                K.some((le) => le.includes("машин")) &&
                (H = {
                  pc: K.findIndex((le) => le.includes("контракт")),
                  sup: K.findIndex((le) => le.includes("поставщик")),
                  cult: K.findIndex((le) => le.includes("товар") || le.includes("культур")),
                  ad: K.findIndex((le) => le.includes("прихода")),
                  w: K.findIndex((le) => le.includes("вес")),
                  unl: K.findIndex((le) => le.includes("выгрузк")),
                  mk: K.findIndex((le) => le.includes("марка")),
                  veh: K.findIndex((le) => le.includes("машины")),
                  trl: K.findIndex((le) => le.includes("прицеп")),
                  drv: K.findIndex((le) => le.includes("фио") || le.includes("водител")),
                  ph: K.findIndex((le) => le.includes("телефон")),
                  ps: K.findIndex((le) => le.includes("паспорт")),
                  prio: K.findIndex((le) => le.includes("очеред") || le.includes("приоритет") || le.includes("очер.")),
                });
              return;
            }
            const L = De(me(H.veh));
            if (!L) return;
            const W = te(me(H.w));
            T.push({
              pc: me(H.pc),
              sup: me(H.sup),
              cult: me(H.cult),
              adate:
                (me(H.ad).match(/^\d{4}-\d{2}-\d{2}/) || [null])[0] ||
                (me(H.ad).match(/(\d{2})[./](\d{2})[./](\d{4})/) ? me(H.ad).replace(/(\d{2})[./](\d{2})[./](\d{4}).*/, "$3-$2-$1") : null),
              w0: W,
              unl: me(H.unl),
              mk: me(H.mk),
              veh: L,
              trl: De(me(H.trl)),
              drv: me(H.drv),
              ph: gn(me(H.ph)),
              ps: me(H.ps),
              prio: H.prio >= 0 ? me(H.prio) : "",
            });
          }),
          !H)
        )
          throw new Error("Не распознал шапку — нужен формат «Реестр машин» (колонки: № Контракт, Поставщик, Товар, …, Номер машины)");
        if (!T.length) throw new Error("Строк с машинами не найдено");
        l(T);
      } catch (a) {
        b(String(a.message || a));
      }
    },
    D = async () => {
      try {
        if (!w) throw new Error("Выбери поручение, к которому привязать машины");
        if (p.length && !d)
          throw new Error(
            `Товар в реестре не совпадает с грузом поручения ${w.order_no} («${w.cargo || "—"}»): ${F.join(", ")} — строк ${p.length}. Выбери верное поручение или исправь файл.`,
          );
        if (y.length && !d)
          throw new Error(
            `${y.length} машин из файла уже заведены на эту дату (${y
              .slice(0, 4)
              .map((a) => a.veh)
              .join(", ")}${y.length > 4 ? "…" : ""}) — похоже, этот реестр уже загружали. Проверь или отметь галочку.`,
          );
        if (C.length && !d)
          throw new Error(
            `В самом файле повторяются машины: ${C.slice(0, 4)
              .map((a) => a.veh)
              .join(", ")}${C.length > 4 ? "…" : ""}`,
          );
        if (U && !d)
          throw new Error(
            `Превышение объёма поручения ${w.order_no}: запланировано ${q($)} кг + ${q(v)} кг из файла = ${q($ + v)} кг при объёме ${q(+w.volume_t * 1e3)} кг.`,
          );
        (x(!0), b(null));
        const E = s.map((a) => {
          var f, P;
          return {
            order_id: w.id,
            client: ((P = (f = w.term_contracts) == null ? void 0 : f.term_counterparties) == null ? void 0 : P.name) || null,
            culture: a.cult || w.cargo || null,
            vehicle_no: a.veh,
            trailer_no: a.trl || null,
            planned_tonnes: h(a.w0) == null ? null : h(a.w0) / 1e3,
            arrive_date: a.adate,
            driver: a.drv || null,
            driver_phone: a.ph || null,
            purchase_contract: a.pc || null,
            supplier: a.sup || null,
            status: "expected",
            created_by: t.me.id,
            priority: (a.prio || "").trim() || null,
            notes:
              [a.mk ? "Марка: " + a.mk : null, a.unl ? "Выгрузка: " + a.unl : null, a.ps ? "Паспорт: " + a.ps : null].filter(Boolean).join(" · ") ||
              null,
          };
        });
        (await Y(A.from("term_requests").insert(E)), g(E.length), x(!1), t.reload());
      } catch (E) {
        (b(String(E.message || E)), x(!1));
      }
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={(E) => {
        E.target === E.currentTarget && n();
      }}
    >
      <div
        className="modal"
        style={{
          width: 860,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Импорт заявок из Excel · Реестр машин</h2>
          <button className="btn sec sm" onClick={n}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <p className="p-sub">
            формат файла — «Реестр_машин»: № Контракт · Поставщик · Товар · Даты · Вес · Вид выгрузки · Марка · Номер машины · Прицеп · ФИО · Телефон
            · Паспорт — каждая строка станет заявкой · колонка «Очередность» (или «Приоритет»), если она есть, тоже подхватывается
          </p>
          <div
            className="row"
            style={{
              marginBottom: 10,
            }}
          >
            <X label="Файл реестра (.xlsx)">
              <input type="file" accept=".xlsx,.xls" onChange={(E) => E.target.files[0] && I(E.target.files[0])} />
            </X>
            <X label="Вес в файле указан в">
              <CPe
                value={z}
                onChange={_}
                w={200}
                options={[
                  ["auto", "определить автоматически"],
                  ["kg", "килограммах"],
                  ["t", "тоннах"],
                ]}
              />
            </X>
            <X label="Поручение (для привязки) *">
              <CPe
                value={i}
                onChange={u}
                options={t.ords.map((E) => {
                  var a, f;
                  return [
                    E.id,
                    `${(f = (a = E.term_contracts) == null ? void 0 : a.term_counterparties) == null ? void 0 : f.name} · ${E.order_no} · ${E.cargo || ""}`,
                  ];
                })}
                w={320}
              />
            </X>
          </div>
          {N && <p className="err">{N}</p>}
          {j != null && <p className="ok">Создано заявок: {j} — они уже видны КПП в «ожидаемых»</p>}
          {s && j == null && (
            <>
              <p
                className="p-sub"
                style={{
                  margin: "4px 0 6px",
                }}
              >
                распознано машин: <b>{s.length}</b> · проверь и подтверди
              </p>
              {w && p.length > 0 && (
                <div
                  className="err"
                  style={{
                    marginBottom: 8,
                  }}
                >
                  <b>Товар не совпадает с поручением.</b> В поручении {w.order_no} груз «{w.cargo || "—"}», а в реестре —{" "}
                  {F.map((E) => "«" + E + "»").join(", ")} ({p.length} стр. из {s.length}, отмечены красным).
                  {Z.length > 0 && (
                    <div
                      style={{
                        marginTop: 5,
                      }}
                    >
                      Подходящие поручения:{" "}
                      {Z.slice(0, 4).map((E) => (
                        <button
                          className="btn sec sm"
                          style={{
                            marginRight: 5,
                          }}
                          onClick={() => {
                            (u(String(E.id)), M(!1), b(null));
                          }}
                        >
                          {E.order_no} · {E.cargo}
                        </button>
                      ))}
                    </div>
                  )}
                  <label
                    className="fkey"
                    style={{
                      marginTop: 6,
                    }}
                  >
                    <input type="checkbox" checked={d} onChange={(E) => M(E.target.checked)} /> всё равно импортировать (товар возьмём из файла, под
                    мою ответственность)
                  </label>
                </div>
              )}
              {w && s.length > 0 && p.length === 0 && (
                <p
                  className="ok"
                  style={{
                    marginBottom: 8,
                  }}
                >
                  ✓ товар в реестре совпадает с грузом поручения «{w.cargo || "—"}»
                </p>
              )}
              {(y.length > 0 || C.length > 0 || U) && (
                <div
                  className="err"
                  style={{
                    marginBottom: 8,
                  }}
                >
                  {y.length > 0 && (
                    <div>
                      <b>Похоже, этот реестр уже загружали.</b> Уже есть заявки на те же машины и даты:{" "}
                      {y
                        .slice(0, 6)
                        .map((E) => E.veh)
                        .join(", ")}
                      {y.length > 6 ? ` и ещё ${y.length - 6}` : ""} ({y.length} из {s.length}).
                    </div>
                  )}
                  {C.length > 0 && (
                    <div>
                      В файле повторяются машины:{" "}
                      {C.slice(0, 6)
                        .map((E) => E.veh)
                        .join(", ")}
                      .
                    </div>
                  )}
                  {U && (
                    <div>
                      Превышение объёма поручения {w.order_no}: {q($)} кг уже запланировано + {q(v)} кг из файла = <b>{q($ + v)}</b> кг при объёме{" "}
                      {q(+w.volume_t * 1e3)} кг.
                    </div>
                  )}
                  <label
                    className="fkey"
                    style={{
                      marginTop: 5,
                    }}
                  >
                    <input type="checkbox" checked={d} onChange={(E) => M(E.target.checked)} /> всё равно импортировать — под мою ответственность
                  </label>
                </div>
              )}
              {w && s.length > 0 && $ != null && w.volume_t != null && !U && (
                <p
                  className="p-sub"
                  style={{
                    margin: "0 0 8px",
                  }}
                >
                  по поручению станет {q($ + v)} из {q(+w.volume_t * 1e3)} кг
                </p>
              )}
              <div
                className="tscroll"
                style={{
                  maxHeight: "40vh",
                }}
              >
                <table>
                  <thead>
                    <tr>
                      <th>Контракт</th>
                      <th>Поставщик</th>
                      <th>Товар</th>
                      <th>Дата прихода</th>
                      <th className="right">Вес, кг</th>
                      <th>Машина</th>
                      <th>Прицеп</th>
                      <th>Водитель</th>
                      <th>Телефон</th>
                      <th>Очер.</th>
                    </tr>
                  </thead>
                  <tbody>
                    {s.map((E, a) => (
                      <tr className={p.includes(E) ? "badrow" : void 0}>
                        <td>{E.pc || "—"}</td>
                        <td>{E.sup || "—"}</td>
                        <td className={p.includes(E) ? "badcell" : void 0}>
                          {E.cult || "—"}
                          {p.includes(E) ? " ⚠" : ""}
                        </td>
                        <td>{E.adate || "—"}</td>
                        <td className="right">{h(E.w0) ? q(h(E.w0)) : "—"}</td>
                        <td>
                          <b>{E.veh}</b>
                        </td>
                        <td>{E.trl || "—"}</td>
                        <td>{E.drv || "—"}</td>
                        <td>{E.ph || "—"}</td>
                        <td>{E.prio || "—"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <div className="m-foot">
                <button className="btn" disabled={o || !w || ((p.length > 0 || y.length > 0 || C.length > 0 || U) && !d)} onClick={D}>
                  {o ? "Создаю…" : `Создать ${s.length} заявок`}
                </button>
                {!w && (
                  <span
                    className="p-sub"
                    style={{
                      margin: 0,
                    }}
                  >
                    выбери поручение
                  </span>
                )}
                {w && p.length > 0 && !d && (
                  <span
                    className="p-sub"
                    style={{
                      margin: 0,
                    }}
                  >
                    импорт заблокирован: товар не совпадает с поручением
                  </span>
                )}
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}
function CBl({ D: t }) {
  const [n, s] = S.useState(!1),
    [l, i] = S.useState(null),
    [u, o] = S.useState(null),
    [x, N] = S.useState(() => ut("reg_cp", "flt")),
    [b, j] = S.useState(null),
    g = S.useMemo(() => new Set(t.ctrs.map((w) => w.counterparty_id)), [t.ctrs]),
    d = Pt("Поиск: наименование, ИНН, ОГРН, директор, банк, счёт…", ut("reg_cp", "q")),
    { TH: M, apply: z } = rt(),
    _ = z(
      t.cps
        .filter((w) => !x || (x === "with" ? g.has(w.id) : !g.has(w.id)))
        .filter((w) => d.test(w.name, w.inn, w.ogrn, w.director, w.legal_address, w.bank_name, w.bik, w.corr_account, w.settle_account, w.kpp)),
      {
        name: (w) => w.name,
        inn: (w) => w.inn,
        dir: (w) => w.director,
        bank: (w) => w.bank_name,
        nc: (w) => t.ctrs.filter((p) => p.counterparty_id === w.id).length,
      },
    );
  d.enterRef.current = _.length === 1 ? () => o(_[0]) : null;
  const h = [
    {
      k: "name",
      t: "Наименование",
      req: 1,
      w: 230,
    },
    {
      k: "inn",
      t: "ИНН",
      w: 110,
    },
    {
      k: "ogrn",
      t: "ОГРН",
      w: 130,
    },
    {
      k: "director",
      t: "Директор",
      w: 180,
    },
    {
      k: "legal_address",
      t: "Юридический адрес",
      w: 260,
    },
    {
      k: "bank_name",
      t: "Банк",
      w: 200,
    },
    {
      k: "corr_account",
      t: "К/с",
      w: 180,
    },
    {
      k: "settle_account",
      t: "Р/с",
      w: 180,
    },
    {
      k: "bik",
      t: "БИК",
      w: 110,
    },
  ];
  return (
    <>
      {n && <CSr D={t} onClose={() => s(!1)} />}
      {l && (
        <CAt
          title={`Контрагент · ${l.name}`}
          fields={h}
          row={l}
          table="term_counterparties"
          onClose={() => i(null)}
          onDone={() => {
            (j({
              ok: "Изменения сохранены",
            }),
              t.reload());
          }}
        />
      )}
      {u && <CHr cp={u} D={t} onClose={() => o(null)} />}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Реестр контрагентов · {Vt(d, _.length, t.cps.length)}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            {mt("cp") && (
              <button className="btn sm" onClick={() => s(!0)}>
                + Контрагент
              </button>
            )}
            <Je
              make={() =>
                Ze("Контрагенты", [
                  {
                    name: "Контрагенты",
                    title: "ФЕНИКС · Терминал — Реестр контрагентов",
                    cols: [
                      {
                        h: "Наименование",
                        w: 30,
                      },
                      {
                        h: "ИНН",
                        w: 14,
                      },
                      {
                        h: "ОГРН",
                        w: 16,
                      },
                      {
                        h: "Директор",
                        w: 22,
                      },
                      {
                        h: "Юр. адрес",
                        w: 34,
                      },
                      {
                        h: "Банк",
                        w: 24,
                      },
                      {
                        h: "К/с",
                        w: 22,
                      },
                      {
                        h: "Р/с",
                        w: 22,
                      },
                      {
                        h: "БИК",
                        w: 12,
                      },
                    ],
                    rows: _.map((w) => [w.name, w.inn, w.ogrn, w.director, w.legal_address, w.bank_name, w.corr_account, w.settle_account, w.bik]),
                  },
                ])
              }
            />
            <button
              className="btn sec sm"
              onClick={() =>
                ns(
                  "Контрагенты",
                  ["Наименование", "ИНН", "ОГРН", "Директор", "Юр. адрес", "Банк", "К/с", "Р/с", "БИК"],
                  _.map((w) => [w.name, w.inn, w.ogrn, w.director, w.legal_address, w.bank_name, w.corr_account, w.settle_account, w.bik]),
                )
              }
            >
              ⇩ CSV
            </button>
          </span>
        </div>
        <p className="p-sub">
          клик по строке — карточка контрагента: реквизиты, договоры, поручения, заявки и вложения{mt("cp") ? " · ✎ — правка" : Mi}
        </p>
        <div className="findrow">
          {d.Find}
          <Yt
            win="reg_cp"
            params={{
              q: d.q,
              flt: x,
            }}
          />
        </div>
        <Tt
          val={x}
          onSel={N}
          items={[
            {
              k: "with",
              t: "С договорами",
              n: t.cps.filter((w) => g.has(w.id)).length,
            },
            {
              k: "no",
              t: "Без договоров",
              n: t.cps.filter((w) => !g.has(w.id)).length,
            },
          ]}
        />
        <CFe err={t.err} />
        <CFe {...(b || {})} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <M k="name">Наименование</M>
                <M k="inn">ИНН</M>
                <th>ОГРН</th>
                <M k="dir">Директор</M>
                <M k="bank">Банк</M>
                <th>БИК</th>
                <M k="nc" right={!0}>
                  Договоров
                </M>
                <th />
              </tr>
            </thead>
            <tbody>
              {_.map((w) => {
                const p = t.ctrs.filter((F) => F.counterparty_id === w.id);
                return (
                  <>
                    <tr className="rowx" title="Открыть карточку контрагента" onClick={() => o(w)}>
                      <td>
                        <b>{w.name}</b>
                      </td>
                      <td>{w.inn || "—"}</td>
                      <td>{w.ogrn || "—"}</td>
                      <td>{w.director || "—"}</td>
                      <td>{w.bank_name || "—"}</td>
                      <td>{w.bik || "—"}</td>
                      <td className="right">{p.length}</td>
                      <td className="nowrap">
                        {mt("cp") && (
                          <>
                            <Ye onClick={() => i(w)} />{" "}
                            <Jt
                              onClick={() =>
                                En(
                                  "term_counterparties",
                                  w.id,
                                  `контрагента «${w.name}»`,
                                  "у контрагента есть договоры — сначала удали их",
                                  t.reload,
                                  j,
                                )
                              }
                            />
                          </>
                        )}
                      </td>
                    </tr>
                  </>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
function CKl({ D: t }) {
  const [n, s] = S.useState(!1),
    [l, i] = S.useState(null),
    [u, o] = S.useState(null),
    [x, N] = S.useState(null),
    [b, j] = S.useState(null),
    [g, d] = S.useState(null),
    M = S.useMemo(() => new Set(t.ords.map((F) => F.contract_id)), [t.ords]),
    z = Pt("Поиск: номер договора, организация, дата…", ut("reg_ctr", "q")),
    { TH: C_, apply: h } = rt(),
    w = h(
      t.ctrs
        .filter((F) => !b || (b === "with" ? M.has(F.id) : !M.has(F.id)))
        .filter((F) => {
          var C, y;
          return z.test(
            F.contract_no,
            F.contract_date,
            (C = F.term_counterparties) == null ? void 0 : C.name,
            (y = F.term_counterparties) == null ? void 0 : y.inn,
          );
        }),
      {
        org: (F) => {
          var C;
          return (C = F.term_counterparties) == null ? void 0 : C.name;
        },
        no: (F) => F.contract_no,
        dt: (F) => F.contract_date,
        no2: (F) => t.ords.filter((C) => C.contract_id === F.id).length,
      },
    );
  z.enterRef.current = w.length === 1 ? () => N(w[0]) : null;
  const p = [
    {
      k: "counterparty_id",
      t: "Контрагент",
      req: 1,
      type: "num",
      w: 240,
      opts: t.cps.map((F) => [F.id, F.name]),
    },
    {
      k: "contract_no",
      t: "Номер договора",
      req: 1,
      w: 160,
    },
    {
      k: "contract_date",
      t: "Дата договора",
      type: "date",
      w: 150,
    },
  ];
  return (
    <>
      {n && <CNr D={t} onClose={() => s(!1)} />}
      {l && (
        <Kt
          me={t.me}
          canAdd={mt("ctr")}
          entity="contract"
          id={l.id}
          title={`Договор ${l.contract_no} · вложения`}
          onClose={() => {
            (i(null), t.freload());
          }}
        />
      )}
      {u && (
        <CAt
          title={`Договор ${u.contract_no}`}
          fields={p}
          row={u}
          table="term_contracts"
          onClose={() => o(null)}
          onDone={() => {
            (d({
              ok: "Изменения сохранены",
            }),
              t.reload());
          }}
        />
      )}
      {x && <CUr ctr={x} D={t} onClose={() => N(null)} />}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Реестр договоров · {Vt(z, w.length, t.ctrs.length)}</h2>
          {mt("ctr") && (
            <button className="btn sm" onClick={() => s(!0)}>
              + Договор
            </button>
          )}
        </div>
        <p className="p-sub">клик по строке — карточка договора: поручения, заявки и скан договора · ✎ — правка</p>
        <div className="findrow">
          {z.Find}
          <Yt
            win="reg_ctr"
            params={{
              q: z.q,
              flt: b,
            }}
          />
        </div>
        <Tt
          val={b}
          onSel={j}
          items={[
            {
              k: "with",
              t: "С поручениями",
              n: t.ctrs.filter((F) => M.has(F.id)).length,
            },
            {
              k: "no",
              t: "Без поручений",
              n: t.ctrs.filter((F) => !M.has(F.id)).length,
            },
          ]}
        />
        <CFe err={t.err} />
        <CFe {...(g || {})} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <C_ k="org">Организация</C_>
                <C_ k="no">Номер</C_>
                <C_ k="dt">Дата</C_>
                <C_ k="no2" right={!0}>
                  Поручений
                </C_>
                <th />
              </tr>
            </thead>
            <tbody>
              {w.map((F) => {
                var y;
                const C = t.ords.filter(($) => $.contract_id === F.id);
                return (
                  <>
                    <tr className="rowx" title="Открыть карточку договора" onClick={() => N(F)}>
                      <td>
                        <b>{(y = F.term_counterparties) == null ? void 0 : y.name}</b>
                      </td>
                      <td>{F.contract_no}</td>
                      <td>{F.contract_date || "—"}</td>
                      <td className="right">{C.length}</td>
                      <td className="nowrap">
                        <CGt n={t.fcnt("contract", F.id)} onClick={() => i(F)} />
                        {mt("ctr") && (
                          <>
                            {" "}
                            <Ye onClick={() => o(F)} />{" "}
                            <Jt
                              onClick={() =>
                                En("term_contracts", F.id, `договор «${F.contract_no}»`, "по договору есть поручения — сначала удали их", t.reload, d)
                              }
                            />
                          </>
                        )}
                      </td>
                    </tr>
                  </>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
function CWl({ D: t }) {
  const [n, s] = S.useState(!1),
    [l, i] = S.useState(null),
    [u, o] = S.useState(null),
    [x, N] = S.useState(null),
    [b, j] = S.useState(null),
    [g, d] = S.useState(null),
    { list: M } = fs("surveyor"),
    z = (y) => {
      const $ = t.reqs.filter((m) => m.order_id === y.id);
      return $.length ? ($.some((m) => ["expected", "arrived", "open"].includes(m.status)) ? "act" : "done") : "no";
    },
    _ = Pt("Поиск: № поручения, груз, ТН ВЭД, организация, договор, страна…", ut("reg_ord", "q")),
    { TH: CH, apply: w } = rt(),
    p = w(
      t.ords
        .filter((y) => !b || z(y) === b)
        .filter((y) => {
          var $, m, v;
          return _.test(
            y.order_no,
            y.cargo,
            y.tnved,
            y.container_type,
            y.dest_country,
            y.survey,
            (y.extra_services || []).join(" "),
            ($ = y.term_contracts) == null ? void 0 : $.contract_no,
            (v = (m = y.term_contracts) == null ? void 0 : m.term_counterparties) == null ? void 0 : v.name,
          );
        }),
      {
        org: (y) => {
          var $, m;
          return (m = ($ = y.term_contracts) == null ? void 0 : $.term_counterparties) == null ? void 0 : m.name;
        },
        ctr: (y) => {
          var $;
          return ($ = y.term_contracts) == null ? void 0 : $.contract_no;
        },
        no: (y) => y.order_no,
        cargo: (y) => y.cargo,
        vol: (y) => (y.volume_t == null ? null : +y.volume_t),
        cn: (y) => (y.containers_n == null ? null : +y.containers_n),
        rate: (y) => (y.rate_per_t == null ? null : +y.rate_per_t),
        nr: (y) => t.reqs.filter(($) => $.order_id === y.id).length,
      },
    );
  _.enterRef.current = p.length === 1 ? () => N(p[0]) : null;
  const F = [
      {
        k: "contract_id",
        t: "Договор",
        req: 1,
        type: "num",
        w: 280,
        opts: t.ctrs.map((y) => {
          var $;
          return [y.id, `${($ = y.term_counterparties) == null ? void 0 : $.name} · дог. ${y.contract_no}`];
        }),
      },
      {
        k: "order_no",
        t: "№ поручения",
        req: 1,
        w: 140,
      },
      {
        k: "cargo",
        t: "Наименование груза",
        w: 210,
        opts: Fe([...Ft(), ...t.ords.map((y) => y.cargo)]).map((y) => [y, y]),
      },
      {
        k: "tnved",
        t: "Код ТН ВЭД",
        w: 120,
      },
      {
        k: "volume_t",
        t: "Объём, т",
        type: "num",
        w: 100,
      },
      {
        k: "containers_n",
        t: "Кол-во контейнеров",
        type: "num",
        w: 100,
      },
      {
        k: "container_type",
        t: "Тип контейнеров",
        w: 110,
      },
      {
        k: "load_norm_t",
        t: "Норма загрузки, т",
        type: "num",
        w: 110,
      },
      {
        k: "rate_per_t",
        t: "Ставка, $/т",
        type: "num",
        w: 110,
      },
      {
        k: "vat_pct",
        t: "Ставка НДС",
        type: "num",
        w: 200,
        opts: sl(u == null ? void 0 : u.vat_pct),
      },
      {
        k: "rate_valid_until",
        t: "Ставка действует до",
        type: "date",
        w: 150,
      },
      {
        k: "dest_country",
        t: "Страна назначения",
        w: 210,
        opts: Fe([...jn, ...t.ords.map((y) => y.dest_country)]).map((y) => [y, y]),
      },
      {
        k: "survey",
        t: "Сюрвей",
        w: 210,
        opts: Fe([...M, ...t.ords.map((y) => y.survey)]).map((y) => [y, y]),
      },
    ],
    C = {
      act: ["in", "Активные заявки"],
      done: ["left", "Заявки завершены"],
      no: ["new", "Без заявок"],
    };
  return (
    <>
      {n && <CLr D={t} onClose={() => s(!1)} />}
      {l && (
        <Kt
          me={t.me}
          canAdd={mt("ord")}
          entity="order"
          id={l.id}
          title={`Поручение ${l.order_no} · вложения`}
          onClose={() => {
            (i(null), t.freload());
          }}
        />
      )}
      {u && (
        <CAt
          title={`Поручение ${u.order_no}`}
          fields={F}
          row={u}
          table="term_orders"
          onClose={() => o(null)}
          onDone={() => {
            (d({
              ok: "Изменения сохранены",
            }),
              t.reload());
          }}
        />
      )}
      {x && <CMr ord={x} D={t} onClose={() => N(null)} />}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Реестр поручений · {Vt(_, p.length, t.ords.length)}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            {mt("ord") && (
              <button className="btn sm" onClick={() => s(!0)}>
                + Поручение
              </button>
            )}
            <Je
              make={() =>
                Ze("Поручения", [
                  {
                    name: "Поручения",
                    title: "ФЕНИКС · Терминал — Реестр поручений",
                    cols: [
                      {
                        h: "Организация",
                        w: 26,
                      },
                      {
                        h: "Договор",
                        w: 14,
                      },
                      {
                        h: "№ поручения",
                        w: 14,
                      },
                      {
                        h: "Груз",
                        w: 16,
                      },
                      {
                        h: "ТН ВЭД",
                        w: 12,
                      },
                      {
                        h: "Объём, т",
                        w: 12,
                        num: 1,
                      },
                      {
                        h: "Конт.",
                        w: 9,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Тип",
                        w: 10,
                      },
                      {
                        h: "Норма, т",
                        w: 11,
                        num: 1,
                      },
                      {
                        h: "Ставка $/т",
                        w: 12,
                        num: 1,
                      },
                      {
                        h: "НДС %",
                        w: 9,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Ставка до",
                        w: 12,
                      },
                      {
                        h: "Страна назнач.",
                        w: 16,
                      },
                      {
                        h: "Сюрвей",
                        w: 16,
                      },
                      {
                        h: "Доп. услуги",
                        w: 30,
                      },
                      {
                        h: "Статус",
                        w: 16,
                      },
                    ],
                    rows: p.map((y) => {
                      var $, m, v;
                      return [
                        (m = ($ = y.term_contracts) == null ? void 0 : $.term_counterparties) == null ? void 0 : m.name,
                        (v = y.term_contracts) == null ? void 0 : v.contract_no,
                        y.order_no,
                        y.cargo,
                        y.tnved,
                        y.volume_t,
                        y.containers_n,
                        y.container_type,
                        y.load_norm_t,
                        y.rate_per_t,
                        y.vat_pct,
                        y.rate_valid_until,
                        y.dest_country,
                        y.survey,
                        (y.extra_services || []).join(", "),
                        C[z(y)][1],
                      ];
                    }),
                  },
                ])
              }
            />
            <button
              className="btn sec sm"
              onClick={() =>
                ns(
                  "Поручения",
                  ["Организация", "Договор", "№ поручения", "Груз", "ТН ВЭД", "Объём т", "Конт.", "Тип", "Норма т", "Ставка $/т", "НДС %"],
                  p.map((y) => {
                    var $, m, v;
                    return [
                      (m = ($ = y.term_contracts) == null ? void 0 : $.term_counterparties) == null ? void 0 : m.name,
                      (v = y.term_contracts) == null ? void 0 : v.contract_no,
                      y.order_no,
                      y.cargo,
                      y.tnved,
                      y.volume_t,
                      y.containers_n,
                      y.container_type,
                      y.load_norm_t,
                      y.rate_per_t,
                      y.vat_pct,
                    ];
                  }),
                )
              }
            >
              ⇩ CSV
            </button>
          </span>
        </div>
        <p className="p-sub">клик по строке — карточка поручения: условия, план против факта, машины и заявки · ✎ — правка</p>
        <div className="findrow">
          {_.Find}
          <Yt
            win="reg_ord"
            params={{
              q: _.q,
              flt: b,
            }}
          />
        </div>
        <Tt
          val={b}
          onSel={j}
          items={[
            {
              k: "act",
              t: "С активными заявками",
              n: t.ords.filter((y) => z(y) === "act").length,
            },
            {
              k: "done",
              t: "Заявки завершены",
              n: t.ords.filter((y) => z(y) === "done").length,
            },
            {
              k: "no",
              t: "Без заявок",
              n: t.ords.filter((y) => z(y) === "no").length,
            },
          ]}
        />
        <CFe err={t.err} />
        <CFe {...(g || {})} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <CH k="org">Организация</CH>
                <CH k="ctr">Договор</CH>
                <CH k="no">№ поруч.</CH>
                <CH k="cargo">Груз</CH>
                <th>ТН ВЭД</th>
                <CH k="vol" right={!0}>
                  Объём, т
                </CH>
                <CH k="cn" right={!0}>
                  Конт.
                </CH>
                <th className="right">Норма, т</th>
                <CH k="rate" right={!0}>
                  Ставка $/т
                </CH>
                <th>Страна</th>
                <th>Сюрвей</th>
                <th>Доп. услуги</th>
                <CH k="nr" right={!0}>
                  Заявок
                </CH>
                <th>Статус</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {p.map((y) => {
                var v, U, Z;
                const $ = t.reqs.filter((I) => I.order_id === y.id),
                  m = z(y);
                return (
                  <>
                    <tr className="rowx" title="Открыть карточку поручения" onClick={() => N(y)}>
                      <td>
                        <b>{(U = (v = y.term_contracts) == null ? void 0 : v.term_counterparties) == null ? void 0 : U.name}</b>
                      </td>
                      <td>{(Z = y.term_contracts) == null ? void 0 : Z.contract_no}</td>
                      <td>
                        <b>{y.order_no}</b>
                      </td>
                      <td>{y.cargo || "—"}</td>
                      <td>{y.tnved || "—"}</td>
                      <td className="right">{y.volume_t ?? "—"}</td>
                      <td className="right">{y.containers_n ?? "—"}</td>
                      <td className="right">{y.load_norm_t ?? "—"}</td>
                      <td className="right">{y.rate_per_t ?? "—"}</td>
                      <td>{y.dest_country || "—"}</td>
                      <td>{y.survey || "—"}</td>
                      <td
                        style={{
                          maxWidth: 200,
                          whiteSpace: "normal",
                        }}
                      >
                        {(y.extra_services || []).join(", ") || "—"}
                      </td>
                      <td className="right">{$.length}</td>
                      <td>
                        <span className={"stage " + C[m][0]}>{C[m][1]}</span>
                      </td>
                      <td className="nowrap">
                        <CGt n={t.fcnt("order", y.id)} onClick={() => i(y)} />
                        {mt("ord") && (
                          <>
                            {" "}
                            <Ye onClick={() => o(y)} />{" "}
                            <Jt
                              onClick={() =>
                                En("term_orders", y.id, `поручение «${y.order_no}»`, "по поручению есть заявки — сначала удали их", t.reload, d)
                              }
                            />
                          </>
                        )}
                      </td>
                    </tr>
                  </>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
function vl(t) {
  const [n, s] = ne(() => Y(A.from("term_devices").select("*").eq("kind", t).order("id")), [t], 6e4, "dev." + t);
  return [n || [], s];
}
function Nl(t, n = 5e3) {
  const [s, l] = ne(
    () =>
      Y(
        A.from("term_device_events")
          .select("*")
          .eq("kind", t)
          .eq("status", "new")
          .order("at", {
            ascending: !1,
          })
          .limit(20),
      ),
    [t],
    n,
  );
  return [s || [], l];
}
function CYl({ devices: t }) {
  return t.length ? (
    <span
      className="row"
      style={{
        gap: 6,
        alignItems: "center",
      }}
    >
      {t.map((n) => {
        const s = ol(n),
          l = dl(n);
        return (
          <span
            className={"devdot" + (s ? " on" : n.enabled ? " off" : " dis")}
            title={`${n.title}${n.place ? " · " + n.place : ""}
${n.enabled ? (s ? "на связи" : l == null ? "ни разу не выходило на связь" : `молчит ${l} мин`) : "отключено в настройках"}`}
          >
            ● {n.title}
          </span>
        );
      })}
    </span>
  ) : null;
}
function CAr({ path: t, h: n = 132 }) {
  const [s, l] = S.useState(null);
  return (
    S.useEffect(() => {
      let i = !0;
      if (!t) {
        l(null);
        return;
      }
      if (/^https?:/.test(t)) {
        l(t);
        return;
      }
      return (
        fn(t, 3600)
          .then((u) => {
            i && l(u);
          })
          .catch(() => {}),
        () => {
          i = !1;
        }
      );
    }, [t]),
    t ? (
      s ? (
        <a href={s} target="_blank" rel="noreferrer">
          <img
            className="devshot"
            style={{
              height: n,
            }}
            src={s}
            alt="кадр распознавания"
          />
        </a>
      ) : (
        <div
          className="devshot none"
          style={{
            height: n,
          }}
        >
          загружаю кадр…
        </div>
      )
    ) : (
      <div
        className="devshot none"
        style={{
          height: n,
        }}
      >
        кадр не передан
      </div>
    )
  );
}
function Sl({ kind: t, rows: n, keysOf: s, label: l, actions: i, title: u, me: o, hint: x }) {
  var F;
  const [N] = vl(t),
    [b, j] = Nl(t),
    [g, d] = S.useState(!1),
    M = b[0],
    z = N.find((C) => C.stream_url && C.enabled);
  if (!N.length) return null;
  const _ = M ? Ni(M.value, n, s) : [],
    h = _.filter((C) => C.d === 0),
    w = _.filter((C) => C.d > 0),
    p = async () => {
      (d(!0), await hl(M, o).catch(() => {}), d(!1), j());
    };
  return (
    <div className="panel dev9">
      <div className="hd">
        <h2 className="p-title mt0">{u}</h2>
        <span
          className="row"
          style={{
            gap: 8,
            alignItems: "center",
          }}
        >
          <CYl devices={N} />
          {z && (
            <a className="btn sec sm" href={z.stream_url} target="_blank" rel="noreferrer">
              Живой поток
            </a>
          )}
          <button className="btn sec sm" onClick={j}>
            Обновить
          </button>
        </span>
      </div>
      <p className="p-sub">{x}</p>
      {M ? (
        <div className="devrow">
          <CAr path={M.photo_url} />
          <div className="devmain">
            <div
              className="row"
              style={{
                gap: 10,
                alignItems: "baseline",
              }}
            >
              <span className="devval">{M.value}</span>
              {M.raw && M.raw !== M.value ? <span className="faint">распознано: {M.raw}</span> : null}
              {M.confidence != null ? (
                <span className={"t2chip" + (+M.confidence >= 0.9 ? " ok" : "")}>уверенность {Math.round(+M.confidence * 100)}%</span>
              ) : null}
              {M.direction ? <span className="t2chip">{M.direction === "in" ? "въезд" : "выезд"}</span> : null}
              <span className="faint">
                {Ue(M.at)}
                {Ls(M) > 3 ? ` · ${Ls(M)} мин назад` : ""}
              </span>
            </div>
            {(F = M.meta) != null && F.warn ? <div className="devwarn">⚠ {M.meta.warn}</div> : null}
            {h.length > 0 && (
              <div className="devcands">
                {h.map(({ row: C }) => (
                  <div className="devcand ok">
                    <span className="dc-l">{l(C)}</span>
                    <span className="dc-a" onClick={ct}>
                      {i(C, M, j)}
                    </span>
                  </div>
                ))}
              </div>
            )}
            {!h.length && w.length > 0 && (
              <>
                <div className="devnote">точного совпадения нет · похожие (отличаются на {w[0].d} симв.) — сверьте с кадром:</div>
                <div className="devcands">
                  {w.map(({ row: C, d: y }) => (
                    <div className="devcand">
                      <span className="dc-l">
                        {l(C)} <span className="faint">· {y} отличие</span>
                      </span>
                      <span className="dc-a" onClick={ct}>
                        {i(C, M, j)}
                      </span>
                    </div>
                  ))}
                </div>
              </>
            )}
            {!_.length && (
              <div className="devnote none">
                среди ожидаемых и находящихся на терминале совпадений нет — оформите вручную кнопками в списке ниже, а это распознавание пропустите
              </div>
            )}
            <div
              className="row"
              style={{
                gap: 8,
                marginTop: 8,
              }}
            >
              <button className="btn sec sm" disabled={g} onClick={p}>
                ✕ Пропустить распознавание
              </button>
            </div>
          </div>
        </div>
      ) : (
        <div className="devwait">распознаваний нет · оформляйте заезд и выезд как обычно, кнопками в списке</div>
      )}
      {b.length > 1 && (
        <p
          className="p-sub"
          style={{
            margin: "8px 0 0",
          }}
        >
          ещё в очереди:{" "}
          {b
            .slice(1, 6)
            .map((C) => C.value)
            .join(" · ")}
          {b.length > 6 ? ` и ещё ${b.length - 6}` : ""}
        </p>
      )}
    </div>
  );
}
function CCr({ me: t, onTake: n, rows: s = [], rowLabel: l }) {
  const [i] = vl("weight"),
    [u, o] = Nl("weight", 4e3),
    [x, N] = S.useState(!1),
    [b, j] = S.useState("");
  if (!i.length) return null;
  const g = u[0],
    d = s.length === 1 ? s[0] : s.find((_) => String(_.id) === String(b)),
    M = async () => {
      if (d) {
        N(!0);
        try {
          (n(Math.round(+g.weight_kg), d), await Rs(g, "scale", d.id, t));
        } catch {}
        (N(!1), j(""), o());
      }
    },
    z = async () => {
      (N(!0), await hl(g, t).catch(() => {}), N(!1), o());
    };
  return (
    <div className="panel dev9">
      <div className="hd">
        <h2 className="p-title mt0">Весы · показание от весового софта</h2>
        <span
          className="row"
          style={{
            gap: 8,
            alignItems: "center",
          }}
        >
          <CYl devices={i} />
          <button className="btn sec sm" onClick={o}>
            Обновить
          </button>
        </span>
      </div>
      <p className="p-sub">
        показание приходит с компьютера весовой · выбери машину, которая сейчас стоит на весах, и нажми «Взять показание» — вес подставится в её поле,
        а сохранит его всё равно весовщик кнопкой «Брутто» или «Тара» · ввод руками и чтение COM-порта работают как работали
      </p>
      {g ? (
        <div
          className="row"
          style={{
            gap: 14,
            alignItems: "center",
            flexWrap: "wrap",
          }}
        >
          <span className="devval big">
            {q(Math.round(+g.weight_kg))}
            <span className="devunit">кг</span>
          </span>
          <span className={"t2chip" + (g.stable ? " ok" : "")}>{g.stable ? "вес устойчив" : "вес ещё меняется"}</span>
          <span className="faint">
            {Ue(g.at)}
            {Ls(g) > 2 ? ` · ${Ls(g)} мин назад` : ""}
          </span>
          {s.length > 1 && (
            <CPe value={b} onChange={j} w={230} ph="— в какую машину —" options={s.map((_) => [String(_.id), l ? l(_) : _.vehicle_no])} />
          )}
          <button
            className="btn sm"
            disabled={x || !g.stable || !d}
            title={g.stable ? (d ? "Подставить в поле веса" : "Выбери машину, которая стоит на весах") : "Показание ещё не устоялось"}
            onClick={M}
          >
            Взять показание →
          </button>
          <button className="btn sec sm" disabled={x} onClick={z}>
            ✕ Пропустить
          </button>
        </div>
      ) : (
        <div className="devwait">показаний нет · вводите вес руками или берите с COM-порта</div>
      )}
    </div>
  );
}
function or({ me: t }) {
  const [n, s, l] = ne(() => Y(A.from("term_devices").select("*").order("kind").order("id")), [], 2e4),
    [i, u] = ne(
      () =>
        Y(
          A.from("term_device_events")
            .select("*")
            .order("id", {
              ascending: !1,
            })
            .limit(40),
        ),
      [],
      1e4,
    ),
    [o, x] = S.useState(null),
    [N, b] = S.useState(!1),
    [j, g] = S.useState(null),
    [d, M] = S.useState({}),
    [z, _] = S.useState({}),
    [h, w] = S.useState(null),
    p = async (m) => {
      (b(!0), x(null));
      try {
        const v =
          m.kind === "weight"
            ? {
                kind: "weight",
                weight_kg: +(d.kg || 0),
                stable: d.stable !== !1,
              }
            : {
                kind: m.kind,
                raw: (d.val || "").trim(),
                confidence: d.conf ? +d.conf / 100 : 0.93,
                direction: d.dir || void 0,
              };
        if (m.kind !== "weight" && !v.raw) throw new Error("введи номер, который «распознала» камера");
        if (m.kind === "weight" && !(+d.kg > 0)) throw new Error("введи вес");
        const Z = await (
          await fetch(Vn, {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              "x-device-key": m.api_key,
            },
            body: JSON.stringify(v),
          })
        ).json();
        if (!Z.ok) throw new Error(Z.error || "точка приёма отказала");
        (x({
          ok: `Принято: ${Z.value}${Z.deduped ? " (склеено с предыдущим — дубль)" : ""}${Z.warn ? " · " + Z.warn : ""}. Смотри в рабочем окне ${m.kind === "weight" ? "весовой" : m.kind === "plate" ? "КПП" : "контейнеров"}.`,
        }),
          s(),
          u());
      } catch (v) {
        x({
          err: String(v.message || v),
        });
      }
      b(!1);
    },
    F = async (m) => {
      (b(!0), x(null));
      try {
        const U = await (
          await fetch(Vn, {
            headers: {
              "x-device-key": m.api_key,
            },
          })
        ).json();
        (x(
          U.ok
            ? {
                ok: `${m.title}: связь есть, устройство опознано`,
              }
            : {
                err: `${m.title}: ${U.error}`,
              },
        ),
          s());
      } catch (v) {
        x({
          err: `${m.title}: точка приёма недоступна — ${String(v.message || v)}`,
        });
      }
      b(!1);
    },
    C = async (m) => {
      if (!window.confirm(`Выдать ${m.title} новый ключ? Старый перестанет работать — его придётся заменить в настройках устройства.`)) return;
      const v =
        "dev_" +
        Array.from(crypto.getRandomValues(new Uint8Array(18)))
          .map((U) => U.toString(16).padStart(2, "0"))
          .join("");
      try {
        (await ue(
          A.from("term_devices")
            .update({
              api_key: v,
            })
            .eq("id", m.id),
          "устройство " + m.title,
        ),
          await je(
            "settings",
            null,
            "device_key",
            {
              устройство: m.id,
            },
            t,
          ),
          x({
            ok: `${m.title}: ключ заменён — впишите новый в настройках устройства`,
          }),
          s());
      } catch (U) {
        x({
          err: String(U.message || U),
        });
      }
    },
    y = async (m, v, U) => {
      try {
        (await ue(A.from("term_devices").update(v).eq("id", m.id), "устройство " + m.title),
          await je(
            "settings",
            null,
            "device_edit",
            {
              устройство: m.id,
              ...v,
            },
            t,
          ),
          s());
      } catch (Z) {
        x({
          err: String(Z.message || Z),
        });
      }
    },
    $ = [
      {
        k: "title",
        t: "Название",
        req: 1,
        w: 240,
      },
      {
        k: "place",
        t: "Где стоит",
        w: 220,
      },
      {
        k: "stream_url",
        t: "Ссылка на живой поток",
        w: 320,
      },
      {
        k: "min_conf",
        t: "Порог уверенности (0–1)",
        type: "num",
        w: 160,
      },
      {
        k: "notes",
        t: "Примечания",
        w: 320,
      },
    ];
  return (
    <>
      {h && (
        <CAt
          title={`Устройство · ${h.title}`}
          fields={$}
          row={h}
          table="term_devices"
          onClose={() => w(null)}
          onDone={() => {
            (x({
              ok: "Сохранено",
            }),
              s());
          }}
        />
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Устройства · камеры и весы · {(n || []).length}</h2>
          <button
            className="btn sec sm"
            onClick={() => {
              (s(), u());
            }}
          >
            Обновить
          </button>
        </div>
        <p className="p-sub">
          внешние устройства кладут распознавание в систему, а сотрудник подтверждает его кнопкой в своём окне ·{" "}
          <b>ручной ввод нигде не отменяется</b> · ключ выдаётся установщику, по нему устройство и опознаётся · полуавтомат по умолчанию выключен:
          включайте только после того, как посмотрите месяц на точность
        </p>
        <CFe err={l} />
        <CFe {...(o || {})} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <th>Устройство</th>
                <th>Тип</th>
                <th>Где стоит</th>
                <th>Связь</th>
                <th>Ключ</th>
                <th>Полуавтомат</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {(n || []).map((m) => {
                const v = ol(m),
                  U = dl(m);
                return (
                  <>
                    <tr className={m.enabled ? void 0 : "delrow"}>
                      <td>
                        <b>{m.title}</b>
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          {m.id}
                        </div>
                      </td>
                      <td>{vi[m.kind]}</td>
                      <td>{m.place || "—"}</td>
                      <td className="nowrap">
                        {m.enabled ? (
                          v ? (
                            <span className="stage tare">на связи</span>
                          ) : U == null ? (
                            <span className="stage in">ещё не подключалось</span>
                          ) : (
                            <span className="stage lab_no">молчит {U} мин</span>
                          )
                        ) : (
                          <span className="stage cancel">отключено</span>
                        )}
                        {m.last_error ? (
                          <div
                            className="faint"
                            style={{
                              fontSize: 10,
                              color: "var(--bad)",
                            }}
                          >
                            {m.last_error}
                          </div>
                        ) : null}
                      </td>
                      <td className="nowrap">
                        {z[m.id] ? (
                          <code
                            style={{
                              fontSize: 10,
                            }}
                          >
                            {m.api_key}
                          </code>
                        ) : (
                          <span className="faint">••••••••</span>
                        )}{" "}
                        <button
                          className="btn sec sm icon"
                          title="Показать / скрыть"
                          onClick={() =>
                            _((Z) => ({
                              ...Z,
                              [m.id]: !Z[m.id],
                            }))
                          }
                        >
                          👁
                        </button>{" "}
                        <button
                          className="btn sec sm icon"
                          title="Скопировать"
                          onClick={() => {
                            var Z;
                            return (Z = navigator.clipboard) == null
                              ? void 0
                              : Z.writeText(m.api_key).then(() =>
                                  x({
                                    ok: "Ключ скопирован",
                                  }),
                                );
                          }}
                        >
                          ⧉
                        </button>{" "}
                        <button className="btn sec sm icon" title="Выдать новый ключ" onClick={() => C(m)}>
                          ⟳
                        </button>
                      </td>
                      <td className="nowrap">
                        <label
                          className="row"
                          style={{
                            gap: 5,
                            alignItems: "center",
                            fontSize: 11,
                          }}
                        >
                          <input
                            type="checkbox"
                            checked={!!m.auto_ok}
                            onChange={(Z) => {
                              (Z.target.checked &&
                                !window.confirm(`Включить полуавтомат для «${m.title}»?

Система будет сама фиксировать заезд и выезд, когда распознавание однозначно совпало с ожидаемой заявкой и уверенность выше ${Math.round((+m.min_conf || 0.9) * 100)}%. Каждый такой случай пишется в журнал изменений, и его можно откатить.

Рекомендуется включать только после месяца работы по кнопке.`)) ||
                                y(m, {
                                  auto_ok: Z.target.checked,
                                });
                            }}
                          />
                          {m.auto_ok ? `от ${Math.round((+m.min_conf || 0.9) * 100)}%` : "выкл"}
                        </label>
                      </td>
                      <td className="nowrap">
                        <button className="btn sec sm" disabled={N} onClick={() => F(m)}>
                          Проверить связь
                        </button>{" "}
                        <button
                          className="btn sm"
                          onClick={() => {
                            (g(j === m.id ? null : m.id), M({}));
                          }}
                        >
                          {j === m.id ? "Свернуть" : "Симулятор"}
                        </button>{" "}
                        <Ye onClick={() => w(m)} />{" "}
                        <button
                          className="btn sec sm"
                          onClick={() =>
                            y(m, {
                              enabled: !m.enabled,
                            })
                          }
                        >
                          {m.enabled ? "Отключить" : "Включить"}
                        </button>
                      </td>
                    </tr>
                    {j === m.id && (
                      <tr className="subtr">
                        <td colSpan={7}>
                          <div className="subwrap">
                            <div className="sub-t">Симулятор · {m.title}</div>
                            <p
                              className="p-sub"
                              style={{
                                marginTop: 0,
                              }}
                            >
                              отправляет событие в ту же точку приёма и тем же ключом, что и настоящее устройство — сотрудники могут обкатать порядок
                              работы до установки оборудования
                            </p>
                            <div
                              className="row"
                              style={{
                                gap: 8,
                                alignItems: "flex-end",
                                flexWrap: "wrap",
                              }}
                            >
                              {m.kind === "weight" ? (
                                <>
                                  <X label="Вес, кг">{Se(d, M, "kg", "например 34820", 150)}</X>
                                  <label
                                    className="row"
                                    style={{
                                      gap: 5,
                                      alignItems: "center",
                                      fontSize: 11.5,
                                    }}
                                  >
                                    <input
                                      type="checkbox"
                                      checked={d.stable !== !1}
                                      onChange={(Z) =>
                                        M((I) => ({
                                          ...I,
                                          stable: Z.target.checked,
                                        }))
                                      }
                                    />{" "}
                                    вес устойчив
                                  </label>
                                </>
                              ) : (
                                <>
                                  <X label={m.kind === "plate" ? "Номер, как «увидела» камера" : "Номер контейнера"}>
                                    {Se(d, M, "val", m.kind === "plate" ? "например O854BB126" : "например MSKU1234567", 210)}
                                  </X>
                                  <X label="Уверенность, %">{Se(d, M, "conf", "93", 110)}</X>
                                  {m.kind === "plate" && (
                                    <X label="Направление">
                                      <CPe
                                        value={d.dir || ""}
                                        onChange={(Z) =>
                                          M((I) => ({
                                            ...I,
                                            dir: Z,
                                          }))
                                        }
                                        options={[
                                          ["", "— не указано —"],
                                          ["in", "въезд"],
                                          ["out", "выезд"],
                                        ]}
                                        w={150}
                                        ph="— не указано —"
                                      />
                                    </X>
                                  )}
                                </>
                              )}
                              <button className="btn" disabled={N} onClick={() => p(m)}>
                                {N ? "Отправляю…" : "Прислать распознавание →"}
                              </button>
                            </div>
                          </div>
                        </td>
                      </tr>
                    )}
                  </>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Последние события устройств · {(i || []).length}</h2>
        </div>
        <p className="p-sub">
          всё, что прислали устройства: «новое» ждёт подтверждения сотрудником, «использовано» — уже привязано к заезду или взвешиванию, «пропущено» —
          сотрудник отклонил распознавание
        </p>
        <div
          className="tscroll"
          style={{
            maxHeight: "46vh",
          }}
        >
          <table>
            <thead>
              <tr>
                <th>Когда</th>
                <th>Устройство</th>
                <th>Значение</th>
                <th>Распознано</th>
                <th className="right">Увер.</th>
                <th>Состояние</th>
                <th>Привязано к</th>
              </tr>
            </thead>
            <tbody>
              {(i || []).map((m) => {
                var v, U;
                return (
                  <tr>
                    <td className="nowrap">{he(m.at)}</td>
                    <td>{((v = (n || []).find((Z) => Z.id === m.device_id)) == null ? void 0 : v.title) || m.device_id || "—"}</td>
                    <td>
                      <b>{m.kind === "weight" ? q(m.weight_kg) + " кг" : m.value}</b>
                      {(U = m.meta) != null && U.warn ? (
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                            color: "var(--warn)",
                          }}
                        >
                          {m.meta.warn}
                        </div>
                      ) : null}
                    </td>
                    <td className="faint">{m.raw || "—"}</td>
                    <td className="right">{m.confidence != null ? Math.round(+m.confidence * 100) + "%" : "—"}</td>
                    <td>
                      <span className={"stage " + (m.status === "used" ? "tare" : m.status === "ignored" ? "cancel" : "in")}>
                        {m.status === "used" ? "использовано" : m.status === "ignored" ? "пропущено" : m.status === "expired" ? "протухло" : "новое"}
                      </span>
                    </td>
                    <td className="faint">
                      {m.entity
                        ? `${
                            {
                              visit: "заезд",
                              container: "контейнер",
                              request: "заявка",
                              load: "затарка",
                              scale: "взвешивание",
                            }[m.entity] || m.entity
                          }${m.entity_id ? " №" + m.entity_id : ""}`
                        : "—"}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
        {!(i || []).length && (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            событий пока не было — отправьте пробное через симулятор
          </p>
        )}
      </div>
    </>
  );
}
function Zt({ id: t, me: n, onClose: s, onSaved: l }) {
  const [i, u] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select(
              "*, term_requests(*, term_orders(order_no, cargo, extra_services, dest_country, survey, term_contracts(contract_no, term_counterparties(name))))",
            )
            .eq("id", t)
            .limit(1),
        ),
      [t],
      15e3,
    ),
    { who: o } = yt(),
    x = (i || [])[0];
  return i ? (
    x ? (
      <Zs
        v={x}
        req={x.term_requests}
        who={o}
        me={n}
        onClose={s}
        onSaved={() => {
          (u(), l && l());
        }}
      />
    ) : (
      <Xs title="Карточка машины" onClose={s} />
    )
  ) : (
    <At title="Карточка машины" onClose={s} />
  );
}
function CDr({ no: t, me: n, onClose: s }) {
  const [l] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("id")
            .eq("container_no", t)
            .order("id", {
              ascending: !1,
            })
            .limit(1),
        ),
      [t],
      0,
    ),
    i = (l || [])[0];
  return l ? (
    i ? (
      <Ht id={i.id} me={n} onClose={s} />
    ) : (
      <At title={`Контейнер ${t} — в учёте не найден`} onClose={s} />
    )
  ) : (
    <At title={`Контейнер ${t}`} onClose={s} />
  );
}
function Ht({ id: t, me: n, onClose: s }) {
  const [l] = ne(() => Y(A.from("term_line_containers").select("*").eq("id", t).limit(1)), [t], 15e3),
    [i] = ne(() => Y(A.from("term_container_loads").select("*").eq("container_id", t).order("id")), [t], 0),
    { who: u } = yt(),
    o = (l || [])[0];
  return l ? (
    o ? (
      <CPl c={o} loads={i || []} who={u} me={n} onClose={s} />
    ) : (
      <Xs title="Карточка контейнера" onClose={s} />
    )
  ) : (
    <At title="Карточка контейнера" onClose={s} />
  );
}
const Xs = ({ title: t, onClose: n }) => (
    <div
      className="modal-bg"
      onMouseDown={(s) => {
        s.target === s.currentTarget && n();
      }}
    >
      <div
        className="modal"
        style={{
          width: 460,
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">{t}</h2>
          <button className="btn sec sm" onClick={n}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            Запись не найдена: её удалили, либо у вашей роли нет к ней доступа.
          </p>
        </div>
      </div>
    </div>
  ),
  At = ({ title: t, onClose: n }) => (
    <div
      className="modal-bg"
      onMouseDown={(s) => {
        s.target === s.currentTarget && n();
      }}
    >
      <div
        className="modal"
        style={{
          width: 420,
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">{t}</h2>
          <button className="btn sec sm" onClick={n}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            загружаю…
          </p>
        </div>
      </div>
    </div>
  ),
  CPt = ({ head: t, rows: n, onRow: s, empty: l, cap: i = 60, tail: u }) => {
    const o = S.useContext(gl);
    if (!n.length)
      return (
        <p
          className="p-sub"
          style={{
            margin: 0,
          }}
        >
          {l}
        </p>
      );
    const x = o || !i ? n : n.slice(0, i);
    return (
      <>
        <div
          className="tscroll"
          style={{
            maxHeight: "34vh",
          }}
        >
          <table className="minit">
            <thead>
              <tr>
                {t.map((N, b) => (
                  <th className={typeof N == "object" && N.r ? "right" : void 0}>{typeof N == "object" ? N.t : N}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {x.map((N, b) => (
                <tr className={s ? "rowx" : void 0} onClick={s ? () => s(N.k) : void 0}>
                  {N.c.map((j, g) => (
                    <td className={typeof t[g] == "object" && t[g].r ? "right" : void 0}>{j}</td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        {x.length < n.length && (
          <p
            className="p-sub"
            style={{
              margin: "6px 0 0",
            }}
          >
            показаны первые {x.length} из {n.length}
            {u || ""} · в выгрузке PDF список полный
          </p>
        )}
      </>
    );
  };
function CHr({ cp: t, D: n, onClose: s }) {
  const l = n.ctrs.filter((b) => b.counterparty_id === t.id),
    i = new Set(l.map((b) => b.id)),
    u = n.ords.filter((b) => i.has(b.contract_id)),
    o = new Set(u.map((b) => b.id)),
    x = n.reqs.filter((b) => o.has(b.order_id) && !b.deleted_at),
    N = x.reduce((b, j) => b + (+j.planned_tonnes || 0) * 1e3, 0);
  return (
    <CDt wide={!0} title={`Контрагент · ${t.name}`} onClose={s} file={st("Контрагент", t.name, t.inn ? "ИНН-" + t.inn : "")}>
      <C_e done={!0} title="Реквизиты">
        <div className="dgrid">
          <R l="Наименование" v={t.name} />
          <R l="ИНН" v={t.inn} />
          <R l="ОГРН" v={t.ogrn} />
          <R l="Директор" v={t.director} />
          <R l="Юридический адрес" v={t.legal_address} />
          <R l="Банк" v={t.bank_name} />
          <R l="К/с" v={t.corr_account} />
          <R l="Р/с" v={t.settle_account} />
          <R l="БИК" v={t.bik} />
          {t.kpp ? <R l="КПП" v={t.kpp} /> : null}
        </div>
      </C_e>
      <C_e done={l.length > 0} skip={!l.length} title="Договоры" extra={`${l.length} шт.`}>
        <CPt
          head={[
            "Номер",
            "Дата",
            {
              t: "Поручений",
              r: 1,
            },
          ]}
          empty="договоров нет"
          rows={l.map((b) => ({
            k: b.id,
            c: [<b>{b.contract_no}</b>, b.contract_date || "—", n.ords.filter((j) => j.contract_id === b.id).length],
          }))}
        />
      </C_e>
      <C_e done={u.length > 0} skip={!u.length} title="Поручения" extra={`${u.length} шт.`}>
        <CPt
          head={[
            "№",
            "Груз",
            {
              t: "Объём, т",
              r: 1,
            },
            {
              t: "Ставка $/т",
              r: 1,
            },
            {
              t: "Заявок",
              r: 1,
            },
          ]}
          empty="поручений нет"
          rows={u.map((b) => ({
            k: b.id,
            c: [
              <b>{b.order_no}</b>,
              b.cargo || "—",
              b.volume_t ?? "—",
              b.rate_per_t ?? "—",
              n.reqs.filter((j) => j.order_id === b.id && !j.deleted_at).length,
            ],
          }))}
        />
      </C_e>
      <C_e done={x.length > 0} skip={!x.length} title="Заявки на машины" extra={`${x.length} шт. · план ${q(Math.round(N))} кг`}>
        <CPt
          head={[
            "Машина",
            "Культура",
            {
              t: "План, кг",
              r: 1,
            },
            "Дата прихода",
            "Статус",
          ]}
          empty="заявок нет"
          rows={x.map((b) => ({
            k: b.id,
            c: [
              <b>{b.vehicle_no || "—"}</b>,
              b.culture || "—",
              b.planned_tonnes != null ? q(qe(b.planned_tonnes)) : "—",
              b.arrive_date || "—",
              <span className={"stage " + et(b).c}>{et(b).t}</span>,
            ],
          }))}
          tail=" — весь список в реестре заявок"
        />
      </C_e>
      <C_e done={!0} title="Вложения · документы контрагента">
        <Bt me={n.me} entity="counterparty" id={t.id} canAdd={!!n.me} />
      </C_e>
    </CDt>
  );
}
function CUr({ ctr: t, D: n, onClose: s }) {
  var x, N;
  const l = n.ords.filter((b) => b.contract_id === t.id),
    i = new Set(l.map((b) => b.id)),
    u = n.reqs.filter((b) => i.has(b.order_id) && !b.deleted_at),
    o = l.reduce((b, j) => b + (+j.volume_t || 0), 0);
  return (
    <CDt
      wide={!0}
      title={`Договор ${t.contract_no}`}
      onClose={s}
      file={st("Договор", t.contract_no, (x = t.term_counterparties) == null ? void 0 : x.name)}
    >
      <C_e done={!0} title="Договор">
        <div className="dgrid">
          <R l="Организация" v={(N = t.term_counterparties) == null ? void 0 : N.name} />
          <R l="Номер договора" v={t.contract_no} />
          <R l="Дата договора" v={t.contract_date} />
          <R l="Поручений по договору" v={l.length} />
          <R l="Суммарный объём поручений, т" v={o ? q(o) : null} />
          <R l="Заявок на машины" v={u.length} />
        </div>
      </C_e>
      <C_e done={l.length > 0} skip={!l.length} title="Поручения" extra={`${l.length} шт.`}>
        <CPt
          head={[
            "№",
            "Груз",
            "ТН ВЭД",
            {
              t: "Объём, т",
              r: 1,
            },
            {
              t: "Конт.",
              r: 1,
            },
            {
              t: "Ставка $/т",
              r: 1,
            },
            "Страна",
            {
              t: "Заявок",
              r: 1,
            },
          ]}
          empty="поручений нет"
          rows={l.map((b) => ({
            k: b.id,
            c: [
              <b>{b.order_no}</b>,
              b.cargo || "—",
              b.tnved || "—",
              b.volume_t ?? "—",
              b.containers_n ?? "—",
              b.rate_per_t ?? "—",
              b.dest_country || "—",
              n.reqs.filter((j) => j.order_id === b.id && !j.deleted_at).length,
            ],
          }))}
        />
      </C_e>
      <C_e done={u.length > 0} skip={!u.length} title="Заявки по договору" extra={`${u.length} шт.`}>
        <CPt
          head={[
            "Машина",
            "Поручение",
            "Культура",
            {
              t: "План, кг",
              r: 1,
            },
            "Статус",
          ]}
          empty="заявок нет"
          rows={u.map((b) => {
            var j;
            return {
              k: b.id,
              c: [
                <b>{b.vehicle_no || "—"}</b>,
                ((j = b.term_orders) == null ? void 0 : j.order_no) || "—",
                b.culture || "—",
                b.planned_tonnes != null ? q(qe(b.planned_tonnes)) : "—",
                <span className={"stage " + et(b).c}>{et(b).t}</span>,
              ],
            };
          })}
        />
      </C_e>
      <C_e done={!0} title="Вложения · скан договора">
        <Bt me={n.me} entity="contract" id={t.id} canAdd={!!n.me} />
      </C_e>
    </CDt>
  );
}
function CMr({ ord: t, D: n, onClose: s }) {
  var M, z, _, h, w;
  const l = n.reqs.filter((p) => p.order_id === t.id && !p.deleted_at),
    i = l.map((p) => p.id),
    [u] = ne(
      () =>
        i.length
          ? Y(
              A.from("term_truck_visits")
                .select(
                  "id, request_id, vehicle_no, culture, net_kg, in_at, out_at, lab_status, lab_result1, gross_kg, tare_kg, cancelled_at, site, mix_id",
                )
                .in("request_id", i)
                .limit(1e3),
            )
          : Promise.resolve([]),
      [t.id, i.length],
      0,
    ),
    o = u || [],
    x = l.reduce((p, F) => p + (+F.planned_tonnes || 0) * 1e3, 0),
    N = o.reduce((p, F) => p + (+F.net_kg || 0), 0),
    b = (+t.volume_t || 0) * 1e3,
    [j] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("id, net_kg, net_final_kg, gross_kg")
            .eq("order_name", t.order_no)
            .not("gross_kg", "is", null)
            .limit(2e3),
        ),
      [t.id],
      0,
    ),
    g = (j || []).reduce((p, F) => p + (+(F.net_final_kg ?? F.net_kg) || 0), 0),
    d = (p) =>
      (p / 1e3).toLocaleString("ru-RU", {
        maximumFractionDigits: 1,
      });
  return (
    <CDt
      wide={!0}
      title={`Поручение ${t.order_no}`}
      onClose={s}
      file={st("Поручение", t.order_no, (z = (M = t.term_contracts) == null ? void 0 : M.term_counterparties) == null ? void 0 : z.name, t.cargo)}
    >
      <C_e done={!0} title="Условия поручения">
        <div className="dgrid">
          <R l="Организация" v={(h = (_ = t.term_contracts) == null ? void 0 : _.term_counterparties) == null ? void 0 : h.name} />
          <R l="Договор" v={(w = t.term_contracts) == null ? void 0 : w.contract_no} />
          <R l="№ поручения" v={t.order_no} />
          <R l="Наименование груза" v={t.cargo} />
          <R l="Код ТН ВЭД" v={t.tnved} />
          <R l="Объём, т" v={t.volume_t} />
          <R l="Кол-во контейнеров" v={t.containers_n} />
          <R l="Тип контейнеров" v={t.container_type} />
          <R l="Норма загрузки, т" v={t.load_norm_t} />
          <R l="Ставка, $/т" v={t.rate_per_t} />
          <R l="Ставка НДС" v={t.vat_pct == null ? null : ni(t.vat_pct)} />
          <R l="Ставка действует до" v={t.rate_valid_until} />
          <R l="Страна назначения" v={t.dest_country} />
          <R l="Сюрвей" v={t.survey} />
          <R l="Доп. услуги" v={(t.extra_services || []).join(", ")} />
        </div>
      </C_e>
      <C_e done={N > 0} title="Исполнение" extra={b ? `${Math.round((N / b) * 100)}% от объёма` : void 0}>
        {b > 0 && (
          <div className="oprog">
            <div className="oprog-t">
              Принято зерна: <b>{d(N)}</b> из <b>{d(b)}</b> т · осталось <b>{d(Math.max(0, b - N))}</b> т
              {g > 0 && (
                <>
                  {" "}
                  · затарено в контейнеры: <b>{d(g)}</b> т ({(j || []).length} шт.)
                </>
              )}
            </div>
            <div className="oprog-bar">
              <i
                style={{
                  width: Math.min(100, (N / b) * 100) + "%",
                }}
              />
              {g > 0 && (
                <u
                  style={{
                    width: Math.min(100, (g / b) * 100) + "%",
                  }}
                />
              )}
            </div>
          </div>
        )}
        <div className="dgrid">
          <R l="Объём по поручению, кг" v={b ? q(b) : null} />
          <R l="Заявлено машинами (план), кг" v={x ? q(Math.round(x)) : null} />
          <R l="Принято фактически (нетто), кг" v={N ? q(Math.round(N)) : null} />
          <R l="Остаток до объёма, кг" v={b ? q(Math.round(b - N)) : null} />
          <R l="Затарено в контейнеры, кг" v={g ? q(Math.round(g)) : null} />
          <R l="Заявок" v={l.length} />
          <R l="Машин заехало" v={o.length} />
          <R l="Отказов лаборатории" v={o.filter((p) => p.lab_status === "rejected").length} />
        </div>
      </C_e>
      <C_e done={o.length > 0} skip={!o.length} title="Машины по поручению" extra={o.length ? `${o.length} шт.` : "машин ещё не было"}>
        <CPt
          head={[
            "Машина",
            "Культура",
            "Заезд",
            {
              t: "Нетто, кг",
              r: 1,
            },
            "Статус",
          ]}
          empty="машин ещё не было"
          rows={o.map((p) => ({
            k: p.id,
            c: [<b>{p.vehicle_no}</b>, p.culture || "—", he(p.in_at), q(p.net_kg), <span className={"stage " + Ae(p).c}>{Ae(p).t}</span>],
          }))}
        />
      </C_e>
      <C_e done={l.length > 0} skip={!l.length} title="Заявки поручения" extra={`${l.length} шт.`}>
        <CPt
          head={[
            "Машина",
            "Культура",
            {
              t: "План, кг",
              r: 1,
            },
            "Дата прихода",
            "Водитель",
            "Статус",
          ]}
          empty="заявок нет"
          rows={l.map((p) => ({
            k: p.id,
            c: [
              <b>{p.vehicle_no || "—"}</b>,
              p.culture || "—",
              p.planned_tonnes != null ? q(qe(p.planned_tonnes)) : "—",
              p.arrive_date || "—",
              p.driver || "—",
              <span className={"stage " + et(p).c}>{et(p).t}</span>,
            ],
          }))}
        />
      </C_e>
      <C_e done={!0} title="Вложения · поручение и переписка">
        <Bt me={n.me} entity="order" id={t.id} canAdd={!!n.me} />
      </C_e>
    </CDt>
  );
}
function Cs({ id: t, me: n, onClose: s }) {
  const [l] = ne(() => Y(A.from("term_mixes").select("*").eq("id", t).limit(1)), [t], 15e3),
    [i] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select(
              "id, vehicle_no, culture, supplier, lab_status, lab_at, lab_result1, site, ts_at, gross_kg, tare_kg, net_kg, in_at, out_at, cancelled_at, mix_id",
            )
            .eq("mix_id", t)
            .order("in_at"),
        ),
      [t],
      0,
    ),
    [u] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("id, net_kg, net_final_kg, gross_at, vehicle_no, container_id, term_line_containers(container_no)")
            .eq("mix_id", t)
            .order("id"),
        ),
      [t],
      0,
    ),
    { who: o } = yt(),
    x = (l || [])[0];
  if (!l) return <At title="Карточка замеса" onClose={s} />;
  if (!x) return <Xs title="Карточка замеса" onClose={s} />;
  const N = i || [],
    b = u || [],
    j = N.reduce((z, _) => z + (+_.net_kg || 0), 0),
    g = b.reduce((z, _) => z + (+(_.net_final_kg ?? _.net_kg) || 0), 0),
    d = N.filter((z) => z.lab_status !== "passed").length,
    M = vs(x, {
      pending: d,
      packed: g,
    });
  return (
    <CDt
      wide={!0}
      title={`Замес ${x.mix_no}`}
      badge={<span className={"stage " + M.c}>{M.t}</span>}
      onClose={s}
      file={st("Замес", x.mix_no, x.culture, x.site)}
    >
      <C_e done={!0} title="Замес">
        <div className="dgrid">
          <R l="Номер" v={x.mix_no} />
          <R l="Культура" v={x.culture} />
          <R l="Параметр смешивания" v={x.param} />
          <R l="Площадка" v={x.site} />
          <R l="Времянка в замесе" v={x.ext_partner ? x.ext_partner + (x.temp_kg != null ? ` · ${q(x.temp_kg)} кг` : "") : null} />
          <R l="Собран" v={he(x.created_at)} />
          <R l="Собрал" v={o(x.created_by)} />
          <R l="Участников" v={N.length} />
        </div>
      </C_e>
      <C_e done={N.length > 0} skip={!N.length} title="Участники замеса" extra={`нетто ${q(Math.round(j))} кг`}>
        <CPt
          head={[
            "Машина",
            "Поставщик",
            "Заезд",
            {
              t: "Брутто",
              r: 1,
            },
            {
              t: "Тара",
              r: 1,
            },
            {
              t: "Нетто",
              r: 1,
            },
            "Статус",
          ]}
          empty="участников нет"
          rows={N.map((z) => ({
            k: z.id,
            c: [
              <b>{z.vehicle_no}</b>,
              z.supplier || "—",
              he(z.in_at),
              q(z.gross_kg),
              q(z.tare_kg),
              <b>{q(z.net_kg)}</b>,
              <span className={"stage " + Ae(z).c}>{Ae(z).t}</span>,
            ],
          }))}
        />
      </C_e>
      <C_e
        done={g > 0}
        skip={!b.length}
        title="Разошлось по контейнерам"
        extra={`затарено ${q(Math.round(g))} из ${q(Math.round(j))} кг · остаток ${q(Math.max(0, Math.round(j - g)))} кг`}
      >
        <CPt
          head={[
            "Контейнер",
            "Машина",
            "Затарен",
            {
              t: "Нетто, кг",
              r: 1,
            },
          ]}
          empty="в контейнеры пока не расходился"
          rows={b.map((z) => {
            var _;
            return {
              k: z.id,
              c: [
                <b>{((_ = z.term_line_containers) == null ? void 0 : _.container_no) || "—"}</b>,
                z.vehicle_no || "—",
                he(z.gross_at),
                q(z.net_final_kg ?? z.net_kg),
              ],
            };
          })}
        />
      </C_e>
    </CDt>
  );
}
function CRs({ id: t, me: n, onClose: s }) {
  const [l] = ne(() => Y(A.from("term_container_loads").select("*, term_line_containers(*)").eq("id", t).limit(1)), [t], 15e3),
    [i] = ne(() => Y(A.from("term_load_allocs").select("*").eq("load_id", t).order("id")), [t], 0),
    [u] = ne(() => Y(A.from("term_mixes").select("id, mix_no, culture").limit(200)), [], 6e4, "mixno9"),
    { who: o } = yt(),
    x = (l || [])[0];
  if (!l) return <At title="Карточка затарки" onClose={s} />;
  if (!x) return <Xs title="Карточка затарки" onClose={s} />;
  const N = x.term_line_containers || {},
    b = i || [],
    j = (u || []).find((M) => M.id === x.mix_id),
    g = b.reduce((M, z) => M + (+z.weight_kg || 0), 0),
    d = x.net_final_kg ?? x.net_kg;
  return (
    <CDt
      wide={!0}
      title={`Затарка №${x.id} · контейнер ${N.container_no || "—"}`}
      badge={
        x.is_temp ? (
          <span className="stage st-temp">Времянка</span>
        ) : x.gross_kg == null ? (
          <span className="stage in">Не закрыта</span>
        ) : (
          <span className="stage tare">Закрыта</span>
        )
      }
      onClose={s}
      file={st("Затарка", N.container_no, x.order_name ? "поруч-" + x.order_name : "", x.culture, "№" + x.id)}
    >
      <Ys kind="load" id={x.id} />
      <C_e done={!0} title="Контейнер">
        <div className="dgrid">
          <R l="Номер контейнера" v={N.container_no} />
          <R l="Тип" v={N.size ? `${N.size}' ${N.height || ""}` : null} />
          <R l="Линия" v={N.line} />
          <R l="Букинг" v={N.booking} />
          <R l="Клиент" v={N.client} />
          <R l="Тара контейнера (паспорт), кг" v={q(N.cont_tare_kg)} />
          <R l="Payload, кг" v={q(N.payload_kg)} />
          <R l="Max gross, кг" v={q(N.max_gross_kg)} />
        </div>
      </C_e>
      <C_e done={x.gross_kg != null} title="Взвешивание" extra={he(x.gross_at || x.tare_at)}>
        <div className="dgrid">
          <R l="Машина (а/т)" v={x.vehicle_no ? <CXt v={x.vehicle_no} /> : null} />
          <R l="Поручение" v={x.order_name} />
          <R l="Культура" v={x.culture} />
          <R l="Замес" v={j ? j.mix_no : null} />
          <R l="Тара (а/т с порожним), кг" v={q(x.tare_kg)} />
          <R l="Брутто, кг" v={q(x.gross_kg)} />
          <R l="Нетто, кг" v={q(x.net_kg)} />
          {x.dotare_kg != null && <R l="Дотарь, кг" v={q(x.dotare_kg)} />}
          {x.dotare_kg != null && +x.dotare_kg != 0 ? (
            <R l={+x.dotare_kg < 0 ? "Растарено, кг" : "Дотарено, кг"} v={q(Math.abs(x.dotare_kg))} />
          ) : null}
          <R l="Нетто финал (в контейнере), кг" v={q(x.net_final_kg ?? x.net_kg)} />
          {N.payload_kg != null && d != null && <R l="Запас до payload, кг" v={q(Math.round(+N.payload_kg - +d))} />}
          {N.cont_tare_kg != null && d != null && <R l="Брутто контейнера (VGM), кг" v={q(Math.round(+d + +N.cont_tare_kg))} />}
          <R l="Пломба" v={x.seal_no || N.seal_no} />
          <R l="Тару взвесил" v={o(x.tare_by)} />
          <R l="Брутто взвесил" v={o(x.gross_by)} />
        </div>
      </C_e>
      <C_e done={b.length > 0} skip={!b.length} title="Распределение по контрактам" extra={b.length ? `${q(Math.round(g))} из ${q(d)} кг` : void 0}>
        <CPt
          head={[
            "Контракт",
            "Маркировка",
            {
              t: "Вес, кг",
              r: 1,
            },
          ]}
          empty="не распределялось"
          rows={b.map((M) => ({
            k: M.id,
            c: [<b>{M.contract}</b>, M.marker || "—", q(M.weight_kg)],
          }))}
        />
        {b.length > 0 && d != null && Math.abs(g - d) > 1 && (
          <p
            className="p-sub"
            style={{
              margin: "6px 0 0",
              color: "var(--warn)",
            }}
          >
            распределено {q(Math.round(g))} кг, а в контейнере {q(d)} кг — расхождение {q(Math.round(Math.abs(g - d)))} кг
          </p>
        )}
      </C_e>
      <C_e done={!0} title="Вложения">
        <Bt me={n} entity="container" id={x.container_id} canAdd={!!n} />
      </C_e>
    </CDt>
  );
}
function CQn({ r: t, me: n, fcnt: s, onEdit: l, onAtt: i, onDel: u, onClose: o }) {
  var M, z, _, h, w;
  const [x] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .eq("request_id", t.id)
            .order("id", {
              ascending: !1,
            })
            .limit(5),
        ),
      [t.id],
      0,
    ),
    [N, b] = S.useState(null),
    j = x || [],
    g = et(t),
    d = t.term_orders;
  return N ? (
    <Zt id={N} me={n} onClose={() => b(null)} />
  ) : (
    <CDt
      wide={!0}
      title={`Заявка №${t.id} · ${t.vehicle_no || "без машины"}`}
      badge={<span className={"stage " + g.c}>{g.t}</span>}
      onClose={o}
      file={st(
        "Заявка",
        t.vehicle_no,
        t.client || ((z = (M = d == null ? void 0 : d.term_contracts) == null ? void 0 : M.term_counterparties) == null ? void 0 : z.name),
        d != null && d.order_no ? "поруч-" + d.order_no : "",
        t.culture,
      )}
    >
      <Ys kind="req" id={t.id} />
      <C_e done={!0} title="Заявка">
        <div className="dgrid">
          <R
            l="Организация"
            v={t.client || ((h = (_ = d == null ? void 0 : d.term_contracts) == null ? void 0 : _.term_counterparties) == null ? void 0 : h.name)}
          />
          <R l="Поручение" v={d == null ? void 0 : d.order_no} />
          <R l="Договор" v={(w = d == null ? void 0 : d.term_contracts) == null ? void 0 : w.contract_no} />
          <R l="Груз по поручению" v={d == null ? void 0 : d.cargo} />
          <R l="Культура" v={t.culture} />
          <R l="Машина / прицеп" v={t.vehicle_no ? t.vehicle_no + (t.trailer_no ? " / " + t.trailer_no : "") : null} />
          <R l="Вес (план), кг" v={t.planned_tonnes != null ? q(qe(t.planned_tonnes)) : null} />
          <R l="Дата прихода (план)" v={t.arrive_date} />
          <R l="Водитель" v={t.driver} />
          <Tn phone={t.driver_phone} />
          <R l="Паспорт водителя" v={t.driver_passport} />
          <R l="Контракт закупочный" v={t.purchase_contract} />
          <R l="Отправитель (поставщик)" v={t.supplier} />
          <R l="Очередность выгрузки" v={t.priority} />
          <R l="Вид выгрузки" v={t.unload_kind} />
          <R l="№ пропуска" v={t.pass_no} />
          <R l="Создана" v={he(t.created_at)} />
          <R l="Примечания" v={t.notes} />
        </div>
        {t.deleted_at ? (
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
              color: "var(--bad)",
            }}
          >
            заявка удалена {he(t.deleted_at)} — в расчёты и отчёты не попадает
          </p>
        ) : null}
      </C_e>
      {t.t2_at || t.t2_called_at ? (
        <C_e done={!0} title="Отстойник (Т2)" extra={he(t.t2_at)}>
          <div className="dgrid">
            <R l="Поставлена на отстойник" v={he(t.t2_at)} />
            <R l="Вызвана на терминал" v={t.t2_called_at ? he(t.t2_called_at) : "ещё не вызывали"} />
          </div>
        </C_e>
      ) : null}
      <C_e
        done={j.length > 0}
        skip={!j.length}
        title="Заезды по этой заявке"
        extra={j.length ? `${j.length} шт. · клик — весь процесс машины` : "машина ещё не заезжала"}
      >
        <CPt
          head={[
            "Машина",
            "Заезд",
            {
              t: "Брутто",
              r: 1,
            },
            {
              t: "Тара",
              r: 1,
            },
            {
              t: "Нетто",
              r: 1,
            },
            "Выезд",
            "Статус",
          ]}
          empty="машина по этой заявке ещё не заезжала"
          onRow={(p) => b(p)}
          rows={j.map((p) => ({
            k: p.id,
            c: [
              <b>{p.vehicle_no}</b>,
              he(p.in_at),
              q(p.gross_kg),
              q(p.tare_kg),
              <b>{q(p.net_kg)}</b>,
              he(p.out_at),
              <span className={"stage " + Ae(p).c}>{Ae(p).t}</span>,
            ],
          }))}
        />
        {j.length > 0 && t.planned_tonnes != null && j[0].net_kg != null && (
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
            }}
          >
            отклонение факта от плана: {(j[0].net_kg - t.planned_tonnes * 1e3 >= 0 ? "+" : "") + q(Math.round(j[0].net_kg - t.planned_tonnes * 1e3))}{" "}
            кг
          </p>
        )}
      </C_e>
      <C_e done={!0} title="Вложения · документы заявки">
        <Bt me={n} entity="request" id={t.id} canAdd={!!n} />
      </C_e>
      {(l || u || i) && (
        <div
          className="row cardact"
          style={{
            marginTop: 10,
          }}
        >
          {i ? <CGt n={s ? s("request", t.id) : 0} onClick={i} /> : null}
          {l ? <Ye title="Исправить заявку" onClick={l} /> : null}
          {u && !t.deleted_at ? (
            <button className="btn danger sm" onClick={u}>
              Удалить (в историю)
            </button>
          ) : null}
        </div>
      )}
    </CDt>
  );
}
function C$l({ D: t }) {
  const [n, s] = S.useState(!1),
    [l, i] = S.useState(!1),
    [u, o] = S.useState(null),
    [x, N] = S.useState(null),
    [b, j] = S.useState(null),
    [g, d] = S.useState(() => ut("reg_req", "flt")),
    [M, z] = S.useState(""),
    _ = Pt("Поиск: машина, водитель, телефон, культура, поручение, контракт, поставщик…", ut("reg_req", "q")),
    [h, w] = S.useState(null),
    { TH: CP, apply: F } = rt(),
    C = Fe(t.reqs.filter((a) => !a.deleted_at).map((a) => a.purchase_contract)),
    y = F(
      t.reqs
        .filter((a) => !g || (g === "deleted" ? !!a.deleted_at : et(a).k === g && !a.deleted_at))
        .filter((a) => (g === "deleted" ? !0 : !a.deleted_at))
        .filter((a) => !M || a.purchase_contract === M)
        .filter((a) => {
          var f, P, T, H, Q;
          return _.test(
            a.vehicle_no,
            a.trailer_no,
            a.driver,
            a.driver_phone,
            a.client,
            a.culture,
            a.supplier,
            a.purchase_contract,
            a.pass_no,
            a.arrive_date,
            (f = a.term_orders) == null ? void 0 : f.order_no,
            (P = a.term_orders) == null ? void 0 : P.cargo,
            (Q = (H = (T = a.term_orders) == null ? void 0 : T.term_contracts) == null ? void 0 : H.term_counterparties) == null ? void 0 : Q.name,
            et(a).t,
          );
        }),
      {
        id: (a) => a.id,
        org: (a) => a.client,
        ord: (a) => {
          var f;
          return (f = a.term_orders) == null ? void 0 : f.order_no;
        },
        cult: (a) => a.culture,
        veh: (a) => a.vehicle_no,
        tons: (a) => (a.planned_tonnes == null ? null : +a.planned_tonnes),
        ad: (a) => a.arrive_date,
        drv: (a) => a.driver,
        pc: (a) => a.purchase_contract,
        sup: (a) => a.supplier,
        st: (a) => et(a).t,
      },
    );
  _.enterRef.current = y.length === 1 ? () => j(y[0]) : null;
  const $ = [
      {
        k: "order_id",
        t: "Поручение",
        type: "num",
        w: 280,
        opts: t.ords.map((a) => {
          var f, P;
          return [
            a.id,
            `${(P = (f = a.term_contracts) == null ? void 0 : f.term_counterparties) == null ? void 0 : P.name} · ${a.order_no} · ${a.cargo || ""}`,
          ];
        }),
      },
      {
        k: "culture",
        t: "Культура",
        w: 200,
        opts: Fe([...Ft(), ...t.ords.map((a) => a.cargo), ...t.reqs.map((a) => a.culture)]).map((a) => [a, a]),
      },
      {
        k: "vehicle_no",
        t: "Машина",
        req: 1,
        w: 130,
      },
      {
        k: "trailer_no",
        t: "Прицеп",
        w: 110,
      },
      {
        k: "planned_tonnes",
        t: "Вес план, кг",
        type: "kg",
        w: 140,
      },
      {
        k: "arrive_date",
        t: "Дата прихода (план)",
        type: "date",
        w: 150,
      },
      {
        k: "driver",
        t: "ФИО водителя",
        w: 190,
      },
      {
        k: "driver_phone",
        t: "Контакт водителя",
        w: 150,
      },
      {
        k: "purchase_contract",
        t: "Контракт закупочный",
        w: 210,
        dict: "pc",
      },
      {
        k: "supplier",
        t: "Отправитель (поставщик)",
        w: 230,
        dict: "supplier",
      },
      {
        k: "status",
        t: "Статус",
        w: 150,
        opts: Object.entries($i).map(([a, f]) => [a, f[1]]),
      },
    ],
    [m, v] = S.useState(0),
    U = async (a) => {
      if (m) return;
      const f = (t.reqs || [])
        .filter((H) => H.vehicle_no === a.vehicle_no && !H.deleted_at)
        .find((H) => H.created_at && Date.now() - new Date(H.created_at).getTime() < 15e3);
      if (f) {
        w({
          err: `Заявка №${f.id} по машине ${a.vehicle_no} создана несколько секунд назад. Если копия действительно нужна ещё раз — подожди четверть минуты.`,
        });
        return;
      }
      const P = (t.reqs || []).filter((H) => H.vehicle_no === a.vehicle_no && H.arrive_date === Ve() && !H.deleted_at),
        T = P.length
          ? `

ВНИМАНИЕ: на сегодня по машине ${a.vehicle_no} уже ${P.length === 1 ? "стоит заявка" : `стоит ${P.length} заявки`} (№${P.map((H) => H.id).join(", ")}). Копия будет ещё одна.`
          : "";
      if (window.confirm(`Создать копию заявки №${a.id} (${a.vehicle_no}) на сегодня, ${Ns()}?${T}`)) {
        v(a.id);
        try {
          const H = await Y(
            A.from("term_requests")
              .insert({
                order_id: a.order_id,
                client: a.client,
                culture: a.culture,
                vehicle_no: a.vehicle_no,
                trailer_no: a.trailer_no,
                planned_tonnes: a.planned_tonnes,
                arrive_date: Ve(),
                driver: a.driver,
                driver_phone: a.driver_phone,
                purchase_contract: a.purchase_contract,
                supplier: a.supplier,
                status: "expected",
                created_by: t.me.id,
                priority: a.priority,
              })
              .select("id"),
          );
          (await je(
            "request",
            H[0].id,
            "copy",
            {
              из: a.id,
              машина: a.vehicle_no,
            },
            t.me,
          ),
            w({
              ok: `Заявка №${H[0].id} создана копией №${a.id}: ${a.vehicle_no} на сегодня — поправь дату и вес, если нужно`,
            }),
            t.reload());
        } catch (H) {
          w({
            err: String(H.message || H),
          });
        } finally {
          v(0);
        }
      }
    },
    Z = async (a) => {
      if (window.confirm(`Отменить заявку №${a.id} (${a.vehicle_no})? Машина считается не приехавшей.`))
        try {
          (await ue(
            A.from("term_requests")
              .update({
                status: "cancelled",
              })
              .eq("id", a.id),
            "заявка",
          ),
            await je(
              "request",
              a.id,
              "cancel",
              {
                машина: a.vehicle_no,
              },
              t.me,
            ),
            t.reload());
        } catch (f) {
          w({
            err: String(f.message || f),
          });
        }
    },
    I = async (a) => {
      if (window.confirm(`Удалить заявку №${a.id} (${a.vehicle_no})? Она уйдёт в историю — восстановить можно фильтром «Удалённые».`))
        try {
          (await ue(
            A.from("term_requests")
              .update({
                deleted_at: new Date().toISOString(),
                deleted_by: t.me.id,
                status: "cancelled",
              })
              .eq("id", a.id),
            "заявка",
          ),
            await je(
              "request",
              a.id,
              "soft_delete",
              {
                машина: a.vehicle_no,
              },
              t.me,
            ),
            w({
              ok: `Заявка №${a.id} (${a.vehicle_no || ""}) удалена — сохранена в истории (фильтр «Удалённые»)`,
            }),
            t.reload());
        } catch (f) {
          w({
            err: String(f.message || f),
          });
        }
    },
    D = async (a) => {
      try {
        (await ue(
          A.from("term_requests")
            .update({
              deleted_at: null,
              deleted_by: null,
              status: "expected",
            })
            .eq("id", a.id),
          "заявка",
        ),
          await je(
            "request",
            a.id,
            "restore",
            {
              машина: a.vehicle_no,
            },
            t.me,
          ),
          w({
            ok: "Заявка восстановлена — снова «Ожидается»",
          }),
          t.reload());
      } catch (f) {
        w({
          err: String(f.message || f),
        });
      }
    },
    E = t.reqs.filter((a) => a.deleted_at).length;
  return (
    <>
      {n && <CIr D={t} onClose={() => s(!1)} />}
      {l && <CRr D={t} onClose={() => i(!1)} />}
      {b && (
        <CQn
          r={b}
          me={t.me}
          fcnt={t.fcnt}
          onEdit={() => {
            (j(null), N(b));
          }}
          onAtt={() => {
            (j(null), o(b));
          }}
          onDel={() => {
            (j(null), I(b));
          }}
          onClose={() => j(null)}
        />
      )}
      {u && (
        <Kt
          me={t.me}
          canAdd={mt("req")}
          entity="request"
          id={u.id}
          title={`Заявка №${u.id} · ${u.vehicle_no || ""} · вложения`}
          onClose={() => {
            (o(null), t.freload());
          }}
        />
      )}
      {x && (
        <CAt
          title={`Заявка №${x.id} · ${x.vehicle_no || ""}`}
          fields={$}
          row={x}
          table="term_requests"
          onClose={() => N(null)}
          onDone={() => {
            (w({
              ok: "Изменения сохранены",
            }),
              t.reload());
          }}
        />
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Реестр заявок · {Vt(_, y.length, t.reqs.filter((a) => !a.deleted_at).length)}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            {mt("req") && (
              <button className="btn sm" onClick={() => s(!0)}>
                + Заявка
              </button>
            )}
            <button className="btn sec sm" title="Загрузить реестр машин из Excel — каждая строка станет заявкой" onClick={() => i(!0)}>
              ⇧ Из Excel
            </button>
            <Je
              make={() =>
                Ze("Заявки", [
                  {
                    name: "Заявки",
                    title: "ФЕНИКС · Терминал — Реестр заявок (машины под поручения)",
                    cols: [
                      {
                        h: "№",
                        w: 8,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Организация",
                        w: 26,
                      },
                      {
                        h: "Поручение",
                        w: 13,
                      },
                      {
                        h: "Культура",
                        w: 14,
                      },
                      {
                        h: "Машина",
                        w: 13,
                      },
                      {
                        h: "Прицеп",
                        w: 12,
                      },
                      {
                        h: "Вес план, кг",
                        w: 12,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Дата прихода",
                        w: 13,
                      },
                      {
                        h: "Водитель",
                        w: 22,
                      },
                      {
                        h: "Контакт",
                        w: 15,
                      },
                      {
                        h: "Контракт закуп.",
                        w: 16,
                      },
                      {
                        h: "Поставщик",
                        w: 20,
                      },
                      {
                        h: "Статус",
                        w: 14,
                      },
                    ],
                    rows: y.map((a) => {
                      var f;
                      return [
                        a.id,
                        a.client,
                        (f = a.term_orders) == null ? void 0 : f.order_no,
                        a.culture,
                        a.vehicle_no,
                        a.trailer_no,
                        qe(a.planned_tonnes),
                        a.arrive_date,
                        a.driver,
                        a.driver_phone,
                        a.purchase_contract,
                        a.supplier,
                        et(a).t,
                      ];
                    }),
                  },
                ])
              }
            />
            <button
              className="btn sec sm"
              onClick={() =>
                ns(
                  "Заявки",
                  [
                    "№",
                    "Организация",
                    "Поручение",
                    "Культура",
                    "Машина",
                    "Прицеп",
                    "Вес план, кг",
                    "Дата прихода",
                    "Водитель",
                    "Контакт",
                    "Поставщик",
                    "Статус",
                  ],
                  y.map((a) => {
                    var f;
                    return [
                      a.id,
                      a.client,
                      (f = a.term_orders) == null ? void 0 : f.order_no,
                      a.culture,
                      a.vehicle_no,
                      a.trailer_no,
                      qe(a.planned_tonnes),
                      a.arrive_date,
                      a.driver,
                      a.driver_phone,
                      a.supplier,
                      et(a).t,
                    ];
                  }),
                )
              }
            >
              ⇩ CSV
            </button>
          </span>
        </div>
        <p className="p-sub">
          клик по строке — карточка заявки · удаление мягкое: заявка остаётся в истории (красная, фильтр «Удалённые») и дальше по процессу не идёт ·
          вес в кг
        </p>
        <div className="findrow">
          {_.Find}
          <CPe value={M} onChange={z} options={[["", "Все закупочные контракты"], ...C.map((a) => [a, a])]} w={230} ph="Контракт закупки" />
          <Yt
            win="reg_req"
            params={{
              q: _.q,
              flt: g,
            }}
          />
        </div>
        <Tt
          val={g}
          onSel={d}
          items={[
            ...[
              ["new", "Ожидается · в пути"],
              ["t2", "Отстойник (Т2)"],
              ["called", "Вызвана на терминал"],
              ["req_in", "На терминале"],
              ["req_done", "Завершена"],
              ["req_no", "Отменена"],
            ]
              .map(([a, f]) => ({
                k: a,
                t: f,
                n: t.reqs.filter((P) => !P.deleted_at && et(P).k === a).length,
              }))
              .filter((a) => a.n),
            {
              k: "deleted",
              t: "Удалённые",
              n: E,
            },
          ]}
        />
        <CFe err={t.err} />
        <CFe {...(h || {})} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <CP k="id">№</CP>
                <CP k="org">Организация</CP>
                <CP k="ord">Поруч.</CP>
                <CP k="cult">Культура</CP>
                <CP k="veh">Машина</CP>
                <CP k="tons" right={!0}>
                  Вес, кг
                </CP>
                <CP k="ad">Дата прихода</CP>
                <CP k="drv">Водитель</CP>
                <th>Телефон</th>
                <CP k="pc">Контракт закуп.</CP>
                <CP k="sup">Поставщик</CP>
                <CP k="st">Статус</CP>
                <th />
              </tr>
            </thead>
            <tbody>
              {y.map((a) => {
                var f, P, T, H;
                return (
                  <tr className={"rowx" + (a.deleted_at ? " delrow" : "")} title="Открыть карточку заявки" onClick={() => j(a)}>
                    <td>{a.id}</td>
                    <td>
                      <b>
                        {a.client ||
                          ((T = (P = (f = a.term_orders) == null ? void 0 : f.term_contracts) == null ? void 0 : P.term_counterparties) == null
                            ? void 0
                            : T.name) ||
                          "—"}
                      </b>
                    </td>
                    <td>{((H = a.term_orders) == null ? void 0 : H.order_no) || "—"}</td>
                    <td>{a.culture || "—"}</td>
                    <td>
                      <b>{a.vehicle_no || "—"}</b>
                      {a.trailer_no ? <span className="faint"> / {a.trailer_no}</span> : null}
                    </td>
                    <td className="right">{a.planned_tonnes != null ? q(qe(a.planned_tonnes)) : "—"}</td>
                    <td className="nowrap">{a.arrive_date || "—"}</td>
                    <td>{a.driver || "—"}</td>
                    <td className="nowrap">{a.driver_phone || "—"}</td>
                    <td>{a.purchase_contract || "—"}</td>
                    <td>{a.supplier || "—"}</td>
                    <td>
                      <span className={"stage " + et(a).c}>{et(a).t}</span>
                    </td>
                    <td className="nowrap" onClick={ct}>
                      <CGt n={t.fcnt("request", a.id)} onClick={() => o(a)} />
                      {mt("req") && (
                        <>
                          {" "}
                          <Ye onClick={() => N(a)} />{" "}
                          {a.deleted_at ? (
                            <button className="btn sec sm" onClick={() => D(a)}>
                              Восстановить
                            </button>
                          ) : (
                            <>
                              <button
                                className="btn sec sm icon"
                                disabled={m === a.id}
                                title="Скопировать заявку на сегодня"
                                onClick={(Q) => {
                                  (Q.stopPropagation(), Q.currentTarget.blur(), U(a));
                                }}
                              >
                                ⧉
                              </button>{" "}
                              <Jt onClick={() => I(a)} />{" "}
                              {a.status === "expected" && (
                                <button className="btn danger sm" onClick={() => Z(a)}>
                                  Отменить
                                </button>
                              )}
                            </>
                          )}
                        </>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
const Cl = [
  {
    k: "vehicle_no",
    t: "Машина",
    req: 1,
    w: 130,
  },
  {
    k: "trailer_no",
    t: "Прицеп",
    w: 110,
  },
  {
    k: "driver",
    t: "ФИО водителя",
    w: 190,
  },
  {
    k: "driver_phone",
    t: "Контакт водителя",
    w: 150,
  },
  {
    k: "client",
    t: "Организация",
    w: 230,
    dict: "client",
  },
  {
    k: "culture",
    t: "Культура",
    w: 200,
    dict: "cargo",
  },
  {
    k: "supplier",
    t: "Поставщик",
    w: 230,
    dict: "supplier",
  },
  {
    k: "purchase_contract",
    t: "Контракт закупочный",
    w: 210,
    dict: "pc",
  },
  {
    k: "planned_tonnes",
    t: "Вес план, кг",
    type: "kg",
    w: 150,
  },
  {
    k: "priority",
    t: "Очередность выгрузки",
    w: 110,
  },
  {
    k: "ttn_ok",
    t: "ТТН у водителя",
    w: 120,
    opts: [
      ["true", "есть"],
      ["false", "нет"],
    ],
  },
];
function xr({ me: t }) {
  const [n, s] = Te("kpp.tab", "trucks");
  return (
    <>
      <div className="tabs">
        <button className={"tab" + (n === "trucks" ? " on" : "")} onClick={() => s("trucks")}>
          Зерновозы
        </button>
        <button className={"tab" + (n === "conts" ? " on" : "")} onClick={() => s("conts")}>
          Контейнеры линии
        </button>
      </div>
      {n === "trucks" ? <CPr me={t} /> : <Ml me={t} />}
    </>
  );
}
const ct = (t) => t.stopPropagation(),
  Tn = ({ phone: t }) => {
    const n = String(t || "").replace(/[^+\d]/g, "");
    return (
      <div className="dv">
        <span>Телефон водителя</span>
        <b>
          {n ? (
            <a className="tel9" href={"tel:" + n} onClick={ct}>
              {t} 📞
            </a>
          ) : (
            "—"
          )}
        </b>
      </div>
    );
  };
function C_r({ r: t, ttn: n, setTtn: s, fcnt: l, onT2: i, onUnT2: u, onArrive: o, onPass: x, onAtt: N, onClose: b }) {
  var j;
  return (
    <div
      className="modal-bg"
      onMouseDown={(g) => {
        g.target === g.currentTarget && b();
      }}
    >
      <div
        className="modal"
        style={{
          width: 600,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">
            Карточка заезда · {t.vehicle_no}
            {t.trailer_no ? <span className="faint"> / {t.trailer_no}</span> : null}
          </h2>
          <button className="btn sec sm" onClick={b}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <div
            className="row"
            style={{
              gap: 8,
              marginBottom: 4,
            }}
          >
            {t.t2_at ? (
              <span className={"t2chip" + (t.t2_called_at ? " ok" : "")}>
                {t.t2_called_at ? `Отстойник (Т2) · вызван лабораторией ${Ue(t.t2_called_at)}` : `на отстойнике (Т2) с ${Ue(t.t2_at)} · ждёт вызова`}
              </span>
            ) : (
              <span className="stage">Ожидается · в пути</span>
            )}
          </div>
          <div
            className="dgrid"
            style={{
              marginTop: 8,
            }}
          >
            <R l="Организация" v={t.client} />
            <R l="Поручение" v={(j = t.term_orders) == null ? void 0 : j.order_no} />
            <R l="Культура" v={t.culture} />
            <R l="Вес план, кг" v={t.planned_tonnes != null ? q(qe(t.planned_tonnes)) : null} />
            <R l="Дата (план)" v={t.arrive_date} />
            <R l="Приоритет" v={t.priority} />
            <R l="Поставщик" v={t.supplier} />
            <R l="Контракт закупки" v={t.purchase_contract} />
            <R l="Водитель" v={t.driver} />
            <Tn phone={t.driver_phone} />
            {t.t2_at ? <R l="Прибыл на отстойник (Т2)" v={he(t.t2_at)} /> : null}
            {t.t2_called_at ? <R l="Вызван лабораторией" v={he(t.t2_called_at)} /> : null}
            {t.notes ? <R l="Примечания" v={t.notes} /> : null}
          </div>
          <div className="row cardact">
            <label className="ttnchk big" title="ТТН у водителя" onClick={ct}>
              <input
                type="checkbox"
                checked={n[t.id] === !0}
                onChange={(g) =>
                  s((d) => ({
                    ...d,
                    [t.id]: g.target.checked,
                  }))
                }
              />
              ТТН у водителя
            </label>
            <button className="btn sec sm" onClick={x}>
              Пропуск · PDF
            </button>
            <CGt n={l("request", t.id)} onClick={N} />
            {t.t2_at ? (
              <button className="btn sec sm" title="Снять отметку отстойника (Т2)" onClick={u}>
                ✕ снять отстойник
              </button>
            ) : (
              <button className="btn sec sm" title="Прибыл на отстойник (Т2)" onClick={i}>
                Отстойник (Т2) ↓
              </button>
            )}
            <button className="btn sm" onClick={o}>
              Прибыл на терминал ↓
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}
function CJr({ v: t, fcnt: n, canExit: s, onTtn: l, onAtt: i, onEdit: u, onExit: o, onClose: x, hideTtn: N, hideEdit: b }) {
  const j = Ae(t);
  return (
    <div
      className="modal-bg"
      onMouseDown={(g) => {
        g.target === g.currentTarget && x();
      }}
    >
      <div
        className="modal"
        style={{
          width: 620,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">
            Машина на территории · {t.vehicle_no}
            {t.trailer_no ? <span className="faint"> / {t.trailer_no}</span> : null}
          </h2>
          <button className="btn sec sm" onClick={x}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <div
            className="row"
            style={{
              gap: 8,
              marginBottom: 4,
            }}
          >
            <span className={"stage " + j.c}>{j.t}</span>
            {t.ttn_ok ? <span className="t2chip ok">ТТН при заезде ✓</span> : null}
          </div>
          <div
            className="dgrid"
            style={{
              marginTop: 8,
            }}
          >
            <R l="Организация" v={t.client} />
            <R l="Поставщик" v={t.supplier} />
            <R l="Культура" v={t.culture} />
            <R l="Контракт закупки" v={t.purchase_contract} />
            <R l="Вес план, кг" v={t.planned_tonnes != null ? q(qe(t.planned_tonnes)) : null} />
            <R l="Приоритет" v={t.priority} />
            <R l="Водитель" v={t.driver} />
            <Tn phone={t.driver_phone} />
            <R l="Заезд" v={he(t.in_at)} />
            <R
              l="Лаборатория"
              v={
                t.lab_status === "passed"
                  ? `Одобрен · ${t.lab_result1 ? Le[t.lab_result1] : ""} (${Ue(t.lab_at)})`
                  : t.lab_status === "rejected"
                    ? "Отказ"
                    : "в очереди"
              }
            />
            {Ks(t) ? <R l="Замес (с кем · параметр · площадка)" v={js(t)} /> : null}
            <R l="Площадка перевалки" v={t.site} />
            {t.lab_moisture != null ? (
              <R l="Влажность / Сорность / Кол-бит, %" v={`${t.lab_moisture ?? "—"} / ${t.lab_impurity ?? "—"} / ${t.lab_broken ?? "—"}`} />
            ) : null}
            <R l="Брутто, кг" v={q(t.gross_kg)} />
            <R l="Тара, кг" v={q(t.tare_kg)} />
            <R l="Нетто, кг" v={q(t.net_kg)} />
            <R l="Место выгрузки" v={t.unload_place} />
            {t.notes ? <R l="Примечания" v={t.notes} /> : null}
          </div>
          <div className="row cardact">
            {!N && (
              <button className="btn sec sm" onClick={l}>
                ТТН · печать
              </button>
            )}
            <CGt n={n("visit", t.id)} onClick={i} />
            {!b && <Ye title="Исправить данные машины/водителя" onClick={u} />}
            {s && (
              <button className="btn sm" onClick={o}>
                Убыл ↑
              </button>
            )}
          </div>
          {!s && (
            <p
              className="p-sub"
              style={{
                margin: "8px 0 0",
              }}
            >
              выезд станет доступен после взвешивания порожним либо при отказе лаборатории
            </p>
          )}
        </div>
      </div>
    </div>
  );
}
function CGr({ reqs: t, visits: n, onArrive: s, onPass: l, onT2: i, onExit: u, onClose: o }) {
  const [x, N] = S.useState(""),
    b = De(x),
    j = (M) => !b || De(M.vehicle_no).includes(b) || De(M.trailer_no || "").includes(b),
    g = (t || []).filter(j).slice(0, 6),
    d = (n || []).filter(j).slice(0, 6);
  return (
    <div
      className="modal-bg gate9"
      onMouseDown={(M) => {
        M.target === M.currentTarget && o();
      }}
    >
      <div
        className="modal"
        style={{
          width: 760,
          maxWidth: "97vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Режим ворот</h2>
          <button className="btn sec sm" onClick={o}>
            ✕ обычный вид
          </button>
        </div>
        <div className="m-body">
          <input className="gate-in" autoFocus={!0} placeholder="Номер машины — хватит 3 символов" value={x} onChange={(M) => N(M.target.value)} />
          {!b && (
            <p
              className="p-sub"
              style={{
                marginTop: 10,
              }}
            >
              набери часть номера — покажу и ожидаемые, и тех, кто уже на территории
            </p>
          )}
          {b && !g.length && !d.length && (
            <p
              className="err"
              style={{
                marginTop: 10,
              }}
            >
              по «{x}» ничего не нашлось · проверь номер или оформи заявку у менеджера
            </p>
          )}
          {g.map((M) => (
            <div className="gate-card">
              <div>
                <div className="gate-no">
                  {M.vehicle_no}
                  {M.trailer_no ? <span className="faint"> / {M.trailer_no}</span> : null}
                </div>
                <div className="gate-sub">
                  {M.client || "—"} · {M.culture || "—"} · {M.planned_tonnes != null ? q(qe(M.planned_tonnes)) + " кг" : "—"}
                  {M.driver ? " · " + M.driver : ""}
                </div>
                <div className="gate-sub">
                  {M.t2_called_at ? "✓ лаборатория вызвала с отстойника" : M.t2_at ? "на отстойнике (Т2), вызова ещё нет" : "ожидается"}
                </div>
              </div>
              <div
                className="row"
                style={{
                  gap: 8,
                }}
              >
                <button className="btn sec big" onClick={() => l(M)}>
                  Пропуск
                </button>
                {!M.t2_at && (
                  <button className="btn sec big" onClick={() => i(M)}>
                    На отстойник (Т2)
                  </button>
                )}
                <button className="btn big" onClick={() => s(M)}>
                  Прибыл ↓
                </button>
              </div>
            </div>
          ))}
          {d.map((M) => {
            const z = Ae(M),
              _ = M.tare_kg != null || M.lab_status === "rejected";
            return (
              <div className="gate-card on">
                <div>
                  <div className="gate-no">{M.vehicle_no}</div>
                  <div className="gate-sub">
                    на территории с {Ue(M.in_at)} · {M.client || "—"} · {M.culture || "—"}
                  </div>
                  <div className="gate-sub">
                    <span className={"stage " + z.c}>{z.t}</span>
                    {M.net_kg != null ? ` · нетто ${q(M.net_kg)} кг` : ""}
                  </div>
                </div>
                <div
                  className="row"
                  style={{
                    gap: 8,
                  }}
                >
                  {_ ? (
                    <button className="btn big" onClick={() => u(M)}>
                      Убыл ↑
                    </button>
                  ) : (
                    <span className="faint">ждём весовую</span>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}
function CPr({ me: t }) {
  const n = S.useRef(new Set()),
    [s, l, i] = ne(
      () => Y(A.from("term_requests").select("*, term_orders(order_no)").eq("status", "expected").is("deleted_at", null).order("arrive_date")),
      [],
      2e4,
    ),
    [u, o, x] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .is("out_at", null)
            .is("cancelled_at", null)
            .order("in_at", {
              ascending: !1,
            })
            .limit(200),
        ),
      [],
      2e4,
    ),
    [N, b] = ne(() => Y(A.from("term_files").select("id, entity, entity_id").in("entity", ["visit", "request"]).limit(5e3)), [], 3e4),
    j = (L, W) => (N || []).reduce((K, le) => K + (le.entity === L && le.entity_id === W ? 1 : 0), 0),
    [g, d] = S.useState(null),
    [M, z] = S.useState(null),
    [_, h] = S.useState(null),
    w = () => {
      (l(), o());
    },
    [p, F] = S.useState({}),
    [C, y] = S.useState(null),
    [$, m] = S.useState(null),
    [v, U] = Te("kpp.gate", !1),
    Z = async (L, W) => {
      if (!n.current.has(L.id)) {
        n.current.add(L.id);
        try {
          await I(L, W);
        } finally {
          n.current.delete(L.id);
        }
      }
    },
    I = async (L, W) => {
      var $e, ee;
      const K = (u || []).find((re) => re.request_id === L.id);
      if (K) {
        h({
          err: `${L.vehicle_no}: по этой заявке уже открыт заезд №${K.id} от ${he(K.in_at)}. Повторный заезд не нужен — машина уже на территории.`,
        });
        return;
      }
      const le = (u || []).find((re) => De(re.vehicle_no) === De(L.vehicle_no));
      if (!(le && !window.confirm(`Машина ${L.vehicle_no} уже на территории (заезд №${le.id} от ${he(le.in_at)}). Точно оформить ещё один заезд?`)))
        try {
          if (
            (await Y(
              A.from("term_truck_visits")
                .insert({
                  request_id: L.id,
                  vehicle_no: L.vehicle_no,
                  trailer_no: L.trailer_no,
                  driver: L.driver,
                  driver_phone: L.driver_phone,
                  client: L.client,
                  culture: L.culture,
                  supplier: L.supplier,
                  purchase_contract: L.purchase_contract,
                  planned_tonnes: L.planned_tonnes,
                  in_at: new Date().toISOString(),
                  in_by: t.id,
                  priority: L.priority || null,
                  ttn_ok: p[L.id] === !0,
                  lab_status: "pending",
                  t2_at: L.t2_at || null,
                  t2_called_at: L.t2_called_at || null,
                  in_source: W ? "camera" : "manual",
                  in_event_id: (W == null ? void 0 : W.id) || null,
                })
                .select("id"),
              "заезд",
            ),
            await Y(
              A.rpc("term_req_op", {
                p_id: L.id,
                p_op: "arrive",
              }),
            ),
            W)
          ) {
            const re = await Y(
              A.from("term_truck_visits")
                .select("id")
                .eq("request_id", L.id)
                .order("id", {
                  ascending: !1,
                })
                .limit(1),
            );
            (await Rs(W, "visit", ($e = re == null ? void 0 : re[0]) == null ? void 0 : $e.id, t),
              await je(
                "visit",
                (ee = re == null ? void 0 : re[0]) == null ? void 0 : ee.id,
                "arrive_camera",
                {
                  машина: L.vehicle_no,
                  распознано: W.value,
                  уверенность: W.confidence,
                },
                t,
              ));
          }
          (h({
            ok: `Заезд: ${L.vehicle_no} — статус «Прибыл»${W ? " (подтверждено по кадру камеры)" : ""}, машина ушла в очередь лаборатории`,
          }),
            w());
        } catch (re) {
          h({
            err: String(re.message || re),
          });
        }
    },
    D = async (L) => {
      if (L.gross_kg != null || L.tare_kg != null || L.lab_status !== "pending") {
        h({
          err: `${L.vehicle_no}: по машине уже есть результаты (лаборатория или весы) — заезд отменить нельзя, обратись к управляющему`,
        });
        return;
      }
      if (window.confirm(`Отменить ошибочный заезд ${L.vehicle_no}? Машина уйдёт с территории, заявка вернётся в «Ожидается».`))
        try {
          (await ue(
            A.from("term_truck_visits")
              .update({
                cancelled_at: new Date().toISOString(),
                cancelled_by: t.id,
                out_at: new Date().toISOString(),
                out_by: t.id,
                notes: [L.notes || "", "ЗАЕЗД ОТМЕНЁН (ошибка оформления)"].filter(Boolean).join(" · "),
              })
              .eq("id", L.id),
            "заезд " + L.vehicle_no,
          ),
            L.request_id &&
              (await Y(
                A.rpc("term_req_op", {
                  p_id: L.request_id,
                  p_op: "arrive_undo",
                }),
              )),
            await je(
              "visit",
              L.id,
              "cancel_arrival",
              {
                машина: L.vehicle_no,
              },
              t,
            ),
            h({
              ok: `Заезд ${L.vehicle_no} отменён — заявка снова «Ожидается»`,
            }),
            w());
        } catch (W) {
          h({
            err: String(W.message || W),
          });
        }
    },
    E = async (L, W) => {
      try {
        const K = [];
        if (
          (L.lab_status !== "rejected" &&
            (L.gross_kg == null && K.push("нет брутто"),
            L.tare_kg == null && K.push("нет тары"),
            L.unload_place || K.push("не указано место выгрузки"),
            L.ts_at || K.push("перевалка не отметила услугу"),
            L.net_kg != null && +L.net_kg <= 0 && K.push("нетто не больше нуля")),
          K.length && !window.confirm(`${L.vehicle_no}: ${K.join(", ")}. Всё равно выпустить машину?`))
        )
          return;
        (await ue(
          A.from("term_truck_visits")
            .update({
              out_at: new Date().toISOString(),
              out_by: t.id,
              out_source: W ? "camera" : "manual",
              out_event_id: (W == null ? void 0 : W.id) || null,
            })
            .eq("id", L.id),
          "машина " + L.vehicle_no,
        ),
          W &&
            (await Rs(W, "visit", L.id, t),
            await je(
              "visit",
              L.id,
              "exit_camera",
              {
                машина: L.vehicle_no,
                распознано: W.value,
              },
              t,
            )),
          L.request_id &&
            (await Y(
              A.rpc("term_req_op", {
                p_id: L.request_id,
                p_op: "finish",
                p_a: L.lab_status === "rejected" ? "rej" : "ok",
              }),
            )),
          K.length &&
            (await je(
              "visit",
              L.id,
              "exit_override",
              {
                машина: L.vehicle_no,
                продавлено: K,
              },
              t,
            )),
          h({
            ok: `Выезд: ${L.vehicle_no} — статус «Убыл»${L.lab_status === "rejected" ? " · заявка помечена «Отменена» (отказ лаборатории)" : ""}`,
          }),
          w());
      } catch (K) {
        h({
          err: String(K.message || K),
        });
      }
    },
    a = async (L) => {
      try {
        (await Y(
          A.rpc("term_req_op", {
            p_id: L.id,
            p_op: "t2",
          }),
        ),
          h({
            ok: `${L.vehicle_no} — поставлен на отстойник (Т2), лаборатория видит машину и вызовет по очереди`,
          }),
          w());
      } catch (W) {
        h({
          err: String(W.message || W),
        });
      }
    },
    f = async (L) => {
      if (!(
        L.t2_called_at &&
        !window.confirm(`${L.vehicle_no}: лаборатория уже вызвала эту машину на терминал. Снять отметку отстойника (Т2) вместе с вызовом?`)
      ))
        try {
          (await Y(
            A.rpc("term_req_op", {
              p_id: L.id,
              p_op: "t2_undo",
            }),
          ),
            h({
              ok: `${L.vehicle_no} — отметка отстойника (Т2) снята`,
            }),
            w());
        } catch (W) {
          h({
            err: String(W.message || W),
          });
        }
    },
    P = S.useMemo(
      () => (s || []).filter((L) => !L.t2_at).sort((L, W) => String(L.arrive_date || "").localeCompare(String(W.arrive_date || ""))),
      [s],
    ),
    T = S.useMemo(
      () =>
        (s || []).filter((L) => L.t2_at).sort((L, W) => (W.t2_called_at ? 1 : 0) - (L.t2_called_at ? 1 : 0) || new Date(L.t2_at) - new Date(W.t2_at)),
      [s],
    ),
    H = (u || []).filter((L) => L.tare_kg != null || L.lab_status === "rejected"),
    { TH: Q, apply: ae } = rt(),
    me = ae(u || [], {
      veh: (L) => L.vehicle_no,
      org: (L) => L.client,
      in: (L) => L.in_at,
      st: (L) => Ae(L).t,
      mx: (L) => js(L),
      n: (L) => (L.net_kg == null ? null : +L.net_kg),
    });
  return (
    <>
      {($ == null ? void 0 : $.k) === "req" && (
        <C_r
          r={$.r}
          ttn={p}
          setTtn={F}
          fcnt={j}
          onT2={() => {
            (m(null), a($.r));
          }}
          onUnT2={() => {
            (m(null), f($.r));
          }}
          onArrive={() => {
            (m(null), Z($.r));
          }}
          onPass={() =>
            y({
              kind: "pass",
              r: $.r,
            })
          }
          onAtt={() =>
            d({
              entity: "request",
              id: $.r.id,
              title: `Заявка №${$.r.id} · ${$.r.vehicle_no} · фото и файлы`,
            })
          }
          onClose={() => m(null)}
        />
      )}
      {($ == null ? void 0 : $.k) === "vis" && (
        <CJr
          v={$.v}
          fcnt={j}
          canExit={$.v.tare_kg != null || $.v.lab_status === "rejected"}
          onTtn={() =>
            y({
              kind: "ttn",
              v: $.v,
            })
          }
          onAtt={() =>
            d({
              entity: "visit",
              id: $.v.id,
              title: `Машина ${$.v.vehicle_no} · фото и файлы`,
            })
          }
          onEdit={() => {
            (m(null), z($.v));
          }}
          onExit={() => {
            (m(null), E($.v));
          }}
          onClose={() => m(null)}
        />
      )}
      {v && (
        <CGr
          reqs={s}
          visits={u}
          onArrive={(L) => {
            (U(!1), Z(L));
          }}
          onPass={(L) =>
            y({
              kind: "pass",
              r: L,
            })
          }
          onT2={(L) => a(L)}
          onExit={(L) => {
            (U(!1), E(L));
          }}
          onClose={() => U(!1)}
        />
      )}
      {M && (
        <CAt
          title={`Машина ${M.vehicle_no} · правка данных`}
          fields={Cl}
          row={M}
          table="term_truck_visits"
          onClose={() => z(null)}
          onDone={() => {
            (h({
              ok: "Изменения сохранены",
            }),
              w());
          }}
        />
      )}
      {(C == null ? void 0 : C.kind) === "pass" && <Bi r={C.r} onClose={() => y(null)} onSaved={() => l()} />}
      {(C == null ? void 0 : C.kind) === "ttn" && <Pi v={C.v} onClose={() => y(null)} />}
      {g && (
        <Kt
          me={t}
          entity={g.entity}
          id={g.id}
          title={g.title}
          onClose={() => {
            (d(null), b());
          }}
        />
      )}
      <Sl
        kind="plate"
        me={t}
        title="Камера ГРЗ · распознавание номера"
        hint="камера подставляет нужную строку, решение всегда за КПП · ищет и по номеру прицепа, и среди похожих номеров — камеры путают О и 0, В и 8 · если совпадения нет или номер распознан неверно, оформляйте заезд и выезд вручную, как обычно"
        rows={[
          ...(s || []).map((L) => ({
            id: "r" + L.id,
            k: "req",
            r: L,
          })),
          ...(u || []).map((L) => ({
            id: "v" + L.id,
            k: "vis",
            v: L,
          })),
        ]}
        keysOf={(L) => (L.k === "req" ? [De(L.r.vehicle_no), De(L.r.trailer_no)] : [De(L.v.vehicle_no), De(L.v.trailer_no)])}
        label={(L) =>
          L.k === "req" ? (
            <>
              <b>{L.r.vehicle_no}</b>
              {L.r.trailer_no ? <span className="faint"> / {L.r.trailer_no}</span> : null} <span className="faint">· {L.r.culture || "—"}</span>{" "}
              <span className={"stage " + et(L.r).c}>{et(L.r).t}</span>
            </>
          ) : (
            <>
              <b>{L.v.vehicle_no}</b>
              {L.v.trailer_no ? <span className="faint"> / {L.v.trailer_no}</span> : null} <span className="faint">· на терминале · {Ae(L.v).t}</span>
            </>
          )
        }
        actions={(L, W, K) =>
          L.k === "req" ? (
            <>
              <button
                className="btn sm"
                onClick={async () => {
                  (await Z(L.r, W), K());
                }}
              >
                Прибыл ↓
              </button>{" "}
              <button
                className="btn sec sm"
                onClick={() =>
                  m({
                    k: "req",
                    r: L.r,
                  })
                }
              >
                Карточка
              </button>
            </>
          ) : (
            <>
              {L.v.tare_kg != null || L.v.lab_status === "rejected" ? (
                <button
                  className="btn sm"
                  onClick={async () => {
                    (await E(L.v, W), K());
                  }}
                >
                  Убыл ↑
                </button>
              ) : (
                <span className="faint">ещё не готова к выезду</span>
              )}{" "}
              <button
                className="btn sec sm"
                onClick={() =>
                  m({
                    k: "vis",
                    v: L.v,
                  })
                }
              >
                Карточка
              </button>
            </>
          )
        }
      />
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Заезд · ожидаемые машины по заявкам · {P.length}</h2>
          <span
            className="row"
            style={{
              gap: 6,
              alignItems: "center",
            }}
          >
            <button className="btn sm" title="Крупный экран для работы у ворот: поиск по номеру машины и большие кнопки" onClick={() => U(!0)}>
              ⛶ Режим ворот
            </button>
            <button className="btn sec sm" onClick={w}>
              Обновить
            </button>
          </span>
        </div>
        <p className="p-sub">
          клик по строке — карточка заезда со всеми данными и телефоном водителя · «Отстойник (Т2) ↓» — машина встала на отстойник и перешла в блок
          ниже · «Прибыл» — заезд сразу на терминал
        </p>
        <CFe err={i} />
        <CFe {...(_ || {})} />
        {!P.length && (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            ожидаемых машин нет — заявки появятся здесь, как только менеджер их заведёт
          </p>
        )}
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <th>Машина / прицеп</th>
                <th>Организация</th>
                <th>Поручение</th>
                <th>Культура</th>
                <th className="right">Вес, кг</th>
                <th>Дата (план)</th>
                <th>Водитель</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {P.map((L) => {
                var W;
                return (
                  <tr
                    className="rowx"
                    title="Открыть карточку заезда"
                    onClick={() =>
                      m({
                        k: "req",
                        r: L,
                      })
                    }
                  >
                    <td>
                      <b>{L.vehicle_no}</b>
                      {L.trailer_no ? <span className="faint"> / {L.trailer_no}</span> : null}
                    </td>
                    <td>{L.client || "—"}</td>
                    <td>{((W = L.term_orders) == null ? void 0 : W.order_no) || "—"}</td>
                    <td>{L.culture || "—"}</td>
                    <td className="right">{L.planned_tonnes != null ? q(qe(L.planned_tonnes)) : "—"}</td>
                    <td className="nowrap">{L.arrive_date || "—"}</td>
                    <td>{L.driver || "—"}</td>
                    <td className="nowrap" onClick={ct}>
                      <button className="btn sec sm" title="Отметить прибытие на отстойник (Т2)" onClick={() => a(L)}>
                        Отстойник (Т2) ↓
                      </button>{" "}
                      <label className="ttnchk" title="ТТН у водителя">
                        <input
                          type="checkbox"
                          checked={p[L.id] === !0}
                          onChange={(K) =>
                            F((le) => ({
                              ...le,
                              [L.id]: K.target.checked,
                            }))
                          }
                        />
                        ТТН
                      </label>{" "}
                      <button
                        className="btn sec sm"
                        title="Печать временного автопропуска"
                        onClick={() =>
                          y({
                            kind: "pass",
                            r: L,
                          })
                        }
                      >
                        Пропуск
                      </button>{" "}
                      <CGt
                        n={j("request", L.id)}
                        onClick={() =>
                          d({
                            entity: "request",
                            id: L.id,
                            title: `Заявка №${L.id} · ${L.vehicle_no} · фото и файлы`,
                          })
                        }
                      />{" "}
                      <button className="btn sm" onClick={() => Z(L)}>
                        Прибыл ↓
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">
            Отстойник (Т2) · {T.length}
            {T.filter((L) => L.t2_called_at).length ? ` · вызвано ${T.filter((L) => L.t2_called_at).length}` : ""}
          </h2>
        </div>
        <p className="p-sub">
          машины зарегистрировались по телефону и ждут вызова лаборатории · вызванные — вверху, их пропускаем на терминал кнопкой «Прибыл» · ✕ — снять
          отметку, машина вернётся в ожидаемые
        </p>
        {T.length ? (
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <th>Машина / прицеп</th>
                  <th>Организация</th>
                  <th>Культура</th>
                  <th className="right">Вес, кг</th>
                  <th>Водитель</th>
                  <th>На отстойнике с</th>
                  <th>Вызов лаборатории</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {T.map((L) => (
                  <tr
                    className="rowx"
                    title="Открыть карточку заезда"
                    onClick={() =>
                      m({
                        k: "req",
                        r: L,
                      })
                    }
                  >
                    <td>
                      <b>{L.vehicle_no}</b>
                      {L.trailer_no ? <span className="faint"> / {L.trailer_no}</span> : null}
                    </td>
                    <td>{L.client || "—"}</td>
                    <td>{L.culture || "—"}</td>
                    <td className="right">{L.planned_tonnes != null ? q(qe(L.planned_tonnes)) : "—"}</td>
                    <td>{L.driver || "—"}</td>
                    <td className="nowrap">{Ue(L.t2_at)}</td>
                    <td className="nowrap">
                      {L.t2_called_at ? (
                        <span className="t2chip ok" title="Лаборатория вызвала машину — пропускаем на терминал">
                          вызван {Ue(L.t2_called_at)}
                        </span>
                      ) : (
                        <span className="t2chip">ждёт вызова</span>
                      )}
                    </td>
                    <td className="nowrap" onClick={ct}>
                      <label className="ttnchk" title="ТТН у водителя">
                        <input
                          type="checkbox"
                          checked={p[L.id] === !0}
                          onChange={(W) =>
                            F((K) => ({
                              ...K,
                              [L.id]: W.target.checked,
                            }))
                          }
                        />
                        ТТН
                      </label>{" "}
                      <button
                        className="btn sec sm"
                        title="Печать временного автопропуска"
                        onClick={() =>
                          y({
                            kind: "pass",
                            r: L,
                          })
                        }
                      >
                        Пропуск
                      </button>{" "}
                      <CGt
                        n={j("request", L.id)}
                        onClick={() =>
                          d({
                            entity: "request",
                            id: L.id,
                            title: `Заявка №${L.id} · ${L.vehicle_no} · фото и файлы`,
                          })
                        }
                      />{" "}
                      <button className="btn sm" onClick={() => Z(L)}>
                        Прибыл ↓
                      </button>{" "}
                      <button className="btn sec sm icon" title="Снять отметку отстойника (Т2)" onClick={() => f(L)}>
                        ✕
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            на отстойнике пусто — отмечай прибывших кнопкой «Отстойник (Т2) ↓» в списке выше
          </p>
        )}
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">
            Машины на территории · {(u || []).length} · к выезду {H.length}
          </h2>
        </div>
        <p className="p-sub">
          выезд доступен после взвешивания порожним (статус «К выезду») либо при отказе лаборатории · ✎ — исправить данные машины/водителя
        </p>
        <CFe err={x} />
        {!me.length && (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            на территории пусто — машины появятся здесь после кнопки «Прибыл ↓»
          </p>
        )}
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <Q k="veh">Машина</Q>
                <Q k="org">Организация</Q>
                <Q k="in">Заезд</Q>
                <Q k="st">Статус</Q>
                <Q k="mx">Замес</Q>
                <Q k="n" right={!0}>
                  Нетто, кг
                </Q>
                <th />
              </tr>
            </thead>
            <tbody>
              {me.map((L) => {
                const W = Ae(L),
                  K = L.tare_kg != null || L.lab_status === "rejected";
                return (
                  <tr
                    className="rowx"
                    title="Открыть карточку машины"
                    onClick={() =>
                      m({
                        k: "vis",
                        v: L,
                      })
                    }
                  >
                    <td>
                      <b>{L.vehicle_no}</b>
                      {L.trailer_no ? <span className="faint"> / {L.trailer_no}</span> : null}
                    </td>
                    <td>{L.client || "—"}</td>
                    <td className="nowrap">{Ue(L.in_at)}</td>
                    <td>
                      <span className={"stage " + W.c}>{W.t}</span>
                    </td>
                    <td
                      style={{
                        maxWidth: 220,
                        whiteSpace: "normal",
                      }}
                    >
                      <Gt v={L} dash={!0} />
                    </td>
                    <td className="right">{q(L.net_kg)}</td>
                    <td className="nowrap" onClick={ct}>
                      <button
                        className="btn sec sm"
                        title="Печать ТТН (зерно)"
                        onClick={() =>
                          y({
                            kind: "ttn",
                            v: L,
                          })
                        }
                      >
                        ТТН
                      </button>{" "}
                      <CGt
                        n={j("visit", L.id)}
                        onClick={() =>
                          d({
                            entity: "visit",
                            id: L.id,
                            title: `Машина ${L.vehicle_no} · фото и файлы`,
                          })
                        }
                      />{" "}
                      <Ye onClick={() => z(L)} />
                      {L.lab_status === "pending" && L.gross_kg == null && (
                        <>
                          {" "}
                          <button className="btn sec sm" title="Отменить ошибочный заезд — заявка вернётся в «Ожидается»" onClick={() => D(L)}>
                            ↩ отменить заезд
                          </button>
                        </>
                      )}
                      {K && (
                        <>
                          {" "}
                          <button className="btn sm" onClick={() => E(L)}>
                            Убыл ↑
                          </button>
                        </>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
const Kn = [
    ["type", ["тип конт", "тип", "размер", "iso", "type"], "Тип (20DC/40HC/40)"],
    ["line", ["линия", "line", "перевозчик"], "Линия"],
    ["booking", ["букинг", "booking", "бронь"], "Букинг"],
    ["release", ["релиз", "наряд", "release"], "№ релиза"],
    ["detach", ["откреплен", "заказ"], "№ открепления"],
    ["term", ["терминал", "площадка порта", "стивидор"], "Терминал порта"],
    ["ord", ["очерёдност", "очередност", "очер.", "приоритет"], "Очерёдность вывоза"],
    ["client", ["клиент", "получател", "грузополучател"], "Клиент"],
    ["cargo", ["груз", "товар", "культур", "cargo"], "Груз"],
    ["ctare", ["тара", "tare"], "Тара контейнера, кг"],
    ["maxg", ["макс", "гросс", "брутто", "gross"], "Max gross, кг"],
    ["payl", ["payload", "полезн", "нагрузк"], "Payload, кг"],
    ["eta", ["дата", "подач", "прибыт", "eta"], "Дата"],
    ["slot", ["слот", "slot", "время"], "Слот"],
    ["veh", ["машин", "авто", "а/м", "а\\м"], "№ машины"],
    ["drv", ["водител", "фио"], "Водитель"],
    ["note", ["примечан", "коммент"], "Примечание"],
  ],
  fr = (t) => !!t && t.length <= 30 && /контейнер|container|конт\.?\b/.test(t) && !/тип|размер|type|size/.test(t),
  br = (t) => {
    const n = String(t || "").trim();
    if (!n) return null;
    const s = n.match(/^(\d{4})-(\d{2})-(\d{2})/);
    if (s) return s[0];
    const l = n.match(/^(\d{1,2})[.\-/](\d{1,2})[.\-/](\d{2,4})/);
    return l ? `${l[3].length === 2 ? "20" + l[3] : l[3]}-${l[2].padStart(2, "0")}-${l[1].padStart(2, "0")}` : null;
  },
  kr = (t) => {
    const n = String(t || "")
        .toUpperCase()
        .replace(/[^0-9A-Z]/g, ""),
      s = (n.match(/^(20|40|45)/) || [])[1] || null,
      l = /HC|HQ/.test(n) ? "HC" : /RE|RF/.test(n) ? "RE" : /DC|DV|GP|ST/.test(n) ? "DC" : null;
    return {
      size: s === "45" ? "40" : s,
      height: l,
    };
  };
function CWr({ me: t, have: n, onClose: s, onDone: l }) {
  const [i, u] = S.useState(null),
    [o, x] = S.useState(null),
    [N, b] = S.useState(""),
    [j, g] = S.useState(!1),
    [d, M] = S.useState(!1),
    [z, _] = S.useState(0),
    [h, w] = S.useState([]),
    p = S.useMemo(() => (i || []).filter(($) => !/^[A-Z]{4}\d{7}$/.test($.no)), [i]),
    F = S.useMemo(() => (i || []).filter(($) => n.has($.no)), [i, n]),
    C = async ($) => {
      (x(null), u(null), _(0), w([]), b($.name));
      try {
        const m = (await import("exceljs")).default || (await import("exceljs")),
          v = new m.Workbook();
        if ((await v.xlsx.load(await $.arrayBuffer()), !v.worksheets.length)) throw new Error("В файле нет ни одного листа");
        const U = [],
          Z = [];
        for (const D of v.worksheets) {
          let E = null,
            a = 0;
          (D.eachRow((f) => {
            const P = [];
            f.eachCell(
              {
                includeEmpty: !0,
              },
              (H, Q) => {
                P[Q - 1] = H.value;
              },
            );
            const T = (H) => {
              if (H == null || H < 0) return "";
              const Q = P[H];
              return Q == null
                ? ""
                : typeof Q == "object" && Q.richText
                  ? Q.richText.map((ae) => ae.text).join("")
                  : typeof Q == "object" && Q.text
                    ? String(Q.text)
                    : Q instanceof Date
                      ? Q.toISOString().slice(0, 10)
                      : String(Q).trim();
            };
            if (!E) {
              const H = P.map((W) =>
                  String(W || "")
                    .toLowerCase()
                    .replace(/\s+/g, " ")
                    .trim(),
                ),
                Q = H.map((W, K) => (fr(W) ? K : -1)).filter((W) => W >= 0);
              if (!Q.length) return;
              const ae = Q[0],
                L = Q.map((W, K) => [Math.max(0, W - ae), K + 1 < Q.length ? Math.max(0, Q[K + 1] - ae) : H.length]).map(([W, K], le) => {
                  const $e = {
                    no: Q[le],
                  };
                  for (const [ee, re] of Kn) {
                    const be = H.findIndex((Ne, ze) => ze >= W && ze < K && Ne && Ne.length <= 40 && re.some((Ke) => Ne.includes(Ke)));
                    $e[ee] = be;
                  }
                  return $e;
                });
              if (!L.some((W) => Object.values(W).filter((K) => K >= 0).length >= 2)) return;
              E = L;
              return;
            }
            for (const H of E) {
              const Q = T(H.no)
                .toUpperCase()
                .replace(/[^A-Z0-9]/g, "");
              if (!/^[A-Z]{4}\d{7}$/.test(Q) && !/^[A-Z]{2,4}\d{6,7}$/.test(Q)) continue;
              const { size: ae, height: me } = kr(T(H.type)),
                L = T(H.slot),
                W = T(H.note);
              (a++,
                U.push({
                  no: Q,
                  size: ae,
                  height: me,
                  sheet: D.name,
                  line: T(H.line),
                  booking: T(H.booking),
                  release: T(H.release) || T(H.detach),
                  term: T(H.term),
                  ord: T(H.ord),
                  client: T(H.client),
                  cargo: T(H.cargo),
                  ctare: te(T(H.ctare)),
                  maxg: te(T(H.maxg)),
                  payl: te(T(H.payl)),
                  eta: br(T(H.eta)),
                  veh: De(T(H.veh)),
                  drv: T(H.drv),
                  note: [L ? "слот " + L : null, W || null].filter(Boolean).join(" · "),
                }));
            }
          }),
            Z.push(`${D.name}: ${E ? `${a} строк` : "шапка не найдена"}`));
        }
        if (!U.length)
          throw new Error(
            `Строк с номерами контейнеров не найдено. По листам — ${Z.join(" · ")}. Нужна строка заголовков, где есть столбец «Контейнер» (или «№ контейнера», «Container»).`,
          );
        const I = new Map();
        for (const D of U) {
          const E = I.get(D.no);
          if (!E) {
            I.set(D.no, D);
            continue;
          }
          for (const a of Object.keys(D)) (E[a] == null || E[a] === "") && D[a] != null && D[a] !== "" && (E[a] = D[a]);
        }
        (u([...I.values()]), _(U.length - I.size), w(Z));
      } catch (m) {
        x(String(m.message || m));
      }
    },
    y = async () => {
      try {
        if (p.length && !d)
          throw new Error(
            `Не в формате ABCD1234567: ${p
              .slice(0, 4)
              .map((v) => v.no)
              .join(", ")}${p.length > 4 ? "…" : ""} — строк ${p.length}. Проверь файл или отметь галочку.`,
          );
        if (F.length && !d)
          throw new Error(
            `${F.length} контейнеров уже числятся в системе (${F.slice(0, 4)
              .map((v) => v.no)
              .join(", ")}${F.length > 4 ? "…" : ""}) — похоже, этот реестр уже загружали.`,
          );
        (g(!0), x(null));
        const $ = i.filter((v) => !n.has(v.no));
        if (!$.length) throw new Error("Все контейнеры из файла уже есть в системе — добавлять нечего");
        const m = new Date().toISOString();
        (await ue(
          A.from("term_line_containers").insert(
            $.map((v) => ({
              container_no: v.no,
              size: v.size,
              height: v.height,
              line: v.line || null,
              booking: v.booking || null,
              release_no: v.release || null,
              client: v.client || null,
              cargo: v.cargo || null,
              port_terminal: v.term || null,
              port_order: v.ord || null,
              cont_tare_kg: v.ctare,
              max_gross_kg: v.maxg,
              payload_kg: v.payl,
              eta_date: v.eta,
              in_vehicle_no: v.veh || null,
              driver: v.drv || null,
              notes: v.note || null,
              state: "expected",
              exp_at: m,
              exp_by: t.id,
              exp_src: [N || "файл", v.sheet && h.length > 1 ? "· " + v.sheet : ""].filter(Boolean).join(" "),
            })),
          ),
          "реестр порта",
        ),
          await je(
            "container",
            null,
            "expect_import",
            {
              файл: N,
              строк: $.length,
              контейнеры: $.slice(0, 20).map((v) => v.no),
            },
            t,
          ),
          g(!1),
          l($.length, N));
      } catch ($) {
        (x(String($.message || $)), g(!1));
      }
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={($) => {
        $.target === $.currentTarget && s();
      }}
    >
      <div
        className="modal"
        style={{
          width: 900,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Реестр порта · загрузка контейнеров к приезду</h2>
          <button className="btn sec sm" onClick={s}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <p className="p-sub">
            подходит любой .xlsx, где есть столбец с номером контейнера. Читаются все листы файла; если на листе тот же набор колонок повторён двумя
            блоками — берутся оба. Остальные колонки подхватываются по названию: {Kn.map(($) => $[2]).join(" · ")}. Чего в файле нет — останется
            пустым и допишется при приёмке.
          </p>
          <div
            className="row"
            style={{
              gap: 10,
            }}
          >
            <X label="Файл реестра (.xlsx)">
              <input type="file" accept=".xlsx,.xls" onChange={($) => $.target.files[0] && C($.target.files[0])} />
            </X>
          </div>
          <CFe err={o} />
          {i && (
            <>
              <p
                className="p-sub"
                style={{
                  margin: "10px 0 6px",
                }}
              >
                распознано контейнеров: <b>{i.length}</b>
                {F.length ? ` · уже в системе: ${F.length}` : ""}
                {p.length ? ` · номер не по формату: ${p.length}` : ""}
                {z ? ` · склеено повторов блока: ${z}` : ""}
              </p>
              <p
                className="p-sub"
                style={{
                  margin: "0 0 6px",
                }}
              >
                по листам: {h.join(" · ")}
              </p>
              <div
                className="tscroll"
                style={{
                  maxHeight: "40vh",
                }}
              >
                <table>
                  <thead>
                    <tr>
                      <th>Контейнер</th>
                      <th>Тип</th>
                      <th>Линия</th>
                      <th>Букинг</th>
                      <th>Релиз</th>
                      <th>Терминал</th>
                      <th>Очер.</th>
                      <th>Дата</th>
                      <th>Машина</th>
                      <th>Водитель</th>
                      <th>Лист</th>
                    </tr>
                  </thead>
                  <tbody>
                    {i.map(($, m) => (
                      <tr className={p.includes($) || F.includes($) ? "badrow" : void 0}>
                        <td>
                          <b>{$.no}</b>
                          {F.includes($) ? <span className="faint"> · уже есть</span> : null}
                        </td>
                        <td>{$.size ? `${$.size}'${$.height ? " " + $.height : ""}` : "—"}</td>
                        <td>{$.line || "—"}</td>
                        <td>{$.booking || "—"}</td>
                        <td>{$.release || "—"}</td>
                        <td>{$.term || "—"}</td>
                        <td>{$.ord || "—"}</td>
                        <td className="nowrap">{$.eta || "—"}</td>
                        <td>{$.veh || "—"}</td>
                        <td>{$.drv || "—"}</td>
                        <td className="faint">{$.sheet}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </>
          )}
        </div>
        <div className="m-foot">
          <button className="btn" disabled={!i || j} onClick={y}>
            {j ? "Загружаю…" : `Добавить в ожидаемые${i ? ` · ${i.length - F.length}` : ""}`}
          </button>
          {(p.length > 0 || F.length > 0) && (
            <label className="fkey">
              <input type="checkbox" checked={d} onChange={($) => M($.target.checked)} /> вижу замечания, всё равно загрузить
            </label>
          )}
        </div>
      </div>
    </div>
  );
}
function Ml({ me: t }) {
  const [n, s] = S.useState(null),
    [l, i, u] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("*")
            .is("out_at", null)
            .neq("state", "expected")
            .order("in_at", {
              ascending: !1,
            })
            .limit(2e3),
        ),
      [],
      2e4,
    ),
    [o, x, N] = ne(() => Y(A.from("term_line_containers").select("*").eq("state", "expected").order("container_no").limit(2e3)), [], 2e4),
    [b, j] = S.useState(!1),
    g = ["dispatcher", "manager", "chief"].includes(t.role),
    [d, M] = S.useState(""),
    [z, _] = Te("draft.kpp.exp", {}),
    h = S.useMemo(
      () =>
        (o || []).filter((r) => {
          const O = d.trim().toLowerCase();
          return (
            !O ||
            [r.container_no, r.line, r.booking, r.release_no, r.port_terminal, r.port_order, r.client, r.cargo, r.in_vehicle_no, r.driver].some((G) =>
              String(G || "")
                .toLowerCase()
                .includes(O),
            )
          );
        }),
      [o, d],
    ),
    [w] = ne(
      () =>
        Y(
          A.from("term_batches")
            .select("id, batch_no, status")
            .order("id", {
              ascending: !1,
            })
            .limit(2e3),
        ),
      [],
      3e4,
    ),
    p = S.useMemo(() => {
      const r = {};
      return (
        (w || []).forEach((O) => {
          r[O.id] = O;
        }),
        r
      );
    }, [w]),
    [F, C] = S.useState(""),
    [y, $] = S.useState(null),
    [m, v] = Te("draft.kpp.cont", {
      size: "40",
      height: "HC",
    }),
    [U, Z] = Te("draft.kpp.out", {}),
    [I, D] = ne(() => Y(A.from("term_files").select("id, entity, entity_id").eq("entity", "container").limit(5e3)), [], 3e4),
    E = (r) => (I || []).reduce((O, G) => O + (G.entity_id === r ? 1 : 0), 0),
    [a, f] = S.useState(null),
    [P, T] = S.useState(null),
    [H, Q] = S.useState(null),
    ae = [
      {
        k: "container_no",
        t: "№ контейнера",
        req: 1,
        w: 160,
      },
      {
        k: "size",
        t: "Тип",
        w: 90,
        opts: us,
      },
      {
        k: "height",
        t: "Высота",
        w: 90,
        opts: ms,
      },
      {
        k: "line",
        t: "Линия",
        w: 180,
        dict: "line",
      },
    ],
    me = S.useRef(!1),
    L = (r) => {
      const O = (o || []).find((G) => String(G.id) === String(r));
      if (!O) {
        v((G) => ({
          ...G,
          exp: "",
          no: "",
        }));
        return;
      }
      (v((G) => ({
        ...G,
        exp: String(O.id),
        no: O.container_no,
        size: O.size || G.size,
        height: O.height || G.height,
        line: O.line || G.line,
        client: O.client || "",
        bk: O.booking || "",
        kept: !1,
      })),
        Q({
          ok: `${O.container_no} из реестра порта${O.port_terminal ? ` · терминал ${O.port_terminal}` : ""}${O.release_no ? ` · релиз ${O.release_no}` : ""}${O.driver ? ` · водитель ${O.driver}` : ""}`,
        }));
    },
    W = (r) => {
      const O = String(r || "")
          .toUpperCase()
          .replace(/[^A-Z0-9]/g, "")
          .slice(0, 11),
        G = (o || []).find((ie) => (ie.container_no || "").toUpperCase() === O);
      G
        ? (v((ie) => ({
            ...ie,
            no: O,
            exp: String(G.id),
            size: G.size || ie.size,
            height: G.height || ie.height,
            line: G.line || ie.line,
            client: G.client || "",
            bk: G.booking || "",
            kept: !1,
          })),
          Q({
            ok: `${O} из реестра порта${G.port_terminal ? ` · терминал ${G.port_terminal}` : ""}${G.release_no ? ` · релиз ${G.release_no}` : ""}${G.eta_date ? ` · подача ${String(G.eta_date).split("-").reverse().join(".")}` : ""}${G.driver ? ` · водитель ${G.driver}` : ""}`,
          }))
        : v((ie) => ({
            ...ie,
            no: O,
            exp: "",
          }));
    },
    K = S.useMemo(() => {
      const r = (m.no || "").trim().toUpperCase();
      return (r && (o || []).find((O) => (O.container_no || "").toUpperCase() === r)) || null;
    }, [o, m.no]),
    le = async () => {
      if (me.current) return;
      const r = (m.no || "").trim().toUpperCase();
      if (!/^[A-Z]{4}\d{7}$/.test(r)) {
        Q({
          err: "Номер контейнера в формате ABCD1234567",
        });
        return;
      }
      const O = (l || []).find((c) => (c.container_no || "").toUpperCase() === r);
      if (O) {
        Q({
          err: `Контейнер ${r} числится на терминале с ${he(O.in_at)}, статус «${tt(O, p)}». Если он давно уехал и выезд не отметили — найди его в списке и нажми «Убыл», потом оформляй заезд заново.`,
        });
        return;
      }
      if (!ss(r) && !m.ovr) {
        Q({
          err: `${r}: не сходится контрольная цифра номера (стандарт ISO 6346) — скорее всего опечатка. Проверь номер или отметь «подтверждаю».`,
        });
        return;
      }
      const G = (o || []).find((c) => (c.container_no || "").toUpperCase() === r);
      if (!(
        !G &&
        (o || []).length &&
        !m.ovr9 &&
        !window.confirm(`${r} не заявлен портом к приезду — в реестре ожидаемых его нет.

Оформить заезд? Контейнер будет помечен «вне реестра», чтобы диспетчеры свели список с портом.`)
      )) {
        me.current = !0;
        try {
          const c = {
            size: m.size,
            height: m.height,
            line: (m.line || "").trim() || null,
            site: m.site || null,
            client: (m.client || "").trim() || null,
            booking: (m.bk || "").trim() || null,
            in_at: new Date().toISOString(),
            in_by: t.id,
            state: "arrived",
          };
          (G
            ? (await ue(A.from("term_line_containers").update(c).eq("id", G.id), "контейнер " + r),
              await je(
                "container",
                G.id,
                "arrive_from_list",
                {
                  контейнер: r,
                  "заявлен на": G.eta_date || null,
                  релиз: G.release_no || void 0,
                },
                t,
              ))
            : (await ue(
                A.from("term_line_containers").insert({
                  ...c,
                  container_no: r,
                  off_list: !0,
                }),
                "контейнер",
              ),
              await je(
                "container",
                null,
                "arrive_off_list",
                {
                  контейнер: r,
                  "в реестре порта": "нет",
                },
                t,
              )),
            ss(r) ||
              (await je(
                "container",
                null,
                "iso_override",
                {
                  контейнер: r,
                },
                t,
              )),
            v({
              size: m.size,
              height: m.height,
              line: m.line,
              kept: !0,
            }),
            Q({
              ok: G
                ? `Заезд ${r} из реестра порта — статус «Порожний», контейнер в очереди приёмки`
                : `Заезд ${r} — статус «Порожний». Контейнер помечен «вне реестра»: в списке от порта его не было`,
            }),
            i(),
            x());
        } catch (c) {
          Q({
            err: /uq_active_container_no|duplicate key/i.test(String(c.message || c))
              ? `${r} уже числится на терминале — второй раз заезд не оформляется`
              : String(c.message || c),
          });
        }
        me.current = !1;
      }
    },
    $e = async () => {
      const r = (z.no || "").trim().toUpperCase();
      if (!/^[A-Z]{4}\d{7}$/.test(r)) {
        Q({
          err: "Номер контейнера в формате ABCD1234567",
        });
        return;
      }
      const O = [...(o || []), ...(l || [])].find((G) => (G.container_no || "").toUpperCase() === r);
      if (O) {
        Q({
          err: `${r} уже в системе — статус «${tt(O, p)}»`,
        });
        return;
      }
      if (!ss(r) && !z.ovr) {
        Q({
          err: `${r}: не сходится контрольная цифра номера (ISO 6346). Проверь или отметь «подтверждаю».`,
        });
        return;
      }
      try {
        (await ue(
          A.from("term_line_containers").insert({
            container_no: r,
            size: z.size || null,
            height: z.height || null,
            line: (z.line || "").trim() || null,
            booking: (z.bk || "").trim() || null,
            release_no: (z.rel || "").trim() || null,
            port_terminal: (z.term || "").trim() || null,
            port_order: (z.ord || "").trim() || null,
            client: (z.client || "").trim() || null,
            cargo: (z.cargo || "").trim() || null,
            cont_tare_kg: te(z.ctare),
            max_gross_kg: te(z.maxg),
            payload_kg: te(z.payl),
            eta_date: z.eta || null,
            in_vehicle_no: De(z.veh) || null,
            driver: (z.drv || "").trim() || null,
            state: "expected",
            exp_at: new Date().toISOString(),
            exp_by: t.id,
            exp_src: "вручную",
          }),
          "ожидаемый контейнер",
        ),
          await je(
            "container",
            null,
            "expect_add",
            {
              контейнер: r,
              "заявлен на": z.eta || null,
            },
            t,
          ),
          _({
            size: z.size,
            height: z.height,
            line: z.line,
            eta: z.eta,
            term: z.term,
            rel: z.rel,
          }),
          Q({
            ok: `${r} добавлен в ожидаемые — на воротах его можно будет выбрать из списка`,
          }),
          x());
      } catch (G) {
        Q({
          err: String(G.message || G),
        });
      }
    },
    ee = async (r) => {
      if (
        window.confirm(`Убрать ${r.container_no} из ожидаемых? Строка удаляется — если контейнер всё же приедет, КПП оформит его как «вне реестра».`)
      )
        try {
          (await ue(A.from("term_line_containers").delete().eq("id", r.id), "ожидаемый контейнер"),
            await je(
              "container",
              r.id,
              "expect_del",
              {
                контейнер: r.container_no,
              },
              t,
            ),
            Q({
              ok: `${r.container_no} убран из ожидаемых`,
            }),
            x());
        } catch (O) {
          Q({
            err: String(O.message || O),
          });
        }
    },
    re = ["loaded", "inspected", "fumigated"],
    be = async (r) => {
      const O = U[r.id] || {};
      if (!(O.veh || "").trim()) {
        Q({
          err: "Укажи номер машины вывоза",
        });
        return;
      }
      const G = !re.includes(r.state),
        ie = (O.seal || "").trim();
      if (!G && !ie) {
        Q({
          err: `${r.container_no}: впиши номер пломбы с контейнера — система сверит его с записанным при затарке`,
        });
        return;
      }
      if (
        G &&
        !window.confirm(
          `${r.container_no} — состояние «${tt(r, p)}». Выпустить контейнер БЕЗ груза (линия забирает порожним / уходит в ремонт вне терминала)?`,
        )
      )
        return;
      const c = [];
      (G && c.push(`выпуск без груза из состояния «${tt(r, p)}»`),
        r.seal_no &&
          ie.toUpperCase() !== String(r.seal_no).toUpperCase() &&
          c.push(`пломба на контейнере «${ie}» не совпадает с записанной при затарке «${r.seal_no}»`),
        r.seal_no || c.push("при затарке пломба не записывалась — сверить не с чем"));
      const V = p[r.batch_id];
      if (
        (r.batch_id
          ? V && V.status !== "ready" && c.push(`партия ${V.batch_no} ещё не готова к отправке (${vt[V.status] || V.status})`)
          : c.push("контейнер не включён ни в одну партию"),
        !(
          !G &&
          c.length &&
          !window.confirm(`${r.container_no}: ${c.join("; ")}.

Всё равно выпустить контейнер?`)
        ))
      )
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                out_at: new Date().toISOString(),
                out_by: t.id,
                state: "dispatched",
                out_vehicle_no: De(O.veh),
                out_seal_no: ie || null,
                empty_out: G,
                seal_checked: !G && !!r.seal_no && ie.toUpperCase() === String(r.seal_no).toUpperCase(),
              })
              .eq("id", r.id),
            "контейнер " + r.container_no,
          ),
            await je(
              "container",
              r.id,
              "dispatch",
              {
                контейнер: r.container_no,
                пломба: ie,
                машина: O.veh,
                продавлено: c.length ? c : void 0,
              },
              t,
            ),
            Q({
              ok: `Выезд: ${r.container_no} — статус «Убыл»${c.length ? " (с подтверждением расхождений)" : " · пломба сверена"}`,
            }),
            i());
        } catch (J) {
          Q({
            err: String(J.message || J),
          });
        }
    },
    Ne = async (r) => {
      const O = r.empty_out ? "ready" : "loaded";
      if (
        window.confirm(
          `Отменить выезд контейнера ${r.container_no}? Он вернётся на терминал в статус «${O === "ready" ? "Принят · свободен под затарку" : "Гружёный"}».`,
        )
      )
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                out_at: null,
                out_by: null,
                out_vehicle_no: null,
                out_seal_no: null,
                seal_checked: !1,
                state: O,
              })
              .eq("id", r.id),
            "контейнер",
          ),
            await je(
              "container",
              r.id,
              "dispatch_undo",
              {
                контейнер: r.container_no,
                "вернулся в статус": O === "ready" ? "Принят" : "Гружёный",
              },
              t,
            ),
            Q({
              ok: `Выезд ${r.container_no} отменён`,
            }),
            i());
        } catch (G) {
          Q({
            err: String(G.message || G),
          });
        }
    },
    ze = ["manager", "chief"].includes(t.role),
    [Ke, He] = ne(
      () =>
        ze
          ? Y(
              A.from("term_line_containers")
                .select("id, container_no, out_at, out_vehicle_no, out_seal_no, seal_no, seal_checked, batch_id, empty_out, state, eta_date")
                .not("out_at", "is", null)
                .order("out_at", {
                  ascending: !1,
                })
                .limit(15),
            )
          : Promise.resolve([]),
      [ze],
      3e4,
    ),
    We = (l || []).filter((r) => ["loaded", "inspected", "fumigated"].includes(r.state)),
    Qe = (l || []).filter((r) => {
      var O;
      return r.batch_id && ((O = p[r.batch_id]) == null ? void 0 : O.status) === "ready";
    }),
    { TH: Ie, apply: ht } = rt(),
    B = ht(
      (l || [])
        .filter((r) => !y || Mt(r, p[r.batch_id]).k === y)
        .filter((r) => {
          var G;
          if (!F.trim()) return !0;
          const O = F.trim().toLowerCase();
          return [r.container_no, r.line, r.client, r.booking, r.cargo, r.stack, r.seal_no, (G = p[r.batch_id]) == null ? void 0 : G.batch_no].some(
            (ie) =>
              String(ie || "")
                .toLowerCase()
                .includes(O),
          );
        }),
      {
        no: (r) => r.container_no,
        tp: (r) => (r.size || "") + (r.height || ""),
        ln: (r) => r.line,
        st: (r) => tt(r, p),
        bt: (r) => {
          var O;
          return (O = p[r.batch_id]) == null ? void 0 : O.batch_no;
        },
        stk: (r) => r.stack,
        sl: (r) => r.seal_no,
        cli: (r) => r.client,
        bk: (r) => r.booking,
        si: (r) => r.site,
        cg: (r) => r.cargo,
        inn: (r) => r.in_at,
        veh: (r) => r.out_vehicle_no,
      },
    );
  return (
    <>
      {P && (
        <CAt
          title={`Контейнер ${P.container_no} · правка`}
          fields={ae}
          row={P}
          table="term_line_containers"
          onClose={() => T(null)}
          onDone={() => {
            (Q({
              ok: "Изменения сохранены",
            }),
              i());
          }}
        />
      )}
      {a && (
        <Kt
          me={t}
          entity="container"
          id={a.id}
          title={`Контейнер ${a.container_no} · фото и файлы`}
          onClose={() => {
            (f(null), D());
          }}
        />
      )}
      <div className="panel">
        <h2 className="p-title">Заезд порожнего контейнера (линия)</h2>
        <p className="p-sub">
          достаточно набрать номер: если контейнер заявлен портом, паспорт подставится сам и остальные поля заполнять не нужно · номера, которого в
          реестре нет, это не блокирует — заезд пройдёт, но контейнер будет помечен «вне реестра»
        </p>
        <CJt id="dl-line" items={Fe((l || []).map((r) => r.line))} />
        <CJt id="dl-lcli" items={Fe((l || []).map((r) => r.client))} />
        <CJt id="dl-exp9" items={(o || []).map((r) => r.container_no)} />
        <div className="row">
          <X label={`№ контейнера · в реестре порта ${(o || []).length}`}>
            <input
              list="dl-exp9"
              style={{
                width: 160,
                minWidth: 160,
              }}
              placeholder="MSKU1234567"
              value={m.no ?? ""}
              onChange={(r) => W(r.target.value)}
              onKeyDown={(r) => {
                r.key === "Enter" && le();
              }}
            />
          </X>
          {K ? (
            <X label="Что известно из реестра порта">
              <div
                className="ordinfo"
                style={{
                  margin: 0,
                  minWidth: 300,
                  padding: "6px 10px",
                  fontSize: 11.5,
                }}
              >
                <b>{K.size ? `${K.size}'${K.height || ""}` : "тип не указан"}</b>
                {K.line ? ` · линия ${K.line}` : ""}
                {K.booking ? ` · букинг ${K.booking}` : ""}
                {K.release_no ? ` · релиз ${K.release_no}` : ""}
                {K.port_terminal ? ` · ${K.port_terminal}` : ""}
                {K.client ? ` · ${K.client}` : ""}
              </div>
            </X>
          ) : null}
          <X label="Площадка">
            <CPe
              value={m.site || ""}
              onChange={(r) =>
                v((O) => ({
                  ...O,
                  site: r,
                }))
              }
              options={_t}
              w={140}
              ph="—"
            />
          </X>
          <button className="btn" onClick={le}>
            Заезд ↓
          </button>
          <label className="fkey">
            <input
              type="checkbox"
              checked={!!m.ovr}
              onChange={(r) =>
                v((O) => ({
                  ...O,
                  ovr: r.target.checked,
                }))
              }
            />{" "}
            подтверждаю номер
          </label>
          <button
            className="btn sec sm"
            onClick={() =>
              v((r) => ({
                ...r,
                more: !r.more,
              }))
            }
          >
            {m.more ? "▴ свернуть" : "▾ поправить вручную"}
          </button>
        </div>
        {(m.more || (!K && /^[A-Z]{4}\d{7}$/.test((m.no || "").trim().toUpperCase()))) && (
          <div
            className="row"
            style={{
              marginTop: 8,
            }}
          >
            <X label={"Тип" + (m.kept ? " · от прошлого" : "")}>
              <CPe
                value={m.size}
                onChange={(r) =>
                  v((O) => ({
                    ...O,
                    size: r,
                    kept: !1,
                  }))
                }
                options={us}
                w={80}
                ph="—"
              />
            </X>
            <X label={"Высота" + (m.kept ? " · от прошлого" : "")}>
              <CPe
                value={m.height}
                onChange={(r) =>
                  v((O) => ({
                    ...O,
                    height: r,
                    kept: !1,
                  }))
                }
                options={ms}
                w={80}
                ph="—"
              />
            </X>
            <X label="Линия">
              <It
                kind="line"
                me={t}
                value={m.line}
                onChange={(r) =>
                  v((O) => ({
                    ...O,
                    line: r,
                    kept: !1,
                  }))
                }
                w={130}
              />
            </X>
            <X label="Клиент (кому линия выдала)">
              <input
                list="dl-lcli"
                style={{
                  width: 170,
                  minWidth: 170,
                }}
                value={m.client ?? ""}
                onChange={(r) =>
                  v((O) => ({
                    ...O,
                    client: r.target.value,
                  }))
                }
              />
            </X>
            <X label="Букинг">{Se(m, v, "bk", "", 120)}</X>
          </div>
        )}
        {m.kept && (m.size || m.height) && (
          <p
            className="p-sub"
            style={{
              margin: "2px 0 0",
              color: "var(--warn)",
            }}
          >
            ⚠ тип {m.size || "—"}
            {m.height ? " " + m.height : ""} остался от прошлого контейнера — сверь с табличкой, если этот другой
          </p>
        )}
        {(() => {
          const r = (m.no || "").trim().toUpperCase();
          if (!/^[A-Z]{4}\d{7}$/.test(r)) return null;
          const O = (o || []).find((G) => (G.container_no || "").toUpperCase() === r);
          return O ? (
            <p
              className="p-sub"
              style={{
                margin: "2px 0 0",
                color: "var(--ok, #6a3)",
              }}
            >
              ✓ {r} есть в реестре порта{O.eta_date ? ` · подача ${String(O.eta_date).split("-").reverse().join(".")}` : ""}
              {O.release_no ? ` · релиз ${O.release_no}` : ""} — заедет по своей карточке
            </p>
          ) : (
            <p
              className="p-sub"
              style={{
                margin: "2px 0 0",
                color: "var(--warn)",
              }}
            >
              ⚠ {r} портом не заявлен — заезд оформится с пометкой «вне реестра»
            </p>
          );
        })()}
        <CFe {...(H || {})} />
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Ожидаются к приезду · {(o || []).length}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            {g && (
              <button className="btn sec sm" onClick={() => j(!0)}>
                ⇧ Загрузить реестр порта
              </button>
            )}
            <button className="btn sec sm" onClick={x}>
              Обновить
            </button>
          </span>
        </div>
        <p className="p-sub">
          {g
            ? "список от порта: что и когда повезут на терминал. Заводится строкой или файлом · на воротах номер выбирается из этого списка, а не набивается руками · строку можно убрать, пока контейнер не приехал"
            : "список от порта ведут диспетчеры — здесь он только для просмотра. Приехал контейнер — нажми «Заезд ↓» в его строке, номер и паспорт подставятся в форму выше"}
        </p>
        {g && (
          <div className="row">
            <X label="№ контейнера">{Se(z, _, "no", "MSKU1234567", 140)}</X>
            <X label="Тип">
              <CPe
                value={z.size || ""}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    size: r,
                  }))
                }
                options={us}
                w={70}
                ph="—"
              />
            </X>
            <X label="Высота">
              <CPe
                value={z.height || ""}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    height: r,
                  }))
                }
                options={ms}
                w={70}
                ph="—"
              />
            </X>
            <X label="Линия">
              <It
                kind="line"
                me={t}
                value={z.line}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    line: r,
                  }))
                }
                w={120}
              />
            </X>
            <X label="Букинг">{Se(z, _, "bk", "", 110)}</X>
            <X label="№ релиза / открепления">{Se(z, _, "rel", "", 150)}</X>
            <X label="Терминал порта">{Se(z, _, "term", "НКТ, НУТЭП…", 130)}</X>
            <X label="Очерёдность">{Se(z, _, "ord", "", 80)}</X>
            <X label="Клиент">
              <input
                list="dl-lcli"
                style={{
                  width: 150,
                  minWidth: 150,
                }}
                value={z.client ?? ""}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    client: r.target.value,
                  }))
                }
              />
            </X>
            <X label="Груз">{Se(z, _, "cargo", "", 120)}</X>
            <X label="Тара конт., кг">{Se(z, _, "ctare", "", 100)}</X>
            <X label="Max gross, кг">{Se(z, _, "maxg", "", 110)}</X>
            <X label="Payload, кг">{Se(z, _, "payl", "", 100)}</X>
            <X label="Дата подачи">
              <input
                type="date"
                style={{
                  width: 140,
                  minWidth: 140,
                }}
                value={z.eta ?? ""}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    eta: r.target.value,
                  }))
                }
              />
            </X>
            <X label="Машина">
              <input
                list="trucks9"
                style={{
                  width: 130,
                  minWidth: 130,
                }}
                value={z.veh ?? ""}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    veh: De(r.target.value),
                  }))
                }
              />
              <CUn />
            </X>
            <X label="Водитель">{Se(z, _, "drv", "", 150)}</X>
            <button className="btn" onClick={$e}>
              Добавить в ожидаемые
            </button>
            <label className="fkey">
              <input
                type="checkbox"
                checked={!!z.ovr}
                onChange={(r) =>
                  _((O) => ({
                    ...O,
                    ovr: r.target.checked,
                  }))
                }
              />{" "}
              подтверждаю номер
            </label>
          </div>
        )}
        <CFe err={N} />
        {(o || []).length > 0 && (
          <>
            <div
              className="row"
              style={{
                gap: 8,
                margin: "8px 0",
              }}
            >
              <input
                className="srch9"
                placeholder="Поиск: контейнер, линия, букинг, релиз, клиент, машина…"
                value={d}
                onChange={(r) => M(r.target.value)}
              />
              {d.trim() && !h.length ? <span className="find9no2">ничего не найдено</span> : null}
            </div>
            <div
              className="tscroll stick2"
              style={{
                maxHeight: "34vh",
              }}
            >
              <table>
                <thead>
                  <tr>
                    <th />
                    <th>Контейнер</th>
                    <th>Тип</th>
                    <th>Линия</th>
                    <th>Букинг</th>
                    <th>Релиз</th>
                    <th>Терминал</th>
                    <th>Очер.</th>
                    <th>Клиент</th>
                    <th>Груз</th>
                    <th>Подача</th>
                    <th>Машина</th>
                    <th>Заявил</th>
                    <th />
                  </tr>
                </thead>
                <tbody>
                  {h.map((r) => {
                    const O = r.eta_date && r.eta_date < Ve();
                    return (
                      <tr
                        className={"rowc" + (O ? " badrow" : "")}
                        title="Карточка контейнера"
                        onClick={(G) => {
                          lt(G) && s(r.id);
                        }}
                      >
                        <td className="nowrap">
                          <button
                            className="btn sm"
                            title="Пропустить на терминал — номер и паспорт подставятся в форму заезда"
                            onClick={() => {
                              var G;
                              (L(r.id),
                                (G = document.querySelector(".main")) == null ||
                                  G.scrollTo({
                                    top: 0,
                                    behavior: "smooth",
                                  }));
                            }}
                          >
                            Заезд ↓
                          </button>
                        </td>
                        <td>
                          <b>{r.container_no}</b>
                        </td>
                        <td>{r.size ? `${r.size}' ${r.height || ""}` : "—"}</td>
                        <td>{r.line || "—"}</td>
                        <td>{r.booking || "—"}</td>
                        <td>{r.release_no || "—"}</td>
                        <td>{r.port_terminal || "—"}</td>
                        <td>{r.port_order || "—"}</td>
                        <td>{r.client || "—"}</td>
                        <td>{r.cargo || "—"}</td>
                        <td className="nowrap">
                          {r.eta_date ? String(r.eta_date).split("-").reverse().join(".") : "—"}
                          {O ? (
                            <span
                              className="faint"
                              style={{
                                color: "var(--warn)",
                              }}
                            >
                              {" "}
                              · просрочена
                            </span>
                          ) : null}
                        </td>
                        <td>
                          <CXt v={r.in_vehicle_no} />
                        </td>
                        <td className="faint">{r.exp_src || "—"}</td>
                        <td className="nowrap">
                          {g ? (
                            <button className="btn danger sm icon" title="Убрать из ожидаемых" onClick={() => ee(r)}>
                              ✕
                            </button>
                          ) : null}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </>
        )}
      </div>
      {b && (
        <CWr
          me={t}
          onClose={() => j(!1)}
          have={new Set([...(o || []), ...(l || [])].map((r) => (r.container_no || "").toUpperCase()))}
          onDone={(r, O) => {
            (j(!1),
              Q({
                ok: `Из файла «${O}» добавлено ${r} контейнеров к приезду`,
              }),
              x());
          }}
        />
      )}
      {ze && (Ke || []).length > 0 && (
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Недавно выпущенные · {(Ke || []).length}</h2>
            <button className="btn sec sm" onClick={He}>
              Обновить
            </button>
          </div>
          <p className="p-sub">если контейнер выпущен по ошибке — верни его на терминал (действие пишется в журнал изменений)</p>
          <div
            className="tscroll"
            style={{
              maxHeight: "24vh",
            }}
          >
            <table>
              <thead>
                <tr>
                  <th>Контейнер</th>
                  <th>Выезд</th>
                  <th>Машина вывоза</th>
                  <th>Пломба на выезде</th>
                  <th>Сверка</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {(Ke || []).map((r) => (
                  <tr
                    className="rowc"
                    title="Карточка контейнера"
                    onClick={(O) => {
                      lt(O) && s(r.id);
                    }}
                  >
                    <td>
                      <b>{r.container_no}</b>
                    </td>
                    <td className="nowrap">{he(r.out_at)}</td>
                    <td>
                      <CXt v={r.out_vehicle_no} />
                    </td>
                    <td>
                      {r.out_seal_no || "—"}
                      {r.seal_no && r.out_seal_no && r.out_seal_no !== r.seal_no ? <span className="faint"> (при затарке {r.seal_no})</span> : null}
                    </td>
                    <td>{r.seal_checked ? <span className="t2chip ok">сошлась</span> : <span className="t2chip">не сверена</span>}</td>
                    <td className="nowrap">
                      <button className="btn sec sm" onClick={() => Ne(r).then(He)}>
                        ↩ вернуть на терминал
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
      {n && <Ht id={n} me={t} onClose={() => s(null)} />}
      <Sl
        kind="container"
        me={t}
        title="Камера номеров контейнеров"
        hint="распознанный номер сверяется по контрольной цифре ISO 6346 · система подбирает контейнер среди находящихся на терминале · заезд и выезд по-прежнему оформляются кнопками, камера только подставляет нужную строку"
        rows={l || []}
        keysOf={(r) => [r.container_no]}
        label={(r) => (
          <>
            <b>{r.container_no}</b> <span className="faint">· {tt(r, p)}</span>
          </>
        )}
        actions={(r, O, G) => (
          <button
            className="btn sm"
            onClick={async () => {
              (s(r.id), await Rs(O, "container", r.id, t), G());
            }}
          >
            Открыть карточку
          </button>
        )}
      />
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">
            Контейнеры на терминале · {(l || []).length} · к выезду {We.length}
            {Qe.length ? ` · в порт ${Qe.length}` : ""}
          </h2>
          <button className="btn sec sm" onClick={i}>
            Обновить
          </button>
        </div>
        <p className="p-sub">
          клик по заголовку столбца — сортировка (↑/↓/сброс) · контейнеры готовых партий помечены «в порт» · «Убыл» фиксирует выезд: гружёный — с
          пломбой и сверкой, порожний или времянка — с подтверждением, что уходит без груза · ✎ — правка
        </p>
        <div
          className="row"
          style={{
            gap: 8,
            marginBottom: 8,
          }}
        >
          <input
            className="srch9"
            placeholder="Поиск: контейнер, линия, букинг, клиент, партия, пломба, штабель…"
            value={F}
            onChange={(r) => C(r.target.value)}
          />
          {F.trim() && !(B || []).length ? <span className="find9no2">ничего не найдено</span> : null}
        </div>
        <Tt
          val={y}
          onSel={$}
          items={kn
            .map(([r, O]) => ({
              k: r,
              t: O,
              n: (l || []).filter((G) => Mt(G, p[G.batch_id]).k === r).length,
            }))
            .filter((r) => r.n)}
        />
        <CFe err={u} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <Ie k="no">Контейнер</Ie>
                <Ie k="tp">Тип</Ie>
                <Ie k="ln">Линия</Ie>
                <Ie k="cli">Клиент</Ie>
                <Ie k="bk">Букинг</Ie>
                <Ie k="si">Площадка</Ie>
                <Ie k="cg">Груз</Ie>
                <Ie k="st">Статус</Ie>
                <Ie k="bt">Партия</Ie>
                <Ie k="stk">Штабель</Ie>
                <Ie k="sl">Пломба</Ie>
                <Ie k="inn">Заезд</Ie>
                <Ie k="veh">
                  Машина вывоза
                  <CUn />
                </Ie>
                <th />
              </tr>
            </thead>
            <tbody>
              {B.map((r) => {
                const O = p[r.batch_id];
                return (
                  <tr
                    className="rowc"
                    title="Карточка контейнера"
                    onClick={(G) => {
                      lt(G) && s(r.id);
                    }}
                  >
                    <td>
                      <b>{r.container_no}</b>
                      {r.off_list ? (
                        <div className="offlist9" title="контейнера не было в реестре порта — свести с портом">
                          вне реестра
                        </div>
                      ) : null}
                    </td>
                    <td>{r.size ? `${r.size}' ${r.height || ""}` : "—"}</td>
                    <td>{r.line || "—"}</td>
                    <td>{r.client || "—"}</td>
                    <td>{r.booking || "—"}</td>
                    <td>{r.site || "—"}</td>
                    <td>{r.cargo || "—"}</td>
                    <td>
                      <Et c={r} b={O} />
                    </td>
                    <td>
                      {O ? (
                        <span className={"t2chip" + (O.status === "ready" ? " ok" : "")} title={vt[O.status]}>
                          {O.batch_no}
                          {O.status === "ready" ? " · в порт" : ""}
                        </span>
                      ) : (
                        "—"
                      )}
                    </td>
                    <td>{r.stack || "—"}</td>
                    <td>{r.seal_no || "—"}</td>
                    <td className="nowrap">{he(r.in_at)}</td>
                    <td>
                      <span
                        className="row"
                        style={{
                          gap: 4,
                        }}
                      >
                        {is(U, Z, r.id, "veh", "номер машины", 120, "trucks9")}
                        {re.includes(r.state) && is(U, Z, r.id, "seal", "пломба с контейнера", 130)}
                      </span>
                    </td>
                    <td className="nowrap">
                      <CGt n={E(r.id)} onClick={() => f(r)} /> <Ye onClick={() => T(r)} />{" "}
                      <button
                        className={"btn sm" + (re.includes(r.state) ? "" : " sec")}
                        title={re.includes(r.state) ? "Выпустить гружёный контейнер" : "Выпустить контейнер без груза (порожний, времянка, ремонт)"}
                        onClick={() => be(r)}
                      >
                        Убыл ↑
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
function CVr({ me: t, picked: n, mixes: s, temps: l, onClose: i, onDone: u }) {
  const [o, x] = S.useState({
      r1: "mix",
      join: "",
    }),
    [N, b] = S.useState(() => Object.fromEntries(n.map((m) => [m.id, {}]))),
    [j, g] = S.useState(!1),
    [d, M] = S.useState(null),
    [z, _] = S.useState(!1),
    h = S.useRef(null),
    w = (s || []).find((m) => String(m.id) === String(o.join)),
    p = [...new Set(n.map((m) => (m.culture || "").trim()).filter(Boolean))],
    F = [];
  (p.length > 1 && F.push(`Разные культуры в замесе: ${p.join(", ")}`),
    w && p[0] && w.culture && w.culture.trim() !== p[0] && F.push(`Культура замеса ${w.mix_no} — «${w.culture}», у выбранных машин — «${p[0]}»`));
  const C = n.filter((m) => {
    const v = N[m.id] || {};
    return te(v.m) == null && te(v.i) == null && te(v.g) == null;
  });
  C.length && F.push(`Без показателей лаборатории: ${C.map((m) => m.vehicle_no).join(", ")}`);
  const y = async () => {
      try {
        if (n.length < 1) throw new Error("Не выбрано ни одной машины — закрой окно и отметь машины в очереди");
        if (n.length < 2 && !w && !(o.ext || "").trim())
          throw new Error(
            "Замес — это минимум две машины. Отметь вторую машину, присоедини к действующему замесу или укажи времянку как второго участника.",
          );
        for (const a of n) {
          const f = N[a.id] || {};
          for (const [P, T] of [
            [te(f.m), "Влажность"],
            [te(f.i), "Сорность"],
            [te(f.b), "Колотые/битые"],
            [te(f.g), "Зерновая примесь"],
          ])
            if (P != null && (P < 0 || P > 100)) throw new Error(`${a.vehicle_no} · ${T}: значение должно быть в пределах 0–100%`);
        }
        if (F.length && !z) throw new Error("Отметь подтверждение внизу — иначе замес не сохранить");
        (g(!0), M(null));
        const m = (l || []).find((a) => String(a.id) === String(o.tmp)),
          v = m ? ki(m, te(o.tkg), new Date().toISOString()) : null;
        if (v != null && v.err) throw new Error(v.err);
        const U = v ? v.take : null,
          Z = m ? "Времянка " + m.container_no : "";
        let I = w || h.current,
          D = !1;
        if (I) {
          const a = {};
          if (((o.param || "").trim() && !I.param && (a.param = (o.param || "").trim()), m))
            if (!I.temp_container_id) ((a.ext_partner = Z), (a.temp_container_id = m.id), (a.temp_kg = U), (D = !0));
            else
              throw String(I.temp_container_id) !== String(m.id)
                ? new Error(`В замесе ${I.mix_no} уже учтена времянка «${I.ext_partner || ""}» — вторую в тот же замес не добавить`)
                : new Error(
                    `Времянка ${m.container_no} уже учтена в замесе ${I.mix_no} (${q(I.temp_kg)} кг) — повторно из неё этот замес не берёт. Убери времянку из формы или собери новый замес.`,
                  );
          Object.keys(a).length && (await ue(A.from("term_mixes").update(a).eq("id", I.id), "замес"));
        } else {
          const a = await Y(A.rpc("term_next_mix_no"));
          ((I = (
            await Y(
              A.from("term_mixes")
                .insert({
                  mix_no: a,
                  culture: p[0] || null,
                  param: (o.param || "").trim() || null,
                  site: o.site || null,
                  ext_partner: Z || null,
                  temp_container_id: m ? m.id : null,
                  temp_kg: m ? U : null,
                  status: "lab_ok",
                  created_by: t.id,
                  lab_at: new Date().toISOString(),
                  lab_by: t.id,
                  notes: (o.note || "").trim() || null,
                })
                .select("*"),
            )
          )[0]),
            (h.current = I),
            (D = !!m));
        }
        const E = async (a) =>
          ((await Y(A.from("term_truck_visits").select("vehicle_no").eq("mix_id", I.id).neq("id", a))) || []).map((P) => P.vehicle_no);
        for (const a of n) {
          const f = N[a.id] || {};
          await ue(
            A.from("term_truck_visits")
              .update({
                lab_status: "passed",
                lab_at: new Date().toISOString(),
                lab_by: t.id,
                lab_result1: o.r1,
                mix_id: I.id,
                mix_group: I.mix_no,
                mix_param: (o.param || "").trim() || I.param || null,
                mix_ext: Z || I.ext_partner || null,
                ...(te(f.m) != null
                  ? {
                      lab_moisture: te(f.m),
                    }
                  : {}),
                ...(te(f.i) != null
                  ? {
                      lab_impurity: te(f.i),
                    }
                  : {}),
                ...(te(f.g) != null
                  ? {
                      lab_broken: te(f.g),
                    }
                  : {}),
                ...((f.rt || "").trim()
                  ? {
                      lab_result_text: f.rt.trim(),
                    }
                  : {}),
              })
              .eq("id", a.id)
              .eq("lab_status", "pending"),
            "машина " + a.vehicle_no + " (её решение уже изменил кто-то другой — обнови страницу)",
          );
        }
        (await Y(
          A.rpc("term_mix_sync", {
            p_mix: I.id,
          }),
        ),
          v &&
            D &&
            (await ue(A.from("term_line_containers").update(v.patch).eq("id", m.id), "времянка " + m.container_no),
            await je(
              "container",
              m.id,
              v.closed ? "temp_close" : "temp_take",
              {
                контейнер: m.container_no,
                замес: I.mix_no,
                взято: v.take,
                остаток: v.left,
              },
              t,
            )),
          await je(
            "mix",
            I.id,
            w ? "join" : "create",
            {
              машины: n.map((a) => a.vehicle_no),
              замес: I.mix_no,
              параметр: o.param || null,
              времянка: m ? `${m.container_no} · ${q(U)} кг` : void 0,
              продавлено: F.length ? F : void 0,
            },
            t,
          ),
          g(!1),
          u(
            `${w ? "Присоединено к замесу" : "Замес собран"} ${I.mix_no}: ${n.map((a) => a.vehicle_no).join(", ")} — все участники одобрены и ушли в перевалку вместе`,
          ));
      } catch (m) {
        (M(String(m.message || m)), g(!1));
      }
    },
    $ = (m, v, U, Z) => (
      <input
        style={{
          width: Z,
          minWidth: Z,
        }}
        placeholder={U}
        value={(N[m.id] || {})[v] ?? ""}
        onChange={(I) =>
          b((D) => ({
            ...D,
            [m.id]: {
              ...(D[m.id] || {}),
              [v]: I.target.value,
            },
          }))
        }
      />
    );
  return (
    <div
      className="modal-bg"
      onMouseDown={(m) => {
        m.target === m.currentTarget && i();
      }}
    >
      <div
        className="modal"
        style={{
          width: 900,
          maxWidth: "96vw",
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Замес из {n.length} машин</h2>
          <button className="btn sec sm" onClick={i}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <p className="p-sub">
            все отмеченные машины получают решение «Одобрен · Замес» одновременно и уходят в перевалку одной группой · дальше замес взвешивается по
            каждой машине и затаривается в конкретные контейнеры
          </p>
          <div className="row">
            <X label="Что делаем">
              <CPe
                value={o.r1}
                onChange={(m) =>
                  x((v) => ({
                    ...v,
                    r1: m,
                  }))
                }
                options={[
                  ["mix", "Замес"],
                  ["clean_mix", "Очистка+Замес"],
                ]}
                w={170}
              />
            </X>
            <X label="Параметр замеса">{Se(o, x, "param", "например 1/2", 150)}</X>
            <X label="Площадка (если известна)">
              <CPe
                value={o.site || ""}
                onChange={(m) =>
                  x((v) => ({
                    ...v,
                    site: m,
                  }))
                }
                options={_t}
                w={150}
                ph="— позже —"
              />
            </X>
            <X label="Присоединить к действующему замесу">
              <CPe
                value={o.join || ""}
                onChange={(m) =>
                  x((v) => ({
                    ...v,
                    join: m,
                  }))
                }
                w={230}
                ph="— новый замес —"
                options={(s || []).map((m) => [m.id, `${m.mix_no} · ${m.culture || "—"} · ${(m.machines || []).join(", ")}`])}
              />
            </X>
            <X label="Времянка в замесе (если есть)">
              <CPe
                value={o.tmp || ""}
                onChange={(m) =>
                  x((v) => {
                    var U;
                    return {
                      ...v,
                      tmp: m,
                      tkg: m ? String(((U = (l || []).find((Z) => String(Z.id) === String(m))) == null ? void 0 : U.temp_kg) ?? "") : "",
                    };
                  })
                }
                w={230}
                ph="— нет —"
                options={(l || []).map((m) => [
                  m.id,
                  m.container_no +
                    (m.cargo ? " · " + m.cargo : "") +
                    (m.temp_kg != null ? " · остаток " + q(m.temp_kg) + " кг" : " · остаток не известен"),
                ])}
              />
            </X>
            {o.tmp && <X label="Сколько берём из времянки, кг">{Se(o, x, "tkg", "весь остаток", 150)}</X>}
          </div>
          <div
            className="tscroll"
            style={{
              maxHeight: "34vh",
              marginTop: 6,
            }}
          >
            <table>
              <thead>
                <tr>
                  <th>Машина</th>
                  <th>Культура · Поставщик</th>
                  <th className="right">Вес план, кг</th>
                  <th>Влаж. %</th>
                  <th>Сор %</th>
                  <th>Кол/бит %</th>
                  <th>Показатели (текст)</th>
                </tr>
              </thead>
              <tbody>
                {n.map((m) => (
                  <tr>
                    <td>
                      <b>{m.vehicle_no}</b>
                    </td>
                    <td>
                      {m.culture || "—"}
                      <div
                        className="faint"
                        style={{
                          fontSize: 10,
                        }}
                      >
                        {m.supplier || ""}
                      </div>
                    </td>
                    <td className="right">{m.planned_tonnes != null ? q(qe(m.planned_tonnes)) : "—"}</td>
                    <td>{$(m, "m", "%", 60)}</td>
                    <td>{$(m, "i", "%", 60)}</td>
                    <td>{$(m, "g", "%", 60)}</td>
                    <td>{$(m, "rt", "результат показателей", 170)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <CYn warns={F} on={z} setOn={_} />
          {d && <p className="err">{d}</p>}
          <div className="m-foot">
            <button className="btn" disabled={j || (F.length > 0 && !z)} onClick={y}>
              {j ? "Сохраняю…" : w ? "Присоединить к замесу" : `Собрать замес из ${n.length} машин`}
            </button>
            <button className="btn sec" onClick={i}>
              Отмена
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}
function Nr({ me: t }) {
  const [n, s, l] = ne(() => Y(A.from("term_settings").select("*").order("key")), [], 0),
    [i, u] = S.useState({}),
    [o, x] = S.useState(null),
    [N, b] = ne(() => Y(A.from("term_culture_norms").select("*").order("culture")), [], 0),
    [j, g] = S.useState({}),
    d = S.useMemo(() => {
      const C = {
        ...Rt,
      };
      for (const y of n || []) y.value != null && (C[y.key] = y.value);
      return C;
    }, [n]),
    M = (C) => i[C] ?? d[C] ?? "",
    z = async (C) => {
      try {
        const y = Object.keys(i)
          .filter(($) => String(i[$]) !== String(d[$]))
          .filter(($) => !C || C.includes($));
        if (!y.length) {
          x({
            ok: C ? "В этом разделе изменений нет" : "Изменений нет",
          });
          return;
        }
        for (const $ of y)
          (n || []).find((v) => v.key === $)
            ? await ue(
                A.from("term_settings")
                  .update({
                    value: String(i[$]),
                    updated_at: new Date().toISOString(),
                    updated_by: t.id,
                  })
                  .eq("key", $),
                "настройка " + $,
              )
            : await ue(
                A.from("term_settings").insert({
                  key: $,
                  value: String(i[$]),
                  updated_by: t.id,
                }),
                "настройка " + $,
              );
        (await je(
          "settings",
          null,
          "update",
          Object.fromEntries(
            y.map(($) => [
              $,
              {
                было: d[$],
                стало: i[$],
              },
            ]),
          ),
          t,
        ),
          u(($) => {
            const m = {
              ...$,
            };
            for (const v of y) delete m[v];
            return m;
          }),
          x({
            ok: `Сохранено настроек: ${y.length} — применится у всех после обновления страницы`,
          }),
          s());
      } catch (y) {
        x({
          err: String(y.message || y),
        });
      }
    },
    _ = async (C) => {
      const y = j[C.culture] || {};
      try {
        const $ = String(y.h ?? C.hs_code ?? "").trim();
        if ($ && !an($)) throw new Error("Код ТН ВЭД — 10 цифр, например 1001 99 000 0");
        (await ue(
          A.from("term_culture_norms")
            .update({
              moisture_max: te(y.m ?? C.moisture_max),
              impurity_max: te(y.i ?? C.impurity_max),
              broken_max: te(y.b ?? C.broken_max),
              grain_adm_max: te(y.g ?? C.grain_adm_max),
              hs_code: $ ? Ln($) : null,
            })
            .eq("culture", C.culture),
          "норма " + C.culture,
        ),
          await ts(),
          g((m) => ({
            ...m,
            [C.culture]: {},
          })),
          x({
            ok: `«${C.culture}»: сохранено`,
          }),
          b());
      } catch ($) {
        x({
          err: String($.message || $),
        });
      }
    },
    h = async () => {
      const C = (window.prompt("Культура (как её пишут в поручении):", "") || "").trim();
      if (!C) return;
      const y = (window.prompt(`Код ТН ВЭД для «${C}» (10 цифр, можно пропустить):`, "") || "").trim();
      if (y && !an(y)) {
        x({
          err: "Код ТН ВЭД — 10 цифр, например 1001 99 000 0",
        });
        return;
      }
      try {
        (await ue(
          A.from("term_culture_norms").insert({
            culture: C,
            hs_code: y ? Ln(y) : null,
          }),
          "культура " + C,
        ),
          await je(
            "settings",
            null,
            "culture_add",
            {
              культура: C,
              "ТН ВЭД": y || "—",
            },
            t,
          ),
          await ts(),
          x({
            ok: `«${C}» добавлена`,
          }),
          b());
      } catch ($) {
        x({
          err: /duplicate|uniq/i.test(String($.message)) ? `«${C}» уже есть в списке` : String($.message || $),
        });
      }
    },
    w = async (C) => {
      if (window.confirm(`Убрать «${C.culture}» из справочника? В старых поручениях и заявках культура останется как есть.`))
        try {
          (await ue(A.from("term_culture_norms").delete().eq("culture", C.culture), "культура " + C.culture),
            await je(
              "settings",
              null,
              "culture_del",
              {
                культура: C.culture,
              },
              t,
            ),
            await ts(),
            b());
        } catch (y) {
          x({
            err: String(y.message || y),
          });
        }
    },
    p = (() => {
      const C = d.scale_calib_until;
      return C ? Math.round((new Date(C) - new Date()) / 864e5) : null;
    })(),
    F = [
      ["Документы отгрузки", ["vgm_method", "vgm_declarant", "weigh_place", "scale_details", "scale_calib_date", "scale_calib_until"]],
      [
        "Пороги весов и отклонений",
        [
          "truck_gross_min",
          "truck_gross_max",
          "truck_tare_min",
          "truck_tare_max",
          "cont_tare_min",
          "cont_tare_max",
          "dotare_warn",
          "dotare_max",
          "plan_dev_pct",
        ],
      ],
      ["Просрочка: когда считать, что процесс встал", ["stuck_lab_h", "stuck_unload_h", "stuck_tare_h", "stuck_cont_d", "call_limit"]],
      ["Этапы процесса", ["ts_step"]],
      ["Лента оповещений", ["feed_audit_all"]],
      ["Дайджест и безопасность", ["digest_on", "autologout_min"]],
    ];
  return (
    <>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Настройки терминала</h2>
          <button className="btn sm" onClick={() => z()}>
            Сохранить всё
          </button>
        </div>
        <p className="p-sub">
          то, что раньше было зашито в код: реквизиты в документах, метод взвешивания VGM, дата поверки весов, пороги для проверки ввода и для
          «просрочено» в ленте · меняет только управляющий · новые значения подхватываются у всех без перезагрузки страницы
        </p>
        {p != null && p < 60 && (
          <div
            className={p < 0 ? "err" : "ovr9"}
            style={{
              marginBottom: 10,
            }}
          >
            {p < 0
              ? `⚠ Поверка весов истекла ${Math.abs(p)} дн. назад — документы выпускаются с неактуальной датой поверки`
              : `⚠ До окончания поверки весов ${p} дн. — не забудьте обновить дату в документах`}
          </div>
        )}
        <CFe err={l} />
        <CFe {...(o || {})} />
        {F.map(([C, y], $) => (
          <div className={"setsec" + ($ === 0 ? " first" : "")}>
            <h3 className="setsec-t">{C}</h3>
            <div className="setgrid">
              {y.map((m) => (
                <X label={di[m] || m}>
                  {m === "vgm_method" ? (
                    <CPe
                      value={M(m)}
                      onChange={(v) =>
                        u((U) => ({
                          ...U,
                          [m]: v,
                        }))
                      }
                      options={[
                        ["METHOD-1", "METHOD-1 — взвешивание гружёного контейнера"],
                        ["METHOD-2", "METHOD-2 — расчётный: груз + тара контейнера"],
                      ]}
                      w={330}
                    />
                  ) : m === "ts_step" ? (
                    <CPe
                      value={String(M(m)).toLowerCase() === "нет" ? "нет" : "да"}
                      onChange={(v) =>
                        u((U) => ({
                          ...U,
                          [m]: v,
                        }))
                      }
                      options={[
                        ["да", "да — машина ждёт отметки перевалки"],
                        ["нет", "нет — перевалка временно вне процесса"],
                      ]}
                      w={300}
                    />
                  ) : (
                    <input
                      style={{
                        width: "100%",
                      }}
                      value={M(m)}
                      onChange={(v) =>
                        u((U) => ({
                          ...U,
                          [m]: v.target.value,
                        }))
                      }
                    />
                  )}
                </X>
              ))}
            </div>
            {(() => {
              const m = y.filter((v) => i[v] != null && String(i[v]) !== String(d[v])).length;
              return (
                <div className="setsec-f">
                  <button className={"btn sm" + (m ? "" : " sec")} onClick={() => z(y)}>
                    Сохранить раздел{m ? ` · ${m}` : ""}
                  </button>
                  {m ? (
                    <span
                      className="faint"
                      style={{
                        fontSize: 11,
                      }}
                    >
                      изменено полей: {m}
                    </span>
                  ) : (
                    <span
                      className="faint"
                      style={{
                        fontSize: 11,
                      }}
                    >
                      изменений в разделе нет
                    </span>
                  )}
                </div>
              );
            })()}
          </div>
        ))}
      </div>
      <Er me={t} />
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Культуры: коды ТН ВЭД и нормы качества · {(N || []).length}</h2>
          <button className="btn sec sm" onClick={h}>
            + Культура
          </button>
        </div>
        <p className="p-sub">
          код ТН ВЭД подставляется в поручение сам, как только менеджер выбрал груз · лаборатория увидит предупреждение, если показатель выше нормы ·
          пустое значение — не проверяем
        </p>
        {(() => {
          const C = (N || []).filter((y) => !String(y.hs_code || "").trim());
          return C.length ? (
            <div
              className="ovr9"
              style={{
                marginBottom: 10,
              }}
            >
              Без кода ТН ВЭД: <b>{C.map((y) => y.culture).join(", ")}</b> — по таким культурам код в поручении придётся вбивать руками
            </div>
          ) : null;
        })()}
        {(() => {
          const C = (N || []).filter((m) => m.moisture_max == null && m.impurity_max == null && m.broken_max == null && m.grain_adm_max == null),
            y = (N || []).filter((m) => m.moisture_max == null && !C.includes(m)),
            $ = [];
          return (
            C.length &&
              $.push(
                <div
                  className="ovr9"
                  style={{
                    marginBottom: 10,
                  }}
                >
                  Без норм качества: <b>{C.map((m) => m.culture).join(", ")}</b> — по таким культурам лаборатория не получит ни одного предупреждения
                </div>,
              ),
            y.length &&
              $.push(
                <div
                  className="ovr9"
                  style={{
                    marginBottom: 10,
                  }}
                >
                  Без нормы влажности: <b>{y.map((m) => m.culture).join(", ")}</b> — влажность у них не проверяется
                </div>,
              ),
            $.length ? $ : null
          );
        })()}
        <CFe {...(o || {})} />
        <div
          className="tscroll"
          style={{
            maxHeight: "46vh",
          }}
        >
          <table>
            <thead>
              <tr>
                <th>Культура</th>
                <th>Код ТН ВЭД</th>
                <th className="right">Влажность, макс %</th>
                <th className="right">Сорность, макс %</th>
                <th className="right">Кол/бит, макс %</th>
                <th className="right">Зерновая примесь, макс %</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {(N || []).map((C) => (
                <tr>
                  <td>
                    <b>{C.culture}</b>
                  </td>
                  <td>
                    <input
                      className="g-in"
                      style={{
                        width: 130,
                      }}
                      placeholder="1001 99 000 0"
                      value={(j[C.culture] || {}).h ?? C.hs_code ?? ""}
                      onChange={(y) =>
                        g(($) => ({
                          ...$,
                          [C.culture]: {
                            ...($[C.culture] || {}),
                            h: y.target.value,
                          },
                        }))
                      }
                    />
                  </td>
                  <td className="right">
                    <input
                      className="g-in"
                      style={{
                        width: 80,
                      }}
                      value={(j[C.culture] || {}).m ?? C.moisture_max ?? ""}
                      onChange={(y) =>
                        g(($) => ({
                          ...$,
                          [C.culture]: {
                            ...($[C.culture] || {}),
                            m: y.target.value,
                          },
                        }))
                      }
                    />
                  </td>
                  <td className="right">
                    <input
                      className="g-in"
                      style={{
                        width: 80,
                      }}
                      value={(j[C.culture] || {}).i ?? C.impurity_max ?? ""}
                      onChange={(y) =>
                        g(($) => ({
                          ...$,
                          [C.culture]: {
                            ...($[C.culture] || {}),
                            i: y.target.value,
                          },
                        }))
                      }
                    />
                  </td>
                  <td className="right">
                    <input
                      className="g-in"
                      style={{
                        width: 80,
                      }}
                      value={(j[C.culture] || {}).b ?? C.broken_max ?? ""}
                      onChange={(y) =>
                        g(($) => ({
                          ...$,
                          [C.culture]: {
                            ...($[C.culture] || {}),
                            b: y.target.value,
                          },
                        }))
                      }
                    />
                  </td>
                  <td className="right">
                    <input
                      className="g-in"
                      style={{
                        width: 80,
                      }}
                      value={(j[C.culture] || {}).g ?? C.grain_adm_max ?? ""}
                      onChange={(y) =>
                        g(($) => ({
                          ...$,
                          [C.culture]: {
                            ...($[C.culture] || {}),
                            g: y.target.value,
                          },
                        }))
                      }
                    />
                  </td>
                  <td className="nowrap">
                    <button className="btn sec sm" onClick={() => _(C)}>
                      Сохранить
                    </button>{" "}
                    <button className="btn danger sm icon" title="Убрать культуру из справочника" onClick={() => w(C)}>
                      ✕
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <CYr me={t} />
      <Sr />
    </>
  );
}
function CYr({ me: t }) {
  const [n, s, l] = ne(() => Y(A.from("term_dict").select("*").order("kind").order("name")), [], 0),
    [i, u] = S.useState(null),
    o = async (j) => {
      const g =
        j === "line" ? "Название линии:" : j === "surveyor" ? "Сюрвейер (организация / фамилия):" : "Госномер машины терминала (например К367ОР):";
      let d = (window.prompt(g, "") || "").trim();
      if (!d) return;
      let M = null;
      if (j === "truck") {
        if (((d = De(d)), !xs(d))) {
          u({
            err: `«${d}» не похоже на госномер: буква, три цифры, две буквы и регион — например К367ОР82`,
          });
          return;
        }
        M = (window.prompt(`Марка машины ${d} (например МАЗ или Скания):`, "") || "").trim() || null;
      }
      try {
        (await ue(
          A.from("term_dict").insert({
            kind: j,
            name: d,
            note: M,
            created_by: t.id,
          }),
          "справочник",
        ),
          u({
            ok: `«${d}» добавлено`,
          }),
          s());
      } catch (z) {
        u({
          err: /duplicate|uniq/i.test(String(z.message)) ? `«${d}» уже есть в справочнике` : String(z.message || z),
        });
      }
    },
    x = async (j) => {
      const g = (window.prompt("Новое написание:", j.name) || "").trim();
      if (!(!g || g === j.name))
        try {
          (await ue(
            A.from("term_dict")
              .update({
                name: g,
              })
              .eq("id", j.id),
            "справочник",
          ),
            await je(
              "dict",
              j.id,
              "edit",
              {
                было: j.name,
                стало: g,
              },
              t,
            ),
            u({
              ok: `«${j.name}» → «${g}» — старые записи не меняются, новые пойдут с новым написанием`,
            }),
            s());
        } catch (d) {
          u({
            err: String(d.message || d),
          });
        }
    },
    N = async (j) => {
      if (window.confirm(`Убрать «${j.name}» из справочника? В старых записях значение останется.`))
        try {
          (await ue(A.from("term_dict").delete().eq("id", j.id), "справочник"), s());
        } catch (g) {
          u({
            err: String(g.message || g),
          });
        }
    },
    b = (j) => (n || []).filter((g) => g.kind === j);
  return (
    <div className="panel">
      <div className="hd">
        <h2 className="p-title mt0">Справочники · линии, сюрвейеры и машины терминала</h2>
      </div>
      <p className="p-sub">
        КПП выбирает линию, приёмка — сюрвейера из этих списков: «BSF», «БСФ» и «Bsf» больше не станут тремя разными линиями · добавить можно и на
        месте, кнопкой «+» у поля · машины терминала подсвечиваются в списках и предлагаются первыми при затарке и вывозе контейнеров
      </p>
      <CFe err={l} />
      <CFe {...(i || {})} />
      <div
        className="row"
        style={{
          gap: 24,
          alignItems: "flex-start",
          flexWrap: "wrap",
        }}
      >
        {[
          ["line", "Линии"],
          ["surveyor", "Сюрвейеры"],
          ["truck", "Машины терминала"],
        ].map(([j, g]) => (
          <div
            style={{
              minWidth: 240,
            }}
          >
            <div className="sub-t">
              {g} · {b(j).length}{" "}
              <button
                className="btn sec sm"
                style={{
                  marginLeft: 8,
                }}
                onClick={() => o(j)}
              >
                + Добавить
              </button>
            </div>
            {b(j).map((d) => (
              <div
                className="row"
                style={{
                  gap: 6,
                  padding: "3px 0",
                  alignItems: "center",
                }}
              >
                <span
                  style={{
                    flex: 1,
                  }}
                >
                  {d.name}
                  {d.note ? (
                    <span
                      className="faint"
                      style={{
                        fontSize: 11,
                      }}
                    >
                      {" "}
                      · {d.note}
                    </span>
                  ) : null}
                </span>
                <Ye onClick={() => x(d)} />
                <Jt onClick={() => N(d)} />
              </div>
            ))}
            {!b(j).length && (
              <p
                className="p-sub"
                style={{
                  margin: 0,
                }}
              >
                пока пусто
              </p>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}
const Jn = [
  ["term_counterparties", "Контрагенты"],
  ["term_contracts", "Договоры"],
  ["term_orders", "Поручения"],
  ["term_requests", "Заявки"],
  ["term_truck_visits", "Зерновозы"],
  ["term_line_containers", "Контейнеры"],
  ["term_container_loads", "Затарки"],
  ["term_mixes", "Замесы"],
  ["term_batches", "Партии"],
  ["term_dict", "Справочники"],
  ["term_culture_norms", "Нормы"],
  ["term_settings", "Настройки"],
  ["term_docs", "Документы"],
  ["term_files", "Вложения (перечень)"],
  ["term_audit", "Журнал изменений"],
];
function Sr() {
  const [t, n] = S.useState(!1),
    [s, l] = S.useState(null),
    i = async () => {
      (n(!0),
        l({
          ok: "Собираю архив…",
        }));
      try {
        const u = [];
        let o = 0;
        for (const [x, N] of Jn) {
          const b = [];
          for (let g = 0; g < 4e4; g += 1e3) {
            const d = await Y(
              A.from(x)
                .select("*")
                .range(g, g + 999),
            );
            if ((b.push(...(d || [])), !d || d.length < 1e3)) break;
          }
          o += b.length;
          const j = b.length ? Object.keys(b[0]) : ["—"];
          u.push({
            name: N.slice(0, 28),
            title: `ФЕНИКС · Терминал — ${N} · ${Ns()}`,
            cols: j.map((g) => ({
              h: g,
              w: Math.min(30, Math.max(10, g.length + 2)),
            })),
            rows: b.map((g) =>
              j.map((d) => {
                const M = g[d];
                return M != null && typeof M == "object" ? JSON.stringify(M) : M;
              }),
            ),
          });
        }
        (Ze(`Архив_базы_${Ve()}`, u),
          l({
            ok: `Архив собран: ${Jn.length} таблиц, ${o} строк — файл скачан. Храни копию вне терминала.`,
          }));
      } catch (u) {
        l({
          err: String(u.message || u),
        });
      }
      n(!1);
    };
  return (
    <div className="panel">
      <h2 className="p-title mt0">Резервная копия</h2>
      <p className="p-sub">
        вся база одной книгой Excel на этот компьютер — раз в неделю нажать и убрать копию на флешку или диск · автокопии Supabase хранятся по тарифу;
        восстановление на момент времени включается в панели Supabase
      </p>
      <div
        className="row"
        style={{
          marginBottom: 4,
        }}
      >
        <button className="btn sm" disabled={t} onClick={i}>
          {t ? "Собираю…" : "⇩ Архив базы (Excel)"}
        </button>
      </div>
      <CFe {...(s || {})} />
    </div>
  );
}
function C$r({ V: t, C: n, R: s, L: l }) {
  const i = Js(),
    [u] = ne(
      () =>
        Y(
          A.from("term_audit")
            .select("id, entity, entity_id, action, details, by_name, at")
            .in("action", ["gross_override", "tare_override", "lab_override", "exit_override", "volume_override", "dispatch", "iso_override"])
            .gte("at", new Date(Date.now() - 7 * 864e5).toISOString())
            .order("id", {
              ascending: !1,
            })
            .limit(60),
        ),
      [],
      6e4,
    ),
    o = (u || []).filter((_) => _.details && (_.details.продавлено || _.action !== "dispatch")),
    x = t.filter((_) => {
      const h = qe(_.planned_tonnes);
      return _.net_kg != null && h && (Math.abs(+_.net_kg - h) / h) * 100 > Oe(i, "plan_dev_pct");
    }),
    N = $t() ? t.filter((_) => _.lab_status === "passed" && _.gross_kg != null && _.tare_kg == null && !_.ts_at && !_.out_at) : [],
    b = t.filter((_) => _.lab_status === "pending" && !_.out_at && Lt(_.in_at, null) >= 1),
    j = n.filter((_) => _.state === "loaded" && !_.seal_no),
    g = n.filter((_) => !_.out_at && Lt(_.in_at, null) >= 180),
    d = (l || []).filter((_) => _.gross_kg == null),
    M = n.filter((_) => _.added_by_scale && !_.out_at),
    z = [
      ["Машины ждут лабораторию больше суток", b.length, b.slice(0, 5).map((_) => _.vehicle_no)],
      ["Выгружены, но перевалка не отметила услугу — тару не снять", N.length, N.slice(0, 5).map((_) => _.vehicle_no)],
      ["Расхождение факта с планом заявки", x.length, x.slice(0, 5).map((_) => `${_.vehicle_no} ${q(_.net_kg)}/${q(qe(_.planned_tonnes))}`)],
      ["Гружёные контейнеры без пломбы", j.length, j.slice(0, 5).map((_) => _.container_no)],
      [
        "Незакрытые затарки (тара есть, брутто нет)",
        d.length,
        d.slice(0, 5).map((_) => {
          var h;
          return ((h = _.term_line_containers) == null ? void 0 : h.container_no) || "№" + _.id;
        }),
      ],
      ["Контейнеры на терминале дольше полугода", g.length, []],
      ["Карточки завела весовая — заезд и осмотр не оформлены", M.length, M.slice(0, 5).map((_) => _.container_no)],
      ["Проверки, продавленные за неделю", o.length, o.slice(0, 5).map((_) => `${_.by_name || "—"}: ${On[_.action] || _.action}`)],
    ].filter((_) => _[1] > 0);
  return z.length ? (
    <div className="panel att9">
      <div className="hd">
        <h2 className="p-title mt0">Требует внимания · {z.length}</h2>
      </div>
      <p className="p-sub">то, где процесс встал или данные разошлись — без этого блока такие места видно только при разборе</p>
      <div className="attgrid">
        {z.map(([_, h, w]) => (
          <div className="attcard">
            <div className="att-n">{h}</div>
            <div className="att-t">{_}</div>
            {w.length ? (
              <div className="att-e">
                {w.join(" · ")}
                {h > w.length ? ` и ещё ${h - w.length}` : ""}
              </div>
            ) : null}
          </div>
        ))}
      </div>
    </div>
  ) : null;
}
const Us = {
    akt: "Акт затарки",
    vgm: "VGM-сертификат",
  },
  El = (t) => {
    const n = new Date();
    return (n.setDate(n.getDate() - t), n.toISOString());
  },
  Cr = [
    ["7", "неделя"],
    ["30", "месяц"],
    ["90", "квартал"],
    ["365", "год"],
    ["0", "всё время"],
  ];
function CQl({ val: t, onChange: n }) {
  return (
    <div
      className="tabs"
      style={{
        margin: 0,
      }}
    >
      {Cr.map(([s, l]) => (
        <button className={"tab" + (t === s ? " on" : "")} onClick={() => n(s)}>
          {l}
        </button>
      ))}
    </div>
  );
}
function Mr({ me: t }) {
  var _;
  const [n, s] = S.useState(null),
    [l, i] = S.useState(""),
    [u, o] = S.useState(""),
    [x, N] = Te("docs.per", "30"),
    [b, j, g] = ne(
      () => {
        let h = A.from("term_docs")
          .select("*")
          .order("id", {
            ascending: !1,
          })
          .limit(2e3);
        return (l && (h = h.eq("kind", l)), x !== "0" && (h = h.gte("created_at", El(+x))), Y(h));
      },
      [l, x],
      3e4,
    ),
    d = (b || []).filter(
      (h) =>
        !u.trim() ||
        [h.doc_no, h.booking, h.client, h.cargo, h.by_name].some((w) =>
          String(w || "")
            .toLowerCase()
            .includes(u.trim().toLowerCase()),
        ),
    ),
    [M, z] = S.useState(null);
  return (
    <div className="panel">
      <div className="hd">
        <h2 className="p-title mt0">Журнал документов · {d.length}</h2>
        <button className="btn sec sm" onClick={j}>
          Обновить
        </button>
      </div>
      <p className="p-sub">
        все выпущенные акты затарки и VGM-сертификаты: номер, состав, кто и когда выпустил · повторная печать того же документа отмечается как «копия»
        · номер нельзя переиспользовать под другой состав
      </p>
      <div
        className="row"
        style={{
          gap: 8,
          marginBottom: 8,
          flexWrap: "wrap",
        }}
      >
        <CQl val={x} onChange={N} />
        <div
          className="tabs"
          style={{
            margin: 0,
          }}
        >
          {[
            ["", "Все"],
            ["akt", "Акты затарки"],
            ["vgm", "VGM"],
          ].map(([h, w]) => (
            <button className={"tab" + (l === h ? " on" : "")} onClick={() => i(h)}>
              {w}
            </button>
          ))}
        </div>
        <input className="srch9" placeholder="Поиск: номер, букинг, клиент, груз, кто выпустил…" value={u} onChange={(h) => o(h.target.value)} />
        {u.trim() && !(d || []).length ? <span className="find9no2">ничего не найдено</span> : null}
      </div>
      <CFe err={g} />
      {n && <CDr no={n} me={t} onClose={() => s(null)} />}
      {M && !n && (
        <div
          className="modal-bg"
          onMouseDown={(h) => {
            h.target === h.currentTarget && z(null);
          }}
        >
          <div
            className="modal"
            style={{
              width: 620,
              maxWidth: "96vw",
            }}
          >
            <div className="hd">
              <h2 className="p-title mt0">
                {Us[M.kind] || M.kind} №{M.doc_no}
              </h2>
              <button className="btn sec sm" onClick={() => z(null)}>
                ✕
              </button>
            </div>
            <div className="m-body">
              <div className="dgrid">
                <R l="Выпущен" v={he(M.created_at)} />
                <R l="Кто выпустил" v={M.by_name} />
                <R l="Дата документа" v={M.doc_date} />
                <R l="Букинг" v={M.booking} />
                <R l="Клиент" v={M.client} />
                <R l="Груз" v={M.cargo} />
                <R l="Контейнеров" v={M.rows_n} />
                <R l="Нетто всего, кг" v={q(M.total_net_kg)} />
              </div>
              <p
                className="p-sub"
                style={{
                  margin: "10px 0 4px",
                }}
              >
                состав документа · клик по контейнеру — его карточка
              </p>
              <div
                className="tscroll"
                style={{
                  maxHeight: "46vh",
                  marginTop: 0,
                }}
              >
                <table>
                  <thead>
                    <tr>
                      <th>№</th>
                      <th>Контейнер</th>
                      <th className="right">Нетто, кг</th>
                      <th className="right">VGM, кг</th>
                      <th>Пломба</th>
                    </tr>
                  </thead>
                  <tbody>
                    {(((_ = M.payload) == null ? void 0 : _.containers) || []).map((h, w) => (
                      <tr className="rowx" title="Карточка контейнера" onClick={() => s(h.cont)}>
                        <td>{w + 1}</td>
                        <td>
                          <b>{h.cont}</b>
                        </td>
                        <td className="right">{q(h.net)}</td>
                        <td className="right">{q(h.vgm)}</td>
                        <td>{h.seal || "—"}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      )}
      <div
        className="tscroll"
        style={{
          maxHeight: "68vh",
        }}
      >
        <table>
          <thead>
            <tr>
              <th>Выпущен</th>
              <th>Тип</th>
              <th>Номер</th>
              <th>Букинг</th>
              <th>Клиент · груз</th>
              <th className="right">Конт.</th>
              <th className="right">Нетто, кг</th>
              <th>Кто</th>
            </tr>
          </thead>
          <tbody>
            {d.map((h) => (
              <tr className="rowx" onClick={() => z(h)}>
                <td className="nowrap">{he(h.created_at)}</td>
                <td>{Us[h.kind] || h.kind}</td>
                <td>
                  <b>{h.doc_no}</b>
                </td>
                <td>{h.booking || "—"}</td>
                <td>{[h.client, h.cargo].filter(Boolean).join(" · ") || "—"}</td>
                <td className="right">{h.rows_n}</td>
                <td className="right">{q(h.total_net_kg)}</td>
                <td>{h.by_name || "—"}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      {!d.length && (
        <p
          className="p-sub"
          style={{
            margin: 0,
          }}
        >
          документов пока нет
        </p>
      )}
    </div>
  );
}
function Er({ me: t }) {
  const n = ys(),
    [s, l] = S.useState(null),
    [i, u] = S.useState("180"),
    [o, x] = S.useState(null),
    [N, b] = S.useState(!1),
    [j, g] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("id, container_no, state, in_at, cargo, batch_id, out_at, empty_out, temp_kg, eta_date")
            .is("out_at", null)
            .order("in_at")
            .limit(1e3),
        ),
      [],
      0,
    ),
    d = Math.max(1, +i || 180),
    M = (j || []).filter((h) => Lt(h.in_at, null) >= d),
    z = M.reduce((h, w) => {
      const p = tt(w, n);
      return ((h[p] = (h[p] || 0) + 1), h);
    }, {}),
    _ = async () => {
      if (!M.length) return;
      const h = window.prompt(
        `Какой датой закрыть ${M.length} контейнеров?

Введи дату в формате ГГГГ-ММ-ДД или оставь пусто — тогда каждый закроется последней известной по нему датой (заезд + ${d} дн.).`,
        "",
      );
      if (h == null) return;
      const w = (h || "").trim();
      if (w && !/^\d{4}-\d{2}-\d{2}$/.test(w)) {
        x({
          err: "Дата в формате ГГГГ-ММ-ДД",
        });
        return;
      }
      if (w && w > Hs()) {
        x({
          err: "Дата закрытия в будущем",
        });
        return;
      }
      if (
        window.confirm(`Пометить как убывшие ${M.length} контейнеров, которые числятся на терминале дольше ${d} дней?

${w ? "Дата выезда: " + w.split("-").reverse().join(".") : "Дата выезда у каждого — своя, расчётная"}. Записи будут помечены как закрытые задним числом, действие уйдёт в журнал изменений.`)
      ) {
        b(!0);
        try {
          let p = 0;
          for (const F of M) {
            const C = new Date(new Date(F.in_at).getTime() + d * 864e5),
              y = w ? new Date(w + "T12:00:00").toISOString() : (C > new Date() ? new Date() : C).toISOString();
            (await ue(
              A.from("term_line_containers")
                .update({
                  out_at: y,
                  out_by: t.id,
                  state: "dispatched",
                  empty_out: !0,
                  out_source: "backdated",
                  notes: `закрыт как зависший (выезд не отмечался), дата ${w ? "указана вручную" : "расчётная"} при разборе ${Hs()}`,
                })
                .eq("id", F.id),
              "контейнер " + F.container_no,
            ),
              p++);
          }
          (await je(
            "container",
            null,
            "stale_close",
            {
              закрыто: p,
              старше_дней: d,
              дата_выезда: w || "расчётная",
              по_статусам: z,
            },
            t,
          ),
            x({
              ok: `Закрыто ${p} зависших контейнеров — их номера освободились. Записи помечены как закрытые задним числом: в отчётах по хранению их видно отдельно.`,
            }),
            g());
        } catch (p) {
          x({
            err: String(p.message || p),
          });
        }
        b(!1);
      }
    };
  return (
    <div className="panel">
      {s && <Ht id={s} me={t} onClose={() => l(null)} />}
      <div className="hd">
        <h2 className="p-title mt0">Зависшие контейнеры · {M.length}</h2>
        <button className="btn sec sm" onClick={g}>
          Обновить
        </button>
      </div>
      <p className="p-sub">
        контейнеры с заездом, по которым никогда не отмечали выезд · они занимают свой номер (повторный заезд не оформить) и попадают в счётчик «на
        терминале» · всего числится на терминале: {(j || []).length}
      </p>
      <div
        className="row"
        style={{
          gap: 8,
          alignItems: "flex-end",
        }}
      >
        <X label="Считать зависшими, если на терминале дольше (дней)">
          <input
            style={{
              width: 120,
            }}
            value={i}
            onChange={(h) => u(h.target.value)}
          />
        </X>
        <button className="btn danger" disabled={N || !M.length} onClick={_}>
          {N ? "Закрываю…" : `Пометить убывшими · ${M.length}`}
        </button>
        <span
          className="p-sub"
          style={{
            margin: 0,
          }}
        >
          {Object.entries(z)
            .map(([h, w]) => `${h}: ${w}`)
            .join(" · ") || "—"}
        </span>
      </div>
      <CFe {...(o || {})} />
      {M.length > 0 && (
        <div
          className="tscroll"
          style={{
            maxHeight: "26vh",
            marginTop: 8,
          }}
        >
          <table>
            <thead>
              <tr>
                <th>Контейнер</th>
                <th>Статус</th>
                <th>Груз</th>
                <th>Заезд</th>
                <th className="right">Дней на терминале</th>
              </tr>
            </thead>
            <tbody>
              {M.slice(0, 100).map((h) => (
                <tr className="rowx" title="Карточка контейнера" onClick={() => l(h.id)}>
                  <td>
                    <b>{h.container_no}</b>
                  </td>
                  <td>
                    <Et c={h} bm={n} />
                  </td>
                  <td>{h.cargo || "—"}</td>
                  <td className="nowrap">{he(h.in_at)}</td>
                  <td className="right">{Lt(h.in_at, null)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
      {M.length > 100 && (
        <p
          className="p-sub"
          style={{
            margin: "6px 0 0",
          }}
        >
          показаны первые 100 из {M.length}
        </p>
      )}
    </div>
  );
}
const On = {
  create: "создан",
  join: "присоединение",
  lab_override: "приём с отклонением",
  gross_override: "брутто с отклонением",
  cancel_arrival: "отмена заезда",
  close: "закрытие",
  disband: "роспуск замеса",
  lab_extra: "доп. услуга лаборатории",
  leave: "выход из замеса",
  edit: "правка данных",
  tare_override: "тара с отклонением",
  exit_override: "выпуск с замечаниями",
  ts_done: "услуга оказана",
  ts_undo: "отмена услуги",
  gross_undo: "снято брутто",
  tare_undo: "снята тара",
  dispatch: "выпуск контейнера",
  dispatch_undo: "отмена выезда",
  accept: "приёмка",
  to_repair: "в ремонт",
  reinspect: "возврат на осмотр",
  iso_override: "номер вне стандарта",
  advance: "смена статуса партии",
  undo: "откат",
  unlink: "отвязка контейнера",
  vgm: "выпуск VGM",
  akt: "выпуск акта",
  volume_override: "превышение объёма",
  soft_delete: "удаление заявки",
  restore: "восстановление",
  cancel: "отмена заявки",
  update: "изменение настроек",
  to_inspect: "на досмотр",
  inspected: "досмотр пройден",
  fumigated: "фумигация",
  departed: "убыла в порт",
  delete: "удаление записи",
  temp_take: "забор из времянки",
  temp_close: "времянка разобрана",
  temp_set: "записан остаток времянки",
  backdated: "закрыт задним числом",
  washing: "на мойку",
};
function qr({ me: t }) {
  const [n, s] = S.useState(null),
    [l, i] = S.useState(""),
    [u, o] = Te("audit.per", "30"),
    [x, N] = S.useState(""),
    [b, j, g] = ne(
      () => {
        let _ = A.from("term_audit")
          .select("*")
          .order("id", {
            ascending: !1,
          })
          .limit(2e3);
        return (l && (_ = _.eq("entity", l)), u !== "0" && (_ = _.gte("at", El(+u))), Y(_));
      },
      [l, u],
      3e4,
    ),
    d = [
      ["", "Все"],
      ["visit", "Зерновозы"],
      ["container", "Контейнеры"],
      ["batch", "Партии"],
      ["mix", "Замесы"],
      ["request", "Заявки"],
      ["doc", "Документы"],
      ["load", "Затарки"],
      ["settings", "Настройки"],
    ],
    M = S.useMemo(() => {
      const _ = x.trim().toLowerCase();
      return _
        ? (b || []).filter((h) =>
            (h.by_name + " " + (h.entity || "") + " №" + (h.entity_id || "") + " " + JSON.stringify(h.details || {})).toLowerCase().includes(_),
          )
        : b || [];
    }, [b, x]),
    z = () => s(null);
  return (
    <div className="panel">
      {(n == null ? void 0 : n.k) === "v" && <Zt id={n.id} me={t} onClose={z} />}
      {(n == null ? void 0 : n.k) === "c" && <Ht id={n.id} me={t} onClose={z} />}
      {(n == null ? void 0 : n.k) === "m" && <Cs id={n.id} me={t} onClose={z} />}
      {(n == null ? void 0 : n.k) === "l" && <CRs id={n.id} me={t} onClose={z} />}
      <div className="hd">
        <h2 className="p-title mt0">Журнал изменений · {M.length}</h2>
        <button className="btn sec sm" onClick={j}>
          Обновить
        </button>
      </div>
      <p className="p-sub">
        кто и когда продавил проверку, отменил действие или изменил настройки · записи не редактируются и не удаляются · период и поиск по объекту —
        ниже
      </p>
      <div
        className="row"
        style={{
          gap: 8,
          marginBottom: 8,
          flexWrap: "wrap",
        }}
      >
        <CQl val={u} onChange={o} />
        <input className="srch9" placeholder="поиск: машина, контейнер, фамилия…" value={x} onChange={(_) => N(_.target.value)} />
        {x.trim() && !(M || []).length ? <span className="find9no2">ничего не найдено</span> : null}
      </div>
      <div
        className="tabs"
        style={{
          marginBottom: 8,
        }}
      >
        {d.map(([_, h]) => (
          <button className={"tab" + (l === _ ? " on" : "")} onClick={() => i(_)}>
            {h}
          </button>
        ))}
      </div>
      <CFe err={g} />
      {M.length !== (b || []).length && (
        <p
          className="p-sub"
          style={{
            margin: "0 0 6px",
          }}
        >
          найдено {M.length} из {(b || []).length} за период
        </p>
      )}
      <div
        className="tscroll"
        style={{
          maxHeight: "68vh",
        }}
      >
        <table>
          <thead>
            <tr>
              <th>Когда</th>
              <th>Кто</th>
              <th>Объект</th>
              <th>Действие</th>
              <th>Подробности</th>
            </tr>
          </thead>
          <tbody>
            {M.map((_) => (
              <tr
                className={_.entity_id && Ts[_.entity] ? "rowx" : void 0}
                title={_.entity_id && Ts[_.entity] ? "Открыть карточку объекта" : void 0}
                onClick={
                  _.entity_id && Ts[_.entity]
                    ? () =>
                        s({
                          k: Ts[_.entity],
                          id: _.entity_id,
                        })
                    : void 0
                }
              >
                <td className="nowrap">{he(_.at)}</td>
                <td>{_.by_name || "—"}</td>
                <td>
                  {(d.find((h) => h[0] === _.entity) || [null, _.entity])[1]}
                  {_.entity_id ? <span className="faint"> №{_.entity_id}</span> : null}
                </td>
                <td>{On[_.action] || _.action}</td>
                <td
                  className="aud9"
                  style={{
                    maxWidth: 520,
                    whiteSpace: "normal",
                  }}
                >
                  {_.details
                    ? Object.entries(_.details)
                        .map(([h, w]) => `${h}: ${Array.isArray(w) ? w.join("; ") : typeof w == "object" && w ? JSON.stringify(w) : w}`)
                        .join(" · ")
                    : "—"}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
const Tr = [
    {
      k: "lab_status",
      t: "Решение",
      w: 170,
      opts: [
        ["passed", "Одобрен"],
        ["rejected", "Отказ"],
        ["pending", "Вернуть в очередь"],
      ],
    },
    {
      k: "lab_result1",
      t: "Результат 1 (путь груза)",
      w: 170,
      opts: Object.entries(Le),
    },
    {
      k: "lab_moisture",
      t: "Влажность, %",
      type: "num",
      w: 110,
    },
    {
      k: "lab_impurity",
      t: "Сорность, %",
      type: "num",
      w: 110,
    },
    {
      k: "lab_broken",
      t: "Колотые/битые, %",
      type: "num",
      w: 130,
    },
    {
      k: "lab_grain_adm",
      t: "Зерновая примесь, %",
      type: "num",
      w: 130,
    },
    {
      k: "lab_result_text",
      t: "Показатели (текст)",
      w: 240,
    },
    {
      k: "lab_notes",
      t: "Примечания",
      w: 240,
    },
  ],
  Os = (t) => {
    if (!t) return 999;
    const n = parseInt(t, 10);
    return isNaN(n) ? 998 : n;
  };
function Or({ me: t }) {
  const [n, s] = S.useState(null),
    [l, i] = S.useState(null),
    [u, o, x] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*, term_requests(term_orders(extra_services, dest_country, survey))")
            .is("out_at", null)
            .eq("lab_status", "pending")
            .not("in_at", "is", null)
            .order("in_at"),
        ),
      [],
      15e3,
    ),
    N = S.useMemo(() => [...(u || [])].sort((c, V) => Os(c.priority) - Os(V.priority) || new Date(c.in_at) - new Date(V.in_at)), [u]),
    [b, j] = S.useState(null),
    [g, d, M] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .in("lab_status", ["passed", "rejected"])
            .is("out_at", null)
            .order("lab_at", {
              ascending: !1,
            })
            .limit(40),
        ),
      [],
      3e4,
    ),
    [z, _, h] = ne(
      () => Y(A.from("term_requests").select("*").eq("status", "expected").is("deleted_at", null).not("t2_at", "is", null).order("t2_at")),
      [],
      15e3,
    ),
    w = S.useMemo(
      () =>
        [...(z || [])].sort(
          (c, V) => (c.t2_called_at ? 1 : 0) - (V.t2_called_at ? 1 : 0) || Os(c.priority) - Os(V.priority) || new Date(c.t2_at) - new Date(V.t2_at),
        ),
      [z],
    ),
    [p, F] = ne(() => Y(A.from("term_files").select("id, entity, entity_id").eq("entity", "visit").limit(5e3)), [], 3e4),
    C = (c) => (p || []).reduce((V, J) => V + (J.entity_id === c ? 1 : 0), 0),
    [y, $] = S.useState(null),
    [m, v] = Te("draft.lab", {}),
    [U, Z] = Te("lab.cards", !1),
    [I, D] = S.useState(null),
    { TH: E, apply: a } = rt(),
    [f, P] = S.useState(null),
    T = () => {
      (o(), d(), _(), me && me(), W && W());
    },
    H = async (c, V) => {
      try {
        if (V) {
          const J = (w || []).filter((oe) => oe.t2_called_at && oe.id !== c.id).length,
            ce = Oe(ot.S, "call_limit") || 5;
          if (
            J >= ce &&
            !window.confirm(`Уже вызвано ${J} машин, и они ещё не заехали. Вызвать ещё одну?

При большой очереди у ворот машины стоят на въезде, а не на отстойнике.`)
          )
            return;
        }
        (await Y(
          A.rpc("term_req_op", {
            p_id: c.id,
            p_op: V ? "call" : "call_undo",
          }),
        ),
          P(
            V
              ? {
                  ok: `${c.vehicle_no} — вызван с отстойника (Т2), КПП видит отметку`,
                }
              : {
                  ok: `${c.vehicle_no} — вызов снят`,
                },
          ),
          _());
      } catch (J) {
        P({
          err: String(J.message || J),
        });
      }
    },
    [Q] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("id, container_no, cargo, temp_kg")
            .eq("state", "temp")
            .is("out_at", null)
            .order("container_no")
            .limit(1e3),
        ),
      [],
      6e4,
    ),
    [ae, me] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select(
              "id, vehicle_no, culture, supplier, site, lab_status, lab_at, lab_result1, mix_id, mix_group, mix_with, mix_param, mix_ext, gross_kg, tare_kg, net_kg",
            )
            .not("in_at", "is", null)
            .order("in_at")
            .limit(1500),
        ),
      [],
      2e4,
    ),
    [L, W] = ne(
      () =>
        Y(
          A.from("term_mixes")
            .select("*")
            .not("status", "in", "(closed)")
            .order("id", {
              ascending: !1,
            })
            .limit(60),
        ),
      [],
      2e4,
    ),
    K = S.useMemo(
      () =>
        (L || []).map((c) => ({
          ...c,
          machines: (ae || []).filter((V) => V.mix_id === c.id).map((V) => V.vehicle_no),
          net: (ae || []).filter((V) => V.mix_id === c.id).reduce((V, J) => V + (+J.net_kg || 0), 0),
          nw: (ae || []).filter((V) => V.mix_id === c.id && V.tare_kg == null).length,
          pend: (ae || []).filter((V) => V.mix_id === c.id && V.lab_status !== "passed").length,
        })),
      [L, ae],
    ),
    le = S.useMemo(() => Object.fromEntries(K.map((c) => [c.id, c])), [K]),
    [$e] = ne(() => Y(A.from("term_culture_norms").select("*")), [], 3e5, "norms"),
    ee = (c) =>
      ($e || []).find(
        (V) =>
          (V.culture || "").trim().toLowerCase() ===
          String(c || "")
            .trim()
            .toLowerCase(),
      ),
    [re, be] = S.useState({}),
    Ne = S.useMemo(() => (N || []).filter((c) => re[c.id]), [N, re]),
    [ze, Ke] = S.useState(!1),
    He = (c) => {
      const V = ee(c.culture);
      if (!V) {
        P({
          err: `Для культуры «${c.culture || "—"}» нормы не заданы — их ведёт лаборатория в настройках`,
        });
        return;
      }
      v((J) => ({
        ...J,
        [c.id]: {
          ...(J[c.id] || {}),
          m: String(V.moisture_max ?? ""),
          i: String(V.impurity_max ?? ""),
          g: String(V.broken_max ?? ""),
        },
      }));
    },
    We = async () => {
      const c = Ne.filter((ce) => {
        const oe = m[ce.id] || {};
        return te(oe.m) == null && te(oe.i) == null && te(oe.g) == null;
      });
      if (
        c.length &&
        !window.confirm(`Без показателей: ${c.map((ce) => ce.vehicle_no).join(", ")}.

Всё равно принять ${Ne.length} машин как «Выгрузка»?`)
      )
        return;
      let V = 0;
      const J = [];
      for (const ce of Ne) {
        const oe = m[ce.id] || {};
        try {
          (await ue(
            A.from("term_truck_visits")
              .update({
                lab_status: "passed",
                lab_at: new Date().toISOString(),
                lab_by: t.id,
                lab_result1: "unload",
                ...(te(oe.m) != null
                  ? {
                      lab_moisture: te(oe.m),
                    }
                  : {}),
                ...(te(oe.i) != null
                  ? {
                      lab_impurity: te(oe.i),
                    }
                  : {}),
                ...(te(oe.g) != null
                  ? {
                      lab_broken: te(oe.g),
                    }
                  : {}),
              })
              .eq("id", ce.id)
              .eq("lab_status", "pending"),
            "машина " + ce.vehicle_no,
          ),
            V++);
        } catch (se) {
          J.push(`${ce.vehicle_no}: ${se.message || se}`);
        }
      }
      (V &&
        (await je(
          "visit",
          null,
          "batch_pass",
          {
            машин: V,
            без_показателей: c.length || void 0,
          },
          t,
        )),
        J.length
          ? P({
              err: `Принято ${V} из ${Ne.length}. Не прошли: ${J.join(" · ")}`,
            })
          : V &&
            P({
              ok: `Принято машин: ${V} — ушли в перевалку как «Выгрузка»`,
            }),
        be({}),
        T());
    },
    Qe = async (c) => {
      if (
        window.confirm(
          `Расформировать замес ${c.mix_no}? Машины (${(c.machines || []).join(", ") || "—"}) останутся одобренными, но перестанут быть связанными.`,
        )
      )
        try {
          (await ue(
            A.from("term_truck_visits")
              .update({
                mix_id: null,
                mix_group: null,
                mix_with: null,
                mix_param: null,
                mix_ext: null,
              })
              .eq("mix_id", c.id),
            "участники замеса " + c.mix_no,
            !0,
          ),
            await ue(A.from("term_mixes").delete().eq("id", c.id), "замес " + c.mix_no),
            await je(
              "mix",
              c.id,
              "disband",
              {
                замес: c.mix_no,
                машины: c.machines,
              },
              t,
            ),
            P({
              ok: `Замес ${c.mix_no} расформирован`,
            }),
            T());
        } catch (V) {
          P({
            err: String(V.message || V),
          });
        }
    },
    Ie = async (c, V) => {
      const J = (ae || []).find((ce) => ce.mix_id === c.id && ce.vehicle_no === V);
      if (J && window.confirm(`Вывести ${V} из замеса ${c.mix_no}? Решение лаборатории у машины сохранится.`))
        try {
          (await ue(
            A.from("term_truck_visits")
              .update({
                mix_id: null,
                mix_group: null,
                mix_with: null,
                mix_param: null,
                mix_ext: null,
              })
              .eq("id", J.id),
            "машина " + V,
          ),
            await Y(
              A.rpc("term_mix_sync", {
                p_mix: c.id,
              }),
            ),
            await je(
              "mix",
              c.id,
              "leave",
              {
                замес: c.mix_no,
                машина: V,
              },
              t,
            ),
            P({
              ok: `${V} выведена из замеса ${c.mix_no}`,
            }),
            T());
        } catch (ce) {
          P({
            err: String(ce.message || ce),
          });
        }
    },
    ht = async (c) => {
      if (window.confirm(`Закрыть замес ${c.mix_no}? Он уйдёт из рабочих списков — так помечают полностью отработанные замесы.`))
        try {
          (await ue(
            A.from("term_mixes")
              .update({
                status: "closed",
                closed_at: new Date().toISOString(),
                closed_by: t.id,
              })
              .eq("id", c.id),
            "замес " + c.mix_no,
          ),
            await je(
              "mix",
              c.id,
              "close",
              {
                замес: c.mix_no,
              },
              t,
            ),
            P({
              ok: `Замес ${c.mix_no} закрыт`,
            }),
            T());
        } catch (V) {
          P({
            err: String(V.message || V),
          });
        }
    },
    [B, r] = S.useState(null),
    O = async (c, V) => {
      const J = m[c.id] || {};
      if (V === "passed" && !J.r1) {
        P({
          err: "Выбери «Результат 1» (что делаем с грузом)",
        });
        return;
      }
      const ce = V === "passed" && (J.r1 === "mix" || J.r1 === "clean_mix");
      if (ce && !(J.mw || "").trim()) {
        P({
          err: `${c.vehicle_no}: замес — это минимум две машины. Отметь галочками обе машины в очереди и нажми «Собрать замес», либо выбери здесь действующий замес, чтобы присоединиться к нему.`,
        });
        return;
      }
      for (const [Me, de] of [
        [te(J.m), "Влажность"],
        [te(J.i), "Сорность"],
        [te(J.b), "Колотые/битые"],
        [te(J.g), "Зерновая примесь"],
      ])
        if (Me != null && (Me < 0 || Me > 100)) {
          P({
            err: `${de}: значение должно быть в пределах 0–100%`,
          });
          return;
        }
      const oe = [];
      V === "passed" && te(J.m) == null && te(J.i) == null && te(J.g) == null && oe.push("не введён ни один показатель качества");
      const se = ee(c.culture);
      if (
        (se &&
          V === "passed" &&
          (te(J.m) != null &&
            se.moisture_max != null &&
            te(J.m) > +se.moisture_max &&
            oe.push(`влажность ${te(J.m)}% выше нормы для «${c.culture}» (${se.moisture_max}%)`),
          te(J.i) != null &&
            se.impurity_max != null &&
            te(J.i) > +se.impurity_max &&
            oe.push(`сорность ${te(J.i)}% выше нормы (${se.impurity_max}%)`),
          te(J.g) != null &&
            se.broken_max != null &&
            te(J.g) > +se.broken_max &&
            oe.push(`колотые/битые ${te(J.g)}% выше нормы (${se.broken_max}%)`)),
        V === "rejected" &&
          !(J.rt || "").trim() &&
          te(J.m) == null &&
          te(J.i) == null &&
          te(J.g) == null &&
          oe.push("отказ без показателей и без текста причины"),
        V === "rejected" &&
          (c.gross_kg != null || c.tare_kg != null) &&
          oe.push("машина уже взвешена — отказ перекроет введённые веса в статусе, но они останутся в тоннаже"),
        oe.length && !J.ovr)
      ) {
        P({
          err: `${c.vehicle_no}: ${oe.join("; ")}. Проверь ввод — или отметь галочку «подтверждаю» в колонке решения.`,
        });
        return;
      }
      const ge = ce ? le[String(J.mw)] : null;
      if (ce && !ge) {
        P({
          err: "Замес не найден — обнови страницу",
        });
        return;
      }
      try {
        if (
          (await ue(
            A.from("term_truck_visits")
              .update({
                lab_status: V,
                lab_at: new Date().toISOString(),
                lab_by: t.id,
                ...(te(J.m) != null
                  ? {
                      lab_moisture: te(J.m),
                    }
                  : {}),
                ...(te(J.i) != null
                  ? {
                      lab_impurity: te(J.i),
                    }
                  : {}),
                ...(te(J.g) != null
                  ? {
                      lab_broken: te(J.g),
                    }
                  : {}),
                ...((J.rt || "").trim()
                  ? {
                      lab_result_text: (J.rt || "").trim(),
                    }
                  : {}),
                lab_result1: V === "passed" ? J.r1 : null,
                mix_id: ce ? ge.id : null,
                mix_group: ce ? ge.mix_no : null,
                mix_param: (ce && ge.param) || null,
                mix_ext: (ce && ge.ext_partner) || null,
              })
              .eq("id", c.id),
            "машина " + c.vehicle_no,
          ),
          ce)
        ) {
          const Me = await Y(A.from("term_truck_visits").select("id, vehicle_no").eq("mix_id", ge.id));
          for (const de of Me || []) {
            const ve = (Me || []).filter((we) => we.id !== de.id).map((we) => we.vehicle_no);
            await ue(
              A.from("term_truck_visits")
                .update({
                  mix_with: [...ve, ge.ext_partner].filter(Boolean).join(", ") || null,
                })
                .eq("id", de.id),
              "подпись замеса",
              !0,
            );
          }
        }
        if (!ce && c.mix_id) {
          const Me = await Y(A.from("term_truck_visits").select("id, vehicle_no, mix_ext").eq("mix_id", c.mix_id).neq("id", c.id));
          for (const de of Me || []) {
            const ve = (Me || []).filter((we) => we.id !== de.id).map((we) => we.vehicle_no);
            await ue(
              A.from("term_truck_visits")
                .update({
                  mix_with: [...ve, de.mix_ext].filter(Boolean).join(", ") || null,
                })
                .eq("id", de.id),
              "подпись замеса",
              !0,
            );
          }
          ((Me || []).length ||
            (await ue(
              A.from("term_mixes")
                .update({
                  status: "closed",
                  closed_at: new Date().toISOString(),
                  notes: "все участники отказаны",
                })
                .eq("id", c.mix_id),
              "замес",
            )),
            await je(
              "mix",
              c.mix_id,
              "leave",
              {
                машина: c.vehicle_no,
                причина: "отказ лаборатории",
              },
              t,
            ));
        }
        (oe.length &&
          (await je(
            "visit",
            c.id,
            "lab_override",
            {
              машина: c.vehicle_no,
              продавлено: oe,
            },
            t,
          )),
          v((Me) => ({
            ...Me,
            [c.id]: {},
          })),
          P({
            ok:
              V === "passed"
                ? `${c.vehicle_no}: «Одобрен» → ${Le[J.r1]}${ce ? ` · присоединён к замесу ${ge.mix_no}` : ""} — заявка ушла в раздел «Перевалка»`
                : `${c.vehicle_no}: отказ`,
          }),
          T());
      } catch (Me) {
        P({
          err: String(Me.message || Me),
        });
      }
    },
    G = (c, V) => !c || !V || String(c).trim() === String(V).trim(),
    ie = (c) =>
      K.filter((V) => !["packed", "closed"].includes(V.status) && G(V.culture, c.culture)).map((V) => [
        V.id,
        `${V.mix_no} · ${V.culture || "—"} · ${[...(V.machines || []), V.ext_partner].filter(Boolean).join(", ")}`,
      ]);
  return (
    <>
      {I && (
        <CAt
          title={`Лаборатория · ${I.vehicle_no} · правка результатов`}
          fields={Tr}
          row={I}
          table="term_truck_visits"
          onClose={() => D(null)}
          onDone={() => {
            (P({
              ok: "Изменения сохранены",
            }),
              T());
          }}
        />
      )}
      {b && (
        <Fi
          v={b}
          onClose={() => j(null)}
          onDone={() => {
            (P({
              ok: "Доп. показатели сохранены",
            }),
              T());
          }}
        />
      )}
      {y && (
        <Kt
          me={t}
          entity="visit"
          id={y.id}
          title={`Машина ${y.vehicle_no} · фото доски разбора и файлы`}
          onClose={() => {
            ($(null), F());
          }}
        />
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Отстойник (Т2) · прибывшие {w.length}</h2>
          <button className="btn sec sm" onClick={_}>
            Обновить
          </button>
        </div>
        <p className="p-sub">
          здесь только машины, отмеченные КПП как прибывшие на отстойник · «Вызвать» — приглашай машину на терминал по очереди, КПП увидит отметку
          «вызван»
        </p>
        <CFe err={h} />
        {w.length ? (
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <th>Оч.</th>
                  <th>Машина / прицеп</th>
                  <th>Водитель</th>
                  <th>Культура · Поставщик</th>
                  <th className="right">Вес, кг</th>
                  <th>На отстойнике с</th>
                  <th>Вызов</th>
                </tr>
              </thead>
              <tbody>
                {w.map((c) => (
                  <tr
                    className="rowc"
                    title="Карточка заявки"
                    onClick={(V) => {
                      lt(V) && i(c);
                    }}
                  >
                    <td>{c.priority || "—"}</td>
                    <td>
                      <b>{c.vehicle_no}</b>
                      {c.trailer_no ? <span className="faint"> / {c.trailer_no}</span> : null}
                    </td>
                    <td>
                      {c.driver || "—"}
                      <div
                        className="faint"
                        style={{
                          fontSize: 10,
                        }}
                      >
                        {c.driver_phone || ""}
                      </div>
                    </td>
                    <td>
                      {c.culture || "—"}
                      <div
                        className="faint"
                        style={{
                          fontSize: 10,
                        }}
                      >
                        {c.supplier || ""}
                      </div>
                    </td>
                    <td className="right">{c.planned_tonnes != null ? q(qe(c.planned_tonnes)) : "—"}</td>
                    <td className="nowrap">{Ue(c.t2_at)}</td>
                    <td className="nowrap">
                      {c.t2_called_at ? (
                        <span
                          className="row"
                          style={{
                            gap: 5,
                            alignItems: "center",
                          }}
                        >
                          <span className="t2chip ok">вызван {Ue(c.t2_called_at)}</span>
                          <button className="btn sec sm icon" title="Снять вызов" onClick={() => H(c, !1)}>
                            ✕
                          </button>
                        </span>
                      ) : (
                        <button className="btn sm" onClick={() => H(c, !0)}>
                          Вызвать →
                        </button>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            пока никто не прибыл — машины появятся после отметки «Отстойник (Т2)» на КПП
          </p>
        )}
      </div>
      {n && <Cs id={n} me={t} onClose={() => s(null)} />}
      {B && <Zt id={B.id} me={t} onClose={() => r(null)} onSaved={T} />}
      {l && <CQn r={l} me={t} onClose={() => i(null)} />}
      {ze && (
        <CVr
          me={t}
          picked={Ne}
          mixes={K}
          temps={Q}
          onClose={() => Ke(!1)}
          onDone={(c) => {
            (Ke(!1),
              be({}),
              P({
                ok: c,
              }),
              T());
          }}
        />
      )}
      {K.length > 0 && (
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Реестр замесов · действующие {K.length}</h2>
            <button className="btn sec sm" onClick={T}>
              Обновить
            </button>
          </div>
          <p className="p-sub">
            замес — связанная группа машин: все участники одобряются одним решением и идут в перевалку и на весы вместе · чтобы добавить машину к
            действующему замесу, в очереди поставь «Результат 1» = Замес и выбери замес в колонке «Замес» · ✕ у машины выводит её из замеса, ✕ у
            строки расформировывает замес целиком
          </p>
          <div
            className="tscroll"
            style={{
              maxHeight: "30vh",
            }}
          >
            <table>
              <thead>
                <tr>
                  <th>Замес</th>
                  <th>Культура</th>
                  <th>Участники</th>
                  <th>Параметр</th>
                  <th>Площадка</th>
                  <th className="right">Нетто, кг</th>
                  <th>Состояние</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {K.map((c) => (
                  <tr
                    className="rowc"
                    title="Карточка замеса"
                    onClick={(V) => {
                      lt(V) && s(c.id);
                    }}
                  >
                    <td>
                      <b>{c.mix_no}</b>
                    </td>
                    <td>{c.culture || "—"}</td>
                    <td
                      style={{
                        maxWidth: 320,
                        whiteSpace: "normal",
                      }}
                    >
                      {(c.machines || []).map((V) => (
                        <span
                          className="bchip"
                          style={{
                            marginRight: 4,
                          }}
                        >
                          {V}
                          <button className="xmini" title={`Вывести ${V} из замеса`} onClick={() => Ie(c, V)}>
                            ✕
                          </button>
                        </span>
                      ))}
                      {c.ext_partner ? <span className="bchip">{c.ext_partner}</span> : null}
                      {!(c.machines || []).length && !c.ext_partner ? <span className="faint">пусто</span> : null}
                    </td>
                    <td>{c.param || "—"}</td>
                    <td>{c.site || "—"}</td>
                    <td className="right">
                      {c.net ? q(c.net) : "—"}
                      {c.nw ? (
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          ждут весов: {c.nw}
                        </div>
                      ) : null}
                    </td>
                    <td>
                      {(() => {
                        const V = vs(c, {
                          pending: c.pend,
                        });
                        return <span className={"stage " + V.c}>{V.t}</span>;
                      })()}
                    </td>
                    <td className="nowrap">
                      <button className="btn sec sm" title="Закрыть отработанный замес" onClick={() => ht(c)}>
                        Закрыть
                      </button>{" "}
                      <button className="btn danger sm icon" title="Расформировать замес" onClick={() => Qe(c)}>
                        ✕
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Проверка качества · очередь {(N || []).length}</h2>
          <span
            className="row"
            style={{
              gap: 6,
              alignItems: "center",
            }}
          >
            <button
              className="btn sm"
              disabled={Ne.length < 1}
              title={Ne.length < 1 ? "Отметь галочками машины для замеса" : ""}
              onClick={() => Ke(!0)}
            >
              Собрать замес{Ne.length ? ` · ${Ne.length}` : ""}
            </button>
            {Ne.length > 0 && (
              <button className="btn sec sm" title="Проставить всем отмеченным «Выгрузка» и принять" onClick={() => We()}>
                Принять отмеченные · {Ne.length}
              </button>
            )}
            {Ne.length > 0 && (
              <button className="btn sec sm" onClick={() => be({})}>
                Снять отметки
              </button>
            )}
            <button className={"btn sm" + (U ? "" : " sec")} title="Крупные карточки для телефона" onClick={() => Z(!U)}>
              {U ? "☰ Таблица" : "⛶ Карточки"}
            </button>
            <button className="btn sec sm" onClick={T}>
              Обновить
            </button>
          </span>
        </div>
        <p className="p-sub">
          Enter в поле показателя — сразу «Принят» · ↑/↓ — переход по колонке между машинами · ≤ — проставить показатели по норме культуры · поле
          краснеет, если выше нормы · <b>замес</b>: отметь галочками машины и нажми «Собрать замес» · 📎 — фото доски разбора
        </p>
        <CFe err={x} />
        <CFe {...(f || {})} />
        {U && (
          <div className="wcards">
            {!(N || []).length && (
              <p
                className="p-sub"
                style={{
                  margin: 0,
                }}
              >
                очередь пуста
              </p>
            )}
            {(N || []).map((c) => {
              const V = m[c.id] || {},
                J = ee(c.culture),
                ce = V.r1,
                oe = ce === "mix" || ce === "clean_mix";
              return (
                <div className="wcard">
                  <div className="wtop">
                    <label className="wsel">
                      <input
                        type="checkbox"
                        checked={!!re[c.id]}
                        onChange={(se) =>
                          be((ge) => ({
                            ...ge,
                            [c.id]: se.target.checked,
                          }))
                        }
                      />
                    </label>
                    <span className="wno" onClick={() => r(c)}>
                      {c.vehicle_no}
                    </span>
                    <span className="faint">{Ue(c.in_at)}</span>
                  </div>
                  <div className="wsub">
                    {c.culture || "—"}
                    {c.supplier ? ` · ${c.supplier}` : ""}
                    {c.planned_tonnes != null ? ` · план ${q(qe(c.planned_tonnes))} кг` : ""}
                    {J ? (
                      <span className="faint">
                        {" "}
                        · норма: вл ≤{J.moisture_max ?? "—"} · сор ≤{J.impurity_max ?? "—"} · кол/бит ≤{J.broken_max ?? "—"}
                      </span>
                    ) : null}
                  </div>
                  <div className="wrow wthree">
                    {[
                      ["m", "Влажность %"],
                      ["i", "Сорность %"],
                      ["g", "Кол/бит %"],
                    ].map(([se, ge], Me) => {
                      const de = J ? [J.moisture_max, J.impurity_max, J.broken_max][Me] : null,
                        ve = te(V[se]),
                        we = ve != null && de != null && ve > +de;
                      return (
                        <X label={ge}>
                          <input
                            className={"g-in wbig" + (we ? " overn" : "")}
                            inputMode="decimal"
                            placeholder={de != null ? "≤" + de : "%"}
                            value={V[se] ?? ""}
                            onChange={(Pe) =>
                              v((Be) => ({
                                ...Be,
                                [c.id]: {
                                  ...(Be[c.id] || {}),
                                  [se]: Pe.target.value,
                                },
                              }))
                            }
                          />
                        </X>
                      );
                    })}
                  </div>
                  <div className="wrow">
                    <CPe
                      value={ce || ""}
                      onChange={(se) =>
                        v((ge) => ({
                          ...ge,
                          [c.id]: {
                            ...(ge[c.id] || {}),
                            r1: se,
                          },
                        }))
                      }
                      options={Object.entries(Le)}
                      w={190}
                      ph="Результат 1 —"
                    />
                    <button className="btn sec big icon" title="Проставить показатели по норме культуры" onClick={() => He(c)}>
                      ≤
                    </button>
                    {oe && (
                      <CPe
                        value={V.mw || ""}
                        onChange={(se) =>
                          v((ge) => ({
                            ...ge,
                            [c.id]: {
                              ...(ge[c.id] || {}),
                              mw: se,
                            },
                          }))
                        }
                        options={ie(c)}
                        w={210}
                        ph="присоединить к замесу"
                      />
                    )}
                  </div>
                  <div className="wrow">
                    <button
                      className="btn big"
                      style={{
                        flex: 1,
                      }}
                      onClick={() => O(c, "passed")}
                    >
                      Принят ✓
                    </button>
                    <button className="btn danger big" onClick={() => O(c, "rejected")}>
                      Отказ
                    </button>
                    <label className="fkey">
                      <input
                        type="checkbox"
                        checked={!!V.ovr}
                        onChange={(se) =>
                          v((ge) => ({
                            ...ge,
                            [c.id]: {
                              ...(ge[c.id] || {}),
                              ovr: se.target.checked,
                            },
                          }))
                        }
                      />{" "}
                      подтверждаю
                    </label>
                  </div>
                </div>
              );
            })}
          </div>
        )}
        {!U && (
          <div className="tscroll stick3">
            <table>
              <thead>
                <tr>
                  <th
                    style={{
                      width: 30,
                    }}
                  >
                    <input
                      type="checkbox"
                      title="Отметить все"
                      checked={Ne.length > 0 && Ne.length === (N || []).length}
                      onChange={(c) => be(c.target.checked ? Object.fromEntries((N || []).map((V) => [V.id, !0])) : {})}
                    />
                  </th>
                  <th>Оч.</th>
                  <th>Машина</th>
                  <th>Культура · Поставщик</th>
                  <th>Контракт закуп.</th>
                  <th>Доп. услуги</th>
                  <th className="right">Вес план, кг</th>
                  <th>Прибытие</th>
                  <th>Влаж. %</th>
                  <th>Сор %</th>
                  <th>Кол/бит %</th>
                  <th>Показатели (текст)</th>
                  <th>Доп.</th>
                  <th>Фото</th>
                  <th>Результат 1</th>
                  <th>Замес</th>
                  <th>Решение</th>
                </tr>
              </thead>
              <tbody>
                {(N || []).map((c) => {
                  var ce, oe;
                  const V = (m[c.id] || {}).r1,
                    J = V === "mix" || V === "clean_mix";
                  return (
                    <tr
                      className={(re[c.id] ? "selrow" : "") + " rowc"}
                      onClick={(se) => {
                        lt(se) && r(c);
                      }}
                    >
                      <td>
                        <input
                          type="checkbox"
                          checked={!!re[c.id]}
                          onChange={(se) =>
                            be((ge) => ({
                              ...ge,
                              [c.id]: se.target.checked,
                            }))
                          }
                        />
                      </td>
                      <td>{c.priority || "—"}</td>
                      <td className="rowx" onClick={() => r(c)} title="Карточка машины">
                        <b>{c.vehicle_no}</b>
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          {c.driver || ""} {c.driver_phone || ""}
                        </div>
                      </td>
                      <td>
                        {c.culture || "—"}
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          {c.supplier || ""}
                        </div>
                        {ee(c.culture) ? (
                          <div
                            className="faint"
                            style={{
                              fontSize: 9.5,
                            }}
                          >
                            норма: вл ≤{ee(c.culture).moisture_max ?? "—"} · сор ≤{ee(c.culture).impurity_max ?? "—"} · кол/бит ≤
                            {ee(c.culture).broken_max ?? "—"}
                          </div>
                        ) : null}
                      </td>
                      <td>{c.purchase_contract || "—"}</td>
                      <td
                        style={{
                          maxWidth: 170,
                          whiteSpace: "normal",
                        }}
                      >
                        {(((oe = (ce = c.term_requests) == null ? void 0 : ce.term_orders) == null ? void 0 : oe.extra_services) || []).join(", ") ||
                          "—"}
                      </td>
                      <td className="right">{c.planned_tonnes != null ? q(qe(c.planned_tonnes)) : "—"}</td>
                      <td className="nowrap">{Ue(c.in_at)}</td>
                      {["m", "i", "g"].map((se, ge) => {
                        const Me = ee(c.culture),
                          de = Me ? [Me.moisture_max, Me.impurity_max, Me.broken_max][ge] : null,
                          ve = te((m[c.id] || {})[se]),
                          we = ve != null && de != null && ve > +de;
                        return (
                          <td>
                            <input
                              className={"g-in" + (we ? " overn" : "")}
                              style={{
                                width: 62,
                              }}
                              inputMode="decimal"
                              placeholder={de != null ? "≤" + de : "%"}
                              title={de != null ? `норма для «${c.culture}»: не выше ${de}%` : ""}
                              value={(m[c.id] || {})[se] ?? ""}
                              data-lab={c.id + "-" + se}
                              onChange={(Pe) =>
                                v((Be) => ({
                                  ...Be,
                                  [c.id]: {
                                    ...(Be[c.id] || {}),
                                    [se]: Pe.target.value,
                                  },
                                }))
                              }
                              onKeyDown={(Pe) => {
                                if ((Pe.key === "Enter" && (Pe.preventDefault(), O(c, "passed")), Pe.key === "ArrowDown" || Pe.key === "ArrowUp")) {
                                  Pe.preventDefault();
                                  const Be = [...document.querySelectorAll(`[data-lab$="-${se}"]`)],
                                    Xt = Be.indexOf(Pe.target),
                                    Ms = Be[Xt + (Pe.key === "ArrowDown" ? 1 : -1)];
                                  Ms && Ms.focus();
                                }
                              }}
                            />
                          </td>
                        );
                      })}
                      <td>{is(m, v, c.id, "rt", "результат показателей", 150)}</td>
                      <td className="nowrap">
                        <button className="btn sec sm icon" title="Проставить показатели по норме культуры" onClick={() => He(c)}>
                          ≤
                        </button>{" "}
                        <button
                          className={"btn sec sm icon" + (c.lab_extra ? " has" : "")}
                          title="Доп. показатели (кол/бит, тёмные, заражённость…)"
                          onClick={() => j(c)}
                        >
                          ＋
                        </button>
                      </td>
                      <td>
                        <CGt n={C(c.id)} onClick={() => $(c)} />
                      </td>
                      <td>
                        <CPe
                          value={V || ""}
                          onChange={(se) =>
                            v((ge) => ({
                              ...ge,
                              [c.id]: {
                                ...(ge[c.id] || {}),
                                r1: se,
                              },
                            }))
                          }
                          options={Object.entries(Le)}
                          w={150}
                          ph="—"
                        />
                      </td>
                      <td>
                        {J ? (
                          <div className="mixcell">
                            <CPe
                              value={(m[c.id] || {}).mw || ""}
                              onChange={(se) =>
                                v((ge) => ({
                                  ...ge,
                                  [c.id]: {
                                    ...(ge[c.id] || {}),
                                    mw: se,
                                  },
                                }))
                              }
                              options={ie(c)}
                              w={230}
                              ph="присоединить к замесу"
                            />
                            {!ie(c).length && (
                              <span
                                className="faint"
                                style={{
                                  fontSize: 10,
                                }}
                              >
                                действующих замесов нет — отметь две машины галочками и нажми «Собрать замес»
                              </span>
                            )}
                          </div>
                        ) : (
                          <span className="faint">—</span>
                        )}
                      </td>
                      <td className="nowrap">
                        <button className="btn sm" onClick={() => O(c, "passed")}>
                          Принят ✓
                        </button>{" "}
                        <button className="btn danger sm" onClick={() => O(c, "rejected")}>
                          Отказ
                        </button>
                        <label
                          className="fkey"
                          style={{
                            marginTop: 3,
                            fontSize: 10,
                          }}
                        >
                          <input
                            type="checkbox"
                            checked={!!(m[c.id] || {}).ovr}
                            onChange={(se) =>
                              v((ge) => ({
                                ...ge,
                                [c.id]: {
                                  ...(ge[c.id] || {}),
                                  ovr: se.target.checked,
                                },
                              }))
                            }
                          />{" "}
                          подтверждаю отклонение
                        </label>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Обработанные · последние {(g || []).length}</h2>
        </div>
        <p className="p-sub">✎ — исправить уже вбитые результаты анализа (или вернуть машину в очередь)</p>
        <CFe err={M} />
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <E k="veh">Машина</E>
                <E k="cult">Культура</E>
                <E k="at">Проверено</E>
                <E k="st">Решение</E>
                <th className="right">Влаж. %</th>
                <th className="right">Сор %</th>
                <th className="right">Зерн. %</th>
                <th>Результат 1</th>
                <th>Фото</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {a(g || [], {
                veh: (c) => c.vehicle_no,
                cult: (c) => c.culture,
                at: (c) => c.lab_at,
                st: (c) => c.lab_status,
              }).map((c) => (
                <tr
                  className="rowc"
                  title="Карточка машины"
                  onClick={(V) => {
                    lt(V) && r(c);
                  }}
                >
                  <td>
                    <b>{c.vehicle_no}</b>
                  </td>
                  <td>{c.culture || "—"}</td>
                  <td className="nowrap">{Ue(c.lab_at)}</td>
                  <td>
                    <span className={"stage " + (c.lab_status === "passed" ? "lab_ok" : "lab_no")}>
                      {c.lab_status === "passed" ? "Одобрен" : "Отказ"}
                    </span>
                  </td>
                  <td className="right">{c.lab_moisture ?? "—"}</td>
                  <td className="right">{c.lab_impurity ?? "—"}</td>
                  <td className="right">{c.lab_broken ?? "—"}</td>
                  <td>
                    {c.lab_result1 ? Le[c.lab_result1] : "—"}
                    <Gt v={c} />
                  </td>
                  <td>
                    <CGt n={C(c.id)} onClick={() => $(c)} />
                  </td>
                  <td>
                    <Ye onClick={() => D(c)} />
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </>
  );
}
const Dr = [
    {
      k: "gross_kg",
      t: "Брутто, кг",
      type: "num",
      w: 120,
    },
    {
      k: "tare_kg",
      t: "Тара, кг",
      type: "num",
      w: 120,
    },
    {
      k: "unload_place",
      t: "Место выгрузки",
      w: 170,
      opts: As,
    },
  ],
  Tl = [
    {
      k: "vehicle_no",
      t: "Машина (а/т)",
      w: 130,
    },
    {
      k: "order_name",
      t: "Поручение",
      w: 150,
    },
    {
      k: "culture",
      t: "Культура",
      w: 130,
    },
    {
      k: "tare_kg",
      t: "Тара, кг",
      type: "num",
      w: 110,
    },
    {
      k: "gross_kg",
      t: "Брутто, кг",
      type: "num",
      w: 110,
    },
    {
      k: "seal_no",
      t: "Пломба",
      w: 130,
    },
  ];
function Ir({ me: t }) {
  const [n, s] = Te("scale.tab", "trucks");
  return (
    <>
      <div className="tabs">
        <button className={"tab" + (n === "trucks" ? " on" : "")} onClick={() => s("trucks")}>
          Зерновозы
        </button>
        <button className={"tab" + (n === "conts" ? " on" : "")} onClick={() => s("conts")}>
          Контейнеры (погрузка)
        </button>
      </div>
      {n === "trucks" ? <Rr me={t} /> : <Lr me={t} />}
    </>
  );
}
function Fr(t) {
  const [n, s] = S.useState(null),
    [l, i] = S.useState(!1),
    [u, o] = S.useState(null),
    x = S.useRef(null),
    N = async () => {
      try {
        (o(null),
          (x.current = Si({
            baudRate: t.scale_baud,
            minRead: t.scale_min_read,
            stableN: t.scale_stable_n,
            onWeight: (j) => s(j),
            onState: (j, g) => {
              (i(j === "on"), j === "err" && o(g));
            },
          })),
          await x.current.connect(),
          i(!0));
      } catch (j) {
        (o(String(j.message || j)), i(!1));
      }
    },
    b = async () => {
      var j;
      try {
        await ((j = x.current) == null ? void 0 : j.disconnect());
      } catch {}
      (i(!1), s(null));
    };
  return (
    S.useEffect(
      () => () => {
        var j;
        (j = x.current) == null || j.disconnect().catch(() => {});
      },
      [],
    ),
    {
      w9: n,
      on: l,
      err: u,
      connect: N,
      disconnect: b,
      supported: xl(),
    }
  );
}
function CZr({ sc: t }) {
  var n, s;
  return (
    <div className="scalebar">
      <div className="sb-l">
        <div className="sb-t">Весы</div>
        {t.on ? (
          <div className={"sb-w" + ((n = t.w9) != null && n.stable ? " ok" : "")}>
            {t.w9 ? q(t.w9.weight) : "—"}
            <span className="sb-u">кг</span>
          </div>
        ) : (
          <div className="sb-off">не подключены</div>
        )}
        {t.on && <div className="sb-s">{(s = t.w9) != null && s.stable ? "вес устойчив — можно брать" : "вес меняется…"}</div>}
      </div>
      <div
        className="row"
        style={{
          gap: 6,
        }}
      >
        {t.on ? (
          <button className="btn sec sm" onClick={t.disconnect}>
            Отключить
          </button>
        ) : (
          <button
            className="btn sm"
            onClick={t.connect}
            disabled={!t.supported}
            title={t.supported ? "Выбрать COM-порт весов" : "Открой систему в Chrome на компьютере весовой"}
          >
            Подключить весы
          </button>
        )}
      </div>
      {t.err && (
        <div
          className="err"
          style={{
            margin: 0,
            flexBasis: "100%",
          }}
        >
          {t.err}
        </div>
      )}
      {!t.supported && (
        <div
          className="p-sub"
          style={{
            margin: 0,
            flexBasis: "100%",
          }}
        >
          чтение весов работает в Chrome на компьютере, к которому подключены весы · на других устройствах вводи вес руками
        </div>
      )}
    </div>
  );
}
function Rr({ me: t }) {
  const [n, s] = S.useState(null),
    [l, i] = S.useState(null),
    [u, o, x] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*, term_requests(term_orders(extra_services))")
            .is("out_at", null)
            .eq("lab_status", "passed")
            .order("in_at")
            .limit(500),
        ),
      [],
      2e4,
    ),
    N = (f) => {
      var P, T;
      return ((T = (P = f.term_requests) == null ? void 0 : P.term_orders) == null ? void 0 : T.extra_services) || [];
    },
    [b, j] = ne(
      () =>
        Y(
          A.from("term_mixes")
            .select("*")
            .in("status", ["lab_ok", "ts_ok", "weighed"])
            .order("id", {
              ascending: !1,
            })
            .limit(60),
        ),
      [],
      2e4,
    ),
    [g, d] = Te("draft.scale.tr", {}),
    [M, z] = Te("scale.cards", !1),
    [_, h] = S.useState(null),
    [w, p] = S.useState(null),
    F = Js(),
    C = Fr(F),
    y = ["manager", "chief"].includes(t.role),
    $ = (f) => {
      C.w9 &&
        d((P) => ({
          ...P,
          [f]: {
            ...(P[f] || {}),
            kg: String(C.w9.weight),
          },
        }));
    },
    m = S.useMemo(
      () =>
        (b || [])
          .map((f) => {
            const P = (u || []).filter((T) => T.mix_id === f.id);
            return {
              ...f,
              list: P,
              net: P.reduce((T, H) => T + (+H.net_kg || 0), 0) + (+f.temp_kg || 0),
              left: P.filter((T) => T.tare_kg == null).length,
            };
          })
          .filter((f) => f.list.length),
      [b, u],
    ),
    [v] = ne(() => Y(A.from("term_truck_visits").select("id, mix_id, tare_kg, net_kg").not("mix_id", "is", null).limit(2e3)), [], 3e4),
    U = S.useMemo(() => {
      const f = {};
      for (const P of v || [])
        ((f[P.mix_id] = f[P.mix_id] || {
          n: 0,
          w: 0,
        }),
          f[P.mix_id].n++,
          P.tare_kg != null && f[P.mix_id].w++);
      return f;
    }, [v]),
    Z = async (f) => {
      try {
        (await ue(
          A.from("term_mixes")
            .update({
              status: "weighed",
            })
            .eq("id", f.id),
          "замес " + f.mix_no,
        ),
          await je(
            "mix",
            f.id,
            "weighed",
            {
              замес: f.mix_no,
              нетто: f.net,
            },
            t,
          ),
          p({
            ok: `Замес ${f.mix_no} готов к затарке · нетто ${q(f.net)} кг`,
          }),
          j(),
          o());
      } catch (P) {
        p({
          err: String(P.message || P),
        });
      }
    },
    I = (f, P) => {
      const T = qe(f.planned_tonnes);
      if (T == null || !P) return null;
      const H = Math.round((Math.abs(P - T) / T) * 100);
      return H > Oe(F, "plan_dev_pct") ? `факт ${q(P)} кг отличается от плана ${q(T)} кг на ${H}%` : null;
    },
    D = async (f) => {
      const P = g[f.id] || {},
        T = te(P.kg);
      if (!T || T <= 0) {
        p({
          err: "Введи брутто, кг",
        });
        return;
      }
      if (!P.pl) {
        p({
          err: "Выбери место выгрузки",
        });
        return;
      }
      const H = Oe(F, "truck_gross_min"),
        Q = Oe(F, "truck_gross_max"),
        ae = [];
      if (
        (T < H && ae.push(`брутто ${q(T)} кг ниже ожидаемого (гружёный зерновоз обычно 20 000–60 000 кг)`),
        T > Q && ae.push(`брутто ${q(T)} кг выше допустимого предела ${q(Q)} кг — проверь, нет ли лишнего нуля`),
        ae.length && !P.ovr)
      ) {
        p({
          err: `${f.vehicle_no}: ${ae.join("; ")}. Проверь ввод — или отметь «подтверждаю».`,
        });
        return;
      }
      try {
        (await ue(
          A.from("term_truck_visits")
            .update({
              gross_kg: T,
              gross_at: new Date().toISOString(),
              gross_by: t.id,
              unload_place: P.pl,
              unload_started_at: new Date().toISOString(),
            })
            .eq("id", f.id),
          "машина " + f.vehicle_no,
        ),
          ae.length &&
            (await je(
              "visit",
              f.id,
              "gross_override",
              {
                машина: f.vehicle_no,
                брутто: T,
                продавлено: ae,
              },
              t,
            )),
          d((me) => ({
            ...me,
            [f.id]: {},
          })),
          p({
            ok: `${f.vehicle_no}: брутто ${q(T)} — статус «Выгрузка» (${P.pl})`,
          }),
          o());
      } catch (me) {
        p({
          err: String(me.message || me),
        });
      }
    },
    E = async (f) => {
      const P = g[f.id] || {},
        T = te(P.kg);
      if (!T || T <= 0) {
        p({
          err: "Введи тару, кг",
        });
        return;
      }
      if (f.gross_kg != null && T >= +f.gross_kg) {
        p({
          err: `${f.vehicle_no}: тара (${q(T)}) не может быть больше или равна брутто (${q(f.gross_kg)})`,
        });
        return;
      }
      if (!f.ts_at && $t()) {
        p({
          err: `${f.vehicle_no}: перевалка ещё не отметила оказание услуги. Тара снимается после выгрузки и услуги — попроси перевалку отметить машину в своём окне, иначе услуга не попадёт в счёт.`,
        });
        return;
      }
      const H = Oe(F, "truck_tare_min"),
        Q = Oe(F, "truck_tare_max"),
        ae = [];
      (T < H && ae.push(`тара ${q(T)} кг ниже ожидаемой (порожний зерновоз обычно 10 000–20 000 кг)`),
        T > Q && ae.push(`тара ${q(T)} кг выше допустимого предела ${q(Q)} кг`));
      const me = f.gross_kg != null ? I(f, +f.gross_kg - T) : null;
      if ((me && ae.push(me), ae.length && !P.ovr)) {
        p({
          err: `${f.vehicle_no}: ${ae.join("; ")}. Проверь ввод — или отметь «подтверждаю».`,
        });
        return;
      }
      try {
        const L = new Date().toISOString(),
          W = !f.ts_at && !$t();
        (await ue(
          A.from("term_truck_visits")
            .update({
              tare_kg: T,
              tare_at: L,
              tare_by: t.id,
              unload_at: f.unload_at || L,
              unload_by: f.unload_by || t.id,
              ...(W
                ? {
                    ts_at: L,
                    ts_by: t.id,
                    ts_service: Le[f.lab_result1] || null,
                  }
                : {}),
            })
            .eq("id", f.id),
          "машина " + f.vehicle_no,
        ),
          W &&
            (await je(
              "visit",
              f.id,
              "ts_auto",
              {
                машина: f.vehicle_no,
                услуга: Le[f.lab_result1] || "—",
                причина: "перевалка выведена из процесса настройкой",
              },
              t,
            )),
          ae.length &&
            (await je(
              "visit",
              f.id,
              "tare_override",
              {
                машина: f.vehicle_no,
                тара: T,
                продавлено: ae,
              },
              t,
            )),
          d((K) => ({
            ...K,
            [f.id]: {},
          })),
          p({
            ok: `${f.vehicle_no}: тара ${q(T)} — нетто ${q((+f.gross_kg || 0) - T)} кг, статус «К выезду»`,
          }),
          o(),
          j());
      } catch (L) {
        p({
          err: String(L.message || L),
        });
      }
    },
    a = async (f, P) => {
      if (window.confirm(`Снять ${P === "gross" ? "брутто" : "тару"} у ${f.vehicle_no}? Значение будет очищено, машина вернётся на предыдущий шаг.`))
        try {
          const T =
            P === "gross"
              ? {
                  gross_kg: null,
                  gross_at: null,
                  gross_by: null,
                  unload_started_at: null,
                }
              : {
                  tare_kg: null,
                  tare_at: null,
                  tare_by: null,
                };
          (await ue(A.from("term_truck_visits").update(T).eq("id", f.id), "машина " + f.vehicle_no),
            await je(
              "visit",
              f.id,
              P === "gross" ? "gross_undo" : "tare_undo",
              {
                машина: f.vehicle_no,
              },
              t,
            ),
            p({
              ok: `${f.vehicle_no}: ${P === "gross" ? "брутто" : "тара"} снято`,
            }),
            o(),
            j());
        } catch (T) {
          p({
            err: String(T.message || T),
          });
        }
    };
  return (
    <>
      {_ && (
        <CAt
          title={`Весовая · ${_.vehicle_no} · правка весов`}
          fields={Dr}
          row={_}
          table="term_truck_visits"
          onClose={() => h(null)}
          onDone={() => {
            (p({
              ok: "Изменения сохранены — нетто пересчитано",
            }),
              o());
          }}
        />
      )}
      {m.length > 0 && (
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Замесы на весах · {m.length}</h2>
            <button
              className="btn sec sm"
              onClick={() => {
                (o(), j());
              }}
            >
              Обновить
            </button>
          </div>
          <p className="p-sub">
            каждая машина замеса взвешивается отдельно · нетто замеса — сумма по участникам · когда взвешены все, нажми «Замес взвешен» — после этого
            замес можно выбирать при затарке контейнеров
          </p>
          <div
            className="tscroll"
            style={{
              maxHeight: "30vh",
            }}
          >
            <table>
              <thead>
                <tr>
                  <th>Замес</th>
                  <th>Культура</th>
                  <th>Машины</th>
                  <th>Площадка</th>
                  <th className="right">Нетто замеса, кг</th>
                  <th>Готовность</th>
                </tr>
              </thead>
              <tbody>
                {m.map((f) => (
                  <tr
                    className="rowc"
                    title="Карточка замеса"
                    onClick={(P) => {
                      lt(P) && i(f.id);
                    }}
                  >
                    <td>
                      <b>{f.mix_no}</b>
                    </td>
                    <td>{f.culture || "—"}</td>
                    <td
                      style={{
                        maxWidth: 300,
                        whiteSpace: "normal",
                      }}
                    >
                      {f.list.map((P) => `${P.vehicle_no}${P.tare_kg != null ? " ✓" : ""}`).join(", ")}
                    </td>
                    <td>{f.site || "—"}</td>
                    <td className="right">
                      <b>{f.net ? q(f.net) : "—"}</b>
                    </td>
                    <td className="nowrap">
                      {(() => {
                        const P = U[f.id] || {
                          n: f.list.length,
                          w: f.list.length - f.left,
                        };
                        return P.w < P.n ? (
                          <span className="t2chip">
                            взвешено {P.w} из {P.n}
                          </span>
                        ) : f.status === "weighed" || f.status === "packed" ? (
                          <span className="t2chip ok">{vs(f).t}</span>
                        ) : (
                          <button className="btn sm" onClick={() => Z(f)}>
                            Замес взвешен · к затарке ✓
                          </button>
                        );
                      })()}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}
      {n && <Zt id={n} me={t} onClose={() => s(null)} />}
      {l && <Cs id={l} me={t} onClose={() => i(null)} />}
      <CCr
        me={t}
        rows={(u || []).filter((f) => f.gross_kg == null || f.tare_kg == null)}
        rowLabel={(f) => `${f.vehicle_no} · ${f.gross_kg == null ? "брутто" : "тара"}`}
        onTake={(f, P) =>
          d((T) => ({
            ...T,
            [P.id]: {
              ...(T[P.id] || {}),
              kg: String(f),
            },
          }))
        }
      />
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Взвешивание зерновозов{M ? ` · ${(u || []).length}` : ""}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <button className={"btn sm" + (M ? "" : " sec")} title="Крупные карточки для телефона и планшета" onClick={() => z(!M)}>
              {M ? "☰ Таблица" : "⛶ Карточки"}
            </button>
            <button className="btn sec sm" onClick={o}>
              Обновить
            </button>
          </span>
        </div>
        <CZr sc={C} />
        <p className="p-sub">
          машина взвешивается дважды: <b>брутто</b> — гружёной, сразу после лаборатории, и <b>тара</b> — порожней, после выгрузки и услуги перевалки ·
          брутто + место выгрузки → машина уходит на площадку · тара → нетто считается само → «К выезду» · тару система не примет, пока перевалка не
          отметила услугу · при подключённых весах жми «← с весов» — вес подставится сам · Enter в поле веса = сохранить
        </p>
        <CFe err={x} />
        <CFe {...(w || {})} />
        {M && (
          <div className="wcards">
            {!(u || []).length && (
              <p
                className="p-sub"
                style={{
                  margin: 0,
                }}
              >
                очередь пуста — одобренных машин нет
              </p>
            )}
            {(u || []).map((f) => {
              const P = Ae(f, {
                  need: N(f),
                }),
                T = f.gross_kg == null,
                H = f.gross_kg != null && f.tare_kg == null,
                Q = g[f.id] || {},
                ae = te(Q.kg);
              return (
                <div className="wcard">
                  <div className="wtop" onClick={() => s(f.id)}>
                    <span className="wno">{f.vehicle_no}</span>
                    <span className={"stage " + P.c}>{P.t}</span>
                  </div>
                  <div className="wsub">
                    {f.culture || "—"}
                    {f.planned_tonnes != null ? ` · план ${q(qe(f.planned_tonnes))} кг` : ""}
                    {f.gross_kg != null ? ` · брутто ${q(f.gross_kg)}` : ""}
                    {f.tare_kg != null ? ` · тара ${q(f.tare_kg)} · нетто ${q(f.net_kg)}` : ""}
                    <Gt v={f} small={!0} />
                  </div>
                  {H && !f.ts_at && $t() && <div className="wwarn">перевалка не отметила услугу — тару снять нельзя</div>}
                  {H && !f.ts_at && !$t() && (
                    <div
                      className="faint"
                      style={{
                        fontSize: 10,
                      }}
                    >
                      перевалка вне процесса — услуга отметится сама
                    </div>
                  )}
                  {(T || H) && (
                    <>
                      <div className="wrow">
                        <input
                          className="g-in wbig"
                          inputMode="numeric"
                          placeholder={T ? "брутто, кг" : "тара, кг"}
                          value={Q.kg ?? ""}
                          onChange={(me) =>
                            d((L) => ({
                              ...L,
                              [f.id]: {
                                ...(L[f.id] || {}),
                                kg: me.target.value,
                              },
                            }))
                          }
                          onKeyDown={(me) => {
                            me.key === "Enter" && (T ? D(f) : E(f));
                          }}
                        />
                        {C.on && (
                          <button className="btn sec big" disabled={!C.w9 || !C.w9.stable} onClick={() => $(f.id)}>
                            ← с весов
                          </button>
                        )}
                      </div>
                      {T && (
                        <div className="wrow">
                          <CPe
                            value={Q.pl || ""}
                            onChange={(me) =>
                              d((L) => ({
                                ...L,
                                [f.id]: {
                                  ...(L[f.id] || {}),
                                  pl: me,
                                },
                              }))
                            }
                            options={As}
                            w={230}
                            ph="место выгрузки"
                          />
                        </div>
                      )}
                      {(() => {
                        if (!ae) return null;
                        if (T) {
                          const K = Oe(F, "truck_gross_max"),
                            le = Oe(F, "truck_gross_min");
                          return (
                            <div className={"liveh" + (ae > K || ae < le ? " bad" : "")}>
                              {ae > K ? `выше предела ${q(K)} кг` : ae < le ? `ниже ожидаемого ${q(le)} кг` : `брутто ${q(ae)} кг`}
                            </div>
                          );
                        }
                        const me = (+f.gross_kg || 0) - ae,
                          L = qe(f.planned_tonnes),
                          W = L ? Math.round(((me - L) / L) * 100) : null;
                        return (
                          <div className={"liveh" + (me <= 0 || (W != null && Math.abs(W) > Oe(F, "plan_dev_pct")) ? " bad" : "")}>
                            нетто {q(me)} кг{L ? ` · план ${q(L)} кг (${W >= 0 ? "+" : ""}${W}%)` : ""}
                          </div>
                        );
                      })()}
                      <div className="wrow">
                        <button
                          className="btn big"
                          style={{
                            flex: 1,
                          }}
                          onClick={() => (T ? D(f) : E(f))}
                        >
                          {T ? "Брутто ✓" : "Тара ✓"}
                        </button>
                        <label className="fkey">
                          <input
                            type="checkbox"
                            checked={!!Q.ovr}
                            onChange={(me) =>
                              d((L) => ({
                                ...L,
                                [f.id]: {
                                  ...(L[f.id] || {}),
                                  ovr: me.target.checked,
                                },
                              }))
                            }
                          />{" "}
                          подтверждаю
                        </label>
                      </div>
                    </>
                  )}
                  {!T && !H && <div className="wsub faint">готово · выгрузка: {f.unload_place || "—"}</div>}
                </div>
              );
            })}
          </div>
        )}
        {!M && (
          <div className="tscroll tight9">
            <table>
              <thead>
                <tr>
                  <th>Машина</th>
                  <th>Культура</th>
                  <th>Лаборатория</th>
                  <th>Замес</th>
                  <th>Статус</th>
                  <th className="right">План</th>
                  <th className="right">Брутто</th>
                  <th className="right">Тара</th>
                  <th className="right">Нетто</th>
                  <th>Действие</th>
                </tr>
              </thead>
              <tbody>
                {(u || []).map((f, P) => {
                  var ae, me;
                  const T = Ae(f, {
                      need: N(f),
                    }),
                    H = f.gross_kg == null,
                    Q = f.gross_kg != null && f.tare_kg == null;
                  return (
                    <tr
                      className="rowc"
                      title="Карточка машины"
                      onClick={(L) => {
                        lt(L) && s(f.id);
                      }}
                    >
                      <td>
                        <b>{f.vehicle_no}</b>
                        {!f.ts_at && f.gross_kg != null && $t() ? (
                          <div
                            className="faint"
                            style={{
                              fontSize: 10,
                              color: "var(--warn)",
                            }}
                          >
                            перевалка не отметила услугу — тару снять нельзя
                          </div>
                        ) : null}
                        {T.k === "ts_extra" ? (
                          <div
                            className="faint"
                            style={{
                              fontSize: 10,
                              color: "var(--warn)",
                            }}
                          >
                            не отмечены:{" "}
                            {N(f)
                              .filter((L) => !(f.extra_done || []).includes(L))
                              .join(", ")}
                          </div>
                        ) : null}
                      </td>
                      <td>{f.culture || "—"}</td>
                      <td>{f.lab_result1 ? Le[f.lab_result1] : "—"}</td>
                      <td>
                        <Gt v={f} dash={!0} />
                      </td>
                      <td>
                        <span className={"stage " + T.c}>{T.t}</span>
                      </td>
                      <td className="right faint">{f.planned_tonnes != null ? q(qe(f.planned_tonnes)) : "—"}</td>
                      <td className="right">{q(f.gross_kg)}</td>
                      <td className="right">{q(f.tare_kg)}</td>
                      <td className="right">
                        <b>{q(f.net_kg)}</b>
                      </td>
                      <td className="nowrap">
                        <span
                          className="row"
                          style={{
                            gap: 6,
                          }}
                        >
                          {H && (
                            <>
                              <input
                                className="g-in big9"
                                style={{
                                  width: 110,
                                }}
                                inputMode="numeric"
                                placeholder="брутто, кг"
                                autoFocus={P === 0}
                                value={(g[f.id] || {}).kg ?? ""}
                                onChange={(L) =>
                                  d((W) => ({
                                    ...W,
                                    [f.id]: {
                                      ...(W[f.id] || {}),
                                      kg: L.target.value,
                                    },
                                  }))
                                }
                                onKeyDown={(L) => {
                                  L.key === "Enter" && D(f);
                                }}
                              />
                              {C.on && (
                                <button
                                  className="btn sec sm"
                                  title={(ae = C.w9) != null && ae.stable ? `Взять с весов: ${q(C.w9.weight)} кг` : "Вес ещё не устойчив"}
                                  disabled={!C.w9 || !C.w9.stable}
                                  onClick={() => $(f.id)}
                                >
                                  ← с весов
                                </button>
                              )}
                              <CPe
                                value={(g[f.id] || {}).pl || ""}
                                onChange={(L) =>
                                  d((W) => ({
                                    ...W,
                                    [f.id]: {
                                      ...(W[f.id] || {}),
                                      pl: L,
                                    },
                                  }))
                                }
                                options={As}
                                w={150}
                                ph="место выгрузки"
                              />
                              <button className="btn sm" onClick={() => D(f)}>
                                Брутто
                              </button>
                            </>
                          )}
                          {Q && (
                            <>
                              <input
                                className="g-in big9"
                                style={{
                                  width: 110,
                                }}
                                inputMode="numeric"
                                placeholder="тара, кг"
                                autoFocus={P === 0}
                                value={(g[f.id] || {}).kg ?? ""}
                                onChange={(L) =>
                                  d((W) => ({
                                    ...W,
                                    [f.id]: {
                                      ...(W[f.id] || {}),
                                      kg: L.target.value,
                                    },
                                  }))
                                }
                                onKeyDown={(L) => {
                                  L.key === "Enter" && E(f);
                                }}
                              />
                              {C.on && (
                                <button
                                  className="btn sec sm"
                                  title={(me = C.w9) != null && me.stable ? `Взять с весов: ${q(C.w9.weight)} кг` : "Вес ещё не устойчив"}
                                  disabled={!C.w9 || !C.w9.stable}
                                  onClick={() => $(f.id)}
                                >
                                  ← с весов
                                </button>
                              )}
                              <button className="btn sm" onClick={() => E(f)}>
                                Тара
                              </button>
                              {y && (
                                <button className="btn sec sm" title="Снять брутто" onClick={() => a(f, "gross")}>
                                  ✕ брутто
                                </button>
                              )}
                            </>
                          )}
                          {(() => {
                            const L = te((g[f.id] || {}).kg);
                            if (!L) return null;
                            if (H) {
                              const $e = Oe(F, "truck_gross_max"),
                                ee = Oe(F, "truck_gross_min");
                              return (
                                <div className={"liveh" + (L > $e || L < ee ? " bad" : "")}>
                                  {L > $e ? `выше предела ${q($e)} кг` : L < ee ? `ниже ожидаемого ${q(ee)} кг` : `брутто ${q(L)} кг`}
                                </div>
                              );
                            }
                            const W = (+f.gross_kg || 0) - L,
                              K = qe(f.planned_tonnes),
                              le = K ? Math.round(((W - K) / K) * 100) : null;
                            return (
                              <div className={"liveh" + (W <= 0 || (le != null && Math.abs(le) > Oe(F, "plan_dev_pct")) ? " bad" : "")}>
                                нетто {q(W)} кг{K ? ` · план ${q(K)} кг (${le >= 0 ? "+" : ""}${le}%)` : ""}
                              </div>
                            );
                          })()}
                          {!H && !Q && (
                            <>
                              <span className="faint">готово · выгрузка: {f.unload_place || "—"}</span>
                              {y && (
                                <button className="btn sec sm" title="Снять тару" onClick={() => a(f, "tare")}>
                                  ✕ тара
                                </button>
                              )}
                            </>
                          )}
                          {(H || Q) && (
                            <label
                              className="fkey"
                              style={{
                                fontSize: 10,
                                marginTop: 2,
                              }}
                            >
                              <input
                                type="checkbox"
                                checked={!!(g[f.id] || {}).ovr}
                                onChange={(L) =>
                                  d((W) => ({
                                    ...W,
                                    [f.id]: {
                                      ...(W[f.id] || {}),
                                      ovr: L.target.checked,
                                    },
                                  }))
                                }
                              />{" "}
                              подтверждаю
                            </label>
                          )}{" "}
                          <Ye onClick={() => h(f)} />
                        </span>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </>
  );
}
function Lr({ me: t }) {
  var ht;
  Nn();
  const [n, s] = S.useState(null),
    [l, i] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("*")
            .is("out_at", null)
            .in("state", ["ready", "to_load", "loaded", "temp"])
            .is("batch_id", null)
            .order("in_at")
            .limit(2e3),
        ),
      [],
      2e4,
    ),
    [u] = ne(
      () =>
        Y(
          A.from("term_orders").select("id, order_no, cargo, load_instruction, term_contracts(term_counterparties(name))").order("id", {
            ascending: !1,
          }),
        ),
      [],
      6e4,
    ),
    [o, x, N] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height, state, cont_tare_kg, max_gross_kg, payload_kg, temp_kg)")
            .order("id", {
              ascending: !1,
            })
            .limit(400),
        ),
      [],
      2e4,
    ),
    [b, j] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height, state, cont_tare_kg, max_gross_kg, payload_kg, temp_kg)")
            .is("gross_kg", null)
            .order("id", {
              ascending: !1,
            })
            .limit(200),
        ),
      [],
      2e4,
    ),
    [g, d] = Te("draft.scale.ld", {}),
    [M, z] = Te("draft.scale.g", {}),
    [_, h] = S.useState(null),
    [w, p] = S.useState(null),
    [F, C] = S.useState(null),
    [y, $] = S.useState(null),
    [m, v] = S.useState(null),
    U = Js(),
    [Z, I] = ne(
      () =>
        Y(
          A.from("term_mixes")
            .select("*")
            .in("status", ["ts_ok", "weighed", "packed"])
            .order("id", {
              ascending: !1,
            })
            .limit(60),
        ),
      [],
      2e4,
    ),
    [D] = ne(() => Y(A.from("term_truck_visits").select("id, vehicle_no, mix_id, net_kg, culture").not("mix_id", "is", null).limit(600)), [], 3e4),
    [E] = ne(() => Y(A.from("term_container_loads").select("id, mix_id, net_kg, net_final_kg").not("mix_id", "is", null).limit(1e3)), [], 3e4),
    a = S.useMemo(
      () =>
        (Z || []).map((B) => {
          const r = (D || []).filter((ie) => ie.mix_id === B.id),
            O = r.reduce((ie, c) => ie + (+c.net_kg || 0), 0) + (+B.temp_kg || 0),
            G = (E || []).filter((ie) => ie.mix_id === B.id).reduce((ie, c) => ie + (+(c.net_final_kg ?? c.net_kg) || 0), 0);
          return {
            ...B,
            machines: r.map((ie) => ie.vehicle_no),
            net: O,
            packed: G,
            left: Math.max(0, O - G),
            ready: r.length > 0 && r.every((ie) => ie.net_kg != null),
          };
        }),
      [Z, D, E],
    ),
    f = () => {
      (i(), x(), j && j(), I && I());
    },
    P = async () => {
      var ge, Me;
      if (!g.cid) {
        v({
          err: "Выбери контейнер (статус «Принят»)",
        });
        return;
      }
      const B = te(g.tare);
      if (!B) {
        v({
          err: "Введи тару: а/т с порожним контейнером, кг",
        });
        return;
      }
      const r = (l || []).find((de) => String(de.id) === String(g.cid)),
        O = Oe(U, "cont_tare_min"),
        G = Oe(U, "cont_tare_max"),
        ie = [];
      (B < O && ie.push(`тара ${q(B)} кг ниже ожидаемой (а/т с порожним контейнером обычно 12 000–22 000 кг)`),
        B > G && ie.push(`тара ${q(B)} кг выше допустимого предела ${q(G)} кг`));
      const c = [
        [!(g.veh || "").trim(), "не указана машина (а/т) — по чьей ходке потом не разобрать"],
        [!g.ord && !g.mix, "не выбрано поручение — затарка не попадёт ни в один контракт"],
        [
          !(g.cult || "").trim() && !g.mix && !((ge = (u || []).find((de) => String(de.id) === String(g.ord))) != null && ge.cargo),
          "не указана культура",
        ],
        [!g.site && !((Me = a.find((de) => String(de.id) === String(g.mix))) != null && Me.site), "не выбрана площадка"],
        [te(g.ctare) == null && (r == null ? void 0 : r.cont_tare_kg) == null, "пустой вес контейнера с таблички — VGM посчитать будет не из чего"],
        [te(g.maxg) == null && (r == null ? void 0 : r.max_gross_kg) == null, "пустой max gross — перегруз система не поймает"],
        [te(g.payl) == null && (r == null ? void 0 : r.payload_kg) == null, "пустой payload — перегруз по нетто система не поймает"],
      ]
        .filter(([de]) => de)
        .map(([, de]) => de);
      ie.push(...c);
      {
        const de = te(g.ctare) ?? ((r == null ? void 0 : r.cont_tare_kg) == null ? null : +r.cont_tare_kg),
          ve = te(g.maxg) ?? ((r == null ? void 0 : r.max_gross_kg) == null ? null : +r.max_gross_kg),
          we = te(g.payl) ?? ((r == null ? void 0 : r.payload_kg) == null ? null : +r.payload_kg);
        (de != null &&
          ve != null &&
          we != null &&
          Math.abs(ve - de - we) > 10 &&
          ie.push(`паспорт не сходится: payload ${q(we)} кг, а max gross минус вес контейнера даёт ${q(ve - de)} кг — сверь с табличкой КБК`),
          ve != null &&
            ![30480, 32500, 34e3].includes(Math.round(ve)) &&
            ie.push(`max gross ${q(ve)} кг — нетиповое значение (обычно 30 480 или 32 500 кг), проверь табличку`),
          de != null && (de < 1500 || de > 5200) && ie.push(`вес контейнера ${q(de)} кг вне разумных границ (1 500–5 200 кг)`),
          we != null && we > 32e3 && ie.push(`payload ${q(we)} кг — больше, чем бывает: проверь, нет ли лишнего нуля`));
      }
      const V = (o || []).find((de) => de.container_id === +g.cid && de.gross_kg == null);
      V && ie.push(`по контейнеру уже есть незакрытая затарка №${V.id} (без брутто) — закрой её или удали`);
      const J = (o || []).filter((de) => de.container_id === +g.cid && de.gross_kg != null);
      if (J.length) {
        const de = J.reduce((ve, we) => ve + (+(we.net_final_kg ?? we.net_kg) || 0), 0);
        ie.push(
          (r == null ? void 0 : r.state) === "temp"
            ? `это времянка, в ней уже ${q(r.temp_kg ?? de)} кг — новая затарка добавится к остатку`
            : `в контейнере уже ${q(de)} кг по ${J.length === 1 ? "затарке" : "затаркам"} №${J.map((ve) => ve.id).join(", ")} — это будет вторая загрузка, вес сложится`,
        );
      }
      if (ie.length && !g.ovr) {
        v({
          err: ie.join("; ") + ". Проверь ввод — или отметь «подтверждаю».",
        });
        return;
      }
      const ce = (u || []).find((de) => String(de.id) === String(g.ord)),
        oe = g.kind === "temp",
        se = a.find((de) => String(de.id) === String(g.mix));
      try {
        await ue(
          A.from("term_container_loads").insert({
            container_id: +g.cid,
            vehicle_no: (g.veh || "").trim().toUpperCase() || null,
            order_name: ce ? ce.order_no : null,
            order_id: ce ? ce.id : null,
            culture: (g.cult || "").trim() || (se == null ? void 0 : se.culture) || ((ce == null ? void 0 : ce.cargo) ?? null),
            tare_kg: B,
            tare_at: new Date().toISOString(),
            tare_by: t.id,
            site: g.site || (se == null ? void 0 : se.site) || null,
            is_temp: oe,
            mix_id: se ? se.id : null,
          }),
          "затарка",
        );
        const de = {
          state: "to_load",
          site: g.site || (se == null ? void 0 : se.site) || (r == null ? void 0 : r.site) || null,
          cargo:
            (g.cult || "").trim() ||
            (se == null ? void 0 : se.culture) ||
            ((ce == null ? void 0 : ce.cargo) ?? null) ||
            (r == null ? void 0 : r.cargo) ||
            null,
        };
        (te(g.ctare) != null && (de.cont_tare_kg = te(g.ctare)),
          te(g.maxg) != null && (de.max_gross_kg = te(g.maxg)),
          te(g.payl) != null && (de.payload_kg = te(g.payl)),
          (te(g.ctare) != null || te(g.maxg) != null || te(g.payl) != null) &&
            ((de.spec_src = "plate"), (de.spec_at = new Date().toISOString()), (de.spec_by = t.id)),
          await ue(A.from("term_line_containers").update(de).eq("id", +g.cid), "контейнер"),
          ie.length &&
            (await je(
              "load",
              +g.cid,
              "tare_override",
              {
                контейнер: r == null ? void 0 : r.container_no,
                тара: B,
                продавлено: ie,
              },
              t,
            )),
          d({}),
          v({
            ok:
              (oe ? "Тара записана — затарка ВО ВРЕМЯНКУ" : "Тара записана, паспорт сохранён — контейнер «Под загрузку»") +
              (se ? ` · замес ${se.mix_no}` : ""),
          }),
          f());
      } catch (de) {
        v({
          err: String(de.message || de),
        });
      }
    },
    T = async (B) => {
      const r = B.term_line_containers || {};
      if (window.confirm(`Удалить незакрытую затарку №${B.id} по контейнеру ${r.container_no || ""}? Контейнер вернётся в статус «Принят».`))
        try {
          (await ue(A.from("term_container_loads").delete().eq("id", B.id), "затарка"),
            B.container_id &&
              (await ue(
                A.from("term_line_containers")
                  .update({
                    state: "ready",
                  })
                  .eq("id", B.container_id),
                "контейнер затарки №" + B.id,
              )),
            await je(
              "load",
              B.id,
              "delete",
              {
                контейнер: r.container_no,
                машина: B.vehicle_no,
              },
              t,
            ),
            v({
              ok: `Затарка №${B.id} удалена, контейнер ${r.container_no || ""} снова «Принят»`,
            }),
            f());
        } catch (O) {
          v({
            err: String(O.message || O),
          });
        }
    },
    H = async (B) => {
      const r = B.term_line_containers || {},
        O = r.temp_kg != null ? Math.round(+r.temp_kg) : null,
        G =
          O > 1
            ? `

ВНИМАНИЕ: по учёту во времянке ещё ${q(O)} кг. Они будут списаны как разобранные — если зерно ушло в замес, сначала проведи забор в замесе.`
            : "";
      if (window.confirm(`Времянка ${r.container_no || ""} разобрана (зерно выбрано)? Контейнер станет «Принят» и снова пойдёт под затарку.${G}`))
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                state: "ready",
                temp_closed_at: new Date().toISOString(),
                cargo: null,
                temp_kg: 0,
              })
              .eq("id", B.container_id),
            "контейнер",
          ),
            await je(
              "container",
              B.container_id,
              "temp_close",
              {
                контейнер: r.container_no,
                затарка: B.id,
                ...(O > 1
                  ? {
                      "списан остаток, кг": O,
                    }
                  : {}),
              },
              t,
            ),
            v({
              ok: `Времянка ${r.container_no || ""} разобрана — контейнер снова «Принят»`,
            }),
            f());
        } catch (ie) {
          v({
            err: String(ie.message || ie),
          });
        }
    },
    [Q, ae] = S.useState(null),
    me = async () => {
      var O;
      const B = ((Q == null ? void 0 : Q.no) || "").trim().toUpperCase();
      if (!/^[A-Z]{4}\d{7}$/.test(B)) {
        v({
          err: "Номер контейнера в формате ABCD1234567",
        });
        return;
      }
      const r = (l || []).find((G) => (G.container_no || "").toUpperCase() === B);
      if (r) {
        v({
          err: `${B} уже в системе — статус «${tt(r, null)}». Выбери его в списке.`,
        });
        return;
      }
      if (!ss(B) && !(Q != null && Q.ovr)) {
        v({
          err: `${B}: не сходится контрольная цифра номера (ISO 6346) — скорее всего опечатка. Проверь или отметь «подтверждаю номер».`,
        });
        return;
      }
      if (!(Q != null && Q.size)) {
        v({
          err: "Укажи тип контейнера",
        });
        return;
      }
      try {
        const G = await ue(
            A.from("term_line_containers")
              .insert({
                container_no: B,
                size: Q.size,
                height: Q.height || null,
                line: (Q.line || "").trim() || null,
                site: Q.site || null,
                state: "ready",
                in_at: new Date().toISOString(),
                in_by: t.id,
                accept_at: new Date().toISOString(),
                off_list: !0,
                added_by_scale: !0,
                notes: "заведён весовой — заезд через КПП и осмотр приёмки не оформлены",
              })
              .select("id"),
            "контейнер",
          ),
          ie = (O = G == null ? void 0 : G[0]) == null ? void 0 : O.id;
        (await je(
          "container",
          ie || null,
          "enter_by_scale",
          {
            контейнер: B,
            тип: `${Q.size}'${Q.height || ""}`,
            линия: (Q.line || "").trim() || null,
          },
          t,
        ),
          ss(B) ||
            (await je(
              "container",
              ie || null,
              "iso_override",
              {
                контейнер: B,
              },
              t,
            )),
          ae(null),
          d((c) => ({
            ...c,
            cid: ie ? String(ie) : c.cid,
            ctare: "",
            maxg: "",
            payl: "",
          })),
          v({
            ok: `${B} заведён и выбран. Передай на КПП — заезд и осмотр по нему не оформлены.`,
          }),
          i());
      } catch (G) {
        v({
          err: /uq_active_container_no|duplicate key/i.test(String(G.message || G)) ? `${B} уже числится на терминале` : String(G.message || G),
        });
      }
    },
    [L, W] = S.useState(""),
    [K, le] = S.useState({}),
    [$e, ee] = S.useState(null),
    re = S.useMemo(() => {
      const B = L.trim().toUpperCase();
      return (l || [])
        .filter((r) => r.state === "temp")
        .filter((r) => !B || `${r.container_no || ""} ${r.cargo || ""} ${r.line || ""}`.toUpperCase().includes(B))
        .sort((r, O) => (+O.temp_kg || 0) - (+r.temp_kg || 0) || String(r.container_no).localeCompare(String(O.container_no)));
    }, [l, L]),
    be = async (B) => {
      const r = K[B.id] || {},
        O = (r.cargo ?? B.cargo ?? "").trim(),
        G = r.kg === void 0 ? (B.temp_kg == null ? null : +B.temp_kg) : te(String(r.kg));
      if (G != null && G < 0) {
        v({
          err: "Остаток не может быть отрицательным",
        });
        return;
      }
      if (!(String(O) === String(B.cargo || "") && String(G ?? "") === String(B.temp_kg == null ? "" : +B.temp_kg)))
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                cargo: O || null,
                temp_kg: G,
              })
              .eq("id", B.id),
            "времянка " + B.container_no,
          ),
            await je(
              "container",
              B.id,
              "temp_fix",
              {
                контейнер: B.container_no,
                культура: O || null,
                "остаток, кг": G,
              },
              t,
            ),
            le((ie) => {
              const c = {
                ...ie,
              };
              return (delete c[B.id], c);
            }),
            v({
              ok: `${B.container_no}: остаток ${G == null ? "не указан" : q(G) + " кг"}${O ? " · " + O : ""}`,
            }),
            i());
        } catch (ie) {
          v({
            err: String(ie.message || ie),
          });
        }
    },
    Ne = async (B) => {
      const r = B.temp_kg != null ? Math.round(+B.temp_kg) : null,
        O =
          r > 1
            ? `

ВНИМАНИЕ: по учёту во времянке ещё ${q(r)} кг. Они будут списаны как разобранные — если зерно ушло в замес, сначала проведи забор в замесе.`
            : "";
      if (window.confirm(`Времянка ${B.container_no} разобрана (зерно выбрано)? Контейнер станет «Принят» и снова пойдёт под затарку.${O}`))
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                state: "ready",
                temp_closed_at: new Date().toISOString(),
                cargo: null,
                temp_kg: 0,
              })
              .eq("id", B.id),
            "контейнер",
          ),
            await je(
              "container",
              B.id,
              "temp_close",
              {
                контейнер: B.container_no,
                ...(r > 1
                  ? {
                      "списан остаток, кг": r,
                    }
                  : {}),
              },
              t,
            ),
            v({
              ok: `Времянка ${B.container_no} разобрана — контейнер снова «Принят»`,
            }),
            i());
        } catch (G) {
          v({
            err: String(G.message || G),
          });
        }
    },
    ze = async (B) => {
      const r = M[B.id] || {},
        O = te(r.kg);
      if (!O) {
        v({
          err: "Введи брутто, кг",
        });
        return;
      }
      if (B.tare_kg != null && O <= +B.tare_kg) {
        v({
          err: `Брутто (${q(O)}) должно быть больше тары (${q(B.tare_kg)})`,
        });
        return;
      }
      const G = B.term_line_containers || {},
        ie = O - (+B.tare_kg || 0),
        c = [],
        V = (o || [])
          .filter((se) => se.container_id === B.container_id && se.id !== B.id && se.gross_kg != null)
          .reduce((se, ge) => se + (+(ge.net_final_kg ?? ge.net_kg) || 0), 0),
        J = ie + V,
        ce = V ? `с учётом прежних затарок (${q(V)} кг) ` : "";
      (G.payload_kg != null &&
        J > +G.payload_kg &&
        c.push(`перегруз: ${ce}нетто ${q(J)} кг больше полезной нагрузки контейнера ${q(G.payload_kg)} кг`),
        G.max_gross_kg != null &&
          G.cont_tare_kg != null &&
          J + +G.cont_tare_kg > +G.max_gross_kg &&
          c.push(`гросс контейнера ${ce}${q(J + +G.cont_tare_kg)} кг выше максимального ${q(G.max_gross_kg)} кг`),
        ["dispatched"].includes(G.state) && c.push("контейнер уже выпущен с терминала"),
        !(r.seal || "").trim() &&
          !B.seal_no &&
          !B.is_temp &&
          c.push("пломба не указана — в акте затарки и справке VGM номер пломбы останется пустым"),
        (G.cont_tare_kg == null || G.max_gross_kg == null) &&
          c.push("у контейнера нет паспортных весов (тара и макс. гросс) — в справке VGM масса брутто не посчитается, а перегруз система не увидит"));
      const oe = a.find((se) => se.id === B.mix_id);
      if ((oe && ie > oe.left + 1 && c.push(`в замесе ${oe.mix_no} осталось ${q(oe.left)} кг, а затариваем ${q(ie)} кг`), c.length && !r.ovr)) {
        v({
          err: c.join("; ") + ". Проверь ввод — или отметь «подтверждаю».",
        });
        return;
      }
      try {
        if (
          (await ue(
            A.from("term_container_loads")
              .update({
                gross_kg: O,
                gross_at: new Date().toISOString(),
                gross_by: t.id,
                load_at: B.load_at || new Date().toISOString(),
                load_by: B.load_by || t.id,
                seal_no: (r.seal || "").trim() || B.seal_no || null,
              })
              .eq("id", B.id),
            "затарка",
          ),
          B.container_id)
        ) {
          const se = {
            state: B.is_temp ? "temp" : "loaded",
          };
          (B.is_temp && (se.temp_kg = (G.temp_kg != null ? +G.temp_kg : 0) + ie),
            (r.seal || "").trim() && (se.seal_no = (r.seal || "").trim()),
            await ue(A.from("term_line_containers").update(se).eq("id", B.container_id), "контейнер"));
        }
        if (oe) {
          const se = oe.packed + ie;
          await ue(
            A.from("term_mixes")
              .update({
                status: se >= oe.net - 1 ? "packed" : "weighed",
                packed_at: se >= oe.net - 1 ? new Date().toISOString() : null,
              })
              .eq("id", oe.id),
            "замес " + oe.mix_no,
          );
        }
        (c.length &&
          (await je(
            "load",
            B.id,
            "gross_override",
            {
              контейнер: G.container_no,
              брутто: O,
              нетто: ie,
              продавлено: c,
            },
            t,
          )),
          z((se) => ({
            ...se,
            [B.id]: {},
          })),
          v({
            ok:
              (B.is_temp ? "Брутто записано — контейнер «Времянка»" : "Брутто записано — контейнер «Гружёный», доступен КПП для выезда") +
              (oe ? ` · замес ${oe.mix_no}: осталось ${q(Math.max(0, oe.left - ie))} кг` : ""),
          }),
          f());
      } catch (se) {
        v({
          err: String(se.message || se),
        });
      }
    },
    Ke = [
      ...(l || []).filter((B) => B.state === "ready"),
      ...(l || [])
        .filter((B) => B.state === "loaded")
        .map((B) => ({
          ...B,
          more9: 1,
        })),
      ...(l || [])
        .filter((B) => B.state === "temp")
        .map((B) => ({
          ...B,
          temp9: 1,
        })),
    ],
    { TH: He, apply: We } = rt(),
    Qe = S.useMemo(() => {
      const B = new Map();
      for (const r of [...(b || []), ...(o || [])]) B.has(r.id) || B.set(r.id, r);
      return [...B.values()].sort((r, O) => O.id - r.id);
    }, [o, b]),
    Ie = We(Qe, {
      no: (B) => {
        var r;
        return (r = B.term_line_containers) == null ? void 0 : r.container_no;
      },
      veh: (B) => B.vehicle_no,
      ord: (B) => B.order_name,
      t: (B) => (B.tare_kg == null ? null : +B.tare_kg),
      g: (B) => (B.gross_kg == null ? null : +B.gross_kg),
      n: (B) => (B.net_kg == null ? null : +B.net_kg),
    });
  return (
    <>
      {_ && (
        <CAt
          title={`Погрузка №${_.id} · правка`}
          fields={Tl}
          row={_}
          table="term_container_loads"
          onClose={() => h(null)}
          onDone={() => {
            (v({
              ok: "Изменения сохранены — нетто пересчитано",
            }),
              f());
          }}
        />
      )}
      {w && <CZi load={w} onClose={() => p(null)} onDone={() => f()} />}
      {n && <CRs id={n} me={t} onClose={() => s(null)} />}
      {F && (
        <Un
          load={F}
          me={t}
          onClose={() => C(null)}
          onDone={() => {
            (v({
              ok: "Дотарка сохранена — нетто финал обновлён",
            }),
              f());
          }}
        />
      )}
      {$e && (
        <Un
          cont={$e}
          me={t}
          onClose={() => ee(null)}
          onDone={() => {
            (v({
              ok: "Операция записана — остаток времянки обновлён",
            }),
              i(),
              f());
          }}
        />
      )}
      {y && (
        <Ri
          c={
            y.term_line_containers
              ? {
                  ...y.term_line_containers,
                  id: y.container_id,
                }
              : {}
          }
          load={y}
          onClose={() => $(null)}
        />
      )}
      <div className="panel">
        <h2 className="p-title">Взвешивание порожнего · начало погрузки</h2>
        <p className="p-sub">
          контейнер со статусом «Принят» · тара = а/т с порожним контейнером · паспорт списывается с таблички контейнера: вес контейнера, max gross,
          payload — система их не угадывает
        </p>
        <div className="row">
          <X label="Контейнер (Принят)">
            <CPe
              value={g.cid || ""}
              onChange={(B) =>
                d((r) => {
                  const O = (l || []).find((G) => String(G.id) === String(B));
                  return {
                    ...r,
                    cid: B,
                    ctare: (O == null ? void 0 : O.cont_tare_kg) ?? "",
                    maxg: (O == null ? void 0 : O.max_gross_kg) ?? "",
                    payl: (O == null ? void 0 : O.payload_kg) ?? "",
                  };
                })
              }
              w={210}
              options={Ke.map((B) => [
                B.id,
                `${B.container_no} · ${B.size}'${B.height}${B.more9 ? " · уже гружён — вторая затарка" : ""}${B.temp9 ? ` · времянка${B.temp_kg != null ? " · остаток " + q(B.temp_kg) + " кг" : ""}` : ""}`,
              ])}
            />
            <button
              className="btn sec sm"
              style={{
                marginTop: 4,
              }}
              title="КПП не успел оформить заезд — завести контейнер прямо здесь"
              onClick={() =>
                ae(
                  Q
                    ? null
                    : {
                        size: "",
                        height: "",
                      },
                )
              }
            >
              {Q ? "▴ свернуть" : "+ контейнера нет в списке"}
            </button>
          </X>
          <X label="Машина (а/т)">
            <input
              style={{
                width: 150,
                minWidth: 150,
              }}
              placeholder="К367ОР"
              list="trucks9"
              value={g.veh ?? ""}
              onChange={(B) =>
                d((r) => ({
                  ...r,
                  veh: De(B.target.value),
                }))
              }
            />
            <CUn />
            {g.veh && qi(g.veh) ? (
              <span
                className="faint"
                style={{
                  fontSize: 10,
                  marginLeft: 6,
                }}
              >
                машина терминала{Bs(g.veh) !== De(g.veh) ? ` · ${Bs(g.veh)}` : ""}
              </span>
            ) : null}
          </X>
          <X label="Поручение">
            <CPe
              value={g.ord || ""}
              onChange={(B) =>
                d((r) => {
                  const O = (u || []).find((G) => String(G.id) === String(B));
                  return {
                    ...r,
                    ord: B,
                    cult: (r.cult || "").trim() ? r.cult : (O == null ? void 0 : O.cargo) || "",
                  };
                })
              }
              w={250}
              options={(u || []).map((B) => {
                var r, O;
                return [B.id, `${(O = (r = B.term_contracts) == null ? void 0 : r.term_counterparties) == null ? void 0 : O.name} · ${B.order_no}`];
              })}
            />
          </X>
          <X label="Культура">
            <Wt
              w={190}
              ph={((ht = (u || []).find((B) => String(B.id) === String(g.ord))) == null ? void 0 : ht.cargo) || "— культура —"}
              options={Fe([...Ft(), ...(u || []).map((B) => B.cargo)])}
              value={g.cult}
              addTitle="Культуры нет в списке"
              addPrompt="Культура:"
              onChange={(B) =>
                d((r) => ({
                  ...r,
                  cult: B,
                }))
              }
            />
          </X>
          <X label="Площадка">
            <CPe
              value={g.site || ""}
              onChange={(B) =>
                d((r) => ({
                  ...r,
                  site: B,
                }))
              }
              options={_t}
              w={130}
              ph="—"
            />
          </X>
          <X label="Назначение">
            <CPe
              value={g.kind || "export"}
              onChange={(B) =>
                d((r) => ({
                  ...r,
                  kind: B,
                }))
              }
              options={[
                ["export", "Экспортная затарка"],
                ["temp", "Времянка (остаток)"],
              ]}
              w={170}
              ph="—"
            />
          </X>
          <X label="Из замеса (если груз из замеса)">
            <CPe
              value={g.mix || ""}
              onChange={(B) =>
                d((r) => {
                  const O = a.find((G) => String(G.id) === String(B));
                  return {
                    ...r,
                    mix: B,
                    cult: (r.cult || "").trim() ? r.cult : (O == null ? void 0 : O.culture) || "",
                    site: r.site || (O == null ? void 0 : O.site) || "",
                  };
                })
              }
              w={260}
              ph="— не из замеса —"
              options={a
                .filter((B) => B.left > 0 || String(g.mix) === String(B.id))
                .map((B) => [B.id, `${B.mix_no} · ${B.culture || "—"} · осталось ${q(B.left)} кг`])}
            />
          </X>
        </div>
        {Q ? (
          <div
            className="row"
            style={{
              marginTop: 8,
              alignItems: "flex-end",
            }}
          >
            <X label="№ контейнера">
              <input
                style={{
                  width: 160,
                  minWidth: 160,
                }}
                placeholder="MSKU1234567"
                value={Q.no ?? ""}
                onChange={(B) =>
                  ae((r) => ({
                    ...r,
                    no: B.target.value.toUpperCase(),
                  }))
                }
                onKeyDown={(B) => {
                  B.key === "Enter" && me();
                }}
              />
            </X>
            <X label="Тип">
              <CPe
                value={Q.size}
                onChange={(B) =>
                  ae((r) => ({
                    ...r,
                    size: B,
                  }))
                }
                options={us}
                w={80}
                ph="—"
              />
            </X>
            <X label="Высота">
              <CPe
                value={Q.height}
                onChange={(B) =>
                  ae((r) => ({
                    ...r,
                    height: B,
                  }))
                }
                options={ms}
                w={80}
                ph="—"
              />
            </X>
            <X label="Линия">
              <It
                kind="line"
                value={Q.line}
                onChange={(B) =>
                  ae((r) => ({
                    ...r,
                    line: B,
                  }))
                }
                w={160}
                me={t}
                ph="—"
              />
            </X>
            <X label="Площадка">
              <CPe
                value={Q.site || ""}
                onChange={(B) =>
                  ae((r) => ({
                    ...r,
                    site: B,
                  }))
                }
                options={_t}
                w={130}
                ph="—"
              />
            </X>
            <button className="btn" onClick={me}>
              Завести и выбрать
            </button>
            <label className="fkey">
              <input
                type="checkbox"
                checked={!!Q.ovr}
                onChange={(B) =>
                  ae((r) => ({
                    ...r,
                    ovr: B.target.checked,
                  }))
                }
              />{" "}
              подтверждаю номер
            </label>
            <span
              className="faint"
              style={{
                fontSize: 10,
                maxWidth: 320,
              }}
            >
              контейнер будет помечен «заведён весовой» — КПП и приёмке видно, что заезд и осмотр по нему не оформлены
            </span>
          </div>
        ) : null}
        {(() => {
          const B = a.find((r) => String(r.id) === String(g.mix));
          return B ? (
            <p className="ordinfo">
              Замес <b>{B.mix_no}</b> · машины: <b>{B.machines.join(", ")}</b> · нетто замеса <b>{q(B.net)}</b> кг · уже затарено <b>{q(B.packed)}</b>{" "}
              кг · осталось <b>{q(B.left)}</b> кг{B.ready ? "" : " · ⚠ не все машины замеса взвешены"}
            </p>
          ) : null;
        })()}
        {(() => {
          const B = (u || []).find((r) => String(r.id) === String(g.ord));
          return B != null && B.load_instruction ? (
            <p className="ordinfo">
              Инструкция на затарку · {B.order_no}: <b>{B.load_instruction}</b>
            </p>
          ) : null;
        })()}
        <div
          className="row"
          style={{
            marginTop: 10,
          }}
        >
          <X label="Тара (а/т + конт.), кг">{Se(g, d, "tare", "", 120)}</X>
          <X label="Вес контейнера (табличка), кг">
            {Se(g, d, "ctare", "", 120)}
            {(() => {
              const B = (l || []).find((O) => String(O.id) === String(g.cid)),
                r = B ? Ar[((B.size || "") + (B.height || "")).toUpperCase()] : null;
              return r && B && B.cont_tare_kg == null ? (
                <span
                  className="faint"
                  style={{
                    fontSize: 10,
                  }}
                >
                  у {B.size}'{B.height} обычно {q(r.tare)} — спиши с таблички
                </span>
              ) : null;
            })()}
          </X>
          <X label="Max gross, кг">{Se(g, d, "maxg", "", 110)}</X>
          <X label="Payload, кг">
            {Se(g, d, "payl", "", 110)}
            {(() => {
              const B = te(g.ctare),
                r = te(g.maxg);
              return B != null && r != null && te(g.payl) == null ? (
                <button
                  className="btn sec sm"
                  style={{
                    marginTop: 4,
                  }}
                  title="max gross минус вес контейнера"
                  onClick={() =>
                    d((O) => ({
                      ...O,
                      payl: String(Math.round(r - B)),
                    }))
                  }
                >
                  = {q(r - B)}
                </button>
              ) : null;
            })()}
          </X>
          <button className="btn" onClick={P}>
            Тара ✓ → Под загрузку
          </button>
          <label className="fkey">
            <input
              type="checkbox"
              checked={!!g.ovr}
              onChange={(B) =>
                d((r) => ({
                  ...r,
                  ovr: B.target.checked,
                }))
              }
            />{" "}
            подтверждаю отклонение
          </label>
        </div>
        {(() => {
          const B = (l || []).find((O) => String(O.id) === String(g.cid));
          return !B || !(B.cont_tare_kg != null || B.max_gross_kg != null || B.payload_kg != null) ? null : B.spec_src === "plate" ? (
            <p
              className="p-sub"
              style={{
                margin: "8px 0 0",
              }}
            >
              паспорт {B.container_no} списан с таблички {B.spec_at ? `· ${he(B.spec_at)}` : ""} — если цифры разошлись, перепиши их здесь
            </p>
          ) : (
            <p
              className="p-sub"
              style={{
                margin: "8px 0 0",
                color: "var(--warn)",
              }}
            >
              ⚠ веса {B.container_no} в системе <b>не подтверждены табличкой КБК</b>: их вписали раньше без указания источника. Сверь с табличкой и
              перепиши — тогда система запомнит, что паспорт настоящий.
            </p>
          );
        })()}
        <CFe {...(m || {})} />
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Взвешивание гружёного · после перетарки</h2>
          <button className="btn sec sm" onClick={f}>
            Обновить
          </button>
        </div>
        <p className="p-sub">
          брутто = а/т с гружёным контейнером · нетто считается автоматически · «нетто финал» — сколько в контейнере сейчас, с учётом дотарок и
          растарок · пломба фиксируется здесь · ✎ — исправить вбитое
        </p>
        <CFe err={N} />
        <div className="tscroll tight9 pin9">
          <table>
            <thead>
              <tr>
                <He k="no">Контейнер</He>
                <He k="veh">Машина</He>
                <He k="ord">Поручение</He>
                <th>Замес</th>
                <He k="t" right={!0}>
                  Тара
                </He>
                <He k="g" right={!0}>
                  Брутто
                </He>
                <He k="n" right={!0}>
                  Нетто
                </He>
                <th className="right">Дотарка / растарка</th>
                <th className="right">Нетто финал</th>
                <th className="right">Payload</th>
                <th>Действие</th>
              </tr>
            </thead>
            <tbody>
              {Ie.map((B) => {
                const r = B.term_line_containers || {},
                  O = B.net_kg != null && r.payload_kg != null && +B.net_kg > +r.payload_kg;
                return (
                  <tr
                    className="rowc"
                    title="Карточка затарки"
                    onClick={(G) => {
                      lt(G) && s(B.id);
                    }}
                  >
                    <td>
                      <b>{r.container_no || "—"}</b>
                      <span className="faint"> {r.size ? `${r.size}'${r.height || ""}` : ""}</span>
                      {B.is_temp ? (
                        <span
                          className="stage st-arrived"
                          style={{
                            marginLeft: 6,
                          }}
                        >
                          Времянка{r.state === "temp" && r.temp_kg != null && +r.temp_kg > 0 ? ` · остаток ${q(Math.round(+r.temp_kg))} кг` : ""}
                        </span>
                      ) : null}
                    </td>
                    <td>
                      <CXt v={B.vehicle_no} />
                    </td>
                    <td>{B.order_name || "—"}</td>
                    <td>
                      {B.mix_id ? (
                        <span className="mixtag sm">Замес {(a.find((G) => G.id === B.mix_id) || {}).mix_no || B.mix_id}</span>
                      ) : (
                        <span className="faint">—</span>
                      )}
                    </td>
                    <td className="right">{q(B.tare_kg)}</td>
                    <td className="right">{q(B.gross_kg)}</td>
                    <td
                      className="right"
                      style={
                        O
                          ? {
                              color: "var(--bad)",
                              fontWeight: 700,
                            }
                          : {
                              fontWeight: 700,
                            }
                      }
                    >
                      {q(B.net_kg)}
                      {O ? " ⚠" : ""}
                    </td>
                    <td className="right">
                      {B.dotare_kg == null || +B.dotare_kg == 0 ? (
                        <span className="faint">—</span>
                      ) : (
                        <b
                          style={{
                            color: +B.dotare_kg < 0 ? "var(--bad)" : "var(--good)",
                          }}
                        >
                          {(+B.dotare_kg > 0 ? "+" : "") + q(B.dotare_kg)}
                        </b>
                      )}
                    </td>
                    <td className="right">
                      <b>{q(B.net_final_kg ?? B.net_kg)}</b>
                    </td>
                    <td className="right">{q(r.payload_kg)}</td>
                    <td className="nowrap">
                      <span
                        className="row"
                        style={{
                          gap: 6,
                        }}
                      >
                        {B.gross_kg == null ? (
                          <>
                            {is(M, z, B.id, "kg", "брутто, кг", 90)}
                            {is(M, z, B.id, "seal", "пломба", 100)}
                            <button className="btn sm" onClick={() => ze(B)}>
                              Брутто
                            </button>
                            <button
                              className="btn danger sm icon"
                              title="Удалить незакрытую затарку — контейнер вернётся в «Принят»"
                              onClick={() => T(B)}
                            >
                              ✕
                            </button>
                            <label
                              className="fkey"
                              style={{
                                fontSize: 10,
                              }}
                            >
                              <input
                                type="checkbox"
                                checked={!!(M[B.id] || {}).ovr}
                                onChange={(G) =>
                                  z((ie) => ({
                                    ...ie,
                                    [B.id]: {
                                      ...(ie[B.id] || {}),
                                      ovr: G.target.checked,
                                    },
                                  }))
                                }
                              />{" "}
                              подтверждаю
                            </label>
                          </>
                        ) : (
                          <>
                            <button className="btn sec sm" title="Распределение по контрактам продажи" onClick={() => p(B)}>
                              Партии
                            </button>
                            <button
                              className="btn sec sm"
                              title="Досыпали в контейнер или забрали из него — вес считается по двум взвешиваниям машины"
                              onClick={() => C(B)}
                            >
                              Дотарка / растарка
                            </button>
                            {B.is_temp && (B.term_line_containers || {}).state === "temp" && (
                              <button className="btn sec sm" title="Времянка разобрана — освободить контейнер" onClick={() => H(B)}>
                                Времянка разобрана
                              </button>
                            )}
                            {!B.is_temp && (
                              <button className="btn sec sm" title="Справка VGM (PDF)" onClick={() => $(B)}>
                                VGM
                              </button>
                            )}
                          </>
                        )}
                        <Ye onClick={() => h(B)} />
                      </span>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Времянки на площадке · {re.length}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <input
              className="srch9"
              style={{
                maxWidth: 220,
              }}
              placeholder="Поиск: контейнер, культура, линия…"
              value={L}
              onChange={(B) => W(B.target.value)}
            />
            <button
              className="btn sec sm"
              onClick={() => {
                (i(), f());
              }}
            >
              Обновить
            </button>
          </span>
        </div>
        <p className="p-sub">
          зерно, которое лежит в контейнере на хранении · <b>забрали из контейнера — это растарка, а не затарка</b>: нажми «Дотарка / растарка», вес
          система посчитает по двум взвешиваниям машины · культуру и остаток можно вписать прямо в строке — по старым времянкам их в системе нет ·
          «Разобрана» освобождает контейнер под новую затарку
        </p>
        <div
          className="tscroll tight9"
          style={{
            maxHeight: "44vh",
          }}
        >
          <table>
            <thead>
              <tr>
                <th>Контейнер</th>
                <th>Тип</th>
                <th>Линия</th>
                <th>Культура</th>
                <th className="right">Остаток, кг</th>
                <th className="right">По затаркам</th>
                <th>Площадка</th>
                <th>Действие</th>
              </tr>
            </thead>
            <tbody>
              {re.map((B) => {
                const r = (Qe || []).filter((ie) => ie.container_id === B.id && ie.gross_kg != null),
                  O = r.reduce((ie, c) => ie + (+(c.net_final_kg ?? c.net_kg) || 0), 0),
                  G = K[B.id] || {};
                return (
                  <tr>
                    <td>
                      <b>{B.container_no}</b>
                    </td>
                    <td>{B.size ? `${B.size}'${B.height || ""}` : "—"}</td>
                    <td>{B.line || "—"}</td>
                    <td>
                      <input
                        className="g-in"
                        style={{
                          width: 140,
                        }}
                        list="cults9"
                        placeholder="культура"
                        value={G.cargo ?? B.cargo ?? ""}
                        onChange={(ie) =>
                          le((c) => ({
                            ...c,
                            [B.id]: {
                              ...(c[B.id] || {}),
                              cargo: ie.target.value,
                            },
                          }))
                        }
                        onBlur={() => be(B)}
                        onKeyDown={(ie) => {
                          ie.key === "Enter" && ie.currentTarget.blur();
                        }}
                      />
                    </td>
                    <td className="right">
                      <input
                        className="g-in right"
                        inputMode="numeric"
                        style={{
                          width: 90,
                        }}
                        placeholder="не указан"
                        value={G.kg ?? (B.temp_kg == null ? "" : Math.round(+B.temp_kg))}
                        onChange={(ie) =>
                          le((c) => ({
                            ...c,
                            [B.id]: {
                              ...(c[B.id] || {}),
                              kg: ie.target.value,
                            },
                          }))
                        }
                        onBlur={() => be(B)}
                        onKeyDown={(ie) => {
                          ie.key === "Enter" && ie.currentTarget.blur();
                        }}
                      />
                    </td>
                    <td className="right">
                      {r.length ? <span title={`затарок: ${r.length}`}>{q(O)}</span> : <span className="faint">нет затарок</span>}
                    </td>
                    <td>{B.site || "—"}</td>
                    <td className="nowrap">
                      <span
                        className="row"
                        style={{
                          gap: 6,
                        }}
                      >
                        <button
                          className="btn sec sm"
                          title="Досыпали в контейнер или забрали из него — вес считается по двум взвешиваниям машины"
                          onClick={() => {
                            const ie = r[0];
                            ie ? C(ie) : ee(B);
                          }}
                        >
                          Дотарка / растарка
                        </button>
                        <button className="btn sec sm" title="Времянка разобрана — освободить контейнер" onClick={() => Ne(B)}>
                          Разобрана
                        </button>
                      </span>
                    </td>
                  </tr>
                );
              })}
              {re.length ? null : (
                <tr>
                  <td colSpan={8} className="faint">
                    {L.trim() ? "ничего не найдено" : "времянок на площадке нет"}
                  </td>
                </tr>
              )}
            </tbody>
          </table>
        </div>
        <CJt id="cults9" items={Ft()} />
      </div>
    </>
  );
}
const Yn = [
    "Вмятина двери",
    "Вмятина борта",
    "Вмятина крыши",
    "Дыра в полу",
    "Гнилой пол",
    "Порван уплотнитель",
    "Не закрывается дверь",
    "Погнута петля",
    "Коррозия",
    "Следы влаги внутри",
    "Посторонний запах",
    "Остатки груза",
    "Грязный — нужна мойка",
  ],
  Ar = {
    "20DC": {
      tare: 2250,
      max: 30480,
      pay: 28230,
    },
    "20DV": {
      tare: 2250,
      max: 30480,
      pay: 28230,
    },
    "40DC": {
      tare: 3750,
      max: 30480,
      pay: 26730,
    },
    "40DV": {
      tare: 3750,
      max: 30480,
      pay: 26730,
    },
    "40HC": {
      tare: 3900,
      max: 30480,
      pay: 26580,
    },
    "45HC": {
      tare: 4800,
      max: 32500,
      pay: 27700,
    },
  },
  Br = [
    {
      k: "line",
      t: "Линия",
      w: 180,
      dict: "line",
    },
    {
      k: "site",
      t: "Площадка",
      w: 140,
      opts: _t,
    },
    {
      k: "client",
      t: "Клиент (кому линия выдала)",
      w: 170,
    },
    {
      k: "booking",
      t: "Букинг",
      w: 130,
    },
    {
      k: "cargo",
      t: "Груз",
      w: 200,
      dict: "cargo",
    },
    {
      k: "damage_note",
      t: "Характер повреждений",
      w: 220,
    },
    {
      k: "repair_cost",
      t: "Сумма ремонта, ₽",
      type: "num",
      w: 130,
    },
    {
      k: "surveyor",
      t: "Сюрвейер",
      w: 200,
      dict: "surveyor",
    },
    {
      k: "seal_no",
      t: "Пломба",
      w: 130,
    },
    {
      k: "state",
      t: "Статус",
      w: 170,
      opts: Object.entries(ul),
    },
    {
      k: "cont_tare_kg",
      t: "Вес контейнера, кг",
      type: "num",
      w: 130,
    },
    {
      k: "max_gross_kg",
      t: "Max gross, кг",
      type: "num",
      w: 130,
    },
    {
      k: "payload_kg",
      t: "Payload, кг",
      type: "num",
      w: 130,
    },
    {
      k: "notes",
      t: "Примечания",
      w: 260,
    },
  ];
function Pr({ me: t }) {
  const n = ys(),
    [s, l] = S.useState(null),
    [i, u, o] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("*")
            .is("out_at", null)
            .order("in_at", {
              ascending: !1,
            })
            .limit(2e3),
        ),
      [],
      2e4,
    ),
    [x, N] = Te("draft.acc", {}),
    [b, j] = S.useState(null),
    [g, d] = S.useState(null),
    M = Pt("Поиск: номер, линия, клиент, букинг, груз, площадка, пломба, сюрвейер…"),
    [z, _] = S.useState(null),
    [h, w] = Te("acc.cards", !1),
    p = Fe((i || []).map((D) => D.surveyor)),
    F = async (D, E) => {
      const a = x[D.id] || {},
        f = (a.srv || "").trim() || D.surveyor || null;
      if (E === "ready" && !f) {
        d({
          err: `${D.container_no}: укажи сюрвейера — обязателен при приёме контейнера`,
        });
        return;
      }
      if (f && !p.includes(f)) {
        const T = p.find((H) => H && H.toLowerCase() !== f.toLowerCase() && wn(H.toLowerCase(), f.toLowerCase()) <= 2);
        if (
          T &&
          !window.confirm(`Сюрвейер «${f}» — новый. Похоже на «${T}», который уже есть в списке.

Завести «${f}» как нового?`)
        )
          return;
      }
      const P = (a.dmg || "").trim() || D.damage_note || "";
      if (E === "repair" && !P) {
        d({
          err: `${D.container_no}: опиши характер повреждения — иначе непонятно, за что ремонт`,
        });
        return;
      }
      if (
        !(E === "washing" && !f && !window.confirm(`${D.container_no}: отправить на мойку без указания сюрвейера?`)) &&
        !(D.accept_at && !window.confirm(`${D.container_no} уже осматривали ${he(D.accept_at)}. Переписать результат осмотра?`))
      )
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                accept_at: D.accept_at || new Date().toISOString(),
                accept_by: D.accept_by || t.id,
                reaccept_at: D.accept_at ? new Date().toISOString() : null,
                accept_condition: E === "ready" ? "clean" : E === "washing" ? "washing" : "repair",
                state: E,
                line: (a.line || "").trim() || D.line || null,
                surveyor: f,
                ...(E === "repair"
                  ? {
                      damage_note: P,
                    }
                  : {}),
              })
              .eq("id", D.id),
            "контейнер " + D.container_no,
          ),
            await je(
              "container",
              D.id,
              E === "ready" ? "accept" : "to_repair",
              {
                контейнер: D.container_no,
                сюрвейер: f,
                повреждение: E === "repair" ? P : void 0,
                повторно: !!D.accept_at || void 0,
              },
              t,
            ),
            N((T) => ({
              ...T,
              [D.id]: {},
            })),
            d({
              ok: `${D.container_no}: ${E === "ready" ? `«Принят» · сюрвейер ${f}` : "«Ремонт» · " + P}`,
            }),
            u());
        } catch (T) {
          d({
            err: String(T.message || T),
          });
        }
    },
    C = async (D) => {
      if (window.confirm(`${D.container_no}: вернуть на осмотр? Прошлый результат приёмки (время, сюрвейер, состояние) будет очищен.`))
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                state: "arrived",
                accept_at: null,
                accept_by: null,
                accept_condition: null,
              })
              .eq("id", D.id),
            "контейнер " + D.container_no,
          ),
            await je(
              "container",
              D.id,
              "reinspect",
              {
                контейнер: D.container_no,
              },
              t,
            ),
            d({
              ok: `${D.container_no}: снова в очереди приёмки, нужен осмотр и выбор сюрвейера`,
            }),
            u());
        } catch (E) {
          d({
            err: String(E.message || E),
          });
        }
    },
    y = (i || []).filter((D) => D.state === "arrived"),
    $ = (i || []).filter((D) => D.state === "repair"),
    m = (i || []).filter((D) => D.state === "washing"),
    { TH: CV, apply: U } = rt(),
    Z = (i || []).filter((D) => !["arrived", "repair", "washing"].includes(D.state)),
    I = U(
      Z.filter((D) => !z || Mt(D, n[D.batch_id]).k === z).filter((D) =>
        M.test(D.container_no, D.line, D.client, D.booking, D.cargo, D.site, D.seal_no, D.surveyor, (D.size || "") + (D.height || ""), tt(D, n)),
      ),
      {
        no: (D) => D.container_no,
        tp: (D) => (D.size || "") + (D.height || ""),
        st: (D) => tt(D, n),
        sv: (D) => D.surveyor,
      },
    );
  return (
    (M.enterRef.current = I.length === 1 ? () => l(I[0].id) : null),
    (
      <>
        <CJt id="dl-srv" items={p} />
        {s && <Ht id={s} me={t} onClose={() => l(null)} />}
        {b && (
          <CAt
            title={`Контейнер ${b.container_no} · правка`}
            fields={Br}
            row={b}
            table="term_line_containers"
            onClose={() => j(null)}
            onDone={() => {
              (d({
                ok: "Изменения сохранены",
              }),
                u());
            }}
          />
        )}
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Приёмка порожних · очередь {y.length}</h2>
            <span
              className="row"
              style={{
                gap: 6,
              }}
            >
              <button className={"btn sm" + (h ? "" : " sec")} title="Крупные карточки для телефона" onClick={() => w(!h)}>
                {h ? "☰ Таблица" : "⛶ Карточки"}
              </button>
              <button className="btn sec sm" onClick={u}>
                Обновить
              </button>
            </span>
          </div>
          <p className="p-sub">
            осмотр после заезда через КПП: «Принят» требует сюрвейера (подсказки — из прошлых осмотров) и открывает контейнер весовой · «В ремонт» —
            до возврата на осмотр
          </p>
          <CFe err={o} />
          <CFe {...(g || {})} />
          {h && (
            <div className="wcards">
              {!y.length && (
                <p
                  className="p-sub"
                  style={{
                    margin: 0,
                  }}
                >
                  очередь пуста — все заехавшие приняты
                </p>
              )}
              {y.map((D) => {
                const E = x[D.id] || {};
                return (
                  <div className="wcard">
                    <div className="wtop" onClick={() => l(D.id)}>
                      <span className="wno">{D.container_no}</span>
                      <span className="faint">
                        {D.size ? `${D.size}' ${D.height || ""}` : "—"} · {Ue(D.in_at)}
                      </span>
                    </div>
                    <div className="wsub">
                      {D.line ? `линия ${D.line}` : "линия не указана"}
                      {D.client ? ` · ${D.client}` : ""}
                    </div>
                    <div className="wrow">
                      <X label="Сюрвейер *">
                        <It
                          kind="surveyor"
                          me={t}
                          value={E.srv || D.surveyor || ""}
                          onChange={(a) =>
                            N((f) => ({
                              ...f,
                              [D.id]: {
                                ...(f[D.id] || {}),
                                srv: a,
                              },
                            }))
                          }
                          w={230}
                          ph={D.surveyor || "сюрвейер"}
                        />
                      </X>
                    </div>
                    <div className="wrow">
                      <X label="Линия">
                        <It
                          kind="line"
                          me={t}
                          value={E.line || D.line || ""}
                          onChange={(a) =>
                            N((f) => ({
                              ...f,
                              [D.id]: {
                                ...(f[D.id] || {}),
                                line: a,
                              },
                            }))
                          }
                          w={230}
                          ph={D.line || "линия"}
                        />
                      </X>
                    </div>
                    <div className="wrow">
                      <X label="Повреждение (для ремонта)">
                        <input
                          className="g-in"
                          placeholder={D.damage_note || "характер повреждения"}
                          value={E.dmg || ""}
                          onChange={(a) =>
                            N((f) => ({
                              ...f,
                              [D.id]: {
                                ...(f[D.id] || {}),
                                dmg: a.target.value,
                              },
                            }))
                          }
                        />
                      </X>
                      <CPe
                        value=""
                        w={150}
                        ph="типовое…"
                        options={Yn.map((a) => [a, a])}
                        onChange={(a) =>
                          a &&
                          N((f) => ({
                            ...f,
                            [D.id]: {
                              ...(f[D.id] || {}),
                              dmg: [(f[D.id] || {}).dmg, a].filter(Boolean).join(", "),
                            },
                          }))
                        }
                      />
                    </div>
                    <div className="wrow">
                      <button
                        className="btn big"
                        style={{
                          flex: 1,
                        }}
                        onClick={() => F(D, "ready")}
                      >
                        Принят ✓
                      </button>
                      <button className="btn sec big" onClick={() => F(D, "repair")}>
                        В ремонт
                      </button>
                      <button className="btn sec big" onClick={() => F(D, "washing")}>
                        На мойку
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
          {!h && !y.length && (
            <p
              className="p-sub"
              style={{
                margin: 0,
              }}
            >
              очередь пуста — все заехавшие контейнеры приняты
            </p>
          )}
          {!h && !!y.length && (
            <div className="tscroll">
              <table>
                <thead>
                  <tr>
                    <th>Контейнер</th>
                    <th>Тип</th>
                    <th>Заезд</th>
                    <th>Линия</th>
                    <th>Сюрвейер *</th>
                    <th>Повреждение (для ремонта)</th>
                    <th>Решение</th>
                  </tr>
                </thead>
                <tbody>
                  {y.map((D) => (
                    <tr
                      className="rowc"
                      title="Карточка контейнера"
                      onClick={(E) => {
                        lt(E) && l(D.id);
                      }}
                    >
                      <td>
                        <b>{D.container_no}</b>
                      </td>
                      <td>{D.size ? `${D.size}' ${D.height || ""}` : "—"}</td>
                      <td className="nowrap">{Ue(D.in_at)}</td>
                      <td>
                        <It
                          kind="line"
                          me={t}
                          value={(x[D.id] || {}).line || D.line || ""}
                          onChange={(E) =>
                            N((a) => ({
                              ...a,
                              [D.id]: {
                                ...(a[D.id] || {}),
                                line: E,
                              },
                            }))
                          }
                          w={130}
                          ph={D.line || "линия"}
                        />
                      </td>
                      <td>
                        <It
                          kind="surveyor"
                          me={t}
                          value={(x[D.id] || {}).srv || D.surveyor || ""}
                          onChange={(E) =>
                            N((a) => ({
                              ...a,
                              [D.id]: {
                                ...(a[D.id] || {}),
                                srv: E,
                              },
                            }))
                          }
                          w={150}
                          ph={D.surveyor || "сюрвейер"}
                        />
                      </td>
                      <td>
                        <span
                          className="row"
                          style={{
                            gap: 4,
                          }}
                        >
                          {is(x, N, D.id, "dmg", D.damage_note || "характер повреждения", 150)}
                          <CPe
                            value=""
                            w={130}
                            ph="типовое…"
                            options={Yn.map((E) => [E, E])}
                            onChange={(E) =>
                              E &&
                              N((a) => ({
                                ...a,
                                [D.id]: {
                                  ...(a[D.id] || {}),
                                  dmg: [(a[D.id] || {}).dmg, E].filter(Boolean).join(", "),
                                },
                              }))
                            }
                          />
                        </span>
                      </td>
                      <td className="nowrap">
                        <button className="btn sm" onClick={() => F(D, "ready")}>
                          Принят ✓
                        </button>{" "}
                        <button className="btn sec sm" onClick={() => F(D, "repair")}>
                          В ремонт
                        </button>{" "}
                        <button className="btn sec sm" title="Контейнер грязный — на мойку" onClick={() => F(D, "washing")}>
                          На мойку
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </div>
        {m.length > 0 && (
          <div className="panel">
            <h2 className="p-title">Мойка · {m.length}</h2>
            <p className="p-sub">после мойки принимай контейнер как обычно — укажи сюрвейера и нажми «Принят ✓»</p>
            <div className="tscroll">
              <table>
                <thead>
                  <tr>
                    <th>Контейнер</th>
                    <th>Тип</th>
                    <th>Сюрвейер *</th>
                    <th />
                  </tr>
                </thead>
                <tbody>
                  {m.map((D) => (
                    <tr
                      className="rowc"
                      title="Карточка контейнера"
                      onClick={(E) => {
                        lt(E) && l(D.id);
                      }}
                    >
                      <td>
                        <b>{D.container_no}</b>
                      </td>
                      <td>{D.size ? `${D.size}'${D.height || ""}` : "—"}</td>
                      <td>
                        <input
                          list="dl-srv"
                          style={{
                            background: "var(--panel-2)",
                            border: "1px solid var(--line-2)",
                            borderRadius: 6,
                            color: "var(--text)",
                            font: "inherit",
                            fontSize: 12,
                            padding: "5px 8px",
                            width: 130,
                          }}
                          placeholder={D.surveyor || "сюрвейер"}
                          value={(x[D.id] || {}).srv || ""}
                          onChange={(E) =>
                            N((a) => ({
                              ...a,
                              [D.id]: {
                                ...(a[D.id] || {}),
                                srv: E.target.value,
                              },
                            }))
                          }
                        />
                      </td>
                      <td className="nowrap">
                        <button className="btn sm" onClick={() => F(D, "ready")}>
                          Принят ✓
                        </button>{" "}
                        <button className="btn sec sm" onClick={() => C(D)}>
                          На осмотр
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}
        {$.length > 0 && (
          <div className="panel">
            <h2 className="p-title">Ремонт · {$.length}</h2>
            <p className="p-sub">
              после ремонта: укажи сюрвейера и прими сразу («Принят ✓»), либо верни контейнер в очередь приёмки на повторный осмотр
            </p>
            <div className="tscroll">
              <table>
                <thead>
                  <tr>
                    <th>Контейнер</th>
                    <th>Тип</th>
                    <th>Сюрвейер *</th>
                    <th />
                  </tr>
                </thead>
                <tbody>
                  {$.map((D) => (
                    <tr
                      className="rowc"
                      title="Карточка контейнера"
                      onClick={(E) => {
                        lt(E) && l(D.id);
                      }}
                    >
                      <td>
                        <b>{D.container_no}</b>
                      </td>
                      <td>{D.size ? `${D.size}'${D.height || ""}` : "—"}</td>
                      <td>
                        <input
                          list="dl-srv"
                          style={{
                            background: "var(--panel-2)",
                            border: "1px solid var(--line-2)",
                            borderRadius: 6,
                            color: "var(--text)",
                            font: "inherit",
                            fontSize: 12,
                            padding: "5px 8px",
                            width: 130,
                          }}
                          placeholder={D.surveyor || "сюрвейер"}
                          value={(x[D.id] || {}).srv || ""}
                          onChange={(E) =>
                            N((a) => ({
                              ...a,
                              [D.id]: {
                                ...(a[D.id] || {}),
                                srv: E.target.value,
                              },
                            }))
                          }
                        />
                      </td>
                      <td className="nowrap">
                        <button className="btn sm" onClick={() => F(D, "ready")}>
                          Принят ✓
                        </button>{" "}
                        <button className="btn sec sm" onClick={() => C(D)}>
                          На осмотр
                        </button>{" "}
                        <button className="btn sec sm" title="Повреждения и сумма ремонта" onClick={() => j(D)}>
                          Детали ремонта
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Учёт контейнеров на терминале · {Vt(M, I.length, Z.length)}</h2>
          </div>
          <p className="p-sub">✎ — правка вбитых данных: линия, сюрвейер, пломба, паспорт, статус, примечания</p>
          <div className="findrow">{M.Find}</div>
          <Tt
            val={z}
            onSel={_}
            items={kn
              .map(([D, E]) => ({
                k: D,
                t: E,
                n: Z.filter((a) => Mt(a, n[a.batch_id]).k === D).length,
              }))
              .filter((D) => D.n)}
          />
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <CV k="no">Контейнер</CV>
                  <CV k="tp">Тип</CV>
                  <CV k="st">Статус</CV>
                  <CV k="sv">Сюрвейер</CV>
                  <th>Пломба</th>
                  <th className="right">Payload, кг</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {I.map((D) => (
                  <tr
                    className="rowc"
                    title="Карточка контейнера"
                    onClick={(E) => {
                      lt(E) && l(D.id);
                    }}
                  >
                    <td>
                      <b>{D.container_no}</b>
                    </td>
                    <td>{D.size ? `${D.size}' ${D.height || ""}` : "—"}</td>
                    <td>
                      <Et c={D} bm={n} />
                    </td>
                    <td>{D.surveyor || "—"}</td>
                    <td>{D.seal_no || "—"}</td>
                    <td className="right">{q(D.payload_kg)}</td>
                    <td>
                      <Ye onClick={() => j(D)} />
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </>
    )
  );
}
const Ol = [
    ...Cl,
    {
      k: "lab_status",
      t: "Лаб. решение",
      w: 150,
      opts: [
        ["pending", "В очереди"],
        ["passed", "Одобрен"],
        ["rejected", "Отказ"],
      ],
    },
    {
      k: "lab_result1",
      t: "Результат 1",
      w: 150,
      opts: Object.entries(Le),
    },
    {
      k: "lab_moisture",
      t: "Влажность, %",
      type: "num",
      w: 100,
    },
    {
      k: "lab_impurity",
      t: "Сорность, %",
      type: "num",
      w: 100,
    },
    {
      k: "lab_broken",
      t: "Кол/бит, %",
      type: "num",
      w: 100,
    },
    {
      k: "lab_grain_adm",
      t: "Зерновая, %",
      type: "num",
      w: 100,
    },
    {
      k: "lab_result_text",
      t: "Показатели",
      w: 200,
    },
    {
      k: "gross_kg",
      t: "Брутто, кг",
      type: "num",
      w: 110,
    },
    {
      k: "tare_kg",
      t: "Тара, кг",
      type: "num",
      w: 110,
    },
    {
      k: "unload_place",
      t: "Место выгрузки",
      w: 160,
      opts: As,
    },
    {
      k: "notes",
      t: "Примечания",
      w: 220,
    },
  ],
  Dl = [
    {
      k: "container_no",
      t: "№ контейнера",
      req: 1,
      w: 150,
    },
    {
      k: "size",
      t: "Тип",
      w: 80,
      opts: us,
    },
    {
      k: "height",
      t: "Высота",
      w: 80,
      opts: ms,
    },
    {
      k: "line",
      t: "Линия",
      w: 180,
      dict: "line",
    },
    {
      k: "site",
      t: "Площадка",
      w: 130,
      opts: _t,
    },
    {
      k: "client",
      t: "Клиент линии",
      w: 150,
    },
    {
      k: "booking",
      t: "Букинг",
      w: 130,
    },
    {
      k: "cargo",
      t: "Груз",
      w: 200,
      dict: "cargo",
    },
    {
      k: "damage_note",
      t: "Повреждения",
      w: 190,
    },
    {
      k: "repair_cost",
      t: "Сумма ремонта, ₽",
      type: "num",
      w: 120,
    },
    {
      k: "surveyor",
      t: "Сюрвейер",
      w: 200,
      dict: "surveyor",
    },
    {
      k: "state",
      t: "Статус",
      w: 160,
      opts: Object.entries(ul),
    },
    {
      k: "seal_no",
      t: "Пломба",
      w: 120,
    },
    {
      k: "out_vehicle_no",
      t: "Машина вывоза",
      w: 130,
    },
    {
      k: "cont_tare_kg",
      t: "Вес конт., кг",
      type: "num",
      w: 110,
    },
    {
      k: "max_gross_kg",
      t: "Max gross, кг",
      type: "num",
      w: 120,
    },
    {
      k: "payload_kg",
      t: "Payload, кг",
      type: "num",
      w: 110,
    },
    {
      k: "notes",
      t: "Примечания",
      w: 220,
    },
  ],
  Xe = (t) => (t ? new Date(t).toLocaleString("ru-RU") : ""),
  bs = (t) => (t === "passed" ? "Одобрен" : t === "rejected" ? "Отказ" : "в очереди"),
  ks = (t, n, s = "Зерновозы") => ({
    name: s,
    title: `ФЕНИКС · Терминал — ${s}: полный журнал зерновозов`,
    cols: [
      {
        h: "№",
        w: 7,
        num: 1,
        int: 1,
      },
      {
        h: "Статус",
        w: 16,
      },
      {
        h: "Машина",
        w: 13,
      },
      {
        h: "Прицеп",
        w: 12,
      },
      {
        h: "Организация",
        w: 24,
      },
      {
        h: "Культура",
        w: 13,
      },
      {
        h: "Поставщик",
        w: 20,
      },
      {
        h: "Контракт закуп.",
        w: 15,
      },
      {
        h: "Водитель",
        w: 20,
      },
      {
        h: "Контакт",
        w: 14,
      },
      {
        h: "Вес план, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Заезд",
        w: 16,
      },
      {
        h: "Оформил заезд",
        w: 16,
      },
      {
        h: "Лаборатория",
        w: 12,
      },
      {
        h: "Влаж. %",
        w: 9,
        num: 1,
      },
      {
        h: "Сор %",
        w: 9,
        num: 1,
      },
      {
        h: "Кол/бит %",
        w: 10,
        num: 1,
      },
      {
        h: "Зерн. %",
        w: 9,
        num: 1,
      },
      {
        h: "Показатели",
        w: 22,
      },
      {
        h: "Результат 1",
        w: 14,
      },
      {
        h: "Замес №",
        w: 11,
      },
      {
        h: "Замес с кем",
        w: 24,
      },
      {
        h: "Параметр замеса",
        w: 18,
      },
      {
        h: "Площадка",
        w: 13,
      },
      {
        h: "Услуга перевалки",
        w: 16,
      },
      {
        h: "Доп. услуги оказаны",
        w: 26,
      },
      {
        h: "Прим. лаб.",
        w: 18,
      },
      {
        h: "Лаборант",
        w: 16,
      },
      {
        h: "Брутто, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Время брутто",
        w: 16,
      },
      {
        h: "Весовщик (брутто)",
        w: 16,
      },
      {
        h: "Место выгрузки",
        w: 14,
      },
      {
        h: "Выгрузка",
        w: 16,
      },
      {
        h: "Тара, кг",
        w: 11,
        num: 1,
        int: 1,
      },
      {
        h: "Время тары",
        w: 16,
      },
      {
        h: "Весовщик (тара)",
        w: 16,
      },
      {
        h: "Нетто, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Выезд",
        w: 16,
      },
      {
        h: "Выпустил",
        w: 16,
      },
      {
        h: "Примечания",
        w: 20,
      },
    ],
    rows: t.map((l) => [
      l.id,
      Ae(l).t,
      l.vehicle_no,
      l.trailer_no,
      l.client,
      l.culture,
      l.supplier,
      l.purchase_contract,
      l.driver,
      l.driver_phone,
      qe(l.planned_tonnes),
      Xe(l.in_at),
      n(l.in_by),
      bs(l.lab_status),
      l.lab_moisture,
      l.lab_impurity,
      l.lab_broken,
      l.lab_grain_adm,
      l.lab_result_text,
      l.lab_result1 ? Le[l.lab_result1] : "",
      l.mix_group,
      l.mix_with,
      l.mix_param,
      l.site,
      l.ts_service,
      (l.extra_done || []).join(", "),
      l.lab_notes,
      n(l.lab_by),
      l.gross_kg,
      Xe(l.gross_at),
      n(l.gross_by),
      l.unload_place,
      Xe(l.unload_at),
      l.tare_kg,
      Xe(l.tare_at),
      n(l.tare_by),
      l.net_kg,
      Xe(l.out_at),
      n(l.out_by),
      l.notes,
    ]),
  }),
  ws = (t, n, s, l = "Контейнеры") => ({
    name: l,
    title: `ФЕНИКС · Терминал — ${l}: полный журнал контейнеров линии`,
    cols: [
      {
        h: "№",
        w: 7,
        num: 1,
        int: 1,
      },
      {
        h: "Статус",
        w: 18,
      },
      {
        h: "Контейнер",
        w: 14,
      },
      {
        h: "Тип",
        w: 7,
      },
      {
        h: "Высота",
        w: 9,
      },
      {
        h: "Линия",
        w: 12,
      },
      {
        h: "Букинг",
        w: 13,
      },
      {
        h: "Заезд",
        w: 16,
      },
      {
        h: "Оформил",
        w: 16,
      },
      {
        h: "Осмотр (приёмка)",
        w: 16,
      },
      {
        h: "Принял",
        w: 16,
      },
      {
        h: "Состояние",
        w: 13,
      },
      {
        h: "Вес конт., кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Max gross, кг",
        w: 13,
        num: 1,
        int: 1,
      },
      {
        h: "Payload, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Пломба",
        w: 13,
      },
      {
        h: "Пломба сверена",
        w: 12,
      },
      {
        h: "Машина вывоза",
        w: 14,
      },
      {
        h: "Выезд",
        w: 16,
      },
      {
        h: "Выпустил",
        w: 16,
      },
      {
        h: "Примечания",
        w: 24,
      },
    ],
    rows: t.map((i) => [
      i.id,
      tt(i, s),
      i.container_no,
      i.size,
      i.height,
      i.line,
      i.booking,
      Xe(i.in_at),
      n(i.in_by),
      Xe(i.accept_at),
      n(i.accept_by),
      i.accept_condition === "clean" ? "чистый" : i.accept_condition === "repair" ? "в ремонт" : i.accept_condition,
      i.cont_tare_kg,
      i.max_gross_kg,
      i.payload_kg,
      i.seal_no,
      i.out_at ? (i.seal_checked ? "да" : "нет") : "",
      i.out_vehicle_no,
      Xe(i.out_at),
      n(i.out_by),
      i.notes,
    ]),
  }),
  Ws = (t, n, s = "Погрузки") => ({
    name: s,
    title: `ФЕНИКС · Терминал — ${s}: журнал погрузок (перетарка)`,
    cols: [
      {
        h: "№",
        w: 7,
        num: 1,
        int: 1,
      },
      {
        h: "Контейнер",
        w: 14,
      },
      {
        h: "Тип",
        w: 9,
      },
      {
        h: "Машина (а/т)",
        w: 13,
      },
      {
        h: "Поручение",
        w: 14,
      },
      {
        h: "Культура",
        w: 13,
      },
      {
        h: "Тара, кг",
        w: 11,
        num: 1,
        int: 1,
      },
      {
        h: "Время тары",
        w: 16,
      },
      {
        h: "Тару взвесил",
        w: 16,
      },
      {
        h: "Брутто, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Время брутто",
        w: 16,
      },
      {
        h: "Брутто взвесил",
        w: 16,
      },
      {
        h: "Нетто, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Пломба",
        w: 13,
      },
      {
        h: "Примечания",
        w: 20,
      },
    ],
    rows: t.map((l) => {
      var i, u;
      return [
        l.id,
        (i = l.term_line_containers) == null ? void 0 : i.container_no,
        (u = l.term_line_containers) != null && u.size ? `${l.term_line_containers.size}'${l.term_line_containers.height || ""}` : "",
        l.vehicle_no,
        l.order_name,
        l.culture,
        l.tare_kg,
        Xe(l.tare_at),
        n(l.tare_by),
        l.gross_kg,
        Xe(l.gross_at),
        n(l.gross_by),
        l.net_kg,
        l.seal_no,
        l.notes,
      ];
    }),
  }),
  mn = (t, n) => ({
    name: "Заявки",
    title: "ФЕНИКС · Терминал — Заявки (машины под поручения)",
    cols: [
      {
        h: "№",
        w: 7,
        num: 1,
        int: 1,
      },
      {
        h: "Статус",
        w: 13,
      },
      {
        h: "Организация",
        w: 24,
      },
      {
        h: "Договор",
        w: 13,
      },
      {
        h: "Поручение",
        w: 13,
      },
      {
        h: "Культура",
        w: 13,
      },
      {
        h: "Машина",
        w: 13,
      },
      {
        h: "Прицеп",
        w: 12,
      },
      {
        h: "Вес план, кг",
        w: 12,
        num: 1,
        int: 1,
      },
      {
        h: "Дата прихода",
        w: 12,
      },
      {
        h: "Водитель",
        w: 20,
      },
      {
        h: "Контакт",
        w: 14,
      },
      {
        h: "Контракт закуп.",
        w: 15,
      },
      {
        h: "Поставщик",
        w: 20,
      },
      {
        h: "Создана",
        w: 16,
      },
    ],
    rows: t.map((s) => {
      var l, i, u, o, x, N;
      return [
        s.id,
        et(s).t,
        s.client ||
          ((u = (i = (l = s.term_orders) == null ? void 0 : l.term_contracts) == null ? void 0 : i.term_counterparties) == null ? void 0 : u.name),
        (x = (o = s.term_orders) == null ? void 0 : o.term_contracts) == null ? void 0 : x.contract_no,
        (N = s.term_orders) == null ? void 0 : N.order_no,
        s.culture,
        s.vehicle_no,
        s.trailer_no,
        qe(s.planned_tonnes),
        s.arrive_date,
        s.driver,
        s.driver_phone,
        s.purchase_contract,
        s.supplier,
        Xe(s.created_at),
      ];
    }),
  });
async function Il(t, n) {
  const s = String(n || new Date().getFullYear()),
    l = window.prompt(
      `За какой период выгрузить книгу?

Введи год (например ${s}) или «всё» — за всё время.`,
      s,
    );
  if (l == null) return;
  const i = /^вс[её]$/i.test(l.trim()),
    u = i ? null : parseInt(l, 10) || +s,
    o = 1e4,
    x = (p, F) => (i ? p : p.gte(F, Nt(u)[0]).lt(F, Nt(u)[1])),
    [N, b, j, g, d, M, z] = await Promise.all([
      Y(A.from("term_counterparties").select("*").order("name").limit(o)),
      Y(A.from("term_contracts").select("*, term_counterparties(name)").order("id").limit(o)),
      Y(A.from("term_orders").select("*, term_contracts(contract_no, term_counterparties(name))").order("id").limit(o)),
      Y(
        x(
          A.from("term_requests").select("*, term_orders(order_no, term_contracts(contract_no, term_counterparties(name)))").order("id").limit(o),
          "created_at",
        ),
      ),
      Y(x(A.from("term_truck_visits").select("*").order("id").limit(o), "created_at")),
      Y(x(A.from("term_line_containers").select("*").order("id").limit(o), "created_at")),
      Y(x(A.from("term_container_loads").select("*, term_line_containers(container_no, size, height)").order("id").limit(o), "created_at")),
    ]),
    _ = [
      ["заявки", g],
      ["зерновозы", d],
      ["контейнеры", M],
      ["погрузки", z],
    ]
      .filter(([, p]) => (p || []).length >= o)
      .map(([p]) => p);
  if (
    _.length &&
    !window.confirm(`В выгрузке достигнут предел ${o} строк на лист: ${_.join(", ")}. Часть данных в файл не попадёт.

Выгрузить как есть? Для полной выгрузки возьми период короче.`)
  )
    return;
  const h = await Y(A.from("term_batches").select("id, batch_no, status").limit(5e3)).catch(() => []),
    w = Object.fromEntries((h || []).map((p) => [p.id, p]));
  await Ze(`ФЕНИКС-Терминал_вся-работа_${i ? "за-всё-время" : u}_${new Date().toISOString().slice(0, 10)}`, [
    mn(g),
    ks(d, t),
    ws(M, t, w),
    Ws(z, t),
    {
      name: "Контрагенты",
      title: "ФЕНИКС · Терминал — Контрагенты",
      cols: [
        {
          h: "Наименование",
          w: 30,
        },
        {
          h: "ИНН",
          w: 14,
        },
        {
          h: "ОГРН",
          w: 16,
        },
        {
          h: "Директор",
          w: 22,
        },
        {
          h: "Юр. адрес",
          w: 34,
        },
        {
          h: "Банк",
          w: 24,
        },
        {
          h: "К/с",
          w: 22,
        },
        {
          h: "Р/с",
          w: 22,
        },
        {
          h: "БИК",
          w: 12,
        },
      ],
      rows: N.map((p) => [p.name, p.inn, p.ogrn, p.director, p.legal_address, p.bank_name, p.corr_account, p.settle_account, p.bik]),
    },
    {
      name: "Договоры",
      title: "ФЕНИКС · Терминал — Договоры",
      cols: [
        {
          h: "Организация",
          w: 30,
        },
        {
          h: "Номер",
          w: 16,
        },
        {
          h: "Дата",
          w: 12,
        },
      ],
      rows: b.map((p) => {
        var F;
        return [(F = p.term_counterparties) == null ? void 0 : F.name, p.contract_no, p.contract_date];
      }),
    },
    {
      name: "Поручения",
      title: "ФЕНИКС · Терминал — Поручения",
      cols: [
        {
          h: "Организация",
          w: 26,
        },
        {
          h: "Договор",
          w: 14,
        },
        {
          h: "№ поручения",
          w: 14,
        },
        {
          h: "Груз",
          w: 16,
        },
        {
          h: "ТН ВЭД",
          w: 12,
        },
        {
          h: "Объём, т",
          w: 12,
          num: 1,
        },
        {
          h: "Конт.",
          w: 9,
          num: 1,
          int: 1,
        },
        {
          h: "Тип",
          w: 10,
        },
        {
          h: "Норма, т",
          w: 11,
          num: 1,
        },
        {
          h: "Ставка $/т",
          w: 12,
          num: 1,
        },
        {
          h: "НДС %",
          w: 9,
          num: 1,
          int: 1,
        },
        {
          h: "Ставка до",
          w: 12,
        },
      ],
      rows: j.map((p) => {
        var F, C, y;
        return [
          (C = (F = p.term_contracts) == null ? void 0 : F.term_counterparties) == null ? void 0 : C.name,
          (y = p.term_contracts) == null ? void 0 : y.contract_no,
          p.order_no,
          p.cargo,
          p.tnved,
          p.volume_t,
          p.containers_n,
          p.container_type,
          p.load_norm_t,
          p.rate_per_t,
          p.vat_pct,
          p.rate_valid_until,
        ];
      }),
    },
  ]);
}
function Vr({ day: t, me: n, onClose: s }) {
  const [l, i] = mi(t),
    { W: u } = yt(),
    o = (T) => Y(A.from("term_truck_visits").select("*").gte(T, l).lt(T, i).order(T)),
    [x] = ne(() => o("in_at"), [t], 0),
    [N] = ne(() => o("tare_at"), [t], 0),
    [b] = ne(() => o("out_at"), [t], 0),
    [j] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height, line, booking, client, cont_tare_kg, payload_kg, batch_id)")
            .gte("gross_at", l)
            .lt("gross_at", i)
            .order("gross_at"),
        ),
      [t],
      0,
    ),
    [g] = ne(() => Y(A.from("term_line_containers").select("*").gte("in_at", l).lt("in_at", i).order("in_at")), [t], 0),
    [d] = ne(() => Y(A.from("term_line_containers").select("*").gte("out_at", l).lt("out_at", i).order("out_at")), [t], 0),
    [M] = ne(() => Y(A.from("term_mixes").select("id, mix_no").limit(400)), [], 6e4, "mixno9"),
    z = !x || !N || !b || !j || !g || !d,
    _ = x || [],
    h = N || [],
    w = b || [],
    p = j || [],
    F = g || [],
    C = d || [],
    y = S.useMemo(() => Object.fromEntries((M || []).map((T) => [T.id, T.mix_no])), [M]),
    $ = h.reduce((T, H) => T + (+H.net_kg || 0), 0),
    m = p.reduce((T, H) => T + (+(H.net_final_kg ?? H.net_kg) || 0), 0),
    v = p.reduce((T, H) => T + Math.max(0, +H.dotare_kg || 0), 0),
    U = p.reduce((T, H) => T + Math.max(0, -(+H.dotare_kg || 0)), 0),
    Z = _.filter((T) => T.lab_status === "rejected"),
    I = S.useMemo(() => {
      const T = {};
      return (
        h.forEach((H) => {
          if (H.net_kg) {
            const Q = (H.culture || "").trim() || "без культуры";
            T[Q] = (T[Q] || 0) + +H.net_kg;
          }
        }),
        Object.entries(T).sort((H, Q) => Q[1] - H[1])
      );
    }, [h]),
    D = S.useMemo(() => {
      const T = {};
      return (
        p.forEach((H) => {
          const Q = (H.culture || "").trim() || "без культуры";
          T[Q] = (T[Q] || 0) + (+(H.net_final_kg ?? H.net_kg) || 0);
        }),
        Object.entries(T).sort((H, Q) => Q[1] - H[1])
      );
    }, [p]),
    E = String(t).split("-").reverse().join("."),
    a = st("Отчёт-за-день", E),
    f = () =>
      Ze(`Отчёт_за_день_${t}`, [
        {
          name: "Итог",
          title: `ФЕНИКС · Терминал — работа за ${E}`,
          cols: [
            {
              h: "Показатель",
              w: 46,
            },
            {
              h: "Значение",
              w: 22,
            },
          ],
          rows: [
            ["Дата", E],
            ["Принято зерна, кг нетто", $],
            ["Зерновозов взвешено", h.length],
            ["Зерновозов заехало", _.length],
            ["Зерновозов убыло", w.length],
            ["Отказов лаборатории", Z.length],
            ["Затарено в контейнеры, кг", m],
            ["Затарок", p.length],
            ["в т.ч. дотарено, кг", v],
            ["в т.ч. растарено, кг", U],
            ["Контейнеров заехало", F.length],
            ["Контейнеров выпущено", C.length],
            ...I.map(([T, H]) => [`Принято · ${T}, кг`, H]),
            ...D.map(([T, H]) => [`Затарено · ${T}, кг`, H]),
          ],
        },
        {
          name: "Зерновозы",
          title: `Зерновозы за ${E} (взвешенные порожним — по ним считается тоннаж)`,
          cols: [
            {
              h: "Машина",
              w: 13,
            },
            {
              h: "Организация",
              w: 22,
            },
            {
              h: "Культура",
              w: 15,
            },
            {
              h: "Поставщик",
              w: 20,
            },
            {
              h: "Заезд",
              w: 17,
            },
            {
              h: "Лаб.",
              w: 12,
            },
            {
              h: "Влаж. %",
              w: 9,
              num: 1,
            },
            {
              h: "Сор %",
              w: 9,
              num: 1,
            },
            {
              h: "Кол/бит %",
              w: 10,
              num: 1,
            },
            {
              h: "Путь груза",
              w: 14,
            },
            {
              h: "Замес",
              w: 12,
            },
            {
              h: "Площадка",
              w: 14,
            },
            {
              h: "Брутто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Тара, кг",
              w: 11,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Выезд",
              w: 17,
            },
          ],
          rows: h.map((T) => [
            T.vehicle_no,
            T.client,
            T.culture,
            T.supplier,
            Xe(T.in_at),
            bs(T.lab_status),
            T.lab_moisture,
            T.lab_impurity,
            T.lab_broken,
            T.lab_result1 ? Le[T.lab_result1] : "",
            y[T.mix_id] || "",
            T.site,
            T.gross_kg,
            T.tare_kg,
            T.net_kg,
            Xe(T.out_at),
          ]),
        },
        {
          name: "Затарки",
          title: `Затарка контейнеров за ${E}`,
          cols: [
            {
              h: "Контейнер",
              w: 14,
            },
            {
              h: "Тип",
              w: 8,
            },
            {
              h: "Линия",
              w: 12,
            },
            {
              h: "Букинг",
              w: 16,
            },
            {
              h: "Поручение",
              w: 13,
            },
            {
              h: "Культура",
              w: 15,
            },
            {
              h: "Машина",
              w: 13,
            },
            {
              h: "Тара, кг",
              w: 11,
              num: 1,
              int: 1,
            },
            {
              h: "Брутто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Дотарка/растарка, кг",
              w: 17,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто финал, кг",
              w: 14,
              num: 1,
              int: 1,
            },
            {
              h: "Пломба",
              w: 13,
            },
            {
              h: "Время",
              w: 17,
            },
            {
              h: "Взвесил",
              w: 18,
            },
          ],
          rows: p.map((T) => {
            const H = T.term_line_containers || {};
            return [
              H.container_no,
              H.size ? `${H.size}'${H.height || ""}` : "",
              H.line,
              H.booking,
              T.order_name,
              T.culture,
              T.vehicle_no,
              T.tare_kg,
              T.gross_kg,
              T.net_kg,
              T.dotare_kg,
              T.net_final_kg ?? T.net_kg,
              T.seal_no,
              Xe(T.gross_at),
              u(T.gross_by),
            ];
          }),
        },
        {
          name: "Контейнеры",
          title: `Заезды и выезды контейнеров за ${E}`,
          cols: [
            {
              h: "Событие",
              w: 12,
            },
            {
              h: "Контейнер",
              w: 14,
            },
            {
              h: "Тип",
              w: 8,
            },
            {
              h: "Линия",
              w: 12,
            },
            {
              h: "Букинг",
              w: 16,
            },
            {
              h: "Клиент",
              w: 20,
            },
            {
              h: "Время",
              w: 17,
            },
            {
              h: "Машина",
              w: 14,
            },
            {
              h: "Пломба",
              w: 13,
            },
          ],
          rows: [
            ...F.map((T) => ["заезд", T.container_no, T.size ? `${T.size}'${T.height || ""}` : "", T.line, T.booking, T.client, Xe(T.in_at), "", ""]),
            ...C.map((T) => [
              "выезд",
              T.container_no,
              T.size ? `${T.size}'${T.height || ""}` : "",
              T.line,
              T.booking,
              T.client,
              Xe(T.out_at),
              T.out_vehicle_no,
              T.out_seal_no,
            ]),
          ],
        },
      ]);
  if (z) return <At title={`Работа за ${E}`} onClose={s} />;
  const P = ({ l: T, v: H, s: Q }) => (
    <div className="kpi">
      <div className="l">{T}</div>
      <div className="v">{H}</div>
      <div className="s">{Q}</div>
    </div>
  );
  return (
    <CDt wide={!0} cls="rep9" title={`Работа терминала за ${E}`} onClose={s} file={a}>
      <div className="crep">
        <div
          className="row no-print"
          style={{
            gap: 8,
            marginBottom: 8,
          }}
        >
          <Je make={f} label="⇩ Excel" />
        </div>
        <div
          className="kpis"
          style={{
            marginBottom: 10,
          }}
        >
          <P l="Принято зерна" v={q($)} s={`кг нетто · машин ${h.length}`} />
          <P l="Затарено" v={q(m)} s={`кг · контейнеров ${p.length}`} />
          <P l="Зерновозы" v={`${_.length} / ${w.length}`} s={`заехало / убыло${Z.length ? ` · отказов ${Z.length}` : ""}`} />
          <P l="Контейнеры" v={`${F.length} / ${C.length}`} s="заехало / выпущено" />
        </div>
        {(v > 0 || U > 0) && (
          <p
            className="p-sub"
            style={{
              margin: "0 0 8px",
            }}
          >
            из затаренного: дотарено {q(v)} кг · растарено {q(U)} кг
          </p>
        )}
        <C_e done={I.length > 0} title="Принято по культурам" extra={`${q($)} кг`}>
          <div className="qgrid">
            {I.map(([T, H]) => (
              <div className="qbox">
                <div className="l">{T}</div>
                <div className="v">{q(H)}</div>
                <div className="s">кг нетто</div>
              </div>
            ))}
            {I.length ? null : <span className="faint">в этот день зерно не взвешивали</span>}
          </div>
        </C_e>
        <C_e done={D.length > 0} title="Затарено по культурам" extra={`${q(m)} кг`}>
          <div className="qgrid">
            {D.map(([T, H]) => (
              <div className="qbox">
                <div className="l">{T}</div>
                <div className="v">{q(H)}</div>
                <div className="s">кг в контейнерах</div>
              </div>
            ))}
            {D.length ? null : <span className="faint">в этот день не затаривали</span>}
          </div>
        </C_e>
        <C_e done={h.length > 0} title="Зерновозы · принято" extra={`${h.length} машин · ${q($)} кг`}>
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <th>Машина</th>
                  <th>Организация</th>
                  <th>Культура</th>
                  <th>Заезд</th>
                  <th>Лаб.</th>
                  <th className="right">Влаж.</th>
                  <th className="right">Сор</th>
                  <th className="right">Кол/бит</th>
                  <th>Площадка</th>
                  <th className="right">Брутто</th>
                  <th className="right">Тара</th>
                  <th className="right">Нетто</th>
                </tr>
              </thead>
              <tbody>
                {h.map((T) => (
                  <tr>
                    <td>
                      <b>{T.vehicle_no}</b>
                    </td>
                    <td>{T.client || "—"}</td>
                    <td>{T.culture || "—"}</td>
                    <td className="nowrap">{he(T.in_at)}</td>
                    <td>{bs(T.lab_status)}</td>
                    <td className="right">{T.lab_moisture ?? "—"}</td>
                    <td className="right">{T.lab_impurity ?? "—"}</td>
                    <td className="right">{T.lab_broken ?? "—"}</td>
                    <td>{T.site || "—"}</td>
                    <td className="right">{q(T.gross_kg)}</td>
                    <td className="right">{q(T.tare_kg)}</td>
                    <td className="right">
                      <b>{q(T.net_kg)}</b>
                    </td>
                  </tr>
                ))}
                {h.length ? null : (
                  <tr>
                    <td colSpan={12} className="faint">
                      в этот день машины порожним не взвешивались
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
          {Z.length ? (
            <p
              className="p-sub"
              style={{
                margin: "6px 0 0",
                color: "var(--bad)",
              }}
            >
              отказано лабораторией: {Z.map((T) => T.vehicle_no).join(", ")}
            </p>
          ) : null}
        </C_e>
        <C_e done={p.length > 0} title="Затарка контейнеров" extra={`${p.length} шт · ${q(m)} кг`}>
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <th>Контейнер</th>
                  <th>Тип</th>
                  <th>Линия</th>
                  <th>Букинг</th>
                  <th>Поручение</th>
                  <th>Культура</th>
                  <th>Машина</th>
                  <th className="right">Нетто</th>
                  <th className="right">Дот./раст.</th>
                  <th className="right">Нетто финал</th>
                  <th>Пломба</th>
                  <th>Время</th>
                </tr>
              </thead>
              <tbody>
                {p.map((T) => {
                  const H = T.term_line_containers || {};
                  return (
                    <tr>
                      <td>
                        <b>{H.container_no}</b>
                      </td>
                      <td>{H.size ? `${H.size}'${H.height || ""}` : "—"}</td>
                      <td>{H.line || "—"}</td>
                      <td>{H.booking || "—"}</td>
                      <td>{T.order_name || "—"}</td>
                      <td>{T.culture || "—"}</td>
                      <td>
                        <CXt v={T.vehicle_no} />
                      </td>
                      <td className="right">{q(T.net_kg)}</td>
                      <td className="right">{T.dotare_kg == null || +T.dotare_kg == 0 ? "—" : (+T.dotare_kg > 0 ? "+" : "") + q(T.dotare_kg)}</td>
                      <td className="right">
                        <b>{q(T.net_final_kg ?? T.net_kg)}</b>
                      </td>
                      <td>{T.seal_no || "—"}</td>
                      <td className="nowrap">{Ue(T.gross_at)}</td>
                    </tr>
                  );
                })}
                {p.length ? null : (
                  <tr>
                    <td colSpan={12} className="faint">
                      в этот день контейнеры не затаривали
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </C_e>
        <C_e done={F.length + C.length > 0} title="Контейнеры · заезды и выезды" extra={`${F.length} заехало · ${C.length} выпущено`}>
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <th>Событие</th>
                  <th>Контейнер</th>
                  <th>Тип</th>
                  <th>Линия</th>
                  <th>Букинг</th>
                  <th>Клиент</th>
                  <th>Время</th>
                  <th>Машина вывоза</th>
                  <th>Пломба</th>
                </tr>
              </thead>
              <tbody>
                {F.map((T) => (
                  <tr>
                    <td>
                      <span className="t2chip">заезд</span>
                    </td>
                    <td>
                      <b>{T.container_no}</b>
                    </td>
                    <td>{T.size ? `${T.size}'${T.height || ""}` : "—"}</td>
                    <td>{T.line || "—"}</td>
                    <td>{T.booking || "—"}</td>
                    <td>{T.client || "—"}</td>
                    <td className="nowrap">{Ue(T.in_at)}</td>
                    <td>—</td>
                    <td>—</td>
                  </tr>
                ))}
                {C.map((T) => (
                  <tr>
                    <td>
                      <span className="t2chip ok">выезд</span>
                    </td>
                    <td>
                      <b>{T.container_no}</b>
                    </td>
                    <td>{T.size ? `${T.size}'${T.height || ""}` : "—"}</td>
                    <td>{T.line || "—"}</td>
                    <td>{T.booking || "—"}</td>
                    <td>{T.client || "—"}</td>
                    <td className="nowrap">{Ue(T.out_at)}</td>
                    <td>
                      <CXt v={T.out_vehicle_no} />
                    </td>
                    <td>{T.out_seal_no || "—"}</td>
                  </tr>
                ))}
                {!F.length && !C.length ? (
                  <tr>
                    <td colSpan={9} className="faint">
                      в этот день контейнеры не заезжали и не выпускались
                    </td>
                  </tr>
                ) : null}
              </tbody>
            </table>
          </div>
        </C_e>
        <C_e done={!0} title="Итог дня">
          <div className="dgrid">
            <R l="Принято зерна, кг" v={q($)} />
            <R l="Затарено в контейнеры, кг" v={q(m)} />
            <R l="Разница «принято − затарено», кг" v={q($ - m)} />
            <R l="Зерновозов заехало / убыло" v={`${_.length} / ${w.length}`} />
            <R l="Контейнеров заехало / выпущено" v={`${F.length} / ${C.length}`} />
            <R l="Отчёт составлен" v={he(new Date().toISOString()) + " · " + ((n == null ? void 0 : n.name) || "")} />
          </div>
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
            }}
          >
            тоннаж приёмки признаётся по времени взвешивания порожним, затарка — по времени брутто: так же, как в сводке и остальных отчётах
          </p>
        </C_e>
      </div>
    </CDt>
  );
}
function Hr({ me: t }) {
  const n = ["manager", "chief"].includes(t.role),
    [s, l] = Te("chief.day", Ve()),
    [i, u] = S.useState(null),
    o = String(new Date().getFullYear()),
    x = {
      vis: 2e3,
      cnt: 3e3,
      req: 500,
      load: 500,
    },
    [N, b] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .is("out_at", null)
            .order("id", {
              ascending: !1,
            })
            .limit(x.vis),
        ),
      [],
      3e4,
    ),
    [j, g] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .not("out_at", "is", null)
            .order("id", {
              ascending: !1,
            })
            .limit(500),
        ),
      [],
      3e4,
    ),
    d = S.useMemo(() => (N || j ? [...(N || []), ...(j || [])].sort((k, xe) => xe.id - k.id) : null), [N, j]),
    M = () => {
      (b(), g());
    },
    z =
      "id, container_no, size, height, line, client, booking, cargo, state, batch_id, in_at, out_at, empty_out, out_vehicle_no, seal_no, temp_kg, payload_kg, surveyor, eta_date, added_by_scale",
    [_, h] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select(z)
            .is("out_at", null)
            .order("id", {
              ascending: !1,
            })
            .limit(3e3),
        ),
      [],
      3e4,
    ),
    [w, p] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select(z)
            .not("out_at", "is", null)
            .order("id", {
              ascending: !1,
            })
            .limit(500),
        ),
      [],
      3e4,
    ),
    F = S.useMemo(() => (_ || w ? [...(_ || []), ...(w || [])].sort((k, xe) => xe.id - k.id) : null), [_, w]),
    C = () => {
      (h(), p());
    },
    y = () =>
      Y(
        A.from("term_line_containers")
          .select("*")
          .order("id", {
            ascending: !1,
          })
          .limit(4e3),
      ),
    [$, m] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height)")
            .order("id", {
              ascending: !1,
            })
            .limit(500),
        ),
      [],
      3e4,
    ),
    [v] = ne(
      () =>
        Y(
          A.from("term_requests")
            .select(
              "id, order_id, status, vehicle_no, trailer_no, client, culture, planned_tonnes, arrive_date, driver, driver_phone, supplier, purchase_contract, t2_at, t2_called_at, created_at, deleted_at, term_orders(order_no, cargo, extra_services)",
            )
            .is("deleted_at", null)
            .order("id", {
              ascending: !1,
            })
            .limit(500),
        ),
      [],
      6e4,
    ),
    [U] = ne(() => Y(A.from("term_profiles").select("user_id, display_name, role")), [], 0, "profiles"),
    [Z] = ne(
      () =>
        Y(
          A.from("term_batches")
            .select("*")
            .order("id", {
              ascending: !1,
            })
            .limit(200),
        ),
      [],
      3e4,
    ),
    [I, D] = Te("chief.year", o),
    [E] = ne(
      () =>
        Y(
          A.rpc("term_dash", {
            p_year: +I,
          }),
        ),
      [I],
      12e4,
    ),
    [a, f] = S.useState(null),
    [P, T] = S.useState(null),
    [H, Q] = S.useState(null),
    [ae] = ne(
      () => {
        if (H == null) return Promise.resolve(null);
        const k = new Date(Date.UTC(+I, H, 1));
        k.setUTCHours(k.getUTCHours() - 3);
        const xe = new Date(Date.UTC(+I, H + 1, 1));
        xe.setUTCHours(xe.getUTCHours() - 3);
        const [ke, Ce] = [k.toISOString(), xe.toISOString()];
        return Promise.all([
          Y(
            A.from("term_truck_visits")
              .select(
                "id, vehicle_no, client, culture, in_at, out_at, cancelled_at, lab_status, lab_result1, gross_kg, tare_kg, net_kg, tare_at, ts_at, site, request_id",
              )
              .gte("in_at", ke)
              .lt("in_at", Ce)
              .order("id", {
                ascending: !1,
              })
              .limit(1e3),
          ),
          Y(
            A.from("term_line_containers")
              .select("id, container_no, size, height, in_at, out_at, empty_out, state, seal_no, temp_kg, batch_id, eta_date")
              .gte("in_at", ke)
              .lt("in_at", Ce)
              .order("id", {
                ascending: !1,
              })
              .limit(1e3),
          ),
          Y(
            A.from("term_container_loads")
              .select("id, vehicle_no, order_name, net_kg, net_final_kg, gross_at, term_line_containers(container_no)")
              .gte("gross_at", ke)
              .lt("gross_at", Ce)
              .order("id", {
                ascending: !1,
              })
              .limit(1e3),
          ),
        ]).then(([ye, Re, Ge]) => ({
          mv: ye,
          mc: Re,
          ml: Ge,
        }));
      },
      [H, I],
      6e4,
    ),
    [me, L] = S.useState(null),
    [W, K] = S.useState(!1),
    [le, $e] = S.useState(null),
    ee = S.useMemo(() => Object.fromEntries((U || []).map((k) => [k.user_id, k.display_name])), [U]),
    re = (k) => (k ? ee[k] || "сотрудник" : "—"),
    be = (k) => (k && ee[k]) || "",
    Ne = Ve(),
    ze = d || [],
    Ke = F || [],
    He = $ || [],
    We = v || [],
    Qe = E || {},
    Ie = ze.filter((k) => k.in_at && !k.out_at),
    ht = ze.filter((k) => k.tare_at && Ve(k.tare_at) === Ne).reduce((k, xe) => k + (+xe.net_kg || 0), 0),
    B = He.filter((k) => k.gross_at && Ve(k.gross_at) === Ne),
    r = Ke.filter((k) => !k.out_at),
    O = (k) => q(Math.round(k)),
    G = [
      ["exp", "Ожидаются · в пути"],
      ["t2", "Отстойник (Т2)"],
      ["in", "На терминале · лаборатория"],
      ["lab_ok", "Одобрен · ждёт брутто"],
      ["gross", $t() ? "Выгрузка и перевалка" : "Выгрузка"],
      ...($t() ? [["ts_ok", "Услуга оказана · ждёт тару"]] : []),
      ["tare", "Взвешен порожним · к выезду"],
    ],
    ie = {
      exp: {},
      t2: {},
      in: {},
      lab_ok: {},
      gross: {},
      ts_ok: {},
      tare: {},
    },
    c = new Set(Ie.map((k) => k.request_id).filter(Boolean));
  (We.filter((k) => k.status === "expected" && !k.deleted_at && !c.has(k.id)).forEach((k) => {
    const xe = (k.culture || "").trim() || "Без культуры",
      ke = k.t2_at ? ie.t2 : ie.exp,
      Ce = (ke[xe] = ke[xe] || {
        n: 0,
        kg: 0,
        rows: [],
      }),
      ye = (+k.planned_tonnes || 0) * 1e3;
    (Ce.n++,
      (Ce.kg += ye),
      Ce.rows.push({
        id: null,
        reqId: k.id,
        veh: k.vehicle_no + (k.t2_called_at ? " · вызван" : ""),
        kg: ye,
      }));
  }),
    Ie.forEach((k) => {
      const xe = Ae(k).c;
      if (!ie[xe]) return;
      const ke = (k.culture || "").trim() || "Без культуры",
        Ce = k.net_kg != null ? +k.net_kg : (+k.planned_tonnes || 0) * 1e3,
        ye = (ie[xe][ke] = ie[xe][ke] || {
          n: 0,
          kg: 0,
          rows: [],
        });
      (ye.n++,
        (ye.kg += Ce),
        ye.rows.push({
          id: k.id,
          veh: k.vehicle_no + (k.site ? " · " + k.site : ""),
          kg: Ce,
        }));
    }));
  const V = Ie.filter((k) => k.lab_status === "rejected"),
    J = S.useMemo(() => Object.fromEntries((Z || []).map((k) => [k.id, k])), [Z]),
    ce = [
      ["arrived", "Заехал · ждёт приёмку"],
      ["ready", "Принят · свободен под затарку"],
      ["to_load", "Под затаркой"],
      ["loaded", "Гружёный · ждёт партию"],
      ["b_formed", "В партии · ждёт досмотр"],
      ["b_insp", "Досмотр РСХН и фумигация"],
      ["b_ready", "Готов к выпуску"],
    ],
    oe = {
      arrived: [],
      ready: [],
      to_load: [],
      loaded: [],
      b_formed: [],
      b_insp: [],
      b_ready: [],
    },
    se = {
      repair: [],
      washing: [],
      temp: [],
    };
  r.forEach((k) => {
    const xe = k.batch_id ? J[k.batch_id] : null;
    if (xe) {
      xe.status === "ready" ? oe.b_ready.push(k) : xe.status === "inspect" || xe.status === "fumig" ? oe.b_insp.push(k) : oe.b_formed.push(k);
      return;
    }
    if (k.state === "temp") {
      se.temp.push(k);
      return;
    }
    k.state === "inspected" || k.state === "fumigated"
      ? oe.b_insp.push(k)
      : k.state === "accepted"
        ? oe.ready.push(k)
        : oe[k.state]
          ? oe[k.state].push(k)
          : se[k.state] && se[k.state].push(k);
  });
  const ge = (Z || []).filter((k) => k.status !== "departed"),
    Me = (k) => ze.find((xe) => xe.id === k),
    de = rt(),
    ve = rt(),
    we = rt(),
    Pe = de.apply(ze, {
      id: (k) => k.id,
      veh: (k) => k.vehicle_no,
      org: (k) => k.client,
      cult: (k) => k.culture,
      in: (k) => k.in_at,
      st: (k) => Ae(k).t,
      g: (k) => (k.gross_kg == null ? null : +k.gross_kg),
      t: (k) => (k.tare_kg == null ? null : +k.tare_kg),
      n: (k) => (k.net_kg == null ? null : +k.net_kg),
      dp: (k) => (k.net_kg != null && k.planned_tonnes != null ? k.net_kg - k.planned_tonnes * 1e3 : null),
      out: (k) => k.out_at,
    }),
    Be = ve.apply(Ke, {
      id: (k) => k.id,
      no: (k) => k.container_no,
      tp: (k) => (k.size || "") + (k.height || ""),
      ln: (k) => k.line,
      in: (k) => k.in_at,
      st: (k) => tt(k, J),
      out: (k) => k.out_at,
    }),
    Xt = we.apply(He, {
      id: (k) => k.id,
      no: (k) => {
        var xe;
        return (xe = k.term_line_containers) == null ? void 0 : xe.container_no;
      },
      veh: (k) => k.vehicle_no,
      ord: (k) => k.order_name,
      t: (k) => (k.tare_kg == null ? null : +k.tare_kg),
      g: (k) => (k.gross_kg == null ? null : +k.gross_kg),
      n: (k) => (k.net_kg == null ? null : +k.net_kg),
    }),
    Ms = (() => {
      if (!a) return null;
      if (a.kind === "visit") {
        const k = Me(a.id);
        return k ? (
          <Zs
            v={k}
            req={We.find((xe) => xe.id === k.request_id)}
            who={re}
            me={t}
            onClose={() => f(null)}
            onSaved={() => {
              (b(), g());
            }}
          />
        ) : (
          <Zt
            id={a.id}
            me={t}
            onClose={() => f(null)}
            onSaved={() => {
              (b(), g());
            }}
          />
        );
      }
      if (a.kind === "cont") return <Ht id={a.id} me={t} onClose={() => f(null)} />;
      if (a.kind === "load") return <CRs id={a.id} me={t} onClose={() => f(null)} />;
      if (a.kind === "req") {
        const k = We.find((xe) => xe.id === a.id);
        return k ? <CQn r={k} me={t} onClose={() => f(null)} /> : null;
      }
      return null;
    })(),
    Rl = [
      {
        t: "Менеджер",
        rows: [
          ["Ожидаемые заявки", We.filter((k) => k.status === "expected" && !k.deleted_at && !c.has(k.id)).length],
          ["Машины на терминале по заявкам", We.filter((k) => k.status === "arrived").length],
          ["Создано заявок сегодня", We.filter((k) => k.created_at && Ve(k.created_at) === Ne).length],
        ],
      },
      {
        t: "КПП",
        rows: [
          ["Машин на территории", Ie.length],
          ["Заездов сегодня", ze.filter((k) => k.in_at && Ve(k.in_at) === Ne).length],
          ["Выездов зерновозов сегодня", ze.filter((k) => k.out_at && Ve(k.out_at) === Ne).length],
          ["Выездов контейнеров сегодня", Ke.filter((k) => k.out_at && Ve(k.out_at) === Ne).length],
        ],
      },
      {
        t: "Лаборатория",
        rows: [
          ["В очереди на анализ", Ie.filter((k) => k.lab_status === "pending").length],
          ["Одобрено сегодня", ze.filter((k) => (k.lab_at || "").slice(0, 10) === Ne && k.lab_status === "passed").length],
          ["Отказов сегодня", ze.filter((k) => (k.lab_at || "").slice(0, 10) === Ne && k.lab_status === "rejected").length],
        ],
      },
      {
        t: "Весовая",
        rows: [
          ["Ждут брутто", Ie.filter((k) => k.lab_status === "passed" && k.gross_kg == null).length],
          ["На выгрузке (ждут тару)", Ie.filter((k) => k.lab_status === "passed" && k.gross_kg != null && k.tare_kg == null).length],
          ["Взвешено сегодня, кг нетто", q(ht)],
        ],
      },
      {
        t: "Приёмка контейнеров",
        rows: [
          ["Очередь осмотра", r.filter((k) => k.state === "arrived").length],
          ["В ремонте", r.filter((k) => k.state === "repair").length],
          ["Принято / под загрузку", r.filter((k) => ["ready", "to_load"].includes(k.state)).length],
          ["Гружёные к выезду", r.filter((k) => ["loaded", "inspected", "fumigated"].includes(k.state)).length],
        ],
      },
    ],
    In = (k) => k.slice(8, 10) + "." + k.slice(5, 7),
    Fn = Qe.days14 || [],
    Ll = Fn.map((k) => ({
      l: In(k.d),
      tip: "Приёмка за " + k.d.split("-").reverse().join("."),
      v: (+k.net_kg || 0) / 1e3,
    })),
    Al = Fn.map((k) => ({
      l: In(k.d),
      tip: "Погрузки за " + k.d.split("-").reverse().join("."),
      v: +k.loads_n || 0,
    })),
    Bl = (Qe.cult30 || [])
      .map((k) => ({
        l: k.culture,
        v: (+k.net_kg || 0) / 1e3,
      }))
      .slice(0, 6),
    Qs = {};
  r.forEach((k) => {
    const xe = tt(k, J);
    Qs[xe] = (Qs[xe] || 0) + 1;
  });
  const Pl = Object.entries(Qs)
      .map(([k, xe]) => ({
        l: k,
        v: xe,
      }))
      .sort((k, xe) => xe.v - k.v),
    en = (Qe.years || []).map(String).filter((k) => +k >= 2021);
  en.includes(o) || en.unshift(o);
  const Vl = dn.map((k, xe) => {
      const ke = (Qe.months || []).find((Ce) => +Ce.m === xe + 1) || {};
      return {
        mi: xe,
        mn: k,
        nv: +ke.trucks || 0,
        nc: +ke.conts || 0,
        nl: +ke.loads || 0,
        net: +ke.net_kg || 0,
        lnet: +ke.lnet_kg || 0,
      };
    }),
    as = Qe.ytot || {},
    Ut = {
      trucks: +as.trucks || 0,
      net: +as.net_kg || 0,
      conts: +as.conts || 0,
      loads: +as.loads || 0,
      lnet: +as.lnet_kg || 0,
    };
  return (
    <>
      {Ms}
      {i && <Vr day={i} me={t} onClose={() => u(null)} />}
      {(P == null ? void 0 : P.kind) === "visit" && (
        <CAt
          title={`Зерновоз ${P.row.vehicle_no} · правка (управляющий)`}
          fields={Ol}
          row={P.row}
          table="term_truck_visits"
          onClose={() => T(null)}
          onDone={() => {
            ($e({
              ok: "Изменения сохранены",
            }),
              M());
          }}
        />
      )}
      {(P == null ? void 0 : P.kind) === "cont" && (
        <CAt
          title={`Контейнер ${P.row.container_no} · правка (управляющий)`}
          fields={Dl}
          row={P.row}
          table="term_line_containers"
          onClose={() => T(null)}
          onDone={() => {
            ($e({
              ok: "Изменения сохранены",
            }),
              C());
          }}
        />
      )}
      {(P == null ? void 0 : P.kind) === "load" && (
        <CAt
          title={`Погрузка №${P.row.id} · правка (управляющий)`}
          fields={Tl}
          row={P.row}
          table="term_container_loads"
          onClose={() => T(null)}
          onDone={() => {
            ($e({
              ok: "Изменения сохранены",
            }),
              m());
          }}
        />
      )}
      {(() => {
        const k = [];
        return (
          (N || []).length >= x.vis && k.push("машины на территории"),
          (_ || []).length >= x.cnt && k.push("контейнеры на терминале"),
          (ze || []).length >= x.req && k.push("журнал зерновозов"),
          (He || []).length >= x.load && k.push("журнал погрузок"),
          (We || []).length >= x.req && k.push("заявки"),
          k.length ? (
            <div
              className="ovr9"
              style={{
                marginBottom: 10,
              }}
            >
              <div className="ovr-l">
                ⚠ Данных больше, чем помещается в выборку — занижено: {k.join(", ")}. Точные итоги за период смотри в разделе «Отчёты», а полный
                список — в реестрах.
              </div>
            </div>
          ) : null
        );
      })()}
      <C$r V={ze} C={Ke} R={We} L={He} />
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Работа за день</h2>
        </div>
        <p className="p-sub">
          весь день целиком: приёмка зерна по машинам с качеством, затарка по контейнерам с дотарками и растарками, заезды и выезды контейнеров, итог
          по культурам · из окна отчёта выгружается PDF и Excel на четыре листа
        </p>
        <div
          className="row"
          style={{
            gap: 8,
          }}
        >
          <X label="Дата">
            <input
              type="date"
              style={{
                width: 160,
                minWidth: 160,
              }}
              value={s}
              onChange={(k) => l(k.target.value)}
              max={Ve()}
            />
          </X>
          <button className="btn" disabled={!s} onClick={() => u(s)}>
            Открыть отчёт за день
          </button>
          <button
            className="btn sec"
            onClick={() => {
              const k = new Date();
              (k.setDate(k.getDate() - 1), l(Ve(k)), u(Ve(k)));
            }}
          >
            За вчера
          </button>
          <button
            className="btn sec"
            onClick={() => {
              (l(Ve()), u(Ve()));
            }}
          >
            За сегодня
          </button>
        </div>
      </div>
      <div className="kpis">
        <div className="kpi">
          <div className="l">Машин на территории</div>
          <div className="v">{Ie.length}</div>
          <div className="s">заездов сегодня: {ze.filter((k) => k.in_at && Ve(k.in_at) === Ne).length}</div>
        </div>
        <div className="kpi">
          <div className="l">Принято зерна сегодня</div>
          <div className="v">{q(ht)}</div>
          <div className="s">кг нетто по взвешенным</div>
        </div>
        <div className="kpi">
          <div className="l">Ожидаемых заявок</div>
          <div className="v">{We.filter((k) => k.status === "expected" && !k.deleted_at && !c.has(k.id)).length}</div>
          <div className="s">всего заявок: {We.filter((k) => !k.deleted_at).length}</div>
        </div>
        <div className="kpi">
          <div className="l">Контейнеров на терминале</div>
          <div className="v">{r.length}</div>
          <div className="s">
            принятых: {r.filter((k) => k.state === "ready").length} · в ремонте: {r.filter((k) => k.state === "repair").length}
          </div>
        </div>
        <div className="kpi">
          <div className="l">Погружено сегодня</div>
          <div className="v">
            {B.length}
            {(() => {
              const k = B.reduce((xe, ke) => xe + (+(ke.net_final_kg ?? ke.net_kg) || 0), 0);
              return k > 0 ? (
                <span className="v2">
                  {" "}
                  ·{" "}
                  {(k / 1e3).toLocaleString("ru-RU", {
                    maximumFractionDigits: 1,
                  })}{" "}
                  т
                </span>
              ) : null;
            })()}
          </div>
          <div className="s">контейнеров · тонн зерна затарено</div>
        </div>
      </div>
      <CFe {...(le || {})} />
      <div className="depts">
        {Rl.map((k) => (
          <div className="panel dept">
            <div className="sub-t">{k.t}</div>
            {k.rows.map(([xe, ke]) => (
              <div className="dv">
                <span>{xe}</span>
                <b>{ke}</b>
              </div>
            ))}
          </div>
        ))}
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Зерновозы · конвейер процесса</h2>
          <span
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            в работе: {Ie.length} · ожидается: {We.filter((k) => k.status === "expected" && !k.deleted_at && !c.has(k.id)).length}
          </span>
        </div>
        <p className="p-sub">
          полный цикл: отстойник (Т2) → лаборатория → весовая (брутто, машина гружёная) →{" "}
          {$t() ? "выгрузка и перевалка на площадке" : "выгрузка на площадке (перевалка выведена из процесса в настройках)"} → весовая (тара, машина
          порожняя) → выезд · до тары объём плановый (≈), на «К выезду» — фактическое нетто, всё в кг · клик по культуре — машины, по машине —
          карточка процесса
        </p>
        <div className="flow">
          {G.map(([k, xe], ke) => {
            const Ce = Object.entries(ie[k]).sort((Ge, Ee) => Ee[1].kg - Ge[1].kg),
              ye = Ce.reduce((Ge, [, Ee]) => Ge + Ee.kg, 0),
              Re = Ce.reduce((Ge, [, Ee]) => Ge + Ee.n, 0);
            return (
              <>
                {ke > 0 && <div className="farr">→</div>}
                <div className={"fstage" + (Re ? " on" : "")}>
                  <div className="fs-h">
                    <span className="fs-t">{xe}</span>
                    <span className="fs-n">{Re || "—"}</span>
                  </div>
                  <div className="fs-sub">{Re ? (k === "tare" ? "" : "≈ ") + O(ye) + " кг" : "сейчас пусто"}</div>
                  {Ce.map(([Ge, Ee]) => {
                    const ft = me === k + ":" + Ge;
                    return (
                      <div className="fcult" onClick={() => L(ft ? null : k + ":" + Ge)}>
                        <div className="fc-top">
                          <span className="fc-name">{Ge}</span>
                          <span className="fc-val">
                            {Ee.n} маш · {O(Ee.kg)} кг
                          </span>
                        </div>
                        <div className="fc-track">
                          <div
                            className="fc-fill"
                            style={{
                              width: Math.max(7, (Ee.kg / Math.max(ye, 1)) * 100) + "%",
                            }}
                          />
                        </div>
                        {ft && (
                          <div className="fc-rows">
                            {Ee.rows.map((bt, Hl) => (
                              <div
                                className="fc-row"
                                title="Открыть карточку"
                                onClick={(Ul) => {
                                  (Ul.stopPropagation(),
                                    bt.id
                                      ? f({
                                          kind: "visit",
                                          id: bt.id,
                                        })
                                      : bt.reqId &&
                                        f({
                                          kind: "req",
                                          id: bt.reqId,
                                        }));
                                }}
                              >
                                <b>{bt.veh || "—"}</b>
                                <span>{O(bt.kg)} кг</span>
                              </div>
                            ))}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              </>
            );
          })}
        </div>
        {V.length > 0 && (
          <p
            className="p-sub"
            style={{
              margin: "10px 0 0",
            }}
          >
            ⚠ отказ лаборатории, ждут выезда:{" "}
            {V.map((k) => (
              <>
                <b
                  style={{
                    cursor: "pointer",
                    color: "var(--bad)",
                  }}
                  onClick={() =>
                    f({
                      kind: "visit",
                      id: k.id,
                    })
                  }
                >
                  {k.vehicle_no}
                </b>{" "}
              </>
            ))}
          </p>
        )}
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Контейнеры · конвейер процесса</h2>
          <span
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            на терминале: {r.length}
          </span>
        </div>
        <p className="p-sub">
          каждый контейнер на своём этапе: приёмка → затарка → партия → досмотр и фумигация → выезд в порт · клик по номеру — весь путь контейнера
        </p>
        <div className="flow">
          {ce.map(([k, xe], ke) => {
            const Ce = oe[k],
              ye = W ? Ce : Ce.slice(0, 10);
            return (
              <>
                {ke > 0 && <div className="farr">→</div>}
                <div className={"fstage" + (Ce.length ? " on" : "")}>
                  <div className="fs-h">
                    <span className="fs-t">{xe}</span>
                    <span className="fs-n">{Ce.length || "—"}</span>
                  </div>
                  <div className="fchips">
                    {ye.map((Re) => (
                      <button
                        className="fchip"
                        onClick={() =>
                          f({
                            kind: "cont",
                            id: Re.id,
                          })
                        }
                      >
                        {Re.container_no}
                      </button>
                    ))}
                    {!W && Ce.length > 10 && (
                      <button className="fchip more" onClick={() => K(!0)}>
                        +{Ce.length - 10} ещё
                      </button>
                    )}
                    {!Ce.length && (
                      <span
                        className="p-sub"
                        style={{
                          margin: 0,
                        }}
                      >
                        пусто
                      </span>
                    )}
                  </div>
                </div>
              </>
            );
          })}
        </div>
        {ge.length > 0 && (
          <div className="bflow">
            {ge.map((k) => {
              const xe = r.filter((ke) => ke.batch_id === k.id).length;
              return (
                <span className={"bchip st-" + k.status}>
                  <b>{k.batch_no}</b> · {vt[k.status]} · {xe} конт.{k.booking ? " · " + k.booking : ""}
                </span>
              );
            })}
          </div>
        )}
        {(se.repair.length > 0 || se.washing.length > 0 || se.temp.length > 0) && (
          <p
            className="p-sub"
            style={{
              margin: "10px 0 0",
            }}
          >
            вне потока:{" "}
            {se.repair.length > 0 && (
              <>
                в ремонте —{" "}
                {se.repair.map((k) => (
                  <>
                    <b
                      style={{
                        cursor: "pointer",
                        color: "var(--warn)",
                      }}
                      onClick={() =>
                        f({
                          kind: "cont",
                          id: k.id,
                        })
                      }
                    >
                      {k.container_no}
                    </b>{" "}
                  </>
                ))}
              </>
            )}
            {se.washing.length > 0 && (
              <>
                {" "}
                · мойка —{" "}
                {se.washing.map((k) => (
                  <>
                    <b
                      style={{
                        cursor: "pointer",
                      }}
                      onClick={() =>
                        f({
                          kind: "cont",
                          id: k.id,
                        })
                      }
                    >
                      {k.container_no}
                    </b>{" "}
                  </>
                ))}
              </>
            )}
            {se.temp.length > 0 && (
              <>
                {" "}
                · времянки —{" "}
                {se.temp.map((k) => (
                  <>
                    <b
                      style={{
                        cursor: "pointer",
                        color: "var(--warn)",
                      }}
                      onClick={() =>
                        f({
                          kind: "cont",
                          id: k.id,
                        })
                      }
                    >
                      {k.container_no}
                    </b>
                    {k.temp_kg != null && +k.temp_kg > 0 ? " · " + q(Math.round(+k.temp_kg)) + " кг" : ""}{" "}
                  </>
                ))}
                {(() => {
                  const k = se.temp.reduce((xe, ke) => xe + (+ke.temp_kg || 0), 0);
                  return k > 0 ? <> (всего в остатках {q(Math.round(k))} кг)</> : null;
                })()}
              </>
            )}
          </p>
        )}
      </div>
      <div className="charts">
        <div className="panel">
          <h2 className="p-title">Порожние по линиям · выданы под клиента</h2>
          <p className="p-sub">принятые и ожидающие приёмку порожние: линия × тип × клиент</p>
          {(() => {
            const k = r.filter((ye) => ["ready", "arrived", "accepted"].includes(ye.state));
            if (!k.length)
              return (
                <p
                  className="p-sub"
                  style={{
                    margin: 0,
                  }}
                >
                  порожних на терминале нет
                </p>
              );
            const xe = {};
            k.forEach((ye) => {
              const Re = (ye.line || "—") + "¦" + (ye.client || "—"),
                Ge = (ye.size || "?") + (ye.height || "");
              ((xe[Re] = xe[Re] || {
                line: ye.line || "—",
                client: ye.client || "—",
                t: {},
                n: 0,
              }),
                (xe[Re].t[Ge] = (xe[Re].t[Ge] || 0) + 1),
                xe[Re].n++);
            });
            const ke = Object.values(xe).sort((ye, Re) => Re.n - ye.n),
              Ce = [...new Set(k.map((ye) => (ye.size || "?") + (ye.height || "")))].sort();
            return (
              <div
                className="tscroll"
                style={{
                  maxHeight: 260,
                }}
              >
                <table>
                  <thead>
                    <tr>
                      <th>Линия</th>
                      <th>Клиент</th>
                      {Ce.map((ye) => (
                        <th className="right">{ye}</th>
                      ))}
                      <th className="right">Всего</th>
                    </tr>
                  </thead>
                  <tbody>
                    {ke.map((ye, Re) => (
                      <tr>
                        <td>
                          <b>{ye.line}</b>
                        </td>
                        <td>{ye.client}</td>
                        {Ce.map((Ge) => (
                          <td className="right">{ye.t[Ge] || "—"}</td>
                        ))}
                        <td className="right">
                          <b>{ye.n}</b>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                  <tfoot>
                    <tr>
                      <td colSpan={2}>
                        <b>Итого</b>
                      </td>
                      {Ce.map((ye) => (
                        <td className="right">
                          <b>{k.filter((Re) => (Re.size || "?") + (Re.height || "") === ye).length}</b>
                        </td>
                      ))}
                      <td className="right">
                        <b>{k.length}</b>
                      </td>
                    </tr>
                  </tfoot>
                </table>
              </div>
            );
          })()}
        </div>
        <div className="panel">
          <h2 className="p-title">Хранение на терминале</h2>
          <p className="p-sub">дни от заезда · подсвечено дольше 30 дней · клик — карточка</p>
          {(() => {
            const k = (ke, Ce) => ({
              t: Ce,
              list: ke
                .map((ye) => ({
                  c: ye,
                  d: Lt(ye.in_at, null),
                }))
                .sort((ye, Re) => Re.d - ye.d),
            });
            return [
              k(
                r.filter((ke) => ["loaded", "inspected", "fumigated"].includes(ke.state)),
                "Гружёные",
              ),
              k(
                r.filter((ke) => ["ready", "arrived", "accepted"].includes(ke.state)),
                "Порожние",
              ),
              k(
                r.filter((ke) => ke.state === "temp"),
                "Времянки (остатки)",
              ),
            ].map((ke) => (
              <div
                style={{
                  marginBottom: 10,
                }}
              >
                <div className="sub-t">
                  {ke.t} · {ke.list.length} · свыше 30 дн: {ke.list.filter((Ce) => Ce.d > 30).length}
                  {ke.t.startsWith("Времянки") &&
                    (() => {
                      const Ce = ke.list.reduce((ye, Re) => ye + (+Re.c.temp_kg || 0), 0);
                      return Ce > 0 ? ` · остаток ${q(Math.round(Ce))} кг` : "";
                    })()}
                </div>
                {ke.list.length ? (
                  <div className="fchips">
                    {ke.list.slice(0, 10).map(({ c: Ce, d: ye }) => (
                      <button
                        className={"fchip" + (ye > 30 ? " over" : "")}
                        onClick={() =>
                          f({
                            kind: "cont",
                            id: Ce.id,
                          })
                        }
                      >
                        {Ce.container_no} · {ye}д
                      </button>
                    ))}
                    {ke.list.length > 10 && <span className="fchip more">+{ke.list.length - 10}</span>}
                  </div>
                ) : (
                  <p
                    className="p-sub"
                    style={{
                      margin: 0,
                    }}
                  >
                    нет
                  </p>
                )}
              </div>
            ));
          })()}
        </div>
        <div className="panel">
          <h2 className="p-title">Приёмка зерна по дням · 14 дней</h2>
          <p className="p-sub">тонн нетто по взвешенным машинам</p>
          <Hn data={Ll} fmt={(k) => (k >= 100 ? q(Math.round(k)) : Math.round(k * 10) / 10 || "")} unit=" т" />
        </div>
        <div className="panel">
          <h2 className="p-title">Погрузки контейнеров по дням · 14 дней</h2>
          <p className="p-sub">завершённых перетарок (брутто взвешено)</p>
          <Hn data={Al} fmt={(k) => k || ""} unit=" шт" />
        </div>
        <div className="panel">
          <h2 className="p-title">Культуры · последние 30 дней</h2>
          <p className="p-sub">принято тонн нетто по культурам</p>
          <Ps data={Bl} fmt={(k) => q(Math.round(k))} unit=" т" />
        </div>
        <div className="panel">
          <h2 className="p-title">Контейнеры на терминале · по статусам</h2>
          <p className="p-sub">текущее размещение парка линии</p>
          <Ps data={Pl} fmt={(k) => k} unit=" шт" />
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Зерновозы · полный журнал</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <Je make={() => Ze("Зерновозы_журнал", [ks(ze, be)])} />
            <button
              className="btn sec sm"
              onClick={() =>
                ns(
                  "Зерновозы",
                  [
                    "№",
                    "Машина",
                    "Прицеп",
                    "Организация",
                    "Культура",
                    "Поставщик",
                    "Водитель",
                    "Заезд",
                    "Лаборатория",
                    "Результат 1",
                    "Брутто кг",
                    "Тара кг",
                    "Нетто кг",
                    "Выгрузка",
                    "Выезд",
                  ],
                  ze.map((k) => [
                    k.id,
                    k.vehicle_no,
                    k.trailer_no,
                    k.client,
                    k.culture,
                    k.supplier,
                    k.driver,
                    he(k.in_at),
                    k.lab_status,
                    k.lab_result1 ? Le[k.lab_result1] : "",
                    k.gross_kg,
                    k.tare_kg,
                    k.net_kg,
                    k.unload_place,
                    he(k.out_at),
                  ]),
                )
              }
            >
              ⇩ CSV
            </button>
          </span>
        </div>
        <p className="p-sub">клик по строке — все детали процесса: заявка → заезд → лаборатория → веса → выезд, с исполнителями · ✎ — правка</p>
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <de.TH k="id">№</de.TH>
                <de.TH k="veh">Машина</de.TH>
                <de.TH k="org">Организация</de.TH>
                <de.TH k="cult">Культура</de.TH>
                <de.TH k="in">Заезд</de.TH>
                <de.TH k="st">Статус</de.TH>
                <th>Лаб. → Результат 1</th>
                <de.TH k="g" right={!0}>
                  Брутто
                </de.TH>
                <de.TH k="t" right={!0}>
                  Тара
                </de.TH>
                <de.TH k="n" right={!0}>
                  Нетто
                </de.TH>
                <de.TH k="dp" right={!0}>
                  Δ к плану
                </de.TH>
                <th>Выгрузка</th>
                <de.TH k="out">Выезд</de.TH>
                <th />
              </tr>
            </thead>
            <tbody>
              {Pe.map((k) => {
                const xe = Ae(k),
                  ke = k.net_kg != null && k.planned_tonnes != null ? Math.round(k.net_kg - k.planned_tonnes * 1e3) : null;
                return (
                  <tr
                    className="rowx"
                    onClick={() =>
                      f({
                        kind: "visit",
                        id: k.id,
                      })
                    }
                  >
                    <td>{k.id}</td>
                    <td>
                      <b>{k.vehicle_no}</b>
                    </td>
                    <td>{k.client || "—"}</td>
                    <td>{k.culture || "—"}</td>
                    <td className="nowrap">{he(k.in_at)}</td>
                    <td>
                      <span className={"stage " + xe.c}>{xe.t}</span>
                    </td>
                    <td>{k.lab_result1 ? Le[k.lab_result1] : k.lab_status === "rejected" ? "отказ" : "—"}</td>
                    <td className="right">{q(k.gross_kg)}</td>
                    <td className="right">{q(k.tare_kg)}</td>
                    <td className="right">
                      <b>{q(k.net_kg)}</b>
                    </td>
                    <td
                      className="right"
                      style={
                        ke != null && k.planned_tonnes && (Math.abs(ke) / (qe(k.planned_tonnes) || 1)) * 100 > Oe(ot.S, "plan_dev_pct")
                          ? {
                              color: "var(--bad)",
                              fontWeight: 700,
                            }
                          : void 0
                      }
                    >
                      {ke == null ? "—" : (ke >= 0 ? "+" : "") + q(ke)}
                    </td>
                    <td>{k.unload_place || "—"}</td>
                    <td className="nowrap">{he(k.out_at)}</td>
                    <td>
                      {n ? (
                        <Ye
                          onClick={() =>
                            T({
                              kind: "visit",
                              row: k,
                            })
                          }
                        />
                      ) : null}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Контейнеры · полный журнал</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <Je make={async () => Ze("Контейнеры_журнал", [ws(await y(), be, J)])} />
            <button
              className="btn sec sm"
              onClick={() =>
                ns(
                  "Контейнеры",
                  ["№", "Контейнер", "Тип", "Высота", "Линия", "Заезд", "Статус", "Пломба", "Машина вывоза", "Выезд"],
                  Ke.map((k) => [k.id, k.container_no, k.size, k.height, k.line, he(k.in_at), tt(k, J), k.seal_no, k.out_vehicle_no, he(k.out_at)]),
                )
              }
            >
              ⇩ CSV
            </button>
          </span>
        </div>
        <p className="p-sub">клик по строке — весь путь контейнера: заезд → приёмка → паспорт → погрузки → выезд · ✎ — правка</p>
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <ve.TH k="id">№</ve.TH>
                <ve.TH k="no">Контейнер</ve.TH>
                <ve.TH k="tp">Тип</ve.TH>
                <ve.TH k="ln">Линия</ve.TH>
                <ve.TH k="in">Заезд</ve.TH>
                <ve.TH k="st">Статус</ve.TH>
                <th>Пломба</th>
                <th>Машина вывоза</th>
                <ve.TH k="out">Выезд</ve.TH>
                <th />
              </tr>
            </thead>
            <tbody>
              {Be.map((k) => (
                <tr
                  className="rowx"
                  onClick={() =>
                    f({
                      kind: "cont",
                      id: k.id,
                    })
                  }
                >
                  <td>{k.id}</td>
                  <td>
                    <b>{k.container_no}</b>
                  </td>
                  <td>{k.size ? `${k.size}' ${k.height || ""}` : "—"}</td>
                  <td>{k.line || "—"}</td>
                  <td className="nowrap">{he(k.in_at)}</td>
                  <td>
                    <Et c={k} bm={J} />
                  </td>
                  <td>{k.seal_no || "—"}</td>
                  <td>
                    <CXt v={k.out_vehicle_no} />
                  </td>
                  <td className="nowrap">{he(k.out_at)}</td>
                  <td>
                    {n ? (
                      <Ye
                        onClick={() =>
                          T({
                            kind: "cont",
                            row: k,
                          })
                        }
                      />
                    ) : null}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Погрузки (перетарка) · журнал</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <Je make={() => Ze("Погрузки_журнал", [Ws(He, be)])} />
            <button
              className="btn sec sm"
              onClick={() =>
                ns(
                  "Погрузки",
                  ["№", "Контейнер", "Машина", "Поручение", "Культура", "Тара кг", "Брутто кг", "Нетто кг", "Пломба"],
                  He.map((k) => {
                    var xe;
                    return [
                      k.id,
                      (xe = k.term_line_containers) == null ? void 0 : xe.container_no,
                      k.vehicle_no,
                      k.order_name,
                      k.culture,
                      k.tare_kg,
                      k.gross_kg,
                      k.net_kg,
                      k.seal_no,
                    ];
                  }),
                )
              }
            >
              ⇩ CSV
            </button>
          </span>
        </div>
        <p className="p-sub">клик по строке — карточка затарки: контейнер, весы, дотарка и распределение по контрактам · ✎ — правка</p>
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <we.TH k="id">№</we.TH>
                <we.TH k="no">Контейнер</we.TH>
                <we.TH k="veh">Машина</we.TH>
                <we.TH k="ord">Поручение</we.TH>
                <we.TH k="t" right={!0}>
                  Тара
                </we.TH>
                <we.TH k="g" right={!0}>
                  Брутто
                </we.TH>
                <we.TH k="n" right={!0}>
                  Нетто
                </we.TH>
                <th>Пломба</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {Xt.map((k) => {
                var xe;
                return (
                  <tr
                    className="rowx"
                    title="Карточка затарки"
                    onClick={() =>
                      f({
                        kind: "load",
                        id: k.id,
                      })
                    }
                  >
                    <td>{k.id}</td>
                    <td>
                      <b>{((xe = k.term_line_containers) == null ? void 0 : xe.container_no) || "—"}</b>
                    </td>
                    <td>
                      <CXt v={k.vehicle_no} />
                    </td>
                    <td>{k.order_name || "—"}</td>
                    <td className="right">{q(k.tare_kg)}</td>
                    <td className="right">{q(k.gross_kg)}</td>
                    <td className="right">
                      <b>{q(k.net_kg)}</b>
                    </td>
                    <td>{k.seal_no || "—"}</td>
                    <td>
                      {n ? (
                        <Ye
                          onClick={() =>
                            T({
                              kind: "load",
                              row: k,
                            })
                          }
                        />
                      ) : null}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Сводный журнал работы терминала · {I}</h2>
          <span
            className="row"
            style={{
              gap: 6,
              alignItems: "center",
            }}
          >
            <CPe
              value={I}
              onChange={(k) => {
                k && (D(k), Q(null));
              }}
              options={en}
              w={100}
              ph={I}
            />
            <Je label="⇩ Excel · вся работа терминала" make={() => Il(be, I)} />
          </span>
        </div>
        <p className="p-sub">
          все процессы года по месяцам: зерновозы, контейнеры, погрузки · клик по месяцу — список процессов, клик по процессу — полная детализация ·
          Excel-кнопка выгружает общий файл всей системы: заявки (ожидаемые и исполненные), зерновозы, контейнеры, погрузки и справочники с
          максимальной детализацией
        </p>
        <div
          className="tscroll"
          style={{
            maxHeight: "none",
          }}
        >
          <table>
            <thead>
              <tr>
                <th>Месяц</th>
                <th className="right">Зерновозов (заезд)</th>
                <th className="right">Нетто зерна, кг</th>
                <th className="right">Контейнеров (заезд)</th>
                <th className="right">Погрузок</th>
                <th className="right">Нетто погрузок, кг</th>
              </tr>
            </thead>
            <tbody>
              {Vl.map((k) => {
                const xe = k.nv + k.nc + k.nl > 0,
                  ke = H === k.mi,
                  Ce = ke ? ae || {} : {},
                  ye = Ce.mv || [],
                  Re = Ce.mc || [],
                  Ge = Ce.ml || [];
                return (
                  <>
                    <tr className={xe ? "rowx" : ""} onClick={() => xe && Q(ke ? null : k.mi)}>
                      <td>
                        <span className="car">{xe ? (ke ? "▾" : "▸") : ""}</span>
                        <b>{k.mn}</b>
                      </td>
                      <td className="right">{k.nv || "—"}</td>
                      <td className="right">{k.net ? q(k.net) : "—"}</td>
                      <td className="right">{k.nc || "—"}</td>
                      <td className="right">{k.nl || "—"}</td>
                      <td className="right">{k.lnet ? q(k.lnet) : "—"}</td>
                    </tr>
                    {ke && (
                      <tr className="subtr">
                        <td colSpan={6}>
                          <div className="subwrap">
                            {!ae && (
                              <p
                                className="p-sub"
                                style={{
                                  margin: 0,
                                }}
                              >
                                загружаю записи за {k.mn}…
                              </p>
                            )}
                            {ye.length > 0 && (
                              <>
                                <div className="sub-t">
                                  Зерновозы · {k.mn} {I} · {ye.length}
                                </div>
                                <table>
                                  <thead>
                                    <tr>
                                      <th>№</th>
                                      <th>Машина</th>
                                      <th>Организация</th>
                                      <th>Культура</th>
                                      <th>Заезд</th>
                                      <th>Статус</th>
                                      <th className="right">Нетто, кг</th>
                                    </tr>
                                  </thead>
                                  <tbody>
                                    {ye.map((Ee) => {
                                      const ft = Ae(Ee);
                                      return (
                                        <tr
                                          className="rowx"
                                          onClick={(bt) => {
                                            (bt.stopPropagation(),
                                              f({
                                                kind: "visit",
                                                id: Ee.id,
                                              }));
                                          }}
                                        >
                                          <td>{Ee.id}</td>
                                          <td>
                                            <b>{Ee.vehicle_no}</b>
                                          </td>
                                          <td>{Ee.client || "—"}</td>
                                          <td>{Ee.culture || "—"}</td>
                                          <td className="nowrap">{he(Ee.in_at)}</td>
                                          <td>
                                            <span className={"stage " + ft.c}>{ft.t}</span>
                                          </td>
                                          <td className="right">
                                            <b>{q(Ee.net_kg)}</b>
                                          </td>
                                        </tr>
                                      );
                                    })}
                                  </tbody>
                                </table>
                              </>
                            )}
                            {Re.length > 0 && (
                              <>
                                <div
                                  className="sub-t"
                                  style={{
                                    marginTop: 12,
                                  }}
                                >
                                  Контейнеры · {k.mn} {I} · {Re.length}
                                </div>
                                <table>
                                  <thead>
                                    <tr>
                                      <th>№</th>
                                      <th>Контейнер</th>
                                      <th>Тип</th>
                                      <th>Заезд</th>
                                      <th>Статус</th>
                                      <th>Пломба</th>
                                      <th>Выезд</th>
                                    </tr>
                                  </thead>
                                  <tbody>
                                    {Re.map((Ee) => (
                                      <tr
                                        className="rowx"
                                        onClick={(ft) => {
                                          (ft.stopPropagation(),
                                            f({
                                              kind: "cont",
                                              id: Ee.id,
                                            }));
                                        }}
                                      >
                                        <td>{Ee.id}</td>
                                        <td>
                                          <b>{Ee.container_no}</b>
                                        </td>
                                        <td>{Ee.size ? `${Ee.size}' ${Ee.height || ""}` : "—"}</td>
                                        <td className="nowrap">{he(Ee.in_at)}</td>
                                        <td>
                                          <Et c={Ee} bm={J} />
                                        </td>
                                        <td>{Ee.seal_no || "—"}</td>
                                        <td className="nowrap">{he(Ee.out_at)}</td>
                                      </tr>
                                    ))}
                                  </tbody>
                                </table>
                              </>
                            )}
                            {Ge.length > 0 && (
                              <>
                                <div
                                  className="sub-t"
                                  style={{
                                    marginTop: 12,
                                  }}
                                >
                                  Погрузки · {k.mn} {I} · {Ge.length} · клик — карточка затарки
                                </div>
                                <table>
                                  <thead>
                                    <tr>
                                      <th>№</th>
                                      <th>Контейнер</th>
                                      <th>Машина</th>
                                      <th>Поручение</th>
                                      <th className="right">Нетто, кг</th>
                                    </tr>
                                  </thead>
                                  <tbody>
                                    {Ge.map((Ee) => {
                                      var ft;
                                      return (
                                        <tr
                                          className="rowx"
                                          title="Карточка затарки"
                                          onClick={(bt) => {
                                            (bt.stopPropagation(),
                                              f({
                                                kind: "load",
                                                id: Ee.id,
                                              }));
                                          }}
                                        >
                                          <td>{Ee.id}</td>
                                          <td>
                                            <b>{((ft = Ee.term_line_containers) == null ? void 0 : ft.container_no) || "—"}</b>
                                          </td>
                                          <td>
                                            <CXt v={Ee.vehicle_no} />
                                          </td>
                                          <td>{Ee.order_name || "—"}</td>
                                          <td className="right">
                                            <b>{q(Ee.net_kg)}</b>
                                          </td>
                                        </tr>
                                      );
                                    })}
                                  </tbody>
                                </table>
                              </>
                            )}
                          </div>
                        </td>
                      </tr>
                    )}
                  </>
                );
              })}
            </tbody>
            <tfoot>
              <tr>
                <td>
                  <b>Итого {I}</b>
                </td>
                <td className="right">
                  <b>{Ut.trucks || "—"}</b>
                </td>
                <td className="right">
                  <b>{Ut.net ? q(Ut.net) : "—"}</b>
                </td>
                <td className="right">
                  <b>{Ut.conts || "—"}</b>
                </td>
                <td className="right">
                  <b>{Ut.loads || "—"}</b>
                </td>
                <td className="right">
                  <b>{Ut.lnet ? q(Ut.lnet) : "—"}</b>
                </td>
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
    </>
  );
}
function Ur({ me: t }) {
  const n = $s(t);
  return <CBl D={n} />;
}
function Wr({ me: t }) {
  const n = $s(t);
  return <CKl D={n} />;
}
function Gr({ me: t }) {
  const n = $s(t);
  return <CWl D={n} />;
}
function Kr({ me: t }) {
  const n = $s(t);
  return <C$l D={n} />;
}
const Jr = bi.filter(([t]) => !["new", "t2", "called"].includes(t)),
  Dn = () => {
    const t = new Date().getFullYear(),
      n = [];
    for (let s = t; s >= 2025; s--) n.push(String(s));
    return n;
  },
  Yr = () => {
    const t = new Date().getFullYear(),
      n = [];
    for (let s = t; s >= 2019; s--) n.push(String(s));
    return n;
  };
function yt() {
  const [t] = ne(() => Y(A.from("term_profiles").select("user_id, display_name")), [], 0, "profiles2"),
    n = S.useMemo(() => Object.fromEntries((t || []).map((s) => [s.user_id, s.display_name])), [t]);
  return {
    who: (s) => (s ? n[s] || "сотрудник" : "—"),
    W: (s) => (s && n[s]) || "",
  };
}
function Zr({ me: t }) {
  const [n, s] = Te("reg.tr.year", String(new Date().getFullYear()), ut("reg_tr", "year")),
    [l, i, u] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .gte("in_at", Nt(+n)[0])
            .lt("in_at", Nt(+n)[1])
            .order("id", {
              ascending: !1,
            })
            .limit(5e3),
        ),
      [n],
      3e4,
    ),
    [o] = ne(
      () =>
        Y(
          A.from("term_requests")
            .select("*, term_orders(order_no, cargo, extra_services, term_contracts(contract_no, term_counterparties(name)))")
            .order("id", {
              ascending: !1,
            })
            .limit(1e3),
        ),
      [],
      6e4,
    ),
    { who: x, W: N } = yt(),
    b = S.useMemo(() => Object.fromEntries((o || []).map((I) => [I.id, I])), [o]),
    j = (I) => {
      var D, E;
      return ((E = (D = b[I.request_id]) == null ? void 0 : D.term_orders) == null ? void 0 : E.extra_services) || [];
    },
    [g, d] = S.useState(() => ut("reg_tr", "flt")),
    [M, z] = S.useState(null),
    [_, h] = S.useState(null),
    [w, p] = S.useState(null),
    [F, C] = S.useState(null),
    y = l || [],
    $ = Pt("Поиск: машина, организация, культура, поставщик, замес, статус…", ut("reg_tr", "q")),
    { TH: CM, apply: v } = rt(),
    U = v(
      y
        .filter((I) => {
          const D = Ae(I, {
            need: j(I),
          });
          return (!g || D.g === g) && (!M || D.k === M);
        })
        .filter((I) => {
          var D, E;
          return $.test(
            I.id,
            I.vehicle_no,
            I.trailer_no,
            I.client,
            I.culture,
            I.supplier,
            I.driver,
            I.site,
            js(I),
            I.mix_group,
            Ae(I, {
              need: j(I),
            }).t,
            (E = (D = b[I.request_id]) == null ? void 0 : D.term_orders) == null ? void 0 : E.order_no,
          );
        }),
      {
        id: (I) => I.id,
        veh: (I) => I.vehicle_no,
        org: (I) => I.client,
        cult: (I) => I.culture,
        sup: (I) => I.supplier,
        in: (I) => I.in_at,
        st: (I) =>
          Ae(I, {
            need: j(I),
          }).t,
        mx: (I) => js(I),
        g: (I) => (I.gross_kg == null ? null : +I.gross_kg),
        t: (I) => (I.tare_kg == null ? null : +I.tare_kg),
        n: (I) => (I.net_kg == null ? null : +I.net_kg),
        out: (I) => I.out_at,
      },
    );
  $.enterRef.current = U.length === 1 ? () => h(U[0].id) : null;
  const Z = U.reduce((I, D) => I + (+D.net_kg || 0), 0);
  return (
    <>
      {_ &&
        (() => {
          const I = y.find((D) => D.id === _);
          return I ? <Zs v={I} req={(o || []).find((D) => D.id === I.request_id)} who={x} me={t} onClose={() => h(null)} onSaved={i} /> : null;
        })()}
      {w && (
        <CAt
          title={`Зерновоз ${w.vehicle_no} · правка`}
          fields={Ol}
          row={w}
          table="term_truck_visits"
          onClose={() => p(null)}
          onDone={() => {
            (C({
              ok: "Изменения сохранены",
            }),
              i());
          }}
        />
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">
            Реестр зерновозов · {n} · {Vt($, U.length, y.length)}
          </h2>
          <span
            className="row"
            style={{
              gap: 6,
              alignItems: "center",
            }}
          >
            <CPe value={n} onChange={(I) => I && s(I)} options={Dn()} w={100} ph={n} />
            <Je make={() => Ze(`Зерновозы_${n}`, [ks(U, N)])} />
          </span>
        </div>
        <p className="p-sub">все машины года по статусам процесса · клик по строке — полная детализация с исполнителями · ✎ — правка</p>
        <div className="findrow">
          {$.Find}
          <Yt
            win="reg_tr"
            params={{
              q: $.q,
              flt: g,
              year: n,
            }}
          />
        </div>
        <Tt
          val={g}
          onSel={(I) => {
            (d(I), z(null));
          }}
          items={gi
            .map(([I, D]) => ({
              k: I,
              t: D,
              n: y.filter(
                (E) =>
                  Ae(E, {
                    need: j(E),
                  }).g === I,
              ).length,
            }))
            .filter((I) => I.n)}
        />
        {g && (
          <Tt
            val={M}
            onSel={z}
            items={Jr.filter(([, , I]) => I === g)
              .map(([I, D]) => ({
                k: I,
                t: D,
                n: y.filter(
                  (E) =>
                    Ae(E, {
                      need: j(E),
                    }).k === I,
                ).length,
              }))
              .filter((I) => I.n)}
          />
        )}
        <CFe err={u} />
        <CFe {...(F || {})} />
        <div
          className="tscroll"
          style={{
            maxHeight: "64vh",
          }}
        >
          <table>
            <thead>
              <tr>
                <CM k="id">№</CM>
                <CM k="veh">Машина</CM>
                <CM k="org">Организация</CM>
                <CM k="cult">Культура</CM>
                <CM k="sup">Поставщик</CM>
                <CM k="in">Заезд</CM>
                <CM k="st">Статус</CM>
                <CM k="mx">Замес</CM>
                <CM k="g" right={!0}>
                  Брутто
                </CM>
                <CM k="t" right={!0}>
                  Тара
                </CM>
                <CM k="n" right={!0}>
                  Нетто
                </CM>
                <CM k="out">Выезд</CM>
                <th />
              </tr>
            </thead>
            <tbody>
              {U.map((I) => {
                const D = Ae(I, {
                  need: j(I),
                });
                return (
                  <tr className="rowx" onClick={() => h(I.id)}>
                    <td>{I.id}</td>
                    <td>
                      <b>{I.vehicle_no}</b>
                    </td>
                    <td>{I.client || "—"}</td>
                    <td>{I.culture || "—"}</td>
                    <td>{I.supplier || "—"}</td>
                    <td className="nowrap">{he(I.in_at)}</td>
                    <td>
                      <span className={"stage " + D.c}>{D.t}</span>
                    </td>
                    <td
                      style={{
                        maxWidth: 230,
                        whiteSpace: "normal",
                      }}
                    >
                      <Gt v={I} dash={!0} />
                    </td>
                    <td className="right">{q(I.gross_kg)}</td>
                    <td className="right">{q(I.tare_kg)}</td>
                    <td className="right">
                      <b>{q(I.net_kg)}</b>
                    </td>
                    <td className="nowrap">{he(I.out_at)}</td>
                    <td>{mt("vis") && <Ye onClick={() => p(I)} />}</td>
                  </tr>
                );
              })}
            </tbody>
            <tfoot>
              <tr>
                <td colSpan={10}>
                  <b>
                    Итого {g || M ? "по фильтру" : n}: {U.length} машин
                  </b>
                </td>
                <td className="right">
                  <b>{q(Z)}</b>
                </td>
                <td colSpan={2} />
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
    </>
  );
}
function Xr({ me: t }) {
  const [n, s] = Te("reg.cult.year", String(new Date().getFullYear()), ut("reg_cult", "year")),
    [l, i, u] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .gte("in_at", Nt(+n)[0])
            .lt("in_at", Nt(+n)[1])
            .order("id", {
              ascending: !1,
            })
            .limit(5e3),
        ),
      [n],
      6e4,
    ),
    [o] = ne(
      () =>
        Y(
          A.from("term_requests")
            .select("*, term_orders(order_no, cargo, term_contracts(contract_no, term_counterparties(name)))")
            .order("id", {
              ascending: !1,
            })
            .limit(1e3),
        ),
      [],
      6e4,
    ),
    { who: x } = yt(),
    [N, b] = S.useState({}),
    [j, g] = S.useState(null),
    d = l || [],
    M = Pt("Поиск: культура, машина, организация…", ut("reg_cult", "q")),
    z = S.useMemo(() => {
      const C = {};
      return (
        d.forEach((y) => {
          const $ = (y.culture || "").trim() || "Без культуры";
          (C[$] = C[$] || []).push(y);
        }),
        Object.entries(C)
          .map(([y, $]) => ({
            cult: y,
            list: $,
            net: $.reduce((m, v) => m + (+v.net_kg || 0), 0),
            onTerm: $.filter((m) => m.in_at && !m.out_at).length,
            left: $.filter((m) => !!m.out_at && m.lab_status !== "rejected").length,
            rej: $.filter((m) => m.lab_status === "rejected").length,
          }))
          .sort((y, $) => $.net - y.net)
      );
    }, [d]),
    _ = S.useMemo(
      () =>
        M.on
          ? z
              .map((C) => {
                if (M.test(C.cult)) return C;
                const y = C.list.filter(($) => M.test($.vehicle_no, $.client, $.supplier, $.culture, $.id));
                return y.length
                  ? {
                      ...C,
                      list: y,
                      net: y.reduce(($, m) => $ + (+m.net_kg || 0), 0),
                      onTerm: y.filter(($) => $.in_at && !$.out_at).length,
                      left: y.filter(($) => !!$.out_at && $.lab_status !== "rejected").length,
                      rej: y.filter(($) => $.lab_status === "rejected").length,
                    }
                  : null;
              })
              .filter(Boolean)
          : z,
      [z, M.q],
    ),
    h = _.reduce((C, y) => C + y.net, 0),
    { TH: CW, apply: p } = rt(),
    F = p(_, {
      cult: (C) => C.cult,
      n: (C) => C.list.length,
      ot: (C) => C.onTerm,
      lf: (C) => C.left,
      rj: (C) => C.rej,
      net: (C) => C.net,
    });
  return (
    <>
      {j &&
        (() => {
          const C = d.find((y) => y.id === j);
          return C ? <Zs v={C} req={(o || []).find((y) => y.id === C.request_id)} who={x} me={t} onClose={() => g(null)} onSaved={i} /> : null;
        })()}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">
            Реестр культур · {n} · {Vt(M, _.length, z.length)}
          </h2>
          <span
            className="row"
            style={{
              gap: 6,
              alignItems: "center",
            }}
          >
            <CPe value={n} onChange={(C) => C && s(C)} options={Dn()} w={100} ph={n} />
            <Je
              make={() =>
                Ze(`Культуры_${n}`, [
                  {
                    name: "Культуры",
                    title: `ФЕНИКС · Терминал — Культуры за ${n}`,
                    cols: [
                      {
                        h: "Культура",
                        w: 22,
                      },
                      {
                        h: "Машин",
                        w: 10,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "На терминале",
                        w: 12,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Убыло",
                        w: 10,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Отказы",
                        w: 10,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Нетто, кг",
                        w: 14,
                        num: 1,
                        int: 1,
                      },
                      {
                        h: "Доля, %",
                        w: 10,
                        num: 1,
                      },
                    ],
                    rows: _.map((C) => [C.cult, C.list.length, C.onTerm, C.left, C.rej, C.net, h ? Math.round((C.net / h) * 1e3) / 10 : 0]),
                  },
                ])
              }
            />
          </span>
        </div>
        <p className="p-sub">принятые культуры года: машины по статусам и нетто · клик по культуре — список машин, клик по машине — детализация</p>
        <div className="findrow">
          {M.Find}
          <Yt
            win="reg_cult"
            params={{
              q: M.q,
              year: n,
            }}
          />
        </div>
        <CFe err={u} />
        {_.length > 0 && (
          <Ps
            data={_.slice(0, 8).map((C) => ({
              l: C.cult,
              v: C.net / 1e3,
              tip: C.cult,
            }))}
            fmt={(C) => q(Math.round(C))}
            unit=" т"
          />
        )}
        <div
          className="tscroll"
          style={{
            maxHeight: "none",
            marginTop: 12,
          }}
        >
          <table>
            <thead>
              <tr>
                <CW k="cult">Культура</CW>
                <CW k="n" right={!0}>
                  Машин
                </CW>
                <CW k="ot" right={!0}>
                  На терминале
                </CW>
                <CW k="lf" right={!0}>
                  Убыло
                </CW>
                <CW k="rj" right={!0}>
                  Отказы
                </CW>
                <CW k="net" right={!0}>
                  Нетто, кг
                </CW>
                <CW k="net" right={!0}>
                  Доля
                </CW>
              </tr>
            </thead>
            <tbody>
              {(F || _).map((C) => {
                const y = !!N[C.cult];
                return (
                  <>
                    <tr
                      className="rowx"
                      onClick={() =>
                        b(($) => ({
                          ...$,
                          [C.cult]: !y,
                        }))
                      }
                    >
                      <td>
                        <span className="car">{y ? "▾" : "▸"}</span>
                        <b>{C.cult}</b>
                      </td>
                      <td className="right">{C.list.length}</td>
                      <td className="right">{C.onTerm || "—"}</td>
                      <td className="right">{C.left || "—"}</td>
                      <td className="right">{C.rej || "—"}</td>
                      <td className="right">
                        <b>{q(C.net)}</b>
                      </td>
                      <td className="right">{h ? Math.round((C.net / h) * 100) + "%" : "—"}</td>
                    </tr>
                    {y && (
                      <tr className="subtr">
                        <td colSpan={7}>
                          <div className="subwrap">
                            <div className="sub-t">
                              Машины · {C.cult} · {C.list.length}
                            </div>
                            <table>
                              <thead>
                                <tr>
                                  <th>№</th>
                                  <th>Машина</th>
                                  <th>Организация</th>
                                  <th>Заезд</th>
                                  <th>Статус</th>
                                  <th className="right">Нетто, кг</th>
                                </tr>
                              </thead>
                              <tbody>
                                {C.list.map(($) => {
                                  const m = Ae($);
                                  return (
                                    <tr
                                      className="rowx"
                                      onClick={(v) => {
                                        (v.stopPropagation(), g($.id));
                                      }}
                                    >
                                      <td>{$.id}</td>
                                      <td>
                                        <b>{$.vehicle_no}</b>
                                      </td>
                                      <td>{$.client || "—"}</td>
                                      <td className="nowrap">{he($.in_at)}</td>
                                      <td>
                                        <span className={"stage " + m.c}>{m.t}</span>
                                      </td>
                                      <td className="right">
                                        <b>{q($.net_kg)}</b>
                                      </td>
                                    </tr>
                                  );
                                })}
                              </tbody>
                            </table>
                          </div>
                        </td>
                      </tr>
                    )}
                  </>
                );
              })}
            </tbody>
            <tfoot>
              <tr>
                <td>
                  <b>Итого {M.on ? "по поиску" : n}</b>
                </td>
                <td className="right">
                  <b>{_.reduce((C, y) => C + y.list.length, 0)}</b>
                </td>
                <td colSpan={3} />
                <td className="right">
                  <b>{q(h)}</b>
                </td>
                <td />
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
    </>
  );
}
function Qr({ me: t }) {
  const n = ys(),
    [s, l] = Te("reg.cont.view", "onterm", ut("reg_cont", "year")),
    i = s === "onterm",
    [u, o, x] = ne(
      () =>
        Y(
          i
            ? A.from("term_line_containers")
                .select("*")
                .is("out_at", null)
                .order("id", {
                  ascending: !1,
                })
                .limit(5e3)
            : A.from("term_line_containers")
                .select("*")
                .gte("in_at", Nt(+s)[0])
                .lt("in_at", Nt(+s)[1])
                .order("id", {
                  ascending: !1,
                })
                .limit(5e3),
        ),
      [s],
      3e4,
    ),
    [N] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height)")
            .order("id", {
              ascending: !1,
            })
            .limit(2e3),
        ),
      [],
      6e4,
    ),
    { who: b, W: j } = yt(),
    [g, d] = S.useState(() => ut("reg_cont", "flt")),
    [M, z] = S.useState(null),
    [_, h] = S.useState(null),
    [w, p] = S.useState(null),
    F = Pt("Поиск: номер, линия, клиент, букинг, площадка, пломба, сюрвейер…", ut("reg_cont", "q")),
    [C, y] = S.useState(!1),
    $ = u || [],
    m = N || [],
    { TH: CV_, apply: U } = rt(),
    Z = U(
      $.filter((I) => !g || Mt(I, n[I.batch_id]).k === g).filter((I) =>
        F.test(
          I.id,
          I.container_no,
          I.line,
          I.client,
          I.booking,
          I.cargo,
          I.site,
          I.seal_no,
          I.surveyor,
          I.out_vehicle_no,
          I.stack,
          (I.size || "") + (I.height || ""),
          tt(I, n),
        ),
      ),
      {
        id: (I) => I.id,
        no: (I) => I.container_no,
        tp: (I) => (I.size || "") + (I.height || ""),
        ln: (I) => I.line,
        cl: (I) => I.client,
        si: (I) => I.site,
        sv: (I) => I.surveyor,
        in: (I) => I.in_at,
        dd: (I) => Lt(I.in_at, I.out_at),
        st: (I) => tt(I, n),
        out: (I) => I.out_at,
      },
    );
  return (
    (F.enterRef.current = Z.length === 1 ? () => z(Z[0].id) : null),
    (
      <>
        {M &&
          (() => {
            const I = $.find((D) => D.id === M);
            return I ? <CPl c={I} loads={m.filter((D) => D.container_id === I.id)} who={b} me={t} onClose={() => z(null)} /> : null;
          })()}
        {_ && (
          <CAt
            title={`Контейнер ${_.container_no} · правка`}
            fields={Dl}
            row={_}
            table="term_line_containers"
            onClose={() => h(null)}
            onDone={() => {
              (p({
                ok: "Изменения сохранены",
              }),
                o());
            }}
          />
        )}
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">
              Реестр контейнеров · {i ? "на терминале" : s} · {Vt(F, Z.length, $.length)}
            </h2>
            <span
              className="row"
              style={{
                gap: 6,
                alignItems: "center",
              }}
            >
              <CPe value={s} onChange={(I) => I && l(I)} options={[["onterm", "На терминале"], ...Yr()]} w={130} ph="На терминале" />
              <Je make={() => Ze(`Контейнеры_${i ? "на_терминале" : s}`, [ws(Z, j, n)])} />
              {sn(t) && Z.length > 0 && Z.length < $.length && (
                <button
                  className="btn danger sm"
                  disabled={C}
                  title="Удалить все контейнеры, попавшие в текущий отбор"
                  onClick={() => Xi(Z, t, y, o, p)}
                >
                  {C ? "Удаляю…" : `✕ Удалить показанные · ${Z.length}`}
                </button>
              )}
            </span>
          </div>
          <p className="p-sub">
            {i ? "весь парк, который стоит на терминале сейчас — независимо от года заезда" : "контейнеры по году заезда"} · клик по строке — весь
            путь контейнера · ✎ — правка{sn(t) ? " · ✕ — удалить из базы вместе с затарками и вложениями" : ""}
          </p>
          <div className="findrow">
            {F.Find}
            <Yt
              win="reg_cont"
              params={{
                q: F.q,
                flt: g,
                year: s,
              }}
            />
          </div>
          <Tt
            val={g}
            onSel={d}
            items={kn
              .map(([I, D]) => ({
                k: I,
                t: D,
                n: $.filter((E) => Mt(E, n[E.batch_id]).k === I).length,
              }))
              .filter((I) => I.n)}
          />
          <CFe err={x} />
          <CFe {...(w || {})} />
          <div
            className="tscroll"
            style={{
              maxHeight: "64vh",
            }}
          >
            <table>
              <thead>
                <tr>
                  <CV_ k="id">№</CV_>
                  <CV_ k="no">Контейнер</CV_>
                  <CV_ k="tp">Тип</CV_>
                  <CV_ k="ln">Линия</CV_>
                  <CV_ k="cl">Клиент</CV_>
                  <CV_ k="si">Площадка</CV_>
                  <CV_ k="sv">Сюрвейер</CV_>
                  <CV_ k="in">Заезд</CV_>
                  <CV_ k="dd" right={!0}>
                    Дней
                  </CV_>
                  <CV_ k="st">Статус</CV_>
                  <th>Пломба</th>
                  <th>Машина вывоза</th>
                  <CV_ k="out">Выезд</CV_>
                  <th />
                </tr>
              </thead>
              <tbody>
                {Z.map((I) => {
                  const D = Lt(I.in_at, I.out_at);
                  return (
                    <tr className="rowx" onClick={() => z(I.id)}>
                      <td>{I.id}</td>
                      <td>
                        <b>{I.container_no}</b>
                      </td>
                      <td>{I.size ? `${I.size}' ${I.height || ""}` : "—"}</td>
                      <td>{I.line || "—"}</td>
                      <td>{I.client || "—"}</td>
                      <td>{I.site || "—"}</td>
                      <td>{I.surveyor || "—"}</td>
                      <td className="nowrap">{he(I.in_at)}</td>
                      <td
                        className="right"
                        style={
                          D != null && D > 30 && !I.out_at
                            ? {
                                color: "var(--warn)",
                                fontWeight: 700,
                              }
                            : void 0
                        }
                      >
                        {D ?? "—"}
                      </td>
                      <td>
                        <Et c={I} bm={n} />
                      </td>
                      <td>{I.seal_no || "—"}</td>
                      <td>
                        <CXt v={I.out_vehicle_no} />
                      </td>
                      <td className="nowrap">{he(I.out_at)}</td>
                      <td className="nowrap">
                        {mt("cont") && <Ye onClick={() => h(I)} />}
                        {sn(t) && (
                          <>
                            {" "}
                            <Jt onClick={() => er(I, t, o, p)} />
                          </>
                        )}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      </>
    )
  );
}
function CEa({ order: t, me: n, onClose: s }) {
  var He, We, Qe, Ie, ht, B;
  const [l, i] = S.useState("card");
  yt();
  const u = t.id,
    o = t.order_no,
    [x] = ne(() => Y(A.from("term_requests").select("*").eq("order_id", u).is("deleted_at", null).order("id")), [u], 0),
    N = S.useMemo(() => (x || []).map((r) => r.id), [x]),
    [b] = ne(
      () => (N.length ? Y(A.from("term_truck_visits").select("*").in("request_id", N).order("in_at")) : Promise.resolve([])),
      [N.join(",")],
      0,
    ),
    [j] = ne(() => Y(A.from("term_container_loads").select("*, term_line_containers(*)").eq("order_id", u).order("id")), [u], 0),
    [g] = ne(
      () => Y(A.from("term_container_loads").select("*, term_line_containers(*)").is("order_id", null).eq("order_name", o).order("id")),
      [o],
      0,
    ),
    [d] = ne(() => Y(A.from("term_orders").select("id, order_no, cargo").eq("order_no", o)), [o], 6e4),
    M = S.useMemo(() => (j || g ? [...(j || []), ...(g || [])] : null), [j, g]),
    [z] = ne(() => Y(A.from("term_mixes").select("*").order("id")), [], 6e4),
    [_] = ne(() => Y(A.from("term_batches").select("*").order("id")), [], 6e4),
    [h] = ne(
      () =>
        Y(
          A.from("term_docs")
            .select("*")
            .order("id", {
              ascending: !1,
            })
            .limit(500),
        ),
      [],
      6e4,
    ),
    w = !x || !b || !j || !g,
    p = b || [],
    F = M || [],
    C = x || [],
    y = S.useMemo(() => Object.fromEntries((_ || []).map((r) => [r.id, r])), [_]),
    $ = S.useMemo(() => Object.fromEntries((z || []).map((r) => [r.id, r])), [z]),
    m = C.reduce((r, O) => r + (+O.planned_tonnes || 0) * 1e3, 0),
    v = p.reduce((r, O) => r + (+O.net_kg || 0), 0),
    U = p.filter((r) => r.lab_status === "rejected"),
    Z = F.reduce((r, O) => r + (+(O.net_final_kg ?? O.net_kg) || 0), 0),
    I = F.reduce((r, O) => r + Math.max(0, +O.dotare_kg || 0), 0),
    D = F.reduce((r, O) => r + Math.max(0, -(+O.dotare_kg || 0)), 0),
    E = v - Z,
    a = F.filter((r) => {
      var O;
      return (O = r.term_line_containers) == null ? void 0 : O.out_at;
    }),
    f = a.reduce((r, O) => r + (+(O.net_final_kg ?? O.net_kg) || 0), 0),
    P = (r) => {
      const O = p
        .map((G) => G[r])
        .filter((G) => G != null && G !== "")
        .map(Number)
        .filter((G) => !isNaN(G));
      return O.length ? Math.round((O.reduce((G, ie) => G + ie, 0) / O.length) * 100) / 100 : null;
    },
    T = (r) => {
      const O = p
        .map((G) => G[r])
        .filter((G) => G != null && G !== "")
        .map(Number)
        .filter((G) => !isNaN(G));
      return O.length ? Math.max(...O) : null;
    },
    H = p
      .map((r) => r.in_at)
      .filter(Boolean)
      .sort()[0],
    Q = [...p.map((r) => r.tare_at), ...F.map((r) => r.gross_at)].filter(Boolean).sort().slice(-1)[0],
    ae = S.useMemo(() => {
      const r = {};
      for (const O of F) {
        const G = O.term_line_containers;
        G && (r[G.id] = G);
      }
      return Object.values(r);
    }, [F]),
    me = S.useMemo(
      () =>
        Fe(ae.map((r) => r.batch_id).filter(Boolean))
          .map((r) => y[r])
          .filter(Boolean),
      [ae, y],
    ),
    L = S.useMemo(() => Fe(ae.map((r) => r.booking).filter(Boolean)), [ae]),
    W = S.useMemo(
      () =>
        (h || []).filter((r) => {
          var O;
          return (
            L.includes(r.booking) ||
            (((O = r.payload) == null ? void 0 : O.containers) || []).some((G) => ae.some((ie) => ie.container_no === G.cont))
          );
        }),
      [h, L, ae],
    ),
    K = (d || []).length > 1,
    le = g || [],
    $e =
      ((We = (He = t.term_contracts) == null ? void 0 : He.term_counterparties) == null ? void 0 : We.name) ||
      ((Qe = C[0]) == null ? void 0 : Qe.client) ||
      "—",
    ee = t.cargo || ((Ie = p[0]) == null ? void 0 : Ie.culture) || ((ht = F[0]) == null ? void 0 : ht.culture) || "—",
    re = H && Q ? `${he(H)} — ${he(Q)}` : "—",
    be = (r) => (v > 0 ? Math.max(0, Math.min(100, Math.round((r / v) * 100))) : 0),
    Ne = st("Отчёт-по-грузу", o, $e, ee),
    ze = () => {
      var r;
      return Ze(`Отчёт_по_грузу_${(o || "").replace(/[^\w\-]+/g, "-")}`, [
        {
          name: "Итог",
          title: `ФЕНИКС · Терминал — отчёт по грузу · ${o} · ${$e}`,
          cols: [
            {
              h: "Показатель",
              w: 46,
            },
            {
              h: "Значение",
              w: 26,
            },
          ],
          rows: [
            ["Поручение", o],
            ["Договор", ((r = t.term_contracts) == null ? void 0 : r.contract_no) || ""],
            ["Клиент", $e],
            ["Груз", ee],
            ["Период работы", re],
            ["Заявлено машин", C.length],
            ["План, кг", m || ""],
            ["Приехало машин", p.length],
            ["Отказано лабораторией", U.length],
            ["Принято зерна, кг нетто", v],
            ["Затарено в контейнеры, кг", Z],
            ["в т.ч. дотарено, кг", I],
            ["в т.ч. растарено, кг", D],
            ["Контейнеров затарено", ae.length],
            ["Выпущено с терминала, кг", f],
            ["Остаток на терминале, кг", E],
            ["Партий", me.length],
            ["Букингов", L.join(", ")],
          ],
        },
        {
          name: "Приёмка",
          title: `Приёмка зерна · ${o}`,
          cols: [
            {
              h: "Машина",
              w: 13,
            },
            {
              h: "Заезд",
              w: 17,
            },
            {
              h: "Поставщик",
              w: 22,
            },
            {
              h: "Культура",
              w: 14,
            },
            {
              h: "Решение лаб.",
              w: 13,
            },
            {
              h: "Влаж. %",
              w: 9,
              num: 1,
            },
            {
              h: "Сор %",
              w: 9,
              num: 1,
            },
            {
              h: "Кол/бит %",
              w: 10,
              num: 1,
            },
            {
              h: "Зерн. %",
              w: 9,
              num: 1,
            },
            {
              h: "Путь груза",
              w: 14,
            },
            {
              h: "Замес",
              w: 12,
            },
            {
              h: "Площадка",
              w: 14,
            },
            {
              h: "Брутто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Тара, кг",
              w: 11,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Выезд",
              w: 17,
            },
          ],
          rows: p.map((O) => {
            var G;
            return [
              O.vehicle_no,
              Xe(O.in_at),
              O.supplier,
              O.culture,
              bs(O.lab_status),
              O.lab_moisture,
              O.lab_impurity,
              O.lab_broken,
              O.lab_grain_adm,
              O.lab_result1 ? Le[O.lab_result1] : "",
              ((G = $[O.mix_id]) == null ? void 0 : G.mix_no) || "",
              O.site,
              O.gross_kg,
              O.tare_kg,
              O.net_kg,
              Xe(O.out_at),
            ];
          }),
        },
        {
          name: "Затарка",
          title: `Затарка в контейнеры · ${o}`,
          cols: [
            {
              h: "Контейнер",
              w: 14,
            },
            {
              h: "Тип",
              w: 8,
            },
            {
              h: "Линия",
              w: 12,
            },
            {
              h: "Букинг",
              w: 14,
            },
            {
              h: "Машина",
              w: 13,
            },
            {
              h: "Тара, кг",
              w: 11,
              num: 1,
              int: 1,
            },
            {
              h: "Брутто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Дотарка/растарка, кг",
              w: 17,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто финал, кг",
              w: 14,
              num: 1,
              int: 1,
            },
            {
              h: "Пломба",
              w: 13,
            },
            {
              h: "Затарено",
              w: 17,
            },
            {
              h: "Партия",
              w: 13,
            },
            {
              h: "Выезд",
              w: 17,
            },
            {
              h: "Машина вывоза",
              w: 14,
            },
          ],
          rows: F.map((O) => {
            var ie;
            const G = O.term_line_containers || {};
            return [
              G.container_no,
              G.size ? `${G.size}'${G.height || ""}` : "",
              G.line,
              G.booking,
              O.vehicle_no,
              O.tare_kg,
              O.gross_kg,
              O.net_kg,
              O.dotare_kg,
              O.net_final_kg ?? O.net_kg,
              O.seal_no || G.seal_no,
              Xe(O.gross_at),
              ((ie = y[G.batch_id]) == null ? void 0 : ie.batch_no) || "",
              Xe(G.out_at),
              G.out_vehicle_no,
            ];
          }),
        },
        {
          name: "Документы",
          title: `Выпущенные документы · ${o}`,
          cols: [
            {
              h: "Вид",
              w: 18,
            },
            {
              h: "Номер",
              w: 16,
            },
            {
              h: "Дата",
              w: 14,
            },
            {
              h: "Букинг",
              w: 14,
            },
            {
              h: "Контейнеров",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Нетто, кг",
              w: 13,
              num: 1,
              int: 1,
            },
            {
              h: "Выпустил",
              w: 18,
            },
          ],
          rows: W.map((O) => [Us[O.kind] || O.kind, O.doc_no, O.doc_date, O.booking, O.rows_n, O.total_net_kg, O.by_name]),
        },
      ]);
    };
  if (w) return <At title={`Отчёт по грузу · ${o}`} onClose={s} />;
  const Ke = (
    <div
      className="row no-print"
      style={{
        gap: 8,
        marginBottom: 6,
      }}
    >
      <CPe
        value={l}
        onChange={i}
        w={230}
        ph="—"
        options={[
          ["card", "Карточка — подробно"],
          ["scheme", "Схема — для клиента"],
        ]}
      />
      <Je make={ze} label="⇩ Excel" />
    </div>
  );
  return (
    <CDt wide={!0} cls="rep9" title={`Отчёт по грузу · ${o} · ${$e}`} onClose={s} file={Ne}>
      <div className="crep">
        {Ke}
        {le.length ? (
          <div
            className="ovr9"
            style={{
              marginBottom: 10,
            }}
          >
            {le.length} затарок привязаны к поручению только номером «{o}»
            {K ? `, а этот номер носят ${(d || []).length} поручения (${(d || []).map((r) => r.cargo || "—").join(", ")})` : ""} — по ним связь не
            гарантирована.{K ? " Чтобы отчёт был точным, дайте поручениям разные номера, а такие затарки переоформите." : ""}
          </div>
        ) : null}
        {C.length ? null : (
          <div
            className="ovr9"
            style={{
              marginBottom: 10,
            }}
          >
            К этому поручению не привязано ни одной заявки — приход зерна показать не из чего. Заявки на машины заводит менеджер в разделе «Заявки».
          </div>
        )}
        {l === "scheme" ? (
          <>
            <C_e done={!0} title={`${ee} · ${$e}`} extra={re}>
              <div className="cflow">
                <div className={"cstep" + (p.length ? " done" : "")}>
                  <div className="cl">Пришло на терминал</div>
                  <div className="cv">{q(v)} кг</div>
                  <div className="cs">
                    {p.length} машин{U.length ? ` · отказано ${U.length}` : ""}
                    <br />
                    {H ? he(H) : "—"}
                  </div>
                </div>
                <div className="carr">→</div>
                <div className={"cstep" + (p.some((r) => r.ts_at) ? " done" : "")}>
                  <div className="cl">Перевалка</div>
                  <div className="cv">
                    {p.filter((r) => r.ts_at).length} / {p.length}
                  </div>
                  <div className="cs">
                    {Fe(p.map((r) => r.ts_service || (r.lab_result1 ? Le[r.lab_result1] : null)).filter(Boolean)).join(", ") || "услуга не отмечена"}
                    <br />
                    площадки: {Fe(p.map((r) => r.site).filter(Boolean)).join(", ") || "—"}
                  </div>
                </div>
                <div className="carr">→</div>
                <div className={"cstep" + (F.length ? " done" : "")}>
                  <div className="cl">Затарено в контейнеры</div>
                  <div className="cv">{q(Z)} кг</div>
                  <div className="cs">
                    {ae.length} контейнеров{I ? ` · дотарено ${q(I)} кг` : ""}
                    {D ? ` · растарено ${q(D)} кг` : ""}
                  </div>
                </div>
                <div className="carr">→</div>
                <div className={"cstep" + (a.length ? " done" : "")}>
                  <div className="cl">Ушло с терминала</div>
                  <div className="cv">{q(f)} кг</div>
                  <div className="cs">
                    {a.length} контейнеров{me.length ? ` · партии ${me.map((r) => r.batch_no).join(", ")}` : ""}
                  </div>
                </div>
              </div>
              <div className="cleg">
                <span className="l1">ушло с терминала</span>
                <span className="l2">затарено, ждёт вывоза</span>
                <span className="l3">на площадке, не затарено</span>
              </div>
              <div className="cbar">
                <i
                  className="b1"
                  style={{
                    width: be(f) + "%",
                  }}
                />
                <i
                  className="b2"
                  style={{
                    width: be(Math.max(0, Z - f)) + "%",
                  }}
                />
                <i
                  className="b3"
                  style={{
                    width: be(Math.max(0, E)) + "%",
                  }}
                />
              </div>
              <p
                className="p-sub"
                style={{
                  margin: "4px 0 0",
                }}
              >
                принято {q(v)} кг · затарено {q(Z)} кг · вывезено {q(f)} кг · осталось на площадке {q(Math.max(0, E))} кг
              </p>
            </C_e>
            <C_e done={p.some((r) => r.lab_at)} title="Качество принятого зерна">
              <div className="qgrid">
                {[
                  ["lab_moisture", "Влажность"],
                  ["lab_impurity", "Сорность"],
                  ["lab_broken", "Колотые/битые"],
                  ["lab_grain_adm", "Зерновая примесь"],
                ].map(([r, O]) => (
                  <div className="qbox">
                    <div className="l">{O}</div>
                    <div className="v">{P(r) != null ? P(r) + " %" : "—"}</div>
                    <div className="s">
                      среднее по {p.filter((G) => G[r] != null).length} машинам{T(r) != null ? ` · макс ${T(r)} %` : ""}
                    </div>
                  </div>
                ))}
              </div>
            </C_e>
            <C_e done={ae.length > 0} title="Контейнеры" extra={`${ae.length} шт`}>
              <div
                className="row"
                style={{
                  gap: 6,
                  flexWrap: "wrap",
                }}
              >
                {ae.map((r) => (
                  <span className={"t2chip" + (r.out_at ? " ok" : "")} title={r.out_at ? `ушёл ${he(r.out_at)}` : tt(r, y)}>
                    {r.container_no}
                  </span>
                ))}
                {ae.length ? null : <span className="faint">ещё ни одного</span>}
              </div>
            </C_e>
          </>
        ) : (
          <>
            <C_e done={!0} title="Поручение" extra={o}>
              <div className="dgrid">
                <R l="Клиент" v={$e} />
                <R l="Договор" v={(B = t.term_contracts) == null ? void 0 : B.contract_no} />
                <R l="Груз" v={ee} />
                <R l="Объём по поручению, т" v={t.volume_t} />
                <R l="Заявлено машин" v={C.length} />
                <R l="План по заявкам, кг" v={m ? q(m) : null} />
                <R l="Период работы" v={re} />
                <R l="Букинг(и)" v={L.join(", ")} />
              </div>
            </C_e>
            <C_e done={p.length > 0} title="Приёмка зерна" extra={`${p.length} машин · ${q(v)} кг нетто`}>
              <div className="tscroll">
                <table>
                  <thead>
                    <tr>
                      <th>Машина</th>
                      <th>Заезд</th>
                      <th>Поставщик</th>
                      <th>Лаб.</th>
                      <th className="right">Влаж.</th>
                      <th className="right">Сор</th>
                      <th className="right">Кол/бит</th>
                      <th>Путь груза</th>
                      <th>Замес</th>
                      <th>Площадка</th>
                      <th className="right">Нетто, кг</th>
                    </tr>
                  </thead>
                  <tbody>
                    {p.map((r) => {
                      var O;
                      return (
                        <tr>
                          <td>
                            <b>{r.vehicle_no}</b>
                          </td>
                          <td className="nowrap">{he(r.in_at)}</td>
                          <td>{r.supplier || "—"}</td>
                          <td>{bs(r.lab_status)}</td>
                          <td className="right">{r.lab_moisture ?? "—"}</td>
                          <td className="right">{r.lab_impurity ?? "—"}</td>
                          <td className="right">{r.lab_broken ?? "—"}</td>
                          <td>{r.lab_result1 ? Le[r.lab_result1] : "—"}</td>
                          <td>{((O = $[r.mix_id]) == null ? void 0 : O.mix_no) || "—"}</td>
                          <td>{r.site || "—"}</td>
                          <td className="right">
                            <b>{q(r.net_kg)}</b>
                          </td>
                        </tr>
                      );
                    })}
                    {p.length ? null : (
                      <tr>
                        <td colSpan={11} className="faint">
                          по этому поручению машины ещё не приезжали
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </div>
              {U.length ? (
                <p
                  className="p-sub"
                  style={{
                    margin: "6px 0 0",
                    color: "var(--bad)",
                  }}
                >
                  отказано лабораторией: {U.map((r) => r.vehicle_no).join(", ")}
                </p>
              ) : null}
            </C_e>
            <C_e done={p.some((r) => r.ts_at)} title="Перевалка · что делали с грузом" extra={`${p.filter((r) => r.ts_at).length} из ${p.length}`}>
              <div className="dgrid">
                <R l="Оказанные услуги" v={Fe(p.map((r) => r.ts_service || (r.lab_result1 ? Le[r.lab_result1] : null)).filter(Boolean)).join(", ")} />
                <R l="Площадки" v={Fe(p.map((r) => r.site).filter(Boolean)).join(", ")} />
                <R
                  l="Замесы"
                  v={Fe(
                    p
                      .map((r) => {
                        var O;
                        return (O = $[r.mix_id]) == null ? void 0 : O.mix_no;
                      })
                      .filter(Boolean),
                  ).join(", ")}
                />
                <R l="Доп. услуги оказаны" v={Fe(p.flatMap((r) => r.extra_done || [])).join(", ")} />
              </div>
            </C_e>
            <C_e done={F.length > 0} title="Затарка в контейнеры" extra={`${ae.length} контейнеров · ${q(Z)} кг`}>
              <div className="tscroll">
                <table>
                  <thead>
                    <tr>
                      <th>Контейнер</th>
                      <th>Тип</th>
                      <th>Линия</th>
                      <th>Букинг</th>
                      <th>Машина</th>
                      <th className="right">Нетто</th>
                      <th className="right">Дот./раст.</th>
                      <th className="right">Нетто финал</th>
                      <th>Пломба</th>
                      <th>Затарено</th>
                      <th>Партия</th>
                      <th>Выезд</th>
                    </tr>
                  </thead>
                  <tbody>
                    {F.map((r) => {
                      var G;
                      const O = r.term_line_containers || {};
                      return (
                        <tr>
                          <td>
                            <b>{O.container_no}</b>
                          </td>
                          <td>{O.size ? `${O.size}'${O.height || ""}` : "—"}</td>
                          <td>{O.line || "—"}</td>
                          <td>{O.booking || "—"}</td>
                          <td>
                            <CXt v={r.vehicle_no} />
                          </td>
                          <td className="right">{q(r.net_kg)}</td>
                          <td className="right">{r.dotare_kg == null || +r.dotare_kg == 0 ? "—" : (+r.dotare_kg > 0 ? "+" : "") + q(r.dotare_kg)}</td>
                          <td className="right">
                            <b>{q(r.net_final_kg ?? r.net_kg)}</b>
                          </td>
                          <td>{r.seal_no || O.seal_no || "—"}</td>
                          <td className="nowrap">{he(r.gross_at)}</td>
                          <td>{((G = y[O.batch_id]) == null ? void 0 : G.batch_no) || "—"}</td>
                          <td className="nowrap">{O.out_at ? he(O.out_at) : "—"}</td>
                        </tr>
                      );
                    })}
                    {F.length ? null : (
                      <tr>
                        <td colSpan={12} className="faint">
                          по этому поручению затарок ещё не было
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </div>
            </C_e>
            <C_e done={a.length > 0} title="Отгрузка с терминала" extra={`${a.length} контейнеров · ${q(f)} кг`}>
              <div className="dgrid">
                <R l="Партии" v={me.map((r) => `${r.batch_no} (${vt[r.status] || r.status})`).join(", ")} />
                <R l="Вывезено контейнеров" v={`${a.length} из ${ae.length}`} />
                <R l="Вывезено, кг" v={q(f)} />
                <R l="Ещё на терминале, кг" v={q(Math.max(0, Z - f))} />
              </div>
            </C_e>
            <C_e done={W.length > 0} title="Выпущенные документы" extra={`${W.length}`}>
              <div className="tscroll">
                <table>
                  <thead>
                    <tr>
                      <th>Вид</th>
                      <th>Номер</th>
                      <th>Дата</th>
                      <th>Букинг</th>
                      <th className="right">Контейнеров</th>
                      <th className="right">Нетто, кг</th>
                      <th>Выпустил</th>
                    </tr>
                  </thead>
                  <tbody>
                    {W.map((r) => (
                      <tr>
                        <td>{Us[r.kind] || r.kind}</td>
                        <td>
                          <b>{r.doc_no}</b>
                        </td>
                        <td>{r.doc_date || "—"}</td>
                        <td>{r.booking || "—"}</td>
                        <td className="right">{r.rows_n ?? "—"}</td>
                        <td className="right">{q(r.total_net_kg)}</td>
                        <td>{r.by_name || "—"}</td>
                      </tr>
                    ))}
                    {W.length ? null : (
                      <tr>
                        <td colSpan={7} className="faint">
                          акты и справки по этому грузу ещё не выпускались
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </div>
            </C_e>
            <C_e done={!0} title="Баланс груза">
              <div className="dgrid">
                <R l="Принято зерна, кг" v={q(v)} />
                <R l="Затарено в контейнеры, кг" v={q(Z)} />
                <R l="в т.ч. дотарено, кг" v={I ? q(I) : null} />
                <R l="в т.ч. растарено, кг" v={D ? q(D) : null} />
                <R l="Осталось на площадке, кг" v={q(E)} />
                <R l="Отчёт составлен" v={he(new Date().toISOString()) + " · " + ((n == null ? void 0 : n.name) || "")} />
              </div>
              {E < 0 ? (
                <p
                  className="p-sub"
                  style={{
                    margin: "6px 0 0",
                    color: "var(--warn)",
                  }}
                >
                  затарено больше, чем принято по этому поручению — часть груза пришла по другому поручению или в затарке указано не то поручение
                </p>
              ) : null}
            </C_e>
          </>
        )}
      </div>
    </CDt>
  );
}
function ta({ me: t }) {
  const n = ys(),
    [s, l] = S.useState(null),
    [i, u] = Te("rep.cargo", {}),
    [o] = ne(
      () =>
        Y(
          A.from("term_orders")
            .select("id, order_no, cargo, volume_t, term_contracts(contract_no, term_counterparties(name))")
            .order("id", {
              ascending: !1,
            })
            .limit(1e3),
        ),
      [],
      6e4,
    ),
    x = S.useMemo(
      () =>
        (o || []).filter((ee) => {
          var re, be;
          return (
            (!i.cli || ((be = (re = ee.term_contracts) == null ? void 0 : re.term_counterparties) == null ? void 0 : be.name) === i.cli) &&
            (!i.cargo || ee.cargo === i.cargo)
          );
        }),
      [o, i.cli, i.cargo],
    ),
    [N, b] = S.useState(null),
    [j, g] = S.useState(null),
    [d, M] = Te("rep.year", String(new Date().getFullYear())),
    [z, _] = Te("rep.mon", ""),
    { W: h } = yt(),
    [w, p] = Nt(+d, z ? +z : null),
    [F, , C] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .gte("tare_at", w)
            .lt("tare_at", p)
            .order("id", {
              ascending: !1,
            })
            .limit(1e4),
        ),
      [d, z],
      6e4,
    ),
    [y] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("id, vehicle_no, culture, lab_at, lab_status")
            .eq("lab_status", "rejected")
            .gte("lab_at", w)
            .lt("lab_at", p)
            .limit(5e3),
        ),
      [d, z],
      6e4,
    ),
    [$] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .gte("in_at", w)
            .lt("in_at", p)
            .order("id", {
              ascending: !1,
            })
            .limit(1e4),
        ),
      [d, z],
      6e4,
    ),
    [m] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("*")
            .gte("in_at", w)
            .lt("in_at", p)
            .order("id", {
              ascending: !1,
            })
            .limit(1e4),
        ),
      [d, z],
      6e4,
    ),
    [v] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height, line, site, booking, seal_no, cont_tare_kg, client, cargo)")
            .gte("tare_at", w)
            .lt("tare_at", p)
            .order("id", {
              ascending: !1,
            })
            .limit(1e4),
        ),
      [d, z],
      6e4,
    ),
    [U] = ne(
      () =>
        Y(
          A.from("term_requests")
            .select("*, term_orders(order_no, term_contracts(contract_no, term_counterparties(name)))")
            .is("deleted_at", null)
            .gte("created_at", w)
            .lt("created_at", p)
            .order("id", {
              ascending: !1,
            })
            .limit(1e4),
        ),
      [d, z],
      6e4,
    ),
    Z = F || [],
    I = m || [],
    D = v || [],
    E = U || [],
    a = $ || [],
    f = Z.reduce((ee, re) => ee + (+re.net_kg || 0), 0),
    P = D.reduce((ee, re) => ee + (+(re.net_final_kg ?? re.net_kg) || 0), 0),
    T = (y || []).length,
    H = z ? `${dn[+z - 1]} ${d}` : `${d} год`,
    Q = "тоннаж признаётся по дате взвешивания порожним (когда нетто фактически известно) — так же, как в Сводке управляющего",
    ae = z ? `${d}-${z}` : d,
    me = {};
  Z.forEach((ee) => {
    if (ee.net_kg) {
      const re = (ee.culture || "").trim() || "Без культуры";
      me[re] = (me[re] || 0) + +ee.net_kg;
    }
  });
  const L = Object.entries(me)
      .map(([ee, re]) => ({
        l: ee,
        v: re / 1e3,
      }))
      .sort((ee, re) => re.v - ee.v)
      .slice(0, 8),
    [W] = ne(
      () =>
        Y(
          A.from("term_load_allocs")
            .select("*")
            .order("id", {
              ascending: !1,
            })
            .limit(1e4),
        ),
      [],
      6e4,
    ),
    K = S.useMemo(() => {
      const ee = new Set(D.map((be) => be.id)),
        re = {};
      return (
        (W || [])
          .filter((be) => ee.has(be.load_id))
          .forEach((be) => {
            const Ne = be.contract + "¦" + (be.marker || "");
            ((re[Ne] = re[Ne] || {
              contract: be.contract,
              marker: be.marker,
              n: 0,
              kg: 0,
              rows: [],
            }),
              re[Ne].n++,
              (re[Ne].kg += +be.weight_kg || 0),
              re[Ne].rows.push(be));
          }),
        Object.values(re).sort((be, Ne) => Ne.kg - be.kg)
      );
    }, [W, D]),
    le = {
      name: "Сводка",
      title: `ФЕНИКС · Терминал — сводный отчёт · ${H}`,
      cols: [
        {
          h: "Показатель",
          w: 44,
        },
        {
          h: "Значение",
          w: 20,
          num: 1,
          int: 1,
        },
      ],
      rows: [
        ["Зерновозов (заезды)", Z.length],
        ["Принято зерна, кг нетто", f],
        ["Отказов лаборатории", T],
        ["Контейнеров (заезды)", I.length],
        ["Погрузок (перетарка)", D.length],
        ["Погружено в контейнеры, кг нетто", P],
        ["Создано заявок", E.length],
      ],
    },
    $e = () =>
      Ze(`Отчёт_${ae}`, [
        le,
        mn(E),
        ks(Z, h),
        ws(I, h, n),
        Ws(D, h),
        {
          name: "Культуры",
          title: `ФЕНИКС · Терминал — культуры · ${H}`,
          cols: [
            {
              h: "Культура",
              w: 24,
            },
            {
              h: "Нетто, кг",
              w: 16,
              num: 1,
              int: 1,
            },
          ],
          rows: Object.entries(me)
            .sort((ee, re) => re[1] - ee[1])
            .map(([ee, re]) => [ee, re]),
        },
      ]);
  return (
    <>
      {s && <CEa order={s} me={t} onClose={() => l(null)} />}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Отчёт клиенту по грузу</h2>
        </div>
        <p className="p-sub">
          весь путь груза одним документом: что пришло и когда, с каким качеством, что делали на площадке, в какие контейнеры затарили (с дотарками и
          растарками) и когда вывезли · два вида одного отчёта — «карточка» подробно и «схема» для клиента · из окна отчёта выгружается PDF и Excel
        </p>
        <div
          className="row"
          style={{
            gap: 8,
          }}
        >
          <X label="Клиент">
            <CPe
              value={i.cli || ""}
              onChange={(ee) =>
                u((re) => ({
                  ...re,
                  cli: ee,
                  ord: "",
                }))
              }
              w={260}
              ph="— все —"
              options={Fe(
                (o || [])
                  .map((ee) => {
                    var re, be;
                    return (be = (re = ee.term_contracts) == null ? void 0 : re.term_counterparties) == null ? void 0 : be.name;
                  })
                  .filter(Boolean),
              ).map((ee) => [ee, ee])}
            />
          </X>
          <X label="Груз (культура)">
            <CPe
              value={i.cargo || ""}
              onChange={(ee) =>
                u((re) => ({
                  ...re,
                  cargo: ee,
                  ord: "",
                }))
              }
              w={190}
              ph="— все —"
              options={Fe((o || []).map((ee) => ee.cargo).filter(Boolean)).map((ee) => [ee, ee])}
            />
          </X>
          <X label={`Поручение · ${x.length}`}>
            <CPe
              value={i.ord || ""}
              onChange={(ee) =>
                u((re) => ({
                  ...re,
                  ord: ee,
                }))
              }
              w={340}
              ph="— выбери поручение —"
              options={x.map((ee) => {
                var re, be;
                return [
                  String(ee.id),
                  `${ee.order_no} · ${ee.cargo || "—"}${ee.volume_t != null ? ` · ${ee.volume_t} т` : ""} · ${((be = (re = ee.term_contracts) == null ? void 0 : re.term_counterparties) == null ? void 0 : be.name) || "—"}`,
                ];
              })}
            />
          </X>
          <button className="btn" disabled={!i.ord} onClick={() => l(x.find((ee) => String(ee.id) === String(i.ord)))}>
            Собрать отчёт
          </button>
        </div>
        {o ? (
          x.length ? null : (
            <p
              className="p-sub"
              style={{
                margin: "6px 0 0",
              }}
            >
              под этот отбор поручений нет
            </p>
          )
        ) : (
          <p
            className="p-sub"
            style={{
              margin: "6px 0 0",
            }}
          >
            загружаю список поручений…
          </p>
        )}
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Отчёты · {H}</h2>
          <span
            className="row"
            style={{
              gap: 6,
              alignItems: "center",
            }}
          >
            <CPe value={d} onChange={(ee) => ee && M(ee)} options={Dn()} w={100} ph={d} />
            <CPe value={z} onChange={(ee) => _(ee)} options={dn.map((ee, re) => [String(re + 1).padStart(2, "0"), ee])} w={140} ph="Весь год" />
          </span>
        </div>
        <p className="p-sub">
          сводные показатели за период и выгрузки Excel в фирменной стилистике · <b>{Q}</b> · удалённые заявки в цифры не попадают
        </p>
        <CFe err={C} />
        <div
          className="kpis"
          style={{
            marginTop: 8,
          }}
        >
          <div className="kpi">
            <div className="l">Зерновозов взвешено</div>
            <div className="v">{Z.length}</div>
            <div className="s">заездов за период: {a.length}</div>
          </div>
          <div className="kpi">
            <div className="l">Принято зерна</div>
            <div className="v">{q(f)}</div>
            <div className="s">кг нетто · отказов: {T}</div>
          </div>
          <div className="kpi">
            <div className="l">Контейнеров</div>
            <div className="v">{I.length}</div>
            <div className="s">заезды за период</div>
          </div>
          <div className="kpi">
            <div className="l">Погрузок</div>
            <div className="v">{D.length}</div>
            <div className="s">перетарка</div>
          </div>
          <div className="kpi">
            <div className="l">Погружено</div>
            <div className="v">{q(P)}</div>
            <div className="s">кг нетто в контейнеры</div>
          </div>
        </div>
        <div
          className="row"
          style={{
            marginTop: 14,
            gap: 8,
          }}
        >
          <Je label="⇩ Excel · сводный отчёт периода" make={$e} />
          <Je label="⇩ Зерновозы" make={() => Ze(`Зерновозы_${ae}`, [ks(Z, h)])} />
          <Je label="⇩ Контейнеры" make={() => Ze(`Контейнеры_${ae}`, [ws(I, h, n)])} />
          <Je label="⇩ Погрузки" make={() => Ze(`Погрузки_${ae}`, [Ws(D, h)])} />
          <Je label="⇩ Заявки" make={() => Ze(`Заявки_${ae}`, [mn(E)])} />
          <Je label="⇩ Excel · вся работа терминала" make={() => Il(h, d)} />
        </div>
      </div>
      <div className="panel">
        <h2 className="p-title">Культуры за период</h2>
        <p className="p-sub">принято тонн нетто · {H}</p>
        <Ps data={L} fmt={(ee) => q(Math.round(ee))} unit=" т" />
      </div>
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Партии · к выставлению счетов · {H}</h2>
          <Je
            make={() =>
              Ze(`Партии_${ae}`, [
                {
                  name: "Партии",
                  title: `ФЕНИКС · Терминал — партии (контракты продажи) · ${H}`,
                  cols: [
                    {
                      h: "Контракт / партия",
                      w: 22,
                    },
                    {
                      h: "Маркер",
                      w: 10,
                    },
                    {
                      h: "Контейнеров",
                      w: 12,
                      num: 1,
                      int: 1,
                    },
                    {
                      h: "Вес, кг",
                      w: 14,
                      num: 1,
                      int: 1,
                    },
                  ],
                  rows: K.map((ee) => [ee.contract, ee.marker, ee.n, ee.kg]),
                },
              ])
            }
          />
        </div>
        <p className="p-sub">
          распределение затарок по контрактам продажи (кнопка «Партии» на весовой) · сводка для счетов по партиям · клик по строке — затарки, вошедшие
          в эту партию
        </p>
        {K.length ? (
          <div
            className="tscroll"
            style={{
              maxHeight: 320,
            }}
          >
            <table>
              <thead>
                <tr>
                  <th>Контракт / партия</th>
                  <th>Маркер</th>
                  <th className="right">Контейнеров</th>
                  <th className="right">Вес, кг</th>
                </tr>
              </thead>
              <tbody>
                {K.map((ee, re) => (
                  <tr className="rowx" title="Затарки, вошедшие в партию" onClick={() => b(ee)}>
                    <td>
                      <b>{ee.contract}</b>
                    </td>
                    <td>{ee.marker || "—"}</td>
                    <td className="right">{ee.n}</td>
                    <td className="right">
                      <b>{q(ee.kg)}</b>
                    </td>
                  </tr>
                ))}
              </tbody>
              <tfoot>
                <tr>
                  <td colSpan={2}>
                    <b>Итого</b>
                  </td>
                  <td className="right">
                    <b>{K.reduce((ee, re) => ee + re.n, 0)}</b>
                  </td>
                  <td className="right">
                    <b>{q(K.reduce((ee, re) => ee + re.kg, 0))}</b>
                  </td>
                </tr>
              </tfoot>
            </table>
          </div>
        ) : (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            за период распределений нет
          </p>
        )}
      </div>
      {j && <CRs id={j} me={t} onClose={() => g(null)} />}
      {N && !j && (
        <div
          className="modal-bg"
          onMouseDown={(ee) => {
            ee.target === ee.currentTarget && b(null);
          }}
        >
          <div
            className="modal wide9"
            style={{
              width: 900,
              maxWidth: "96vw",
            }}
          >
            <div className="hd">
              <h2 className="p-title mt0">
                Партия · {N.contract}
                {N.marker ? ` · ${N.marker}` : ""}
              </h2>
              <button className="btn sec sm" onClick={() => b(null)}>
                ✕
              </button>
            </div>
            <div className="m-body">
              <p
                className="p-sub"
                style={{
                  marginTop: 0,
                }}
              >
                затарок в партии: {N.n} · вес {q(Math.round(N.kg))} кг · клик по строке — карточка затарки
              </p>
              <div
                className="tscroll"
                style={{
                  maxHeight: "56vh",
                }}
              >
                <table className="minit">
                  <thead>
                    <tr>
                      <th>Контейнер</th>
                      <th>Машина</th>
                      <th>Затарен</th>
                      <th className="right">Вес в партию, кг</th>
                      <th className="right">Нетто затарки, кг</th>
                    </tr>
                  </thead>
                  <tbody>
                    {N.rows.map((ee) => {
                      var be;
                      const re = D.find((Ne) => Ne.id === ee.load_id) || {};
                      return (
                        <tr className="rowx" onClick={() => g(ee.load_id)}>
                          <td>
                            <b>{((be = re.term_line_containers) == null ? void 0 : be.container_no) || "—"}</b>
                          </td>
                          <td>
                            <CXt v={re.vehicle_no} />
                          </td>
                          <td className="nowrap">{he(re.gross_at)}</td>
                          <td className="right">
                            <b>{q(ee.weight_kg)}</b>
                          </td>
                          <td className="right">{q(re.net_final_kg ?? re.net_kg)}</td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      )}
      <CSa L={D} me={t} />
    </>
  );
}
function CSa({ L: t, me: n }) {
  const [s, l] = S.useState(null),
    [i, u] = Te("rep.docs", {}),
    [o, x] = S.useState(null),
    N = S.useMemo(() => (t || []).filter((h) => h.gross_kg != null && h.term_line_containers), [t]),
    b = Fe(N.map((h) => h.term_line_containers.booking)),
    j = Fe(N.map((h) => Ve(h.gross_at || h.tare_at)))
      .sort()
      .reverse(),
    g = S.useMemo(
      () =>
        !i.bk && !i.dt
          ? []
          : N.filter((h) => {
              const w = h.term_line_containers;
              return !((i.bk && (w.booking || "") !== i.bk) || (i.dt && Ve(h.gross_at || h.tare_at) !== i.dt));
            }).sort((h, w) => (h.gross_at || "").localeCompare(w.gross_at || "")),
      [N, i.bk, i.dt],
    ),
    d = () => g.map(ml),
    M = Ns(),
    z = (h, w) => {
      const p = [],
        F = h.filter((v) => v.tare == null);
      F.length &&
        p.push(
          `нет паспортной тары контейнера: ${F.slice(0, 4)
            .map((v) => v.cont)
            .join(", ")}${F.length > 4 ? "…" : ""}`,
        );
      const C = h.filter((v) => v.net == null);
      C.length &&
        p.push(
          `нет веса затарки: ${C.slice(0, 4)
            .map((v) => v.cont)
            .join(", ")}`,
        );
      const y = h.filter((v) => !v.seal);
      y.length &&
        p.push(
          `нет пломбы: ${y
            .slice(0, 4)
            .map((v) => v.cont)
            .join(", ")}`,
        );
      const $ = h.filter((v) => v.is_temp);
      $.length && p.push(`в списке есть времянки (внутреннее перемещение, не отгрузка): ${$.map((v) => v.cont).join(", ")}`);
      const m = [...new Set(h.map((v) => v.booking).filter(Boolean))];
      return (m.length > 1 && p.push(`в одном документе разные букинги: ${m.join(", ")}`), p);
    },
    _ = async () => {
      if (!i.bk && !i.dt) {
        x({
          err: "Укажи букинг и/или дату затарки — иначе сертификат выпишется на все затарки периода, то есть на разные отправки сразу",
        });
        return;
      }
      if (!g.length) {
        x({
          err: "По выбранному отбору затарок нет",
        });
        return;
      }
      if (!(i.cert || "").trim()) {
        x({
          err: "Укажи номер VGM-сертификата — он записывается в журнал документов",
        });
        return;
      }
      const h = d(),
        w = h.filter((F) => F.vgm == null);
      if (w.length) {
        x({
          err: `У ${w.length} контейнеров нет тары (паспорта) — VGM не посчитать: ${w
            .slice(0, 3)
            .map((F) => F.cont)
            .join(", ")}…`,
        });
        return;
      }
      const p = z(h);
      if (!(
        p.length &&
        !window.confirm(`VGM выпускается с замечаниями:

• ${p.join(`
• `)}

Всё равно выпустить?`)
      ))
        try {
          const F = i.adate || M,
            C = await vn({
              kind: "vgm",
              no: (i.cert || "").trim(),
              date: F,
              booking: i.bk || h[0].booking || null,
              rows: h,
              me: qt.me,
            });
          (await ji({
            certNo: (i.cert || "").trim(),
            certDate: i.adate || M,
            calibDate: i.calib || ot.S.scale_calib_date,
            declarant: i.decl || ot.S.vgm_declarant,
            method: ot.S.vgm_method,
            rows: h,
          }),
            x({
              ok: `VGM-сертификат №${(i.cert || "").trim()}: ${h.length} контейнеров${C === "copy" ? " — повторная печать (копия)" : " — записан в журнал документов"}`,
            }));
        } catch (F) {
          x({
            err: String(F.message || F),
          });
        }
    };
  return (
    <div className="panel">
      {s && <CRs id={s} me={n} onClose={() => l(null)} />}
      <div className="hd">
        <h2 className="p-title mt0">Документы отгрузки · VGM-сертификат</h2>
      </div>
      <p className="p-sub">
        выбери букинг и/или дату затарки · номер сертификата обязателен и проверяется на повтор, каждый выпуск пишется в журнал документов ниже ·{" "}
        <b>акт затарки выпускается в разделе «Партии · отправка»</b> — там единый номер и единые проверки
      </p>
      <div
        className="row"
        style={{
          gap: 8,
        }}
      >
        <X label="Букинг">
          <CPe
            value={i.bk || ""}
            onChange={(h) =>
              u((w) => ({
                ...w,
                bk: h,
              }))
            }
            options={b}
            w={190}
            ph="— любой —"
          />
        </X>
        <X label="Дата затарки">
          <CPe
            value={i.dt || ""}
            onChange={(h) =>
              u((w) => ({
                ...w,
                dt: h,
              }))
            }
            options={j.map((h) => [h, h.split("-").reverse().join(".")])}
            w={140}
            ph="— любая —"
          />
        </X>
        <X label="Дата документа">{Se(i, u, "adate", M, 110)}</X>
        <X label="№ VGM-сертификата *">{Se(i, u, "cert", "например VGM-26-0007", 170)}</X>
      </div>
      <div
        className="row"
        style={{
          marginTop: 12,
          gap: 8,
        }}
      >
        <Je label={`⇩ VGM-сертификат (${g.length})`} make={_} />
        <span
          className="p-sub"
          style={{
            margin: 0,
          }}
        >
          подходит затарок: {g.length}
          {g.length ? ` · нетто ${q(g.reduce((h, w) => h + (+(w.net_final_kg ?? w.net_kg) || 0), 0))} кг` : ""}
        </span>
      </div>
      <CFe {...(o || {})} />
      {g.length > 0 && (
        <div
          className="tscroll"
          style={{
            maxHeight: 240,
          }}
        >
          <table>
            <thead>
              <tr>
                <th>№</th>
                <th>Контейнер</th>
                <th>Тип</th>
                <th>Линия</th>
                <th>Дата затарки</th>
                <th className="right">Нетто, кг</th>
                <th className="right">Тара конт., кг</th>
                <th className="right">VGM, кг</th>
                <th>Пломба</th>
              </tr>
            </thead>
            <tbody>
              {d().map((h, w) => (
                <tr className="rowx" title="Карточка затарки" onClick={() => l(g[w].id)}>
                  <td>{w + 1}</td>
                  <td>
                    <b>{h.cont}</b>
                  </td>
                  <td>{h.type}</td>
                  <td>{h.line || "—"}</td>
                  <td className="nowrap">{he(g[w].gross_at)}</td>
                  <td className="right">{q(h.net)}</td>
                  <td className="right">{q(h.tare)}</td>
                  <td className="right">
                    <b>{h.vgm != null ? q(h.vgm) : "—"}</b>
                  </td>
                  <td>{h.seal || "—"}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}
const xn = () => {
  const t = "abcdefghjkmnpqrstuvwxyz",
    n = "ABCDEFGHJKMNPQRSTUVWXYZ",
    s = "23456789",
    l = (i, u) =>
      Array.from(
        {
          length: u,
        },
        () => i[Math.floor(Math.random() * i.length)],
      ).join("");
  return "Fx-" + l(n, 1) + l(t, 3) + "-" + l(s, 4);
};
function CNa({ call: t, onClose: n, onDone: s }) {
  const [l, i] = S.useState({
      role: "manager",
      password: xn(),
    }),
    [u, o] = S.useState(!1),
    [x, N] = S.useState(null),
    b = async () => {
      const j = (l.email || "").trim().toLowerCase();
      if (!/^\S+@\S+\.\S+$/.test(j)) {
        N("Укажи корректный email — он будет логином");
        return;
      }
      if (!(l.name || "").trim()) {
        N("Укажи ФИО сотрудника");
        return;
      }
      if (String(l.password || "").length < 8) {
        N("Пароль не короче 8 символов");
        return;
      }
      (o(!0), N(null));
      const g = await t({
        action: "create",
        email: j,
        password: l.password,
        display_name: l.name.trim(),
        role: l.role,
        phone: gn(l.phone),
      });
      if ((o(!1), g.error)) {
        N(g.error);
        return;
      }
      s({
        email: j,
        password: l.password,
        t: "Сотрудник создан",
      });
    };
  return (
    <Ss
      title="Новый сотрудник"
      hint="сотрудник входит по email и паролю · роль определяет его окно и права записи"
      onClose={n}
      onSave={b}
      busy={u}
      err={x}
    >
      <X label="ФИО *">{Se(l, i, "name", "Иванов Иван Иванович", 260)}</X>
      <X label="Email (логин) *">{Se(l, i, "email", "name@fenix-zop.ru", 260)}</X>
      <X label="Рабочий телефон">{Se(l, i, "phone", "+7 999 123-45-67", 200)}</X>
      <X label="Роль *">
        <CPe
          value={l.role}
          onChange={(j) =>
            j &&
            i((g) => ({
              ...g,
              role: j,
            }))
          }
          options={Object.entries(wt).map(([j, g]) => [j, g.label])}
          w={260}
        />
      </X>
      <X label="Пароль *">
        <span
          className="row"
          style={{
            gap: 6,
            alignItems: "center",
          }}
        >
          <input
            style={{
              width: 160,
              minWidth: 160,
            }}
            value={l.password || ""}
            onChange={(j) =>
              i((g) => ({
                ...g,
                password: j.target.value,
              }))
            }
          />
          <button
            className="btn sec sm"
            onClick={() =>
              i((j) => ({
                ...j,
                password: xn(),
              }))
            }
          >
            ↻ Сгенерировать
          </button>
        </span>
      </X>
    </Ss>
  );
}
function la({ me: t }) {
  const [n, s] = S.useState(null),
    [l, i] = S.useState(null),
    [u, o] = S.useState(null),
    [x, N] = S.useState(!1),
    [b, j] = S.useState(null),
    [g, d] = S.useState(null),
    { TH: M, apply: z } = rt(),
    _ = async (v) => {
      try {
        const { data: U, error: Z } = await A.functions.invoke("term-users", {
          body: v,
        });
        return Z
          ? {
              error: String(Z.message || Z),
            }
          : U || {
              error: "Пустой ответ сервера",
            };
      } catch (U) {
        return {
          error: String(U.message || U),
        };
      }
    },
    h = async () => {
      i(null);
      const v = await _({
        action: "list",
      });
      v.error ? i(v.error) : s(v.users);
    };
  S.useEffect(() => {
    h();
  }, []);
  const w = async (v, U) => {
      var I;
      if (v.id === t.id) {
        o({
          err: "Свою собственную роль менять нельзя — иначе можно потерять доступ к этому окну. Попроси другого управляющего.",
        });
        return;
      }
      if (
        !window.confirm(
          `Сменить роль сотрудника ${v.display_name || v.email} на «${((I = wt[U]) == null ? void 0 : I.label) || U}»? Применится при следующем входе.`,
        ) ||
        !U ||
        U === v.role
      )
        return;
      d(v.id);
      const Z = await _({
        action: "set_role",
        user_id: v.id,
        role: U,
        display_name: v.display_name || v.email,
      });
      if ((d(null), Z.error)) {
        i(Z.error);
        return;
      }
      (o({
        ok: `${v.display_name || v.email}: роль → «${wt[U].label}» (применится при следующем входе)`,
      }),
        h());
    },
    p = async (v) => {
      const U = window.prompt("ФИО сотрудника", v.display_name || "");
      if (U == null || !U.trim()) return;
      if (!v.role) {
        i("У сотрудника не задана роль — сначала выбери роль в списке, потом меняй ФИО (иначе система молча выдала бы роль «Менеджер»)");
        return;
      }
      const Z = await _({
        action: "set_role",
        user_id: v.id,
        role: v.role,
        display_name: U.trim(),
      });
      Z.error
        ? i(Z.error)
        : (o({
            ok: "ФИО обновлено",
          }),
          h());
    },
    F = async (v) => {
      const U = window.prompt(`Рабочий телефон · ${v.display_name || v.email}`, v.phone || "");
      if (U == null) return;
      if (!v.role) {
        i("Сначала выбери роль сотрудника, потом телефон");
        return;
      }
      const Z = await _({
        action: "set_role",
        user_id: v.id,
        role: v.role,
        display_name: v.display_name || v.email,
        phone: U,
      });
      Z.error
        ? i(Z.error)
        : (o({
            ok: U.trim() ? "Телефон сохранён" : "Телефон убран",
          }),
          h());
    },
    C = async (v) => {
      if (!window.confirm(`Сбросить пароль для ${v.email}? Новый пароль будет показан один раз.`)) return;
      const U = xn(),
        Z = await _({
          action: "reset_password",
          user_id: v.id,
          password: U,
        });
      Z.error
        ? i(Z.error)
        : j({
            email: v.email,
            password: U,
            t: "Новый пароль установлен",
          });
    },
    [y, $] = S.useState(!1),
    m = async (v) => {
      if (!window.confirm(v.banned ? `Разблокировать вход для ${v.email}?` : `Заблокировать вход для ${v.email}? История работы сохранится.`)) return;
      const U = await _({
        action: "toggle_ban",
        user_id: v.id,
        ban: !v.banned,
      });
      U.error
        ? i(U.error)
        : (o({
            ok: v.banned ? "Доступ восстановлен" : "Вход заблокирован",
          }),
          h());
    };
  return (
    <>
      {x && (
        <CNa
          call={_}
          onClose={() => N(!1)}
          onDone={(v) => {
            (N(!1), j(v), h());
          }}
        />
      )}
      {b && (
        <div
          className="modal-bg"
          onMouseDown={(v) => {
            v.target === v.currentTarget && j(null);
          }}
        >
          <div
            className="modal"
            style={{
              minWidth: 380,
            }}
          >
            <div className="hd">
              <h2 className="p-title mt0">{b.t}</h2>
              <button className="btn sec sm" onClick={() => j(null)}>
                ✕
              </button>
            </div>
            <p className="p-sub">передай сотруднику — пароль показывается только один раз · кнопка ниже копирует логин и пароль одной строкой</p>
            <div
              className="dsec done"
              style={{
                marginTop: 6,
              }}
            >
              <div className="dv">
                <span>Логин (email)</span>
                <b>{b.email}</b>
              </div>
              <div className="dv">
                <span>Пароль</span>
                <b
                  style={{
                    fontSize: 16,
                    color: "var(--accent)",
                    letterSpacing: ".03em",
                  }}
                >
                  {b.password}
                </b>
              </div>
            </div>
            <div
              className="m-foot"
              style={{
                marginTop: 12,
              }}
            >
              <button
                className="btn"
                onClick={async () => {
                  const v = `Терминал ФЕНИКС · app.terminal-solutions.ru
Логин: ${b.email}
Пароль: ${b.password}`;
                  try {
                    (await navigator.clipboard.writeText(v), $(!0), setTimeout(() => $(!1), 2500));
                  } catch {
                    window.prompt("Скопируй вручную:", v);
                  }
                }}
              >
                {y ? "✓ Скопировано" : "Скопировать логин и пароль"}
              </button>
              <button className="btn sec" onClick={() => j(null)}>
                Закрыть
              </button>
            </div>
          </div>
        </div>
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Сотрудники и права · {(n || []).length}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <button className="btn sm" onClick={() => N(!0)}>
              + Сотрудник
            </button>
            <button className="btn sec sm" onClick={h}>
              Обновить
            </button>
          </span>
        </div>
        <p className="p-sub">
          роль определяет окно и права записи сотрудника · смена роли применяется при следующем входе · блокировка закрывает вход, вся история работы
          сохраняется · ✎ у имени — изменить ФИО, ✎ у телефона — рабочий номер (с телефона по нему можно позвонить)
        </p>
        <CFe err={l} />
        <CFe {...(u || {})} />
        {!(n || []).length && (
          <p
            className="p-sub"
            style={{
              margin: 0,
            }}
          >
            список сотрудников пуст — нажми «Обновить»; если пусто и после этого, значит служба управления доступом не ответила
          </p>
        )}
        <div
          className="tscroll"
          style={{
            maxHeight: "none",
          }}
        >
          <table>
            <thead>
              <tr>
                <M k="nm">Сотрудник</M>
                <M k="em">Email (логин)</M>
                <M k="ph">Телефон</M>
                <M k="rl">Роль</M>
                <M k="ls">Последний вход</M>
                <M k="bn">Статус</M>
                <th>Действия</th>
              </tr>
            </thead>
            <tbody>
              {z(n || [], {
                nm: (v) => v.display_name,
                em: (v) => v.email,
                ph: (v) => v.phone,
                rl: (v) => (v.role && wt[v.role] ? wt[v.role].label : null),
                ls: (v) => v.last_sign_in_at,
                bn: (v) => (v.banned ? 1 : 0),
              }).map((v) => (
                <tr>
                  <td className="nowrap">
                    <b>{v.display_name || "—"}</b>
                    {v.id === t.id ? <span className="faint"> · это я</span> : null} <Ye onClick={() => p(v)} title="Изменить ФИО" />
                  </td>
                  <td>{v.email}</td>
                  <td className="nowrap">
                    {v.phone ? (
                      <a className="lnk9" href={"tel:" + v.phone}>
                        {v.phone}
                      </a>
                    ) : (
                      <span className="faint">—</span>
                    )}{" "}
                    <Ye onClick={() => F(v)} title="Изменить телефон" />
                  </td>
                  <td>
                    {g === v.id ? (
                      "…"
                    ) : (
                      <CPe
                        value={v.role || ""}
                        onChange={(U) => w(v, U)}
                        w={200}
                        ph="без роли"
                        options={Object.entries(wt).map(([U, Z]) => [U, Z.label])}
                      />
                    )}
                  </td>
                  <td className="nowrap">{he(v.last_sign_in_at)}</td>
                  <td>{v.banned ? <span className="stage lab_no">Заблокирован</span> : <span className="stage tare">Активен</span>}</td>
                  <td className="nowrap">
                    <button className="btn sec sm" onClick={() => C(v)}>
                      Сбросить пароль
                    </button>{" "}
                    {v.id !== t.id && (
                      <button className={v.banned ? "btn sm" : "btn danger sm"} onClick={() => m(v)}>
                        {v.banned ? "Разблокировать" : "Заблокировать"}
                      </button>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        {!n && !l && <p className="p-sub">загрузка списка…</p>}
      </div>
    </>
  );
}
function CIa({ me: t }) {
  const [n, s] = S.useState(!1),
    [l, i] = S.useState([]),
    [u, o] = S.useState(""),
    [x, N] = Fl("chat"),
    [b, j] = S.useState(null),
    g = S.useRef(null),
    d = S.useRef(!1);
  d.current = n;
  const M = S.useRef(!0),
    z = S.useRef(!0),
    _ = (m) => +new Date(m.created_at) || 0,
    h = async () => {
      try {
        const v = [
          ...(await Y(
            A.from("term_chat")
              .select("*")
              .order("created_at", {
                ascending: !1,
              })
              .limit(200),
          )),
        ].reverse();
        if ((i(v), j(null), z.current)) {
          z.current = !1;
          const U = v.reduce((Z, I) => Math.max(Z, _(I)), 0);
          +localStorage.getItem("term9.chat.seen") || N(U);
        }
      } catch (m) {
        j("Чат не загрузился: " + (m.message || m));
      }
    };
  (S.useEffect(() => {
    h();
    const m = setInterval(h, 1e4);
    let v = 0;
    const U = () => {
      const I = Date.now();
      I - v > 1500 && ((v = I), h());
    };
    window.addEventListener("term:changed", U);
    let Z = null;
    return (
      pn().then(() => {
        Z = A.channel("term_chat_live")
          .on(
            "postgres_changes",
            {
              event: "INSERT",
              schema: "public",
              table: "term_chat",
            },
            (I) => {
              i((D) => (D.some((E) => E.id === I.new.id) ? D : [...D, I.new]));
            },
          )
          .on(
            "postgres_changes",
            {
              event: "DELETE",
              schema: "public",
              table: "term_chat",
            },
            (I) => {
              i((D) => D.filter((E) => E.id !== I.old.id));
            },
          )
          .subscribe((I) => {
            I !== "SUBSCRIBED" && console.debug("[term] чат · канал:", I);
          });
      }),
      () => {
        (clearInterval(m), Z && A.removeChannel(Z), window.removeEventListener("term:changed", U));
      }
    );
  }, []),
    S.useEffect(() => {
      const m = () => {
        document.visibilityState === "visible" && h();
      };
      return (
        document.addEventListener("visibilitychange", m),
        window.addEventListener("focus", m),
        () => {
          (document.removeEventListener("visibilitychange", m), window.removeEventListener("focus", m));
        }
      );
    }, []),
    S.useEffect(() => {
      if (!n) return;
      const m = g.current;
      (m && M.current && (m.scrollTop = m.scrollHeight), N(l.reduce((v, U) => Math.max(v, _(U)), 0)));
    }, [n, l]));
  const w = n ? 0 : l.filter((m) => _(m) > x && m.author !== t.id).length,
    [p, F] = S.useState(null),
    C = async () => {
      const m = u.trim();
      if (m)
        try {
          (await Y(
            A.from("term_chat").insert({
              author_name: t.name || (wt[t.role] || {}).label || "",
              author_role: t.role,
              body: m,
            }),
          ),
            o(""),
            F(null),
            h());
        } catch (v) {
          F("Не отправилось: " + (v.message || v) + " — текст сохранён, попробуй ещё раз");
        }
    },
    y = async (m) => {
      if (window.confirm(`Удалить сообщение «${(m.body || "").slice(0, 60)}${(m.body || "").length > 60 ? "…" : ""}»? Восстановить будет нельзя.`))
        try {
          (await ue(A.from("term_chat").delete().eq("id", m.id), "сообщение"), i((v) => v.filter((U) => U.id !== m.id)));
        } catch (v) {
          F(String(v.message || v));
        }
    };
  let $ = "";
  return (
    <>
      <button
        className={"chat-fab" + (n ? " on" : "")}
        title="Внутренний чат отделов"
        onClick={() => {
          (n || (M.current = !0), s(!n));
        }}
      >
        <svg
          viewBox="0 0 24 24"
          width="18"
          height="18"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
        >
          <path d="M21 11.5a8.5 8.5 0 0 1-8.5 8.5c-1.2 0-2.4-.25-3.4-.7L3 21l1.7-5.1a8.5 8.5 0 1 1 16.3-4.4z" />
        </svg>
        <span className="chat-fab-t">{n ? "Закрыть" : "Чат"}</span>
        {w > 0 && <i className="chat-bdg">{w > 99 ? "99+" : w}</i>}
      </button>
      {n && (
        <div className="chat-pane">
          <div className="chat-hd">
            <b>Внутренний чат</b>
            <span className="faint">все отделы онлайн</span>
            <button
              className="btn sec sm icon"
              style={{
                marginLeft: "auto",
              }}
              onClick={() => s(!1)}
            >
              ✕
            </button>
          </div>
          <div
            className="chat-box"
            ref={g}
            onScroll={(m) => {
              const v = m.currentTarget;
              M.current = v.scrollHeight - v.scrollTop - v.clientHeight < 40;
            }}
          >
            {l.map((m) => {
              const v = new Date(m.created_at).toLocaleDateString("ru-RU", {
                  day: "2-digit",
                  month: "long",
                }),
                U =
                  v !== $ ? (
                    <div className="chat-day">
                      <span>{v}</span>
                    </div>
                  ) : null;
              return (
                ($ = v),
                (
                  <>
                    {U}
                    <div className={"chat-m" + (m.author === t.id ? " mine" : "") + (m.author_role === "система" ? " chat-dig" : "")}>
                      <div className="chat-meta">
                        <b>{m.author_name || "—"}</b>
                        <i>{(wt[m.author_role] || {}).label || m.author_role || ""}</i>
                        <span>{Ue(m.created_at)}</span>
                        {(m.author === t.id || t.role === "chief") && (
                          <button className="chat-x" title="Удалить сообщение" onClick={() => y(m)}>
                            ✕
                          </button>
                        )}
                      </div>
                      <div className="chat-b">{m.body}</div>
                    </div>
                  </>
                )
              );
            })}
            {!l.length && !b && (
              <div
                className="faint"
                style={{
                  textAlign: "center",
                  padding: "28px 10px",
                }}
              >
                Сообщений пока нет — напиши первым
              </div>
            )}
            {!l.length && b && (
              <div
                className="err"
                style={{
                  margin: "18px 4px",
                }}
              >
                {b}
              </div>
            )}
          </div>
          {p && (
            <div
              className="err"
              style={{
                margin: "0 10px 6px",
              }}
            >
              {p}
            </div>
          )}
          <div className="chat-in">
            <textarea
              rows={1}
              placeholder="Сообщение… (Enter — отправить)"
              value={u}
              onChange={(m) => o(m.target.value)}
              onKeyDown={(m) => {
                m.key === "Enter" && !m.shiftKey && (m.preventDefault(), C());
              }}
            />
            <button className="btn sm" onClick={C} title="Отправить">
              ➤
            </button>
          </div>
        </div>
      )}
    </>
  );
}
const ra = {
    visit: ["Зерновозы", "v"],
    cont: ["Контейнеры", "c"],
    load: ["Затарка", "l"],
    mix: ["Замесы", "m"],
    batch: ["Партии", null],
    req: ["Заявки", null],
    doc: ["Документы", null],
    audit: ["Исключения", null],
  },
  aa = {
    visit: {
      in: "заехал на терминал",
      t2call: "вызван из отстойника",
      lab: "решение лаборатории",
      gross: "взвешен гружёным",
      unload_start: "начата выгрузка",
      unload: "выгружен",
      tare: "взвешен порожним",
      ts: "перевалка выполнена",
      out: "выпущен с терминала",
      cancel: "заезд отменён",
    },
    cont: {
      in: "контейнер заехал",
      accept: "принят",
      reaccept: "возвращён на осмотр",
      surveyor: "осмотр сюрвейера",
      rsn: "РСН",
      fumig: "фумигация",
      out: "выпущен с терминала",
    },
    load: {
      tare: "тара контейнера",
      load: "затарен",
      gross: "брутто и нетто",
    },
    mix: {
      create: "собран",
      lab: "параметры лаборатории",
      ts: "перевалка выполнена",
      packed: "затарен в контейнеры",
      closed: "закрыт",
    },
    batch: {
      create: "создана",
      to_inspect: "отправлена на досмотр",
      inspected: "досмотр пройден",
      fumig: "фумигация",
      ready: "готова к отправке",
      departed: "убыла в порт",
    },
    req: {
      create: "создана",
      pass: "выдан пропуск",
      t2: "отмечен отстойник Т2",
      t2call: "вызвана на терминал",
      deleted: "удалена",
    },
    doc: {
      vgm: "выпущен VGM",
      akt: "выпущен акт",
      doc: "выпущен документ",
    },
  },
  ca = {
    visit: "Зерновоз",
    container: "Контейнер",
    batch: "Партия",
    mix: "Замес",
    request: "Заявка",
    doc: "Документ",
    load: "Затарка",
    container_loads: "Затарка",
    settings: "Настройки",
  },
  oa = (t) => {
    var n;
    return ((n = ot.S) == null ? void 0 : n.feed_audit_all) === "нет" ? ["manager", "chief"].includes(t == null ? void 0 : t.role) : !0;
  },
  da = (t) => (t.kind === "audit" ? On[t.action] || t.action || "изменение" : (aa[t.kind] || {})[t.action] || t.action || "изменение"),
  ha = (t) =>
    t.kind === "audit"
      ? `${ca[t.obj] || t.obj}${t.entity_id ? " №" + t.entity_id : ""}`
      : t.kind === "req"
        ? `Заявка ${t.obj}`
        : t.kind === "mix"
          ? `Замес ${t.obj}`
          : t.kind === "batch"
            ? `Партия ${t.obj}`
            : t.obj,
  ua = (t) =>
    t.extra
      ? t.kind === "visit" && t.action === "lab"
        ? t.extra === "passed"
          ? "одобрен"
          : t.extra === "rejected"
            ? "отказ"
            : t.extra
        : (t.kind === "visit" && ["gross", "tare", "out"].includes(t.action)) || (t.kind === "load" && ["tare", "gross"].includes(t.action))
          ? q(+t.extra) + " кг"
          : t.extra
      : null,
  Zn = (t) => `${t.kind}|${t.entity_id}|${t.action}|${t.at}`,
  ma = {
    visit: "v",
    cont: "c",
    load: "l",
    mix: "m",
  },
  xa = {
    visit: "v",
    container: "c",
    mix: "m",
    load: "l",
    container_loads: "l",
  },
  _a = (t) => (t.kind === "audit" ? xa[t.obj] : ma[t.kind]),
  ja = {
    visit: "v",
    cont: "c",
    load: "l",
    req: null,
  };
function Fl(t) {
  const n = `term9.${t}.seen`,
    [s, l] = S.useState(() => +localStorage.getItem(n) || 0),
    i = S.useRef(s);
  i.current = s;
  const u = S.useRef(0),
    o = S.useRef(null),
    x = () => {
      const b = u.current;
      if (!(b > 0)) return;
      u.current = 0;
      const j = new Date(b).toISOString();
      Y(
        A.rpc(
          "term_seen_mark",
          t === "feed"
            ? {
                p_feed: j,
              }
            : {
                p_chat: j,
              },
        ),
      ).catch(() => {});
    },
    N = (b) => {
      if (!(b > 0)) return;
      const j = +localStorage.getItem(n) || 0;
      (b > j && localStorage.setItem(n, String(b)),
        l((g) => (b > g ? b : g)),
        b > j && ((u.current = Math.max(u.current, b)), clearTimeout(o.current), (o.current = setTimeout(x, 1200))));
    };
  return (
    S.useEffect(() => {
      let b = !1;
      const j = async () => {
        try {
          const _ = ((await Y(A.from("term_seen").select("feed_seen_at, chat_seen_at").limit(1))) || [])[0];
          if (!_ || b) return;
          const h = +new Date(t === "feed" ? _.feed_seen_at : _.chat_seen_at) || 0;
          h > (+localStorage.getItem(n) || 0) && (localStorage.setItem(n, String(h)), l((w) => (h > w ? h : w)));
        } catch {}
      };
      j();
      const g = setInterval(j, 6e4),
        d = () => {
          document.visibilityState === "visible" && j();
        };
      (document.addEventListener("visibilitychange", d), window.addEventListener("focus", d));
      const M = () => {
        (clearTimeout(o.current), x());
      };
      return (
        window.addEventListener("pagehide", M),
        () => {
          ((b = !0),
            clearInterval(g),
            clearTimeout(o.current),
            document.removeEventListener("visibilitychange", d),
            window.removeEventListener("focus", d),
            window.removeEventListener("pagehide", M));
        }
      );
    }, []),
    [s, N, i]
  );
}
const ds = 25,
  ga = (t) => (t == null ? "" : t < 60 ? `${t} мин` : t < 60 * 48 ? `${Math.floor(t / 60)} ч` : `${Math.floor(t / 1440)} дн`);
function CPa({ me: t }) {
  const [n, s] = S.useState(!1),
    [l, i] = S.useState([]),
    [u, o] = S.useState([]),
    [x, N] = S.useState(24),
    [b, j] = S.useState(""),
    [g, d] = S.useState(null),
    [M, z] = S.useState(!1),
    [_, h] = S.useState(null),
    [w, p] = Fl("feed"),
    [F, C] = S.useState(0),
    y = S.useRef(!0),
    $ = S.useRef(0),
    m = S.useRef(24);
  m.current = x;
  const v = (W) => +new Date(W.at) || 0,
    U = async (W) => {
      const K = W || m.current;
      try {
        z(!0);
        const le = new Date(Date.now() - K * 3600 * 1e3).toISOString(),
          ee = (
            (await Y(
              A.rpc("term_feed", {
                p_since: le,
                p_limit: 600,
              }),
            )) || []
          ).filter((re) => re.kind !== "audit" || oa(t));
        if ((i(ee), d(null), Date.now() - $.current > 6e4)) {
          $.current = Date.now();
          try {
            const re = ot.S || {},
              be = await Y(
                A.rpc("term_stuck", {
                  p_lab_h: +Oe(re, "stuck_lab_h") || 2,
                  p_unload_h: +Oe(re, "stuck_unload_h") || 4,
                  p_tare_h: +Oe(re, "stuck_tare_h") || 6,
                  p_cont_d: +Oe(re, "stuck_cont_d") || 30,
                  p_cap: ds,
                }),
              );
            o(be || []);
          } catch {
            o([]);
          }
        }
        if (y.current) {
          y.current = !1;
          const re = ee.reduce((Ne, ze) => Math.max(Ne, v(ze)), 0);
          +localStorage.getItem("term9.feed.seen") || 0 || p(re);
        }
      } catch (le) {
        d(String(le.message || le));
      } finally {
        z(!1);
      }
    };
  (S.useEffect(() => {
    U(24);
    const W = setInterval(() => U(), 2e4);
    let K = null,
      le = 0;
    const $e = () => {
      const be = Date.now();
      be - le > 2500
        ? ((le = be), U())
        : (clearTimeout(K),
          (K = setTimeout(() => {
            ((le = Date.now()), U());
          }, 1500)));
      try {
        window.dispatchEvent(new Event("term:changed"));
      } catch {}
    };
    let ee = null;
    pn().then(() => {
      ee = A.channel("term_feed_live")
        .on(
          "postgres_changes",
          {
            event: "*",
            schema: "public",
          },
          $e,
        )
        .subscribe((be) => {
          be !== "SUBSCRIBED" && console.debug("[term] лента · канал:", be);
        });
    });
    const re = () => {
      document.visibilityState === "visible" && U();
    };
    return (
      document.addEventListener("visibilitychange", re),
      window.addEventListener("focus", re),
      () => {
        (clearInterval(W),
          clearTimeout(K),
          ee && A.removeChannel(ee),
          document.removeEventListener("visibilitychange", re),
          window.removeEventListener("focus", re));
      }
    );
  }, []),
    S.useEffect(() => {
      n && p(l.reduce((W, K) => Math.max(W, v(K)), 0));
    }, [n, l]),
    S.useEffect(() => (document.body.classList.toggle("feed-open", n), () => document.body.classList.remove("feed-open")), [n]));
  const Z = n ? 0 : l.filter((W) => v(W) > w).length,
    I = !n && Z === 0 && u.length > 0,
    D = S.useMemo(() => {
      const W = {};
      for (const K of l) W[K.kind] = (W[K.kind] || 0) + 1;
      return Object.entries(ra)
        .filter(([K]) => W[K])
        .map(([K, le]) => [K, le[0], W[K]]);
    }, [l]),
    E = b === "stuck" ? [] : b ? l.filter((W) => W.kind === b) : l,
    a = S.useMemo(() => {
      const W = {};
      for (const K of u) W[K.what] = Math.max(W[K.what] || 0, +K.nall || 0) || (W[K.what] || 0) + 1;
      return Object.entries(W).sort((K, le) => le[1] - K[1]);
    }, [u]),
    [f, P] = S.useState(() => new Set()),
    [T, H] = S.useState(null),
    Q = async (W) => {
      if ((P((K) => new Set(K).add(W)), !T))
        try {
          const K = ot.S || {},
            le = await Y(
              A.rpc("term_stuck", {
                p_lab_h: +Oe(K, "stuck_lab_h") || 2,
                p_unload_h: +Oe(K, "stuck_unload_h") || 4,
                p_tare_h: +Oe(K, "stuck_tare_h") || 6,
                p_cont_d: +Oe(K, "stuck_cont_d") || 30,
                p_cap: 0,
              }),
            );
          H(le || []);
        } catch {}
    },
    ae = S.useMemo(() => {
      const W = {};
      return (f.size && T ? T : u).filter((le) => ((W[le.what] = (W[le.what] || 0) + 1), f.has(le.what) || W[le.what] <= ds));
    }, [u, T, f]),
    me = () => {
      const W = x >= 168 ? 720 : x * 3,
        K = Math.min(W, 720);
      (N(K), U(K));
    };
  let L = "";
  return (
    <>
      <button
        className={"bell9" + (n ? " on" : "")}
        title="Что происходит на терминале — все смены статусов"
        onClick={() => {
          (n || (C(w), u.length && !l.some((W) => v(W) > w) && j("stuck")), s(!n));
        }}
      >
        <svg
          viewBox="0 0 24 24"
          width="16"
          height="16"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
        >
          <path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9" />
          <path d="M13.7 21a2 2 0 0 1-3.4 0" />
        </svg>
        {Z > 0 && <i className="bell-bdg">{Z > 99 ? "99+" : Z}</i>}
        {I && <i className="bell-dot" title={`Просрочено: ${u.length}`} />}
      </button>
      {n &&
        _n.createPortal(
          <>
            <div className="feed-ovl" onClick={() => s(!1)} />
            <div className="feed9">
              <div className="feed-hd">
                <b>Что происходит на терминале</b>
                <span className="faint">
                  {x <= 24 ? "за сутки" : x <= 72 ? "за 3 дня" : x <= 168 ? "за неделю" : "за месяц"} · {E.length}
                </span>
                <button
                  className="btn sec sm icon"
                  style={{
                    marginLeft: "auto",
                  }}
                  title="Обновить"
                  onClick={() => U()}
                >
                  ⟳
                </button>
                <button className="btn sec sm icon" title="Закрыть" onClick={() => s(!1)}>
                  ✕
                </button>
              </div>
              <div className="feed-flt">
                <button className={"tab" + (b === "" ? " on" : "")} onClick={() => j("")}>
                  Все · {l.length}
                </button>
                {u.length > 0 && (
                  <button className={"tab warn9t" + (b === "stuck" ? " on" : "")} onClick={() => j("stuck")}>
                    ⚠ Просрочено · {u.length}
                  </button>
                )}
                {D.map(([W, K, le]) => (
                  <button className={"tab" + (b === W ? " on" : "")} onClick={() => j(W)}>
                    {K} · {le}
                  </button>
                ))}
              </div>
              <div className="feed-box">
                {g && (
                  <div
                    className="err"
                    style={{
                      margin: "10px 4px",
                    }}
                  >
                    Лента не загрузилась: {g}
                  </div>
                )}
                {b === "stuck" && (
                  <>
                    <p
                      className="p-sub"
                      style={{
                        margin: "2px 4px 8px",
                      }}
                    >
                      процессы, которые не двигаются дольше положенного · пороги задаются в настройках терминала
                    </p>
                    {a.map(
                      ([W, K]) =>
                        K > ds && (
                          <div
                            className="p-sub"
                            style={{
                              margin: "0 4px 6px",
                              color: "var(--warn)",
                            }}
                          >
                            «{W}» — {K} шт.
                            {f.has(W) ? (
                              <>
                                {" "}
                                <button
                                  className="lnk9"
                                  onClick={() =>
                                    P((le) => {
                                      const $e = new Set(le);
                                      return ($e.delete(W), $e);
                                    })
                                  }
                                >
                                  свернуть до {ds}
                                </button>
                              </>
                            ) : (
                              <>
                                , показаны первые {ds} ·{" "}
                                <button className="lnk9" onClick={() => Q(W)}>
                                  показать все {K}
                                </button>
                              </>
                            )}
                          </div>
                        ),
                    )}
                    {ae.map((W) => {
                      const K = ja[W.kind];
                      return (
                        <div
                          className={"feed-i warn" + (K ? " go" : "")}
                          title={K ? "Открыть карточку" : void 0}
                          onClick={
                            K
                              ? () =>
                                  h({
                                    k: K,
                                    id: W.entity_id,
                                  })
                              : void 0
                          }
                        >
                          <span className="feed-t">{ga(W.mins)}</span>
                          <span className="feed-c">
                            <b>{W.obj}</b> <span className="feed-a">{W.what}</span>
                            {W.extra && <span className="feed-v">{W.extra}</span>}
                            <i className="feed-w">с {he(W.since)}</i>
                          </span>
                        </div>
                      );
                    })}
                    {!u.length && (
                      <div
                        className="faint"
                        style={{
                          textAlign: "center",
                          padding: "28px 10px",
                        }}
                      >
                        Всё идёт по времени — просроченных процессов нет
                      </div>
                    )}
                  </>
                )}
                {!g && !E.length && !M && (
                  <div
                    className="faint"
                    style={{
                      textAlign: "center",
                      padding: "28px 10px",
                    }}
                  >
                    За выбранный период изменений нет
                  </div>
                )}
                {E.map((W) => {
                  const K = new Date(W.at).toLocaleDateString("ru-RU", {
                      day: "2-digit",
                      month: "long",
                    }),
                    le =
                      K !== L ? (
                        <div className="chat-day">
                          <span>{K}</span>
                        </div>
                      ) : null;
                  L = K;
                  const $e = _a(W),
                    ee = ua(W);
                  return (
                    <>
                      {le}
                      <div
                        className={"feed-i" + (W.kind === "audit" ? " warn" : "") + ($e && W.entity_id ? " go" : "") + (v(W) > F ? " new" : "")}
                        title={$e && W.entity_id ? "Открыть карточку" : void 0}
                        onClick={
                          $e && W.entity_id
                            ? () =>
                                h({
                                  k: $e,
                                  id: W.entity_id,
                                })
                            : void 0
                        }
                      >
                        <span className="feed-t">{Ue(W.at)}</span>
                        <span className="feed-c">
                          <b>{ha(W)}</b> <span className="feed-a">{da(W)}</span>
                          {ee && <span className="feed-v">{ee}</span>}
                          <i className="feed-w">{W.who || "—"}</i>
                        </span>
                      </div>
                    </>
                  );
                })}
                {!g && E.length > 0 && x < 720 && (
                  <button
                    className="btn sec sm"
                    style={{
                      margin: "10px auto",
                      display: "block",
                    }}
                    onClick={me}
                    disabled={M}
                  >
                    {M ? "Загрузка…" : "Показать ещё"}
                  </button>
                )}
              </div>
            </div>
          </>,
          document.body,
        )}
      {(_ == null ? void 0 : _.k) === "v" && <Zt id={_.id} me={t} onClose={() => h(null)} />}
      {(_ == null ? void 0 : _.k) === "c" && <Ht id={_.id} me={t} onClose={() => h(null)} />}
      {(_ == null ? void 0 : _.k) === "m" && <Cs id={_.id} me={t} onClose={() => h(null)} />}
      {(_ == null ? void 0 : _.k) === "l" && <CRs id={_.id} me={t} onClose={() => h(null)} />}
    </>
  );
}
function fa({ me: t }) {
  const [n, s] = S.useState(null),
    [l, i] = Te("ts.site", ""),
    [u, o, x] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*, term_requests(term_orders(order_no, extra_services, dest_country, survey))")
            .eq("lab_status", "passed")
            .is("out_at", null)
            .is("ts_at", null)
            .not("in_at", "is", null)
            .order("lab_at"),
        ),
      [],
      2e4,
    ),
    [N, b, j] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("*")
            .not("ts_at", "is", null)
            .is("out_at", null)
            .order("ts_at", {
              ascending: !1,
            })
            .limit(40),
        ),
      [],
      3e4,
    );
  ne(
    () =>
      Y(
        A.from("term_container_loads")
          .select("*, term_line_containers(container_no, size, height, booking, line, client, site, cont_tare_kg, seal_no)")
          .not("gross_kg", "is", null)
          .order("id", {
            ascending: !1,
          })
          .limit(800),
      ),
    [],
    6e4,
  );
  const [g, d] = ne(
      () =>
        Y(
          A.from("term_mixes")
            .select("*")
            .in("status", ["formed", "lab_ok", "ts_ok", "weighed"])
            .order("id", {
              ascending: !1,
            })
            .limit(60),
        ),
      [],
      2e4,
    ),
    M = ["manager", "chief"].includes(t.role),
    [z, _] = S.useState(null),
    [h, w] = S.useState(null),
    [p, F] = S.useState(null),
    C = (u || []).filter((a) => !l || (a.site || "") === l),
    y = C.filter((a) => !a.mix_id),
    $ = S.useMemo(
      () =>
        (g || [])
          .map((a) => ({
            ...a,
            list: C.filter((f) => f.mix_id === a.id),
            all: (u || []).filter((f) => f.mix_id === a.id),
          }))
          .filter((a) => a.list.length),
      [g, u, l],
    ),
    m = (a) => {
      var f, P;
      return ((P = (f = a.term_requests) == null ? void 0 : f.term_orders) == null ? void 0 : P.extra_services) || [];
    },
    v = async (a, f) => {
      try {
        (await ue(
          A.from("term_truck_visits")
            .update({
              site: f || null,
            })
            .eq("id", a.id),
          "машина " + a.vehicle_no,
        ),
          o());
      } catch (P) {
        _({
          err: String(P.message || P),
        });
      }
    },
    U = async (a, f) => {
      const P = a.extra_done || [],
        T = P.includes(f) ? P.filter((H) => H !== f) : [...P, f];
      try {
        (await ue(
          A.from("term_truck_visits")
            .update({
              extra_done: T.length ? T : null,
            })
            .eq("id", a.id),
          "машина " + a.vehicle_no,
        ),
          await je(
            "visit",
            a.id,
            "extra_service",
            {
              машина: a.vehicle_no,
              услуга: f,
              оказана: !P.includes(f),
            },
            t,
          ),
          o());
      } catch (H) {
        _({
          err: String(H.message || H),
        });
      }
    },
    Z = async (a) => {
      if (!a.site) {
        _({
          err: `${a.vehicle_no}: сначала укажи площадку (ЗПК/Движение)`,
        });
        return;
      }
      const f = m(a),
        P = f.filter((T) => !(a.extra_done || []).includes(T));
      if (!(
        P.length &&
        !window.confirm(`${a.vehicle_no}: по поручению есть доп. услуги, которые не отмечены как оказанные — ${P.join(", ")}.

Всё равно закрыть перевалку?`)
      ))
        try {
          (await ue(
            A.from("term_truck_visits")
              .update({
                ts_at: new Date().toISOString(),
                ts_by: t.id,
                ts_service: Le[a.lab_result1] || null,
              })
              .eq("id", a.id),
            "машина " + a.vehicle_no,
          ),
            await je(
              "visit",
              a.id,
              "ts_done",
              {
                машина: a.vehicle_no,
                услуга: Le[a.lab_result1],
                площадка: a.site,
              },
              t,
            ),
            _({
              ok: `${a.vehicle_no}: услуга «${Le[a.lab_result1] || "—"}» оказана на «${a.site}»`,
            }),
            o(),
            b());
        } catch (T) {
          _({
            err: String(T.message || T),
          });
        }
    },
    I = async (a) => {
      if (window.confirm(`Отменить отметку «Услуга оказана» для ${a.vehicle_no}? Машина вернётся в очередь перевалки.`))
        try {
          (await ue(
            A.from("term_truck_visits")
              .update({
                ts_at: null,
                ts_by: null,
                ts_service: null,
              })
              .eq("id", a.id),
            "машина " + a.vehicle_no,
          ),
            a.mix_id &&
              (((await Y(A.from("term_truck_visits").select("id, ts_at").eq("mix_id", a.mix_id).is("out_at", null))) || []).some((P) => P.ts_at) ||
                (await ue(
                  A.from("term_mixes")
                    .update({
                      status: "lab_ok",
                      ts_at: null,
                      ts_by: null,
                    })
                    .eq("id", a.mix_id),
                  "замес",
                ))),
            await je(
              "visit",
              a.id,
              "ts_undo",
              {
                машина: a.vehicle_no,
              },
              t,
            ),
            _({
              ok: `${a.vehicle_no}: отметка услуги снята — машина снова в очереди`,
            }),
            o(),
            b(),
            d());
        } catch (f) {
          _({
            err: String(f.message || f),
          });
        }
    },
    D = async (a, f) => {
      try {
        await ue(
          A.from("term_mixes")
            .update({
              site: f || null,
            })
            .eq("id", a.id),
          "замес " + a.mix_no,
        );
        for (const P of a.all)
          await ue(
            A.from("term_truck_visits")
              .update({
                site: f || null,
              })
              .eq("id", P.id),
            "машина " + P.vehicle_no,
          );
        (o(), d());
      } catch (P) {
        _({
          err: String(P.message || P),
        });
      }
    },
    E = async (a) => {
      if (!a.site) {
        _({
          err: `Замес ${a.mix_no}: сначала укажи площадку`,
        });
        return;
      }
      try {
        const f = new Date().toISOString();
        for (const P of a.all)
          P.ts_at ||
            (await ue(
              A.from("term_truck_visits")
                .update({
                  ts_at: f,
                  ts_by: t.id,
                  ts_service: Le[P.lab_result1] || "Замес",
                })
                .eq("id", P.id),
              "машина " + P.vehicle_no,
            ));
        (["weighed", "packed", "closed"].includes(a.status) ||
          (await ue(
            A.from("term_mixes")
              .update({
                status: "ts_ok",
                ts_at: f,
                ts_by: t.id,
              })
              .eq("id", a.id),
            "замес " + a.mix_no,
          )),
          await je(
            "mix",
            a.id,
            "ts_done",
            {
              замес: a.mix_no,
              машины: a.all.map((P) => P.vehicle_no),
              площадка: a.site,
            },
            t,
          ),
          _({
            ok: `Замес ${a.mix_no}: услуга оказана на «${a.site}» — все ${a.all.length} машины ушли на весы`,
          }),
          o(),
          b(),
          d());
      } catch (f) {
        _({
          err: String(f.message || f),
        });
      }
    };
  return (
    [..._t],
    (
      <>
        {p && <Kt me={t} entity="visit" id={p.id} title={`Машина ${p.vehicle_no} · фото и файлы`} onClose={() => F(null)} />}
        {h && <Zt id={h.id} me={t} onClose={() => w(null)} />}
        {n && <Cs id={n} me={t} onClose={() => s(null)} />}
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Доска площадок</h2>
            <button className="btn sec sm" onClick={o}>
              Обновить
            </button>
          </div>
          <p className="p-sub">
            клик по машине в колонке «Без площадки» ставит её на площадку · внутри колонки видно, сколько тонн на неё уже назначено
          </p>
          <div className="board9">
            {[["", "Без площадки"], ..._t.map((a) => [a, a])].map(([a, f]) => {
              const P = C.filter((H) => (H.site || "") === a),
                T = P.reduce((H, Q) => H + (qe(Q.planned_tonnes) || 0), 0);
              return (
                <div className={"bcol" + (a ? "" : " none")}>
                  <div className="bcol-h">
                    <b>{f}</b>
                    <span className="faint">
                      {P.length} · {q(T)} кг
                    </span>
                  </div>
                  <div className="bcol-b">
                    {P.map((H) => (
                      <div className="bcard">
                        <div className="bcard-t">
                          <b>{H.vehicle_no}</b>
                          <span className="faint"> {H.culture || ""}</span>
                        </div>
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          {Le[H.lab_result1] || "—"}
                          {H.mix_group ? " · " + H.mix_group : ""}
                        </div>
                        <div
                          className="row"
                          style={{
                            gap: 4,
                            marginTop: 5,
                          }}
                        >
                          {a ? (
                            <>
                              <button className="btn sm" onClick={() => Z(H)}>
                                Услуга оказана ✓
                              </button>
                              <button className="btn sec sm icon" title="Снять площадку" onClick={() => v(H, "")}>
                                ✕
                              </button>
                            </>
                          ) : (
                            _t.map((Q) => (
                              <button className="btn sec sm" title={`Поставить на «${Q}»`} onClick={() => v(H, Q)}>
                                {Q.replace("ЗПК ", "")}
                              </button>
                            ))
                          )}
                        </div>
                      </div>
                    ))}
                    {!P.length && (
                      <div
                        className="faint"
                        style={{
                          fontSize: 11,
                          padding: "10px 2px",
                        }}
                      >
                        пусто
                      </div>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>
        {$.length > 0 && (
          <div className="panel">
            <div className="hd">
              <h2 className="p-title mt0">Замесы на перевалке · {$.length}</h2>
              <button
                className="btn sec sm"
                onClick={() => {
                  (o(), d());
                }}
              >
                Обновить
              </button>
            </div>
            <p className="p-sub">
              замес обрабатывается как одна группа: одна площадка на всех участников, одна отметка услуги — после неё все машины замеса уходят на весы
            </p>
            <div className="tscroll">
              <table>
                <thead>
                  <tr>
                    <th>Замес</th>
                    <th>Культура</th>
                    <th>Машины</th>
                    <th>Параметр</th>
                    <th className="right">Вес план, кг</th>
                    <th>Площадка</th>
                    <th />
                  </tr>
                </thead>
                <tbody>
                  {$.map((a) => (
                    <tr
                      className="rowc"
                      title="Карточка замеса"
                      onClick={(f) => {
                        lt(f) && s(a.id);
                      }}
                    >
                      <td
                        className="rowx"
                        title="Карточка замеса"
                        onClick={(f) => {
                          (f.stopPropagation(), s(a.id));
                        }}
                      >
                        <b>{a.mix_no}</b>
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          {vs(a).t}
                        </div>
                      </td>
                      <td>{a.culture || "—"}</td>
                      <td
                        style={{
                          maxWidth: 280,
                          whiteSpace: "normal",
                        }}
                      >
                        {[...a.all.map((f) => f.vehicle_no), a.ext_partner].filter(Boolean).join(", ")}
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          участников: {a.all.length + (a.ext_partner ? 1 : 0)}
                        </div>
                      </td>
                      <td>{a.param || "—"}</td>
                      <td className="right">{q(a.all.reduce((f, P) => f + (qe(P.planned_tonnes) || 0), 0)) || "—"}</td>
                      <td>
                        <CPe value={a.site || ""} onChange={(f) => D(a, f)} options={_t} w={140} ph="— площадка —" />
                      </td>
                      <td className="nowrap">
                        <button className="btn sm" onClick={() => E(a)}>
                          Услуга оказана всему замесу ✓
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Перевалка · услуги по данным лаборатории · {y.length}</h2>
            <button className="btn sec sm" onClick={o}>
              Обновить
            </button>
          </div>
          <p className="p-sub">
            одиночные машины после одобрения лаборатории · услуга из «Результата 1»: Выгрузка, Очистка, Замес, Очистка+Замес · укажи площадку и отметь
            оказание услуги · замесы обрабатываются группой в блоке выше
          </p>
          <div
            className="tabs"
            style={{
              marginBottom: 8,
            }}
          >
            {[["", "Все площадки"], ..._t.map((a) => [a, a])].map(([a, f]) => (
              <button className={"tab" + (l === a ? " on" : "")} onClick={() => i(a)}>
                {f}
                {a ? ` · ${(u || []).filter((P) => (P.site || "") === a).length}` : ""}
              </button>
            ))}
          </div>
          <CFe err={x} />
          <CFe {...(z || {})} />
          <div className="tscroll">
            <table>
              <thead>
                <tr>
                  <th>Машина</th>
                  <th>Культура · Поставщик</th>
                  <th className="right">Вес план, кг</th>
                  <th>Статус</th>
                  <th>Услуга</th>
                  <th>Замес (с кем · параметр)</th>
                  <th>Доп. услуги поручения</th>
                  <th>Площадка</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {y.map((a) => {
                  const f = Ae(a, {
                    need: m(a),
                  });
                  return (
                    <tr
                      className="rowc"
                      onClick={(P) => {
                        lt(P) && w(a);
                      }}
                    >
                      <td className="rowx" onClick={() => w(a)} title="Карточка машины">
                        <b>{a.vehicle_no}</b>
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          лаборатория {Ue(a.lab_at)}
                        </div>
                      </td>
                      <td>
                        {a.culture || "—"}
                        <div
                          className="faint"
                          style={{
                            fontSize: 10,
                          }}
                        >
                          {a.supplier || ""}
                        </div>
                      </td>
                      <td className="right">{a.planned_tonnes != null ? q(qe(a.planned_tonnes)) : "—"}</td>
                      <td>
                        <span className={"stage " + f.c}>{f.t}</span>
                      </td>
                      <td>
                        <span className={"stage " + (a.lab_result1 === "unload" ? "lab_ok" : "in")}>{Le[a.lab_result1] || "—"}</span>
                      </td>
                      <td
                        style={{
                          maxWidth: 240,
                          whiteSpace: "normal",
                        }}
                      >
                        <Gt v={a} dash={!0} />
                      </td>
                      <td
                        style={{
                          maxWidth: 220,
                          whiteSpace: "normal",
                        }}
                      >
                        {m(a).length ? (
                          <span className="svcchips">
                            {m(a).map((P) => {
                              const T = (a.extra_done || []).includes(P);
                              return (
                                <button
                                  className={"bchip" + (T ? " st-ready" : "")}
                                  title={T ? "оказана — снять отметку" : "отметить как оказанную"}
                                  onClick={() => U(a, P)}
                                >
                                  {T ? "✓ " : ""}
                                  {P}
                                </button>
                              );
                            })}
                          </span>
                        ) : (
                          <span className="faint">—</span>
                        )}
                      </td>
                      <td>
                        <CPe value={a.site || ""} onChange={(P) => v(a, P)} options={_t} w={140} ph="— площадка —" />
                      </td>
                      <td className="nowrap">
                        <button className="btn sm" onClick={() => Z(a)}>
                          Услуга оказана ✓
                        </button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
          {!y.length && (
            <p
              className="p-sub"
              style={{
                margin: "8px 0 0",
              }}
            >
              очередь пуста — машины появятся после одобрения лабораторией
            </p>
          )}
        </div>
        <div className="panel">
          <div className="hd">
            <h2 className="p-title mt0">Выполненные услуги · последние {(N || []).length}</h2>
          </div>
          <p className="p-sub">
            машины, по которым перевалка отметила услугу · пока список пуст — отмечай услугу в очереди выше, и машина появится здесь
          </p>
          <CFe err={j} />
          <div
            className="tscroll"
            style={{
              maxHeight: "34vh",
            }}
          >
            <table>
              <thead>
                <tr>
                  <th>Машина</th>
                  <th>Культура</th>
                  <th>Услуга</th>
                  <th>Замес</th>
                  <th>Площадка</th>
                  <th>Когда</th>
                  <th />
                </tr>
              </thead>
              <tbody>
                {(N || []).map((a) => (
                  <tr>
                    <td>
                      <b>{a.vehicle_no}</b>
                    </td>
                    <td>{a.culture || "—"}</td>
                    <td>{a.ts_service || Le[a.lab_result1] || "—"}</td>
                    <td
                      style={{
                        maxWidth: 240,
                        whiteSpace: "normal",
                      }}
                    >
                      <Gt v={a} dash={!0} />
                    </td>
                    <td>
                      <CPe value={a.site || ""} onChange={(f) => v(a, f)} options={_t} w={130} ph="—" />
                    </td>
                    <td className="nowrap">{he(a.ts_at)}</td>
                    <td className="nowrap">
                      {M && (
                        <button className="btn sec sm" title="Отменить отметку услуги" onClick={() => I(a)}>
                          ✕ отменить
                        </button>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </>
    )
  );
}
function CBa({ me: t }) {
  const [n] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("*, term_line_containers(container_no, size, height, booking, line, client, site, cont_tare_kg, seal_no)")
            .not("gross_kg", "is", null)
            .order("id", {
              ascending: !1,
            })
            .limit(800),
        ),
      [],
      6e4,
    ),
    [s, l] = Te("ts.akt", {}),
    [i, u] = S.useState(null),
    [o, x] = S.useState(null),
    N = S.useMemo(() => (n || []).filter((p) => p.gross_kg != null && p.term_line_containers), [n]),
    b = Fe(N.map((p) => p.term_line_containers.booking)),
    j = (p) => (p.gross_at || p.tare_at ? Ve(p.gross_at || p.tare_at) : ""),
    g = Fe(N.map(j)).sort().reverse().slice(0, 60),
    d = S.useMemo(
      () =>
        !s.bk && !s.zd
          ? []
          : N.filter((p) => !((s.bk && (p.term_line_containers.booking || "") !== s.bk) || (s.zd && j(p) !== s.zd))).sort((p, F) =>
              (p.gross_at || "").localeCompare(F.gross_at || ""),
            ),
      [N, s.bk, s.zd],
    ),
    M = () => d.map(ml),
    z = Ns(),
    _ = () => {
      var F, C, y;
      const p = M();
      return {
        aktNo: (s.no || "").trim(),
        aktDate: s.adate || z,
        zatDate: s.dt || z,
        client: (s.client || "").trim() || ((F = p[0]) == null ? void 0 : F.client) || "",
        cargo: (s.cargo || "").trim() || ((C = p[0]) == null ? void 0 : C.culture) || "",
        addr: s.addr || "",
        dtNo: s.dtno || "",
        booking: s.bk || ((y = p[0]) == null ? void 0 : y.booking) || "",
        rows: p,
      };
    },
    h = () => {
      const p = M(),
        F = [],
        C = p.filter((U) => U.tare == null);
      C.length &&
        F.push(
          `нет паспортной тары контейнера (без неё брутто в акте не посчитать): ${C.slice(0, 4)
            .map((U) => U.cont)
            .join(", ")}${C.length > 4 ? "…" : ""}`,
        );
      const y = p.filter((U) => U.net == null);
      y.length &&
        F.push(
          `нет веса затарки: ${y
            .slice(0, 4)
            .map((U) => U.cont)
            .join(", ")}`,
        );
      const $ = p.filter((U) => !U.seal);
      $.length &&
        F.push(
          `нет пломбы: ${$.slice(0, 4)
            .map((U) => U.cont)
            .join(", ")}`,
        );
      const m = p.filter((U) => U.is_temp);
      m.length && F.push(`в списке есть времянки (внутреннее перемещение, а не отгрузка): ${m.map((U) => U.cont).join(", ")}`);
      const v = [...new Set(p.map((U) => U.booking).filter(Boolean))];
      return (v.length > 1 && F.push(`в одном акте разные букинги: ${v.join(", ")}`), F);
    },
    w = async (p) => {
      if (!d.length) {
        x({
          err: "Не выбраны затарки: укажи букинг и/или дату",
        });
        return;
      }
      if (!(s.no || "").trim()) {
        x({
          err: "Укажи номер акта — он записывается в журнал документов и проверяется на повтор",
        });
        return;
      }
      const F = h();
      if (
        F.length &&
        !window.confirm(`Акт выпускается с замечаниями:

• ${F.join(`
• `)}

Всё равно выпустить?`)
      )
        return;
      const C = _();
      try {
        const y = await vn({
          kind: "akt",
          no: C.aktNo,
          date: C.aktDate || Ve(),
          booking: C.booking || null,
          cargo: C.cargo || null,
          client: C.client || null,
          rows: C.rows,
          me: t,
        });
        await je(
          "doc",
          null,
          "akt",
          {
            номер: C.aktNo,
            контейнеров: C.rows.length,
            копия: y === "copy" || void 0,
            продавлено: F.length ? F : void 0,
          },
          t,
        );
        const $ = y === "copy" ? " — повторная печать (копия), состав тот же" : " — записан в журнал документов";
        p === "xls"
          ? (await _i(C),
            x({
              ok: `Акт затарки №${C.aktNo} (Excel): ${C.rows.length} конт.${$}`,
            }))
          : (u({
              k: "aktpdf",
              p: C,
            }),
            x({
              ok: `Акт затарки №${C.aktNo}: ${C.rows.length} конт.${$}`,
            }));
      } catch (y) {
        x({
          err: String(y.message || y),
        });
      }
    };
  return (
    <>
      {(i == null ? void 0 : i.k) === "aktpdf" && <CZl p={i.p} onClose={() => u(null)} />}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Акт затарки · итоговый документ услуги</h2>
        </div>
        <p className="p-sub">
          единственное место выпуска акта затарки · выбери букинг и/или дату затарки — подтянутся все взвешенные затарки · номер акта обязателен и
          проверяется на повтор, каждый выпуск пишется в журнал документов · «Вес брутто» в акте = нетто груза + паспортная тара контейнера
        </p>
        <div
          className="row"
          style={{
            gap: 8,
          }}
        >
          <X label="Букинг">
            <CPe
              value={s.bk || ""}
              onChange={(p) =>
                l((F) => ({
                  ...F,
                  bk: p,
                }))
              }
              options={b}
              w={190}
              ph="— все —"
            />
          </X>
          <X label="Дата затарки">
            <CPe
              value={s.zd || ""}
              onChange={(p) =>
                l((F) => ({
                  ...F,
                  zd: p,
                  dt: p ? p.split("-").reverse().join(".") : F.dt,
                }))
              }
              options={g}
              w={150}
              ph="— выбери —"
            />
          </X>
          <X label="№ акта">{Se(s, l, "no", "", 80)}</X>
          <X label="Дата акта">{Se(s, l, "adate", z, 110)}</X>
          <X label="Дата затарки">{Se(s, l, "dt", z, 110)}</X>
          <X label="ДТ №">{Se(s, l, "dtno", "", 140)}</X>
          <X label="Клиент (по поручению)">{Se(s, l, "client", "из данных контейнера", 200)}</X>
          <X label="Груз">{Se(s, l, "cargo", "из данных затарки", 150)}</X>
          <X label="Адрес отгрузки (в адрес…)">{Se(s, l, "addr", "", 240)}</X>
          <button className="btn sec sm" disabled={!d.length} onClick={() => w("xls")}>
            ⇩ Excel
          </button>
          <button className="btn sm" disabled={!d.length} onClick={() => w("pdf")}>
            Акт · PDF
          </button>
        </div>
        {d.length > 0 && h().length > 0 && (
          <div
            className="ovr9"
            style={{
              marginTop: 8,
            }}
          >
            {h().map((p, F) => (
              <div className="ovr-l">⚠ {p}</div>
            ))}
          </div>
        )}
        {s.bk || s.zd ? (
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
            }}
          >
            подходит затарок: <b>{d.length}</b>
            {s.bk ? ` · букинг ${s.bk}` : ""}
            {s.zd ? ` · дата ${s.zd}` : ""} · нетто {q(d.reduce((p, F) => p + (+(F.net_final_kg ?? F.net_kg) || 0), 0))} кг
          </p>
        ) : (
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
            }}
          >
            выбери букинг или дату затарки
          </p>
        )}
        <CFe {...(o || {})} />
      </div>
    </>
  );
}
function CZl({ p: t, onClose: n }) {
  const s = t.rows.reduce(
    (l, i) => ({
      n: l.n + (+i.net || 0),
      g: l.g + (+i.gross || 0),
    }),
    {
      n: 0,
      g: 0,
    },
  );
  return (
    <CDt
      title={`Акт затарки №${t.aktNo || "—"} · ${t.booking || ""}`}
      onClose={n}
      pages=".pdoc"
      file={st("Акт-затарки", t.aktNo ? "№" + t.aktNo : "", t.client, t.booking ? "букинг-" + t.booking : "", t.cont)}
    >
      <div className="pdoc pass9 aktdoc">
        <div className="plogo9">
          <img src="/logo-side.png" alt="ФЕНИКС" />
        </div>
        <div className="ak-h1">ООО "ЗЕРНОВОЙ ОПЕРАТОР" {t.client ? `по поручению ${t.client}` : ""}</div>
        <div className="ak-h2">
          АКТ №{t.aktNo || "__"} от {t.aktDate}
        </div>
        <div className="ak-h3">Перетарки груза из автомобиля в контейнер</div>
        <div className="ak-p">
          Настоящим акт подтверждает, что груз «{(t.cargo || "").toUpperCase()}», предназначенный к отгрузке на экспорт
          {t.addr ? ` в адрес ${t.addr}` : ""}, перетарен в контейнеры и перевешен на весах автомобильных ВА "СХТ", мод. ВА СХТ 2-80-20-3-0, 66276-16
          (ТВ-003/05 Н №48186).
        </div>
        <div className="ak-p">
          дата затарки {t.zatDate} · ДТ № {t.dtNo || "—"} · БУКИНГ {t.booking || "—"}
        </div>
        <table className="ak-t">
          <thead>
            <tr>
              <th>№</th>
              <th>Склад</th>
              <th>Погружено в контейнер</th>
              <th>Тип конт., фут</th>
              <th>Линия</th>
              <th>Вес нетто, кг</th>
              <th>Вес брутто, кг</th>
              <th>Тара конт., кг</th>
              <th>№ пломбы</th>
              <th>CU m3</th>
            </tr>
          </thead>
          <tbody>
            {t.rows.map((l, i) => (
              <tr>
                <td>{i + 1}</td>
                <td>{l.sklad}</td>
                <td>{l.cont}</td>
                <td>{l.type}</td>
                <td>{l.line}</td>
                <td className="r">{q(l.net)}</td>
                <td className="r">{q(l.gross)}</td>
                <td className="r">{q(l.tare)}</td>
                <td>{l.seal}</td>
                <td>{l.cum}</td>
              </tr>
            ))}
            <tr className="tot">
              <td colSpan={5}>Всего:</td>
              <td className="r">{q(s.n)}</td>
              <td className="r">{q(s.g)}</td>
              <td colSpan={3} />
            </tr>
          </tbody>
        </table>
        <div className="ak-sign">
          <span>представитель ООО «ЗЕРНОВОЙ ОПЕРАТОР» ______________________</span>
          <span>м.п.</span>
        </div>
      </div>
    </CDt>
  );
}
function CKa({ b: t, rows: n, onClose: s }) {
  const l = Js(),
    i = t.vgm_no || "",
    u = t.vgm_date ? t.vgm_date.split("-").reverse().join(".") : Ns(),
    o = n.length
      ? n
      : [
          {
            cont: "",
            vgm: null,
            seal: "",
          },
        ],
    x = (b) => (o.length > 1 ? `${i || "__"}/${b + 1}` : i || "__"),
    N = ({ r: b, i: j }) => (
      <div className="pdoc vgmdoc">
        <div className="vg-h">
          СЕРТИФИКАТ О ПОДТВЕРЖДЕНИИ МАССЫ БРУТТО КОНТЕЙНЕРА
          <br />
          <i>CERTIFICATE OF VERIFIED GROSS MASS OF CONTAINER</i>
        </div>
        <div className="vg-org">
          ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ «ЗЕРНОВОЙ ОПЕРАТОР» ИНН/КПП 2315243025/231501001, ОГРН 1262300005098, 353920, Краснодарский край,
          г. Новороссийск, пр-кт Дзержинского, д. 156Б · E-mail: terminal@raevkahills.ru
          <br />
          <i>
            LLC "GRAIN OPERATOR", INN/KPP 2315243025/231501001, PSRN 1262300005098, 353920, Krasnodar krai, Novorossiysk, Dzerzhinskogo ave., 156B
          </i>
        </div>
        <table className="vg-t">
          <tbody>
            <tr>
              <td>Номер Сертификата / Certificate No.</td>
              <td>
                <b>{x(j)}</b>
              </td>
            </tr>
            <tr>
              <td>Дата взвешивания и выдачи / Date of issue (weighing)</td>
              <td>
                <b>{u}</b>
              </td>
            </tr>
            <tr>
              <td>Место взвешивания / Place of weighing</td>
              <td>{l.weigh_place}</td>
            </tr>
            <tr>
              <td>Средство взвешивания / Weighing scale details</td>
              <td>{l.scale_details}</td>
            </tr>
            <tr>
              <td>Свидетельство о поверке / Calibration certificate</td>
              <td>Дата поверки / Validity date: {l.scale_calib_date}</td>
            </tr>
            <tr>
              <td>Идентификационный номер контейнера / Container Number</td>
              <td>
                <b>{b.cont || "__"}</b>
              </td>
            </tr>
            <tr>
              <td>Метод взвешивания / Method of weighing</td>
              <td>
                <b>{l.vgm_method}</b>
              </td>
            </tr>
            <tr>
              <td>Подтверждённая масса брутто, кг / Verified gross mass, kgs</td>
              <td>
                <b>
                  {b.vgm != null
                    ? Number(b.vgm).toLocaleString("ru-RU", {
                        minimumFractionDigits: 2,
                        maximumFractionDigits: 2,
                      })
                    : "__"}
                </b>
              </td>
            </tr>
            <tr>
              <td>Пломба контейнера / Seal number</td>
              <td>
                <b>{b.seal || "__"}</b>
              </td>
            </tr>
          </tbody>
        </table>
        <div className="vg-decl">
          ДЕКЛАРАЦИЯ: масса брутто контейнера подтверждена в соответствии с требованиями конвенции СОЛАС.
          <br />
          <i>DECLARATION: gross weight of the container is confirmed in accordance with the requirements of SOLAS convention.</i>
        </div>
        <div className="vg-sign">
          <span>Фамилия исполнителя / Name of declarant: {l.vgm_declarant || "________________"}</span>
          <span>Подпись / Signature ____________</span>
        </div>
      </div>
    );
  return (
    <CDt
      title={`VGM · сертификаты ${i || "—"} · ${t.batch_no} · ${o.length} шт.`}
      onClose={s}
      pages=".pdoc"
      file={st("VGM", "партия-" + t.batch_no, t.booking ? "букинг-" + t.booking : "", o.length + "-справок")}
    >
      {o.map((b, j) => (
        <N r={b} i={j} />
      ))}
    </CDt>
  );
}
function wa({ me: t }) {
  var G, ie;
  const [n, s] = S.useState(null),
    [l, i, u] = ne(
      () =>
        Y(
          A.from("term_batches")
            .select("*")
            .order("id", {
              ascending: !1,
            })
            .limit(200),
        ),
      [],
      2e4,
    ),
    [o, x, N] = ne(
      () =>
        Y(
          A.from("term_line_containers")
            .select("*")
            .is("out_at", null)
            .is("batch_id", null)
            .in("state", ["loaded", "inspected", "fumigated"])
            .order("in_at")
            .limit(2e3),
        ),
      [],
      2e4,
    ),
    [b, j] = ne(() => Y(A.from("term_line_containers").select("*").not("batch_id", "is", null).order("id").limit(2e3)), [], 2e4),
    [g] = ne(
      () =>
        Y(
          A.from("term_container_loads")
            .select("id, container_id, net_kg, net_final_kg, seal_no, culture, gross_at, site, order_id, order_name")
            .order("id", {
              ascending: !1,
            })
            .limit(3e3),
        ),
      [],
      6e4,
    ),
    d = 14,
    [M] = ne(
      () =>
        Y(
          A.from("term_truck_visits")
            .select("id, culture, site, unload_place, tare_at, net_kg, lab_moisture, lab_impurity, lab_broken")
            .not("tare_at", "is", null)
            .order("tare_at", {
              ascending: !1,
            })
            .limit(4e3),
        ),
      [],
      12e4,
      "vq9",
    ),
    [z] = ne(
      () => Y(A.from("term_orders").select("id, order_no, term_contracts(contract_no, term_counterparties(name))").limit(2e3)),
      [],
      12e4,
      "ords9b",
    ),
    _ = S.useMemo(() => {
      const c = {},
        V = {};
      for (const J of z || []) ((c[J.id] = J), J.order_no && !V[J.order_no] && (V[J.order_no] = J));
      return {
        byId: c,
        byNo: V,
      };
    }, [z]),
    h = (c) => (c && ((c.order_id ? _.byId[c.order_id] : null) || (c.order_name ? _.byNo[c.order_name] : null))) || null,
    w = (c) => {
      const V = (g || []).find((de) => de.container_id === c);
      if (!V || !V.gross_at) return null;
      const J = +new Date(V.gross_at),
        ce = J - d * 864e5,
        oe = (V.site || "").trim(),
        se = (M || []).filter((de) => {
          const ve = +new Date(de.tare_at);
          if (!(ve <= J && ve >= ce) || !_s(de.culture, V.culture)) return !1;
          const we = (de.site || de.unload_place || "").trim();
          return !oe || !we || we === oe;
        }),
        ge = se.reduce((de, ve) => de + (+ve.net_kg || 0), 0);
      if (!se.length || !ge) return null;
      const Me = (de) => {
        const ve = se.filter((Pe) => Pe[de] != null && +Pe.net_kg > 0),
          we = ve.reduce((Pe, Be) => Pe + (+Be.net_kg || 0), 0);
        return we ? Math.round((ve.reduce((Pe, Be) => Pe + +Be[de] * +Be.net_kg, 0) / we) * 100) / 100 : null;
      };
      return {
        m: Me("lab_moisture"),
        i: Me("lab_impurity"),
        b: Me("lab_broken"),
        n: se.length,
      };
    },
    [p, F] = S.useState(!1),
    [C, y] = S.useState({}),
    $ = async (c) => {
      const V = (C[c.id] ?? c.dt_no ?? "").trim();
      if (V !== (c.dt_no || ""))
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                dt_no: V || null,
              })
              .eq("id", c.id),
            "контейнер " + c.container_no,
          ),
            await je(
              "container",
              c.id,
              "dt_no",
              {
                контейнер: c.container_no,
                ДТ: V || null,
              },
              t,
            ),
            y((J) => {
              const ce = {
                ...J,
              };
              return (delete ce[c.id], ce);
            }),
            P({
              ok: `${c.container_no}: ДТ ${V || "очищена"}`,
            }),
            x());
        } catch (J) {
          P({
            err: String(J.message || J),
          });
        }
    },
    [m, v] = S.useState({}),
    [U, Z] = S.useState({}),
    [I, D] = S.useState({}),
    [E, a] = S.useState(null),
    [f, P] = S.useState(null),
    [T, H] = S.useState(null),
    [Q, ae] = S.useState(null),
    [me, L] = S.useState(""),
    W = (c) => {
      const V = (g || []).find((J) => J.container_id === c);
      return V ? (V.net_final_kg ?? V.net_kg) : null;
    },
    K = (c) => (b || []).filter((V) => V.batch_id === c),
    le = () =>
      (o || []).map((c) => {
        var ce, oe, se;
        const V = w(c.id),
          J = h((g || []).find((ge) => ge.container_id === c.id));
        return {
          no: c.container_no,
          type: c.size ? `${c.size}'${c.height || ""}` : "",
          line: c.line || "",
          booking: c.booking || "",
          cargo: c.cargo || "",
          qual: V ? `вл ${V.m ?? "—"} · сор ${V.i ?? "—"} · к/б ${V.b ?? "—"}` : "",
          qn: V ? V.n : null,
          contract: ((ce = J == null ? void 0 : J.term_contracts) == null ? void 0 : ce.contract_no) || "",
          client:
            c.client ||
            ((se = (oe = J == null ? void 0 : J.term_contracts) == null ? void 0 : oe.term_counterparties) == null ? void 0 : se.name) ||
            "",
          dt: c.dt_no || "",
          net: W(c.id),
          seal: c.seal_no || "",
          stack: c.stack || "",
          st: Mt(c).t,
        };
      }),
    $e = () =>
      Ze("Формирование_партии", [
        {
          name: "К формированию",
          title: "ФЕНИКС · Терминал — затаренные контейнеры на площадке",
          cols: [
            {
              h: "Контейнер",
              w: 14,
            },
            {
              h: "Тип",
              w: 8,
            },
            {
              h: "Линия",
              w: 12,
            },
            {
              h: "Букинг",
              w: 18,
            },
            {
              h: "Груз",
              w: 16,
            },
            {
              h: "Качество груза",
              w: 26,
            },
            {
              h: "Машин в расчёте",
              w: 14,
              num: 1,
              int: 1,
            },
            {
              h: "Экспортный контракт",
              w: 20,
            },
            {
              h: "Клиент",
              w: 24,
            },
            {
              h: "Таможенная декларация",
              w: 22,
            },
            {
              h: "Нетто, кг",
              w: 12,
              num: 1,
              int: 1,
            },
            {
              h: "Пломба",
              w: 13,
            },
            {
              h: "Штабель",
              w: 11,
            },
            {
              h: "Статус",
              w: 22,
            },
          ],
          rows: le().map((c) => [c.no, c.type, c.line, c.booking, c.cargo, c.qual, c.qn, c.contract, c.client, c.dt, c.net, c.seal, c.stack, c.st]),
        },
      ]),
    ee = Object.keys(m)
      .filter((c) => m[c])
      .map(Number),
    re = async () => {
      var ge, Me, de, ve;
      if (!ee.length) {
        P({
          err: "Отметь контейнеры для партии (галочки слева)",
        });
        return;
      }
      const c = (o || []).filter((we) => ee.includes(we.id)),
        V = (we) => [...new Set(c.map((Pe) => (Pe[we] || "").trim()).filter(Boolean))],
        J = [];
      (V("booking").length > 1 && J.push(`в партии разные букинги: ${V("booking").join(", ")}`),
        V("line").length > 1 && J.push(`разные линии: ${V("line").join(", ")}`),
        V("cargo").length > 1 && J.push(`разный груз: ${V("cargo").join(", ")}`));
      const ce = c.filter((we) => W(we.id) == null);
      ce.length && J.push(`нет веса затарки: ${ce.map((we) => we.container_no).join(", ")}`);
      const oe = c.filter((we) => we.cont_tare_kg == null);
      oe.length && J.push(`нет паспортной тары (без неё не посчитать VGM): ${oe.map((we) => we.container_no).join(", ")}`);
      const se = c.filter((we) => !we.seal_no);
      if (
        (se.length && J.push(`нет пломбы: ${se.map((we) => we.container_no).join(", ")}`),
        !(
          J.length &&
          !window.confirm(`Партия собирается с замечаниями:

• ${J.join(`
• `)}

Всё равно сформировать?`)
        ))
      )
        try {
          const we = await Y(A.rpc("term_next_batch_no")),
            Pe = await Y(
              A.from("term_batches")
                .insert({
                  batch_no: we,
                  booking: ((ge = c.find((Be) => Be.booking)) == null ? void 0 : ge.booking) || null,
                  line: ((Me = c.find((Be) => Be.line)) == null ? void 0 : Me.line) || null,
                  cargo:
                    ((de = c.find((Be) => Be.cargo)) == null ? void 0 : de.cargo) ||
                    ((ve = (g || []).find((Be) => {
                      var Xt;
                      return Be.container_id === ((Xt = c[0]) == null ? void 0 : Xt.id);
                    })) == null
                      ? void 0
                      : ve.culture) ||
                    null,
                  vgm_no: we.replace("П-", "VGM-"),
                  vgm_date: Ve(),
                })
                .select("id, batch_no"),
            );
          for (const Be of c)
            await ue(
              A.from("term_line_containers")
                .update({
                  batch_id: Pe[0].id,
                })
                .eq("id", Be.id),
              "контейнер " + Be.container_no,
            );
          (v({}),
            P({
              ok: `Партия ${Pe[0].batch_no}: ${c.length} контейнеров — присвой пломбы и VGM в карточке`,
            }),
            i(),
            x(),
            j());
        } catch (we) {
          P({
            err: String(we.message || we),
          });
        }
    },
    be = ["manager", "chief"].includes(t.role),
    Ne = async (c, V, J, ce) => {
      try {
        await ue(A.from("term_batches").update(V).eq("id", c.id), "партия " + c.batch_no);
        const oe = V.status === "fumig" ? "inspected" : V.status === "ready" ? "fumigated" : null;
        if (oe)
          for (const se of K(c.id))
            se.out_at ||
              (await ue(
                A.from("term_line_containers")
                  .update({
                    state: oe,
                    ...(oe === "fumigated"
                      ? {
                          fumigation_at: new Date().toISOString(),
                        }
                      : {}),
                  })
                  .eq("id", se.id),
                "контейнер " + se.container_no,
              ));
        (await je(
          "batch",
          c.id,
          ce || "advance",
          {
            партия: c.batch_no,
            статус: V.status,
          },
          t,
        ),
          P({
            ok: J,
          }),
          i(),
          j());
      } catch (oe) {
        P({
          err: String(oe.message || oe),
        });
      }
    },
    ze = ["formed", "inspect", "fumig", "ready", "departed"],
    Ke = async (c) => {
      const V = ze.indexOf(c.status);
      if (V <= 0) {
        P({
          err: "Партия в начальном состоянии — откатывать нечего",
        });
        return;
      }
      const J = ze[V - 1];
      if (!window.confirm(`Откатить партию ${c.batch_no}: «${vt[c.status]}» → «${vt[J]}»?`)) return;
      const ce =
        {
          inspect: {
            inspect_at: null,
            inspect_by: null,
          },
          fumig: {
            insp_at: null,
            insp_by: null,
          },
          ready: {
            fumig_at: null,
            fumig_by: null,
            ready_at: null,
          },
          departed: {
            departed_at: null,
            departed_by: null,
          },
        }[c.status] || {};
      try {
        await ue(
          A.from("term_batches")
            .update({
              status: J,
              ...ce,
            })
            .eq("id", c.id),
          "партия " + c.batch_no,
        );
        const oe = {
          inspect: "loaded",
          fumig: "loaded",
          ready: "inspected",
        }[c.status];
        if (oe)
          for (const se of K(c.id))
            se.out_at ||
              (await ue(
                A.from("term_line_containers")
                  .update({
                    state: oe,
                  })
                  .eq("id", se.id),
                "контейнер " + se.container_no,
              ));
        (await je(
          "batch",
          c.id,
          "undo",
          {
            партия: c.batch_no,
            было: c.status,
            стало: J,
          },
          t,
        ),
          P({
            ok: `${c.batch_no}: откат на «${vt[J]}»`,
          }),
          i(),
          j());
      } catch (oe) {
        P({
          err: String(oe.message || oe),
        });
      }
    },
    He = async (c) => {
      const V = K(c.id);
      if (V.length) {
        P({
          err: `В партии ${c.batch_no} ещё ${V.length} контейнеров — сначала отвяжи их (✕ в списке контейнеров)`,
        });
        return;
      }
      if (window.confirm(`Удалить пустую партию ${c.batch_no}?`))
        try {
          (await ue(A.from("term_batches").delete().eq("id", c.id), "партия " + c.batch_no),
            await je(
              "batch",
              c.id,
              "delete",
              {
                партия: c.batch_no,
              },
              t,
            ),
            P({
              ok: `Партия ${c.batch_no} удалена`,
            }),
            H(null),
            i(),
            j(),
            x());
        } catch (J) {
          P({
            err: String(J.message || J),
          });
        }
    },
    We = async (c, V) => {
      if (window.confirm(`Убрать контейнер ${V.container_no} из партии ${c.batch_no}?`))
        try {
          (await ue(
            A.from("term_line_containers")
              .update({
                batch_id: null,
              })
              .eq("id", V.id),
            "контейнер " + V.container_no,
          ),
            await je(
              "batch",
              c.id,
              "unlink",
              {
                партия: c.batch_no,
                контейнер: V.container_no,
              },
              t,
            ),
            P({
              ok: `${V.container_no} убран из партии ${c.batch_no}`,
            }),
            j(),
            x());
        } catch (J) {
          P({
            err: String(J.message || J),
          });
        }
    },
    Qe = (c) => {
      if (c.status === "formed")
        return (
          <button
            className="btn sec sm"
            onClick={(V) => {
              (ct(V),
                Ne(
                  c,
                  {
                    status: "inspect",
                    inspect_at: new Date().toISOString(),
                    inspect_by: t.id,
                  },
                  `${c.batch_no} → на досмотре`,
                  "to_inspect",
                ));
            }}
          >
            → Досмотр
          </button>
        );
      if (c.status === "inspect")
        return (
          <button
            className="btn sec sm"
            onClick={(V) => {
              (ct(V),
                Ne(
                  c,
                  {
                    status: "fumig",
                    insp_at: new Date().toISOString(),
                    insp_by: t.id,
                  },
                  `${c.batch_no}: досмотр пройден → фумигация`,
                  "inspected",
                ));
            }}
          >
            Досмотр пройден ✓
          </button>
        );
      if (c.status === "fumig")
        return (
          <button
            className="btn sec sm"
            onClick={(V) => {
              (ct(V),
                Ne(
                  c,
                  {
                    status: "ready",
                    fumig_at: new Date().toISOString(),
                    fumig_by: t.id,
                    ready_at: new Date().toISOString(),
                  },
                  `${c.batch_no}: фумигация проведена — партия готова, КПП выпускает в порт`,
                  "fumigated",
                ));
            }}
          >
            Фумигация ✓
          </button>
        );
      if (c.status === "ready") {
        const V = K(c.id),
          J = V.filter((ce) => ce.out_at).length;
        return V.length ? (
          J === V.length ? (
            <button
              className="btn sm"
              onClick={(ce) => {
                (ct(ce),
                  Ne(
                    c,
                    {
                      status: "departed",
                      departed_at: new Date().toISOString(),
                      departed_by: t.id,
                    },
                    `${c.batch_no} убыла в порт`,
                    "departed",
                  ));
              }}
            >
              Убыла в порт ✓
            </button>
          ) : (
            <span className="t2chip ok">
              выезд через КПП · {J}/{V.length}
            </span>
          )
        ) : (
          <span className="t2chip">пустая партия — удали её в карточке</span>
        );
      }
      return null;
    },
    Ie = async (c) => {
      const V = K(c.id);
      try {
        let J = 0;
        for (const ce of V) {
          const oe = U[ce.id];
          oe != null &&
            oe.trim() &&
            oe !== (ce.seal_no || "") &&
            (await ue(
              A.from("term_line_containers")
                .update({
                  seal_no: oe.trim(),
                })
                .eq("id", ce.id),
              "пломба " + ce.container_no,
            ),
            J++);
        }
        (P({
          ok: J ? `Пломбы сохранены: ${J}` : "Изменений нет",
        }),
          j());
      } catch (J) {
        P({
          err: String(J.message || J),
        });
      }
    },
    ht = async (c) => {
      var se, ge, Me, de;
      const V = ((((se = I[c.id]) == null ? void 0 : se.no) ?? c.vgm_no) || "").trim();
      if (!V) {
        P({
          err: "Укажи номер VGM-сертификата — он записывается в журнал документов и проверяется на повтор",
        });
        return;
      }
      const J = B(c),
        ce = J.filter((ve) => ve.vgm == null);
      if (ce.length) {
        P({
          err: `Нельзя выпустить VGM: у ${ce.length} контейнеров нет веса затарки или паспортной тары — ${ce
            .slice(0, 4)
            .map((ve) => ve.cont)
            .join(", ")}${ce.length > 4 ? "…" : ""}. Заполни данные и повтори.`,
        });
        return;
      }
      const oe = J.filter((ve) => !ve.seal);
      if (!(
        oe.length &&
        !window.confirm(`У ${oe.length} контейнеров не сохранена пломба (${oe
          .slice(0, 4)
          .map((ve) => ve.cont)
          .join(", ")}). В сертификате она будет пустой.

Выпустить сертификат?`)
      ))
        try {
          const ve = await vn({
            kind: "vgm",
            no: V,
            date: (((ge = I[c.id]) == null ? void 0 : ge.dt) ?? c.vgm_date) || Ve(),
            booking: c.booking || null,
            batchId: c.id,
            cargo: c.cargo || null,
            rows: J,
            me: t,
          });
          (await ue(
            A.from("term_batches")
              .update({
                vgm_no: V,
                vgm_date: (((Me = I[c.id]) == null ? void 0 : Me.dt) ?? c.vgm_date) || null,
              })
              .eq("id", c.id),
            "партия " + c.batch_no,
          ),
            await je(
              "batch",
              c.id,
              "vgm",
              {
                партия: c.batch_no,
                номер: V,
                контейнеров: J.length,
                копия: ve === "copy" || void 0,
              },
              t,
            ),
            ae({
              k: "vgm",
              b: {
                ...c,
                vgm_no: V,
                vgm_date: ((de = I[c.id]) == null ? void 0 : de.dt) ?? c.vgm_date,
              },
              rows: J,
            }),
            P({
              ok: `VGM №${V}: ${J.length} сертификатов${ve === "copy" ? " — повторная печать (копия)" : " — записан в журнал документов"}`,
            }),
            i());
        } catch (ve) {
          P({
            err: String(ve.message || ve),
          });
        }
    },
    B = (c) =>
      K(c.id).map((V) => {
        const J = W(V.id),
          ce = J != null && V.cont_tare_kg != null ? +J + +V.cont_tare_kg : null;
        return {
          cont: V.container_no,
          net: J,
          tare: V.cont_tare_kg,
          vgm: ce,
          seal: V.seal_no || "",
          type: (V.size || "") + (V.height || ""),
          line: V.line || "",
          sklad: V.site || "Склад",
          gross: ce,
          cum: al(V.size, V.height),
        };
      }),
    r = (l || []).filter(
      (c) =>
        !me.trim() ||
        [c.batch_no, c.booking, c.line, c.cargo, c.vgm_no].some((V) =>
          String(V || "")
            .toLowerCase()
            .includes(me.trim().toLowerCase()),
        ),
    ),
    O = T != null ? (l || []).find((c) => c.id === T) : null;
  return (
    <>
      {(Q == null ? void 0 : Q.k) === "vgm" && <CKa b={Q.b} rows={Q.rows} onClose={() => ae(null)} />}
      {E && <Li b={E.b} items={E.items} onClose={() => a(null)} />}
      {(Q == null ? void 0 : Q.k) === "aktpdf" && <CZl p={Q.p} onClose={() => ae(null)} />}
      {O && (
        <div
          className="modal-bg"
          onMouseDown={(c) => {
            c.target === c.currentTarget && H(null);
          }}
        >
          <div
            className="modal"
            style={{
              width: 760,
              maxWidth: "96vw",
            }}
          >
            <div className="hd">
              <h2 className="p-title mt0">
                Партия {O.batch_no} · {vt[O.status]}
              </h2>
              <button className="btn sec sm" onClick={() => H(null)}>
                ✕
              </button>
            </div>
            <div className="m-body">
              <div className="dgrid">
                <R l="Букинг" v={O.booking} />
                <R l="Линия" v={O.line} />
                <R l="Груз" v={O.cargo} />
                <R l="Контейнеров" v={K(O.id).length} />
                <R l="Сформирована" v={he(O.created_at)} />
                <R l="Досмотр" v={O.insp_at ? he(O.insp_at) : "—"} />
                <R l="Фумигация" v={O.fumig_at ? he(O.fumig_at) : "—"} />
                <R l="Готова к отправке" v={O.ready_at ? he(O.ready_at) : "—"} />
                <R l="Убыла в порт" v={O.departed_at ? he(O.departed_at) : "—"} />
              </div>
              <div
                className="row"
                style={{
                  gap: 8,
                  marginTop: 10,
                }}
              >
                <X label="VGM · номер сертификата">
                  <input
                    style={{
                      width: 130,
                    }}
                    value={((G = I[O.id]) == null ? void 0 : G.no) ?? O.vgm_no ?? ""}
                    onChange={(c) =>
                      D((V) => ({
                        ...V,
                        [O.id]: {
                          ...(V[O.id] || {}),
                          no: c.target.value,
                        },
                      }))
                    }
                  />
                </X>
                <X label="VGM · дата">
                  <input
                    type="date"
                    value={((ie = I[O.id]) == null ? void 0 : ie.dt) ?? O.vgm_date ?? ""}
                    onChange={(c) =>
                      D((V) => ({
                        ...V,
                        [O.id]: {
                          ...(V[O.id] || {}),
                          dt: c.target.value,
                        },
                      }))
                    }
                  />
                </X>
                <button
                  className="btn sec sm"
                  onClick={() => {
                    var c, V;
                    return Ne(
                      O,
                      {
                        vgm_no: (((c = I[O.id]) == null ? void 0 : c.no) ?? O.vgm_no) || null,
                        vgm_date: (((V = I[O.id]) == null ? void 0 : V.dt) ?? O.vgm_date) || null,
                      },
                      "Реквизиты VGM сохранены",
                    );
                  }}
                >
                  Сохранить
                </button>
                <button className="btn sm" onClick={() => ht(O)}>
                  VGM · PDF
                </button>
                <button
                  className="btn sec sm"
                  title="Все индивидуальные справки VGM одной печатью"
                  onClick={() => {
                    const c = K(O.id)
                      .map((V) => ({
                        c: V,
                        load: (g || []).find((J) => J.container_id === V.id && J.gross_kg != null),
                      }))
                      .filter((V) => V.load);
                    if (!c.length) {
                      P({
                        err: "У контейнеров партии нет закрытых затарок — справкам не из чего собраться",
                      });
                      return;
                    }
                    a({
                      b: O,
                      items: c,
                    });
                  }}
                >
                  Справки VGM · {K(O.id).length}
                </button>
                {be && (
                  <button className="btn sec sm" title="Откатить статус партии на шаг назад" onClick={() => Ke(O)}>
                    ↩ откатить статус
                  </button>
                )}
                {be && !K(O.id).length && (
                  <button className="btn danger sm" title="Удалить пустую партию" onClick={() => He(O)}>
                    Удалить партию
                  </button>
                )}
              </div>
              <p
                className="p-sub"
                style={{
                  margin: "6px 0 0",
                }}
              >
                акт затарки выпускается ниже, в панели «Акт затарки» этого же раздела — там один номер, одни проверки и журнал выпущенных документов
              </p>
              {(() => {
                const c = K(O.id).filter((V) => W(V.id) == null || V.cont_tare_kg == null);
                return c.length ? (
                  <p
                    className="p-sub"
                    style={{
                      margin: "10px 0 0",
                      color: "var(--warn)",
                    }}
                  >
                    у {c.length} конт. нет веса затарки или тары по паспорту — в VGM масса брутто будет пустой:{" "}
                    {c
                      .slice(0, 4)
                      .map((V) => V.container_no)
                      .join(", ")}
                    {c.length > 4 ? "…" : ""}
                  </p>
                ) : null;
              })()}
              <p
                className="p-sub"
                style={{
                  margin: "10px 0 4px",
                }}
              >
                контейнеры партии · пломбы можно править прямо здесь
              </p>
              <div
                className="tscroll"
                style={{
                  maxHeight: "34vh",
                }}
              >
                <table>
                  <thead>
                    <tr>
                      <th>Контейнер</th>
                      <th>Тип</th>
                      <th className="right">Нетто, кг</th>
                      <th className="right">Тара конт., кг</th>
                      <th className="right">Брутто (VGM), кг</th>
                      <th>Пломба</th>
                      <th>Штабель</th>
                      <th>Статус</th>
                      <th />
                    </tr>
                  </thead>
                  <tbody>
                    {K(O.id).map((c) => {
                      const V = W(c.id),
                        J = V != null && c.cont_tare_kg != null ? +V + +c.cont_tare_kg : null;
                      return (
                        <tr
                          className="rowc"
                          onClick={(ce) => {
                            lt(ce) && s(c.id);
                          }}
                        >
                          <td className="rowx" title="Карточка контейнера">
                            <b>{c.container_no}</b>
                          </td>
                          <td>{c.size ? `${c.size}' ${c.height || ""}` : "—"}</td>
                          <td className="right">{q(V)}</td>
                          <td className="right">{q(c.cont_tare_kg)}</td>
                          <td className="right">
                            <b>{q(J)}</b>
                          </td>
                          <td>
                            <input
                              className="g-in"
                              style={{
                                width: 110,
                              }}
                              value={U[c.id] ?? c.seal_no ?? ""}
                              onChange={(ce) =>
                                Z((oe) => ({
                                  ...oe,
                                  [c.id]: ce.target.value,
                                }))
                              }
                            />
                          </td>
                          <td>{c.stack || "—"}</td>
                          <td>{c.out_at ? <span className="stage left">Убыл {Ue(c.out_at)}</span> : <Et c={c} b={O} />}</td>
                          <td className="nowrap">
                            {be && !c.out_at && (
                              <button className="btn sec sm" title="Убрать контейнер из партии" onClick={() => We(O, c)}>
                                ✕
                              </button>
                            )}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
              <div className="m-foot">
                <button className="btn sec sm" onClick={() => Ie(O)}>
                  Сохранить пломбы
                </button>
                {Qe(O)}
              </div>
            </div>
          </div>
        </div>
      )}
      {n && <Ht id={n} me={t} onClose={() => s(null)} />}
      {p && (
        <CDt
          wide={!0}
          cls="rep9"
          title={`К формированию партии · ${(o || []).length} контейнеров`}
          onClose={() => F(!1)}
          file={st("К-формированию-партии")}
        >
          <div className="crep">
            <C_e
              done={!0}
              title="Затаренные контейнеры на площадке"
              extra={`${(o || []).length} шт · ${q((o || []).reduce((c, V) => c + (+W(V.id) || 0), 0))} кг`}
            >
              <div className="tscroll">
                <table>
                  <thead>
                    <tr>
                      <th>Контейнер</th>
                      <th>Тип</th>
                      <th>Линия</th>
                      <th>Букинг</th>
                      <th>Груз</th>
                      <th>Качество груза</th>
                      <th>Экспортный контракт</th>
                      <th>Клиент</th>
                      <th>Тамож. декларация</th>
                      <th className="right">Нетто, кг</th>
                      <th>Пломба</th>
                      <th>Статус</th>
                    </tr>
                  </thead>
                  <tbody>
                    {le().map((c, V) => (
                      <tr>
                        <td>
                          <b>{c.no}</b>
                        </td>
                        <td>{c.type || "—"}</td>
                        <td>{c.line || "—"}</td>
                        <td>{c.booking || "—"}</td>
                        <td>{c.cargo || "—"}</td>
                        <td>
                          {c.qual || "—"}
                          {c.qn ? (
                            <div
                              className="faint"
                              style={{
                                fontSize: 9.5,
                              }}
                            >
                              по {c.qn} машинам
                            </div>
                          ) : null}
                        </td>
                        <td>{c.contract || "—"}</td>
                        <td>{c.client || "—"}</td>
                        <td>{c.dt || "—"}</td>
                        <td className="right">
                          <b>{q(c.net)}</b>
                        </td>
                        <td>{c.seal || "—"}</td>
                        <td>{c.st}</td>
                      </tr>
                    ))}
                    {(o || []).length ? null : (
                      <tr>
                        <td colSpan={12} className="faint">
                          на площадке нет затаренных контейнеров без партии
                        </td>
                      </tr>
                    )}
                  </tbody>
                </table>
              </div>
              <p
                className="p-sub"
                style={{
                  margin: "8px 0 0",
                }}
              >
                качество — средневзвешенно по анализам машин той же культуры и площадки за {d} дней до затарки
              </p>
            </C_e>
          </div>
        </CDt>
      )}
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Формирование партии · затаренные контейнеры на площадке · {(o || []).length}</h2>
          <span
            className="row"
            style={{
              gap: 6,
            }}
          >
            <Je make={$e} label="⇩ Excel" />
            <button className="btn sec sm" onClick={() => F(!0)}>
              ⇩ PDF
            </button>
            <button
              className="btn sec sm"
              onClick={() => {
                (x(), i(), j());
              }}
            >
              Обновить
            </button>
          </span>
        </div>
        <p className="p-sub">
          отметь контейнеры и сформируй партию под отправку в порт · пломбы и VGM присваиваются в карточке партии · далее: досмотр → фумигация → выезд
          через КПП · качество считается по анализам машин той же культуры и площадки за {d} дней до затарки · номер ДТ вписывается прямо в строке
        </p>
        <CFe err={u || N} />
        <CFe {...(f || {})} />
        <div
          className="tscroll stick2"
          style={{
            maxHeight: "42vh",
          }}
        >
          <table>
            <thead>
              <tr>
                <th />
                <th>Контейнер</th>
                <th>Тип</th>
                <th>Линия</th>
                <th>Букинг</th>
                <th>Груз</th>
                <th>Качество груза</th>
                <th>Экспортный контракт</th>
                <th>Клиент</th>
                <th>Таможенная декларация</th>
                <th className="right">Нетто, кг</th>
                <th>Пломба</th>
                <th>Штабель</th>
                <th>Статус</th>
              </tr>
            </thead>
            <tbody>
              {(o || []).map((c) => {
                var ce, oe, se;
                const V = w(c.id),
                  J = h((g || []).find((ge) => ge.container_id === c.id));
                return (
                  <tr
                    className="rowx"
                    onClick={() =>
                      v((ge) => ({
                        ...ge,
                        [c.id]: !ge[c.id],
                      }))
                    }
                  >
                    <td onClick={ct}>
                      <input
                        type="checkbox"
                        checked={!!m[c.id]}
                        onChange={(ge) =>
                          v((Me) => ({
                            ...Me,
                            [c.id]: ge.target.checked,
                          }))
                        }
                      />
                    </td>
                    <td
                      className="rowx"
                      title="Карточка контейнера"
                      onClick={(ge) => {
                        (ge.stopPropagation(), s(c.id));
                      }}
                    >
                      <b>{c.container_no}</b>
                    </td>
                    <td>{c.size ? `${c.size}' ${c.height || ""}` : "—"}</td>
                    <td>{c.line || "—"}</td>
                    <td>{c.booking || "—"}</td>
                    <td>{c.cargo || "—"}</td>
                    <td className="nowrap">
                      {V ? (
                        <span title={`средневзвешенно по ${V.n} машинам той же культуры и площадки`}>
                          вл {V.m ?? "—"} · сор {V.i ?? "—"} · к/б {V.b ?? "—"}
                          <div
                            className="faint"
                            style={{
                              fontSize: 9.5,
                            }}
                          >
                            по {V.n} машинам
                          </div>
                        </span>
                      ) : (
                        <span className="faint">—</span>
                      )}
                    </td>
                    <td>{((ce = J == null ? void 0 : J.term_contracts) == null ? void 0 : ce.contract_no) || "—"}</td>
                    <td>
                      {c.client ||
                        ((se = (oe = J == null ? void 0 : J.term_contracts) == null ? void 0 : oe.term_counterparties) == null ? void 0 : se.name) ||
                        "—"}
                    </td>
                    <td onClick={ct}>
                      <input
                        className="g-in"
                        style={{
                          width: 150,
                        }}
                        placeholder="номер ДТ"
                        value={C[c.id] ?? c.dt_no ?? ""}
                        onChange={(ge) =>
                          y((Me) => ({
                            ...Me,
                            [c.id]: ge.target.value,
                          }))
                        }
                        onBlur={() => $(c)}
                        onKeyDown={(ge) => {
                          ge.key === "Enter" && ge.currentTarget.blur();
                        }}
                      />
                    </td>
                    <td className="right">{q(W(c.id))}</td>
                    <td>{c.seal_no || "—"}</td>
                    <td>{c.stack || "—"}</td>
                    <td>
                      <Et c={c} />
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
        <div className="m-foot">
          <button className="btn" disabled={!ee.length} onClick={re}>
            Сформировать партию · {ee.length} конт.
          </button>
          {ee.length ? (
            <span
              className="p-sub"
              style={{
                margin: 0,
              }}
            >
              нетто {q(ee.reduce((c, V) => c + (+W(V) || 0), 0))} кг
            </span>
          ) : null}
        </div>
      </div>
      <CBa me={t} />
      <div className="panel">
        <div className="hd">
          <h2 className="p-title mt0">Партии · {r.length}</h2>
          <input
            className="srch9"
            style={{
              maxWidth: 260,
            }}
            placeholder="Поиск: партия, букинг, линия…"
            value={me}
            onChange={(c) => L(c.target.value)}
          />
          {me.trim() && !(r || []).length ? <span className="find9no2">ничего не найдено</span> : null}
        </div>
        <p className="p-sub">
          клик по партии — карточка: контейнеры, пломбы, VGM-сертификат PDF, акт затарки · статусы: {Object.values(vt).join(" → ")} · плюс «Частично
          выпущена» и «Все выпущены · отметить убытие», когда контейнеры уходят через КПП
        </p>
        <div className="tscroll">
          <table>
            <thead>
              <tr>
                <th>Партия</th>
                <th>Статус</th>
                <th className="right">Конт.</th>
                <th className="right">Нетто, кг</th>
                <th>Букинг</th>
                <th>Линия</th>
                <th>Груз</th>
                <th>VGM №</th>
                <th>Сформирована</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {r.map((c) => {
                const V = K(c.id),
                  J = V.reduce((ce, oe) => ce + (+W(oe.id) || 0), 0);
                return (
                  <tr className="rowx" title="Карточка партии" onClick={() => H(c.id)}>
                    <td>
                      <b>{c.batch_no}</b>
                    </td>
                    <td>
                      {(() => {
                        const ce = wi(c, V);
                        return <span className={"stage " + ce.c}>{ce.t}</span>;
                      })()}
                    </td>
                    <td className="right">{V.length}</td>
                    <td className="right">{q(J)}</td>
                    <td>{c.booking || "—"}</td>
                    <td>{c.line || "—"}</td>
                    <td>{c.cargo || "—"}</td>
                    <td>{c.vgm_no || "—"}</td>
                    <td className="nowrap">{he(c.created_at)}</td>
                    <td className="nowrap" onClick={ct}>
                      {Qe(c)}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
        {!r.length && (
          <p
            className="p-sub"
            style={{
              margin: "8px 0 0",
            }}
          >
            партий пока нет — сформируй первую из затаренных контейнеров выше
          </p>
        )}
      </div>
    </>
  );
}
const Ds = {
    chief: {
      t: "Сводка",
      c: Hr,
    },
    manager: {
      t: "Менеджер · Реестры",
      c: tr,
    },
    kpp: {
      t: "КПП",
      c: xr,
    },
    lab: {
      t: "Лаборатория",
      c: Or,
    },
    scale: {
      t: "Весовая",
      c: Ir,
    },
    container: {
      t: "Приёмка контейнеров",
      c: Pr,
    },
    transship: {
      t: "Перевалка",
      c: fa,
    },
    batches: {
      t: "Партии · отправка",
      c: wa,
    },
    dispatcher: {
      t: "Диспетчеры",
      c: Ml,
    },
    reg_cp: {
      t: "Контрагенты",
      c: Ur,
    },
    reg_ctr: {
      t: "Договоры",
      c: Wr,
    },
    reg_ord: {
      t: "Поручения",
      c: Gr,
    },
    reg_req: {
      t: "Заявки",
      c: Kr,
    },
    reg_tr: {
      t: "Зерновозы",
      c: Zr,
    },
    reg_cult: {
      t: "Культуры",
      c: Xr,
    },
    reg_cont: {
      t: "Контейнеры",
      c: Qr,
    },
    reports: {
      t: "Отчёты",
      c: ta,
    },
    docs: {
      t: "Журнал документов",
      c: Mr,
    },
    settings: {
      t: "Настройки терминала",
      c: Nr,
    },
    devices: {
      t: "Камеры и весы",
      c: or,
    },
    audit: {
      t: "Журнал изменений",
      c: qr,
    },
    users: {
      t: "Пользователи",
      c: la,
    },
  },
  Xn = {
    chief: "M3 3h8v8H3zM13 3h8v8h-8zM3 13h8v8H3zM13 13h8v8h-8z",
    manager: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z",
    kpp: "M4 21V9l8-6 8 6v12M4 13h16M9 21v-4h6v4",
    lab: "M9 3h6M10 3v5.5L4.8 18a2 2 0 0 0 1.8 3h10.8a2 2 0 0 0 1.8-3L14 8.5V3",
    scale: "M12 3v18M8 21h8M12 5L5 8m7-3l7 3M5 8l-2.5 5h5zM19 8l-2.5 5h5z",
    container: "M3 8l9-5 9 5v8l-9 5-9-5zM3 8l9 5m0 0l9-5m-9 5v8",
    dispatcher:
      "M4 13v-2a8 8 0 0 1 16 0v2M3 15a2 2 0 0 1 2-2h1v6H5a2 2 0 0 1-2-2zM21 15a2 2 0 0 0-2-2h-1v6h1a2 2 0 0 0 2-2zM18 19.5a3.5 3.5 0 0 1-3.5 3.5H12",
    transship: "M7 21V9m0 0L3 13m4-4l4 4M17 3v12m0 0l4-4m-4 4l-4-4",
    batches: "M3 14h7v7H3zM14 14h7v7h-7zM8.5 3h7v7h-7z",
    reg_cp: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM22 21v-2a4 4 0 0 0-3-3.9M15 3.1a4 4 0 0 1 0 7.8",
    reg_ctr: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M16 13H8M16 17H8",
    reg_ord:
      "M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v0a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2zM9 13h6M9 17h4",
    reg_req: "M1 7h13v9H1zM14 10h4l3 3v3h-7zM6 19a1.8 1.8 0 1 0 0-3.6A1.8 1.8 0 0 0 6 19zM17.5 19a1.8 1.8 0 1 0 0-3.6 1.8 1.8 0 0 0 0 3.6z",
    reg_tr: "M1 5h13v10H1zM14 8h4l3 3v4h-7zM6 19a1.8 1.8 0 1 0 0-3.6A1.8 1.8 0 0 0 6 19zM17.5 19a1.8 1.8 0 1 0 0-3.6 1.8 1.8 0 0 0 0 3.6z",
    devices: "M4 7h3l2-2h6l2 2h3v12H4zM12 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z",
    reg_cult: "M12 21V8M12 8c0-3-2-5-5-5 0 3 2 5 5 5zm0 0c0-3 2-5 5-5 0 3-2 5-5 5zM12 14c0-3-2-5-5-5 0 3 2 5 5 5zm0 0c0-3 2-5 5-5 0 3-2 5-5 5",
    reg_cont: "M2 8h20v9H2zM6 8v9M10 8v9M14 8v9M18 8v9",
    reports: "M4 20v-8M10 20V5M16 20v-5M20 20V9M2 20h20",
    users: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM19 8v6M22 11h-6",
    settings: "M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6zM4 12h2M18 12h2M12 4v2M12 18v2M6.6 6.6l1.4 1.4M16 16l1.4 1.4M17.4 6.6L16 8M8 16l-1.4 1.4",
    audit: "M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 1 1 4 0M9 12h6M9 16h4",
    docs: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8zM14 2v6h6M9 15l2 2 4-4",
  },
  CVa = ({ n: t }) => (
    <svg
      viewBox="0 0 24 24"
      width="15"
      height="15"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.7"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden="true"
    >
      <path d={Xn[t] || Xn.chief} />
    </svg>
  );
function Na({ me: t, onClose: n }) {
  const [s, l] = S.useState(""),
    [i, u] = S.useState(""),
    [o, x] = S.useState(!1),
    [N, b] = S.useState(null),
    j = async () => {
      if (s.length < 8) {
        b({
          err: "Пароль короче 8 символов — подбери длиннее",
        });
        return;
      }
      if (s !== i) {
        b({
          err: "Пароли не совпадают",
        });
        return;
      }
      x(!0);
      const { error: g } = await A.auth.updateUser({
        password: s,
      });
      if ((x(!1), g)) {
        b({
          err: /weak|short/i.test(String(g.message)) ? "Пароль слишком простой — добавь буквы и цифры" : String(g.message),
        });
        return;
      }
      (await je(
        "user",
        null,
        "password_change",
        {
          кто: t.name,
        },
        t,
      ),
        b({
          ok: "Пароль изменён — при следующем входе используй новый",
        }),
        setTimeout(n, 1600));
    };
  return (
    <div
      className="modal-bg"
      onMouseDown={(g) => {
        g.target === g.currentTarget && n();
      }}
    >
      <div
        className="modal"
        style={{
          width: 380,
        }}
      >
        <div className="hd">
          <h2 className="p-title mt0">Сменить пароль</h2>
          <button className="btn sec sm" onClick={n}>
            ✕
          </button>
        </div>
        <div className="m-body">
          <div className="fcol">
            <X label="Новый пароль (от 8 символов)">
              <input type="password" autoFocus={!0} value={s} onChange={(g) => l(g.target.value)} autoComplete="new-password" />
            </X>
            <X label="Ещё раз">
              <input
                type="password"
                value={i}
                onChange={(g) => u(g.target.value)}
                autoComplete="new-password"
                onKeyDown={(g) => {
                  g.key === "Enter" && j();
                }}
              />
            </X>
          </div>
        </div>
        <div className="m-foot">
          <button className="btn" disabled={o} onClick={j}>
            {o ? "…" : "Сменить"}
          </button>
          <CFe {...(N || {})} />
        </div>
      </div>
    </div>
  );
}
function CYa({ S: t }) {
  const n = S.useRef(Date.now()),
    [s, l] = S.useState(!1),
    i = Math.max(0, +(t || {}).autologout_min || 0);
  return (
    S.useEffect(() => {
      if (!i) return;
      const u = () => {
          ((n.current = Date.now()), l(!1));
        },
        o = ["mousemove", "mousedown", "keydown", "touchstart", "scroll"];
      o.forEach((N) =>
        window.addEventListener(N, u, {
          passive: !0,
        }),
      );
      const x = setInterval(() => {
        const N = (Date.now() - n.current) / 6e4;
        N >= i ? (hn(), A.auth.signOut()) : l(N >= i - 1);
      }, 15e3);
      return () => {
        (o.forEach((N) => window.removeEventListener(N, u)), clearInterval(x));
      };
    }, [i]),
    !i || !s ? null : <div className="idle9">Без движения {i - 1}+ мин — через минуту выйду из системы. Коснись экрана, чтобы остаться.</div>
  );
}
function Sa() {
  var I, D;
  const [t, n] = S.useState(void 0),
    [s, l] = S.useState(null),
    [i, u] = Te("win", null, on.v || null),
    [o, x] = Te("theme", "dark"),
    [N, b] = Te("side.slim", !1),
    [j, g] = Te("side.grp", {}),
    [d, M] = S.useState(!1),
    [z, _] = S.useState(!1),
    [h, w] = S.useState(Rt);
  (S.useEffect(() => {
    if (!t) return;
    const E = () =>
      hi().then((T) => {
        (w(T), (ot.S = T));
      });
    E();
    const a = setInterval(E, 12e4);
    let f = null;
    pn().then(() => {
      f = A.channel("term_settings_live")
        .on(
          "postgres_changes",
          {
            event: "*",
            schema: "public",
            table: "term_settings",
          },
          E,
        )
        .subscribe((T) => {
          T !== "SUBSCRIBED" && console.debug("[term] настройки · канал:", T);
        });
    });
    const P = () => {
      document.visibilityState === "visible" && E();
    };
    return (
      document.addEventListener("visibilitychange", P),
      () => {
        (clearInterval(a), f && A.removeChannel(f), document.removeEventListener("visibilitychange", P));
      }
    );
  }, [t]),
    S.useEffect(() => {
      document.documentElement.dataset.theme = o;
    }, [o]));
  const { rows: p, reload: F } = fs("truck");
  (S.useEffect(() => {
    t && F();
  }, [t]),
    S.useEffect(() => {
      ((it.list = (p || []).map((a) => a.name)),
        (it.set = new Set(it.list.map((a) => De(a)).filter(Boolean))),
        (it.make = Object.fromEntries((p || []).map((a) => [De(a.name), a.note || ""]))));
      const E = {};
      for (const a of it.set) {
        const f = (a.match(/\d{3}/) || [])[0];
        f && (E[f] = E[f] === void 0 ? a : null);
      }
      ((it.short = Object.fromEntries(Object.entries(E).filter(([, a]) => a))), Ei());
    }, [p]),
    S.useEffect(() => {
      if (!t) return;
      ts();
      const E = setInterval(ts, 3e5),
        a = () => {
          document.visibilityState === "visible" && ts();
        };
      return (
        document.addEventListener("visibilitychange", a),
        () => {
          (clearInterval(E), document.removeEventListener("visibilitychange", a));
        }
      );
    }, [t]),
    S.useEffect(() => {
      A.auth.getSession().then(({ data: a }) => n((f) => (f === void 0 ? (a.session ?? null) : f)));
      const { data: E } = A.auth.onAuthStateChange((a, f) => {
        n((P) => {
          var T, H;
          return P === void 0
            ? (f ?? null)
            : (((T = P == null ? void 0 : P.user) == null ? void 0 : T.id) ?? null) ===
                (((H = f == null ? void 0 : f.user) == null ? void 0 : H.id) ?? null)
              ? P
              : (f ?? null);
        });
      });
      return () => E.subscription.unsubscribe();
    }, []));
  const C = t && t.user ? t.user.id : null;
  if (
    (S.useEffect(() => {
      if (!C) {
        l(null);
        return;
      }
      let E = !1;
      return (
        Y(A.from("term_profiles").select("*").eq("user_id", C).single())
          .then((a) => {
            E || l(a);
          })
          .catch(() => {
            E ||
              l({
                role: null,
              });
          }),
        () => {
          E = !0;
        }
      );
    }, [C]),
    t === void 0)
  )
    return null;
  if (!t) return <Ki />;
  if (!s)
    return (
      <div className="login">
        <div className="card">Загрузка профиля…</div>
      </div>
    );
  if (!s.role)
    return (
      <div className="login">
        <div className="card">
          Нет роли для этого пользователя — обратись к управляющему.
          <button
            className="btn sec"
            style={{
              marginTop: 12,
            }}
            onClick={() => {
              (hn(), A.auth.signOut());
            }}
          >
            Выйти
          </button>
        </div>
      </div>
    );
  const y = wt[s.role].tabs,
    $ = y.includes(i) ? i : y[0],
    CM_ = ((I = Ds[$]) == null ? void 0 : I.c) || (() => null),
    v = {
      id: t.user.id,
      name: s.display_name,
      role: s.role,
    };
  qt.me = v;
  const U =
      s.role === "chief"
        ? [
            ["g1", "Отделы", ["chief", "manager", "kpp", "lab", "scale", "container", "transship", "batches", "dispatcher"]],
            ["g2", "Реестры · статусы", ["reg_cp", "reg_ctr", "reg_ord", "reg_req", "reg_tr", "reg_cult", "reg_cont"]],
            ["g3", "Отчётность", ["reports", "docs"]],
            ["g4", "Администрирование", ["users", "settings", "devices", "audit"]],
          ]
        : s.role === "manager"
          ? [
              ["g1", "Отделы", ["manager", "kpp", "lab", "scale", "container", "transship", "batches", "dispatcher"]],
              ["g2", "Реестры · статусы", ["reg_cp", "reg_ctr", "reg_ord", "reg_req", "reg_tr", "reg_cult", "reg_cont"]],
              ["g3", "Отчётность", ["reports", "docs", "audit"]],
            ]
          : [
              ["g1", "Мои окна", y.filter((E) => !Ot.includes(E))],
              ["g2", "Реестры · статусы", y.filter((E) => Ot.includes(E))],
            ],
    Z = (E) => (
      <button
        className={"nav-link" + ($ === E ? " active" : "")}
        title={Ds[E].t}
        onClick={() => {
          (u(E), M(!1));
        }}
      >
        <span className="nav-ic">
          <CVa n={E} />
        </span>
        <span className="nav-label">{Ds[E].t}</span>
      </button>
    );
  return (
    <div className={"app" + (N ? " sb-slim" : "")}>
      <div className="top9">
        <CPa me={v} />
        <button className="btn sec sm refresh9" title="Обновить страницу системы" onClick={() => window.location.reload()}>
          ⟳<span className="rf-t"> Обновить</span>
        </button>
      </div>
      <div className="topbar">
        <button className="tb-burger" onClick={() => M(!0)} aria-label="Меню">
          ☰
        </button>
        <img
          src="/logo-side.png"
          alt="ФЕНИКС"
          style={{
            height: 20,
          }}
        />
        <span className="tb-t">{(D = Ds[$]) == null ? void 0 : D.t}</span>
      </div>
      {d && <div className="sb-ovl" onClick={() => M(!1)} />}
      <div className={"side" + (d ? " mob-open" : "")}>
        <div className="brand">
          <div className="brand-row">
            <img src="/logo-side.png" alt="ФЕНИКС" />
            <button className="sb-close" aria-label="Закрыть меню" onClick={() => M(!1)}>
              ✕
            </button>
            <button className="sb-toggle" title={N ? "Развернуть меню" : "Свернуть меню"} onClick={() => b(!N)}>
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <polyline points="15 18 9 12 15 6" />
              </svg>
            </button>
          </div>
          <small>
            Терминал
            <br />
            Управленческий учёт
          </small>
        </div>
        <div className="sb-nav">
          {U.map(([E, a, f]) =>
            a ? (
              <div className="side-section">
                <span className="side-label">
                  <button
                    className="side-label-btn"
                    onClick={() =>
                      g((P) => ({
                        ...P,
                        [E]: P[E] === !1,
                      }))
                    }
                  >
                    <span>{a}</span>
                    <i className="g-car">{j[E] === !1 ? "▸" : "▾"}</i>
                  </button>
                </span>
                {j[E] !== !1 && f.map(Z)}
              </div>
            ) : (
              <div className="side-section">{f.map(Z)}</div>
            ),
          )}
        </div>
        <div className="sb-user">
          <div className="sb-u-info">
            <b>{s.display_name}</b>
            <span className="sb-u-role">
              <i className="role-dot" />
              {wt[s.role].label}
            </span>
          </div>
          <div
            className="row"
            style={{
              gap: 5,
            }}
          >
            <button className="btn sec sm icon" title="Светлый / тёмный режим" onClick={() => x(o === "dark" ? "light" : "dark")}>
              {o === "dark" ? "☀" : "●"}
            </button>
            <button className="btn sec sm icon" title="Сменить свой пароль" onClick={() => _(!0)}>
              <Sn n="key" />
            </button>
            <button
              className="btn sec sm"
              onClick={() => {
                (hn(), A.auth.signOut());
              }}
            >
              Выйти
            </button>
          </div>
        </div>
      </div>
      <div className="main">
        <_l.Provider value={h}>
          <CM_ me={v} />
        </_l.Provider>
      </div>
      {z && <Na me={v} onClose={() => _(!1)} />}
      <CYa S={h} />
      <CIa me={v} />
    </div>
  );
}
tl(document.getElementById("root")).render(<Sa />);
