Appearance
Monitoring Module - Monitoramento de Horas
Módulo para acompanhamento de horas trabalhadas pelos prestadores (providers). O borrower (contratante) acompanha as horas que os providers (prestadores) lançam na plataforma.
Visão Geral
O módulo permite:
- Listar prestadores com resumo de horas (semanal/mensal)
- Visualizar detalhes de horas por prestador
- Visualizar entradas diárias de trabalho
- Criar/editar/excluir entradas de trabalho
- Gerar relatórios de horas
Estrutura do Módulo
src/modules/monitoring/
├── pages/
│ ├── index.vue # Página raiz (redirect)
│ ├── ListMonitoring.vue # Lista de prestadores
│ ├── MonitoringDetail.vue # Detalhes de um prestador
│ └── ListReport.vue # Relatórios (em desenvolvimento)
├── components/
│ ├── List/
│ │ ├── MonitoringTableList.vue # Tabela de prestadores
│ │ ├── MonitoringFilters.vue # Filtro por status
│ │ ├── TableHeader.vue # Cabeçalho com busca
│ │ └── ExportListModal.vue # Modal para exportar lista
│ └── Detail/
│ ├── DetailHeader.vue # Cabeçalho do detalhe
│ ├── SummaryCard.vue # Card de resumo
│ ├── WeeklySummary.vue # Gráfico semanal
│ ├── MonthlySummary.vue # Gráfico mensal
│ ├── DailyEntriesFlat.vue # Lista de entradas diárias
│ ├── ConsolidatedTable.vue # Tabela consolidada
│ ├── WorkEntryModal.vue # Modal CRUD de entradas
│ └── ExportReportModal.vue # Modal para exportar relatório
├── services/
│ └── monitoring.ts # Chamadas de API
├── stores/
│ └── monitoring.ts # Pinia store
└── router/
└── index.ts # Rotas do móduloAPI Endpoints
Providers (Monitoring)
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /monitoring/ | Lista providers com resumo de horas |
| GET | /monitoring/:id | Detalhes de um provider (com summaries) |
| GET | /monitoring/:id/entries | Lista entradas de trabalho |
Work Entries
| Método | Endpoint | Descrição |
|---|---|---|
| GET | /monitoring/entries/:id | Busca entrada específica |
| POST | /monitoring/entries | Cria nova entrada |
| PUT | /monitoring/entries/:id | Atualiza entrada |
| DELETE | /monitoring/entries/:id | Remove entrada |
Query Parameters
GET /monitoring/
?search=string # Busca por nome da empresa ou contrato
&status=string # 'active' | 'inactive' | 'all'GET /monitoring/:id/entries
?startDate=string # Data inicial (ISO date)
&endDate=string # Data final (ISO date)Tipos (Domain)
ProviderWithHours
typescript
interface ProviderWithHours {
id: string // UUID
companyId: string
companyName: string
contractId: string
contractName: string
totalHoursMonth: number
totalHoursWeek: number
lastEntry?: Date
status: 'active' | 'inactive'
}ProviderHoursDetail
Retornado pelo endpoint GET /monitoring/:id:
typescript
interface ProviderHoursDetail {
provider: ProviderWithHours
dailySummary: DailySummary[]
weeklySummary: WeeklySummary
monthlySummary: MonthlySummary
}WorkEntry
typescript
interface WorkEntry {
id: string // UUID
providerId: string // UUID do provider
date: Date
startTime: string // Formato "HH:mm"
endTime: string // Formato "HH:mm"
totalMinutes: number
description: string
reason?: string // Motivo (para exclusões)
tasks: WorkTask[]
createdAt: Date
updatedAt: Date
}
interface WorkTask {
id: string
description: string
durationMinutes: number
}Summaries
typescript
interface DailySummary {
date: Date
totalMinutes: number
entries: WorkEntry[]
}
interface WeeklySummary {
weekStart: Date
weekEnd: Date
totalMinutes: number
dailyTotals: { date: Date; minutes: number }[]
}
interface MonthlySummary {
month: number // 1-12
year: number
totalMinutes: number
weeklyTotals: { weekNumber: number; minutes: number }[]
}Payloads
typescript
// POST /monitoring/entries - Criar nova entrada
interface CreateWorkEntryPayload {
providerId: string // Obrigatório no POST
date: Date
startTime: string // Formato "HH:mm"
endTime: string // Formato "HH:mm"
description: string
reason?: string
tasks: { description: string; durationMinutes: number }[]
}
// PUT /monitoring/entries/:id - Atualizar entrada existente
// Nota: providerId NÃO é enviado no PUT (já está associado à entry)
interface UpdateWorkEntryPayload {
date?: Date
startTime?: string // Formato "HH:mm"
endTime?: string // Formato "HH:mm"
description?: string
reason?: string
tasks?: { description: string; durationMinutes: number }[]
}
interface MonitoringFilter {
search?: string
status?: 'active' | 'inactive' | 'all'
}
interface WorkEntryFilter {
providerId?: string
startDate?: Date
endDate?: Date
}Store (Pinia)
Estado
typescript
{
items: ProviderWithHours[] // Lista de prestadores
total: number // Total de prestadores
search: string // Valor de busca
status: 'active' | 'inactive' | 'all' // Filtro de status
selectedIds: string[] // IDs selecionados
currentProvider: ProviderHoursDetail | null // Prestador atual
entries: WorkEntry[] // Entradas do prestador atual
entriesTotal: number // Total de entradas
loadingDetail: boolean // Flag de carregamento
initialized: boolean // Flag de inicialização
loading: boolean // Flag de carregamento da lista
}Ações
| Ação | Descrição |
|---|---|
loadProviders(params?) | Carrega lista de prestadores |
setSearch(params) | Define filtros e recarrega |
loadProviderDetail(id) | Carrega detalhes de um prestador |
loadProviderEntries(id, params?) | Carrega entradas de um prestador |
deleteEntry(id) | Deleta uma entrada |
setSelectedIds(ids) | Define IDs selecionados |
clearSelection() | Limpa seleção |
reset() | Reseta filtros |
resetDetail() | Reseta detalhes do prestador atual |
Services
typescript
// Lista prestadores com horas
getProvidersWithHoursService(params?: ProvidersFilter)
=> GET /monitoring/
// Detalhes de um prestador
getProviderDetailService(id: string)
=> GET /monitoring/:id
// Entradas de um prestador
getProviderEntriesService(id: string, params?: EntriesFilter)
=> GET /monitoring/:id/entries
// Busca entrada específica
getWorkEntryService(id: string)
=> GET /monitoring/entries/:id
// Cria entrada
createWorkEntryService(data: CreateWorkEntryPayload)
=> POST /monitoring/entries
// Atualiza entrada
updateWorkEntryService(id: string, data: Partial<CreateWorkEntryPayload>)
=> PUT /monitoring/entries/:id
// Remove entrada
deleteWorkEntryService(id: string)
=> DELETE /monitoring/entries/:idRotas
| Path | Nome | Componente | Descrição |
|---|---|---|---|
/monitoring | monitoring-list | ListMonitoring.vue | Lista de prestadores |
/monitoring/:id | monitoring-detail | MonitoringDetail.vue | Detalhes do prestador |
Fluxo de Dados
Backend API
↓
services/monitoring.ts (HTTP calls)
↓
stores/monitoring.ts (Pinia Store)
↓
Componentes Vue
├── ListMonitoring (lê items, loading)
├── MonitoringDetail (lê currentProvider, entries)
└── WorkEntryModal (create/update entries)Respostas da API
GET /monitoring/
json
{
"data": [
{
"id": "uuid",
"companyId": "uuid",
"companyName": "Tech Solutions Ltda",
"contractId": "uuid",
"contractName": "Contrato de Prestação de Serviços",
"totalHoursMonth": 168,
"totalHoursWeek": 42,
"lastEntry": "2026-01-26T10:00:00Z",
"status": "active"
}
],
"total": 1
}GET /monitoring/:id
json
{
"provider": { ... },
"dailySummary": [
{
"date": "2026-01-26T00:00:00Z",
"totalMinutes": 480,
"entries": [ ... ]
}
],
"weeklySummary": {
"weekStart": "2026-01-20T00:00:00Z",
"weekEnd": "2026-01-26T00:00:00Z",
"totalMinutes": 2400,
"dailyTotals": [
{ "date": "2026-01-20T00:00:00Z", "minutes": 480 },
...
]
},
"monthlySummary": {
"month": 1,
"year": 2026,
"totalMinutes": 10080,
"weeklyTotals": [
{ "weekNumber": 1, "minutes": 2400 },
...
]
}
}GET /monitoring/:id/entries
json
{
"data": [
{
"id": "uuid",
"providerId": "uuid",
"date": "2026-01-26T00:00:00Z",
"startTime": "08:00",
"endTime": "12:00",
"totalMinutes": 240,
"description": "Desenvolvimento de funcionalidades",
"tasks": [
{
"id": "uuid",
"description": "Implementação da listagem",
"durationMinutes": 90
}
],
"createdAt": "2026-01-26T08:00:00Z",
"updatedAt": "2026-01-26T08:00:00Z"
}
],
"total": 1
}POST /monitoring/entries
Request:
json
{
"providerId": "uuid",
"date": "2026-01-26T00:00:00Z",
"startTime": "08:00",
"endTime": "12:00",
"description": "Desenvolvimento de funcionalidades",
"tasks": [{ "description": "Implementação", "durationMinutes": 90 }]
}Response: WorkEntry criada (status 201)
Integração com Provider Module
O módulo provider também utiliza o store de monitoring para que prestadores lancem suas próprias horas:
LogHoursEntryPage.vue- Página para prestador lançar horasLogHoursHeader.vue- Cabeçalho com informações do prestador
Esses componentes usam as mesmas actions do store (loadProviderDetail, loadProviderEntries).