如何用PHP项目实现保质期管理?

wen java案例 5

本文目录导读:

如何用PHP项目实现保质期管理?

  1. 数据库表设计
  2. PHP后端实现步骤
  3. 前端展示与预警
  4. 定时任务的配置(Linux crontab示例)
  5. 进阶建议

使用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

cron_update_status.php

<?php
require_once 'path_to_db.php';
updateExpiryStatus();   // 调用之前定义的函数
echo "状态更新完成:", date('Y-m-d H:i:s');
?>

进阶建议

1 使用队列或缓存

  • 如果数据量大,每次查询都扫描全表更新状态效率低,可以只更新最近30天的数据。
  • 可以用 Redis 存一批即将过期的 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 生成二维码),使用扫码枪或手机扫码后快速入库、出库、查询。

这个方案涵盖了:

  1. 数据库设计:产品主表 + 库存批次表,按批次管理关键日期。
  2. 后端逻辑
    • 入库:自动计算到期日。
    • 出库:减库存或标记出库。
    • 状态更新:通过定时任务或查询时实时计算。
  3. 前端展示:按状态显示不同颜色预警。
  4. 扩展性:可轻松对接定时通知、扫码、报表等功能。

如果需要更完整的项目代码(如用户管理、权限控制、分页、导出Excel),可以基于此框架逐步扩展。

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