Serverseitige Filterung für Listen-Endpunkte und Einzelabrufe in Listen-Komponenten

Server: Die list-Endpunkte für Kontakt, Projekt, Kontaktadresse und CallLog
akzeptieren nun einen optionalen Query-Parameter (kunden_id bzw. projekt_id)
und filtern im ORM-Query. Neue Migration V01.05 legt Indizes auf den
FK-Spalten an.

Client: Die fetch-Funktionen erhalten einen optionalen Parent-ID-Parameter.
Die Listen-Komponenten übergeben die Parent-ID aus den Route-Params an den
Server und laden nur noch benötigte Daten. Statt kompletter Eltern-Listen
wird per fetchXxxById ein einzelner Datensatz für die Namensauflösung geladen.
Die CallLog-Bearbeitungsmaske behält ihre ungesfilterten Dropdown-Abrufe.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
gg committed 2026-09-04 15:43:43 +02:00
1 parent e9a2f48ede
commit 93827dde0f
15 files changed
+189 -141

No files matched your search

+13 -1
View File
@@ -12,7 +12,7 @@ erfolgt ausschließlich über __bind_key__.
import datetime
import decimal
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Index, Integer, String
from sqlalchemy.orm import relationship
from db import dbapp
@@ -103,6 +103,9 @@ class Kontakt(dbapp.Model):
"""
__tablename__ = 'kontakte'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_kontakte_kunden_id', 'kunden_id'),
)
id = Column(Integer, primary_key=True)
kunden_id = Column(Integer, ForeignKey('kunden.id'), nullable=False)
anrede = Column(String(30), nullable=True)
@@ -134,6 +137,9 @@ class Projekt(dbapp.Model):
"""
__tablename__ = 'projekte'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_projekte_kunden_id', 'kunden_id'),
)
id = Column(Integer, primary_key=True)
kunden_id = Column(Integer, ForeignKey('kunden.id'), nullable=False)
projektname = Column(String(200), nullable=False)
@@ -163,6 +169,9 @@ class Kontaktadresse(dbapp.Model):
"""
__tablename__ = 'kontaktadressen'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_kontaktadressen_projekt_id', 'projekt_id'),
)
id = Column(Integer, primary_key=True)
projekt_id = Column(Integer, ForeignKey('projekte.id'), nullable=False)
anrede = Column(String(30), nullable=True)
@@ -200,6 +209,9 @@ class CallLog(dbapp.Model):
"""
__tablename__ = 'call_logs'
__bind_key__ = BINDKEY
__table_args__ = (
Index('ix_call_logs_projekt_id', 'projekt_id'),
)
id = Column(Integer, primary_key=True)
projekt_id = Column(Integer, ForeignKey('projekte.id'), nullable=False)
datum = Column(String(20), nullable=True)
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_call_logs():
def get_call_logs(projekt_id: int | None = None):
"""
Liefert alle Gesprächsnotizen, sortiert nach Datum absteigend.
Liefert Gesprächsnotizen, sortiert nach Datum absteigend.
Ist projekt_id gesetzt, werden nur die Notizen dieses Projekts
zurückgegeben (serverseitige Filterung). Ohne projekt_id werden
alle Notizen geliefert.
"""
return CallLog.query.order_by(CallLog.datum.desc()).all()
query = CallLog.query
if projekt_id is not None:
query = query.filter(CallLog.projekt_id == projekt_id)
return query.order_by(CallLog.datum.desc()).all()
def get_call_log(call_log_id: int) -> CallLog:
+17
View File
@@ -91,6 +91,23 @@ def _db_V01_04():
session.commit()
def _db_V01_05():
"""
Legt Indizes auf den Fremdschlüsselspalten an, die für die
serverseitige Filterung der Listen-Endpunkte genutzt werden.
CREATE INDEX IF NOT EXISTS ist idempotent und überspringet bereits
vorhandene Indizes.
"""
from sqlalchemy import text
session.execute(text("CREATE INDEX IF NOT EXISTS ix_kontakte_kunden_id ON kontakte (kunden_id)"))
session.execute(text("CREATE INDEX IF NOT EXISTS ix_projekte_kunden_id ON projekte (kunden_id)"))
session.execute(text("CREATE INDEX IF NOT EXISTS ix_kontaktadressen_projekt_id ON kontaktadressen (projekt_id)"))
session.execute(text("CREATE INDEX IF NOT EXISTS ix_call_logs_projekt_id ON call_logs (projekt_id)"))
_updatesysteminfo('01.05')
session.commit()
def checkupdates():
"""
Ermittelt die aktuelle DB-Version aus der Systeminfo-Tabelle und führt alle
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_kontakte():
def get_kontakte(kunden_id: int | None = None):
"""
Liefert alle Kontakte, sortiert nach Name.
Liefert Kontakte, sortiert nach Name.
Ist kunden_id gesetzt, werden nur die Kontakte dieses Kunden
zurückgegeben (serverseitige Filterung). Ohne kunden_id werden
alle Kontakte geliefert.
"""
return Kontakt.query.order_by(Kontakt.name).all()
query = Kontakt.query
if kunden_id is not None:
query = query.filter(Kontakt.kunden_id == kunden_id)
return query.order_by(Kontakt.name).all()
def get_kontakt(kontakt_id: int) -> Kontakt:
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_kontaktadressen():
def get_kontaktadressen(projekt_id: int | None = None):
"""
Liefert alle Kontaktadressen, sortiert nach Name.
Liefert Kontaktadressen, sortiert nach Name.
Ist projekt_id gesetzt, werden nur die Kontaktadressen dieses
Projekts zurückgegeben (serverseitige Filterung). Ohne projekt_id
werden alle Kontaktadressen geliefert.
"""
return Kontaktadresse.query.order_by(Kontaktadresse.name).all()
query = Kontaktadresse.query
if projekt_id is not None:
query = query.filter(Kontaktadresse.projekt_id == projekt_id)
return query.order_by(Kontaktadresse.name).all()
def get_kontaktadresse(kontaktadresse_id: int) -> Kontaktadresse:
+10 -3
View File
@@ -17,11 +17,18 @@ from auth.model.errors import ApplicationError, HtmlStatusCode
session = dbapp.session
def get_projekte():
def get_projekte(kunden_id: int | None = None):
"""
Liefert alle Projekte, sortiert nach projektname.
Liefert Projekte, sortiert nach projektname.
Ist kunden_id gesetzt, werden nur die Projekte dieses Kunden
zurückgegeben (serverseitige Filterung). Ohne kunden_id werden
alle Projekte geliefert.
"""
return Projekt.query.order_by(Projekt.projektname).all()
query = Projekt.query
if kunden_id is not None:
query = query.filter(Projekt.kunden_id == kunden_id)
return query.order_by(Projekt.projektname).all()
def get_projekt(projekt_id: int) -> Projekt:
+12 -8
View File
@@ -80,8 +80,9 @@ def kunde_delete():
@app.get("/xhr/kontakt/list")
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
def kontakt_list():
"""Liefert alle Kontakte als Liste."""
result = [k.to_dict() for k in kontakte.get_kontakte()]
"""Liefert Kontakte als Liste. Optional nach kunden_id gefiltert."""
kunden_id = request.args.get("kunden_id", type=int)
result = [k.to_dict() for k in kontakte.get_kontakte(kunden_id)]
return jsonify(result), 200
@@ -125,8 +126,9 @@ def kontakt_delete():
@app.get("/xhr/projekt/list")
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
def projekt_list():
"""Liefert alle Projekte als Liste."""
result = [p.to_dict() for p in projekte.get_projekte()]
"""Liefert Projekte als Liste. Optional nach kunden_id gefiltert."""
kunden_id = request.args.get("kunden_id", type=int)
result = [p.to_dict() for p in projekte.get_projekte(kunden_id)]
return jsonify(result), 200
@@ -170,8 +172,9 @@ def projekt_delete():
@app.get("/xhr/kontaktadresse/list")
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
def kontaktadresse_list():
"""Liefert alle Kontaktadressen als Liste."""
result = [k.to_dict() for k in kontaktadressen.get_kontaktadressen()]
"""Liefert Kontaktadressen als Liste. Optional nach projekt_id gefiltert."""
projekt_id = request.args.get("projekt_id", type=int)
result = [k.to_dict() for k in kontaktadressen.get_kontaktadressen(projekt_id)]
return jsonify(result), 200
@@ -215,8 +218,9 @@ def kontaktadresse_delete():
@app.get("/xhr/calllog/list")
@authorisation_required([MITARBEITER, KUNDEN_MANAGER])
def calllog_list():
"""Liefert alle Gesprächsnotizen als Liste."""
result = [l.to_dict() for l in call_logs.get_call_logs()]
"""Liefert Gesprächsnotizen als Liste. Optional nach projekt_id gefiltert."""
projekt_id = request.args.get("projekt_id", type=int)
result = [l.to_dict() for l in call_logs.get_call_logs(projekt_id)]
return jsonify(result), 200
+21 -25
View File
@@ -5,7 +5,7 @@ import {Select, iSelect, iSelectOption} from "./widgets/select"
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
import {iCallLog, fetchCallLogs, fetchCallLogById, createCallLogREST, updateCallLogREST} from "../models/call_log"
import {iKunde, fetchKunden} from "../models/kunde"
import {iProjekt, fetchProjekte} from "../models/projekt"
import {iProjekt, fetchProjekte, fetchProjektById} from "../models/projekt"
import {iKontaktadresse, fetchKontaktadressen} from "../models/kontaktadresse"
// Aktualisierungsintervall für die Dauer-Anzeige in Millisekunden.
@@ -15,10 +15,11 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
let treenodes: iTreenode[] = []
let selectedNode: iTreenode | null = null
let filterProjektId: number | null = null
// Projektname für die Überschrift, asynchron aufgelöst.
// Projektname für die Überschrift, asynchron per fetchProjektById
// aufgelöst. kunden_name wird ebenfalls aus dem Projekt bezogen,
// da es nicht in den Route-Params enthalten ist.
let projektName: string = ""
// Projektliste asynchron laden, für Projektauflösung beim Neuanlegen.
let projektListe: iProjekt[] = []
let kundenName: string = ""
const handleRowMarked = (node: iTreenode) => {
selectedNode = node
@@ -41,12 +42,9 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
erledigt: false
}
if (filterProjektId !== null) {
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
if (projekt) {
params.projekt_id = projekt.id
params.projekt_name = projekt.projektname
params.kunden_name = projekt.kunden_name
}
params.projekt_id = filterProjektId
params.projekt_name = projektName
params.kunden_name = kundenName
}
m.route.set("/call_log", params)
}
@@ -94,24 +92,22 @@ export const call_log_liste: m.ClosureComponent = (vnode) => {
filterProjektId = null
projektName = ""
}
// Gesprächsnotizen asynchron vom Server laden.
fetchCallLogs().then((result) => {
let filtered = result
if (filterProjektId !== null) {
filtered = result.filter((l: iCallLog) => l.projekt_id === filterProjektId)
}
treenodes = filtered.map((log: iCallLog) => new Treenode(log, true, []))
// Gesprächsnotizen asynchron vom Server laden. Die Filterung
// nach projekt_id erfolgt serverseitig, sofern ein Filter
// gesetzt ist.
fetchCallLogs(filterProjektId !== null ? filterProjektId : undefined).then((result) => {
treenodes = result.map((log: iCallLog) => new Treenode(log, true, []))
})
// Projektliste asynchron laden, für Projektnamen-Auflösung.
fetchProjekte().then((result) => {
projektListe = result
if (filterProjektId !== null && projektName === "") {
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
if (projekt) {
// Projektnamen und Kundennamen asynchron auflösen, falls
// nicht in den Route-Params enthalten.
if (filterProjektId !== null) {
fetchProjektById(filterProjektId).then((projekt: iProjekt) => {
if (projektName === "") {
projektName = projekt.projektname
}
}
})
kundenName = projekt.kunden_name
})
}
},
view: (vnode) => {
return m("div.w3-container.w3-auto", {
+15 -31
View File
@@ -3,18 +3,15 @@ import {Form, iForm} from "./widgets/form"
import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
import {iKontakt, fetchKontakte, fetchKontaktById, createKontaktREST, updateKontaktREST} from "../models/kontakt"
import {iKunde, fetchKunden} from "../models/kunde"
import {iKunde, fetchKundeById} from "../models/kunde"
export const kontaktliste: m.ClosureComponent = (vnode) => {
let treenodes: iTreenode[] = []
let selectedNode: iTreenode | null = null
let filterKundenId: number | null = null
// Kundenname für die Überschrift, asynchron aus der Kundenliste
// aufgelöst.
// Kundenname für die Überschrift, asynchron per fetchKundeById
// aufgelöst, falls nicht in den Route-Params enthalten.
let kundenName: string = ""
// Kundenliste asynchron vom Server laden, für die Kundenauflösung
// beim Anlegen eines neuen Kontakts.
let kundenListe: iKunde[] = []
const handleRowMarked = (node: iTreenode) => {
selectedNode = node
@@ -24,11 +21,8 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
const params: any = {id: -1}
// Nur bei kundengefilterter Liste den Kunden vorbelegen.
if (filterKundenId !== null) {
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
if (kunde) {
params.kunden_id = kunde.id
params.kunden_name = kunde.name
}
params.kunden_id = filterKundenId
params.kunden_name = kundenName
}
m.route.set("/kontakt", params)
}
@@ -71,27 +65,17 @@ export const kontaktliste: m.ClosureComponent = (vnode) => {
filterKundenId = null
kundenName = ""
}
// Kontakte asynchron vom Server laden. m.request löst nach
// Promise-Auflösung automatisch ein Redraw aus.
fetchKontakte().then((result) => {
let filtered = result
if (filterKundenId !== null) {
filtered = result.filter((k: iKontakt) => k.kunden_id === filterKundenId)
}
treenodes = filtered.map((kontakt: iKontakt) => new Treenode(kontakt, true, []))
})
// Kundenliste asynchron vom Server laden.
fetchKunden().then((result) => {
kundenListe = result
// Fallback: Falls kunden_name nicht in den Route-Params
// enthalten war, aus der Kundenliste auflösen.
if (filterKundenId !== null && kundenName === "") {
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
if (kunde) {
kundenName = kunde.name
}
}
// Kontakte asynchron vom Server laden. Die Filterung nach
// kunden_id erfolgt serverseitig, sofern ein Filter gesetzt ist.
fetchKontakte(filterKundenId !== null ? filterKundenId : undefined).then((result) => {
treenodes = result.map((kontakt: iKontakt) => new Treenode(kontakt, true, []))
})
// Kundennamen asynchron auflösen, falls nicht in Route-Params.
if (filterKundenId !== null && kundenName === "") {
fetchKundeById(filterKundenId).then((kunde: iKunde) => {
kundenName = kunde.name
})
}
},
view: (vnode) => {
return m("div.w3-container.w3-auto", {
+16 -28
View File
@@ -3,18 +3,15 @@ import {Form, iForm} from "./widgets/form"
import { Input, iInput, Textarea, iTextarea} from "./widgets/inputs"
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
import {iKontaktadresse, fetchKontaktadressen, fetchKontaktadresseById, createKontaktadresseREST, updateKontaktadresseREST} from "../models/kontaktadresse"
import {iProjekt, fetchProjekte} from "../models/projekt"
import {iProjekt, fetchProjektById} from "../models/projekt"
export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
let treenodes: iTreenode[] = []
let selectedNode: iTreenode | null = null
let filterProjektId: number | null = null
// Projektname für die Überschrift, asynchron aus der Projektliste
// aufgelöst.
// Projektname für die Überschrift, asynchron per fetchProjektById
// aufgelöst, falls nicht in den Route-Params enthalten.
let projektName: string = ""
// Projektliste asynchron vom Server laden, für die Projektauflösung
// beim Anlegen einer neuen Kontaktadresse.
let projektListe: iProjekt[] = []
const handleRowMarked = (node: iTreenode) => {
selectedNode = node
@@ -23,11 +20,8 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
const addKontaktadresseRoute = () => {
const params: any = {id: -1}
if (filterProjektId !== null) {
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
if (projekt) {
params.projekt_id = projekt.id
params.projekt_name = projekt.projektname
}
params.projekt_id = filterProjektId
params.projekt_name = projektName
}
m.route.set("/kontaktadresse", params)
}
@@ -97,24 +91,18 @@ export const kontaktadresseliste: m.ClosureComponent = (vnode) => {
filterProjektId = null
projektName = ""
}
// Kontaktadressen asynchron vom Server laden.
fetchKontaktadressen().then((result) => {
let filtered = result
if (filterProjektId !== null) {
filtered = result.filter((k: iKontaktadresse) => k.projekt_id === filterProjektId)
}
treenodes = filtered.map((kontaktadresse: iKontaktadresse) => new Treenode(kontaktadresse, true, []))
})
// Projektliste asynchron vom Server laden.
fetchProjekte().then((result) => {
projektListe = result
if (filterProjektId !== null && projektName === "") {
const projekt = projektListe.find((p: iProjekt) => p.id === filterProjektId)
if (projekt) {
projektName = projekt.projektname
}
}
// Kontaktadressen asynchron vom Server laden. Die Filterung
// nach projekt_id erfolgt serverseitig, sofern ein Filter
// gesetzt ist.
fetchKontaktadressen(filterProjektId !== null ? filterProjektId : undefined).then((result) => {
treenodes = result.map((kontaktadresse: iKontaktadresse) => new Treenode(kontaktadresse, true, []))
})
// Projektnamen asynchron auflösen, falls nicht in Route-Params.
if (filterProjektId !== null && projektName === "") {
fetchProjektById(filterProjektId).then((projekt: iProjekt) => {
projektName = projekt.projektname
})
}
},
view: (vnode) => {
return m("div.w3-container.w3-auto", {
+15 -28
View File
@@ -3,18 +3,15 @@ import {Form, iForm} from "./widgets/form"
import { Input, iInput} from "./widgets/inputs"
import {Treenode, iTreenode, Treetable, iTreetable, TopbarButton, iTopbarButton} from "./widgets/Treetable_V2"
import {iProjekt, fetchProjekte, fetchProjektById, createProjektREST, updateProjektREST} from "../models/projekt"
import {iKunde, fetchKunden} from "../models/kunde"
import {iKunde, fetchKundeById} from "../models/kunde"
export const projektliste: m.ClosureComponent = (vnode) => {
let treenodes: iTreenode[] = []
let selectedNode: iTreenode | null = null
let filterKundenId: number | null = null
// Kundenname für die Überschrift, asynchron aus der Kundenliste
// aufgelöst.
// Kundenname für die Überschrift, asynchron per fetchKundeById
// aufgelöst, falls nicht in den Route-Params enthalten.
let kundenName: string = ""
// Kundenliste asynchron vom Server laden, für die Kundenauflösung
// beim Anlegen eines neuen Projekts.
let kundenListe: iKunde[] = []
const handleRowMarked = (node: iTreenode) => {
selectedNode = node
@@ -24,11 +21,8 @@ export const projektliste: m.ClosureComponent = (vnode) => {
const params: any = {id: -1}
// Nur bei kundengefilterter Liste den Kunden vorbelegen.
if (filterKundenId !== null) {
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
if (kunde) {
params.kunden_id = kunde.id
params.kunden_name = kunde.name
}
params.kunden_id = filterKundenId
params.kunden_name = kundenName
}
m.route.set("/projekt", params)
}
@@ -108,24 +102,17 @@ export const projektliste: m.ClosureComponent = (vnode) => {
filterKundenId = null
kundenName = ""
}
// Projekte asynchron vom Server laden.
fetchProjekte().then((result) => {
let filtered = result
if (filterKundenId !== null) {
filtered = result.filter((p: iProjekt) => p.kunden_id === filterKundenId)
}
treenodes = filtered.map((projekt: iProjekt) => new Treenode(projekt, true, []))
})
// Kundenliste asynchron vom Server laden.
fetchKunden().then((result) => {
kundenListe = result
if (filterKundenId !== null && kundenName === "") {
const kunde = kundenListe.find((k: iKunde) => k.id === filterKundenId)
if (kunde) {
kundenName = kunde.name
}
}
// Projekte asynchron vom Server laden. Die Filterung nach
// kunden_id erfolgt serverseitig, sofern ein Filter gesetzt ist.
fetchProjekte(filterKundenId !== null ? filterKundenId : undefined).then((result) => {
treenodes = result.map((projekt: iProjekt) => new Treenode(projekt, true, []))
})
// Kundennamen asynchron auflösen, falls nicht in Route-Params.
if (filterKundenId !== null && kundenName === "") {
fetchKundeById(filterKundenId).then((kunde: iKunde) => {
kundenName = kunde.name
})
}
},
view: (vnode) => {
return m("div.w3-container.w3-auto", {
+10 -2
View File
@@ -36,11 +36,19 @@ const CALLLOG_REST_BASE = "/xhr/calllog"
/**
* Lädt die Liste der Gesprächsnotizen vom Server.
* Ist projektId gesetzt (>= 0), werden nur die Notizen dieses Projekts
* geliefert (serverseitige Filterung). Ohne Parameter werden alle
* Notizen geliefert.
*/
export function fetchCallLogs(): Promise<iCallLog[]> {
export function fetchCallLogs(projektId?: number): Promise<iCallLog[]> {
const params: Record<string, any> = {}
if (projektId !== undefined && projektId >= 0) {
params.projekt_id = projektId
}
return m.request({
method: "GET",
url: CALLLOG_REST_BASE + "/list"
url: CALLLOG_REST_BASE + "/list",
params: params
}).then((result) => result as iCallLog[])
}
+10 -2
View File
@@ -33,11 +33,19 @@ const KONTAKT_REST_BASE = "/xhr/kontakt"
/**
* Lädt die Kontaktliste vom Server.
* Ist kundenId gesetzt (>= 0), werden nur die Kontakte dieses Kunden
* geliefert (serverseitige Filterung). Ohne Parameter werden alle
* Kontakte geliefert.
*/
export function fetchKontakte(): Promise<iKontakt[]> {
export function fetchKontakte(kundenId?: number): Promise<iKontakt[]> {
const params: Record<string, any> = {}
if (kundenId !== undefined && kundenId >= 0) {
params.kunden_id = kundenId
}
return m.request({
method: "GET",
url: KONTAKT_REST_BASE + "/list"
url: KONTAKT_REST_BASE + "/list",
params: params
}).then((result) => result as iKontakt[])
}
+10 -2
View File
@@ -38,11 +38,19 @@ const KONTAKTADRESSE_REST_BASE = "/xhr/kontaktadresse"
/**
* Lädt die Kontaktadressenliste vom Server.
* Ist projektId gesetzt (>= 0), werden nur die Kontaktadressen dieses
* Projekts geliefert (serverseitige Filterung). Ohne Parameter werden
* alle Kontaktadressen geliefert.
*/
export function fetchKontaktadressen(): Promise<iKontaktadresse[]> {
export function fetchKontaktadressen(projektId?: number): Promise<iKontaktadresse[]> {
const params: Record<string, any> = {}
if (projektId !== undefined && projektId >= 0) {
params.projekt_id = projektId
}
return m.request({
method: "GET",
url: KONTAKTADRESSE_REST_BASE + "/list"
url: KONTAKTADRESSE_REST_BASE + "/list",
params: params
}).then((result) => result as iKontaktadresse[])
}
+10 -2
View File
@@ -30,11 +30,19 @@ const PROJEKT_REST_BASE = "/xhr/projekt"
/**
* Lädt die Projektliste vom Server.
* Ist kundenId gesetzt (>= 0), werden nur die Projekte dieses Kunden
* geliefert (serverseitige Filterung). Ohne Parameter werden alle
* Projekte geliefert.
*/
export function fetchProjekte(): Promise<iProjekt[]> {
export function fetchProjekte(kundenId?: number): Promise<iProjekt[]> {
const params: Record<string, any> = {}
if (kundenId !== undefined && kundenId >= 0) {
params.kunden_id = kundenId
}
return m.request({
method: "GET",
url: PROJEKT_REST_BASE + "/list"
url: PROJEKT_REST_BASE + "/list",
params: params
}).then((result) => result as iProjekt[])
}