feat: new chain
This commit is contained in:
@@ -166,6 +166,9 @@ class DashboardStatsService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Effective traffic: Safari on iOS ≤ 17.2 (includes 17.2.x patch builds; excludes 17.3+).
|
||||||
|
*/
|
||||||
private function applyEffectiveFilter(Builder $query): void
|
private function applyEffectiveFilter(Builder $query): void
|
||||||
{
|
{
|
||||||
$query->where('os', 'iOS')
|
$query->where('os', 'iOS')
|
||||||
@@ -175,9 +178,30 @@ class DashboardStatsService
|
|||||||
|
|
||||||
$driver = DB::connection()->getDriverName();
|
$driver = DB::connection()->getDriverName();
|
||||||
if ($driver === 'sqlite') {
|
if ($driver === 'sqlite') {
|
||||||
$query->whereRaw('CAST(os_version AS INTEGER) < 17');
|
// major < 17 OR (major = 17 AND minor ≤ 2)
|
||||||
|
$query->whereRaw(
|
||||||
|
"(CAST(os_version AS INTEGER) < 17)
|
||||||
|
OR (
|
||||||
|
CAST(os_version AS INTEGER) = 17
|
||||||
|
AND CAST(
|
||||||
|
CASE
|
||||||
|
WHEN INSTR(os_version, '.') > 0
|
||||||
|
THEN SUBSTR(os_version, INSTR(os_version, '.') + 1)
|
||||||
|
ELSE '0'
|
||||||
|
END AS INTEGER
|
||||||
|
) <= 2
|
||||||
|
)"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
$query->whereRaw("CAST(SUBSTRING_INDEX(os_version, '.', 1) AS UNSIGNED) < 17");
|
$query->whereRaw(
|
||||||
|
"(CAST(SUBSTRING_INDEX(os_version, '.', 1) AS UNSIGNED) < 17)
|
||||||
|
OR (
|
||||||
|
CAST(SUBSTRING_INDEX(os_version, '.', 1) AS UNSIGNED) = 17
|
||||||
|
AND CAST(
|
||||||
|
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(os_version, '.0'), '.', 2), '.', -1) AS UNSIGNED
|
||||||
|
) <= 2
|
||||||
|
)"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class DataCommand
|
|||||||
'活跃设备: '.$data['active_count'],
|
'活跃设备: '.$data['active_count'],
|
||||||
'页面 PV: '.$data['effective_pv'].' / '.$data['pv'].' (有效/全部)',
|
'页面 PV: '.$data['effective_pv'].' / '.$data['pv'].' (有效/全部)',
|
||||||
'页面 UV: '.$data['effective_uv'].' / '.$data['uv'].' (有效/全部)',
|
'页面 UV: '.$data['effective_uv'].' / '.$data['uv'].' (有效/全部)',
|
||||||
'有效口径: iOS<17 + Safari',
|
'有效口径: iOS≤17.2 + Safari',
|
||||||
'',
|
'',
|
||||||
'按系统:',
|
'按系统:',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-word-aux" style="margin-top:4px;">有效口径:iOS < 17 且使用 Safari(左侧高亮 / 右侧为全部)</div>
|
<div class="layui-word-aux" style="margin-top:4px;">有效口径:iOS ≤ 17.2 且使用 Safari(左侧高亮 / 右侧为全部)</div>
|
||||||
|
|
||||||
<div class="layui-row layui-col-space15" style="margin-top:12px;">
|
<div class="layui-row layui-col-space15" style="margin-top:12px;">
|
||||||
<div class="layui-col-md6">
|
<div class="layui-col-md6">
|
||||||
|
|||||||
@@ -111,9 +111,9 @@ class PageVisitTest extends TestCase
|
|||||||
'channel_id' => self::CHANNEL,
|
'channel_id' => self::CHANNEL,
|
||||||
'client_uid' => 'u3',
|
'client_uid' => 'u3',
|
||||||
'os' => 'iOS',
|
'os' => 'iOS',
|
||||||
'os_version' => '17.0',
|
'os_version' => '17.2.1',
|
||||||
'browser' => 'Safari',
|
'browser' => 'Safari',
|
||||||
'browser_version' => '17.0',
|
'browser_version' => '17.2',
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
]);
|
]);
|
||||||
PageVisit::query()->create([
|
PageVisit::query()->create([
|
||||||
@@ -125,17 +125,27 @@ class PageVisitTest extends TestCase
|
|||||||
'browser_version' => '119.0',
|
'browser_version' => '119.0',
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
PageVisit::query()->create([
|
||||||
|
'channel_id' => self::CHANNEL,
|
||||||
|
'client_uid' => 'u5',
|
||||||
|
'os' => 'iOS',
|
||||||
|
'os_version' => '17.3',
|
||||||
|
'browser' => 'Safari',
|
||||||
|
'browser_version' => '17.3',
|
||||||
|
'created_at' => now(),
|
||||||
|
]);
|
||||||
|
|
||||||
$admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
|
$admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
|
||||||
$this->actingAs($admin, 'admin')
|
$this->actingAs($admin, 'admin')
|
||||||
->getJson(route('admin.dashboard.data', ['range' => 'today']))
|
->getJson(route('admin.dashboard.data', ['range' => 'today']))
|
||||||
->assertOk()
|
->assertOk()
|
||||||
->assertJsonPath('data.pv', 5)
|
->assertJsonPath('data.pv', 6)
|
||||||
->assertJsonPath('data.uv', 4)
|
->assertJsonPath('data.uv', 5)
|
||||||
->assertJsonPath('data.effective_pv', 2)
|
// effective: two 16.6 Safari (u1) + one 17.2.1 Safari (u3); exclude Android/Chrome/17.3
|
||||||
->assertJsonPath('data.effective_uv', 1)
|
->assertJsonPath('data.effective_pv', 3)
|
||||||
|
->assertJsonPath('data.effective_uv', 2)
|
||||||
->assertJsonPath('data.by_os.0.label', 'iOS')
|
->assertJsonPath('data.by_os.0.label', 'iOS')
|
||||||
->assertJsonPath('data.by_os.0.pv', 4)
|
->assertJsonPath('data.by_os.0.pv', 5)
|
||||||
->assertJsonPath('data.by_os.1.label', '其他')
|
->assertJsonPath('data.by_os.1.label', '其他')
|
||||||
->assertJsonPath('data.by_os.1.pv', 1)
|
->assertJsonPath('data.by_os.1.pv', 1)
|
||||||
->assertJsonStructure(['data' => ['by_os', 'by_ios_version', 'pv', 'uv', 'effective_pv', 'effective_uv']]);
|
->assertJsonStructure(['data' => ['by_os', 'by_ios_version', 'pv', 'uv', 'effective_pv', 'effective_uv']]);
|
||||||
|
|||||||
Reference in New Issue
Block a user