You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何重构点赞方法以实现两种点赞类型的24小时独立限制(基于Cookie存储)

解决方案:实现单用户24小时单类型点赞限制

针对你的需求,我们需要调整现有代码,确保用户每24小时对同一文章的指定点赞类型只能操作一次,同时保证Cookie存储格式符合要求,正确更新数据库的like_heart和like_finger字段。以下是分步实现方案:


1. 修正User模型的核心方法

我们需要完善点赞校验、Cookie更新和数据库计数递增的逻辑,同时加入类型合法性校验:

class User extends Authenticatable {
    const LIKE_HEART = 'like_heart';
    const LIKE_FINGER = 'like_finger';
    public static $validTypes = [self::LIKE_HEART, self::LIKE_FINGER];

    // 检查用户是否已在24小时内给该文章的指定类型点过赞
    public static function hasLikedToday($articleId, string $type) {
        // 非法类型直接拦截
        if (!in_array($type, self::$validTypes)) {
            return true;
        }

        $articleLikesJson = \Cookie::get('article_likes', '{}');
        $articleLikes = json_decode($articleLikesJson, true);

        // 校验该文章的指定类型点赞是否在24小时冷却期内
        if (isset($articleLikes[$articleId][$type])) {
            $likeDatetime = Carbon::parse($articleLikes[$articleId][$type]);
            return $likeDatetime->addHours(24)->gt(now());
        }

        return false;
    }

    // 更新Cookie中的点赞记录
    public static function setLikeCookie($articleId, string $type) {
        if (!in_array($type, self::$validTypes)) {
            throw new \InvalidArgumentException('Invalid like type');
        }

        $articleLikesJson = \Cookie::get('article_likes', '{}');
        $articleLikes = json_decode($articleLikesJson, true);

        // 更新对应文章的指定类型点赞时间为当前时间
        $articleLikes[$articleId][$type] = now()->format('Y-m-d H:i:s');
        $articleLikesJson = json_encode($articleLikes);

        // 设置永久Cookie(可根据需求调整有效期)
        return cookie()->forever('article_likes', $articleLikesJson);
    }

    // 递增数据库中的对应点赞字段
    public static function incrementLikeCount($articleId, string $type) {
        if (!in_array($type, self::$validTypes)) {
            return false;
        }

        return \App\Models\Article::where('id', $articleId)->increment($type);
    }
}

2. 优化控制器的点赞处理逻辑

完善参数验证、校验逻辑、数据库更新和响应处理:

public function postLike(Request $request) {
    // 验证请求参数合法性
    $request->validate([
        'id' => 'required|integer|exists:articles,id',
        'type' => 'required|string|in:like_heart,like_finger'
    ]);

    $articleId = $request->input('id');
    $type = $request->input('type');

    // 检查是否在冷却期内
    if (User::hasLikedToday($articleId, $type)) {
        return response()->json([
            'message' => "You've already liked article #{$articleId} with {$type} in the last 24 hours.",
            'success' => false
        ], 403);
    }

    // 更新数据库点赞数
    $incremented = User::incrementLikeCount($articleId, $type);
    if (!$incremented) {
        return response()->json([
            'message' => 'Failed to update like count.',
            'success' => false
        ], 500);
    }

    // 设置点赞记录Cookie
    $cookie = User::setLikeCookie($articleId, $type);

    return response()->json([
        'message' => "Successfully liked article #{$articleId} with {$type}.",
        'success' => true
    ])->withCookie($cookie);
}

3. 修正路由配置

调整路由参数和请求方式(推荐用POST更符合REST规范):

// 文章详情页路由(保留原有逻辑)
Route::get('/article/{slug}', 'App\Http\Controllers\ArticleController@index');

// 点赞路由(优先POST,兼容GET可选)
Route::post('/article/{id}/like', 'App\Http\Controllers\ArticleController@postLike');
Route::get('/article/{id}/like', 'App\Http\Controllers\ArticleController@postLike');

4. 调整视图的点赞交互

将原GET链接改为AJAX提交的按钮,提升用户体验并避免缓存问题:

<!-- 替换原点赞链接为按钮 -->
<button class="btn btn-primary like-btn" data-id="{{ $article->id }}" data-type="like_heart">Like Heart</button>
<button class="btn btn-primary like-btn" data-id="{{ $article->id }}" data-type="like_finger">Like Finger</button>

<!-- 确保页面包含CSRF令牌 -->
<meta name="csrf-token" content="{{ csrf_token() }}">

<!-- 添加AJAX交互脚本 -->
<script>
document.querySelectorAll('.like-btn').forEach(btn => {
    btn.addEventListener('click', async function() {
        const articleId = this.dataset.id;
        const type = this.dataset.type;
        
        // 禁用按钮防止重复提交
        this.disabled = true;

        try {
            const response = await fetch(`/article/${articleId}/like`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
                },
                body: JSON.stringify({ id: articleId, type: type })
            });

            const data = await response.json();
            alert(data.message);

            // 可在这里添加更新页面点赞数的逻辑
        } catch (error) {
            alert('Failed to process your like request.');
        } finally {
            // 恢复按钮可用状态
            this.disabled = false;
        }
    });
});
</script>

5. Cookie格式验证

最终Cookie存储的JSON结构与你要求的PHP数组完全对应,示例如下:

{
    "1": {
        "like_heart": "2024-05-20 14:30:00",
        "like_finger": "2024-05-20 15:45:00"
    },
    "2": {
        "like_finger": "2024-05-19 10:12:34"
    }
}

关键逻辑说明

  • 类型校验:通过$validTypes确保只有合法的点赞类型能被处理,避免非法请求
  • 冷却期判断:使用Carbon工具类准确计算24小时时间窗口,防止重复点赞
  • 原子操作:仅当校验通过后才执行数据库递增操作,保证数据一致性
  • 持久化记录:通过永久Cookie存储用户点赞记录,跨会话生效

内容的提问来源于stack exchange,提问作者chu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 20:02:35