419 lines
15 KiB
PHP
419 lines
15 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire;
|
|
|
|
use Livewire\Component;
|
|
use Livewire\WithPagination;
|
|
use App\Models\Device;
|
|
use App\Models\DeviceGroup;
|
|
use App\Models\Driver;
|
|
use App\Services\TraccarService;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class DeviceManagement extends Component
|
|
{
|
|
use WithPagination;
|
|
|
|
public $search = '';
|
|
public $statusFilter = 'all';
|
|
public $groupFilter = 'all';
|
|
public $showForm = false;
|
|
public $editingDevice = null;
|
|
|
|
// Form fields
|
|
public $name = '';
|
|
public $unique_id = '';
|
|
public $imei = '';
|
|
public $phone = '';
|
|
public $model = '';
|
|
public $contact = '';
|
|
public $category = 'default';
|
|
public $protocol = '';
|
|
public $group_id = '';
|
|
public $driver_id = '';
|
|
public $is_active = true;
|
|
public $deviceAttributes = '';
|
|
|
|
protected $traccarService;
|
|
|
|
public function mount()
|
|
{
|
|
// Initialize TraccarService
|
|
$this->traccarService = app(TraccarService::class);
|
|
}
|
|
|
|
public function boot(TraccarService $traccarService)
|
|
{
|
|
$this->traccarService = $traccarService;
|
|
}
|
|
|
|
protected function getTraccarService()
|
|
{
|
|
if (!$this->traccarService) {
|
|
$this->traccarService = app(TraccarService::class);
|
|
}
|
|
return $this->traccarService;
|
|
}
|
|
|
|
protected $rules = [
|
|
'name' => 'required|string|max:255',
|
|
'unique_id' => 'required|string|max:255|unique:devices,unique_id',
|
|
'imei' => 'nullable|string|max:255',
|
|
'phone' => 'nullable|string|max:255',
|
|
'model' => 'nullable|string|max:255',
|
|
'contact' => 'nullable|string|max:255',
|
|
'category' => 'required|string|max:255',
|
|
'protocol' => 'nullable|string|max:255',
|
|
'group_id' => 'nullable|exists:device_groups,id',
|
|
'driver_id' => 'nullable|exists:drivers,id',
|
|
'is_active' => 'boolean',
|
|
'deviceAttributes' => 'nullable|json',
|
|
];
|
|
|
|
public function updatingSearch()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatingStatusFilter()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function updatingGroupFilter()
|
|
{
|
|
$this->resetPage();
|
|
}
|
|
|
|
public function createDevice()
|
|
{
|
|
$this->openCreateModal();
|
|
}
|
|
|
|
public function openCreateModal()
|
|
{
|
|
$this->reset(['name', 'unique_id', 'imei', 'phone', 'model', 'contact', 'category', 'group_id', 'driver_id', 'is_active', 'deviceAttributes']);
|
|
$this->editingDevice = false;
|
|
$this->showForm = true;
|
|
}
|
|
|
|
public function editDevice($deviceId)
|
|
{
|
|
$device = Device::findOrFail($deviceId);
|
|
|
|
if ($device->user_id !== Auth::id()) {
|
|
abort(403);
|
|
}
|
|
|
|
$this->editingDevice = $device;
|
|
$this->name = $device->name;
|
|
$this->unique_id = $device->unique_id;
|
|
$this->imei = $device->imei;
|
|
$this->phone = $device->phone;
|
|
$this->model = $device->model;
|
|
$this->contact = $device->contact;
|
|
$this->category = $device->category;
|
|
$this->protocol = $device->protocol;
|
|
$this->group_id = $device->group_id;
|
|
$this->driver_id = $device->driver_id;
|
|
$this->is_active = $device->is_active;
|
|
$this->deviceAttributes = $device->attributes ? json_encode($device->attributes) : '';
|
|
|
|
$this->showForm = true;
|
|
}
|
|
|
|
public function saveDevice()
|
|
{
|
|
if ($this->editingDevice) {
|
|
$this->rules['unique_id'] = 'required|string|max:255|unique:devices,unique_id,' . $this->editingDevice->id;
|
|
}
|
|
|
|
$this->validate();
|
|
|
|
try {
|
|
// Prepare attributes for Traccar (must be an object, not null)
|
|
$attributes = [];
|
|
if ($this->deviceAttributes) {
|
|
$decoded = json_decode($this->deviceAttributes, true);
|
|
if (is_array($decoded)) {
|
|
$attributes = $decoded;
|
|
}
|
|
}
|
|
|
|
$deviceData = [
|
|
'name' => $this->name,
|
|
'uniqueId' => $this->unique_id,
|
|
'phone' => $this->phone ?: null,
|
|
'model' => $this->model ?: null,
|
|
'contact' => $this->contact ?: null,
|
|
'category' => $this->category ?: 'default',
|
|
'attributes' => (object)$attributes, // Always send as object for Traccar
|
|
];
|
|
|
|
if ($this->editingDevice) {
|
|
// Update existing device
|
|
try {
|
|
if ($this->editingDevice->traccar_device_id) {
|
|
$this->getTraccarService()->updateDevice($this->editingDevice->traccar_device_id, $deviceData);
|
|
}
|
|
} catch (\Exception $e) {
|
|
// Log Traccar error but continue with local update
|
|
\Log::warning('Failed to update device in Traccar: ' . $e->getMessage());
|
|
}
|
|
|
|
$this->editingDevice->update([
|
|
'name' => $this->name,
|
|
'unique_id' => $this->unique_id,
|
|
'imei' => $this->imei,
|
|
'phone' => $this->phone,
|
|
'model' => $this->model,
|
|
'contact' => $this->contact,
|
|
'category' => $this->category,
|
|
'protocol' => $this->protocol,
|
|
'group_id' => $this->group_id ?: null,
|
|
'driver_id' => $this->driver_id ?: null,
|
|
'is_active' => $this->is_active,
|
|
'attributes' => $this->deviceAttributes ? json_decode($this->deviceAttributes, true) : null,
|
|
]);
|
|
|
|
session()->flash('message', 'Device updated successfully' . ($this->editingDevice->traccar_device_id ? ' and synced with Traccar' : ''));
|
|
$this->dispatch('device-updated');
|
|
} else {
|
|
// Create new device - try Traccar first, then local
|
|
$traccarDeviceId = null;
|
|
$traccarSyncMessage = '';
|
|
|
|
try {
|
|
$traccarDevice = $this->getTraccarService()->createDevice($deviceData);
|
|
if (isset($traccarDevice['id']) && !empty($traccarDevice['id'])) {
|
|
$traccarDeviceId = $traccarDevice['id'];
|
|
$traccarSyncMessage = ' and automatically synced with Traccar';
|
|
} else {
|
|
\Log::info('Traccar device creation returned empty response', ['response' => $traccarDevice]);
|
|
$traccarSyncMessage = '. Traccar sync is available but returned empty response';
|
|
}
|
|
} catch (\Exception $e) {
|
|
// Log Traccar error but continue with local creation
|
|
\Log::warning('Failed to create device in Traccar: ' . $e->getMessage());
|
|
$traccarSyncMessage = '. Traccar sync failed - device can be synced manually later';
|
|
}
|
|
|
|
// Create device in local database
|
|
$device = Device::create([
|
|
'user_id' => Auth::id(),
|
|
'traccar_device_id' => $traccarDeviceId,
|
|
'name' => $this->name,
|
|
'unique_id' => $this->unique_id,
|
|
'imei' => $this->imei,
|
|
'phone' => $this->phone,
|
|
'model' => $this->model,
|
|
'contact' => $this->contact,
|
|
'category' => $this->category,
|
|
'protocol' => $this->protocol,
|
|
'status' => 'unknown',
|
|
'group_id' => $this->group_id ?: null,
|
|
'driver_id' => $this->driver_id ?: null,
|
|
'is_active' => $this->is_active,
|
|
'attributes' => $this->deviceAttributes ? json_decode($this->deviceAttributes, true) : null,
|
|
]);
|
|
|
|
$message = 'Device "' . $this->name . '" created successfully' . $traccarSyncMessage;
|
|
session()->flash('message', $message);
|
|
$this->dispatch('device-created');
|
|
}
|
|
|
|
$this->resetForm();
|
|
$this->showForm = false;
|
|
|
|
} catch (\Exception $e) {
|
|
$this->dispatch('device-error', ['message' => 'Failed to save device: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
public function deleteDevice($deviceId)
|
|
{
|
|
$device = Device::findOrFail($deviceId);
|
|
|
|
if ($device->user_id !== Auth::id()) {
|
|
abort(403);
|
|
}
|
|
|
|
try {
|
|
// Delete from Traccar if it exists
|
|
if ($device->traccar_device_id) {
|
|
try {
|
|
$this->getTraccarService()->deleteDevice($device->traccar_device_id);
|
|
} catch (\Exception $e) {
|
|
// Log Traccar error but continue with local deletion
|
|
\Log::warning('Failed to delete device from Traccar: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
$device->delete();
|
|
session()->flash('message', 'Device deleted successfully' . ($device->traccar_device_id ? ' and removed from Traccar' : ''));
|
|
$this->dispatch('device-deleted');
|
|
} catch (\Exception $e) {
|
|
session()->flash('error', 'Failed to delete device: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function syncWithTraccar()
|
|
{
|
|
try {
|
|
$traccarDevices = $this->getTraccarService()->getDevices();
|
|
$user = Auth::user();
|
|
$syncedCount = 0;
|
|
|
|
foreach ($traccarDevices as $traccarDevice) {
|
|
Device::updateOrCreate(
|
|
['traccar_device_id' => $traccarDevice['id']],
|
|
[
|
|
'user_id' => $user->id,
|
|
'name' => $traccarDevice['name'],
|
|
'unique_id' => $traccarDevice['uniqueId'],
|
|
'phone' => $traccarDevice['phone'] ?? null,
|
|
'model' => $traccarDevice['model'] ?? null,
|
|
'contact' => $traccarDevice['contact'] ?? null,
|
|
'category' => $traccarDevice['category'] ?? 'default',
|
|
'attributes' => $traccarDevice['attributes'] ?? null,
|
|
]
|
|
);
|
|
$syncedCount++;
|
|
}
|
|
|
|
session()->flash('message', "Successfully synced {$syncedCount} devices from Traccar");
|
|
$this->dispatch('devices-synced');
|
|
} catch (\Exception $e) {
|
|
session()->flash('error', 'Failed to sync with Traccar: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function syncUnsyncedDevicesToTraccar()
|
|
{
|
|
try {
|
|
$unsyncedDevices = Device::whereNull('traccar_device_id')->get();
|
|
$syncedCount = 0;
|
|
$errorCount = 0;
|
|
|
|
foreach ($unsyncedDevices as $device) {
|
|
try {
|
|
// Prepare attributes for Traccar
|
|
$attributes = [];
|
|
if ($device->attributes) {
|
|
if (is_string($device->attributes)) {
|
|
$decoded = json_decode($device->attributes, true);
|
|
if (is_array($decoded)) {
|
|
$attributes = $decoded;
|
|
}
|
|
} elseif (is_array($device->attributes)) {
|
|
$attributes = $device->attributes;
|
|
}
|
|
}
|
|
|
|
$deviceData = [
|
|
'name' => $device->name,
|
|
'uniqueId' => $device->unique_id,
|
|
'phone' => $device->phone ?: null,
|
|
'model' => $device->model ?: null,
|
|
'contact' => $device->contact ?: null,
|
|
'category' => $device->category ?: 'default',
|
|
'attributes' => (object)$attributes,
|
|
];
|
|
|
|
$traccarDevice = $this->getTraccarService()->createDevice($deviceData);
|
|
|
|
if (isset($traccarDevice['id']) && !empty($traccarDevice['id'])) {
|
|
$device->update(['traccar_device_id' => $traccarDevice['id']]);
|
|
$syncedCount++;
|
|
} else {
|
|
$errorCount++;
|
|
}
|
|
} catch (\Exception $e) {
|
|
\Log::warning("Failed to sync device {$device->name} to Traccar: " . $e->getMessage());
|
|
$errorCount++;
|
|
}
|
|
}
|
|
|
|
if ($syncedCount > 0) {
|
|
session()->flash('message', "Successfully synced {$syncedCount} unsynced devices to Traccar" . ($errorCount > 0 ? ". {$errorCount} devices failed to sync." : ""));
|
|
} else {
|
|
session()->flash('error', "No devices were synced. " . ($errorCount > 0 ? "{$errorCount} devices failed." : "All devices are already synced."));
|
|
}
|
|
|
|
$this->dispatch('devices-synced');
|
|
} catch (\Exception $e) {
|
|
session()->flash('error', 'Failed to sync unsynced devices: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function cancelForm()
|
|
{
|
|
$this->resetForm();
|
|
$this->showForm = false;
|
|
}
|
|
|
|
private function resetForm()
|
|
{
|
|
$this->editingDevice = null;
|
|
$this->name = '';
|
|
$this->unique_id = '';
|
|
$this->imei = '';
|
|
$this->phone = '';
|
|
$this->model = '';
|
|
$this->contact = '';
|
|
$this->category = 'default';
|
|
$this->protocol = '';
|
|
$this->group_id = '';
|
|
$this->driver_id = '';
|
|
$this->is_active = true;
|
|
$this->deviceAttributes = '';
|
|
$this->resetValidation();
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
$query = Device::where('user_id', Auth::id())
|
|
->with(['group', 'driver', 'currentPosition']);
|
|
|
|
// Apply filters
|
|
if ($this->search) {
|
|
$query->where(function ($q) {
|
|
$q->where('name', 'like', '%' . $this->search . '%')
|
|
->orWhere('unique_id', 'like', '%' . $this->search . '%')
|
|
->orWhere('imei', 'like', '%' . $this->search . '%');
|
|
});
|
|
}
|
|
|
|
if ($this->statusFilter !== 'all') {
|
|
$query->where('status', $this->statusFilter);
|
|
}
|
|
|
|
if ($this->groupFilter !== 'all') {
|
|
$query->where('group_id', $this->groupFilter);
|
|
}
|
|
|
|
$devices = $query->orderBy('name')->paginate(10);
|
|
|
|
$deviceGroups = DeviceGroup::active()->get();
|
|
$drivers = Driver::active()->get();
|
|
|
|
return view('livewire.device-management', [
|
|
'devices' => $devices,
|
|
'deviceGroups' => $deviceGroups,
|
|
'drivers' => $drivers,
|
|
]);
|
|
}
|
|
|
|
public function getStatsProperty()
|
|
{
|
|
$userId = Auth::id();
|
|
|
|
return [
|
|
'total_devices' => Device::where('user_id', $userId)->count(),
|
|
'active_devices' => Device::where('user_id', $userId)->where('is_active', true)->count(),
|
|
'online_devices' => Device::where('user_id', $userId)->where('status', 'online')->count(),
|
|
'with_traccar' => Device::where('user_id', $userId)->whereNotNull('traccar_device_id')->count(),
|
|
];
|
|
}
|
|
}
|