PHP:在foreach循环中检查产品借阅日期范围/可用性
实现图书馆产品借阅系统:表格展示与可用性标记方案
嘿,我来帮你梳理下怎么搞定这个需求,分几个关键步骤推进,都是实际开发中常用的思路:
第一步:从数据库拉取基础产品数据
首先得把符合基础条件的产品(比如未下架、属于当前馆的产品)和它们的有效借阅记录一起查出来——毕竟要判断可用性,得知道每个产品已经被借走的时间段对吧?
以MySQL为例,给你个参考查询语句:
SELECT p.product_id, p.product_name, p.category, br.start_date AS borrowed_start, br.end_date AS borrowed_end FROM products p LEFT JOIN borrow_records br ON p.product_id = br.product_id AND br.status = 'active' -- 只关联还没归还的有效借阅 WHERE p.is_active = 1 -- 基础筛选:只取启用的产品
用LEFT JOIN是为了把那些从没被借过的产品也包含进来,这类产品的借阅日期字段会是NULL,默认就是可用的。
第二步:判断产品可用性的核心逻辑
用户输入的是MM/DD/YYYY格式的日期范围,首先得把所有日期转成统一可比较的格式(比如前端用Date对象,后端用对应语言的日期类型),然后判断用户要借的时间段和产品已被占用的时间段有没有重叠——只要有重叠,产品就不可用。
给你写个通俗易懂的伪代码逻辑:
function checkAvailability(userStart, userEnd, borrowedRecords) { // 先把用户输入的日期转成可比较的Date对象 const userStartDate = new Date(userStart); const userEndDate = new Date(userEnd); // 没有任何借阅记录?直接返回可用 if (!borrowedRecords || borrowedRecords.length === 0) return true; // 遍历每条借阅记录,检查是否重叠 for (const record of borrowedRecords) { const borrowStart = new Date(record.borrowed_start); const borrowEnd = new Date(record.borrowed_end); // 重叠判断规则:用户的起始日期 ≤ 借阅结束日期,且用户的结束日期 ≥ 借阅起始日期 if (userStartDate <= borrowEnd && userEndDate >= borrowStart) { return false; // 有重叠,不可用 } } return true; // 没重叠,可用 }
提醒下:一定要提前做用户输入的日期格式校验,比如用户输了个无效日期,得给个友好提示,别直接进判断逻辑。
第三步:表格渲染与状态可视化
拿到处理好的产品列表(带可用性状态)后,前端渲染表格的时候,用视觉差异区分状态,比如可用的标绿打勾,不可用的标红打叉,用户一眼就能看明白。
给你个React的示例代码(其他框架思路类似):
import React from 'react'; function BorrowTable({ products, userSelectedStart, userSelectedEnd }) { // 提前把每个产品的可用性算好 const processedProducts = products.map(product => ({ ...product, isAvailable: checkAvailability(userSelectedStart, userSelectedEnd, product.borrowedRecords) })); return ( <table style={{ borderCollapse: 'collapse', width: '100%', marginTop: '1rem' }}> <thead> <tr style={{ backgroundColor: '#f5f5f5' }}> <th style={{ border: '1px solid #ddd', padding: '8px' }}>产品ID</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>产品名称</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>分类</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>状态</th> </tr> </thead> <tbody> {processedProducts.map(prod => ( <tr key={prod.product_id} style={{ backgroundColor: prod.isAvailable ? '#e8f8f5' : '#fff5f5', textAlign: 'center' }} > <td style={{ border: '1px solid #ddd', padding: '8px' }}>{prod.product_id}</td> <td style={{ border: '1px solid #ddd', padding: '8px' }}>{prod.product_name}</td> <td style={{ border: '1px solid #ddd', padding: '8px' }}>{prod.category}</td> <td style={{ border: '1px solid #ddd', padding: '8px' }}> {prod.isAvailable ? ( <span style={{ color: '#27ae60', fontWeight: 'bold' }}>✅ 可用</span> ) : ( <span style={{ color: '#e74c3c', fontWeight: 'bold' }}>❌ 不可用</span> )} </td> </tr> ))} </tbody> </table> ); } // 复用可用性判断函数 function checkAvailability(userStart, userEnd, borrowedRecords) { const userStartDate = new Date(userStart); const userEndDate = new Date(userEnd); if (!borrowedRecords || borrowedRecords.length === 0) return true; for (const record of borrowedRecords) { const borrowStart = new Date(record.borrowed_start); const borrowEnd = new Date(record.borrowed_end); if (userStartDate <= borrowEnd && userEndDate >= borrowStart) { return false; } } return true; } export default BorrowTable;
几个额外的坑要注意
- 日期格式统一:用户输入的MM/DD/YYYY格式要先转成ISO标准格式(YYYY-MM-DD)再和数据库的日期对比,避免跨时区或者格式转换错误。
- 性能优化:如果产品数量特别多,尽量把可用性判断逻辑放在后端做(比如用SQL的日期函数直接计算),减少前端的计算压力,同时给数据库的
product_id、start_date、end_date加索引,提升查询速度。 - 边界场景处理:比如用户选的起始日期刚好等于某个产品的归还日期,这种情况算不算可用?得根据你的业务规则调整判断逻辑——如果允许“无缝衔接”,那这种情况应该算可用,把判断条件改成
userStartDate < borrowEnd && userEndDate > borrowStart就行。
内容的提问来源于stack exchange,提问作者user982124
相关产品推荐
相关产品推荐

