Commit 0295ea54 authored by 刘小敏's avatar 刘小敏

PV UV 采集代码

parent 1f5ee2ec
This diff is collapsed.
<?php
namespace addons\shopro\controller\api;
use think\Queue;
//use app\admin\controller\shopro\Common;
use addons\shopro\controller\Common;
class Track extends Common
{
/**
* 无需登录的方法
* @var array
*/
protected $noNeedLogin = ['upload', 'stats'];
protected $noNeedRight = ['*'];
/**
* 接收埋点数据(推入队列)
*/
public function upload() {
// 限制请求大小
if ($_SERVER['CONTENT_LENGTH'] > 5 * 1024 * 1024) {
$this->error('请求数据过大');
}
// 获取原始数据
$rawData = file_get_contents('php://input');
if (empty($rawData)) {
$this->error('请求数据为空');
}
// 解析JSON
$requestData = json_decode($rawData, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$this->error('JSON解析失败');
}
// 验证必要参数
if (!isset($requestData['list']) || !is_array($requestData['list'])) {
$this->error('参数错误');
}
//print_r([
// 'data' => $requestData['list'],
// 'ip' => $this->request->ip(),
// 'timestamp' => time()
//]);
// 推入队列
$jobId = Queue::push('addons\shopro\job\TrackProcessJob@fire', [
'data' => $requestData['list'],
'ip' => $this->request->ip(),
'timestamp' => time()
], 'shopro-high');
if ($jobId) {
$this->success('接收成功');
} else {
$this->error('队列推送失败');
}
}
/**
* 获取统计数据
*/
public function stats() {
$startDate = $this->request->param('start', date('Y-m-d', strtotime('-7 days')));
$endDate = $this->request->param('end', date('Y-m-d'));
// 参数验证
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $endDate)) {
$this->error('日期格式错误');
}
$stats = \app\admin\model\shopro\MiniProgramStats::whereBetween('date', [$startDate, $endDate])
->order('date ASC')
->select();
$this->success('获取成功', $stats);
}
}
\ No newline at end of file
<?php
// addons/shopro/job/TrackProcessJob.php
namespace addons\shopro\job;
use think\queue\Job;
use think\Db;
use think\Queue;
class TrackProcessJob
{
/**
* 执行队列任务
*/
public function fire(Job $job, $data) {
try {
$trackData = $data['data'] ?? [];
$clientIp = $data['ip'] ?? '';
if (empty($trackData)) {
$job->delete();
return;
}
// 1. 批量插入埋点数据
$this->insertTracks($trackData, $clientIp);
// 2. 更新统计数据
$this->updateStats();
// 3. 删除任务
$job->delete();
} catch (\Exception $e) {
// 重试机制
if ($job->attempts() < 3) {
$job->release(60); // 60秒后重试
} else {
// 记录失败数据
$this->saveFailed($data, $e->getMessage());
$job->delete();
}
}
}
/**
* 批量插入埋点数据
*/
protected function insertTracks($trackData, $clientIp) {
$insertData = [];
$now = time();
foreach ($trackData as $item) {
$insertData[] = [
'user_id' => $item['user_id'] ?? 0,
'openid' => $item['openid'] ?? '',
'session_id' => $item['session_id'] ?? '',
'event_type' => $item['event_type'] ?? '',
'page_path' => $item['page_path'] ?? '',
'page_title' => $item['page_title'] ?? '',
'params' => !empty($item['params']) ? json_encode($item['params']) : '',
'ip' => $clientIp,
'create_time' => isset($item['create_time']) ? (int)($item['create_time'] / 1000) : $now
];
}
// 分批插入(每批500条)
$batches = array_chunk($insertData, 500);
foreach ($batches as $batch) {
Db::name('shopro_miniprogram_track')->insertAll($batch);
}
}
/**
* 更新统计数据
*/
protected function updateStats() {
$date = date('Y-m-d');
// 统计UV(按openid去重)
$uv = Db::name('shopro_miniprogram_track')
->whereDate('create_time', $date)
->distinct(true)
->count('openid');
// 统计PV(页面浏览量)
$pv = Db::name('shopro_miniprogram_track')
->whereDate('create_time', $date)
->where('event_type', 'page_view')
->count();
// 更新或插入统计记录
Db::name('shopro_miniprogram_stats')->updateOrCreate(
['date' => $date],
[
'uv' => $uv,
'pv' => $pv,
'update_time' => time()
]
);
}
/**
* 保存失败数据
*/
protected function saveFailed($data, $error) {
Db::name('shopro_track_failed')->insert([
'data' => json_encode($data),
'error' => $error,
'attempts' => 3,
'create_time' => time()
]);
}
// 恢复失败数据的脚本
public function retryFailed()
{
$failedList = Db::name('shopro_track_failed')
->where('status', 0)
->select();
foreach ($failedList as $item) {
try {
$data = json_decode($item['data'], true);
// 重新推入队列
Queue::push('\addons\shopro\job\TrackProcessJob@fire', $data, 'shopro-high');
// 更新状态为已处理
Db::name('shopro_track_failed')
->where('id', $item['id'])
->update(['status' => 1, 'update_time' => time()]);
} catch (\Exception $e) {
// 更新状态为已放弃
Db::name('shopro_track_failed')
->where('id', $item['id'])
->update(['status' => 2, 'error' => $e->getMessage(), 'update_time' => time()]);
}
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment