defmodule DaProductAppWeb.ParameterManagementLive.Dashboard do use DaProductAppWeb, :live_view alias DaProductApp.ParameterManagement alias DaProductApp.TerminalManagement @impl true def mount(_params, _session, socket) do parameter_templates = ParameterManagement.list_parameter_templates(%{is_active: true}) terminal_groups = TerminalManagement.list_terminal_groups() {:ok, assign(socket, # Core assigns current_page: "parameter_management", parameter_templates: parameter_templates, terminal_groups: terminal_groups, selected_template: nil, template_preview: nil, device_compatibility: %{}, # Form states show_parameter_form: false, show_custom_parameter_form: false, show_bulk_operations: false, show_device_groups: false, show_template_manager: false, show_job_management: false, parameter_mode: "template", # Results and status last_operation_result: nil, parameter_jobs: [], job_statistics: %{total: 0, completed: 0, running: 0, failed: 0} )} end @impl true def handle_params(_params, _url, socket) do # Load recent parameter jobs and statistics parameter_jobs = ParameterManagement.list_recent_parameter_push_logs(limit: 10) job_statistics = ParameterManagement.get_parameter_job_statistics() {:noreply, assign(socket, parameter_jobs: parameter_jobs, job_statistics: job_statistics )} end # Parameter Form Events @impl true def handle_event("show_parameter_form", _params, socket) do {:noreply, assign(socket, show_parameter_form: true, show_custom_parameter_form: false, show_bulk_operations: false, show_device_groups: false )} end def handle_event("hide_parameter_form", _params, socket) do {:noreply, assign(socket, show_parameter_form: false)} end def handle_event("show_custom_parameter_form", _params, socket) do {:noreply, assign(socket, show_custom_parameter_form: true, show_parameter_form: false, show_bulk_operations: false, show_device_groups: false )} end def handle_event("hide_custom_parameter_form", _params, socket) do {:noreply, assign(socket, show_custom_parameter_form: false)} end def handle_event("set_parameter_mode", %{"mode" => mode}, socket) do {:noreply, assign(socket, parameter_mode: mode, selected_template: nil, template_preview: nil, device_compatibility: %{} )} end # Template Selection Events def handle_event("select_template", %{"template_id" => template_id}, socket) do template_id = String.to_integer(template_id) template = ParameterManagement.get_parameter_template!(template_id) template_values = ParameterManagement.list_template_values_by_template(template_id) {:noreply, assign(socket, selected_template: template, template_preview: template_values )} end def handle_event("check_template_compatibility", %{"template_id" => template_id, "device_serials" => device_serials}, socket) do template_id = String.to_integer(template_id) device_list = String.split(device_serials, [",", ";", " "], trim: true) compatibility_results = Enum.map(device_list, fn device_serial -> case ParameterManagement.check_template_compatibility(template_id, device_serial) do {:ok, compatibility} -> %{device_serial: device_serial, compatible: true, info: compatibility} {:error, reason} -> %{device_serial: device_serial, compatible: false, reason: reason} end end) compatible_count = Enum.count(compatibility_results, & &1.compatible) compatibility_summary = %{ total: length(device_list), compatible: compatible_count, incompatible: length(device_list) - compatible_count, results: compatibility_results } {:noreply, assign(socket, device_compatibility: compatibility_summary)} end # Parameter Push Events def handle_event("push_parameters", params, socket) do IO.inspect(params, label: "push_parameters received params") device_serials_str = params["device_serials"] || "" # Handle custom parameters custom_parameters = params["custom_parameters"] || %{} # Build parameters map from custom fields parameters = %{ "mqtt_ip" => custom_parameters["mqtt_ip"] || "", "mqtt_port" => custom_parameters["mqtt_port"] || "", "http_ip" => custom_parameters["http_ip"] || "", "http_port" => custom_parameters["http_port"] || "", "username" => custom_parameters["username"] || "", "keepalive_time" => custom_parameters["keepalive_time"] || "" } |> Enum.filter(fn {_k, v} -> v != "" end) |> Enum.into(%{}) device_serials = String.split(device_serials_str, [",", ";", " "], trim: true) if device_serials == [] do {:noreply, put_flash(socket, :error, "Please enter at least one device serial number")} else case TerminalManagement.ParameterPushService.batch_send_parameters(device_serials, parameters) do {:ok, result} -> {:noreply, socket |> put_flash(:info, "Parameter push completed: #{result.successes} successful, #{result.failures} failed") |> assign(show_parameter_form: false)} {:error, reason} -> {:noreply, put_flash(socket, :error, "Parameter push failed: #{reason}")} end end end def handle_event("apply_template", params, socket) do IO.inspect(params, label: "apply_template received params") template_id = case params["template_id"] do nil -> socket.assigns.selected_template && socket.assigns.selected_template.id id_str -> String.to_integer(id_str) end device_serials_str = params["device_serials"] || "" schedule_at = params["schedule_at"] || "" device_list = String.split(device_serials_str, [",", ";", " "], trim: true) cond do template_id == nil -> {:noreply, put_flash(socket, :error, "Please select a parameter template")} device_list == [] -> {:noreply, put_flash(socket, :error, "Please enter at least one device serial number")} true -> case schedule_at do "" -> # Immediate execution result = apply_template_to_devices(device_list, template_id) message = if result.success do "Template applied successfully: #{result.successes}/#{result.total} devices" else "Template application completed with errors: #{result.successes} successful, #{result.failures} failed" end {:noreply, assign(socket, show_parameter_form: false, last_operation_result: result ) |> put_flash(if(result.success, do: :info, else: :warning), message)} schedule_time -> # Scheduled execution case DateTime.from_iso8601(schedule_time <> ":00Z") do {:ok, datetime, _} -> case DaProductApp.Workers.ParameterPushWorker.schedule_batch_template_application( device_list, template_id, %{}, schedule_at: datetime ) do {:ok, job} -> {:noreply, assign(socket, show_parameter_form: false, last_operation_result: %{ success: true, message: "Template application scheduled successfully", job_id: job.id, scheduled_at: datetime } ) |> put_flash(:info, "Template application scheduled for #{Calendar.strftime(datetime, "%Y-%m-%d %H:%M")}")} {:error, reason} -> {:noreply, put_flash(socket, :error, "Failed to schedule template application: #{reason}")} end {:error, _} -> {:noreply, put_flash(socket, :error, "Invalid schedule time format")} end end end end # Bulk Operations Events def handle_event("show_bulk_operations", _params, socket) do {:noreply, assign(socket, show_bulk_operations: true, show_parameter_form: false, show_custom_parameter_form: false, show_device_groups: false )} end def handle_event("hide_bulk_operations", _params, socket) do {:noreply, assign(socket, show_bulk_operations: false)} end # Device Groups Events def handle_event("show_device_groups", _params, socket) do {:noreply, assign(socket, show_device_groups: true, show_parameter_form: false, show_custom_parameter_form: false, show_bulk_operations: false )} end def handle_event("hide_device_groups", _params, socket) do {:noreply, assign(socket, show_device_groups: false)} end def handle_event("apply_template_to_group", %{"group_id" => _group_id}, socket) do # TODO: Implement group template application {:noreply, put_flash(socket, :info, "Group template application feature coming soon")} end # Export Events def handle_event("export_parameter_logs", _params, socket) do # TODO: Implement parameter logs export {:noreply, put_flash(socket, :info, "Parameter logs export feature coming soon")} end def handle_event("export_template_usage", _params, socket) do # TODO: Implement template usage export {:noreply, put_flash(socket, :info, "Template usage export feature coming soon")} end # Refresh Events def handle_event("refresh_data", _params, socket) do parameter_jobs = ParameterManagement.list_recent_parameter_push_logs(limit: 10) job_statistics = ParameterManagement.get_parameter_job_statistics() {:noreply, assign(socket, parameter_jobs: parameter_jobs, job_statistics: job_statistics )} end # Template Manager Events def handle_event("show_template_manager", _params, socket) do {:noreply, assign(socket, show_template_manager: true, show_parameter_form: false, show_custom_parameter_form: false, show_bulk_operations: false, show_device_groups: false )} end def handle_event("hide_template_manager", _params, socket) do {:noreply, assign(socket, show_template_manager: false)} end # Job Management Events def handle_event("show_job_management", _params, socket) do {:noreply, assign(socket, show_job_management: true, show_parameter_form: false, show_custom_parameter_form: false, show_bulk_operations: false, show_device_groups: false, show_template_manager: false )} end def handle_event("hide_job_management", _params, socket) do {:noreply, assign(socket, show_job_management: false)} end # Catch-all for unhandled events def handle_event(event, params, socket) do IO.puts("DEBUG: Unhandled event in Parameter Dashboard: #{event}") IO.inspect(params, label: "params") {:noreply, socket} end # Private helper functions defp apply_template_to_devices(device_serials, template_id) do results = Enum.map(device_serials, fn device_serial -> case ParameterManagement.apply_parameter_template(device_serial, template_id, %{}) do {:ok, push_log} -> {device_serial, :ok, push_log.request_id} {:error, reason} -> {device_serial, :error, reason} end end) successes = Enum.count(results, fn {_, status, _} -> status == :ok end) failures = Enum.count(results, fn {_, status, _} -> status == :error end) %{ success: failures == 0, total: length(device_serials), successes: successes, failures: failures, results: results, message: "Template applied to #{successes}/#{length(device_serials)} devices" } end end