Adicionado CRUD Minha Turma e Observações Especiais
This commit is contained in:
+302
-1
@@ -2778,17 +2778,43 @@ const initApp = () => {
|
|||||||
// ============================================================
|
// ============================================================
|
||||||
const obsModal = document.getElementById('obsModal');
|
const obsModal = document.getElementById('obsModal');
|
||||||
const btnObservacoes = document.getElementById('btnObservacoes');
|
const btnObservacoes = document.getElementById('btnObservacoes');
|
||||||
|
const btnObsEspeciais = document.getElementById('btnObsEspeciais');
|
||||||
const btnCloseObsModal = document.getElementById('btnCloseObsModal');
|
const btnCloseObsModal = document.getElementById('btnCloseObsModal');
|
||||||
|
const obsModalTitle = document.getElementById('obsModalTitle');
|
||||||
const obsList = document.getElementById('obsList');
|
const obsList = document.getElementById('obsList');
|
||||||
const obsFilterMes = document.getElementById('obsFilterMes');
|
const obsFilterMes = document.getElementById('obsFilterMes');
|
||||||
const obsFilterTag = document.getElementById('obsFilterTag');
|
const obsFilterTag = document.getElementById('obsFilterTag');
|
||||||
const obsSearchCrianca = document.getElementById('obsSearchCrianca');
|
const obsSearchCrianca = document.getElementById('obsSearchCrianca');
|
||||||
|
|
||||||
let allObservations = [];
|
let allObservations = [];
|
||||||
|
let isSpecialObsMode = false;
|
||||||
|
|
||||||
// Abrir modal de observações
|
// Abrir modal de observações
|
||||||
if (btnObservacoes) {
|
if (btnObservacoes) {
|
||||||
btnObservacoes.addEventListener('click', async () => {
|
btnObservacoes.addEventListener('click', async () => {
|
||||||
|
isSpecialObsMode = false;
|
||||||
|
if (obsModalTitle) obsModalTitle.textContent = '📒 Minhas Observações';
|
||||||
|
obsModal.style.display = 'flex';
|
||||||
|
obsList.innerHTML = '<div class="obs-empty">Carregando...</div>';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/observacoes');
|
||||||
|
const data = await res.json();
|
||||||
|
allObservations = data.observations || [];
|
||||||
|
populateMonthFilter();
|
||||||
|
renderObsList();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Erro ao carregar observações:', err);
|
||||||
|
obsList.innerHTML = '<div class="obs-empty">Erro ao carregar observações.</div>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abrir modal de observações Especiais
|
||||||
|
if (btnObsEspeciais) {
|
||||||
|
btnObsEspeciais.addEventListener('click', async () => {
|
||||||
|
isSpecialObsMode = true;
|
||||||
|
if (obsModalTitle) obsModalTitle.textContent = '📒 Observações Educação Especial';
|
||||||
obsModal.style.display = 'flex';
|
obsModal.style.display = 'flex';
|
||||||
obsList.innerHTML = '<div class="obs-empty">Carregando...</div>';
|
obsList.innerHTML = '<div class="obs-empty">Carregando...</div>';
|
||||||
|
|
||||||
@@ -2838,11 +2864,30 @@ const initApp = () => {
|
|||||||
const tag = obsFilterTag?.value || '';
|
const tag = obsFilterTag?.value || '';
|
||||||
const search = obsSearchCrianca?.value.toLowerCase() || '';
|
const search = obsSearchCrianca?.value.toLowerCase() || '';
|
||||||
|
|
||||||
|
let especialKidsNames = [];
|
||||||
|
if (isSpecialObsMode) {
|
||||||
|
const turma = JSON.parse(localStorage.getItem('camila_turma') || '[]');
|
||||||
|
especialKidsNames = turma.filter(c => c.especial).map(c => (c.nome || '').toLowerCase().trim()).filter(Boolean);
|
||||||
|
if (especialKidsNames.length === 0) {
|
||||||
|
obsList.innerHTML = '<div class="obs-empty">Nenhuma criança com "Educação Especial" cadastrada na Minha Turma.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const filtered = allObservations.filter(o => {
|
const filtered = allObservations.filter(o => {
|
||||||
if (mes && !o.date?.startsWith(mes)) return false;
|
if (mes && !o.date?.startsWith(mes)) return false;
|
||||||
if (tag && !o.tags?.includes(tag)) return false;
|
if (tag && !o.tags?.includes(tag)) return false;
|
||||||
|
|
||||||
|
const nomes = (o.criancas || []).join(' ').toLowerCase();
|
||||||
|
|
||||||
|
if (isSpecialObsMode) {
|
||||||
|
// Must contain at least one special kid's name
|
||||||
|
const preview = (o.preview || '').toLowerCase();
|
||||||
|
const isEspecial = especialKidsNames.some(ekn => nomes.includes(ekn) || preview.includes(ekn));
|
||||||
|
if (!isEspecial) return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
const nomes = (o.criancas || []).join(' ').toLowerCase();
|
|
||||||
if (!nomes.includes(search) && !(o.preview || '').toLowerCase().includes(search)) return false;
|
if (!nomes.includes(search) && !(o.preview || '').toLowerCase().includes(search)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -2886,6 +2931,262 @@ const initApp = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// MODAL: MINHA TURMA
|
||||||
|
// ============================================================
|
||||||
|
const minhaTurmaModal = document.getElementById('minhaTurmaModal');
|
||||||
|
const btnMinhaTurma = document.getElementById('btnMinhaTurma');
|
||||||
|
const btnCloseMinhaTurmaModal = document.getElementById('btnCloseMinhaTurmaModal');
|
||||||
|
const childrenList = document.getElementById('childrenList');
|
||||||
|
const btnCreateChild = document.getElementById('btnCreateChild');
|
||||||
|
const btnCancelChild = document.getElementById('btnCancelChild');
|
||||||
|
const btnSaveChild = document.getElementById('btnSaveChild');
|
||||||
|
const childFormTitle = document.getElementById('childFormTitle');
|
||||||
|
|
||||||
|
// Fields
|
||||||
|
const cFormId = document.getElementById('childFormId');
|
||||||
|
const cFormTurma = document.getElementById('childFormTurma');
|
||||||
|
const cFormSala = document.getElementById('childFormSala');
|
||||||
|
const cFormPeriodo = document.getElementById('childFormPeriodo');
|
||||||
|
const cFormAuxiliares = document.getElementById('childFormAuxiliares');
|
||||||
|
const cFormNome = document.getElementById('childFormNome');
|
||||||
|
const cFormApelido = document.getElementById('childFormApelido');
|
||||||
|
const cFormDataNasc = document.getElementById('childFormDataNasc');
|
||||||
|
const cFormEspecial = document.getElementById('childFormEspecial');
|
||||||
|
const divEspecialDetalhes = document.getElementById('divEspecialDetalhes');
|
||||||
|
const cFormEspecialDetalhes = document.getElementById('childFormEspecialDetalhes');
|
||||||
|
const cFormPais = document.getElementById('childFormPais');
|
||||||
|
const cFormAutorizados = document.getElementById('childFormAutorizados');
|
||||||
|
|
||||||
|
// Toggle Especial Fields
|
||||||
|
if (cFormEspecial) {
|
||||||
|
cFormEspecial.addEventListener('change', () => {
|
||||||
|
if (cFormEspecial.checked) {
|
||||||
|
divEspecialDetalhes.style.display = 'flex';
|
||||||
|
} else {
|
||||||
|
divEspecialDetalhes.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadTurma = () => {
|
||||||
|
return JSON.parse(localStorage.getItem('camila_turma') || '[]');
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveTurma = (turma) => {
|
||||||
|
localStorage.setItem('camila_turma', JSON.stringify(turma));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTurmaList = () => {
|
||||||
|
if (!childrenList) return;
|
||||||
|
const turma = loadTurma();
|
||||||
|
if (turma.length === 0) {
|
||||||
|
childrenList.innerHTML = '<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Nenhuma criança cadastrada.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by name
|
||||||
|
turma.sort((a, b) => (a.nome || '').localeCompare(b.nome || ''));
|
||||||
|
|
||||||
|
childrenList.innerHTML = turma.map(c => `
|
||||||
|
<div style="background: var(--bg-secondary); border: 1px solid var(--border-light); padding: 12px; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<div>
|
||||||
|
<div style="font-weight: 600; color: var(--text-primary);">${escapeHtml(c.nome)} ${c.especial ? '⭐' : ''}</div>
|
||||||
|
<div style="font-size: 0.8rem; color: var(--text-secondary);">${escapeHtml(c.turma || '')} - ${escapeHtml(c.periodo || '')}</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; gap: 8px;">
|
||||||
|
<button onclick="editChild('${c.id}')" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; padding: 4px;" title="Editar">✏️</button>
|
||||||
|
<button onclick="deleteChild('${c.id}')" style="background: none; border: none; color: #ef4444; cursor: pointer; padding: 4px;" title="Excluir">🗑️</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearChildForm = () => {
|
||||||
|
cFormId.value = '';
|
||||||
|
cFormTurma.value = '';
|
||||||
|
cFormSala.value = '';
|
||||||
|
cFormPeriodo.value = 'Integral';
|
||||||
|
cFormAuxiliares.value = '';
|
||||||
|
cFormNome.value = '';
|
||||||
|
cFormApelido.value = '';
|
||||||
|
cFormDataNasc.value = '';
|
||||||
|
cFormEspecial.checked = false;
|
||||||
|
cFormEspecialDetalhes.value = '';
|
||||||
|
divEspecialDetalhes.style.display = 'none';
|
||||||
|
cFormPais.value = '';
|
||||||
|
cFormAutorizados.value = '';
|
||||||
|
childFormTitle.textContent = 'Cadastrar Criança';
|
||||||
|
};
|
||||||
|
|
||||||
|
window.editChild = (id) => {
|
||||||
|
const turma = loadTurma();
|
||||||
|
const c = turma.find(x => x.id === id);
|
||||||
|
if (!c) return;
|
||||||
|
|
||||||
|
cFormId.value = c.id;
|
||||||
|
cFormTurma.value = c.turma || '';
|
||||||
|
cFormSala.value = c.sala || '';
|
||||||
|
cFormPeriodo.value = c.periodo || 'Integral';
|
||||||
|
cFormAuxiliares.value = c.auxiliares || '';
|
||||||
|
cFormNome.value = c.nome || '';
|
||||||
|
cFormApelido.value = c.apelido || '';
|
||||||
|
cFormDataNasc.value = c.dataNasc || '';
|
||||||
|
cFormEspecial.checked = !!c.especial;
|
||||||
|
cFormEspecialDetalhes.value = c.especialDetalhes || '';
|
||||||
|
divEspecialDetalhes.style.display = c.especial ? 'flex' : 'none';
|
||||||
|
cFormPais.value = c.pais || '';
|
||||||
|
cFormAutorizados.value = c.autorizados || '';
|
||||||
|
|
||||||
|
childFormTitle.textContent = 'Editar Criança';
|
||||||
|
};
|
||||||
|
|
||||||
|
window.deleteChild = async (id) => {
|
||||||
|
const isOk = await showCustomConfirm('Excluir', 'Deseja excluir esta criança? Isso não removerá as observações já feitas, apenas removerá da lista da turma.', true);
|
||||||
|
if (isOk) {
|
||||||
|
let turma = loadTurma();
|
||||||
|
turma = turma.filter(x => x.id !== id);
|
||||||
|
saveTurma(turma);
|
||||||
|
renderTurmaList();
|
||||||
|
clearChildForm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (btnMinhaTurma) {
|
||||||
|
btnMinhaTurma.addEventListener('click', () => {
|
||||||
|
minhaTurmaModal.style.display = 'flex';
|
||||||
|
renderTurmaList();
|
||||||
|
clearChildForm();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnCloseMinhaTurmaModal) btnCloseMinhaTurmaModal.addEventListener('click', () => minhaTurmaModal.style.display = 'none');
|
||||||
|
if (minhaTurmaModal) {
|
||||||
|
minhaTurmaModal.addEventListener('click', (e) => {
|
||||||
|
if (e.target === minhaTurmaModal) minhaTurmaModal.style.display = 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnCreateChild) btnCreateChild.addEventListener('click', clearChildForm);
|
||||||
|
if (btnCancelChild) btnCancelChild.addEventListener('click', clearChildForm);
|
||||||
|
|
||||||
|
if (btnSaveChild) {
|
||||||
|
btnSaveChild.addEventListener('click', () => {
|
||||||
|
if (!cFormNome.value.trim()) {
|
||||||
|
showCustomAlert('Aviso', 'O Nome Completo é obrigatório.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let turma = loadTurma();
|
||||||
|
const id = cFormId.value || 'child_' + Date.now();
|
||||||
|
|
||||||
|
const newChild = {
|
||||||
|
id,
|
||||||
|
turma: cFormTurma.value.trim(),
|
||||||
|
sala: cFormSala.value.trim(),
|
||||||
|
periodo: cFormPeriodo.value,
|
||||||
|
auxiliares: cFormAuxiliares.value.trim(),
|
||||||
|
nome: cFormNome.value.trim(),
|
||||||
|
apelido: cFormApelido.value.trim(),
|
||||||
|
dataNasc: cFormDataNasc.value,
|
||||||
|
especial: cFormEspecial.checked,
|
||||||
|
especialDetalhes: cFormEspecialDetalhes.value.trim(),
|
||||||
|
pais: cFormPais.value.trim(),
|
||||||
|
autorizados: cFormAutorizados.value.trim()
|
||||||
|
};
|
||||||
|
|
||||||
|
const idx = turma.findIndex(x => x.id === id);
|
||||||
|
if (idx > -1) {
|
||||||
|
turma[idx] = newChild;
|
||||||
|
} else {
|
||||||
|
turma.push(newChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTurma(turma);
|
||||||
|
renderTurmaList();
|
||||||
|
clearChildForm();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preencher com Voz
|
||||||
|
const btnVoiceRecordChild = document.getElementById('btnVoiceRecordChild');
|
||||||
|
if (btnVoiceRecordChild && window.SpeechRecognition || window.webkitSpeechRecognition) {
|
||||||
|
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||||
|
const formRecognition = new SpeechRecognition();
|
||||||
|
formRecognition.lang = 'pt-BR';
|
||||||
|
formRecognition.continuous = false;
|
||||||
|
formRecognition.interimResults = false;
|
||||||
|
|
||||||
|
formRecognition.onstart = () => {
|
||||||
|
btnVoiceRecordChild.innerHTML = '🛑 Gravando... (Clique para parar)';
|
||||||
|
btnVoiceRecordChild.style.background = 'rgba(239, 68, 68, 0.1)';
|
||||||
|
btnVoiceRecordChild.style.color = '#ef4444';
|
||||||
|
btnVoiceRecordChild.style.borderColor = '#ef4444';
|
||||||
|
};
|
||||||
|
|
||||||
|
formRecognition.onresult = async (event) => {
|
||||||
|
const transcript = event.results[0][0].transcript;
|
||||||
|
btnVoiceRecordChild.innerHTML = '⏳ Processando com IA...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/chat', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
messages: [{
|
||||||
|
role: 'user',
|
||||||
|
content: `A professora ditou as seguintes informações para cadastrar uma criança na turma: "${transcript}".
|
||||||
|
Por favor, extraia os dados e retorne APENAS um JSON válido com os seguintes campos:
|
||||||
|
"turma", "sala", "periodo", "auxiliares", "nome", "apelido", "dataNasc" (formato YYYY-MM-DD), "especial" (boolean), "especialDetalhes", "pais", "autorizados".
|
||||||
|
Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
|
||||||
|
}],
|
||||||
|
temperature: 0.1
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const assistantReply = data.message;
|
||||||
|
// Extract JSON block
|
||||||
|
const match = assistantReply.match(/```json\n([\s\S]*?)\n```/) || assistantReply.match(/\{[\s\S]*\}/);
|
||||||
|
if (match) {
|
||||||
|
const parsed = JSON.parse(match[1] || match[0]);
|
||||||
|
if (parsed.turma) cFormTurma.value = parsed.turma;
|
||||||
|
if (parsed.sala) cFormSala.value = parsed.sala;
|
||||||
|
if (parsed.periodo) cFormPeriodo.value = parsed.periodo;
|
||||||
|
if (parsed.auxiliares) cFormAuxiliares.value = parsed.auxiliares;
|
||||||
|
if (parsed.nome) cFormNome.value = parsed.nome;
|
||||||
|
if (parsed.apelido) cFormApelido.value = parsed.apelido;
|
||||||
|
if (parsed.dataNasc) cFormDataNasc.value = parsed.dataNasc;
|
||||||
|
if (parsed.especial) cFormEspecial.checked = parsed.especial;
|
||||||
|
divEspecialDetalhes.style.display = cFormEspecial.checked ? 'flex' : 'none';
|
||||||
|
if (parsed.especialDetalhes) cFormEspecialDetalhes.value = parsed.especialDetalhes;
|
||||||
|
if (parsed.pais) cFormPais.value = parsed.pais;
|
||||||
|
if (parsed.autorizados) cFormAutorizados.value = parsed.autorizados;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Erro ao processar voz:', err);
|
||||||
|
showCustomAlert('Erro', 'Não foi possível extrair os dados. Tente novamente ou preencha manualmente.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
formRecognition.onend = () => {
|
||||||
|
btnVoiceRecordChild.innerHTML = '🎤 Preencher com Voz';
|
||||||
|
btnVoiceRecordChild.style.background = 'rgba(16, 163, 127, 0.1)';
|
||||||
|
btnVoiceRecordChild.style.color = 'var(--brand-green)';
|
||||||
|
btnVoiceRecordChild.style.borderColor = 'var(--brand-green)';
|
||||||
|
};
|
||||||
|
|
||||||
|
btnVoiceRecordChild.addEventListener('click', () => {
|
||||||
|
if (btnVoiceRecordChild.innerHTML.includes('Gravando')) {
|
||||||
|
formRecognition.stop();
|
||||||
|
} else {
|
||||||
|
formRecognition.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Mostra detalhe da observação em modal
|
// Mostra detalhe da observação em modal
|
||||||
const showObsDetail = (mdText) => {
|
const showObsDetail = (mdText) => {
|
||||||
const modal = document.createElement('div');
|
const modal = document.createElement('div');
|
||||||
|
|||||||
+125
-1
@@ -82,6 +82,26 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span>Minhas Observações</span>
|
<span>Minhas Observações</span>
|
||||||
</button>
|
</button>
|
||||||
|
<!-- Botão: Obs. Especiais -->
|
||||||
|
<button class="btn-observacoes" id="btnObsEspeciais" style="border-color: #f59e0b; color: #f59e0b; background: rgba(245, 158, 11, 0.05);">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" />
|
||||||
|
</svg>
|
||||||
|
<span>Obs. Educação Especial</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Divisor -->
|
||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
|
||||||
|
<!-- Seção: Minha Turma -->
|
||||||
|
<div class="sidebar-actions-turma" style="display: flex; flex-wrap: wrap; gap: 6px; padding: 0 16px 4px 16px;">
|
||||||
|
<button class="btn-observacoes" id="btnMinhaTurma" style="border-color: #3b82f6; color: #3b82f6; background: rgba(59, 130, 246, 0.05);">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
|
||||||
|
</svg>
|
||||||
|
<span>Minha Turma</span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Divisor -->
|
<!-- Divisor -->
|
||||||
@@ -461,7 +481,7 @@
|
|||||||
<div id="obsModal" class="settings-modal" style="display: none;">
|
<div id="obsModal" class="settings-modal" style="display: none;">
|
||||||
<div class="settings-modal-content obs-modal-content">
|
<div class="settings-modal-content obs-modal-content">
|
||||||
<div class="settings-modal-header">
|
<div class="settings-modal-header">
|
||||||
<h3>📒 Minhas Observações</h3>
|
<h3 id="obsModalTitle">📒 Minhas Observações</h3>
|
||||||
<button id="btnCloseObsModal" class="btn-close-modal">
|
<button id="btnCloseObsModal" class="btn-close-modal">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
||||||
@@ -494,6 +514,110 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal: Minha Turma -->
|
||||||
|
<div id="minhaTurmaModal" class="settings-modal" style="display: none;">
|
||||||
|
<div class="settings-modal-content" style="max-width: 800px; width: 95%; max-height: 90vh; display: flex; flex-direction: column;">
|
||||||
|
<div class="settings-modal-header">
|
||||||
|
<h3>🧑🤝🧑 Minha Turma</h3>
|
||||||
|
<button id="btnCloseMinhaTurmaModal" class="btn-close-modal">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="settings-modal-body" style="padding: 16px; overflow: hidden; display: flex; flex-direction: row; gap: 16px; flex: 1; min-height: 500px;">
|
||||||
|
<!-- Lado Esquerdo: Lista de Crianças -->
|
||||||
|
<div style="flex: 1; border-right: 1px solid var(--border-light); padding-right: 16px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
|
||||||
|
<h4 style="margin: 0; color: var(--text-primary);">Lista de Crianças</h4>
|
||||||
|
<button id="btnCreateChild" style="background: var(--brand-green); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s;">+ Nova Criança</button>
|
||||||
|
</div>
|
||||||
|
<div id="childrenList" style="display: flex; flex-direction: column; gap: 8px;">
|
||||||
|
<!-- Carregado via JS -->
|
||||||
|
<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Carregando turma...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Lado Direito: Formulário de Cadastro/Edição -->
|
||||||
|
<div id="childFormContainer" style="flex: 1.5; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; padding-left: 4px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
|
||||||
|
<h4 id="childFormTitle" style="margin: 0; color: var(--text-primary);">Cadastrar Criança</h4>
|
||||||
|
<button id="btnVoiceRecordChild" style="background: rgba(16, 163, 127, 0.1); border: 1px solid var(--brand-green); color: var(--brand-green); padding: 4px 8px; border-radius: 6px; font-size: 0.8rem; cursor: pointer; display: flex; align-items: center; gap: 4px;">
|
||||||
|
🎤 Preencher com Voz
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="childFormId">
|
||||||
|
|
||||||
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Turma</label>
|
||||||
|
<input type="text" id="childFormTurma" placeholder="Ex: Berçário 2" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Sala</label>
|
||||||
|
<input type="text" id="childFormSala" placeholder="Ex: Sala 4" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Período</label>
|
||||||
|
<select id="childFormPeriodo" class="obs-select" style="width: 100%;">
|
||||||
|
<option value="Integral">Integral</option>
|
||||||
|
<option value="Matutino">Matutino</option>
|
||||||
|
<option value="Vespertino">Vespertino</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Prof. Auxiliares / Funções</label>
|
||||||
|
<input type="text" id="childFormAuxiliares" placeholder="Ex: Maria (Apoio)" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Nome Completo da Criança</label>
|
||||||
|
<input type="text" id="childFormNome" placeholder="Ex: João da Silva" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Apelido (Opcional)</label>
|
||||||
|
<input type="text" id="childFormApelido" placeholder="Ex: Joãozinho" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Data de Nascimento</label>
|
||||||
|
<input type="date" id="childFormDataNasc" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Educação Especial?</label>
|
||||||
|
<div style="display: flex; gap: 10px; align-items: center; margin-top: 4px;">
|
||||||
|
<label style="display: flex; align-items: center; gap: 4px; color: var(--text-primary); cursor: pointer;"><input type="checkbox" id="childFormEspecial" style="cursor: pointer;"> Sim (Marcar se for Educação Especial)</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-group" style="gap: 4px;" id="divEspecialDetalhes" style="display:none;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Diagnóstico / Observações da Educação Especial</label>
|
||||||
|
<input type="text" id="childFormEspecialDetalhes" placeholder="Ex: TEA, TDAH..." class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Nome dos Pais (Opcional)</label>
|
||||||
|
<input type="text" id="childFormPais" placeholder="Ex: Pedro e Ana" class="obs-input" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-group" style="gap: 4px;">
|
||||||
|
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Autorizados a buscar (Máx 3: Nome e Parentesco)</label>
|
||||||
|
<textarea id="childFormAutorizados" placeholder="1. Carlos (Avô) 2. Maria (Tia) 3. ..." class="obs-input" style="width: 100%; min-height: 70px; resize: vertical;"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display: flex; gap: 8px; justify-content: flex-end; border-top: 1px solid var(--border-light); padding-top: 12px; margin-top: auto;">
|
||||||
|
<button id="btnCancelChild" style="background: none; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 8px 16px; border-radius: 8px; cursor: pointer; font-size: 0.9rem;">Cancelar</button>
|
||||||
|
<button id="btnSaveChild" style="background: var(--brand-green); border: none; color: white; padding: 8px 16px; border-radius: 8px; font-weight: 600; cursor: pointer; font-size: 0.9rem;">Salvar Criança</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Modal: Modelos de Relatório (CRUD Templates) -->
|
<!-- Modal: Modelos de Relatório (CRUD Templates) -->
|
||||||
<div id="modelosRelatorioModal" class="settings-modal" style="display: none;">
|
<div id="modelosRelatorioModal" class="settings-modal" style="display: none;">
|
||||||
<div class="settings-modal-content" style="max-width: 800px; width: 95%; max-height: 90vh; display: flex; flex-direction: column;">
|
<div class="settings-modal-content" style="max-width: 800px; width: 95%; max-height: 90vh; display: flex; flex-direction: column;">
|
||||||
|
|||||||
Reference in New Issue
Block a user