Рендеринг HTML-кода в ScreenCloud с помощью JavaScriptJavascript

Форум по Javascript
Ответить
Anonymous
 Рендеринг HTML-кода в ScreenCloud с помощью JavaScript

Сообщение Anonymous »

Я пытаюсь отобразить панель управления в HTML-коде на экране ScreenCloud. ScreenCloud — это медиаплеер. Вы загружаете любые медиафайлы со своего ПК в веб-приложение ScreenCloud, применяете их к экрану, и медиа-окно отображается через HDMI на соответствующем экране.
У меня есть некоторые данные, которые выводятся из одной из наших баз данных Microsoft Access, когда кто-то нажимает определенную кнопку в базе данных. Данные будут выведены в документ Word (попробовал файл CSV, но это испортило данные, файл .xlsx был единственным способом получить единообразные данные).
Итак, у меня есть поток Power Automate, который проверяет наличие таблицы, если в документе нет таблицы, он создает ее, если таблица есть, поток завершается на этом. Существует 7 потоков Power Automate, которые следуют за потоками, которые организуют данные из таблицы Excel, поэтому выводятся только необходимые данные, они имеют формат JSON, и каждый поток обрабатывает данные, специфичные для часа, с 1 по 7 час. Затем 7 потоков выводят данные JSON в ScreenCloud, где данные находятся в окне «Данные приложения».
У меня есть код HTML и код JavaScript, HTML на этом этапе: просто стили, я возился, пытаясь внедрить стили и перехватчики данных в HTML, прежде чем я провел дополнительные исследования и понял, что лучше всего использовать стили в HTML и использовать JavaScript, чтобы получить все, что мне нужно, с точки зрения данных.
Проблема, с которой я столкнулся, заключается в том, что панель мониторинга, которая должна быть создана, не возвращает таблицы или диаграммы, она предназначена для отображения сводной таблицы, целевого и фактического выходного графика и комментариев стол. Я не знаю, почему данные приложения не попадают в код JavaScript или HTML и, следовательно, не отображают таблицы или диаграммы.
Это JavaScript:

Код: Выделить всё

(function () {
// ---------- Helpers ----------
const log = (...a) => console.log('[Hourly Report]', ...a);

const toNum = (v) => {
if (v == null) return 0;
const s = String(v).replace(/,/g, '').trim();
const n = parseFloat(s);
return Number.isFinite(n) ? n : 0;
};

const decodeHTML = (s) => {
if (s == null) return '';
try { return new DOMParser().parseFromString(String(s), 'text/html').body.textContent || ''; }
catch { const ta = document.createElement('textarea'); ta.innerHTML = String(s); return ta.value; }
};
const escapeHTML = (s) =>
String(s ?? '').replace(/[&"']/g, (ch) =>
({'&':'&','':'>','"':'"',"'":'''}[ch]));
const safeHTML = (s) => escapeHTML(decodeHTML(s));

function domReady() {
return new Promise((r) =>
document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', r, { once: true })
: r()
);
}

// ---------- Robust Application Data extraction ----------
function extractArray(any) {
const seen = new Set();
function tryParseStringToArray(str) {
if (typeof str !== 'string') return null;
try {
const parsed = JSON.parse(str);
if (Array.isArray(parsed)) return parsed;
} catch {}
const m = str.match(/\[[\s\S]*\]/);
if (m) {
try { const parsed = JSON.parse(m[0]); if (Array.isArray(parsed)) return parsed; } catch {}
}
return null;
}
function walk(node) {
if (!node || seen.has(node)) return null;
if (Array.isArray(node)) return node;
if (typeof node === 'string') return tryParseStringToArray(node);
if (typeof node === 'object') {
seen.add(node);
const keysToTry = ['applicationData', 'appData', 'payload', 'data', 'rows', 'items', 'params'];
for (const k of keysToTry) {
if (k in node) {
const arr = walk(node[k]);
if (arr) return arr;
}
}
for (const k in node) {
const arr = walk(node[k]);
if (arr) return arr;
}
}
return null;
}
const found = walk(any);
return Array.isArray(found) ? found : [];
}

// ---------- Your compact single-key parser ----------
function parseCompactObject(obj) {
const keys = Object.keys(obj || {});
if (keys.length !== 1) return null;
const lines = keys[0].split(/\r?\n/);
const out = {};
for (const line of lines) {
const parts = line.split(/\s*(?:→|->)\s*/);
if (parts.length >= 2) out[parts[0].trim()] = parts.slice(1).join('→').trim();
}
return {
Line: out['Line'] || '',
Bay: out['Bay'] || '',
Product: out['Product'] || '',
Supervisor: out['Supervisor'] || '',
Actual: toNum(out['Actual Output']),
Target: toNum(out['Target']),
Comments: out['Comments'] || ''
};
}

function normalizeRows(raw) {
if (!Array.isArray(raw)) return [];
return raw.map(parseCompactObject).filter(Boolean);
}

// ---------- Tables (use real HTML) ----------
function renderTables(rows) {
const summary = document.getElementById('summary-body');
const comments = document.getElementById('comments-body');

if (summary) {
summary.innerHTML = rows.length
? rows.map((r) =>
`
${safeHTML(r.Line)}
${safeHTML(r.Bay)}
${safeHTML(r.Product)}
${safeHTML(r.Supervisor)}
`
).join('')
: `No summary data`;
}

if (comments) {
comments.innerHTML = rows.length
? rows.map((r) =>
`
${safeHTML(r.Line)}
${safeHTML(r.Bay)}
${safeHTML(r.Product)}
${safeHTML(r.Comments)}
`
).join('')
: `No comments`;
}
}

// ---------- Group rows by Bay for per‑Bay bars ----------
function drawGroupedBarChart(rows) {
const c = document.getElementById('chart1');
if (!c) { log('No #chart1 canvas found'); return; }
const ctx = c.getContext('2d');

// Sync canvas size to CSS box each render
const w = Math.max(300, c.clientWidth || c.width || 1100);
const h = Math.max(200, c.clientHeight || c.height || 300);
if (c.width !== w) c.width = w;
if (c.height !== h) c.height = h;

// Clear
ctx.clearRect(0, 0, c.width, c.height);

// --- Group by Bay ---
// For each Bay, get Target and Actual
const bayMap = new Map();
for (const r of rows) {
const bay = (r.Bay || '').trim() || '(No Bay)';
if (!bayMap.has(bay)) bayMap.set(bay, { target: 0, actual: 0 });
const agg = bayMap.get(bay);
agg.target += (r.Target || 0);
agg.actual += (r.Actual || 0);
}
const labels = Array.from(bayMap.keys());
const targets = labels.map(bay => bayMap.get(bay).target);
const actuals = labels.map(bay => bayMap.get(bay).actual);
const N = labels.length;

if (N === 0) {
ctx.fillStyle = '#666';
ctx.textAlign = 'center';
ctx.font = 'bold 18px Arial';
ctx.fillText('No chart data', c.width / 2, c.height / 2);
return;
}

// Layout
const margin = { left: 80, right: 30, top: 26, bottom: 60 };
const W = c.width, H = c.height;
const chartW = W - margin.left - margin.right;
const chartH = H - margin.top - margin.bottom;
const baseX = margin.left;
const baseY = H - margin.bottom;

// Axes
ctx.strokeStyle = '#193D35';
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(baseX, margin.top);
ctx.lineTo(baseX, baseY);
ctx.lineTo(W - margin.right, baseY);
ctx.stroke();

// Scale
const maxVal = Math.max(...targets, ...actuals, 1);
const scaleY = chartH / maxVal;

// Group/bar geometry
const groupPitch = chartW / N;
const barGapInGroup = Math.max(4, Math.min(12, groupPitch * 0.12));
const barW = Math.max(6, Math.min(40, (groupPitch - barGapInGroup) / 2));
const groupInner = 2 * barW + barGapInGroup;

// Grid lines
const gridLines = 5;
ctx.strokeStyle = '#e5e5e5';
ctx.lineWidth = 1;
ctx.setLineDash([3, 3]);
for (let g = 1; g  12) ctx.fillText(String(targets[i]), gx + barW / 2, baseY - hT - 6);
if (hA > 12) ctx.fillText(String(actuals[i]), gx + barW + barGapInGroup + barW / 2, baseY - hA - 6);

// X label (Bay)
ctx.save();
ctx.translate(baseX + i * groupPitch + groupPitch / 2, baseY + 6);
const rotate = N >  10 ? -Math.PI / 6 : 0;
ctx.rotate(rotate);
ctx.fillStyle = '#111';
ctx.font = '12px Arial';
ctx.fillText(String(labels[i]), 0, 18);
ctx.restore();
}

// Legend
ctx.fillStyle = '#193D35';
ctx.fillRect(W - margin.right - 160, margin.top - 14, 14, 10);
ctx.fillStyle = '#111';
ctx.font = '12px Arial';
ctx.textAlign = 'left';
ctx.fillText('Target', W - margin.right - 140, margin.top - 5);

ctx.fillStyle = '#4CAF50';
ctx.fillRect(W - margin.right - 80, margin.top - 14, 14, 10);
ctx.fillStyle = '#111';
ctx.fillText('Actual', W - margin.right - 60, margin.top - 5);
}

// ---------- ScreenCloud Data Hook ----------
function hookScreenCloud(ingest) {
const sc = window.ScreenCloud || window.SC;

// Dev/runtime API if present
if (sc) {
if (typeof sc.getData === 'function') sc.getData().then(ingest).catch(() => {});
if (typeof sc.onData === 'function') sc.onData(ingest);
if (sc.data) ingest(sc.data);
}

// HTML App message-based payloads
window.addEventListener('message', (e) => {
ingest(e?.data);
});
}

// ---------- Boot ----------
(async function init() {
await domReady();

function handleInbound(raw) {
log('Inbound payload:', raw);

const arr = extractArray(raw);
let rows = normalizeRows(arr);

if (!rows.length) {
rows = [
{
Line: 'Test Line',
Bay: '1.1',
Product: 'Sample Product',
Supervisor: 'John Doe',
Actual: 500,
Target: 1000,
Comments: 'Test comment'
}
];
log('No data received from ScreenCloud.  Using fallback rows:', rows);
}

renderTables(rows);
drawGroupedBarChart(rows);

window.__hourlyReportState = { rows: rows.length, lastUpdate: new Date().toISOString() };
}

const arr = extractArray(raw);
const rows = normalizeRows(arr);
console.log('Extracted array:', arr);
console.log('Normalised rows:', rows);

log('Inbound payload:', raw, JSON.stringify(raw));
``

renderTables(rows);          // real  rendering
drawGroupedBarChart(rows);   // per‑Bay Target vs Actual bars

(function(hookScreenCloud){(handleInbound)}
Это HTML:

Код: Выделить всё




Hourly Efficiency Report Hour 1

html, body {
width: 1613px;
height: 1026px;
margin: 0;
padding: 0;
overflow: hidden;
background: #fff;
color: #111;
font-family: Arial, Helvetica, sans-serif;
}
#hourly-app {
width: 1613px;
height: 1026px;
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
padding: 10px;
gap: 10px;
}
.brand-header {
height: 56px;
background: #193D35;
color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 4px;
padding: 8px 12px;
flex-shrink: 0;
}
.brand-left { display: flex; align-items: center; gap: 10px; }
.title { margin: 0; font-size: 20px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.content { flex: 1; display: flex; flex-direction: column; gap: 10px; }

.summary-box { height: 22%; min-height: 120px; }
.charts-row { height: 45%; min-height: 350px; display: flex; align-items: center; justify-content: center; }
.chart-box { width: 80%; height: 100%; border: 1px solid #e5e5e5; border-radius: 4px; padding: 8px; background: #fafbfc; display: flex; align-items: center; justify-content: center; }
.comments-box { flex: 1; min-height: 120px; }

table { width: 100%; height: 100%; border-collapse: collapse; border: 1px solid #ccc; font-size: 12px; }
thead th { background: #193D35; color: #fff; padding: 4px 6px; text-align: left; }
tbody td { border: 1px solid #E1E1E1; padding: 3px 6px; }
.status { font-size: 12px; color: #666; padding-left: 8px; }

/* Ensure canvas fills its box without external libs */
#chart1 { width: 100% !important; height: 100% !important; display: block; background: #fff; }






Hourly Efficiency Report - Hour 1






LineBayProductSupervisor
Waiting for data…












LineBayProductComments
Waiting for data…






Все данные должны отображаться с помощью кода автоматически, так как при их отображении не будет клавиатуры или мыши для извлечения данных вручную.


Подробнее здесь: https://stackoverflow.com/questions/798 ... javascript
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»