图:

代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>电脑配件商品库</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft Yahei", sans-serif;
}
body {
background-color: #f5f5f5;
padding: 2px;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 0 10px;
}
header {
text-align: center;
margin-bottom: 6px;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
position: relative;
}
/* 购物车样式 */
.cart-icon {
position: absolute;
top: 20px;
right: 20px;
font-size: 24px;
cursor: pointer;
color: #007bff;
display: flex;
align-items: center;
gap: 5px;
}
.cart-badge {
background-color: #e63946;
color: white;
font-size: 12px;
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
/* 购物车弹窗 */
.cart-modal {
position: fixed;
top: 0;
right: 0;
width: 380px;
height: 100vh;
background-color: white;
box-shadow: -2px 0 10px rgba(0,0,0,0.1);
z-index: 1000;
transform: translateX(100%);
transition: transform 0.3s ease;
display: flex;
flex-direction: column;
}
.cart-modal.show {
transform: translateX(0);
}
.cart-header {
padding: 15px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
}
.cart-close {
font-size: 20px;
cursor: pointer;
color: #666;
}
.cart-body {
flex: 1;
padding: 15px;
overflow-y: auto;
}
.cart-empty {
text-align: center;
padding: 40px 0;
color: #999;
}
.cart-item {
display: flex;
padding: 10px 0;
border-bottom: 1px solid #eee;
gap: 10px;
}
.cart-item-img {
width: 60px;
height: 60px;
object-fit: contain;
background-color: #f9f9f9;
border-radius: 4px;
}
.cart-item-info {
flex: 1;
}
.cart-item-name {
font-size: 14px;
margin-bottom: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.cart-item-price {
font-size: 14px;
color: #e63946;
font-weight: bold;
margin-bottom: 8px;
}
.cart-item-quantity {
display: flex;
align-items: center;
gap: 8px;
}
.quantity-btn {
width: 24px;
height: 24px;
border: 1px solid #ddd;
background-color: #f5f5f5;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.quantity-input {
width: 30px;
height: 24px;
text-align: center;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 12px;
}
.cart-item-delete {
color: #999;
font-size: 12px;
cursor: pointer;
margin-top: 5px;
}
.cart-item-delete:hover {
color: #e63946;
}
.cart-footer {
padding: 15px;
border-top: 1px solid #eee;
}
.cart-total {
display: flex;
justify-content: space-between;
font-size: 16px;
margin-bottom: 15px;
}
.cart-total-price {
color: #e63946;
font-weight: bold;
}
.cart-actions {
display: flex;
gap: 10px;
}
.cart-btn {
flex: 1;
padding: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.cart-clear {
background-color: #f5f5f5;
color: #666;
}
.cart-export {
background-color: #28a745;
color: white;
}
.cart-checkout {
background-color: #007bff;
color: white;
}
/* 遮罩层 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.3);
z-index: 999;
display: none;
}
.overlay.show {
display: block;
}
/* 密码验证弹窗样式 */
.password-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
z-index: 2000;
display: none;
align-items: center;
justify-content: center;
}
.password-modal.show {
display: flex;
}
.password-content {
background-color: white;
padding: 25px;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
width: 90%;
max-width: 350px;
}
.password-content h3 {
margin-bottom: 10px;
color: #333;
text-align: center;
}
.password-content p {
color: #666;
margin-bottom: 20px;
text-align: center;
font-size: 14px;
}
.password-content input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
margin-bottom: 20px;
box-sizing: border-box;
}
.password-content input:focus {
outline: none;
border-color: #007bff;
}
.password-actions {
display: flex;
gap: 10px;
}
.password-btn {
flex: 1;
padding: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.3s;
}
.password-btn:hover {
opacity: 0.9;
}
#passwordCancel {
background-color: #f5f5f5;
color: #666;
}
.password-confirm {
background-color: #28a745;
color: white;
}
/* 打印容器 - 重要修改:改为正常隐藏 */
.print-container {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: auto;
min-height: 100%;
background: white;
color: black;
padding: 15px;
box-sizing: border-box;
font-size: 12px;
z-index: 99999;
overflow: visible;
}
/* 打印预览容器 - 用于正常显示 */
.print-preview-container {
width: 100%;
max-width: 210mm; /* A4宽度 */
margin: 0 auto;
padding: 15mm;
box-sizing: border-box;
}
.print-header {
text-align: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #333;
}
.print-header h2 {
font-size: 18px;
margin-bottom: 5px;
}
.print-header p {
font-size: 12px;
color: #666;
}
.print-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 15px;
font-size: 11px;
table-layout: fixed;
}
.print-table th, .print-table td {
border: 1px solid #333;
padding: 6px 4px;
text-align: center;
word-break: break-word;
vertical-align: middle;
}
.print-table th {
background-color: #f0f0f0;
font-weight: bold;
}
.print-table td:nth-child(2) {
text-align: left;
padding-left: 8px;
}
.print-total {
text-align: right;
font-size: 14px;
font-weight: bold;
margin-top: 10px;
padding-right: 20px;
}
.print-footer {
text-align: center;
margin-top: 20px;
font-size: 10px;
color: #666;
border-top: 1px solid #ddd;
padding-top: 10px;
}
/* 打印样式 - 核心修复:简化打印逻辑 */
@media print {
/* 隐藏所有非打印元素 */
body * {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
}
/* 只显示打印容器及其内容 */
.print-container,
.print-container * {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
position: static !important;
top: auto !important;
left: auto !important;
width: 100% !important;
height: auto !important;
max-width: none !important;
min-height: auto !important;
margin: 0 !important;
padding: 0 !important;
box-shadow: none !important;
background: white !important;
color: black !important;
float: none !important;
overflow: visible !important;
page-break-inside: avoid !important;
}
.print-container {
display: block !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
}
.print-preview-container {
width: 100% !important;
max-width: 100% !important;
padding: 10mm !important;
margin: 0 !important;
}
/* A5纸张设置 */
@page {
size: A5 portrait;
margin: 10mm;
}
.print-table {
width: 100% !important;
border-collapse: collapse !important;
font-size: 10px !important;
page-break-inside: avoid !important;
}
.print-table th, .print-table td {
border: 1px solid #000 !important;
padding: 4px 3px !important;
page-break-inside: avoid !important;
page-break-before: avoid !important;
page-break-after: avoid !important;
}
.print-table th {
background-color: #f0f0f0 !important;
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
.print-header {
margin-bottom: 10px !important;
padding-bottom: 5px !important;
border-bottom: 2px solid #333 !important;
page-break-after: avoid !important;
}
.print-header h2 {
font-size: 16px !important;
margin-bottom: 3px !important;
}
.print-total {
text-align: right !important;
font-size: 12px !important;
font-weight: bold !important;
margin-top: 8px !important;
padding-right: 10px !important;
page-break-before: avoid !important;
}
.print-footer {
text-align: center !important;
margin-top: 10px !important;
font-size: 9px !important;
color: #666 !important;
page-break-before: avoid !important;
}
/* 避免表格跨页断裂 */
tr {
page-break-inside: avoid !important;
page-break-after: auto !important;
}
}
h1 {
color: #333;
margin-bottom: 10px;
}
.filter-section {
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 6px;
}
.category-filter {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
align-items: center;
}
.category-btn {
padding: 8px 16px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #fff;
cursor: pointer;
transition: all 0.3s;
}
.category-btn:hover {
background-color: #007bff;
color: #fff;
border-color: #007bff;
}
.category-btn.active {
background-color: #007bff;
color: #fff;
border-color: #007bff;
}
/* 新增:导出全部商品按钮样式 */
.export-all-btn {
padding: 8px 16px;
border: 1px solid #28a745;
border-radius: 4px;
background-color: #28a745;
color: white;
cursor: pointer;
transition: all 0.3s;
margin-left: auto;
}
.export-all-btn:hover {
background-color: #218838;
border-color: #1e7e34;
}
.search-box {
display: flex;
gap: 10px;
}
#search-input {
flex: 1;
padding: 8px 16px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
#search-btn {
padding: 8px 16px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
#search-btn:hover {
background-color: #0056b3;
}
/* 核心修改:调整网格布局为一行5列 */
.product-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 15px;
}
.product-card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow: hidden;
transition: transform 0.3s;
}
.product-card:hover {
transform: translateY(-5px);
}
.product-img {
width: 100%;
height: 160px;
object-fit: contain;
padding: 15px;
background-color: #f9f9f9;
}
.product-info {
padding: 12px;
}
.product-name {
font-size: 14px;
color: #333;
margin-bottom: 8px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.product-price {
font-size: 16px;
color: #e63946;
font-weight: bold;
margin-bottom: 8px;
}
.product-stock {
font-size: 12px;
color: #666;
margin-bottom: 8px;
}
.product-stock.out-of-stock {
color: #e63946;
}
.product-category {
font-size: 11px;
color: #999;
background-color: #f0f0f0;
padding: 2px 6px;
border-radius: 4px;
display: inline-block;
margin-bottom: 8px;
}
/* 添加购物车按钮 */
.add-to-cart {
width: 100%;
padding: 6px 0;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
transition: background-color 0.3s;
}
.add-to-cart:hover {
background-color: #0056b3;
}
.add-to-cart:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.no-result {
grid-column: 1 / -1;
text-align: center;
padding: 50px;
color: #666;
font-size: 18px;
}
/* 强制宽屏时固定5列 */
@media (min-width: 1400px) {
.product-list {
grid-template-columns: repeat(5, 1fr) !important;
}
}
/* 移动端适配 */
@media (max-width: 768px) {
.cart-modal {
width: 100%;
}
.cart-actions {
flex-direction: column;
}
.category-filter {
flex-direction: column;
align-items: stretch;
}
.export-all-btn {
margin-left: 0;
margin-top: 10px;
width: 100%;
}
.product-list {
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 10px;
}
.product-img {
height: 140px;
padding: 10px;
}
.product-info {
padding: 10px;
}
.product-name {
font-size: 13px;
}
.product-price {
font-size: 14px;
}
}
@media (max-width: 480px) {
.product-list {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.product-img {
height: 120px;
}
.product-name {
font-size: 12px;
}
.product-price {
font-size: 13px;
}
}
</style>
<!-- 引入SheetJS库用于导出Excel -->
<script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>
</head>
<body>
<div class="container">
<header>
<h1>电脑配件商品库</h1>
<p>各类电脑配件、外设、网络产品等价格参考,不是现价!</p>
<!-- 购物车图标 -->
<div class="cart-icon" id="cartIcon">
🛒 <span class="cart-badge" id="cartBadge">0</span>
</div>
</header>
<section class="filter-section">
<div class="category-filter">
<button class="category-btn active" data-category="all">全部商品</button>
<!-- 分类按钮会通过JS动态生成 -->
<!-- 新增:导出全部商品按钮 -->
<button class="export-all-btn" id="exportAllBtn">导出全部商品Excel</button>
</div>
<div class="search-box">
<input type="text" id="search-input" placeholder="输入商品名称搜索...">
<button id="search-btn">搜索</button>
</div>
</section>
<section class="product-list" id="product-list">
<!-- 商品卡片会通过JS动态生成 -->
</section>
</div>
<!-- 购物车弹窗 -->
<div class="cart-modal" id="cartModal">
<div class="cart-header">
<h3>我的购物车</h3>
<span class="cart-close" id="cartClose">×</span>
</div>
<div class="cart-body" id="cartBody">
<div class="cart-empty">购物车空空如也~</div>
</div>
<div class="cart-footer">
<div class="cart-total">
<span>总计:</span>
<span class="cart-total-price" id="cartTotalPrice">¥0.00</span>
</div>
<div class="cart-actions">
<button class="cart-btn cart-clear" id="cartClear">清空购物车</button>
<button class="cart-btn cart-export" id="cartExport">导出Excel</button>
<button class="cart-btn cart-checkout" id="cartCheckout">结算/打印</button>
</div>
</div>
</div>
<!-- 密码验证弹窗 -->
<div class="password-modal" id="passwordModal">
<div class="password-content">
<h3>验证密码</h3>
<p>请输入密码以导出全部商品</p>
<input type="password" id="passwordInput" placeholder="请输入密码" autocomplete="off">
<div class="password-actions">
<button class="password-btn" id="passwordCancel">取消</button>
<button class="password-btn password-confirm" id="passwordConfirm">确认</button>
</div>
</div>
</div>
<!-- 打印容器 -->
<div class="print-container" id="printContainer">
<div class="print-preview-container">
<div class="print-header">
<h2>电脑配件采购清单</h2>
<p id="printDate"></p>
</div>
<table class="print-table">
<thead>
<tr>
<th width="10%">序号</th>
<th width="40%">商品名称</th>
<th width="15%">单价(¥)</th>
<th width="15%">数量</th>
<th width="20%">小计(¥)</th>
</tr>
</thead>
<tbody id="printTableBody">
<!-- 打印内容会动态生成 -->
</tbody>
</table>
<div class="print-total" id="printTotal">
合计金额:¥0.00
</div>
<div class="print-footer">
打印时间:<span id="printTime"></span> | 备注:价格仅为参考,非实际交易价格
</div>
</div>
</div>
<!-- 遮罩层 -->
<div class="overlay" id="overlay"></div>
<script>
// 商品数据
const productData = [
{"id":1,"name":"大正色带LQ630K_LQ635k","price":10,"stock":5,"category":"耗材","image_path":"images\\51_20251005_192131.jpg"},
// ... 其他商品数据保持不变 ...
{"id":138,"name":"TP BE6400 6线路由器","price":245,"stock":1,"category":"网络产品","image_path":"images\\product_20251107140555_BE6400.jpg"}
];
// 获取DOM元素
const categoryFilter = document.querySelector('.category-filter');
const productList = document.getElementById('product-list');
const searchInput = document.getElementById('search-input');
const searchBtn = document.getElementById('search-btn');
const exportAllBtn = document.getElementById('exportAllBtn');
// 购物车相关DOM
const cartIcon = document.getElementById('cartIcon');
const cartModal = document.getElementById('cartModal');
const cartClose = document.getElementById('cartClose');
const cartBody = document.getElementById('cartBody');
const cartBadge = document.getElementById('cartBadge');
const cartTotalPrice = document.getElementById('cartTotalPrice');
const cartClear = document.getElementById('cartClear');
const cartExport = document.getElementById('cartExport');
const cartCheckout = document.getElementById('cartCheckout');
const overlay = document.getElementById('overlay');
// 密码验证相关DOM
const passwordModal = document.getElementById('passwordModal');
const passwordInput = document.getElementById('passwordInput');
const passwordConfirm = document.getElementById('passwordConfirm');
const passwordCancel = document.getElementById('passwordCancel');
// 打印相关DOM
const printContainer = document.getElementById('printContainer');
const printTableBody = document.getElementById('printTableBody');
const printTotal = document.getElementById('printTotal');
const printDate = document.getElementById('printDate');
const printTime = document.getElementById('printTime');
// 导出全部商品的密码
const EXPORT_PASSWORD = '123';
// 购物车数据
let cart = JSON.parse(localStorage.getItem('productCart')) || [];
// 生成分类按钮
function renderCategoryButtons() {
const categories = [...new Set(productData.map(item => item.category))];
categories.forEach(category => {
const btn = document.createElement('button');
btn.className = 'category-btn';
btn.dataset.category = category;
btn.textContent = category;
categoryFilter.appendChild(btn);
});
// 分类按钮点击事件
const categoryBtns = document.querySelectorAll('.category-btn');
categoryBtns.forEach(btn => {
btn.addEventListener('click', () => {
// 移除所有active类
categoryBtns.forEach(b => b.classList.remove('active'));
// 添加当前active类
btn.classList.add('active');
// 筛选商品
const category = btn.dataset.category;
filterProducts(category);
});
});
}
// 渲染商品列表
function renderProducts(products) {
productList.innerHTML = '';
if (products.length === 0) {
const noResult = document.createElement('div');
noResult.className = 'no-result';
noResult.textContent = '暂无匹配的商品';
productList.appendChild(noResult);
return;
}
products.forEach(product => {
const card = document.createElement('div');
card.className = 'product-card';
// 处理图片路径(替换反斜杠)
const imgPath = product.image_path.replace(/\\/g, '/');
// 库存状态类名
const stockClass = product.stock === 0 ? 'out-of-stock' : '';
// 库存文本
const stockText = product.stock === 0 ? '缺货' : `库存:${product.stock}件`;
// 禁用添加购物车按钮(缺货时)
const isDisabled = product.stock === 0 ? 'disabled' : '';
card.innerHTML = `
<img src="${imgPath}" alt="${product.name}" class="product-img">
<div class="product-info">
<h3 class="product-name">${product.name}</h3>
<div class="product-price">¥${product.price.toFixed(2)}</div>
<div class="product-stock ${stockClass}">${stockText}</div>
<div class="product-category">${product.category}</div>
<button class="add-to-cart" ${isDisabled} data-id="${product.id}">
${product.stock === 0 ? '缺货' : '加入购物车'}
</button>
</div>
`;
productList.appendChild(card);
});
// 绑定加入购物车事件
bindAddToCartEvents();
}
// 筛选商品
function filterProducts(category = 'all', keyword = '') {
let filteredProducts = productData;
// 按分类筛选
if (category !== 'all') {
filteredProducts = filteredProducts.filter(item => item.category === category);
}
// 按关键词筛选
if (keyword) {
filteredProducts = filteredProducts.filter(item =>
item.name.toLowerCase().includes(keyword.toLowerCase())
);
}
// 渲染筛选后的商品
renderProducts(filteredProducts);
}
// 绑定加入购物车事件
function bindAddToCartEvents() {
const addToCartBtns = document.querySelectorAll('.add-to-cart');
addToCartBtns.forEach(btn => {
btn.addEventListener('click', () => {
const productId = parseInt(btn.dataset.id);
const product = productData.find(item => item.id === productId);
if (product) {
addToCart(product);
// 简单的添加成功提示
btn.textContent = '已加入';
setTimeout(() => {
btn.textContent = '加入购物车';
}, 1000);
}
});
});
}
// 添加商品到购物车
function addToCart(product) {
// 检查商品是否已在购物车
const existingItem = cart.find(item => item.id === product.id);
if (existingItem) {
// 已存在,增加数量(不超过库存)
existingItem.quantity = Math.min(existingItem.quantity + 1, product.stock);
} else {
// 不存在,添加新商品
cart.push({
id: product.id,
name: product.name,
price: product.price,
quantity: 1,
stock: product.stock,
image_path: product.image_path
});
}
// 保存到本地存储
saveCart();
// 更新购物车UI
updateCartUI();
}
// 更新购物车数量
function updateCartItemQuantity(productId, newQuantity) {
const itemIndex = cart.findIndex(item => item.id === productId);
if (itemIndex !== -1) {
const product = productData.find(item => item.id === productId);
// 限制数量在1-库存之间
newQuantity = Math.max(1, Math.min(newQuantity, product.stock));
cart[itemIndex].quantity = newQuantity;
// 保存并更新UI
saveCart();
updateCartUI();
}
}
// 从购物车删除商品
function removeFromCart(productId) {
cart = cart.filter(item => item.id !== productId);
saveCart();
updateCartUI();
}
// 清空购物车
function clearCart() {
cart = [];
saveCart();
updateCartUI();
}
// 保存购物车到本地存储
function saveCart() {
localStorage.setItem('productCart', JSON.stringify(cart));
}
// 更新购物车UI
function updateCartUI() {
// 更新购物车数量徽章
const totalItems = cart.reduce((total, item) => total + item.quantity, 0);
cartBadge.textContent = totalItems;
// 更新购物车总价
const totalPrice = cart.reduce((total, item) => total + (item.price * item.quantity), 0);
cartTotalPrice.textContent = `¥${totalPrice.toFixed(2)}`;
// 渲染购物车列表
renderCartItems();
}
// 渲染购物车商品列表
function renderCartItems() {
if (cart.length === 0) {
cartBody.innerHTML = '<div class="cart-empty">购物车空空如也~</div>';
return;
}
cartBody.innerHTML = '';
cart.forEach(item => {
const imgPath = item.image_path.replace(/\\/g, '/');
const cartItem = document.createElement('div');
cartItem.className = 'cart-item';
cartItem.innerHTML = `
<img src="${imgPath}" alt="${item.name}" class="cart-item-img">
<div class="cart-item-info">
<div class="cart-item-name">${item.name}</div>
<div class="cart-item-price">¥${item.price.toFixed(2)}</div>
<div class="cart-item-quantity">
<span class="quantity-btn minus" data-id="${item.id}">-</span>
<input type="text" class="quantity-input" value="${item.quantity}" data-id="${item.id}">
<span class="quantity-btn plus" data-id="${item.id}">+</span>
</div>
<div class="cart-item-delete" data-id="${item.id}">删除</div>
</div>
`;
cartBody.appendChild(cartItem);
});
// 绑定购物车操作事件
bindCartItemEvents();
}
// 绑定购物车商品操作事件
function bindCartItemEvents() {
// 数量减
const minusBtns = document.querySelectorAll('.quantity-btn.minus');
minusBtns.forEach(btn => {
btn.addEventListener('click', () => {
const productId = parseInt(btn.dataset.id);
const item = cart.find(item => item.id === productId);
if (item) {
updateCartItemQuantity(productId, item.quantity - 1);
}
});
});
// 数量加
const plusBtns = document.querySelectorAll('.quantity-btn.plus');
plusBtns.forEach(btn => {
btn.addEventListener('click', () => {
const productId = parseInt(btn.dataset.id);
const item = cart.find(item => item.id === productId);
if (item) {
updateCartItemQuantity(productId, item.quantity + 1);
}
});
});
// 输入框修改数量
const quantityInputs = document.querySelectorAll('.quantity-input');
quantityInputs.forEach(input => {
input.addEventListener('change', () => {
const productId = parseInt(input.dataset.id);
const newQuantity = parseInt(input.value) || 1;
updateCartItemQuantity(productId, newQuantity);
});
});
// 删除商品
const deleteBtns = document.querySelectorAll('.cart-item-delete');
deleteBtns.forEach(btn => {
btn.addEventListener('click', () => {
const productId = parseInt(btn.dataset.id);
removeFromCart(productId);
});
});
}
// 绑定购物车弹窗事件
function bindCartModalEvents() {
// 打开购物车
cartIcon.addEventListener('click', () => {
cartModal.classList.add('show');
overlay.classList.add('show');
});
// 关闭购物车
cartClose.addEventListener('click', () => {
cartModal.classList.remove('show');
overlay.classList.remove('show');
});
// 点击遮罩层关闭
overlay.addEventListener('click', () => {
cartModal.classList.remove('show');
overlay.classList.remove('show');
});
// 清空购物车
cartClear.addEventListener('click', clearCart);
// 导出Excel
cartExport.addEventListener('click', exportCartToExcel);
// 结算/打印
cartCheckout.addEventListener('click', handleCheckout);
}
// 导出购物车为Excel
function exportCartToExcel() {
if (cart.length === 0) {
alert('购物车为空,无法导出!');
return;
}
// 准备Excel数据
const excelData = [
['序号', '商品名称', '单价(¥)', '数量', '小计(¥)']
];
let total = 0;
cart.forEach((item, index) => {
const subtotal = item.price * item.quantity;
total += subtotal;
excelData.push([
index + 1,
item.name,
item.price.toFixed(2),
item.quantity,
subtotal.toFixed(2)
]);
});
// 添加合计行
excelData.push(['', '', '', '合计', total.toFixed(2)]);
// 创建工作簿和工作表
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.aoa_to_sheet(excelData);
// 设置列宽
const wscols = [
{wch: 6}, // 序号
{wch: 30}, // 商品名称
{wch: 10}, // 单价
{wch: 6}, // 数量
{wch: 10} // 小计
];
worksheet['!cols'] = wscols;
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, '采购清单');
// 生成并下载Excel文件
const date = new Date();
const fileName = `电脑配件采购清单_${date.getFullYear()}${(date.getMonth()+1).toString().padStart(2,0)}${date.getDate().toString().padStart(2,0)}.xlsx`;
XLSX.writeFile(workbook, fileName);
}
// 导出全部商品为Excel
function exportAllProductsToExcel() {
if (productData.length === 0) {
alert('商品库为空,无法导出!');
return;
}
// 准备Excel数据
const excelData = [
['商品ID', '商品名称', '单价(¥)', '库存数量', '商品分类', '图片链接']
];
productData.forEach((item, index) => {
excelData.push([
item.id,
item.name,
item.price.toFixed(2),
item.stock,
item.category,
item.image_path
]);
});
// 创建工作簿和工作表
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.aoa_to_sheet(excelData);
// 设置列宽
const wscols = [
{wch: 8}, // 商品ID
{wch: 40}, // 商品名称
{wch: 10}, // 单价
{wch: 10}, // 库存数量
{wch: 12}, // 商品分类
{wch: 30} // 图片链接
];
worksheet['!cols'] = wscols;
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, '全部商品库');
// 生成并下载Excel文件
const date = new Date();
const fileName = `电脑配件商品库_${date.getFullYear()}${(date.getMonth()+1).toString().padStart(2,0)}${date.getDate().toString().padStart(2,0)}.xlsx`;
XLSX.writeFile(workbook, fileName);
}
// 处理结算/打印 - 关键修复:使用iframe打印
function handleCheckout() {
if (cart.length === 0) {
alert('购物车为空,无法结算!');
return;
}
// 创建打印专用的iframe
createPrintIframe();
}
// 创建打印专用的iframe - 核心修复
function createPrintIframe() {
// 填充打印内容
fillPrintContent();
// 将打印容器显示出来(仅用于获取内容)
printContainer.style.display = 'block';
// 获取打印内容HTML
const printContent = printContainer.innerHTML;
// 隐藏打印容器
printContainer.style.display = 'none';
// 创建iframe
const iframe = document.createElement('iframe');
iframe.style.position = 'fixed';
iframe.style.right = '0';
iframe.style.bottom = '0';
iframe.style.width = '0';
iframe.style.height = '0';
iframe.style.border = 'none';
iframe.style.visibility = 'hidden';
document.body.appendChild(iframe);
// 写入内容到iframe
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write(`
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打印采购清单</title>
<style>
body {
margin: 0;
padding: 10mm;
font-family: "Microsoft Yahei", Arial, sans-serif;
font-size: 12px;
color: black;
}
.print-header {
text-align: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #333;
}
.print-header h2 {
font-size: 18px;
margin-bottom: 5px;
}
.print-header p {
font-size: 12px;
color: #666;
}
.print-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 15px;
font-size: 11px;
table-layout: fixed;
}
.print-table th, .print-table td {
border: 1px solid #333;
padding: 6px 4px;
text-align: center;
word-break: break-word;
vertical-align: middle;
}
.print-table th {
background-color: #f0f0f0;
font-weight: bold;
}
.print-table td:nth-child(2) {
text-align: left;
padding-left: 8px;
}
.print-total {
text-align: right;
font-size: 14px;
font-weight: bold;
margin-top: 10px;
padding-right: 20px;
}
.print-footer {
text-align: center;
margin-top: 20px;
font-size: 10px;
color: #666;
border-top: 1px solid #ddd;
padding-top: 10px;
}
@media print {
@page {
size: A5 portrait;
margin: 10mm;
}
body {
padding: 0;
margin: 0;
}
}
</style>
</head>
<body>
${printContent}
</body>
</html>
`);
iframeDoc.close();
// 等待内容加载后打印
setTimeout(() => {
// 移动端和桌面端统一处理
iframe.contentWindow.focus();
iframe.contentWindow.print();
// 打印后移除iframe
setTimeout(() => {
document.body.removeChild(iframe);
}, 1000);
}, 300);
// 关闭购物车弹窗
cartModal.classList.remove('show');
overlay.classList.remove('show');
}
// 填充打印内容
function fillPrintContent() {
// 清空之前的打印内容
printTableBody.innerHTML = '';
// 设置日期和时间
const now = new Date();
const dateStr = `${now.getFullYear()}年${now.getMonth()+1}月${now.getDate()}日`;
const timeStr = `${now.getHours().toString().padStart(2,'0')}:${now.getMinutes().toString().padStart(2,'0')}:${now.getSeconds().toString().padStart(2,'0')}`;
printDate.textContent = dateStr;
printTime.textContent = timeStr;
// 填充商品列表
let total = 0;
cart.forEach((item, index) => {
const subtotal = item.price * item.quantity;
total += subtotal;
// 缩短过长的商品名称
let displayName = item.name;
if (displayName.length > 25) {
displayName = displayName.substring(0, 23) + '...';
}
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${index + 1}</td>
<td>${displayName}</td>
<td>${item.price.toFixed(2)}</td>
<td>${item.quantity}</td>
<td>${subtotal.toFixed(2)}</td>
`;
printTableBody.appendChild(tr);
});
// 添加合计行
const totalTr = document.createElement('tr');
totalTr.innerHTML = `
<td colspan="3"></td>
<td><strong>合计</strong></td>
<td><strong>${total.toFixed(2)}</strong></td>
`;
printTableBody.appendChild(totalTr);
// 设置总计显示
printTotal.textContent = `合计金额:¥${total.toFixed(2)}`;
}
// 搜索按钮点击事件
searchBtn.addEventListener('click', () => {
const keyword = searchInput.value.trim();
const activeCategory = document.querySelector('.category-btn.active').dataset.category;
filterProducts(activeCategory, keyword);
});
// 回车搜索
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
searchBtn.click();
}
});
// 绑定密码验证事件
function bindPasswordEvents() {
// 导出全部商品按钮点击事件
exportAllBtn.addEventListener('click', () => {
// 显示密码输入弹窗
passwordInput.value = '';
passwordModal.classList.add('show');
overlay.classList.add('show');
// 聚焦到密码输入框
setTimeout(() => {
passwordInput.focus();
}, 100);
});
// 密码确认按钮事件
passwordConfirm.addEventListener('click', () => {
const inputPassword = passwordInput.value.trim();
if (inputPassword === EXPORT_PASSWORD) {
// 密码正确,执行导出
exportAllProductsToExcel();
// 关闭弹窗
passwordModal.classList.remove('show');
overlay.classList.remove('show');
// 清空输入框
passwordInput.value = '';
} else {
// 密码错误提示
alert('密码错误!请输入正确的密码');
passwordInput.value = '';
passwordInput.focus();
}
});
// 密码取消按钮事件
passwordCancel.addEventListener('click', () => {
passwordModal.classList.remove('show');
overlay.classList.remove('show');
passwordInput.value = '';
});
// 点击遮罩层关闭密码弹窗
overlay.addEventListener('click', () => {
passwordModal.classList.remove('show');
passwordInput.value = '';
});
// 回车键确认密码
passwordInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
passwordConfirm.click();
}
});
}
// 初始化
function init() {
// 生成分类按钮
renderCategoryButtons();
// 渲染所有商品
filterProducts('all');
// 更新购物车UI
updateCartUI();
// 绑定购物车弹窗事件
bindCartModalEvents();
// 绑定密码验证事件
bindPasswordEvents();
}
// 页面加载完成后初始化
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>
电脑配件商pos系统
一个功能完善的电脑配件商品库存管理与采购清单生成系统,支持商品浏览、购物车管理、Excel导出和打印功能。
🌟 功能特点
1. 商品管理
-
138种电脑配件商品展示(CPU、内存、硬盘、外设、耗材等)
-
按分类筛选(耗材、网络产品、电脑配件、线材转接等12个分类)
-
关键词搜索功能
-
实时库存显示(缺货/有货状态)
2. 购物车系统
-
添加/删除商品
-
数量调整(支持加减按钮和直接输入)
-
实时计算总价
-
本地存储,关闭页面后数据不丢失
-
购物车徽章显示商品数量
3. 导出功能
-
导出购物车:将购物车内容导出为Excel文件
-
导出全部商品:密码保护,导出完整商品库到Excel
-
打印采购清单:A5格式,适合移动端和电脑端打印
4. 移动端适配
-
响应式设计,适配手机、平板、电脑
-
移动端友好的触控操作
-
优化的打印体验
🚀 快速开始
在线使用
直接将代码保存为HTML文件,在浏览器中打开即可使用。
本地部署
-
将代码保存为
index.html -
确保
images文件夹存在并包含所有商品图片 -
用浏览器打开
index.html
📁 文件结构
电脑配件商品库/
├── index.html # 主程序文件
├── images/ # 商品图片目录(138张图片)
│ ├── 51_20251005_192131.jpg
│ ├── MW325R.png
│ └── ... (其他图片)
└── README.md # 说明文档
🎯 使用指南
1. 浏览商品
-
点击分类按钮筛选特定类别商品
-
使用搜索框查找特定商品
-
查看商品价格、库存和图片
2. 购物车操作
-
点击"加入购物车"按钮添加商品
-
点击右上角购物车图标打开购物车
-
在购物车中调整商品数量或删除商品
-
点击"清空购物车"移除所有商品
3. 导出和打印
-
导出Excel:在购物车中点击"导出Excel"
-
打印清单:在购物车中点击"结算/打印"
-
导出全部商品:点击"导出全部商品Excel"(需密码)
4. 密码功能
-
导出全部商品需要密码验证
-
默认密码:
123 -
可在代码中修改
EXPORT_PASSWORD常量
🔧 技术特性
前端技术
-
HTML5/CSS3:响应式布局,网格系统
-
JavaScript ES6+:原生JavaScript实现所有功能
-
LocalStorage:本地存储购物车数据
-
SheetJS (xlsx):Excel文件导出功能
打印功能
-
A5纸张格式:适合小票打印
-
iframe打印:解决移动端打印兼容性问题
-
CSS打印媒体查询:优化打印样式
-
移动端适配:完美支持手机打印
响应式设计
-
桌面端:一行5列商品
-
平板:3-4列商品
-
手机:2列商品
-
打印:A5格式适配
⚙️ 自定义配置
修改密码
在JavaScript代码中修改:
const EXPORT_PASSWORD = '123'; // 改为你的密码
添加商品
在 productData 数组中添加新商品:
{
"id": 139,
"name": "商品名称",
"price": 100,
"stock": 10,
"category": "分类名称",
"image_path": "images/图片文件.jpg"
}
修改分类
程序会自动从商品数据中提取所有分类并生成按钮。
📱 移动端支持
触控优化
-
大尺寸按钮和触摸区域
-
滑动友好的购物车面板
-
移动端打印预览优化
打印适配
-
自动检测移动设备
-
优化字体大小和边距
-
表格自动换行和截断
📊 数据格式
商品数据结构
{
id: Number, // 商品ID
name: String, // 商品名称
price: Number, // 单价
stock: Number, // 库存数量
category: String, // 分类
image_path: String // 图片路径
}
购物车数据结构
{
id: Number, // 商品ID
name: String, // 商品名称
price: Number, // 单价
quantity: Number, // 数量
stock: Number, // 最大库存
image_path: String // 图片路径
}
🔒 安全特性
-
本地存储:所有数据保存在浏览器本地
-
密码保护:导出全部商品需要密码验证
-
输入验证:数量调整有限制(1-库存最大值)
-
XSS防护:文本内容自动转义
🌐 浏览器兼容性
-
Chrome 60+ ✅
-
Firefox 55+ ✅
-
Safari 11+ ✅
-
Edge 79+ ✅
-
iOS Safari 11+ ✅
-
Android Chrome 60+ ✅
📄 许可证
本项目仅供学习和内部使用。
🐛 故障排除
常见问题
-
图片不显示
-
检查
images文件夹是否存在 -
检查图片路径是否正确
-
检查图片文件名是否匹配
-
-
打印问题
-
确保浏览器允许弹窗
-
移动端可能需要允许打印权限
-
如遇空白页,尝试刷新页面
-
-
Excel导出问题
-
确保网络连接正常(需要加载SheetJS库)
-
检查浏览器是否允许下载
-
-
数据丢失
-
购物车数据保存在localStorage
-
清除浏览器缓存会删除数据
-
建议定期导出重要数据
-
调试方法
-
按F12打开开发者工具
-
查看Console是否有错误信息
-
检查Application > LocalStorage查看数据
🎨 界面预览
桌面端
-
顶部:标题和购物车图标
-
中部:分类筛选和搜索框
-
底部:5列商品网格
移动端
-
顶部:标题和购物车图标
-
中部:分类筛选(垂直排列)
-
底部:2列商品网格
-
右侧滑出购物车面板
打印预览
-
A5纸张尺寸
-
简洁的采购清单表格
-
包含日期、时间和总价