峰峦@叠嶂 2026-03-30 09:55 采纳率: 97.6%
浏览 8

填写的数据会自动四舍五入的问题

请教一个,我设计了一个BS端的软件,用于工厂工时填写用,但遇到一个问题,在操作人员填写日产量和累计产量,比如是1.256时,保存总是自动的四舍五入成了1.260,请见附图,我们需要最大保留小数点后的三位,不要四舍五入 ,这两个字段的数据类型是decimal(18,3),请指导一下是什么原因导致的自动四舍五入吧;
相关图片如下:

img


img

相关代码如下
填写部分的设计(Index.cshtml)

   <div class="col-6">
       <label asp-for="Input.DailyOutput" class="form-label"></label>
       <input asp-for="Input.DailyOutput" class="form-control" />
   </div>
   <div class="col-6">
       <label asp-for="Input.CumulativeOutput" class="form-label"></label>
       <input asp-for="Input.CumulativeOutput" class="form-control" />
   </div>

保存部分代码(Index.cshtml.cs):

       DailyOutput = Input.DailyOutput ?? 0,
       CumulativeOutput = Input.CumulativeOutput ?? 0,

前端的完整代码;production.js


$(document).ready(function () {

    // 标记用户是否手动修改过累计产量
    var userModifiedCumulative = false;

    // 当日产量自动填充累计产量(仅在用户未手动修改时)
    $('#Input_DailyOutput').on('input', function () {
        var daily = $(this).val();
        if (!userModifiedCumulative) {
            $('#Input_CumulativeOutput').val(daily);
        }
    });

    // 监听累计产量输入,检测用户手动修改
    $('#Input_CumulativeOutput').on('input', function () {
        var val = $(this).val();
        if (val === '') {
            // 如果用户清空了累计产量,重置标记,允许重新自动同步
            userModifiedCumulative = false;
        } else {
            userModifiedCumulative = true;
        }
    });

    // 产品名称变更(静态元素)
    $('#productNameSelect').change(function () {
        var productName = $(this).val();
        $('#specificationSelect').html('<option value="">-- 加载中... --</option>');
        $('#processSelect').html('<option value="">-- 请先选择规格 --</option>');
        $('#selectedProductId').val('');
        $('#unitField').val('');

        if (productName) {
            $.getJSON(`?handler=Specifications&productName=${encodeURIComponent(productName)}`, function (data) {
                var options = '<option value="">-- 请选择规格 --</option>';
                $.each(data, function (i, item) {
                    options += `<option value="${item.value}">${item.text}</option>`;
                });
                $('#specificationSelect').html(options);
            });
        } else {
            $('#specificationSelect').html('<option value="">-- 请选择产品名称 --</option>');
        }
    });

    // 规格变更(动态元素)→ 使用委托
    $(document).on('change', '#specificationSelect', function () {
        var productId = $(this).val();
        $('#processSelect').html('<option value="">-- 加载中... --</option>');
        $('#unitField').val('');

        if (productId) {
            $.getJSON(`?handler=Processes&productId=${productId}`, function (data) {
                var options = '<option value="">-- 请选择工序 --</option>';
                $.each(data, function (i, item) {
                    options += `<option value="${item.value}">${item.text}</option>`;
                });
                $('#processSelect').html(options);
            });
        } else {
            $('#processSelect').html('<option value="">-- 请先选择规格 --</option>');
            $('#unitField').val('');
        }
    });

    // 工序变更(动态元素)→ 使用委托
    $(document).on('change', '#processSelect', function () {
        var processId = $(this).val();
        console.log('工序变更,processId=', processId);  // 新增
        if (processId) {
            $.getJSON(`?handler=ProcessUnit&processId=${processId}`, function (data) {
                console.log('获取到单位:', data.unit);   // 添加此行
                $('#unitField').val(data.unit);
            });
        } else {
            $('#unitField').val('');
        }
    });

    // 当日产量自动填充(静态元素)
    $('#Input_DailyOutput').on('input', function () {
        var daily = $(this).val();
        var cumulative = $('#Input_CumulativeOutput').val();
        if (cumulative === '' || parseFloat(cumulative) === 0) {
            $('#Input_CumulativeOutput').val(daily);
        }
    });

    // ========== 新增:计算人数和总工时 ==========
    function updateTotals() {
        var totalWorkers = 0;
        var totalHours = 0;
        $('#workerHourContainer .worker-row').each(function () {
            var nameInput = $(this).find('input[name$=".EmployeeName"]');
            var hoursInput = $(this).find('input.hours-input');
            var name = nameInput.val();
            var hours = parseFloat(hoursInput.val()) || 0;
            if (name && name.trim() !== '') {
                totalWorkers++;
                totalHours += hours;
            }
        });
        $('#workerCount').val(totalWorkers);
        $('#totalHours').val(totalHours.toFixed(1));
    }

    // 监听姓名变化(动态元素)
    $(document).on('input', 'input[name$=".EmployeeName"]', function () {
        updateTotals();
    });

    // 监听工时变化(原有事件基础上添加 updateTotals)
    $(document).on('input', '.hours-input', function () {
        updateTotals();
    });

    // 添加人员行(静态按钮)
    $('#addRowBtn').click(function () {
        var index = $('#workerHourContainer .worker-row').length;
        var newRow = `<div class="row g-2 mb-2 worker-row">
            <div class="col-7">
                <input type="text" name="Input.WorkerHours[${index}].EmployeeName" class="form-control" placeholder="人员姓名" />
            </div>
            <div class="col-4">
                <input type="number" step="any" name="Input.WorkerHours[${index}].HoursWorked" class="form-control hours-input" placeholder="工时" />
            </div>
            <div class="col-1">
                <button type="button" class="btn btn-outline-danger btn-sm remove-row">×</button>
            </div>
        </div>`;
        $('#workerHourContainer').append(newRow);
    });

    // 删除人员行(动态元素)→ 使用委托
    $(document).on('click', '.remove-row', function () {
        $(this).closest('.worker-row').remove();
        reindexWorkerRows();
    });

    // 重新索引所有行的name属性
    function reindexWorkerRows() {
        $('#workerHourContainer .worker-row').each(function (index) {
            $(this).find('input[name^="Input.WorkerHours"]').each(function () {
                var name = $(this).attr('name');
                name = name.replace(/\[[0-9]+\]/, `[${index}]`);
                $(this).attr('name', name);
            });
        });
    }

});

模型设计如下:

public class ProductionEntryViewModel
{
    // 顶部字段
    [Required]
    [DataType(DataType.Date)]
    public DateTime ProductionDate { get; set; } = DateTime.Today;

    // 其他手填字段0310添加
   public int Id { get; set; }

    [Display(Name = "产品名称")]
    public int? SelectedProductId { get; set; }   // 最终选中的具体产品Id(包含规格)

    [Display(Name = "规格")]
    public int? SelectedSpecificationProductId { get; set; } // 与SelectedProductId实际相同,用于联动

    [Display(Name = "工序")]
    public int? SelectedProcessId { get; set; }

    // 其他手填字段
    [Display(Name = "批号")]
    public string BatchNo { get; set; }

    [Display(Name = "产品批号")]
    public string ProductBatchNo { get; set; }

    [Display(Name = "单位")]
    public string Unit { get; set; }

    [Display(Name = "当日产量")]
    public decimal? DailyOutput { get; set; }

    [Display(Name = "累计产量")]
    public decimal? CumulativeOutput { get; set; }

    [Display(Name = "完工状态")]
    public string CompletionStatus { get; set; } // 下拉选项

    [Display(Name = "人数")]
    public int NumberOfWorkers { get; set; }

    [Display(Name = "总工时")]
    public decimal ManHours { get; set; }

    [Display(Name = "备注")]

    [ValidateNever]
    public string Remarks { get; set; }

    // 人员详细工时列表(动态添加)
    public List<WorkerHourEntry> WorkerHours { get; set; } = new List<WorkerHourEntry>();

    // 用于联动下拉的数据源
    [ValidateNever]
    public List<SelectListItem> ProductNames { get; set; }  // 去重的产品名称列表

    [ValidateNever]
    public List<SelectListItem> Specifications { get; set; } // 根据产品名称筛选出的规格(产品)

    [ValidateNever]
    public List<SelectListItem> Processes { get; set; }     // 根据产品Id筛选出的工序

    [ValidateNever]
    public List<SelectListItem> CompletionStatuses { get; set; } // 完工状态预设

    public string SelectedProductName { get; set; }
}

public class WorkerHourEntry
{
    public string EmployeeName { get; set; }
    public decimal HoursWorked { get; set; }
}

  • 写回答

3条回答 默认 最新

  • 檀越@新空间 2026-03-30 09:56
    关注

    上午好☀️☀️☀️️
    本答案参考通义千问

    你提到的问题是:在填写数据时,例如 1.256,保存后自动变成 1.260,即被四舍五入了。但你希望保留三位小数,且不进行四舍五入。

    这个问题的根本原因在于 数据的格式化、解析或存储过程中发生了四舍五入,而不是数据库本身的问题(因为 decimal(18,3) 会保留三位小数)。


    🚨 问题分析

    1. 前端输入框的值可能被格式化

    你使用的是 <input type="text">,用户输入的数字可能被浏览器或 JavaScript 自动格式化为带有两位小数的形式(比如 1.26),而没有保留三位小数。

    2. JavaScript 中对数值的处理方式

    如果你在前端将字符串转换为浮点数(如用 parseFloat() 或直接赋值给变量),可能会导致精度丢失或四舍五入。

    3. ASP.NET Core 的模型绑定行为

    ASP.NET Core 在模型绑定时,如果字段类型是 decimal,会尝试将字符串转换为 decimal。如果输入值不是严格符合三位小数,可能会被自动四舍五入。


    ✅ 解决方案

    第一步:确保前端输入值保留三位小数

    你需要确保用户输入的值是 精确到三位小数,并防止浏览器或 JS 自动格式化。

    修改前端代码:

    // 在输入时强制保留三位小数
    $('#Input_DailyOutput').on('input', function () {
        var value = $(this).val();
        if (value) {
            // 使用正则表达式确保只保留三位小数
            value = value.replace(/[^0-9.]/g, ''); // 只允许数字和小数点
            var parts = value.split('.');
            if (parts.length === 1) {
                // 没有小数点,添加三位小数
                $(this).val(value + '.000');
            } else {
                // 有小数点,截断或补零到三位
                var decimalPart = parts[1].substring(0, 3);
                $(this).val(parts[0] + '.' + decimalPart.padEnd(3, '0'));
            }
        }
    });
    

    重点: 这段代码确保用户输入的值始终是三位小数,避免四舍五入。


    第二步:确保 ASP.NET Core 不自动四舍五入

    ASP.NET Core 在模型绑定时,默认会将字符串转换为 decimal,但在某些情况下(如输入格式不规范)可能会自动四舍五入。

    修改你的模型绑定逻辑(Index.cshtml.cs):

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }
    
        // 确保输入的值是三位小数,不自动四舍五入
        var dailyOutputStr = Request.Form["Input.DailyOutput"];
        var cumulativeOutputStr = Request.Form["Input.CumulativeOutput"];
    
        // 将字符串转换为 decimal 时保留三位小数
        if (decimal.TryParse(dailyOutputStr, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal dailyOutput))
        {
            Input.DailyOutput = dailyOutput;
        }
    
        if (decimal.TryParse(cumulativeOutputStr, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal cumulativeOutput))
        {
            Input.CumulativeOutput = cumulativeOutput;
        }
    
        // 保存逻辑
        await _context.YourEntity.AddAsync(new YourEntity
        {
            DailyOutput = Input.DailyOutput,
            CumulativeOutput = Input.CumulativeOutput
        });
    
        await _context.SaveChangesAsync();
    
        return RedirectToPage("Index");
    }
    

    重点: 使用 NumberStyles.AnyCultureInfo.InvariantCulture 来确保正确解析,避免四舍五入。


    第三步:前端表单提交时保留原始输入值

    确保在表单提交时,输入框的值是原始的三位小数形式,不要被自动修改。

    <input asp-for="Input.DailyOutput" class="form-control" oninput="formatDecimal(this)" />
    <input asp-for="Input.CumulativeOutput" class="form-control" oninput="formatDecimal(this)" />
    
    function formatDecimal(input) {
        var value = input.value;
        if (value) {
            value = value.replace(/[^0-9.]/g, '');
            var parts = value.split('.');
            if (parts.length === 1) {
                input.value = value + '.000';
            } else {
                var decimalPart = parts[1].substring(0, 3);
                input.value = parts[0] + '.' + decimalPart.padEnd(3, '0');
            }
        }
    }
    

    重点: 使用 oninput 事件实时格式化输入值,确保三位小数。


    📌 总结

    | 问题 | 原因 | 解决方法 | |------|------|----------| | 输入值被四舍五入 | 浏览器或 JS 自动格式化 | 使用 JavaScript 强制保留三位小数 | | 模型绑定时自动四舍五入 | .NET 默认转换逻辑 | 使用 decimal.TryParse 并指定 CultureInfo.InvariantCulture | | 表单提交值不一致 | 输入值未正确格式化 | 添加 oninput 事件格式化输入 |


    🔧 最终建议

    • 前端:使用 JavaScript 实时格式化输入值,确保始终是三位小数。
    • 后端:使用 decimal.TryParse 并指定文化信息,避免自动四舍五入。
    • 数据库decimal(18,3) 是正确的配置,无需更改。

    如有需要,我可以提供完整的前端和后端修改示例代码。欢迎继续提问!

    评论

报告相同问题?

问题事件

  • 创建了问题 3月30日