Merge branch 'main' of https://gitea.fhgr.ch/stoffelmauro/ConsultancyProject_2_ETL
commit
4487932f1b
|
@ -23,7 +23,7 @@ class Api
|
||||||
return Cache::get($request);
|
return Cache::get($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
$get = Http::timeout(800)->get($request);
|
$get = Http::timeout(1600)->get($request);
|
||||||
|
|
||||||
if($get->successful()){
|
if($get->successful()){
|
||||||
$result = $get->json();
|
$result = $get->json();
|
||||||
|
@ -94,6 +94,11 @@ class Api
|
||||||
return self::get("/region/{$id}/capacities");
|
return self::get("/region/{$id}/capacities");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function regionMovingAverage(int $id, string $date): mixed
|
||||||
|
{
|
||||||
|
return self::get("/region/{$id}/movingAverage/{$date}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,10 +178,10 @@ body.property main{
|
||||||
grid-template-columns: repeat(4, minmax(10%, 50%));
|
grid-template-columns: repeat(4, minmax(10%, 50%));
|
||||||
grid-template-rows: repeat(3, 1fr) 4em;
|
grid-template-rows: repeat(3, 1fr) 4em;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"chart2 chart2 chart5 chart5"
|
"chart2 chart2 chart1 chart1"
|
||||||
"chart1 chart1 chart3 chart4"
|
"chart5 chart5 chart1 chart1"
|
||||||
"chart1 chart1 chart3 chart4"
|
"chart5 chart5 chart3 chart4"
|
||||||
"timeline timeline timeline timeline";
|
"chart5 chart5 timeline timeline";
|
||||||
}
|
}
|
||||||
|
|
||||||
body.region main{
|
body.region main{
|
||||||
|
@ -190,8 +190,8 @@ body.region main{
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"chart1 chart1 chart2 chart2"
|
"chart1 chart1 chart2 chart2"
|
||||||
"chart1 chart1 chart3 chart4"
|
"chart1 chart1 chart3 chart4"
|
||||||
"chart1 chart1 chart3 chart4"
|
"chart6 chart6 chart3 chart4"
|
||||||
"chart1 chart1 timeline timeline";
|
"chart6 chart6 timeline timeline";
|
||||||
}
|
}
|
||||||
|
|
||||||
article{
|
article{
|
||||||
|
@ -204,10 +204,18 @@ article{
|
||||||
|
|
||||||
article.header{
|
article.header{
|
||||||
grid-template-columns: 100%;
|
grid-template-columns: 100%;
|
||||||
grid-template-rows: minmax(1%, 10%) 1fr;
|
grid-template-rows: minmax(1%, 2.5em) 1fr;
|
||||||
padding: .5em 1em 1em .5em;
|
padding: .5em 1em 1em .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
article.map{
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
article.map>header{
|
||||||
|
padding: .5em 1em 1em .5em;
|
||||||
|
}
|
||||||
|
|
||||||
article>header{
|
article>header{
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1em;
|
grid-template-columns: 1fr 1em;
|
||||||
|
@ -231,3 +239,33 @@ article>header>h2{
|
||||||
grid-template-rows: repeat(4, minmax(20em, 25em));
|
grid-template-rows: repeat(4, minmax(20em, 25em));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leaflet-marker-icon span{
|
||||||
|
background: blue;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
display: block;
|
||||||
|
left: -1rem;
|
||||||
|
top: -1rem;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 50% 50% 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
border: 2px solid #fff
|
||||||
|
}
|
||||||
|
|
||||||
|
/*['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'*/
|
||||||
|
.leaflet-marker-icon.region1 span{
|
||||||
|
background: #9ecae1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-marker-icon.region2 span{
|
||||||
|
background: #6baed6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-marker-icon.region3 span{
|
||||||
|
background: #4292c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-marker-icon.region4 span{
|
||||||
|
background: #2171b5;
|
||||||
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
const sharedOptions = {
|
const sharedOptions = {
|
||||||
basic: {
|
basic: {
|
||||||
color: ['#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'],
|
color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#08519c','#08306b'],
|
||||||
grid: {
|
grid: {
|
||||||
top: 20,
|
top: 20,
|
||||||
left: 60,
|
left: 60,
|
||||||
|
@ -156,6 +156,7 @@ const chartPropsPerRegion = document.getElementById('chart-props-per-region');
|
||||||
const cPropsPerRegion = echarts.init(chartPropsPerRegion);
|
const cPropsPerRegion = echarts.init(chartPropsPerRegion);
|
||||||
const cPropsPerRegionOptions = {
|
const cPropsPerRegionOptions = {
|
||||||
grid: sharedOptions.basic.grid,
|
grid: sharedOptions.basic.grid,
|
||||||
|
color: sharedOptions.basic.color,
|
||||||
xAxis: {
|
xAxis: {
|
||||||
name: 'Region',
|
name: 'Region',
|
||||||
nameLocation: 'center',
|
nameLocation: 'center',
|
||||||
|
@ -178,8 +179,13 @@ const cPropsPerRegionOptions = {
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
data: {!! $propsPerRegion[1] !!},
|
data: {!! $propsPerRegion[1] !!},
|
||||||
type: 'bar'
|
type: 'bar',
|
||||||
}
|
itemStyle: {
|
||||||
|
color: (e) => {
|
||||||
|
return sharedOptions.basic.color[e.dataIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,13 +199,13 @@ const filters = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const cExtractionsOptions = {
|
const cExtractionsOptions = {
|
||||||
|
color: sharedOptions.basic.color,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis'
|
trigger: 'axis'
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
data: filters.regions
|
data: filters.regions
|
||||||
},
|
},
|
||||||
color: sharedOptions.basic.color,
|
|
||||||
grid: sharedOptions.basic.grid,
|
grid: sharedOptions.basic.grid,
|
||||||
xAxis: {
|
xAxis: {
|
||||||
name: 'Zeitpunkt Scraping',
|
name: 'Zeitpunkt Scraping',
|
||||||
|
@ -226,30 +232,26 @@ const cExtractionsOptions = {
|
||||||
name: 'Alle',
|
name: 'Alle',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: 'Total',
|
stack: 'Total',
|
||||||
data: {!! json_encode($growth['total_all']) !!}
|
data: {!! json_encode($growth['total_all']) !!},
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Heidiland',
|
|
||||||
type: 'line',
|
|
||||||
stack: 'Heidiland',
|
|
||||||
data: {!! json_encode($growth['total_heidiland']) !!}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Davos',
|
name: 'Davos',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: 'Davos',
|
|
||||||
data: {!! json_encode($growth['total_davos']) !!}
|
data: {!! json_encode($growth['total_davos']) !!}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Engadin',
|
name: 'Engadin',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: 'Engadin',
|
|
||||||
data: {!! json_encode($growth['total_engadin']) !!}
|
data: {!! json_encode($growth['total_engadin']) !!}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Heidiland',
|
||||||
|
type: 'line',
|
||||||
|
data: {!! json_encode($growth['total_heidiland']) !!}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'St. Moritz',
|
name: 'St. Moritz',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: 'St. Moritz',
|
|
||||||
data: {!! json_encode($growth['total_stmoritz']) !!}
|
data: {!! json_encode($growth['total_stmoritz']) !!}
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -257,19 +259,38 @@ const cExtractionsOptions = {
|
||||||
|
|
||||||
cExtractions.setOption(cExtractionsOptions);
|
cExtractions.setOption(cExtractionsOptions);
|
||||||
|
|
||||||
const map = L.map('leaflet').setView([46.862962, 9.535296], 9);
|
const map = L.map('leaflet');
|
||||||
|
|
||||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||||
}).addTo(map);
|
}).addTo(map);
|
||||||
|
|
||||||
const properties = {!! json_encode($geo) !!}
|
function icon(id){
|
||||||
properties.forEach( prop => {
|
return L.divIcon({
|
||||||
let coords = prop.coordinates.split(',');
|
className: "region"+id,
|
||||||
L.marker(coords).addTo(map).bindPopup('<a href="/prop/'+prop.id+'">'+prop.coordinates+'</a>');
|
html: '<span></span>'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const markers = L.featureGroup([
|
||||||
|
@foreach($geo as $g)
|
||||||
|
L.marker([{{ $g['latlng'] }}], {icon: icon({{ $g['region_id'] }})}).bindPopup('<a href="/property/{{ $g['property_id'] }}">{{ $g['latlng'] }}</a>'),
|
||||||
|
@endforeach
|
||||||
|
]).addTo(map);
|
||||||
|
|
||||||
|
map.fitBounds(markers.getBounds(), {padding: [20,20]})
|
||||||
|
|
||||||
|
cHeatmap.on('click', 'series', (e) => {
|
||||||
|
window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||||
})
|
})
|
||||||
|
|
||||||
|
cPropsPerRegion.on('click', 'series', (e) => {
|
||||||
|
console.log(e.dataIndex);
|
||||||
|
//window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
@ -32,6 +32,14 @@
|
||||||
</header>
|
</header>
|
||||||
<div id="chart-calendar"></div>
|
<div id="chart-calendar"></div>
|
||||||
</article>
|
</article>
|
||||||
|
<article class="header map" style="grid-area: chart5;">
|
||||||
|
<header>
|
||||||
|
<h2 id="belegung-title">
|
||||||
|
Kurzzeitmietobjekte in der Nähe
|
||||||
|
</h2>
|
||||||
|
</header>
|
||||||
|
<div id="chart-map"></div>
|
||||||
|
</article>
|
||||||
<article class="header" style="grid-area: chart3;">
|
<article class="header" style="grid-area: chart3;">
|
||||||
<header>
|
<header>
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -80,7 +88,7 @@ const cTimelineOptions = {
|
||||||
label: {
|
label: {
|
||||||
show: false
|
show: false
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
cTimeline.setOption(cTimelineOptions);
|
cTimeline.setOption(cTimelineOptions);
|
||||||
|
@ -168,6 +176,7 @@ const chartCapacity = document.getElementById('chart-capacity');
|
||||||
const cCapacity = echarts.init(chartCapacity);
|
const cCapacity = echarts.init(chartCapacity);
|
||||||
|
|
||||||
const cCapacityOptions = {
|
const cCapacityOptions = {
|
||||||
|
color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'],
|
||||||
legend: {
|
legend: {
|
||||||
data: ['Auslastung Property', 'Auslastung {{ $base['region_name'] }}', 'Auslastung alle Regionen']
|
data: ['Auslastung Property', 'Auslastung {{ $base['region_name'] }}', 'Auslastung alle Regionen']
|
||||||
},
|
},
|
||||||
|
@ -176,7 +185,7 @@ const cCapacityOptions = {
|
||||||
valueFormatter: (value) => value.toFixed(2)+' %'
|
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: 20,
|
top: 40,
|
||||||
left: 25,
|
left: 25,
|
||||||
right: 10,
|
right: 10,
|
||||||
bottom: 20,
|
bottom: 20,
|
||||||
|
@ -348,6 +357,29 @@ cTimeline.on('timelinechanged', (e) => {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* Map w/ neighbours*/
|
||||||
|
const map = L.map('chart-map');
|
||||||
|
|
||||||
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
maxZoom: 19,
|
||||||
|
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
function icon(id = 0){
|
||||||
|
return L.divIcon({
|
||||||
|
className: "region"+id,
|
||||||
|
html: '<span></span>'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const markers = L.featureGroup([
|
||||||
|
@foreach($neighbours as $n)
|
||||||
|
L.marker([{{ $n['lat'] }}, {{ $n['lon'] }}], {icon: icon()}).bindPopup('<a href="/property/{{ $n['id'] }}">{{ $n['lat'] }}, {{ $n['lon'] }}</a>'),
|
||||||
|
@endforeach
|
||||||
|
]).addTo(map);
|
||||||
|
|
||||||
|
map.fitBounds(markers.getBounds(), {padding: [20,20]})
|
||||||
|
|
||||||
cCapacity.on('click', 'series', (e) => {
|
cCapacity.on('click', 'series', (e) => {
|
||||||
|
|
||||||
// Switch to correct calendar in the timeline
|
// Switch to correct calendar in the timeline
|
||||||
|
@ -356,7 +388,6 @@ cCapacity.on('click', 'series', (e) => {
|
||||||
currentIndex: e.dataIndex
|
currentIndex: e.dataIndex
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,15 @@
|
||||||
<article style="grid-area: timeline;">
|
<article style="grid-area: timeline;">
|
||||||
<div id="timeline"></div>
|
<div id="timeline"></div>
|
||||||
</article>
|
</article>
|
||||||
|
<article class="header" style="grid-area: chart6;">
|
||||||
|
<header>
|
||||||
|
<h2 id="prediction-title">Auslastung Vorhersage</h2>
|
||||||
|
</header>
|
||||||
|
<div id="chart-prediction"></div>
|
||||||
|
</article>
|
||||||
<article class="header" style="grid-area: chart1;">
|
<article class="header" style="grid-area: chart1;">
|
||||||
<header>
|
<header>
|
||||||
<h2 id="belegung-title"></h2>
|
<h2 id="belegung-title">Gesamtauslastung</h2>
|
||||||
</header>
|
</header>
|
||||||
<div id="chart-heatmap"></div>
|
<div id="chart-heatmap"></div>
|
||||||
</article>
|
</article>
|
||||||
|
@ -58,7 +64,7 @@
|
||||||
|
|
||||||
const sharedOptions = {
|
const sharedOptions = {
|
||||||
basic: {
|
basic: {
|
||||||
color: ['#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'],
|
color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'],
|
||||||
grid: {
|
grid: {
|
||||||
top: 20,
|
top: 20,
|
||||||
left: 60,
|
left: 60,
|
||||||
|
@ -134,22 +140,90 @@ const cCapacityOptions = {
|
||||||
|
|
||||||
cCapacity.setOption(cCapacityOptions);
|
cCapacity.setOption(cCapacityOptions);
|
||||||
|
|
||||||
|
const chartPrediction = document.getElementById('chart-prediction');
|
||||||
|
const cPrediction = echarts.init(chartPrediction);
|
||||||
|
|
||||||
|
const cPredictionOptions = {
|
||||||
|
legend: {
|
||||||
|
data: ['Moving Average', 'Earlier', 'Later']
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
valueFormatter: (value) => value.toFixed(2)+' %'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 20,
|
||||||
|
left: 25,
|
||||||
|
right: 10,
|
||||||
|
bottom: 20,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: {!! json_encode($prediction['dates']) !!},
|
||||||
|
name: 'Zeitpunkt Scraping',
|
||||||
|
nameLocation: 'center',
|
||||||
|
nameGap: 24,
|
||||||
|
nameTextStyle: {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
|
name: 'Auslastung in Prozent',
|
||||||
|
nameLocation: 'center',
|
||||||
|
nameGap: 38,
|
||||||
|
nameTextStyle: {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'Moving Average',
|
||||||
|
type: 'line',
|
||||||
|
symbolSize: 7,
|
||||||
|
data: {!! json_encode($prediction['movAvg']) !!}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Earlier',
|
||||||
|
type: 'line',
|
||||||
|
symbolSize: 7,
|
||||||
|
data: {!! json_encode($prediction['cap_earlierTimeframe']) !!}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Later',
|
||||||
|
type: 'line',
|
||||||
|
symbolSize: 7,
|
||||||
|
data: {!! json_encode($prediction['cap_laterTimeframe']) !!}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
cPrediction.setOption(cPredictionOptions);
|
||||||
|
|
||||||
|
|
||||||
const chartHeatmap = document.getElementById('chart-heatmap');
|
const chartHeatmap = document.getElementById('chart-heatmap');
|
||||||
const cHeatmap = echarts.init(chartHeatmap);
|
const cHeatmap = echarts.init(chartHeatmap);
|
||||||
const cHeatmapOptions = {
|
const cHeatmapOptions = {
|
||||||
|
animation: false,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
position: 'top'
|
position: 'top'
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: 30,
|
top: 30,
|
||||||
right: 0,
|
right: 45,
|
||||||
bottom: 0,
|
bottom: 50,
|
||||||
left: 0
|
left: 5
|
||||||
},
|
},
|
||||||
dataZoom: [{
|
dataZoom: [{
|
||||||
type: 'inside'
|
type: 'slider'
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
|
type: 'slider',
|
||||||
|
show: true,
|
||||||
|
yAxisIndex: 0,
|
||||||
|
}],
|
||||||
xAxis: {
|
xAxis: {
|
||||||
show: false,
|
show: false,
|
||||||
name: 'Kurzzeitmietobjekt',
|
name: 'Kurzzeitmietobjekt',
|
||||||
|
@ -196,8 +270,7 @@ const cHeatmapOptions = {
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
formatter: (data) => {
|
formatter: (data) => {
|
||||||
let v = data.value
|
return `Kurzzeitmietobjekte-ID: ${data.data[1]}<br />Datum Scraping: ${data.data[0]}<br/>Auslastung: ${data.data[2].toFixed(2)} %`
|
||||||
return `Kurzzeitmietobjekte-ID: ${data.name}<br />Datum Scraping: ${extractionDates[v[1]]}<br/>Auslastung: ${v[2]} %`
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
|
|
|
@ -12,18 +12,20 @@ Route::get('/', function () {
|
||||||
$propsPerRegion = Api::propertiesPerRegion();
|
$propsPerRegion = Api::propertiesPerRegion();
|
||||||
$propsPerRegionName = [];
|
$propsPerRegionName = [];
|
||||||
$propsPerRegionCounts = [];
|
$propsPerRegionCounts = [];
|
||||||
|
$propsPerRegionId = [];
|
||||||
|
|
||||||
foreach ($propsPerRegion as $el) {
|
foreach ($propsPerRegion as $el) {
|
||||||
$propsPerRegionName[] = $el['name'];
|
$propsPerRegionName[] = $el['name'];
|
||||||
|
$propsPerRegionId[] = $el['id'];
|
||||||
$propsPerRegionCounts[] = $el['count_properties'];
|
$propsPerRegionCounts[] = $el['count_properties'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$propertiesGeo = Api::propertiesGeo();
|
$propertiesGeo = Api::propertiesGeo();
|
||||||
|
|
||||||
return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
|
return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionId), json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/prop/{id}', function (int $id) {
|
Route::get('/property/{id}', function (int $id) {
|
||||||
|
|
||||||
$propertyBase = Api::propertyBase($id);
|
$propertyBase = Api::propertyBase($id);
|
||||||
$calendars = Api::propertyExtractions($id);
|
$calendars = Api::propertyExtractions($id);
|
||||||
|
@ -90,13 +92,14 @@ Route::get('/region/{id}', function (int $id) {
|
||||||
$regionBaseAll = Api::regionBase(-1);
|
$regionBaseAll = Api::regionBase(-1);
|
||||||
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
|
$regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
|
||||||
$regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']];
|
$regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']];
|
||||||
|
$regionMovingAverage = Api::regionMovingAverage($id, '2024-04-25');
|
||||||
|
|
||||||
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
|
$regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
|
||||||
$regionCapacitiesRegion = Api::regionCapacities($id);
|
$regionCapacitiesRegion = Api::regionCapacities($id);
|
||||||
$regionCapacitiesAll = Api::regionCapacities(-1);
|
$regionCapacitiesAll = Api::regionCapacities(-1);
|
||||||
$regionCapacities = [$regionCapacitiesAll, $regionCapacitiesRegion];
|
$regionCapacities = [$regionCapacitiesAll, $regionCapacitiesRegion];
|
||||||
|
|
||||||
return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities]);
|
return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities, 'prediction' => $regionMovingAverage]);
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,30 +1,92 @@
|
||||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0" version="25.0.3">
|
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0" version="26.0.5">
|
||||||
<diagram name="Seite-1" id="5abS_fUiar5VuBZXZINZ">
|
<diagram name="Seite-1" id="chpUGVRRn7alPJZ1I-il">
|
||||||
<mxGraphModel dx="1195" dy="1534" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
<mxGraphModel dx="819" dy="1052" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0" />
|
<mxCell id="0" />
|
||||||
<mxCell id="1" parent="0" />
|
<mxCell id="1" parent="0" />
|
||||||
<object placeholders="1" c4Name="REST-API" c4Type="Python (FastAPI)" c4Description="REST Schnittstelle" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-1">
|
<object placeholders="1" c4Name="RDBMS" c4Type="Container" c4Technology="DuckDB" c4Description="Aggregierte Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-2">
|
||||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
|
||||||
<mxGeometry x="360" y="40" width="240" height="120" as="geometry" />
|
|
||||||
</mxCell>
|
|
||||||
</object>
|
|
||||||
<mxCell id="DRD_0cKAZXVdgcTgqyKr-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="DRD_0cKAZXVdgcTgqyKr-2" target="DRD_0cKAZXVdgcTgqyKr-1">
|
|
||||||
<mxGeometry relative="1" as="geometry" />
|
|
||||||
</mxCell>
|
|
||||||
<object placeholders="1" c4Name="Data" c4Type="Python (Polars)" c4Description="Eigenes Python Package. Enthält Programmcode für das ETL" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-2">
|
|
||||||
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
|
||||||
<mxGeometry x="40" y="40" width="240" height="120" as="geometry" />
|
|
||||||
</mxCell>
|
|
||||||
</object>
|
|
||||||
<object placeholders="1" c4Name="Datenbank" c4Type="Container" c4Technology="DuckDB" c4Description="Datenbank, welches die aggregierten Daten enthält." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-3">
|
|
||||||
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||||
<mxGeometry x="40" y="240" width="240" height="120" as="geometry" />
|
<mxGeometry x="50" y="60" width="240" height="120" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
</object>
|
</object>
|
||||||
<mxCell id="DRD_0cKAZXVdgcTgqyKr-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="DRD_0cKAZXVdgcTgqyKr-2" target="DRD_0cKAZXVdgcTgqyKr-3">
|
<object placeholders="1" c4Name="ETL" c4Type="SQL, Python (Polars)" c4Description="Bereitet Daten mittels algorithmischer<br> Verfahren auf." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-3">
|
||||||
|
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="480" y="60" width="240" height="120" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</object>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-4" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-3" target="_wAeSdXpbb6KPP4DEc36-2">
|
||||||
<mxGeometry relative="1" as="geometry" />
|
<mxGeometry relative="1" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-5" value="Liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-4">
|
||||||
|
<mxGeometry x="0.0412" y="1" relative="1" as="geometry">
|
||||||
|
<mxPoint x="-1" y="-1" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-15" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-13">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-21" value="<div>Führt Abfragen aus</div><div>[JSON/HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-15">
|
||||||
|
<mxGeometry x="-0.0541" y="-1" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<object placeholders="1" c4Name="Webapplikation" c4Type="PHP (Laravel)" c4Description="Verarbeitet Anfragen von Benutzer:innen" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-6">
|
||||||
|
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="50" y="230" width="240" height="120" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</object>
|
||||||
|
<object placeholders="1" c4Name="Dashboard" c4Type="Container" c4Technology="Apache Echarts" c4Description="Stellt Benutzer:innen Auswertungs-<br>möglichkeiten zur Verfügbarkeit von Kurzzeitmietobjekten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-8">
|
||||||
|
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="480" y="370" width="240" height="160" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</object>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-10" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-6">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-16" value="<div>Besucht Webapplikation</div><div>[HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-10">
|
||||||
|
<mxGeometry x="0.1247" y="-2" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-11" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-8">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-17" value="Betrachtet Auswertungen" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-11">
|
||||||
|
<mxGeometry x="0.2151" y="-1" relative="1" as="geometry">
|
||||||
|
<mxPoint x="2" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<object placeholders="1" c4Name="Benutzer:in" c4Type="Person" c4Description="Person welche Auswertungen zur Verfügbarkeit von Kurzzeitmietobjekten in Ferienregionen durchführt." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-9">
|
||||||
|
<mxCell style="html=1;fontSize=11;dashed=0;whiteSpace=wrap;fillColor=#083F75;strokeColor=#06315C;fontColor=#ffffff;shape=mxgraph.c4.person2;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0]];resizable=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="314" y="600" width="200" height="180" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</object>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-14" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-13" target="_wAeSdXpbb6KPP4DEc36-3">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-20" value="Ruft ETL Verfahren auf" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-14">
|
||||||
|
<mxGeometry x="-0.0667" y="-1" relative="1" as="geometry">
|
||||||
|
<mxPoint as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<object placeholders="1" c4Name="FastAPI" c4Type="Python (FastAPI)" c4Description="Stellt aufbereitete Daten via <br>JSON/HTTPS API zur Verfügung." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-13">
|
||||||
|
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="480" y="230" width="240" height="120" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</object>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-18" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-8">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="_wAeSdXpbb6KPP4DEc36-19" value="<div>Liefert Inhalte zum Webbrowser&nbsp;</div><div>von Benutzer:innen</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-18">
|
||||||
|
<mxGeometry x="-0.0888" y="-2" relative="1" as="geometry">
|
||||||
|
<mxPoint x="5" y="7" as="offset" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<object placeholders="1" c4Name="Visual Analytics Tool" c4Type="SystemScopeBoundary" c4Application="Software System" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="_wAeSdXpbb6KPP4DEc36-23">
|
||||||
|
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="30" y="40" width="710" height="540" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</object>
|
||||||
</root>
|
</root>
|
||||||
</mxGraphModel>
|
</mxGraphModel>
|
||||||
</diagram>
|
</diagram>
|
||||||
|
|
|
@ -9,6 +9,7 @@ from data import etl_region_capacities_weekdays as etl_rcw
|
||||||
from data import etl_region_movAverage as etl_rmA
|
from data import etl_region_movAverage as etl_rmA
|
||||||
from data import etl_region_properties_capacities as etl_rpc
|
from data import etl_region_properties_capacities as etl_rpc
|
||||||
from data import etl_region_capacities_comparison as etl_rcc
|
from data import etl_region_capacities_comparison as etl_rcc
|
||||||
|
from data import etl_region_movAverage as etl_rmA
|
||||||
from data import etl_region_properties_capacities as etl_rpc
|
from data import etl_region_properties_capacities as etl_rpc
|
||||||
from fastapi import FastAPI, Response
|
from fastapi import FastAPI, Response
|
||||||
|
|
||||||
|
|
|
@ -137,6 +137,7 @@ class Database:
|
||||||
return self.connection.sql("""
|
return self.connection.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
regions.name,
|
regions.name,
|
||||||
|
regions.id,
|
||||||
COUNT(*) AS count_properties
|
COUNT(*) AS count_properties
|
||||||
FROM
|
FROM
|
||||||
consultancy_d.properties
|
consultancy_d.properties
|
||||||
|
@ -146,7 +147,8 @@ class Database:
|
||||||
consultancy_d.regions ON regions.id = seeds.region_id
|
consultancy_d.regions ON regions.id = seeds.region_id
|
||||||
GROUP BY
|
GROUP BY
|
||||||
properties.seed_id,
|
properties.seed_id,
|
||||||
regions.name
|
regions.name,
|
||||||
|
regions.id
|
||||||
ORDER BY
|
ORDER BY
|
||||||
count_properties ASC
|
count_properties ASC
|
||||||
""")
|
""")
|
||||||
|
@ -427,10 +429,15 @@ class Database:
|
||||||
def properties_geo(self):
|
def properties_geo(self):
|
||||||
return self.connection.sql("""
|
return self.connection.sql("""
|
||||||
SELECT
|
SELECT
|
||||||
p.id,
|
p.id as property_id,
|
||||||
p.check_data as coordinates
|
p.check_data as latlng,
|
||||||
|
r.id as region_id
|
||||||
FROM
|
FROM
|
||||||
consultancy_d.properties p
|
consultancy_d.properties p
|
||||||
|
LEFT JOIN
|
||||||
|
consultancy_d.seeds s ON s.id = p.seed_id
|
||||||
|
LEFT JOIN
|
||||||
|
consultancy_d.regions r ON r.id = s.region_id
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def properties_geo_seeds(self):
|
def properties_geo_seeds(self):
|
||||||
|
|
Loading…
Reference in New Issue