Skip to content

Commit bd33bd2

Browse files
authored
Merge pull request #143 from DevKor-github/develop
#142까지 반영해 배포
2 parents dd2f191 + 13908c6 commit bd33bd2

9 files changed

Lines changed: 86 additions & 17 deletions

File tree

src/main/java/com/devkor/ifive/nadab/domain/stats/application/MonthlyStatsService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,13 @@ public MonthlyStatsViewModel getMonthlyStatsLast5Months() {
5656
Map<YearMonth, Long> completedMap = aggregateByMonth(
5757
repo.findCompletedMonthlyReportCountsByDateBetween(startDate, endDateInclusive)
5858
);
59+
Map<YearMonth, Long> completedDailyMap = aggregateByMonth(
60+
repo.findCompletedDailyReportCountsByDateBetween(startDate, endDateInclusive)
61+
);
5962

6063
List<Long> signupCounts = months.stream().map(m -> signupMap.getOrDefault(m, 0L)).toList();
6164
List<Long> assignedCounts = months.stream().map(m -> assignedMap.getOrDefault(m, 0L)).toList();
65+
List<Long> completedDailyCounts = months.stream().map(m -> completedDailyMap.getOrDefault(m, 0L)).toList();
6266
List<Long> completedCounts = months.stream().map(m -> completedMap.getOrDefault(m, 0L)).toList();
6367

6468
long inProgressNow = repo.countInProgressMonthlyReportsNow();
@@ -67,6 +71,7 @@ public MonthlyStatsViewModel getMonthlyStatsLast5Months() {
6771
labels,
6872
signupCounts,
6973
assignedCounts,
74+
completedDailyCounts,
7075
completedCounts,
7176
inProgressNow,
7277
OffsetDateTime.now(SEOUL).format(FMT)

src/main/java/com/devkor/ifive/nadab/domain/stats/application/WeeklyStatsService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,13 @@ public WeeklyStatsViewModel getWeeklyStatsLast7Weeks() {
5555
Map<LocalDate, Long> completedMap = aggregateByWeekStart(
5656
repo.findCompletedWeeklyReportCountsByDateBetween(startWeekStart, endDateInclusive)
5757
);
58+
Map<LocalDate, Long> completedDailyMap = aggregateByWeekStart(
59+
repo.findCompletedDailyReportCountsByDateBetween(startWeekStart, endDateInclusive)
60+
);
5861

5962
List<Long> signupCounts = weekStarts.stream().map(d -> signupMap.getOrDefault(d, 0L)).toList();
6063
List<Long> assignedCounts = weekStarts.stream().map(d -> assignedMap.getOrDefault(d, 0L)).toList();
64+
List<Long> completedDailyCounts = weekStarts.stream().map(d -> completedDailyMap.getOrDefault(d, 0L)).toList();
6165
List<Long> completedCounts = weekStarts.stream().map(d -> completedMap.getOrDefault(d, 0L)).toList();
6266

6367
long inProgressNow = repo.countInProgressWeeklyReportsNow();
@@ -66,6 +70,7 @@ public WeeklyStatsViewModel getWeeklyStatsLast7Weeks() {
6670
labels,
6771
signupCounts,
6872
assignedCounts,
73+
completedDailyCounts,
6974
completedCounts,
7075
inProgressNow,
7176
OffsetDateTime.now(SEOUL).format(FMT)

src/main/java/com/devkor/ifive/nadab/domain/stats/core/dto/monthly/MonthlyStatsViewModel.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public record MonthlyStatsViewModel(
66
List<String> labels,
77
List<Long> signupCounts,
88
List<Long> assignedQuestionCounts,
9+
List<Long> completedDailyReportCounts,
910
List<Long> completedMonthlyReportCounts,
1011
long inProgressMonthlyReportCount,
1112
String refreshedAt

src/main/java/com/devkor/ifive/nadab/domain/stats/core/dto/weekly/WeeklyStatsViewModel.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ public record WeeklyStatsViewModel(
66
List<String> labels,
77
List<Long> signupCounts,
88
List<Long> assignedQuestionCounts,
9+
List<Long> completedDailyReportCounts,
910
List<Long> completedWeeklyReportCounts,
1011
long inProgressWeeklyReportCount,
1112
String refreshedAt

src/main/java/com/devkor/ifive/nadab/domain/stats/core/repository/MonthlyStatsRepository.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ public List<DateCountDto> findCompletedMonthlyReportCountsByDateBetween(LocalDat
6969
.getResultList();
7070
}
7171

72+
public List<DateCountDto> findCompletedDailyReportCountsByDateBetween(LocalDate startDate, LocalDate endDateInclusive) {
73+
return em.createQuery("""
74+
select new com.devkor.ifive.nadab.domain.stats.core.dto.daily.DateCountDto(dr.date, count(dr.id))
75+
from DailyReport dr
76+
where dr.date between :startDate and :endDate
77+
and dr.status = com.devkor.ifive.nadab.domain.dailyreport.core.entity.DailyReportStatus.COMPLETED
78+
group by dr.date
79+
order by dr.date
80+
""", DateCountDto.class)
81+
.setParameter("startDate", startDate)
82+
.setParameter("endDate", endDateInclusive)
83+
.getResultList();
84+
}
85+
7286
public long countInProgressMonthlyReportsNow() {
7387
return em.createQuery("""
7488
select count(mr.id)

src/main/java/com/devkor/ifive/nadab/domain/stats/core/repository/WeeklyStatsRepository.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ public List<DateCountDto> findCompletedWeeklyReportCountsByDateBetween(
7272
.getResultList();
7373
}
7474

75+
public List<DateCountDto> findCompletedDailyReportCountsByDateBetween(
76+
LocalDate startDate,
77+
LocalDate endDateInclusive
78+
) {
79+
return em.createQuery("""
80+
select new com.devkor.ifive.nadab.domain.stats.core.dto.daily.DateCountDto(dr.date, count(dr.id))
81+
from DailyReport dr
82+
where dr.date between :startDate and :endDate
83+
and dr.status = com.devkor.ifive.nadab.domain.dailyreport.core.entity.DailyReportStatus.COMPLETED
84+
group by dr.date
85+
order by dr.date
86+
""", DateCountDto.class)
87+
.setParameter("startDate", startDate)
88+
.setParameter("endDate", endDateInclusive)
89+
.getResultList();
90+
}
91+
7592
public long countInProgressWeeklyReportsNow() {
7693
return em.createQuery("""
7794
select count(wr.id)

src/main/java/com/devkor/ifive/nadab/domain/user/application/helper/NicknameValidator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public NicknameValidationResultDto validateNickname(String nickname) {
2929
return NicknameValidationResultDto.fail("닉네임은 2자 이상 10자 이하여야 합니다.");
3030
}
3131

32+
// 한글 자모(ㄱ-ㅎ, ㅏ-ㅣ) 포함 금지
33+
if (nickname.matches(".*[ㄱ-ㅎㅏ-ㅣ].*")) {
34+
return NicknameValidationResultDto.fail("닉네임에는 완성되지 않은 한글을 사용할 수 없습니다.");
35+
}
36+
3237
// 한글/영문만 허용
3338
if (!nickname.matches("^[가-힣a-zA-Z]+$")) {
3439
return NicknameValidationResultDto.fail("닉네임은 한글과 영문만 사용할 수 있습니다.");

src/main/resources/templates/stats/monthly.html

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,8 @@
179179
grid-template-columns: repeat(2, 1fr);
180180
gap: 20px;
181181
}
182-
.chart-card-wide { grid-column: 1 / -1; }
183-
184182
@media (max-width: 800px) {
185183
.charts-grid { grid-template-columns: 1fr; }
186-
.chart-card-wide { grid-column: unset; }
187184
}
188185

189186
.chart-card {
@@ -222,6 +219,7 @@
222219
.dot-blue { background: var(--accent); }
223220
.dot-pink { background: var(--accent-2); }
224221
.dot-teal { background: var(--accent-3); }
222+
.dot-orange { background: #f5a524; }
225223
</style>
226224
</head>
227225
<body>
@@ -289,13 +287,23 @@
289287
</div>
290288
</div>
291289

292-
<div class="chart-card chart-card-wide">
290+
<div class="chart-card">
291+
<div class="chart-card-header">
292+
<div class="chart-card-title"><span class="dot dot-teal"></span>생성된 일간 리포트 수</div>
293+
<div class="chart-card-subtitle">최근 5개월</div>
294+
</div>
295+
<div class="chart-card-body">
296+
<canvas id="completedDailyChart" height="140"></canvas>
297+
</div>
298+
</div>
299+
300+
<div class="chart-card">
293301
<div class="chart-card-header">
294-
<div class="chart-card-title"><span class="dot dot-teal"></span>생성된 월간 리포트 수</div>
302+
<div class="chart-card-title"><span class="dot dot-orange"></span>생성된 월간 리포트 수</div>
295303
<div class="chart-card-subtitle">최근 5개월</div>
296304
</div>
297305
<div class="chart-card-body">
298-
<canvas id="completedChart" height="90"></canvas>
306+
<canvas id="completedMonthlyChart" height="140"></canvas>
299307
</div>
300308
</div>
301309
</div>
@@ -304,7 +312,8 @@
304312
const labels = [[${vm.labels}]];
305313
const signupCounts = [[${vm.signupCounts}]].map(v => parseInt(v, 10));
306314
const assignedCounts = [[${vm.assignedQuestionCounts}]].map(v => parseInt(v, 10));
307-
const completedCounts = [[${vm.completedMonthlyReportCounts}]].map(v => parseInt(v, 10));
315+
const completedDailyCounts = [[${vm.completedDailyReportCounts}]].map(v => parseInt(v, 10));
316+
const completedMonthlyCounts = [[${vm.completedMonthlyReportCounts}]].map(v => parseInt(v, 10));
308317

309318
Chart.defaults.color = '#8b91a8';
310319
Chart.defaults.font.family = "'DM Mono', monospace";
@@ -323,7 +332,8 @@
323332
const configs = [
324333
{ id: 'signupChart', label: '가입자 수', data: signupCounts, color: 'rgba(108,143,255,1)' },
325334
{ id: 'assignedChart', label: '할당 질문 수', data: assignedCounts, color: 'rgba(255,126,179,1)' },
326-
{ id: 'completedChart', label: '월간 리포트 생성 수', data: completedCounts, color: 'rgba(77,232,194,1)' },
335+
{ id: 'completedDailyChart', label: '일간 리포트 생성 수', data: completedDailyCounts, color: 'rgba(77,232,194,1)' },
336+
{ id: 'completedMonthlyChart', label: '월간 리포트 생성 수', data: completedMonthlyCounts, color: 'rgba(245,165,36,1)' },
327337
];
328338

329339
configs.forEach(({ id, label, data, color }) => {

src/main/resources/templates/stats/weekly.html

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,8 @@
179179
grid-template-columns: repeat(2, 1fr);
180180
gap: 20px;
181181
}
182-
.chart-card-wide { grid-column: 1 / -1; }
183-
184182
@media (max-width: 800px) {
185183
.charts-grid { grid-template-columns: 1fr; }
186-
.chart-card-wide { grid-column: unset; }
187184
}
188185

189186
.chart-card {
@@ -222,6 +219,7 @@
222219
.dot-blue { background: var(--accent); }
223220
.dot-pink { background: var(--accent-2); }
224221
.dot-teal { background: var(--accent-3); }
222+
.dot-orange { background: #f5a524; }
225223
</style>
226224
</head>
227225
<body>
@@ -289,13 +287,23 @@
289287
</div>
290288
</div>
291289

292-
<div class="chart-card chart-card-wide">
290+
<div class="chart-card">
291+
<div class="chart-card-header">
292+
<div class="chart-card-title"><span class="dot dot-teal"></span>생성된 일간 리포트 수</div>
293+
<div class="chart-card-subtitle">최근 5주</div>
294+
</div>
295+
<div class="chart-card-body">
296+
<canvas id="completedDailyChart" height="140"></canvas>
297+
</div>
298+
</div>
299+
300+
<div class="chart-card">
293301
<div class="chart-card-header">
294-
<div class="chart-card-title"><span class="dot dot-teal"></span>생성된 주간 리포트 수</div>
302+
<div class="chart-card-title"><span class="dot dot-orange"></span>생성된 주간 리포트 수</div>
295303
<div class="chart-card-subtitle">최근 5주</div>
296304
</div>
297305
<div class="chart-card-body">
298-
<canvas id="completedChart" height="90"></canvas>
306+
<canvas id="completedWeeklyChart" height="140"></canvas>
299307
</div>
300308
</div>
301309
</div>
@@ -304,7 +312,8 @@
304312
const rawLabels = [[${vm.labels}]];
305313
const rawSignupCounts = [[${vm.signupCounts}]].map(v => parseInt(v, 10));
306314
const rawAssignedCounts = [[${vm.assignedQuestionCounts}]].map(v => parseInt(v, 10));
307-
const rawCompletedCounts = [[${vm.completedWeeklyReportCounts}]].map(v => parseInt(v, 10));
315+
const rawCompletedDailyCounts = [[${vm.completedDailyReportCounts}]].map(v => parseInt(v, 10));
316+
const rawCompletedWeeklyCounts = [[${vm.completedWeeklyReportCounts}]].map(v => parseInt(v, 10));
308317

309318
const slicedRawLabels = rawLabels.slice(-5);
310319
const labels = slicedRawLabels.map(label => {
@@ -313,7 +322,8 @@
313322
});
314323
const signupCounts = rawSignupCounts.slice(-5);
315324
const assignedCounts = rawAssignedCounts.slice(-5);
316-
const completedCounts = rawCompletedCounts.slice(-5);
325+
const completedDailyCounts = rawCompletedDailyCounts.slice(-5);
326+
const completedWeeklyCounts = rawCompletedWeeklyCounts.slice(-5);
317327

318328
Chart.defaults.color = '#8b91a8';
319329
Chart.defaults.font.family = "'DM Mono', monospace";
@@ -332,7 +342,8 @@
332342
const configs = [
333343
{ id: 'signupChart', label: '가입자 수', data: signupCounts, color: 'rgba(108,143,255,1)' },
334344
{ id: 'assignedChart', label: '할당 질문 수', data: assignedCounts, color: 'rgba(255,126,179,1)' },
335-
{ id: 'completedChart', label: '주간 리포트 생성 수', data: completedCounts, color: 'rgba(77,232,194,1)' },
345+
{ id: 'completedDailyChart', label: '일간 리포트 생성 수', data: completedDailyCounts, color: 'rgba(77,232,194,1)' },
346+
{ id: 'completedWeeklyChart', label: '주간 리포트 생성 수', data: completedWeeklyCounts, color: 'rgba(245,165,36,1)' },
336347
];
337348

338349
configs.forEach(({ id, label, data, color }) => {

0 commit comments

Comments
 (0)