# [Xlsx-Group-Write](https://crates.io/crates/xlsx_group_write) --- ## 一、解决什么问题 日常我们数据在需要导出为 Excel xlsx 文件时,实际上大部分需求就是将对应数据按照顺序一行行写入到 xlsx 表格中,具体的实现其实很容易,就是用 xlsx 相关库编码即可。这样的实现路径存在如下问题: 1、大量重复工作 但是如果你有多个数据需要导出为 xlsx 文件,每个数据都要单独写调用 xlsx 单元格写入 api,非常枯燥又效率低下。 2、大量重复代码 导出为 xlsx 文件,除了 xlsx 格式相关的代码外,还有文件保存,保存文件路径检测等各种需要处理。 3、无法聚焦数据差异性 实际导出 excel xlsx 文件时,主要是各种数据的差异性,xlsx 相关的写入是类似的,手工的实现,在考虑数据的差异性时,还得考虑 xlsx 的操作等,无法聚焦。 4、分组输出工作量大 无法自动按照某一数据字段,将数据分组输出到不同的 xlsx 文件,硬编码实现有大量文件初始化和写入逻辑需要处理。 ## 二、我们干什么 本工具库帮助您聚焦数据导出到xlsx的编辑处理,可以在导出时自动按照某一字段对数据进行分割导出到不同的xlsx文件,同时支持xlsx加密、自动添加导出日期等功能。 主要由两部分组成: * [xlsx_group_write](https://crates.io/crates/xlsx_group_write) 核心库 * [xlsx_group_write_macro_derive](https://crates.io/crates/xlsx_group_write_macro_derive) 派生宏 ### (一)核心库用法 #### 个性化特性 * date 自动在文件名称中加入导出日期 * encrypt 支持xlsx文件加密,添加该特性后,向接口会增加密码参数 #### 1、 添加依赖 ```rust [dependencies.xlsx_group_write] version = "1" # 根据需要添加对应特性 feature = ["date","encrypt"] ``` #### 2、 定义您的导出数据结构,并实现XlsxGroupWrite,并根据需要使用不同的方法和属性 #### 3、 调用不同的write2xlsx_方法导出数据到xlsx文件 支持灵活的自动分组导出和汇总导出数据 * write2xlsx_group_only * 只导出分组数据 * 按照分组id,将不同数据导出到不同的xlsx文件中 * 如果添加了encrypt特性,该函数会增加一个加密密码参数 * 如果数据为&[&Self}则调用:write2xlsx_group_only_ref * 如果要额外传递个性化参数到文件名获取器或者写入其他信息到xlsx文件中,则调用:write2xlsx_group_only_with_extra_arg或者write2xlsx_group_only_ref_with_extra_arg * write2xlsx_merge_only * 所有数据导入到同一个汇总xlsx文件 * 如果仅使用该函数,可不设置group_maker * 如果添加了encrypt特性,该函数会增加一个加密密码参数 * 如果数据为&[&Self}则调用:write2xlsx_merge_only_ref * 如果要额外传递个性化参数到文件名获取器或者写入其他信息到xlsx文件中,则调用:write2xlsx_merge_only_with_extra_arg或者write2xlsx_merge_only_ref_with_extra_arg * write2xlsx_all * 以上同时导出 * 如果添加了encrypt特性,该函数会增加一个加密密码参数 * 如果数据为&[&Self}则调用:write2xlsx_all_ref * 如果要额外传递个性化参数到文件名获取器或者写入其他信息到xlsx文件中,则调用:则调用:write2xlsx_all_with_extra_arg或者write2xlsx_all_ref_with_extra_arg ### (二)派生宏用法 ```rust use xlsx_group_write_macro_derive::XlsxGroupWriteQuicker; #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( // 快捷行数据写入定义 // 各列以逗号分隔,可使用两个函数参数: // * line_index 为行号 // * &self 为待写入的数据 // 每个列数据定义为value:type // * value 要写入的数据,可为表达式,如:line_index-1,表示当前待写入数据行号-1 // * type 数据类型,number/string,不指定则为string类型 line_writer_simple = "line_index-1:number,&self.name,&self.tel,&self.dep", // 个性化行数据写入,调用对应函数进行写入行数据 // 与line_writer_simple互斥,line_writer_simple优先 // 该函数签名:fn write_xlsx_line(line_data:&MyAdvanceData, sheet: &mut Worksheet, line_index: u32,) -> Option line_writer_advance = "write_xlsx_line", // 个性化行数据写入,调用对应函数进行写入行数据,同时附加额外的参数 // 与line_writer_simple互斥,line_writer_simple优先 // 该函数签名:fn write_xlsx_line(line_data:&MyAdvanceData, sheet: &mut Worksheet, line_index: u32,extra_arg: Option,) -> Option line_writer_advance_with_extra_arg = "write_xlsx_line_with_extra_arg", // 通过模板文件生成表头,设置列宽等 // 设置格式:模板文件位置,数据起始写入行行号(第一行序号从1开始) // 与template_simple、template_getter互斥,template_simple优先 template_advance = "/home/feiy/Desktop/temp.xlsx,4", // 通过函数获取模板信息 // 用于模板文件动态确定场景 // 与template_simple、template_advance互斥,template_simple优先、template_advance次之 // 该函数签名:fn get_template() -> xlsx_group_write::data::XlsxInitTemplet; template_getter = "my_template_getter", // 分组id指定,如无需分组输出xlsx文件,可不指定。示例为使用写入数据的dep属性, group_maker = "&self.dep", // 快捷表头设置,各列以逗号分隔 template_simple = "序号,姓名,手机,部门" // 通过模板文件生成表头,设置列宽等 // 设置格式:模板文件位置,数据起始写入行行号(第一行序号从1开始) // 与template_simple互斥,template_simple优先 template_advance = "/home/feiy/Desktop/temp.xlsx,4", // 表格个性化信息添加器设置 // 在表格中添加自定义个性化信息 // 该函数签名:fn add_custom_info(sheet: &mut Worksheet, group_id: &str) // 如果设置了额外的个性化参数extra_arg_type属性,函数签名为: // 该函数签名:fn add_custom_info(sheet: &mut Worksheet, group_id: &str,extra_arg:Option<&Self::ExtraArgType>) custom_info_adder = "add_custom_info", // 输出的xlsx文件名前缀,含有完整路径,实际输出会自动添加.xlsx后缀 output_file_name_simple = "/tmp/test", // 设置自动在输出文件名中添加当前日期 // 需与output_file_name_simple一起使用, // 最终生成文件名称为类似:/tmp/test-2023-04-23.xlsx output_file_name_add_date = "true", // 个性化文件名称生成器,将调用指定的函数获取输出文件名称 // 该函数签名:fn get_output_file_name_advance(group_id: &str) -> String // 如果设置了额外的个性化参数extra_arg_type属性,函数签名为: // 该函数签名:fn get_output_file_name_advance(group_id: &str,extra_arg:Option<&Self::ExtraArgType>) -> String output_file_name_advance = "get_output_file_name_advance", // 个性化信息类型 // 输出xlsx文件时,向文件名称生成器函数和custom_info_add传入个性化信息 extra_arg_type ="String", )] ``` 推荐使用xlsx_group_write_macro_derive ## 三、使用示例 ### (一)示例 1 最快捷使用场景:自动生成表头,各行数据自动写入。 #### 1、 示例 1 - 宏版本(推荐用法) ```rust use xlsx_group_write::prelude::*; #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( line_writer_simple = "line_index-1:number,&self.name,&self.tel,&self.dep", group_maker = "&self.dep", template_simple = "序号,姓名,手机,部门", output_file_name_simple = "/tmp/test" )] struct MySimpleData { pub name: String, pub tel: String, pub dep: String, } impl MySimpleData { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } } #[test] fn test_simple() { // 初始化待导出数据 let data = vec![ MySimpleData::new("张三", "185xxxx2228", "网金部"), MySimpleData::new("李四", "185xxxx2229", "运管部"), MySimpleData::new("王二", "185xxxx2230", "网金部"), ]; // 导出数据到xlsx文件 // 自动按照部门分别导出,同时还汇总导出一个汇总xlsx文件 // 成功导出返回对应的文件信息和分组id let resp = MySimpleData::write2xlsx_all(&data); println!("resp:{resp:#?}"); } ``` #### 2、 示例1 - 自行实现trait版本 ```rust use xlsx_group_write::*; use xlsx_group_write::data::XlsxColValueType; /// 将要导出为xlsx文件的数据结构 struct MySimpleData { pub name: String, pub tel: String, pub dep: String, } impl MySimpleData { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } } // 实现trait,以便快捷导出为xlsx impl XlsxGroupWrite for MySimpleData { /// 每行数据写入方式为简便模式 /// 即直接根据line_writer_simple返回的对照表自动写入数据 /// 无需了解xlsx写入api const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple; /// 每一行写入四列数据,分别为:序号、姓名,手机和部门. /// # 参数说明 /// /// * index 为正在写入行的行号,行号从1开始计数。 fn line_writer_simple(&self, index: u32) -> Vec { vec![ // 因为第一行是自动生成的表头,因此序号-1 XlsxColValue::new(index - 1, XlsxColValueType::NumberValue), XlsxColValue::new(&self.name, XlsxColValueType::StringValue), XlsxColValue::new(&self.tel, XlsxColValueType::StringValue), XlsxColValue::new(&self.dep, XlsxColValueType::StringValue), ] } /// 设置分组id /// /// 按照部门对数据进行分组 /// 如网金部,写入到网金部文件,运管部写入到运管部文件中。 fn group_make(&self) -> String { self.dep.clone() } /// 设置表头内容 /// 列之间使用英文,分隔,将自动写入表格第一行。 /// /// 设置四列表头分别为:序号、姓名、手机和部门。 fn get_template() -> XlsxInitTemplet { XlsxInitTemplet::new_header("序号,姓名,手机,部门") } /// 输出xlsx文件名设置 /// 生成的文件名称为:/tmp/test-分组id.xlsx const OUTPUT_FILE_NAME_GETTER_SIMPLE: Option = Some(OutputFileNameSimpleGetter::new( "/tmp/test", )); } #[test] fn test_simple_temp() { // 初始化待导出数据 let data = vec![ MySimpleData::new("张三", "185xxxx2228", "网金部"), MySimpleData::new("李四", "185xxxx2229", "运管部"), MySimpleData::new("王二", "185xxxx2230", "网金部"), ]; // 导出数据到xlsx文件 // 自动按照部门分别导出,同时还汇总导出一个汇总xlsx文件 // 成功导出返回对应的文件信息和分组id let resp = MySimpleData::write2xlsx_all( &data ); /* 输出: Ok( [ XlsxGroupWriteResp { group_id: "网金部", file_name: "/tmp/test-网金部.xlsx", }, XlsxGroupWriteResp { group_id: "运管部", file_name: "/tmp/test-运管部.xlsx", }, XlsxGroupWriteResp { group_id: "合并", file_name: "/tmp/test-合并.xlsx", }, ], ) */ println!("{resp:#?}"); } ``` ### (二)示例 2 我们可以自己先编辑好一个excel表格的样式,设置好标题、表头、字体等,然后以此xlsx文件为模板,生成表标题和表头,并在表格添加自定义信息,各行数据自动写入 #### 1、 示例2-宏版本(推荐用法) ```rust use umya_spreadsheet::Worksheet; use xlsx_group_write::prelude::*; #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( line_writer_simple = "line_index-1:number,&self.name,&self.tel,&self.dep", group_maker = "&self.dep", template_advance = "/home/feiy/Desktop/temp.xlsx,4", custom_info_adder = "Self::add_custom_info", output_file_name_simple = "/tmp/test", )] struct MySimpleDataWithTemplate { pub name: String, pub tel: String, pub dep: String, } impl MySimpleDataWithTemplate { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } /// 对导出的xlsx文件进行一些个性化修改 /// 比如需要在第二行插入对应分组名称,插入报表日期等信息 /// /// 将在xlsx初始化完成后自动调用该方法 /// /// # 参数说明 /// /// * sheet 要修改的xlsx工作表 /// * group_id 该xlsx对应的分组id fn add_custom_info(sheet: &mut Worksheet, group_id: &str) { sheet .get_cell_mut((&1, &2)) .set_value_string(&format!("{group_id},报表日期:2023年4月20日")); } } #[test] fn test_simple_with_template() { // 初始化待导出数据 let data = vec![ MySimpleDataWithTemplate::new("张三", "185xxxx2228", "网金部"), MySimpleDataWithTemplate::new("李四", "185xxxx2229", "运管部"), MySimpleDataWithTemplate::new("王二", "185xxxx2230", "网金部"), ]; // 导出数据到xlsx文件 // 自动按照部门分别导出,同时还汇总导出一个汇总xlsx文件 // 成功导出返回对应的文件信息和分组id let resp = MySimpleDataWithTemplate::write2xlsx_all(&data); println!("resp:{resp:#?}"); } ``` #### 1.1、 示例2.1-宏版本(完全个性化模板) 动态确定xlsx文件模板,生成表标题和表头,并在表格添加自定义信息,各行数据自动写入 ```rust #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( line_writer_simple = "line_index-1:number,&self.name,&self.tel,&self.dep", group_maker = "&self.dep", template_getter = "Self::get_cur_template", custom_info_adder = "Self::add_custom_info", output_file_name_simple = "/tmp/test", output_file_name_add_date = "true" )] struct MySimpleDataWithTemplateGetter { pub name: String, pub tel: String, pub dep: String, } impl MySimpleDataWithTemplateGetter { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } /// 动态确定模板文件 fn get_cur_template() -> XlsxInitTemplet{ XlsxInitTemplet::new_advance("/home/feiy/Desktop/template.xlsx", 3) } /// 对导出的xlsx文件进行一些个性化修改 /// 比如需要在第二行插入对应分组名称,插入报表数据范围等信息 /// /// 将在xlsx初始化完成后自动调用该方法 /// /// # 参数说明 /// /// * sheet 要修改的xlsx工作表 /// * group_id 该xlsx对应的分组id fn add_custom_info(sheet: &mut Worksheet, group_id: &str) { sheet .get_cell_mut((&1, &2)) .set_value_string(&format!("{group_id},报表日期:2023年4月20日")); } } #[test] fn test_simple_with_template_getter() { // 初始化待导出数据 let data = vec![ MySimpleDataWithTemplateGetter::new("张三", "185xxxx2228", "网金部"), MySimpleDataWithTemplateGetter::new("李四", "185xxxx2229", "运管部"), MySimpleDataWithTemplateGetter::new("王二", "185xxxx2230", "网金部"), ]; // 导出数据到xlsx文件 // 自动按照部门分别导出,同时还汇总导出一个汇总xlsx文件 // 成功导出返回对应的文件信息和分组id let resp = MySimpleDataWithTemplateGetter::write2xlsx_all(&data); println!("resp:{resp:#?}"); } ``` #### 2、 示例2 - 自行实现trait版本 ```rust use umya_spreadsheet::Worksheet; use xlsx_group_write::prelude::*; struct MyData { pub name: String, pub tel: String, pub dep: String, } impl MyData { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } } impl XlsxGroupWrite for MyData { const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple; fn line_writer_simple(&self, index: u32) -> Vec { vec![ XlsxColValue::new(index - 3, XlsxColValueType::NumberValue), XlsxColValue::new(&self.name, XlsxColValueType::StringValue), XlsxColValue::new(&self.tel, XlsxColValueType::StringValue), XlsxColValue::new(&self.dep, XlsxColValueType::StringValue), ] } fn group_make(&self) -> String { self.dep.clone() } /// 设置以/home/feiy/Desktop/temp.xlsx为模板创建导出xlsx文件, /// 该模板中从第4行开始写入实际需要导出的数据。 fn get_template() -> XlsxInitTemplet { XlsxInitTemplet::new_advance("/home/feiy/Desktop/temp.xlsx", 4) } /// 对生成的excel表格增加个性化信息 /// /// 在第二行加入,部门信息和导出日期信息 /// /// # 参数说明 /// /// * sheet 要修改的xlsx工作表 /// * group_id 该xlsx对应的分组id fn add_custom_info_to_sheet(sheet: &mut Worksheet, group_id: &str) { sheet .get_cell_mut((&1, &2)) .set_value_string(&format!("{group_id},报表日期:2023年4月20日")); } const OUTPUT_FILE_NAME_GETTER_SIMPLE: Option = Some(OutputFileNameSimpleGetter::new( "/tmp/test", )); } #[test] fn test_custom_info() { let data = vec![ MyData::new("张三", "185xxxx2228", "网金部"), MyData::new("李四", "185xxxx2229", "运管部"), MyData::new("王二", "185xxxx2230", "网金部"), ]; // 只分组导出对应部门xlsx文件,不导出所有数据合并到一个文件的汇总文件 let resp = MyData::write2xlsx_group_only( &data, ); println!("{resp:#?}"); } ``` ### (三)示例 3 自动生成表头,各行数据调用个性化写入函数write_xlsx_line写入 如果您的数据并不是一个字段写入一列的,需要合并写入,或者需要自定义单元格样式。 #### 1、 示例3-宏版本(推荐用法) ```rust use umya_spreadsheet::Worksheet; use xlsx_group_write::prelude::*; #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( line_writer_advance = "Self::write_xlsx_line", group_maker = "&self.dep", template_simple = "序号,姓名,手机,部门", output_file_name_simple = "/tmp/test", )] struct MyAdvanceData { pub name: String, pub tel: String, pub dep: String, } impl MyAdvanceData { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } /// 个性化写入行数据 fn write_xlsx_line( line_data:&MyAdvanceData, sheet: &mut Worksheet, line_index: u32, ) -> Option { XlsxWriterTool::set_excel_cell_value_number(sheet, 1, line_index, line_index - 1); XlsxWriterTool::set_excel_cell_value_str(sheet, 2, line_index, &format!("ad-{}",&line_data.name)); XlsxWriterTool::set_excel_cell_value_str(sheet, 3, line_index, &line_data.tel); XlsxWriterTool::set_excel_cell_value_str(sheet, 4, line_index, &line_data.dep); None } } #[test] fn test_advance_write() { // 初始化待导出数据 let data = vec![ MyAdvanceData::new("张三", "185xxxx2228", "网金部"), MyAdvanceData::new("李四", "185xxxx2229", "运管部"), MyAdvanceData::new("王二", "185xxxx2230", "网金部"), ]; // 导出数据到xlsx文件 // 自动按照部门分别导出,同时还汇总导出一个汇总xlsx文件 // 成功导出返回对应的文件信息和分组id let resp = MyAdvanceData::write2xlsx_all(&data); println!("resp:{resp:#?}"); } ``` #### 2、 示例3 - 自行实现trait版本 ```rust use xlsx_group_write::*; use xlsx_group_write::data::XlsxColValueType; struct MyData3 { pub name: String, pub tel: String, pub dep: String, } impl MyData3 { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } } impl XlsxGroupWrite for MyData3 { /// 行写入模式为高级写入模式,完全自定义 const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Advance; /// 使用xlsx api 写入每行的数据 fn line_writer_advance( &self, sheet: &mut Worksheet, index: u32, ) -> Option { xlsx_util::XlsxWriterTool::set_excel_cell_value_number(sheet, 1, index, index - 2); xlsx_util::XlsxWriterTool::set_excel_cell_value_str(sheet, 2, index, &self.name); xlsx_util::XlsxWriterTool::set_excel_cell_value_str(sheet, 3, index, &self.tel); xlsx_util::XlsxWriterTool::set_excel_cell_value_str(sheet, 4, index, &self.dep); None } /// 设置表头内容 /// 列之间使用英文,分隔,将自动写入表格第一行。 /// /// 设置四列表头分别为:序号、姓名、手机和部门。 fn get_template() -> XlsxInitTemplet { XlsxInitTemplet::new_header("序号,姓名,手机,部门") } /// 输出文件位置和文件名称由函数自行控制,比如每个部门文件存放不同的路径中等 fn get_output_file_name_advance(groupt_id: &str) -> String { format!("/tmp/advance-{groupt_id}.xlsx") } fn add_custom_info_to_sheet(sheet: &mut Worksheet, group_id: &str) { sheet .get_cell_mut((&1, &2)) .set_value_string(&format!("{group_id},报表日期:2023年4月20日")); } } #[test] fn test_advance_write() { let data = vec![ MyData3::new("张三", "185xxxx2228", "网金部"), MyData3::new("李四", "185xxxx2229", "运管部"), MyData3::new("王二", "185xxxx2230", "网金部"), ]; let resp = MyData3::write2xlsx_merge_only( &data ); println!("{resp:#?}"); } ``` ### (四)示例 4 自动生成表头,各行数据自动写入,输出文件名称通过函数获取 #### 1、 示例4-宏版本(推荐用法) ```rust use umya_spreadsheet::Worksheet; use xlsx_group_write::prelude::*; #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( line_writer_simple = "line_index-1:number,&self.name,&self.tel,&self.dep", group_maker = "&self.dep", template_simple = "序号,姓名,手机,部门", output_file_name_advance = "Self::get_output_file_name_advance", )] struct MyFileNameData { pub name: String, pub tel: String, pub dep: String, } impl MyFileNameData { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } /// 完全自定义的输出文件名称名称生成器 /// /// 参数说明: /// /// * groupt_id :当期数据的分组id #[allow(dead_code)] fn get_output_file_name_advance(group_id: &str) -> String { format!("/tmp/f-{group_id}.xlsx") } } #[test] fn test_advance_file_name() { // 初始化待导出数据 let data = vec![ MyFileNameData::new("张三", "185xxxx2228", "网金部"), MyFileNameData::new("李四", "185xxxx2229", "运管部"), MyFileNameData::new("王二", "185xxxx2230", "网金部"), ]; // 导出数据到xlsx文件 // 自动按照部门分别导出,同时还汇总导出一个汇总xlsx文件 // 成功导出返回对应的文件信息和分组id let resp = MyFileNameData::write2xlsx_all(&data); println!("resp:{resp:#?}"); } ``` #### 2、 示例4 - 自行实现trait版本 ```rust use xlsx_group_write::*; use xlsx_group_write::data::XlsxColValueType; struct MyData3 { pub name: String, pub tel: String, pub dep: String, } impl MyData3 { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } } impl XlsxGroupWrite for MyData3 { const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple; fn line_writer_simple(&self, index: u32) -> Vec { vec![ XlsxColValue::new(index - 1, XlsxColValueType::NumberValue), XlsxColValue::new(&self.name, XlsxColValueType::StringValue), XlsxColValue::new(&self.tel, XlsxColValueType::StringValue), XlsxColValue::new(&self.dep, XlsxColValueType::StringValue), ] } /// 设置表头内容 /// 列之间使用英文,分隔,将自动写入表格第一行。 /// /// 设置四列表头分别为:序号、姓名、手机和部门。 fn get_template() -> XlsxInitTemplet { XlsxInitTemplet::new_header("序号,姓名,手机,部门") } /// 输出文件位置和文件名称由函数自行控制,比如每个部门文件存放不同的路径中等 fn get_output_file_name_advance(groupt_id: &str) -> String { format!("/tmp/advance-{groupt_id}.xlsx") } } #[test] fn test_advance_write() { let data = vec![ MyData3::new("张三", "185xxxx2228", "网金部"), MyData3::new("李四", "185xxxx2229", "运管部"), MyData3::new("王二", "185xxxx2230", "网金部"), ]; let resp = MyData3::write2xlsx_merge_only( &data ); println!("{resp:#?}"); } ``` ### (四)示例 5 自动生成表头,各行数据个性化写入,传递额外参数到文件名称,写入个性化信息到xlsx表中 ```rust use xlsx_group_write::*; #[derive(XlsxGroupWriteQuicker)] #[xlsx_group_write( line_writer_advance_with_extra_arg = "Self::write_xlsx_line", group_maker = "&self.dep", template_simple = "序号,姓名,手机,部门", extra_arg_type ="String", custom_info_adder = "Self::add_custom_info", output_file_name_advance = "Self::get_output_file_name_advance", )] struct MySimpleDataWithExtraArg { pub name: String, pub tel: String, pub dep: String, } impl MySimpleDataWithExtraArg { pub fn new(name: &str, tel: &str, dep: &str) -> Self { Self { name: name.into(), tel: tel.into(), dep: dep.into(), } } /// 写入行数据,传入额外参数 fn write_xlsx_line( line_data:&MySimpleDataWithExtraArg, sheet: &mut Worksheet, line_index: u32, extra_arg: Option<&String>, ) -> Option { XlsxWriterTool::set_excel_cell_value_number(sheet, 1, line_index, line_index - 1); XlsxWriterTool::set_excel_cell_value_str(sheet, 2, line_index, &format!("ad-{}",&line_data.name)); XlsxWriterTool::set_excel_cell_value_str(sheet, 3, line_index, &line_data.tel); XlsxWriterTool::set_excel_cell_value_str(sheet, 4, line_index, &line_data.dep); if let Some(extra_arg) = extra_arg{ XlsxWriterTool::set_excel_cell_value_str(sheet, 5, line_index, extra_arg); } None } /// 对导出的xlsx文件进行一些个性化修改 /// 比如需要在第二行插入对应分组名称,插入报表数据范围等信息 /// /// 将在xlsx初始化完成后自动调用该方法 /// /// # 参数说明 /// /// * sheet 要修改的xlsx工作表 /// * group_id 该xlsx对应的分组id fn add_custom_info(sheet: &mut Worksheet, group_id: &str,org_name:Option<&String>) { if let Some(org_name) = org_name{ sheet .get_cell_mut((&1, &5)) .set_value_string(&format!("{org_name} {group_id},报表日期:2023年4月20日")); }else{ sheet .get_cell_mut((&1, &5)) .set_value_string(&format!("{group_id},报表日期:2023年4月20日")); } } /// 完全自定义的输出文件名称名称生成器 /// /// 参数说明: /// /// * groupt_id :当期数据的分组id #[allow(dead_code)] fn get_output_file_name_advance(group_id: &str,org_name:Option<&String>) -> String { if let Some(org_name) = org_name{ format!("/tmp/f-{org_name}-{group_id}.xlsx") }else{ format!("/tmp/f-{group_id}.xlsx") } } } #[test] fn test_simple_with_extra_arg() { // 初始化待导出数据 let data = vec![ MySimpleDataWithExtraArg::new("张三", "185xxxx2228", "网金部"), MySimpleDataWithExtraArg::new("李四", "185xxxx2229", "运管部"), MySimpleDataWithExtraArg::new("王二", "185xxxx2230", "网金部"), ]; // 导出汇总数据到xlsx文件 // 成功导出返回对应的文件信息和分组id // 传入个性化参数 let resp = MySimpleDataWithExtraArg::write2xlsx_merge_only_with_extra_arg(&data,Some(String::from("个性化参数"))); println!("resp:{resp:#?}"); } ```