Initial commit with Email Import Wizard and Task Processor updates

This commit is contained in:
2026-05-04 08:02:11 +02:00
commit effdc5d59f
170 changed files with 67739 additions and 0 deletions
@@ -0,0 +1,168 @@
import { useEffect, useState } from 'react';
import { Table, Button, Space, Tag, Tooltip, Popconfirm, message, ConfigProvider } from 'antd';
import { ReloadOutlined, DeleteOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import { tasksApi } from '../api/tasks';
import type { Task } from '../api/tasks';
function statusTag(fertig: number | null) {
if (fertig === 1) return <Tag color="success">Fertig</Tag>;
if (fertig === 0) return <Tag color="warning">Ausstehend</Tag>;
return <Tag color="default">Neu</Tag>;
}
export default function TaskLogPage() {
const [data, setData] = useState<Task[]>([]);
const [loading, setLoading] = useState(false);
const [deleting, setDeleting] = useState(false);
const fetchData = async () => {
setLoading(true);
try {
const tasks = await tasksApi.getAll();
setData(tasks || []);
} catch {
message.error('Task-Log konnte nicht geladen werden.');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchData();
const interval = setInterval(fetchData, 30000);
return () => clearInterval(interval);
}, []);
const handleDeleteFertige = async () => {
setDeleting(true);
try {
const result = await tasksApi.deleteFertige();
message.success(`${result.deleted} erledigte Task(s) gelöscht.`);
await fetchData();
} catch {
message.error('Fehler beim Löschen der erledigten Tasks.');
} finally {
setDeleting(false);
}
};
const handleDeleteOne = async (taskId: string) => {
try {
await tasksApi.deleteOne(taskId);
message.success('Task gelöscht.');
await fetchData();
} catch {
message.error('Task konnte nicht gelöscht werden.');
}
};
const columns = [
{
title: 'Task-ID',
dataIndex: 'TaskId',
key: 'TaskId',
width: 100,
render: (id: string) => (
<Tooltip title={id}>
<span style={{ fontFamily: 'monospace', fontSize: 12 }}>{id.slice(0, 8)}</span>
</Tooltip>
),
},
{
title: 'Interne Belegnr.',
dataIndex: 'InterneBelegnummer',
key: 'InterneBelegnummer',
},
{
title: 'Lieferant',
dataIndex: 'Lieferant',
key: 'Lieferant',
render: (v: string | null) => v || '-',
},
{
title: 'Belegdatum',
dataIndex: 'Belegdatum',
key: 'Belegdatum',
render: (v: string | null) => (v ? dayjs(v).format('DD.MM.YYYY') : '-'),
},
{
title: 'Eingangsdatum',
dataIndex: 'Eingangsdatum',
key: 'Eingangsdatum',
render: (v: string | null) => (v ? dayjs(v).format('DD.MM.YYYY') : '-'),
},
{
title: 'Paperless-Dok.-ID',
dataIndex: 'PaperlessDocumentID',
key: 'PaperlessDocumentID',
render: (v: number | null) => v ?? '-',
},
{
title: 'Status',
dataIndex: 'Fertig',
key: 'Fertig',
render: (v: number | null) => statusTag(v),
filters: [
{ text: 'Fertig', value: 1 },
{ text: 'Ausstehend', value: 0 },
{ text: 'Neu', value: null as any },
],
onFilter: (value: any, record: Task) => record.Fertig === value,
},
{
title: '',
key: 'actions',
width: 60,
render: (_: any, record: Task) => (
<Popconfirm
title="Task löschen"
description={`Task ${record.TaskId.slice(0, 8)}… dauerhaft entfernen?`}
onConfirm={() => handleDeleteOne(record.TaskId)}
okText="Löschen"
cancelText="Abbrechen"
okButtonProps={{ danger: true }}
>
<Button danger size="small" icon={<DeleteOutlined />} />
</Popconfirm>
),
},
];
return (
<ConfigProvider>
<div>
<div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center', marginBottom: 16 }}>
<Space>
<Tooltip title="Manuell aktualisieren">
<Button icon={<ReloadOutlined />} onClick={fetchData} loading={loading} />
</Tooltip>
<Popconfirm
title="Erledigte Tasks löschen"
description="Alle Tasks mit Status 'Fertig' werden dauerhaft aus der Datenbank entfernt."
onConfirm={handleDeleteFertige}
okText="Löschen"
cancelText="Abbrechen"
okButtonProps={{ danger: true }}
>
<Button
danger
icon={<DeleteOutlined />}
loading={deleting}
>
Erledigte löschen
</Button>
</Popconfirm>
</Space>
</div>
<Table
columns={columns}
dataSource={data}
rowKey="TaskId"
loading={loading}
pagination={{ pageSize: 20 }}
/>
</div>
</ConfigProvider>
);
}