10.April 2026

This commit is contained in:
Kevin Adametz 2026-04-10 17:15:27 +02:00
parent a00c42e770
commit f58c709945
208 changed files with 19280 additions and 2914 deletions

View file

@ -0,0 +1,111 @@
@php
$chartId = 'aboChart_' . str_replace('.', '', microtime(true));
$chartDataJson = json_encode(array_values($chartData));
$chartLabelsJson = json_encode(array_values($chartMonths));
$nonNullValues = array_filter($chartData, fn($v) => $v !== null);
$maxVal = count($nonNullValues) ? max($nonNullValues) : 0;
// Großzügige Schritte für die Y-Achse
if ($maxVal <= 5) { $stepSize = 1; }
elseif ($maxVal <= 10) { $stepSize = 2; }
elseif ($maxVal <= 20) { $stepSize = 5; }
elseif ($maxVal <= 50) { $stepSize = 10; }
elseif ($maxVal <= 100) { $stepSize = 20; }
elseif ($maxVal <= 200) { $stepSize = 50; }
elseif ($maxVal <= 500) { $stepSize = 100; }
elseif ($maxVal <= 1000) { $stepSize = 200; }
else { $stepSize = 500; }
// Genug Platz nach oben, damit das Label nicht abgeschnitten wird
$suggestedMax = $maxVal + $stepSize;
@endphp
<div class="card mb-4">
<div class="card-body pb-2">
<div class="d-flex justify-content-between align-items-center flex-wrap">
<h6 class="font-weight-bold mb-2">
{{ __('abo.chart_monthly_abos') }}
<span class="text-muted font-weight-normal ml-1">{{ $chartYear }}</span>
</h6>
<div class="mb-2">
@foreach($chartYears as $y)
<a href="{{ url()->current() }}?year={{ $y }}"
class="btn btn-xs btn-sm {{ $chartYear == $y ? 'btn-secondary' : 'btn-outline-secondary' }} mr-1 mb-1">
{{ $y }}
</a>
@endforeach
</div>
</div>
</div>
<hr class="m-0">
<div class="card-body pt-3 pb-2">
<canvas id="{{ $chartId }}" height="80"></canvas>
</div>
</div>
<script src="/vendor/libs/chartjs/chartjs.js"></script>
<script>
(function () {
// Inline data-labels plugin für Chart.js v2
var dataLabelsPlugin = {
afterDatasetsDraw: function (chart) {
var ctx = chart.ctx;
chart.data.datasets.forEach(function (dataset, i) {
var meta = chart.getDatasetMeta(i);
if (meta.hidden) { return; }
meta.data.forEach(function (bar, index) {
var value = dataset.data[index];
if (value === null || value === undefined || value === 0) { return; }
ctx.save();
ctx.fillStyle = '#495057';
ctx.font = 'bold 11px -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText(value, bar._model.x, bar._model.y - 3);
ctx.restore();
});
});
}
};
var ctx = document.getElementById('{{ $chartId }}').getContext('2d');
new Chart(ctx, {
type: 'bar',
plugins: [dataLabelsPlugin],
data: {
labels: {!! $chartLabelsJson !!},
datasets: [{
label: '{{ __('abo.chart_active_abos') }}',
data: {!! $chartDataJson !!},
backgroundColor: 'rgba(102, 110, 232, 0.2)',
borderColor: 'rgba(102, 110, 232, 0.8)',
borderWidth: 1
}]
},
options: {
responsive: true,
legend: { display: false },
tooltips: { enabled: false },
layout: {
padding: { top: 20 }
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: {{ $stepSize }},
suggestedMax: {{ $suggestedMax }},
callback: function (value) {
return Number.isInteger(value) ? value : null;
}
},
gridLines: { color: 'rgba(0,0,0,0.05)' }
}],
xAxes: [{
gridLines: { display: false }
}]
}
}
});
}());
</script>

View file

@ -1,27 +1,39 @@
@extends('layouts.layout-2')
@section('content')
<h4 class="font-weight-bold py-2 mb-2">
<a href="{{route('user_abos', [$view])}}" class="btn btn-sm btn-default float-right">{{ __('back') }}</a>
<a href="{{ route('user_abos', [$view]) }}" class="btn btn-sm btn-default float-right">{{ __('back') }}</a>
<div>
@if($view === 'ot') {{ __('navigation.customerabo') }} @endif
@if($view === 'me') {{ __('navigation.myabo') }} @endif
<span class="text-muted">{{ '#'.$user_abo->payone_userid }}</span>
@if ($view === 'ot')
{{ __('navigation.customerabo') }}
@endif
@if ($view === 'me')
{{ __('navigation.myabo') }}
@endif
<span class="text-muted">{{ '#' . $user_abo->payone_userid }}</span>
</div>
</h4>
@if(Session::has('alert-error'))
<div class="col-sm-12">
<div class="alert alert-danger p-2 mt-2">
<ul>
<li>{{ Session::get('alert-error') }}</li>
</ul>
</div>
</div>
@endif
@if (Session::has('alert-error'))
<div class="col-sm-12">
<div class="alert alert-danger p-2 mt-2">
<ul>
<li>{{ Session::get('alert-error') }}</li>
</ul>
</div>
</div>
@endif
@if (Session::has('alert-warning'))
<div class="col-sm-12">
<div class="alert alert-warning p-2 mt-2">
<ul>
<li>{{ Session::get('alert-warning') }}</li>
</ul>
</div>
</div>
@endif
<div class="card">
@include('admin.abo._detail')
</div>
@ -34,13 +46,18 @@
@php
$addOnlyMode = App\Services\AboHelper::isAddOnlyMode($user_abo, $view);
@endphp
{!! Form::open(['action' => route('user_abos_update', [$view, $user_abo->id]), 'class' => 'form-horizontal', 'id'=>'cart-order-form', 'data-add-only-mode' => $addOnlyMode ? '1' : '0']) !!}
<input type="hidden" name="is_for" value="{{ $user_abo->is_for }}">
{!! Form::open([
'action' => route('user_abos_update', [$view, $user_abo->id]),
'class' => 'form-horizontal',
'id' => 'cart-order-form',
'data-add-only-mode' => $addOnlyMode ? '1' : '0',
]) !!}
<input type="hidden" name="is_for" value="{{ $user_abo->is_for }}">
<div class="card mt-3">
@include('admin.abo._order_abo', ['add_only_mode' => $addOnlyMode])
</div>
@if($comp_products && Yard::instance('shopping')->getNumComp() > 0)
@if ($comp_products && Yard::instance('shopping')->getNumComp() > 0)
<div id="holder_html_view_comp_product">
@include('user.order.comp_product')
</div>
@ -52,48 +69,49 @@
</div>
<a href="{{route('user_abos', [$view])}}" class="btn btn-sm btn-default float-right">{{ __('back') }}</a>
<a href="{{ route('user_abos', [$view]) }}" class="btn btn-sm btn-default float-right">{{ __('back') }}</a>
<div class="modal fade" id="modal-confirm-add" tabindex="-1" role="dialog" aria-labelledby="modal-confirm-add-label" aria-hidden="true"
data-title-add-only="{{ __('abo.confirm_add_title') }}"
data-title-normal="{{ __('abo.confirm_add_title_normal') }}"
data-warning-add-only="{{ __('abo.confirm_add_warning') }}"
data-warning-normal="{{ __('abo.confirm_add_warning_normal') }}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-confirm-add-label"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="alert alert-warning mb-3">
<i class="fa fa-exclamation-triangle"></i> <span id="confirm-add-warning-text"></span>
<div class="modal fade" id="modal-confirm-add" tabindex="-1" role="dialog" aria-labelledby="modal-confirm-add-label"
aria-hidden="true" data-title-add-only="{{ __('abo.confirm_add_title') }}"
data-title-normal="{{ __('abo.confirm_add_title_normal') }}"
data-warning-add-only="{{ __('abo.confirm_add_warning') }}"
data-warning-normal="{{ __('abo.confirm_add_warning_normal') }}">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-confirm-add-label"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="alert alert-warning mb-3">
<i class="fa fa-exclamation-triangle"></i> <span id="confirm-add-warning-text"></span>
</div>
<table class="table table-sm mb-0">
<tr>
<td class="font-weight-bold">{{ __('order.article') }}:</td>
<td id="confirm-add-product-name"></td>
</tr>
<tr>
<td class="font-weight-bold">{{ __('tables.price') }}:</td>
<td id="confirm-add-product-price"></td>
</tr>
<tr>
<td class="font-weight-bold">{{ __('tables.quantity') }}:</td>
<td id="confirm-add-qty-info"></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
data-dismiss="modal">{{ __('abo.confirm_add_cancel') }}</button>
<button type="button" class="btn btn-primary"
id="confirm-add-btn">{{ __('abo.confirm_add_ok') }}</button>
</div>
<table class="table table-sm mb-0">
<tr>
<td class="font-weight-bold">{{ __('order.article') }}:</td>
<td id="confirm-add-product-name"></td>
</tr>
<tr>
<td class="font-weight-bold">{{ __('tables.price') }}:</td>
<td id="confirm-add-product-price"></td>
</tr>
<tr>
<td class="font-weight-bold">{{ __('tables.quantity') }}:</td>
<td id="confirm-add-qty-info"></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ __('abo.confirm_add_cancel') }}</button>
<button type="button" class="btn btn-primary" id="confirm-add-btn">{{ __('abo.confirm_add_ok') }}</button>
</div>
</div>
</div>
</div>
@endsection
@section('scripts')
@ -105,4 +123,4 @@
</script>
@endsection
@endsection

View file

@ -9,6 +9,10 @@
</div>
</h4>
@if(isset($chartData))
@include('user.abo._abo_chart')
@endif
<div class="row">
<div class="col-12">
@ -82,8 +86,13 @@
{{ $user_abo->getCountOrders() }}
</div>
<div class="col-md-3 mb-3">
<div class="text-muted small">{{ __('tables.amount') }}</div>
{{ $user_abo->getFormattedAmount() }}
@if($view === 'ot')
<div class="text-muted small">{{ __('navigation.points') }}</div>
<strong class="text-primary">{{ $user_abo->getFormattedTotalPoints() }} Pkt.</strong>
@else
<div class="text-muted small">{{ __('tables.amount') }}</div>
{{ $user_abo->getFormattedAmount() }}
@endif
</div>
<div class="col-md-3 mb-3">
<div class="text-muted small">{{ __('tables.payment') }}</div>