Xlsx-Group-Write


解决问题

日常我们数据在需要导出为 Excel xlsx 文件时,实际上大部分需求就是将对应数据按照顺序一行行写入到 xlsx 表格中,具体的实现其实很容易,就是用 xlsx 相关库编码即可。这样的实现路径存在如下问题:

1、大量重复工作

但是如果你有多个数据需要导出为 xlsx 文件,每个数据都要单独写调用 xlsx 单元格写入 api,非常枯燥又效率低下。

2、大量重复代码

导出为 xlsx 文件,除了 xlsx 格式相关的代码外,还有文件保存,保存文件路径检测等各种需要处理。

3、无法聚焦数据差异性

实际导出 excel xlsx 文件时,主要是各种数据的差异性,xlsx 相关的写入是类似的,手工的实现,在考虑数据的差异性时,还得考虑 xlsx 的操作等,无法聚焦。

4、分组输出工作量大

无法自动按照某一数据字段,将数据分组输出到不同的 xlsx 文件,硬编码实现有大量文件初始化和写入逻辑需要处理。

我们干什么

因此,这就有了 Xlsx-Group-Write 的出现了,主要实现如下功能:

1、聚焦数据处理

无需了解 xlsx 的写入 api,只需要聚焦数据如何写入到的哪一列。即可实现自动导出到xlsx,支持分类导出,支持加密导出等,比如有如下数据结构

```rust

struct MyDate{ name:String, tel:String, dep:String } ```

我们只需要维护各字段对应将写入到表格的第几列即可完成 xlsx 导出。示例如下:

```rust use xlsxgroupwrite::*; use xlsxgroupwrite::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 { /// 每行数据写入方式为简便模式 /// 即直接根据linewritersimple返回的对照表自动写入数据 /// 无需了解xlsx写入api const LINEWRITERMODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple;

/// 每一行写入四列数据,分别为:序号、姓名,手机和部门.
/// # 参数说明
/// 
/// * index 为正在写入行的行号,行号从1开始计数。
fn line_writer_simple(&self, index: u32) -> Vec<XlsxColValue> {
    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<OutputFileNameSimpleGetter> =
    Some(OutputFileNameSimpleGetter::new(
        "/tmp/test",
    ));

}

[test]

fn testsimpletemp() { // 初始化待导出数据 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、支持从某个xlsx文件模板生成导出数据

我们可以自己先编辑好一个excel表格的样式,设置好标题、表头、字体等,然后以此模板生成导出数据,例如:

```rust

use xlsxgroupwrite::*; use xlsxgroupwrite::data::XlsxColValueType;

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 LINEWRITERMODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple;

fn line_writer_simple(&self, index: u32) -> Vec<XlsxColValue> {
    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<OutputFileNameSimpleGetter> =
    Some(OutputFileNameSimpleGetter::new(
        "/tmp/test",
    ));

}

[test]

fn testcustominfo() { let data = vec![ MyData::new("张三", "185xxxx2228", "网金部"), MyData::new("李四", "185xxxx2229", "运管部"), MyData::new("王二", "185xxxx2230", "网金部"), ]; // 只分组导出对应部门xlsx文件,不导出所有数据合并到一个文件的汇总文件 let resp = MyData::write2xlsxgrouponly( &data, ); println!("{resp:#?}"); } ```

3、灵活的自动分组导出和汇总导出数据

4、可实现完全个性化自行控制的行数据写入

如果您的数据并不是一个字段写入一列的,需要合并写入,或者需要自定义单元格样式,可以如下使用:

```rust use xlsxgroupwrite::*; use xlsxgroupwrite::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 LINEWRITERMODEL: XlsxLineWriterModel = XlsxLineWriterModel::Advance; /// 使用xlsx api 写入每行的数据 fn linewriteradvance( &self, sheet: &mut Worksheet, index: u32, ) -> Option { xlsxutil::XlsxWriterTool::setexcelcellvaluenumber(sheet, 1, index, index - 2); xlsxutil::XlsxWriterTool::setexcelcellvaluestr(sheet, 2, index, &self.name); xlsxutil::XlsxWriterTool::setexcelcellvaluestr(sheet, 3, index, &self.tel); xlsxutil::XlsxWriterTool::setexcelcellvaluestr(sheet, 4, index, &self.dep); None } fn gettemplate() -> XlsxInitTemplet { XlsxInitTemplet::newadvance("/home/feiy/Desktop/temp.xlsx", 4) } /// 输出文件位置和文件名称由函数自行控制,比如每个部门文件存放不同的路径中等 fn getoutputfilenameadvance(grouptid: &str) -> String { format!("/tmp/advance-{grouptid}.xlsx") } fn addcustominfotosheet(sheet: &mut Worksheet, groupid: &str) { sheet .getcellmut((&1, &2)) .setvaluestring(&format!("{groupid},报表日期:2023年4月20日")); } }

[test]

fn testadvancewrite() { let data = vec![ MyData3::new("张三", "185xxxx2228", "网金部"), MyData3::new("李四", "185xxxx2229", "运管部"), MyData3::new("王二", "185xxxx2230", "网金部"), ]; let resp = MyData3::write2xlsxmergeonly( &data ); println!("{resp:#?}"); } ```

个性化特性

用法

  1. 添加依赖

``` [dependencies.xlsxgroupwrite] version = "1"

根据需要添加对应特性

feature = ["date","encrypt"] ```

  1. 定义里的导出数据结构,并实现XlsxGroupWrite,并根据需要使用不同的方法和属性

  2. 调用不同的write2xlsx_方法导出数据到xlsx文件。