Files
ctbjrj/成套报价软件/价格格式化.cs
T

135 lines
6.3 KiB
C#

using System;
using System.Collections.Generic;
namespace 成套报价软件
{
/// <summary>
/// 价格显示格式化的统一规则:
/// 1) 小数位选择:控制价格单元格显示的小数位数(0~6 位)
/// 2) 取整方式:额外的取整规则(不取整/四舍五入到角/元/最近5元/最近10元等)
/// 配置存在每个项目的「项目信息」表里,四个字段:
/// 单台小数位 / 单台取整方式 / 项目小数位 / 项目取整方式
/// 本类只负责“显示前格式化”,不改原始数值,不写库(精度不丢失)。
/// </summary>
public static class 价格格式化
{
// ============================================================
// 下拉框预置项(供新建项目/修改项目窗口使用)
// ============================================================
/// <summary>小数位下拉框的预置选项文本(同时也是存库的值)。</summary>
public static readonly string[] 小数位选项 =
{
"保留整数", "保留1位小数", "保留2位小数", "保留3位小数",
"保留4位小数", "保留5位小数", "保留6位小数"
};
/// <summary>取整方式下拉框的预置选项文本(同时也是存库的值)。</summary>
public static readonly string[] 取整方式选项 =
{
"不取整",
"四舍五入", // 精确到 1(通用别名,与“四舍五入到元”等价)
"四舍五入到角", // 精确到 0.1
"四舍五入到元", // 精确到 1
"四舍五入到十元", // 精确到 10
"向上取整到元", // Math.Ceiling 到 1
"最近5元", // 精确到 5
"最近10元" // 精确到 10
};
// ============================================================
// 解析:把下拉框文本 → 小数位数 / 取整步长
// ============================================================
/// <summary>把“保留N位小数”选项文本解析成小数位数;解析失败返回 -1(表示用默认)。</summary>
public static int 解析小数位(string 选项文本)
{
if (string.IsNullOrWhiteSpace(选项文本)) return -1;
string s = 选项文本.Trim();
// "保留整数" → 0;"保留N位小数" → N
if (s.Contains("整数")) return 0;
// 截取“保留”和“位”之间的数字
int i1 = s.IndexOf('保');
int i2 = s.IndexOf('位');
if (i1 >= 0 && i2 > i1 + 1)
{
string num = s.Substring(i1 + 1, i2 - i1 - 1).Replace("留", "").Trim();
int n;
if (int.TryParse(num, out n) && n >= 0 && n <= 10) return n;
}
return -1;
}
/// <summary>
/// 把取整方式文本解析成对应的步长(>0 表示按此步长取整);
/// 返回 null 表示“不取整”或无法识别。
/// 例:“四舍五入到角” → 0.1m;“最近5元” → 5m;“向上取整到元” → 1m(另带向上标记)。
/// </summary>
/// <param name="向上">out 参数:为 true 时表示向上取整(Math.Ceiling),否则四舍五入。</param>
public static decimal? 解析取整步长(string 选项文本, out bool 向上)
{
向上 = false;
if (string.IsNullOrWhiteSpace(选项文本)) return null;
string s = 选项文本.Trim();
if (s == "不取整" || s.Contains("不取")) return null;
// “四舍五入”(纯文本) = 精确到元(步长 1)
if (s == "四舍五入") return 1m;
if (s.Contains("到角")) return 0.1m;
if (s.Contains("最近5")) return 5m;
if (s.Contains("最近10") || s.Contains("到十元")) return 10m;
if (s.Contains("向上") && s.Contains("到元")) { 向上 = true; return 1m; }
if (s.Contains("到元") || s.Contains("四舍五入到元")) return 1m;
if (s.Contains("到十")) return 10m;
return null;
}
// ============================================================
// 核心:格式化一个数值(只改显示,不改原始精度)
// ============================================================
/// <summary>
/// 把原始 decimal 按“小数位 + 取整方式”格式化为显示字符串。
/// 规则:先按取整方式对原值取整(用于显示,不改原值),再按小数位格式化。
/// 值为 0 时返回空串(与原 SetCell 的“0 显示空”规则保持一致)。
/// </summary>
/// <param name="value">原始数值</param>
/// <param name="小数位">-1 表示未配置(默认 2 位);0~6 表示保留位数</param>
/// <param name="取整方式">取整方式文本(可为空/null)</param>
public static string 格式化(decimal value, int 小数位, string 取整方式)
{
if (value == 0m) return "";
// 1) 先按取整方式得到“用于显示的值”(不改 value 本身)
decimal 显示值 = value;
bool 向上;
decimal? 步长 = 解析取整步长(取整方式, out 向上);
if (步长.HasValue && 步长.Value > 0m)
{
if (向上)
{
显示值 = Math.Ceiling(显示值 / 步长.Value) * 步长.Value;
}
else
{
显示值 = Math.Round(显示值 / 步长.Value, MidpointRounding.AwayFromZero) * 步长.Value;
}
}
// 2) 小数位:-1 用默认 2 位;否则按配置
int 位数 = (小数位 < 0 || 小数位 > 10) ? 2 : 小数位;
return 显示值.ToString("F" + 位数.ToString());
}
/// <summary>
/// 便捷重载:直接用 4 个配置文本格式化(避免调用方手动解析)。
/// 单台层和项目层共用同一套逻辑,只是传入的配置不同。
/// </summary>
public static string 格式化(decimal value, string 小数位文本, string 取整方式文本)
{
int n = 解析小数位(小数位文本);
return 格式化(value, n, 取整方式文本);
}
}
}