mirror of
https://github.com/complexcaresolutions/dak.c2s.git
synced 2026-03-17 17:13:42 +00:00
feat: add year filter to Coding queue
Add jahr parameter to the coding queue API endpoint and frontend filter, allowing admins to filter the coding queue by year. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d5b357b60d
commit
2e41242c9e
3 changed files with 27 additions and 8 deletions
|
|
@ -19,6 +19,7 @@ router = APIRouter()
|
||||||
@router.get("/queue", response_model=CaseListResponse)
|
@router.get("/queue", response_model=CaseListResponse)
|
||||||
def coding_queue(
|
def coding_queue(
|
||||||
fallgruppe: str | None = Query(None),
|
fallgruppe: str | None = Query(None),
|
||||||
|
jahr: int | None = Query(None),
|
||||||
page: int = Query(1, ge=1),
|
page: int = Query(1, ge=1),
|
||||||
per_page: int = Query(50, ge=1, le=200),
|
per_page: int = Query(50, ge=1, le=200),
|
||||||
db: Session = Depends(get_db),
|
db: Session = Depends(get_db),
|
||||||
|
|
@ -26,9 +27,9 @@ def coding_queue(
|
||||||
):
|
):
|
||||||
"""Return cases that need coding (gutachten=True, gutachten_typ=NULL).
|
"""Return cases that need coding (gutachten=True, gutachten_typ=NULL).
|
||||||
|
|
||||||
Admin only. Supports optional fallgruppe filter and pagination.
|
Admin only. Supports optional fallgruppe and jahr filters with pagination.
|
||||||
"""
|
"""
|
||||||
cases, total = get_coding_queue(db, fallgruppe, page, per_page)
|
cases, total = get_coding_queue(db, fallgruppe, jahr, page, per_page)
|
||||||
return CaseListResponse(
|
return CaseListResponse(
|
||||||
items=[CaseResponse.model_validate(c) for c in cases],
|
items=[CaseResponse.model_validate(c) for c in cases],
|
||||||
total=total,
|
total=total,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ settings = get_settings()
|
||||||
def get_coding_queue(
|
def get_coding_queue(
|
||||||
db: Session,
|
db: Session,
|
||||||
fallgruppe: str | None = None,
|
fallgruppe: str | None = None,
|
||||||
|
jahr: int | None = None,
|
||||||
page: int = 1,
|
page: int = 1,
|
||||||
per_page: int = 50,
|
per_page: int = 50,
|
||||||
) -> tuple[list[Case], int]:
|
) -> tuple[list[Case], int]:
|
||||||
|
|
@ -32,6 +33,8 @@ def get_coding_queue(
|
||||||
)
|
)
|
||||||
if fallgruppe:
|
if fallgruppe:
|
||||||
query = query.filter(Case.fallgruppe == fallgruppe)
|
query = query.filter(Case.fallgruppe == fallgruppe)
|
||||||
|
if jahr:
|
||||||
|
query = query.filter(Case.jahr == jahr)
|
||||||
|
|
||||||
total = query.count()
|
total = query.count()
|
||||||
cases = (
|
cases = (
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ function getInitialFormState(c: Case): CodingFormState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CodingPage() {
|
export function CodingPage() {
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
const years = Array.from({ length: 5 }, (_, i) => currentYear - i)
|
||||||
|
const [jahr, setJahr] = useState<string>('__all__')
|
||||||
const [fallgruppe, setFallgruppe] = useState<string>('__all__')
|
const [fallgruppe, setFallgruppe] = useState<string>('__all__')
|
||||||
const [page, setPage] = useState(1)
|
const [page, setPage] = useState(1)
|
||||||
const [data, setData] = useState<CaseListResponse | null>(null)
|
const [data, setData] = useState<CaseListResponse | null>(null)
|
||||||
|
|
@ -63,6 +66,7 @@ export function CodingPage() {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const params: Record<string, string | number> = { page, per_page: 50 }
|
const params: Record<string, string | number> = { page, per_page: 50 }
|
||||||
if (fallgruppe !== '__all__') params.fallgruppe = fallgruppe
|
if (fallgruppe !== '__all__') params.fallgruppe = fallgruppe
|
||||||
|
if (jahr !== '__all__') params.jahr = Number(jahr)
|
||||||
|
|
||||||
api.get<CaseListResponse>('/coding/queue', { params, signal: controller.signal })
|
api.get<CaseListResponse>('/coding/queue', { params, signal: controller.signal })
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
|
@ -84,7 +88,7 @@ export function CodingPage() {
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => controller.abort()
|
return () => controller.abort()
|
||||||
}, [page, fallgruppe])
|
}, [page, fallgruppe, jahr])
|
||||||
|
|
||||||
const updateFormField = (caseId: number, field: keyof CodingFormState, value: unknown) => {
|
const updateFormField = (caseId: number, field: keyof CodingFormState, value: unknown) => {
|
||||||
setFormStates((prev) => ({
|
setFormStates((prev) => ({
|
||||||
|
|
@ -136,9 +140,9 @@ export function CodingPage() {
|
||||||
? data.items.filter((c) => savedIds.has(c.id) || c.gutachten_typ !== null).length
|
? data.items.filter((c) => savedIds.has(c.id) || c.gutachten_typ !== null).length
|
||||||
: 0
|
: 0
|
||||||
const grandTotal = data?.total ?? 0
|
const grandTotal = data?.total ?? 0
|
||||||
const activeFilterLabel = fallgruppe !== '__all__'
|
const activeFilters: string[] = []
|
||||||
? FALLGRUPPEN_LABELS[fallgruppe] || fallgruppe
|
if (fallgruppe !== '__all__') activeFilters.push(FALLGRUPPEN_LABELS[fallgruppe] || fallgruppe)
|
||||||
: null
|
if (jahr !== '__all__') activeFilters.push(jahr)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 space-y-4">
|
<div className="p-6 space-y-4">
|
||||||
|
|
@ -148,8 +152,8 @@ export function CodingPage() {
|
||||||
{!loading && data && (
|
{!loading && data && (
|
||||||
<p className="text-sm text-muted-foreground mt-0.5">
|
<p className="text-sm text-muted-foreground mt-0.5">
|
||||||
{grandTotal} {grandTotal === 1 ? 'Fall' : 'Fälle'} offen
|
{grandTotal} {grandTotal === 1 ? 'Fall' : 'Fälle'} offen
|
||||||
{activeFilterLabel && (
|
{activeFilters.length > 0 && (
|
||||||
<> — gefiltert nach <span className="font-medium text-foreground">{activeFilterLabel}</span></>
|
<> — gefiltert nach <span className="font-medium text-foreground">{activeFilters.join(', ')}</span></>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
@ -158,6 +162,17 @@ export function CodingPage() {
|
||||||
<Badge variant="outline" className="text-sm py-1 px-3">
|
<Badge variant="outline" className="text-sm py-1 px-3">
|
||||||
{codedCount} / {data?.items.length ?? 0} auf dieser Seite codiert
|
{codedCount} / {data?.items.length ?? 0} auf dieser Seite codiert
|
||||||
</Badge>
|
</Badge>
|
||||||
|
<Select value={jahr} onValueChange={(v) => { setJahr(v); setPage(1) }}>
|
||||||
|
<SelectTrigger className="w-[130px]">
|
||||||
|
<SelectValue placeholder="Jahr" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="__all__">Alle Jahre</SelectItem>
|
||||||
|
{years.map((y) => (
|
||||||
|
<SelectItem key={y} value={String(y)}>{y}</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
<Select value={fallgruppe} onValueChange={(v) => { setFallgruppe(v); setPage(1) }}>
|
<Select value={fallgruppe} onValueChange={(v) => { setFallgruppe(v); setPage(1) }}>
|
||||||
<SelectTrigger className="w-[180px]">
|
<SelectTrigger className="w-[180px]">
|
||||||
<SelectValue placeholder="Fallgruppe" />
|
<SelectValue placeholder="Fallgruppe" />
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue