|
@@ -6,8 +6,8 @@
|
|
|
<div class="col-12">
|
|
<div class="col-12">
|
|
|
<div class="card">
|
|
<div class="card">
|
|
|
<div class="card-header d-flex align-items-center justify-content-between">
|
|
<div class="card-header d-flex align-items-center justify-content-between">
|
|
|
- <h3 class="card-title mb-0">1234 权重配置 & 点击统计</h3>
|
|
|
|
|
- <small class="text-muted">配置 1/2/3/4 的权重(整数),前端按权重抽取,后台记录用户点击</small>
|
|
|
|
|
|
|
+ <h3 class="card-title mb-0">1234 权重配置 & 数据统计</h3>
|
|
|
|
|
+ <small class="text-muted">配置 1/2/3/4 权重;带 <code>show</code> 只记曝光;每日明细 Redis 保留约 3 天</small>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="card-body">
|
|
<div class="card-body">
|
|
|
<ul class="nav nav-tabs mb-3" role="tablist">
|
|
<ul class="nav nav-tabs mb-3" role="tablist">
|
|
@@ -18,7 +18,7 @@
|
|
|
</li>
|
|
</li>
|
|
|
<li class="nav-item">
|
|
<li class="nav-item">
|
|
|
<a class="nav-link" data-toggle="tab" href="#tab-stats" role="tab">
|
|
<a class="nav-link" data-toggle="tab" href="#tab-stats" role="tab">
|
|
|
- <i class="mdi mdi-chart-bar"></i> 点击统计
|
|
|
|
|
|
|
+ <i class="mdi mdi-chart-bar"></i> 数据统计
|
|
|
</a>
|
|
</a>
|
|
|
</li>
|
|
</li>
|
|
|
</ul>
|
|
</ul>
|
|
@@ -71,74 +71,138 @@
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="tab-pane fade" id="tab-stats" role="tabpanel">
|
|
<div class="tab-pane fade" id="tab-stats" role="tabpanel">
|
|
|
- <div class="d-flex align-items-center justify-content-between mb-3">
|
|
|
|
|
- <h5 class="mb-0">总点击统计</h5>
|
|
|
|
|
- <button class="btn btn-sm btn-outline-danger" id="reset-stats">
|
|
|
|
|
- <i class="mdi mdi-delete"></i> 清除总统计
|
|
|
|
|
- </button>
|
|
|
|
|
|
|
+ @php
|
|
|
|
|
+ $chartIds = [1, 2, 3, 4];
|
|
|
|
|
+ $chartTodayShows = array_map(fn ($id) => (int) ($todayShows[$id] ?? 0), $chartIds);
|
|
|
|
|
+ $chartTodayClicks = array_map(fn ($id) => (int) ($todayClicks[$id] ?? 0), $chartIds);
|
|
|
|
|
+ $chartTotalShows = array_map(fn ($id) => (int) ($totalShows[$id] ?? 0), $chartIds);
|
|
|
|
|
+ $chartTotalClicks = array_map(fn ($id) => (int) ($totalClicks[$id] ?? 0), $chartIds);
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <div class="card border mb-4 shadow-sm">
|
|
|
|
|
+ <div class="card-body">
|
|
|
|
|
+ <div class="d-flex flex-wrap align-items-center justify-content-between mb-2">
|
|
|
|
|
+ <h5 class="card-title mb-0">曝光 & 点击(按 ID)</h5>
|
|
|
|
|
+ <div class="btn-group btn-group-sm" role="group" aria-label="统计维度">
|
|
|
|
|
+ <button type="button" class="btn btn-outline-primary active weight-chart-mode" data-mode="today">当天</button>
|
|
|
|
|
+ <button type="button" class="btn btn-outline-primary weight-chart-mode" data-mode="total">总计</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <p class="text-muted small mb-3 mb-md-2">
|
|
|
|
|
+ <span id="weight-chart-subtitle">当天数据 · {{ date('Y-m-d') }}</span>
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <div id="weight-stats-chart" style="width:100%;height:340px;"></div>
|
|
|
|
|
+ <div class="d-flex justify-content-center align-items-center mt-2 small text-muted">
|
|
|
|
|
+ <span class="mr-3"><span class="weight-chart-legend-swatch" style="background:#c8bdb0;"></span> 曝光(show)</span>
|
|
|
|
|
+ <span><span class="weight-chart-legend-swatch" style="background:#2563eb;"></span> 点击</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ <h5 class="mb-3">总计(Redis 累计)</h5>
|
|
|
@php
|
|
@php
|
|
|
$totalClicksAll = array_sum($totalClicks);
|
|
$totalClicksAll = array_sum($totalClicks);
|
|
|
|
|
+ $totalShowsAll = array_sum($totalShows);
|
|
|
@endphp
|
|
@endphp
|
|
|
<div class="table-responsive mb-4">
|
|
<div class="table-responsive mb-4">
|
|
|
- <table class="table table-bordered align-middle" style="max-width: 600px;">
|
|
|
|
|
|
|
+ <table class="table table-bordered align-middle weight-stats-merge-table" style="max-width: 920px;">
|
|
|
<thead class="thead-light">
|
|
<thead class="thead-light">
|
|
|
<tr>
|
|
<tr>
|
|
|
<th>ID</th>
|
|
<th>ID</th>
|
|
|
- <th>点击次数</th>
|
|
|
|
|
- <th>占比</th>
|
|
|
|
|
|
|
+ <th class="text-right">曝光</th>
|
|
|
|
|
+ <th class="text-right">曝光%</th>
|
|
|
|
|
+ <th class="text-right">点击</th>
|
|
|
|
|
+ <th class="text-right">点击%</th>
|
|
|
|
|
+ <th class="text-center" style="min-width:140px;">操作</th>
|
|
|
</tr>
|
|
</tr>
|
|
|
</thead>
|
|
</thead>
|
|
|
<tbody>
|
|
<tbody>
|
|
|
@foreach([1,2,3,4] as $id)
|
|
@foreach([1,2,3,4] as $id)
|
|
|
@php
|
|
@php
|
|
|
$c = intval($totalClicks[$id] ?? 0);
|
|
$c = intval($totalClicks[$id] ?? 0);
|
|
|
- $p = $totalClicksAll > 0 ? round($c / $totalClicksAll * 100, 2) : 0;
|
|
|
|
|
|
|
+ $s = intval($totalShows[$id] ?? 0);
|
|
|
|
|
+ $pClick = $totalClicksAll > 0 ? round($c / $totalClicksAll * 100, 2) : 0;
|
|
|
|
|
+ $pShow = $totalShowsAll > 0 ? round($s / $totalShowsAll * 100, 2) : 0;
|
|
|
@endphp
|
|
@endphp
|
|
|
<tr>
|
|
<tr>
|
|
|
- <td><span class="badge badge-info">{{ $id }}</span></td>
|
|
|
|
|
- <td>{{ $c }}</td>
|
|
|
|
|
- <td>{{ $p }}%</td>
|
|
|
|
|
|
|
+ <td><span class="badge badge-primary">{{ $id }}</span></td>
|
|
|
|
|
+ <td class="text-right">{{ $s }}</td>
|
|
|
|
|
+ <td class="text-right">{{ $pShow }}%</td>
|
|
|
|
|
+ <td class="text-right">{{ $c }}</td>
|
|
|
|
|
+ <td class="text-right">{{ $pClick }}%</td>
|
|
|
|
|
+ <td class="text-center">
|
|
|
|
|
+ <button type="button" class="btn btn-outline-secondary btn-sm py-0 px-2 mr-1 reset-stats-btn"
|
|
|
|
|
+ data-type="show_id" data-id="{{ $id }}"
|
|
|
|
|
+ data-confirm="确认清除 ID {{ $id }} 的曝光总计及每日明细中该 ID?">
|
|
|
|
|
+ 清曝光
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button type="button" class="btn btn-outline-danger btn-sm py-0 px-2 reset-stats-btn"
|
|
|
|
|
+ data-type="click_id" data-id="{{ $id }}"
|
|
|
|
|
+ data-confirm="确认清除 ID {{ $id }} 的点击总计及每日明细中该 ID?">
|
|
|
|
|
+ 清点击
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </td>
|
|
|
</tr>
|
|
</tr>
|
|
|
@endforeach
|
|
@endforeach
|
|
|
<tr class="table-secondary">
|
|
<tr class="table-secondary">
|
|
|
<td><strong>合计</strong></td>
|
|
<td><strong>合计</strong></td>
|
|
|
- <td colspan="2"><strong>{{ $totalClicksAll }}</strong></td>
|
|
|
|
|
|
|
+ <td class="text-right"><strong>{{ $totalShowsAll }}</strong></td>
|
|
|
|
|
+ <td class="text-right">—</td>
|
|
|
|
|
+ <td class="text-right"><strong>{{ $totalClicksAll }}</strong></td>
|
|
|
|
|
+ <td class="text-right">—</td>
|
|
|
|
|
+ <td class="text-center text-muted small">—</td>
|
|
|
</tr>
|
|
</tr>
|
|
|
</tbody>
|
|
</tbody>
|
|
|
</table>
|
|
</table>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <h5 class="mb-3">最近 7 天每日点击</h5>
|
|
|
|
|
- <div class="table-responsive">
|
|
|
|
|
- <table class="table table-bordered align-middle" style="max-width: 800px;">
|
|
|
|
|
|
|
+ <h5 class="mb-3">最近 3 天每日(曝光 / 点击)</h5>
|
|
|
|
|
+ <div class="table-responsive mb-4">
|
|
|
|
|
+ <table class="table table-bordered align-middle table-sm weight-stats-merge-table" style="max-width: 920px;">
|
|
|
<thead class="thead-light">
|
|
<thead class="thead-light">
|
|
|
<tr>
|
|
<tr>
|
|
|
- <th>日期</th>
|
|
|
|
|
- <th>1</th>
|
|
|
|
|
- <th>2</th>
|
|
|
|
|
- <th>3</th>
|
|
|
|
|
- <th>4</th>
|
|
|
|
|
- <th>合计</th>
|
|
|
|
|
|
|
+ <th class="align-middle">日期</th>
|
|
|
|
|
+ @foreach([1,2,3,4] as $hid)
|
|
|
|
|
+ <th class="text-center">{{ $hid }}</th>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ <th class="text-right">曝光∑</th>
|
|
|
|
|
+ <th class="text-right">点击∑</th>
|
|
|
</tr>
|
|
</tr>
|
|
|
</thead>
|
|
</thead>
|
|
|
<tbody>
|
|
<tbody>
|
|
|
- @foreach($dailyClicks as $row)
|
|
|
|
|
|
|
+ @foreach($dailyClicks as $idx => $row)
|
|
|
@php
|
|
@php
|
|
|
- $sum = intval($row[1]) + intval($row[2]) + intval($row[3]) + intval($row[4]);
|
|
|
|
|
|
|
+ $rowS = $dailyShows[$idx] ?? ['date' => $row['date'], 1=>0,2=>0,3=>0,4=>0];
|
|
|
|
|
+ $sumShow = 0;
|
|
|
|
|
+ $sumClick = 0;
|
|
|
@endphp
|
|
@endphp
|
|
|
<tr>
|
|
<tr>
|
|
|
<td>{{ $row['date'] }}</td>
|
|
<td>{{ $row['date'] }}</td>
|
|
|
- <td>{{ $row[1] }}</td>
|
|
|
|
|
- <td>{{ $row[2] }}</td>
|
|
|
|
|
- <td>{{ $row[3] }}</td>
|
|
|
|
|
- <td>{{ $row[4] }}</td>
|
|
|
|
|
- <td><strong>{{ $sum }}</strong></td>
|
|
|
|
|
|
|
+ @foreach([1,2,3,4] as $hid)
|
|
|
|
|
+ @php
|
|
|
|
|
+ $sv = intval($rowS[$hid] ?? 0);
|
|
|
|
|
+ $cv = intval($row[$hid] ?? 0);
|
|
|
|
|
+ $sumShow += $sv;
|
|
|
|
|
+ $sumClick += $cv;
|
|
|
|
|
+ @endphp
|
|
|
|
|
+ <td class="text-center cell-exp-click">
|
|
|
|
|
+ <span class="text-muted small">曝</span> {{ $sv }}
|
|
|
|
|
+ <span class="mx-1 text-muted">/</span>
|
|
|
|
|
+ <span class="text-muted small">点</span> {{ $cv }}
|
|
|
|
|
+ </td>
|
|
|
|
|
+ @endforeach
|
|
|
|
|
+ <td class="text-right"><strong>{{ $sumShow }}</strong></td>
|
|
|
|
|
+ <td class="text-right"><strong>{{ $sumClick }}</strong></td>
|
|
|
</tr>
|
|
</tr>
|
|
|
@endforeach
|
|
@endforeach
|
|
|
</tbody>
|
|
</tbody>
|
|
|
</table>
|
|
</table>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="alert alert-secondary mb-0">
|
|
|
|
|
+ <button type="button" class="btn btn-sm btn-danger reset-stats-btn" data-type="all" data-confirm="确认清除点击与曝光的全部总计及每日明细?此操作不可恢复。">
|
|
|
|
|
+ <i class="mdi mdi-delete-forever"></i> 清除全部统计(点击+曝光含明细)
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -147,8 +211,115 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
|
|
<script>
|
|
<script>
|
|
|
$(function() {
|
|
$(function() {
|
|
|
|
|
+ var weightChartData = {
|
|
|
|
|
+ today: {
|
|
|
|
|
+ shows: @json($chartTodayShows),
|
|
|
|
|
+ clicks: @json($chartTodayClicks),
|
|
|
|
|
+ subtitle: @json('当天数据 · ' . date('Y-m-d'))
|
|
|
|
|
+ },
|
|
|
|
|
+ total: {
|
|
|
|
|
+ shows: @json($chartTotalShows),
|
|
|
|
|
+ clicks: @json($chartTotalClicks),
|
|
|
|
|
+ subtitle: @json('总计(Redis 累计)')
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ function initWeightStatsChart() {
|
|
|
|
|
+ var chartDom = document.getElementById('weight-stats-chart');
|
|
|
|
|
+ if (!chartDom || typeof echarts === 'undefined') {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ var chart = echarts.init(chartDom);
|
|
|
|
|
+
|
|
|
|
|
+ function buildOption(pack) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ backgroundColor: '#ffffff',
|
|
|
|
|
+ tooltip: {
|
|
|
|
|
+ trigger: 'axis',
|
|
|
|
|
+ axisPointer: { type: 'shadow' }
|
|
|
|
|
+ },
|
|
|
|
|
+ legend: {
|
|
|
|
|
+ data: ['曝光', '点击'],
|
|
|
|
|
+ bottom: 6,
|
|
|
|
|
+ itemGap: 28,
|
|
|
|
|
+ textStyle: { color: '#555' }
|
|
|
|
|
+ },
|
|
|
|
|
+ grid: {
|
|
|
|
|
+ left: '2%',
|
|
|
|
|
+ right: '2%',
|
|
|
|
|
+ bottom: '16%',
|
|
|
|
|
+ top: '10%',
|
|
|
|
|
+ containLabel: true
|
|
|
|
|
+ },
|
|
|
|
|
+ xAxis: {
|
|
|
|
|
+ type: 'category',
|
|
|
|
|
+ data: ['1', '2', '3', '4'],
|
|
|
|
|
+ axisLine: { lineStyle: { color: '#ddd' } },
|
|
|
|
|
+ axisTick: { alignWithLabel: true },
|
|
|
|
|
+ axisLabel: { color: '#666', fontSize: 12 }
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: {
|
|
|
|
|
+ type: 'value',
|
|
|
|
|
+ minInterval: 1,
|
|
|
|
|
+ splitLine: { lineStyle: { color: '#eeeeee', width: 1 } },
|
|
|
|
|
+ axisLabel: { color: '#666' }
|
|
|
|
|
+ },
|
|
|
|
|
+ series: [
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '曝光',
|
|
|
|
|
+ type: 'bar',
|
|
|
|
|
+ barMaxWidth: 36,
|
|
|
|
|
+ barGap: '18%',
|
|
|
|
|
+ barCategoryGap: '40%',
|
|
|
|
|
+ data: pack.shows,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ color: '#c8bdb0',
|
|
|
|
|
+ borderRadius: [4, 4, 0, 0]
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ name: '点击',
|
|
|
|
|
+ type: 'bar',
|
|
|
|
|
+ barMaxWidth: 36,
|
|
|
|
|
+ data: pack.clicks,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ color: '#2563eb',
|
|
|
|
|
+ borderRadius: [4, 4, 0, 0]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function applyMode(mode) {
|
|
|
|
|
+ var pack = mode === 'today' ? weightChartData.today : weightChartData.total;
|
|
|
|
|
+ chart.setOption(buildOption(pack), true);
|
|
|
|
|
+ $('#weight-chart-subtitle').text(pack.subtitle);
|
|
|
|
|
+ $('.weight-chart-mode').removeClass('active');
|
|
|
|
|
+ $('.weight-chart-mode[data-mode="' + mode + '"]').addClass('active');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $('.weight-chart-mode').on('click', function () {
|
|
|
|
|
+ applyMode($(this).data('mode'));
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $('a[data-toggle="tab"][href="#tab-stats"]').on('shown.bs.tab', function () {
|
|
|
|
|
+ chart.resize();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ $(window).on('resize', function () {
|
|
|
|
|
+ chart.resize();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ applyMode('today');
|
|
|
|
|
+ return chart;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ initWeightStatsChart();
|
|
|
|
|
+
|
|
|
function refreshPercents() {
|
|
function refreshPercents() {
|
|
|
let total = 0;
|
|
let total = 0;
|
|
|
$('.weight-input').each(function(){
|
|
$('.weight-input').each(function(){
|
|
@@ -196,12 +367,16 @@ $(function() {
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- $('#reset-stats').click(function(){
|
|
|
|
|
- if (!confirm('确认清除总点击统计?(每日明细仍保留)')) return;
|
|
|
|
|
- $.post("{{ url('/admin/weight-config/reset-stats') }}", {
|
|
|
|
|
- type: 'total',
|
|
|
|
|
- _token: "{{ csrf_token() }}"
|
|
|
|
|
- }).done(function(res){
|
|
|
|
|
|
|
+ $('.reset-stats-btn').click(function(){
|
|
|
|
|
+ const type = $(this).data('type');
|
|
|
|
|
+ const id = $(this).data('id');
|
|
|
|
|
+ const msg = $(this).data('confirm') || '确认清除?';
|
|
|
|
|
+ if (!confirm(msg)) return;
|
|
|
|
|
+ const payload = { type: type, _token: "{{ csrf_token() }}" };
|
|
|
|
|
+ if (id !== undefined && id !== '') {
|
|
|
|
|
+ payload.id = id;
|
|
|
|
|
+ }
|
|
|
|
|
+ $.post("{{ url('/admin/weight-config/reset-stats') }}", payload).done(function(res){
|
|
|
if (res.status === 'success') {
|
|
if (res.status === 'success') {
|
|
|
location.reload();
|
|
location.reload();
|
|
|
} else {
|
|
} else {
|
|
@@ -217,6 +392,14 @@ $(function() {
|
|
|
<style>
|
|
<style>
|
|
|
.table thead th { white-space: nowrap; }
|
|
.table thead th { white-space: nowrap; }
|
|
|
.table tbody td { vertical-align: middle; }
|
|
.table tbody td { vertical-align: middle; }
|
|
|
-.badge { font-size: .85rem; padding: .5em .6em; }
|
|
|
|
|
|
|
+.cell-exp-click { white-space: nowrap; font-size: 0.875rem; }
|
|
|
|
|
+.weight-stats-merge-table tbody td { vertical-align: middle; }
|
|
|
|
|
+ display: inline-block;
|
|
|
|
|
+ width: 12px;
|
|
|
|
|
+ height: 12px;
|
|
|
|
|
+ border-radius: 3px;
|
|
|
|
|
+ vertical-align: -2px;
|
|
|
|
|
+ margin-right: 6px;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|
|
|
@endsection
|
|
@endsection
|