Преглед изворни кода

[add]

<檀家一覧(基本情報)>
タイトル 檀家詳細-〇〇家に変更 〇
茶色のバーの中身の情報を世帯名と情報の更新日を追加 〇
回忌ボタンを削除 〇
右側の「家族を見る」「過去帳を見る」を削除 〇

<檀家一覧(家族)>
世帯主を一番上に 〇

<檀家一覧(過去等)>
年次法要を見るを削除 〇
編集ボタンを削除 〇
poohr пре 3 недеља
родитељ
комит
1c4debc98a

+ 1
- 0
src/app/models/danka.ts Прегледај датотеку

6
   postalCode: string;
6
   postalCode: string;
7
   address: string;
7
   address: string;
8
   phones: Phone[];
8
   phones: Phone[];
9
+  updatedAt: string;
9
 }
10
 }
10
 
11
 
11
 export interface Phone {
12
 export interface Phone {

+ 17
- 61
src/app/pages/danka-detail/danka-detail.html Прегледај датотеку

13
         <div class="page-title-row">
13
         <div class="page-title-row">
14
           <div>
14
           <div>
15
             <h1>
15
             <h1>
16
-              檀家(世帯)詳細 -
17
-              @if (selectedTab === 'basic') {
18
-                基本情報
19
-              }
20
-              @if (selectedTab === 'family') {
21
-                家族
22
-              }
23
-              @if (selectedTab === 'kakocho') {
24
-                過去帳
25
-              }
26
-              @if (selectedTab === 'familyTree') {
27
-                家系図
28
-              }
16
+              檀家詳細 - {{ danka.householdName }}
29
             </h1>
17
             </h1>
30
 
18
 
31
             <nav class="tab-list">
19
             <nav class="tab-list">
84
             >
72
             >
85
               故人を登録
73
               故人を登録
86
             </button>
74
             </button>
87
-
88
-            <button
89
-              type="button"
90
-              class="edit-button"
91
-              [routerLink]="['/kakocho-edit', danka.id, kakocholist[0].id]"
92
-            >
93
-              編集
94
-            </button>
95
           }
75
           }
96
         </div>
76
         </div>
97
 
77
 
100
             @if (selectedTab === 'basic') {
80
             @if (selectedTab === 'basic') {
101
               <div class="family-name-area">
81
               <div class="family-name-area">
102
                 <p class="family-name">{{ danka.householdName }}</p>
82
                 <p class="family-name">{{ danka.householdName }}</p>
103
-                <p class="family-head">世帯主: {{ danka.householder }}</p>
104
-              </div>
105
-
106
-              <div class="family-address">
107
-                <p>郵便番号 〒{{ danka.postalCode }}</p>
108
-                <p>住所 {{ danka.address }}</p>
83
+                <p class="family-head">更新日: {{ formatUpdatedAt(danka.updatedAt) }}</p>
109
               </div>
84
               </div>
110
-
111
-              <button type="button" class="memo-button">
112
-                回忌を見る
113
-              </button>
114
             }
85
             }
115
 
86
 
116
             @if (selectedTab === 'kakocho') {
87
             @if (selectedTab === 'kakocho') {
117
               <div class="family-name-area">
88
               <div class="family-name-area">
118
                 <p class="family-name">{{ danka.householdName }}の過去帳{{ kakocholist.length }} 名</p>
89
                 <p class="family-name">{{ danka.householdName }}の過去帳{{ kakocholist.length }} 名</p>
119
               </div>
90
               </div>
120
-
121
-              <button type="button" class="memo-button">
122
-                年次法要を見る
123
-              </button>
124
             }
91
             }
125
           </section>
92
           </section>
126
         }
93
         }
180
                 <button
147
                 <button
181
                   type="button"
148
                   type="button"
182
                   class="status-card"
149
                   class="status-card"
183
-                  (click)="selectedTab = 'family'"
184
-                >
150
+                  (click)="selectedTab = 'family'">
185
                   <p class="status-label">家族</p>
151
                   <p class="status-label">家族</p>
186
                   <p class="status-count">{{ families.length }} 名</p>
152
                   <p class="status-count">{{ families.length }} 名</p>
187
                   <p class="status-link">詳細へ</p>
153
                   <p class="status-link">詳細へ</p>
190
                 <button
156
                 <button
191
                   type="button"
157
                   type="button"
192
                   class="status-card"
158
                   class="status-card"
193
-                  (click)="selectedTab = 'kakocho'"
194
-                >
159
+                  (click)="selectedTab = 'kakocho'">
195
                   <p class="status-label">過去帳</p>
160
                   <p class="status-label">過去帳</p>
196
                   <p class="status-count">{{ kakocholist.length }}  名</p>
161
                   <p class="status-count">{{ kakocholist.length }}  名</p>
197
                   <p class="status-link">詳細へ</p>
162
                   <p class="status-link">詳細へ</p>
202
                 <h3>次の法要</h3>
167
                 <h3>次の法要</h3>
203
 
168
 
204
                 <div class="memorial-card">
169
                 <div class="memorial-card">
205
-                  <p class="memorial-title">佐藤 ハナ - 三回忌</p>
206
-                  <p class="memorial-text">
207
-                    対象年 2026 / 没年月日 2024-01-08
208
-                  </p>
170
+                  @if (nextMemorial) {
171
+                    <p class="memorial-title">
172
+                      {{ nextMemorial.name }} - {{ nextMemorial.memorialType }}
173
+                    </p>
174
+                    <p class="memorial-text">
175
+                      対象年 {{ nextMemorial.targetYear }} / 没年月日 {{ nextMemorial.deathDate }}
176
+                    </p>
177
+                  } @else {
178
+                    <p class="memorial-title">対象の法要はありません</p>
179
+                    <p class="memorial-text">
180
+                      今年の年忌法要対象者がいる場合に表示されます。
181
+                    </p>
182
+                  }
209
                 </div>
183
                 </div>
210
               </section>
184
               </section>
211
-
212
-              <div class="status-button-list">
213
-                <button
214
-                  type="button"
215
-                  class="status-button"
216
-                  (click)="selectedTab = 'family'"
217
-                >
218
-                  家族を見る
219
-                </button>
220
-
221
-                <button
222
-                  type="button"
223
-                  class="status-button"
224
-                  (click)="selectedTab = 'kakocho'"
225
-                >
226
-                  過去帳を見る
227
-                </button>
228
-              </div>
229
             </aside>
185
             </aside>
230
           </div>
186
           </div>
231
         }
187
         }

+ 118
- 1
src/app/pages/danka-detail/danka-detail.ts Прегледај датотеку

11
 import { AppSideMenu } from '../../share/side-menu/app-side-menu';
11
 import { AppSideMenu } from '../../share/side-menu/app-side-menu';
12
 import { MarriageRelationService } from '../../services/marriage-relation-service';
12
 import { MarriageRelationService } from '../../services/marriage-relation-service';
13
 
13
 
14
+interface NextMemorial {
15
+  name: string;
16
+  memorialType: string;
17
+  targetYear: number;
18
+  deathDate: string;
19
+}
20
+
14
 @Component({
21
 @Component({
15
   selector: 'app-danka-detail',
22
   selector: 'app-danka-detail',
16
   imports: [AppHeader, AppSideMenu, RouterLink],
23
   imports: [AppHeader, AppSideMenu, RouterLink],
22
   families: Family[] = [];
29
   families: Family[] = [];
23
   kakocholist: Kakocho[] = [];
30
   kakocholist: Kakocho[] = [];
24
   marriageRelations: MarriageRelation[] = [];
31
   marriageRelations: MarriageRelation[] = [];
32
+  nextMemorial: NextMemorial | undefined;
25
   currentYear = new Date().getFullYear();
33
   currentYear = new Date().getFullYear();
26
 
34
 
27
   selectedTab: 'basic' | 'family' | 'kakocho' | 'familyTree' = 'basic';
35
   selectedTab: 'basic' | 'family' | 'kakocho' | 'familyTree' = 'basic';
47
     if (id) {
55
     if (id) {
48
       this.danka = this.dankaService.getDankaById(id);
56
       this.danka = this.dankaService.getDankaById(id);
49
       this.marriageRelations = this.marriageRelationService.getMarriageRelationsByDankaId(id);
57
       this.marriageRelations = this.marriageRelationService.getMarriageRelationsByDankaId(id);
50
-      this.families = this.familyService.getFamiliesByDankaId(id);
58
+      this.families = this.sortFamiliesByHouseholder(this.familyService.getFamiliesByDankaId(id));
51
       this.selectedFamily = this.families[0];
59
       this.selectedFamily = this.families[0];
52
       this.kakocholist = this.kakochoService.getKakochoByDankaId(id);
60
       this.kakocholist = this.kakochoService.getKakochoByDankaId(id);
61
+      this.nextMemorial = this.getNextMemorial();
53
     }
62
     }
54
   }
63
   }
55
 
64
 
75
     return this.currentYear - new Date(deathDate).getFullYear() + 1;
84
     return this.currentYear - new Date(deathDate).getFullYear() + 1;
76
   }
85
   }
77
 
86
 
87
+  formatUpdatedAt(updatedAt: string): string {
88
+    const date = this.parseDate(updatedAt);
89
+    if (!date) {
90
+      return '未登録';
91
+    }
92
+
93
+    return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
94
+  }
95
+
96
+  getMemorialType(deathDate: string): string {
97
+    const deathYear = Number(deathDate.slice(0, 4));
98
+    const yearDiff = this.currentYear - deathYear;
99
+
100
+    switch (yearDiff) {
101
+      case 1:
102
+        return '一周忌';
103
+      case 2:
104
+        return '三回忌';
105
+      case 6:
106
+        return '七回忌';
107
+      case 12:
108
+        return '十三回忌';
109
+      case 16:
110
+        return '十七回忌';
111
+      case 22:
112
+        return '二十三回忌';
113
+      default:
114
+        return '';
115
+    }
116
+  }
117
+
118
+  private getNextMemorial(): NextMemorial | undefined {
119
+    const today = this.toDateOnly(new Date());
120
+
121
+    return this.kakocholist
122
+      .map((kakocho) => {
123
+        const memorialType = this.getMemorialType(kakocho.deathDate);
124
+        const deathDate = this.parseDate(kakocho.deathDate);
125
+
126
+        if (!memorialType || !deathDate) {
127
+          return undefined;
128
+        }
129
+
130
+        const memorialDate = new Date(
131
+          this.currentYear,
132
+          deathDate.getMonth(),
133
+          deathDate.getDate(),
134
+        );
135
+
136
+        if (memorialDate < today) {
137
+          return undefined;
138
+        }
139
+
140
+        return {
141
+          memorialDate,
142
+          memorial: {
143
+            name: kakocho.name,
144
+            memorialType,
145
+            targetYear: this.currentYear,
146
+            deathDate: kakocho.deathDate,
147
+          },
148
+        };
149
+      })
150
+      .filter(
151
+        (item): item is { memorialDate: Date; memorial: NextMemorial } => item !== undefined,
152
+      )
153
+      .sort(
154
+        (a, b) =>
155
+          a.memorialDate.getTime() - b.memorialDate.getTime() ||
156
+          a.memorial.name.localeCompare(b.memorial.name, 'ja'),
157
+      )[0]?.memorial;
158
+  }
159
+
160
+  private toDateOnly(date: Date): Date {
161
+    return new Date(date.getFullYear(), date.getMonth(), date.getDate());
162
+  }
163
+
164
+  private parseDate(value: string): Date | null {
165
+    const [year, month, day] = value.split('-').map(Number);
166
+    if (!year || !month || !day) {
167
+      return null;
168
+    }
169
+    return new Date(year, month - 1, day);
170
+  }
171
+
78
   selectFamily(family: Family): void {
172
   selectFamily(family: Family): void {
79
     this.selectedFamily = family;
173
     this.selectedFamily = family;
80
   }
174
   }
81
 
175
 
176
+  private sortFamiliesByHouseholder(families: Family[]): Family[] {
177
+    if (!this.danka) {
178
+      return families;
179
+    }
180
+
181
+    const householderName = this.normalizeName(this.danka.householder);
182
+
183
+    return [...families].sort((a, b) => {
184
+      const aIsHouseholder = this.normalizeName(a.name) === householderName;
185
+      const bIsHouseholder = this.normalizeName(b.name) === householderName;
186
+
187
+      if (aIsHouseholder === bIsHouseholder) {
188
+        return 0;
189
+      }
190
+
191
+      return aIsHouseholder ? -1 : 1;
192
+    });
193
+  }
194
+
195
+  private normalizeName(name: string): string {
196
+    return name.replace(/\s/g, '');
197
+  }
198
+
82
   getFamilyById(id: string): Family | undefined {
199
   getFamilyById(id: string): Family | undefined {
83
     if (!id) {
200
     if (!id) {
84
       return undefined;
201
       return undefined;

+ 9
- 1
src/app/pages/danka-edit/danka-edit.ts Прегледај датотеку

87
     const formValue = this.dankaForm.value;
87
     const formValue = this.dankaForm.value;
88
     const isEdit = !!this.danka;
88
     const isEdit = !!this.danka;
89
     const dankaId = isEdit ? this.danka!.id : Date.now().toString();
89
     const dankaId = isEdit ? this.danka!.id : Date.now().toString();
90
-    const updatedDanka = {
90
+    const updatedDanka: Danka = {
91
       id: dankaId,
91
       id: dankaId,
92
       householdName: formValue.householdName?.trim() ?? '',
92
       householdName: formValue.householdName?.trim() ?? '',
93
       householder: formValue.householder?.trim() ?? '',
93
       householder: formValue.householder?.trim() ?? '',
94
       postalCode: formValue.postalCode?.trim() ?? '',
94
       postalCode: formValue.postalCode?.trim() ?? '',
95
       address: formValue.address?.trim() ?? '',
95
       address: formValue.address?.trim() ?? '',
96
+      updatedAt: this.formatDateForSave(new Date()),
96
       phones: (formValue.phones ?? [])
97
       phones: (formValue.phones ?? [])
97
         .map((phone) => ({
98
         .map((phone) => ({
98
           tel: phone.tel?.trim() ?? '',
99
           tel: phone.tel?.trim() ?? '',
110
     }
111
     }
111
   }
112
   }
112
 
113
 
114
+  private formatDateForSave(date: Date): string {
115
+    const year = date.getFullYear();
116
+    const month = String(date.getMonth() + 1).padStart(2, '0');
117
+    const day = String(date.getDate()).padStart(2, '0');
118
+    return `${year}-${month}-${day}`;
119
+  }
120
+
113
   //削除の処理
121
   //削除の処理
114
   deleteDanka() {
122
   deleteDanka() {
115
     if (!this.danka) {
123
     if (!this.danka) {

+ 2
- 0
src/app/services/dankaService.ts Прегледај датотеку

12
       householder: '鈴木 太郎',
12
       householder: '鈴木 太郎',
13
       postalCode: '123-4567',
13
       postalCode: '123-4567',
14
       address: '市内 1-2-3',
14
       address: '市内 1-2-3',
15
+      updatedAt: '2026-05-28',
15
       phones: [
16
       phones: [
16
         {
17
         {
17
           tel: '03-4567-8910',
18
           tel: '03-4567-8910',
29
       householder: '古田 太郎',
30
       householder: '古田 太郎',
30
       postalCode: '234-4567',
31
       postalCode: '234-4567',
31
       address: '市内 1-2-3',
32
       address: '市内 1-2-3',
33
+      updatedAt: '2026-05-28',
32
       phones: [
34
       phones: [
33
         {
35
         {
34
           tel: '0-5678-9101',
36
           tel: '0-5678-9101',

Loading…
Откажи
Сачувај