Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8744e98a0 | ||
|
|
a8838a1a38 |
No files matched your search
@@ -6,6 +6,7 @@ In den Programmen sollen aussagekräftige Kommentare in deutsch erstellt werden.
|
||||
Verwende bei der GUI primar die widgets, die es in client/Components/widgets gibt. Fehler widgets, gib eines Hinweis und erstelle einen Vorschlag für ein entsprechendes neues Widget.
|
||||
Es soll immer ein responsive Design implmentiert werden, da die App sowohl auf PCs als auch auf mobilen Geräten laufen soll.
|
||||
Verwende für Attribute der GUI-Oberfläche nach Möglichkeit Klassen aus NGINX_Server/html/static/w3.css, insbesondere wenn es darum geht, eine Respnosive Design zu implentieren.
|
||||
Für Farben (foreground und background) verwende priorisiert die Klassen aus NGINX_Server/html/static/app-theme.css
|
||||
View-Container werden mit `w3-container.w3-auto` gewrappt, damit sie auf kleinen Bildschirmen 100% und auf großen bis max. 1140px (bzw. 95%) zentriert nutzen.
|
||||
|
||||
Bei Mithril `m(...)`-Aufrufen mit längeren Attributlisten (z.B. mehrere `style`-Eigenschaften oder mehrere Attribute) schreibe die Attribute untereinander, sobald sie in einer Zeile nicht mehr gut lesbar sind (Faustregel: mehr als 2–3 Attribute oder ein mehrzeiliges `style`-Objekt). Kurze Attributlisten (1–2 Attribute, einzeiliges `style`) dürfen in einer Zeile bleiben. Formatbeispiel:
|
||||
|
||||
@@ -6,6 +6,7 @@ import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton}
|
||||
import {iCallLog, getCallLogsByProjektId, getNewCallLogId, addCallLogData, updateCallLogData} from "../models/call_log"
|
||||
import {iKunde, getKunden} from "../models/kunde"
|
||||
import {getProjekteByKundenId, getProjektById} from "../models/projekt"
|
||||
import {getKontaktadressenByProjektId, getKontaktadresseById} from "../models/kontaktadresse"
|
||||
|
||||
// Aktualisierungsintervall für die Dauer-Anzeige in Millisekunden.
|
||||
// 1000 = jede Sekunde, 60000 = jede Minute.
|
||||
@@ -86,7 +87,7 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
|
||||
m("span", log.betreff),
|
||||
m("span", log.wiedervorlageDatum),
|
||||
m("span", log.erledigt ? "Erledigt" : "Offen"),
|
||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editCallLog(log, e)}, m("i.material-icons", "edit"))
|
||||
m("button.w3-button.w3-small", {title: "Gesprächsnotiz bearbeiten", style: {padding: '0 2px'}, onclick: (e: Event) => editCallLog(log, e)}, m("i.material-icons", "edit"))
|
||||
]
|
||||
}
|
||||
|
||||
@@ -177,6 +178,10 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
// Sind Kunde und Projekt voreingestellt (Liste wurde projektgefiltert
|
||||
// oder aus der Projektliste aufgerufen)?
|
||||
let kundeVoreingestellt: boolean = false
|
||||
// Ist der Ansprechpartner voreingestellt (aus Kontaktadressenliste)?
|
||||
// Wenn ja, wird ein readonly Input gezeigt; sonst ein Select, das die
|
||||
// Kontaktadressen des gewählten Projekts anbietet.
|
||||
let ansprechpartnerVoreingestellt: boolean = false
|
||||
// Startzeit für die Dauer-Messung (nur bei Neuanlage gesetzt).
|
||||
let startZeit: Date | null = null
|
||||
// Timer-Handle für die Dauer-Aktualisierung.
|
||||
@@ -224,6 +229,7 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
erledigt: routeParams.erledigt === true || routeParams.erledigt === "true"
|
||||
}
|
||||
// Bei Neuanlage Startzeit merken und Dauer-Timer starten.
|
||||
ansprechpartnerVoreingestellt = currentLog.nameAnsprechpartner !== ""
|
||||
if (currentLog.id === -1) {
|
||||
startZeit = new Date()
|
||||
timerId = window.setInterval(() => {
|
||||
@@ -254,6 +260,13 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
const projektOptionen: iSelectOption[] = getProjekteByKundenId(currentLog.kundenId).map((p) => {
|
||||
return {value: p.id, label: p.projektname}
|
||||
})
|
||||
// Kontaktadressen-Optionen sind vom gewählten Projekt abhängig.
|
||||
// Werden nur benötigt, wenn der Ansprechpartner nicht voreingestellt ist.
|
||||
const kontaktadressenOptionen: iSelectOption[] = !ansprechpartnerVoreingestellt
|
||||
? getKontaktadressenByProjektId(currentLog.projektId).map((ka) => {
|
||||
return {value: ka.id, label: ka.name + (ka.firma ? " (" + ka.firma + ")" : "")}
|
||||
})
|
||||
: []
|
||||
// Einheit der Dauer-Anzeige im Format mm:ss.
|
||||
return m("div.w3-container.w3-auto.form-view-container",
|
||||
m("h1", currentLog.id === -1 ? "Neue Gesprächsnotiz anlegen" : "Gesprächsnotiz"),
|
||||
@@ -283,7 +296,16 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
value: currentLog.projektId,
|
||||
options: projektOptionen,
|
||||
readonly: kundeVoreingestellt,
|
||||
required: true
|
||||
required: true,
|
||||
onchanged: (projektId: number) => {
|
||||
currentLog.projektId = projektId
|
||||
// Bei Projektwechsel Ansprechpartner und Telefon
|
||||
// zurücksetzen, falls nicht voreingestellt.
|
||||
if (!ansprechpartnerVoreingestellt) {
|
||||
currentLog.nameAnsprechpartner = ""
|
||||
currentLog.telefon = ""
|
||||
}
|
||||
}
|
||||
} as iSelect)),
|
||||
// Datum, Startzeit und Dauer in einer Zeile.
|
||||
m("div", {style: {display: 'flex', gap: '8px', 'margin-bottom': '5px'}},
|
||||
@@ -306,9 +328,26 @@ export const Call_Log: m.ClosureComponent = (vnode) => {
|
||||
),
|
||||
m("label", "Betreff", m(Input, {name: "betreff", value: currentLog.betreff, type: "text"} as iInput)),
|
||||
// Ansprechpartner und Telefon in einer Zeile.
|
||||
// Wenn der Ansprechpartner voreingestellt ist (aus Kontaktadressenliste),
|
||||
// wird ein readonly Input gezeigt; sonst ein Select, das die
|
||||
// Kontaktadressen des gewählten Projekts anbietet. Bei Auswahl
|
||||
// werden Name und Telefon automatisch übernommen.
|
||||
m("div", {style: {display: 'flex', gap: '8px', 'margin-bottom': '5px'}},
|
||||
m("label", {style: {flex: '1'}}, "Name Ansprechpartner",
|
||||
m(Input, {name: "nameAnsprechpartner", value: currentLog.nameAnsprechpartner, type: "text"} as iInput)),
|
||||
ansprechpartnerVoreingestellt
|
||||
? m(Input, {name: "nameAnsprechpartner", value: currentLog.nameAnsprechpartner, type: "text", readonly: true} as iInput)
|
||||
: m(Select, {
|
||||
name: "kontaktadresseId",
|
||||
value: -1,
|
||||
options: kontaktadressenOptionen,
|
||||
onchanged: (kontaktadresseId: number) => {
|
||||
const ka = getKontaktadresseById(kontaktadresseId)
|
||||
if (ka) {
|
||||
currentLog.nameAnsprechpartner = ka.name
|
||||
currentLog.telefon = ka.telefon
|
||||
}
|
||||
}
|
||||
} as iSelect)),
|
||||
m("label", {style: {flex: '1'}}, "Telefon",
|
||||
m(Input, {name: "telefon", value: currentLog.telefon, type: "tel"} as iInput))
|
||||
),
|
||||
|
||||
@@ -4,7 +4,7 @@ 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 {iKontaktadresse, getKontaktadressenByProjektId, getNewKontaktadresseId, addKontaktadresse, updateKontaktadresse} from "../models/kontaktadresse"
|
||||
import {iProjekt, getProjekte} from "../models/projekt"
|
||||
import {iProjekt, getProjekte, getProjektById} from "../models/projekt"
|
||||
|
||||
function createKontaktadresseTreenodes(projektId: number | null = null): iTreenode[] {
|
||||
let filteredKontaktadressen = getKontaktadressenByProjektId(projektId)
|
||||
@@ -67,6 +67,30 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
||||
})
|
||||
}
|
||||
|
||||
const addCallLog = (kontaktadresse: iKontaktadresse, e: Event) => {
|
||||
e.stopPropagation()
|
||||
const now = new Date()
|
||||
const datum = now.toISOString().split('T')[0]
|
||||
const uhrzeit = now.toTimeString().split(':')[0] + ':' + now.toTimeString().split(':')[1]
|
||||
// Kundennamen über das Projekt auflösen.
|
||||
const projekt = getProjektById(kontaktadresse.projektId)
|
||||
m.route.set("/call_log", {
|
||||
id: -1,
|
||||
kundenName: projekt ? projekt.kundenName : "",
|
||||
projektId: kontaktadresse.projektId,
|
||||
projektName: kontaktadresse.projektName,
|
||||
datum: datum,
|
||||
uhrzeitBeginn: uhrzeit,
|
||||
dauer: "",
|
||||
betreff: "",
|
||||
nameAnsprechpartner: kontaktadresse.name,
|
||||
telefon: kontaktadresse.telefon,
|
||||
notiz: "",
|
||||
wiedervorlageDatum: "",
|
||||
erledigt: false
|
||||
})
|
||||
}
|
||||
|
||||
const columnmapper: (node: iTreenode) => any[] = (node: iTreenode) => {
|
||||
let kontaktadresse: iKontaktadresse = node.nodevalue
|
||||
|
||||
@@ -77,7 +101,10 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
|
||||
m("span", kontaktadresse.email),
|
||||
m("span", kontaktadresse.ort),
|
||||
m("span", kontaktadresse.projektName),
|
||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editKontaktadresse(kontaktadresse, e)}, m("i.material-icons", "edit"))
|
||||
m("div", {style: {display: 'flex', gap: '0', 'white-space': 'nowrap'}},
|
||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editKontaktadresse(kontaktadresse, e)}, m("i.material-icons", "edit")),
|
||||
m("button.w3-button.w3-small", {title: "Gesprächsnotiz hinzufügen", style: {padding: '0 2px'}, onclick: (e: Event) => addCallLog(kontaktadresse, e)}, m("i.material-icons", "add_call"))
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ export const kundenliste: m.ClosureComponent = (vnode) => {
|
||||
m("span", kunde.ort),
|
||||
m("span", kunde.land),
|
||||
m("div", {style: {display: 'flex', gap: '0', 'white-space': 'nowrap'}},
|
||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editKunde(kunde, e)}, m("i.material-icons", "edit")),
|
||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => showProjekte(kunde, e)}, m("i.material-icons", "library_books")),
|
||||
m("button.w3-button.w3-small", {title: "Kunde bearbeiten", style: {padding: '0 2px'}, onclick: (e: Event) => editKunde(kunde, e)}, m("i.material-icons", "edit")),
|
||||
m("button.w3-button.w3-small", {title: "Projekte anzeigen", style: {padding: '0 2px'}, onclick: (e: Event) => showProjekte(kunde, e)}, m("i.material-icons", "library_books")),
|
||||
m("button.w3-button.w3-small", {title: "Kontakte anzeigen", style: {padding: '0 2px'}, onclick: (e: Event) => showKontakte(kunde, e)}, m("i.material-icons", "contact_page"))
|
||||
)
|
||||
]
|
||||
|
||||
@@ -98,7 +98,7 @@ export const projektliste: m.ClosureComponent = (vnode) => {
|
||||
m("span", projekt.verantwortlicher),
|
||||
m("span", projekt.startdatum),
|
||||
m("div", {style: {display: 'flex', gap: '0', 'white-space': 'nowrap'}},
|
||||
m("button.w3-button.w3-small", {style: {padding: '0 2px'}, onclick: (e: Event) => editProjekt(projekt, e)}, m("i.material-icons", "edit")),
|
||||
m("button.w3-button.w3-small", {title: "Projekt bearbeiten", style: {padding: '0 2px'}, onclick: (e: Event) => editProjekt(projekt, e)}, m("i.material-icons", "edit")),
|
||||
m("button.w3-button.w3-small", {title: "Kontaktadressen anzeigen", style: {padding: '0 2px'}, onclick: (e: Event) => showKontaktadressen(projekt, e)}, m("i.material-icons", "contact_page")),
|
||||
m("button.w3-button.w3-small", {title: "Gesprächsnotizen anzeigen", style: {padding: '0 2px'}, onclick: (e: Event) => showCallLogs(projekt, e)}, m("i.material-icons", "call_log")),
|
||||
m("button.w3-button.w3-small", {title: "Gesprächsnotiz hinzufügen", style: {padding: '0 2px'}, onclick: (e: Event) => addCallLog(projekt, e)}, m("i.material-icons", "add_call"))
|
||||
|
||||
Reference in new issue
Block a user