From 019412c72aff187c52bde6fb4c1fc3d4da4b60d9 Mon Sep 17 00:00:00 2001 From: shibafu Date: Sun, 24 May 2020 17:27:42 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=E3=82=B0=E3=83=A9=E3=83=95=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=82=92=E5=AF=BE=E8=B1=A1=E6=9C=9F=E9=96=93?= =?UTF-8?q?=E3=81=94=E3=81=A8=E3=81=AB=E6=8E=98=E3=82=8A=E4=B8=8B=E3=81=92?= =?UTF-8?q?=E3=82=8B=E5=BD=A2=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/UserController.php | 192 ++++++++++++------ resources/assets/js/user/stats.js | 78 +++---- .../views/components/profile-mini.blade.php | 14 ++ resources/views/user/base.blade.php | 15 +- resources/views/user/stats/all.blade.php | 20 ++ resources/views/user/stats/base.blade.php | 70 +++++++ resources/views/user/stats/monthly.blade.php | 17 ++ .../yearly.blade.php} | 22 +- routes/web.php | 5 +- 9 files changed, 302 insertions(+), 131 deletions(-) create mode 100644 resources/views/components/profile-mini.blade.php create mode 100644 resources/views/user/stats/all.blade.php create mode 100644 resources/views/user/stats/base.blade.php create mode 100644 resources/views/user/stats/monthly.blade.php rename resources/views/user/{stats.blade.php => stats/yearly.blade.php} (54%) diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index be151d4..8e12497 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use App\Ejaculation; use App\User; use Carbon\Carbon; +use Carbon\CarbonInterface; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; @@ -63,80 +64,56 @@ SQL return view('user.profile')->with(compact('user', 'ejaculations', 'tags')); } - public function stats($name) + public function statsAll($name) { $user = User::where('name', $name)->first(); if (empty($user)) { abort(404); } - $dateUntil = now()->addMonth()->startOfMonth(); + $availableMonths = $this->makeStatsAvailableMonths($user); + $graphData = $this->makeGraphData($user); - $groupByDay = Ejaculation::select(DB::raw( - <<<'SQL' -to_char(ejaculated_date, 'YYYY/MM/DD') AS "date", -count(*) AS "count" -SQL - )) - ->where('user_id', $user->id) - ->where('ejaculated_date', '<', $dateUntil) - ->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) - ->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) - ->get(); + return view('user.stats.all')->with(compact('user', 'graphData', 'availableMonths')); + } - $groupByHour = Ejaculation::select(DB::raw( - <<<'SQL' -to_char(ejaculated_date, 'HH24') AS "hour", -count(*) AS "count" -SQL - )) - ->where('user_id', $user->id) - ->where('ejaculated_date', '<', $dateUntil) - ->groupBy(DB::raw("to_char(ejaculated_date, 'HH24')")) - ->orderBy(DB::raw('1')) - ->get(); - - $dailySum = []; - $monthlySum = []; - $yearlySum = []; - $dowSum = array_fill(0, 7, 0); - $hourlySum = array_fill(0, 24, 0); - - // 年間グラフ用の配列初期化 - if ($groupByDay->first() !== null) { - $year = Carbon::createFromFormat('Y/m/d', $groupByDay->first()->date)->year; - $currentYear = date('Y'); - for (; $year <= $currentYear; $year++) { - $yearlySum[$year] = 0; - } + public function statsYearly($name, $year) + { + $user = User::where('name', $name)->first(); + if (empty($user)) { + abort(404); } - foreach ($groupByDay as $data) { - $date = Carbon::createFromFormat('Y/m/d', $data->date); - $yearAndMonth = $date->format('Y/m'); + $availableMonths = $this->makeStatsAvailableMonths($user); + $graphData = $this->makeGraphData( + $user, + Carbon::createFromDate($year, 1, 1, config('app.timezone'))->startOfDay(), + Carbon::createFromDate($year, 1, 1, config('app.timezone'))->addYear()->startOfDay() + ); - $dailySum[$date->timestamp] = $data->count; - $yearlySum[$date->year] += $data->count; - $dowSum[$date->dayOfWeek] += $data->count; - $monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count; + return view('user.stats.yearly') + ->with(compact('user', 'graphData', 'availableMonths')) + ->with('currentYear', (int) $year); + } + + public function statsMonthly($name, $year, $month) + { + $user = User::where('name', $name)->first(); + if (empty($user)) { + abort(404); } - foreach ($groupByHour as $data) { - $hour = (int)$data->hour; - $hourlySum[$hour] += $data->count; - } + $availableMonths = $this->makeStatsAvailableMonths($user); + $graphData = $this->makeGraphData( + $user, + Carbon::createFromDate($year, $month, 1, config('app.timezone'))->startOfDay(), + Carbon::createFromDate($year, $month, 1, config('app.timezone'))->addMonth()->startOfDay() + ); - $graphData = [ - 'dailySum' => $dailySum, - 'dowSum' => $dowSum, - 'monthlySum' => $monthlySum, - 'yearlyKey' => array_keys($yearlySum), - 'yearlySum' => array_values($yearlySum), - 'hourlyKey' => array_keys($hourlySum), - 'hourlySum' => array_values($hourlySum), - ]; - - return view('user.stats')->with(compact('user', 'graphData')); + return view('user.stats.monthly') + ->with(compact('user', 'graphData', 'availableMonths')) + ->with('currentYear', (int) $year) + ->with('currentMonth', (int) $month); } public function okazu($name) @@ -191,4 +168,99 @@ SQL return view('user.likes')->with(compact('user', 'likes')); } + + private function makeStatsAvailableMonths(User $user): array + { + $availableMonths = []; + $oldest = $user->ejaculations()->orderBy('ejaculated_date')->first(); + if (isset($oldest)) { + $oldestMonth = $oldest->ejaculated_date->startOfMonth(); + $currentMonth = now()->startOfMonth(); + for ($month = $currentMonth; $oldestMonth <= $currentMonth; $month = $month->subMonth()) { + if (!isset($availableMonths[$month->year])) { + $availableMonths[$month->year] = []; + } + $availableMonths[$month->year][] = $month->month; + } + } + + return $availableMonths; + } + + private function makeGraphData(User $user, CarbonInterface $dateSince = null, CarbonInterface $dateUntil = null): array + { + if ($dateUntil === null) { + $dateUntil = now()->addMonth()->startOfMonth(); + } + $dateCondition = [ + ['ejaculated_date', '<', $dateUntil], + ]; + if ($dateSince !== null) { + $dateCondition[] = ['ejaculated_date', '>=', $dateSince]; + } + + $groupByDay = Ejaculation::select(DB::raw( + <<<'SQL' +to_char(ejaculated_date, 'YYYY/MM/DD') AS "date", +count(*) AS "count" +SQL + )) + ->where('user_id', $user->id) + ->where($dateCondition) + ->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) + ->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) + ->get(); + + $groupByHour = Ejaculation::select(DB::raw( + <<<'SQL' +to_char(ejaculated_date, 'HH24') AS "hour", +count(*) AS "count" +SQL + )) + ->where('user_id', $user->id) + ->where($dateCondition) + ->groupBy(DB::raw("to_char(ejaculated_date, 'HH24')")) + ->orderBy(DB::raw('1')) + ->get(); + + $dailySum = []; + $monthlySum = []; + $yearlySum = []; + $dowSum = array_fill(0, 7, 0); + $hourlySum = array_fill(0, 24, 0); + + // 年間グラフ用の配列初期化 + if ($groupByDay->first() !== null) { + $year = Carbon::createFromFormat('Y/m/d', $groupByDay->first()->date)->year; + $currentYear = date('Y'); + for (; $year <= $currentYear; $year++) { + $yearlySum[$year] = 0; + } + } + + foreach ($groupByDay as $data) { + $date = Carbon::createFromFormat('Y/m/d', $data->date); + $yearAndMonth = $date->format('Y/m'); + + $dailySum[$date->timestamp] = $data->count; + $yearlySum[$date->year] += $data->count; + $dowSum[$date->dayOfWeek] += $data->count; + $monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count; + } + + foreach ($groupByHour as $data) { + $hour = (int)$data->hour; + $hourlySum[$hour] += $data->count; + } + + return [ + 'dailySum' => $dailySum, + 'dowSum' => $dowSum, + 'monthlySum' => $monthlySum, + 'yearlyKey' => array_keys($yearlySum), + 'yearlySum' => array_values($yearlySum), + 'hourlyKey' => array_keys($hourlySum), + 'hourlySum' => array_values($hourlySum), + ]; + } } diff --git a/resources/assets/js/user/stats.js b/resources/assets/js/user/stats.js index 2bc1c7c..d1fda72 100644 --- a/resources/assets/js/user/stats.js +++ b/resources/assets/js/user/stats.js @@ -1,6 +1,6 @@ import CalHeatMap from 'cal-heatmap'; import Chart from 'chart.js'; -import {addMonths, format, startOfMonth, subMonths} from 'date-fns'; +import {addMonths, format} from 'date-fns'; const graphData = JSON.parse(document.getElementById('graph-data').textContent); @@ -90,53 +90,35 @@ function createMonthlyGraphData(from) { return {keys, values}; } -new CalHeatMap().init({ - itemSelector: '#cal-heatmap', - domain: 'month', - subDomain: 'day', - domainLabelFormat: '%Y/%m', - weekStartOnMonday: false, - start: new Date().setMonth(new Date().getMonth() - 9), - range: 10, - data: graphData.dailySum, - legend: [1, 2, 3, 4] -}); - -// 直近1年の月間グラフのデータを準備 -const monthlyTermFrom = subMonths(startOfMonth(new Date()), 11); -const {keys: monthlyKey, values: monthlySum} = createMonthlyGraphData(monthlyTermFrom); - -const monthlyGraph = createLineGraph('monthly-graph', monthlyKey, monthlySum); -createLineGraph('yearly-graph', graphData.yearlyKey, graphData.yearlySum); -createBarGraph('hourly-graph', graphData.hourlyKey, graphData.hourlySum); -createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], graphData.dowSum); - -// 月間グラフの期間セレクターを準備 -const monthlyTermSelector = document.getElementById('monthly-term'); -const earliestYear = [...new Set(Object.keys(graphData.monthlySum).map(v => v.substr(0, 4)))].shift(); -for (let year = earliestYear; year <= new Date().getFullYear(); year++) { - const opt = document.createElement('option'); - opt.setAttribute('value', year); - opt.textContent = `${year}年`; - monthlyTermSelector.insertBefore(opt, monthlyTermSelector.firstChild); -} -if (monthlyTermSelector.children.length) { - monthlyTermSelector.selectedIndex = 0; +function getCurrentYear() { + const year = location.pathname.split('/').pop(); + return /^(20[0-9]{2})$/.test(year) ? year : null; } -monthlyTermSelector.addEventListener('change', function (e) { - let monthlyTermFrom; - if (e.target.selectedIndex === 0) { - // 今年のデータを表示する時は、直近12ヶ月を表示 - monthlyTermFrom = subMonths(startOfMonth(new Date()), 11); - } else { - // 過去のデータを表示する時は、選択年の1〜12月を表示 - monthlyTermFrom = new Date(e.target.value, 0, 1); - } +if (document.getElementById('cal-heatmap')) { + new CalHeatMap().init({ + itemSelector: '#cal-heatmap', + domain: 'month', + subDomain: 'day', + domainLabelFormat: '%Y/%m', + weekStartOnMonday: false, + start: new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0), + range: 12, + data: graphData.dailySum, + legend: [1, 2, 3, 4] + }); +} - const {keys, values} = createMonthlyGraphData(monthlyTermFrom); - - monthlyGraph.data.labels = keys; - monthlyGraph.data.datasets[0].data = values; - monthlyGraph.update(); -}); +if (document.getElementById('monthly-graph')) { + const {keys: monthlyKey, values: monthlySum} = createMonthlyGraphData(new Date(getCurrentYear(), 0, 1, 0, 0, 0, 0)); + createLineGraph('monthly-graph', monthlyKey, monthlySum); +} +if (document.getElementById('yearly-graph')) { + createLineGraph('yearly-graph', graphData.yearlyKey, graphData.yearlySum); +} +if (document.getElementById('hourly-graph')) { + createBarGraph('hourly-graph', graphData.hourlyKey, graphData.hourlySum); +} +if (document.getElementById('dow-graph')) { + createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], graphData.dowSum); +} diff --git a/resources/views/components/profile-mini.blade.php b/resources/views/components/profile-mini.blade.php new file mode 100644 index 0000000..58e72b5 --- /dev/null +++ b/resources/views/components/profile-mini.blade.php @@ -0,0 +1,14 @@ +
+ +
+
+ {{ $user->display_name }} +
+
+ @{{ $user->name }} + @if ($user->is_protected) + + @endif +
+
+
diff --git a/resources/views/user/base.blade.php b/resources/views/user/base.blade.php index 49598ac..67c49ee 100644 --- a/resources/views/user/base.blade.php +++ b/resources/views/user/base.blade.php @@ -4,8 +4,17 @@
- @component('components.profile', ['user' => $user]) - @endcomponent + @if (Route::currentRouteName() === 'user.profile') + @component('components.profile', ['user' => $user]) + @endcomponent + @else +
+
+ @component('components.profile-mini', ['user' => $user]) + @endcomponent +
+
+ @endif @section('sidebar') @show
@@ -15,7 +24,7 @@ タイムライン - @if (Route::currentRouteName() === 'user.stats.all') + @if (Route::currentRouteName() === 'user.stats') From 8fb8677406dedca773c430553487a1e20c16a6d5 Mon Sep 17 00:00:00 2001 From: shibafu Date: Sun, 24 May 2020 19:03:15 +0900 Subject: [PATCH 7/7] =?UTF-8?q?=E3=83=97=E3=83=AD=E3=83=95=E3=82=A3?= =?UTF-8?q?=E3=83=BC=E3=83=AB=E3=83=88=E3=83=83=E3=83=97=E3=81=AB=E6=9C=80?= =?UTF-8?q?=E8=BF=91=E3=81=AE=E3=82=B7=E3=82=B3=E8=8D=89=E3=82=92=E7=A7=BB?= =?UTF-8?q?=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/UserController.php | 36 ++++++++++++++++++------- resources/assets/js/user/profile.js | 15 +++++++++++ resources/views/user/profile.blade.php | 18 +++++++++++++ webpack.mix.js | 1 + 4 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 resources/assets/js/user/profile.js diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 3c51369..618997c 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -62,7 +62,18 @@ SQL ->limit(10) ->get(); - return view('user.profile')->with(compact('user', 'ejaculations', 'tags')); + // シコ草 + $countByDayQuery = $this->countEjaculationByDay($user) + ->where('ejaculated_date', '>=', now()->startOfMonth()->subMonths(9)) + ->where('ejaculated_date', '<', now()->addMonth()->startOfMonth()) + ->get(); + $countByDay = []; + foreach ($countByDayQuery as $data) { + $date = Carbon::createFromFormat('Y/m/d', $data->date); + $countByDay[$date->timestamp] = $data->count; + } + + return view('user.profile')->with(compact('user', 'ejaculations', 'tags', 'countByDay')); } public function stats($name) @@ -223,16 +234,8 @@ SQL $dateCondition[] = ['ejaculated_date', '>=', $dateSince]; } - $groupByDay = Ejaculation::select(DB::raw( - <<<'SQL' -to_char(ejaculated_date, 'YYYY/MM/DD') AS "date", -count(*) AS "count" -SQL - )) - ->where('user_id', $user->id) + $groupByDay = $this->countEjaculationByDay($user) ->where($dateCondition) - ->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) - ->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) ->get(); $groupByHour = Ejaculation::select(DB::raw( @@ -287,4 +290,17 @@ SQL 'hourlySum' => array_values($hourlySum), ]; } + + private function countEjaculationByDay(User $user) + { + return Ejaculation::select(DB::raw( + <<<'SQL' +to_char(ejaculated_date, 'YYYY/MM/DD') AS "date", +count(*) AS "count" +SQL + )) + ->where('user_id', $user->id) + ->groupBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")) + ->orderBy(DB::raw("to_char(ejaculated_date, 'YYYY/MM/DD')")); + } } diff --git a/resources/assets/js/user/profile.js b/resources/assets/js/user/profile.js new file mode 100644 index 0000000..24cba77 --- /dev/null +++ b/resources/assets/js/user/profile.js @@ -0,0 +1,15 @@ +import CalHeatMap from 'cal-heatmap'; + +if (document.getElementById('cal-heatmap')) { + new CalHeatMap().init({ + itemSelector: '#cal-heatmap', + domain: 'month', + subDomain: 'day', + domainLabelFormat: '%Y/%m', + weekStartOnMonday: false, + start: new Date().setMonth(new Date().getMonth() - 9), + range: 10, + data: JSON.parse(document.getElementById('count-by-day').textContent), + legend: [1, 2, 3, 4] + }); +} diff --git a/resources/views/user/profile.blade.php b/resources/views/user/profile.blade.php index 5823026..978a39a 100644 --- a/resources/views/user/profile.blade.php +++ b/resources/views/user/profile.blade.php @@ -2,6 +2,12 @@ @section('title', $user->display_name . ' (@' . $user->name . ')') +@push('head') + @if (Route::currentRouteName() === 'user.profile') + + @endif +@endpush + @section('sidebar') {{-- TODO: タイムラインとオカズのテンプレを分けたら条件外す --}} @if (Route::currentRouteName() === 'user.profile') @@ -32,6 +38,11 @@ このユーザはチェックイン履歴を公開していません。

@else + @if ($ejaculations->count() !== 0 && $ejaculations->currentPage() === 1) +
Shikontributions
+
+
+ @endif
    @forelse ($ejaculations as $ejaculation)
  • @@ -116,3 +127,10 @@ @endslot @endcomponent @endsection + +@push('script') + + + +@endpush + diff --git a/webpack.mix.js b/webpack.mix.js index 59b6cee..94f9909 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -14,6 +14,7 @@ require('laravel-mix-bundle-analyzer') mix.js('resources/assets/js/app.js', 'public/js') .js('resources/assets/js/home.js', 'public/js') + .js('resources/assets/js/user/profile.js', 'public/js/user') .js('resources/assets/js/user/stats.js', 'public/js/user') .js('resources/assets/js/setting/privacy.js', 'public/js/setting') .js('resources/assets/js/setting/import.js', 'public/js/setting')