Der Weg ueber die TikTok-Datei des Creators ist entfernt
Filipe, mit den drei Knoepfen im Bild: "ich will nur dass wir manager
scouts, dogfather oder spicy sachen eintragen koennen und nicht die
creator. ich will keine daten von denen kriegen, nur wir."
Gebaut am Vormittag, am Nachmittag wieder ausgebaut. Der Weg war
technisch in Ordnung -- und er war der einzige, bei dem ein CREATOR uns
etwas gibt: seine eigene Datenkopie aus der TikTok-App. Genau das soll
nicht sein. Es bleiben die beiden Wir-Wege: die eigene Datei und die
Backstage-Tabelle der Agentur.
VOLLSTAENDIG ENTFERNT, NICHT VERSTECKT:
- beide Schnittstellen (/tiktok-datei und /tiktok-datei/vorschau)
- der Leser workspace-tiktok-datei.js (263 Zeilen)
- Knopf, Fenster, Dateiauswahl, Vorschau, Stilregeln
- der fertige Text, der einen Creator um seine Daten bittet
- der Erklaersatz unter der Knopfreihe
Ein Weg, der nur unsichtbar ist, ist weiterhin ein Weg -- wer die
Adresse kennt, benutzt ihn. Und eine Bitte an einen Creator um seine
Daten soll in diesem Haus nirgends mehr stehen, auch nicht in einem
Fenster, das niemand oeffnet.
GEPRUEFT WIRD JETZT DIE ABWESENHEIT, an drei Stellen: Knopf weg,
Fenster weg, und die Schnittstelle antwortet DOGFATHER mit 404 -- dem
staerksten Zugang, den es gibt. Bekommt er 404, bekommt ihn jeder.
Daneben die Gegenprobe, dass der Backstage-Weg weiterhin mit 200
antwortet; sonst bewiese das 404 nur einen Tippfehler.
pruef-tiktok-datei.mjs (47 Pruefungen) faellt mit dem Weg weg. Die
Zahl sinkt dadurch, und das ist hier richtig: Sie pruefte etwas, das
es nicht mehr gibt. Was bleibt, sind sechs Pruefungen, die das
Fehlen sichern -- pruef-backstage-import 63 -> 66.
NEBENBEI GEDREHT, NICHT GELOESCHT: pruef-leistung-optik behauptete
noch die Regel vom 07.09. ("beim Manager fehlt die Kachel", "die Seite
weist den Creator ab"). Beide Aussagen sind jetzt umgekehrt und messen
zusaetzlich, was vorher niemand gemessen hat: dass die Creatorin auf
der Zahlen-Seite ihre EIGENEN Zahlen sieht und trotzdem keinen
einzigen Knopf zum Eintragen hat -- beides zusammen, denn "keine
Knoepfe" waere auch auf einer leeren Seite wahr. 56 -> 59.
Nicht von mir, nachgemessen gegen den Stand ohne diese Aenderungen:
pruef-struktur meldet dieselben 6 Fehler (crew-index/teamlage nicht
verlinkt, start.css 348 KB, totes CSS .nase, UTC-Datum).
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -317,38 +317,6 @@
|
||||
color: var(--text-still); font-size: .8rem;
|
||||
}
|
||||
|
||||
/* ---- Die Auswahl in der TikTok-Datei (11.09.2026) -------------------
|
||||
Das Format der Datei ist nicht dokumentiert. Der Server schlägt vor,
|
||||
der Mensch entscheidet -- und eine Entscheidung gehört als sichtbare
|
||||
Auswahl auf die Seite, nicht in ein Aufklappfeld, in dem man die
|
||||
erste Zeile für gesetzt hält. */
|
||||
.tt-wahl {
|
||||
display: flex; align-items: flex-start; gap: 10px;
|
||||
margin: 6px 0;
|
||||
padding: 9px 11px;
|
||||
border: 1px solid var(--rand); border-radius: 11px;
|
||||
background: rgba(255, 255, 255, .02);
|
||||
cursor: pointer;
|
||||
}
|
||||
.tt-wahl:hover { border-color: var(--rand-hell); }
|
||||
.tt-wahl:has(input:checked) {
|
||||
border-color: color-mix(in srgb, var(--akzent) 55%, transparent);
|
||||
background: color-mix(in srgb, var(--akzent) 10%, transparent);
|
||||
}
|
||||
.tt-wahl input { margin-top: 3px; flex: none; }
|
||||
.tt-wahl__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
||||
.tt-wahl__text strong {
|
||||
font-family: ui-monospace, "Cascadia Code", "Consolas", monospace;
|
||||
font-size: .82rem; color: var(--text);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.tt-wahl__zahl { font-size: .8rem; color: var(--text-leise); }
|
||||
.tt-wahl__felder {
|
||||
font-size: .76rem; color: var(--text-still);
|
||||
font-family: ui-monospace, "Cascadia Code", "Consolas", monospace;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DIE ANLEITUNGEN (11.09.2026)
|
||||
|
||||
@@ -387,17 +355,4 @@
|
||||
.anleitung li::marker { color: var(--akzent); font-weight: 700; }
|
||||
.anleitung strong { color: var(--text); }
|
||||
|
||||
/* Der fertige Text zum Weiterschicken. Als <pre>, damit die Nummerierung
|
||||
stehen bleibt -- und mit Umbruch, damit er nicht seitlich herausläuft. */
|
||||
.anleitung-text {
|
||||
margin: 4px 0 8px;
|
||||
max-height: 210px; overflow-y: auto;
|
||||
padding: 11px 13px;
|
||||
border: 1px solid var(--rand); border-radius: 11px;
|
||||
background: rgba(0, 0, 0, .28);
|
||||
font-family: inherit; font-size: .81rem; line-height: 1.55;
|
||||
color: var(--text-leise);
|
||||
white-space: pre-wrap; overflow-wrap: anywhere;
|
||||
}
|
||||
.dialog__unter--still { font-size: .8rem; color: var(--text-still); }
|
||||
.dialog__knoepfe--links { justify-content: flex-start; margin: 0 0 10px; }
|
||||
|
||||
+12
-135
@@ -197,24 +197,24 @@
|
||||
hier geht es darum, niemandem einen Knopf hinzustellen, der
|
||||
eine Absage bringt. */
|
||||
['netz-oeffnen', LEITUNG.has(ich?.rolle)],
|
||||
/* Die Datei gehoert EINEM Creator -- deshalb sichtbar fuer alle,
|
||||
die fuer ihn eintragen duerfen, also auch fuer seinen Scout. */
|
||||
['tt-oeffnen', darfEintragen()],
|
||||
];
|
||||
for (const [knopf, darf] of KNOEPFE) $(knopf).hidden = !darf;
|
||||
|
||||
/* Jeder Erklaersatz haengt an SEINEM Knopf, nicht am Block. Ein
|
||||
Scout sieht nur die TikTok-Datei -- ihm die Backstage-Tabelle zu
|
||||
erklaeren, an die er gar nicht kommt, ist keine Hilfe, sondern
|
||||
eine Absage, die er nicht gesucht hat. Und ein Creator sieht
|
||||
keinen von beiden, also auch keinen Satz. Abgeleitet statt
|
||||
zweimal aufgeschrieben: kommt ein dritter Weg dazu, stimmt es
|
||||
weiter. */
|
||||
for (const [satz, knopf] of [['quelle-netz', 'netz-oeffnen'],
|
||||
['quelle-tt', 'tt-oeffnen']]) {
|
||||
Scout, der die Backstage-Tabelle nicht hat, soll sie auch nicht
|
||||
erklaert bekommen -- das waere keine Hilfe, sondern eine Absage,
|
||||
die er nicht gesucht hat. Und ein Creator sieht keinen Knopf,
|
||||
also auch keinen Satz.
|
||||
|
||||
Die Liste hat seit dem 11.09.2026 nur noch einen Eintrag (der
|
||||
Weg ueber die TikTok-Datei des Creators ist entfernt). Sie
|
||||
bleibt trotzdem eine Liste: Der naechste Weg haengt sich dann
|
||||
daneben, statt dass jemand die Regel ein zweites Mal
|
||||
aufschreibt. */
|
||||
for (const [satz, knopf] of [['quelle-netz', 'netz-oeffnen']]) {
|
||||
$(satz).hidden = $(knopf).hidden;
|
||||
}
|
||||
$('quellen-hinweis').hidden = $('quelle-netz').hidden && $('quelle-tt').hidden;
|
||||
$('quellen-hinweis').hidden = $('quelle-netz').hidden;
|
||||
|
||||
if (!z || (!z.diamanten && !z.tage && !z.verweildauer)) {
|
||||
ziel.append(el('p', 'leistung__leer',
|
||||
@@ -582,109 +582,6 @@
|
||||
$('tag-form').addEventListener('submit', tagSpeichern);
|
||||
$('tag-zu').addEventListener('click', () => $('tag-dialog').close());
|
||||
$('tag-loeschen').addEventListener('click', tagLoeschen);
|
||||
/* =====================================================================
|
||||
DIE TIKTOK-DATEI DES CREATORS
|
||||
|
||||
Das Format ist nicht dokumentiert. Deshalb wird hier nichts
|
||||
geraten: Der Server durchsucht die Datei nach Listen mit Datum und
|
||||
schickt sie zur Auswahl zurück -- mit Anzahl, Zeitraum und dem,
|
||||
was dabei herauskäme. Bestätigt wird von Hand.
|
||||
===================================================================== */
|
||||
let ttInhalt = null; /* die gelesene Datei -- bleibt im Browser */
|
||||
let ttWahl = null; /* der bestätigte Kandidat */
|
||||
|
||||
async function ttDateiGewaehlt(ereignis) {
|
||||
const datei = ereignis.target.files?.[0];
|
||||
$('tt-fehler').textContent = '';
|
||||
$('tt-vorschau').hidden = true;
|
||||
$('tt-los').disabled = true;
|
||||
ttInhalt = null; ttWahl = null;
|
||||
if (!datei) return;
|
||||
|
||||
/* Ein Vollarchiv kann zweistellige Megabyte haben. Das Lesen
|
||||
passiert im Browser; auf den Server geht es erst danach -- und
|
||||
nur einmal, nicht bei jedem Klick. */
|
||||
$('tt-fehler').textContent = 'Datei wird gelesen …';
|
||||
let text;
|
||||
try { text = await datei.text(); } catch { $('tt-fehler').textContent = 'Die Datei ließ sich nicht lesen.'; return; }
|
||||
try { ttInhalt = JSON.parse(text); } catch {
|
||||
$('tt-fehler').textContent = 'Das ist keine JSON-Datei. Beim Herunterladen bei TikTok '
|
||||
+ 'muss als Format JSON gewählt werden, nicht TXT.';
|
||||
return;
|
||||
}
|
||||
$('tt-fehler').textContent = 'Datei wird durchsucht …';
|
||||
|
||||
const a = await hole(`/workspace/api/leistung/${offenerCreator}/tiktok-datei/vorschau`, {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ inhalt: ttInhalt }),
|
||||
}).catch(() => null);
|
||||
if (!a) { $('tt-fehler').textContent = 'Die Datei konnte nicht geprüft werden.'; return; }
|
||||
const d = await a.json().catch(() => ({}));
|
||||
if (!a.ok) { $('tt-fehler').textContent = d.fehler || 'Die Datei wurde nicht verstanden.'; return; }
|
||||
$('tt-fehler').textContent = '';
|
||||
|
||||
const v = $('tt-vorschau');
|
||||
v.textContent = ''; v.hidden = false;
|
||||
const zeile = (text2, art) => {
|
||||
const p = el('p', 'import-vorschau__zeile');
|
||||
if (art) p.dataset.art = art;
|
||||
p.textContent = text2;
|
||||
v.append(p);
|
||||
return p;
|
||||
};
|
||||
|
||||
zeile(`${d.kandidaten.length} Liste(n) mit Datum gefunden. Welche ist der LIVE-Verlauf?`);
|
||||
|
||||
/* Die Auswahl als echte Radioknöpfe: Es ist eine Entscheidung, und
|
||||
eine Entscheidung gehört nicht in ein Aufklappfeld, in dem man
|
||||
die erste Zeile für gesetzt hält. */
|
||||
d.kandidaten.forEach((k, i) => {
|
||||
const box = el('label', 'tt-wahl');
|
||||
const r = document.createElement('input');
|
||||
r.type = 'radio'; r.name = 'tt-kandidat'; r.value = String(i);
|
||||
if (i === 0) { r.checked = true; ttWahl = k; }
|
||||
r.addEventListener('change', () => { ttWahl = k; $('tt-los').disabled = false; });
|
||||
const t = el('span', 'tt-wahl__text');
|
||||
t.append(el('strong', null, k.pfad || '(oberste Ebene)'));
|
||||
t.append(el('span', 'tt-wahl__zahl',
|
||||
` ${k.anzahl} Einträge · ${k.tage_gesamt} Tage`
|
||||
+ (k.von ? ` · ${k.von} bis ${k.bis}` : '')));
|
||||
const felder = ['tag', 'dauer', 'diamanten', 'zuschauer']
|
||||
.filter((f) => k.vorschlag[f])
|
||||
.map((f) => `${f}: ${k.vorschlag[f]}`).join(' · ');
|
||||
t.append(el('span', 'tt-wahl__felder', felder || 'nur ein Datum erkannt'));
|
||||
box.append(r, t);
|
||||
v.append(box);
|
||||
});
|
||||
|
||||
if (ttWahl) $('tt-los').disabled = false;
|
||||
}
|
||||
|
||||
async function ttUebernehmen(ereignis) {
|
||||
ereignis.preventDefault();
|
||||
if (!ttInhalt || !ttWahl) return;
|
||||
$('tt-los').disabled = true;
|
||||
const a = await hole(`/workspace/api/leistung/${offenerCreator}/tiktok-datei`, {
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ inhalt: ttInhalt, pfad: ttWahl.pfad, zuordnung: ttWahl.vorschlag }),
|
||||
}).catch(() => null);
|
||||
if (!a) { $('tt-los').disabled = false; return; }
|
||||
const d = await a.json().catch(() => ({}));
|
||||
if (!a.ok) {
|
||||
$('tt-fehler').textContent = d.fehler === 'keine_brauchbaren_tage'
|
||||
? 'In dieser Liste stehen keine Tage mit Zahlen.'
|
||||
: (d.fehler || 'Übernehmen ging nicht.');
|
||||
$('tt-los').disabled = false;
|
||||
return;
|
||||
}
|
||||
/* Die Datei loslassen, sobald sie nicht mehr gebraucht wird. */
|
||||
ttInhalt = null; ttWahl = null;
|
||||
$('tt-dialog').close();
|
||||
melde(`${d.geschrieben} Tage neu, ${d.ergaenzt} ergänzt`);
|
||||
setTimeout(() => melde(''), 6000);
|
||||
await laden();
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DIE BACKSTAGE-TABELLE — Vorschau und Übernahme
|
||||
===================================================================== */
|
||||
@@ -797,26 +694,6 @@
|
||||
$('netz-text').focus();
|
||||
});
|
||||
$('netz-zu').addEventListener('click', () => $('netz-dialog').close());
|
||||
$('tt-oeffnen').addEventListener('click', () => {
|
||||
$('tt-vorschau').hidden = true; $('tt-los').disabled = true;
|
||||
$('tt-fehler').textContent = ''; $('tt-datei').value = '';
|
||||
$('tt-dialog').showModal();
|
||||
});
|
||||
$('tt-zu').addEventListener('click', () => $('tt-dialog').close());
|
||||
$('tt-datei').addEventListener('change', ttDateiGewaehlt);
|
||||
/* Den Text fuer den Creator in die Zwischenablage. Kein
|
||||
Erfolgshaken ohne Beleg: Geht es schief (kein Recht, alter
|
||||
Browser), steht das auch da -- sonst glaubt man, es sei kopiert,
|
||||
und schickt eine leere Nachricht. */
|
||||
$('tt-text-kopieren').addEventListener('click', async (e) => {
|
||||
const knopf = e.currentTarget;
|
||||
try {
|
||||
await navigator.clipboard.writeText($('tt-text').textContent);
|
||||
knopf.textContent = 'Kopiert';
|
||||
} catch { knopf.textContent = 'Ging nicht - bitte von Hand markieren'; }
|
||||
setTimeout(() => { knopf.textContent = 'Text kopieren'; }, 2600);
|
||||
});
|
||||
$('tt-form').addEventListener('submit', ttUebernehmen);
|
||||
/* Beim EINFÜGEN sofort nachsehen -- nicht erst auf einen Knopf warten.
|
||||
Wer eine Tabelle einfügt, will wissen, ob sie erkannt wurde; ein
|
||||
zweiter Klick dazwischen ist nur eine Gelegenheit, es nicht zu tun. */
|
||||
|
||||
Reference in New Issue
Block a user