Add API service layer, authentication store, and composables

- Implement API service modules for sensors, rooms, analytics, health,
and auth - Add Pinia auth store for JWT token management and validation
- Create Vue composables for API integration and state management -
Update settings and AI optimization views for code style and connection
URLs - Add test-websocket.html for local WebSocket testing
This commit is contained in:
rafaeldpsilva
2025-09-18 14:29:36 +01:00
parent 32c63628b6
commit faed09d3b6
10 changed files with 1498 additions and 114 deletions

341
src/composables/useApi.ts Normal file
View File

@@ -0,0 +1,341 @@
/**
* Vue Composable for API Integration
* Provides reactive API state management
*/
import { ref, reactive } from 'vue'
import {
sensorsApi,
roomsApi,
analyticsApi,
healthApi,
type SensorInfo,
type RoomInfo,
type RoomData,
type AnalyticsSummary,
type EnergyTrends,
type RoomComparison,
type SystemEvent,
type HealthCheck,
type SystemStatus,
type DataQuery,
type DataResponse
} from '@/services'
interface ApiState {
loading: boolean
error: string | null
}
export function useApi() {
// Global API state
const globalState = reactive<ApiState>({
loading: false,
error: null
})
// Helper to handle API calls with state management
async function handleApiCall<T>(
apiCall: () => Promise<T>,
localState?: { loading: boolean; error: string | null }
): Promise<T | null> {
const state = localState || globalState
state.loading = true
state.error = null
try {
const result = await apiCall()
return result
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'
state.error = errorMessage
console.error('API call failed:', errorMessage)
return null
} finally {
state.loading = false
}
}
return {
globalState,
handleApiCall
}
}
// Sensors API composable
export function useSensorsApi() {
const state = reactive<ApiState>({
loading: false,
error: null
})
const sensors = ref<SensorInfo[]>([])
const currentSensor = ref<SensorInfo | null>(null)
const sensorData = ref<DataResponse | null>(null)
const { handleApiCall } = useApi()
const fetchSensors = async (params?: {
room?: string
sensor_type?: any
status?: any
}) => {
const result = await handleApiCall(
() => sensorsApi.getSensors(params),
state
)
if (result) {
sensors.value = result
}
return result
}
const fetchSensor = async (sensorId: string) => {
const result = await handleApiCall(
() => sensorsApi.getSensor(sensorId),
state
)
if (result) {
currentSensor.value = result
}
return result
}
const fetchSensorData = async (
sensorId: string,
params?: {
start_time?: number
end_time?: number
limit?: number
offset?: number
}
) => {
const result = await handleApiCall(
() => sensorsApi.getSensorData(sensorId, params),
state
)
if (result) {
sensorData.value = result
}
return result
}
const queryData = async (query: DataQuery) => {
return handleApiCall(
() => sensorsApi.queryData(query),
state
)
}
const updateSensorMetadata = async (
sensorId: string,
metadata: Record<string, any>
) => {
return handleApiCall(
() => sensorsApi.updateSensorMetadata(sensorId, metadata),
state
)
}
const deleteSensor = async (sensorId: string) => {
return handleApiCall(
() => sensorsApi.deleteSensor(sensorId),
state
)
}
const exportData = async (params: {
start_time: number
end_time: number
sensor_ids?: string
format?: 'json' | 'csv'
}) => {
return handleApiCall(
() => sensorsApi.exportData(params),
state
)
}
return {
state,
sensors,
currentSensor,
sensorData,
fetchSensors,
fetchSensor,
fetchSensorData,
queryData,
updateSensorMetadata,
deleteSensor,
exportData
}
}
// Rooms API composable
export function useRoomsApi() {
const state = reactive<ApiState>({
loading: false,
error: null
})
const rooms = ref<RoomInfo[]>([])
const currentRoomData = ref<RoomData | null>(null)
const { handleApiCall } = useApi()
const fetchRooms = async () => {
const result = await handleApiCall(
() => roomsApi.getRooms(),
state
)
if (result) {
rooms.value = result
}
return result
}
const fetchRoomData = async (
roomName: string,
params?: {
start_time?: number
end_time?: number
limit?: number
}
) => {
const result = await handleApiCall(
() => roomsApi.getRoomData(roomName, params),
state
)
if (result) {
currentRoomData.value = result
}
return result
}
return {
state,
rooms,
currentRoomData,
fetchRooms,
fetchRoomData
}
}
// Analytics API composable
export function useAnalyticsApi() {
const state = reactive<ApiState>({
loading: false,
error: null
})
const summary = ref<AnalyticsSummary | null>(null)
const trends = ref<EnergyTrends | null>(null)
const roomComparison = ref<RoomComparison | null>(null)
const events = ref<SystemEvent[]>([])
const { handleApiCall } = useApi()
const fetchAnalyticsSummary = async (hours: number = 24) => {
const result = await handleApiCall(
() => analyticsApi.getAnalyticsSummary(hours),
state
)
if (result) {
summary.value = result
}
return result
}
const fetchEnergyTrends = async (hours: number = 168) => {
const result = await handleApiCall(
() => analyticsApi.getEnergyTrends(hours),
state
)
if (result) {
trends.value = result
}
return result
}
const fetchRoomComparison = async (hours: number = 24) => {
const result = await handleApiCall(
() => analyticsApi.getRoomComparison(hours),
state
)
if (result) {
roomComparison.value = result
}
return result
}
const fetchEvents = async (params?: {
severity?: string
event_type?: string
hours?: number
limit?: number
}) => {
const result = await handleApiCall(
() => analyticsApi.getEvents(params),
state
)
if (result) {
events.value = result.events
}
return result
}
return {
state,
summary,
trends,
roomComparison,
events,
fetchAnalyticsSummary,
fetchEnergyTrends,
fetchRoomComparison,
fetchEvents
}
}
// Health API composable
export function useHealthApi() {
const state = reactive<ApiState>({
loading: false,
error: null
})
const health = ref<HealthCheck | null>(null)
const status = ref<SystemStatus | null>(null)
const { handleApiCall } = useApi()
const fetchHealth = async () => {
const result = await handleApiCall(
() => healthApi.getHealth(),
state
)
if (result) {
health.value = result
}
return result
}
const fetchStatus = async () => {
const result = await handleApiCall(
() => healthApi.getStatus(),
state
)
if (result) {
status.value = result
}
return result
}
return {
state,
health,
status,
fetchHealth,
fetchStatus
}
}