PHP项目如何实现积分商城功能?

wen PHP项目 3

本文目录导读:

PHP项目如何实现积分商城功能?

  1. 数据库设计
  2. 核心功能实现
  3. 前端页面示例
  4. 安全建议

我来详细介绍PHP项目实现积分商城功能的完整方案。

数据库设计

核心数据表

-- 用户表(扩展字段)
ALTER TABLE `user` ADD COLUMN `points` INT(11) DEFAULT 0 COMMENT '用户积分';
-- 积分记录表
CREATE TABLE `points_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `type` tinyint(1) NOT NULL COMMENT '类型:1增加 -1减少',
  `points` int(11) NOT NULL COMMENT '积分数量',
  `source` varchar(50) NOT NULL COMMENT '来源:sign/order/exchange/admin',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 商品表
CREATE TABLE `points_goods` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL COMMENT '商品名称',
  `image` varchar(255) DEFAULT NULL COMMENT '商品图片',
  `points` int(11) NOT NULL COMMENT '所需积分',
  `stock` int(11) DEFAULT 0 COMMENT '库存',
  `sold_count` int(11) DEFAULT 0 COMMENT '已兑换数量',
  `status` tinyint(1) DEFAULT 1 COMMENT '状态:1上架 0下架',
  `description` text COMMENT '商品描述',
  `type` tinyint(1) DEFAULT 1 COMMENT '类型:1实物 2虚拟(优惠券等)',
  `sort_order` int(11) DEFAULT 0 COMMENT '排序',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 兑换记录表
CREATE TABLE `points_exchange` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `goods_id` int(11) NOT NULL,
  `points` int(11) NOT NULL COMMENT '消耗积分',
  `status` tinyint(1) DEFAULT 0 COMMENT '状态:0待处理 1已完成 2已取消',
  `order_no` varchar(32) DEFAULT NULL COMMENT '兑换订单号',
  `user_name` varchar(50) DEFAULT NULL COMMENT '收货人',
  `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `address` varchar(255) DEFAULT NULL COMMENT '收货地址',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `order_no` (`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

核心功能实现

积分管理类

<?php
// PointsManager.php
class PointsManager {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    /**
     * 增加积分
     */
    public function addPoints($userId, $points, $source, $remark = '') {
        if ($points <= 0) return false;
        $this->db->beginTransaction();
        try {
            // 更新用户积分
            $sql = "UPDATE user SET points = points + ? WHERE id = ?";
            $this->db->execute($sql, [$points, $userId]);
            // 记录日志
            $sql = "INSERT INTO points_log (user_id, type, points, source, remark) 
                    VALUES (?, 1, ?, ?, ?)";
            $this->db->execute($sql, [$userId, $points, $source, $remark]);
            $this->db->commit();
            return true;
        } catch (Exception $e) {
            $this->db->rollback();
            return false;
        }
    }
    /**
     * 扣除积分
     */
    public function deductPoints($userId, $points, $source, $remark = '') {
        if ($points <= 0) return false;
        // 检查积分是否足够
        if (!$this->hasEnoughPoints($userId, $points)) {
            return false;
        }
        $this->db->beginTransaction();
        try {
            $sql = "UPDATE user SET points = points - ? WHERE id = ? AND points >= ?";
            $affected = $this->db->execute($sql, [$points, $userId, $points]);
            if ($affected == 0) {
                $this->db->rollback();
                return false;
            }
            // 记录日志
            $sql = "INSERT INTO points_log (user_id, type, points, source, remark) 
                    VALUES (?, -1, ?, ?, ?)";
            $this->db->execute($sql, [$userId, $points, $source, $remark]);
            $this->db->commit();
            return true;
        } catch (Exception $e) {
            $this->db->rollback();
            return false;
        }
    }
    /**
     * 检查积分是否足够
     */
    public function hasEnoughPoints($userId, $points) {
        $sql = "SELECT points FROM user WHERE id = ?";
        $user = $this->db->fetchOne($sql, [$userId]);
        return $user && $user['points'] >= $points;
    }
    /**
     * 获取用户积分
     */
    public function getUserPoints($userId) {
        $sql = "SELECT points FROM user WHERE id = ?";
        $user = $this->db->fetchOne($sql, [$userId]);
        return $user ? $user['points'] : 0;
    }
    /**
     * 获取积分明细
     */
    public function getPointsLog($userId, $page = 1, $pageSize = 20) {
        $offset = ($page - 1) * $pageSize;
        $sql = "SELECT * FROM points_log WHERE user_id = ? 
                ORDER BY created_at DESC LIMIT ?, ?";
        return $this->db->fetchAll($sql, [$userId, $offset, $pageSize]);
    }
}

商品管理类

<?php
// GoodsManager.php
class GoodsManager {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    /**
     * 获取商品列表
     */
    public function getGoodsList($page = 1, $pageSize = 20) {
        $offset = ($page - 1) * $pageSize;
        $sql = "SELECT * FROM points_goods WHERE status = 1 
                ORDER BY sort_order ASC, id DESC LIMIT ?, ?";
        return $this->db->fetchAll($sql, [$offset, $pageSize]);
    }
    /**
     * 获取商品详情
     */
    public function getGoodsDetail($goodsId) {
        $sql = "SELECT * FROM points_goods WHERE id = ? AND status = 1";
        return $this->db->fetchOne($sql, [$goodsId]);
    }
    /**
     * 检查库存
     */
    public function checkStock($goodsId, $quantity = 1) {
        $sql = "SELECT stock FROM points_goods WHERE id = ?";
        $goods = $this->db->fetchOne($sql, [$goodsId]);
        return $goods && $goods['stock'] >= $quantity;
    }
    /**
     * 扣减库存
     */
    public function deductStock($goodsId, $quantity = 1) {
        $sql = "UPDATE points_goods SET stock = stock - ?, sold_count = sold_count + ? 
                WHERE id = ? AND stock >= ?";
        return $this->db->execute($sql, [$quantity, $quantity, $goodsId, $quantity]);
    }
}

兑换功能实现

<?php
// ExchangeController.php
class ExchangeController {
    private $db;
    private $pointsManager;
    private $goodsManager;
    public function __construct($db) {
        $this->db = $db;
        $this->pointsManager = new PointsManager($db);
        $this->goodsManager = new GoodsManager($db);
    }
    /**
     * 执行兑换
     */
    public function exchange($userId, $goodsId, $quantity = 1, $userInfo = []) {
        // 获取商品信息
        $goods = $this->goodsManager->getGoodsDetail($goodsId);
        if (!$goods) {
            return ['code' => 0, 'msg' => '商品不存在或已下架'];
        }
        // 检查库存
        if (!$this->goodsManager->checkStock($goodsId, $quantity)) {
            return ['code' => 0, 'msg' => '库存不足'];
        }
        // 计算所需积分
        $totalPoints = $goods['points'] * $quantity;
        // 检查用户积分
        if (!$this->pointsManager->hasEnoughPoints($userId, $totalPoints)) {
            return ['code' => 0, 'msg' => '积分不足'];
        }
        $this->db->beginTransaction();
        try {
            // 生成订单号
            $orderNo = $this->generateOrderNo();
            // 扣减库存
            $this->goodsManager->deductStock($goodsId, $quantity);
            // 扣除积分
            $this->pointsManager->deductPoints(
                $userId, 
                $totalPoints, 
                'exchange',
                "兑换商品:{$goods['name']} x{$quantity}"
            );
            // 创建兑换记录
            $sql = "INSERT INTO points_exchange (user_id, goods_id, points, order_no, 
                    user_name, phone, address, status) 
                    VALUES (?, ?, ?, ?, ?, ?, ?, 0)";
            $this->db->execute($sql, [
                $userId, 
                $goodsId, 
                $totalPoints, 
                $orderNo,
                $userInfo['name'] ?? '',
                $userInfo['phone'] ?? '',
                $userInfo['address'] ?? ''
            ]);
            $this->db->commit();
            return ['code' => 1, 'msg' => '兑换成功', 'order_no' => $orderNo];
        } catch (Exception $e) {
            $this->db->rollback();
            return ['code' => 0, 'msg' => '兑换失败,请重试'];
        }
    }
    /**
     * 获取兑换记录
     */
    public function getExchangeList($userId, $page = 1, $pageSize = 20) {
        $offset = ($page - 1) * $pageSize;
        $sql = "SELECT e.*, g.name as goods_name, g.image as goods_image 
                FROM points_exchange e 
                LEFT JOIN points_goods g ON e.goods_id = g.id 
                WHERE e.user_id = ? 
                ORDER BY e.created_at DESC LIMIT ?, ?";
        return $this->db->fetchAll($sql, [$userId, $offset, $pageSize]);
    }
    /**
     * 生成订单号
     */
    private function generateOrderNo() {
        return 'EX' . date('YmdHis') . rand(100000, 999999);
    }
}

前端页面示例

<!-- goods_list.php -->
<!DOCTYPE html>
<html>
<head>积分商城</title>
    <style>
        .goods-grid {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 20px;
            padding: 20px;
        }
        .goods-item {
            border: 1px solid #ddd;
            padding: 15px;
            text-align: center;
        }
        .goods-item img {
            max-width: 200px;
            height: 200px;
            object-fit: cover;
        }
        .points {
            color: #ff6600;
            font-size: 18px;
            font-weight: bold;
        }
        .exchange-btn {
            background: #ff6600;
            color: white;
            border: none;
            padding: 8px 20px;
            cursor: pointer;
            border-radius: 4px;
        }
        .exchange-btn:hover {
            background: #e55d00;
        }
        .stock-info {
            color: #999;
            font-size: 12px;
        }
    </style>
</head>
<body>
    <div class="header">
        <h2>积分商城</h2>
        <div class="user-points">
            我的积分:<span id="points"><?php echo $userPoints; ?></span>
        </div>
    </div>
    <div class="goods-grid" id="goodsList">
        <!-- 商品列表由PHP动态生成 -->
        <?php foreach ($goodsList as $goods): ?>
        <div class="goods-item">
            <img src="<?php echo $goods['image']; ?>" alt="<?php echo $goods['name']; ?>">
            <h3><?php echo $goods['name']; ?></h3>
            <p class="points"><?php echo $goods['points']; ?> 积分</p>
            <p class="stock-info">库存:<?php echo $goods['stock']; ?></p>
            <button class="exchange-btn" onclick="exchange(<?php echo $goods['id']; ?>)">
                立即兑换
            </button>
        </div>
        <?php endforeach; ?>
    </div>
    <script>
    function exchange(goodsId) {
        // 弹出收货信息对话框
        showExchangeDialog(goodsId);
    }
    function showExchangeDialog(goodsId) {
        // 实现弹窗让用户输入收货信息
        // 然后调用ajax提交兑换
    }
    </script>
</body>
</html>

安全建议

  1. 防刷机制:限制兑换频率,添加验证码
  2. 事务处理:确保库存和积分操作的原子性
  3. 锁机制:高并发场景下使用Redis锁或数据库行锁
  4. 数据验证:前后端双重验证积分和库存
  5. 日志记录:记录所有敏感操作

这个实现可以满足大多数积分商城的基本需求,你可以根据具体业务进行调整和扩展。

抱歉,评论功能暂时关闭!