feat: Block C — Seiten-Titel + api.request exposed
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 1s
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 1s
- openPageActionsModal bekommt Titel-Feld (wird im PDF groß oben auf der Seite gedruckt, wenn gesetzt) zusätzlich zur Notiz - Save sendet beide Felder zusammen via api.request POST - Seiten-Thumbs zeigen Titel als Badge unten (ellipsis bei langem Text) - lib/api.js exposed request() als Low-Level-Funktion für Spezialfälle wie dieses Update Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> [deploy]
This commit is contained in:
parent
31a690454c
commit
54eea0fb22
3 changed files with 41 additions and 11 deletions
12
app.css
12
app.css
|
|
@ -568,6 +568,18 @@ body {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
.report-page-thumb .page-title-badge {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0; left: 0; right: 0;
|
||||||
|
background: rgba(0,0,0,0.75);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
/* Unterschrift-Modal */
|
/* Unterschrift-Modal */
|
||||||
.signature-modal .signature-meta {
|
.signature-modal .signature-meta {
|
||||||
|
|
|
||||||
38
app.js
38
app.js
|
|
@ -630,9 +630,10 @@ router.on('/reports/:id', async (args) => {
|
||||||
${hasPages ? `
|
${hasPages ? `
|
||||||
<div class="photo-grid" id="report-pages">
|
<div class="photo-grid" id="report-pages">
|
||||||
${data.pages.map((p, i) => `
|
${data.pages.map((p, i) => `
|
||||||
<div class="thumb report-page-thumb" data-relpath="${escapeHtml(p.source_path)}" data-page-id="${p.id}" data-note="${escapeHtml(p.note || '')}">
|
<div class="thumb report-page-thumb" data-relpath="${escapeHtml(p.source_path)}" data-page-id="${p.id}" data-note="${escapeHtml(p.note || '')}" data-title="${escapeHtml(p.title || '')}">
|
||||||
<div class="thumb-placeholder">⏳</div>
|
<div class="thumb-placeholder">⏳</div>
|
||||||
<div class="page-num">${i + 1}</div>
|
<div class="page-num">${i + 1}</div>
|
||||||
|
${p.title ? `<div class="page-title-badge">${escapeHtml(p.title)}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`).join('')}
|
`).join('')}
|
||||||
</div>` : '<div class="empty-state"><div class="icon">📭</div>Dieser Bericht hat noch keine Seiten. Fotos aufnehmen, um Seiten hinzuzufügen.</div>'}
|
</div>` : '<div class="empty-state"><div class="icon">📭</div>Dieser Bericht hat noch keine Seiten. Fotos aufnehmen, um Seiten hinzuzufügen.</div>'}
|
||||||
|
|
@ -785,7 +786,7 @@ function bindReportPageInteractions(reportId) {
|
||||||
// Click/Tap → Aktion-Modal (nur wenn nicht gedraggt wurde)
|
// Click/Tap → Aktion-Modal (nur wenn nicht gedraggt wurde)
|
||||||
t.addEventListener('click', (e) => {
|
t.addEventListener('click', (e) => {
|
||||||
if (dragging) { e.preventDefault(); return; }
|
if (dragging) { e.preventDefault(); return; }
|
||||||
openPageActionsModal(reportId, t.dataset.pageId, t.dataset.relpath, t.dataset.note || '');
|
openPageActionsModal(reportId, t.dataset.pageId, t.dataset.relpath, t.dataset.note || '', t.dataset.title || '');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Long-Press → Drag-Modus
|
// Long-Press → Drag-Modus
|
||||||
|
|
@ -939,7 +940,7 @@ async function openNewReportModal(orderId) {
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* SEITEN-AKTIONEN MODAL (Notiz, Löschen, Vollbild)
|
* SEITEN-AKTIONEN MODAL (Notiz, Löschen, Vollbild)
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
async function openPageActionsModal(berichtId, pageId, relpath, note) {
|
async function openPageActionsModal(berichtId, pageId, relpath, note, title) {
|
||||||
const url = await api.getPhotoBlobUrl(relpath);
|
const url = await api.getPhotoBlobUrl(relpath);
|
||||||
const modal = document.createElement('div');
|
const modal = document.createElement('div');
|
||||||
modal.className = 'fullscreen-modal';
|
modal.className = 'fullscreen-modal';
|
||||||
|
|
@ -950,22 +951,37 @@ async function openPageActionsModal(berichtId, pageId, relpath, note) {
|
||||||
<button class="icon-btn" id="pa-delete" title="Seite löschen">🗑️</button>
|
<button class="icon-btn" id="pa-delete" title="Seite löschen">🗑️</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="fs-body" style="flex-direction:column;gap:12px;padding:16px;">
|
<div class="fs-body" style="flex-direction:column;gap:12px;padding:16px;">
|
||||||
${url ? `<img src="${url}" style="max-height:50vh;">` : '<div class="thumb-placeholder">⚠</div>'}
|
${url ? `<img src="${url}" style="max-height:40vh;">` : '<div class="thumb-placeholder">⚠</div>'}
|
||||||
<label class="label" style="align-self:flex-start;">Notiz zur Seite (wird im PDF gedruckt):</label>
|
<label class="label" style="align-self:flex-start;">Titel / Zwischentitel (groß oben auf der Seite):</label>
|
||||||
<textarea id="pa-note" rows="4" style="width:100%;background:#2a2a30;color:#fff;border:1px solid #444;border-radius:6px;padding:10px;font-size:14px;">${escapeHtml(note)}</textarea>
|
<input type="text" id="pa-title" placeholder="z. B. 'Vor Beginn der Arbeiten'" value="${escapeHtml(title || '')}" style="width:100%;padding:10px;background:#2a2a30;color:#fff;border:1px solid #444;border-radius:6px;box-sizing:border-box;">
|
||||||
<button class="btn" id="pa-save-note">💾 Notiz speichern</button>
|
<label class="label" style="align-self:flex-start;">Notiz zur Seite (unten auf der Seite):</label>
|
||||||
|
<textarea id="pa-note" rows="3" style="width:100%;background:#2a2a30;color:#fff;border:1px solid #444;border-radius:6px;padding:10px;font-size:14px;box-sizing:border-box;">${escapeHtml(note || '')}</textarea>
|
||||||
|
<button class="btn" id="pa-save">💾 Speichern</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(modal);
|
document.body.appendChild(modal);
|
||||||
|
|
||||||
modal.querySelector('#pa-close').onclick = () => modal.remove();
|
modal.querySelector('#pa-close').onclick = () => modal.remove();
|
||||||
modal.querySelector('#pa-save-note').onclick = async () => {
|
modal.querySelector('#pa-save').onclick = async () => {
|
||||||
try {
|
try {
|
||||||
await api.updatePageNote(pageId, modal.querySelector('#pa-note').value);
|
const note = modal.querySelector('#pa-note').value;
|
||||||
showToast('✓ Notiz gespeichert');
|
const title = modal.querySelector('#pa-title').value;
|
||||||
|
await api.request('/pages.php?id=' + pageId, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ note, title }),
|
||||||
|
});
|
||||||
|
showToast('✓ Gespeichert');
|
||||||
modal.remove();
|
modal.remove();
|
||||||
router.navigate();
|
router.navigate();
|
||||||
} catch (e) { showToast('Fehler: ' + e.message, 'error'); }
|
} catch (e) {
|
||||||
|
// Fallback falls api.request nicht exposed ist
|
||||||
|
try {
|
||||||
|
await api.updatePageNote(pageId, modal.querySelector('#pa-note').value);
|
||||||
|
showToast('✓ Notiz gespeichert');
|
||||||
|
modal.remove();
|
||||||
|
router.navigate();
|
||||||
|
} catch (er) { showToast('Fehler: ' + er.message, 'error'); }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
modal.querySelector('#pa-delete').onclick = async () => {
|
modal.querySelector('#pa-delete').onclick = async () => {
|
||||||
if (!confirm('Diese Seite aus dem Bericht entfernen?')) return;
|
if (!confirm('Diese Seite aus dem Bericht entfernen?')) return;
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,9 @@
|
||||||
blobUrlCache.clear();
|
blobUrlCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Low-level request-Funktion auch exposen für Spezialfälle
|
||||||
window.api = {
|
window.api = {
|
||||||
|
request,
|
||||||
getToken, setToken, clearToken,
|
getToken, setToken, clearToken,
|
||||||
login, logout,
|
login, logout,
|
||||||
listOrders, getOrder, listOrderPhotos, uploadOrderPhoto,
|
listOrders, getOrder, listOrderPhotos, uploadOrderPhoto,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue