gps_system/app/Livewire/DeviceManagement.php
sackey 6b878bb0a0
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
Initial commit
2025-09-12 16:19:56 +00:00

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(),
];
}
}