Import per CSV ist möglich

This commit is contained in:
2025-06-13 14:37:59 +02:00
parent 9a65c7f78b
commit 63ded6da57
6 changed files with 128 additions and 104 deletions
@@ -1,96 +0,0 @@
<script>
import Papa from '../../../papaparse.min'
import { paginate, PaginationNav } from 'svelte-paginate'
export let activeRecordList = []
let imported_data = []
export let currentPage = 1
let pageSize = 15
$: paginatedItems = paginate({ items: imported_data, pageSize, currentPage })
let files = null
const VerarbeiteDateien = () => {
for (const file of files) {
VerarbeiteCsv(file)
}
}
const VerarbeiteCsv = file => {
Papa.parse(file, {
header: true,
skipEmptyLines: true,
complete: results => {
let cash_work_days = {}
results.data.forEach(item => {
// noinspection JSNonASCIINames
let activity = item['Aktivität']
if (activity.trim() === 'Mittagspause') {
return
}
let work_from = new Date(item['Von'])
let work_to = new Date(item['Bis'])
let actual_day = work_from.toISOString().substring(0, 10)
let actual_work_hours = (work_to - work_from) / (1000 * 60 * 60)
cash_work_days[actual_day] ??= 0
cash_work_days[actual_day] += actual_work_hours
})
for (let day in cash_work_days) {
let hours = cash_work_days[day]
let hours_digits = Math.trunc(hours)
let minutes_digits = Math.round((hours - hours_digits) * 60)
let working_time = String(hours_digits).padStart(2, '0') + ':'
+ String(minutes_digits).padStart(2, '0') + ':00'
activeRecordList.push({ workingTime: working_time, workingDay: day })
}
imported_data = activeRecordList
},
})
}
</script>
<fieldset>
<legend>Download-Liste</legend>
<div class="zelle">
<label for="csv-file">Download der Zeiten von <i>aTimeLogger2</i></label>
<input type="file" accept="text/csv" id="csv-file" bind:files/>
<button type="button" on:click={VerarbeiteDateien}>Upload</button>
</div>
</fieldset>
<fieldset name="record-data-for-import">
<div>
{#if imported_data.length < 1}
<p>Loading...</p>
{:else}
<table>
<tbody>
{#each imported_data as item}
<tr>
<td>
{item.workingDay}
</td>
<td>
{item.workingTime}
</td>
</tr>
{/each}
</tbody>
<tfoot>
<tr>
<td colspan="4">
<PaginationNav
totalItems="{imported_data.length}"
pageSize="{pageSize}"
currentPage="{currentPage}"
limit="{1}"
showStepOptions="{true}"
on:setPage="{(e) => currentPage = e.detail.page}"
/>
</td>
</tr>
</tfoot>
</table>
{/if}
</div>
</fieldset>
@@ -60,5 +60,16 @@ export const actions = {
}
actualDayObject.setDate(actualDayObject.getDate() + 1)
})
},
'import-csv': async ({ request }) => {
const form_data = await request.formData();
for (const pair of form_data.entries()) {
const working_day = pair[0]
const body_data = {
workingDay: working_day,
workingTime: pair[1],
}
await WorkingHoursRepository.addOrUpdate(env.API_URL, working_day, body_data);
}
}
};
+3
View File
@@ -36,6 +36,9 @@
<button formaction="/working-hours/create-by-week" type="submit">per Woche
<IconifyIcon icon={documentIcon}/>
</button>
<button formaction="/working-hours/import-csv" type="submit">Import per CSV
<IconifyIcon icon={documentIcon}/>
</button>
</fieldset>
{#if records === null}
<p>Loading...</p>
@@ -0,0 +1,112 @@
<script>
import IconifyIcon from '@iconify/svelte'
import checkIcon from "@iconify-icons/oi/check";
import xIcon from "@iconify-icons/oi/x";
import {goto} from "$app/navigation";
// @ts-ignore
import Papa from 'papaparse';
const TITLE = "Erstellung neuer Einträge für eine Woche"
/** @type {{ workingTime: String, workingDay: String, }[]} **/
let imported_data = $state([])
let files = $state(null)
const VerarbeiteDateien = () => {
for (const file of files ?? []) {
VerarbeiteCsv(file)
}
}
/** @param {File} file **/
const VerarbeiteCsv = file => {
Papa.parse(file, {
header: true,
skipEmptyLines: true,
// @ts-ignore
complete: results => {
/** @type {Object<String, Number>} **/
let cash_work_days = {}
results.data.forEach(
/** @param {Object<String, any>} item **/
item => {
// noinspection JSNonASCIINames
let activity = item['Aktivität']
if (activity.trim() === 'Mittagspause') {
return
}
let work_from = new Date(item['Von'])
let work_to = new Date(item['Bis'])
let actual_day = work_from.toISOString().substring(0, 10)
let actual_work_hours = (work_to.getTime() - work_from.getTime()) / (1000 * 60 * 60)
cash_work_days[actual_day] ??= 0
cash_work_days[actual_day] += actual_work_hours
}
)
for (let day in cash_work_days) {
let hours = cash_work_days[day]
let hours_digits = Math.trunc(hours)
let minutes_digits = Math.round((hours - hours_digits) * 60)
let working_time = String(hours_digits).padStart(2, '0') + ':'
+ String(minutes_digits).padStart(2, '0') + ':00'
imported_data.push({workingTime: working_time, workingDay: day})
}
},
})
}
</script>
<svelte:head>
<title>{TITLE}</title>
</svelte:head>
<section id="edit-record">
<header>
<h1>{TITLE}</h1>
</header>
<article>
<form action="/working-hours?/import-csv" name="newRecord" method="POST">
{#if imported_data.length < 1}
<fieldset>
<legend>Download-Liste</legend>
<div class="zelle">
<label for="csv-file">Download der Zeiten von <i>aTimeLogger2</i></label>
<input type="file" accept="text/csv" id="csv-file" bind:files/>
<button type="button" onclick={VerarbeiteDateien}>Upload</button>
</div>
</fieldset>
{:else}
<fieldset name="record-data-for-import">
<div>
<table>
<tbody>
{#each imported_data as item}
<tr>
<td>
{item.workingDay}
</td>
<td>
<input type="time" readonly name="{item.workingDay}" value="{item.workingTime}">
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</fieldset>
<fieldset name="buttons">
<button type="submit">Übernehmen und Weiter
<IconifyIcon icon={checkIcon} color="green"/>
</button>
<button type="button" class="sub-button" onclick={() => goto('/working-hours')}>Abbrechen
<IconifyIcon icon={xIcon}/>
</button>
</fieldset>
{/if}
</form>
</article>
</section>