mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-24 10:22:18 +00:00
Merge branch 'feature-24647/Konfigurierbare_Dashboards' into feature-25999/C4
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class Test extends Auth_Controller
|
||||||
|
{
|
||||||
|
private $_uid; // uid of the logged user
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Set required permissions
|
||||||
|
parent::__construct(
|
||||||
|
array(
|
||||||
|
'index' => 'dashboard/benutzer:r',
|
||||||
|
'db' => 'dashboard/benutzer:r',
|
||||||
|
'admin' => 'dashboard/admin:r',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->load->library('AuthLib');
|
||||||
|
|
||||||
|
$this->_setAuthUID(); // sets property uid
|
||||||
|
|
||||||
|
$this->setControllerId(); // sets the controller id
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
// Public methods
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$this->load->view('test/Test.php', ['dashboard' => 'CIS']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public methods
|
||||||
|
public function db($dashboard)
|
||||||
|
{
|
||||||
|
$this->load->view('test/Test.php', ['dashboard' => $dashboard]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function admin()
|
||||||
|
{
|
||||||
|
$this->load->view('test/Admin.php', []);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
// Private methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the UID of the logged user and checks if it is valid
|
||||||
|
*/
|
||||||
|
private function _setAuthUID()
|
||||||
|
{
|
||||||
|
$this->_uid = getAuthUID();
|
||||||
|
|
||||||
|
if (!$this->_uid) show_error('User authentification failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -207,7 +207,13 @@ class Config extends Auth_Controller
|
|||||||
foreach ($funktionen as $funktion) {
|
foreach ($funktionen as $funktion) {
|
||||||
$conf = $this->DashboardLib->getPreset($db, $funktion);
|
$conf = $this->DashboardLib->getPreset($db, $funktion);
|
||||||
if ($conf)
|
if ($conf)
|
||||||
$result[$funktion] = json_decode($conf->preset, true)['widgets'][$funktion];
|
{
|
||||||
|
$preset = json_decode($conf->preset, true);
|
||||||
|
if (!isset($preset['widgets']) || !isset($preset['widgets'][$funktion]))
|
||||||
|
$result[$funktion] = [];
|
||||||
|
else
|
||||||
|
$result[$funktion] = $preset['widgets'][$funktion];
|
||||||
|
}
|
||||||
else
|
else
|
||||||
$result[$funktion] = [];
|
$result[$funktion] = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ class Widget extends Auth_Controller
|
|||||||
{
|
{
|
||||||
parent::__construct(
|
parent::__construct(
|
||||||
array(
|
array(
|
||||||
'index' => 'dashboard/benutzer:r',
|
'index' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
|
||||||
'getAll' => 'dashboard/admin:r',
|
'getAll' => 'dashboard/admin:r',
|
||||||
'getWidgetsForDashboard' => 'dashboard/benutzer:rw',
|
'getWidgetsForDashboard' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
|
||||||
'setAllowed' => 'dashboard/admin:rw'
|
'setAllowed' => 'dashboard/admin:rw'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ class Widget_model extends DB_Model
|
|||||||
public function getWithAllowedForDashboard($dashboard_id)
|
public function getWithAllowedForDashboard($dashboard_id)
|
||||||
{
|
{
|
||||||
$this->addSelect($this->dbTable . '.*');
|
$this->addSelect($this->dbTable . '.*');
|
||||||
$this->addSelect('CASE WHEN dashboard_id = ? THEN 1 ELSE 0 END AS allowed', false);
|
$this->addSelect('CASE WHEN dashboard_id IS NULL THEN 0 ELSE 1 END AS allowed', false);
|
||||||
$this->addJoin('dashboard.tbl_dashboard_widget', 'widget_id', 'LEFT');
|
$this->db->join('dashboard.tbl_dashboard_widget dw', $this->dbTable . '.widget_id=dw.widget_id AND dashboard_id = ?', 'LEFT', false);
|
||||||
|
|
||||||
return $this->execQuery($this->db->get_compiled_select($this->dbTable), [$dashboard_id]);
|
return $this->execQuery($this->db->get_compiled_select($this->dbTable), [$dashboard_id]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
$this->load->view('templates/FHC-Header',
|
||||||
|
array(
|
||||||
|
'title' => 'FH-Complete',
|
||||||
|
'bootstrap5' => true,
|
||||||
|
'fontawesome6' => true,
|
||||||
|
'axios027' => true,
|
||||||
|
'restclient' => true,
|
||||||
|
'vue3' => true,
|
||||||
|
'customJSModules' => ['public/js/apps/Test.js'],
|
||||||
|
'customCSSs' => [
|
||||||
|
'public/css/components/dashboard.css'
|
||||||
|
],
|
||||||
|
'navigationcomponent' => true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
|
<core-navigation-cmpt :add-side-menu-entries="appSideMenuEntries"></core-navigation-cmpt>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h1 class="h2">Dashboard</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<dashboard-admin/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php $this->load->view('templates/FHC-Footer'); ?>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
$this->load->view('templates/FHC-Header',
|
||||||
|
array(
|
||||||
|
'title' => 'FH-Complete',
|
||||||
|
'bootstrap5' => true,
|
||||||
|
'fontawesome6' => true,
|
||||||
|
'axios027' => true,
|
||||||
|
'restclient' => true,
|
||||||
|
'vue3' => true,
|
||||||
|
'customJSModules' => ['public/js/apps/Test.js'],
|
||||||
|
'customCSSs' => [
|
||||||
|
'public/css/components/dashboard.css'
|
||||||
|
],
|
||||||
|
'navigationcomponent' => true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="main">
|
||||||
|
<core-navigation-cmpt :add-side-menu-entries="appSideMenuEntries"></core-navigation-cmpt>
|
||||||
|
|
||||||
|
<div id="content">
|
||||||
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
|
<h1 class="h2">Dashboard</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<core-dashboard dashboard="<?= $dashboard; ?>"/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php $this->load->view('templates/FHC-Footer'); ?>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import {CoreNavigationCmpt} from '../components/navigation/Navigation.js';
|
||||||
|
import CoreDashboard from '../components/Dashboard/Dashboard.js';
|
||||||
|
import DashboardAdmin from '../components/Dashboard/Admin.js';
|
||||||
|
|
||||||
|
Vue.createApp({
|
||||||
|
data: () => ({
|
||||||
|
appSideMenuEntries: {}
|
||||||
|
}),
|
||||||
|
components: {
|
||||||
|
CoreNavigationCmpt,
|
||||||
|
DashboardAdmin,
|
||||||
|
CoreDashboard/*,
|
||||||
|
"CoreFilterCmpt": CoreFilterCmpt,
|
||||||
|
"verticalsplit": verticalsplit,
|
||||||
|
"searchbar": searchbar*/
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
}
|
||||||
|
}).mount('#main');
|
||||||
@@ -14,6 +14,7 @@ export default {
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
funktionen: {},
|
funktionen: {},
|
||||||
sections: [],
|
sections: [],
|
||||||
|
tmpLoading: ''
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
apiurl() {
|
apiurl() {
|
||||||
@@ -117,10 +118,14 @@ export default {
|
|||||||
loadSections(evt) {
|
loadSections(evt) {
|
||||||
let funktionen = Array.from(evt.target.querySelectorAll("option:checked"),e=>e.value);
|
let funktionen = Array.from(evt.target.querySelectorAll("option:checked"),e=>e.value);
|
||||||
this.sections = [];
|
this.sections = [];
|
||||||
|
this.tmpLoading = funktionen.join('###');
|
||||||
axios.get(this.apiurl + '/Config/PresetBatch', {params: {
|
axios.get(this.apiurl + '/Config/PresetBatch', {params: {
|
||||||
db: this.dashboard,
|
db: this.dashboard,
|
||||||
funktionen
|
funktionen
|
||||||
}}).then(res => {
|
}}).then(res => {
|
||||||
|
if (this.tmpLoading !== funktionen.join('###'))
|
||||||
|
return; // NOTE(chris): prevent race condition
|
||||||
|
|
||||||
for (var section in res.data.retval) {
|
for (var section in res.data.retval) {
|
||||||
let widgets = [];
|
let widgets = [];
|
||||||
for (var wid in res.data.retval[section]) {
|
for (var wid in res.data.retval[section]) {
|
||||||
@@ -145,10 +150,16 @@ export default {
|
|||||||
});
|
});
|
||||||
}).catch(err => console.error('ERROR:', err));
|
}).catch(err => console.error('ERROR:', err));
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
dashboard() {
|
||||||
|
// TODO(chris): this should be done without a watcher
|
||||||
|
this.loadSections({target:this.$refs.funktionenList});
|
||||||
|
}
|
||||||
|
},
|
||||||
template: `<div class="dashboard-admin-presets">
|
template: `<div class="dashboard-admin-presets">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<select class="form-control" multiple @input="loadSections">
|
<select ref="funktionenList" style="height:30em" class="form-control" multiple @input="loadSections">
|
||||||
<option v-for="name,id in funktionen" :key="id" :value="id">{{ name }}</option>
|
<option v-for="name,id in funktionen" :key="id" :value="id">{{ name }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
gridWidth: 0,
|
gridWidth: 0,
|
||||||
containerRect: {top:0,left:0},
|
|
||||||
changeHeight: 1,
|
changeHeight: 1,
|
||||||
movedObjects: [],
|
movedObjects: [],
|
||||||
editMode: this.adminMode ? 1 : 0,
|
editMode: this.adminMode ? 1 : 0,
|
||||||
gridXLast: 0,
|
gridXLast: -1, // NOTE(chris): 0 based
|
||||||
gridYLast: 0,
|
gridYLast: -1,
|
||||||
dataTransfer: {}
|
dragging: 0,
|
||||||
|
dataTransfer: {},
|
||||||
|
gridAddFound: false,
|
||||||
|
gridXAdd: -1, // NOTE(chris): 0 based
|
||||||
|
gridYAdd: -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -38,7 +41,7 @@ export default {
|
|||||||
this.widgets.forEach((item,i) => item.index = i);
|
this.widgets.forEach((item,i) => item.index = i);
|
||||||
return this.widgets;
|
return this.widgets;
|
||||||
},
|
},
|
||||||
itemCoords() {
|
itemCoords() { // NOTE(chris): 1 based
|
||||||
if (!this.gridWidth)
|
if (!this.gridWidth)
|
||||||
return [];
|
return [];
|
||||||
let itemCoords = this.items.map(item => item.place[this.gridWidth] || this.createItemPlacement(item));
|
let itemCoords = this.items.map(item => item.place[this.gridWidth] || this.createItemPlacement(item));
|
||||||
@@ -103,11 +106,13 @@ export default {
|
|||||||
if (!this.gridWidth || !this.changeHeight)
|
if (!this.gridWidth || !this.changeHeight)
|
||||||
return 0;
|
return 0;
|
||||||
let minH = 0;
|
let minH = 0;
|
||||||
this.itemCoords.forEach((item,i) => minH = Math.max(minH, (!this.editMode && this.items[i].hidden) ? 0 : item.y + item.h - 1));
|
this.itemCoords.forEach((item,i) => minH = Math.max(minH, (!this.editMode && this.items[i].hidden) ? 0 : item.y - 1 + item.h));
|
||||||
// TODO(chris): the extraline should only be present if all slots are occupied
|
// TODO(chris): the extraline should only be present if all slots are occupied
|
||||||
return minH + this.editMode;
|
if (minH == 0 && this.editMode)
|
||||||
|
return 1;
|
||||||
|
return minH + this.editMode*this.dragging;
|
||||||
},
|
},
|
||||||
gridOccupiers() {
|
gridOccupiers() { // NOTE(chris): 0 based
|
||||||
let occupiers = [];
|
let occupiers = [];
|
||||||
let gridWidth = this.gridWidth;
|
let gridWidth = this.gridWidth;
|
||||||
this.items.forEach(item => {
|
this.items.forEach(item => {
|
||||||
@@ -123,20 +128,26 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return occupiers;
|
return occupiers;
|
||||||
|
},
|
||||||
|
cssBg() {
|
||||||
|
if (!this.editMode || this.dragging || !this.gridAddFound)
|
||||||
|
return 'transparent';
|
||||||
|
let x = this.gridXAdd, y = this.gridYAdd, h = this.gridHeight-1 || 1, w = this.gridWidth-1 || 1;
|
||||||
|
return `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="lightgray" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>')` + (100 * x/w) + '% ' + (100 * y/h) + '%/' + (100/this.gridWidth) + '% ' + (100/this.gridHeight) + '% no-repeat;cursor:pointer';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addWidget(evt) {
|
addWidget(evt) {
|
||||||
if (evt.target != this.$refs.container || !this.editMode)
|
if (evt.target != this.$refs.container || !this.editMode)
|
||||||
return;
|
return;
|
||||||
const rect = this.containerRect;
|
const rect = this.$refs.container.getBoundingClientRect();
|
||||||
const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth);
|
const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth);
|
||||||
const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight);
|
const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight);
|
||||||
if (this.gridOccupiers[gridY * this.gridWidth + gridX] === undefined) {
|
if (this.gridOccupiers[gridY * this.gridWidth + gridX] === undefined) {
|
||||||
let widget = { widget: 1, config: {}, place: {}, custom: 1 };
|
let widget = { widget: 1, config: {}, place: {}, custom: 1 };
|
||||||
widget.place[this.gridWidth] = {
|
widget.place[this.gridWidth] = {
|
||||||
x: gridX,
|
x: gridX+1,
|
||||||
y: gridY,
|
y: gridY+1,
|
||||||
w: 1,
|
w: 1,
|
||||||
h: 1
|
h: 1
|
||||||
};
|
};
|
||||||
@@ -162,7 +173,29 @@ export default {
|
|||||||
});*/
|
});*/
|
||||||
return item.place[this.gridWidth];
|
return item.place[this.gridWidth];
|
||||||
},
|
},
|
||||||
|
onMouseMove(evt) {
|
||||||
|
if (!this.editMode || this.dragging) {
|
||||||
|
this.gridXAdd = this.gridYAdd = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = this.$refs.container.getBoundingClientRect();
|
||||||
|
const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth);
|
||||||
|
const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight);
|
||||||
|
|
||||||
|
if (this.gridXAdd == gridX && this.gridYAdd == gridY)
|
||||||
|
return;
|
||||||
|
// TODO(chris): only mark it when its not occupied
|
||||||
|
this.gridXAdd = gridX;
|
||||||
|
this.gridYAdd = gridY;
|
||||||
|
this.gridAddFound = (this.gridOccupiers[gridX + gridY * this.gridWidth] === undefined);
|
||||||
|
},
|
||||||
|
onMouseLeave() {
|
||||||
|
this.gridXAdd = this.gridYAdd = -1;
|
||||||
|
this.gridAddFound = false;
|
||||||
|
},
|
||||||
startDrag(evt, item) {
|
startDrag(evt, item) {
|
||||||
|
this.dragging = 1;
|
||||||
this.gridXLast = -1;
|
this.gridXLast = -1;
|
||||||
this.gridYLast = -1;
|
this.gridYLast = -1;
|
||||||
item._x = this.itemCoords[item.index].x;
|
item._x = this.itemCoords[item.index].x;
|
||||||
@@ -178,6 +211,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
startResize(evt, item) {
|
startResize(evt, item) {
|
||||||
|
this.dragging = 1;
|
||||||
this.gridXLast = -1;
|
this.gridXLast = -1;
|
||||||
this.gridYLast = -1;
|
this.gridYLast = -1;
|
||||||
item._w = this.itemCoords[item.index].w;
|
item._w = this.itemCoords[item.index].w;
|
||||||
@@ -239,7 +273,7 @@ export default {
|
|||||||
onDragOver(evt) {
|
onDragOver(evt) {
|
||||||
let id, x, y, w, h;
|
let id, x, y, w, h;
|
||||||
const action = this.dataTransfer.action;
|
const action = this.dataTransfer.action;
|
||||||
const rect = this.containerRect;
|
const rect = this.$refs.container.getBoundingClientRect();
|
||||||
const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth);
|
const gridX = Math.floor(this.gridWidth * (evt.clientX - rect.left) / this.$refs.container.clientWidth);
|
||||||
const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight);
|
const gridY = Math.floor(this.gridHeight * (evt.clientY - rect.top) / this.$refs.container.clientHeight);
|
||||||
|
|
||||||
@@ -304,6 +338,9 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDrop() {
|
onDrop() {
|
||||||
|
this.dragging = 0;
|
||||||
|
this.gridXLast = -1;
|
||||||
|
this.gridYLast = -1;
|
||||||
let id = 0;
|
let id = 0;
|
||||||
let update = {};
|
let update = {};
|
||||||
while ((id = this.movedObjects.pop())) {
|
while ((id = this.movedObjects.pop())) {
|
||||||
@@ -376,14 +413,12 @@ export default {
|
|||||||
let self = this;
|
let self = this;
|
||||||
let cont = self.$refs.container;
|
let cont = self.$refs.container;
|
||||||
self.gridWidth = window.getComputedStyle(cont).getPropertyValue('grid-template-columns').split(" ").length;
|
self.gridWidth = window.getComputedStyle(cont).getPropertyValue('grid-template-columns').split(" ").length;
|
||||||
self.containerRect = cont.getBoundingClientRect();
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
for (const child of cont.children) {
|
for (const child of cont.children) {
|
||||||
child.style.display = 'none';
|
child.style.display = 'none';
|
||||||
}
|
}
|
||||||
self.gridWidth = window.getComputedStyle(cont).getPropertyValue('grid-template-columns').split(" ").length;
|
self.gridWidth = window.getComputedStyle(cont).getPropertyValue('grid-template-columns').split(" ").length;
|
||||||
self.containerRect = cont.getBoundingClientRect();
|
|
||||||
for (const child of cont.children) {
|
for (const child of cont.children) {
|
||||||
child.style.display = '';
|
child.style.display = '';
|
||||||
}
|
}
|
||||||
@@ -394,14 +429,16 @@ export default {
|
|||||||
<span class="col">{{name}}</span>
|
<span class="col">{{name}}</span>
|
||||||
<button class="col-auto btn" @click.prevent="editMode = editMode ? 0 : 1"><i class="fa-solid fa-gear"></i></button>
|
<button class="col-auto btn" @click.prevent="editMode = editMode ? 0 : 1"><i class="fa-solid fa-gear"></i></button>
|
||||||
</h3>
|
</h3>
|
||||||
<div class="position-relative" :style="'height:0;padding-bottom:' + (gridHeight * 100/gridWidth) + '%'">
|
<div :h="gridHeight" :w="gridWidth" class="position-relative" :style="'height:0;padding-bottom:' + (gridHeight * 100/gridWidth) + '%'">
|
||||||
<div ref="container"
|
<div ref="container"
|
||||||
class="position-absolute top-0 left-0 w-100 h-100 draganddropcontainer"
|
class="position-absolute top-0 left-0 w-100 h-100 draganddropcontainer"
|
||||||
:style="'display:grid;grid-template-rows:repeat('+gridHeight+',1fr)'"
|
:style="'display:grid;grid-template-rows:repeat('+gridHeight+',1fr);background:'+cssBg"
|
||||||
@click="addWidget($event)"
|
@click="addWidget($event)"
|
||||||
@drop="onDrop($event, 1)"
|
@drop="onDrop($event, 1)"
|
||||||
@dragover.prevent="onDragOver"
|
@dragover.prevent="onDragOver"
|
||||||
@dragenter.prevent>
|
@dragenter.prevent
|
||||||
|
@mousemove="onMouseMove"
|
||||||
|
@mouseleave="onMouseLeave">
|
||||||
|
|
||||||
<dashboard-item
|
<dashboard-item
|
||||||
v-for="item in items"
|
v-for="item in items"
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.allNewsList.slice(0, quantity);
|
return this.allNewsList.slice(0, quantity);
|
||||||
}
|
},
|
||||||
|
placeHolderImgURL: function() {
|
||||||
|
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'skin/images/fh_technikum_wien_illustration_klein.png';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created(){
|
created(){
|
||||||
axios
|
axios
|
||||||
@@ -69,7 +72,7 @@ export default {
|
|||||||
<div v-else class="h-100" :class="'row row-cols-' + width">
|
<div v-else class="h-100" :class="'row row-cols-' + width">
|
||||||
<div v-for="news in newsList" :key="news.id">
|
<div v-for="news in newsList" :key="news.id">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<img src="../../skin/images/fh_technikum_wien_illustration_klein.png" class="card-img-top">
|
<img :src="placeHolderImgURL" class="card-img-top">
|
||||||
<div class="card-footer"><span class="card-subtitle small text-muted">{{ formatDateTime(news.insertamum) }}</span></div>
|
<div class="card-footer"><span class="card-subtitle small text-muted">{{ formatDateTime(news.insertamum) }}</span></div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a href="#newsModal" class="card-title h5 stretched-link" @click="setSingleNews(news)">{{ news.betreff }}</a><br>
|
<a href="#newsModal" class="card-title h5 stretched-link" @click="setSingleNews(news)">{{ news.betreff }}</a><br>
|
||||||
@@ -85,7 +88,7 @@ export default {
|
|||||||
<BsModal ref="newsModal" id="newsModal" dialog-class="modal-lg">
|
<BsModal ref="newsModal" id="newsModal" dialog-class="modal-lg">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-5"><img src="../../skin/images/fh_technikum_wien_illustration_klein.png" class="img-fluid rounded-start"></div>
|
<div class="col-5"><img :src="placeHolderImgURL" class="img-fluid rounded-start"></div>
|
||||||
<div class="col-7 d-flex align-items-end">
|
<div class="col-7 d-flex align-items-end">
|
||||||
<p>{{ singleNews.betreff }}<br><small class="text-muted">{{ formatDateTime(singleNews.insertamum) }}</small></p>
|
<p>{{ singleNews.betreff }}<br><small class="text-muted">{{ formatDateTime(singleNews.insertamum) }}</small></p>
|
||||||
</div>
|
</div>
|
||||||
@@ -101,7 +104,7 @@ export default {
|
|||||||
<div class="row row-cols-5 g-4 h-100 px-5">
|
<div class="row row-cols-5 g-4 h-100 px-5">
|
||||||
<div v-for="news in allNewsList" :key="news.id">
|
<div v-for="news in allNewsList" :key="news.id">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<img src="../../skin/images/fh_technikum_wien_illustration_klein.png" class="card-img-top">
|
<img :src="placeHolderImgURL" class="card-img-top">
|
||||||
<div class="card-footer"><span class="card-subtitle small">{{ formatDateTime(news.insertamum) }}</span></div>
|
<div class="card-footer"><span class="card-subtitle small">{{ formatDateTime(news.insertamum) }}</span></div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a href="" class="card-title h5 stretched-link" @click="setSingleNews1(news)">{{ news.betreff }}</a><br>
|
<a href="" class="card-title h5 stretched-link" @click="setSingleNews1(news)">{{ news.betreff }}</a><br>
|
||||||
@@ -112,4 +115,4 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</BsModal>`
|
</BsModal>`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user