네비서◒
당신의 하루를 더 가볍게

좋은 아침이에요!

오늘도 당신의 멋진 하루를 응원해요 ♥

오늘의 핵심 업무
기획안 초안 완성하기
◷오후 3:00까지작은 집중이
큰 변화를 만듭니다.

오늘의 일정

🍃 “오늘도, 조금 더 나은 내가 되는 하루.”
`; const blob=new Blob(['\ufeff', html],{type:'application/vnd.ms-excel;charset=utf-8;'}); const url=URL.createObjectURL(blob); const a=document.createElement('a'); a.href=url; a.download=`weekly_report_${key(new Date())}.xls`; document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(url),1000); } function progressChoices(selected=""){const items=["everyday","0%","10%","20%","30%","40%","50%","60%","70%","80%","90%","100%"];return items.map(v=>``).join("")} function updateTaskProgress(taskId,value){const t=tasks.find(x=>x.id===taskId);if(!t)return;t.progress=value;t.updatedAt=new Date().toISOString();saveStore();toast("진행률이 업데이트되었습니다.");if($("reportModal").classList.contains("open"))openWeeklyReport()} function printReportAsPdf(){toast("인쇄 창에서 'PDF로 저장'을 선택하세요.");window.print()} function inferProgress(task,currentStart,currentEnd){ if(task.progress) return task.progress; if(isDone(task)) return "100%"; const deadline=new Date(task.deadline); if(isOverdue(task)) return "80%"; if(inRange(deadline,currentStart,currentEnd)) return "60%"; if(deadline>currentEnd) return "30%"; return "50%"; } function inferLastWeekWork(task,prevStart,prevEnd,currentStart){ const deadline=new Date(task.deadline); const desc=shortText(task.description||"",90); if(inRange(deadline,prevStart,prevEnd)) return shortText((desc?desc+" / ":"")+task.title,120); if(deadlinecurrentEnd) return shortText(`${task.title} 관련 자료 준비 및 선행 작업`,120); return shortText(`${task.title} 후속 조치 및 결과 정리`,120); } function buildWeeklyReportData(){ const now=new Date(); const currentStart=startOfWeek(now), currentEnd=endOfWeek(now); const prevStart=new Date(currentStart); prevStart.setDate(prevStart.getDate()-7); const prevEnd=new Date(currentStart); prevEnd.setMilliseconds(-1); const candidates=tasks.filter(t=>t.deadline).filter(t=>{ const d=new Date(t.deadline); return inRange(d,prevStart,currentEnd) || isOverdue(t) || (t.updatedAt && inRange(t.updatedAt,prevStart,currentEnd)); }); const list=(candidates.length?candidates:tasks.filter(t=>t.deadline)).slice().sort((a,b)=>new Date(a.deadline)-new Date(b.deadline)); const rows=list.map((t,idx)=>({ no: idx+1, project: shortText(t.category || t.title, 45), lastWeek: inferLastWeekWork(t,prevStart,prevEnd,currentStart), thisWeek: inferThisWeekPlan(t,currentStart,currentEnd), progress: t.progress || inferProgress(t,currentStart,currentEnd), raw: t })); const prevSummary = rows.length ? rows.slice(0,8).map(r=>r.lastWeek) : ["전주 업무 데이터가 없습니다."]; const currentSummary = rows.length ? rows.slice(0,8).map(r=>r.thisWeek) : ["금주 계획 데이터가 없습니다."]; return {now,currentStart,currentEnd,prevStart,prevEnd,rows,prevSummary,currentSummary}; } function generateReportText(data){ const header=`주간 업무 리포트\n발행일: ${fmtDT(data.now)}\n전주: ${weekLabel(data.prevStart,data.prevEnd)}\n금주: ${weekLabel(data.currentStart,data.currentEnd)}\n`; const body=data.rows.map(r=>`${r.no}. [${r.project}] 전주업무: ${r.lastWeek} / 금주계획: ${r.thisWeek} / 진행률: ${r.progress}`).join("\n"); return header + "\n" + body; } function openWeeklyReport(){ const data=buildWeeklyReportData(); const isMonday=new Date().getDay()===1; const assigneeGroups=buildAssigneeGroups(data.rows); const totalCount=data.rows.length; const doneCount=data.rows.filter(r=>numericProgressValue(r.progress)>=100).length; const avgProgress=totalCount?Math.round(data.rows.reduce((s,r)=>s+numericProgressValue(r.progress),0)/totalCount):0; const delayedCount=data.rows.filter(r=>isOverdue(r.raw)).length; $("reportTitle").textContent=isMonday?"월요일 주간 업무 리포트":"주간 업무 리포트"; $("reportSub").textContent=isMonday?"전주 업무와 금주 계획을 월요일 기준으로 종합했습니다.":"전주 업무와 금주 계획을 자동 종합했습니다."; const summaryHtml=`
리포트 발행 발행일
${fmtDT(data.now)}
전주 기준 ${weekLabel(data.prevStart,data.prevEnd)}
금주 기준 ${weekLabel(data.currentStart,data.currentEnd)}
진행률은 표 안에서 직접 수정할 수 있습니다.
전체 일정${totalCount}
주간 리포트 대상
완료 건수${doneCount}
진행률 100%
평균 진행률${avgProgress}%
전체 평균
지연 일정${delayedCount}
마감 경과

Last week work (전주 업무)

    ${data.prevSummary.map(x=>`
  • ${esc(x)}
  • `).join("")}

This week plan (금주 계획)

    ${data.currentSummary.map(x=>`
  • ${esc(x)}
  • `).join("")}
${data.rows.length ? data.rows.map(r=>` `).join("") : ``}
No Project (프로젝트) Last week work (전주 업무) This week plan (금주 계획) Progress (진행률)
${r.no} ${esc(r.project)}
담당: ${esc(r.raw.assignee||"미지정")}
${esc(r.lastWeek)} ${esc(r.thisWeek)}
${esc(r.progress)}
리포트에 표시할 일정이 없습니다.

담당자별 리포트

담당자별로 전주 업무 / 금주 계획 / 진행률을 분리해서 보여줍니다.
${assigneeGroups.length ? assigneeGroups.map(([name,list])=>`

${esc(name)} (${list.length}건)

    ${list.map(r=>`
  • ${esc(r.project)}
    전주: ${esc(r.lastWeek)}
    금주: ${esc(r.thisWeek)}
    진행률: ${esc(r.progress)}
  • `).join("")}
`).join("") : `
담당자별 데이터가 없습니다.
`}
`; $("reportContent").innerHTML=summaryHtml; $("copyReportBtn").onclick=()=>copyText(generateReportText(buildWeeklyReportData())); $("printReportBtn").onclick=()=>window.print(); $("downloadPdfBtn").onclick=printReportAsPdf; $("downloadExcelBtn").onclick=exportWeeklyReportExcel; openModal("reportModal"); } /** * 네비서 v30 * 담당 영역: 한국어 포함 10개 언어 번역과 사용자 이름 * A/S 시 이 파일의 담당 영역만 수정하십시오. */ const I18N={ ko:{hello:"안녕하세요, {name}님 👋",namePrompt:"표시할 이름을 입력하세요.",menu:"메뉴",name:"이름",ticker:"오늘 일정",noToday:"오늘 일정이 없습니다.",heroTitle:"오늘의 업무 현황",heroSub:"6개 요약을 한 줄로 간략하게 정리했어요.",addTask:"+ 일정",report:"리포트",quickPlaceholder:"오늘 해야 할 일을 입력해 주세요",save:"저장",voice:"🎙️ 음성 입력",read:"🔊 일정 말해줘",pause:"⏸️ 정지",resume:"▶️ 계속",low:"낮음",normal:"보통",important:"중요",urgent:"긴급",today:"오늘",tomorrow:"내일",week:"주간",month:"월간",year:"년간",todaySchedule:"오늘 스케쥴",todayScheduleSub:"오늘 해야 할 일을 보여줍니다.",unit:"건",todayShort:"오늘",urgentShort:"긴급",attention:"주의",doneShort:"완료",lateShort:"지연",none:"없음",recommendShort:"추천",idle:"대기",cardToday:"오늘",cardTasks:"일정",cardUrgent:"긴급",cardAlerts:"알림",cardComplete:"완료",cardMonth:"월간",cardLate:"지연",cardAI:"AI",cardTotal:"전체",p1:"참고",p2:"낮음",p3:"보통",p4:"중요",p5:"긴급"}, en:{hello:"Hello, {name} 👋",namePrompt:"Enter the display name.",menu:"Menu",name:"Name",ticker:"Today's Tasks",noToday:"No tasks today.",heroTitle:"Today's Dashboard",heroSub:"Six key summaries in one compact line.",addTask:"+ Task",report:"Report",quickPlaceholder:"Enter a task for today",save:"Save",voice:"🎙️ Voice",read:"🔊 Read",pause:"⏸️ Pause",resume:"▶️ Resume",low:"Low",normal:"Normal",important:"Important",urgent:"Urgent",today:"Today",tomorrow:"Tomorrow",week:"Week",month:"Month",year:"Year",todaySchedule:"Today Schedule",todayScheduleSub:"Shows tasks for today.",unit:"",todayShort:"Today",urgentShort:"Urgent",attention:"Alert",doneShort:"Done",lateShort:"Late",none:"None",recommendShort:"Ready",idle:"Idle",cardToday:"Today",cardTasks:"Tasks",cardUrgent:"Urgent",cardAlerts:"Alerts",cardComplete:"Done",cardMonth:"Month",cardLate:"Late",cardAI:"AI",cardTotal:"Total",p1:"Ref",p2:"Low",p3:"Normal",p4:"Important",p5:"Urgent"}, ja:{hello:"こんにちは、{name}さん 👋",namePrompt:"表示名を入力してください。",menu:"メニュー",name:"名前",ticker:"今日の予定",noToday:"今日の予定はありません。",heroTitle:"今日の業務状況",heroSub:"6つの要約を1行で表示します。",addTask:"+ 予定",report:"レポート",quickPlaceholder:"今日やることを入力してください",save:"保存",voice:"🎙️ 音声入力",read:"🔊 読み上げ",pause:"⏸️ 停止",resume:"▶️ 続行",low:"低",normal:"通常",important:"重要",urgent:"緊急",today:"今日",tomorrow:"明日",week:"週",month:"月",year:"年",todaySchedule:"今日の予定",todayScheduleSub:"今日のタスクを表示します。",unit:"件",todayShort:"今日",urgentShort:"緊急",attention:"注意",doneShort:"完了",lateShort:"遅延",none:"なし",recommendShort:"準備",idle:"待機",cardToday:"今日",cardTasks:"予定",cardUrgent:"緊急",cardAlerts:"通知",cardComplete:"完了",cardMonth:"月間",cardLate:"遅延",cardAI:"AI",cardTotal:"合計",p1:"参考",p2:"低",p3:"通常",p4:"重要",p5:"緊急"}, zh:{hello:"你好,{name} 👋",namePrompt:"请输入显示名称。",menu:"菜单",name:"名称",ticker:"今日任务",noToday:"今天没有任务。",heroTitle:"今日工作概览",heroSub:"一行显示6个关键摘要。",addTask:"+ 任务",report:"报告",quickPlaceholder:"请输入今天要做的事",save:"保存",voice:"🎙️ 语音输入",read:"🔊 朗读日程",pause:"⏸️ 暂停",resume:"▶️ 继续",low:"低",normal:"普通",important:"重要",urgent:"紧急",today:"今天",tomorrow:"明天",week:"周",month:"月",year:"年",todaySchedule:"今日日程",todayScheduleSub:"显示今天的任务。",unit:"项",todayShort:"今天",urgentShort:"紧急",attention:"提醒",doneShort:"完成",lateShort:"逾期",none:"无",recommendShort:"就绪",idle:"待机",cardToday:"今天",cardTasks:"任务",cardUrgent:"紧急",cardAlerts:"提醒",cardComplete:"完成",cardMonth:"月度",cardLate:"逾期",cardAI:"AI",cardTotal:"总计",p1:"参考",p2:"低",p3:"普通",p4:"重要",p5:"紧急"}, es:{hello:"Hola, {name} 👋",namePrompt:"Ingresa el nombre visible.",menu:"Menú",name:"Nombre",ticker:"Tareas de hoy",noToday:"No hay tareas hoy.",heroTitle:"Panel de hoy",heroSub:"Seis resúmenes clave en una línea.",addTask:"+ Tarea",report:"Informe",quickPlaceholder:"Ingresa una tarea para hoy",save:"Guardar",voice:"🎙️ Voz",read:"🔊 Leer",pause:"⏸️ Pausa",resume:"▶️ Continuar",low:"Baja",normal:"Normal",important:"Importante",urgent:"Urgente",today:"Hoy",tomorrow:"Mañana",week:"Semana",month:"Mes",year:"Año",todaySchedule:"Agenda de hoy",todayScheduleSub:"Muestra las tareas de hoy.",unit:"",todayShort:"Hoy",urgentShort:"Urgente",attention:"Alerta",doneShort:"Hecho",lateShort:"Tarde",none:"Ninguno",recommendShort:"Listo",idle:"Espera",cardToday:"Hoy",cardTasks:"Tareas",cardUrgent:"Urgente",cardAlerts:"Alertas",cardComplete:"Hecho",cardMonth:"Mes",cardLate:"Tarde",cardAI:"AI",cardTotal:"Total",p1:"Ref",p2:"Baja",p3:"Normal",p4:"Importante",p5:"Urgente"}, fr:{hello:"Bonjour, {name} 👋",namePrompt:"Saisissez le nom affiché.",menu:"Menu",name:"Nom",ticker:"Tâches du jour",noToday:"Aucune tâche aujourd’hui.",heroTitle:"Tableau du jour",heroSub:"Six résumés clés sur une seule ligne.",addTask:"+ Tâche",report:"Rapport",quickPlaceholder:"Saisir une tâche pour aujourd’hui",save:"Enregistrer",voice:"🎙️ Voix",read:"🔊 Lire",pause:"⏸️ Pause",resume:"▶️ Reprendre",low:"Faible",normal:"Normal",important:"Important",urgent:"Urgent",today:"Aujourd’hui",tomorrow:"Demain",week:"Semaine",month:"Mois",year:"Année",todaySchedule:"Agenda du jour",todayScheduleSub:"Affiche les tâches du jour.",unit:"",todayShort:"Jour",urgentShort:"Urgent",attention:"Alerte",doneShort:"Fait",lateShort:"Retard",none:"Aucun",recommendShort:"Prêt",idle:"Attente",cardToday:"Jour",cardTasks:"Tâches",cardUrgent:"Urgent",cardAlerts:"Alertes",cardComplete:"Fait",cardMonth:"Mois",cardLate:"Retard",cardAI:"IA",cardTotal:"Total",p1:"Réf",p2:"Faible",p3:"Normal",p4:"Important",p5:"Urgent"}, de:{hello:"Hallo, {name} 👋",namePrompt:"Anzeigenamen eingeben.",menu:"Menü",name:"Name",ticker:"Heutige Aufgaben",noToday:"Heute keine Aufgaben.",heroTitle:"Heutiges Dashboard",heroSub:"Sechs Kurzinfos in einer Zeile.",addTask:"+ Aufgabe",report:"Bericht",quickPlaceholder:"Aufgabe für heute eingeben",save:"Speichern",voice:"🎙️ Sprache",read:"🔊 Vorlesen",pause:"⏸️ Pause",resume:"▶️ Weiter",low:"Niedrig",normal:"Normal",important:"Wichtig",urgent:"Dringend",today:"Heute",tomorrow:"Morgen",week:"Woche",month:"Monat",year:"Jahr",todaySchedule:"Heutiger Plan",todayScheduleSub:"Zeigt heutige Aufgaben.",unit:"",todayShort:"Heute",urgentShort:"Dringend",attention:"Alarm",doneShort:"Fertig",lateShort:"Verspätet",none:"Keine",recommendShort:"Bereit",idle:"Warten",cardToday:"Heute",cardTasks:"Aufgaben",cardUrgent:"Dringend",cardAlerts:"Alarme",cardComplete:"Fertig",cardMonth:"Monat",cardLate:"Spät",cardAI:"KI",cardTotal:"Gesamt",p1:"Ref",p2:"Niedrig",p3:"Normal",p4:"Wichtig",p5:"Dringend"}, vi:{hello:"Xin chào, {name} 👋",namePrompt:"Nhập tên hiển thị.",menu:"Menu",name:"Tên",ticker:"Việc hôm nay",noToday:"Hôm nay không có việc.",heroTitle:"Tổng quan hôm nay",heroSub:"6 tóm tắt chính trên một dòng.",addTask:"+ Việc",report:"Báo cáo",quickPlaceholder:"Nhập việc cần làm hôm nay",save:"Lưu",voice:"🎙️ Giọng nói",read:"🔊 Đọc",pause:"⏸️ Dừng",resume:"▶️ Tiếp tục",low:"Thấp",normal:"Thường",important:"Quan trọng",urgent:"Khẩn",today:"Hôm nay",tomorrow:"Ngày mai",week:"Tuần",month:"Tháng",year:"Năm",todaySchedule:"Lịch hôm nay",todayScheduleSub:"Hiển thị việc hôm nay.",unit:"",todayShort:"Hôm nay",urgentShort:"Khẩn",attention:"Cảnh báo",doneShort:"Xong",lateShort:"Trễ",none:"Không",recommendShort:"Sẵn sàng",idle:"Chờ",cardToday:"Hôm nay",cardTasks:"Việc",cardUrgent:"Khẩn",cardAlerts:"Báo",cardComplete:"Xong",cardMonth:"Tháng",cardLate:"Trễ",cardAI:"AI",cardTotal:"Tổng",p1:"Tham khảo",p2:"Thấp",p3:"Thường",p4:"Quan trọng",p5:"Khẩn"}, id:{hello:"Halo, {name} 👋",namePrompt:"Masukkan nama tampilan.",menu:"Menu",name:"Nama",ticker:"Tugas Hari Ini",noToday:"Tidak ada tugas hari ini.",heroTitle:"Dasbor Hari Ini",heroSub:"6 ringkasan utama dalam satu baris.",addTask:"+ Tugas",report:"Laporan",quickPlaceholder:"Masukkan tugas hari ini",save:"Simpan",voice:"🎙️ Suara",read:"🔊 Bacakan",pause:"⏸️ Jeda",resume:"▶️ Lanjut",low:"Rendah",normal:"Normal",important:"Penting",urgent:"Mendesak",today:"Hari ini",tomorrow:"Besok",week:"Minggu",month:"Bulan",year:"Tahun",todaySchedule:"Jadwal Hari Ini",todayScheduleSub:"Menampilkan tugas hari ini.",unit:"",todayShort:"Hari ini",urgentShort:"Mendesak",attention:"Peringatan",doneShort:"Selesai",lateShort:"Terlambat",none:"Tidak ada",recommendShort:"Siap",idle:"Siaga",cardToday:"Hari ini",cardTasks:"Tugas",cardUrgent:"Mendesak",cardAlerts:"Alert",cardComplete:"Selesai",cardMonth:"Bulan",cardLate:"Terlambat",cardAI:"AI",cardTotal:"Total",p1:"Ref",p2:"Rendah",p3:"Normal",p4:"Penting",p5:"Mendesak"}, ar:{hello:"مرحباً، {name} 👋",namePrompt:"أدخل اسم العرض.",menu:"القائمة",name:"الاسم",ticker:"مهام اليوم",noToday:"لا توجد مهام اليوم.",heroTitle:"لوحة اليوم",heroSub:"ستة ملخصات رئيسية في سطر واحد.",addTask:"+ مهمة",report:"تقرير",quickPlaceholder:"أدخل مهمة اليوم",save:"حفظ",voice:"🎙️ صوت",read:"🔊 قراءة",pause:"⏸️ إيقاف",resume:"▶️ متابعة",low:"منخفض",normal:"عادي",important:"مهم",urgent:"عاجل",today:"اليوم",tomorrow:"غداً",week:"أسبوع",month:"شهر",year:"سنة",todaySchedule:"جدول اليوم",todayScheduleSub:"يعرض مهام اليوم.",unit:"",todayShort:"اليوم",urgentShort:"عاجل",attention:"تنبيه",doneShort:"تم",lateShort:"متأخر",none:"لا يوجد",recommendShort:"جاهز",idle:"انتظار",cardToday:"اليوم",cardTasks:"مهام",cardUrgent:"عاجل",cardAlerts:"تنبيهات",cardComplete:"تم",cardMonth:"شهر",cardLate:"متأخر",cardAI:"AI",cardTotal:"إجمالي",p1:"مرجع",p2:"منخفض",p3:"عادي",p4:"مهم",p5:"عاجل"} }; let currentLang="ko"; function tr(k){return (I18N[currentLang]&&I18N[currentLang][k])||I18N.ko[k]||k} function pri(n){return tr("p"+n)||priorityNames[n]} function getDisplayName(){return localStorage.getItem("secretary_display_name")||"아삽"} function setGreeting(){if($("greetingTitle"))$("greetingTitle").textContent=tr("hello").replace("{name}",getDisplayName())} function applyLanguage(){ if(!I18N[currentLang]) currentLang="ko"; document.documentElement.lang=currentLang; document.documentElement.dir=currentLang==="ar"?"rtl":"ltr"; setGreeting(); if($("moreBtn"))$("moreBtn").textContent=tr("menu"); if($("editNameBtn"))$("editNameBtn").textContent=tr("name"); const ticker=document.querySelector(".ticker-label"); if(ticker)ticker.textContent=tr("ticker"); const heroTitle=document.querySelector(".hero-title"); if(heroTitle)heroTitle.textContent=tr("heroTitle"); const heroSub=document.querySelector(".hero .sub"); if(heroSub)heroSub.textContent=tr("heroSub"); if($("openInputBtn"))$("openInputBtn").textContent=tr("addTask"); if($("reportBtn"))$("reportBtn").textContent=tr("report"); if($("quickTitle"))$("quickTitle").placeholder=tr("quickPlaceholder"); if($("quickSaveBtn"))$("quickSaveBtn").textContent=tr("save"); if($("voiceInputBtn"))$("voiceInputBtn").textContent=tr("voice"); if($("readCurrentViewBtn"))$("readCurrentViewBtn").textContent=tr("read"); if($("pauseSpeechBtn"))$("pauseSpeechBtn").textContent=tr("pause"); if($("resumeSpeechBtn"))$("resumeSpeechBtn").textContent=tr("resume"); const chip=[tr("low"),tr("normal"),tr("important"),tr("urgent")];document.querySelectorAll(".chip-btn").forEach((b,i)=>b.textContent=chip[i]||b.textContent); const nav=[tr("today"),tr("tomorrow"),tr("week"),tr("month"),tr("year")];document.querySelectorAll("[data-view]").forEach((b,i)=>b.textContent=nav[i%5]||b.textContent); if($("dashBtnToday")){$("dashBtnToday").querySelector("h2").textContent=tr("cardToday");$("dashBtnToday").querySelector("small").textContent=tr("cardTasks")} if($("dashBtnUrgent")){$("dashBtnUrgent").querySelector("h2").textContent=tr("cardUrgent");$("dashBtnUrgent").querySelector("small").textContent=tr("cardAlerts")} if($("dashBtnWeek"))$("dashBtnWeek").querySelector("h2").textContent=tr("cardComplete"); if($("dashBtnMonth")){$("dashBtnMonth").querySelector("h2").textContent=tr("cardMonth");$("dashBtnMonth").querySelector("small").textContent=tr("cardTotal")} if($("dashBtnMemo")){$("dashBtnMemo").querySelector("h2").textContent=tr("cardLate")} if($("dashBtnAi")){$("dashBtnAi").querySelector("h2").textContent=tr("cardAI")} if($("viewTitle"))$("viewTitle").textContent=currentView==="today"?tr("todaySchedule"):nav[["today","tomorrow","week","month","year"].indexOf(currentView)]||$("viewTitle").textContent; if($("viewSub")&¤tView==="today")$("viewSub").textContent=tr("todayScheduleSub"); if($("addForViewBtn"))$("addForViewBtn").textContent=tr("addTask").replace("+ ",""); } function initI18n(){ currentLang=localStorage.getItem("secretary_lang")||"ko"; if($("langSelect")){$("langSelect").value=currentLang;$("langSelect").onchange=()=>{currentLang=$("langSelect").value;localStorage.setItem("secretary_lang",currentLang);applyLanguage();render()}} if($("editNameBtn"))$("editNameBtn").onclick=()=>{const n=prompt(tr("namePrompt"),getDisplayName());if(n&&n.trim()){localStorage.setItem("secretary_display_name",n.trim());setGreeting()}}; applyLanguage(); } /** * 네비서 v30 * 담당 영역: 버튼 이벤트 연결과 앱 초기 실행 * A/S 시 이 파일의 담당 영역만 수정하십시오. */ document.addEventListener("DOMContentLoaded",()=>{document.addEventListener("click",()=>initAlarmAudio(),{once:true});document.addEventListener("touchstart",()=>initAlarmAudio(),{once:true});initI18n();load();initForm();render();$("openInputBtn").onclick=()=>openInput(new Date());$("quickSaveBtn").onclick=quickSave;$("reportBtn").onclick=openWeeklyReport;$("voiceInputBtn").onclick=startVoiceInput;$("readCurrentViewBtn").onclick=readCurrent;$("pauseSpeechBtn").onclick=pauseSpeaking;$("resumeSpeechBtn").onclick=resumeSpeaking;$("saveBtn").onclick=saveTask;$("clearFormBtn").onclick=()=>initForm();$("deleteCurrentBtn").onclick=deleteCurrent;$("analyzeBtn").onclick=analyzeCurrent;$("moreBtn").onclick=()=>openModal("moreModal");$("notifyBtn").onclick=requestNotification;$("soundToggleBtn").onclick=toggleAlarmSound;$("soundTestBtn").onclick=testAlarmSound;$("backupDataBtn").onclick=backupData;$("restoreDataBtn").onclick=()=>$("restoreFileInput").click();$("restoreFileInput").onchange=e=>restoreDataFromFile(e.target.files[0]);$("setPinBtn").onclick=setPin;$("lockNowBtn").onclick=lockNow;$("pwaHelpBtn").onclick=pwaHelp;$("unlockBtn").onclick=unlockWithPin;$("pinInput").addEventListener("keydown",e=>{if(e.key==="Enter")unlockWithPin()});$("pinResetGuideBtn").onclick=()=>alert("PIN을 잊은 경우 브라우저의 사이트 데이터/localStorage를 초기화해야 합니다. 판매용 서비스에서는 이메일 인증 기반 비밀번호 재설정 기능을 별도로 구현해야 합니다.");updateSoundButton();initLock();$("exportCsvBtn").onclick=exportCsv;$("exportIcsBtn").onclick=exportIcs;$("printBtn").onclick=()=>window.print();$("readTodayBtn").onclick=readToday;$("stopSpeakBtn").onclick=stopSpeaking;$("openMailBtn").onclick=openMail;$("copyShareBtn").onclick=()=>copyText($("shareBody").value);$("copyAnalysisBtn").onclick=()=>copyText(lastAnalysisText);["importance","reminder","deadlineDate","deadlineTime"].forEach(id=>$(id).addEventListener("change",updatePreview));document.querySelectorAll("[data-view]").forEach(b=>b.onclick=()=>setView(b.dataset.view));$("dashBtnToday").onclick=()=>openDashboardDetail("today");$("dashBtnUrgent").onclick=()=>openDashboardDetail("urgent");$("dashBtnWeek").onclick=()=>openDashboardDetail("week");$("dashBtnMonth").onclick=()=>openDashboardDetail("month");$("dashBtnMemo").onclick=()=>openDashboardDetail("memo");$("dashBtnAi").onclick=()=>openDashboardDetail("ai");document.querySelectorAll("[data-quick-imp]").forEach(b=>b.onclick=()=>{selectedQuickImportance=Number(b.dataset.quickImp);toast(priorityNames[selectedQuickImportance]+"로 설정되었습니다.")});setInterval(checkReminders,30000)});