mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 10:16:24 +00:00
Merge branch 'main' of https://github.com/hwanny1128/HGZero into feat/meeting-reservation
This commit is contained in:
commit
48b760d850
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,8 +1,12 @@
|
|||||||
# Build outputs
|
# Build outputs
|
||||||
build/
|
build/*
|
||||||
|
build/*/*
|
||||||
|
build/*/*/*
|
||||||
**/build/
|
**/build/
|
||||||
.gradle/
|
.gradle/
|
||||||
**/.gradle/
|
**/.gradle/
|
||||||
|
.vscode/
|
||||||
|
**/.vscode/
|
||||||
|
|
||||||
# Serena
|
# Serena
|
||||||
serena/
|
serena/
|
||||||
@ -37,3 +41,8 @@ examples/
|
|||||||
|
|
||||||
# Claude settings
|
# Claude settings
|
||||||
.claude/settings.local.json
|
.claude/settings.local.json
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
design/*/*backup.md
|
||||||
|
design/*backup.md
|
||||||
|
backup/
|
||||||
|
|||||||
545
backup/v1.4.16/07-회의종료.html
Normal file
545
backup/v1.4.16/07-회의종료.html
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
<!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>
|
||||||
@ -1,527 +0,0 @@
|
|||||||
<!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>
|
|
||||||
/* 페이지별 커스텀 스타일만 유지 */
|
|
||||||
/* 공통 스타일(헤더, 메인콘텐츠, 액션바)은 common.css 사용 */
|
|
||||||
|
|
||||||
.progress-container {
|
|
||||||
margin-bottom: var(--space-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: var(--space-sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-percentage {
|
|
||||||
font-size: var(--font-h2);
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
color: var(--primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verification-card {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--space-md);
|
|
||||||
padding: var(--space-md);
|
|
||||||
background: var(--white);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
box-shadow: var(--shadow-md);
|
|
||||||
margin-bottom: var(--space-md);
|
|
||||||
transition: all var(--transition-normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verification-card:hover {
|
|
||||||
box-shadow: var(--shadow-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verification-card.verified {
|
|
||||||
border-left: 4px solid var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verification-card.unverified {
|
|
||||||
border-left: 4px solid var(--gray-300);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verification-card.locked {
|
|
||||||
background: var(--gray-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verify-icon {
|
|
||||||
font-size: 32px;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.verify-icon.verified {
|
|
||||||
color: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.verify-icon.unverified {
|
|
||||||
color: var(--gray-300);
|
|
||||||
}
|
|
||||||
|
|
||||||
.lock-icon {
|
|
||||||
font-size: 20px;
|
|
||||||
color: var(--gray-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 편집 모드 스타일 */
|
|
||||||
.edit-field {
|
|
||||||
width: 100%;
|
|
||||||
padding: var(--space-sm);
|
|
||||||
border: 1px solid var(--gray-300);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
font-size: var(--font-small);
|
|
||||||
line-height: 1.6;
|
|
||||||
margin-bottom: var(--space-sm);
|
|
||||||
transition: border-color var(--transition-normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-field:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: var(--primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-label {
|
|
||||||
display: block;
|
|
||||||
font-weight: var(--font-weight-medium);
|
|
||||||
margin-bottom: var(--space-xs);
|
|
||||||
color: var(--text-primary);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="page">
|
|
||||||
<!-- Header -->
|
|
||||||
<header class="header">
|
|
||||||
<div class="header-left">
|
|
||||||
<button class="back-btn" onclick="history.back()">←</button>
|
|
||||||
<h1 class="header-title">검증 완료</h1>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- Main Content -->
|
|
||||||
<main class="main-content has-action-bar">
|
|
||||||
<!-- Progress Bar -->
|
|
||||||
<div class="progress-container">
|
|
||||||
<div class="progress-header">
|
|
||||||
<h2 class="text-small font-bold">전체 진행률</h2>
|
|
||||||
<span class="progress-percentage" id="progressText">50%</span>
|
|
||||||
</div>
|
|
||||||
<div class="progress" style="height: 12px;">
|
|
||||||
<div class="progress-bar progress-bar-success" id="progressBar" style="width: 50%;"></div>
|
|
||||||
</div>
|
|
||||||
<p class="text-small text-muted mt-sm">4개 섹션 중 2개 검증 완료</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Meeting Info -->
|
|
||||||
<div class="card mb-lg">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3 class="card-title">2025년 1분기 제품 기획 회의</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="text-small text-muted">
|
|
||||||
<div style="display: flex; gap: var(--space-md); margin-bottom: var(--space-xs);">
|
|
||||||
<span>📅 2025-10-25 14:00</span>
|
|
||||||
<span>⏱️ 90분</span>
|
|
||||||
</div>
|
|
||||||
<div>👥 김민준, 박서연, 이준호, 최유진</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Section List -->
|
|
||||||
<div>
|
|
||||||
<h2 class="text-small font-bold mb-md">섹션별 검증 상태</h2>
|
|
||||||
|
|
||||||
<!-- 섹션 1 - 검증 완료 -->
|
|
||||||
<div class="verification-card verified">
|
|
||||||
<div class="verify-icon verified">✓</div>
|
|
||||||
<div style="flex: 1;">
|
|
||||||
<h3 class="text-small font-bold" style="margin: 0 0 4px 0;">회의 개요</h3>
|
|
||||||
<div style="display: flex; align-items: center; gap: var(--space-sm);">
|
|
||||||
<div class="avatar-group">
|
|
||||||
<div class="avatar avatar-green avatar-sm">김</div>
|
|
||||||
<div class="avatar avatar-blue avatar-sm">박</div>
|
|
||||||
</div>
|
|
||||||
<span class="text-caption text-muted">2명 검증 완료</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-secondary btn-sm" onclick="viewSection(0)">보기</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 섹션 2 - 검증 완료 + 잠금 -->
|
|
||||||
<div class="verification-card verified locked">
|
|
||||||
<div class="verify-icon verified">✓</div>
|
|
||||||
<div style="flex: 1;">
|
|
||||||
<h3 class="text-small font-bold" style="margin: 0 0 4px 0;">
|
|
||||||
논의 사항
|
|
||||||
<span class="lock-icon">🔒</span>
|
|
||||||
</h3>
|
|
||||||
<div style="display: flex; align-items: center; gap: var(--space-sm);">
|
|
||||||
<div class="avatar-group">
|
|
||||||
<div class="avatar avatar-green avatar-sm">김</div>
|
|
||||||
<div class="avatar avatar-blue avatar-sm">박</div>
|
|
||||||
<div class="avatar avatar-yellow avatar-sm">이</div>
|
|
||||||
</div>
|
|
||||||
<span class="text-caption text-muted">3명 검증 완료 · 잠금됨</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-secondary btn-sm" onclick="unlockSection(1)">잠금해제</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 섹션 3 - 미검증 -->
|
|
||||||
<div class="verification-card unverified">
|
|
||||||
<div class="verify-icon unverified">○</div>
|
|
||||||
<div style="flex: 1;">
|
|
||||||
<h3 class="text-small font-bold" style="margin: 0 0 4px 0;">결정 사항</h3>
|
|
||||||
<div style="display: flex; align-items: center; gap: var(--space-sm);">
|
|
||||||
<div class="avatar-group">
|
|
||||||
<div class="avatar avatar-blue avatar-sm">박</div>
|
|
||||||
</div>
|
|
||||||
<span class="text-caption text-muted">1명 검증 완료</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary btn-sm" onclick="verifySection(2)">검증하기</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 섹션 4 - 미검증 -->
|
|
||||||
<div class="verification-card unverified">
|
|
||||||
<div class="verify-icon unverified">○</div>
|
|
||||||
<div style="flex: 1;">
|
|
||||||
<h3 class="text-small font-bold" style="margin: 0 0 4px 0;">액션 아이템</h3>
|
|
||||||
<div style="display: flex; align-items: center; gap: var(--space-sm);">
|
|
||||||
<span class="text-caption text-muted">아직 검증되지 않음</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary btn-sm" onclick="verifySection(3)">검증하기</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- 하단 액션 바 -->
|
|
||||||
<div class="action-bar">
|
|
||||||
<button class="btn btn-secondary" onclick="saveLater()">나중에 하기</button>
|
|
||||||
<button class="btn btn-primary" id="completeBtn" disabled onclick="completeAllVerification()">
|
|
||||||
모두 검증 완료
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Section View Modal -->
|
|
||||||
<div id="sectionModal" class="modal-overlay">
|
|
||||||
<div class="modal" style="max-height: 80vh; overflow-y: auto;">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h2 class="modal-title" id="sectionTitle">회의 개요</h2>
|
|
||||||
<button class="modal-close" onclick="closeModal('sectionModal')">✕</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div id="sectionContent">
|
|
||||||
<!-- 섹션 내용이 여기에 표시됨 -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-secondary btn-sm" onclick="closeModal('sectionModal')">닫기</button>
|
|
||||||
<button class="btn btn-primary btn-sm" id="editBtn" onclick="toggleEditMode()">편집</button>
|
|
||||||
<button class="btn btn-primary btn-sm" id="saveBtn" style="display: none;" onclick="saveSection()">저장</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Verification Confirm Modal -->
|
|
||||||
<div id="verifyModal" class="modal-overlay">
|
|
||||||
<div class="modal">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h2 class="modal-title">섹션 검증</h2>
|
|
||||||
<button class="modal-close" onclick="closeModal('verifyModal')">✕</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p class="text-small mb-md" id="verifyMessage">이 섹션의 내용을 검증하시겠습니까?</p>
|
|
||||||
<div class="card" style="background: var(--primary-light);">
|
|
||||||
<p class="text-small font-medium">검증 후에는 다른 참석자들도 이 섹션이 확인되었음을 알 수 있습니다.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-secondary btn-sm" onclick="closeModal('verifyModal')">취소</button>
|
|
||||||
<button class="btn btn-primary btn-sm" onclick="confirmVerification()">검증 완료</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Unlock Confirm Modal -->
|
|
||||||
<div id="unlockModal" class="modal-overlay">
|
|
||||||
<div class="modal">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h2 class="modal-title">섹션 잠금 해제</h2>
|
|
||||||
<button class="modal-close" onclick="closeModal('unlockModal')">✕</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p class="text-small mb-md">이 섹션의 잠금을 해제하시겠습니까?</p>
|
|
||||||
<div class="card" style="background: transparent; color: var(--error); border: 1px solid var(--error);">
|
|
||||||
<p class="text-small font-medium">⚠️ 잠금 해제 시 다른 참석자들이 내용을 수정할 수 있습니다.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-sm" style="background: transparent; color: var(--error); border: 1px solid var(--error);" onclick="closeModal('unlockModal')">취소</button>
|
|
||||||
<button class="btn btn-error btn-sm" onclick="confirmUnlock()">잠금 해제</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="common.js"></script>
|
|
||||||
<script>
|
|
||||||
// 섹션 검증 상태
|
|
||||||
const sectionVerifications = [
|
|
||||||
{ name: '회의 개요', verified: true, locked: false, verifiers: ['김민준', '박서연'] },
|
|
||||||
{ name: '논의 사항', verified: true, locked: true, verifiers: ['김민준', '박서연', '이준호'] },
|
|
||||||
{ name: '결정 사항', verified: false, locked: false, verifiers: ['박서연'] },
|
|
||||||
{ name: '액션 아이템', verified: false, locked: false, verifiers: [] }
|
|
||||||
];
|
|
||||||
|
|
||||||
let currentSectionIndex = -1;
|
|
||||||
let isEditMode = false;
|
|
||||||
let originalContent = '';
|
|
||||||
|
|
||||||
// 섹션 데이터 (편집 가능한 필드)
|
|
||||||
const sectionData = [
|
|
||||||
{
|
|
||||||
purpose: '2025년 1분기 신제품 개발 방향 수립',
|
|
||||||
attendees: '김민준(PM), 박서연(AI), 이준호(Backend), 최유진(Frontend)',
|
|
||||||
datetime: '2025년 10월 25일 14:00 - 15:30',
|
|
||||||
location: '본사 2층 대회의실'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
topic1: 'AI 모델 정확도',
|
|
||||||
detail1: '현재 STT 정확도: 92%, 목표 정확도: 95% 이상',
|
|
||||||
topic2: '사용자 인터페이스',
|
|
||||||
detail2: 'Mobile First 디자인 채택, 실시간 협업 기능 필수'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 진행률 업데이트
|
|
||||||
function updateProgress() {
|
|
||||||
const totalSections = sectionVerifications.length;
|
|
||||||
const verifiedCount = sectionVerifications.filter(s => s.verified).length;
|
|
||||||
const percentage = Math.round((verifiedCount / totalSections) * 100);
|
|
||||||
|
|
||||||
$('#progressBar').style.width = percentage + '%';
|
|
||||||
$('#progressText').textContent = percentage + '%';
|
|
||||||
|
|
||||||
const completeBtn = $('#completeBtn');
|
|
||||||
if (percentage === 100) {
|
|
||||||
completeBtn.disabled = false;
|
|
||||||
completeBtn.style.opacity = '1';
|
|
||||||
} else {
|
|
||||||
completeBtn.disabled = true;
|
|
||||||
completeBtn.style.opacity = '0.5';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 섹션 보기
|
|
||||||
function viewSection(index) {
|
|
||||||
currentSectionIndex = index;
|
|
||||||
isEditMode = false;
|
|
||||||
const section = sectionVerifications[index];
|
|
||||||
|
|
||||||
$('#sectionTitle').textContent = section.name;
|
|
||||||
|
|
||||||
// 편집 모드 초기화
|
|
||||||
$('#editBtn').style.display = 'inline-block';
|
|
||||||
$('#saveBtn').style.display = 'none';
|
|
||||||
|
|
||||||
// 회의 개요만 편집 가능
|
|
||||||
if (index === 0) {
|
|
||||||
renderSectionContent(index, false);
|
|
||||||
} else {
|
|
||||||
// 다른 섹션은 읽기 전용
|
|
||||||
const sampleContent = `
|
|
||||||
<p><strong>1. AI 모델 정확도</strong></p>
|
|
||||||
<p>- 현재 STT 정확도: 92%</p>
|
|
||||||
<p>- 목표 정확도: 95% 이상</p>
|
|
||||||
<br>
|
|
||||||
<p><strong>2. 사용자 인터페이스</strong></p>
|
|
||||||
<p>- Mobile First 디자인 채택</p>
|
|
||||||
<p>- 실시간 협업 기능 필수</p>
|
|
||||||
`;
|
|
||||||
$('#sectionContent').innerHTML = sampleContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
openModal('sectionModal');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 섹션 내용 렌더링
|
|
||||||
function renderSectionContent(index, editMode) {
|
|
||||||
const data = sectionData[index];
|
|
||||||
const contentDiv = $('#sectionContent');
|
|
||||||
|
|
||||||
if (editMode && index === 0) {
|
|
||||||
// 회의 개요 편집 모드
|
|
||||||
contentDiv.innerHTML = `
|
|
||||||
<div>
|
|
||||||
<label class="edit-label">회의 목적</label>
|
|
||||||
<input type="text" class="edit-field" id="edit_purpose" value="${data.purpose}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="edit-label">참석자</label>
|
|
||||||
<input type="text" class="edit-field" id="edit_attendees" value="${data.attendees}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="edit-label">일시</label>
|
|
||||||
<input type="text" class="edit-field" id="edit_datetime" value="${data.datetime}">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="edit-label">장소</label>
|
|
||||||
<input type="text" class="edit-field" id="edit_location" value="${data.location}">
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
} else if (index === 0) {
|
|
||||||
// 회의 개요 보기 모드
|
|
||||||
contentDiv.innerHTML = `
|
|
||||||
<p><strong>회의 목적:</strong> ${data.purpose}</p>
|
|
||||||
<p><strong>참석자:</strong> ${data.attendees}</p>
|
|
||||||
<p><strong>일시:</strong> ${data.datetime}</p>
|
|
||||||
<p><strong>장소:</strong> ${data.location}</p>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 섹션 검증
|
|
||||||
function verifySection(index) {
|
|
||||||
currentSectionIndex = index;
|
|
||||||
const section = sectionVerifications[index];
|
|
||||||
|
|
||||||
$('#verifyMessage').textContent = `"${section.name}" 섹션의 내용을 검증하시겠습니까?`;
|
|
||||||
openModal('verifyModal');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 검증 확인
|
|
||||||
function confirmVerification() {
|
|
||||||
const section = sectionVerifications[currentSectionIndex];
|
|
||||||
section.verified = true;
|
|
||||||
|
|
||||||
if (!section.verifiers.includes('김민준')) {
|
|
||||||
section.verifiers.push('김민준');
|
|
||||||
}
|
|
||||||
|
|
||||||
closeModal('verifyModal');
|
|
||||||
showToast(`"${section.name}" 섹션이 검증되었습니다`, 'success');
|
|
||||||
|
|
||||||
// 화면 새로고침 시뮬레이션
|
|
||||||
setTimeout(() => {
|
|
||||||
location.reload();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 섹션 잠금 해제
|
|
||||||
function unlockSection(index) {
|
|
||||||
currentSectionIndex = index;
|
|
||||||
openModal('unlockModal');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 잠금 해제 확인
|
|
||||||
function confirmUnlock() {
|
|
||||||
const section = sectionVerifications[currentSectionIndex];
|
|
||||||
section.locked = false;
|
|
||||||
|
|
||||||
closeModal('unlockModal');
|
|
||||||
showToast(`"${section.name}" 섹션의 잠금이 해제되었습니다`, 'success');
|
|
||||||
|
|
||||||
// 화면 새로고침 시뮬레이션
|
|
||||||
setTimeout(() => {
|
|
||||||
location.reload();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 편집 모드 토글
|
|
||||||
function toggleEditMode() {
|
|
||||||
if (currentSectionIndex !== 0) {
|
|
||||||
// 회의 개요가 아닌 경우
|
|
||||||
closeModal('sectionModal');
|
|
||||||
showToast('이 섹션은 회의록수정 화면에서 수정할 수 있습니다', 'info');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
isEditMode = !isEditMode;
|
|
||||||
|
|
||||||
if (isEditMode) {
|
|
||||||
// 편집 모드로 전환
|
|
||||||
renderSectionContent(currentSectionIndex, true);
|
|
||||||
$('#editBtn').style.display = 'none';
|
|
||||||
$('#saveBtn').style.display = 'inline-block';
|
|
||||||
} else {
|
|
||||||
// 보기 모드로 전환
|
|
||||||
renderSectionContent(currentSectionIndex, false);
|
|
||||||
$('#editBtn').style.display = 'inline-block';
|
|
||||||
$('#saveBtn').style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 섹션 저장
|
|
||||||
function saveSection() {
|
|
||||||
if (currentSectionIndex !== 0) return;
|
|
||||||
|
|
||||||
// 편집된 값 가져오기
|
|
||||||
const updatedData = {
|
|
||||||
purpose: $('#edit_purpose').value,
|
|
||||||
attendees: $('#edit_attendees').value,
|
|
||||||
datetime: $('#edit_datetime').value,
|
|
||||||
location: $('#edit_location').value
|
|
||||||
};
|
|
||||||
|
|
||||||
// 데이터 업데이트
|
|
||||||
sectionData[currentSectionIndex] = updatedData;
|
|
||||||
|
|
||||||
// 보기 모드로 전환
|
|
||||||
isEditMode = false;
|
|
||||||
renderSectionContent(currentSectionIndex, false);
|
|
||||||
$('#editBtn').style.display = 'inline-block';
|
|
||||||
$('#saveBtn').style.display = 'none';
|
|
||||||
|
|
||||||
// 성공 메시지
|
|
||||||
showToast('회의 개요가 저장되었습니다', 'success');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 모두 검증 완료
|
|
||||||
function completeAllVerification() {
|
|
||||||
if (confirm('모든 섹션 검증을 완료하고 회의록을 확정하시겠습니까?')) {
|
|
||||||
showToast('회의록이 최종 확정되었습니다', 'success');
|
|
||||||
|
|
||||||
// 회의 종료 화면 또는 대시보드로 이동
|
|
||||||
setTimeout(() => {
|
|
||||||
alert('회의록이 확정되었습니다.\n참석자들에게 알림이 전송되었습니다.');
|
|
||||||
// navigateTo('01-대시보드.html');
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 나중에 하기
|
|
||||||
function saveLater() {
|
|
||||||
if (confirm('검증을 나중에 완료하시겠습니까?\n회의록은 임시 저장됩니다.')) {
|
|
||||||
// 회의록 상태를 '작성중'으로 저장
|
|
||||||
// 실제로는 Meeting Service API 호출하여 임시 저장
|
|
||||||
showToast('회의록이 임시 저장되었습니다', 'info');
|
|
||||||
|
|
||||||
// 대시보드로 이동
|
|
||||||
setTimeout(() => {
|
|
||||||
navigateTo('02-대시보드.html');
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 초기 진행률 업데이트
|
|
||||||
updateProgress();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -25,92 +25,85 @@
|
|||||||
color: var(--gray-700);
|
color: var(--gray-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 통계 카드 그리드 */
|
/* 통계 카드 그리드 - 10-회의록상세조회와 동일한 디자인 */
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: var(--space-md);
|
gap: var(--space-md);
|
||||||
margin-bottom: var(--space-lg);
|
margin-bottom: var(--space-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card {
|
/* 모바일에서 gap 축소 */
|
||||||
background: var(--white);
|
@media (max-width: 600px) {
|
||||||
padding: var(--space-md);
|
.stats-grid {
|
||||||
border-radius: var(--radius-lg);
|
gap: var(--space-xs);
|
||||||
box-shadow: var(--shadow-md);
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
padding: var(--space-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: var(--font-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: var(--font-xs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
padding: var(--space-lg);
|
||||||
|
background: var(--gray-100);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-value {
|
.stat-value {
|
||||||
font-size: var(--font-h1);
|
font-size: var(--font-h1);
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
margin-bottom: var(--space-xs);
|
margin-bottom: var(--space-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-label {
|
.stat-label {
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-body);
|
||||||
color: var(--gray-500);
|
color: var(--gray-600);
|
||||||
}
|
|
||||||
|
|
||||||
/* 키워드 클라우드 */
|
|
||||||
.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);
|
font-weight: var(--font-weight-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 발언 통계 바 차트 */
|
/* 키워드 섹션 - 10-회의록상세조회와 동일한 디자인 */
|
||||||
.speaker-stats {
|
.keywords-section {
|
||||||
padding: var(--space-md) 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.speaker-item {
|
.keywords-title {
|
||||||
display: flex;
|
font-size: var(--font-h4);
|
||||||
align-items: center;
|
font-weight: var(--font-weight-bold);
|
||||||
gap: var(--space-md);
|
color: var(--gray-900);
|
||||||
margin-bottom: var(--space-md);
|
margin-bottom: var(--space-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.speaker-info {
|
.keyword-tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-wrap: wrap;
|
||||||
gap: var(--space-sm);
|
gap: var(--space-sm);
|
||||||
min-width: 120px;
|
margin: var(--space-md) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.speaker-bar-container {
|
.keyword-tag {
|
||||||
flex: 1;
|
padding: 6px 12px;
|
||||||
height: 32px;
|
background: var(--primary-light);
|
||||||
background: var(--gray-100);
|
color: var(--primary);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
overflow: hidden;
|
font-size: var(--font-small);
|
||||||
position: relative;
|
cursor: pointer;
|
||||||
|
transition: all var(--transition-fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
.speaker-bar {
|
.keyword-tag:hover {
|
||||||
height: 100%;
|
|
||||||
background: var(--primary);
|
background: var(--primary);
|
||||||
border-radius: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding-right: var(--space-sm);
|
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
font-size: var(--font-caption);
|
|
||||||
font-weight: var(--font-weight-bold);
|
|
||||||
transition: width 1s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 안건 카드 */
|
/* 안건 카드 */
|
||||||
@ -182,99 +175,69 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.agenda-section {
|
.agenda-section {
|
||||||
margin-bottom: var(--space-md);
|
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 {
|
.agenda-section-title {
|
||||||
font-size: var(--font-small);
|
font-size: var(--font-small);
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
color: var(--gray-500);
|
color: var(--gray-900);
|
||||||
margin-bottom: var(--space-xs);
|
margin-bottom: var(--space-sm);
|
||||||
text-transform: uppercase;
|
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 {
|
.agenda-section-content {
|
||||||
font-size: var(--font-body);
|
font-size: var(--font-body);
|
||||||
color: var(--gray-700);
|
color: var(--gray-700);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
padding-left: var(--space-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Todo 리스트 (읽기 전용) */
|
.agenda-section-content ul {
|
||||||
.todo-list-item {
|
margin: 0;
|
||||||
padding: var(--space-md);
|
padding-left: var(--space-lg);
|
||||||
background: var(--gray-50);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
margin-bottom: var(--space-sm);
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-header {
|
.agenda-section-content li {
|
||||||
display: flex;
|
margin-bottom: var(--space-xs);
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-start;
|
|
||||||
margin-bottom: var(--space-sm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.todo-checkbox {
|
/* 하단 버튼 비율 조정 (1:2:1) */
|
||||||
margin-right: var(--space-sm);
|
.action-bar .btn:nth-child(1) {
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-content {
|
|
||||||
flex: 1;
|
|
||||||
font-weight: var(--font-weight-medium);
|
|
||||||
color: var(--gray-700);
|
|
||||||
}
|
|
||||||
|
|
||||||
.todo-meta {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--space-md);
|
|
||||||
font-size: var(--font-small);
|
|
||||||
color: var(--gray-500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 하단 액션 바 - 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;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-bar .btn-primary {
|
.action-bar .btn:nth-child(2) {
|
||||||
flex: 2; /* 바로 최종 확정 버튼 강조 */
|
flex: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-bar .btn:nth-child(3) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 데스크톱 반응형 */
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
grid-template-columns: repeat(4, 1fr);
|
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 {
|
.readonly-notice {
|
||||||
@ -303,44 +266,42 @@
|
|||||||
🔒 이 화면은 <strong>확인 전용</strong>입니다. 내용을 수정하려면 "회의록 수정" 버튼을 클릭하세요.
|
🔒 이 화면은 <strong>확인 전용</strong>입니다. 내용을 수정하려면 "회의록 수정" 버튼을 클릭하세요.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 통계 카드 그리드 -->
|
<!-- 회의 통계 및 키워드 카드 -->
|
||||||
<div class="stats-grid">
|
<div class="card mb-lg">
|
||||||
<div class="stat-card">
|
<!-- 통계 카드 그리드 -->
|
||||||
<div class="stat-value" id="durationValue">0</div>
|
<div class="stats-grid">
|
||||||
<div class="stat-label">회의 시간 (분)</div>
|
<div class="stat-item">
|
||||||
|
<div class="stat-value" id="participantsValue">4명</div>
|
||||||
|
<div class="stat-label">참석자</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value" id="durationValue">90분</div>
|
||||||
|
<div class="stat-label">회의 시간</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value" id="agendasValue">3개</div>
|
||||||
|
<div class="stat-label">주요 안건</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-item">
|
||||||
|
<div class="stat-value" id="todosValue">5개</div>
|
||||||
|
<div class="stat-label">Todo 생성</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
|
||||||
<div class="stat-value" id="participantsValue">0</div>
|
<!-- 주요 키워드 -->
|
||||||
<div class="stat-label">참석자</div>
|
<div class="keywords-section">
|
||||||
</div>
|
<h3 class="keywords-title">주요 키워드</h3>
|
||||||
<div class="stat-card">
|
<div class="keyword-tags">
|
||||||
<div class="stat-value" id="agendasValue">0</div>
|
<span class="keyword-tag">#신제품기획</span>
|
||||||
<div class="stat-label">안건</div>
|
<span class="keyword-tag">#예산편성</span>
|
||||||
</div>
|
<span class="keyword-tag">#일정조율</span>
|
||||||
<div class="stat-card">
|
<span class="keyword-tag">#시장조사</span>
|
||||||
<div class="stat-value" id="todosValue">0</div>
|
<span class="keyword-tag">#UI/UX</span>
|
||||||
<div class="stat-label">Todo</div>
|
<span class="keyword-tag">#개발스펙</span>
|
||||||
|
</div>
|
||||||
</div>
|
</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>
|
|
||||||
|
|
||||||
<!-- 발언 통계 -->
|
|
||||||
<div class="card mb-md">
|
|
||||||
<h3 class="card-title">발언 통계</h3>
|
|
||||||
<div class="speaker-stats" id="speakerStats"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 안건별 AI 요약 -->
|
<!-- 안건별 AI 요약 -->
|
||||||
<div class="card mb-md">
|
<div class="card mb-md">
|
||||||
@ -352,7 +313,7 @@
|
|||||||
|
|
||||||
<!-- 하단 액션 바 (3가지 선택 옵션) -->
|
<!-- 하단 액션 바 (3가지 선택 옵션) -->
|
||||||
<div class="action-bar">
|
<div class="action-bar">
|
||||||
<button class="btn btn-ghost" onclick="navigateTo('02-대시보드.html')">
|
<button class="btn btn-neutral" onclick="navigateTo('02-대시보드.html')">
|
||||||
대시보드
|
대시보드
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">
|
<button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">
|
||||||
@ -459,9 +420,6 @@
|
|||||||
const totalTodos = SAMPLE_AGENDAS.reduce((sum, agenda) => sum + (agenda.todos?.length || 0), 0);
|
const totalTodos = SAMPLE_AGENDAS.reduce((sum, agenda) => sum + (agenda.todos?.length || 0), 0);
|
||||||
animateCounter('todosValue', totalTodos);
|
animateCounter('todosValue', totalTodos);
|
||||||
|
|
||||||
// 발언 통계 렌더링
|
|
||||||
renderSpeakerStats();
|
|
||||||
|
|
||||||
// 안건 리스트 렌더링
|
// 안건 리스트 렌더링
|
||||||
renderAgendaList();
|
renderAgendaList();
|
||||||
}
|
}
|
||||||
@ -482,42 +440,6 @@
|
|||||||
}, 30);
|
}, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 발언 통계 렌더링
|
|
||||||
function renderSpeakerStats() {
|
|
||||||
const stats = [
|
|
||||||
{ user: SAMPLE_MEETINGS[0].participants[0], count: 15, duration: 35 },
|
|
||||||
{ user: SAMPLE_MEETINGS[0].participants[1], count: 12, duration: 28 },
|
|
||||||
{ user: SAMPLE_MEETINGS[0].participants[2], count: 10, duration: 20 },
|
|
||||||
{ user: SAMPLE_MEETINGS[0].participants[3], count: 8, duration: 17 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const maxDuration = Math.max(...stats.map(s => s.duration));
|
|
||||||
const container = $('#speakerStats');
|
|
||||||
|
|
||||||
stats.forEach(stat => {
|
|
||||||
const percentage = (stat.duration / maxDuration) * 100;
|
|
||||||
const item = createElement('div', { className: 'speaker-item' }, `
|
|
||||||
<div class="speaker-info">
|
|
||||||
${createAvatar(stat.user, 'sm')}
|
|
||||||
<span class="text-small">${stat.user.name}</span>
|
|
||||||
</div>
|
|
||||||
<div class="speaker-bar-container">
|
|
||||||
<div class="speaker-bar" style="width: 0%;" data-width="${percentage}">
|
|
||||||
${stat.duration}분
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
container.appendChild(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 애니메이션 시작
|
|
||||||
setTimeout(() => {
|
|
||||||
$$('.speaker-bar').forEach(bar => {
|
|
||||||
bar.style.width = bar.dataset.width + '%';
|
|
||||||
});
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 안건 리스트 렌더링
|
// 안건 리스트 렌더링
|
||||||
function renderAgendaList() {
|
function renderAgendaList() {
|
||||||
const container = $('#agendaList');
|
const container = $('#agendaList');
|
||||||
@ -554,59 +476,85 @@
|
|||||||
`));
|
`));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 발언자별 의견
|
|
||||||
if (agenda.details.opinions && agenda.details.opinions.length > 0) {
|
|
||||||
const opinionsHtml = agenda.details.opinions.map(op =>
|
|
||||||
`<li><strong>${op.speaker}:</strong> ${op.opinion}</li>`
|
|
||||||
).join('');
|
|
||||||
content.appendChild(createElement('div', { className: 'agenda-section' }, `
|
|
||||||
<div class="agenda-section-title">발언자별 의견</div>
|
|
||||||
<div class="agenda-section-content"><ul>${opinionsHtml}</ul></div>
|
|
||||||
`));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 결정 사항
|
// 결정 사항
|
||||||
if (agenda.details.decisions && agenda.details.decisions.length > 0) {
|
if (agenda.details.decisions && agenda.details.decisions.length > 0) {
|
||||||
const decisionsHtml = agenda.details.decisions.map(d => `<li>✓ ${d}</li>`).join('');
|
const decisionsSection = createElement('div', { className: 'agenda-section' }, `
|
||||||
content.appendChild(createElement('div', { className: 'agenda-section' }, `
|
|
||||||
<div class="agenda-section-title">결정 사항</div>
|
<div class="agenda-section-title">결정 사항</div>
|
||||||
<div class="agenda-section-content"><ul>${decisionsHtml}</ul></div>
|
`);
|
||||||
`));
|
|
||||||
|
const decisionsList = createElement('ul', {
|
||||||
|
className: 'agenda-section-content',
|
||||||
|
style: 'list-style: none; padding: 0; margin: 0; padding-left: var(--space-md);'
|
||||||
|
});
|
||||||
|
|
||||||
|
agenda.details.decisions.forEach(decision => {
|
||||||
|
const decisionItem = createElement('li', {
|
||||||
|
style: 'display: flex; align-items: flex-start; gap: var(--space-sm); padding: var(--space-xs) 0; font-size: var(--font-body); color: var(--gray-700);'
|
||||||
|
}, `
|
||||||
|
<span style="color: var(--gray-500); margin-top: 2px;">•</span>
|
||||||
|
<span style="flex: 1;">${decision}</span>
|
||||||
|
`);
|
||||||
|
decisionsList.appendChild(decisionItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
decisionsSection.appendChild(decisionsList);
|
||||||
|
content.appendChild(decisionsSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 보류 사항
|
// 보류 사항
|
||||||
if (agenda.details.pending && agenda.details.pending.length > 0) {
|
if (agenda.details.pending && agenda.details.pending.length > 0) {
|
||||||
const pendingHtml = agenda.details.pending.map(p => `<li>⏸ ${p}</li>`).join('');
|
const pendingSection = createElement('div', { className: 'agenda-section' }, `
|
||||||
content.appendChild(createElement('div', { className: 'agenda-section' }, `
|
|
||||||
<div class="agenda-section-title">보류 사항</div>
|
<div class="agenda-section-title">보류 사항</div>
|
||||||
<div class="agenda-section-content"><ul>${pendingHtml}</ul></div>
|
`);
|
||||||
`));
|
|
||||||
|
const pendingList = createElement('ul', {
|
||||||
|
className: 'agenda-section-content',
|
||||||
|
style: 'list-style: none; padding: 0; margin: 0; padding-left: var(--space-md);'
|
||||||
|
});
|
||||||
|
|
||||||
|
agenda.details.pending.forEach(pending => {
|
||||||
|
const pendingItem = createElement('li', {
|
||||||
|
style: 'display: flex; align-items: flex-start; gap: var(--space-sm); padding: var(--space-xs) 0; font-size: var(--font-body); color: var(--gray-700);'
|
||||||
|
}, `
|
||||||
|
<span style="color: var(--gray-500); margin-top: 2px;">•</span>
|
||||||
|
<span style="flex: 1;">${pending}</span>
|
||||||
|
`);
|
||||||
|
pendingList.appendChild(pendingItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
pendingSection.appendChild(pendingList);
|
||||||
|
content.appendChild(pendingSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo 목록
|
// Todo 목록 - 제목만 간단히 표시
|
||||||
if (agenda.todos && agenda.todos.length > 0) {
|
if (agenda.todos && agenda.todos.length > 0) {
|
||||||
const todosSection = createElement('div', { className: 'agenda-section' }, `
|
const todosSection = createElement('div', { className: 'agenda-section' }, `
|
||||||
<div class="agenda-section-title">Todo 자동 추출 결과</div>
|
<div class="agenda-section-title">Todo 자동 추출 결과</div>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
agenda.todos.forEach(todo => {
|
const todoList = createElement('ul', {
|
||||||
const todoItem = createElement('div', { className: 'todo-list-item' }, `
|
className: 'agenda-section-content',
|
||||||
<div class="todo-header">
|
style: 'list-style: none; padding: 0; margin: 0; padding-left: var(--space-md);'
|
||||||
<input type="checkbox" class="todo-checkbox" disabled>
|
|
||||||
<div class="todo-content">${todo.title}</div>
|
|
||||||
${createBadge(todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음',
|
|
||||||
`priority-${todo.priority}`)}
|
|
||||||
</div>
|
|
||||||
<div class="todo-meta">
|
|
||||||
${createAvatar(todo.assignee, 'sm')}
|
|
||||||
<span>${todo.assignee.name}</span>
|
|
||||||
<span>•</span>
|
|
||||||
<span>${formatDate(todo.dueDate)}</span>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
todosSection.appendChild(todoItem);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
agenda.todos.forEach(todo => {
|
||||||
|
const todoItem = createElement('li', {
|
||||||
|
style: 'display: flex; align-items: flex-start; gap: var(--space-sm); padding: var(--space-xs) 0; font-size: var(--font-body); color: var(--gray-700);'
|
||||||
|
}, `
|
||||||
|
<span style="color: var(--gray-500); margin-top: 2px;">•</span>
|
||||||
|
<span style="flex: 1;">${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);
|
content.appendChild(todosSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -165,6 +165,23 @@
|
|||||||
.participant {
|
.participant {
|
||||||
width: calc(50% - var(--space-md) / 2);
|
width: calc(50% - var(--space-md) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 통계 그리드: 모바일에서도 4열 유지, gap만 축소 */
|
||||||
|
.stats-grid {
|
||||||
|
gap: var(--space-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
padding: var(--space-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: var(--font-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: var(--font-xs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 회의록 섹션 */
|
/* 회의록 섹션 */
|
||||||
@ -333,9 +350,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 대시보드 탭 콘텐츠 */
|
/* 대시보드 탭 콘텐츠 */
|
||||||
.dashboard-section {
|
|
||||||
margin-bottom: var(--space-lg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.key-points {
|
.key-points {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
@ -393,7 +407,7 @@
|
|||||||
|
|
||||||
.stats-grid {
|
.stats-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: var(--space-md);
|
gap: var(--space-md);
|
||||||
margin-top: var(--space-md);
|
margin-top: var(--space-md);
|
||||||
}
|
}
|
||||||
@ -724,7 +738,11 @@
|
|||||||
<!-- 기본 정보 카드 -->
|
<!-- 기본 정보 카드 -->
|
||||||
<div class="info-card">
|
<div class="info-card">
|
||||||
<div class="meeting-basic-info">
|
<div class="meeting-basic-info">
|
||||||
<h2>2025년 1분기 제품 기획 회의</h2>
|
<div id="meeting-title-container" style="display: flex; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-sm);">
|
||||||
|
<span class="badge badge-complete">확정완료</span>
|
||||||
|
<!-- 생성자일 경우 👑 아이콘이 JavaScript로 추가됨 -->
|
||||||
|
<h2 style="margin: 0;">2025년 1분기 제품 기획 회의</h2>
|
||||||
|
</div>
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="info-icon">📅</span>
|
<span class="info-icon">📅</span>
|
||||||
<span>2025년 10월 25일 14:00 (90분)</span>
|
<span>2025년 10월 25일 14:00 (90분)</span>
|
||||||
@ -733,10 +751,6 @@
|
|||||||
<span class="info-icon">📍</span>
|
<span class="info-icon">📍</span>
|
||||||
<span>본사 2층 대회의실</span>
|
<span>본사 2층 대회의실</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-row">
|
|
||||||
<span class="info-icon">✅</span>
|
|
||||||
<span class="badge badge-complete">확정완료</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="participants-list">
|
<div class="participants-list">
|
||||||
@ -951,10 +965,8 @@
|
|||||||
<!-- 대시보드 탭 (기본 노출 탭 - 유저스토리 UFR-MEET-047 요구사항) -->
|
<!-- 대시보드 탭 (기본 노출 탭 - 유저스토리 UFR-MEET-047 요구사항) -->
|
||||||
<div id="dashboard-content" class="tab-content active">
|
<div id="dashboard-content" class="tab-content active">
|
||||||
<!-- 핵심내용 -->
|
<!-- 핵심내용 -->
|
||||||
<div class="section dashboard-section">
|
<div class="card mb-lg">
|
||||||
<div class="section-header">
|
<h3 class="card-title">💡 핵심내용</h3>
|
||||||
<h3 class="section-title">💡 핵심내용</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ol class="key-points">
|
<ol class="key-points">
|
||||||
<li class="key-point">
|
<li class="key-point">
|
||||||
@ -1004,10 +1016,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 결정사항 -->
|
<!-- 결정사항 -->
|
||||||
<div class="section dashboard-section">
|
<div class="card mb-lg">
|
||||||
<div class="section-header">
|
<h3 class="card-title">✅ 결정사항</h3>
|
||||||
<h3 class="section-title">✅ 결정사항</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="decision-card">
|
<div class="decision-card">
|
||||||
<div class="decision-content">베타 버전 출시일: 2025년 12월 1일</div>
|
<div class="decision-content">베타 버전 출시일: 2025년 12월 1일</div>
|
||||||
@ -1033,10 +1043,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Todo 진행상황 -->
|
<!-- Todo 진행상황 -->
|
||||||
<div class="section dashboard-section">
|
<div class="card mb-lg">
|
||||||
<div class="section-header">
|
<h3 class="card-title">📋 Todo 진행상황</h3>
|
||||||
<h3 class="section-title">📋 Todo 진행상황</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 전체 진행률 -->
|
<!-- 전체 진행률 -->
|
||||||
<div style="margin-bottom: var(--space-lg);">
|
<div style="margin-bottom: var(--space-lg);">
|
||||||
@ -1182,10 +1190,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 관련회의록 -->
|
<!-- 관련회의록 -->
|
||||||
<div class="section dashboard-section">
|
<div class="card mb-lg">
|
||||||
<div class="section-header">
|
<h3 class="card-title">📚 관련회의록 (3건)</h3>
|
||||||
<h3 class="section-title">📚 관련회의록 (3건)</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="reference-item" onclick="window.open('10-회의록상세조회.html', '_blank')">
|
<div class="reference-item" onclick="window.open('10-회의록상세조회.html', '_blank')">
|
||||||
<div class="reference-header">
|
<div class="reference-header">
|
||||||
@ -1729,6 +1735,20 @@
|
|||||||
* 페이지 초기화
|
* 페이지 초기화
|
||||||
*/
|
*/
|
||||||
function initPage() {
|
function initPage() {
|
||||||
|
// 회의 생성자 확인 후 👑 표시
|
||||||
|
const currentUser = '김민준'; // 현재 로그인 사용자
|
||||||
|
const isCreator = checkIfUserIsCreator(CURRENT_MEETING_ID, currentUser);
|
||||||
|
|
||||||
|
if (isCreator) {
|
||||||
|
const titleContainer = document.getElementById('meeting-title-container');
|
||||||
|
const badge = titleContainer.querySelector('.badge');
|
||||||
|
const crownIcon = document.createElement('span');
|
||||||
|
crownIcon.textContent = '👑';
|
||||||
|
crownIcon.style.fontSize = '24px';
|
||||||
|
// badge 다음에 👑 삽입
|
||||||
|
badge.insertAdjacentElement('afterend', crownIcon);
|
||||||
|
}
|
||||||
|
|
||||||
updateTodoProgress();
|
updateTodoProgress();
|
||||||
updateFilterCounts();
|
updateFilterCounts();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -179,6 +179,7 @@ a:hover {
|
|||||||
font-size: var(--font-h3);
|
font-size: var(--font-h3);
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
|
margin-bottom: var(--space-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-body {
|
.card-body {
|
||||||
@ -258,6 +259,28 @@ a:hover {
|
|||||||
background: var(--gray-100);
|
background: var(--gray-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Outline Button (회색 테두리) */
|
||||||
|
.btn-outline {
|
||||||
|
background: var(--white);
|
||||||
|
color: var(--gray-700);
|
||||||
|
border: 1px solid var(--gray-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline:hover:not(:disabled) {
|
||||||
|
background: var(--gray-50);
|
||||||
|
border-color: var(--gray-600);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Neutral Button (진한 회색 배경) */
|
||||||
|
.btn-neutral {
|
||||||
|
background: #424242;
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-neutral:hover:not(:disabled) {
|
||||||
|
background: var(--gray-900);
|
||||||
|
}
|
||||||
|
|
||||||
/* Error Button */
|
/* Error Button */
|
||||||
.btn-error {
|
.btn-error {
|
||||||
background: var(--error);
|
background: var(--error);
|
||||||
@ -1238,9 +1261,9 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
22. 섹션 카드 컴포넌트
|
22. 안건 카드 컴포넌트
|
||||||
======================================== */
|
======================================== */
|
||||||
.section {
|
.agenda {
|
||||||
background: var(--white);
|
background: var(--white);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
box-shadow: var(--shadow-md);
|
box-shadow: var(--shadow-md);
|
||||||
@ -1248,14 +1271,14 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
|||||||
margin-bottom: var(--space-lg);
|
margin-bottom: var(--space-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-header {
|
.agenda-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: var(--space-md);
|
margin-bottom: var(--space-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-title {
|
.agenda-title {
|
||||||
font-size: var(--font-h3);
|
font-size: var(--font-h3);
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
@ -1264,7 +1287,7 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
|||||||
gap: var(--space-sm);
|
gap: var(--space-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-content {
|
.agenda-content {
|
||||||
color: var(--gray-700);
|
color: var(--gray-700);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
- **작성일**: 2025-10-21
|
- **작성일**: 2025-10-21
|
||||||
- **최종 수정일**: 2025-10-24
|
- **최종 수정일**: 2025-10-24
|
||||||
- **작성자**: 이미준 (서비스 기획자)
|
- **작성자**: 이미준 (서비스 기획자)
|
||||||
- **버전**: 1.4.16
|
- **버전**: 1.4.18
|
||||||
- **설계 철학**: Mobile First Design
|
- **설계 철학**: Mobile First Design
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -847,7 +847,15 @@ graph TD
|
|||||||
- 상태 표시 없음 (발언 중/온라인 등 제거)
|
- 상태 표시 없음 (발언 중/온라인 등 제거)
|
||||||
- 참석자 수 동적 업데이트 (초대 성공 시)
|
- 참석자 수 동적 업데이트 (초대 성공 시)
|
||||||
|
|
||||||
- **AI 제안 탭**: AI가 생성한 회의록 개선 제안 (3가지 유형)
|
- **AI 제안 탭**: AI가 생성한 회의록 개선 제안
|
||||||
|
|
||||||
|
- **실시간 주요 메모 추천** (UFR-MEET-030):
|
||||||
|
- 음성→텍스트 변환 후 AI가 실시간 분석
|
||||||
|
- **중요한 내용으로 판단된 경우에만** 주요 메모 항목 추천
|
||||||
|
- 추천 빈도는 중요 내용 발생에 따라 가변적 (고정 간격 아님)
|
||||||
|
- 각 추천 항목에 "주요 메모에 추가" 버튼 제공
|
||||||
|
- 클릭 시 해당 안건의 주요 메모에 자동 저장
|
||||||
|
- 실시간 업데이트: 새로운 추천은 상단에 표시
|
||||||
|
|
||||||
- **논의사항 제안 카드**: 제안 내용 + "논의사항에 적용" 버튼
|
- **논의사항 제안 카드**: 제안 내용 + "논의사항에 적용" 버튼
|
||||||
- 제안 구조:
|
- 제안 구조:
|
||||||
@ -976,7 +984,6 @@ graph TD
|
|||||||
- 회의 총 시간
|
- 회의 총 시간
|
||||||
- 참석자 수
|
- 참석자 수
|
||||||
- 주요 키워드 (태그 클라우드)
|
- 주요 키워드 (태그 클라우드)
|
||||||
- 발언 통계 (화자별 발언 횟수 및 시간 - 바 차트)
|
|
||||||
|
|
||||||
- **안건별 AI 요약 섹션** (신규)
|
- **안건별 AI 요약 섹션** (신규)
|
||||||
- **안건 카드** (안건 개수만큼 반복):
|
- **안건 카드** (안건 개수만큼 반복):
|
||||||
@ -986,7 +993,6 @@ graph TD
|
|||||||
- 🔒 "편집 불가" 아이콘 표시
|
- 🔒 "편집 불가" 아이콘 표시
|
||||||
- 민트 그린 좌측 액센트 라인
|
- 민트 그린 좌측 액센트 라인
|
||||||
- **상세 요약 정리** (읽기 전용)
|
- **상세 요약 정리** (읽기 전용)
|
||||||
- 논의 주제
|
|
||||||
- 발언자별 의견
|
- 발언자별 의견
|
||||||
- 결정 사항
|
- 결정 사항
|
||||||
- 보류 사항
|
- 보류 사항
|
||||||
@ -1237,9 +1243,9 @@ graph TD
|
|||||||
|
|
||||||
#### 주요 기능
|
#### 주요 기능
|
||||||
1. 회의 기본 정보 표시
|
1. 회의 기본 정보 표시
|
||||||
2. **섹션별 AI 요약 표시** (섹션 최상단)
|
2. **안건별 AI 요약 표시** (안건 최상단)
|
||||||
3. 섹션별 상세 내용 표시
|
3. 안건별 상세 내용 표시
|
||||||
4. **참고자료 표시** (섹션 하단)
|
4. **참고자료 표시** (안건 하단)
|
||||||
5. Todo 항목 및 진행 상황 표시
|
5. Todo 항목 및 진행 상황 표시
|
||||||
6. 첨부파일 다운로드
|
6. 첨부파일 다운로드
|
||||||
7. 회의록 수정/공유 액션
|
7. 회의록 수정/공유 액션
|
||||||
@ -1263,17 +1269,17 @@ graph TD
|
|||||||
- "대시보드" 탭 (기본 활성)
|
- "대시보드" 탭 (기본 활성)
|
||||||
- "회의록" 탭
|
- "회의록" 탭
|
||||||
|
|
||||||
- **회의록 탭 콘텐츠** (섹션별 구조)
|
- **회의록 탭 콘텐츠** (안건별 구조)
|
||||||
- 각 섹션:
|
- 각 안건:
|
||||||
- 섹션 제목
|
- 안건 제목
|
||||||
- 검증 완료 배지 (검증된 경우)
|
- 검증 완료 배지 (검증된 경우)
|
||||||
- **AI 회의 내용 요약 영역** (섹션 최상단, 강조 박스)
|
- **AI 회의 내용 요약 영역** (안건 최상단, 강조 박스)
|
||||||
- 요약 아이콘 (💡)
|
- 요약 아이콘 (💡)
|
||||||
- AI 자동 생성 요약 (2-3문장)
|
- AI 자동 생성 요약 (2-3문장)
|
||||||
- 요약 생성/수정 시간
|
- 요약 생성/수정 시간
|
||||||
- "수정" 버튼 (권한 있는 경우)
|
- "수정" 버튼 (권한 있는 경우)
|
||||||
- 섹션 내용 (마크다운 렌더링)
|
- 안건 내용 (마크다운 렌더링)
|
||||||
- **참고자료 영역** (섹션 하단, 별도 영역)
|
- **참고자료 영역** (안건 하단, 별도 영역)
|
||||||
- "참고자료" 라벨
|
- "참고자료" 라벨
|
||||||
- 관련 회의록 링크 리스트 (최대 3개):
|
- 관련 회의록 링크 리스트 (최대 3개):
|
||||||
- 링크 아이콘 (📄)
|
- 링크 아이콘 (📄)
|
||||||
@ -1331,17 +1337,17 @@ graph TD
|
|||||||
- 대시보드 (기본 활성)
|
- 대시보드 (기본 활성)
|
||||||
- 회의록
|
- 회의록
|
||||||
- **메인 영역**:
|
- **메인 영역**:
|
||||||
- 회의록 탭: 전체 회의록 내용 (섹션별 구조)
|
- 회의록 탭: 전체 회의록 내용 (안건별 구조)
|
||||||
- 대시보드 탭: 핵심내용, 결정사항, Todo 진행상황, 참고자료 (11-회의록대시보드.html 구조 참조)
|
- 대시보드 탭: 핵심내용, 결정사항, Todo 진행상황, 참고자료 (11-회의록대시보드.html 구조 참조)
|
||||||
|
|
||||||
#### 인터랙션
|
#### 인터랙션
|
||||||
1. **탭 전환**
|
1. **탭 전환**
|
||||||
- "회의록" 탭: 전체 회의록 내용 표시 (섹션별 구조)
|
- "회의록" 탭: 전체 회의록 내용 표시 (안건별 구조)
|
||||||
- "대시보드" 탭: 핵심내용, 결정사항, Todo, 참고자료 요약 표시
|
- "대시보드" 탭: 핵심내용, 결정사항, Todo, 참고자료 요약 표시
|
||||||
- 탭 전환 시 URL 변경 없이 클라이언트 사이드 렌더링
|
- 탭 전환 시 URL 변경 없이 클라이언트 사이드 렌더링
|
||||||
|
|
||||||
2. **회의록 탭 인터랙션**
|
2. **회의록 탭 인터랙션**
|
||||||
- **섹션 네비게이션**: 섹션 제목 클릭 → 해당 섹션으로 스크롤
|
- **안건 네비게이션**: 안건 제목 클릭 → 해당 안건으로 스크롤
|
||||||
- **접기/펼치기**: 긴 내용은 초기 접힌 상태, 클릭으로 펼침
|
- **접기/펼치기**: 긴 내용은 초기 접힌 상태, 클릭으로 펼침
|
||||||
- **AI 요약 편집**:
|
- **AI 요약 편집**:
|
||||||
- "수정" 버튼 클릭 (권한 있는 경우) → 인라인 편집 모드
|
- "수정" 버튼 클릭 (권한 있는 경우) → 인라인 편집 모드
|
||||||
@ -1354,10 +1360,10 @@ graph TD
|
|||||||
|
|
||||||
3. **대시보드 탭 인터랙션**
|
3. **대시보드 탭 인터랙션**
|
||||||
- **핵심내용 섹션**:
|
- **핵심내용 섹션**:
|
||||||
- 키워드 태그 클릭 → 해당 키워드 관련 섹션으로 스크롤
|
- 키워드 태그 클릭 → 해당 키워드 관련 안건으로 스크롤
|
||||||
- 통계 항목 클릭 → 상세 정보 툴팁 표시
|
- 통계 항목 클릭 → 상세 정보 툴팁 표시
|
||||||
- **결정사항 섹션**:
|
- **결정사항 섹션**:
|
||||||
- 결정사항 카드 클릭 → 회의록 탭의 해당 섹션으로 이동
|
- 결정사항 카드 클릭 → 회의록 탭의 해당 안건으로 이동
|
||||||
- 배경 설명 접기/펼치기
|
- 배경 설명 접기/펼치기
|
||||||
- **Todo 진행상황**:
|
- **Todo 진행상황**:
|
||||||
- 필터 탭 클릭 → 해당 상태의 Todo만 표시
|
- 필터 탭 클릭 → 해당 상태의 Todo만 표시
|
||||||
@ -1384,8 +1390,8 @@ graph TD
|
|||||||
- **입력**: 회의록 ID, 활성 탭 (회의록/대시보드/타임라인)
|
- **입력**: 회의록 ID, 활성 탭 (회의록/대시보드/타임라인)
|
||||||
- **출력**:
|
- **출력**:
|
||||||
- **회의 기본 정보**: 제목, 일시, 참석자, 장소, 상태, 작성자, 수정 시간
|
- **회의 기본 정보**: 제목, 일시, 참석자, 장소, 상태, 작성자, 수정 시간
|
||||||
- **섹션별 AI 요약**: 자동 생성 요약, 수정 이력
|
- **안건별 AI 요약**: 자동 생성 요약, 수정 이력
|
||||||
- **섹션별 내용**: 마크다운 형식
|
- **안건별 내용**: 마크다운 형식
|
||||||
- **참고자료 목록**:
|
- **참고자료 목록**:
|
||||||
- 관련 회의록 (제목, 날짜, 관련도, 요약)
|
- 관련 회의록 (제목, 날짜, 관련도, 요약)
|
||||||
- 프로젝트 문서 (제목, 작성자, 관련도)
|
- 프로젝트 문서 (제목, 작성자, 관련도)
|
||||||
@ -1403,7 +1409,7 @@ graph TD
|
|||||||
|
|
||||||
#### 에러 처리
|
#### 에러 처리
|
||||||
- **회의록 로딩 실패**: "회의록을 불러올 수 없습니다" + 재시도 버튼
|
- **회의록 로딩 실패**: "회의록을 불러올 수 없습니다" + 재시도 버튼
|
||||||
- **AI 요약 로딩 실패**: "요약을 불러올 수 없습니다" (섹션 내용은 정상 표시)
|
- **AI 요약 로딩 실패**: "요약을 불러올 수 없습니다" (안건 내용은 정상 표시)
|
||||||
- **참고자료 로딩 실패**: "참고자료를 불러올 수 없습니다" (빈 상태 표시)
|
- **참고자료 로딩 실패**: "참고자료를 불러올 수 없습니다" (빈 상태 표시)
|
||||||
- **대시보드 데이터 로딩 실패**: "대시보드를 불러올 수 없습니다" + 재시도 버튼
|
- **대시보드 데이터 로딩 실패**: "대시보드를 불러올 수 없습니다" + 재시도 버튼
|
||||||
- **권한 없음**: "수정" 버튼 비활성화, "조회 권한만 있습니다" 메시지
|
- **권한 없음**: "수정" 버튼 비활성화, "조회 권한만 있습니다" 메시지
|
||||||
@ -2130,6 +2136,7 @@ graph TD
|
|||||||
| 1.4.14 | 2025-10-24 | 이미준 | 12-회의록목록조회 화면 데이터 아키텍처 문서화<br>- **데이터 아키텍처 섹션 추가**: 데이터/뷰 레이어 분리 구조 설명<br> - 데이터 레이어: common.js → SAMPLE_MINUTES 배열 (30개 샘플)<br> - 뷰 레이어: 12-회의록목록조회.html → renderMeetings(), createMeetingCard() 함수<br> - 렌더링 방식: 동적 렌더링, 초기 10개 표시, "10개 더보기" 버튼으로 추가 로딩<br>- **정렬 옵션 레이블 변경**: "최신순" → "최근수정순", "회의일시순" → "최근회의순"<br>- **페이지네이션 기능 문서화**: 초기 10개 표시, "10개 더보기" 버튼 기능 설명<br>- **샘플 데이터 분포 명시**: 총 30개 (작성중 13개, 확정완료 17개)<br>- **프로토타입 파일 경로 추가**: design/uiux/prototype/12-회의록목록조회.html<br>- **스타일 가이드 버전 동기화**: v1.2.4 |
|
| 1.4.14 | 2025-10-24 | 이미준 | 12-회의록목록조회 화면 데이터 아키텍처 문서화<br>- **데이터 아키텍처 섹션 추가**: 데이터/뷰 레이어 분리 구조 설명<br> - 데이터 레이어: common.js → SAMPLE_MINUTES 배열 (30개 샘플)<br> - 뷰 레이어: 12-회의록목록조회.html → renderMeetings(), createMeetingCard() 함수<br> - 렌더링 방식: 동적 렌더링, 초기 10개 표시, "10개 더보기" 버튼으로 추가 로딩<br>- **정렬 옵션 레이블 변경**: "최신순" → "최근수정순", "회의일시순" → "최근회의순"<br>- **페이지네이션 기능 문서화**: 초기 10개 표시, "10개 더보기" 버튼 기능 설명<br>- **샘플 데이터 분포 명시**: 총 30개 (작성중 13개, 확정완료 17개)<br>- **프로토타입 파일 경로 추가**: design/uiux/prototype/12-회의록목록조회.html<br>- **스타일 가이드 버전 동기화**: v1.2.4 |
|
||||||
| 1.4.15 | 2025-10-24 | 이미준 | 06-검증완료 화면 삭제 (유저스토리 v2.1.2 변경사항 반영)<br>- **화면 삭제**: 06-검증완료 화면 전체 삭제<br> - 안건별 검증 기능이 11-회의록수정 화면으로 통합됨<br> - 섹션별 검증 방식에서 안건별 검증 방식으로 변경 (유저스토리 UFR-COLLAB-030 → 안건 기반 구조로 전환)<br>- **유저스토리 매핑 업데이트**:<br> - Collaboration 서비스: UFR-COLLAB-010 ~ UFR-COLLAB-030 → UFR-COLLAB-010 ~ UFR-COLLAB-020로 변경<br> - 프로토타입 화면 목록 테이블에서 06-검증완료 행 제거<br>- **화면 번호 유지**: 다른 화면 번호는 변경하지 않음 (프로토타입 파일명 유지)<br> - 07-회의종료, 09-Todo관리, 10-회의록상세조회, 11-회의록수정, 12-회의록목록조회 번호 유지<br>- **변경 이력**: 과거 버전의 UFR-COLLAB-030 언급은 역사적 맥락으로 유지 |
|
| 1.4.15 | 2025-10-24 | 이미준 | 06-검증완료 화면 삭제 (유저스토리 v2.1.2 변경사항 반영)<br>- **화면 삭제**: 06-검증완료 화면 전체 삭제<br> - 안건별 검증 기능이 11-회의록수정 화면으로 통합됨<br> - 섹션별 검증 방식에서 안건별 검증 방식으로 변경 (유저스토리 UFR-COLLAB-030 → 안건 기반 구조로 전환)<br>- **유저스토리 매핑 업데이트**:<br> - Collaboration 서비스: UFR-COLLAB-010 ~ UFR-COLLAB-030 → UFR-COLLAB-010 ~ UFR-COLLAB-020로 변경<br> - 프로토타입 화면 목록 테이블에서 06-검증완료 행 제거<br>- **화면 번호 유지**: 다른 화면 번호는 변경하지 않음 (프로토타입 파일명 유지)<br> - 07-회의종료, 09-Todo관리, 10-회의록상세조회, 11-회의록수정, 12-회의록목록조회 번호 유지<br>- **변경 이력**: 과거 버전의 UFR-COLLAB-030 언급은 역사적 맥락으로 유지 |
|
||||||
| 1.4.16 | 2025-10-24 | 이미준 | 사용자 역할 용어 통일 (유저스토리 v2.1.2 반영)<br>- **용어 정의 명확화**: "회의 생성자"와 "회의 참석자" 용어로 통일<br> - 설계 목표: "회의록 작성자" → "회의 참석자"로 수정<br>- **화면별 권한 정보 추가**:<br> - 03-회의예약: 모든 사용자 (예약 생성 시 자동으로 회의 생성자가 됨)<br> - 04-템플릿선택: 회의 생성자 전용<br> - 05-회의진행: 회의 시작/종료는 회의 생성자 전용, 회의록 편집은 모든 참석자<br> - 07-회의종료: 회의 생성자 전용<br> - 09-Todo관리: 모든 회의 참석자 (본인이 담당자인 Todo만 조회/수정 가능)<br> - 10-회의록상세조회: 모든 회의 참석자 (조회 전용)<br> - 11-회의록수정: 검증완료 전(모든 참석자), 검증완료 후(회의 생성자만) - 기존 권한 제어 유지<br> - 12-회의록목록조회: 모든 회의 참석자 (본인이 참석한 회의록만 조회)<br>- **스타일 가이드 동기화**: design/uiux/style-guide.md v1.2.5 (용어 정의 섹션 추가)<br>- **통일성 달성**: 유저스토리, 화면설계서, 스타일 가이드 간 용어 완전 통일 |
|
| 1.4.16 | 2025-10-24 | 이미준 | 사용자 역할 용어 통일 (유저스토리 v2.1.2 반영)<br>- **용어 정의 명확화**: "회의 생성자"와 "회의 참석자" 용어로 통일<br> - 설계 목표: "회의록 작성자" → "회의 참석자"로 수정<br>- **화면별 권한 정보 추가**:<br> - 03-회의예약: 모든 사용자 (예약 생성 시 자동으로 회의 생성자가 됨)<br> - 04-템플릿선택: 회의 생성자 전용<br> - 05-회의진행: 회의 시작/종료는 회의 생성자 전용, 회의록 편집은 모든 참석자<br> - 07-회의종료: 회의 생성자 전용<br> - 09-Todo관리: 모든 회의 참석자 (본인이 담당자인 Todo만 조회/수정 가능)<br> - 10-회의록상세조회: 모든 회의 참석자 (조회 전용)<br> - 11-회의록수정: 검증완료 전(모든 참석자), 검증완료 후(회의 생성자만) - 기존 권한 제어 유지<br> - 12-회의록목록조회: 모든 회의 참석자 (본인이 참석한 회의록만 조회)<br>- **스타일 가이드 동기화**: design/uiux/style-guide.md v1.2.5 (용어 정의 섹션 추가)<br>- **통일성 달성**: 유저스토리, 화면설계서, 스타일 가이드 간 용어 완전 통일 |
|
||||||
|
| 1.4.17 | 2025-10-24 | 강지수 | 10-회의록상세조회 화면 용어 통일 (섹션 → 안건)<br>- **용어 변경 (요구사항설계검토-report-V1.2.md 반영)**:<br> - 모든 "섹션별" → "안건별"로 용어 통일<br> - 주요 기능, UI 구성요소, 인터랙션, 데이터 요구사항, 에러 처리 섹션 전체 업데이트<br>- **CSS 클래스명 변경 (공통 스타일 + 프로토타입)**:<br> - common.css: `.section` → `.agenda`, `.section-header` → `.agenda-header`, `.section-title` → `.agenda-title`, `.section-content` → `.agenda-content`<br> - 10-회의록상세조회.html: 모든 section 클래스를 agenda 클래스로 일괄 변경<br>- **HTML 주석 업데이트**: "회의록 섹션" → "회의록 안건", "섹션 내용" → "안건 내용"<br>- **일관성 달성**: 유저스토리 v2.1.2의 안건 기반 구조와 완전히 일치 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -2145,3 +2152,5 @@ graph TD
|
|||||||
- 타이포그래피
|
- 타이포그래피
|
||||||
- 컴포넌트 라이브러리
|
- 컴포넌트 라이브러리
|
||||||
- 아이콘 세트
|
- 아이콘 세트
|
||||||
|
| 1.4.17 | 2025-10-24 | 강지수 | 07-회의종료 화면 STT 한계 반영 (유저스토리 v2.1.2)<br>- **STT 화자 식별 불가 반영**: STT는 화자를 식별할 수 없으므로 화자 관련 기능 제거<br> - 발언 통계 섹션 삭제<br> - 안건별 "발언자별 의견" 섹션 삭제<br>- **통계 영역 디자인 개선**: 정보성 디자인으로 명확화<br> - 배경색: var(--white) → var(--gray-50)<br> - 숫자 색상: var(--primary) → var(--gray-900)<br> - 라벨 색상: var(--gray-500) → var(--gray-600)<br> - 정보 표시 전용으로 시각적 구분 명확화<br>- **안건 섹션 구분 개선**:<br> - 안건 간 하단 보더 추가 (1px solid var(--gray-200))<br> - 섹션 제목에 primary 색상 세로 바 추가 (::before pseudo-element)<br> - 콘텐츠 영역 좌측 패딩 추가로 계층 구조 명확화<br>- **연관 문서 업데이트**:<br> - 유저스토리 UFR-MEET-040: "발언 횟수 (화자별)" 항목 제거<br> - UI/UX 설계서 07-회의종료: 발언 통계 및 발언자별 의견 항목 제거 |
|
||||||
|
| 1.4.18 | 2025-10-24 | 강지수 | 05-회의진행 실시간 주요 메모 추천 기능 명확화 (유저스토리 v2.1.1)<br>- **AI 제안 탭 기능 상세화**: 실시간 주요 메모 추천 기능 명시 추가<br> - UFR-MEET-030: 실시간 AI 주요 메모 추천<br> - 음성→텍스트 변환 후 AI가 실시간 분석<br> - **중요한 내용으로 판단된 경우에만** 주요 메모 항목 추천<br> - 추천 빈도는 중요 내용 발생에 따라 가변적 (3-5초 고정 간격 아님)<br> - 각 추천 항목에 "주요 메모에 추가" 버튼 제공<br> - 실시간 업데이트: 새로운 추천은 상단에 표시<br>- **프로토타입 확인**: 05-회의진행.html의 AI 제안 탭이 실시간 주요 메모 추천 기능을 포함하고 있음을 확인<br>- **참조**: design/uiux/요구사항설계검토-report-V1.2.md (실시간 주요 메모 추천 명시 부족 개선) |
|
||||||
|
|||||||
@ -216,7 +216,6 @@ UFR-MEET-040: [회의종료] 회의 생성자로서 | 나는, 회의를 종료
|
|||||||
- 회의 통계 자동 생성
|
- 회의 통계 자동 생성
|
||||||
- 회의 총 시간
|
- 회의 총 시간
|
||||||
- 참석자 수
|
- 참석자 수
|
||||||
- 발언 횟수 (화자별)
|
|
||||||
- 주요 키워드
|
- 주요 키워드
|
||||||
|
|
||||||
[처리 결과]
|
[처리 결과]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user