Ki Prompt Button eingefügt
This commit is contained in:
@@ -423,287 +423,460 @@
|
||||
|
||||
using(Html.BeginForm("CreateOrUpdateServiceRecord", "Main", FormMethod.Post, new { id = "singleBookingForm" }))
|
||||
{
|
||||
<div>
|
||||
@* ----- Einzelbuchung: Mitarbeiter ----- *@
|
||||
<div class="form-row">
|
||||
<div class="col-md">
|
||||
<div class="mt-2" id="single-booking-employee-container">
|
||||
@Html.PopupWithSearchForIFilterables(Model.Employees, "setSelectedEmployeeForSingleBooking", null, Model.SelectedEmployee?.DetailDescription, "single-booking-employee-modal-popup", false)
|
||||
|
||||
@{
|
||||
var sbEmployeeInputValue = string.Empty;
|
||||
|
||||
if(Model.SelectedEmployee?.EmployeeOid is not null)
|
||||
{
|
||||
sbEmployeeInputValue = $"value=\"{Model.SelectedEmployee.EmployeeOid}\"";
|
||||
}
|
||||
}
|
||||
|
||||
<input type="hidden" id="sb-employee-input" onchange="window.updateEmployeeOids('sb', $(this).val())" @sbEmployeeInputValue />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* ----- Einzelbuchung: Ziele ----- *@
|
||||
@if(Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any())
|
||||
{
|
||||
<div>
|
||||
@* ----- Einzelbuchung: Mitarbeiter ----- *@
|
||||
<div class="form-row">
|
||||
<div class="col-md mt-2">
|
||||
<div class="card w-100">
|
||||
<div class="card-header py-0" onclick="cardHeaderClick2(this)">
|
||||
<div class="d-inline-flex">
|
||||
<i class="fas @Html.GetCollapsibleChevron(Model, "goals-container") h-100 text-dark"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex h-100">
|
||||
<button type="button" class="btn btn-link text-dark">
|
||||
Ziele
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse @Html.GetCollapsibleClass(Model.Collapsibles2IsShown, "goals-container")" id="goals-container">
|
||||
<div class="card-body p-1">
|
||||
<div class="input-group input-group-sm mb-1">
|
||||
<input type="text" class="form-control" placeholder="Suchen ..." id="goal-search-input" oninput="goalTreeSearchOnChangeV2($(this))" />
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="resetGoalTreeSearch()">
|
||||
<span class="fas fa-times-circle"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm mb-1 w-100" role="group">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="window.showAllGoals()">Alle auf</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="window.hideAllGoals()">Alle zu</button>
|
||||
</div>
|
||||
<div class="container p-0 m-0" id="goals-tree">
|
||||
@Html.Partial("GoalTreePartial", Model)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="col-md">
|
||||
<div class="mt-2" id="single-booking-employee-container">
|
||||
@Html.PopupWithSearchForIFilterables(Model.Employees, "setSelectedEmployeeForSingleBooking", null, Model.SelectedEmployee?.DetailDescription, "single-booking-employee-modal-popup", false)
|
||||
|
||||
@* ----- Einzelbuchung: Kategorie & Leistung ----- *@
|
||||
<div id="category-to-description-container">
|
||||
@Html.Partial("Category2ServiceDescriptionPartial", Model)
|
||||
</div>
|
||||
@{
|
||||
var sbEmployeeInputValue = string.Empty;
|
||||
|
||||
@* ----- Marker ----- *@
|
||||
@if(Model.ShowMarker)
|
||||
{
|
||||
var markerCheckedValue = Model.SelectedServiceRecord?.ServiceRecordType == ServiceRecordTypeId.Content ? "checked" : string.Empty;
|
||||
if (Model.SelectedEmployee?.EmployeeOid is not null)
|
||||
{
|
||||
sbEmployeeInputValue = $"value=\"{Model.SelectedEmployee.EmployeeOid}\"";
|
||||
}
|
||||
}
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-md mt-1">
|
||||
<div class=" custom-control custom-checkbox custom-control-inline my-0">
|
||||
<input type="checkbox" class="custom-control-input" onchange="window.updateMarker('sb', $(this).val());" name="@FormCollectionConstants.MarkerKey" id="sb-marker-cb" @markerCheckedValue />
|
||||
<label class="custom-control-label" for="sb-marker-cb">Marker</label>
|
||||
<input type="hidden" id="sb-employee-input" onchange="window.updateEmployeeOids('sb', $(this).val())" @sbEmployeeInputValue />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* ----- Betrag ----- *@
|
||||
@if(Model.ShowBetrag)
|
||||
{
|
||||
var betrag = string.Empty;
|
||||
if(Model.SelectedServiceRecord?.Betrag is > 0)
|
||||
@* ----- Einzelbuchung: Ziele ----- *@
|
||||
@if (Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any())
|
||||
{
|
||||
betrag = Model.SelectedServiceRecord.Betrag.Value.ToString("#.00");
|
||||
}
|
||||
|
||||
<div class="form-row mt-1">
|
||||
<div class="col-md">
|
||||
<div class="form-group my-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text prepend-input-group-text">
|
||||
Betrag
|
||||
<div class="form-row">
|
||||
<div class="col-md mt-2">
|
||||
<div class="card w-100">
|
||||
<div class="card-header py-0" onclick="cardHeaderClick2(this)">
|
||||
<div class="d-inline-flex">
|
||||
<i class="fas @Html.GetCollapsibleChevron(Model, "goals-container") h-100 text-dark"></i>
|
||||
</div>
|
||||
<div class="d-inline-flex h-100">
|
||||
<button type="button" class="btn btn-link text-dark">
|
||||
Ziele
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<input class="form-control" autocomplete="on" onchange="window.updateBetrag('sb', $(this).val())" type="text" id="sb-betrag" name="betrag" value="@betrag" />
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">€</div>
|
||||
<div class="collapse @Html.GetCollapsibleClass(Model.Collapsibles2IsShown, "goals-container")" id="goals-container">
|
||||
<div class="card-body p-1">
|
||||
<div class="input-group input-group-sm mb-1">
|
||||
<input type="text" class="form-control" placeholder="Suchen ..." id="goal-search-input" oninput="goalTreeSearchOnChangeV2($(this))" />
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="resetGoalTreeSearch()">
|
||||
<span class="fas fa-times-circle"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm mb-1 w-100" role="group">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="window.showAllGoals()">Alle auf</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="window.hideAllGoals()">Alle zu</button>
|
||||
</div>
|
||||
<div class="container p-0 m-0" id="goals-tree">
|
||||
@Html.Partial("GoalTreePartial", Model)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* ----- Einzelbuchung: Kategorie & Leistung ----- *@
|
||||
<div id="category-to-description-container">
|
||||
@Html.Partial("Category2ServiceDescriptionPartial", Model)
|
||||
</div>
|
||||
}
|
||||
|
||||
<hr class="mt-2 mb-0" />
|
||||
|
||||
@* ----- Einzelbuchung: Startdatum und gegebenenfalls Enddatum ----- *@
|
||||
@{
|
||||
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
|
||||
var durationValue = Model.DurationToEdit;
|
||||
|
||||
var afterValidationState = TempData[TempDataConstants.AfterValidationStateKey];
|
||||
|
||||
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode && afterValidationState is false)
|
||||
@* ----- Marker ----- *@
|
||||
@if (Model.ShowMarker)
|
||||
{
|
||||
durationValue = Model.NewDuration?.ToString();
|
||||
if(Model.NewDuration.HasValue)
|
||||
var markerCheckedValue = Model.SelectedServiceRecord?.ServiceRecordType == ServiceRecordTypeId.Content ? "checked" : string.Empty;
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-md mt-1">
|
||||
<div class=" custom-control custom-checkbox custom-control-inline my-0">
|
||||
<input type="checkbox" class="custom-control-input" onchange="window.updateMarker('sb', $(this).val());" name="@FormCollectionConstants.MarkerKey" id="sb-marker-cb" @markerCheckedValue />
|
||||
<label class="custom-control-label" for="sb-marker-cb">Marker</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* ----- Betrag ----- *@
|
||||
@if (Model.ShowBetrag)
|
||||
{
|
||||
var betrag = string.Empty;
|
||||
if (Model.SelectedServiceRecord?.Betrag is > 0)
|
||||
{
|
||||
durationValue = (Model.NewDuration / divisor).ToString();
|
||||
betrag = Model.SelectedServiceRecord.Betrag.Value.ToString("#.00");
|
||||
}
|
||||
|
||||
<div class="form-row mt-1">
|
||||
<div class="col-md">
|
||||
<div class="form-group my-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text prepend-input-group-text">
|
||||
Betrag
|
||||
</div>
|
||||
</div>
|
||||
<input class="form-control" autocomplete="on" onchange="window.updateBetrag('sb', $(this).val())" type="text" id="sb-betrag" name="betrag" value="@betrag" />
|
||||
<div class="input-group-append">
|
||||
<div class="input-group-text">€</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
var columnWidth = Model.IsEndDateVisible ? "col-md-6" : "col";
|
||||
}
|
||||
<hr class="mt-2 mb-0" />
|
||||
|
||||
<div class="form-row">
|
||||
<div class="@columnWidth mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text prepend-input-group-text">
|
||||
Startdatum
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" type="date" name="Datum" id="sb-start-date-input" onchange="calcDuration('sb', false, true, false); window.updateStartDate('sb', $(this).val());" value="@Model.StartDateToEditJSFormat" />
|
||||
</div>
|
||||
</div>
|
||||
@if(Model.IsEndDateVisible)
|
||||
{
|
||||
<div class="col-md-6 mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text prepend-input-group-text">
|
||||
Enddatum
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" type="date" name="Enddatum" id="sb-end-date-input" onchange="calcDuration('sb', false, false, true); window.updateEndDate('sb', $(this).val());" value="@Model.EndDateToEditJSFormat" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@* ----- Einzelbuchung: Startdatum und gegebenenfalls Enddatum ----- *@
|
||||
@{
|
||||
var von = Model.IsInTransferMode || Model.IsInEditingMode || afterValidationState is true ? Model.StartTimeToEdit : Model.NewStartTime;
|
||||
var bis = Model.IsInTransferMode || Model.IsInEditingMode || afterValidationState is true ? Model.EndTimeToEdit : Model.NewEndTime;
|
||||
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
|
||||
var durationValue = Model.DurationToEdit;
|
||||
|
||||
var x = von;
|
||||
var afterValidationState = TempData[TempDataConstants.AfterValidationStateKey];
|
||||
|
||||
if (Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode && afterValidationState is false)
|
||||
{
|
||||
durationValue = Model.NewDuration?.ToString();
|
||||
if (Model.NewDuration.HasValue)
|
||||
{
|
||||
durationValue = (Model.NewDuration / divisor).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
var columnWidth = Model.IsEndDateVisible ? "col-md-6" : "col";
|
||||
}
|
||||
<div class="col mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
Von
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" type="time" name="Start" id="sb-start-time-input" onchange="calcDuration('sb', false, true, false);window.updateStartTime('sb', $(this).val());" value="@von"/>
|
||||
<span class="input-group-text rounded-0 border-left-0 border-right-0">
|
||||
Bis
|
||||
</span>
|
||||
<input class="form-control" type="time" name="Ende" id="sb-end-time-input" onchange="calcDuration('sb', false, false, true);window.updateEndTime('sb', $(this).val());" value="@bis"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* ----- Einzelbuchung: Dauer ----- *@
|
||||
<div class="form-row mt-2">
|
||||
<div class="col-md">
|
||||
<div class="form-group my-0">
|
||||
<div class="form-row">
|
||||
<div class="@columnWidth mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
@{
|
||||
var labelText = Model.EinheitZeiterfassung == 1 ? "Dauer (h)" : "Dauer";
|
||||
}
|
||||
<div class="input-group-text prepend-input-group-text" id="sb-duration-label">
|
||||
@labelText
|
||||
</div>
|
||||
<span class="input-group-text prepend-input-group-text">
|
||||
Startdatum
|
||||
</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="sb-duration-input" name="Dauer" onchange="beiDaueraenderung('sb'); window.updateDuration('sb', $(this).val());" value="@durationValue">
|
||||
@if(Model.IsZeiterfassungInStdMin)
|
||||
{
|
||||
<div class="input-group-append">
|
||||
<button id="sb-hours-minutes-dropdown-btn" class="btn btn-outline-primary dropdown-toggle w-100" type="button" data-toggle="dropdown">
|
||||
@Model.SelectedDurationUnit
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item hours-minutes-link" href="#">Minuten</a>
|
||||
<a class="dropdown-item hours-minutes-link" href="#">Stunden</a>
|
||||
</div>
|
||||
<input class="form-control" type="date" name="Datum" id="sb-start-date-input" onchange="calcDuration('sb', false, true, false); window.updateStartDate('sb', $(this).val());" value="@Model.StartDateToEditJSFormat" />
|
||||
</div>
|
||||
</div>
|
||||
@if (Model.IsEndDateVisible)
|
||||
{
|
||||
<div class="col-md-6 mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text prepend-input-group-text">
|
||||
Enddatum
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
<input class="form-control" type="date" name="Enddatum" id="sb-end-date-input" onchange="calcDuration('sb', false, false, true); window.updateEndDate('sb', $(this).val());" value="@Model.EndDateToEditJSFormat" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-row">
|
||||
@{
|
||||
var von = Model.IsInTransferMode || Model.IsInEditingMode || afterValidationState is true ? Model.StartTimeToEdit : Model.NewStartTime;
|
||||
var bis = Model.IsInTransferMode || Model.IsInEditingMode || afterValidationState is true ? Model.EndTimeToEdit : Model.NewEndTime;
|
||||
|
||||
var x = von;
|
||||
}
|
||||
<div class="col mt-2">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
Von
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" type="time" name="Start" id="sb-start-time-input" onchange="calcDuration('sb', false, true, false);window.updateStartTime('sb', $(this).val());" value="@von" />
|
||||
<span class="input-group-text rounded-0 border-left-0 border-right-0">
|
||||
Bis
|
||||
</span>
|
||||
<input class="form-control" type="time" name="Ende" id="sb-end-time-input" onchange="calcDuration('sb', false, false, true);window.updateEndTime('sb', $(this).val());" value="@bis" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@* ----- Einzelbuchung: Distanz ----- *@
|
||||
@if(Model.ShowDistanceField)
|
||||
{
|
||||
@* ----- Einzelbuchung: Dauer ----- *@
|
||||
<div class="form-row mt-2">
|
||||
<div class="col-md">
|
||||
<div class="form-group my-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">
|
||||
Gefahrene Kilometer
|
||||
@{
|
||||
var labelText = Model.EinheitZeiterfassung == 1 ? "Dauer (h)" : "Dauer";
|
||||
}
|
||||
<div class="input-group-text prepend-input-group-text" id="sb-duration-label">
|
||||
@labelText
|
||||
</div>
|
||||
</div>
|
||||
<input class="form-control" autocomplete="on" id="sb-distance-input" name="Distanz" onchange="validateDistanceInput(); window.updateDistance('sb', $(this).val());" value="@Model.DistanceToEdit">
|
||||
<input type="text" class="form-control" id="sb-duration-input" name="Dauer" onchange="beiDaueraenderung('sb'); window.updateDuration('sb', $(this).val());" value="@durationValue">
|
||||
@if (Model.IsZeiterfassungInStdMin)
|
||||
{
|
||||
<div class="input-group-append">
|
||||
<button id="sb-hours-minutes-dropdown-btn" class="btn btn-outline-primary dropdown-toggle w-100" type="button" data-toggle="dropdown">
|
||||
@Model.SelectedDurationUnit
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item hours-minutes-link" href="#">Minuten</a>
|
||||
<a class="dropdown-item hours-minutes-link" href="#">Stunden</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* ----- Einzelbuchung: Textbausteine ----- *@
|
||||
@if(Model.HasRightToSeeTextModules)
|
||||
{
|
||||
<script type="text/javascript">
|
||||
@* ----- Einzelbuchung: Distanz ----- *@
|
||||
@if (Model.ShowDistanceField)
|
||||
{
|
||||
<div class="form-row mt-2">
|
||||
<div class="col-md">
|
||||
<div class="form-group my-0">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">
|
||||
Gefahrene Kilometer
|
||||
</div>
|
||||
</div>
|
||||
<input class="form-control" autocomplete="on" id="sb-distance-input" name="Distanz" onchange="validateDistanceInput(); window.updateDistance('sb', $(this).val());" value="@Model.DistanceToEdit">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* ----- Einzelbuchung: Textbausteine ----- *@
|
||||
@if (Model.HasRightToSeeTextModules)
|
||||
{
|
||||
<script type="text/javascript">
|
||||
function textModuleButtonOnClick() {
|
||||
$('#tree').load('@Url.Action("LoadUpToDateTextModules")');
|
||||
}
|
||||
</script>
|
||||
<div class="form-row mt-2" id="textmodule-container">
|
||||
<div class="col-md">
|
||||
<button type="button" class="btn btn-primary form-control" data-toggle="modal" data-target="#textbausteine-popup" id="sb-textbausteine-btn" onclick="textModuleButtonOnClick()">Textbausteine</button>
|
||||
</script>
|
||||
<div class="form-row mt-2" id="textmodule-container">
|
||||
<div class="col-md">
|
||||
<button type="button" class="btn btn-primary form-control" data-toggle="modal" data-target="#textbausteine-popup" id="sb-textbausteine-btn" onclick="textModuleButtonOnClick()">Textbausteine</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@* ----- Einzelbuchung: KI Funktionen ----- *@
|
||||
@if (Model.HasRightToSeeAiPromptsInZeiterfassung)
|
||||
{
|
||||
<script type="text/javascript">
|
||||
|
||||
</script>
|
||||
<div class="form-row mt-2" id="aifunction-container">
|
||||
<div class="col-md">
|
||||
@if (Model.HasRightToUseAiVoice)
|
||||
{
|
||||
<button type="button" class="btn btn-primary float-right mr-1" id="aivoice-button" onclick="startExternalCall();" title="KI-Spracheingabe & Transkription" style="padding: 0 0.6em; overflow: hidden; line-height: 0;"><img src="@Url.Content("~/Content/images/Icon_Mikro_Weiss.png")" alt="KI-Spracheingabe & Transkription" style="height:2.25em; display: block;" /></button>
|
||||
}
|
||||
<button type="button" class="btn btn-primary float-right mr-1" id="aiprompt-btn" style="padding: 0 0.6em; overflow: hidden; line-height: 0;"><img src="@Url.Content("~/Content/images/Icon_KI_Funktion_Weiss+Gruen.png")" alt="KI-Promptbausteine auswählen" style="height:2.25em; display: block;" /></button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- KI-Promptbausteine Modal -->
|
||||
<div class="modal fade" id="aiprompt-modal" tabindex="-1" role="dialog" aria-labelledby="aiprompt-modal-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="aiprompt-modal-title">KI-Promptbausteine auswählen</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Schließen">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row" style="min-height: 350px;">
|
||||
<div class="col-md-5 border-right" id="aiprompt-tree-col">
|
||||
<div id="aiprompt-tree" style="overflow-y: auto; max-height: 400px;">
|
||||
<div class="text-muted small p-2">Wird geladen…</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7" id="aiprompt-prompts-col">
|
||||
<div id="aiprompt-prompts-list">
|
||||
<div class="text-muted small p-2">Bitte einen Ordner auswählen.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Schließen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
function buildTree(folders, container, level) {
|
||||
folders.forEach(function (folder) {
|
||||
var indent = level * 16;
|
||||
var item = $('<div class="aiprompt-folder-item" style="cursor:pointer; padding: 4px 6px; border-radius:4px; margin-bottom:2px;">'
|
||||
+ '<span style="display:inline-block; width:' + indent + 'px;"></span>'
|
||||
+ '<span class="aiprompt-folder-toggle mr-1" style="display:inline-block; width:14px;">'
|
||||
+ (folder.SubFolders && folder.SubFolders.length > 0 ? '▶' : ' ')
|
||||
+ '</span>'
|
||||
+ '<span class="aiprompt-folder-label"><strong>' + $('<div>').text(folder.Title).html() + '</strong></span>'
|
||||
+ '</div>');
|
||||
|
||||
var subContainer = null;
|
||||
if (folder.SubFolders && folder.SubFolders.length > 0) {
|
||||
subContainer = $('<div class="aiprompt-subfolders" style="display:none;"></div>');
|
||||
buildTree(folder.SubFolders, subContainer, level + 1);
|
||||
}
|
||||
|
||||
item.on('click', function (e) {
|
||||
e.stopPropagation();
|
||||
$('.aiprompt-folder-item').removeClass('bg-primary text-white').css('color', '');
|
||||
item.addClass('bg-primary text-white');
|
||||
|
||||
if (subContainer) {
|
||||
var expanded = subContainer.is(':visible');
|
||||
subContainer.toggle(!expanded);
|
||||
item.find('.aiprompt-folder-toggle').html(expanded ? '▶' : '▼');
|
||||
}
|
||||
|
||||
showPrompts(folder.SubPrompts || []);
|
||||
});
|
||||
|
||||
container.append(item);
|
||||
if (subContainer) container.append(subContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function showPrompts(prompts) {
|
||||
var list = $('#aiprompt-prompts-list').empty();
|
||||
if (!prompts || prompts.length === 0) {
|
||||
list.html('<div class="text-muted small p-2">Keine Prompts in diesem Ordner.</div>');
|
||||
return;
|
||||
}
|
||||
prompts.forEach(function (p) {
|
||||
var card = $('<div class="card mb-2" style="cursor:pointer;"></div>');
|
||||
var body = $('<div class="card-body p-2"></div>');
|
||||
body.append($('<h6 class="card-title mb-1"></h6>').text(p.Title));
|
||||
if (p.Description) body.append($('<p class="card-text small text-muted mb-0"></p>').text(p.Description));
|
||||
card.append(body);
|
||||
card.on('click', function () {
|
||||
if (p.Oid == null) return;
|
||||
// Prompt server-seitig ausführen und Ergebnis ins Doku-Feld schreiben
|
||||
var $card = $(this);
|
||||
$('#aiprompt-prompts-list .card').css('pointer-events', 'none').css('opacity', '0.5');
|
||||
$card.css('opacity', '1').append(
|
||||
'<div class="aiprompt-loading text-muted small mt-1">'
|
||||
+ '<span class="spinner-border spinner-border-sm mr-1"></span>Wird ausgeführt …</div>');
|
||||
$.ajax({
|
||||
url: '@Url.Action("StartPrompt", "Main")',
|
||||
type: 'POST',
|
||||
data: { promptOid: p.Oid },
|
||||
success: function (resp) {
|
||||
$('#aiprompt-modal').modal('hide');
|
||||
var text = resp && resp.text ? resp.text : '';
|
||||
var activeTextarea = $('textarea:visible:first[id^="sb-doku-textarea"]');
|
||||
if (activeTextarea.length && text) {
|
||||
var current = activeTextarea.val();
|
||||
activeTextarea.val(current ? current + '\n' + text : text).trigger('change');
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
var msg = 'Fehler beim Ausführen des Prompts.';
|
||||
try {
|
||||
var r = JSON.parse(xhr.responseText);
|
||||
if (r && r.message) msg += '\n' + r.message;
|
||||
} catch (e) { }
|
||||
console.error('StartPrompt Fehler:', xhr.status, xhr.responseText);
|
||||
$('.aiprompt-loading').remove();
|
||||
$('#aiprompt-prompts-list .card').css('pointer-events', '').css('opacity', '');
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
list.append(card);
|
||||
});
|
||||
}
|
||||
|
||||
var dataLoaded = false;
|
||||
|
||||
$('#aiprompt-btn').on('click', function () {
|
||||
$('#aiprompt-modal').modal('show');
|
||||
if (dataLoaded) return;
|
||||
$.ajax({
|
||||
url: '@Url.Action("GetAiPromptbausteinFolder", "Main")',
|
||||
type: 'GET',
|
||||
success: function (data) {
|
||||
dataLoaded = true;
|
||||
var tree = $('#aiprompt-tree').empty();
|
||||
if (!data || data.length === 0) {
|
||||
tree.html('<div class="text-muted small p-2">Keine Ordner verfügbar.</div>');
|
||||
return;
|
||||
}
|
||||
buildTree(data, tree, 0);
|
||||
},
|
||||
error: function (xhr, textStatus, errorThrown) {
|
||||
var details = 'Status: ' + xhr.status + ' ' + (xhr.statusText || '')
|
||||
+ '\ntextStatus: ' + textStatus
|
||||
+ '\nerror: ' + errorThrown;
|
||||
if (xhr.responseText) {
|
||||
details += '\n\nAntwort:\n' + xhr.responseText.substring(0, 4000);
|
||||
}
|
||||
console.error('GetAiPromptbausteinFolder Fehler:', details);
|
||||
$('#aiprompt-tree').html(
|
||||
'<div class="text-danger small p-2">Fehler beim Laden der Promptbausteine.<br/>'
|
||||
+ '<pre style="white-space:pre-wrap; font-size:11px; max-height:320px; overflow:auto;">'
|
||||
+ $('<div>').text(details).html()
|
||||
+ '</pre></div>');
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
@* ----- Einzelbuchung: Dokumentation ----- *@
|
||||
<div class="form-row">
|
||||
<div class="col-md mt-3">
|
||||
@if (Model.NumberOfDokuTypes == 0)
|
||||
{
|
||||
<div class="form-group my-0">
|
||||
<label for="sb-doku-textarea-5">Dokumentation</label>
|
||||
<textarea class="form-control" autocomplete="on" style="overflow: scroll;" onchange="window.updateDokuText('sb', $(this).val(), 5)" name="Dokumentation6" id="sb-doku-textarea-5">@Model.NoticeToEdit</textarea>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul class="nav nav-tabs" role="tab-list">
|
||||
@for (var i = 0; i < Model.Dokutypes.Length; i++)
|
||||
{
|
||||
var currentDokuType = Model.Dokutypes[i];
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="#sb-doku_@i" id="sb-doku_@i-tab" onchange="window.updateDokuText('sb', $(this).val(), @i)" data-toggle="tab" role="tab" class="nav-link@(i == 0 ? " active" : string.Empty)">
|
||||
@currentDokuType.DisplayName
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content" id="dokufelderTab">
|
||||
@for (var i = 0; i < Model.Dokutypes.Length; i++)
|
||||
{
|
||||
var textareaName = i + 1 < 1 ? "Dokumentation" : "Dokumentation" + (i + 1);
|
||||
|
||||
<div class="tab-pane show@(i == 0 ? " active" : string.Empty)" id="sb-doku_@i" role="tabpanel">
|
||||
<textarea class="form-control doku-form-control" onchange="window.updateDokuText('sb', $(this).val(), @i)" autocomplete="on" style="overflow: scroll;" id="sb-doku-textarea-@i" name="@textareaName">@Model.NoticeListToEdit[i]</textarea>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@* ----- Einzelbuchung: Dokumentation ----- *@
|
||||
<div class="form-row">
|
||||
<div class="col-md mt-3">
|
||||
@if(Model.NumberOfDokuTypes == 0)
|
||||
{
|
||||
<div class="form-group my-0">
|
||||
<label for="sb-doku-textarea-5">Dokumentation</label>
|
||||
<textarea class="form-control" autocomplete="on" style="overflow: scroll;" onchange="window.updateDokuText('sb', $(this).val(), 5)" name="Dokumentation6" id="sb-doku-textarea-5">@Model.NoticeToEdit</textarea>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<ul class="nav nav-tabs" role="tab-list">
|
||||
@for(var i = 0; i < Model.Dokutypes.Length; i++)
|
||||
{
|
||||
var currentDokuType = Model.Dokutypes[i];
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="#sb-doku_@i" id="sb-doku_@i-tab" onchange="window.updateDokuText('sb', $(this).val(), @i)" data-toggle="tab" role="tab" class="nav-link@(i == 0 ? " active" : string.Empty)">
|
||||
@currentDokuType.DisplayName
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content" id="dokufelderTab">
|
||||
@for(var i = 0; i < Model.Dokutypes.Length; i++)
|
||||
{
|
||||
var textareaName = i + 1 < 1 ? "Dokumentation" : "Dokumentation" + (i + 1);
|
||||
|
||||
<div class="tab-pane show@(i == 0 ? " active" : string.Empty)" id="sb-doku_@i" role="tabpanel">
|
||||
<textarea class="form-control doku-form-control" onchange="window.updateDokuText('sb', $(this).val(), @i)" autocomplete="on" style="overflow: scroll;" id="sb-doku-textarea-@i" name="@textareaName">@Model.NoticeListToEdit[i]</textarea>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="w-100 mt-2">
|
||||
@@ -727,12 +900,7 @@
|
||||
{
|
||||
<button type="button" class="btn btn-primary float-right" id="reset-button" onclick="resetSingleBookingForm();">Abbrechen</button>
|
||||
}
|
||||
|
||||
@if (Model.HasRightToUseAiVoice)
|
||||
{
|
||||
<button type="button" class="btn btn-primary float-right mr-1" id="aivoice-button" onclick="startExternalCall();" title="KI-Spracheingabe & Transkription" style="padding: 0 0.6em; overflow: hidden; line-height: 0;"><img src="@Url.Content("~/Content/images/Icon_Mikro_Weiss.png")" alt="KI-Spracheingabe & Transkription" style="height:2.25em; display: block;" /></button>
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Html.Partial("RestoreServiceRecordInputsPartial", Model)
|
||||
|
||||
Reference in New Issue
Block a user