Преглед на файлове

[add]

年次法要のページを追加
対象年の対象者を表示
回忌タブによる切り替え表示を追加
poohr преди 3 седмици
родител
ревизия
4379e21223

+ 98
- 0
src/app/pages/memorial-list/memorial-list.html Целия файл

@@ -0,0 +1,98 @@
1
+<app-header></app-header>
2
+
3
+<div class="breadcrumb">
4
+  ホーム &gt; 年次法要
5
+</div>
6
+
7
+<div class="memorial-list-page">
8
+  <app-side-menu></app-side-menu>
9
+
10
+  <main class="memorial-list-main">
11
+    <section class="memorial-panel">
12
+      <div class="page-title-row">
13
+        <div class="title-filter-area">
14
+          <h1>年次法要(回忌)一覧</h1>
15
+
16
+          <div class="filter-row">
17
+            <div class="year-filter">
18
+              <label for="targetYear">対象年</label>
19
+              <input id="targetYear" type="number" [(ngModel)]="targetYear"/>
20
+            </div>
21
+
22
+            <div class="memorial-filter">
23
+              <span>回忌</span>
24
+              @for (filter of memorialTypeFilters; track filter.value) {
25
+                <button
26
+                  type="button"
27
+                  class="filter-button"
28
+                  [class.active]="selectedMemorialType === filter.value"
29
+                  (click)="changeMemorialType(filter.value)"
30
+                >
31
+                  {{ filter.label }}
32
+                </button>
33
+              }
34
+            </div>
35
+          </div>
36
+        </div>
37
+
38
+        <button type="button" class="reload-button" (click)="createMemorialList()">
39
+          再表示
40
+        </button>
41
+      </div>
42
+
43
+      <div class="list-header-row">
44
+        <h2>対象 {{ memorialList.length }} 名</h2>
45
+
46
+        <p>並び順: 没年月日 / 氏名</p>
47
+      </div>
48
+
49
+      <section class="memorial-table-section">
50
+        <div class="memorial-table">
51
+          <div class="memorial-table-header">
52
+            <div>俗名</div>
53
+            <div>戒名</div>
54
+            <div>関係</div>
55
+            <div>檀家(世帯)</div>
56
+            <div>没年月日</div>
57
+            <div>回忌</div>
58
+            <div>詳細</div>
59
+          </div>
60
+
61
+          @if (memorialList.length > 0) {
62
+            @for (memorial of memorialList; track memorial.id) {
63
+              <div class="memorial-table-row">
64
+                <div class="person-name">
65
+                  {{ memorial.name }}
66
+                </div>
67
+                <div>
68
+                  {{ memorial.kaimyo }}
69
+                </div>
70
+                <div>
71
+                  {{ memorial.relationship }}
72
+                </div>
73
+                <div>
74
+                  {{ memorial.householdName }}
75
+                </div>
76
+                <div>
77
+                  {{ memorial.deathDate }}
78
+                </div>
79
+                <div class="memorial-type">
80
+                  {{ memorial.memorialType }}
81
+                </div>
82
+                <div>
83
+                  <a class="detail-link" [routerLink]="['/danka-detail', memorial.dankaId]" [queryParams]="{tab: 'kakocho'}">
84
+                    開く
85
+                  </a>
86
+                </div>
87
+              </div>
88
+            }
89
+          } @else {
90
+            <div class="empty-message">
91
+              対象となる法要はありません。
92
+            </div>
93
+          }
94
+        </div>
95
+      </section>
96
+    </section>
97
+  </main>
98
+</div>

+ 331
- 0
src/app/pages/memorial-list/memorial-list.scss Целия файл

@@ -0,0 +1,331 @@
1
+:host {
2
+  position: relative;
3
+  display: block;
4
+  min-height: 100vh;
5
+  background: #f4eee4;
6
+  color: #2f2720;
7
+}
8
+
9
+.breadcrumb {
10
+  position: absolute;
11
+  top: 28px;
12
+  left: 50%;
13
+  transform: translateX(-50%);
14
+  color: #7b6b5c;
15
+  font-size: 14px;
16
+  z-index: 2;
17
+}
18
+
19
+.memorial-list-page {
20
+  display: flex;
21
+  align-items: flex-start;
22
+  gap: 8px;
23
+  background: #f4eee4;
24
+}
25
+
26
+.memorial-list-main {
27
+  flex: 1;
28
+  padding-right: 34px;
29
+  box-sizing: border-box;
30
+}
31
+
32
+.memorial-panel {
33
+  min-height: 650px;
34
+  padding: 26px 34px 36px;
35
+  background: #ffffff;
36
+  border: 2px solid #d8caba;
37
+  border-radius: 76px;
38
+  box-sizing: border-box;
39
+}
40
+
41
+.page-title-row {
42
+  display: flex;
43
+  justify-content: space-between;
44
+  align-items: flex-start;
45
+  gap: 24px;
46
+  margin-bottom: 22px;
47
+}
48
+
49
+.title-filter-area {
50
+  display: grid;
51
+  gap: 4px;
52
+}
53
+
54
+.page-title-row h1 {
55
+  margin: 0;
56
+  color: #2f2720;
57
+  font-size: 32px;
58
+  line-height: 1.2;
59
+  font-weight: 800;
60
+  letter-spacing: 0.02em;
61
+}
62
+
63
+.filter-row {
64
+  display: flex;
65
+  align-items: center;
66
+  gap: 28px;
67
+  flex-wrap: wrap;
68
+}
69
+
70
+.year-filter {
71
+  display: flex;
72
+  align-items: center;
73
+  gap: 12px;
74
+}
75
+
76
+.year-filter label,
77
+.memorial-filter span {
78
+  color: #4b3c31;
79
+  font-size: 16px;
80
+  font-weight: 800;
81
+}
82
+
83
+.year-filter input {
84
+  width: 96px;
85
+  height: 48px;
86
+  padding: 0 14px;
87
+  border: 2px solid #d8caba;
88
+  border-radius: 8px;
89
+  background: #fffdf9;
90
+  color: #2f2720;
91
+  font-size: 17px;
92
+  font-weight: 700;
93
+  box-sizing: border-box;
94
+}
95
+
96
+.memorial-filter {
97
+  display: flex;
98
+  align-items: center;
99
+  gap: 8px;
100
+}
101
+
102
+.filter-button {
103
+  width: 108px;
104
+  height: 40px;
105
+  border: 2px solid #d8caba;
106
+  border-radius: 6px;
107
+  background: #f1e7d8;
108
+  color: #2f2720;
109
+  font-size: 15px;
110
+  font-weight: 700;
111
+  cursor: pointer;
112
+  box-sizing: border-box;
113
+}
114
+
115
+.filter-button:hover {
116
+  background: #eadfce;
117
+}
118
+
119
+.filter-button.active {
120
+  background: #8a6543;
121
+  border-color: #8a6543;
122
+  color: #ffffff;
123
+}
124
+
125
+.reload-button {
126
+  width: 120px;
127
+  height: 48px;
128
+  margin-top: 30px;
129
+  border: 2px solid #8a6543;
130
+  border-radius: 6px;
131
+  background: #8a6543;
132
+  color: #ffffff;
133
+  font-size: 17px;
134
+  font-weight: 800;
135
+  cursor: pointer;
136
+  box-sizing: border-box;
137
+}
138
+
139
+.reload-button:hover {
140
+  background: #765639;
141
+}
142
+
143
+.list-header-row {
144
+  display: flex;
145
+  justify-content: space-between;
146
+  align-items: flex-end;
147
+  margin: 18px 0 10px;
148
+}
149
+
150
+.list-header-row h2 {
151
+  margin: 0;
152
+  color: #2f2720;
153
+  font-size: 26px;
154
+  font-weight: 800;
155
+}
156
+
157
+.list-header-row p {
158
+  margin: 0;
159
+  color: #7b6b5c;
160
+  font-size: 14px;
161
+}
162
+
163
+.memorial-table-section {
164
+  margin-top: 8px;
165
+}
166
+
167
+.memorial-table {
168
+  display: grid;
169
+  gap: 4px;
170
+}
171
+
172
+.memorial-table-header,
173
+.memorial-table-row {
174
+  display: grid;
175
+  grid-template-columns: 1.2fr 1.4fr 0.8fr 1.2fr 1.1fr 0.8fr 0.7fr;
176
+  align-items: center;
177
+  column-gap: 12px;
178
+}
179
+
180
+.memorial-table-header {
181
+  min-height: 38px;
182
+  padding: 0 12px;
183
+  border: 2px solid #d8caba;
184
+  border-radius: 8px;
185
+  background: #eadfce;
186
+  color: #5a4a3c;
187
+  font-size: 15px;
188
+  font-weight: 800;
189
+  box-sizing: border-box;
190
+}
191
+
192
+.memorial-table-row {
193
+  min-height: 58px;
194
+  padding: 0 12px;
195
+  border: 2px solid #d8caba;
196
+  border-radius: 10px;
197
+  background: #fffdf9;
198
+  color: #2f2720;
199
+  font-size: 16px;
200
+  box-sizing: border-box;
201
+}
202
+
203
+.memorial-table-row:hover {
204
+  background: #f6efe6;
205
+}
206
+
207
+.person-name {
208
+  font-weight: 800;
209
+}
210
+
211
+.memorial-type {
212
+  color: #8a6543;
213
+  font-weight: 800;
214
+}
215
+
216
+.detail-link {
217
+  color: #3f6f45;
218
+  font-size: 15px;
219
+  font-weight: 800;
220
+  text-decoration: none;
221
+}
222
+
223
+.detail-link:hover {
224
+  text-decoration: underline;
225
+}
226
+
227
+.empty-message {
228
+  min-height: 58px;
229
+  padding: 18px 20px;
230
+  border: 2px solid #d8caba;
231
+  border-radius: 10px;
232
+  background: #fffdf9;
233
+  color: #7b6b5c;
234
+  font-size: 15px;
235
+  font-weight: 700;
236
+  box-sizing: border-box;
237
+}
238
+
239
+.notice-box {
240
+  margin-top: 26px;
241
+  padding: 18px 26px;
242
+  border: 2px solid #d8caba;
243
+  border-radius: 10px;
244
+  background: #fffdf9;
245
+  box-sizing: border-box;
246
+}
247
+
248
+.notice-box p {
249
+  margin: 0;
250
+  color: #7b6b5c;
251
+  font-size: 15px;
252
+  line-height: 1.7;
253
+}
254
+
255
+.bottom-note {
256
+  width: 700px;
257
+  margin: 18px 0 22px 36px;
258
+  padding: 4px 12px;
259
+  border: 2px solid #d8caba;
260
+  border-radius: 4px;
261
+  background: #eadfce;
262
+  color: #7b6b5c;
263
+  font-size: 14px;
264
+  box-sizing: border-box;
265
+}
266
+
267
+@media (max-width: 1100px) {
268
+  .page-title-row {
269
+    flex-direction: column;
270
+  }
271
+
272
+  .reload-button {
273
+    margin-top: 0;
274
+  }
275
+
276
+  .memorial-table {
277
+    overflow-x: auto;
278
+  }
279
+
280
+  .memorial-table-header,
281
+  .memorial-table-row {
282
+    min-width: 980px;
283
+  }
284
+}
285
+
286
+@media (max-width: 800px) {
287
+  .breadcrumb {
288
+    position: static;
289
+    transform: none;
290
+    padding: 16px 20px 0;
291
+  }
292
+
293
+  .memorial-list-page {
294
+    flex-direction: column;
295
+  }
296
+
297
+  .memorial-list-main {
298
+    width: 100%;
299
+    padding: 16px 20px 32px;
300
+  }
301
+
302
+  .memorial-panel {
303
+    padding: 24px 20px 30px;
304
+    border-radius: 32px;
305
+  }
306
+
307
+  .page-title-row h1 {
308
+    font-size: 26px;
309
+  }
310
+
311
+  .filter-row {
312
+    align-items: flex-start;
313
+    flex-direction: column;
314
+    gap: 14px;
315
+  }
316
+
317
+  .memorial-filter {
318
+    flex-wrap: wrap;
319
+  }
320
+
321
+  .list-header-row {
322
+    align-items: flex-start;
323
+    flex-direction: column;
324
+    gap: 8px;
325
+  }
326
+
327
+  .bottom-note {
328
+    width: auto;
329
+    margin: 10px 20px 22px;
330
+  }
331
+}

+ 22
- 0
src/app/pages/memorial-list/memorial-list.spec.ts Целия файл

@@ -0,0 +1,22 @@
1
+import { ComponentFixture, TestBed } from '@angular/core/testing';
2
+
3
+import { MemorialList } from './memorial-list';
4
+
5
+describe('MemorialList', () => {
6
+  let component: MemorialList;
7
+  let fixture: ComponentFixture<MemorialList>;
8
+
9
+  beforeEach(async () => {
10
+    await TestBed.configureTestingModule({
11
+      imports: [MemorialList],
12
+    }).compileComponents();
13
+
14
+    fixture = TestBed.createComponent(MemorialList);
15
+    component = fixture.componentInstance;
16
+    await fixture.whenStable();
17
+  });
18
+
19
+  it('should create', () => {
20
+    expect(component).toBeTruthy();
21
+  });
22
+});

+ 95
- 0
src/app/pages/memorial-list/memorial-list.ts Целия файл

@@ -0,0 +1,95 @@
1
+import { Component } from '@angular/core';
2
+import { ActivatedRoute, Router, RouterLink } from '@angular/router';
3
+import { Memorial } from '../../models/memorial';
4
+import { DankaService } from '../../services/dankaService';
5
+import { KakochoService } from '../../services/kakocho-service';
6
+import { AppHeader } from '../../share/header/app-header';
7
+import { AppSideMenu } from '../../share/side-menu/app-side-menu';
8
+import { FormsModule } from '@angular/forms';
9
+
10
+@Component({
11
+  selector: 'app-memorial-list',
12
+  imports: [AppHeader, AppSideMenu, RouterLink, FormsModule],
13
+  templateUrl: './memorial-list.html',
14
+  styleUrl: './memorial-list.scss',
15
+})
16
+export class MemorialList {
17
+  memorialList: Memorial[] = [];
18
+  targetYear: number = 2026;
19
+  selectedMemorialType = 'all';
20
+  memorialTypeFilters = [
21
+    { label: 'すべて', value: 'all' },
22
+    { label: '一周忌', value: '一周忌' },
23
+    { label: '三回忌', value: '三回忌' },
24
+    { label: '七回忌', value: '七回忌' },
25
+    { label: '十三回忌', value: '十三回忌' },
26
+  ];
27
+
28
+  constructor(
29
+    private dankaService: DankaService,
30
+    private kakochoService: KakochoService,
31
+  ) {
32
+    this.createMemorialList();
33
+  }
34
+
35
+  createMemorialList(): void {
36
+    this.memorialList = [];
37
+    const kakochoList = this.kakochoService.getKakochoList();
38
+
39
+    kakochoList.forEach((kakocho) => {
40
+      const deathYear = Number(kakocho.deathDate.slice(0, 4));
41
+      const yearDiff = this.targetYear - deathYear;
42
+      const memorialType = this.getMemorialType(yearDiff);
43
+
44
+      if (memorialType === '') {
45
+        return;
46
+      }
47
+
48
+      if (this.selectedMemorialType !== 'all' && this.selectedMemorialType !== memorialType) {
49
+        return;
50
+      }
51
+
52
+      const danka = this.dankaService.getDankaById(kakocho.dankaId);
53
+
54
+      const memorialTarget: Memorial = {
55
+        id: kakocho.id,
56
+        dankaId: kakocho.dankaId,
57
+        name: kakocho.name,
58
+        kaimyo: kakocho.kaimyo,
59
+        relationship: kakocho.relationship,
60
+        householdName: danka?.householdName ?? '不明',
61
+        deathDate: kakocho.deathDate,
62
+        memorialType: memorialType,
63
+      };
64
+      this.memorialList.push(memorialTarget);
65
+    });
66
+  }
67
+
68
+  changeMemorialType(memorialType: string): void {
69
+    this.selectedMemorialType = memorialType;
70
+    this.createMemorialList();
71
+  }
72
+
73
+  getMemorialType(yearDiff: number) {
74
+    switch (yearDiff) {
75
+      case 1:
76
+        return '一周忌';
77
+      case 2:
78
+        return '三回忌';
79
+      case 6:
80
+        return '七回忌';
81
+      case 12:
82
+        return '十三回忌';
83
+      case 16:
84
+        return '十七回忌';
85
+      case 22:
86
+        return '二十三回忌';
87
+      case 26:
88
+        return '二十七回忌';
89
+      case 32:
90
+        return '三十三回忌';
91
+      default:
92
+        return '';
93
+    }
94
+  }
95
+}

Loading…
Отказ
Запис