本文目录导读:

在PHP项目中实现商品上下架功能,核心是设计数据库状态字段 + 后端逻辑控制 + 前端交互,下面是完整实现方案:
数据库设计
在商品表中添加状态字段:
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
price DECIMAL(10,2),
stock INT DEFAULT 0,
status TINYINT DEFAULT 1 COMMENT '1=上架 0=下架',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
状态字段设计要点:
- 建议用
TINYINT或INT类型 - 值含义清晰:
1上架,0下架 - 后续扩展可加
2=待审核等状态
后端实现
1 商品模型层
class Product {
private $db;
public function __construct($db) {
$this->db = $db;
}
// 切换商品状态
public function toggleStatus($productId) {
$sql = "UPDATE products SET status = !status WHERE id = ?";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$productId]);
}
// 设置指定状态
public function setStatus($productId, $status) {
$allowedStatus = [0, 1];
if (!in_array($status, $allowedStatus)) {
return false;
}
$sql = "UPDATE products SET status = ? WHERE id = ?";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$status, $productId]);
}
// 批量操作
public function batchSetStatus($productIds, $status) {
if (empty($productIds)) return false;
$placeholders = implode(',', array_fill(0, count($productIds), '?'));
$sql = "UPDATE products SET status = ? WHERE id IN ($placeholders)";
$params = array_merge([$status], $productIds);
$stmt = $this->db->prepare($sql);
return $stmt->execute($params);
}
// 获取在售商品
public function getActiveProducts() {
$sql = "SELECT * FROM products WHERE status = 1";
return $this->db->query($sql)->fetchAll();
}
}
2 控制器层
class ProductController {
private $productModel;
public function __construct($productModel) {
$this->productModel = $productModel;
}
// 切换状态接口
public function toggleStatus($request) {
$productId = $request['id'] ?? 0;
// 验证商品存在
if (!$this->productExists($productId)) {
return ['code' => 404, 'msg' => '商品不存在'];
}
$result = $this->productModel->toggleStatus($productId);
if ($result) {
return ['code' => 200, 'msg' => '状态切换成功'];
} else {
return ['code' => 500, 'msg' => '操作失败'];
}
}
// 上下架操作接口
public function updateStatus($request) {
$productId = $request['id'] ?? 0;
$status = $request['status'] ?? 0;
// 权限验证
if (!$this->checkPermission()) {
return ['code' => 403, 'msg' => '无权限'];
}
$result = $this->productModel->setStatus($productId, $status);
if ($result) {
$action = $status == 1 ? '上架' : '下架';
// 记录操作日志
$this->logOperation($productId, $action);
return ['code' => 200, 'msg' => "商品{$action}成功"];
}
return ['code' => 500, 'msg' => '操作失败'];
}
}
前端实现
1 使用 AJAX 实现
<!-- 商品列表页面 -->
<div id="product-list">
<table>
<thead>
<tr>
<th><input type="checkbox" id="select-all"></th>
<th>商品名称</th>
<th>价格</th>
<th>库存</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($products as $product): ?>
<tr data-id="<?= $product['id'] ?>">
<td><input type="checkbox" class="product-checkbox"></td>
<td><?= htmlspecialchars($product['name']) ?></td>
<td>¥<?= $product['price'] ?></td>
<td><?= $product['stock'] ?></td>
<td>
<span class="status-badge <?= $product['status'] ? 'active' : 'inactive' ?>">
<?= $product['status'] ? '上架' : '下架' ?>
</span>
</td>
<td>
<button class="btn-toggle-status" data-id="<?= $product['id'] ?>">
<?= $product['status'] ? '下架' : '上架' ?>
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- 批量操作按钮 -->
<div class="batch-actions">
<button id="batch-on">批量上架</button>
<button id="batch-off">批量下架</button>
</div>
2 JavaScript 交互
$(document).ready(function() {
// 单个商品上架/下架切换
$('.btn-toggle-status').click(function() {
const productId = $(this).data('id');
const $button = $(this);
// 显示加载状态
$button.prop('disabled', true).text('处理中...');
$.ajax({
url: '/api/product/toggle-status',
method: 'POST',
data: { id: productId },
dataType: 'json',
success: function(response) {
if (response.code === 200) {
// 更新UI
const $row = $button.closest('tr');
const $badge = $row.find('.status-badge');
const $toggleBtn = $row.find('.btn-toggle-status');
// 切换状态显示
if ($badge.hasClass('active')) {
$badge.removeClass('active').addClass('inactive');
$badge.text('下架');
$toggleBtn.text('上架');
} else {
$badge.removeClass('inactive').addClass('active');
$badge.text('上架');
$toggleBtn.text('下架');
}
showToast('操作成功', 'success');
} else {
showToast(response.msg || '操作失败', 'error');
}
},
error: function() {
showToast('网络错误,请重试', 'error');
},
complete: function() {
$button.prop('disabled', false);
}
});
});
// 批量操作
$('#batch-on, #batch-off').click(function() {
const status = $(this).attr('id') === 'batch-on' ? 1 : 0;
const selectedIds = [];
// 收集选中的商品ID
$('.product-checkbox:checked').each(function() {
selectedIds.push($(this).closest('tr').data('id'));
});
if (selectedIds.length === 0) {
showToast('请先选择商品', 'warning');
return;
}
// 确认对话框
if (!confirm(`确定要${status ? '上架' : '下架'}选中的${selectedIds.length}个商品吗?`)) {
return;
}
$.ajax({
url: '/api/product/batch-status',
method: 'POST',
data: {
ids: selectedIds,
status: status
},
dataType: 'json',
success: function(response) {
if (response.code === 200) {
location.reload();
} else {
showToast(response.msg, 'error');
}
}
});
});
});
安全考虑
1 权限验证
// 中间件示例
class AuthMiddleware {
public function handle($request) {
// 只有管理员可以操作上架/下架
if ($_SESSION['user_role'] !== 'admin') {
header('HTTP/1.1 403 Forbidden');
echo json_encode(['code' => 403, 'msg' => '无权限']);
exit;
}
}
}
2 防止 SQL 注入
- 始终使用预处理语句
- 对输入进行验证和过滤
// 安全的查询
$stmt = $pdo->prepare("UPDATE products SET status = ? WHERE id = ?");
$stmt->execute([intval($status), intval($id)]);
高级功能扩展
1 定时上下架
// 创建定时任务表
CREATE TABLE schedule_products (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT,
action TINYINT COMMENT '1=上架 0=下架',
execute_time DATETIME,
status TINYINT DEFAULT 0 COMMENT '0=待执行 1=已执行',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
// 定时任务脚本
class ScheduleTask {
public function execute() {
$sql = "SELECT * FROM schedule_products
WHERE status = 0 AND execute_time <= NOW()";
$tasks = $this->db->query($sql)->fetchAll();
foreach ($tasks as $task) {
// 执行上下架操作
$this->updateProductStatus($task['product_id'], $task['action']);
// 更新任务状态
$updateSql = "UPDATE schedule_products SET status = 1 WHERE id = ?";
$this->db->prepare($updateSql)->execute([$task['id']]);
}
}
}
2 日志记录
CREATE TABLE product_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT,
action VARCHAR(50),
operator INT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_product_id (product_id)
);
最佳实践建议
- 使用事务:批量操作时使用事务确保数据一致性
- 缓存处理:频繁查询的商品状态可加入 Redis 缓存
- SEO 处理:下架商品返回 404 状态码,避免搜索引擎索引
- 前端优化:使用防抖处理,避免频繁点击导致多次请求
- 状态机模式:复杂状态流转建议使用状态机模式
这个实现方案适合大多数 PHP 项目,可以根据具体需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播