feat(excel): 添加日期时间解析和换行格式处理功能
- 新增日期时间解析函数,支持多种日期格式转换为Excel序列号 - 实现Excel序列号与Chrono时间的相互转换功能 - 添加对各种换行符格式的统一处理(\r\n、\\r\\n、\\n等) - 在插入和更新操作中集成日期格式识别和设置 - 实现自动换行和行高自适应功能 - 优化单元格值获取逻辑以支持日期格式化显示
This commit is contained in:
+58
-10
@@ -411,7 +411,7 @@ fn count_excel(book: &Spreadsheet, sheet_name: &Option<String>) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 修改版:插入行 (支持日期写入) ---
|
// --- 最终版:插入行 (支持所有换行格式 + 自动换行 + 样式保留) ---
|
||||||
fn insert_excel(
|
fn insert_excel(
|
||||||
book: &mut Spreadsheet,
|
book: &mut Spreadsheet,
|
||||||
value: &str,
|
value: &str,
|
||||||
@@ -438,7 +438,7 @@ fn insert_excel(
|
|||||||
sheet.insert_new_row(&insert_idx_1based, &1);
|
sheet.insert_new_row(&insert_idx_1based, &1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 写入数据 (逻辑增强)
|
// 写入数据
|
||||||
let vals: Vec<&str> = value.split(split).collect();
|
let vals: Vec<&str> = value.split(split).collect();
|
||||||
for (i, val) in vals.iter().enumerate() {
|
for (i, val) in vals.iter().enumerate() {
|
||||||
let col = (i + 1) as u32;
|
let col = (i + 1) as u32;
|
||||||
@@ -446,15 +446,40 @@ fn insert_excel(
|
|||||||
let val_trimmed = val.trim();
|
let val_trimmed = val.trim();
|
||||||
|
|
||||||
if !val_trimmed.is_empty() {
|
if !val_trimmed.is_empty() {
|
||||||
// 1. 尝试解析日期
|
// 1. 统一换行格式:处理所有换行符为 Excel 标准的 \n
|
||||||
|
// 同时保留对 Shell 转义的兼容(即使 Shell 吃掉了也能工作)
|
||||||
|
let processed_val = val_trimmed
|
||||||
|
.replace("\r\n", "\n") // 真正的 Windows 换行 (ASCII 13+10) -> Unix 换行
|
||||||
|
.replace("\\r\\n", "\n") // 字面量 \r\n (4个字符) -> Unix 换行
|
||||||
|
.replace("\\n", "\n") // 字面量 \n (2个字符) -> Unix 换行
|
||||||
|
.replace("\\t", "\t"); // 字面量 \t (2个字符) -> 制表符
|
||||||
|
|
||||||
|
// 2. 尝试解析日期(用原始 trim 后的值,日期不应该包含换行)
|
||||||
if let Some((dt, excel_fmt)) = try_parse_datetime(val_trimmed) {
|
if let Some((dt, excel_fmt)) = try_parse_datetime(val_trimmed) {
|
||||||
let serial = datetime_to_excel_serial(&dt);
|
let serial = datetime_to_excel_serial(&dt);
|
||||||
cell.set_value_number(serial);
|
cell.set_value_number(serial);
|
||||||
// 关键:设置单元格格式,这样 Excel 才会把它当日期看
|
|
||||||
cell.get_style_mut().get_number_format_mut().set_format_code(excel_fmt);
|
cell.get_style_mut().get_number_format_mut().set_format_code(excel_fmt);
|
||||||
} else {
|
} else {
|
||||||
// 2. 写入文本
|
// 3. 写入处理后的纯文本
|
||||||
cell.set_value(val_trimmed);
|
cell.set_value(processed_val.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 【关键】统一判断:只要内容包含换行符,就强制开启自动换行 + 自动调整行高
|
||||||
|
// 不管是日期还是文本(虽然日期带换行极少见,但逻辑完整)
|
||||||
|
if processed_val.contains('\n') {
|
||||||
|
// 保留单元格原有的所有对齐样式,只开启自动换行
|
||||||
|
let mut align = cell.get_style().get_alignment().cloned().unwrap_or_default();
|
||||||
|
align.set_wrap_text(true);
|
||||||
|
cell.get_style_mut().set_alignment(align);
|
||||||
|
|
||||||
|
// 5. 自动调整行高(简单估算)
|
||||||
|
let line_count = processed_val.matches('\n').count() + 1;
|
||||||
|
let estimated_height = (line_count as f64) * 15.0; // 每行约 15 磅
|
||||||
|
let row_dim = sheet.get_row_dimension_mut(&insert_idx_1based);
|
||||||
|
// 只有当当前行高小于估算值时才调整,避免覆盖用户已设置的行高
|
||||||
|
if *row_dim.get_height() < estimated_height {
|
||||||
|
row_dim.set_height(estimated_height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -463,7 +488,7 @@ fn insert_excel(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 修改版:更新行 (支持日期写入) ---
|
// --- 最终版:更新行 (支持所有换行格式 + 自动换行 + 样式保留) ---
|
||||||
fn update_excel(
|
fn update_excel(
|
||||||
book: &mut Spreadsheet,
|
book: &mut Spreadsheet,
|
||||||
value: &str,
|
value: &str,
|
||||||
@@ -486,14 +511,37 @@ fn update_excel(
|
|||||||
let val_trimmed = val.trim();
|
let val_trimmed = val.trim();
|
||||||
|
|
||||||
if !val_trimmed.is_empty() {
|
if !val_trimmed.is_empty() {
|
||||||
// 1. 尝试解析日期
|
// 1. 统一换行格式
|
||||||
|
let processed_val = val_trimmed
|
||||||
|
.replace("\r\n", "\n") // 真正的 Windows 换行 (ASCII 13+10) -> Unix 换行
|
||||||
|
.replace("\\r\\n", "\n") // 字面量 \r\n (4个字符) -> Unix 换行
|
||||||
|
.replace("\\n", "\n") // 字面量 \n (2个字符) -> Unix 换行
|
||||||
|
.replace("\\t", "\t"); // 字面量 \t (2个字符) -> 制表符
|
||||||
|
|
||||||
|
// 2. 尝试解析日期
|
||||||
if let Some((dt, excel_fmt)) = try_parse_datetime(val_trimmed) {
|
if let Some((dt, excel_fmt)) = try_parse_datetime(val_trimmed) {
|
||||||
let serial = datetime_to_excel_serial(&dt);
|
let serial = datetime_to_excel_serial(&dt);
|
||||||
cell_obj.set_value_number(serial);
|
cell_obj.set_value_number(serial);
|
||||||
cell_obj.get_style_mut().get_number_format_mut().set_format_code(excel_fmt);
|
cell_obj.get_style_mut().get_number_format_mut().set_format_code(excel_fmt);
|
||||||
} else {
|
} else {
|
||||||
// 2. 写入文本
|
// 3. 写入文本
|
||||||
cell_obj.set_value(val_trimmed);
|
cell_obj.set_value(processed_val.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 统一开启自动换行 + 自动调整行高
|
||||||
|
if processed_val.contains('\n') {
|
||||||
|
let mut align = cell_obj.get_style().get_alignment().cloned().unwrap_or_default();
|
||||||
|
align.set_wrap_text(true);
|
||||||
|
cell_obj.get_style_mut().set_alignment(align);
|
||||||
|
|
||||||
|
// 5. 自动调整行高(简单估算)
|
||||||
|
let line_count = processed_val.matches('\n').count() + 1;
|
||||||
|
let estimated_height = (line_count as f64) * 15.0; // 每行约 15 磅
|
||||||
|
let row_dim = sheet.get_row_dimension_mut(&target_row);
|
||||||
|
// 只有当当前行高小于估算值时才调整,避免覆盖用户已设置的行高
|
||||||
|
if *row_dim.get_height() < estimated_height {
|
||||||
|
row_dim.set_height(estimated_height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user