Compare commits
1 Commits
ai/issue-9
...
ai/task-4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7560529699 |
47
application/Api/v1/MeasurementsApicontroller.php
Normal file
47
application/Api/v1/MeasurementsApicontroller.php
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once(APPDIR."/Measurement/Measurement.php");
|
||||||
|
require_once(APPDIR."/Measurement/MeasurementModel.php");
|
||||||
|
|
||||||
|
class MeasurementsApicontroller extends mfBaseApicontroller
|
||||||
|
{
|
||||||
|
protected function init()
|
||||||
|
{
|
||||||
|
// Initialize database connection if needed
|
||||||
|
$this->addRoute("/measurements/latest", "getLatestMeasurements", "GET");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the latest measurements grouped by unique device_id and sensor_id combinations
|
||||||
|
* Returns one measurement per combination, limited to 50 results
|
||||||
|
*/
|
||||||
|
protected function getLatestMeasurements()
|
||||||
|
{
|
||||||
|
// Get limit from query parameters, default to 50, max 100
|
||||||
|
$limit = 50;
|
||||||
|
if (isset($this->get['limit']) && is_numeric($this->get['limit'])) {
|
||||||
|
$limit = min(100, max(1, intval($this->get['limit'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the latest measurements grouped by device_id and sensor_id
|
||||||
|
$measurements = MeasurementModel::getLatestGroupedByDeviceAndSensor($limit);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($measurements as $measurement) {
|
||||||
|
$result[] = [
|
||||||
|
'id' => $measurement->id,
|
||||||
|
'device_id' => $measurement->device_id,
|
||||||
|
'sensor_id' => $measurement->sensor_id,
|
||||||
|
'value' => (float)$measurement->value,
|
||||||
|
'unit' => $measurement->unit,
|
||||||
|
'timestamp' => $measurement->create,
|
||||||
|
'created_at' => date('Y-m-d H:i:s', $measurement->create)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return mfResponse::Ok([
|
||||||
|
'count' => count($result),
|
||||||
|
'measurements' => $result
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
application/Measurement/Measurement.php
Normal file
53
application/Measurement/Measurement.php
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Measurement extends mfBaseModel
|
||||||
|
{
|
||||||
|
private $device;
|
||||||
|
private $sensor;
|
||||||
|
|
||||||
|
public function getProperty($name)
|
||||||
|
{
|
||||||
|
if ($this->$name == null) {
|
||||||
|
if (!$this->id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($name == "device") {
|
||||||
|
$this->device = mfValuecache::singleton()->get("Device-id-".$this->device_id);
|
||||||
|
if($this->device === null) {
|
||||||
|
$this->device = new Device($this->device_id);
|
||||||
|
if($this->device->id) {
|
||||||
|
mfValuecache::singleton()->set("Device-id-".$this->device_id, $this->device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->device;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($name == "sensor") {
|
||||||
|
// Sensor would be a separate entity if it exists
|
||||||
|
// For now, just return the sensor_id
|
||||||
|
return $this->sensor_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$classname = ucfirst($name);
|
||||||
|
$idfield = $name."_id";
|
||||||
|
if(property_exists($this->data, $idfield)) {
|
||||||
|
$this->$name = mfValuecache::singleton()->get("mfObjectmodel-$name-".$this->$idfield);
|
||||||
|
if(!$this->$name) {
|
||||||
|
$this->$name = new $classname($this->$idfield);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->$name->id) {
|
||||||
|
mfValuecache::singleton()->set("mfObjectmodel-$name-".$this->$name->id, $this->$name);
|
||||||
|
return $this->$name;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->$name;
|
||||||
|
}
|
||||||
|
}
|
||||||
91
application/Measurement/MeasurementModel.php
Normal file
91
application/Measurement/MeasurementModel.php
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class MeasurementModel extends mfBaseModel
|
||||||
|
{
|
||||||
|
public static function search($filter = [])
|
||||||
|
{
|
||||||
|
$db = FronkDB::singleton();
|
||||||
|
$where = [];
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
if (isset($filter['device_id'])) {
|
||||||
|
if (is_array($filter['device_id'])) {
|
||||||
|
$where[] = "device_id IN (" . implode(',', array_map('intval', $filter['device_id'])) . ")";
|
||||||
|
} else {
|
||||||
|
$where[] = "device_id = " . intval($filter['device_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($filter['sensor_id'])) {
|
||||||
|
if (is_array($filter['sensor_id'])) {
|
||||||
|
$where[] = "sensor_id IN (" . implode(',', array_map('intval', $filter['sensor_id'])) . ")";
|
||||||
|
} else {
|
||||||
|
$where[] = "sensor_id = " . intval($filter['sensor_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$whereClause = '';
|
||||||
|
if (count($where)) {
|
||||||
|
$whereClause = ' WHERE ' . implode(' AND ', $where);
|
||||||
|
}
|
||||||
|
|
||||||
|
$order = ' ORDER BY `create` DESC';
|
||||||
|
if (isset($filter['order'])) {
|
||||||
|
$order = ' ORDER BY ' . $db->escape($filter['order']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$limit = '';
|
||||||
|
if (isset($filter['limit'])) {
|
||||||
|
$limit = ' LIMIT ' . intval($filter['limit']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM Measurement" . $whereClause . $order . $limit;
|
||||||
|
$res = $db->query($sql);
|
||||||
|
|
||||||
|
$measurements = [];
|
||||||
|
while ($row = $db->fetch_object($res)) {
|
||||||
|
$measurement = new Measurement();
|
||||||
|
$measurement->load($row);
|
||||||
|
$measurements[] = $measurement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $measurements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLatestGroupedByDeviceAndSensor($limit = 50)
|
||||||
|
{
|
||||||
|
$db = FronkDB::singleton();
|
||||||
|
|
||||||
|
// Get the most recent measurements, grouped by unique device_id and sensor_id combinations
|
||||||
|
// This query gets the latest measurement for each device_id/sensor_id combination
|
||||||
|
$sql = "
|
||||||
|
SELECT m.*
|
||||||
|
FROM Measurement m
|
||||||
|
INNER JOIN (
|
||||||
|
SELECT device_id, sensor_id, MAX(`create`) as max_create
|
||||||
|
FROM (
|
||||||
|
SELECT device_id, sensor_id, `create`
|
||||||
|
FROM Measurement
|
||||||
|
ORDER BY `create` DESC
|
||||||
|
LIMIT 1000
|
||||||
|
) AS recent
|
||||||
|
GROUP BY device_id, sensor_id
|
||||||
|
) AS latest
|
||||||
|
ON m.device_id = latest.device_id
|
||||||
|
AND m.sensor_id = latest.sensor_id
|
||||||
|
AND m.`create` = latest.max_create
|
||||||
|
ORDER BY m.`create` DESC
|
||||||
|
LIMIT " . intval($limit);
|
||||||
|
|
||||||
|
$res = $db->query($sql);
|
||||||
|
|
||||||
|
$measurements = [];
|
||||||
|
while ($row = $db->fetch_object($res)) {
|
||||||
|
$measurement = new Measurement();
|
||||||
|
$measurement->load($row);
|
||||||
|
$measurements[] = $measurement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $measurements;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -342,60 +342,5 @@ class WorkorderAdminController extends WorkorderBaseController
|
|||||||
|
|
||||||
self::returnJson(['success' => true, 'message' => 'Status erfolgreich auf "Zugewiesen" zurückgesetzt.']);
|
self::returnJson(['success' => true, 'message' => 'Status erfolgreich auf "Zugewiesen" zurückgesetzt.']);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function scheduleAppointmentAction()
|
|
||||||
{
|
|
||||||
if (empty($this->postData['workorderId']) || empty($this->postData['appointmentDate'])) self::sendError("Erforderliche Felder fehlen.");
|
|
||||||
$workorder = WorkorderModel::get($this->postData['workorderId']);
|
|
||||||
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
||||||
if ((int)date('H', $this->postData['appointmentDate']) >= 23 || (int)date('H', $this->postData['appointmentDate']) < 1) self::sendError("Bitte geben Sie eine Uhrzeit an!");
|
|
||||||
|
|
||||||
$workorder->appointmentDate = $this->postData['appointmentDate'];
|
|
||||||
$workorder->status = 'scheduled';
|
|
||||||
WorkorderModel::update((array)$workorder);
|
|
||||||
|
|
||||||
WorkorderJournalModel::create([
|
|
||||||
'workorderId' => $workorder->id, 'text' => 'Termin festgelegt auf: ' . date('d.m.Y H:i', $this->postData['appointmentDate']),
|
|
||||||
'create' => time(), 'createBy' => $this->user->id,
|
|
||||||
]);
|
|
||||||
self::returnJson(['success' => true, 'message' => 'Termin erfolgreich gespeichert.']);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function rescheduleAppointmentAction()
|
|
||||||
{
|
|
||||||
if (empty($this->postData['workorderId']) || empty($this->postData['appointmentDate']) || empty($this->postData['reason'])) self::sendError("Erforderliche Felder fehlen.");
|
|
||||||
$workorder = WorkorderModel::get($this->postData['workorderId']);
|
|
||||||
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
||||||
if ((int)date('H', $this->postData['appointmentDate']) >= 23 || (int)date('H', $this->postData['appointmentDate']) < 1) self::sendError("Bitte geben Sie eine Uhrzeit an!");
|
|
||||||
|
|
||||||
$oldDateFormatted = $workorder->appointmentDate ? date('d.m.Y H:i', $workorder->appointmentDate) : 'N/A';
|
|
||||||
$newDateFormatted = date('d.m.Y H:i', $this->postData['appointmentDate']);
|
|
||||||
$workorder->appointmentDate = $this->postData['appointmentDate'];
|
|
||||||
WorkorderModel::update((array)$workorder);
|
|
||||||
|
|
||||||
WorkorderJournalModel::create([
|
|
||||||
'workorderId' => $workorder->id, 'text' => "Termin verschoben von {$oldDateFormatted} auf {$newDateFormatted}. Grund: " . $this->postData['reason'],
|
|
||||||
'create' => time(), 'createBy' => $this->user->id,
|
|
||||||
]);
|
|
||||||
self::returnJson(['success' => true, 'message' => 'Termin erfolgreich verschoben.']);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function clearAppointmentAction()
|
|
||||||
{
|
|
||||||
if (empty($this->postData['workorderId'])) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
||||||
$workorder = WorkorderModel::get($this->postData['workorderId']);
|
|
||||||
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
||||||
|
|
||||||
$oldDateFormatted = $workorder->appointmentDate ? date('d.m.Y H:i', $workorder->appointmentDate) : 'N/A';
|
|
||||||
$workorder->appointmentDate = null;
|
|
||||||
$workorder->status = 'assigned';
|
|
||||||
WorkorderModel::update((array)$workorder);
|
|
||||||
|
|
||||||
WorkorderJournalModel::create([
|
|
||||||
'workorderId' => $workorder->id, 'text' => "Termin gelöscht (war: {$oldDateFormatted}).",
|
|
||||||
'create' => time(), 'createBy' => $this->user->id,
|
|
||||||
]);
|
|
||||||
self::returnJson(['success' => true, 'message' => 'Termin erfolgreich gelöscht.']);
|
|
||||||
}
|
|
||||||
//endregion
|
//endregion
|
||||||
}
|
}
|
||||||
@@ -90,23 +90,7 @@ Vue.component('workorder-admin', {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:appointmentdate="{ row }">
|
<template v-slot:appointmentdate="{ row }">{{ formatDate(row.appointmentDate, true) }}</template>
|
||||||
<div v-if="!row.appointmentDate && ['new', 'assigned', 'scheduled', 'correction_requested', 'problem_solved', 'civil_engineering_completed'].includes(row.status)">
|
|
||||||
<tt-date-picker placeholder="Termin festlegen..." :date-range="false"
|
|
||||||
@input="setAppointment(row, $event)" sm no-form-group
|
|
||||||
:additional-props="{ timePicker: true, timePicker24Hour: true, locale: { format: 'DD.MM.YYYY HH:mm' }, drops: 'up' }"/>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="row.appointmentDate">
|
|
||||||
<span>{{ formatDate(row.appointmentDate, true) }}</span>
|
|
||||||
<tt-button v-if="!['completed', 'cancelled', 'documented', 'charged', 'archived'].includes(row.status)"
|
|
||||||
icon="fas fa-edit" @click="openRescheduleModal(row)"
|
|
||||||
additional-class="btn-link btn-sm p-0 ml-2" title="Termin ändern"/>
|
|
||||||
<tt-button v-if="!['completed', 'cancelled', 'documented', 'charged', 'archived'].includes(row.status)"
|
|
||||||
icon="fas fa-times" @click="clearAppointment(row)"
|
|
||||||
additional-class="btn-link btn-sm p-0 ml-1 text-danger" title="Termin löschen"/>
|
|
||||||
</div>
|
|
||||||
<span v-else>–</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:expandedRow="{ row }">
|
<template v-slot:expandedRow="{ row }">
|
||||||
<civil-engineering-manager v-if="row.status === 'civil_engineering_required'" :workorder-id="row.id" :is-admin="true" class="mb-3"/>
|
<civil-engineering-manager v-if="row.status === 'civil_engineering_required'" :workorder-id="row.id" :is-admin="true" class="mb-3"/>
|
||||||
@@ -136,20 +120,13 @@ Vue.component('workorder-admin', {
|
|||||||
<tt-date-picker label="Deadline" v-model="massAssignModalData.deadline" :date-range="false" sm row/>
|
<tt-date-picker label="Deadline" v-model="massAssignModalData.deadline" :date-range="false" sm row/>
|
||||||
</tt-modal>
|
</tt-modal>
|
||||||
|
|
||||||
<tt-modal v-if="rescheduleModalData" :show.sync="rescheduleModalData" title="Termin verschieben" @submit="rescheduleAppointment">
|
|
||||||
<p><strong>Auftrag:</strong> #{{ rescheduleModalData.workorder.id }}</p>
|
|
||||||
<tt-date-picker label="Neuer Termin" :date-range="false" v-model="rescheduleModalData.newDate"
|
|
||||||
:additional-props="{ timePicker: true, timePicker24Hour: true, locale: { format: 'DD.MM.YYYY HH:mm' }, singleDatePicker: true }" sm row/>
|
|
||||||
<tt-textarea label="Grund" v-model="rescheduleModalData.reason" sm row required/>
|
|
||||||
</tt-modal>
|
|
||||||
|
|
||||||
</tt-card>
|
</tt-card>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
window, workordersToAssign: [], editingWorkorderId: null, editingDeadlineId: null, editingAdditionalInfoId: null,
|
window, workordersToAssign: [], editingWorkorderId: null, editingDeadlineId: null, editingAdditionalInfoId: null,
|
||||||
civilEngineeringData: null, tempAdditionalInfo: '', expandedNotes: [], companiesByTenant: {}, companiesLoading: false, massAssignCompanyId: null,
|
civilEngineeringData: null, tempAdditionalInfo: '', expandedNotes: [], companiesByTenant: {}, companiesLoading: false, massAssignCompanyId: null,
|
||||||
cancelWorkorderModalData: null, problemSolvedModalData: null, massAssignModalData: null, rescheduleModalData: null,
|
cancelWorkorderModalData: null, problemSolvedModalData: null, massAssignModalData: null,
|
||||||
crudConfig: {
|
crudConfig: {
|
||||||
...window.TT_CONFIG.CRUD_CONFIG, selectable: false, expandable: true,
|
...window.TT_CONFIG.CRUD_CONFIG, selectable: false, expandable: true,
|
||||||
customRowClass: (row) => {
|
customRowClass: (row) => {
|
||||||
@@ -344,98 +321,6 @@ Vue.component('workorder-admin', {
|
|||||||
this.$refs.table.$refs.table.refreshTable();
|
this.$refs.table.$refs.table.refreshTable();
|
||||||
this.cancelWorkorderModalData = null;
|
this.cancelWorkorderModalData = null;
|
||||||
} else window.notify('error', data.message || 'Stornierung fehlgeschlagen.');
|
} else window.notify('error', data.message || 'Stornierung fehlgeschlagen.');
|
||||||
},
|
|
||||||
getCalendarType(networkOwnerName) {
|
|
||||||
if (!networkOwnerName) return '1';
|
|
||||||
const name = networkOwnerName.toLowerCase();
|
|
||||||
if (name.includes('xinon')) return '2';
|
|
||||||
if (name.includes('sbidi')) return '7';
|
|
||||||
if (name.includes('estmk')) return '3';
|
|
||||||
return '1';
|
|
||||||
},
|
|
||||||
getCampaignName(preordercampaignId) {
|
|
||||||
const col = this.crudConfig.columns.find(c => c.key === 'preordercampaign_id');
|
|
||||||
const opt = col?.table?.filterOptions?.find(o => o.value == preordercampaignId);
|
|
||||||
return opt?.text || '';
|
|
||||||
},
|
|
||||||
openCalendarWithPrefill(workorder, dateUnix, win) {
|
|
||||||
const m = window.moment.unix(dateUnix);
|
|
||||||
const zeitraum = m.hour() < 12 ? 'VM' : 'NM';
|
|
||||||
const campaignName = this.getCampaignName(workorder.preordercampaign_id);
|
|
||||||
const locationParts = [workorder.street, workorder.hausnummer];
|
|
||||||
if (workorder.stiege) locationParts.push('/' + workorder.stiege);
|
|
||||||
const location = locationParts.join(' ') + ', ' + workorder.plz + ' ' + workorder.city;
|
|
||||||
const descLines = [];
|
|
||||||
if (workorder.oaid || campaignName || workorder.city) {
|
|
||||||
descLines.push([workorder.oaid, campaignName, workorder.city].filter(Boolean).join(' - '));
|
|
||||||
}
|
|
||||||
descLines.push('Zeitraum: ' + zeitraum);
|
|
||||||
if (workorder.phone) descLines.push('Tel.: ' + workorder.phone);
|
|
||||||
if (workorder.additionalInfo) descLines.push(workorder.additionalInfo);
|
|
||||||
const calendarData = {
|
|
||||||
type: this.getCalendarType(workorder.networkOwnerName),
|
|
||||||
subject: workorder.customerCompany || workorder.customerName || '',
|
|
||||||
location: location,
|
|
||||||
cstart: m.format('DD.MM.YYYY HH:mm'),
|
|
||||||
cend: m.clone().add(90, 'minutes').format('DD.MM.YYYY HH:mm'),
|
|
||||||
description: descLines.join('<br>'),
|
|
||||||
customer_phone: workorder.phone || null,
|
|
||||||
customer_email: workorder.email || null,
|
|
||||||
calendar_user_name: 'Pusnik',
|
|
||||||
attendee_names: ['Ziga Harc'],
|
|
||||||
};
|
|
||||||
localStorage.setItem('Calendar_create', JSON.stringify(calendarData));
|
|
||||||
win.location.href = '/Calendar/View';
|
|
||||||
},
|
|
||||||
async setAppointment(workorder, date) {
|
|
||||||
if (!date) return;
|
|
||||||
if (moment.unix(date).hour() >= 23 || moment.unix(date).hour() < 1) {
|
|
||||||
this.$refs.table.$refs.table.refreshTable();
|
|
||||||
return window.notify('error', 'Bitte Uhrzeit angeben!');
|
|
||||||
}
|
|
||||||
const calWin = window.open('about:blank', '_blank');
|
|
||||||
const {data} = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderAdmin/scheduleAppointment`, {
|
|
||||||
workorderId: workorder.id, appointmentDate: date
|
|
||||||
});
|
|
||||||
if (data.success) {
|
|
||||||
window.notify('success', data.message);
|
|
||||||
this.$refs.table.$refs.table.refreshTable();
|
|
||||||
this.openCalendarWithPrefill(workorder, date, calWin);
|
|
||||||
} else {
|
|
||||||
if (calWin) calWin.close();
|
|
||||||
window.notify('error', data.message || 'Ein Fehler ist aufgetreten.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
openRescheduleModal(row) {
|
|
||||||
this.rescheduleModalData = { workorder: row, newDate: row.appointmentDate, reason: '' };
|
|
||||||
},
|
|
||||||
async rescheduleAppointment() {
|
|
||||||
const { workorder, newDate, reason } = this.rescheduleModalData;
|
|
||||||
if (!newDate || !reason) return window.notify('error', 'Bitte geben Sie ein neues Datum und einen Grund an.');
|
|
||||||
if (moment.unix(newDate).hour() >= 23 || moment.unix(newDate).hour() < 1) return window.notify('error', 'Bitte Uhrzeit angeben!');
|
|
||||||
const calWin = window.open('about:blank', '_blank');
|
|
||||||
const {data} = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderAdmin/rescheduleAppointment`, {
|
|
||||||
workorderId: workorder.id, appointmentDate: newDate, reason: reason
|
|
||||||
});
|
|
||||||
if (data.success) {
|
|
||||||
window.notify('success', data.message);
|
|
||||||
this.$refs.table.$refs.table.refreshTable();
|
|
||||||
this.openCalendarWithPrefill(workorder, newDate, calWin);
|
|
||||||
this.rescheduleModalData = null;
|
|
||||||
} else {
|
|
||||||
if (calWin) calWin.close();
|
|
||||||
window.notify('error', data.message || 'Ein Fehler ist aufgetreten.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async clearAppointment(workorder) {
|
|
||||||
if (!confirm('Möchten Sie den Termin wirklich löschen?')) return;
|
|
||||||
const {data} = await axios.post(`${window.TT_CONFIG.BASE_PATH}/WorkorderAdmin/clearAppointment`, {
|
|
||||||
workorderId: workorder.id
|
|
||||||
});
|
|
||||||
if (data.success) {
|
|
||||||
window.notify('success', data.message);
|
|
||||||
this.$refs.table.$refs.table.refreshTable();
|
|
||||||
} else window.notify('error', data.message || 'Ein Fehler ist aufgetreten.');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|||||||
Reference in New Issue
Block a user