add substeps to upload installation protocal and time and mateiral documents on site

This commit is contained in:
Yinyin Liu 2026-04-28 09:09:03 +02:00
parent 45c816616f
commit 127e16eb34
13 changed files with 41 additions and 9 deletions

View File

@ -2599,6 +2599,7 @@ public class Controller : ControllerBase
[FromQuery] Int64? ticketCommentId, [FromQuery] Int64? ticketCommentId,
[FromQuery] Int64? installationId, [FromQuery] Int64? installationId,
[FromQuery] Int64? checklistItemId, [FromQuery] Int64? checklistItemId,
[FromQuery] String? subtaskKey,
[FromQuery] Token authToken) [FromQuery] Token authToken)
{ {
var user = Db.GetSession(authToken)?.User; var user = Db.GetSession(authToken)?.User;
@ -2678,6 +2679,7 @@ public class Controller : ControllerBase
TicketCommentId = ticketCommentId, TicketCommentId = ticketCommentId,
InstallationId = installationId, InstallationId = installationId,
ChecklistItemId = checklistItemId, ChecklistItemId = checklistItemId,
SubtaskKey = subtaskKey,
Scope = scope, Scope = scope,
S3Key = s3Key, S3Key = s3Key,
OriginalName = safeFileName, OriginalName = safeFileName,
@ -2728,6 +2730,7 @@ public class Controller : ControllerBase
[FromQuery] Int64? ticketCommentId, [FromQuery] Int64? ticketCommentId,
[FromQuery] Int64? installationId, [FromQuery] Int64? installationId,
[FromQuery] Int64? checklistItemId, [FromQuery] Int64? checklistItemId,
[FromQuery] String? subtaskKey,
[FromQuery] Token authToken) [FromQuery] Token authToken)
{ {
var user = Db.GetSession(authToken)?.User; var user = Db.GetSession(authToken)?.User;
@ -2742,7 +2745,7 @@ public class Controller : ControllerBase
if (checklistItemId.HasValue) if (checklistItemId.HasValue)
{ {
if (user.UserType != 2) return Unauthorized(); if (user.UserType != 2) return Unauthorized();
return Ok(Db.GetDocumentsForChecklistItem(checklistItemId.Value)); return Ok(Db.GetDocumentsForChecklistItem(checklistItemId.Value, subtaskKey));
} }
if (installationId.HasValue) if (installationId.HasValue)

View File

@ -48,7 +48,13 @@ public static class ChecklistStepDefinitions
] ]
"""), """),
new( 9, "Installation connected to grid", NoSubtasks), new( 9, "Installation connected to grid", NoSubtasks),
new(10, "Hardware verified on site", NoSubtasks), new(10, "Hardware verified on site",
"""
[
{"text":"checklistStep10Sub1","checked":false},
{"text":"checklistStep10Sub2","checked":false}
]
"""),
new(11, "Software verified on site", NoSubtasks), new(11, "Software verified on site", NoSubtasks),
new(12, "Installation online on Monitor", NoSubtasks), new(12, "Installation online on Monitor", NoSubtasks),
new(13, "Customer informed about Monitor account and reports", NoSubtasks), new(13, "Customer informed about Monitor account and reports", NoSubtasks),

View File

@ -16,6 +16,7 @@ public class Document
[Indexed] public Int64? TicketCommentId { get; set; } [Indexed] public Int64? TicketCommentId { get; set; }
[Indexed] public Int64? InstallationId { get; set; } [Indexed] public Int64? InstallationId { get; set; }
[Indexed] public Int64? ChecklistItemId { get; set; } [Indexed] public Int64? ChecklistItemId { get; set; }
public String? SubtaskKey { get; set; }
public Int32 Scope { get; set; } = (Int32)DocumentScope.TicketAttachment; public Int32 Scope { get; set; } = (Int32)DocumentScope.TicketAttachment;
public String S3Key { get; set; } = ""; public String S3Key { get; set; } = "";

View File

@ -142,6 +142,12 @@ public static partial class Db
"UPDATE ChecklistItem SET Subtasks = ? WHERE StepNumber = 8 AND (Subtasks IS NULL OR Subtasks = '')", "UPDATE ChecklistItem SET Subtasks = ? WHERE StepNumber = 8 AND (Subtasks IS NULL OR Subtasks = '')",
"[{\"text\":\"checklistStep8Sub1\",\"checked\":false}]"); "[{\"text\":\"checklistStep8Sub1\",\"checked\":false}]");
// One-time backfill: step 10 originally had no subtasks; add the two upload subtasks
// (installation protocol + time & material report) to existing rows.
Connection.Execute(
"UPDATE ChecklistItem SET Subtasks = ? WHERE StepNumber = 10 AND (Subtasks IS NULL OR Subtasks = '')",
"[{\"text\":\"checklistStep10Sub1\",\"checked\":false},{\"text\":\"checklistStep10Sub2\",\"checked\":false}]");
//UpdateKeys(); //UpdateKeys();
CleanupSessions().SupressAwaitWarning(); CleanupSessions().SupressAwaitWarning();
DeleteSnapshots().SupressAwaitWarning(); DeleteSnapshots().SupressAwaitWarning();

View File

@ -234,10 +234,11 @@ public static partial class Db
.OrderBy(d => d.CreatedAt) .OrderBy(d => d.CreatedAt)
.ToList(); .ToList();
public static List<Document> GetDocumentsForChecklistItem(Int64 checklistItemId) public static List<Document> GetDocumentsForChecklistItem(Int64 checklistItemId, String? subtaskKey = null)
=> Documents => Documents
.Where(d => d.ChecklistItemId == checklistItemId .Where(d => d.ChecklistItemId == checklistItemId
&& d.Scope == (Int32)DocumentScope.InstallationDocument) && d.Scope == (Int32)DocumentScope.InstallationDocument
&& (subtaskKey == null || d.SubtaskKey == subtaskKey))
.OrderBy(d => d.CreatedAt) .OrderBy(d => d.CreatedAt)
.ToList(); .ToList();

View File

@ -33,6 +33,7 @@ interface FileUploadButtonProps {
ticketCommentId?: number; ticketCommentId?: number;
installationId?: number; installationId?: number;
checklistItemId?: number; checklistItemId?: number;
subtaskKey?: string;
onUploaded?: (doc: UploadedDocument) => void; onUploaded?: (doc: UploadedDocument) => void;
disabled?: boolean; disabled?: boolean;
} }
@ -43,6 +44,7 @@ function FileUploadButton({
ticketCommentId, ticketCommentId,
installationId, installationId,
checklistItemId, checklistItemId,
subtaskKey,
onUploaded, onUploaded,
disabled = false disabled = false
}: FileUploadButtonProps) { }: FileUploadButtonProps) {
@ -89,7 +91,7 @@ function FileUploadButton({
try { try {
const res = await axiosConfig.post('/UploadDocument', formData, { const res = await axiosConfig.post('/UploadDocument', formData, {
params: { scope, ticketId, ticketCommentId, installationId, checklistItemId }, params: { scope, ticketId, ticketCommentId, installationId, checklistItemId, subtaskKey },
headers: { 'Content-Type': 'multipart/form-data' }, headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (e) => { onUploadProgress: (e) => {
if (e.total) setProgress(Math.round((e.loaded * 100) / e.total)); if (e.total) setProgress(Math.round((e.loaded * 100) / e.total));

View File

@ -305,6 +305,7 @@ function ChecklistStepRow({ item, installationId, adminUsers, onUpdate, onNotify
<SubtaskDocumentUpload <SubtaskDocumentUpload
installationId={installationId} installationId={installationId}
checklistItemId={item.id} checklistItemId={item.id}
subtaskKey={s.text}
/> />
)} )}
</Box> </Box>

View File

@ -20,6 +20,7 @@ interface DocumentItem {
interface Props { interface Props {
installationId: number; installationId: number;
checklistItemId: number; checklistItemId: number;
subtaskKey: string;
} }
function fileIcon(contentType: string) { function fileIcon(contentType: string) {
@ -28,18 +29,18 @@ function fileIcon(contentType: string) {
return <InsertDriveFileIcon fontSize="small" />; return <InsertDriveFileIcon fontSize="small" />;
} }
function SubtaskDocumentUpload({ installationId, checklistItemId }: Props) { function SubtaskDocumentUpload({ installationId, checklistItemId, subtaskKey }: Props) {
const [docs, setDocs] = useState<DocumentItem[]>([]); const [docs, setDocs] = useState<DocumentItem[]>([]);
const [refreshKey, setRefreshKey] = useState(0); const [refreshKey, setRefreshKey] = useState(0);
const fetchDocs = useCallback(() => { const fetchDocs = useCallback(() => {
axiosConfig axiosConfig
.get('/GetDocuments', { params: { checklistItemId } }) .get('/GetDocuments', { params: { checklistItemId, subtaskKey } })
.then((res) => { .then((res) => {
if (Array.isArray(res.data)) setDocs(res.data); if (Array.isArray(res.data)) setDocs(res.data);
}) })
.catch(() => setDocs([])); .catch(() => setDocs([]));
}, [checklistItemId]); }, [checklistItemId, subtaskKey]);
useEffect(() => { useEffect(() => {
fetchDocs(); fetchDocs();
@ -100,6 +101,7 @@ function SubtaskDocumentUpload({ installationId, checklistItemId }: Props) {
scope={1} scope={1}
installationId={installationId} installationId={installationId}
checklistItemId={checklistItemId} checklistItemId={checklistItemId}
subtaskKey={subtaskKey}
onUploaded={handleUploaded} onUploaded={handleUploaded}
/> />
</Box> </Box>

View File

@ -26,7 +26,9 @@ export type ChecklistItem = {
export const CHECKLIST_ENABLED_PRODUCTS: ReadonlySet<number> = new Set([2, 4, 5]); export const CHECKLIST_ENABLED_PRODUCTS: ReadonlySet<number> = new Set([2, 4, 5]);
export const UPLOADABLE_SUBTASK_KEYS: ReadonlySet<string> = new Set([ export const UPLOADABLE_SUBTASK_KEYS: ReadonlySet<string> = new Set([
'checklistStep8Sub1' 'checklistStep8Sub1',
'checklistStep10Sub1',
'checklistStep10Sub2'
]); ]);
export type ChecklistSummary = { export type ChecklistSummary = {

View File

@ -744,6 +744,8 @@
"checklistStep7Sub3": "USB-ID in config.json konfiguriert", "checklistStep7Sub3": "USB-ID in config.json konfiguriert",
"checklistStep7Sub4": "Datenlesung vom Wechselrichter getestet", "checklistStep7Sub4": "Datenlesung vom Wechselrichter getestet",
"checklistStep8Sub1": "Lieferschein mit Kundenunterschrift erhalten und hochgeladen", "checklistStep8Sub1": "Lieferschein mit Kundenunterschrift erhalten und hochgeladen",
"checklistStep10Sub1": "Installationsprotokoll hochgeladen",
"checklistStep10Sub2": "Zeit- und Materialbericht in Monitoring hochgeladen",
"checklistNoAttachments": "Noch keine Datei angehängt.", "checklistNoAttachments": "Noch keine Datei angehängt.",
"setupProgress": "Setup-Fortschritt", "setupProgress": "Setup-Fortschritt",
"checklistPhaseEmpty": "Nicht gestartet", "checklistPhaseEmpty": "Nicht gestartet",

View File

@ -492,6 +492,8 @@
"checklistStep7Sub3": "USB ID configured in config.json", "checklistStep7Sub3": "USB ID configured in config.json",
"checklistStep7Sub4": "Inverter data reading from inverter tested", "checklistStep7Sub4": "Inverter data reading from inverter tested",
"checklistStep8Sub1": "Delivery receipt with customer signature received and uploaded", "checklistStep8Sub1": "Delivery receipt with customer signature received and uploaded",
"checklistStep10Sub1": "Installation protocol uploaded",
"checklistStep10Sub2": "Time and material report uploaded to Monitoring",
"checklistNoAttachments": "No file attached yet.", "checklistNoAttachments": "No file attached yet.",
"setupProgress": "Setup Progress", "setupProgress": "Setup Progress",
"checklistPhaseEmpty": "Not started", "checklistPhaseEmpty": "Not started",

View File

@ -744,6 +744,8 @@
"checklistStep7Sub3": "ID USB configuré dans config.json", "checklistStep7Sub3": "ID USB configuré dans config.json",
"checklistStep7Sub4": "Lecture des données de l'onduleur testée", "checklistStep7Sub4": "Lecture des données de l'onduleur testée",
"checklistStep8Sub1": "Bon de livraison signé par le client reçu et téléversé", "checklistStep8Sub1": "Bon de livraison signé par le client reçu et téléversé",
"checklistStep10Sub1": "Procès-verbal d'installation téléversé",
"checklistStep10Sub2": "Rapport de temps et matériaux téléversé dans Monitoring",
"checklistNoAttachments": "Aucun fichier joint pour le moment.", "checklistNoAttachments": "Aucun fichier joint pour le moment.",
"setupProgress": "Progression installation", "setupProgress": "Progression installation",
"checklistPhaseEmpty": "Non commencé", "checklistPhaseEmpty": "Non commencé",

View File

@ -744,6 +744,8 @@
"checklistStep7Sub3": "ID USB configurato in config.json", "checklistStep7Sub3": "ID USB configurato in config.json",
"checklistStep7Sub4": "Lettura dati inverter testata", "checklistStep7Sub4": "Lettura dati inverter testata",
"checklistStep8Sub1": "Bolla di consegna con firma del cliente ricevuta e caricata", "checklistStep8Sub1": "Bolla di consegna con firma del cliente ricevuta e caricata",
"checklistStep10Sub1": "Verbale di installazione caricato",
"checklistStep10Sub2": "Rapporto tempi e materiali caricato su Monitoring",
"checklistNoAttachments": "Nessun file allegato.", "checklistNoAttachments": "Nessun file allegato.",
"setupProgress": "Avanzamento installazione", "setupProgress": "Avanzamento installazione",
"checklistPhaseEmpty": "Non avviato", "checklistPhaseEmpty": "Non avviato",