v-sistec-features 1.31.12 → 1.31.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "v-sistec-features",
3
3
  "private": false,
4
- "version": "1.31.12",
4
+ "version": "1.31.13",
5
5
  "author": "Márlon Bento Azevedo (https://github.com/marlon-bento)",
6
6
  "repository": {
7
7
  "type": "git",
@@ -3,14 +3,16 @@
3
3
  O layout raiz que orquestra a interface com cabeçalhos modulares separados.
4
4
  Suporta os modos 'calendario', 'tabela' (matriz horizontal) e 'tabela-horario' (grade vertical de horários por turno).
5
5
  Repassa as configurações de usuário, layout, recurso único opcional, blocos por agenda e o cliente HTTP para os filhos,
6
- além de destacar a semana operacional ativa e bloquear dias inativos no minicalendário lateral.
6
+ além de destacar a semana operacional ativa, bloquear dias inativos no minicalendário lateral e expor a lista de
7
+ recursos atualmente em exibição no modelo ativo.
7
8
  ========
8
9
  -->
9
10
  <script setup lang="ts">
10
11
  import { ref, computed, onMounted, provide } from 'vue';
11
12
  import { VueCal } from 'vue-cal';
12
13
  import 'vue-cal/style.css';
13
- import { useAgenda } from './composables/useAgenda.ts';
14
+ import { useAgenda } from './composables/useAgenda';
15
+ import { calcularDataInicioSemana, formatarDataIso } from './composables/useGradeCompartilhada';
14
16
  import AgendaVueCal from './components/AgendaVueCal.vue';
15
17
  import AgendaMatrix from './components/AgendaMatrix.vue';
16
18
  import AgendaMatrixUnico from './components/AgendaMatrixUnico.vue';
@@ -19,142 +21,131 @@ import HeaderCalendario from './components/HeaderCalendario.vue';
19
21
  import HeaderTabela from './components/HeaderTabela.vue';
20
22
 
21
23
  const props = withDefaults(defineProps<{
22
- modoLayout?: 'calendario' | 'tabela' | 'tabela-horario',
23
- idRecursoUnico?: number | string | null,
24
- usaInterceptador?: boolean,
25
- usuarioLogado?: string,
26
- tituloPadrao?: string,
27
- ocultarTituloModal?: boolean,
28
- configuracaoBlocos?: any,
29
- fetch: any,
24
+ modoLayout?: 'calendario' | 'tabela' | 'tabela-horario',
25
+ idRecursoUnico?: number | string | null,
26
+ usaInterceptador?: boolean,
27
+ usuarioLogado?: string,
28
+ tituloPadrao?: string,
29
+ ocultarTituloModal?: boolean,
30
+ configuracaoBlocos?: any,
31
+ fetch: any,
30
32
  }>(), {
31
- modoLayout: 'calendario',
32
- idRecursoUnico: null,
33
- usaInterceptador: false,
34
- usuarioLogado: '',
35
- tituloPadrao: '',
36
- ocultarTituloModal: false,
37
- configuracaoBlocos: null
33
+ modoLayout: 'calendario',
34
+ idRecursoUnico: null,
35
+ usaInterceptador: false,
36
+ usuarioLogado: '',
37
+ tituloPadrao: '',
38
+ ocultarTituloModal: false,
39
+ configuracaoBlocos: null
38
40
  });
39
41
 
40
42
  provide('api-instance-agenda', props.fetch);
43
+ defineEmits(['before-save']);
41
44
 
42
- const emit = defineEmits(['before-save']);
43
-
44
- // Armazena as referências e funções do composable de agenda para manipulação global.
45
45
  const {
46
- dataSelecionada,
47
- dataVisao,
48
- agendasDisponiveis,
49
- agendaSelecionada,
50
- datasDesabilitadas,
51
- carregarRecursosEAgendas
46
+ dataSelecionada,
47
+ dataVisao,
48
+ agendasDisponiveis,
49
+ agendaSelecionada,
50
+ datasDesabilitadas,
51
+ carregarRecursosEAgendas
52
52
  } = useAgenda(props.fetch);
53
53
 
54
- // Controla o estado de abertura da barra lateral (menu) contendo o minicalendário.
55
54
  const menuAberto = ref(true);
56
-
57
- // Armazena a referência da instância do componente vue-cal em sua versão miniatura.
58
55
  const calendarioMiniRef = ref<any>(null);
56
+ const modeloAtivoRef = ref<any>(null);
59
57
 
60
- // Armazena a referência da instância principal do componente AgendaVueCal.
61
- const agendaVueCalRef = ref<any>(null);
62
-
63
- // Executa o carregamento inicial de recursos ao montar o componente na tela.
64
- onMounted(() => { carregarRecursosEAgendas(); });
65
-
66
- // Extrai de forma segura o objeto de data embutido na célula customizada do vue-cal.
67
- const obterDataDaCelula = (cell: any): Date | null => {
68
- if (!cell) return null;
69
- if (cell instanceof Date) return cell;
70
- if (cell.start) return new Date(cell.start);
71
- return null;
72
- };
73
-
74
- // Recebe um objeto Date e devolve a string formatada em YYYY-MM-DD local.
75
- const formatarDataIsoCurta = (data: Date): string => {
76
- const ano = data.getFullYear();
77
- const mes = String(data.getMonth() + 1).padStart(2, '0');
78
- const dia = String(data.getDate()).padStart(2, '0');
79
- return `${ano}-${mes}-${dia}`;
80
- };
81
-
82
- // Devolve um Set para consulta rápida contendo todas as datas desabilitadas da agenda atual.
83
- const conjuntoDatasDesabilitadas = computed(() => {
84
- return new Set<string>(datasDesabilitadas.value);
58
+ const componenteModeloAtivo = computed(() => {
59
+ if (props.modoLayout === 'calendario') return AgendaVueCal;
60
+ if (props.modoLayout === 'tabela-horario') return AgendaTabelaHorario;
61
+ if (props.modoLayout === 'tabela' && props.idRecursoUnico) return AgendaMatrixUnico;
62
+ return AgendaMatrix;
85
63
  });
86
64
 
87
- // Calcula e devolve um Set com as strings (YYYY-MM-DD) dos dias operacionais que já estão visíveis na grade tabela-horario.
88
- const datasVisiveisNaSemana = computed(() => {
89
- const visiveis = new Set<string>();
90
- if (props.modoLayout !== 'tabela-horario' || !dataSelecionada.value || !agendaSelecionada.value) {
91
- return visiveis;
92
- }
65
+ const propriedadesModeloAtivo = computed(() => {
66
+ const base = {
67
+ usaInterceptador: props.usaInterceptador,
68
+ tituloPadrao: props.tituloPadrao,
69
+ ocultarTituloModal: props.ocultarTituloModal
70
+ };
71
+
72
+ if (props.modoLayout === 'calendario') {
73
+ return { ...base, usuarioLogado: props.usuarioLogado };
74
+ }
75
+ if (props.modoLayout === 'tabela-horario') {
76
+ return { ...base, idRecursoUnico: props.idRecursoUnico, configuracaoBlocos: props.configuracaoBlocos };
77
+ }
78
+ if (props.modoLayout === 'tabela' && props.idRecursoUnico) {
79
+ return { ...base, idRecurso: props.idRecursoUnico, configuracaoBlocos: props.configuracaoBlocos };
80
+ }
81
+ return { ...base, configuracaoBlocos: props.configuracaoBlocos };
82
+ });
93
83
 
94
- const agendaObj = agendasDisponiveis.value.find(
95
- (a: any) => Number(a.id_agenda) === Number(agendaSelecionada.value)
96
- );
97
- if (!agendaObj || !agendaObj.detalhes) return visiveis;
84
+ const recursosEmExibicao = computed(() => modeloAtivoRef.value?.recursosEmExibicao ?? []);
98
85
 
99
- const diaInicioPython = Number(agendaObj.detalhes.dia_inicio_semana_agenda ?? 0);
100
- const diasVisiveis = Number(agendaObj.detalhes.dias_visiveis_agenda ?? 6);
101
- const diaInicioJs = (diaInicioPython + 1) % 7;
86
+ defineExpose({ recursosEmExibicao });
102
87
 
103
- let dataBase: Date;
104
- if (typeof dataSelecionada.value === 'string') {
105
- const apenasData = String(dataSelecionada.value).substring(0, 10);
106
- const [ano, mes, dia] = apenasData.split('-').map(Number);
107
- dataBase = new Date(ano!, mes! - 1, dia!);
108
- } else {
109
- const d = new Date(dataSelecionada.value);
110
- dataBase = new Date(d.getFullYear(), d.getMonth(), d.getDate());
111
- }
88
+ onMounted(() => { carregarRecursosEAgendas(); });
112
89
 
113
- const diff = (dataBase.getDay() - diaInicioJs + 7) % 7;
114
- const inicioSemana = new Date(dataBase);
115
- inicioSemana.setDate(dataBase.getDate() - diff);
90
+ const obterDataDaCelula = (cell: any): Date | null => {
91
+ if (!cell) return null;
92
+ if (cell instanceof Date) return cell;
93
+ if (cell.start) return new Date(cell.start);
94
+ return null;
95
+ };
116
96
 
117
- for (let i = 0; i < diasVisiveis; i++) {
118
- const diaCorrente = new Date(inicioSemana);
119
- diaCorrente.setDate(inicioSemana.getDate() + i);
120
- visiveis.add(formatarDataIsoCurta(diaCorrente));
121
- }
97
+ const conjuntoDatasDesabilitadas = computed(() => new Set<string>(datasDesabilitadas.value));
122
98
 
99
+ const datasVisiveisNaSemana = computed(() => {
100
+ const visiveis = new Set<string>();
101
+ if (props.modoLayout !== 'tabela-horario' || !dataSelecionada.value || !agendaSelecionada.value) {
123
102
  return visiveis;
103
+ }
104
+
105
+ const agendaObj = agendasDisponiveis.value.find(
106
+ (a: any) => Number(a.id_agenda) === Number(agendaSelecionada.value)
107
+ );
108
+ if (!agendaObj?.detalhes) return visiveis;
109
+
110
+ const inicioSemana = calcularDataInicioSemana(
111
+ dataSelecionada.value,
112
+ Number(agendaObj.detalhes.dia_inicio_semana_agenda ?? 0)
113
+ );
114
+ const diasVisiveis = Number(agendaObj.detalhes.dias_visiveis_agenda ?? 6);
115
+
116
+ for (let i = 0; i < diasVisiveis; i++) {
117
+ const diaCorrente = new Date(inicioSemana);
118
+ diaCorrente.setDate(inicioSemana.getDate() + i);
119
+ visiveis.add(formatarDataIso(diaCorrente));
120
+ }
121
+
122
+ return visiveis;
124
123
  });
125
124
 
126
- // Recebe a célula do minicalendário e devolve true se aquele dia da semana não funcionar na agenda.
127
125
  const ehDiaBloqueadoNoMini = (cell: any): boolean => {
128
- const data = obterDataDaCelula(cell);
129
- if (!data || props.modoLayout !== 'tabela-horario') return false;
130
- return conjuntoDatasDesabilitadas.value.has(formatarDataIsoCurta(data));
126
+ const data = obterDataDaCelula(cell);
127
+ if (!data || props.modoLayout !== 'tabela-horario') return false;
128
+ return conjuntoDatasDesabilitadas.value.has(formatarDataIso(data));
131
129
  };
132
130
 
133
- // Recebe a célula do minicalendário e devolve true se ela já estiver sendo exibida na tabela atual.
134
131
  const ehDiaVisivelNaGrade = (cell: any): boolean => {
135
- const data = obterDataDaCelula(cell);
136
- if (!data || props.modoLayout !== 'tabela-horario') return false;
137
- return datasVisiveisNaSemana.value.has(formatarDataIsoCurta(data));
132
+ const data = obterDataDaCelula(cell);
133
+ if (!data || props.modoLayout !== 'tabela-horario') return false;
134
+ return datasVisiveisNaSemana.value.has(formatarDataIso(data));
138
135
  };
139
136
 
140
- // Recebe nada. Devolve nada.
141
- // É usada para retrair ou expandir a aba esquerda de navegação rápida.
142
137
  const alternarMenu = () => { menuAberto.value = !menuAberto.value; };
143
138
 
144
- // Recebe nada. Devolve nada.
145
- // É usada para devolver o usuário à data atual do sistema nas visualizações principais e no mini-calendário.
146
- const irParaHoje = () => {
147
- const hoje = new Date();
148
- dataSelecionada.value = hoje;
149
- dataVisao.value = hoje;
150
- if (props.modoLayout === 'calendario') agendaVueCalRef.value?.irParaHoje();
151
- if (calendarioMiniRef.value) calendarioMiniRef.value.view.goToToday();
139
+ const irParaHoje = () => {
140
+ const hoje = new Date();
141
+ dataSelecionada.value = hoje;
142
+ dataVisao.value = hoje;
143
+ if (props.modoLayout === 'calendario') modeloAtivoRef.value?.irParaHoje?.();
144
+ if (calendarioMiniRef.value) calendarioMiniRef.value.view.goToToday();
152
145
  };
153
146
 
154
- // Recebe o identificador em string do modo de visualização. Devolve nada.
155
- // É usada para trocar a apresentação do calendário grande entre visão de dias singulares e a semana expandida.
156
- const mudarVisao = (novaVisao: string) => {
157
- agendaVueCalRef.value?.mudarVisao(novaVisao);
147
+ const mudarVisao = (novaVisao: string) => {
148
+ modeloAtivoRef.value?.mudarVisao?.(novaVisao);
158
149
  };
159
150
  </script>
160
151
 
@@ -227,207 +218,53 @@ const mudarVisao = (novaVisao: string) => {
227
218
  </aside>
228
219
 
229
220
  <main class="area-calendario">
230
- <AgendaVueCal
231
- v-if="props.modoLayout === 'calendario'"
232
- ref="agendaVueCalRef"
233
- :usa-interceptador="props.usaInterceptador"
234
- :usuario-logado="props.usuarioLogado"
235
- :titulo-padrao="props.tituloPadrao"
236
- :ocultar-titulo-modal="props.ocultarTituloModal"
237
- @before-save="$emit('before-save', $event)"
238
- >
239
- <template #campos-extras>
240
- <slot name="campos-extras"></slot>
241
- </template>
242
- </AgendaVueCal>
243
-
244
- <AgendaTabelaHorario
245
- v-else-if="props.modoLayout === 'tabela-horario'"
246
- :id-recurso-unico="props.idRecursoUnico"
247
- :usa-interceptador="props.usaInterceptador"
248
- :titulo-padrao="props.tituloPadrao"
249
- :ocultar-titulo-modal="props.ocultarTituloModal"
250
- :configuracao-blocos="props.configuracaoBlocos"
251
- @before-save="$emit('before-save', $event)"
252
- >
253
- <template #campos-extras>
254
- <slot name="campos-extras"></slot>
255
- </template>
256
- </AgendaTabelaHorario>
257
-
258
- <AgendaMatrixUnico
259
- v-else-if="props.modoLayout === 'tabela' && props.idRecursoUnico"
260
- :id-recurso="props.idRecursoUnico"
261
- :usa-interceptador="props.usaInterceptador"
262
- :titulo-padrao="props.tituloPadrao"
263
- :ocultar-titulo-modal="props.ocultarTituloModal"
264
- :configuracao-blocos="props.configuracaoBlocos"
221
+ <component
222
+ :is="componenteModeloAtivo"
223
+ ref="modeloAtivoRef"
224
+ v-bind="propriedadesModeloAtivo"
265
225
  @before-save="$emit('before-save', $event)"
266
226
  >
267
- <template #campos-extras>
268
- <slot name="campos-extras"></slot>
227
+ <template v-for="(_, nomeSlot) in $slots" :key="nomeSlot" #[nomeSlot]="slotProps">
228
+ <slot :name="nomeSlot" v-bind="slotProps ?? {}"></slot>
269
229
  </template>
270
- </AgendaMatrixUnico>
271
-
272
- <AgendaMatrix
273
- v-else-if="props.modoLayout === 'tabela'"
274
- :usa-interceptador="props.usaInterceptador"
275
- :titulo-padrao="props.tituloPadrao"
276
- :ocultar-titulo-modal="props.ocultarTituloModal"
277
- :configuracao-blocos="props.configuracaoBlocos"
278
- @before-save="$emit('before-save', $event)"
279
- >
280
- <template #campos-extras>
281
- <slot name="campos-extras"></slot>
282
- </template>
283
- </AgendaMatrix>
230
+ </component>
284
231
  </main>
285
232
  </div>
286
233
  </div>
287
234
  </div>
288
235
  </template>
236
+
289
237
  <style lang="scss">
290
238
  @use '../assets/scss/main.scss';
291
239
  </style>
292
240
 
293
241
  <style scoped>
294
- .painel-agenda-unificado {
295
- background: var(--bg-primary);
296
- border-radius: 16px;
297
- box-shadow: var(--shadow-float);
298
- border: 1px solid var(--border-light);
299
- flex-grow: 1;
300
- display: flex;
301
- flex-direction: column;
302
- overflow: hidden;
303
- }
304
- .painel-header-topo {
305
- height: 60px;
306
- background-color: var(--bg-primary);
307
- border-bottom: 1px solid var(--border-light);
308
- display: flex;
309
- align-items: center;
310
- justify-content: space-between;
311
- padding: 0 20px;
312
- flex-shrink: 0;
313
- }
242
+ .painel-agenda-unificado { background: var(--bg-primary); border-radius: 16px; box-shadow: var(--shadow-float); border: 1px solid var(--border-light); flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; }
243
+ .painel-header-topo { height: 60px; background-color: var(--bg-primary); border-bottom: 1px solid var(--border-light); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; flex-shrink: 0; }
314
244
  .corpo-principal { display: flex; flex-grow: 1; overflow: hidden; }
315
- .barra-lateral {
316
- width: 300px;
317
- background-color: var(--bg-primary);
318
- border-right: 1px solid var(--border-light);
319
- transition: width 0.3s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.2s;
320
- overflow: hidden;
321
- flex-shrink: 0;
322
- }
245
+ .barra-lateral { width: 300px; background-color: var(--bg-primary); border-right: 1px solid var(--border-light); transition: width 0.3s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.2s; overflow: hidden; flex-shrink: 0; }
323
246
  .barra-lateral.oculta { width: 0; border-right: none; opacity: 0; }
324
247
  .conteudo-lateral-fixo { width: 300px; padding: 15px; }
325
248
  .secao-mini-cal { width: 100%; }
326
- .area-calendario {
327
- flex-grow: 1;
328
- overflow: hidden;
329
- background-color: var(--bg-primary);
330
- display: flex;
331
- flex-direction: column;
332
- }
333
-
249
+ .area-calendario { flex-grow: 1; overflow: hidden; background-color: var(--bg-primary); display: flex; flex-direction: column; }
334
250
  .calendario-mini { border: none !important; box-shadow: none !important; background-color: transparent !important; }
335
- :deep(.calendario-mini .vuecal__header), :deep(.calendario-mini .vuecal__title-bar) { background-color: transparent !important; border: none !important; padding-bottom: 5px; }
336
- :deep(.calendario-mini .vuecal__title), :deep(.calendario-mini .vuecal__arrow) {
337
- font-size: 1rem;
338
- font-weight: 600;
339
- color: var(--color-brand) !important;
340
- background: transparent !important;
341
- }
342
- :deep(.calendario-mini .vuecal__heading) { border: none !important; background-color: transparent !important; font-weight: 600; color: var(--text-secondary); padding-bottom: 4px; }
251
+ :deep(.calendario-mini .vuecal__header), :deep(.calendario-mini .vuecal__title-bar) { background-color: var(--bg-primary) !important; border: none !important; padding-bottom: 5px; }
252
+ :deep(.calendario-mini .vuecal__title), :deep(.calendario-mini .vuecal__arrow) { font-size: 1rem; font-weight: 600; color: var(--color-brand) !important; background: transparent !important; }
253
+ :deep(.calendario-mini .vuecal__weekdays-headings) { background-color: var(--bg-primary) !important; border-bottom: 1px solid var(--border-light) !important; }
254
+ :deep(.calendario-mini .vuecal__heading), :deep(.calendario-mini .vuecal__weekday), :deep(.calendario-mini .vuecal__weekday-name), :deep(.calendario-mini .vuecal__heading *) { background-color: var(--bg-primary) !important; color: var(--text-secondary) !important; font-weight: 600 !important; border: none !important; padding-bottom: 4px; }
343
255
  :deep(.calendario-mini .vuecal__cell) { border: none !important; background-color: transparent !important; height: 32px !important; min-height: 32px !important; aspect-ratio: auto !important; }
344
256
  :deep(.calendario-mini .vuecal__cell::before) { display: none !important; content: none !important; }
345
257
  :deep(.calendario-mini .vuecal__cell-content) { height: 32px !important; min-height: 32px !important; padding: 0 !important; margin: 0 !important; justify-content: center !important; align-items: center !important; width: 100% !important; }
346
- :deep(.calendario-mini .vuecal__cell-date) { width: 26px !important; height: 26px !important; font-size: 12px !important; line-height: 26px !important; padding: 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; margin: 0 auto !important; border-radius: 50% !important; border: 2px solid transparent !important; box-sizing: border-box !important; transition: all 0.2s ease; cursor: pointer; }
347
- :deep(.calendario-mini .vuecal__cell--selected) { background-color: transparent !important; }
348
- :deep(.calendario-mini:not(.modo-mini-tabela-horario) .vuecal__cell--selected .vuecal__cell-date) {
349
- background-color: var(--color-brand) !important;
350
- color: var(--text-inverse) !important;
351
- border-color: var(--color-brand) !important;
352
- }
258
+ :deep(.calendario-mini .vuecal__cell-date) { width: 26px !important; height: 26px !important; font-size: 12px !important; line-height: 26px !important; padding: 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; margin: 0 auto !important; border-radius: 50% !important; border: 2px solid transparent !important; box-sizing: border-box !important; transition: all 0.2s ease; cursor: pointer; background-color: transparent !important; color: var(--text-primary); }
259
+ :deep(.calendario-mini .vuecal__cell--selected), :deep(.calendario-mini .vuecal__cell--today) { background-color: transparent !important; }
260
+ :deep(.calendario-mini:not(.modo-mini-tabela-horario) .vuecal__cell--selected .vuecal__cell-date) { background-color: var(--color-brand) !important; color: var(--text-inverse) !important; border-color: var(--color-brand) !important; }
261
+ :deep(.calendario-mini .vuecal__cell--today:not(.vuecal__cell--selected) .vuecal__cell-date:not(.dia-semana-visivel)) { background-color: var(--color-brand-light) !important; border-color: transparent !important; color: var(--color-brand) !important; }
353
262
  :deep(.vuecal__body) { padding: 0; gap: 0; margin: 0; }
354
- :deep(.calendario-mini .vuecal__cell--today) { background-color: transparent !important; }
355
- :deep(.calendario-mini .vuecal__cell-date){ background-color: transparent !important; color: var(--text-primary); }
356
- :deep(.calendario-mini .vuecal__cell--today:not(.vuecal__cell--selected) .vuecal__cell-date:not(.dia-semana-visivel)) {
357
- background-color: var(--color-brand-light) !important;
358
- border-color: transparent !important;
359
- color: var(--color-brand) !important;
360
- }
361
263
  :deep(.calendario-mini .vuecal__views-bar) { display: none !important; }
362
264
  :deep(.calendario-mini .vuecal__nav--next), :deep(.calendario-mini .vuecal__nav--prev) { color: var(--text-primary) !important; }
363
- :deep(.calendario-mini .vuecal__body){ height: 0%!important; }
364
- :deep(.calendario-mini .vuecal__scrollable-wrap){ background-color: transparent!important; }
365
-
366
- /* Estilização específica para o modo tabela-horario no minicalendário */
367
- :deep(.calendario-mini.modo-mini-tabela-horario .vuecal__cell--disabled) {
368
- pointer-events: none !important;
369
- cursor: not-allowed !important;
370
- }
371
-
372
- :deep(.calendario-mini.modo-mini-tabela-horario .vuecal__cell-date.dia-coluna-inativa) {
373
- opacity: 0.22 !important;
374
- color: var(--text-secondary) !important;
375
- background-color: transparent !important;
376
- border-color: transparent !important;
377
- cursor: not-allowed !important;
378
- pointer-events: none !important;
379
- text-decoration: line-through;
380
- }
381
-
382
- :deep(.calendario-mini.modo-mini-tabela-horario .vuecal__cell-date.dia-semana-visivel) {
383
- background-color: var(--color-brand) !important;
384
- color: var(--text-inverse) !important;
385
- border-color: var(--color-brand) !important;
386
- font-weight: 700 !important;
387
- width: 92% !important;
388
- border-radius: 6px !important;
389
- cursor: default !important;
390
- box-shadow: var(--shadow-sm);
391
- }
392
-
393
- :deep(.calendario-mini .vuecal__weekdays-headings),
394
- :deep(.calendario-mini .vuecal__weekday) {
395
- background-color: transparent !important;
396
- border: none !important;
397
- color: var(--text-secondary) !important;
398
- }
399
-
400
- :deep(.calendario-mini .vuecal__weekdays-headings) {
401
- background: transparent !important;
402
- background-color: transparent !important;
403
- border-bottom: 1px solid var(--border-light) !important;
404
- }
405
-
406
- :deep(.calendario-mini .vuecal__heading),
407
- :deep(.calendario-mini .vuecal__weekday),
408
- :deep(.calendario-mini .vuecal__heading *) {
409
- background: transparent !important;
410
- background-color: transparent !important;
411
- color: var(--text-secondary) !important;
412
- font-weight: 600 !important;
413
- border: none !important;
414
- }
415
-
416
- :deep(.calendario-mini .vuecal__header),
417
- :deep(.calendario-mini .vuecal__weekdays-headings) {
418
- background: var(--bg-primary) !important;
419
- background-color: var(--bg-primary) !important;
420
- border-bottom: 1px solid var(--border-light) !important;
421
- }
422
-
423
- :deep(.calendario-mini .vuecal__heading),
424
- :deep(.calendario-mini .vuecal__weekday),
425
- :deep(.calendario-mini .vuecal__weekday-name),
426
- :deep(.calendario-mini .vuecal__heading *) {
427
- background: var(--bg-primary) !important;
428
- background-color: var(--bg-primary) !important;
429
- color: var(--text-secondary) !important;
430
- font-weight: 600 !important;
431
- border: none !important;
432
- }
265
+ :deep(.calendario-mini .vuecal__body) { height: 0% !important; }
266
+ :deep(.calendario-mini .vuecal__scrollable-wrap) { background-color: transparent !important; }
267
+ :deep(.calendario-mini.modo-mini-tabela-horario .vuecal__cell--disabled) { pointer-events: none !important; cursor: not-allowed !important; }
268
+ :deep(.calendario-mini.modo-mini-tabela-horario .vuecal__cell-date.dia-coluna-inativa) { opacity: 0.22 !important; color: var(--text-secondary) !important; background-color: transparent !important; border-color: transparent !important; cursor: not-allowed !important; pointer-events: none !important; text-decoration: line-through; }
269
+ :deep(.calendario-mini.modo-mini-tabela-horario .vuecal__cell-date.dia-semana-visivel) { background-color: var(--color-brand) !important; color: var(--text-inverse) !important; border-color: var(--color-brand) !important; font-weight: 700 !important; width: 92% !important; border-radius: 6px !important; cursor: default !important; box-shadow: var(--shadow-sm); }
433
270
  </style>
@@ -1,8 +1,9 @@
1
1
  <!--
2
2
  ========
3
3
  Este arquivo representa a visualização em matriz para múltiplos recursos com suporte a filtragem.
4
- Ele utiliza o AgendaMatrixBase para renderizar a grade, repassa a configuração de blocos da agenda
5
- e gerencia o dropdown de seleção de salas preservando os filtros ativos ao mudar a data.
4
+ Ele utiliza o AgendaMatrixBase para renderizar a grade, repassa a configuração de blocos da agenda,
5
+ gerencia o dropdown de seleção de salas preservando os filtros ativos ao mudar a data e expõe a lista
6
+ de recursos atualmente em exibição (já filtrada).
6
7
  ========
7
8
  -->
8
9
  <script setup lang="ts">
@@ -18,26 +19,18 @@ const props = defineProps({
18
19
  });
19
20
 
20
21
  const api = inject('api-instance-agenda') as any;
21
- const emit = defineEmits(['before-save']);
22
+ defineEmits(['before-save']);
22
23
 
23
- const { dadosMatrix, agendaSelecionada } = useAgenda(api);
24
+ const { dadosMatrix, agendaSelecionada, recursosDisponiveis } = useAgenda(api);
24
25
 
25
- // Armazena os IDs (em string) dos recursos visíveis selecionados no filtro.
26
26
  const recursosVisiveisIds = ref<string[]>([]);
27
-
28
- // Armazena o ID da última agenda cujo filtro foi inicializado para evitar reset ao mudar apenas a data.
29
27
  const idAgendaFiltroInicializado = ref<number | null>(null);
30
-
31
- // Controla a abertura do menu dropdown de filtro de salas.
32
28
  const menuFiltroAberto = ref(false);
33
29
 
34
- // Extrai a lista de recursos presentes no primeiro dia retornado na matriz.
35
30
  const recursosPermitidosNaMatriz = computed(() => {
36
- if (!dadosMatrix.value?.datas_matriz?.[0]?.recursos_slot) return [];
37
- return dadosMatrix.value.datas_matriz[0].recursos_slot;
31
+ return dadosMatrix.value?.datas_matriz?.[0]?.recursos_slot || [];
38
32
  });
39
33
 
40
- // Observa os recursos da matriz e inicializa o filtro apenas quando a agenda muda ou na primeira carga.
41
34
  watch(recursosPermitidosNaMatriz, (novosRecursos) => {
42
35
  if (novosRecursos.length === 0) {
43
36
  recursosVisiveisIds.value = [];
@@ -54,15 +47,31 @@ watch(recursosPermitidosNaMatriz, (novosRecursos) => {
54
47
  }
55
48
  }, { immediate: true });
56
49
 
57
- // Marca todos os recursos disponíveis no filtro de salas.
50
+ const recursosEmExibicao = computed(() => {
51
+ if (recursosVisiveisIds.value.length === 0) return [];
52
+
53
+ return recursosPermitidosNaMatriz.value
54
+ .filter((recMatriz: any) => recursosVisiveisIds.value.includes(String(recMatriz.id_recurso)))
55
+ .map((recMatriz: any) => {
56
+ return recursosDisponiveis.value.find(
57
+ (r: any) => Number(r.id_recurso) === Number(recMatriz.id_recurso)
58
+ ) || {
59
+ id_recurso: recMatriz.id_recurso,
60
+ nome_recurso: recMatriz.nome_recurso,
61
+ id_agenda: agendaSelecionada.value
62
+ };
63
+ });
64
+ });
65
+
58
66
  const selecionarTodos = () => {
59
67
  recursosVisiveisIds.value = recursosPermitidosNaMatriz.value.map((r: any) => String(r.id_recurso));
60
68
  };
61
69
 
62
- // Desmarca todos os recursos no filtro de salas.
63
70
  const limparFiltros = () => {
64
71
  recursosVisiveisIds.value = [];
65
72
  };
73
+
74
+ defineExpose({ recursosEmExibicao });
66
75
  </script>
67
76
 
68
77
  <template>
@@ -73,7 +82,7 @@ const limparFiltros = () => {
73
82
  :ocultar-titulo-modal="props.ocultarTituloModal"
74
83
  :configuracao-blocos="props.configuracaoBlocos"
75
84
  mensagem-vazio="Nenhuma sala selecionada."
76
- @before-save="$emit('before-save', $event)"
85
+ @before-save="$emit('before-save',$event)"
77
86
  >
78
87
  <template #topo>
79
88
  <div class="barra-filtros" v-if="recursosPermitidosNaMatriz.length > 0">
@@ -125,8 +134,8 @@ const limparFiltros = () => {
125
134
  </div>
126
135
  </template>
127
136
 
128
- <template #campos-extras>
129
- <slot name="campos-extras"></slot>
137
+ <template v-for="(_, nomeSlot) in $slots" :key="nomeSlot" #[nomeSlot]="slotProps">
138
+ <slot :name="nomeSlot" v-bind="slotProps ?? {}"></slot>
130
139
  </template>
131
140
  </AgendaMatrixBase>
132
141
  </template>