|
@@ -58,6 +58,39 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
#product-container {
|
|
|
margin-bottom: 20px;
|
|
|
}
|
|
|
+ .productlist {
|
|
|
+ display: none;
|
|
|
+ position: absolute;
|
|
|
+ background: white;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ max-height: 200px;
|
|
|
+ overflow-y: auto;
|
|
|
+ width: 100%;
|
|
|
+ z-index: 1000;
|
|
|
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
|
+ }
|
|
|
+ .productlist ul {
|
|
|
+ list-style: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ .productlist li {
|
|
|
+ padding: 8px 10px;
|
|
|
+ cursor: pointer;
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
+ }
|
|
|
+ .productlist li:hover {
|
|
|
+ background-color: #f5f5f5;
|
|
|
+ }
|
|
|
+ .productinput {
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+ .productlist li .category-tag {
|
|
|
+ color: #777;
|
|
|
+ font-size: 12px;
|
|
|
+ font-style: italic;
|
|
|
+ margin-left: 5px;
|
|
|
+ }
|
|
|
</style>
|
|
|
</head>
|
|
|
<body>
|
|
@@ -132,8 +165,8 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
<td>
|
|
|
<select id="currency" name="currency">
|
|
|
<option value="CNY" selected>人民币 (CNY)</option>
|
|
|
- <option value="USD">美元 (USD)</option>
|
|
|
- <option value="EUR">欧元 (EUR)</option>
|
|
|
+<!-- <option value="USD">美元 (USD)</option>-->
|
|
|
+<!-- <option value="EUR">欧元 (EUR)</option>-->
|
|
|
</select>
|
|
|
</td>
|
|
|
</tr>
|
|
@@ -146,16 +179,12 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
<span class="delete-product">×</span>
|
|
|
<div>
|
|
|
<label>产品:</label>
|
|
|
- <select name="items[0][product_id]" class="product-select" onchange="updateProductInfo(this)">
|
|
|
- <option value="">请选择产品</option>
|
|
|
- <?php
|
|
|
- $productSql = "SELECT id, ProductName FROM products ORDER BY ProductName";
|
|
|
- $productResult = mysqli_query($conn, $productSql);
|
|
|
- while ($productRow = mysqli_fetch_assoc($productResult)) {
|
|
|
- echo "<option value=\"{$productRow['id']}\">" . htmlspecialcharsFix($productRow['ProductName']) . "</option>";
|
|
|
- }
|
|
|
- ?>
|
|
|
- </select>
|
|
|
+ <div style="display: inline-block; width: 60%;" class="productinput">
|
|
|
+ <input type="text" class="product-search fastsearch" placeholder="输入产品名称搜索..." style="width: 100%;">
|
|
|
+ <div class="productlist"><ul></ul></div>
|
|
|
+ <input type="hidden" name="items[0][product_id]" class="product-id-input" value="">
|
|
|
+ <div class="selected-product-info" style="margin-top: 5px; font-weight: bold;"></div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div style="margin-top: 5px;">
|
|
|
<label>数量:</label>
|
|
@@ -168,18 +197,11 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
<input type="number" step="0.01" name="items[0][unit_price]" value="0.00" class="price-input" onchange="calculateItemTotal(this)">
|
|
|
</div>
|
|
|
<div style="margin-top: 5px;">
|
|
|
- <label>折扣金额:</label>
|
|
|
- <input type="number" step="0.01" name="items[0][discount_amount]" value="0.00" class="discount-amount-input" onchange="calculateItemTotal(this)">
|
|
|
-
|
|
|
- <label style="margin-left: 10px;">折扣率:</label>
|
|
|
- <input type="number" step="0.01" name="items[0][discount_percent]" value="0" class="discount-percent-input" max="100" min="0">%
|
|
|
-
|
|
|
- <label style="margin-left: 10px;">总价:</label>
|
|
|
+ <label>总价:</label>
|
|
|
<input type="number" step="0.01" name="items[0][total_price]" value="0.00" class="total-price-input" readonly>
|
|
|
- </div>
|
|
|
- <div style="margin-top: 5px;">
|
|
|
- <label>备注:</label>
|
|
|
- <input type="text" name="items[0][notes]" value="" style="width: 80%;">
|
|
|
+
|
|
|
+ <label style="margin-left: 10px;">备注:</label>
|
|
|
+ <input type="text" name="items[0][notes]" value="" style="width: 60%;">
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -189,10 +211,6 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
<span id="subtotal">0.00</span>
|
|
|
<input type="hidden" name="subtotal" id="subtotal-input" value="0.00">
|
|
|
</div>
|
|
|
- <div style="margin-top: 5px;">
|
|
|
- <label>运费:</label>
|
|
|
- <input type="number" step="0.01" name="shipping_fee" id="shipping-fee" value="0.00" onchange="calculateOrderTotal()">
|
|
|
- </div>
|
|
|
<div style="margin-top: 5px;">
|
|
|
<label>订单折扣:</label>
|
|
|
<input type="number" step="0.01" name="discount_amount" id="order-discount" value="0.00" onchange="calculateOrderTotal()">
|
|
@@ -251,33 +269,89 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
}
|
|
|
});
|
|
|
|
|
|
- // 更新折扣率和折扣金额之间的关系
|
|
|
- $(document).on('change', '.discount-percent-input', function() {
|
|
|
- var row = $(this).closest('.product-row');
|
|
|
- var percent = parseFloat($(this).val()) || 0;
|
|
|
- var quantity = parseInt(row.find('.quantity-input').val()) || 0;
|
|
|
- var price = parseFloat(row.find('.price-input').val()) || 0;
|
|
|
- var subtotal = quantity * price;
|
|
|
-
|
|
|
- var discountAmount = (subtotal * percent / 100).toFixed(2);
|
|
|
- row.find('.discount-amount-input').val(discountAmount);
|
|
|
-
|
|
|
- calculateItemTotal(this);
|
|
|
+ // 实时产品搜索功能 - 使用防抖动以减少请求数量
|
|
|
+ var searchTimeout = null;
|
|
|
+ $(document).on('keyup', '.product-search', function() {
|
|
|
+ var $this = $(this);
|
|
|
+ var row = $this.closest('.product-row');
|
|
|
+ var searchTerm = $this.val().trim();
|
|
|
+ var productList = row.find('.productlist');
|
|
|
+
|
|
|
+ // 清除之前的超时
|
|
|
+ clearTimeout(searchTimeout);
|
|
|
+
|
|
|
+ // 隐藏之前的结果
|
|
|
+ productList.hide();
|
|
|
+
|
|
|
+ // 如果搜索词少于2个字符,不执行搜索
|
|
|
+ if (searchTerm.length < 2) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置一个300毫秒的超时,以减少请求数量
|
|
|
+ searchTimeout = setTimeout(function() {
|
|
|
+ $.ajax({
|
|
|
+ url: 'get_product_info.php',
|
|
|
+ type: 'GET',
|
|
|
+ data: {search: searchTerm},
|
|
|
+ dataType: 'json',
|
|
|
+ success: function(data) {
|
|
|
+ var productList = row.find('.productlist');
|
|
|
+ var ul = productList.find('ul');
|
|
|
+ ul.empty();
|
|
|
+
|
|
|
+ if (data && data.products && data.products.length > 0) {
|
|
|
+ $.each(data.products, function(i, product) {
|
|
|
+ ul.append('<li data-id="' + product.id + '">' +
|
|
|
+ product.ProductName +
|
|
|
+ (product.category_name ? ' <span class="category-tag">(' + product.category_name + ')</span>' : '') +
|
|
|
+ '</li>');
|
|
|
+ });
|
|
|
+ productList.show();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: function() {
|
|
|
+ console.log('搜索产品失败,请重试');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }, 300);
|
|
|
});
|
|
|
-
|
|
|
- $(document).on('change', '.discount-amount-input', function() {
|
|
|
- var row = $(this).closest('.product-row');
|
|
|
- var amount = parseFloat($(this).val()) || 0;
|
|
|
- var quantity = parseInt(row.find('.quantity-input').val()) || 0;
|
|
|
- var price = parseFloat(row.find('.price-input').val()) || 0;
|
|
|
- var subtotal = quantity * price;
|
|
|
-
|
|
|
- if (subtotal > 0) {
|
|
|
- var percent = ((amount / subtotal) * 100).toFixed(2);
|
|
|
- row.find('.discount-percent-input').val(percent);
|
|
|
+
|
|
|
+ // 点击选择产品
|
|
|
+ $(document).on('click', '.productlist li', function() {
|
|
|
+ var $this = $(this);
|
|
|
+ var productId = $this.data('id');
|
|
|
+ var productName = $this.text(); // 这会包含分类名,需要清理
|
|
|
+ var categoryTag = $this.find('.category-tag').text();
|
|
|
+
|
|
|
+ // 清理产品名称,移除分类信息
|
|
|
+ if (categoryTag) {
|
|
|
+ productName = productName.replace(categoryTag, '').trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ var row = $this.closest('.product-row');
|
|
|
+
|
|
|
+ // 设置选中的产品ID和名称
|
|
|
+ row.find('.product-id-input').val(productId);
|
|
|
+ row.find('.product-search').val(productName);
|
|
|
+
|
|
|
+ // 显示包含分类的完整产品信息
|
|
|
+ var displayName = productName;
|
|
|
+ if (categoryTag) {
|
|
|
+ displayName += ' <span class="category-tag">' + categoryTag + '</span>';
|
|
|
+ }
|
|
|
+ row.find('.selected-product-info').html(displayName);
|
|
|
+ row.find('.productlist').hide();
|
|
|
+
|
|
|
+ // 获取产品信息
|
|
|
+ getProductInfo(productId, row);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 点击其他地方隐藏产品列表
|
|
|
+ $(document).on('click', function(e) {
|
|
|
+ if (!$(e.target).closest('.productinput').length) {
|
|
|
+ $('.productlist').hide();
|
|
|
}
|
|
|
-
|
|
|
- calculateItemTotal(this);
|
|
|
});
|
|
|
});
|
|
|
|
|
@@ -287,10 +361,12 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
<span class="delete-product">×</span>
|
|
|
<div>
|
|
|
<label>产品:</label>
|
|
|
- <select name="items[${productIndex}][product_id]" class="product-select" onchange="updateProductInfo(this)">
|
|
|
- <option value="">请选择产品</option>
|
|
|
- ${getProductOptions()}
|
|
|
- </select>
|
|
|
+ <div style="display: inline-block; width: 60%;" class="productinput">
|
|
|
+ <input type="text" class="product-search fastsearch" placeholder="输入产品名称搜索..." style="width: 100%;">
|
|
|
+ <div class="productlist"><ul></ul></div>
|
|
|
+ <input type="hidden" name="items[${productIndex}][product_id]" class="product-id-input" value="">
|
|
|
+ <div class="selected-product-info" style="margin-top: 5px; font-weight: bold;"></div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div style="margin-top: 5px;">
|
|
|
<label>数量:</label>
|
|
@@ -303,18 +379,11 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
<input type="number" step="0.01" name="items[${productIndex}][unit_price]" value="0.00" class="price-input" onchange="calculateItemTotal(this)">
|
|
|
</div>
|
|
|
<div style="margin-top: 5px;">
|
|
|
- <label>折扣金额:</label>
|
|
|
- <input type="number" step="0.01" name="items[${productIndex}][discount_amount]" value="0.00" class="discount-amount-input" onchange="calculateItemTotal(this)">
|
|
|
-
|
|
|
- <label style="margin-left: 10px;">折扣率:</label>
|
|
|
- <input type="number" step="0.01" name="items[${productIndex}][discount_percent]" value="0" class="discount-percent-input" max="100" min="0">%
|
|
|
-
|
|
|
- <label style="margin-left: 10px;">总价:</label>
|
|
|
+ <label>总价:</label>
|
|
|
<input type="number" step="0.01" name="items[${productIndex}][total_price]" value="0.00" class="total-price-input" readonly>
|
|
|
- </div>
|
|
|
- <div style="margin-top: 5px;">
|
|
|
- <label>备注:</label>
|
|
|
- <input type="text" name="items[${productIndex}][notes]" value="" style="width: 80%;">
|
|
|
+
|
|
|
+ <label style="margin-left: 10px;">备注:</label>
|
|
|
+ <input type="text" name="items[${productIndex}][notes]" value="" style="width: 60%;">
|
|
|
</div>
|
|
|
</div>
|
|
|
`;
|
|
@@ -323,18 +392,6 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
productIndex++;
|
|
|
}
|
|
|
|
|
|
- function getProductOptions() {
|
|
|
- var options = '';
|
|
|
- <?php
|
|
|
- $productSql = "SELECT id, ProductName FROM products ORDER BY ProductName";
|
|
|
- $productResult = mysqli_query($conn, $productSql);
|
|
|
- while ($productRow = mysqli_fetch_assoc($productResult)) {
|
|
|
- echo "options += '<option value=\"{$productRow['id']}\">" . addslashes(htmlspecialcharsFix($productRow['ProductName'])) . "</option>';\n";
|
|
|
- }
|
|
|
- ?>
|
|
|
- return options;
|
|
|
- }
|
|
|
-
|
|
|
function reindexProductRows() {
|
|
|
$('.product-row').each(function(index) {
|
|
|
$(this).attr('data-index', index);
|
|
@@ -349,40 +406,30 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
productIndex = $('.product-row').length;
|
|
|
}
|
|
|
|
|
|
- function updateProductInfo(selectElement) {
|
|
|
- var productId = $(selectElement).val();
|
|
|
- var row = $(selectElement).closest('.product-row');
|
|
|
-
|
|
|
- if (productId) {
|
|
|
- // 使用AJAX获取产品信息
|
|
|
- $.ajax({
|
|
|
- url: 'get_product_info.php',
|
|
|
- type: 'GET',
|
|
|
- data: {id: productId},
|
|
|
- dataType: 'json',
|
|
|
- success: function(data) {
|
|
|
- if (data) {
|
|
|
- row.find('.unit-input').val(data.unit);
|
|
|
- row.find('.price-input').val(data.price);
|
|
|
- calculateItemTotal(selectElement);
|
|
|
- }
|
|
|
+ function getProductInfo(productId, row) {
|
|
|
+ if (!productId) return;
|
|
|
+
|
|
|
+ $.ajax({
|
|
|
+ url: 'get_product_info.php',
|
|
|
+ type: 'GET',
|
|
|
+ data: {id: productId},
|
|
|
+ dataType: 'json',
|
|
|
+ success: function(data) {
|
|
|
+ if (data) {
|
|
|
+ row.find('.unit-input').val(data.unit);
|
|
|
+ row.find('.price-input').val(data.price);
|
|
|
+ calculateItemTotal(row.find('.price-input')[0]);
|
|
|
}
|
|
|
- });
|
|
|
- } else {
|
|
|
- row.find('.unit-input').val('');
|
|
|
- row.find('.price-input').val('0.00');
|
|
|
- calculateItemTotal(selectElement);
|
|
|
- }
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
function calculateItemTotal(element) {
|
|
|
var row = $(element).closest('.product-row');
|
|
|
var quantity = parseInt(row.find('.quantity-input').val()) || 0;
|
|
|
var price = parseFloat(row.find('.price-input').val()) || 0;
|
|
|
- var discountAmount = parseFloat(row.find('.discount-amount-input').val()) || 0;
|
|
|
|
|
|
- var subtotal = quantity * price;
|
|
|
- var total = subtotal - discountAmount;
|
|
|
+ var total = quantity * price;
|
|
|
if (total < 0) total = 0;
|
|
|
|
|
|
row.find('.total-price-input').val(total.toFixed(2));
|
|
@@ -396,9 +443,8 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
subtotal += parseFloat($(this).val()) || 0;
|
|
|
});
|
|
|
|
|
|
- var shippingFee = parseFloat($('#shipping-fee').val()) || 0;
|
|
|
var orderDiscount = parseFloat($('#order-discount').val()) || 0;
|
|
|
- var total = subtotal + shippingFee - orderDiscount;
|
|
|
+ var total = subtotal - orderDiscount;
|
|
|
|
|
|
if (total < 0) total = 0;
|
|
|
|
|
@@ -435,7 +481,7 @@ $hrefstr = "keys=$keys&Page=$page";
|
|
|
var customerId = $('#customer_id').val();
|
|
|
var hasProducts = false;
|
|
|
|
|
|
- $('.product-select').each(function() {
|
|
|
+ $('.product-id-input').each(function() {
|
|
|
if ($(this).val()) {
|
|
|
hasProducts = true;
|
|
|
return false; // break the loop
|