v-sistec-features 1.31.11 → 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.11",
4
+ "version": "1.31.13",
5
5
  "author": "Márlon Bento Azevedo (https://github.com/marlon-bento)",
6
6
  "repository": {
7
7
  "type": "git",
@@ -1,75 +1,151 @@
1
1
  <!--
2
2
  ========
3
3
  O layout raiz que orquestra a interface com cabeçalhos modulares separados.
4
- Utiliza as propriedades nativas de visão e seleção do Vue 3 para manter tudo em sincronia.
5
- Atua como o ponto de entrada da biblioteca, repassando as configurações de usuário, layout, recurso único opcional e o cliente HTTP para os filhos.
4
+ Suporta os modos 'calendario', 'tabela' (matriz horizontal) e 'tabela-horario' (grade vertical de horários por turno).
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, bloquear dias inativos no minicalendário lateral e expor a lista de
7
+ recursos atualmente em exibição no modelo ativo.
6
8
  ========
7
9
  -->
8
10
  <script setup lang="ts">
9
- import { ref, onMounted, provide } from 'vue';
11
+ import { ref, computed, onMounted, provide } from 'vue';
10
12
  import { VueCal } from 'vue-cal';
11
13
  import 'vue-cal/style.css';
12
- import { useAgenda } from './composables/useAgenda.ts';
14
+ import { useAgenda } from './composables/useAgenda';
15
+ import { calcularDataInicioSemana, formatarDataIso } from './composables/useGradeCompartilhada';
13
16
  import AgendaVueCal from './components/AgendaVueCal.vue';
14
17
  import AgendaMatrix from './components/AgendaMatrix.vue';
15
18
  import AgendaMatrixUnico from './components/AgendaMatrixUnico.vue';
19
+ import AgendaTabelaHorario from './components/AgendaTabelaHorario.vue';
16
20
  import HeaderCalendario from './components/HeaderCalendario.vue';
17
21
  import HeaderTabela from './components/HeaderTabela.vue';
18
22
 
19
23
  const props = withDefaults(defineProps<{
20
- modoLayout?: 'calendario' | 'tabela',
21
- idRecursoUnico?: number | string | null,
22
- usaInterceptador?: boolean,
23
- usuarioLogado?: string,
24
- tituloPadrao?: string,
25
- ocultarTituloModal?: boolean,
26
- 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,
27
32
  }>(), {
28
- modoLayout: 'calendario',
29
- idRecursoUnico: null,
30
- usaInterceptador: false,
31
- usuarioLogado: '',
32
- tituloPadrao: '',
33
- ocultarTituloModal: false
33
+ modoLayout: 'calendario',
34
+ idRecursoUnico: null,
35
+ usaInterceptador: false,
36
+ usuarioLogado: '',
37
+ tituloPadrao: '',
38
+ ocultarTituloModal: false,
39
+ configuracaoBlocos: null
34
40
  });
35
41
 
36
42
  provide('api-instance-agenda', props.fetch);
43
+ defineEmits(['before-save']);
37
44
 
38
- const emit = defineEmits(['before-save']);
45
+ const {
46
+ dataSelecionada,
47
+ dataVisao,
48
+ agendasDisponiveis,
49
+ agendaSelecionada,
50
+ datasDesabilitadas,
51
+ carregarRecursosEAgendas
52
+ } = useAgenda(props.fetch);
39
53
 
40
- // Armazena as referências e funções do composable de agenda para manipulação global.
41
- const { dataSelecionada, dataVisao, carregarRecursosEAgendas } = useAgenda(props.fetch);
42
-
43
- // Controla o estado de abertura da barra lateral (menu) contendo o minicalendário.
44
54
  const menuAberto = ref(true);
45
-
46
- // Armazena a referência da instância do componente vue-cal em sua versão miniatura.
47
55
  const calendarioMiniRef = ref<any>(null);
56
+ const modeloAtivoRef = ref<any>(null);
57
+
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;
63
+ });
64
+
65
+ const propriedadesModeloAtivo = computed(() => {
66
+ const base = {
67
+ usaInterceptador: props.usaInterceptador,
68
+ tituloPadrao: props.tituloPadrao,
69
+ ocultarTituloModal: props.ocultarTituloModal
70
+ };
48
71
 
49
- // Armazena a referência da instância principal do componente AgendaVueCal.
50
- const agendaVueCalRef = ref<any>(null);
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
+ });
83
+
84
+ const recursosEmExibicao = computed(() => modeloAtivoRef.value?.recursosEmExibicao ?? []);
85
+
86
+ defineExpose({ recursosEmExibicao });
51
87
 
52
- // Executa o carregamento inicial de recursos ao montar o componente na tela.
53
88
  onMounted(() => { carregarRecursosEAgendas(); });
54
89
 
55
- // Recebe nada. Devolve nada.
56
- // É usada para retrair ou expandir a aba esquerda de navegação rápida.
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
+ };
96
+
97
+ const conjuntoDatasDesabilitadas = computed(() => new Set<string>(datasDesabilitadas.value));
98
+
99
+ const datasVisiveisNaSemana = computed(() => {
100
+ const visiveis = new Set<string>();
101
+ if (props.modoLayout !== 'tabela-horario' || !dataSelecionada.value || !agendaSelecionada.value) {
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;
123
+ });
124
+
125
+ const ehDiaBloqueadoNoMini = (cell: any): boolean => {
126
+ const data = obterDataDaCelula(cell);
127
+ if (!data || props.modoLayout !== 'tabela-horario') return false;
128
+ return conjuntoDatasDesabilitadas.value.has(formatarDataIso(data));
129
+ };
130
+
131
+ const ehDiaVisivelNaGrade = (cell: any): boolean => {
132
+ const data = obterDataDaCelula(cell);
133
+ if (!data || props.modoLayout !== 'tabela-horario') return false;
134
+ return datasVisiveisNaSemana.value.has(formatarDataIso(data));
135
+ };
136
+
57
137
  const alternarMenu = () => { menuAberto.value = !menuAberto.value; };
58
138
 
59
- // Recebe nada. Devolve nada.
60
- // É usada para devolver o usuário à data atual do sistema nas visualizações principais e no mini-calendário.
61
- const irParaHoje = () => {
62
- const hoje = new Date();
63
- dataSelecionada.value = hoje;
64
- dataVisao.value = hoje;
65
- if (props.modoLayout === 'calendario') agendaVueCalRef.value?.irParaHoje();
66
- 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();
67
145
  };
68
146
 
69
- // Recebe o identificador em string do modo de visualização. Devolve nada.
70
- // É usada para trocar a apresentação do calendário grande entre visão de dias singulares e a semana expandida.
71
- const mudarVisao = (novaVisao: string) => {
72
- agendaVueCalRef.value?.mudarVisao(novaVisao);
147
+ const mudarVisao = (novaVisao: string) => {
148
+ modeloAtivoRef.value?.mudarVisao?.(novaVisao);
73
149
  };
74
150
  </script>
75
151
 
@@ -99,6 +175,7 @@ const mudarVisao = (novaVisao: string) => {
99
175
  <vue-cal
100
176
  ref="calendarioMiniRef"
101
177
  class="calendario-mini vuecal--blue-theme"
178
+ :class="{ 'modo-mini-tabela-horario': props.modoLayout === 'tabela-horario' }"
102
179
  small
103
180
  active-view="month"
104
181
  :views="['month']"
@@ -106,180 +183,88 @@ const mudarVisao = (novaVisao: string) => {
106
183
  hide-view-selector
107
184
  :click-to-navigate="false"
108
185
  locale="pt-br"
186
+ :disable-days="props.modoLayout === 'tabela-horario' ? datasDesabilitadas : []"
109
187
  v-model:selected-date="dataSelecionada"
110
188
  :view-date="dataVisao"
111
189
  @update:selected-date="dataVisao = $event"
112
190
  >
113
191
  <template #views-bar></template>
114
192
  <template #today-button></template>
193
+
194
+ <template #cell-content="{ cell }">
195
+ <div
196
+ class="vuecal__cell-date"
197
+ :class="{
198
+ 'dia-semana-visivel': ehDiaVisivelNaGrade(cell),
199
+ 'dia-coluna-inativa': ehDiaBloqueadoNoMini(cell)
200
+ }"
201
+ @mousedown.stop="
202
+ (ehDiaVisivelNaGrade(cell) || ehDiaBloqueadoNoMini(cell))
203
+ ? $event.preventDefault()
204
+ : null
205
+ "
206
+ @click.stop="
207
+ (!ehDiaVisivelNaGrade(cell) && !ehDiaBloqueadoNoMini(cell))
208
+ ? (dataSelecionada = obterDataDaCelula(cell) || dataSelecionada, dataVisao = obterDataDaCelula(cell) || dataVisao)
209
+ : null
210
+ "
211
+ >
212
+ {{ cell.content }}
213
+ </div>
214
+ </template>
115
215
  </vue-cal>
116
216
  </div>
117
217
  </div>
118
218
  </aside>
119
219
 
120
220
  <main class="area-calendario">
121
- <AgendaVueCal
122
- v-if="props.modoLayout === 'calendario'"
123
- ref="agendaVueCalRef"
124
- :usa-interceptador="props.usaInterceptador"
125
- :usuario-logado="props.usuarioLogado"
126
- :titulo-padrao="props.tituloPadrao"
127
- :ocultar-titulo-modal="props.ocultarTituloModal"
128
- @before-save="$emit('before-save', $event)"
129
- >
130
- <template #campos-extras>
131
- <slot name="campos-extras"></slot>
132
- </template>
133
- </AgendaVueCal>
134
-
135
- <AgendaMatrixUnico
136
- v-else-if="props.modoLayout === 'tabela' && props.idRecursoUnico"
137
- :id-recurso="props.idRecursoUnico"
138
- :usa-interceptador="props.usaInterceptador"
139
- :titulo-padrao="props.tituloPadrao"
140
- :ocultar-titulo-modal="props.ocultarTituloModal"
141
- @before-save="$emit('before-save', $event)"
142
- >
143
- <template #campos-extras>
144
- <slot name="campos-extras"></slot>
145
- </template>
146
- </AgendaMatrixUnico>
147
-
148
- <AgendaMatrix
149
- v-else-if="props.modoLayout === 'tabela'"
150
- :usa-interceptador="props.usaInterceptador"
151
- :titulo-padrao="props.tituloPadrao"
152
- :ocultar-titulo-modal="props.ocultarTituloModal"
221
+ <component
222
+ :is="componenteModeloAtivo"
223
+ ref="modeloAtivoRef"
224
+ v-bind="propriedadesModeloAtivo"
153
225
  @before-save="$emit('before-save', $event)"
154
226
  >
155
- <template #campos-extras>
156
- <slot name="campos-extras"></slot>
227
+ <template v-for="(_, nomeSlot) in $slots" :key="nomeSlot" #[nomeSlot]="slotProps">
228
+ <slot :name="nomeSlot" v-bind="slotProps ?? {}"></slot>
157
229
  </template>
158
- </AgendaMatrix>
230
+ </component>
159
231
  </main>
160
232
  </div>
161
233
  </div>
162
234
  </div>
163
235
  </template>
236
+
164
237
  <style lang="scss">
165
- // importa o main.scss
166
238
  @use '../assets/scss/main.scss';
167
239
  </style>
168
240
 
169
241
  <style scoped>
170
- .painel-agenda-unificado {
171
- background: var(--bg-primary);
172
- border-radius: 16px;
173
- box-shadow: var(--shadow-float);
174
- border: 1px solid var(--border-light);
175
- flex-grow: 1;
176
- display: flex;
177
- flex-direction: column;
178
- overflow: hidden;
179
- }
180
- .painel-header-topo {
181
- height: 60px;
182
- background-color: var(--bg-primary);
183
- border-bottom: 1px solid var(--border-light);
184
- display: flex;
185
- align-items: center;
186
- justify-content: space-between;
187
- padding: 0 20px;
188
- flex-shrink: 0;
189
- }
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; }
190
244
  .corpo-principal { display: flex; flex-grow: 1; overflow: hidden; }
191
- .barra-lateral {
192
- width: 300px;
193
- background-color: var(--bg-primary);
194
- border-right: 1px solid var(--border-light);
195
- transition: width 0.3s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.2s;
196
- overflow: hidden;
197
- flex-shrink: 0;
198
- }
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; }
199
246
  .barra-lateral.oculta { width: 0; border-right: none; opacity: 0; }
200
247
  .conteudo-lateral-fixo { width: 300px; padding: 15px; }
201
248
  .secao-mini-cal { width: 100%; }
202
- .area-calendario {
203
- flex-grow: 1;
204
- overflow: hidden;
205
- background-color: var(--bg-primary);
206
- display: flex;
207
- flex-direction: column;
208
- }
209
-
249
+ .area-calendario { flex-grow: 1; overflow: hidden; background-color: var(--bg-primary); display: flex; flex-direction: column; }
210
250
  .calendario-mini { border: none !important; box-shadow: none !important; background-color: transparent !important; }
211
- :deep(.calendario-mini .vuecal__header), :deep(.calendario-mini .vuecal__title-bar) { background-color: transparent !important; border: none !important; padding-bottom: 5px; }
212
- :deep(.calendario-mini .vuecal__title), :deep(.calendario-mini .vuecal__arrow) {
213
- font-size: 1rem;
214
- font-weight: 600;
215
- color: var(--color-brand) !important;
216
- background: transparent !important;
217
- }
218
- :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; }
219
255
  :deep(.calendario-mini .vuecal__cell) { border: none !important; background-color: transparent !important; height: 32px !important; min-height: 32px !important; aspect-ratio: auto !important; }
220
256
  :deep(.calendario-mini .vuecal__cell::before) { display: none !important; content: none !important; }
221
- :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; }
222
- :deep(.calendario-mini .vuecal__cell-date) { width: 24px !important; height: 24px !important; font-size: 12px !important; line-height: 24px !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; }
223
- :deep(.calendario-mini .vuecal__cell--selected) { background-color: transparent !important; }
224
- :deep(.calendario-mini .vuecal__cell--selected .vuecal__cell-date) {
225
- background-color: var(--color-brand) !important;
226
- color: var(--text-inverse) !important;
227
- border-color: var(--color-brand) !important;
228
- }
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; }
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; }
229
262
  :deep(.vuecal__body) { padding: 0; gap: 0; margin: 0; }
230
- :deep(.calendario-mini .vuecal__cell--today) { background-color: transparent !important; }
231
- :deep(.calendario-mini .vuecal__cell-date){ background-color: transparent !important; color: var(--text-primary); }
232
- :deep(.calendario-mini .vuecal__cell--today:not(.vuecal__cell--selected) .vuecal__cell-date) {
233
- background-color: var(--color-brand-light) !important;
234
- border-color: transparent !important;
235
- color: var(--color-brand) !important;
236
- }
237
263
  :deep(.calendario-mini .vuecal__views-bar) { display: none !important; }
238
264
  :deep(.calendario-mini .vuecal__nav--next), :deep(.calendario-mini .vuecal__nav--prev) { color: var(--text-primary) !important; }
239
- :deep(.calendario-mini .vuecal__body){ height: 0%!important; }
240
- :deep(.calendario-mini .vuecal__scrollable-wrap){ background-color: transparent!important; }
241
-
242
- /* Remove o fundo branco forçado dos dias da semana no mini-calendário */
243
- :deep(.calendario-mini .vuecal__weekdays-headings),
244
- :deep(.calendario-mini .vuecal__weekday) {
245
- background-color: transparent !important;
246
- border: none !important;
247
- color: var(--text-secondary) !important;
248
- }
249
-
250
- :deep(.calendario-mini .vuecal__weekdays-headings) {
251
- background: transparent !important;
252
- background-color: transparent !important;
253
- border-bottom: 1px solid var(--border-light) !important;
254
- }
255
-
256
- /* Aplica o fundo transparente e a cor correta a cada dia individualmente e seus filhos */
257
- :deep(.calendario-mini .vuecal__heading),
258
- :deep(.calendario-mini .vuecal__weekday),
259
- :deep(.calendario-mini .vuecal__heading *) {
260
- background: transparent !important;
261
- background-color: transparent !important;
262
- color: var(--text-secondary) !important;
263
- font-weight: 600 !important;
264
- border: none !important;
265
- }
266
-
267
- :deep(.calendario-mini .vuecal__header),
268
- :deep(.calendario-mini .vuecal__weekdays-headings) {
269
- background: var(--bg-primary) !important;
270
- background-color: var(--bg-primary) !important;
271
- border-bottom: 1px solid var(--border-light) !important;
272
- }
273
-
274
- /* Garante que os itens individuais e o texto adotem o fundo escuro e texto legível */
275
- :deep(.calendario-mini .vuecal__heading),
276
- :deep(.calendario-mini .vuecal__weekday),
277
- :deep(.calendario-mini .vuecal__weekday-name),
278
- :deep(.calendario-mini .vuecal__heading *) {
279
- background: var(--bg-primary) !important;
280
- background-color: var(--bg-primary) !important;
281
- color: var(--text-secondary) !important;
282
- font-weight: 600 !important;
283
- border: none !important;
284
- }
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); }
285
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 e gerencia o dropdown de seleção de salas,
5
- preservando os filtros ativos mesmo quando o usuário altera a data no mini-calendário.
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">
@@ -13,30 +14,23 @@ import AgendaMatrixBase from './AgendaMatrixBase.vue';
13
14
  const props = defineProps({
14
15
  usaInterceptador: { type: Boolean, default: false },
15
16
  tituloPadrao: { type: String, default: '' },
16
- ocultarTituloModal: { type: Boolean, default: false }
17
+ ocultarTituloModal: { type: Boolean, default: false },
18
+ configuracaoBlocos: { type: [Array, Object], default: null }
17
19
  });
18
20
 
19
21
  const api = inject('api-instance-agenda') as any;
20
- const emit = defineEmits(['before-save']);
22
+ defineEmits(['before-save']);
21
23
 
22
- const { dadosMatrix, agendaSelecionada } = useAgenda(api);
24
+ const { dadosMatrix, agendaSelecionada, recursosDisponiveis } = useAgenda(api);
23
25
 
24
- // Armazena os IDs (em string) dos recursos visíveis selecionados no filtro.
25
26
  const recursosVisiveisIds = ref<string[]>([]);
26
-
27
- // Armazena o ID da última agenda cujo filtro foi inicializado para evitar reset ao mudar apenas a data.
28
27
  const idAgendaFiltroInicializado = ref<number | null>(null);
29
-
30
- // Controla a abertura do menu dropdown de filtro de salas.
31
28
  const menuFiltroAberto = ref(false);
32
29
 
33
- // Extrai a lista de recursos presentes no primeiro dia retornado na matriz.
34
30
  const recursosPermitidosNaMatriz = computed(() => {
35
- if (!dadosMatrix.value?.datas_matriz?.[0]?.recursos_slot) return [];
36
- return dadosMatrix.value.datas_matriz[0].recursos_slot;
31
+ return dadosMatrix.value?.datas_matriz?.[0]?.recursos_slot || [];
37
32
  });
38
33
 
39
- // Observa os recursos da matriz e inicializa o filtro apenas quando a agenda muda ou na primeira carga.
40
34
  watch(recursosPermitidosNaMatriz, (novosRecursos) => {
41
35
  if (novosRecursos.length === 0) {
42
36
  recursosVisiveisIds.value = [];
@@ -53,15 +47,31 @@ watch(recursosPermitidosNaMatriz, (novosRecursos) => {
53
47
  }
54
48
  }, { immediate: true });
55
49
 
56
- // 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
+
57
66
  const selecionarTodos = () => {
58
67
  recursosVisiveisIds.value = recursosPermitidosNaMatriz.value.map((r: any) => String(r.id_recurso));
59
68
  };
60
69
 
61
- // Desmarca todos os recursos no filtro de salas.
62
70
  const limparFiltros = () => {
63
71
  recursosVisiveisIds.value = [];
64
72
  };
73
+
74
+ defineExpose({ recursosEmExibicao });
65
75
  </script>
66
76
 
67
77
  <template>
@@ -70,8 +80,9 @@ const limparFiltros = () => {
70
80
  :usa-interceptador="props.usaInterceptador"
71
81
  :titulo-padrao="props.tituloPadrao"
72
82
  :ocultar-titulo-modal="props.ocultarTituloModal"
83
+ :configuracao-blocos="props.configuracaoBlocos"
73
84
  mensagem-vazio="Nenhuma sala selecionada."
74
- @before-save="$emit('before-save', $event)"
85
+ @before-save="$emit('before-save',$event)"
75
86
  >
76
87
  <template #topo>
77
88
  <div class="barra-filtros" v-if="recursosPermitidosNaMatriz.length > 0">
@@ -123,8 +134,8 @@ const limparFiltros = () => {
123
134
  </div>
124
135
  </template>
125
136
 
126
- <template #campos-extras>
127
- <slot name="campos-extras"></slot>
137
+ <template v-for="(_, nomeSlot) in $slots" :key="nomeSlot" #[nomeSlot]="slotProps">
138
+ <slot :name="nomeSlot" v-bind="slotProps ?? {}"></slot>
128
139
  </template>
129
140
  </AgendaMatrixBase>
130
141
  </template>