mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 23:06:23 +00:00
05-회의진행 실시간 주요 메모 추천 기능 명확화 - UFR-MEET-030: AI가 중요한 내용으로 판단한 경우에만 추천 - 추천 빈도는 가변적 (3-5초 고정 간격 아님) - 프로토타입 확인: 05-회의진행.html AI 제안 탭 기능 포함 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
546 lines
16 KiB
HTML
546 lines
16 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>회의 종료 - 회의록 서비스</title>
|
|
<link rel="stylesheet" href="common.css">
|
|
<style>
|
|
/* 페이지 특화 스타일 */
|
|
.page-header {
|
|
text-align: center;
|
|
padding: var(--space-lg) 0;
|
|
background: var(--primary-light);
|
|
margin: calc(var(--space-md) * -1) calc(var(--space-md) * -1) var(--space-lg);
|
|
}
|
|
|
|
.page-header h1 {
|
|
font-size: var(--font-h2);
|
|
color: var(--primary);
|
|
margin-bottom: var(--space-sm);
|
|
}
|
|
|
|
.page-header .meeting-title {
|
|
font-size: var(--font-body);
|
|
color: var(--gray-700);
|
|
}
|
|
|
|
/* 통계 카드 그리드 - 정보 표시용 (인터랙션 없음) */
|
|
.stats-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: var(--space-sm);
|
|
margin-bottom: var(--space-lg);
|
|
}
|
|
|
|
.stat-card {
|
|
min-height: 80px;
|
|
padding: var(--space-md);
|
|
background: var(--gray-50);
|
|
border: 1px solid var(--gray-200);
|
|
border-radius: var(--radius-md);
|
|
text-align: center;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: var(--font-h1);
|
|
font-weight: var(--font-weight-bold);
|
|
color: var(--gray-900);
|
|
margin-bottom: var(--space-xs);
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: var(--font-small);
|
|
color: var(--gray-600);
|
|
font-weight: var(--font-weight-medium);
|
|
}
|
|
|
|
/* 키워드 클라우드 */
|
|
.keyword-cloud {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: var(--space-sm);
|
|
padding: var(--space-md);
|
|
}
|
|
|
|
.keyword-tag {
|
|
display: inline-block;
|
|
padding: 6px 12px;
|
|
background: var(--primary-light);
|
|
color: var(--primary-dark);
|
|
border-radius: 16px;
|
|
font-size: var(--font-small);
|
|
font-weight: var(--font-weight-medium);
|
|
}
|
|
|
|
/* 안건 카드 */
|
|
.agenda-card {
|
|
background: var(--white);
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow-sm);
|
|
margin-bottom: var(--space-md);
|
|
overflow: hidden;
|
|
border: 1px solid var(--gray-200);
|
|
}
|
|
|
|
.agenda-header {
|
|
padding: var(--space-md);
|
|
cursor: pointer;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
background: var(--gray-50);
|
|
}
|
|
|
|
.agenda-header:hover {
|
|
background: var(--gray-100);
|
|
}
|
|
|
|
.agenda-title {
|
|
font-size: var(--font-h4);
|
|
font-weight: var(--font-weight-bold);
|
|
color: var(--gray-900);
|
|
margin-bottom: var(--space-xs);
|
|
}
|
|
|
|
.ai-summary-short {
|
|
background: var(--gray-100);
|
|
border-left: 4px solid var(--primary);
|
|
padding: var(--space-sm) var(--space-md);
|
|
margin-top: var(--space-sm);
|
|
border-radius: var(--radius-sm);
|
|
font-size: var(--font-small);
|
|
color: var(--gray-700);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.ai-summary-short .lock-icon {
|
|
color: var(--gray-500);
|
|
font-size: 16px;
|
|
}
|
|
|
|
.expand-icon {
|
|
font-size: 20px;
|
|
color: var(--gray-500);
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.agenda-card.expanded .expand-icon {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.agenda-content {
|
|
display: none;
|
|
padding: var(--space-md);
|
|
border-top: 1px solid var(--gray-200);
|
|
}
|
|
|
|
.agenda-card.expanded .agenda-content {
|
|
display: block;
|
|
}
|
|
|
|
.agenda-section {
|
|
margin-bottom: var(--space-lg);
|
|
padding-bottom: var(--space-md);
|
|
border-bottom: 1px solid var(--gray-200);
|
|
}
|
|
|
|
.agenda-section:last-child {
|
|
border-bottom: none;
|
|
padding-bottom: 0;
|
|
}
|
|
|
|
.agenda-section-title {
|
|
font-size: var(--font-small);
|
|
font-weight: var(--font-weight-bold);
|
|
color: var(--gray-900);
|
|
margin-bottom: var(--space-sm);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-xs);
|
|
}
|
|
|
|
.agenda-section-title::before {
|
|
content: '';
|
|
display: inline-block;
|
|
width: 4px;
|
|
height: 16px;
|
|
background: var(--primary);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.agenda-section-content {
|
|
font-size: var(--font-body);
|
|
color: var(--gray-700);
|
|
line-height: 1.6;
|
|
padding-left: var(--space-md);
|
|
}
|
|
|
|
.agenda-section-content ul {
|
|
margin: 0;
|
|
padding-left: var(--space-lg);
|
|
}
|
|
|
|
.agenda-section-content li {
|
|
margin-bottom: var(--space-xs);
|
|
}
|
|
|
|
/* 하단 액션 바 - 3개 버튼 배치 */
|
|
.action-bar {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background: var(--white);
|
|
padding: var(--space-md);
|
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
|
|
display: flex;
|
|
gap: var(--space-sm);
|
|
z-index: 100;
|
|
}
|
|
|
|
.action-bar .btn {
|
|
flex: 1;
|
|
}
|
|
|
|
.action-bar .btn-primary {
|
|
flex: 2; /* 바로 최종 확정 버튼 강조 */
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.stats-grid {
|
|
grid-template-columns: repeat(4, 1fr);
|
|
}
|
|
|
|
.action-bar {
|
|
position: static;
|
|
box-shadow: none;
|
|
justify-content: center;
|
|
gap: var(--space-md);
|
|
}
|
|
|
|
.action-bar .btn {
|
|
flex: 0 1 200px;
|
|
}
|
|
|
|
.action-bar .btn-primary {
|
|
flex: 0 1 250px;
|
|
}
|
|
}
|
|
|
|
.readonly-notice {
|
|
background: var(--warning-light);
|
|
border: 1px solid var(--warning);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--space-md);
|
|
margin-bottom: var(--space-lg);
|
|
font-size: var(--font-small);
|
|
color: var(--warning-dark);
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="page">
|
|
<div class="container has-action-bar">
|
|
<!-- 페이지 헤더 -->
|
|
<div class="page-header">
|
|
<h1>✅ 회의가 종료되었습니다</h1>
|
|
<p class="meeting-title">2025년 1분기 제품 기획 회의</p>
|
|
</div>
|
|
|
|
<!-- 읽기 전용 안내 -->
|
|
<div class="readonly-notice">
|
|
🔒 이 화면은 <strong>확인 전용</strong>입니다. 내용을 수정하려면 "회의록 수정" 버튼을 클릭하세요.
|
|
</div>
|
|
|
|
<!-- 통계 카드 그리드 -->
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<div class="stat-value" id="durationValue">0</div>
|
|
<div class="stat-label">회의 시간 (분)</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value" id="participantsValue">0</div>
|
|
<div class="stat-label">참석자</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value" id="agendasValue">0</div>
|
|
<div class="stat-label">안건</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-value" id="todosValue">0</div>
|
|
<div class="stat-label">Todo</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 주요 키워드 -->
|
|
<div class="card mb-md">
|
|
<h3 class="card-title">주요 키워드</h3>
|
|
<div class="keyword-cloud">
|
|
<span class="keyword-tag">신제품 기획</span>
|
|
<span class="keyword-tag">예산 편성</span>
|
|
<span class="keyword-tag">일정 조율</span>
|
|
<span class="keyword-tag">시장 조사</span>
|
|
<span class="keyword-tag">UI/UX</span>
|
|
<span class="keyword-tag">개발 스펙</span>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- 안건별 AI 요약 -->
|
|
<div class="card mb-md">
|
|
<h3 class="card-title">안건별 AI 요약</h3>
|
|
<div id="agendaList"></div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- 하단 액션 바 (3가지 선택 옵션) -->
|
|
<div class="action-bar">
|
|
<button class="btn btn-ghost" onclick="navigateTo('02-대시보드.html')">
|
|
대시보드
|
|
</button>
|
|
<button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">
|
|
회의록 수정
|
|
</button>
|
|
<button class="btn btn-primary" onclick="confirmMeetingDirectly()">
|
|
바로 최종 확정
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="common.js"></script>
|
|
<script>
|
|
// 샘플 안건 데이터
|
|
const SAMPLE_AGENDAS = [
|
|
{
|
|
id: 'agenda-1',
|
|
title: '1. 신제품 기획 방향성',
|
|
aiSummaryShort: '타겟 고객을 20-30대로 설정, UI/UX 개선 집중',
|
|
details: {
|
|
discussion: '신제품의 주요 타겟 고객층을 20-30대 직장인으로 설정하고, 기존 제품 대비 UI/UX를 대폭 개선하기로 함',
|
|
opinions: [
|
|
{ speaker: '김민준', opinion: '타겟 고객층을 명확히 설정하여 마케팅 전략 수립 필요' },
|
|
{ speaker: '박서연', opinion: 'UI/UX 개선에 AI 기술 적용 검토' }
|
|
],
|
|
decisions: ['타겟 고객: 20-30대 직장인', 'UI/UX 개선을 최우선 과제로 설정'],
|
|
pending: []
|
|
},
|
|
todos: [
|
|
{
|
|
title: '시장 조사 보고서 작성',
|
|
assignee: SAMPLE_MEETINGS[0].participants[0],
|
|
dueDate: '2025-11-01',
|
|
priority: 'high'
|
|
},
|
|
{
|
|
title: 'UI/UX 개선안 초안 작성',
|
|
assignee: SAMPLE_MEETINGS[0].participants[1],
|
|
dueDate: '2025-11-05',
|
|
priority: 'medium'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
id: 'agenda-2',
|
|
title: '2. 예산 편성 및 일정',
|
|
aiSummaryShort: '총 예산 5억, 개발 기간 6개월 확정',
|
|
details: {
|
|
discussion: '신제품 개발을 위한 총 예산을 5억원으로 책정하고, 개발 기간은 6개월로 확정함',
|
|
opinions: [
|
|
{ speaker: '이준호', opinion: '개발 기간 6개월은 타이트하므로 우선순위 명확화 필요' },
|
|
{ speaker: '최유진', opinion: '예산 배분은 개발 60%, 마케팅 40%로 제안' }
|
|
],
|
|
decisions: ['총 예산: 5억원', '개발 기간: 6개월', '예산 배분: 개발 60%, 마케팅 40%'],
|
|
pending: ['세부 일정 확정은 다음 회의에서 논의']
|
|
},
|
|
todos: [
|
|
{
|
|
title: '세부 개발 일정 수립',
|
|
assignee: SAMPLE_MEETINGS[0].participants[2],
|
|
dueDate: '2025-10-28',
|
|
priority: 'high'
|
|
}
|
|
]
|
|
},
|
|
{
|
|
id: 'agenda-3',
|
|
title: '3. 기술 스택 및 개발 방향',
|
|
aiSummaryShort: 'React 기반 프론트엔드, AI 챗봇 기능 추가',
|
|
details: {
|
|
discussion: '프론트엔드는 React 기반으로 개발하고, 고객 지원을 위한 AI 챗봇 기능을 추가하기로 함',
|
|
opinions: [
|
|
{ speaker: '박서연', opinion: 'AI 챗봇은 GPT-4 기반으로 개발 제안' },
|
|
{ speaker: '이준호', opinion: 'React 외에 Next.js 도입 검토 필요' }
|
|
],
|
|
decisions: ['프론트엔드: React 기반', 'AI 챗봇 기능 추가', 'Next.js 도입 검토'],
|
|
pending: ['AI 챗봇 학습 데이터 확보 방안']
|
|
},
|
|
todos: [
|
|
{
|
|
title: 'AI 챗봇 프로토타입 개발',
|
|
assignee: SAMPLE_MEETINGS[0].participants[1],
|
|
dueDate: '2025-11-10',
|
|
priority: 'medium'
|
|
},
|
|
{
|
|
title: 'Next.js 도입 검토 보고서',
|
|
assignee: SAMPLE_MEETINGS[0].participants[3],
|
|
dueDate: '2025-11-03',
|
|
priority: 'low'
|
|
}
|
|
]
|
|
}
|
|
];
|
|
|
|
// 페이지 초기화
|
|
function initPage() {
|
|
// 통계 카운트 애니메이션
|
|
animateCounter('durationValue', 90);
|
|
animateCounter('participantsValue', 4);
|
|
animateCounter('agendasValue', SAMPLE_AGENDAS.length);
|
|
|
|
// Todo 전체 개수 계산
|
|
const totalTodos = SAMPLE_AGENDAS.reduce((sum, agenda) => sum + (agenda.todos?.length || 0), 0);
|
|
animateCounter('todosValue', totalTodos);
|
|
|
|
// 안건 리스트 렌더링
|
|
renderAgendaList();
|
|
}
|
|
|
|
// 카운터 애니메이션
|
|
function animateCounter(elementId, target) {
|
|
const element = $(`#${elementId}`);
|
|
let current = 0;
|
|
const increment = target / 30;
|
|
const timer = setInterval(() => {
|
|
current += increment;
|
|
if (current >= target) {
|
|
element.textContent = target;
|
|
clearInterval(timer);
|
|
} else {
|
|
element.textContent = Math.floor(current);
|
|
}
|
|
}, 30);
|
|
}
|
|
|
|
// 안건 리스트 렌더링
|
|
function renderAgendaList() {
|
|
const container = $('#agendaList');
|
|
|
|
SAMPLE_AGENDAS.forEach(agenda => {
|
|
// 안건 카드
|
|
const card = createElement('div', {
|
|
className: 'agenda-card',
|
|
id: `agenda-${agenda.id}`,
|
|
onclick: `toggleAgenda('${agenda.id}')`
|
|
});
|
|
|
|
// 헤더
|
|
const header = createElement('div', { className: 'agenda-header' }, `
|
|
<div>
|
|
<div class="agenda-title">${agenda.title}</div>
|
|
<div class="ai-summary-short">
|
|
<span class="lock-icon">🔒</span>
|
|
<span>${agenda.aiSummaryShort}</span>
|
|
</div>
|
|
</div>
|
|
<div class="expand-icon">▼</div>
|
|
`);
|
|
card.appendChild(header);
|
|
|
|
// 상세 내용
|
|
const content = createElement('div', { className: 'agenda-content' });
|
|
|
|
// 논의 주제
|
|
if (agenda.details.discussion) {
|
|
content.appendChild(createElement('div', { className: 'agenda-section' }, `
|
|
<div class="agenda-section-title">논의 주제</div>
|
|
<div class="agenda-section-content">${agenda.details.discussion}</div>
|
|
`));
|
|
}
|
|
|
|
// 결정 사항
|
|
if (agenda.details.decisions && agenda.details.decisions.length > 0) {
|
|
const decisionsHtml = agenda.details.decisions.map(d => `<li>✓ ${d}</li>`).join('');
|
|
content.appendChild(createElement('div', { className: 'agenda-section' }, `
|
|
<div class="agenda-section-title">결정 사항</div>
|
|
<div class="agenda-section-content"><ul>${decisionsHtml}</ul></div>
|
|
`));
|
|
}
|
|
|
|
// 보류 사항
|
|
if (agenda.details.pending && agenda.details.pending.length > 0) {
|
|
const pendingHtml = agenda.details.pending.map(p => `<li>⏸ ${p}</li>`).join('');
|
|
content.appendChild(createElement('div', { className: 'agenda-section' }, `
|
|
<div class="agenda-section-title">보류 사항</div>
|
|
<div class="agenda-section-content"><ul>${pendingHtml}</ul></div>
|
|
`));
|
|
}
|
|
|
|
// Todo 목록 - 제목만 간단히 표시
|
|
if (agenda.todos && agenda.todos.length > 0) {
|
|
const todosSection = createElement('div', { className: 'agenda-section' }, `
|
|
<div class="agenda-section-title">Todo 자동 추출 결과</div>
|
|
`);
|
|
|
|
const todoList = createElement('ul', {
|
|
style: 'list-style: none; padding: 0; margin: 0;'
|
|
});
|
|
|
|
agenda.todos.forEach(todo => {
|
|
const todoItem = createElement('li', {
|
|
style: 'display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-sm) 0; font-size: var(--font-body); color: var(--gray-700);'
|
|
}, `
|
|
<span style="color: var(--gray-500);">•</span>
|
|
<span>${todo.title}</span>
|
|
`);
|
|
todoList.appendChild(todoItem);
|
|
});
|
|
|
|
todosSection.appendChild(todoList);
|
|
|
|
// 안내 문구 추가
|
|
const notice = createElement('p', {
|
|
style: 'font-size: var(--font-small); color: var(--gray-500); margin-top: var(--space-md); padding-top: var(--space-sm); border-top: 1px solid var(--gray-200);'
|
|
}, '💡 담당자 및 마감일은 회의록 수정 화면에서 지정할 수 있습니다.');
|
|
todosSection.appendChild(notice);
|
|
|
|
content.appendChild(todosSection);
|
|
}
|
|
|
|
card.appendChild(content);
|
|
container.appendChild(card);
|
|
});
|
|
}
|
|
|
|
// 안건 카드 확장/축소
|
|
function toggleAgenda(agendaId) {
|
|
const card = $(`#agenda-${agendaId}`);
|
|
card.classList.toggle('expanded');
|
|
}
|
|
|
|
// 바로 최종 확정
|
|
function confirmMeetingDirectly() {
|
|
if (confirm('AI가 정리한 내용 그대로 최종 확정하시겠습니까?\n\n모든 안건이 자동으로 검증 완료 처리되며, 참석자에게 확정 알림이 발송됩니다.')) {
|
|
showToast('회의록이 최종 확정되었습니다', 'success');
|
|
setTimeout(() => {
|
|
navigateTo('02-대시보드.html');
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
// 페이지 로드 시 초기화
|
|
initPage();
|
|
</script>
|
|
</body>
|
|
</html>
|