Files
2026-06-11 12:15:29 +08:00

141 lines
4.5 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}