@@ -8,6 +8,9 @@ class DailyPlanner {
88 this . updatePlanTable ( ) ;
99 this . updateCompletionStats ( ) ;
1010 this . loadTodayReflection ( ) ;
11+
12+ // 确保在初始化时加载今天的完成情况数据
13+ setTimeout ( ( ) => this . loadCompletionData ( ) , 200 ) ;
1114 }
1215
1316 initEventListeners ( ) {
@@ -288,23 +291,101 @@ class DailyPlanner {
288291 const tbody = document . getElementById ( 'completion-tbody' ) ;
289292 tbody . innerHTML = '' ;
290293
291- const completedPlans = this . plans . filter ( p => p . completed ) ;
292294 const pendingPlans = this . plans . filter ( p => ! p . completed ) ;
293295
294- const maxRows = Math . max ( completedPlans . length , pendingPlans . length , 1 ) ;
296+ if ( pendingPlans . length === 0 ) {
297+ const row = document . createElement ( 'tr' ) ;
298+ row . innerHTML = `
299+ <td colspan="3" style="text-align: center; color: #666;">🎉 所有计划都已完成!</td>
300+ ` ;
301+ tbody . appendChild ( row ) ;
302+ return ;
303+ }
295304
296- for ( let i = 0 ; i < maxRows ; i ++ ) {
305+ pendingPlans . forEach ( ( plan , index ) => {
297306 const row = document . createElement ( 'tr' ) ;
298- const completed = completedPlans [ i ] ;
299- const pending = pendingPlans [ i ] ;
300-
301307 row . innerHTML = `
302- <td>${ completed ? completed . event : '' } </td>
303- <td>${ pending ? pending . event : '' } </td>
304- <td>${ pending ? '<input type="text" placeholder="输入未完成原因..." class="form-control">' : '' } </td>
305- <td>${ pending ? '<input type="text" placeholder="调整策略..." class="form-control">' : '' } </td>
308+ <td>${ plan . event } </td>
309+ <td><input type="text" placeholder="输入未完成原因..." class="form-control incomplete-reason" data-plan-id="${ plan . id } "></td>
310+ <td><input type="text" placeholder="调整策略..." class="form-control adjustment-strategy" data-plan-id="${ plan . id } "></td>
306311 ` ;
307312 tbody . appendChild ( row ) ;
313+ } ) ;
314+
315+ // 为输入框添加事件监听器以自动保存
316+ this . setupCompletionInputListeners ( ) ;
317+
318+ // 加载已保存的完成情况数据
319+ setTimeout ( ( ) => this . loadCompletionData ( ) , 100 ) ;
320+ }
321+
322+ setupCompletionInputListeners ( ) {
323+ // 为未完成原因和调整策略输入框添加事件监听器
324+ const reasonInputs = document . querySelectorAll ( '.incomplete-reason' ) ;
325+ const adjustmentInputs = document . querySelectorAll ( '.adjustment-strategy' ) ;
326+
327+ [ ...reasonInputs , ...adjustmentInputs ] . forEach ( input => {
328+ input . addEventListener ( 'blur' , ( ) => this . saveCompletionData ( ) ) ;
329+ input . addEventListener ( 'input' , ( ) => {
330+ clearTimeout ( this . completionSaveTimeout ) ;
331+ this . completionSaveTimeout = setTimeout ( ( ) => {
332+ this . saveCompletionData ( ) ;
333+ } , 1000 ) ;
334+ } ) ;
335+ } ) ;
336+ }
337+
338+ saveCompletionData ( ) {
339+ const today = new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] ;
340+ const completionData = { } ;
341+
342+ // 收集未完成原因
343+ document . querySelectorAll ( '.incomplete-reason' ) . forEach ( input => {
344+ const planId = input . getAttribute ( 'data-plan-id' ) ;
345+ if ( input . value . trim ( ) ) {
346+ if ( ! completionData [ planId ] ) completionData [ planId ] = { } ;
347+ completionData [ planId ] . incompleteReason = input . value . trim ( ) ;
348+ }
349+ } ) ;
350+
351+ // 收集调整策略
352+ document . querySelectorAll ( '.adjustment-strategy' ) . forEach ( input => {
353+ const planId = input . getAttribute ( 'data-plan-id' ) ;
354+ if ( input . value . trim ( ) ) {
355+ if ( ! completionData [ planId ] ) completionData [ planId ] = { } ;
356+ completionData [ planId ] . adjustmentStrategy = input . value . trim ( ) ;
357+ }
358+ } ) ;
359+
360+ localStorage . setItem ( `completion_data_${ today } ` , JSON . stringify ( completionData ) ) ;
361+ }
362+
363+ loadCompletionData ( ) {
364+ const today = new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] ;
365+ const completionData = localStorage . getItem ( `completion_data_${ today } ` ) ;
366+
367+ if ( completionData ) {
368+ try {
369+ const data = JSON . parse ( completionData ) ;
370+
371+ // 加载未完成原因
372+ document . querySelectorAll ( '.incomplete-reason' ) . forEach ( input => {
373+ const planId = input . getAttribute ( 'data-plan-id' ) ;
374+ if ( data [ planId ] && data [ planId ] . incompleteReason ) {
375+ input . value = data [ planId ] . incompleteReason ;
376+ }
377+ } ) ;
378+
379+ // 加载调整策略
380+ document . querySelectorAll ( '.adjustment-strategy' ) . forEach ( input => {
381+ const planId = input . getAttribute ( 'data-plan-id' ) ;
382+ if ( data [ planId ] && data [ planId ] . adjustmentStrategy ) {
383+ input . value = data [ planId ] . adjustmentStrategy ;
384+ }
385+ } ) ;
386+ } catch ( e ) {
387+ console . error ( '加载完成情况数据失败:' , e ) ;
388+ }
308389 }
309390 }
310391
@@ -427,6 +508,24 @@ class DailyPlanner {
427508
428509 const dailyThoughts = document . getElementById ( 'daily-thoughts' ) . value ;
429510
511+ // 收集完成情况数据(未完成原因和调整策略)
512+ const completionDetails = { } ;
513+ document . querySelectorAll ( '.incomplete-reason' ) . forEach ( input => {
514+ const planId = input . getAttribute ( 'data-plan-id' ) ;
515+ if ( input . value . trim ( ) ) {
516+ if ( ! completionDetails [ planId ] ) completionDetails [ planId ] = { } ;
517+ completionDetails [ planId ] . incompleteReason = input . value . trim ( ) ;
518+ }
519+ } ) ;
520+
521+ document . querySelectorAll ( '.adjustment-strategy' ) . forEach ( input => {
522+ const planId = input . getAttribute ( 'data-plan-id' ) ;
523+ if ( input . value . trim ( ) ) {
524+ if ( ! completionDetails [ planId ] ) completionDetails [ planId ] = { } ;
525+ completionDetails [ planId ] . adjustmentStrategy = input . value . trim ( ) ;
526+ }
527+ } ) ;
528+
430529 // 构建完整的日记数据,确保包含完整的日期信息
431530 const dateObj = new Date ( ) ;
432531 const dailyRecord = {
@@ -451,6 +550,7 @@ class DailyPlanner {
451550 gratitude : gratitude ,
452551 dailyThoughts : dailyThoughts
453552 } ,
553+ completionDetails : completionDetails ,
454554 statistics : {
455555 totalPlans : plansData . length ,
456556 completedPlans : plansData . filter ( p => p . completed ) . length ,
@@ -485,6 +585,9 @@ class DailyPlanner {
485585
486586 this . showMessage ( `💾 保存成功!` , 'success' ) ;
487587
588+ // 保存完成情况数据到localStorage
589+ this . saveCompletionData ( ) ;
590+
488591 // 更新侧边栏树状结构
489592 updateRecordTreeAfterSave ( ) ;
490593 }
@@ -635,6 +738,24 @@ class DailyPlanner {
635738
636739 const dailyThoughts = document . getElementById ( 'daily-thoughts' ) . value ;
637740
741+ // 收集完成情况数据
742+ const completionDetails = { } ;
743+ document . querySelectorAll ( '.incomplete-reason' ) . forEach ( input => {
744+ const planId = input . getAttribute ( 'data-plan-id' ) ;
745+ if ( input . value . trim ( ) ) {
746+ if ( ! completionDetails [ planId ] ) completionDetails [ planId ] = { } ;
747+ completionDetails [ planId ] . incompleteReason = input . value . trim ( ) ;
748+ }
749+ } ) ;
750+
751+ document . querySelectorAll ( '.adjustment-strategy' ) . forEach ( input => {
752+ const planId = input . getAttribute ( 'data-plan-id' ) ;
753+ if ( input . value . trim ( ) ) {
754+ if ( ! completionDetails [ planId ] ) completionDetails [ planId ] = { } ;
755+ completionDetails [ planId ] . adjustmentStrategy = input . value . trim ( ) ;
756+ }
757+ } ) ;
758+
638759 // 构建PDF内容
639760 let pdfContent = `
640761<!DOCTYPE html>
@@ -691,6 +812,31 @@ class DailyPlanner {
691812 </tbody>
692813 </table>
693814
815+ <h2>📝 计划完成情况分析</h2>
816+ ${ this . plans . filter ( p => ! p . completed ) . length > 0 ? `
817+ <table class="plans-table">
818+ <thead>
819+ <tr>
820+ <th>未完成计划</th>
821+ <th>未完成原因</th>
822+ <th>需要调整</th>
823+ </tr>
824+ </thead>
825+ <tbody>
826+ ${ this . plans . filter ( p => ! p . completed ) . map ( plan => {
827+ const details = completionDetails [ plan . id ] || { } ;
828+ return `
829+ <tr class="incomplete">
830+ <td>${ plan . event } </td>
831+ <td>${ details . incompleteReason || '未填写' } </td>
832+ <td>${ details . adjustmentStrategy || '未填写' } </td>
833+ </tr>
834+ ` ;
835+ } ) . join ( '' ) }
836+ </tbody>
837+ </table>
838+ ` : '<p style="color: #28a745; font-weight: bold;">🎉 恭喜!所有计划都已完成!</p>' }
839+
694840 <h2>🤔 感悟反思</h2>
695841
696842 <h3>👉 相比昨天的进步之处:</h3>
@@ -1567,6 +1713,15 @@ function loadRecordFromData(date, record, source = 'local', filePath = null) {
15671713 }
15681714 }
15691715
1716+ // 加载完成情况数据
1717+ if ( record . completionDetails ) {
1718+ // 先保存到localStorage用于后续加载
1719+ localStorage . setItem ( `completion_data_${ date } ` , JSON . stringify ( record . completionDetails ) ) ;
1720+ }
1721+
1722+ // 更新完成情况统计和表格
1723+ planner . updateCompletionStats ( ) ;
1724+
15701725 // 高亮选中的记录
15711726 document . querySelectorAll ( '.tree-level-3 .tree-item' ) . forEach ( item => {
15721727 item . classList . remove ( 'active' ) ;
0 commit comments