diff --git a/Layout/default/Pop/Detail.php b/Layout/default/Pop/Detail.php
index aa661967a..e4a85413e 100644
--- a/Layout/default/Pop/Detail.php
+++ b/Layout/default/Pop/Detail.php
@@ -70,6 +70,15 @@ if (!empty(trim($pops->vlan_ipv6)))
| Standort |
diff --git a/Layout/default/Pop/Form.php b/Layout/default/Pop/Form.php
index 213563879..b3e71457d 100644
--- a/Layout/default/Pop/Form.php
+++ b/Layout/default/Pop/Form.php
@@ -112,11 +112,60 @@ if (isset($_GET['returnto']) && $_GET['returnto'] == "pop-detail") {
+
+
+
+
diff --git a/application/Pop/PopController.php b/application/Pop/PopController.php
index e03af32a7..c9c58c4b5 100644
--- a/application/Pop/PopController.php
+++ b/application/Pop/PopController.php
@@ -52,6 +52,10 @@ class PopController extends mfBaseController
"category" => $pop->category ?: 99,
"networkArea" => $pop->networks,
"location" => $pop->location,
+ "zip" => $pop->zip,
+ "city" => $pop->city,
+ "street" => $pop->street,
+ "number" => $pop->number,
"state" => $pop->state,
"folder_link" => $pop->folder_link,
"doku_date" => $pop->doku_date,
@@ -142,6 +146,7 @@ class PopController extends mfBaseController
{
$network_id = 90;
$this->layout()->set("network_id", $network_id);
+ $this->layout()->set("networks", NetworkModel::getAll());
$this->layout()->set("categories", $this->getMapCategories());
$this->layout()->setTemplate("Pop/Map");
}
@@ -1295,6 +1300,10 @@ class PopController extends mfBaseController
$data['gps_lat'] = ($r->gps_lat) ? $r->gps_lat : null;
$data['gps_long'] = ($r->gps_long) ? $r->gps_long : null;
$data['location'] = $r->location;
+ $data['zip'] = $r->zip;
+ $data['city'] = $r->city;
+ $data['street'] = $r->street;
+ $data['number'] = $r->number;
$data['vlan_public'] = ($r->vlan_public) ? $r->vlan_public : null;
$data['vlan_nat'] = ($r->vlan_nat) ? $r->vlan_nat : null;
$data['vlan_ipv6'] = ($r->vlan_ipv6) ? $r->vlan_ipv6 : null;
@@ -1561,7 +1570,7 @@ class PopController extends mfBaseController
$db = FronkDB::singleton();
$pops = [];
$popQuery = "
- SELECT DISTINCT p.id, p.name, p.gps_lat, p.gps_long
+ SELECT DISTINCT p.id, p.name, p.gps_lat, p.gps_long, p.zip, p.city, p.street, p.number
FROM Pop p
INNER JOIN PopNetwork pn ON p.id = pn.pop_id
INNER JOIN Network n ON pn.network_id = n.id
@@ -1577,6 +1586,10 @@ class PopController extends mfBaseController
'name' => $popData->name,
'lat' => floatval($popData->gps_lat),
'lng' => floatval($popData->gps_long),
+ 'zip' => $popData->zip,
+ 'city' => $popData->city,
+ 'street' => $popData->street,
+ 'number' => $popData->number,
'type' => 'pop'
];
}
@@ -1769,9 +1782,62 @@ class PopController extends mfBaseController
}
}
+ $pipes = [];
+ $pipeQuery = "
+ SELECT DISTINCT p.id, p.description, p.coordinates, p.type_tmp, p.coat_color, p.layer, p.status, p.state
+ FROM FiberPlanPipe p
+ INNER JOIN FiberPlanPipeEndpoint pe ON p.id = pe.fiberPlanPipe_id
+ LEFT JOIN FiberPlanDispatcher d ON pe.fiberPlanDispatcher_id = d.id
+ LEFT JOIN FiberPlanAddress a ON pe.fiberPlanAddress_id = a.id
+ LEFT JOIN PopNetwork pn ON pe.pop_id = pn.pop_id
+ WHERE
+ (d.network_id = $network_id) OR
+ (a.network_id = $network_id) OR
+ (pn.network_id = $network_id)
+ ";
+
+ $pipeRes = $db->query($pipeQuery);
+ if ($db->num_rows($pipeRes)) {
+ while ($pipeData = $db->fetch_object($pipeRes)) {
+ if (!empty($pipeData->coordinates)) {
+ $coords_array = json_decode($pipeData->coordinates, true);
+ if (is_array($coords_array) && count($coords_array) > 0) {
+ $convertedCoords = [];
+ foreach ($coords_array as $coord) {
+ if (isset($coord['gps_lat']) && isset($coord['gps_long'])) {
+ $convertedCoords[] = [
+ 'lat' => floatval($coord['gps_lat']),
+ 'lng' => floatval($coord['gps_long'])
+ ];
+ } elseif (isset($coord['lat']) && isset($coord['lng'])) {
+ $convertedCoords[] = [
+ 'lat' => floatval($coord['lat']),
+ 'lng' => floatval($coord['lng'])
+ ];
+ }
+ }
+
+ if (count($convertedCoords) >= 2) {
+ $pipes[] = [
+ 'id' => intval($pipeData->id),
+ 'name' => $pipeData->description,
+ 'coordinates' => $convertedCoords,
+ 'type' => $pipeData->type_tmp,
+ 'color' => $pipeData->coat_color,
+ 'layer' => $pipeData->layer,
+ 'status' => $pipeData->status,
+ 'state' => $pipeData->state
+ ];
+ }
+ }
+ }
+ }
+ }
+
return mfBaseController::returnJson(mfResponse::Ok([
'pops' => $pops,
'cables' => $cables,
+ 'pipes' => $pipes,
'distributors' => $distributors,
'splices' => $splices,
'customerConnections' => $customerConnections
diff --git a/application/Pop/PopModel.php b/application/Pop/PopModel.php
index f6c15b14e..1ed53948b 100644
--- a/application/Pop/PopModel.php
+++ b/application/Pop/PopModel.php
@@ -8,6 +8,10 @@ class PopModel
public $gps_lat = null;
public $gps_long = null;
public $location = null;
+ public $zip = null;
+ public $city = null;
+ public $street = null;
+ public $number = null;
public $vlan_public = null;
public $vlan_nat = null;
public $vlan_ipv6 = null;
diff --git a/db/migrations/20260220100000_pop_add_address_fields.php b/db/migrations/20260220100000_pop_add_address_fields.php
new file mode 100644
index 000000000..76076cb71
--- /dev/null
+++ b/db/migrations/20260220100000_pop_add_address_fields.php
@@ -0,0 +1,36 @@
+table('Pop');
+ if (!$table->hasColumn('zip')) {
+ $table->addColumn('zip', 'string', ['null' => true, 'limit' => 10, 'after' => 'location']);
+ }
+ if (!$table->hasColumn('city')) {
+ $table->addColumn('city', 'string', ['null' => true, 'limit' => 255, 'after' => 'zip']);
+ }
+ if (!$table->hasColumn('street')) {
+ $table->addColumn('street', 'string', ['null' => true, 'limit' => 255, 'after' => 'city']);
+ }
+ if (!$table->hasColumn('number')) {
+ $table->addColumn('number', 'string', ['null' => true, 'limit' => 20, 'after' => 'street']);
+ }
+ $table->update();
+ }
+
+ public function down(): void
+ {
+ $table = $this->table('Pop');
+ $table->removeColumn('zip')
+ ->removeColumn('city')
+ ->removeColumn('street')
+ ->removeColumn('number')
+ ->update();
+ }
+}
diff --git a/public/js/pages/Pop/PopMap.js b/public/js/pages/Pop/PopMap.js
index 87f13abb4..d267f91b0 100644
--- a/public/js/pages/Pop/PopMap.js
+++ b/public/js/pages/Pop/PopMap.js
@@ -28,7 +28,12 @@ Vue.component('pop-map-modal', {
{{ pop.name }}
- {{ categories[pop.category || 99] }} | {{ pop.location }}
+
+
+ {{ pop.street }} {{ pop.number }}, {{ pop.zip }} {{ pop.city }} |
+
+ {{ categories[pop.category || 99] }}
+
@@ -257,11 +262,15 @@ Vue.component('pop-map-modal', {
let categoryName = this.categories[category] || 'Unbekannt';
let stateText = this.states[pop.state] || pop.state || '-';
+ let addressHtml = (pop.street || pop.city)
+ ? `Adresse: ${pop.street || ''} ${pop.number || ''}, ${pop.zip || ''} ${pop.city || ''} `
+ : '';
const popupContent = `
${pop.name}
+ ${addressHtml}
Kategorie: ${categoryName}
Status: ${stateText}
Info: ${pop.location || '-'}
@@ -300,7 +309,10 @@ Vue.component('pop-map-modal', {
this.filteredPops = this.allPops.filter(pop =>
pop.name.toLowerCase().includes(query) ||
- (pop.location && pop.location.toLowerCase().includes(query))
+ (pop.location && pop.location.toLowerCase().includes(query)) ||
+ (pop.street && pop.street.toLowerCase().includes(query)) ||
+ (pop.city && pop.city.toLowerCase().includes(query)) ||
+ (pop.zip && pop.zip.toLowerCase().includes(query))
).slice(0, 10);
this.showSuggestions = true;
@@ -345,10 +357,20 @@ Vue.component('pop-map-modal', {
this.showSuggestions = false;
this.selectedIndex = -1;
- let found = this.markers.find(m => m.popData.name.toLowerCase().includes(query));
+ let found = this.markers.find(m =>
+ m.popData.name.toLowerCase().includes(query) ||
+ (m.popData.street && m.popData.street.toLowerCase().includes(query)) ||
+ (m.popData.city && m.popData.city.toLowerCase().includes(query)) ||
+ (m.popData.zip && m.popData.zip.toLowerCase().includes(query))
+ );
if (!found) {
- const hiddenPop = this.allPops.find(p => p.name.toLowerCase().includes(query));
+ const hiddenPop = this.allPops.find(p =>
+ p.name.toLowerCase().includes(query) ||
+ (p.street && p.street.toLowerCase().includes(query)) ||
+ (p.city && p.city.toLowerCase().includes(query)) ||
+ (p.zip && p.zip.toLowerCase().includes(query))
+ );
if (hiddenPop) {
const category = hiddenPop.category || 99;
if (!this.visibleCategories[category]) {
diff --git a/public/js/pages/Pop/PopView.js b/public/js/pages/Pop/PopView.js
index 49e765e7f..527aa77ca 100644
--- a/public/js/pages/Pop/PopView.js
+++ b/public/js/pages/Pop/PopView.js
@@ -20,6 +20,17 @@ Vue.component('Pop', {
{{row.name}}
+
+
+ {{row.street}} {{row.number}}, {{row.zip}} {{row.city}}
+
+
+
{{ {1: 'Outdoor', 2: 'Indoor', 3: 'Sender/Funk', 4: 'Container', 99: 'Unbekannt'}[row.category] || 'Unbekannt' }}
@@ -64,12 +75,6 @@ Vue.component('Pop', {
defaultPageSize: 25,
headers: [
{text: 'Name', key: 'name', priority: 10},
- {text: 'Kategorie', key: 'category', class: 'text-center', priority: 4, filter: 'select', filterOptions: [
- {value: '1', text: 'Outdoor (Kasten/Schrank)'},
- {value: '2', text: 'Indoor (Keller Gebäude)'},
- {value: '3', text: 'Sender/Funk (Sendemast)'},
- {value: '4', text: 'Container (Garage, Container)'},
- {value: '99', text: 'Unbekannt'}]},
{text: 'Netzgebiet', key: 'networkArea', class: 'text-center',
// TODO: fix autocomplete Filter
// filter: 'autocomplete',
@@ -78,7 +83,8 @@ Vue.component('Pop', {
},
{text: 'Zutritt', key: 'location', class: 'text-center', priority: 1},
{text: 'Standort', key: 'gps', class: 'text-center', priority: 2},
- {text: 'Status', key: 'state', class: 'text-center', priority: 3, filter: 'select', filterOptions: [
+ {text: 'Adresse', key: 'address', class: 'text-center', priority: 3},
+ {text: 'Status', key: 'state', class: 'text-center', priority: 4, filter: 'select', filterOptions: [
{value: '1', text: 'Planung'},
{value: '2', text: 'Bauphase'},
{value: '3', text: 'Grobdoku'},
|