diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52a777c83..859ce02b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org
- Selected material, personnel and vehicles are now highlighted on the map.
- When material or personnel is selected, the corresponding vehicle is highlighted as well.
- When a vehicle is selected, the corresponding material and personnel are highlighted as well.
+- The reports behavior can generate reports on the counts of transferred patients per triage category.
### Changed
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/human-readable-radiogram-type.pipe.ts b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/human-readable-radiogram-type.pipe.ts
index 4ef2d47aa..dde5c1291 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/human-readable-radiogram-type.pipe.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/human-readable-radiogram-type.pipe.ts
@@ -10,6 +10,7 @@ const map: { [Key in ExerciseRadiogram['type']]: string } = {
treatmentStatusRadiogram: 'Behandlungsstatus',
vehicleCountRadiogram: 'Anzahl an Fahrzeugen',
resourceRequestRadiogram: 'Anfrage nach Fahrzeugen',
+ transferCountsRadiogram: 'Anzahl abtransportierter Patienten',
};
@Pipe({
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.html b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.html
new file mode 100644
index 000000000..1327e36ab
--- /dev/null
+++ b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.html
@@ -0,0 +1,64 @@
+
Transportstatus
+
+
+ Für diese Patientenablage.
+
+ Für alle von dieser Transportorganisation verwalteten Patientenablagen.
+
+
+
+
+
+ SK |
+ Abtransportiert |
+ Verbleibend |
+
+
+
+
+
+
+ |
+
+ {{ radiogram.transferredPatientsCounts[category] }}
+ |
+
+ {{ radiogram.remainingPatientsCounts[category] }}
+ |
+
+
+ 0 ||
+ radiogram.remainingPatientsCounts[category] > 0
+ "
+ >
+
+
+ |
+
+ {{ radiogram.transferredPatientsCounts[category] }}
+ |
+
+ {{ radiogram.remainingPatientsCounts[category] }}
+ |
+
+
+
+ 0">
+
+
+ |
+
+ {{ radiogram.transferredPatientsCounts[category] }}
+ |
+
+ {{ radiogram.remainingPatientsCounts[category] }}
+ |
+
+
+
+
+
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.scss b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.ts b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.ts
new file mode 100644
index 000000000..34c659e07
--- /dev/null
+++ b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component.ts
@@ -0,0 +1,46 @@
+import type { OnInit } from '@angular/core';
+import { Component, Input } from '@angular/core';
+import { Store } from '@ngrx/store';
+import type { TransferCountsRadiogram } from 'digital-fuesim-manv-shared';
+import { UUID } from 'digital-fuesim-manv-shared';
+import type { Observable } from 'rxjs';
+import type { AppState } from 'src/app/state/app.state';
+import { createSelectRadiogram } from 'src/app/state/application/selectors/exercise.selectors';
+
+@Component({
+ selector: 'app-radiogram-card-content-transfer-counts',
+ templateUrl: './radiogram-card-content-transfer-counts.component.html',
+ styleUrls: ['./radiogram-card-content-transfer-counts.component.scss'],
+})
+export class RadiogramCardContentTransferCountsComponent implements OnInit {
+ /**
+ * Categories that should always be listed in the table.
+ */
+ readonly alwaysShowCategories = ['red', 'yellow', 'green'] as const;
+
+ /**
+ * Categories that should be listed in the table if patients of these categories have been transferred and/or are remaining.
+ */
+ readonly showIfTransferredOrRemainingCategories = [
+ 'blue',
+ 'white',
+ ] as const;
+
+ /**
+ * Categories that should only be listed in the table if patients of these categories have been transferred.
+ * (Black patients should usually never be transferred, so its okay to not show their remaining number.)
+ */
+ readonly showIfTransferredCategories = ['black'] as const;
+
+ @Input() radiogramId!: UUID;
+
+ radiogram$!: Observable;
+
+ constructor(private readonly store: Store) {}
+
+ ngOnInit(): void {
+ this.radiogram$ = this.store.select(
+ createSelectRadiogram(this.radiogramId)
+ );
+ }
+}
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content/radiogram-card-content.component.html b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content/radiogram-card-content.component.html
index a211acb09..a1006ec7f 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content/radiogram-card-content.component.html
+++ b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/radiogram-list/radiogram-card/radiogram-card-content/radiogram-card-content.component.html
@@ -5,39 +5,42 @@
+ />
-
+ />
+ />
+ />
+ />
+ />
+ />
+
+ />
+ />
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/simulated-region-overview.module.ts b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/simulated-region-overview.module.ts
index b752dcb93..5f611040c 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/simulated-region-overview.module.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/simulated-region-overview.module.ts
@@ -50,6 +50,7 @@ import { SimulatedRegionOverviewVehiclesTabComponent } from './tabs/vehicles-tab
import { SimulatedRegionOverviewPatientsTableComponent } from './patients-table/simulated-region-overview-patients-table.component';
import { StartTransferService } from './start-transfer.service';
import { SimulatedRegionOverviewBehaviorTransferVehiclesComponent } from './tabs/behavior-tab/behaviors/transfer-vehicles/simulated-region-overview-behavior-transfer-vehicles.component';
+import { RadiogramCardContentTransferCountsComponent } from './radiogram-list/radiogram-card/radiogram-card-content-transfer-counts/radiogram-card-content-transfer-counts.component';
@NgModule({
declarations: [
@@ -90,6 +91,7 @@ import { SimulatedRegionOverviewBehaviorTransferVehiclesComponent } from './tabs
SimulatedRegionOverviewVehiclesTabComponent,
SimulatedRegionOverviewPatientsTableComponent,
SimulatedRegionOverviewBehaviorTransferVehiclesComponent,
+ RadiogramCardContentTransferCountsComponent,
],
imports: [
FormsModule,
diff --git a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/tabs/behavior-tab/behaviors/report/simulated-region-overview-behavior-report.component.ts b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/tabs/behavior-tab/behaviors/report/simulated-region-overview-behavior-report.component.ts
index 276fc1596..b61cbf4b5 100644
--- a/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/tabs/behavior-tab/behaviors/report/simulated-region-overview-behavior-report.component.ts
+++ b/frontend/src/app/pages/exercises/exercise/shared/simulated-region-overview/tabs/behavior-tab/behaviors/report/simulated-region-overview-behavior-report.component.ts
@@ -43,6 +43,7 @@ export class SimulatedRegionOverviewBehaviorReportComponent implements OnInit {
personnelCount: 'Anzahl an Rettungskräften',
materialCount: 'Anzahl an Material',
treatmentStatus: 'Behandlungsstatus',
+ transferCounts: 'Anzahl der ins Krankenhaus transportierten Patienten',
};
createReportCollapsed = true;
diff --git a/shared/src/models/radiogram/exercise-radiogram.ts b/shared/src/models/radiogram/exercise-radiogram.ts
index 1ac3e1fc1..492d61208 100644
--- a/shared/src/models/radiogram/exercise-radiogram.ts
+++ b/shared/src/models/radiogram/exercise-radiogram.ts
@@ -8,6 +8,7 @@ import { Radiogram } from './radiogram';
import { TreatmentStatusRadiogram } from './treatment-status-radiogram';
import { VehicleCountRadiogram } from './vehicle-count-radiogram';
import { ResourceRequestRadiogram } from './resource-request-radiogram';
+import { TransferCountsRadiogram } from './transfer-counts-radiogram';
export const radiograms = {
MaterialCountRadiogram,
@@ -15,6 +16,7 @@ export const radiograms = {
PatientCountRadiogram,
PersonnelCountRadiogram,
ResourceRequestRadiogram,
+ TransferCountsRadiogram,
TreatmentStatusRadiogram,
VehicleCountRadiogram,
};
@@ -33,6 +35,7 @@ export const radiogramDictionary: ExerciseRadiogramDictionary = {
patientCountRadiogram: PatientCountRadiogram,
personnelCountRadiogram: PersonnelCountRadiogram,
resourceRequestRadiogram: ResourceRequestRadiogram,
+ transferCountsRadiogram: TransferCountsRadiogram,
treatmentStatusRadiogram: TreatmentStatusRadiogram,
vehicleCountRadiogram: VehicleCountRadiogram,
};
diff --git a/shared/src/models/radiogram/index.ts b/shared/src/models/radiogram/index.ts
index dfea8ddf1..01d5f969a 100644
--- a/shared/src/models/radiogram/index.ts
+++ b/shared/src/models/radiogram/index.ts
@@ -8,3 +8,5 @@ export * from './treatment-status-radiogram';
export * from './vehicle-count-radiogram';
export * from './resource-request-radiogram';
export * from './status';
+export * from './transfer-counts-radiogram';
+export * from './utils';
diff --git a/shared/src/models/radiogram/transfer-counts-radiogram.ts b/shared/src/models/radiogram/transfer-counts-radiogram.ts
new file mode 100644
index 000000000..265f898e1
--- /dev/null
+++ b/shared/src/models/radiogram/transfer-counts-radiogram.ts
@@ -0,0 +1,77 @@
+import { IsBoolean, IsUUID, ValidateNested } from 'class-validator';
+import { UUID, uuidValidationOptions } from '../../utils';
+import { IsLiteralUnion, IsValue } from '../../utils/validators';
+import { IsRadiogramStatus } from '../../utils/validators/is-radiogram-status';
+import type { PatientStatus } from '../utils';
+import { getCreate } from '../utils';
+import { ResourceDescription } from '../utils/resource-description';
+import { IsResourceDescription } from '../../utils/validators/is-resource-description';
+import type { Radiogram } from './radiogram';
+import { ExerciseRadiogramStatus } from './status/exercise-radiogram-status';
+import { Scope, scopeAllowedValues } from './utils/scope';
+
+export class TransferCountsRadiogram implements Radiogram {
+ @IsUUID(4, uuidValidationOptions)
+ readonly id: UUID;
+
+ @IsValue('transferCountsRadiogram')
+ readonly type = 'transferCountsRadiogram';
+
+ @IsUUID(4, uuidValidationOptions)
+ readonly simulatedRegionId: UUID;
+
+ /**
+ * @deprecated use the helpers from {@link radiogram-helpers.ts}
+ * or {@link radiogram-helpers-mutable.ts} instead
+ */
+ @IsRadiogramStatus()
+ @ValidateNested()
+ readonly status: ExerciseRadiogramStatus;
+
+ @IsBoolean()
+ readonly informationAvailable: boolean = false;
+
+ @IsResourceDescription()
+ readonly transferredPatientsCounts: ResourceDescription = {
+ red: 0,
+ yellow: 0,
+ green: 0,
+ blue: 0,
+ black: 0,
+ white: 0,
+ };
+
+ @IsResourceDescription()
+ readonly remainingPatientsCounts: ResourceDescription = {
+ red: 0,
+ yellow: 0,
+ green: 0,
+ blue: 0,
+ black: 0,
+ white: 0,
+ };
+
+ /**
+ * Defines the scope of the counts reported with this radiogram.
+ * * `singleRegion`: The patient counts refer only to the simulated region that sent the radiogram
+ * * `transportManagement`: The patient counts refer to all simulated regions
+ * that are managed by the transport management behavior of the simulated region that sent the radiogram
+ */
+ @IsLiteralUnion(scopeAllowedValues)
+ readonly scope: Scope = 'singleRegion';
+
+ /**
+ * @deprecated Use {@link create} instead
+ */
+ constructor(
+ id: UUID,
+ simulatedRegionId: UUID,
+ status: ExerciseRadiogramStatus
+ ) {
+ this.id = id;
+ this.simulatedRegionId = simulatedRegionId;
+ this.status = status;
+ }
+
+ static readonly create = getCreate(this);
+}
diff --git a/shared/src/models/radiogram/utils/index.ts b/shared/src/models/radiogram/utils/index.ts
new file mode 100644
index 000000000..4f041b0c7
--- /dev/null
+++ b/shared/src/models/radiogram/utils/index.ts
@@ -0,0 +1 @@
+export * from './scope';
diff --git a/shared/src/models/radiogram/utils/scope.ts b/shared/src/models/radiogram/utils/scope.ts
new file mode 100644
index 000000000..8bb06460f
--- /dev/null
+++ b/shared/src/models/radiogram/utils/scope.ts
@@ -0,0 +1,8 @@
+import type { AllowedValues } from '../../../utils/validators';
+
+export type Scope = 'singleRegion' | 'transportManagement';
+
+export const scopeAllowedValues: AllowedValues = {
+ singleRegion: true,
+ transportManagement: true,
+};
diff --git a/shared/src/simulation/behaviors/utils.ts b/shared/src/simulation/behaviors/utils.ts
index 679d24ff0..b5fcd1157 100644
--- a/shared/src/simulation/behaviors/utils.ts
+++ b/shared/src/simulation/behaviors/utils.ts
@@ -1,3 +1,4 @@
+import { TransferCountsRadiogram } from '../../models/radiogram';
import type { ExerciseRadiogram } from '../../models/radiogram/exercise-radiogram';
import { MaterialCountRadiogram } from '../../models/radiogram/material-count-radiogram';
import { PatientCountRadiogram } from '../../models/radiogram/patient-count-radiogram';
@@ -14,6 +15,7 @@ export const reportableInformationAllowedValues: AllowedValues