141 lines
4.5 KiB
PHP
141 lines
4.5 KiB
PHP
<?php
|
||
|
||
namespace app\api\controller;
|
||
|
||
use app\common\model\popup\PagePopup;
|
||
use app\common\model\popup\PagePopupLog;
|
||
use think\response\Json;
|
||
|
||
/**
|
||
* 页面弹窗
|
||
* GET /api/popup/list?page_path=...&platform=...
|
||
* POST /api/popup/report body: popup_id, action(1=show 2=click 3=close), page_path, device_id
|
||
*/
|
||
class PopupController extends BaseApiController
|
||
{
|
||
public array $notNeedLogin = ['list', 'report'];
|
||
|
||
/**
|
||
* 获取当前页面匹配的弹窗列表
|
||
*/
|
||
public function list(): Json
|
||
{
|
||
$pagePath = trim((string) $this->request->get('page_path', ''));
|
||
$platform = trim((string) $this->request->get('platform', ''));
|
||
if (!$pagePath) {
|
||
return $this->data(['lists' => []]);
|
||
}
|
||
|
||
$now = time();
|
||
$query = PagePopup::where('status', 1)
|
||
->where(function ($q) use ($now) {
|
||
$q->whereOr([
|
||
['start_time', '=', 0],
|
||
['start_time', '<=', $now]
|
||
]);
|
||
})
|
||
->where(function ($q) use ($now) {
|
||
$q->whereOr([
|
||
['end_time', '=', 0],
|
||
['end_time', '>=', $now]
|
||
]);
|
||
})
|
||
->order(['sort' => 'desc', 'id' => 'desc']);
|
||
|
||
$all = $query->select()->toArray();
|
||
|
||
// 路径匹配 + 平台筛选(PHP 端处理通配符)
|
||
$matched = [];
|
||
foreach ($all as $item) {
|
||
// 平台筛选
|
||
if (!empty($item['target_platform']) && $platform) {
|
||
$platforms = array_filter(array_map('trim', explode(',', $item['target_platform'])));
|
||
if (!empty($platforms) && !in_array($platform, $platforms, true)) {
|
||
continue;
|
||
}
|
||
}
|
||
// 路径匹配
|
||
if (!self::pathMatch($item['page_path'], $pagePath)) {
|
||
continue;
|
||
}
|
||
$matched[] = [
|
||
'id' => $item['id'],
|
||
'name' => $item['name'],
|
||
'popup_type' => $item['popup_type'],
|
||
'image' => $item['image'],
|
||
'title' => $item['title'],
|
||
'content' => $item['content'],
|
||
'link_type' => $item['link_type'],
|
||
'link_url' => $item['link_url'],
|
||
'frequency' => $item['frequency'],
|
||
'delay_seconds' => $item['delay_seconds'],
|
||
'auto_close_seconds' => $item['auto_close_seconds'] ?? 0,
|
||
'is_closable' => $item['is_closable'] ?? 1,
|
||
'sort' => $item['sort'],
|
||
];
|
||
}
|
||
|
||
return $this->data(['lists' => $matched]);
|
||
}
|
||
|
||
/**
|
||
* 上报弹窗操作
|
||
*/
|
||
public function report(): Json
|
||
{
|
||
$popupId = (int) $this->request->post('popup_id/d', 0);
|
||
$action = (int) $this->request->post('action/d', 0);
|
||
$pagePath = (string) $this->request->post('page_path', '');
|
||
$deviceId = (string) $this->request->post('device_id', '');
|
||
$platform = (string) $this->request->post('platform', '');
|
||
|
||
if ($popupId <= 0 || !in_array($action, [1, 2, 3], true)) {
|
||
return $this->fail('参数错误');
|
||
}
|
||
|
||
$now = time();
|
||
$ip = $this->request->ip() ?: '';
|
||
$ua = $this->request->header('user-agent', '');
|
||
if (mb_strlen($ua) > 500)
|
||
$ua = mb_substr($ua, 0, 500);
|
||
|
||
PagePopupLog::insert([
|
||
'popup_id' => $popupId,
|
||
'user_id' => $this->userId ?: 0,
|
||
'device_id' => $deviceId,
|
||
'action' => $action,
|
||
'page_path' => $pagePath,
|
||
'platform' => $platform,
|
||
'ip' => $ip,
|
||
'ua' => $ua,
|
||
'create_time' => $now,
|
||
]);
|
||
|
||
// 冗余统计字段
|
||
$field = [1 => 'show_count', 2 => 'click_count', 3 => 'close_count'][$action] ?? '';
|
||
if ($field) {
|
||
PagePopup::where('id', $popupId)->inc($field)->update();
|
||
}
|
||
|
||
return $this->data(['ok' => true]);
|
||
}
|
||
|
||
/**
|
||
* 路径匹配规则:
|
||
* - * 匹配所有
|
||
* - 末尾 * 表示前缀匹配(/pages/news_detail/*)
|
||
* - 完全相等
|
||
*/
|
||
private static function pathMatch(string $pattern, string $path): bool
|
||
{
|
||
$pattern = trim($pattern);
|
||
if ($pattern === '' || $pattern === '*')
|
||
return true;
|
||
if (substr($pattern, -1) === '*') {
|
||
$prefix = substr($pattern, 0, -1);
|
||
return strpos($path, $prefix) === 0;
|
||
}
|
||
return $pattern === $path;
|
||
}
|
||
}
|