<?php require_once 'conn.php'; checkLogin(); $page = $_GET['Page'] ?? ''; $keys = urlencode($_GET['Keys'] ?? ''); $customerId = isset($_GET['customer_id']) ? intval($_GET['customer_id']) : 0; // 添加获取客户ID参数 $hrefstr = "keys=$keys&Page=$page"; // 如果有客户ID,获取客户信息 $customerInfo = null; $contactOptions = '<option value="">请选择联系人</option>'; if ($customerId > 0) { $customerQuery = $conn->query("SELECT c.id, c.cs_code, c.cs_company FROM customer c WHERE c.id = " . $customerId); if ($customerQuery && $customerQuery->num_rows > 0) { $customerInfo = $customerQuery->fetch_assoc(); // 获取该客户的联系人列表,不再自动选择第一个联系人 $contactsQuery = $conn->query("SELECT id, contact_name FROM customer_contact WHERE customer_id = " . $customerId); if ($contactsQuery && $contactsQuery->num_rows > 0) { // 移除自动选择联系人的逻辑 while ($contact = $contactsQuery->fetch_assoc()) { $contactOptions .= '<option value="' . $contact['id'] . '">' . htmlspecialcharsFix($contact['contact_name']) . '</option>'; } } } } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>新增订单</title> <link rel="stylesheet" href="css/common.css" type="text/css" /> <link rel="stylesheet" href="css/alert.css" type="text/css" /> <script src="js/jquery-1.7.2.min.js"></script> <script src="js/js.js"></script> <style> body { margin: 0; padding: 20px; background: #fff; } #man_zone { margin-left: 0; } .product-row { position: relative; padding: 12px 15px; padding-right: 40px; /* Add right padding to make room for delete button */ margin-bottom: 8px; border-radius: 4px; display: flex; align-items: center; flex-wrap: wrap; gap: 20px; /* 增加间距 */ background-color: #f9f9f9; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .delete-product { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); color: #e74c3c; font-weight: bold; font-size: 18px; cursor: pointer; width: 24px; height: 24px; line-height: 24px; text-align: center; border-radius: 50%; z-index: 5; } .delete-product:hover { background-color: #e74c3c; color: white; } .product-info { flex: 3; min-width: 200px; } .product-spec { flex: 2; min-width: 200px; } .product-quantity { flex: 1; min-width: 80px; } .product-unit { flex: 0.8; min-width: 60px; } .product-price { flex: 1; min-width: 100px; } .product-total { flex: 1.2; min-width: 100px; font-weight: bold; } .product-row input[type="number"] { width: 90%; padding: 5px; border: 1px solid #ddd; border-radius: 4px; } .product-row select { width: 100%; padding: 5px; } .selected-product-info { font-weight: bold; margin-bottom: 3px; } .row-section { display: flex; flex-direction: column; } .row-section-label { font-size: 12px; color: #666; margin-bottom: 3px; } .row-section-label span { display: none; /* 在大屏幕上隐藏标签文本 */ } .spec-info { margin-top: 2px; font-size: 12px; color: #666; } /* 在小屏幕上的响应式布局 */ @media (max-width: 768px) { .product-row { flex-direction: column; align-items: flex-start; } .product-info, .product-spec, .product-quantity, .product-unit, .product-price, .product-total { width: 100%; min-width: 100%; margin-bottom: 8px; } .row-section-label span { display: inline; /* 在小屏幕上显示标签文本 */ } .product-list-header { display: none !important; /* 在小屏幕上隐藏表头 */ } } .add-product-btn { background-color: #4CAF50; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; margin-bottom: 15px; font-size: 14px; display: flex; align-items: center; justify-content: center; gap: 8px; transition: background-color 0.2s; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .add-product-btn:hover { background-color: #45a049; } .total-section { margin-top: 20px; padding: 10px; background-color: #eee; font-weight: bold; } #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 3px 8px rgba(0,0,0,0.25); border-radius: 0 0 4px 4px; top: 100%; left: 0; } .productlist ul { list-style: none; padding: 0; margin: 0; } .productlist li { padding: 10px 12px; cursor: pointer; border-bottom: 1px solid #eee; transition: background-color 0.2s; } .productlist li:hover { background-color: #f0f0f0; } .productlist li:last-child { border-bottom: none; } .productinput { position: relative; } .productlist li .category-tag { color: #777; font-size: 12px; font-style: italic; margin-left: 5px; } /* Specification select styling */ .spec-select { width: 100%; padding: 6px; margin-top: 5px; border: 1px solid #ccc; border-radius: 4px; } .spec-select:disabled { background-color: #f9f9f9; } .spec-price { font-weight: bold; color: #d9534f; } /* 产品行样式优化 - 单行布局 */ /* 客户选择样式 */ .customer-search-container { display: flex; align-items: center; margin-bottom: 10px; position: relative; width: 60%; } .customer-dropdown { display: none; position: absolute; background: white; border: 1px solid #ccc; max-height: 200px; overflow-y: auto; width: 100%; z-index: 1000; box-shadow: 0 3px 8px rgba(0,0,0,0.25); border-radius: 0 0 4px 4px; top: 100%; left: 0; } .customer-item { padding: 10px 12px; cursor: pointer; border-bottom: 1px solid #eee; transition: background-color 0.2s; } .customer-item:hover { background-color: #f0f0f0; } .customer-item:last-child { border-bottom: none; } .selected-customer-info { font-weight: bold; padding: 8px 10px; border: 1px solid #ddd; background-color: #f9f9f9; display: none; width: 100%; box-sizing: border-box; word-break: break-all; overflow: hidden; text-overflow: ellipsis; white-space: normal; min-height: 38px; cursor: pointer; } .selected-customer-info:hover { background-color: #f0f0f0; } .customer-clear-btn { margin-left: 5px; color: #e74c3c; font-weight: bold; cursor: pointer; float: right; } .customer-clear-btn:hover { color: #c0392b; } .product-row .total-price-input { width: 90%; } </style> </head> <body> <div id="man_zone"> <form name="form1" id="form1" method="post" action="order_save.php?<?= $hrefstr ?>" onsubmit="return validateOrderForm()"> <table width="100%" border="0" cellpadding="3" cellspacing="1" class="table1"> <tbody> <tr> <th width="8%" nowrap>销售开单号</th> <td><input type="text" id="order_code" name="order_code" value="" class="txt1" placeholder="请输入销售开单号 (多个用 / 分隔) " maxlength="100" /></td> </tr> <tr> <th width="8%" nowrap>订单类型</th> <td> <div style="display: flex; gap: 20px;"> <label style="display: flex; align-items: center;"> <input type="radio" name="order_type" id="order_type_1" value="1"> 美特柏品牌订单 </label> <label style="display: flex; align-items: center;"> <input type="radio" name="order_type" id="order_type_2" value="2"> 定制订单 </label> </div> </td> </tr> <tr> <th width="8%" nowrap>客户选择</th> <td> <?php if ($customerInfo): ?> <!-- 已有客户ID,只显示客户信息 --> <div class="customer-search-container"> <input type="hidden" name="customer_id" id="customer_id" value="<?= $customerId ?>"> <!-- 联系人字段设为空 --> <input type="hidden" name="contact_id" id="contact_id" value=""> <div class="selected-customer-info" style="display: block;" title="<?= htmlspecialcharsFix($customerInfo['cs_code'] . ' - ' . $customerInfo['cs_company']) ?>"> <?= htmlspecialcharsFix($customerInfo['cs_code'] . ' - ' . $customerInfo['cs_company']) ?> <span class="customer-clear-btn" data-type="customer" style="display: none;">X</span> </div> </div> <?php else: ?> <!-- 无客户ID,显示搜索框 --> <div class="customer-search-container"> <input type="text" id="customer_search" class="customer-search txt1" data-type="customer" placeholder="输入客户编码或名称搜索..." style="width: 100%;"> <div id="customer_dropdown" class="customer-dropdown"></div> <div id="customer_selected" class="selected-customer-info" title=""></div> <input type="hidden" name="customer_id" id="customer_id" value="0"> <input type="hidden" name="contact_id" id="contact_id" value=""> </div> <?php endif; ?> </td> </tr> <tr> <th width="8%" nowrap>最新销售单日期</th> <td><input type="date" id="order_date" name="order_date" value="<?= date('Y-m-d') ?>" class="txt1" style="width: 20%; min-width: 200px;" /> <span style="color: red">注:以上你录入的单号里面最新的销售开单单号日期</span></td> </tr> <tr> <th width="8%" nowrap>出货日期</th> <td><input type="date" id="shipping_date" name="shipping_date" value="<?= date('Y-m-d') ?>" class="txt1" style="width: 20%; min-width: 200px;" /> <span style="color: red"></span></td> </tr> <tr> <th width="8%" valign="top" nowrap>产品列表</th> <td> <button type="button" id="add-product-btn" class="add-product-btn">添加产品</button> <div class="product-list-header" style="display: flex; background-color: #eee; padding: 8px 15px; margin-bottom: 10px; border-radius: 4px; font-weight: bold; color: #555; font-size: 13px; gap: 20px;"> <div style="flex: 3; min-width: 200px;">产品</div> <div style="flex: 1; min-width: 80px;">数量</div> <div style="flex: 0.8; min-width: 60px;">单位</div> <div style="flex: 1.2; min-width: 100px;">总价</div> </div> <div id="product-container"> <!-- 产品行将通过添加按钮添加 --> <div id="no-products-message" style="padding: 15px; text-align: center; color: #777; background-color: #f5f5f5; border: 1px dashed #ddd; border-radius: 4px; margin-bottom: 15px; display: block;"> <i class="fa fa-info-circle"></i> 请点击"添加产品"按钮添加产品 </div> </div> <div class="total-section" style="margin-top: 20px; padding: 15px; background-color: #f5f5f5; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);"> <div style="display: flex; justify-content: flex-end; align-items: center;"> <label style="font-size: 16px; margin-right: 10px;">订单总额:</label> <span id="total-amount" style="font-size: 18px; font-weight: bold; color: #e74c3c;">0.00</span> <input type="hidden" name="total_amount" id="total-amount-input" value="0.00"> <input type="hidden" name="subtotal" id="subtotal-input" value="0.00"> </div> </div> </td> </tr> <tr> <th width="8%" nowrap>订单备注</th> <td> <textarea name="notes" rows="3" style="width: 90%;"></textarea> </td> </tr> <tr> <th></th> <td> <input type="submit" name="save" value="保存订单" class="btn1"> <input type="button" value="返回" class="btn1" onClick="location.href='order.php?<?= $hrefstr ?>'" /> </td> </tr> </tbody> </table> </form> <script> var productIndex = 1; $(document).ready(function() { // 初始化计算 calculateOrderTotal(); // 移除第一个默认产品行(如果不需要的话) if ($('.product-row').length > 0) { $('.product-row').first().remove(); } // 添加默认的产品行 addEmptyProductRow(); updateNoProductsMessage(); // 添加产品行按钮点击事件 $('#add-product-btn').on('click', function() { addEmptyProductRow(); updateNoProductsMessage(); }); // 删除产品行 $(document).on('click', '.delete-product', function() { if ($('.product-row').length > 1) { $(this).closest('.product-row').remove(); reindexProductRows(); calculateOrderTotal(); updateNoProductsMessage(); } else { // 如果只剩最后一个产品行,则清空它而不是删除 $(this).closest('.product-row').remove(); updateNoProductsMessage(); calculateOrderTotal(); // 确保在删除最后一个产品时也更新总额 } }); // 客户搜索功能 var customerSearchTimeout = null; var customerIsComposing = false; // 监听输入法组合事件 $(document).on('compositionstart', '.customer-search', function() { customerIsComposing = true; }); $(document).on('compositionend', '.customer-search', function() { customerIsComposing = false; $(this).trigger('input'); // 手动触发一次input事件 }); // 客户搜索输入处理 $(document).on('input', '#customer_search', function() { // 如果是输入法正在组合中文,不处理 if (customerIsComposing) return; var $this = $(this); var searchTerm = $this.val().trim(); var customerDropdown = $('#customer_dropdown'); // 清除之前的超时 clearTimeout(customerSearchTimeout); // 隐藏之前的结果 customerDropdown.hide().empty(); // 清除之前的选择 $('#customer_id').val('0'); $('#customer_selected').hide(); // 如果搜索词少于1个字符,不执行搜索 if (searchTerm.length < 1) { return; } // 设置一个300毫秒的超时,以减少请求数量 customerSearchTimeout = setTimeout(function() { $.ajax({ url: 'get_customer_search.php', type: 'GET', data: {search: searchTerm}, dataType: 'json', success: function(data) { customerDropdown.empty(); if (data && data.customers && data.customers.length > 0) { $.each(data.customers, function(i, customer) { var displayText = customer.cs_company; if (customer.cs_code) { displayText = customer.cs_code + ' - ' + displayText; } var item = $('<div class="customer-item"></div>') .attr('data-id', customer.id) .attr('data-company', customer.cs_company) .attr('data-display', displayText) .text(displayText); customerDropdown.append(item); }); customerDropdown.show(); } }, error: function() { console.log('搜索客户失败,请重试'); } }); }, 300); }); // 点击选择客户 $(document).on('click', '.customer-item', function() { var $this = $(this); var customerId = $this.data('id'); var customerName = $this.data('company'); var displayText = $this.data('display'); // 设置选中的客户ID和名称 $('#customer_id').val(customerId); $('#customer_search').hide(); $('#customer_selected').text(displayText).append('<span class="customer-clear-btn" data-type="customer">X</span>').show(); // 添加标题属性,便于查看完整信息 $('#customer_selected').attr('title', displayText); // 隐藏下拉菜单 $('#customer_dropdown').hide(); // 加载客户联系人 loadCustomerContacts(customerId); }); // 点击X按钮清除选择的客户 $(document).on('click', '.customer-clear-btn', function(e) { e.stopPropagation(); // 显示搜索框,隐藏已选信息 $('#customer_search').val('').show(); $('#customer_selected').hide(); // 清空客户ID和联系人ID $('#customer_id').val('0'); $('#contact_id').val(''); }); // 点击其他地方隐藏下拉列表 $(document).on('click', function(e) { if (!$(e.target).closest('.customer-search-container').length) { $('#customer_dropdown').hide(); } }); // 产品搜索框聚焦时显示搜索提示 $(document).on('focus', '.product-search', function() { // 隐藏所有已打开的产品搜索列表 $('.productlist').hide(); // 当前搜索框的值 var searchTerm = $(this).val().trim(); if (searchTerm.length >= 2) { // 找到当前行的产品列表并显示 $(this).siblings('.productlist').show(); } }); // 产品搜索功能 - 行内搜索 var productSearchTimeouts = {}; var isComposing = false; // 监听输入法组合事件 $(document).on('compositionstart', '.product-search', function() { isComposing = true; }); $(document).on('compositionend', '.product-search', function() { isComposing = false; $(this).trigger('input'); // 手动触发一次input事件 }); $(document).on('input', '.product-search', function() { // 如果是输入法正在组合中文,不处理 if (isComposing) return; var $this = $(this); var rowIndex = $this.closest('.product-row').data('index'); var searchTerm = $this.val().trim(); var productList = $this.siblings('.productlist'); // 清除之前的超时 clearTimeout(productSearchTimeouts[rowIndex]); // 隐藏之前的结果 productList.hide(); // 如果搜索词少于2个字符,不执行搜索 if (searchTerm.length < 1) { return; } console.warn(searchTerm); // 设置一个300毫秒的超时,以减少请求数量 productSearchTimeouts[rowIndex] = setTimeout(function() { $.ajax({ url: 'get_product_info.php', type: 'GET', data: {search: searchTerm}, dataType: 'json', success: function(data) { 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('click', '.productlist li', function() { var $this = $(this); var productId = $this.data('id'); var productName = $this.text(); // 这会包含分类名,需要清理 var categoryTag = $this.find('.category-tag').text(); var row = $this.closest('.product-row'); // 检查是否已存在相同的产品 var isDuplicate = false; $('.product-id-input').not(row.find('.product-id-input')).each(function() { if ($(this).val() == productId) { isDuplicate = true; return false; // 跳出循环 } }); if (isDuplicate) { alert('该产品已添加,不能添加相同的产品'); return; } // 清理产品名称,移除分类信息 if (categoryTag) { productName = productName.replace(categoryTag, '').trim(); } // 设置产品ID和名称 row.find('.product-id-input').val(productId); row.find('.product-search').hide(); // 显示包含分类的完整产品信息 var displayName = productName; if (categoryTag) { displayName += ' <span class="category-tag">' + categoryTag + '</span>'; } row.find('.selected-product-info').html(displayName).show(); // 隐藏产品搜索结果 row.find('.productlist').hide(); // 获取产品单位信息 getProductSpecifications(productId, row); }); // 点击其他地方隐藏下拉列表 $(document).on('click', function(e) { if (!$(e.target).closest('.product-search').length && !$(e.target).closest('.productlist').length) { $('.productlist').hide(); } if (!$(e.target).closest('.customerinput').length) { $('.customerlist').hide(); } }); // 点击已选产品名显示的标签时,切换回搜索模式 $(document).on('click', '.selected-product-info', function() { var row = $(this).closest('.product-row'); var productId = row.find('.product-id-input').val(); // 只有当已经选择了产品时才允许重新选择 if (productId) { if (confirm('确定要重新选择产品吗?这将清除当前选择的产品信息。')) { // 清空产品ID row.find('.product-id-input').val(''); // 隐藏产品信息,显示搜索框 $(this).hide(); row.find('.product-search').val('').show(); // 清除单位信息 row.find('.unit-input').val(''); row.find('.unit-label').text(''); // 清除总价信息并重新计算总额 row.find('.total-price-input').val('0.00'); calculateOrderTotal(); } } }); }); function addEmptyProductRow() { var html = ` <div class="product-row" data-index="${productIndex}"> <span class="delete-product">×</span> <div class="row-section product-info"> <div class="row-section-label"><span>产品</span></div> <input type="hidden" name="items[${productIndex}][product_id]" class="product-id-input" value=""> <input type="text" class="product-search" placeholder="输入产品名称搜索..." style="width: 100%; padding: 5px; border: 1px solid #ddd; border-radius: 4px;"> <div class="productlist" style="width: 100%; max-height: 200px;"><ul></ul></div> <div class="selected-product-info" style="cursor: pointer; display: none;" title="点击重新选择产品"></div> </div> <div class="row-section product-quantity"> <div class="row-section-label"><span>数量</span></div> <input type="number" name="items[${productIndex}][quantity]" value="1" min="1" class="quantity-input"> </div> <div class="row-section product-unit"> <div class="row-section-label"><span>单位</span></div> <span class="unit-label" style="display: inline-block; padding: 2px 5px; min-width: 30px;"></span> <input type="hidden" name="items[${productIndex}][unit]" class="unit-input" value=""> </div> <div class="row-section product-total"> <div class="row-section-label"><span>总价</span></div> <input type="number" step="0.01" name="items[${productIndex}][total_price]" value="0.00" class="total-price-input" placeholder="输入总价" onchange="calculateOrderTotal()"> </div> </div> `; $('#product-container').append(html); productIndex++; return productIndex - 1; // 返回新添加行的索引 } function getProductSpecifications(productId, row) { if (!productId) return; $.ajax({ url: 'get_product_info.php', type: 'GET', data: {product_id: productId}, dataType: 'json', success: function(data) { if (data && data.product) { // 设置单位信息 if (data.product.unit) { row.find('.unit-input').val(data.product.unit); row.find('.unit-label').text(data.product.unit); } } else { alert('获取产品信息失败'); // 重置产品选择 row.find('.product-id-input').val(''); row.find('.selected-product-info').hide(); row.find('.product-search').val('').show(); } }, error: function() { alert('获取产品信息失败,请重试'); // 重置产品选择 row.find('.product-id-input').val(''); row.find('.selected-product-info').hide(); row.find('.product-search').val('').show(); } }); } function reindexProductRows() { $('.product-row').each(function(index) { $(this).attr('data-index', index); $(this).find('select, input').each(function() { var name = $(this).attr('name'); if (name) { name = name.replace(/items\[\d+\]/, 'items[' + index + ']'); $(this).attr('name', name); } }); }); productIndex = $('.product-row').length; } function calculateOrderTotal() { var total = 0; $('.total-price-input').each(function() { total += parseFloat($(this).val()) || 0; }); // 更新总额和隐藏的小计字段 $('#total-amount').text(total.toFixed(2)); $('#total-amount-input').val(total.toFixed(2)); $('#subtotal-input').val(total.toFixed(2)); // 为兼容性保留 } function loadCustomerContacts(customerId) { if (customerId) { $.ajax({ url: 'get_customer_contacts.php', type: 'GET', data: {customer_id: customerId}, dataType: 'json', success: function(data) { // 不自动选择第一个联系人,让字段为空 $('#contact_id').val(''); } }); } else { $('#contact_id').val(''); } } function validateOrderForm() { var orderCode = $('#order_code').val(); var customerId = $('#customer_id').val(); var customerName = $('#customer_search').val(); var orderType = $('input[name="order_type"]:checked').val(); var hasProducts = false; var allTotalPricesValid = true; var firstInvalidField = null; var hasUnselectedProducts = false; // 检查是否有产品行 if ($('.product-row').length === 0) { alert('请至少添加一个产品'); $('#add-product-btn').focus(); return false; } // 检查订单类型是否已选择 if (!orderType) { alert('请选择订单类型'); $('#order_type_1').focus(); return false; } $('.product-row').each(function() { var productId = $(this).find('.product-id-input').val(); var totalPriceInput = $(this).find('.total-price-input'); var totalPrice = parseFloat(totalPriceInput.val()) || 0; var productSearch = $(this).find('.product-search'); var searchValue = productSearch.val().trim(); // 检查产品是否已选择 if (!productId) { if (searchValue) { // 如果有搜索内容但未选择产品 hasUnselectedProducts = true; if (!firstInvalidField) { firstInvalidField = productSearch; } } else { // 如果既没有选择产品也没有搜索内容 if (!firstInvalidField) { firstInvalidField = productSearch; } } return true; // continue } hasProducts = true; // 检查总价是否有效 if (totalPrice <= 0) { allTotalPricesValid = false; if (!firstInvalidField) { firstInvalidField = totalPriceInput; } } }); if (!orderCode) { alert('销售开单号不能为空'); $('#order_code').focus(); return false; } if (!customerId || customerId == '0') { alert('请选择客户'); $('#customer_search').focus(); return false; } // 只有当客户ID为0时才检查客户名称 if (customerId == '0' && !customerName) { alert('请输入并选择有效的客户'); $('#customer_search').focus(); return false; } if (!hasProducts) { alert('请至少添加一个有效的产品'); if (firstInvalidField) { firstInvalidField.focus(); } else { $('#add-product-btn').focus(); } return false; } if (hasUnselectedProducts) { alert('请从搜索结果中选择产品,不能直接提交未选择的产品'); if (firstInvalidField) { firstInvalidField.focus(); } return false; } if (!allTotalPricesValid) { alert('请为所有产品输入有效的总价'); if (firstInvalidField) { firstInvalidField.focus(); } return false; } return true; } function updateNoProductsMessage() { if ($('.product-row').length > 0) { $('#no-products-message').hide(); } else { $('#no-products-message').show(); } } </script> </div> </body> </html>