Call_Log: Notiz als Textarea, Dauer-Timer mit mm:ss und DOM-Direktaktualisierung
Notiz-Feld auf Textarea-Widget umgestellt (mehrzeilige Eingabe). Dauer-Feld bei Neuanlage mit Timer automatisch aktualisiert: verstrichene Sekunden als mm:ss formatiert, direkt im DOM gesetzt (ohne redraw, damit andere Felder nicht überschrieben werden). Timer in onremove gestoppt. Konstante DAUER_UPDATE_INTERVALL steuert die Update-Frequenz (Sekunde/Minute). Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
16eaab8b64
commit
3accb8f690
1 file changed
+57
-3
@@ -1,12 +1,16 @@
|
||||
import m from "mithril"
|
||||
import {Form, iForm} from "./widgets/form"
|
||||
import { Input, iInput} from "./widgets/inputs"
|
||||
import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
|
||||
import {Select, iSelect, iSelectOption} from "./widgets/select"
|
||||
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
|
||||
import {iCallLog, getCallLogsByProjektId, getNewCallLogId, addCallLogData, updateCallLogData} from "../models/call_log"
|
||||
import {iKunde, getKunden} from "../models/kunde"
|
||||
import {getProjekteByKundenId, getProjektById} from "../models/projekt"
|
||||
|
||||
// Aktualisierungsintervall für die Dauer-Anzeige in Millisekunden.
|
||||
// 1000 = jede Sekunde, 60000 = jede Minute.
|
||||
const DAUER_UPDATE_INTERVALL = 1000
|
||||
|
||||
function createCallLogTreenodes(projektId: number | null = null): iTreenode[] {
|
||||
let filteredLogs = getCallLogsByProjektId(projektId)
|
||||
|
||||
@@ -174,6 +178,23 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
// Sind Kunde und Projekt voreingestellt (Liste wurde projektgefiltert
|
||||
// oder aus der Projektliste aufgerufen)?
|
||||
let kundeVoreingestellt: boolean = false
|
||||
// Startzeit für die Dauer-Messung (nur bei Neuanlage gesetzt).
|
||||
let startZeit: Date | null = null
|
||||
// Timer-Handle für die Dauer-Aktualisierung.
|
||||
let timerId: number | null = null
|
||||
// Direkte DOM-Referenz auf das Dauer-Feld, damit der Timer den Wert
|
||||
// ohne Redraw aktualisieren kann (ein Redraw würde die übrigen Felder
|
||||
// mit den veralteten currentLog-Werten überschreiben).
|
||||
let dauerInput: HTMLInputElement | null = null
|
||||
|
||||
/**
|
||||
* Formatiert verstrichene Sekunden als mm:ss (Minuten:Sekunden).
|
||||
*/
|
||||
const formatDauer = (sekunden: number): string => {
|
||||
const m = Math.floor(sekunden / 60)
|
||||
const s = sekunden % 60
|
||||
return m.toString().padStart(2, '0') + ':' + s.toString().padStart(2, '0')
|
||||
}
|
||||
|
||||
return {
|
||||
oninit: (vnode) => {
|
||||
@@ -203,7 +224,27 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
wiedervorlageDatum: routeParams.wiedervorlageDatum || "",
|
||||
erledigt: routeParams.erledigt === true || routeParams.erledigt === "true"
|
||||
}
|
||||
// Bei Neuanlage Startzeit merken und Dauer-Timer starten.
|
||||
if (currentLog.id === -1) {
|
||||
startZeit = new Date()
|
||||
timerId = window.setInterval(() => {
|
||||
if (startZeit) {
|
||||
// Verstrichene Sekunden berechnen; das Intervall
|
||||
// steuert nur die Update-Frequenz.
|
||||
const sekunden = Math.floor((Date.now() - startZeit.getTime()) / 1000)
|
||||
const dauer = formatDauer(sekunden)
|
||||
currentLog.dauer = dauer
|
||||
// Nur das Dauer-Feld direkt im DOM aktualisieren,
|
||||
// ohne redraw (sonst werden andere Felder zurückgesetzt).
|
||||
if (dauerInput) { dauerInput.value = dauer }
|
||||
}
|
||||
}, DAUER_UPDATE_INTERVALL)
|
||||
}
|
||||
}
|
||||
},
|
||||
onremove: (vnode) => {
|
||||
// Timer stoppen, damit er nach Verlassen des Views nicht weiterläuft.
|
||||
if (timerId != null) { window.clearInterval(timerId) }
|
||||
},
|
||||
view: (vnode) => {
|
||||
// Select-Optionen aus Kunden- und Projektliste aufbauen.
|
||||
@@ -214,6 +255,7 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
const projektOptionen: iSelectOption[] = getProjekteByKundenId(currentLog.kundenId).map((p) => {
|
||||
return {value: p.id, label: p.projektname}
|
||||
})
|
||||
// Einheit der Dauer-Anzeige im Format mm:ss.
|
||||
return m("div.w3-container.w3-auto",
|
||||
m("h1", currentLog.id === -1 ? "Neue Gesprächsnotiz anlegen" : "Gesprächsnotiz"),
|
||||
m(Form, {showButtons: true, onsubmit: (null), oncancel: (null)} as iForm, [
|
||||
@@ -242,11 +284,23 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
} as iSelect)),
|
||||
m("label", "Datum", m(Input, {name: "datum", value: currentLog.datum, type: "date"} as iInput)),
|
||||
m("label", "Uhrzeit Beginn", m(Input, {name: "uhrzeitBeginn", value: currentLog.uhrzeitBeginn, type: "time"} as iInput)),
|
||||
m("label", "Dauer (Minuten)", m(Input, {name: "dauer", value: currentLog.dauer, type: "number"} as iInput)),
|
||||
m("label", "Dauer (mm:ss)",
|
||||
// Raw input statt Input-Widget, damit oncreate die
|
||||
// DOM-Referenz für den Timer greifen kann. Text-Typ,
|
||||
// da das Format mm:ss keine Zahl ist.
|
||||
m("input.w3-input.w3-border", {
|
||||
name: "dauer",
|
||||
type: "text",
|
||||
value: currentLog.dauer,
|
||||
style: {'margin-bottom': '5px', width: '100%'},
|
||||
oncreate: (vnode: m.VnodeDOM) => {
|
||||
dauerInput = vnode.dom as HTMLInputElement
|
||||
}
|
||||
})),
|
||||
m("label", "Betreff", m(Input, {name: "betreff", value: currentLog.betreff, type: "text"} as iInput)),
|
||||
m("label", "Name Ansprechpartner", m(Input, {name: "nameAnsprechpartner", value: currentLog.nameAnsprechpartner, type: "text"} as iInput)),
|
||||
m("label", "Telefon", m(Input, {name: "telefon", value: currentLog.telefon, type: "tel"} as iInput)),
|
||||
m("label", "Notiz", m(Input, {name: "notiz", value: currentLog.notiz, type: "text"} as iInput)),
|
||||
m("label", "Notiz", m(Textarea, {name: "notiz", value: currentLog.notiz, rows: 4} as iTextarea)),
|
||||
m("label", "Wiedervorlage Datum", m(Input, {name: "wiedervorlageDatum", value: currentLog.wiedervorlageDatum, type: "date"} as iInput)),
|
||||
m("label", m(Input, {name: "erledigt", type: "checkbox", value: currentLog.erledigt} as iInput), "Erledigt")
|
||||
])
|
||||
|
||||
Reference in new issue
Block a user