本文目录导读:

使用PHP实现保质期管理,通常涉及数据库设计、后端逻辑处理以及前端交互,下面提供一个完整的实现思路和代码示例,涵盖从入库到预警的全流程。
数据库表设计
首先设计两张核心表:products(产品)和inventory(库存批次)。
-- 产品主表
CREATE TABLE `products` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`sku` VARCHAR(50) NOT NULL UNIQUE, -- 商品编码
`name` VARCHAR(100) NOT NULL, -- 商品名称
`shelf_life_days` INT NOT NULL, -- 保质期天数
`unit` VARCHAR(10) DEFAULT '个', -- 单位
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 库存批次表(一个产品可以有多个批次)
CREATE TABLE `inventory` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`product_id` INT NOT NULL, -- 关联 products.id
`batch_number` VARCHAR(50) NOT NULL, -- 批次号
`quantity` INT NOT NULL DEFAULT 0, -- 库存数量
`production_date` DATE NOT NULL, -- 生产日期
`expiry_date` DATE NOT NULL, -- 到期日期(由生产日期+保质期计算得出)
`status` ENUM('正常','即将过期','已过期','已出库') DEFAULT '正常',
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) ON DELETE CASCADE,
INDEX `idx_expiry` (`expiry_date`),
INDEX `idx_status` (`status`)
);
说明:
expiry_date可以通过production_date + shelf_life_days自动计算,但建议入库时直接存储,减少后续SQL计算。status可以设置为“正常/即将过期/已过期/已出库”,便于快速筛选。
PHP后端实现步骤
1 连接数据库(使用PDO)
创建一个 db.php 文件:
<?php
function getDB() {
$host = 'localhost';
$dbname = 'your_database';
$user = 'root';
$pass = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
} catch (PDOException $e) {
die('数据库连接失败: ' . $e->getMessage());
}
}
?>
2 入库操作(自动计算到期日)
<?php
require_once 'db.php';
function addInventory($product_id, $batch_number, $quantity, $production_date) {
$pdo = getDB();
// 1. 查询该产品的保质期天数
$stmt = $pdo->prepare("SELECT shelf_life_days FROM products WHERE id = ?");
$stmt->execute([$product_id]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
throw new Exception("产品不存在");
}
// 2. 计算到期日期
$shelf_life_days = (int)$product['shelf_life_days'];
$production = new DateTime($production_date);
$expiry = $production->add(new DateInterval("P{$shelf_life_days}D"));
$expiry_date = $expiry->format('Y-m-d');
// 3. 插入库存记录
$sql = "INSERT INTO inventory (product_id, batch_number, quantity, production_date, expiry_date, status)
VALUES (?, ?, ?, ?, ?, '正常')";
$stmt = $pdo->prepare($sql);
$stmt->execute([$product_id, $batch_number, $quantity, $production_date, $expiry_date]);
return $pdo->lastInsertId();
}
// 示例调用
// addInventory(1, 'BATCH202501', 100, '2025-01-01');
?>
3 自动更新状态(可放在定时任务或每次查询前执行)
<?php
function updateExpiryStatus() {
$pdo = getDB();
$today = date('Y-m-d');
$warning_days = 30; // 提前30天预警
// 1. 将到期的批次标记为“已过期”
$sql = "UPDATE inventory SET status = '已过期' WHERE expiry_date < ? AND status != '已出库'";
$pdo->prepare($sql)->execute([$today]);
// 2. 即将过期(30天内到期)
$future = date('Y-m-d', strtotime("+{$warning_days} days"));
$sql = "UPDATE inventory SET status = '即将过期'
WHERE expiry_date BETWEEN ? AND ? AND status = '正常'";
$pdo->prepare($sql)->execute([$today, $future]);
// 3. 恢复状态:若之前标记为“即将过期”,但日期已过30天且未过期(比如用户主动延期?视业务而定)
// 通常不需要,因为“即将过期”是一种预警状态,保持即可。
}
?>
说明:建议通过 cron job 每天执行一次 updateExpiryStatus(),或者在每次查询库存页面时调用(虽然性能稍低但实时性好)。
4 查询库存列表(含视图)
<?php
function getInventoryList($status_filter = '', $product_id = 0) {
$pdo = getDB();
$sql = "SELECT i.*, p.name AS product_name, p.sku, p.shelf_life_days
FROM inventory i
JOIN products p ON i.product_id = p.id
WHERE 1=1";
$params = [];
if ($status_filter) {
$sql .= " AND i.status = ?";
$params[] = $status_filter;
}
if ($product_id > 0) {
$sql .= " AND i.product_id = ?";
$params[] = $product_id;
}
$sql .= " ORDER BY i.expiry_date ASC";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 示例:获取所有即将过期的
// $items = getInventoryList('即将过期');
?>
5 出库操作(修改数量或标记出库)
<?php
function outboundInventory($id, $quantity_to_out) {
$pdo = getDB();
// 查询当前库存
$stmt = $pdo->prepare("SELECT quantity FROM inventory WHERE id = ? AND status != '已出库'");
$stmt->execute([$id]);
$item = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$item) {
throw new Exception("记录不存在或已出库");
}
if ($item['quantity'] < $quantity_to_out) {
throw new Exception("库存不足,当前库存: {$item['quantity']}");
}
// 减少数量
$new_quantity = $item['quantity'] - $quantity_to_out;
if ($new_quantity == 0) {
// 数量为0时,标记为已出库
$sql = "UPDATE inventory SET quantity = 0, status = '已出库' WHERE id = ?";
} else {
$sql = "UPDATE inventory SET quantity = ? WHERE id = ?";
}
$stmt = $pdo->prepare($sql);
$stmt->execute($new_quantity == 0 ? [$id] : [$new_quantity, $id]);
return true;
}
?>
前端展示与预警
1 HTML示例(显示库存列表并高亮预警)
<?php
// 假设我们调用 getInventoryList() 获取数据
$inventoryList = getInventoryList(); // 可传入筛选参数
?>
<!DOCTYPE html>
<html>
<head>保质期管理系统</title>
<style>
.expired { background-color: #fdd; } /* 红色提醒 */
.warning { background-color: #ffd; } /* 黄色警告 */
.normal { background-color: #efe; } /* 绿色正常 */
td { padding: 8px; border: 1px solid #ccc; }
table { border-collapse: collapse; width: 100%; }
</style>
</head>
<body>
<h1>库存批次列表</h1>
<table>
<tr>
<th>商品名称</th>
<th>批次号</th>
<th>库存数量</th>
<th>生产日期</th>
<th>到期日期</th>
<th>状态</th>
<th>操作</th>
</tr>
<?php foreach ($inventoryList as $item): ?>
<?php
$row_class = 'normal';
if ($item['status'] == '已过期') $row_class = 'expired';
elseif ($item['status'] == '即将过期') $row_class = 'warning';
?>
<tr class="<?= $row_class ?>">
<td><?= htmlspecialchars($item['product_name']) ?></td>
<td><?= htmlspecialchars($item['batch_number']) ?></td>
<td><?= $item['quantity'] ?></td>
<td><?= $item['production_date'] ?></td>
<td><?= $item['expiry_date'] ?></td>
<td><?= $item['status'] ?></td>
<td>
<!-- 出库表单示例 -->
<form method="post" style="display:inline;">
<input type="hidden" name="action" value="outbound">
<input type="hidden" name="inventory_id" value="<?= $item['id'] ?>">
<input type="number" name="quantity" min="1" max="<?= $item['quantity'] ?>" required>
<button type="submit">出库</button>
</form>
</td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>
2 处理出库请求
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
require_once 'db.php';
if ($_POST['action'] === 'outbound') {
try {
$id = (int)$_POST['inventory_id'];
$quantity = (int)$_POST['quantity'];
outboundInventory($id, $quantity);
header('Location: inventory_list.php?success=出库成功');
} catch (Exception $e) {
header('Location: inventory_list.php?error=' . urlencode($e->getMessage()));
}
exit;
}
}
?>
定时任务的配置(Linux crontab示例)
# 每天凌晨2点执行更新状态 0 2 * * * php /path/to/your/project/cron_update_status.php
这个方案涵盖了: 如果需要更完整的项目代码(如用户管理、权限控制、分页、导出Excel),可以基于此框架逐步扩展。
cron_update_status.php
<?php
require_once 'path_to_db.php';
updateExpiryStatus(); // 调用之前定义的函数
echo "状态更新完成:", date('Y-m-d H:i:s');
?>
进阶建议
1 使用队列或缓存
product_id,前端直接从 Redis 读取预警通知。2 短信 / 邮件 / 消息推送
updateExpiryStatus() 中,当记录从“正常”变为“即将过期”时,触发通知:if ($updated_count > 0) {
// 发送通知给管理员
sendWarningEmail($newly_warning_items);
}
3 考虑“保质期剩余天数”字段
inventory 表加一个 remaining_days 字段,每次更新状态时计算并存储,避免SQL实时计算 DATEDIFF(expiry_date, CURDATE())。4 扫码出入库
batch_number 生成二维码),使用扫码枪或手机扫码后快速入库、出库、查询。