feat(lieferung/neu): PDF upload with SSE streaming and result dialog

- Add PDF-Upload button to ManifestHeader (delivery forms only)
- New ManifestPdfDialog: live SSE event log, structured basedata,
  and line-items table streamed from POST /api/delivery/parsePDF
- ApiClient.delivery.parsePdfSse: multipart/form-data upload,
  async generator yielding typed SSE events (status, llm_call,
  tool_call, usage, progress, result, error)
- ManifestForm.handlePdfUpload: drives SSE generator, updates
  dialog state in real-time; dialog opens immediately on upload
- Fix MUI icon imports (CheckCircle, ErrorOutlined)
This commit is contained in:
seb
2026-09-15 08:50:16 +02:00
parent 4df5110253
commit dbf978d015
9 changed files with 2064 additions and 33 deletions

View File

@@ -81,7 +81,7 @@ async function http(path, { method = 'GET', body } = {}) {
return json;
}
async function httpBinary(path, { method = 'POST', body, contentType } = {}) {
async function httpBinary(path, { method = 'POST', body, contentType, headers: extraHeaders } = {}) {
const url = new URL(path, window.location.origin).href;
logApi('request', {
@@ -96,7 +96,7 @@ async function httpBinary(path, { method = 'POST', body, contentType } = {}) {
const res = await fetch(path, {
method,
headers: { 'Content-Type': contentType },
headers: { 'Content-Type': contentType, ...(extraHeaders || {}) },
credentials: 'include',
body,
});
@@ -603,6 +603,19 @@ export const delivery = {
delete(id) {
return http(`/api/delivery/${id}`, { method: 'DELETE' });
},
/**
* POST /api/delivery/parse-pdf
* Body: raw PDF bytes (Content-Type: application/pdf)
*/
parsePdf(file) {
return httpBinary('/api/delivery/parse-pdf', {
method: 'POST',
contentType: 'application/pdf',
body: file,
headers: file?.name ? { 'X-Filename': encodeURIComponent(file.name) } : undefined,
});
},
};
/**