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/dist/v-sistec-features.css +1 -1
- package/dist/vDataAgenda.d.ts +591 -17
- package/dist/vDataAgenda.js +3382 -3469
- package/package.json +1 -1
- package/src/DataAgenda/VDataAgenda.vue +122 -285
- package/src/DataAgenda/components/AgendaMatrix.vue +27 -18
- package/src/DataAgenda/components/AgendaMatrixBase.vue +93 -501
- package/src/DataAgenda/components/AgendaMatrixUnico.vue +18 -28
- package/src/DataAgenda/components/AgendaTabelaHorario.vue +105 -515
- package/src/DataAgenda/components/AgendaVueCal.vue +118 -199
- package/src/DataAgenda/components/ModalReserva.vue +200 -291
- package/src/DataAgenda/composables/useGradeCompartilhada.ts +216 -0
|
@@ -7,10 +7,17 @@ e mescla células de reservas contínuas com colspan.
|
|
|
7
7
|
========
|
|
8
8
|
-->
|
|
9
9
|
<script setup lang="ts">
|
|
10
|
-
import { computed,
|
|
11
|
-
import { useAgenda } from '../composables/useAgenda';
|
|
10
|
+
import { computed, inject } from 'vue';
|
|
12
11
|
import { useCoresAgenda } from '../composables/useCoresAgenda';
|
|
13
12
|
import { useSelecaoArrasto } from '../composables/useSelecaoArrasto';
|
|
13
|
+
import {
|
|
14
|
+
SIGLAS_DIAS_JS,
|
|
15
|
+
extrairDataHoraLocal,
|
|
16
|
+
extrairHoraFormatada,
|
|
17
|
+
criarDataLocal,
|
|
18
|
+
mesclarSlotsReservados,
|
|
19
|
+
useGradeSemanal
|
|
20
|
+
} from '../composables/useGradeCompartilhada';
|
|
14
21
|
import BlocoArrastavel from './BlocoArrastavel.vue';
|
|
15
22
|
import ModalReserva from './ModalReserva.vue';
|
|
16
23
|
import ModalDetalhesReserva from './ModalDetalhesReserva.vue';
|
|
@@ -32,51 +39,21 @@ const props = defineProps<{
|
|
|
32
39
|
}>();
|
|
33
40
|
|
|
34
41
|
const api = inject('api-instance-agenda') as any;
|
|
35
|
-
|
|
42
|
+
defineEmits(['before-save']);
|
|
43
|
+
|
|
44
|
+
const { obterCoresBloco } = useCoresAgenda();
|
|
36
45
|
|
|
37
46
|
const {
|
|
38
47
|
dadosMatrix,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const { obterCoresBloco } = useCoresAgenda();
|
|
48
|
-
|
|
49
|
-
// Lista de siglas dos dias da semana ordenada conforme o retorno de Date.getDay() do JavaScript (0=DOM a 6=SAB).
|
|
50
|
-
const SIGLAS_DIAS_JS = ['DOM', 'SEG', 'TER', 'QUA', 'QUI', 'SEX', 'SAB'];
|
|
51
|
-
|
|
52
|
-
// Indica se a matriz está buscando e processando dados na API.
|
|
53
|
-
const carregando = ref(false);
|
|
54
|
-
|
|
55
|
-
// Controla a abertura do modal de criação de reserva.
|
|
56
|
-
const modalAberto = ref(false);
|
|
57
|
-
|
|
58
|
-
// Armazena os dados do slot ou intervalo selecionado para preencher o modal de criação.
|
|
59
|
-
const dadosParaModal = ref({});
|
|
60
|
-
|
|
61
|
-
// Controla a abertura do modal de detalhes de uma reserva existente.
|
|
62
|
-
const modalDetalhesAberto = ref(false);
|
|
63
|
-
|
|
64
|
-
// Armazena o objeto da reserva clicada para exibição no modal de detalhes.
|
|
65
|
-
const reservaSelecionadaDetalhes = ref<any>(null);
|
|
66
|
-
|
|
67
|
-
// Recebe uma string ISO UTC e devolve objeto com data (YYYY-MM-DD) e hora (HH:MM) locais.
|
|
68
|
-
// É usada para converter os limites dos slots selecionados para o formato esperado pelo ModalReserva.
|
|
69
|
-
const extrairDataHoraLocal = (isoString: string) => {
|
|
70
|
-
const d = new Date(isoString);
|
|
71
|
-
const ano = d.getFullYear();
|
|
72
|
-
const mes = String(d.getMonth() + 1).padStart(2, '0');
|
|
73
|
-
const dia = String(d.getDate()).padStart(2, '0');
|
|
74
|
-
const horas = String(d.getHours()).padStart(2, '0');
|
|
75
|
-
const min = String(d.getMinutes()).padStart(2, '0');
|
|
76
|
-
return { data: `${ano}-${mes}-${dia}`, hora: `${horas}:${min}` };
|
|
77
|
-
};
|
|
48
|
+
carregando,
|
|
49
|
+
modalAberto,
|
|
50
|
+
dadosParaModal,
|
|
51
|
+
modalDetalhesAberto,
|
|
52
|
+
reservaSelecionadaDetalhes,
|
|
53
|
+
obterBlocosDoDia,
|
|
54
|
+
dispararBuscaSemanal
|
|
55
|
+
} = useGradeSemanal(api, () => props.configuracaoBlocos);
|
|
78
56
|
|
|
79
|
-
// Instância do controlador genérico de arrasto configurada para operar nas linhas horizontais da matriz.
|
|
80
57
|
const controladorArrastoHorizontal = useSelecaoArrasto({
|
|
81
58
|
aoClicarItemIndisponivel: (item) => {
|
|
82
59
|
if (item?.slot?.reservado_slot && item?.slot?.detalhes_reserva) {
|
|
@@ -105,117 +82,10 @@ const controladorArrastoHorizontal = useSelecaoArrasto({
|
|
|
105
82
|
}
|
|
106
83
|
});
|
|
107
84
|
|
|
108
|
-
// Calcula a data de início da semana (Segunda-feira por padrão) com base na data selecionada.
|
|
109
|
-
const obterInicioDaSemana = (dataRef: Date, idAgenda: number | null) => {
|
|
110
|
-
const d = new Date(dataRef.getFullYear(), dataRef.getMonth(), dataRef.getDate());
|
|
111
|
-
const agendaObj = agendasDisponiveis.value.find((a: any) => Number(a.id_agenda) === Number(idAgenda));
|
|
112
|
-
const diaInicioPython = agendaObj?.detalhes?.dia_inicio_semana_agenda ?? 0;
|
|
113
|
-
const diaInicioJs = (diaInicioPython + 1) % 7;
|
|
114
|
-
const diff = (d.getDay() - diaInicioJs + 7) % 7;
|
|
115
|
-
d.setDate(d.getDate() - diff);
|
|
116
|
-
return d;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// Busca os slots da matriz e as reservas correspondentes à semana ordenada a partir do dia inicial da agenda.
|
|
120
|
-
const dispararBuscaMatrix = async () => {
|
|
121
|
-
const idAgenda = agendaSelecionada.value;
|
|
122
|
-
if (!idAgenda) return;
|
|
123
|
-
|
|
124
|
-
carregando.value = true;
|
|
125
|
-
|
|
126
|
-
const valorData = dataSelecionada.value || new Date();
|
|
127
|
-
let dataBase: Date;
|
|
128
|
-
|
|
129
|
-
if (typeof valorData === 'string') {
|
|
130
|
-
const apenasData = String(valorData).substring(0, 10);
|
|
131
|
-
const [ano, mes, dia] = apenasData.split('-');
|
|
132
|
-
dataBase = new Date(Number(ano), Number(mes) - 1, Number(dia));
|
|
133
|
-
} else {
|
|
134
|
-
dataBase = new Date(valorData);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const dataInicio = obterInicioDaSemana(dataBase, idAgenda);
|
|
138
|
-
const dataFim = new Date(dataInicio);
|
|
139
|
-
dataFim.setDate(dataInicio.getDate() + 6);
|
|
140
|
-
|
|
141
|
-
const formatar = (dt: Date) => {
|
|
142
|
-
const ano = dt.getFullYear();
|
|
143
|
-
const mes = String(dt.getMonth() + 1).padStart(2, '0');
|
|
144
|
-
const dia = String(dt.getDate()).padStart(2, '0');
|
|
145
|
-
return `${ano}-${mes}-${dia}`;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const strInicio = formatar(dataInicio);
|
|
149
|
-
const strFim = formatar(dataFim);
|
|
150
|
-
|
|
151
|
-
const inicioUtc = encodeURIComponent(converterParaUtc(strInicio, '00:00'));
|
|
152
|
-
const fimUtc = encodeURIComponent(converterParaUtc(strFim, '23:59'));
|
|
153
|
-
|
|
154
|
-
await buscarSlotsMatrix(idAgenda, inicioUtc, fimUtc);
|
|
155
|
-
await buscarReservas(`${strInicio}T00:00:00`, `${strFim}T23:59:59`);
|
|
156
|
-
carregando.value = false;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
onMounted(() => {
|
|
160
|
-
dispararBuscaMatrix();
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
watch([dataSelecionada, agendaSelecionada], () => {
|
|
164
|
-
dispararBuscaMatrix();
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// Recebe uma string ISO UTC e devolve uma string no formato HH:MM local.
|
|
168
|
-
const extrairHoraFormatada = (isoStr: string) => {
|
|
169
|
-
const d = new Date(isoStr);
|
|
170
|
-
const horas = String(d.getHours()).padStart(2, '0');
|
|
171
|
-
const minutos = String(d.getMinutes()).padStart(2, '0');
|
|
172
|
-
return `${horas}:${minutos}`;
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
// Recebe uma string de data YYYY-MM-DD e devolve a sigla do dia da semana correspondente (SEG, TER, etc.).
|
|
176
|
-
const obterSiglaDia = (isoData: string): string => {
|
|
177
|
-
const apenasData = String(isoData).substring(0, 10);
|
|
178
|
-
const [ano, mes, dia] = apenasData.split('-');
|
|
179
|
-
const data = new Date(Number(ano), Number(mes) - 1, Number(dia));
|
|
180
|
-
return SIGLAS_DIAS_JS[data.getDay()] || 'SEG';
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
// Localiza e devolve a configuração de blocos correspondente à agenda exibida no momento.
|
|
184
|
-
const configuracaoAgendaAtual = computed(() => {
|
|
185
|
-
if (!props.configuracaoBlocos || !agendaSelecionada.value) return null;
|
|
186
|
-
|
|
187
|
-
const idAtual = Number(agendaSelecionada.value);
|
|
188
|
-
|
|
189
|
-
if (Array.isArray(props.configuracaoBlocos)) {
|
|
190
|
-
return props.configuracaoBlocos.find((c: any) => Number(c.id_agenda) === idAtual) || null;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (typeof props.configuracaoBlocos === 'object') {
|
|
194
|
-
if (Number(props.configuracaoBlocos.id_agenda) === idAtual) {
|
|
195
|
-
return props.configuracaoBlocos;
|
|
196
|
-
}
|
|
197
|
-
if (props.configuracaoBlocos[idAtual]) {
|
|
198
|
-
return props.configuracaoBlocos[idAtual];
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return null;
|
|
203
|
-
});
|
|
204
|
-
|
|
205
85
|
// Constrói os blocos principais, subdivisões, cores e bordas por coluna para o cabeçalho e células de um dia específico.
|
|
206
86
|
const construirCabecalhosDeBlocos = (slotsBase: { horaInicio: string; horaFim: string }[], siglaDia: string) => {
|
|
207
87
|
const totalSlots = slotsBase.length;
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
let listaBlocosConfig: any[] | null = null;
|
|
211
|
-
|
|
212
|
-
if (configAgenda) {
|
|
213
|
-
if (configAgenda.por_dia && configAgenda.por_dia[siglaDia]) {
|
|
214
|
-
listaBlocosConfig = configAgenda.por_dia[siglaDia];
|
|
215
|
-
} else if (Array.isArray(configAgenda.blocos)) {
|
|
216
|
-
listaBlocosConfig = configAgenda.blocos;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
88
|
+
const listaBlocosConfig = obterBlocosDoDia(siglaDia);
|
|
219
89
|
|
|
220
90
|
const metadadosColunas: MetadadoColuna[] = slotsBase.map(() => ({
|
|
221
91
|
corFundo: null,
|
|
@@ -239,17 +109,30 @@ const construirCabecalhosDeBlocos = (slotsBase: { horaInicio: string; horaFim: s
|
|
|
239
109
|
let cursor = 0;
|
|
240
110
|
let algumSubblocoDefinido = false;
|
|
241
111
|
|
|
112
|
+
const adicionarSubbloco = (inicioIdx: number, tam: number, cor: string, corBorda: string, fimPrincipal: boolean, marcarSub: boolean) => {
|
|
113
|
+
const iniSub = slotsBase[inicioIdx];
|
|
114
|
+
const fimSub = slotsBase[inicioIdx + tam - 1];
|
|
115
|
+
subblocos.push({
|
|
116
|
+
colspan: tam,
|
|
117
|
+
cor,
|
|
118
|
+
corBorda,
|
|
119
|
+
fimDeBlocoPrincipal: fimPrincipal,
|
|
120
|
+
etiqueta: `${iniSub?.horaInicio ?? ''} - ${fimSub?.horaFim ?? ''}`
|
|
121
|
+
});
|
|
122
|
+
if (marcarSub) {
|
|
123
|
+
const metaFimSub = metadadosColunas[inicioIdx + tam - 1];
|
|
124
|
+
if (metaFimSub) metaFimSub.fimDeSubbloco = true;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
242
128
|
listaBlocosConfig.forEach((blocoCfg: any, idxBloco: number) => {
|
|
243
129
|
if (cursor >= totalSlots) return;
|
|
244
130
|
|
|
245
131
|
const qtdSolicitada = Number(blocoCfg.quantidade) || 0;
|
|
246
|
-
if (qtdSolicitada <= 0) return;
|
|
247
|
-
|
|
248
132
|
const qtdReal = Math.min(qtdSolicitada, totalSlots - cursor);
|
|
249
133
|
if (qtdReal <= 0) return;
|
|
250
134
|
|
|
251
135
|
const { corFundo: corBloco, corBorda } = obterCoresBloco(idxBloco);
|
|
252
|
-
|
|
253
136
|
const slotPrimeiro = slotsBase[cursor];
|
|
254
137
|
const slotUltimo = slotsBase[cursor + qtdReal - 1];
|
|
255
138
|
|
|
@@ -257,7 +140,7 @@ const construirCabecalhosDeBlocos = (slotsBase: { horaInicio: string; horaFim: s
|
|
|
257
140
|
nome: blocoCfg.nome || `Bloco ${idxBloco + 1}`,
|
|
258
141
|
colspan: qtdReal,
|
|
259
142
|
cor: corBloco,
|
|
260
|
-
corBorda
|
|
143
|
+
corBorda,
|
|
261
144
|
horaInicio: slotPrimeiro?.horaInicio ?? '',
|
|
262
145
|
horaFim: slotUltimo?.horaFim ?? ''
|
|
263
146
|
});
|
|
@@ -279,83 +162,35 @@ const construirCabecalhosDeBlocos = (slotsBase: { horaInicio: string; horaFim: s
|
|
|
279
162
|
listaSubCustom.forEach((tamSub: number) => {
|
|
280
163
|
if (consumido >= qtdReal) return;
|
|
281
164
|
const tamEfetivo = Math.min(Number(tamSub) || 1, qtdReal - consumido);
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
const ehUltimoDoBloco = (consumido + tamEfetivo) >= qtdReal;
|
|
285
|
-
|
|
286
|
-
subblocos.push({
|
|
287
|
-
colspan: tamEfetivo,
|
|
288
|
-
cor: corBloco,
|
|
289
|
-
corBorda: corBorda,
|
|
290
|
-
fimDeBlocoPrincipal: ehUltimoDoBloco,
|
|
291
|
-
etiqueta: `${iniSub?.horaInicio ?? ''} - ${fimSub?.horaFim ?? ''}`
|
|
292
|
-
});
|
|
293
|
-
|
|
165
|
+
const ehUltimo = (consumido + tamEfetivo) >= qtdReal;
|
|
166
|
+
adicionarSubbloco(cursor + consumido, tamEfetivo, corBloco, corBorda, ehUltimo, true);
|
|
294
167
|
consumido += tamEfetivo;
|
|
295
|
-
const metaFimSub = metadadosColunas[cursor + consumido - 1];
|
|
296
|
-
if (metaFimSub) metaFimSub.fimDeSubbloco = true;
|
|
297
168
|
});
|
|
298
169
|
if (consumido < qtdReal) {
|
|
299
|
-
|
|
300
|
-
const iniSub = slotsBase[cursor + consumido];
|
|
301
|
-
const fimSub = slotsBase[cursor + qtdReal - 1];
|
|
302
|
-
subblocos.push({
|
|
303
|
-
colspan: restante,
|
|
304
|
-
cor: corBloco,
|
|
305
|
-
corBorda: corBorda,
|
|
306
|
-
fimDeBlocoPrincipal: true,
|
|
307
|
-
etiqueta: `${iniSub?.horaInicio ?? ''} - ${fimSub?.horaFim ?? ''}`
|
|
308
|
-
});
|
|
309
|
-
const metaFimSub = metadadosColunas[cursor + qtdReal - 1];
|
|
310
|
-
if (metaFimSub) metaFimSub.fimDeSubbloco = true;
|
|
170
|
+
adicionarSubbloco(cursor + consumido, qtdReal - consumido, corBloco, corBorda, true, true);
|
|
311
171
|
}
|
|
312
172
|
} else if (tamanhoSubFixo > 0) {
|
|
313
173
|
algumSubblocoDefinido = true;
|
|
314
174
|
let consumido = 0;
|
|
315
175
|
while (consumido < qtdReal) {
|
|
316
176
|
const tamEfetivo = Math.min(tamanhoSubFixo, qtdReal - consumido);
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
const ehUltimoDoBloco = (consumido + tamEfetivo) >= qtdReal;
|
|
320
|
-
|
|
321
|
-
subblocos.push({
|
|
322
|
-
colspan: tamEfetivo,
|
|
323
|
-
cor: corBloco,
|
|
324
|
-
corBorda: corBorda,
|
|
325
|
-
fimDeBlocoPrincipal: ehUltimoDoBloco,
|
|
326
|
-
etiqueta: `${iniSub?.horaInicio ?? ''} - ${fimSub?.horaFim ?? ''}`
|
|
327
|
-
});
|
|
328
|
-
|
|
177
|
+
const ehUltimo = (consumido + tamEfetivo) >= qtdReal;
|
|
178
|
+
adicionarSubbloco(cursor + consumido, tamEfetivo, corBloco, corBorda, ehUltimo, true);
|
|
329
179
|
consumido += tamEfetivo;
|
|
330
|
-
const metaFimSub = metadadosColunas[cursor + consumido - 1];
|
|
331
|
-
if (metaFimSub) metaFimSub.fimDeSubbloco = true;
|
|
332
180
|
}
|
|
333
181
|
} else {
|
|
334
|
-
|
|
335
|
-
const fimSub = slotsBase[cursor + qtdReal - 1];
|
|
336
|
-
subblocos.push({
|
|
337
|
-
colspan: qtdReal,
|
|
338
|
-
cor: corBloco,
|
|
339
|
-
corBorda: corBorda,
|
|
340
|
-
fimDeBlocoPrincipal: true,
|
|
341
|
-
etiqueta: `${iniSub?.horaInicio ?? ''} - ${fimSub?.horaFim ?? ''}`
|
|
342
|
-
});
|
|
182
|
+
adicionarSubbloco(cursor, qtdReal, corBloco, corBorda, true, false);
|
|
343
183
|
}
|
|
344
184
|
|
|
345
185
|
const metaFimPrincipal = metadadosColunas[cursor + qtdReal - 1];
|
|
346
|
-
if (metaFimPrincipal)
|
|
347
|
-
metaFimPrincipal.fimDeBlocoPrincipal = true;
|
|
348
|
-
}
|
|
186
|
+
if (metaFimPrincipal) metaFimPrincipal.fimDeBlocoPrincipal = true;
|
|
349
187
|
|
|
350
188
|
cursor += qtdReal;
|
|
351
189
|
});
|
|
352
190
|
|
|
353
191
|
if (cursor < totalSlots) {
|
|
354
192
|
const restante = totalSlots - cursor;
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
const { corFundo: corRestante, corBorda: corBordaRestante } = obterCoresBloco(idxExtra);
|
|
358
|
-
|
|
193
|
+
const { corFundo: corRestante, corBorda: corBordaRestante } = obterCoresBloco(blocosPrincipais.length);
|
|
359
194
|
const slotPrimeiro = slotsBase[cursor];
|
|
360
195
|
const slotUltimo = slotsBase[totalSlots - 1];
|
|
361
196
|
|
|
@@ -376,18 +211,10 @@ const construirCabecalhosDeBlocos = (slotsBase: { horaInicio: string; horaFim: s
|
|
|
376
211
|
}
|
|
377
212
|
}
|
|
378
213
|
|
|
379
|
-
|
|
380
|
-
colspan: restante,
|
|
381
|
-
cor: corRestante,
|
|
382
|
-
corBorda: corBordaRestante,
|
|
383
|
-
fimDeBlocoPrincipal: true,
|
|
384
|
-
etiqueta: `${slotPrimeiro?.horaInicio ?? ''} - ${slotUltimo?.horaFim ?? ''}`
|
|
385
|
-
});
|
|
214
|
+
adicionarSubbloco(cursor, restante, corRestante, corBordaRestante, true, false);
|
|
386
215
|
|
|
387
216
|
const metaUltimo = metadadosColunas[totalSlots - 1];
|
|
388
|
-
if (metaUltimo)
|
|
389
|
-
metaUltimo.fimDeBlocoPrincipal = true;
|
|
390
|
-
}
|
|
217
|
+
if (metaUltimo) metaUltimo.fimDeBlocoPrincipal = true;
|
|
391
218
|
}
|
|
392
219
|
|
|
393
220
|
return {
|
|
@@ -399,7 +226,7 @@ const construirCabecalhosDeBlocos = (slotsBase: { horaInicio: string; horaFim: s
|
|
|
399
226
|
};
|
|
400
227
|
};
|
|
401
228
|
|
|
402
|
-
// Gera a lista ordenada de dias operacionais
|
|
229
|
+
// Gera a lista ordenada de dias operacionais com cabeçalhos e células mescladas por colspan.
|
|
403
230
|
const diasProcessados = computed(() => {
|
|
404
231
|
if (!dadosMatrix.value?.datas_matriz) return [];
|
|
405
232
|
|
|
@@ -411,12 +238,9 @@ const diasProcessados = computed(() => {
|
|
|
411
238
|
const recursosFiltrados = (dia.recursos_slot || []).filter((res: any) =>
|
|
412
239
|
props.idsRecursosVisiveis.includes(String(res.id_recurso))
|
|
413
240
|
);
|
|
414
|
-
|
|
415
241
|
if (recursosFiltrados.length === 0) return;
|
|
416
242
|
|
|
417
|
-
const
|
|
418
|
-
const slotsValidosBase = (primeiroRecurso.horarios_slot || []).filter((s: any) => !s.bloqueado_slot);
|
|
419
|
-
|
|
243
|
+
const slotsValidosBase = (recursosFiltrados[0].horarios_slot || []).filter((s: any) => !s.bloqueado_slot);
|
|
420
244
|
if (slotsValidosBase.length === 0) return;
|
|
421
245
|
|
|
422
246
|
const definicaoColunas = slotsValidosBase.map((s: any) => ({
|
|
@@ -424,69 +248,23 @@ const diasProcessados = computed(() => {
|
|
|
424
248
|
horaFim: extrairHoraFormatada(s.data_fim_slot)
|
|
425
249
|
}));
|
|
426
250
|
|
|
427
|
-
const siglaDia =
|
|
251
|
+
const siglaDia = SIGLAS_DIAS_JS[criarDataLocal(dia.data_slot).getDay()] || 'SEG';
|
|
428
252
|
const infoBlocos = construirCabecalhosDeBlocos(definicaoColunas, siglaDia);
|
|
429
253
|
|
|
430
254
|
const recursosProcessados = recursosFiltrados.map((rec: any) => {
|
|
431
255
|
const slotsBrutos = (rec.horarios_slot || []).filter((s: any) => !s.bloqueado_slot);
|
|
432
|
-
const celulasMescladas: any[] = [];
|
|
433
|
-
|
|
434
|
-
let i = 0;
|
|
435
|
-
while (i < slotsBrutos.length) {
|
|
436
|
-
const slotAtual = slotsBrutos[i];
|
|
437
|
-
const codRef = slotAtual?.detalhes_reserva?.codigo_referencia_reserva;
|
|
438
|
-
|
|
439
|
-
if (slotAtual?.reservado_slot && codRef) {
|
|
440
|
-
let span = 1;
|
|
441
|
-
while (
|
|
442
|
-
i + span < slotsBrutos.length &&
|
|
443
|
-
slotsBrutos[i + span]?.reservado_slot &&
|
|
444
|
-
slotsBrutos[i + span]?.detalhes_reserva?.codigo_referencia_reserva === codRef
|
|
445
|
-
) {
|
|
446
|
-
span++;
|
|
447
|
-
}
|
|
448
|
-
celulasMescladas.push({
|
|
449
|
-
...slotAtual,
|
|
450
|
-
indiceColuna: i,
|
|
451
|
-
colspan: span,
|
|
452
|
-
ocultaPorColspan: false
|
|
453
|
-
});
|
|
454
|
-
for (let k = 1; k < span; k++) {
|
|
455
|
-
celulasMescladas.push({
|
|
456
|
-
...slotsBrutos[i + k],
|
|
457
|
-
indiceColuna: i + k,
|
|
458
|
-
colspan: 1,
|
|
459
|
-
ocultaPorColspan: true
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
i += span;
|
|
463
|
-
} else {
|
|
464
|
-
celulasMescladas.push({
|
|
465
|
-
...slotAtual,
|
|
466
|
-
indiceColuna: i,
|
|
467
|
-
colspan: 1,
|
|
468
|
-
ocultaPorColspan: false
|
|
469
|
-
});
|
|
470
|
-
i++;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
256
|
return {
|
|
475
257
|
id_recurso: rec.id_recurso,
|
|
476
258
|
nome_recurso: rec.nome_recurso,
|
|
477
259
|
slotsBrutos,
|
|
478
|
-
horarios_slot:
|
|
260
|
+
horarios_slot: mesclarSlotsReservados(slotsBrutos, 'colspan')
|
|
479
261
|
};
|
|
480
262
|
});
|
|
481
263
|
|
|
482
264
|
resultado.push({
|
|
483
265
|
data_slot: dia.data_slot,
|
|
484
266
|
colunasHorarios: definicaoColunas,
|
|
485
|
-
|
|
486
|
-
temSubblocos: infoBlocos.temSubblocos,
|
|
487
|
-
blocosPrincipais: infoBlocos.blocosPrincipais,
|
|
488
|
-
subblocos: infoBlocos.subblocos,
|
|
489
|
-
metadadosColunas: infoBlocos.metadadosColunas,
|
|
267
|
+
...infoBlocos,
|
|
490
268
|
recursos_slot: recursosProcessados
|
|
491
269
|
});
|
|
492
270
|
});
|
|
@@ -494,12 +272,13 @@ const diasProcessados = computed(() => {
|
|
|
494
272
|
return resultado;
|
|
495
273
|
});
|
|
496
274
|
|
|
497
|
-
// Formata a data YYYY-MM-DD por extenso em português para a barra superior de cada dia.
|
|
498
275
|
const formatarData = (isoData: string) => {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
276
|
+
return criarDataLocal(isoData).toLocaleDateString('pt-BR', {
|
|
277
|
+
weekday: 'long',
|
|
278
|
+
day: '2-digit',
|
|
279
|
+
month: 'long',
|
|
280
|
+
year: 'numeric'
|
|
281
|
+
});
|
|
503
282
|
};
|
|
504
283
|
</script>
|
|
505
284
|
|
|
@@ -511,10 +290,10 @@ const formatarData = (isoData: string) => {
|
|
|
511
290
|
:usa-interceptador="props.usaInterceptador"
|
|
512
291
|
:ocultar-titulo-modal="props.ocultarTituloModal"
|
|
513
292
|
@before-save="$emit('before-save', $event)"
|
|
514
|
-
@salvo="
|
|
293
|
+
@salvo="dispararBuscaSemanal"
|
|
515
294
|
>
|
|
516
|
-
<template #
|
|
517
|
-
<slot name="
|
|
295
|
+
<template v-for="(_, nomeSlot) in $slots" :key="nomeSlot" #[nomeSlot]="slotProps">
|
|
296
|
+
<slot v-if="nomeSlot !== 'topo'" :name="nomeSlot" v-bind="slotProps ?? {}"></slot>
|
|
518
297
|
</template>
|
|
519
298
|
</ModalReserva>
|
|
520
299
|
|
|
@@ -522,7 +301,7 @@ const formatarData = (isoData: string) => {
|
|
|
522
301
|
v-model="modalDetalhesAberto"
|
|
523
302
|
:reserva="reservaSelecionadaDetalhes"
|
|
524
303
|
:titulo-padrao="props.tituloPadrao"
|
|
525
|
-
@excluido="
|
|
304
|
+
@excluido="dispararBuscaSemanal"
|
|
526
305
|
/>
|
|
527
306
|
|
|
528
307
|
<div class="aviso-vazio" v-if="carregando">
|
|
@@ -668,224 +447,43 @@ const formatarData = (isoData: string) => {
|
|
|
668
447
|
.spinner { width: 32px; height: 32px; border: 3px solid var(--border-light); border-top-color: var(--color-brand); border-radius: 50%; animation: spin 1s linear infinite; }
|
|
669
448
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
670
449
|
|
|
671
|
-
.tabelas-scroll-container {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
.bloco-
|
|
682
|
-
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
.
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
.tabela-premium th,
|
|
694
|
-
.tabela-premium td {
|
|
695
|
-
padding: 4px 6px;
|
|
696
|
-
min-width: 68px;
|
|
697
|
-
height: 44px;
|
|
698
|
-
border-bottom: 1px solid var(--border-light);
|
|
699
|
-
border-right: 1px solid var(--border-light);
|
|
700
|
-
box-sizing: border-box;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
.tabela-premium th:first-child,
|
|
704
|
-
.tabela-premium td:first-child {
|
|
705
|
-
border-left: 1px solid var(--border-light);
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
.tabela-premium thead th {
|
|
709
|
-
background: var(--bg-primary);
|
|
710
|
-
font-weight: 700;
|
|
711
|
-
color: var(--text-primary);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
.coluna-fixa {
|
|
715
|
-
width: 200px;
|
|
716
|
-
min-width: 200px;
|
|
717
|
-
max-width: 200px;
|
|
718
|
-
text-align: left;
|
|
719
|
-
background: var(--bg-primary);
|
|
720
|
-
position: sticky;
|
|
721
|
-
left: 0;
|
|
722
|
-
z-index: 2;
|
|
723
|
-
border-right: 2px solid var(--border-light) !important;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
.cabecalho-canto {
|
|
727
|
-
z-index: 3 !important;
|
|
728
|
-
padding-left: 24px !important;
|
|
729
|
-
background: var(--bg-primary) !important;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
.th-barra-dia {
|
|
733
|
-
padding: 0 !important;
|
|
734
|
-
height: auto !important;
|
|
735
|
-
border-top: 1px solid #005291 !important;
|
|
736
|
-
border-bottom: 1px solid #005291 !important;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
.th-bloco-principal {
|
|
740
|
-
color: #111827 !important;
|
|
741
|
-
padding: 6px 4px !important;
|
|
742
|
-
height: 36px !important;
|
|
743
|
-
border-bottom-width: 1.5px !important;
|
|
744
|
-
border-bottom-style: solid !important;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
.titulo-bloco-principal {
|
|
748
|
-
font-size: 13px;
|
|
749
|
-
font-weight: 800;
|
|
750
|
-
letter-spacing: 0.3px;
|
|
751
|
-
line-height: 1.2;
|
|
752
|
-
text-transform: uppercase;
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
.subtitulo-bloco-principal {
|
|
756
|
-
font-size: 10.5px;
|
|
757
|
-
font-weight: 700;
|
|
758
|
-
opacity: 0.9;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
.th-subbloco {
|
|
762
|
-
color: #111827 !important;
|
|
763
|
-
font-size: 11px !important;
|
|
764
|
-
font-weight: 700 !important;
|
|
765
|
-
height: 26px !important;
|
|
766
|
-
padding: 2px 4px !important;
|
|
767
|
-
border-bottom-width: 1.5px !important;
|
|
768
|
-
border-bottom-style: solid !important;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
.th-horario-individual {
|
|
772
|
-
height: 42px !important;
|
|
773
|
-
padding: 4px 2px !important;
|
|
774
|
-
color: #111827 !important;
|
|
775
|
-
border-bottom-width: 2px !important;
|
|
776
|
-
border-bottom-style: solid !important;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
.empilhado-horarios {
|
|
780
|
-
display: flex;
|
|
781
|
-
flex-direction: column;
|
|
782
|
-
align-items: center;
|
|
783
|
-
justify-content: center;
|
|
784
|
-
line-height: 1.15;
|
|
785
|
-
gap: 2px;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
.hora-topo {
|
|
789
|
-
font-size: 11.5px;
|
|
790
|
-
font-weight: 700;
|
|
791
|
-
color: #111827;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
.hora-base {
|
|
795
|
-
font-size: 11.5px;
|
|
796
|
-
font-weight: 700;
|
|
797
|
-
color: #111827;
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
.td-celula-slot {
|
|
801
|
-
cursor: pointer;
|
|
802
|
-
transition: filter 0.12s ease, box-shadow 0.12s ease;
|
|
803
|
-
vertical-align: middle;
|
|
804
|
-
color: #111827 !important;
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
.td-celula-slot:hover {
|
|
808
|
-
filter: brightness(0.93);
|
|
809
|
-
box-shadow: inset 0 0 0 1.5px var(--color-brand);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
.slot-selecionado-arrasto {
|
|
813
|
-
box-shadow: inset 0 0 0 2px var(--color-brand) !important;
|
|
814
|
-
}
|
|
815
|
-
|
|
450
|
+
.tabelas-scroll-container { flex-grow: 1; overflow: auto; background: var(--bg-primary); display: flex; flex-direction: column; gap: 18px; padding-bottom: 24px; }
|
|
451
|
+
.bloco-dia-tabela { width: 100%; }
|
|
452
|
+
.tabela-premium { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; text-align: center; }
|
|
453
|
+
.tabela-premium th, .tabela-premium td { padding: 4px 6px; min-width: 68px; height: 44px; border-bottom: 1px solid var(--border-light); border-right: 1px solid var(--border-light); box-sizing: border-box; }
|
|
454
|
+
.tabela-premium th:first-child, .tabela-premium td:first-child { border-left: 1px solid var(--border-light); }
|
|
455
|
+
.tabela-premium thead th { background: var(--bg-primary); font-weight: 700; color: var(--text-primary); }
|
|
456
|
+
|
|
457
|
+
.coluna-fixa { width: 200px; min-width: 200px; max-width: 200px; text-align: left; background: var(--bg-primary); position: sticky; left: 0; z-index: 2; border-right: 2px solid var(--border-light) !important; }
|
|
458
|
+
.cabecalho-canto { z-index: 3 !important; padding-left: 24px !important; background: var(--bg-primary) !important; }
|
|
459
|
+
.th-barra-dia { padding: 0 !important; height: auto !important; border-top: 1px solid #005291 !important; border-bottom: 1px solid #005291 !important; }
|
|
460
|
+
.th-bloco-principal { color: #111827 !important; padding: 6px 4px !important; height: 36px !important; border-bottom-width: 1.5px !important; border-bottom-style: solid !important; }
|
|
461
|
+
.titulo-bloco-principal { font-size: 13px; font-weight: 800; letter-spacing: 0.3px; line-height: 1.2; text-transform: uppercase; }
|
|
462
|
+
.subtitulo-bloco-principal { font-size: 10.5px; font-weight: 700; opacity: 0.9; }
|
|
463
|
+
.th-subbloco { color: #111827 !important; font-size: 11px !important; font-weight: 700 !important; height: 26px !important; padding: 2px 4px !important; border-bottom-width: 1.5px !important; border-bottom-style: solid !important; }
|
|
464
|
+
.th-horario-individual { height: 42px !important; padding: 4px 2px !important; color: #111827 !important; border-bottom-width: 2px !important; border-bottom-style: solid !important; }
|
|
465
|
+
.empilhado-horarios { display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.15; gap: 2px; }
|
|
466
|
+
.hora-topo, .hora-base { font-size: 11.5px; font-weight: 700; color: #111827; }
|
|
467
|
+
|
|
468
|
+
.td-celula-slot { cursor: pointer; transition: filter 0.12s ease, box-shadow 0.12s ease; vertical-align: middle; color: #111827 !important; }
|
|
469
|
+
.td-celula-slot:hover { filter: brightness(0.93); box-shadow: inset 0 0 0 1.5px var(--color-brand); }
|
|
470
|
+
.slot-selecionado-arrasto { box-shadow: inset 0 0 0 2px var(--color-brand) !important; }
|
|
816
471
|
.slot-ocupado {
|
|
817
472
|
font-weight: 700;
|
|
818
473
|
background-color: #e5e7eb !important;
|
|
819
|
-
background-image: repeating-linear-gradient(
|
|
820
|
-
45deg,
|
|
821
|
-
rgba(0, 0, 0, 0.06),
|
|
822
|
-
rgba(0, 0, 0, 0.06) 10px,
|
|
823
|
-
transparent 10px,
|
|
824
|
-
transparent 20px
|
|
825
|
-
) !important;
|
|
474
|
+
background-image: repeating-linear-gradient(45deg, rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.06) 10px, transparent 10px, transparent 20px) !important;
|
|
826
475
|
}
|
|
827
476
|
|
|
828
|
-
.conteudo-slot-matrix {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
.etiqueta-reserva {
|
|
837
|
-
font-size: 12px;
|
|
838
|
-
font-weight: 700;
|
|
839
|
-
color: #111827;
|
|
840
|
-
line-height: 1.25;
|
|
841
|
-
word-break: break-word;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
.borda-col-subbloco {
|
|
845
|
-
border-right-width: 2px !important;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
.borda-col-bloco-principal {
|
|
849
|
-
border-right-width: 2.5px !important;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
.barra-data-full {
|
|
853
|
-
display: flex;
|
|
854
|
-
align-items: center;
|
|
855
|
-
justify-content: center;
|
|
856
|
-
width: 100%;
|
|
857
|
-
background-color: #0066B3 !important;
|
|
858
|
-
color: #FFFFFF !important;
|
|
859
|
-
padding: 9px 0;
|
|
860
|
-
border-radius: 0;
|
|
861
|
-
box-shadow: none;
|
|
862
|
-
box-sizing: border-box;
|
|
863
|
-
border: none;
|
|
864
|
-
text-align: center;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
.texto-data {
|
|
868
|
-
font-weight: 800;
|
|
869
|
-
font-size: 13.5px;
|
|
870
|
-
text-transform: uppercase;
|
|
871
|
-
letter-spacing: 0.5px;
|
|
872
|
-
}
|
|
873
|
-
|
|
874
|
-
.nome-recurso {
|
|
875
|
-
font-weight: 700;
|
|
876
|
-
color: var(--text-primary);
|
|
877
|
-
background: var(--bg-primary) !important;
|
|
878
|
-
padding-left: 20px !important;
|
|
879
|
-
padding-right: 12px !important;
|
|
880
|
-
white-space: nowrap;
|
|
881
|
-
overflow: hidden;
|
|
882
|
-
text-overflow: ellipsis;
|
|
883
|
-
box-shadow: 4px 0 8px rgba(0,0,0,0.03);
|
|
884
|
-
}
|
|
477
|
+
.conteudo-slot-matrix { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; }
|
|
478
|
+
.etiqueta-reserva { font-size: 12px; font-weight: 700; color: #111827; line-height: 1.25; word-break: break-word; }
|
|
479
|
+
.borda-col-subbloco { border-right-width: 2px !important; }
|
|
480
|
+
.borda-col-bloco-principal { border-right-width: 2.5px !important; }
|
|
481
|
+
.barra-data-full { display: flex; align-items: center; justify-content: center; width: 100%; background-color: #0066B3 !important; color: #FFFFFF !important; padding: 9px 0; box-sizing: border-box; text-align: center; }
|
|
482
|
+
.texto-data { font-weight: 800; font-size: 13.5px; text-transform: uppercase; letter-spacing: 0.5px; }
|
|
483
|
+
.nome-recurso { font-weight: 700; color: var(--text-primary); background: var(--bg-primary) !important; padding-left: 20px !important; padding-right: 12px !important; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-shadow: 4px 0 8px rgba(0,0,0,0.03); }
|
|
885
484
|
</style>
|
|
886
485
|
|
|
887
486
|
<style>
|
|
888
|
-
/* CSS injetado globalmente para os blocos da matriz base escurecerem o texto no dark theme */
|
|
889
487
|
[data-bs-theme="dark"] .th-bloco-principal,
|
|
890
488
|
[data-bs-theme="dark"] .th-subbloco,
|
|
891
489
|
[data-bs-theme="dark"] .th-horario-individual,
|
|
@@ -898,12 +496,6 @@ const formatarData = (isoData: string) => {
|
|
|
898
496
|
|
|
899
497
|
[data-bs-theme="dark"] .slot-ocupado {
|
|
900
498
|
background-color: #374151 !important;
|
|
901
|
-
background-image: repeating-linear-gradient(
|
|
902
|
-
45deg,
|
|
903
|
-
rgba(255, 255, 255, 0.03),
|
|
904
|
-
rgba(255, 255, 255, 0.03) 10px,
|
|
905
|
-
transparent 10px,
|
|
906
|
-
transparent 20px
|
|
907
|
-
) !important;
|
|
499
|
+
background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.03) 10px, transparent 10px, transparent 20px) !important;
|
|
908
500
|
}
|
|
909
501
|
</style>
|