mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-06-13 08:19:10 +00:00
Merge branch 'main' into feature/stt-ai - 로그 파일 충돌 해결
This commit is contained in:
@@ -150,6 +150,7 @@
|
||||
}
|
||||
|
||||
/* 회의 카드 */
|
||||
/* 최근 회의는 최대 3개만 표시하므로 3열로 제한 */
|
||||
.meeting-grid {
|
||||
display: grid;
|
||||
gap: var(--space-md);
|
||||
@@ -168,12 +169,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
.meeting-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.meeting-card {
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-lg);
|
||||
@@ -238,7 +233,7 @@
|
||||
|
||||
/* Todo 카드 스타일은 common.css에서 공통 관리 */
|
||||
|
||||
/* 통계 영역 - 정보 표시용 (클릭 불가) */
|
||||
/* 통계 영역 - 정보 표시용 (클릭 불가) - UFR-USER-020: 2개 항목 표시 */
|
||||
.stats-overview {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@@ -513,15 +508,12 @@
|
||||
<div class="sidebar-logo-text">회의록 서비스</div>
|
||||
</a>
|
||||
|
||||
<!-- MVP 스코프 축소: Todo 관리 메뉴 제거 -->
|
||||
<nav class="sidebar-nav">
|
||||
<a href="12-회의록목록조회.html" class="sidebar-nav-item">
|
||||
<span class="sidebar-nav-icon"><img src="img/edit.png" width="32"></span>
|
||||
<span>회의록</span>
|
||||
</a>
|
||||
<a href="09-Todo관리.html" class="sidebar-nav-item">
|
||||
<span class="sidebar-nav-icon"><img src="img/list.png" width="32"></span>
|
||||
<span>Todo 관리</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- 사용자 정보 영역 (Desktop) -->
|
||||
@@ -559,7 +551,7 @@
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
|
||||
<!-- 통계 개요 -->
|
||||
<!-- 통계 개요 (UFR-USER-020) -->
|
||||
<div class="stats-overview">
|
||||
<div class="stat-box stat-meeting">
|
||||
<div class="stat-icon">📅</div>
|
||||
@@ -567,9 +559,9 @@
|
||||
<div class="stat-text">예정된 회의</div>
|
||||
</div>
|
||||
<div class="stat-box stat-todo">
|
||||
<div class="stat-icon">✅</div>
|
||||
<div class="stat-number" id="stat-todos">0</div>
|
||||
<div class="stat-text">나의 Todo</div>
|
||||
<div class="stat-icon">📝</div>
|
||||
<div class="stat-number" id="stat-drafts">0</div>
|
||||
<div class="stat-text">작성중 회의록</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -583,16 +575,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 나의 Todo -->
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">나의 Todo</h2>
|
||||
<a href="09-Todo관리.html" class="section-link">전체 보기 →</a>
|
||||
</div>
|
||||
<div class="todo-list" id="my-todos">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</section>
|
||||
<!-- MVP 스코프 축소: "나의 Todo" 섹션 제거 -->
|
||||
|
||||
<!-- 나의 회의록 -->
|
||||
<section>
|
||||
@@ -607,7 +590,7 @@
|
||||
|
||||
</main>
|
||||
|
||||
<!-- 하단 네비게이션 (모바일) -->
|
||||
<!-- 하단 네비게이션 (모바일) - MVP 스코프 축소: Todo 관리 메뉴 제거 -->
|
||||
<nav class="bottom-nav">
|
||||
<a href="02-대시보드.html" class="nav-item active">
|
||||
<img src="img/home.png" alt="홈" style="width: 45px;">
|
||||
@@ -615,9 +598,6 @@
|
||||
<a href="12-회의록목록조회.html" class="nav-item">
|
||||
<img src="img/edit.png" alt="회의록" style="width: 45px;">
|
||||
</a>
|
||||
<a href="09-Todo관리.html" class="nav-item">
|
||||
<img src="img/list.png" alt="Todo" style="width: 45px;">
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- FAB 오버레이 -->
|
||||
@@ -704,8 +684,17 @@
|
||||
const statusInfo = getMeetingStatusInfo(meeting);
|
||||
const isCreator = meeting.participants.some(p => p.id === currentUser.id && p.role === 'creator');
|
||||
|
||||
// 버튼 표시 규칙
|
||||
// - ongoing: 참여하기 버튼 표시
|
||||
// - scheduled: 버튼 없음 (카드 클릭으로 수정 화면 이동)
|
||||
// - draft/complete: 버튼 없음 (카드 클릭으로 상세조회 이동)
|
||||
let actionButton = '';
|
||||
if (meeting.status === 'ongoing') {
|
||||
actionButton = `<button class="btn btn-primary btn-sm" onclick="navigateTo('05-회의진행.html'); event.stopPropagation();">참여하기</button>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="meeting-card ${meeting.status === 'ongoing' ? 'ongoing' : ''}" data-id="${meeting.id}">
|
||||
<div class="meeting-card ${meeting.status === 'ongoing' ? 'ongoing' : ''}" data-id="${meeting.id}" data-status="${meeting.status}">
|
||||
<div class="meeting-card-header">
|
||||
${createBadge(statusInfo.badgeText, statusInfo.badgeType)}
|
||||
<h3 class="meeting-card-title">${meeting.title}${isCreator ? ' <span style="font-size: 16px;" title="생성자">👑</span>' : ''}</h3>
|
||||
@@ -714,14 +703,7 @@
|
||||
<div class="meeting-card-meta-item">📅 ${formatDate(meeting.date)} ${formatTime(meeting.time)} 👥 ${meeting.participants.length}명</div>
|
||||
<div class="meeting-card-meta-item">📍 ${meeting.location}</div>
|
||||
</div>
|
||||
<div class="meeting-card-actions">
|
||||
${meeting.status === 'ongoing'
|
||||
? `<button class="btn btn-primary btn-sm" onclick="navigateTo('05-회의진행.html'); event.stopPropagation();">참여하기</button>`
|
||||
: meeting.status === 'scheduled' && isCreator
|
||||
? `<button class="btn btn-secondary btn-sm" onclick="navigateTo('03-회의예약.html'); event.stopPropagation();">수정</button>`
|
||||
: `<button class="btn btn-ghost btn-sm" onclick="navigateTo('10-회의록상세조회.html'); event.stopPropagation();">보기</button>`
|
||||
}
|
||||
</div>
|
||||
${actionButton ? `<div class="meeting-card-actions">${actionButton}</div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
@@ -731,12 +713,14 @@
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.tagName !== 'BUTTON') {
|
||||
const meetingId = card.dataset.id;
|
||||
const meeting = SAMPLE_MEETINGS.find(m => m.id === meetingId);
|
||||
if (meeting.status === 'ongoing') {
|
||||
const meetingStatus = card.dataset.status;
|
||||
|
||||
// 상태에 따른 이동 처리
|
||||
if (meetingStatus === 'ongoing') {
|
||||
navigateTo('05-회의진행.html');
|
||||
} else if (meeting.status === 'completed') {
|
||||
} else if (meetingStatus === 'draft' || meetingStatus === 'complete' || meetingStatus === 'completed') {
|
||||
navigateTo('10-회의록상세조회.html');
|
||||
} else {
|
||||
} else if (meetingStatus === 'scheduled') {
|
||||
navigateTo('03-회의예약.html');
|
||||
}
|
||||
}
|
||||
@@ -745,104 +729,9 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* 내 Todo 렌더링 (09-Todo관리.html과 동일한 정렬 기준)
|
||||
* MVP 스코프 축소: renderMyTodos() 함수 제거됨
|
||||
* 대시보드에서 Todo 위젯이 제거되어 더 이상 사용되지 않음
|
||||
*/
|
||||
function renderMyTodos() {
|
||||
const container = $('#my-todos');
|
||||
|
||||
const myTodos = SAMPLE_TODOS
|
||||
.filter(todo => todo.assignee.id === currentUser.id)
|
||||
.sort((a, b) => {
|
||||
// 09-Todo관리.html과 동일한 정렬: 완료되지 않은 것 우선, 마감일 순
|
||||
if (a.status === 'completed' && b.status !== 'completed') return 1;
|
||||
if (a.status !== 'completed' && b.status === 'completed') return -1;
|
||||
return new Date(a.dueDate) - new Date(b.dueDate);
|
||||
})
|
||||
.slice(0, 3); // 상위 3개만 표시
|
||||
|
||||
if (myTodos.length === 0) {
|
||||
container.innerHTML = '<div class="empty-state"><div class="empty-icon">✅</div><p>할당된 Todo가 없습니다</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = myTodos.map(todo => {
|
||||
const dday = calculateDday(todo.dueDate);
|
||||
const isCompleted = todo.status === 'completed';
|
||||
const isOverdue = dday < 0 && !isCompleted;
|
||||
|
||||
// D-day 배지
|
||||
let ddayBadge = '';
|
||||
let ddayClass = '';
|
||||
if (isCompleted) {
|
||||
ddayBadge = '완료';
|
||||
ddayClass = 'badge-complete';
|
||||
} else if (isOverdue) {
|
||||
ddayBadge = `D+${Math.abs(dday)} (지연)`;
|
||||
ddayClass = 'badge-overdue';
|
||||
} else if (dday === 0) {
|
||||
ddayBadge = 'D-DAY';
|
||||
ddayClass = 'badge-warning';
|
||||
} else if (dday <= 3) {
|
||||
ddayBadge = `D-${dday}`;
|
||||
ddayClass = 'badge-warning';
|
||||
} else if (dday <= 7) {
|
||||
ddayBadge = `D-${dday}`;
|
||||
ddayClass = 'badge-primary';
|
||||
} else {
|
||||
ddayBadge = `D-${dday}`;
|
||||
ddayClass = 'badge-secondary';
|
||||
}
|
||||
|
||||
// 우선순위 배지
|
||||
const priorityText = todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음';
|
||||
const priorityClass = `badge-${todo.priority}`;
|
||||
|
||||
return `
|
||||
<div class="todo-card ${isCompleted ? 'completed' : ''}" data-todo-id="${todo.id}" data-meeting-id="${todo.meetingId}">
|
||||
<div class="todo-top">
|
||||
<div class="todo-checkbox-wrapper">
|
||||
<input type="checkbox" class="todo-checkbox" id="check-${todo.id}"
|
||||
${isCompleted ? 'checked' : ''}
|
||||
onchange="toggleTodoComplete('${todo.id}', this.checked)">
|
||||
</div>
|
||||
<div class="todo-content-wrapper">
|
||||
<div class="todo-badges">
|
||||
<span class="badge ${ddayClass}">${ddayBadge}</span>
|
||||
<span class="badge ${priorityClass}">${priorityText}</span>
|
||||
</div>
|
||||
<div class="todo-title">${todo.title}</div>
|
||||
<div class="todo-meta-row">
|
||||
<a class="todo-meeting-link" onclick="navigateTo('10-회의록상세조회.html'); event.stopPropagation();">
|
||||
🔗 ${todo.meetingTitle}
|
||||
</a>
|
||||
<span>${formatDate(todo.dueDate)}</span>
|
||||
</div>
|
||||
</div>
|
||||
${!isCompleted ? `
|
||||
<div class="todo-actions">
|
||||
<button class="icon-btn" onclick="editTodo('${todo.id}')" title="편집">✏️</button>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
// Todo 카드 클릭 시 해당 회의록 상세로 이동 (체크박스와 버튼 제외)
|
||||
$$('.todo-card').forEach(card => {
|
||||
card.addEventListener('click', (e) => {
|
||||
// 체크박스나 버튼 클릭은 무시
|
||||
if (e.target.classList.contains('todo-checkbox') ||
|
||||
e.target.classList.contains('icon-btn') ||
|
||||
e.target.closest('.icon-btn')) {
|
||||
return;
|
||||
}
|
||||
const meetingId = card.dataset.meetingId;
|
||||
const todoId = card.dataset.todoId;
|
||||
navigateTo(`10-회의록상세조회.html?meetingId=${meetingId}&todoId=${todoId}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 나의 회의록 렌더링 (참여자 또는 생성자로 등록된 회의록, 최신순 정렬)
|
||||
@@ -887,31 +776,33 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* 통계 업데이트
|
||||
* 통계 업데이트 (UFR-USER-020)
|
||||
*/
|
||||
function updateStats() {
|
||||
// 예정된 회의 개수 (예정 + 진행중)
|
||||
const scheduled = SAMPLE_MEETINGS.filter(m => m.status === 'scheduled' || m.status === 'ongoing').length;
|
||||
|
||||
// 나의 Todo 개수 (전체)
|
||||
const myTodos = SAMPLE_TODOS.filter(t => t.assignee.id === currentUser.id).length;
|
||||
// 작성중 회의록 개수 (내가 참석한 회의 중 '작성중' 상태)
|
||||
const drafts = SAMPLE_MINUTES.filter(m =>
|
||||
m.status === 'draft' &&
|
||||
m.participants.some(p => p.id === currentUser.id)
|
||||
).length;
|
||||
|
||||
$('#stat-scheduled').textContent = scheduled;
|
||||
$('#stat-todos').textContent = myTodos;
|
||||
$('#stat-drafts').textContent = drafts;
|
||||
}
|
||||
|
||||
/**
|
||||
* 초기화
|
||||
* 초기화 - MVP 스코프 축소: renderMyTodos() 제거
|
||||
*/
|
||||
function init() {
|
||||
renderSidebarUser();
|
||||
renderHeader();
|
||||
updateStats();
|
||||
renderRecentMeetings();
|
||||
renderMyTodos();
|
||||
renderMyMinutes();
|
||||
|
||||
console.log('대시보드 초기화 완료');
|
||||
console.log('대시보드 초기화 완료 (MVP 스코프 축소)');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1002,48 +893,11 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 완료 토글
|
||||
* @param {string} todoId - Todo ID
|
||||
* @param {boolean} isChecked - 체크박스 상태
|
||||
* MVP 스코프 축소: Todo 관련 함수 제거됨
|
||||
* - toggleTodoComplete()
|
||||
* - editTodo()
|
||||
* 대시보드에서 Todo 위젯이 제거되어 더 이상 사용되지 않음
|
||||
*/
|
||||
function toggleTodoComplete(todoId, isChecked) {
|
||||
if (isChecked) {
|
||||
// 완료 처리
|
||||
if (confirm('완료 처리하시겠습니까?')) {
|
||||
const todo = SAMPLE_TODOS.find(t => t.id === todoId);
|
||||
if (todo) {
|
||||
todo.status = 'completed';
|
||||
showToast('Todo가 완료되었습니다', 'success');
|
||||
updateStats();
|
||||
renderMyTodos();
|
||||
}
|
||||
} else {
|
||||
event.target.checked = false;
|
||||
}
|
||||
} else {
|
||||
// 미완료로 되돌리기
|
||||
if (confirm('미완료로 변경하시겠습니까?')) {
|
||||
const todo = SAMPLE_TODOS.find(t => t.id === todoId);
|
||||
if (todo) {
|
||||
todo.status = 'incomplete';
|
||||
showToast('미완료로 변경되었습니다', 'info');
|
||||
updateStats();
|
||||
renderMyTodos();
|
||||
}
|
||||
} else {
|
||||
event.target.checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 편집 (간이 버전 - 09-Todo관리.html로 이동)
|
||||
* @param {string} todoId - Todo ID
|
||||
*/
|
||||
function editTodo(todoId) {
|
||||
// Todo 관리 화면으로 이동하여 편집
|
||||
navigateTo(`09-Todo관리.html?todoId=${todoId}`);
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
|
||||
.meeting-title {
|
||||
font-size: var(--font-large);
|
||||
font-size: var(--font-h2);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--gray-800);
|
||||
margin: 0;
|
||||
@@ -100,7 +100,7 @@
|
||||
}
|
||||
|
||||
.recording-time {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
@@ -173,9 +173,9 @@
|
||||
.info-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-xs) 0;
|
||||
align-items: flex-start;
|
||||
gap: 0;
|
||||
padding: var(--space-sm) 0;
|
||||
border-bottom: 1px solid var(--gray-300);
|
||||
}
|
||||
|
||||
@@ -186,14 +186,28 @@
|
||||
.info-label {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-600);
|
||||
font-size: var(--font-caption);
|
||||
min-width: 60px;
|
||||
font-size: var(--font-small);
|
||||
width: 70px;
|
||||
min-width: 70px;
|
||||
max-width: 70px;
|
||||
flex-shrink: 0;
|
||||
padding-right: var(--space-sm);
|
||||
border-right: 1px solid var(--gray-300);
|
||||
margin-right: var(--space-sm);
|
||||
}
|
||||
|
||||
/* 데스크톱에서 라벨 폭 확장 */
|
||||
@media (min-width: 768px) {
|
||||
.info-label {
|
||||
width: 100px;
|
||||
min-width: 100px;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: var(--gray-800);
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
line-height: 1.5;
|
||||
flex: 1;
|
||||
}
|
||||
@@ -229,7 +243,7 @@
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-600);
|
||||
transition: all var(--transition-fast);
|
||||
@@ -289,13 +303,13 @@
|
||||
}
|
||||
|
||||
.participant-section-title {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.participant-count {
|
||||
font-size: var(--font-caption);
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
@@ -307,13 +321,13 @@
|
||||
|
||||
.invite-input {
|
||||
flex: 1;
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.invite-btn {
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -337,13 +351,13 @@
|
||||
}
|
||||
|
||||
.participant-name {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-800);
|
||||
}
|
||||
|
||||
.participant-email {
|
||||
font-size: var(--font-caption);
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
margin-top: 2px;
|
||||
overflow: hidden;
|
||||
@@ -351,7 +365,7 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* AI 제안 탭 */
|
||||
/* AI 기반 메모 탭 - MVP 스코프 축소 v1.5.1 */
|
||||
.memo-input-section {
|
||||
background: var(--gray-50);
|
||||
border-radius: var(--radius-md);
|
||||
@@ -360,7 +374,7 @@
|
||||
}
|
||||
|
||||
.memo-input-label {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-700);
|
||||
margin-bottom: var(--space-xs);
|
||||
@@ -373,7 +387,7 @@
|
||||
padding: var(--space-sm);
|
||||
border: 1px solid var(--gray-300);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-family: inherit;
|
||||
resize: vertical;
|
||||
line-height: 1.5;
|
||||
@@ -388,17 +402,17 @@
|
||||
width: 100%;
|
||||
margin-top: var(--space-xs);
|
||||
padding: var(--space-sm);
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
}
|
||||
|
||||
.ai-suggestion-list-title {
|
||||
font-size: var(--font-body);
|
||||
font-size: var(--font-h3);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--gray-900);
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
/* AI 제안 카드 */
|
||||
/* AI 주요 내용 카드 */
|
||||
.ai-suggestion-card {
|
||||
background: #FAFAFA;
|
||||
border: 1px dashed #D0D0D0;
|
||||
@@ -416,7 +430,7 @@
|
||||
}
|
||||
|
||||
.ai-suggestion-time {
|
||||
font-size: var(--font-caption);
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
font-weight: var(--font-weight-regular);
|
||||
}
|
||||
@@ -446,7 +460,7 @@
|
||||
}
|
||||
|
||||
.ai-suggestion-text {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
color: var(--gray-700);
|
||||
line-height: 1.5;
|
||||
}
|
||||
@@ -460,13 +474,13 @@
|
||||
|
||||
.term-search-input {
|
||||
flex: 1;
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.term-search-btn {
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -493,7 +507,7 @@
|
||||
}
|
||||
|
||||
.term-name {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--primary);
|
||||
display: flex;
|
||||
@@ -512,14 +526,14 @@
|
||||
}
|
||||
|
||||
.term-definition {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
color: var(--gray-700);
|
||||
line-height: 1.5;
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.term-context {
|
||||
font-size: 11px;
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
padding-top: var(--space-xs);
|
||||
border-top: 1px dashed #D0D0D0;
|
||||
@@ -546,7 +560,7 @@
|
||||
}
|
||||
|
||||
.related-doc-title {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--primary);
|
||||
margin-bottom: var(--space-xs);
|
||||
@@ -555,7 +569,7 @@
|
||||
.related-doc-meta {
|
||||
display: flex;
|
||||
gap: var(--space-xs);
|
||||
font-size: var(--font-caption);
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-600);
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
@@ -566,7 +580,7 @@
|
||||
}
|
||||
|
||||
.related-doc-text {
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
color: var(--gray-700);
|
||||
line-height: 1.5;
|
||||
}
|
||||
@@ -668,7 +682,7 @@
|
||||
참석자
|
||||
</button>
|
||||
<button class="tab-button" onclick="switchTab('ai-suggestions')">
|
||||
AI 제안
|
||||
AI 메모
|
||||
</button>
|
||||
<button class="tab-button" onclick="switchTab('terms')">
|
||||
용어사전
|
||||
@@ -732,7 +746,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI 제안 탭 -->
|
||||
<!-- AI 기반 메모 탭 (MVP 스코프 축소 v1.5.1) -->
|
||||
<div class="tab-content" id="tab-ai-suggestions">
|
||||
<div class="memo-input-section">
|
||||
<label class="memo-input-label">📝 회의 메모</label>
|
||||
@@ -1053,7 +1067,7 @@
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||
}
|
||||
|
||||
// AI 제안을 메모에 추가
|
||||
// AI가 감지한 주요 내용을 메모에 추가 (MVP 스코프 축소 v1.5.1)
|
||||
function addToMemo(suggestionText, cardElement) {
|
||||
const memoTextarea = document.getElementById('meetingMemo');
|
||||
const currentMemo = memoTextarea.value;
|
||||
@@ -1062,7 +1076,7 @@
|
||||
const recordingTime = document.getElementById('recordingTime').textContent;
|
||||
const timePrefix = '[' + recordingTime.substring(0, 5) + '] '; // HH:MM만 추출
|
||||
|
||||
// 시간 정보 + 제안 내용
|
||||
// 시간 정보 + 주요 내용
|
||||
const memoWithTime = timePrefix + suggestionText;
|
||||
|
||||
if (currentMemo) {
|
||||
@@ -1071,7 +1085,7 @@
|
||||
memoTextarea.value = memoWithTime;
|
||||
}
|
||||
|
||||
// AI 제안 카드 삭제
|
||||
// AI 주요 내용 카드 삭제 (선택 후 제거)
|
||||
if (cardElement) {
|
||||
cardElement.remove();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -107,11 +107,41 @@
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
/* 회의 제목 컨테이너 */
|
||||
.meeting-title-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
/* 배지 영역 (배지 + 크라운) */
|
||||
.meeting-badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
/* 회의 제목 */
|
||||
.meeting-basic-info h2 {
|
||||
font-size: var(--font-h2);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--gray-900);
|
||||
margin-bottom: var(--space-sm);
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* 데스크톱: 기존 가로 배치 유지 */
|
||||
@media (min-width: 768px) {
|
||||
.meeting-title-container {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.meeting-basic-info h2 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.info-row {
|
||||
@@ -165,23 +195,6 @@
|
||||
.participant {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 회의록 섹션 */
|
||||
@@ -279,22 +292,6 @@
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
.reference-item {
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-sm);
|
||||
margin-bottom: var(--space-sm);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.reference-item:hover {
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.reference-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.reference-header {
|
||||
display: flex;
|
||||
@@ -310,7 +307,7 @@
|
||||
|
||||
.reference-title {
|
||||
flex: 1;
|
||||
font-size: var(--font-small);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-900);
|
||||
}
|
||||
@@ -338,7 +335,7 @@
|
||||
}
|
||||
|
||||
.reference-meta {
|
||||
font-size: var(--font-caption);
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
@@ -405,10 +402,11 @@
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
/* 통계 그리드 - 모바일 기본 (2x2) */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: var(--space-md);
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--space-sm);
|
||||
margin-top: var(--space-md);
|
||||
}
|
||||
|
||||
@@ -431,6 +429,14 @@
|
||||
color: var(--gray-500);
|
||||
}
|
||||
|
||||
/* 데스크톱: 1x4 그리드 */
|
||||
@media (min-width: 768px) {
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: var(--space-md);
|
||||
}
|
||||
}
|
||||
|
||||
/* 결정사항 카드 */
|
||||
.decision-card {
|
||||
background: var(--white);
|
||||
@@ -462,7 +468,7 @@
|
||||
border-top: 1px solid var(--gray-300);
|
||||
}
|
||||
|
||||
/* Todo 진행상황 */
|
||||
/* Todo 리스트 */
|
||||
.todo-filters {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
@@ -523,7 +529,64 @@
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
/* Todo 진행상황 - 09-Todo관리 스타일 적용 */
|
||||
/* Todo 리스트 - 단순 조회 스타일 */
|
||||
.simple-todo-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.simple-todo-item {
|
||||
position: relative;
|
||||
padding: var(--space-md);
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--gray-300);
|
||||
}
|
||||
|
||||
.simple-todo-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: var(--space-sm);
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.simple-todo-title {
|
||||
flex: 1;
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-900);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.simple-todo-edit-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
color: var(--gray-500);
|
||||
transition: all var(--transition-fast);
|
||||
flex-shrink: 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.simple-todo-edit-btn:hover {
|
||||
color: var(--primary);
|
||||
background: var(--primary-light);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.simple-todo-meta {
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-600);
|
||||
display: flex;
|
||||
gap: var(--space-md);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Todo 리스트 - 09-Todo관리 스타일 적용 */
|
||||
.todo-filters {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
@@ -688,6 +751,24 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 대시보드 탭의 관련회의록 카드 스타일 강화 */
|
||||
.card .reference-item {
|
||||
border: 1px solid var(--gray-200) !important;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08) !important;
|
||||
margin-bottom: var(--space-sm) !important;
|
||||
}
|
||||
|
||||
.card .reference-item:hover {
|
||||
border-color: var(--primary) !important;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12) !important;
|
||||
transform: translateY(-1px) !important;
|
||||
}
|
||||
|
||||
.card .reference-item:active {
|
||||
transform: translateY(0) !important;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08) !important;
|
||||
}
|
||||
|
||||
/* 모바일 화면에서 관련회의록 왼쪽 정렬 */
|
||||
@media (max-width: 600px) {
|
||||
.reference-item {
|
||||
@@ -738,10 +819,14 @@
|
||||
<!-- 기본 정보 카드 -->
|
||||
<div class="info-card">
|
||||
<div class="meeting-basic-info">
|
||||
<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 class="meeting-title-container">
|
||||
<!-- 배지 + 크라운 영역 -->
|
||||
<div class="meeting-badges" id="meeting-badges">
|
||||
<span class="badge badge-complete">확정완료</span>
|
||||
<!-- 생성자일 경우 👑 아이콘이 JavaScript로 추가됨 -->
|
||||
</div>
|
||||
<!-- 회의 제목 -->
|
||||
<h2>2025년 1분기 제품 기획 회의</h2>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-icon">📅</span>
|
||||
@@ -757,7 +842,7 @@
|
||||
<div class="participant">
|
||||
<div class="avatar avatar-green">김</div>
|
||||
<span class="participant-name">김민준</span>
|
||||
<span class="role-badge">작성자</span>
|
||||
<span class="role-badge">생성자</span>
|
||||
</div>
|
||||
<div class="participant">
|
||||
<div class="avatar avatar-blue">박</div>
|
||||
@@ -1042,148 +1127,70 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Todo 진행상황 -->
|
||||
<!-- Todo 단순 조회 (MVP 스코프 축소 v1.5.1) -->
|
||||
<div class="card mb-lg">
|
||||
<h3 class="card-title">📋 Todo 진행상황</h3>
|
||||
|
||||
<!-- 전체 진행률 -->
|
||||
<div style="margin-bottom: var(--space-lg);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--space-xs);">
|
||||
<span style="font-size: var(--font-body); font-weight: var(--font-weight-medium); color: var(--gray-900);">전체 진행률</span>
|
||||
<span style="font-size: var(--font-body); font-weight: var(--font-weight-bold); color: var(--primary);">40%</span>
|
||||
</div>
|
||||
<div style="width: 100%; height: 8px; background: var(--gray-200); border: 1px solid var(--gray-300); border-radius: 4px; overflow: hidden;">
|
||||
<div style="width: 40%; height: 100%; background: var(--primary); transition: width 0.3s ease;"></div>
|
||||
</div>
|
||||
<div style="font-size: var(--font-caption); color: var(--gray-600); margin-top: var(--space-xs);">
|
||||
2 / 5 완료
|
||||
</div>
|
||||
<div class="section-header">
|
||||
<h3 class="card-title">📋 Todo 리스트</h3>
|
||||
<button class="btn btn-primary btn-sm" onclick="openModal('addTodoModal')">추가</button>
|
||||
</div>
|
||||
<p style="font-size: var(--font-small); color: var(--gray-600); margin-bottom: var(--space-md);">
|
||||
Todo 항목은 조회만 가능합니다. 제목, 담당자, 마감일 정보만 표시됩니다.
|
||||
</p>
|
||||
|
||||
<div class="todo-filters">
|
||||
<button class="filter-btn active" data-filter="all" onclick="filterTodos('all')">
|
||||
전체 (<span id="filterAllCount">5</span>)
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="overdue" onclick="filterTodos('overdue')">
|
||||
지연 (<span id="filterOverdueCount">1</span>)
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="urgent" onclick="filterTodos('urgent')">
|
||||
마감 임박 (<span id="filterUrgentCount">2</span>)
|
||||
</button>
|
||||
<button class="filter-btn" data-filter="completed" onclick="filterTodos('completed')">
|
||||
완료 (<span id="filterCompletedCount">2</span>)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Todo 카드 리스트 -->
|
||||
<div class="todo-card">
|
||||
<div class="todo-top">
|
||||
<div class="todo-checkbox-wrapper">
|
||||
<input type="checkbox" class="todo-checkbox" id="check-todo-002"
|
||||
onchange="toggleTodoComplete('todo-002', this.checked)">
|
||||
<!-- Todo 단순 조회 리스트 (제목 + 담당자 + 마감일 + 수정 버튼) -->
|
||||
<div class="simple-todo-list">
|
||||
<div class="simple-todo-item">
|
||||
<div class="simple-todo-header">
|
||||
<div class="simple-todo-title">데이터베이스 스키마 설계</div>
|
||||
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(1)" title="수정">✏️</button>
|
||||
</div>
|
||||
<div class="todo-content-wrapper">
|
||||
<div class="todo-badges">
|
||||
<span class="badge badge-overdue">D+1 (지연)</span>
|
||||
<span class="badge badge-high">높음</span>
|
||||
</div>
|
||||
<div class="todo-title">데이터베이스 스키마 설계</div>
|
||||
<div class="todo-meta-row">
|
||||
<span>담당자: 이준호</span>
|
||||
<span>2025-10-20 마감</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="todo-actions">
|
||||
<button class="icon-btn" onclick="editTodo('todo-002')" title="편집">✏️</button>
|
||||
<div class="simple-todo-meta">
|
||||
<span>👤 이준호</span>
|
||||
<span>📅 2025-10-20</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="todo-card">
|
||||
<div class="todo-top">
|
||||
<div class="todo-checkbox-wrapper">
|
||||
<input type="checkbox" class="todo-checkbox" id="check-todo-001"
|
||||
onchange="toggleTodoComplete('todo-001', this.checked)">
|
||||
<div class="simple-todo-item">
|
||||
<div class="simple-todo-header">
|
||||
<div class="simple-todo-title">API 명세서 작성</div>
|
||||
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(2)" title="수정">✏️</button>
|
||||
</div>
|
||||
<div class="todo-content-wrapper">
|
||||
<div class="todo-badges">
|
||||
<span class="badge badge-warning">D-2</span>
|
||||
<span class="badge badge-high">높음</span>
|
||||
</div>
|
||||
<div class="todo-title">API 명세서 작성</div>
|
||||
<div class="todo-meta-row">
|
||||
<span>담당자: 이준호</span>
|
||||
<span>2025-10-23 마감</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="todo-actions">
|
||||
<button class="icon-btn" onclick="editTodo('todo-001')" title="편집">✏️</button>
|
||||
<div class="simple-todo-meta">
|
||||
<span>👤 이준호</span>
|
||||
<span>📅 2025-10-23</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="todo-card">
|
||||
<div class="todo-top">
|
||||
<div class="todo-checkbox-wrapper">
|
||||
<input type="checkbox" class="todo-checkbox" id="check-todo-005"
|
||||
onchange="toggleTodoComplete('todo-005', this.checked)">
|
||||
<div class="simple-todo-item">
|
||||
<div class="simple-todo-header">
|
||||
<div class="simple-todo-title">예산 편성안 검토</div>
|
||||
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(3)" title="수정">✏️</button>
|
||||
</div>
|
||||
<div class="todo-content-wrapper">
|
||||
<div class="todo-badges">
|
||||
<span class="badge badge-warning">D-1</span>
|
||||
<span class="badge badge-high">높음</span>
|
||||
</div>
|
||||
<div class="todo-title">예산 편성안 검토</div>
|
||||
<div class="todo-meta-row">
|
||||
<span>담당자: 김민준</span>
|
||||
<span>2025-10-22 마감</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="todo-actions">
|
||||
<button class="icon-btn" onclick="editTodo('todo-005')" title="편집">✏️</button>
|
||||
<div class="simple-todo-meta">
|
||||
<span>👤 김민준</span>
|
||||
<span>📅 2025-10-22</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="todo-card">
|
||||
<div class="todo-top">
|
||||
<div class="todo-checkbox-wrapper">
|
||||
<input type="checkbox" class="todo-checkbox" id="check-todo-003"
|
||||
onchange="toggleTodoComplete('todo-003', this.checked)">
|
||||
<div class="simple-todo-item">
|
||||
<div class="simple-todo-header">
|
||||
<div class="simple-todo-title">UI 프로토타입 디자인</div>
|
||||
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(4)" title="수정">✏️</button>
|
||||
</div>
|
||||
<div class="todo-content-wrapper">
|
||||
<div class="todo-badges">
|
||||
<span class="badge badge-primary">D-7</span>
|
||||
<span class="badge badge-medium">보통</span>
|
||||
</div>
|
||||
<div class="todo-title">UI 프로토타입 디자인</div>
|
||||
<div class="todo-meta-row">
|
||||
<span>담당자: 최유진</span>
|
||||
<span>2025-10-28 마감</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="todo-actions">
|
||||
<button class="icon-btn" onclick="editTodo('todo-003')" title="편집">✏️</button>
|
||||
<div class="simple-todo-meta">
|
||||
<span>👤 최유진</span>
|
||||
<span>📅 2025-10-28</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="todo-card completed">
|
||||
<div class="todo-top">
|
||||
<div class="todo-checkbox-wrapper">
|
||||
<input type="checkbox" class="todo-checkbox" id="check-todo-004" checked
|
||||
onchange="toggleTodoComplete('todo-004', this.checked)">
|
||||
<div class="simple-todo-item">
|
||||
<div class="simple-todo-header">
|
||||
<div class="simple-todo-title">사용자 피드백 분석</div>
|
||||
<button class="simple-todo-edit-btn creator-only" onclick="editTodo(5)" title="수정">✏️</button>
|
||||
</div>
|
||||
<div class="todo-content-wrapper">
|
||||
<div class="todo-badges">
|
||||
<span class="badge badge-complete">완료</span>
|
||||
<span class="badge badge-medium">보통</span>
|
||||
</div>
|
||||
<div class="todo-title">사용자 피드백 분석</div>
|
||||
<div class="todo-meta-row">
|
||||
<span>담당자: 김민준</span>
|
||||
<span>2025-10-19 마감</span>
|
||||
</div>
|
||||
<div class="simple-todo-meta">
|
||||
<span>👤 김민준</span>
|
||||
<span>📅 2025-10-19</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1199,7 +1206,7 @@
|
||||
<span class="reference-title">AI 기능 개선 회의</span>
|
||||
<span class="relevance-badge relevance-high">92%</span>
|
||||
</div>
|
||||
<div class="reference-meta">2025-10-23 15:00 · 이준호</div>
|
||||
<div class="reference-meta">이준호 · 2025-10-23 15:00</div>
|
||||
<div class="reference-summary">
|
||||
AI 요약 정확도 개선 방안 논의. BERT 모델 도입 및 학습 데이터 확보 계획 수립.
|
||||
</div>
|
||||
@@ -1211,7 +1218,7 @@
|
||||
<span class="reference-title">개발 리소스 계획 회의</span>
|
||||
<span class="relevance-badge relevance-medium">88%</span>
|
||||
</div>
|
||||
<div class="reference-meta">2025-10-22 11:00 · 김민준</div>
|
||||
<div class="reference-meta">김민준 · 2025-10-22 11:00</div>
|
||||
<div class="reference-summary">
|
||||
Q4 개발 리소스 현황 및 배분 계획. 신규 프로젝트 우선순위 협의.
|
||||
</div>
|
||||
@@ -1223,7 +1230,7 @@
|
||||
<span class="reference-title">경쟁사 분석 회의</span>
|
||||
<span class="relevance-badge relevance-medium">78%</span>
|
||||
</div>
|
||||
<div class="reference-meta">2025-10-20 10:00 · 박서연</div>
|
||||
<div class="reference-meta">박서연 · 2025-10-20 10:00</div>
|
||||
<div class="reference-summary">
|
||||
경쟁사 A, B, C 분석 결과. 우리의 차별점은 실시간 협업 및 검증 기능.
|
||||
</div>
|
||||
@@ -1237,6 +1244,43 @@
|
||||
<button class="btn btn-secondary" onclick="navigateTo('11-회의록수정.html')">수정</button>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Todo 추가 모달 -->
|
||||
<div class="modal-overlay" id="addTodoModal">
|
||||
<div class="modal">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Todo 추가</h3>
|
||||
<button class="modal-close" onclick="closeModal('addTodoModal')">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Todo 내용 <span class="text-error">*</span></label>
|
||||
<input type="text" id="addTodoTitle" class="form-control" placeholder="할 일을 입력하세요">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">담당자 <span class="text-error">*</span></label>
|
||||
<select id="addTodoAssignee" class="form-control">
|
||||
<option value="">담당자를 선택하세요</option>
|
||||
<option value="김민준">김민준</option>
|
||||
<option value="이준호">이준호</option>
|
||||
<option value="박서연">박서연</option>
|
||||
<option value="최유진">최유진</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">마감일 <span class="text-error">*</span></label>
|
||||
<div class="date-input-wrapper">
|
||||
<input type="date" id="addTodoDueDate" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-ghost" onclick="closeModal('addTodoModal')">취소</button>
|
||||
<button class="btn btn-primary" onclick="addTodo()">추가</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Todo 편집 모달 -->
|
||||
<div class="modal-overlay" id="editTodoModal">
|
||||
<div class="modal">
|
||||
@@ -1245,6 +1289,7 @@
|
||||
<button class="modal-close" onclick="closeModal('editTodoModal')">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="editTodoId">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Todo 제목 <span class="text-error">*</span></label>
|
||||
<input type="text" id="editTodoTitle" class="form-control" placeholder="할 일을 입력하세요">
|
||||
@@ -1258,30 +1303,12 @@
|
||||
<option value="박서연">박서연</option>
|
||||
<option value="최유진">최유진</option>
|
||||
</select>
|
||||
<p class="form-hint">👤 담당자 변경 시 이전/새 담당자에게 알림이 전송됩니다</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">마감일 <span class="text-error">*</span></label>
|
||||
<div class="date-input-wrapper">
|
||||
<input type="date" id="editTodoDueDate" class="form-control">
|
||||
</div>
|
||||
<p class="form-hint">📅 마감일 변경 시 캘린더가 자동 업데이트됩니다</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">우선순위 <span class="text-error">*</span></label>
|
||||
<select id="editTodoPriority" class="form-control">
|
||||
<option value="high">높음</option>
|
||||
<option value="medium">보통</option>
|
||||
<option value="low">낮음</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- 권한 안내 (동적 메시지) -->
|
||||
<div class="alert alert-info" id="editTodoPermissionInfo">
|
||||
<span class="material-icons" style="font-size: 20px;">info</span>
|
||||
<div>
|
||||
<strong>권한 안내</strong>
|
||||
<p style="margin: 4px 0 0 0; font-size: 14px;" id="editTodoPermissionText">회의 생성자로서 모든 항목을 수정할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -1323,95 +1350,39 @@
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Todo 편집 모달 - 모바일 전체화면 */
|
||||
/* Todo 추가/편집 모달 - 바텀시트 스타일 */
|
||||
#addTodoModal .modal,
|
||||
#editTodoModal .modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
max-width: none;
|
||||
max-height: none;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#editTodoModal .modal-header {
|
||||
flex-shrink: 0;
|
||||
padding: var(--space-lg) var(--space-md);
|
||||
border-bottom: 1px solid var(--gray-200);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#editTodoModal .modal-title {
|
||||
font-size: var(--font-h3);
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#editTodoModal .modal-close {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: var(--gray-600);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
#editTodoModal .modal-close:hover {
|
||||
background: var(--gray-100);
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
#editTodoModal .modal-body {
|
||||
flex: 1;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
padding: var(--space-lg) var(--space-md);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
#addTodoModal .modal-footer,
|
||||
#editTodoModal .modal-footer {
|
||||
flex-shrink: 0;
|
||||
padding: var(--space-md);
|
||||
border-top: 1px solid var(--gray-200);
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
background: var(--white);
|
||||
justify-content: flex-end;
|
||||
margin-top: var(--space-md);
|
||||
}
|
||||
|
||||
#addTodoModal .modal-footer .btn,
|
||||
#editTodoModal .modal-footer .btn {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 데스크톱에서는 중앙 모달로 복원 */
|
||||
/* 데스크톱에서는 중앙 모달 */
|
||||
@media (min-width: 768px) {
|
||||
#addTodoModal .modal,
|
||||
#editTodoModal .modal {
|
||||
position: relative;
|
||||
top: auto;
|
||||
left: auto;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
height: auto;
|
||||
max-height: 90vh;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--radius-lg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 회의 생성자 전용 요소 숨김 */
|
||||
.creator-only.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="common.js"></script>
|
||||
@@ -1460,24 +1431,17 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 필터링 (09-Todo관리와 동일)
|
||||
* MVP 스코프 축소 v1.5.1: Todo 필터링/편집 함수 제거됨
|
||||
* Todo는 단순 조회만 가능하므로 더 이상 사용되지 않음
|
||||
*/
|
||||
|
||||
/*
|
||||
function filterTodos(filter) {
|
||||
currentFilter = filter;
|
||||
|
||||
// 탭 활성화
|
||||
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
});
|
||||
document.querySelector(`.filter-btn[data-filter="${filter}"]`).classList.add('active');
|
||||
|
||||
renderTodoList();
|
||||
// 제거됨: Todo 필터링 기능
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Todo 편집 모달 열기
|
||||
* @param {string} todoId - 편집할 Todo ID
|
||||
*/
|
||||
/*
|
||||
function editTodo(todoId) {
|
||||
const todo = meetingTodos.find(t => t.id === todoId);
|
||||
if (!todo) return;
|
||||
@@ -1610,39 +1574,13 @@
|
||||
* @param {string} todoId - Todo ID
|
||||
* @param {boolean} isChecked - 체크박스 상태
|
||||
*/
|
||||
/*
|
||||
function toggleTodoComplete(todoId, isChecked) {
|
||||
if (isChecked) {
|
||||
// 완료 처리
|
||||
if (confirm('완료 처리하시겠습니까?')) {
|
||||
const todo = meetingTodos.find(t => t.id === todoId);
|
||||
if (todo) {
|
||||
todo.status = 'completed';
|
||||
showToast('Todo가 완료되었습니다', 'success');
|
||||
updateTodoProgress();
|
||||
renderTodoList();
|
||||
}
|
||||
} else {
|
||||
event.target.checked = false;
|
||||
}
|
||||
} else {
|
||||
// 미완료로 되돌리기
|
||||
if (confirm('미완료로 변경하시겠습니까?')) {
|
||||
const todo = meetingTodos.find(t => t.id === todoId);
|
||||
if (todo) {
|
||||
todo.status = 'incomplete';
|
||||
showToast('미완료로 변경되었습니다', 'info');
|
||||
updateTodoProgress();
|
||||
renderTodoList();
|
||||
}
|
||||
} else {
|
||||
event.target.checked = true;
|
||||
}
|
||||
}
|
||||
// 제거됨: Todo 완료 토글 기능
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Todo 진행률 업데이트
|
||||
*/
|
||||
/*
|
||||
function updateTodoProgress() {
|
||||
const total = meetingTodos.length;
|
||||
const completed = meetingTodos.filter(t => t.status === 'completed').length;
|
||||
@@ -1731,6 +1669,191 @@
|
||||
if (filterCompletedCount) filterCompletedCount.textContent = completed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 회의 생성자 여부 확인
|
||||
* @param {string} meetingId - 회의 ID
|
||||
* @param {string} userName - 사용자 이름
|
||||
* @returns {boolean} 회의 생성자 여부
|
||||
*/
|
||||
function checkIfUserIsCreator(meetingId, userName) {
|
||||
// 실제로는 서버 API를 호출하여 확인
|
||||
// 프로토타입에서는 샘플 데이터로 시뮬레이션
|
||||
const meetingCreators = {
|
||||
'meeting-001': '김민준',
|
||||
'meeting-002': '이서연',
|
||||
'meeting-003': '박준호'
|
||||
};
|
||||
|
||||
return meetingCreators[meetingId] === userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 수정 함수 (index 기반)
|
||||
* @param {number} index - Todo 인덱스 (1-based)
|
||||
*/
|
||||
function editTodo(index) {
|
||||
// 1-based index를 0-based로 변환
|
||||
const todo = meetingTodos[index - 1];
|
||||
if (!todo) {
|
||||
showToast('Todo를 찾을 수 없습니다', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 모달에 데이터 채우기
|
||||
document.getElementById('editTodoId').value = index;
|
||||
document.getElementById('editTodoTitle').value = todo.title;
|
||||
|
||||
// 담당자 처리 (assignee가 객체인 경우 name 속성 사용)
|
||||
const assigneeName = typeof todo.assignee === 'object' ? todo.assignee.name : todo.assignee;
|
||||
document.getElementById('editTodoAssignee').value = assigneeName;
|
||||
|
||||
document.getElementById('editTodoDueDate').value = todo.dueDate;
|
||||
|
||||
// 회의 생성자 여부 확인
|
||||
const currentUser = '김민준'; // 현재 로그인 사용자
|
||||
const isCreator = checkIfUserIsCreator(CURRENT_MEETING_ID, currentUser);
|
||||
|
||||
// 담당자 필드 표시 여부 결정 (회의 생성자만 표시)
|
||||
const assigneeGroup = document.getElementById('editTodoAssigneeGroup');
|
||||
if (isCreator) {
|
||||
assigneeGroup.style.display = 'block';
|
||||
} else {
|
||||
assigneeGroup.style.display = 'none';
|
||||
}
|
||||
|
||||
// 모달 열기
|
||||
openModal('editTodoModal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 수정 저장 (index 기반)
|
||||
*/
|
||||
function saveTodoEdit() {
|
||||
const index = parseInt(document.getElementById('editTodoId').value);
|
||||
const title = document.getElementById('editTodoTitle').value.trim();
|
||||
const assignee = document.getElementById('editTodoAssignee').value.trim();
|
||||
const dueDate = document.getElementById('editTodoDueDate').value;
|
||||
|
||||
if (!title) {
|
||||
showToast('제목을 입력해주세요', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!assignee) {
|
||||
showToast('담당자를 입력해주세요', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dueDate) {
|
||||
showToast('마감일을 선택해주세요', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 1-based index를 0-based로 변환하여 Todo 업데이트
|
||||
const todoIndex = index - 1;
|
||||
if (todoIndex >= 0 && todoIndex < meetingTodos.length) {
|
||||
const todo = meetingTodos[todoIndex];
|
||||
const oldAssignee = typeof todo.assignee === 'object' ? todo.assignee.name : todo.assignee;
|
||||
const oldDueDate = todo.dueDate;
|
||||
|
||||
// Todo 업데이트 (실제로는 API 호출)
|
||||
todo.title = title;
|
||||
|
||||
// assignee가 객체인 경우 name 속성만 업데이트
|
||||
if (typeof todo.assignee === 'object') {
|
||||
todo.assignee.name = assignee;
|
||||
} else {
|
||||
todo.assignee = assignee;
|
||||
}
|
||||
|
||||
todo.dueDate = dueDate;
|
||||
|
||||
showToast('Todo가 수정되었습니다', 'success');
|
||||
|
||||
// 담당자 변경 시 알림
|
||||
if (oldAssignee !== assignee) {
|
||||
setTimeout(() => {
|
||||
showToast(`${oldAssignee}와 ${assignee}에게 알림이 전송되었습니다`, 'info');
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 마감일 변경 시 알림
|
||||
if (oldDueDate !== dueDate) {
|
||||
setTimeout(() => {
|
||||
showToast('캘린더가 업데이트되었습니다', 'info');
|
||||
}, oldAssignee !== assignee ? 2000 : 1000);
|
||||
}
|
||||
}
|
||||
|
||||
closeModal('editTodoModal');
|
||||
|
||||
// 페이지 새로고침 (실제로는 해당 Todo 항목만 업데이트)
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Todo 추가 함수
|
||||
*/
|
||||
function addTodo() {
|
||||
const title = document.getElementById('addTodoTitle').value.trim();
|
||||
const assignee = document.getElementById('addTodoAssignee').value.trim();
|
||||
const dueDate = document.getElementById('addTodoDueDate').value;
|
||||
|
||||
// 유효성 검사
|
||||
if (!title) {
|
||||
showToast('Todo 내용을 입력해주세요', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!assignee) {
|
||||
showToast('담당자를 선택해주세요', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dueDate) {
|
||||
showToast('마감일을 선택해주세요', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 새 Todo 추가 (실제로는 API 호출)
|
||||
const newTodo = {
|
||||
id: 'todo-' + Date.now(),
|
||||
meetingId: CURRENT_MEETING_ID,
|
||||
title: title,
|
||||
assignee: assignee,
|
||||
dueDate: dueDate,
|
||||
status: 'pending'
|
||||
};
|
||||
|
||||
meetingTodos.push(newTodo);
|
||||
|
||||
showToast('Todo가 추가되었습니다', 'success');
|
||||
|
||||
// 담당자에게 알림 전송
|
||||
setTimeout(() => {
|
||||
showToast(`${assignee}에게 알림이 전송되었습니다`, 'info');
|
||||
}, 1000);
|
||||
|
||||
// 캘린더 업데이트 알림
|
||||
setTimeout(() => {
|
||||
showToast('캘린더가 업데이트되었습니다', 'info');
|
||||
}, 2000);
|
||||
|
||||
closeModal('addTodoModal');
|
||||
|
||||
// 입력 필드 초기화
|
||||
document.getElementById('addTodoTitle').value = '';
|
||||
document.getElementById('addTodoAssignee').value = '';
|
||||
document.getElementById('addTodoDueDate').value = '';
|
||||
|
||||
// 페이지 새로고침 (실제로는 Todo 리스트만 업데이트)
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 2500);
|
||||
}
|
||||
|
||||
/**
|
||||
* 페이지 초기화
|
||||
*/
|
||||
@@ -1740,13 +1863,19 @@
|
||||
const isCreator = checkIfUserIsCreator(CURRENT_MEETING_ID, currentUser);
|
||||
|
||||
if (isCreator) {
|
||||
const titleContainer = document.getElementById('meeting-title-container');
|
||||
const badge = titleContainer.querySelector('.badge');
|
||||
const badgesContainer = document.getElementById('meeting-badges');
|
||||
const crownIcon = document.createElement('span');
|
||||
crownIcon.textContent = '👑';
|
||||
crownIcon.style.fontSize = '24px';
|
||||
// badge 다음에 👑 삽입
|
||||
badge.insertAdjacentElement('afterend', crownIcon);
|
||||
crownIcon.style.fontSize = '20px';
|
||||
crownIcon.title = '회의 생성자';
|
||||
// 배지 영역에 크라운 추가
|
||||
badgesContainer.appendChild(crownIcon);
|
||||
} else {
|
||||
// 회의 생성자가 아닐 경우 creator-only 요소 숨김
|
||||
const creatorOnlyElements = document.querySelectorAll('.creator-only');
|
||||
creatorOnlyElements.forEach(element => {
|
||||
element.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
updateTodoProgress();
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
<title>회의록 수정 - 회의록 서비스</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
/*
|
||||
MVP 스코프 축소 v1.5.2 적용됨:
|
||||
- ❌ 실시간 협업 표시 ("편집 중" 표시 제거)
|
||||
- ❌ Todo 편집 기능 제거 (단순 조회만 가능)
|
||||
- ❌ 검증률 표시 및 최종 확정 버튼 제거
|
||||
- ✅ 안건별 검증 완료 체크박스 사용
|
||||
- ✅ Last Write Wins (LWW) 정책 적용
|
||||
- ✅ AI 요약 기능 통합: "AI 상세 요약" → "AI 요약"으로 명칭 변경
|
||||
- ✅ AI 재생성 버튼: 텍스트 편집 영역 내용 기반으로 한줄 요약 재생성
|
||||
*/
|
||||
|
||||
/* 페이지별 커스텀 스타일만 유지 */
|
||||
/* 공통 스타일(헤더, 메인콘텐츠, 안건, AI요약, 관련회의록, 액션바)은 common.css 사용 */
|
||||
|
||||
@@ -101,32 +112,8 @@
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
/* AI 한줄 요약 (읽기 전용, UFR-AI-036) */
|
||||
.ai-summary-oneline {
|
||||
background: var(--gray-50);
|
||||
border-left: 4px solid var(--primary);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
margin-bottom: var(--space-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.ai-summary-oneline .lock-icon {
|
||||
font-size: 18px;
|
||||
color: var(--gray-500);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ai-summary-oneline .summary-text {
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-700);
|
||||
font-weight: var(--font-weight-medium);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* AI 요약 편집 영역 (UFR-AI-036) */
|
||||
/* 헤더, textarea, footer 스타일은 common.css 사용 */
|
||||
/* AI 요약 편집 Footer (common.css에 없는 부분) */
|
||||
.ai-summary-footer {
|
||||
display: flex;
|
||||
@@ -187,6 +174,14 @@
|
||||
.reference-item {
|
||||
position: relative;
|
||||
padding-right: 40px; /* 삭제 버튼 공간 확보 */
|
||||
cursor: default; /* 카드 전체는 클릭 불가 */
|
||||
}
|
||||
|
||||
/* 수정 페이지에서는 카드 hover 효과 제거 (삭제 버튼만 클릭 가능) */
|
||||
.reference-item:hover {
|
||||
transform: none;
|
||||
border-color: var(--gray-200);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
@@ -245,6 +240,19 @@
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
/* 회의 생성자 전용 UI 표시 제어 */
|
||||
.creator-only {
|
||||
display: flex; /* 기본: 회의 생성자 환경 */
|
||||
}
|
||||
|
||||
.agenda-verification:not([data-is-creator="true"]) .creator-only {
|
||||
display: none; /* 참석자 환경에서는 숨김 */
|
||||
}
|
||||
|
||||
.agenda-verification:not(.verified) .creator-only {
|
||||
display: none; /* 검증 안 된 경우 버튼 숨김 */
|
||||
}
|
||||
|
||||
/* 읽기 전용 표시 */
|
||||
.readonly-badge {
|
||||
display: inline-flex;
|
||||
@@ -395,23 +403,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI 한줄 요약 (읽기 전용, UFR-AI-036) -->
|
||||
<div class="ai-summary-oneline">
|
||||
<span class="lock-icon">🔒</span>
|
||||
<span class="summary-text">타겟 고객을 20-30대로 설정, UI/UX 개선 집중</span>
|
||||
</div>
|
||||
|
||||
<!-- AI 상세 요약 편집 -->
|
||||
<!-- AI 요약 편집 (UFR-AI-036) -->
|
||||
<div class="ai-summary-edit">
|
||||
<div class="ai-summary-header">
|
||||
<span class="ai-summary-label">💡 AI 상세 요약</span>
|
||||
<button class="btn-secondary btn-sm" onclick="regenerateSummary(1)">AI 재생성</button>
|
||||
<span class="ai-summary-label">💡 AI 요약</span>
|
||||
<button class="btn btn-primary btn-sm" onclick="regenerateSummary(1)">AI 재생성</button>
|
||||
</div>
|
||||
<textarea
|
||||
class="ai-summary-textarea"
|
||||
placeholder="AI 요약을 입력하거나 수정하세요"
|
||||
readonly
|
||||
>신제품은 AI 기반 회의록 자동화 서비스로 결정. 타겟은 중소기업 및 스타트업이며, 주요 기능은 음성인식, AI 요약, Todo 추출입니다. 경쟁사 대비 차별점은 실시간 검증 및 협업 기능입니다.</textarea>
|
||||
>타겟 고객을 20-30대로 설정, UI/UX 개선 집중</textarea>
|
||||
<div class="ai-summary-footer">
|
||||
<span class="ai-summary-time">마지막 수정: 1시간 전</span>
|
||||
</div>
|
||||
@@ -466,16 +468,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 안건별 검증 (회의 생성자 권한) -->
|
||||
<div class="agenda-verification verified" id="verify-agenda-1">
|
||||
<!-- 안건별 검증 (UFR-COLLAB-030) -->
|
||||
<!-- 참석자: 체크박스만 표시 (검증완료 시 읽기 전용) -->
|
||||
<!-- 생성자: 검증완료 시 "잠금 해제" 버튼 표시 -->
|
||||
<div class="agenda-verification verified" id="verify-agenda-1" data-is-creator="true">
|
||||
<input type="checkbox" class="checkbox" id="verify-1" checked disabled>
|
||||
<div class="verification-label">
|
||||
<label for="verify-1">
|
||||
<span class="font-medium">검증 완료</span>
|
||||
<span class="text-caption text-muted"> (잠금됨 · 회의 생성자만 수정 가능)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="verification-actions">
|
||||
<!-- 회의 생성자만 보이는 잠금 해제 버튼 (검증완료 시에만 표시) -->
|
||||
<div class="verification-actions creator-only">
|
||||
<button class="btn btn-secondary btn-sm" onclick="unlockAgendaVerification(1)">🔓 잠금 해제</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -492,23 +496,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI 한줄 요약 (읽기 전용, UFR-AI-036) -->
|
||||
<div class="ai-summary-oneline">
|
||||
<span class="lock-icon">🔒</span>
|
||||
<span class="summary-text">개발 기간 3개월, 백엔드 2명/프론트 2명/AI 1명 투입</span>
|
||||
</div>
|
||||
|
||||
<!-- AI 상세 요약 편집 -->
|
||||
<!-- AI 요약 편집 (UFR-AI-036) -->
|
||||
<div class="ai-summary-edit">
|
||||
<div class="ai-summary-header">
|
||||
<span class="ai-summary-label">💡 AI 상세 요약</span>
|
||||
<button class="btn-secondary btn-sm" onclick="regenerateSummary(2)">AI 재생성</button>
|
||||
<span class="ai-summary-label">💡 AI 요약</span>
|
||||
<button class="btn btn-primary btn-sm" onclick="regenerateSummary(2)">AI 재생성</button>
|
||||
</div>
|
||||
<textarea
|
||||
class="ai-summary-textarea"
|
||||
placeholder="AI 요약을 입력하거나 수정하세요"
|
||||
readonly
|
||||
>개발 기간은 3개월로 설정. 백엔드 2명, 프론트 2명, AI 엔지니어 1명 투입. 주간 스프린트로 진행하며, 2주마다 베타 테스트 실시.</textarea>
|
||||
>개발 기간 3개월, 백엔드 2명/프론트 2명/AI 1명 투입</textarea>
|
||||
<div class="ai-summary-footer">
|
||||
<span class="ai-summary-time">생성: 2025-10-25 16:32</span>
|
||||
</div>
|
||||
@@ -547,16 +545,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 안건별 검증 (회의 생성자 권한) -->
|
||||
<div class="agenda-verification verified" id="verify-agenda-2">
|
||||
<!-- 안건별 검증 (UFR-COLLAB-030) -->
|
||||
<!-- 참석자: 체크박스만 표시 (검증완료 시 읽기 전용) -->
|
||||
<!-- 생성자: 검증완료 시 "잠금 해제" 버튼 표시 -->
|
||||
<div class="agenda-verification verified" id="verify-agenda-2" data-is-creator="true">
|
||||
<input type="checkbox" class="checkbox" id="verify-2" checked disabled>
|
||||
<div class="verification-label">
|
||||
<label for="verify-2">
|
||||
<span class="font-medium">검증 완료</span>
|
||||
<span class="text-caption text-muted"> (잠금됨 · 회의 생성자만 수정 가능)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="verification-actions">
|
||||
<!-- 회의 생성자만 보이는 잠금 해제 버튼 (검증완료 시에만 표시) -->
|
||||
<div class="verification-actions creator-only">
|
||||
<button class="btn btn-secondary btn-sm" onclick="unlockAgendaVerification(2)">🔓 잠금 해제</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -573,23 +573,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI 한줄 요약 (읽기 전용, UFR-AI-036) -->
|
||||
<div class="ai-summary-oneline">
|
||||
<span class="lock-icon">🔒</span>
|
||||
<span class="summary-text">프리 런칭 캠페인, LinkedIn 및 스타트업 커뮤니티 집중</span>
|
||||
</div>
|
||||
|
||||
<!-- AI 상세 요약 편집 -->
|
||||
<!-- AI 요약 편집 (UFR-AI-036) -->
|
||||
<div class="ai-summary-edit">
|
||||
<div class="ai-summary-header">
|
||||
<span class="ai-summary-label">💡 AI 상세 요약</span>
|
||||
<button class="btn-secondary btn-sm" onclick="regenerateSummary(3)">AI 재생성</button>
|
||||
<span class="ai-summary-label">💡 AI 요약</span>
|
||||
<button class="btn btn-primary btn-sm" onclick="regenerateSummary(3)">AI 재생성</button>
|
||||
</div>
|
||||
<textarea
|
||||
class="ai-summary-textarea"
|
||||
placeholder="AI 요약을 입력하거나 수정하세요"
|
||||
readonly
|
||||
>베타 출시 전 프리 런칭 캠페인 진행. 주요 채널은 LinkedIn 및 스타트업 커뮤니티. 초기 100팀 무료 제공 후 유료 전환 유도.</textarea>
|
||||
>프리 런칭 캠페인, LinkedIn 및 스타트업 커뮤니티 집중</textarea>
|
||||
<div class="ai-summary-footer">
|
||||
<span class="ai-summary-time">생성: 2025-10-25 16:35</span>
|
||||
</div>
|
||||
@@ -624,15 +618,15 @@
|
||||
</div>
|
||||
|
||||
<!-- 안건별 검증 (회의 생성자 권한) -->
|
||||
<div class="agenda-verification verified" id="verify-agenda-3">
|
||||
<div class="agenda-verification verified" id="verify-agenda-3" data-is-creator="true">
|
||||
<input type="checkbox" class="checkbox" id="verify-3" checked disabled>
|
||||
<div class="verification-label">
|
||||
<label for="verify-3">
|
||||
<span class="font-medium">검증 완료</span>
|
||||
<span class="text-caption text-muted"> (잠금됨 · 회의 생성자만 수정 가능)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="verification-actions">
|
||||
<!-- 회의 생성자만 보이는 잠금 해제 버튼 (검증완료 시에만 표시) -->
|
||||
<div class="verification-actions creator-only">
|
||||
<button class="btn btn-secondary btn-sm" onclick="unlockAgendaVerification(3)">🔓 잠금 해제</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -743,12 +737,13 @@
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// AI 요약 재생성
|
||||
// AI 한줄 요약 재생성 (텍스트 편집 영역 내용 기반, UFR-AI-036)
|
||||
function regenerateSummary(agendaId) {
|
||||
showToast('AI 요약을 생성 중입니다...', 'info');
|
||||
showToast('AI 요약을 재생성 중입니다...', 'info');
|
||||
|
||||
setTimeout(() => {
|
||||
showToast('AI 요약이 생성되었습니다', 'success');
|
||||
showToast('재생성되었습니다', 'success');
|
||||
// 재생성된 한줄 요약은 회의록 상세조회 화면의 대시보드 및 회의록 탭에 즉시 반영됨
|
||||
markAsUnsaved();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
@@ -453,10 +453,6 @@
|
||||
<span class="sidebar-nav-icon"><img src="img/edit.png" width="32"></span>
|
||||
<span>회의록</span>
|
||||
</a>
|
||||
<a href="09-Todo관리.html" class="sidebar-nav-item">
|
||||
<span class="sidebar-nav-icon"><img src="img/list.png" width="32"></span>
|
||||
<span>Todo 관리</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- 사용자 정보 영역 (Desktop) -->
|
||||
@@ -581,9 +577,6 @@
|
||||
<a href="12-회의록목록조회.html" class="nav-item active">
|
||||
<img src="img/edit.png" alt="회의록" style="width: 45px;">
|
||||
</a>
|
||||
<a href="09-Todo관리.html" class="nav-item">
|
||||
<img src="img/list.png" alt="Todo" style="width: 45px;">
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<script src="common.js"></script>
|
||||
|
||||
@@ -1429,11 +1429,12 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
.related-meeting-item {
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-sm);
|
||||
padding: var(--space-md);
|
||||
margin-bottom: var(--space-sm);
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
transition: background var(--transition-fast);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
border: 1px solid var(--gray-200);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.reference-item:last-child,
|
||||
@@ -1443,7 +1444,15 @@ input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
|
||||
.reference-item:hover,
|
||||
.related-meeting-item:hover {
|
||||
background: var(--gray-100);
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.reference-item:active,
|
||||
.related-meeting-item:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.reference-content,
|
||||
|
||||
Vendored
+9
-2
@@ -31,7 +31,7 @@ const SAMPLE_MEETINGS = [
|
||||
time: '14:00',
|
||||
duration: 90,
|
||||
location: '본사 2층 대회의실',
|
||||
status: 'scheduled', // ongoing, scheduled, completed
|
||||
status: 'draft', // ongoing, scheduled, completed, draft(작성중), complete(확정완료)
|
||||
participants: [
|
||||
{ id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green' },
|
||||
{ id: 'user-002', name: '박서연', avatar: '박', avatarColor: 'blue' },
|
||||
@@ -39,7 +39,8 @@ const SAMPLE_MEETINGS = [
|
||||
{ id: 'user-004', name: '최유진', avatar: '최', avatarColor: 'pink' }
|
||||
],
|
||||
sections: 3,
|
||||
todos: 5
|
||||
todos: 5,
|
||||
minutesId: 'minutes-001' // 회의록 ID 연결
|
||||
},
|
||||
{
|
||||
id: 'meeting-002',
|
||||
@@ -1083,6 +1084,12 @@ function getMeetingStatusInfo(meeting) {
|
||||
if (meeting.status === 'ongoing') {
|
||||
return { badgeType: 'ongoing', badgeText: '진행중' };
|
||||
}
|
||||
if (meeting.status === 'draft') {
|
||||
return { badgeType: 'draft', badgeText: '작성중' };
|
||||
}
|
||||
if (meeting.status === 'complete') {
|
||||
return { badgeType: 'complete', badgeText: '확정완료' };
|
||||
}
|
||||
if (meeting.status === 'completed') {
|
||||
return { badgeType: 'complete', badgeText: '확정완료' };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user