销售单系统 html 单页版

35 阅读10分钟

图A5 横:

image.png

image.png

代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>XXXXX销售单</title>
    <script src="https://cdn.sheetjs.com/xlsx-0.19.3/package/dist/xlsx.full.min.js"></script>
    <style>
        body {
            font-family: "宋体", "微软雅黑", sans-serif;
            margin: 20px;
        }
        .title {
            text-align: center;
            font-size: 24px;
            font-weight: bold;
            margin-bottom: 2px;
            margin-top: 8px;
        }
        .order-info {
            text-align: right;
            margin-bottom: 2px;
            font-size: 16px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        th, td {
            border: 1px solid #000;
            padding: 2px;
            text-align: left;
        }
        .info-table th {
            width: 100px;
            background-color: #f0f0f0;
        }
        .goods-table th {
            background-color: #f0f0f0;
        }
        .total-row {
            background-color: #e6f3ff;
        }
        input, select {
            width: 90%;
            padding: 0px;
            border: none;
            box-sizing: border-box;
        }
        .goods-select {
            width: 100%;
            height: 20px;
        }
        .btn-group {
            margin: 20px 0;
        }
        .btn {
            padding: 10px 20px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            margin-right: 10px;
        }
        .btn:hover {
            opacity: 0.9;
        }
        .btn-export {
            background-color: #2196F3;
        }
        .btn-print {
            background-color: #607D8B;
        }
        .btn-add-goods {
            background-color: #FF9800;
        }
        /* 未选择商品时隐藏相关输入框 */
        .goods-field {
            display: none;
        }
        /* 只读输入框样式 */
        .readonly-input {
            background-color: #f9f9f9;
            cursor: default;
        }
        /* 付款方式复选框横排样式 */
        .pay-type-group {
            display: flex;
            gap: 20px; /* 选项之间的间距 */
            align-items: center;
            margin-top: 5px;
        }
        .pay-type-group label {
            display: flex;
            align-items: center;
            cursor: pointer;
        }
        .pay-type-group input[type="checkbox"] {
            width: auto; /* 取消宽度限制 */
            margin-right: 5px; /* 复选框和文字间距 */
        }
        /* 添加商品弹窗样式 */
        .modal {
            display: none;
            position: fixed;
            z-index: 1000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0,0,0,0.4);
        }
        .modal-content {
            background-color: #fefefe;
            margin: 15% auto;
            padding: 20px;
            border: 1px solid #888;
            width: 400px;
            border-radius: 8px;
        }
        .modal-content h3 {
            margin-top: 0;
            text-align: center;
        }
        .modal-form {
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
        .modal-form div {
            display: flex;
            align-items: center;
        }
        .modal-form label {
            width: 80px;
            font-weight: bold;
        }
        .modal-form input {
            flex: 1;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        .modal-buttons {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin-top: 20px;
        }
        .modal-btn {
            padding: 8px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        .modal-btn.save {
            background-color: #4CAF50;
            color: white;
        }
        .modal-btn.cancel {
            background-color: #f44336;
            color: white;
        }
        
        @media print {
            .btn-group {
                display: none;
            }
            .modal {
                display: none !important;
            }
            body {
                margin: 0;
                padding: 10px;
            }
            input, select {
                border: none;
                width: 100%;
                padding: 0;
            }
            /* 打印时保持付款方式横排 */
            .pay-type-group {
                display: flex;
                gap: 15px;
            }
            .goods-row td {
                border: none;
            }
            .goods-row td:first-child {
                border-left: 1px solid #000;
            }
            .goods-row td:last-child {
                border-right: 1px solid #000;
            }
            .total-table td{
                border-top: 1px solid #000 !important;
            }
            .total-table th{
                border-top: 1px solid #000 !important;
            }
            
            .goods-row input, select {
                border: none;
                width: 100%;
                padding: 0;
                /* 打印时隐藏所有输入框/选择框的箭头 */
                -webkit-appearance: none !important;
                -moz-appearance: none !important;
                appearance: none !important;
            }
            /* 单独隐藏选择框的下拉箭头(覆盖所有浏览器) */
            select.goods-select::-ms-expand {
                display: none !important;
            }
            select.goods-select {
                background: transparent !important;
            }
            /* 隐藏数字输入框箭头(彻底兜底) */
            .goods-row input.goodsQty::-webkit-outer-spin-button,
            input.goodsQty::-webkit-inner-spin-button {
                display: none !important;
                -webkit-appearance: none !important;
                margin: 0 !important;
            }
            
            }
    </style>
</head>
<body>
    <div class="title">开平XXXXX销售单</div>
    <div class="order-info">
        NO: <input type="text" id="orderNo" readonly class="readonly-input" style="width:120px;"> <br>
        开单日期: <input type="date" id="orderDate" readonly class="readonly-input" style="width:120px;">
    </div>

    <table class="info-table">
        <tr style="border-bottom: none;">
            <th  style="width:40px;border-bottom: none;">购买方信息</th>
            <td style="border-bottom: none;">
                名称: <input type="text" id="buyerName" style="width:200px;" value="零售客户">
                <br>
                联系信息: <input type="text" id="buyerContact" style="width:200px;">
            </td>
            <th style="width:40px;border-bottom: none;">销售方信息</th>
            <td style="border-bottom: none;">
                名称: <input type="text" id="sellerName" value="开平市三埠区XXXXX行" style="width:200px;">
                <br>
                地址: <input type="text" id="sellerAddr" value="开平市XXXXXX" style="width:200px;">
                <br>
                电话: <input type="text" id="sellerTel" value="0750-xxxxxx" style="width:120px;">
            </td>
        </tr>
    </table>

    <table class="goods-table" id="goodsTable">
        <tr>
            <th>序号</th>
            <th>名称规格</th>
            <th>单位</th>
            <th>数量</th>
            <th>单价</th>
            <th>总金额</th>
            <th>备注</th>
        </tr>
        <!-- 固定7行商品 -->
        <tr class="goods-row">
            <td style="border-left: 1px solid #000;"><input type="text" value="1" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)" style="width:220px;">
                    <option value="">-- --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
        <tr class="goods-row">
            <td><input type="text" value="2" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)">
                    <option value="">--  --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
        <tr class="goods-row">
            <td><input type="text" value="3" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)">
                    <option value="">--  --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
        <tr class="goods-row">
            <td><input type="text" value="4" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)">
                    <option value="">--  --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
        <tr class="goods-row">
            <td><input type="text" value="5" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)">
                    <option value="">--  --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
        <tr class="goods-row">
            <td><input type="text" value="6" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)">
                    <option value="">--  --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
        <tr class="goods-row">
            <td><input type="text" value="7" readonly style="width:50px;"></td>
            <td>
                <select class="goods-select goodsName" onchange="selectGoods(this)">
                    <option value="">--  --</option>
                    <!-- 商品选项将通过JS动态生成 -->
                </select>
            </td>
            <td><input type="text" class="goodsUnit goods-field" value="" readonly></td>
            <td><input type="number" class="goodsQty goods-field" value="" oninput="calculateRow(this)"></td>
            <td><input type="number" class="goodsPrice goods-field" value="" readonly></td>
            <td><input type="number" class="goodsAmount goods-field" readonly style="color:rgb(4, 62, 117);"></td>
            <td><input type="text" class="goodsRemark"></td>
        </tr>
    </table>

    <table class="total-table" >
        <tr style="border-top: none;border-bottom: none;">
            <th style="border-top: none;border-bottom: none;">合计(大写)</th>
            <td style="border-top: none;border-bottom: none;"><input type="text" id="totalCapital" style="width:200px;"></td>
            <th style="border-top: none;border-bottom: none;">(小写)</th>
            <td style="border-top: none;border-bottom: none;"><input type="text" id="totalLower" readonly style="color:rgb(38, 4, 163);font-weight:bold;"></td>
        </tr>
    </table>

    <table class="note-table" style="width:100%; font-size: 12px;">
        <tr>
            <th>备注</th>
            <td>
                注: 如对以上签收之表列货物的质量有异议请务必在三天内提出,多谢!
              
                <div class="pay-type-group">
                    <label >付款方式:</label>
                    <label><input type="checkbox" name="payType"> 现金</label>
                    <label><input type="checkbox" name="payType"> 转账</label>
                    <label><input type="checkbox" name="payType"> 微信</label>
                    <label><input type="checkbox" name="payType"> 支付宝</label>
                </div>
            </td>
            <th>客户签名:</th>
            <td><input type="text" style="width:150px;"></td>
        </tr>
        <tr >
            <td colspan="2" style="border-bottom: none;border-left: none;border-right: none;">销售人员: <input type="text" style="width:150px;"></td>
            <td colspan="2" style="border-bottom: none;border-right: none;border-left: none;">收款人: <input type="text" style="width:150px;"></td>
        </tr>
    </table>

    <div class="btn-group">
        <button class="btn btn-add-goods" onclick="openAddGoodsModal()">添加商品</button>
        <button class="btn btn-export" onclick="exportToExcel()">导出Excel</button>
        <button class="btn btn-print" onclick="printTable()">打印销售单</button>
    </div>

    <!-- 添加商品弹窗 -->
    <div id="addGoodsModal" class="modal">
        <div class="modal-content">
            <h3>添加新商品</h3>
            <div class="modal-form">
                <div>
                    <label>商品名称:</label>
                    <input type="text" id="newGoodsName" placeholder="请输入商品名称" required>
                </div>
                <div>
                    <label>单位:</label>
                    <input type="text" id="newGoodsUnit" placeholder="如:个、项、令" required>
                </div>
                <div>
                    <label>默认数量:</label>
                    <input type="number" id="newGoodsQty" value="1" min="1" required>
                </div>
                <div>
                    <label>单价:</label>
                    <input type="number" id="newGoodsPrice" placeholder="请输入商品单价" min="0" step="0.01" required>
                </div>
            </div>
            <div class="modal-buttons">
                <button class="modal-btn save" onclick="saveNewGoods()">保存</button>
                <button class="modal-btn cancel" onclick="closeAddGoodsModal()">取消</button>
            </div>
        </div>
    </div>

    <script>
        // 商品数据 - JSON格式管理
        const goodsData = [
            { id: 1, name: "上门电脑维修", unit: "项", defaultQty: 1, price: 60 },
            { id: 2, name: "电脑维修", unit: "项", defaultQty: 1, price: 40 },
            { id: 3, name: "A4 打印纸", unit: "令", defaultQty: 1, price: 25 },
            { id: 4, name: "鼠标", unit: "个", defaultQty: 1, price: 25 },
            { id: 5, name: "键盘", unit: "个", defaultQty: 1, price: 30 },
            { id: 6, name: "色带", unit: "条", defaultQty: 1, price: 10 },
            { id: 7, name: "打印机维修", unit: "项", defaultQty: 1, price: 60 },
            { id: 8, name: "笔记本维修", unit: "项", defaultQty: 1, price: 250 }
        ];

        // 生成系统日期格式的订单号
        function generateOrderNo() {
            const now = new Date();
            // 获取年月日(YYYYMMDD)
            const year = now.getFullYear();
            const month = String(now.getMonth() + 1).padStart(2, '0');
            const day = String(now.getDate()).padStart(2, '0');
            // 生成随机数(避免单号重复)
            const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
            // 组合单号:日期 + 随机数(例如:202512251234)
            return `${year}${month}${day}${random}`;
        }

        // 格式化日期为YYYY-MM-DD(适配date输入框)
        function formatDateForInput(date) {
            const year = date.getFullYear();
            const month = String(now.getMonth() + 1).padStart(2, '0');
            const day = String(now.getDate()).padStart(2, '0');
            return `${year}-${month}-${day}`;
        }

        // 页面加载完成后初始化
        window.onload = function() {
            // 修复formatDateForInput函数的变量名错误
            function formatDateForInput(date) {
                const year = date.getFullYear();
                const month = String(date.getMonth() + 1).padStart(2, '0');
                const day = String(date.getDate()).padStart(2, '0');
                return `${year}-${month}-${day}`;
            }
            
            // 1. 生成并填充订单号
            const orderNo = generateOrderNo();
            document.getElementById('orderNo').value = orderNo;
            
            // 2. 填充当前系统日期到开单日期
            const today = new Date();
            document.getElementById('orderDate').value = formatDateForInput(today);
            
            // 3. 初始化商品下拉框
            initGoodsSelectors();
            
            // 4. 初始化计算总金额
            calculateTotal();
        };

        // 初始化所有商品下拉选择框
        function initGoodsSelectors() {
            const selectors = document.querySelectorAll('.goods-select');
            selectors.forEach(selector => {
                // 清空除了默认选项外的所有选项
                while (selector.options.length > 1) {
                    selector.remove(1);
                }
                
                // 动态添加商品选项
                goodsData.forEach(goods => {
                    const option = document.createElement('option');
                    option.value = goods.id; // 使用商品ID作为值
                    option.textContent = goods.name;
                    selector.appendChild(option);
                });
            });
        }

        // 根据商品ID获取商品详情
        function getGoodsById(goodsId) {
            return goodsData.find(item => item.id === parseInt(goodsId));
        }

        // 选择商品后自动填充信息并显示相关字段
        function selectGoods(el) {
            const row = el.closest('tr');
            const fields = row.querySelectorAll('.goods-field');
            
            // 清空并隐藏字段(未选择商品时)
            if (!el.value) {
                row.querySelector('.goodsUnit').value = '';
                row.querySelector('.goodsQty').value = '';
                row.querySelector('.goodsPrice').value = '';
                row.querySelector('.goodsAmount').value = '';
                fields.forEach(field => field.style.display = 'none');
                calculateTotal();
                return;
            }
            
            // 根据商品ID获取商品信息
            const goods = getGoodsById(el.value);
            if (!goods) return;
            
            // 填充信息
            row.querySelector('.goodsUnit').value = goods.unit;
            row.querySelector('.goodsQty').value = goods.defaultQty;
            row.querySelector('.goodsPrice').value = goods.price;
            
            // 显示相关字段
            fields.forEach(field => field.style.display = 'block');
            
            // 计算该行金额
            calculateRow(row.querySelector('.goodsQty'));
        }

        // 计算单行金额
        function calculateRow(el) {
            const row = el.closest('tr');
            const qty = parseFloat(row.querySelector('.goodsQty').value) || 0;
            const price = parseFloat(row.querySelector('.goodsPrice').value) || 0;
            const amount = qty * price;
            row.querySelector('.goodsAmount').value = amount.toFixed(2);
            calculateTotal();
        }

        // 计算总金额
        function calculateTotal() {
            let total = 0;
            const rows = document.querySelectorAll('#goodsTable .goods-row');
            rows.forEach(row => {
                const amount = parseFloat(row.querySelector('.goodsAmount').value) || 0;
                total += amount;
            });
            document.getElementById('totalLower').value = total.toFixed(2);
            
            // 大写金额转换(优化版)
            const digitToCapital = {
                0: '零',1: '壹',2: '贰',3: '叁',4: '肆',
                5: '伍',6: '陆',7: '柒',8: '捌',9: '玖'
            };
            const unit = ['元','拾','佰','仟','万','拾','佰','仟','亿'];
            
            // 处理0的情况
            if (total === 0) {
                document.getElementById('totalCapital').value = '零元零角零分';
                return;
            }
            
            const numStr = total.toFixed(2).replace('.', '');
            let capitalStr = '';
            
            // 处理元以上部分
            for(let i=0; i<numStr.length-2; i++){
                if (numStr[i] !== '0' || (i < numStr.length-3 && numStr[i+1] !== '0')) {
                    capitalStr += digitToCapital[numStr[i]] + unit[numStr.length-3 -i];
                } else if (i === numStr.length-3 && numStr[i] === '0' && capitalStr) {
                    capitalStr += digitToCapital[numStr[i]];
                }
            }
            
            // 处理角分
            const jiao = numStr[numStr.length-2];
            const fen = numStr[numStr.length-1];
            
            if (jiao !== '0') {
                capitalStr += digitToCapital[jiao] + '角';
            } else if (capitalStr && fen !== '0') {
                capitalStr += '零';
            }
            
            if (fen !== '0') {
                capitalStr += digitToCapital[fen] + '分';
            } else if (!capitalStr) {
                capitalStr = '零元';
            }
            
            // 清理多余的零
            capitalStr = capitalStr.replace(/零+/g, '零').replace(/零元/, '元').replace(/零角/, '零');
            if (capitalStr.endsWith('零')) capitalStr = capitalStr.slice(0, -1);
            if (!capitalStr.includes('元')) capitalStr = '零元' + capitalStr;
            
            document.getElementById('totalCapital').value = capitalStr;
        }

        // 导出Excel
        function exportToExcel() {
            calculateTotal();
            const data = [];
            // 标题行
            data.push(['开平XXXXX (销售单)']);
            data.push([`NO: ${document.getElementById('orderNo').value}`, `开单日期: ${document.getElementById('orderDate').value}`]);
            data.push([]);
            // 买卖方信息
            data.push(['购买方信息', `名称: ${document.getElementById('buyerName').value}`, '销售方信息', `名称: ${document.getElementById('sellerName').value}`]);
            data.push(['', `联系信息: ${document.getElementById('buyerContact').value}`, '', `地址: ${document.getElementById('sellerAddr').value} 电话: ${document.getElementById('sellerTel').value}`]);
            data.push([]);
            // 商品表头
            data.push(['序号', '名称规格', '单位', '数量', '单价', '总金额', '备注']);
            // 商品数据
            const rows = document.querySelectorAll('#goodsTable .goods-row');
            rows.forEach(row => {
                // 获取商品名称(处理下拉框)
                const goodsSelect = row.querySelector('.goods-select');
                let goodsName = '';
                let goodsUnit = '';
                let goodsPrice = '';
                
                if (goodsSelect.value) {
                    const goods = getGoodsById(goodsSelect.value);
                    if (goods) {
                        goodsName = goods.name;
                        goodsUnit = row.querySelector('.goodsUnit').value || goods.unit;
                        goodsPrice = row.querySelector('.goodsPrice').value || goods.price;
                    }
                }
                
                data.push([
                    row.querySelector('td:nth-child(1) input').value,
                    goodsName,
                    goodsUnit,
                    row.querySelector('.goodsQty').value,
                    goodsPrice,
                    row.querySelector('.goodsAmount').value,
                    row.querySelector('.goodsRemark').value
                ]);
            });
            data.push([]);
            // 合计
            data.push(['合计(大写)', document.getElementById('totalCapital').value, '(小写)', document.getElementById('totalLower').value]);
            data.push([]);
            // 备注和签名
            data.push(['备注: 如对以上签收之表列货物的质量有异议请务必在三天内提出,多谢!', '客户签名:']);
            data.push(['销售人员:', '', '收款人:']);

            const ws = XLSX.utils.aoa_to_sheet(data);
            const wb = XLSX.utils.book_new();
            XLSX.utils.book_append_sheet(wb, ws, "销售单");
            XLSX.writeFile(wb, `开平XXXXX销售单_${document.getElementById('orderNo').value}.xlsx`);
        }

        // 打印销售单
        function printTable() {
            alert('打印前请在浏览器打印设置中关闭"页眉和页脚"以获得最佳效果');
            window.print();
        }

        // 打开添加商品弹窗
        function openAddGoodsModal() {
            document.getElementById('addGoodsModal').style.display = 'block';
            // 清空表单
            document.getElementById('newGoodsName').value = '';
            document.getElementById('newGoodsUnit').value = '';
            document.getElementById('newGoodsQty').value = '1';
            document.getElementById('newGoodsPrice').value = '';
        }

        // 关闭添加商品弹窗
        function closeAddGoodsModal() {
            document.getElementById('addGoodsModal').style.display = 'none';
        }

        // 保存新商品
        function saveNewGoods() {
            // 获取表单值
            const name = document.getElementById('newGoodsName').value.trim();
            const unit = document.getElementById('newGoodsUnit').value.trim();
            const defaultQty = parseInt(document.getElementById('newGoodsQty').value);
            const price = parseFloat(document.getElementById('newGoodsPrice').value);
            
            // 简单验证
            if (!name) {
                alert('请输入商品名称!');
                return;
            }
            if (!unit) {
                alert('请输入商品单位!');
                return;
            }
            if (isNaN(defaultQty) || defaultQty < 1) {
                alert('默认数量必须是大于0的数字!');
                return;
            }
            if (isNaN(price) || price < 0) {
                alert('单价必须是大于等于0的数字!');
                return;
            }
            
            // 生成新商品ID(最大ID+1)
            const maxId = goodsData.length > 0 ? Math.max(...goodsData.map(item => item.id)) : 0;
            const newId = maxId + 1;
            
            // 添加新商品到数组
            goodsData.push({
                id: newId,
                name: name,
                unit: unit,
                defaultQty: defaultQty,
                price: price
            });
            
            // 重新初始化下拉选择框
            initGoodsSelectors();
            
            // 关闭弹窗
            closeAddGoodsModal();
            
            // 提示成功
            alert(`商品"${name}"添加成功!`);
        }

        // 点击弹窗外区域关闭弹窗
        window.onclick = function(event) {
            const modal = document.getElementById('addGoodsModal');
            if (event.target === modal) {
                closeAddGoodsModal();
            }
        }
    </script>
</body>
</html>

概述

这是一个用于XXXXX销售的电子单据管理系统,包含商品管理、销售单生成、打印和导出功能。

主要功能

1. 单据基本信息

  • 自动生成订单号:系统根据当前日期和随机数生成唯一订单号
  • 自动填写开单日期:默认为当前系统日期
  • 购买方信息:可输入客户名称和联系信息
  • 销售方信息:预设默认值,可根据需要修改

2. 商品管理

  • 商品选择:下拉菜单选择预设商品
  • 自动填充:选择商品后自动填充单位、单价和默认数量
  • 实时计算:输入数量后自动计算单行金额和总金额
  • 金额大写转换:自动将小写金额转换为中文大写金额

3. 交互功能

  • 添加新商品:通过弹窗添加新的商品信息到系统
  • 导出Excel:将销售单导出为Excel文件
  • 打印销售单:调用浏览器打印功能

操作指南

创建销售单

  1. 系统加载后自动生成订单号和日期
  2. 填写购买方信息(名称和联系信息)
  3. 在商品行中选择商品:
    • 从下拉菜单中选择商品
    • 系统自动填充单位、单价和默认数量
    • 可修改数量,系统自动计算金额
    • 可添加备注信息

添加新商品

  1. 点击"添加商品"按钮
  2. 在弹出的窗口中填写:
    • 商品名称
    • 单位(如:个、项、令)
    • 默认数量
    • 单价
  3. 点击"保存"按钮
  4. 新商品将添加到所有商品下拉菜单中

导出和打印

  1. 导出Excel:点击"导出Excel"按钮,系统将生成并下载Excel文件
  2. 打印销售单:点击"打印销售单"按钮,进入打印预览

付款方式选择

  • 提供现金、转账、微信、支付宝四种付款方式
  • 支持多选(可根据实际业务需求调整)

技术特点

数据管理

  • 商品数据使用JSON格式管理
  • 支持动态添加新商品
  • 数据在页面会话期间保持

打印优化

  • 打印时自动隐藏操作按钮
  • 优化输入框显示,确保打印效果
  • 提供打印提示信息

计算功能

  • 实时金额计算
  • 中文大写金额自动转换
  • 支持小数计算

使用注意事项

  1. 浏览器兼容性:建议使用Chrome、Edge等现代浏览器
  2. 打印设置:打印前建议在浏览器打印设置中关闭"页眉和页脚"
  3. 数据保存:当前版本数据保存在页面内存中,刷新页面会重置
  4. Excel导出:依赖SheetJS库,需要网络连接加载

代码结构说明

主要文件

  • HTML:整体页面结构
  • CSS:样式设计,包含打印样式优化
  • JavaScript:核心业务逻辑

核心函数

  • generateOrderNo():生成订单号
  • initGoodsSelectors():初始化商品下拉菜单
  • selectGoods(el):选择商品处理
  • calculateRow(el):计算单行金额
  • calculateTotal():计算总金额
  • exportToExcel():导出Excel
  • saveNewGoods():保存新商品

维护说明

  • 修改公司信息:直接在HTML代码中搜索"开平市三埠区XXXXX"相关字段
  • 调整商品数据:修改JavaScript中的goodsData数组
  • 更改样式:修改CSS中的相关类

注CSS对打印调整:

@media print {
            .btn-group {
                display: none;
            }
            .modal {
                display: none !important;
            }
            body {
                margin: 0;
                padding: 10px;
            }
            input, select {
                border: none;
                width: 100%;
                padding: 0;
            }
            /* 打印时保持付款方式横排 */
            .pay-type-group {
                display: flex;
                gap: 15px;
            }
            .goods-row td {
                border: none;
            }
            .goods-row td:first-child {
                border-left: 1px solid #000;
            }
            .goods-row td:last-child {
                border-right: 1px solid #000;
            }
            .total-table td{
                border-top: 1px solid #000 !important;
            }
            .total-table th{
                border-top: 1px solid #000 !important;
            }
            
            .goods-row input, select {
                border: none;
                width: 100%;
                padding: 0;
                /* 打印时隐藏所有输入框/选择框的箭头 */
                -webkit-appearance: none !important;
                -moz-appearance: none !important;
                appearance: none !important;
            }
            /* 单独隐藏选择框的下拉箭头(覆盖所有浏览器) */
            select.goods-select::-ms-expand {
                display: none !important;
            }
            select.goods-select {
                background: transparent !important;
            }
            /* 隐藏数字输入框箭头(彻底兜底) */
            .goods-row input.goodsQty::-webkit-outer-spin-button,
            input.goodsQty::-webkit-inner-spin-button {
                display: none !important;
                -webkit-appearance: none !important;
                margin: 0 !important;
            }
            
            }