本文目录导读:

在 PHP 项目(特别是进销存、ERP、资产盘点等系统)中,标记“账面与实际不符”的数据,核心是将盘点数据与账面数据进行比对,找出差异并设置状态字段。
下面给出一个完整的实现思路和代码示例,包含数据库设计、后端逻辑和前端标记。
数据库表设计(关键字段)
假设有两张核心表:
inventory_book(账面库存/资产表)inventory_check_record(盘点记录表)
-- 账面表(当前系统账面数据) CREATE TABLE `inventory_book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `item_code` varchar(50) NOT NULL COMMENT '物品编码', `quantity` decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT '账面数量', `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_item_code` (`item_code`) ); -- 盘点记录表(每次盘点结果) CREATE TABLE `inventory_check_record` ( `id` int(11) NOT NULL AUTO_INCREMENT, `check_batch` varchar(50) NOT NULL COMMENT '盘点批次号', `item_code` varchar(50) NOT NULL COMMENT '物品编码', `book_quantity` decimal(10,2) NOT NULL COMMENT '账面数量(盘点时快照)', `actual_quantity` decimal(10,2) NOT NULL COMMENT '实盘数量', `diff_quantity` decimal(10,2) NOT NULL COMMENT '差异数量 (=actual-book)', `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '0-未处理 1-已处理 2-待审核 3-差异确认', `is_discrepancy` tinyint(4) NOT NULL DEFAULT 0 COMMENT '0-相符 1-不符', `remark` varchar(255) DEFAULT NULL COMMENT '差异说明', `check_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_check_batch` (`check_batch`), KEY `idx_status` (`status`), KEY `idx_is_discrepancy` (`is_discrepancy`) );
关键字段说明:
diff_quantity:差异数量(正数=盘盈,负数=盘亏)is_discrepancy:标记是否不符,当actual_quantity != book_quantity时设为 1。status:后续流程状态(可扩展)。
PHP 后端:比对并生成差异标记
<?php
/**
* 执行盘点,比对账面与实际,标记不符数据
* @param string $checkBatch 盘点批次号
* @param array $checkData 从客户端提交的盘点数据 [ ['item_code'=>'A001', 'actual_quantity'=>10], ... ]
* @return array 盘点结果统计
*/
function executeInventoryCheck($checkBatch, $checkData) {
$db = getDBConnection(); // 你的数据库连接
$matchedCount = 0;
$discrepancyCount = 0;
$resultList = [];
// 开始事务
$db->beginTransaction();
try {
foreach ($checkData as $item) {
$itemCode = $item['item_code'];
$actualQty = $item['actual_quantity'];
// 1. 查询账面数量(快照当前账面值)
$bookRow = $db->query("SELECT id, quantity FROM inventory_book WHERE item_code = ?", [$itemCode])->fetch();
if (!$bookRow) {
// 账面无此物品 -> 视为全部盘盈,差异 = actual_quantity
$bookQty = 0;
$diffQty = $actualQty;
$isDiscrepancy = 1;
} else {
$bookQty = $bookRow['quantity'];
$diffQty = $actualQty - $bookQty;
$isDiscrepancy = ($diffQty != 0) ? 1 : 0; // 标记不符
}
// 2. 插入盘点记录
$insertSql = "INSERT INTO inventory_check_record
(check_batch, item_code, book_quantity, actual_quantity, diff_quantity, is_discrepancy, check_time)
VALUES (?, ?, ?, ?, ?, ?, NOW())";
$db->execute($insertSql, [
$checkBatch,
$itemCode,
$bookQty,
$actualQty,
$diffQty,
$isDiscrepancy
]);
// 3. 统计
if ($isDiscrepancy) {
$discrepancyCount++;
} else {
$matchedCount++;
}
$resultList[] = [
'item_code' => $itemCode,
'book_qty' => $bookQty,
'actual_qty' => $actualQty,
'diff' => $diffQty,
'is_discrepancy' => $isDiscrepancy
];
}
$db->commit();
return [
'success' => true,
'total_items' => count($checkData),
'matched' => $matchedCount,
'discrepancy' => $discrepancyCount,
'details' => $resultList
];
} catch (\Exception $e) {
$db->rollback();
return ['success' => false, 'message' => $e->getMessage()];
}
}
// 调用示例
$result = executeInventoryCheck('20250328001', [
['item_code' => 'A001', 'actual_quantity' => 10],
['item_code' => 'A002', 'actual_quantity' => 5],
['item_code' => 'A003', 'actual_quantity' => 12]
]);
前端展示:高亮/标记差异行
前端可以是 HTML + JS,也可以是基于 Vue/React 的界面,关键是通过 is_discrepancy 或 diff != 0 来做样式标记。
示例 HTML + JavaScript (纯展示)
<table id="inventoryTable" border="1">
<thead>
<tr>
<th>物品编码</th>
<th>账面数量</th>
<th>实盘数量</th>
<th>差异</th>
<th>状态</th>
</tr>
</thead>
<tbody id="tableBody">
<!-- 动态填充 -->
</tbody>
</table>
<script>
// 假设从后端API获取数据
const inventoryData = [
{ item_code: 'A001', book_qty: 10, actual_qty: 10, diff: 0, is_discrepancy: 0 },
{ item_code: 'A002', book_qty: 8, actual_qty: 5, diff: -3, is_discrepancy: 1 },
{ item_code: 'A003', book_qty: 12, actual_qty: 15, diff: 3, is_discrepancy: 1 },
{ item_code: 'A004', book_qty: 6, actual_qty: 6, diff: 0, is_discrepancy: 0 }
];
function renderTable(data) {
const tbody = document.getElementById('tableBody');
tbody.innerHTML = '';
data.forEach(item => {
const tr = document.createElement('tr');
// 关键:根据是否相符添加不同CSS类
if (item.is_discrepancy) {
tr.classList.add('discrepancy-row'); // 自定义样式:红色背景或特殊图标
} else {
tr.classList.add('match-row'); // 绿色背景或正常样式
}
tr.innerHTML = `
<td>${item.item_code}</td>
<td>${item.book_qty}</td>
<td>${item.actual_qty}</td>
<td class="diff-${item.diff > 0 ? 'positive' : (item.diff < 0 ? 'negative' : 'zero')}">${item.diff}</td>
<td>${item.is_discrepancy ? '⚠️ 不符' : '✅ 相符'}</td>
`;
// 差异列可再细分颜色:正数(盘盈蓝),负数(盘亏红)
tbody.appendChild(tr);
});
}
renderTable(inventoryData);
</script>
<style>
.discrepancy-row {
background-color: #ffe6e6; /* 浅红色背景 */
font-weight: bold;
}
.match-row {
background-color: #e6ffe6; /* 浅绿色背景 */
}
.diff-positive { color: blue; }
.diff-negative { color: red; }
.diff-zero { color: gray; }
</style>
高级标记策略(可选)
a. 标记“部分不符”或“严重不符”
在数据库加一个字段 discrepancy_level,根据差异绝对值分级:
if ($diffQty == 0) {
$level = 0; // 相符
} elseif (abs($diffQty) <= 5) {
$level = 1; // 轻微不符
} else {
$level = 2; // 严重不符
}
b. 标记“账面存在但未盘点”(遗漏)
如果在盘点提交时没有传入某个账面物品,可以在比对后额外生成一条记录:
// 查询所有账面物品,与提交的盘点物品取差集
$bookItems = $db->query("SELECT item_code, quantity FROM inventory_book")->fetchAll();
$checkedCodes = array_column($checkData, 'item_code');
$missedItems = array_filter($bookItems, function($item) use ($checkedCodes) {
return !in_array($item['item_code'], $checkedCodes);
});
// 对这些未盘点到的物品也标记为不符(实际数量视为0或缺失)
foreach ($missedItems as $missed) {
// 插入盘点记录,actual_quantity = NULL 或 0,diff = -book_quantity
}
c. 利用 is_discrepancy 做后续审核流
- 后端查询时添加过滤:
SELECT * FROM inventory_check_record WHERE is_discrepancy = 1 AND status = 0
- 前端只展示不符数据,方便快速处理。
核心原则
| 步骤 | 关键操作 |
|---|---|
| 比对 | actual_quantity - book_quantity 计算差异 |
| 标记 | 将差异 !=0 的记录 is_discrepancy 设为 1 |
| 存储 | 同时记录账面快照,防止后续修改影响历史 |
| 展示 | 前端根据 is_discrepancy 应用高亮样式 |
| 扩展 | 可增加差异级别、未盘点标记、审核状态 |
这样,从数据库到前端都能清晰、准确地标记出“账面与实际不符”的数据,方便后续盘点差异分析和调账。