diff --git a/app.js b/app.js
index 307e377..37ac6bc 100644
--- a/app.js
+++ b/app.js
@@ -2,6 +2,10 @@ const SUPABASE_URL = "https://qfjghplxbtogshfjkawx.supabase.co";
const SUPABASE_KEY = "sb_publishable_rIcKdaflOvJ0DLTJDcOrxA_bpTGG2hA";
const supabaseClient = window.supabase.createClient(SUPABASE_URL, SUPABASE_KEY);
+const STORAGE_KEY = "dts-store-v3";
+const USERS_KEY = "users-store-v1";
+const SESSION_KEY = "users-session-v1";
+
const STAR_PRODUCTS = [
["20104425", "PANO SCOTT DURAMAX 58X03X08 BRANCO"],
["20092384", "GUARDANAPO SCALA 22X20 - 3600 UN"],
@@ -26,33 +30,238 @@ const STAR_PRODUCTS = [
["20111061", "TOAX430 2R 120F 3X6 SCALA WARM UP"]
];
+const STATUS_OPTIONS = ["EXPEDIDO", "CARREGANDO", "AG CHEGADA", "NO SHOW", "VEICULO RECUSADO", "SEPARANDO", "EM FATURAMENTO", "PATIO", "DT EXCLUDA", "FOI EMBORA"];
+
+const STATUS_COLORS = {
+ EXPEDIDO: "#2e7d32",
+ CARREGANDO: "#1565c0",
+ "AG CHEGADA": "#f9a825",
+ "NO SHOW": "#6d4c41",
+ "VEICULO RECUSADO": "#c62828",
+ SEPARANDO: "#5e35b1",
+ "EM FATURAMENTO": "#00897b",
+ PATIO: "#ef6c00",
+ "DT EXCLUDA": "#546e7a",
+ "FOI EMBORA": "#37474f"
+};
+
+const STATUS_BASE = {
+ VENDA: { planejado: 59, realizado: 30 },
+ TNF: { planejado: 0, realizado: 8 },
+ MOGI: { planejado: 53, realizado: 37 },
+ "Pré Fat Amazon": { planejado: 0, realizado: 0 },
+ "TRANSFERÊNCIA": { planejado: 26, realizado: 26 },
+ DESCARGA: { planejado: 0, realizado: 0 },
+ DEVOLUÇÃO: { planejado: 0, realizado: 0 },
+ GRADE: { planejado: 69, realizado: 69 }
+};
+
+let store = loadStore();
+let users = loadUsers();
+let currentUser = loadSession();
+
const tabButtons = document.querySelectorAll(".tab-btn");
const panels = document.querySelectorAll(".tab-panel");
const statusEl = document.getElementById("status");
+const statusLocaisEl = document.getElementById("status-locais");
const resumoImportacaoEl = document.getElementById("resumo-importacao");
const listaDtsEl = document.getElementById("lista-dts");
-
-const STORAGE_KEY = "dts-store-v2";
-let dtStore = loadStore();
+const gradeBody = document.getElementById("grade-body");
+const dashboardBody = document.getElementById("dashboard-body");
function loadStore() {
const raw = localStorage.getItem(STORAGE_KEY);
- return raw ? JSON.parse(raw) : {};
+ const parsed = raw ? JSON.parse(raw) : {};
+ return { dts: parsed.dts || {}, grade: parsed.grade || [], dashboard: parsed.dashboard || [] };
}
function saveStore() {
- localStorage.setItem(STORAGE_KEY, JSON.stringify(dtStore));
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(store));
+}
+
+function loadUsers() {
+ const raw = localStorage.getItem(USERS_KEY);
+ const parsed = raw ? JSON.parse(raw) : [];
+ const hasMaster = parsed.some((u) => u.role === "mestre");
+ if (!hasMaster) {
+ parsed.push({ username: "mestre", password: "123456", role: "mestre" });
+ localStorage.setItem(USERS_KEY, JSON.stringify(parsed));
+ }
+ return parsed;
+}
+
+function saveUsers() {
+ localStorage.setItem(USERS_KEY, JSON.stringify(users));
+}
+
+function loadSession() {
+ const raw = localStorage.getItem(SESSION_KEY);
+ return raw ? JSON.parse(raw) : null;
+}
+
+function saveSession(user) {
+ localStorage.setItem(SESSION_KEY, JSON.stringify(user));
+}
+
+function clearSession() {
+ localStorage.removeItem(SESSION_KEY);
+}
+
+function setupAuth() {
+ const authScreen = document.getElementById("auth-screen");
+ const appShell = document.getElementById("app-shell");
+ const loginForm = document.getElementById("login-form");
+ const registerForm = document.getElementById("register-form");
+ const authStatus = document.getElementById("auth-status");
+
+ document.getElementById("show-login").addEventListener("click", () => {
+ loginForm.classList.remove("hidden");
+ registerForm.classList.add("hidden");
+ });
+
+ document.getElementById("show-register").addEventListener("click", () => {
+ registerForm.classList.remove("hidden");
+ loginForm.classList.add("hidden");
+ });
+
+ loginForm.addEventListener("submit", (event) => {
+ event.preventDefault();
+ const username = document.getElementById("login-user").value.trim();
+ const password = document.getElementById("login-pass").value;
+ const found = users.find((u) => u.username === username && u.password === password);
+ if (!found) {
+ authStatus.textContent = "Usuário ou senha inválidos.";
+ return;
+ }
+ currentUser = { username: found.username, role: found.role };
+ saveSession(currentUser);
+ authStatus.textContent = "";
+ authScreen.classList.add("hidden");
+ appShell.classList.remove("hidden");
+ onAuthenticated();
+ });
+
+ registerForm.addEventListener("submit", (event) => {
+ event.preventDefault();
+ const username = document.getElementById("register-user").value.trim();
+ const password = document.getElementById("register-pass").value;
+ if (!username || !password) {
+ authStatus.textContent = "Preencha usuário e senha.";
+ return;
+ }
+ if (users.some((u) => u.username === username)) {
+ authStatus.textContent = "Usuário já existe.";
+ return;
+ }
+ users.push({ username, password, role: "padrao" });
+ saveUsers();
+ authStatus.textContent = "Registro concluído. Agora faça login.";
+ registerForm.reset();
+ loginForm.classList.remove("hidden");
+ registerForm.classList.add("hidden");
+ });
+
+ document.getElementById("logout-btn").addEventListener("click", () => {
+ clearSession();
+ currentUser = null;
+ appShell.classList.add("hidden");
+ authScreen.classList.remove("hidden");
+ });
+
+ if (currentUser) {
+ authScreen.classList.add("hidden");
+ appShell.classList.remove("hidden");
+ onAuthenticated();
+ }
+}
+
+function onAuthenticated() {
+ document.getElementById("current-user").textContent = `Usuário: ${currentUser.username} (${currentUser.role})`;
+ applyRoleVisibility();
+ setupAdminPanel();
+ bindAppEvents();
+ renderResumoImportacao();
+ pesquisarPorFinalDT();
+ renderGrade();
+ renderDashboard();
+ renderStatusPage();
+ renderStarProducts();
}
-tabButtons.forEach((btn) => {
- btn.addEventListener("click", () => {
- const target = btn.dataset.tab;
- tabButtons.forEach((b) => b.classList.remove("active"));
- panels.forEach((p) => p.classList.remove("active"));
- btn.classList.add("active");
- document.getElementById(target).classList.add("active");
+function applyRoleVisibility() {
+ const role = currentUser?.role || "padrao";
+ document.querySelectorAll(".role-protected").forEach((el) => {
+ const allowed = String(el.dataset.roles || "").split(",").map((v) => v.trim());
+ el.classList.toggle("hidden", !allowed.includes(role));
});
-});
+
+ if (document.querySelector(".tab-btn.active.hidden")) {
+ const first = document.querySelector(".tab-btn:not(.hidden)");
+ if (first) first.click();
+ }
+}
+
+function setupAdminPanel() {
+ const panel = document.getElementById("admin-panel");
+ const select = document.getElementById("promote-user");
+ const adminStatus = document.getElementById("admin-status");
+ if (currentUser?.role !== "mestre") {
+ panel.classList.add("hidden");
+ return;
+ }
+
+ panel.classList.remove("hidden");
+ select.innerHTML = "";
+ users.filter((u) => u.role !== "mestre" && u.role !== "analista").forEach((u) => {
+ const opt = document.createElement("option");
+ opt.value = u.username;
+ opt.textContent = u.username;
+ select.appendChild(opt);
+ });
+
+ document.getElementById("promote-btn").onclick = () => {
+ const username = select.value;
+ const found = users.find((u) => u.username === username);
+ if (!found) {
+ adminStatus.textContent = "Nenhum usuário padrão disponível para promoção.";
+ return;
+ }
+ found.role = "analista";
+ saveUsers();
+ adminStatus.textContent = `${username} promovido para analista.`;
+ setupAdminPanel();
+ };
+}
+
+let appEventsBound = false;
+function bindAppEvents() {
+ if (appEventsBound) return;
+ appEventsBound = true;
+
+ tabButtons.forEach((btn) => {
+ btn.addEventListener("click", () => {
+ if (btn.classList.contains("hidden")) return;
+ const target = btn.dataset.tab;
+ tabButtons.forEach((b) => b.classList.remove("active"));
+ panels.forEach((p) => p.classList.remove("active"));
+ btn.classList.add("active");
+ document.getElementById(target).classList.add("active");
+ });
+ });
+
+ document.getElementById("importar-sap").addEventListener("click", () => importarMateriais().catch((e) => (statusEl.textContent = `Erro: ${e.message}`)));
+ document.getElementById("importar-locais").addEventListener("click", () => importarLocais().catch((e) => (statusLocaisEl.textContent = `Erro: ${e.message}`)));
+ document.getElementById("pesquisar-dt").addEventListener("click", pesquisarPorFinalDT);
+ document.getElementById("carregar-dt").addEventListener("click", () => {
+ const dt = listaDtsEl.value;
+ if (!dt || !store.dts[dt]) {
+ alert("Selecione uma DT válida.");
+ return;
+ }
+ fillSheet(store.dts[dt]);
+ });
+ document.getElementById("imprimir").addEventListener("click", () => window.print());
+}
function formatDateFromSAP(value) {
const clean = String(value || "").trim();
@@ -63,21 +272,33 @@ function formatDateFromSAP(value) {
return clean;
}
-async function buscarPadraoPorSku(sku) {
- const { data, error } = await supabaseClient
- .from("produtos")
- .select("sku, fardos_por_palete")
- .eq("sku", sku)
- .limit(1);
+function parseSheetFromFile(file) {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ try {
+ const data = new Uint8Array(event.target.result);
+ const wb = XLSX.read(data, { type: "array" });
+ const ws = wb.Sheets[wb.SheetNames[0]];
+ const rows = XLSX.utils.sheet_to_json(ws, { header: 1, raw: false });
+ resolve(rows);
+ } catch (error) {
+ reject(error);
+ }
+ };
+ reader.onerror = reject;
+ reader.readAsArrayBuffer(file);
+ });
+}
+async function buscarPadraoPorSku(sku) {
+ const { data, error } = await supabaseClient.from("produtos").select("sku, fardos_por_palete").eq("sku", sku).limit(1);
if (error || !data?.length) return null;
return Number(data[0].fardos_por_palete || 0);
}
-async function parseSapLineToItem(line) {
- const cols = line.split("\t").map((v) => v.trim());
+async function parseSapColsToItem(cols) {
if (cols.length < 14) return null;
-
const material = cols[6];
const qtd = Number(cols[5] || 0);
const padraoSupabase = await buscarPadraoPorSku(material);
@@ -106,22 +327,14 @@ async function parseSapLineToItem(line) {
};
}
-async function importarLinhasSAP() {
- const raw = document.getElementById("sap-linhas").value.trim();
- if (!raw) {
- statusEl.textContent = "Cole uma ou mais linhas do SAP.";
- return;
- }
-
- const lines = raw.split("\n").map((l) => l.trim()).filter(Boolean);
+async function importSAPRows(rows) {
let importadas = 0;
-
- for (const line of lines) {
- const parsed = await parseSapLineToItem(line);
+ for (const row of rows) {
+ const parsed = await parseSapColsToItem(row.map((v) => String(v || "").trim()));
if (!parsed?.numeroTransporte) continue;
- if (!dtStore[parsed.numeroTransporte]) {
- dtStore[parsed.numeroTransporte] = {
+ if (!store.dts[parsed.numeroTransporte]) {
+ store.dts[parsed.numeroTransporte] = {
codCliente: parsed.codCliente,
codTransportadora: parsed.codTransportadora,
numeroTransporte: parsed.numeroTransporte,
@@ -138,21 +351,257 @@ async function importarLinhasSAP() {
};
}
- dtStore[parsed.numeroTransporte].itens.push(parsed.item);
+ store.dts[parsed.numeroTransporte].itens.push(parsed.item);
importadas += 1;
}
+ return importadas;
+}
+
+async function importarMateriais() {
+ const text = document.getElementById("sap-linhas").value.trim();
+ const file = document.getElementById("sap-file").files[0];
+ let rows = [];
+
+ if (text) {
+ rows = text.split("\n").map((line) => line.split("\t").map((v) => v.trim())).filter((c) => c.length >= 14);
+ } else if (file) {
+ const fileRows = await parseSheetFromFile(file);
+ rows = fileRows.filter((r) => r.filter(Boolean).length).map((r) => r.map((v) => String(v || "").trim()));
+ } else {
+ statusEl.textContent = "Cole linhas SAP ou envie uma planilha.";
+ return;
+ }
+ const total = await importSAPRows(rows);
saveStore();
renderResumoImportacao();
- statusEl.textContent = `${importadas} linha(s) importada(s) e agrupada(s) por DT.`;
+ pesquisarPorFinalDT();
+ statusEl.textContent = `${total} linha(s) de materiais importada(s).`;
}
-document.getElementById("importar-sap").addEventListener("click", importarLinhasSAP);
+function parseLocaisByPosition(row) {
+ return {
+ dt: String(row[2] || "").trim(),
+ local: String(row[4] || "").trim(),
+ cidadeDestino: String(row[7] || "").trim(),
+ peso: Number(String(row[9] || "0").replace(",", ".")) || 0,
+ transportadora: String(row[12] || "").trim(),
+ motorista: String(row[14] || "").trim(),
+ placaVeiculo: String(row[16] || "").trim(),
+ placaComp1: String(row[17] || "").trim(),
+ placaComp2: String(row[18] || "").trim(),
+ agenda: String(row[20] || "").trim(),
+ fimAgenda: String(row[22] || "").trim()
+ };
+}
+
+function ensureGradeRow(item) {
+ const idx = store.grade.findIndex((g) => g.dt === item.dt);
+ const base = {
+ dt: item.dt,
+ transportadora: item.transportadora,
+ gradeCarregamento: item.agenda,
+ fimCarregamento: item.fimAgenda,
+ horaChegada: "",
+ status: "AG CHEGADA",
+ tipo: item.local,
+ toneladas: item.peso,
+ agenda: item.agenda,
+ placa: item.placaVeiculo || item.placaComp1 || item.placaComp2,
+ cidadeDestino: item.cidadeDestino,
+ peso: item.peso
+ };
+
+ if (idx === -1) store.grade.push(base);
+ else store.grade[idx] = { ...store.grade[idx], ...base, status: store.grade[idx].status || "AG CHEGADA", horaChegada: store.grade[idx].horaChegada || "" };
+}
+
+async function importarLocais() {
+ const file = document.getElementById("locais-file").files[0];
+ if (!file) {
+ statusLocaisEl.textContent = "Selecione a planilha de shipment.";
+ return;
+ }
+ const rows = await parseSheetFromFile(file);
+ let count = 0;
+ rows.slice(1).forEach((row) => {
+ const item = parseLocaisByPosition(row);
+ if (!item.dt) return;
+ ensureGradeRow(item);
+ count += 1;
+ });
+ saveStore();
+ renderGrade();
+ renderStatusPage();
+ statusLocaisEl.textContent = `${count} registro(s) importado(s) para a grade.`;
+}
+
+function upsertDashboardFromPatio(gradeItem) {
+ const idx = store.dashboard.findIndex((d) => d.dt === gradeItem.dt);
+ const now = new Date();
+ const hora = now.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
+ const data = now.toLocaleDateString("pt-BR");
+
+ if (idx === -1) {
+ store.dashboard.push({
+ dt: gradeItem.dt,
+ hora,
+ data,
+ placa: gradeItem.placa || "",
+ transportadora: gradeItem.transportadora || "",
+ status: gradeItem.status,
+ mapa: gradeItem.cidadeDestino || "",
+ grade: gradeItem.gradeCarregamento || "",
+ tipo: gradeItem.tipo || "",
+ peso: gradeItem.peso || 0
+ });
+ return;
+ }
+
+ store.dashboard[idx] = {
+ ...store.dashboard[idx],
+ dt: gradeItem.dt,
+ placa: gradeItem.placa || store.dashboard[idx].placa,
+ transportadora: gradeItem.transportadora || store.dashboard[idx].transportadora,
+ status: gradeItem.status,
+ mapa: gradeItem.cidadeDestino || store.dashboard[idx].mapa,
+ grade: gradeItem.gradeCarregamento || store.dashboard[idx].grade,
+ tipo: gradeItem.tipo || store.dashboard[idx].tipo,
+ peso: gradeItem.peso || store.dashboard[idx].peso
+ };
+}
+
+function renderGrade() {
+ gradeBody.innerHTML = "";
+ if (!store.grade.length) {
+ gradeBody.innerHTML = '
Nenhuma linha importada. ';
+ return;
+ }
+
+ store.grade.forEach((row, index) => {
+ const tr = document.createElement("tr");
+ tr.innerHTML = `
+ ${row.dt || "-"}
+ ${row.transportadora || "-"}
+ ${row.gradeCarregamento || "-"}
+ ${row.fimCarregamento || "-"}
+
+
+
+ ${STATUS_OPTIONS.map((s) => `${s} `).join("")}
+
+
+ ${row.tipo || "-"}
+ ${Number(row.toneladas || 0).toFixed(2)}
+ ${row.agenda || "-"}
+ `;
+ gradeBody.appendChild(tr);
+ });
+
+ document.querySelectorAll("[data-grade-time]").forEach((el) => {
+ el.addEventListener("change", (e) => {
+ const idx = Number(e.target.dataset.gradeTime);
+ store.grade[idx].horaChegada = e.target.value;
+ saveStore();
+ });
+ });
+
+ document.querySelectorAll("[data-grade-status]").forEach((el) => {
+ el.addEventListener("change", (e) => {
+ const idx = Number(e.target.dataset.gradeStatus);
+ store.grade[idx].status = e.target.value;
+ e.target.style.background = STATUS_COLORS[e.target.value] || "#eceff1";
+ if (e.target.value === "PATIO") upsertDashboardFromPatio(store.grade[idx]);
+ saveStore();
+ renderDashboard();
+ renderStatusPage();
+ });
+ });
+}
+
+function renderDashboard() {
+ dashboardBody.innerHTML = "";
+ if (!store.dashboard.length) {
+ dashboardBody.innerHTML = 'Nenhum veículo em pátio. ';
+ return;
+ }
+
+ store.dashboard.forEach((row, index) => {
+ const tr = document.createElement("tr");
+ tr.innerHTML = `
+ ${row.dt || "-"}
+
+
+ ${row.placa || "-"}
+ ${row.transportadora || "-"}
+ ${row.status}
+ ${row.mapa || "-"}
+ ${row.grade || "-"}
+ ${row.tipo || "-"}
+ ${Number(row.peso || 0).toFixed(2)}
+ `;
+ dashboardBody.appendChild(tr);
+ });
+
+ document.querySelectorAll("[data-dash-hora]").forEach((el) => {
+ el.addEventListener("change", (e) => {
+ store.dashboard[Number(e.target.dataset.dashHora)].hora = e.target.value;
+ saveStore();
+ });
+ });
+
+ document.querySelectorAll("[data-dash-data]").forEach((el) => {
+ el.addEventListener("change", (e) => {
+ store.dashboard[Number(e.target.dataset.dashData)].data = fromIsoDate(e.target.value);
+ saveStore();
+ });
+ });
+}
+
+function toIsoDate(brDate) {
+ const parts = String(brDate || "").split("/");
+ if (parts.length !== 3) return "";
+ return `${parts[2]}-${parts[1].padStart(2, "0")}-${parts[0].padStart(2, "0")}`;
+}
+
+function fromIsoDate(iso) {
+ if (!iso) return "";
+ const [yyyy, mm, dd] = iso.split("-");
+ return `${dd}/${mm}/${yyyy}`;
+}
+
+function renderStatusPage() {
+ const body = document.getElementById("status-body");
+ const charts = document.getElementById("charts");
+ body.innerHTML = "";
+ charts.innerHTML = "";
+
+ const gradeRealizado = store.grade.filter((g) => ["EXPEDIDO", "PATIO", "CARREGANDO"].includes(g.status)).length;
+ const merged = JSON.parse(JSON.stringify(STATUS_BASE));
+ merged.GRADE.realizado = gradeRealizado;
+
+ Object.entries(merged).forEach(([label, values]) => {
+ const pend = Number(values.planejado) - Number(values.realizado);
+ const tr = document.createElement("tr");
+ tr.innerHTML = `${label} ${values.planejado} ${values.realizado} ${pend} `;
+ body.appendChild(tr);
+
+ const max = Math.max(values.planejado, values.realizado, Math.abs(pend), 1);
+ const card = document.createElement("div");
+ card.className = "chart-card";
+ card.innerHTML = `
+ ${label}
+ Planejado
${values.planejado}
+ Realizado
${values.realizado}
+
+ `;
+ charts.appendChild(card);
+ });
+}
function renderResumoImportacao() {
resumoImportacaoEl.innerHTML = "";
- const registros = Object.values(dtStore);
-
+ const registros = Object.values(store.dts);
if (!registros.length) {
resumoImportacaoEl.innerHTML = 'Nenhuma DT importada ainda. ';
return;
@@ -161,22 +610,17 @@ function renderResumoImportacao() {
registros.forEach((dt) => {
const total = (dt.itens || []).reduce((acc, item) => acc + Number(item.qtd || 0), 0);
const tr = document.createElement("tr");
- tr.innerHTML = `
- ${dt.numeroTransporte}
- ${dt.nomeCliente || "-"}
- ${dt.itens?.length || 0}
- ${total}
- `;
+ tr.innerHTML = `${dt.numeroTransporte} ${dt.nomeCliente || "-"} ${dt.itens?.length || 0} ${total} `;
resumoImportacaoEl.appendChild(tr);
});
}
function pesquisarPorFinalDT() {
const term = document.getElementById("busca-dt").value.trim();
- const allDts = Object.keys(dtStore);
+ const allDts = Object.keys(store.dts);
const matches = allDts.filter((dt) => !term || dt.endsWith(term));
-
listaDtsEl.innerHTML = "";
+
if (!matches.length) {
listaDtsEl.innerHTML = 'Nenhuma DT encontrada ';
return;
@@ -185,13 +629,11 @@ function pesquisarPorFinalDT() {
matches.forEach((dt) => {
const option = document.createElement("option");
option.value = dt;
- option.textContent = `${dt} - ${dtStore[dt].nomeCliente || "Sem cliente"}`;
+ option.textContent = `${dt} - ${store.dts[dt].nomeCliente || "Sem cliente"}`;
listaDtsEl.appendChild(option);
});
}
-document.getElementById("pesquisar-dt").addEventListener("click", pesquisarPorFinalDT);
-
function fillSheet(data) {
document.getElementById("sheet-dt").textContent = `DT: ${data.numeroTransporte || "-"}`;
document.getElementById("sheet-cliente").textContent = `Cliente: ${data.nomeCliente || "-"}`;
@@ -220,19 +662,9 @@ function fillSheet(data) {
document.getElementById("sheet-total").textContent = total;
}
-document.getElementById("carregar-dt").addEventListener("click", () => {
- const dt = listaDtsEl.value;
- if (!dt || !dtStore[dt]) {
- alert("Selecione uma DT válida.");
- return;
- }
- fillSheet(dtStore[dt]);
-});
-
-document.getElementById("imprimir").addEventListener("click", () => window.print());
-
function renderStarProducts() {
const body = document.getElementById("produtos-estrela-body");
+ if (body.childNodes.length) return;
STAR_PRODUCTS.forEach(([sku, descricao]) => {
const tr = document.createElement("tr");
tr.innerHTML = `${sku} ${descricao} `;
@@ -240,7 +672,4 @@ function renderStarProducts() {
});
}
-renderResumoImportacao();
-pesquisarPorFinalDT();
-renderStarProducts();
-
\ No newline at end of file
+setupAuth();
diff --git a/index.html b/index.html
index 9a8fce6..4b6a934 100644
--- a/index.html
+++ b/index.html
@@ -7,123 +7,261 @@
-
-
-
- ZLES002
- Relatório
- Produtos Estrela
-
-
-
-
- Importação SAP (múltiplas linhas)
-
-
- Cole as linhas do SAP (uma linha por item/remessa)
-
-
-
Formato esperado por linha (TAB): Cód Cliente, Cód Transportadora, Nº transporte, Inf Agenda, Nome Cliente, Qtde Remessa, Material, Setor, Cliente Pallet, Agrupamento Regional, Qtd Teórica Convertida, Nº NFe, Quantidade Teórica, Data Agendamento.
-
Importar linhas SAP
-
-
+
+
+
Painel Logístico
+
Acesse com seu usuário ou faça um novo registro.
-
-
DTs importadas no navegador
-
-
-
- DT
- Cliente
- Itens
- Total fardos
-
-
-
-
+
+ Login
+ Registro
-
-
- Relatório para Impressão
-
-
Pesquisar DT (digite os 4 últimos números)
-
+
+
+
+
+ Novo registro entra como usuário padrão. Somente mestre pode promover para analista.
+
+
+
+
+
+
+
+
+ ZLES002
+ Grade
+ Dashboard
+ Status
+ MB51
+ Relatório
+ Produtos Estrela
+
+
+
+
+ Detalhes de Materiais
-
-
+
+
Administração de usuários
+
Promover usuário para analista
+
+
+
Promover para analista
+
+
+
+
+ Cole as linhas do SAP (uma linha por item/remessa)
+
+
+
Formato esperado por linha (TAB): Cód Cliente, Cód Transportadora, Nº transporte, Inf Agenda, Nome Cliente, Qtde Remessa, Material, Setor, Cliente Pallet, Agrupamento Regional, Qtd Teórica Convertida, Nº NFe, Quantidade Teórica, Data Agendamento.
+
+ Ou envie uma planilha de materiais (.xlsx/.xls/.csv)
+
+
+
Importar materiais
+
+
+
+
+
Locais (importação de shipment)
+
A leitura da planilha usa o mapeamento solicitado por linha/posição: 3=DT, 5=LOCAL, 8=CIDADE DESTINO, 10=PESO, 13=NOME TRANSPORTADORA, 15=NOME MOTORISTA, 17-19=PLACAS, 21=AGENDA, 23=FIM AGENDA.
+
+ Envie a planilha de shipment
+
+
+
Importar locais
+
+
+
+
+
DTs importadas no navegador
+
+
+
+ DT
+ Cliente
+ Itens
+ Total fardos
+
+
+
+
+
+
+
+
+ Grade
+
+
+
+
+ DT
+ Transportadora
+ Grade Carregamento
+ Fim de Carregamento
+ Hora Chegada
+ Status
+ Tipo
+ Toneladas
+ Agenda
+
+
+
+
+
+
+
+
+ Dashboard (Pátio)
+
+
+
+
+ DT
+ HORA
+ DATA
+ Placa
+ Transportadora
+ Status
+ Mapa
+ Grade
+ Tipo
+ Peso
+
+
+
+
+
+
+
+
+ Status
+
+
Venda TOTAL: 175
+
As fórmulas da lógica de status foram preservadas e os indicadores são atualizados automaticamente.
+
+
+ Status Planejado Realizado Pend
+
+
+
+
+
+
+
+
+ MB51
+
+
Área exclusiva para usuários mestre e analista .
+
Use esta aba para consultas e controles MB51.
+
+
+
+
+ Relatório para Impressão
+
+ Pesquisar DT (digite os 4 últimos números)
+
+
+ Pesquisar
+
+ Carregar DT selecionada
+ Imprimir em paisagem
+
+
+
+
+
+
+
+
+ Nº transporte
+ SKU
+ Qtde
+ Padrão Plt
+ Plt Fechado
+ Fração
+ Conferido
+ Avaria
+
+
+
+
+
+ Total de fardos
+ 0
+
+
+
+
+
+
+ Anotações do Conferente
+
+
+
+ Lacre: _____________________________________________
+
+
+
+
+ Produtos Estrela
- Nº transporte
SKU
- Qtde
- Padrão Plt
- Plt Fechado
- Fração
- Conferido
- Avaria
+ Descrição
-
-
-
- Total de fardos
- 0
-
-
-
+
+
+
+
-
- Anotações do Conferente
-
-
-
-
Lacre: _____________________________________________
-
-
-
-
- Produtos Estrela
-
-
-
- SKU
- Descrição
-
-
-
-
-
-
-
+