Bündelt die Neuentwicklung in AssigmentMonitorV2 (eigene Ports/DB), die Umstellung auf numerische Bewertungen, Meeting-Checklisten, KI-Tagging und die geplante Feedback-Kaskade — als Basis für Versionsverwaltung in Gitea. Co-authored-by: Cursor <cursoragent@cursor.com>
64 lines
3.3 KiB
TypeScript
64 lines
3.3 KiB
TypeScript
import {
|
|
getAllRows, getRowsWhereEquals, getRowsWhereIn, insertRow, updateRow, deleteRowById, deleteRowsWhereEquals,
|
|
} from '../crud'
|
|
import type { ChecklistItemDef, ChecklistResponse } from '../../../src/db/types'
|
|
|
|
export const listChecklistItemDefsForPhaseTemplate = (phaseTemplateId: number): ChecklistItemDef[] => {
|
|
const rows = getRowsWhereEquals<ChecklistItemDef>('checklistItemDefs', 'phaseTemplateId', phaseTemplateId)
|
|
return rows.sort((a, b) => a.order - b.order)
|
|
}
|
|
|
|
/** Bulk-Variante für Berichte über mehrere Phasentypen hinweg (Assignment-Report-PDF, Gesamtprotokoll). */
|
|
export const listChecklistItemDefsForPhaseTemplates = (phaseTemplateIds: number[]): ChecklistItemDef[] =>
|
|
getRowsWhereIn<ChecklistItemDef>('checklistItemDefs', 'phaseTemplateId', phaseTemplateIds).sort((a, b) => a.order - b.order)
|
|
|
|
export const addChecklistItemDef = (def: Omit<ChecklistItemDef, 'id'>): number => insertRow('checklistItemDefs', def)
|
|
export const updateChecklistItemDef = (id: number, patch: Partial<ChecklistItemDef>): number =>
|
|
updateRow('checklistItemDefs', id, patch)
|
|
|
|
/** Räumt zugehörige `checklistResponses` mit auf — gleiches Verteidigungs-Prinzip wie `deleteFeedbackCriterionItem`. */
|
|
export function deleteChecklistItemDef(id: number): void {
|
|
deleteRowsWhereEquals('checklistResponses', 'checklistItemId', id)
|
|
deleteRowById('checklistItemDefs', id)
|
|
}
|
|
|
|
/** Cascade-Baustein für `deletePhaseTemplate`/`deleteAssignmentType` — löscht alle Checklisten-Punkte samt Antworten einer Phase. */
|
|
export function deleteChecklistItemDefsForPhaseTemplate(phaseTemplateId: number): void {
|
|
for (const def of listChecklistItemDefsForPhaseTemplate(phaseTemplateId)) {
|
|
deleteChecklistItemDef(def.id!)
|
|
}
|
|
}
|
|
|
|
export const listChecklistResponsesForMeeting = (meetingInstanceId: number): ChecklistResponse[] =>
|
|
getRowsWhereEquals<ChecklistResponse>('checklistResponses', 'meetingInstanceId', meetingInstanceId)
|
|
|
|
/** Bulk-Variante für Berichte über mehrere Meetings hinweg (Assignment-Report-PDF, Gesamtprotokoll). */
|
|
export const listChecklistResponsesForMeetings = (meetingInstanceIds: number[]): ChecklistResponse[] =>
|
|
getRowsWhereIn<ChecklistResponse>('checklistResponses', 'meetingInstanceId', meetingInstanceIds)
|
|
|
|
/**
|
|
* Upsert per Komposit-Schlüssel (meetingInstanceId, checklistItemId, instituteeId ?? null), gleiches
|
|
* Find-or-Insert-Muster wie `setAssessmentScore`/`saveAssessmentNote` in MeetingView.tsx. `criterionItemId`
|
|
* überschreibt pro Antwort individuell die Konfigurations-Vorgabe (`ChecklistItemDef.linkedCriterionItemId`)
|
|
* — siehe CLAUDE.md „Individuelle Kriterium-Zuordnung pro Checklisten-Antwort".
|
|
*/
|
|
export function upsertChecklistResponse(input: {
|
|
meetingInstanceId: number
|
|
instituteeId?: number
|
|
checklistItemId: number
|
|
rating: ChecklistResponse['rating']
|
|
note: string
|
|
criterionItemId?: number
|
|
}): number {
|
|
const existing = getAllRows<ChecklistResponse>('checklistResponses').find(r =>
|
|
r.meetingInstanceId === input.meetingInstanceId &&
|
|
r.checklistItemId === input.checklistItemId &&
|
|
(r.instituteeId ?? null) === (input.instituteeId ?? null),
|
|
)
|
|
if (existing?.id) {
|
|
updateRow('checklistResponses', existing.id, { rating: input.rating, note: input.note, criterionItemId: input.criterionItemId })
|
|
return existing.id
|
|
}
|
|
return insertRow('checklistResponses', input)
|
|
}
|