.NET驾驭Word之力:数据驱动文档 - 邮件合并与自定义数据填充完全指南

你是否曾经需要为数百名员工生成个性化的工资条?你是否希望根据客户信息批量生成合同文档?你是否想要根据数据库中的数据自动生成各类报告?通过本文介绍的邮件合并和自定义数据填充技术,你将能够轻松实现这些功能,大大提高文档处理的效率和准确性。

在实际的企业应用场景中,基于.net平台的 Word 自动化处理技术可以实现:

  • 人力资源管理:批量生成工资条、入职通知书、绩效评估报告等
  • 销售与客户管理:批量生成客户合同、报价单、服务协议等
  • 财务管理:批量生成发票、对账单、财务报告等
  • 行政办公:批量生成各类通知、证书、证明文件等
  • 教育培训:批量生成成绩单、结业证书、培训记录等
  • 法律服务:批量生成法律文书、合同模板、案件报告等

本文将详细介绍如何使用MudTools.OfficeInterop.Word 库来实现传统的邮件合并功能和更灵活的自定义数据填充方案。如何从数据库(SQL Server)、Excel、JSON文件等数据源读取数据,并使用循环和上文技术(书签、查找替换、表格操作)将数据批量填充到Word文档的指定位置。最后,将通过一个实战示例,创建一个批量员工工资条生成系统,真正掌握Word数据交互的精髓。

使用传统的邮件合并功能

邮件合并是Word中最经典的数据交互功能之一,它允许我们将外部数据源(如Excel表格、Access数据库等)与Word文档模板结合,批量生成个性化的文档。

传统的邮件合并功能虽然强大,但在现代应用开发中,我们往往需要更灵活的控制方式。不过,了解邮件合并的基本原理仍然很有价值,因为它为我们理解数据驱动文档的核心概念提供了基础。

传统的邮件合并过程通常包括以下步骤:

  1. 创建包含合并域的主文档(模板)
  2. 准备数据源(如Excel文件或数据库)
  3. 在Word中配置邮件合并向导
  4. 预览并完成合并

虽然MudTools.OfficeInterop.Word库目前没有直接提供邮件合并功能,但我们可以通过自定义数据填充的方式实现更强大、更灵活的功能。

实际业务场景:传统邮件合并的局限性

在许多企业环境中,传统的邮件合并功能虽然能满足基本需求,但在面对复杂业务场景时往往显得力不从心。

场景一:多数据源整合

某大型制造企业需要为供应商生成年度评估报告。这些报告需要整合来自多个系统的数据:

  • ERP系统(供应商基本信息、交易记录)
  • 质量管理系统(质量检测数据)
  • 财务系统(付款记录、信用评级)

传统的邮件合并只能处理单一数据源,无法满足这种多源数据整合的需求。

场景二:动态格式要求

某金融机构需要为客户生成个性化的投资报告。不同类型的客户(个人客户、企业客户、VIP客户)需要不同的报告格式和内容结构。传统的邮件合并只能生成格式固定的文档,无法根据客户类型动态调整文档结构。

场景三:复杂的业务逻辑

某咨询公司需要为不同行业的客户生成市场分析报告。报告内容需要根据客户的行业特点、规模、地理位置等信息应用不同的分析模型和展示方式。传统的邮件合并缺乏处理复杂业务逻辑的能力。

通过自定义数据填充方案,我们可以突破这些限制,实现更智能、更灵活的文档生成系统。

更灵活的方案:自定义数据填充

自定义数据填充是一种比传统邮件合并更灵活、更可控的数据交互方案。通过这种方式,我们可以从各种数据源读取数据,并精确控制数据在文档中的填充位置和格式。

从数据库(SQL Server)、Excel、JSON文件等数据源读取数据

在实际应用中,数据可能来自各种不同的源,包括关系型数据库、Excel文件、JSON数据等。我们需要能够灵活地处理这些不同的数据源。

csharp 复制代码
using MudTools.OfficeInterop;
using MudTools.OfficeInterop.Word;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using Newtonsoft.Json;

// 数据模型
public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Department { get; set; }
    public decimal Salary { get; set; }
    public decimal Bonus { get; set; }
    public DateTime HireDate { get; set; }
}

// 数据访问服务
public class DataService
{
    /// <summary>
    /// 从SQL Server数据库读取员工数据
    /// </summary>
    /// <param name="connectionString">数据库连接字符串</param>
    /// <returns>员工数据列表</returns>
    public List<Employee> GetEmployeesFromDatabase(string connectionString)
    {
        var employees = new List<Employee>();
        
        try
        {
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
                var command = new SqlCommand("SELECT Id, Name, Department, Salary, Bonus, HireDate FROM Employees", connection);
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        employees.Add(new Employee
                        {
                            Id = reader.GetInt32("Id"),
                            Name = reader.GetString("Name"),
                            Department = reader.GetString("Department"),
                            Salary = reader.GetDecimal("Salary"),
                            Bonus = reader.GetDecimal("Bonus"),
                            HireDate = reader.GetDateTime("HireDate")
                        });
                    }
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"从数据库读取员工数据时发生错误: {ex.Message}");
        }
        
        return employees;
    }
    
    /// <summary>
    /// 从Excel文件读取员工数据
    /// </summary>
    /// <param name="excelFilePath">Excel文件路径</param>
    /// <returns>员工数据列表</returns>
    public List<Employee> GetEmployeesFromExcel(string excelFilePath)
    {
        var employees = new List<Employee>();
        
        try
        {
            // 这里应该使用适当的Excel读取库,如EPPlus或NPOI
            // 为简化示例,我们直接返回模拟数据
            employees.Add(new Employee
            {
                Id = 1,
                Name = "张三",
                Department = "技术部",
                Salary = 15000,
                Bonus = 3000,
                HireDate = new DateTime(2020, 1, 15)
            });
            
            employees.Add(new Employee
            {
                Id = 2,
                Name = "李四",
                Department = "销售部",
                Salary = 12000,
                Bonus = 5000,
                HireDate = new DateTime(2019, 3, 22)
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"从Excel文件读取员工数据时发生错误: {ex.Message}");
        }
        
        return employees;
    }
    
    /// <summary>
    /// 从JSON文件读取员工数据
    /// </summary>
    /// <param name="jsonFilePath">JSON文件路径</param>
    /// <returns>员工数据列表</returns>
    public List<Employee> GetEmployeesFromJson(string jsonFilePath)
    {
        var employees = new List<Employee>();
        
        try
        {
            if (File.Exists(jsonFilePath))
            {
                var jsonContent = File.ReadAllText(jsonFilePath);
                employees = JsonConvert.DeserializeObject<List<Employee>>(jsonContent);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"从JSON文件读取员工数据时发生错误: {ex.Message}");
        }
        
        return employees;
    }
}

应用场景:多数据源集成处理与复杂业务逻辑实现

在现代企业运营中,数据孤岛现象普遍存在,关键信息分散在HR系统、财务系统、CRM系统、ERP系统等多个独立平台中。传统的邮件合并功能只能处理单一数据源,而自定义数据填充方案则能够打破这些壁垒,实现跨系统的数据整合与智能处理。

csharp 复制代码
using MudTools.OfficeInterop;
using MudTools.OfficeInterop.Word;
using System;
using System.Collections.Generic;

// 综合数据服务
public class ComprehensiveDataService
{
    private readonly DataService _dataService;
    
    public ComprehensiveDataService()
    {
        _dataService = new DataService();
    }
    
    /// <summary>
    /// 获取综合员工数据
    /// </summary>
    /// <returns>综合员工数据列表</returns>
    public List<ComprehensiveEmployeeData> GetComprehensiveEmployeeData()
    {
        var comprehensiveDataList = new List<ComprehensiveEmployeeData>();
        
        try
        {
            // 从不同数据源获取数据
            var hrEmployees = _dataService.GetEmployeesFromDatabase("HR数据库连接字符串");
            // var financeData = _dataService.GetEmployeesFromExcel("财务数据Excel路径");
            // var projectData = _dataService.GetEmployeesFromJson("项目数据JSON路径");
            
            // 整合数据
            foreach (var employee in hrEmployees)
            {
                var comprehensiveData = new ComprehensiveEmployeeData
                {
                    Id = employee.Id,
                    Name = employee.Name,
                    Department = employee.Department,
                    Salary = employee.Salary,
                    Bonus = employee.Bonus,
                    HireDate = employee.HireDate,
                    // 这里可以添加从其他数据源获取的信息
                    PerformanceRating = CalculatePerformanceRating(employee),
                    ProjectsCompleted = GetProjectsCompleted(employee.Id)
                };
                
                comprehensiveDataList.Add(comprehensiveData);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取综合员工数据时发生错误: {ex.Message}");
        }
        
        return comprehensiveDataList;
    }
    
    /// <summary>
    /// 计算绩效评级
    /// </summary>
    /// <param name="employee">员工信息</param>
    /// <returns>绩效评级</returns>
    private string CalculatePerformanceRating(Employee employee)
    {
        // 简化的绩效评级计算逻辑
        if (employee.Salary > 15000)
            return "优秀";
        else if (employee.Salary > 10000)
            return "良好";
        else
            return "合格";
    }
    
    /// <summary>
    /// 获取完成的项目数量
    /// </summary>
    /// <param name="employeeId">员工ID</param>
    /// <returns>完成的项目数量</returns>
    private int GetProjectsCompleted(int employeeId)
    {
        // 模拟数据
        return employeeId switch
        {
            1 => 5,
            2 => 3,
            _ => 0
        };
    }
}

/// <summary>
/// 综合员工数据模型
/// </summary>
public class ComprehensiveEmployeeData
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Department { get; set; }
    public decimal Salary { get; set; }
    public decimal Bonus { get; set; }
    public DateTime HireDate { get; set; }
    public string PerformanceRating { get; set; }
    public int ProjectsCompleted { get; set; }
    
    /// <summary>
    /// 获取总收入(薪资+奖金)
    /// </summary>
    public decimal TotalIncome => Salary + Bonus;
    
    /// <summary>
    /// 获取工作年限
    /// </summary>
    public int YearsOfService => DateTime.Now.Year - HireDate.Year;
}

使用循环和上文技术(书签、查找替换、表格操作)将数据批量填充到Word文档的指定位置

有了数据源之后,我们需要将数据填充到Word文档中。通过结合循环和之前学习的技术(书签、查找替换、表格操作),我们可以实现灵活的数据填充。

csharp 复制代码
using MudTools.OfficeInterop;
using MudTools.OfficeInterop.Word;
using System;
using System.Collections.Generic;

// 文档生成服务
public class DocumentGenerationService
{
    /// <summary>
    /// 生成员工工资条
    /// </summary>
    /// <param name="templatePath">模板路径</param>
    /// <param name="outputDirectory">输出目录</param>
    /// <param name="employees">员工数据列表</param>
    public void GeneratePaySlips(string templatePath, string outputDirectory, List<Employee> employees)
    {
        foreach (var employee in employees)
        {
            try
            {
                // 基于模板创建新文档
                using var wordApp = WordFactory.CreateFrom(templatePath);
                var document = wordApp.ActiveDocument;
                
                // 隐藏Word应用程序以提高性能
                wordApp.Visibility = WordAppVisibility.Hidden;
                wordApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
                
                // 使用书签填充数据
                FillDataUsingBookmarks(document, employee);
                
                // 生成文件名
                string fileName = $"工资条_{employee.Name}_{DateTime.Now:yyyyMM}.docx";
                string outputPath = Path.Combine(outputDirectory, fileName);
                
                // 保存文档
                document.SaveAs(outputPath, WdSaveFormat.wdFormatXMLDocument);
                document.Close();
                
                Console.WriteLine($"已生成工资条: {fileName}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"为员工 {employee.Name} 生成工资条时发生错误: {ex.Message}");
            }
        }
    }
    
    /// <summary>
    /// 使用书签填充数据
    /// </summary>
    /// <param name="document">Word文档</param>
    /// <param name="employee">员工数据</param>
    private void FillDataUsingBookmarks(IWordDocument document, Employee employee)
    {
        // 填充基本信息
        SetBookmarkText(document, "EmployeeName", employee.Name);
        SetBookmarkText(document, "EmployeeId", employee.Id.ToString());
        SetBookmarkText(document, "Department", employee.Department);
        SetBookmarkText(document, "PayPeriod", DateTime.Now.ToString("yyyy年MM月"));
        
        // 填充薪资信息
        SetBookmarkText(document, "BaseSalary", employee.Salary.ToString("C"));
        SetBookmarkText(document, "Bonus", employee.Bonus.ToString("C"));
        SetBookmarkText(document, "TotalIncome", (employee.Salary + employee.Bonus).ToString("C"));
        SetBookmarkText(document, "Deductions", "0.00");
        SetBookmarkText(document, "NetPay", (employee.Salary + employee.Bonus).ToString("C"));
        
        // 填充日期信息
        SetBookmarkText(document, "PayDate", DateTime.Now.ToString("yyyy年MM月dd日"));
        SetBookmarkText(document, "HireDate", employee.HireDate.ToString("yyyy年MM月dd日"));
    }
    
    /// <summary>
    /// 设置书签文本
    /// </summary>
    /// <param name="document">Word文档</param>
    /// <param name="bookmarkName">书签名称</param>
    /// <param name="text">文本内容</param>
    private void SetBookmarkText(IWordDocument document, string bookmarkName, string text)
    {
        try
        {
            var bookmark = document.Bookmarks[bookmarkName];
            if (bookmark != null)
            {
                bookmark.Range.Text = text;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"设置书签 {bookmarkName} 文本时发生错误: {ex.Message}");
        }
    }
    
    /// <summary>
    /// 使用查找替换填充数据
    /// </summary>
    /// <param name="document">Word文档</param>
    /// <param name="employee">员工数据</param>
    private void FillDataUsingFindReplace(IWordDocument document, Employee employee)
    {
        // 使用查找替换填充数据
        document.FindAndReplace("[员工姓名]", employee.Name);
        document.FindAndReplace("[员工编号]", employee.Id.ToString());
        document.FindAndReplace("[部门]", employee.Department);
        document.FindAndReplace("[薪资月份]", DateTime.Now.ToString("yyyy年MM月"));
        document.FindAndReplace("[基本工资]", employee.Salary.ToString("C"));
        document.FindAndReplace("[奖金]", employee.Bonus.ToString("C"));
        document.FindAndReplace("[总收入]", (employee.Salary + employee.Bonus).ToString("C"));
        document.FindAndReplace("[扣除项]", "0.00");
        document.FindAndReplace("[实发工资]", (employee.Salary + employee.Bonus).ToString("C"));
        document.FindAndReplace("[发放日期]", DateTime.Now.ToString("yyyy年MM月dd日"));
        document.FindAndReplace("[入职日期]", employee.HireDate.ToString("yyyy年MM月dd日"));
    }
}

应用场景:复杂企业级批量文档生成系统

在现代企业运营中,文档自动化处理已成为提升效率、确保合规性和改善客户体验的关键环节。通过结合循环和上文技术(书签、查找替换、表格操作),我们能够构建一个功能强大、灵活可扩展的企业级批量文档生成系统,满足各种复杂的业务需求。

特别值得一提的是,还可以集成SemanticKernel、ML.Net实现以下AI能力:

  • 使用自然语言处理技术,自动生成个性化的绩效评语和职业发展建议
  • 通过机器学习分析历史数据,预测可能的薪酬纠纷并提前预警
  • 利用光学字符识别(OCR)技术,自动解析纸质文档并将其纳入数字工作流
csharp 复制代码
// 批量文档生成系统
public class BatchDocumentGenerationSystem
{
    private readonly DataService _dataService;
    private readonly DocumentGenerationService _documentService;
    
    public BatchDocumentGenerationSystem()
    {
        _dataService = new DataService();
        _documentService = new DocumentGenerationService();
    }
    
    /// <summary>
    /// 批量生成员工工资条
    /// </summary>
    /// <param name="templatePath">模板路径</param>
    /// <param name="outputDirectory">输出目录</param>
    /// <param name="dataSourceType">数据源类型</param>
    /// <param name="dataSourcePath">数据源路径</param>
    public void BatchGeneratePaySlips(string templatePath, string outputDirectory, 
        DataSourceType dataSourceType, string dataSourcePath)
    {
        try
        {
            // 确保输出目录存在
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }
            
            // 根据数据源类型获取员工数据
            List<Employee> employees = dataSourceType switch
            {
                DataSourceType.Database => _dataService.GetEmployeesFromDatabase(dataSourcePath),
                DataSourceType.Excel => _dataService.GetEmployeesFromExcel(dataSourcePath),
                DataSourceType.Json => _dataService.GetEmployeesFromJson(dataSourcePath),
                _ => throw new ArgumentException("不支持的数据源类型")
            };
            
            Console.WriteLine($"从{dataSourceType}数据源获取到 {employees.Count} 名员工的数据");
            
            // 生成工资条
            _documentService.GeneratePaySlips(templatePath, outputDirectory, employees);
            
            Console.WriteLine($"批量工资条生成完成,共生成 {employees.Count} 份工资条");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"批量生成工资条时发生错误: {ex.Message}");
        }
    }
    
    /// <summary>
    /// 批量生成客户合同
    /// </summary>
    /// <param name="templatePath">模板路径</param>
    /// <param name="outputDirectory">输出目录</param>
    /// <param name="customers">客户数据列表</param>
    public void BatchGenerateContracts(string templatePath, string outputDirectory, List<Customer> customers)
    {
        try
        {
            // 确保输出目录存在
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }
            
            foreach (var customer in customers)
            {
                try
                {
                    // 基于模板创建新文档
                    using var wordApp = WordFactory.CreateFrom(templatePath);
                    var document = wordApp.ActiveDocument;
                    
                    // 隐藏Word应用程序以提高性能
                    wordApp.Visibility = WordAppVisibility.Hidden;
                    wordApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
                    
                    // 填充客户数据
                    FillCustomerContractData(document, customer);
                    
                    // 生成文件名
                    string fileName = $"合同_{customer.Name}_{DateTime.Now:yyyyMMdd}.docx";
                    string outputPath = Path.Combine(outputDirectory, fileName);
                    
                    // 保存文档
                    document.SaveAs(outputPath, WdSaveFormat.wdFormatXMLDocument);
                    document.Close();
                    
                    Console.WriteLine($"已生成合同: {fileName}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"为客户 {customer.Name} 生成合同时发生错误: {ex.Message}");
                }
            }
            
            Console.WriteLine($"批量合同生成完成,共生成 {customers.Count} 份合同");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"批量生成合同时发生错误: {ex.Message}");
        }
    }
    
    /// <summary>
    /// 填充客户合同数据
    /// </summary>
    /// <param name="document">Word文档</param>
    /// <param name="customer">客户数据</param>
    private void FillCustomerContractData(IWordDocument document, Customer customer)
    {
        // 使用书签填充数据
        SetBookmarkText(document, "CustomerName", customer.Name);
        SetBookmarkText(document, "CustomerAddress", customer.Address);
        SetBookmarkText(document, "CustomerPhone", customer.Phone);
        SetBookmarkText(document, "ContractDate", DateTime.Now.ToString("yyyy年MM月dd日"));
        SetBookmarkText(document, "ContractAmount", customer.ContractAmount.ToString("C"));
        SetBookmarkText(document, "ServiceDescription", customer.ServiceDescription);
        SetBookmarkText(document, "ContractTerm", customer.ContractTerm);
    }
    
    /// <summary>
    /// 设置书签文本
    /// </summary>
    /// <param name="document">Word文档</param>
    /// <param name="bookmarkName">书签名称</param>
    /// <param name="text">文本内容</param>
    private void SetBookmarkText(IWordDocument document, string bookmarkName, string text)
    {
        try
        {
            var bookmark = document.Bookmarks[bookmarkName];
            if (bookmark != null)
            {
                bookmark.Range.Text = text;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"设置书签 {bookmarkName} 文本时发生错误: {ex.Message}");
        }
    }
}

/// <summary>
/// 数据源类型枚举
/// </summary>
public enum DataSourceType
{
    Database,
    Excel,
    Json
}

/// <summary>
/// 客户数据模型
/// </summary>
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
    public decimal ContractAmount { get; set; }
    public string ServiceDescription { get; set; }
    public string ContractTerm { get; set; }
}

实战:生成批量员工工资条或客户合同

创建一个完整的批量文档生成系统,展示如何实现数据驱动的文档处理。

创建工资条模板

创建一个工资条模板,其中包含用于数据填充的书签。

csharp 复制代码
// 工资条模板创建器
public class PaySlipTemplateCreator
{
    /// <summary>
    /// 创建工资条模板
    /// </summary>
    /// <param name="templatePath">模板保存路径</param>
    public void CreatePaySlipTemplate(string templatePath)
    {
        try
        {
            // 创建新文档
            using var wordApp = WordFactory.BlankWorkbook();
            var document = wordApp.ActiveDocument;
            
            // 隐藏Word应用程序以提高性能
            wordApp.Visibility = WordAppVisibility.Hidden;
            wordApp.DisplayAlerts = WdAlertLevel.wdAlertsNone;
            
            // 设置文档格式
            SetupDocumentFormat(document);
            
            // 添加模板内容
            AddTemplateContent(document);
            
            // 添加书签
            AddBookmarks(document);
            
            // 保存为模板
            document.SaveAs(templatePath, WdSaveFormat.wdFormatXMLTemplate);
            document.Close();
            
            Console.WriteLine($"工资条模板已创建: {templatePath}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"创建工资条模板时发生错误: {ex.Message}");
        }
    }
    
    /// <summary>
    /// 设置文档格式
    /// </summary>
    /// <param name="document">Word文档</param>
    private void SetupDocumentFormat(IWordDocument document)
    {
        // 设置页面格式
        foreach (IWordSection section in document.Sections)
        {
            var pageSetup = section.PageSetup;
            pageSetup.PaperSize = WdPaperSize.wdPaperA4;
            pageSetup.Orientation = WdOrientation.wdOrientPortrait;
            pageSetup.TopMargin = 36;  // 0.5英寸
            pageSetup.BottomMargin = 36;
            pageSetup.LeftMargin = 36;
            pageSetup.RightMargin = 36;
        }
    }
    
    /// <summary>
    /// 添加模板内容
    /// </summary>
    /// <param name="document">Word文档</param>
    private void AddTemplateContent(IWordDocument document)
    {
        var content = document.Content;
        
        // 添加标题
        content.Text = "员工工资条\n\n";
        content.Font.Name = "微软雅黑";
        content.Font.Size = 16;
        content.Font.Bold = true;
        content.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphCenter;
        
        // 添加基本信息表格
        var infoRange = content.Duplicate;
        infoRange.Collapse(WdCollapseDirection.wdCollapseEnd);
        infoRange.Text = "基本信息\n";
        infoRange.Font.Size = 12;
        infoRange.Font.Bold = true;
        infoRange.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphLeft;
        
        // 创建基本信息表格(3行4列)
        var infoTable = document.Tables.Add(infoRange, 3, 4);
        infoTable.Borders.Enable = 1;
        infoTable.AllowAutoFit = true;
        
        // 设置表头
        infoTable.Cell(1, 1).Range.Text = "员工姓名";
        infoTable.Cell(1, 2).Range.Text = "[员工姓名]";
        infoTable.Cell(1, 3).Range.Text = "员工编号";
        infoTable.Cell(1, 4).Range.Text = "[员工编号]";
        
        infoTable.Cell(2, 1).Range.Text = "部门";
        infoTable.Cell(2, 2).Range.Text = "[部门]";
        infoTable.Cell(2, 3).Range.Text = "薪资月份";
        infoTable.Cell(2, 4).Range.Text = "[薪资月份]";
        
        infoTable.Cell(3, 1).Range.Text = "入职日期";
        infoTable.Cell(3, 2).Range.Text = "[入职日期]";
        infoTable.Cell(3, 3).Range.Text = "发放日期";
        infoTable.Cell(3, 4).Range.Text = "[发放日期]";
        
        // 添加薪资明细
        var salaryRange = infoRange.Duplicate;
        salaryRange.Collapse(WdCollapseDirection.wdCollapseEnd);
        salaryRange.Text = "\n薪资明细\n";
        salaryRange.Font.Size = 12;
        salaryRange.Font.Bold = true;
        salaryRange.ParagraphFormat.Alignment = WdParagraphAlignment.wdAlignParagraphLeft;
        
        // 创建薪资明细表格(4行2列)
        var salaryTable = document.Tables.Add(salaryRange, 4, 2);
        salaryTable.Borders.Enable = 1;
        salaryTable.AllowAutoFit = true;
        
        // 设置表头
        salaryTable.Cell(1, 1).Range.Text = "项目";
        salaryTable.Cell(1, 2).Range.Text = "金额";
        
        salaryTable.Cell(2, 1).Range.Text = "基本工资";
        salaryTable.Cell(2, 2).Range.Text = "[基本工资]";
        
        salaryTable.Cell(3, 1).Range.Text = "奖金";
        salaryTable.Cell(3, 2).Range.Text = "[奖金]";
        
        salaryTable.Cell(4, 1).Range.Text = "总收入";
        salaryTable.Cell(4, 2).Range.Text = "[总收入]";
        
        // 添加扣除项和实发工资
        var deductionRange = salaryRange.Duplicate;
        deductionRange.Collapse(WdCollapseDirection.wdCollapseEnd);
        deductionRange.Text = "\n";
        
        // 创建扣除项表格(3行2列)
        var deductionTable = document.Tables.Add(deductionRange, 3, 2);
        deductionTable.Borders.Enable = 1;
        deductionTable.AllowAutoFit = true;
        
        deductionTable.Cell(1, 1).Range.Text = "扣除项";
        deductionTable.Cell(1, 2).Range.Text = "[扣除项]";
        
        deductionTable.Cell(2, 1).Range.Text = "实发工资";
        deductionTable.Cell(2, 2).Range.Text = "[实发工资]";
        
        deductionTable.Cell(3, 1).Range.Text = "大写金额";
        deductionTable.Cell(3, 2).Range.Text = "人民币[大写实发工资]";
    }
    
    /// <summary>
    /// 添加书签
    /// </summary>
    /// <param name="document">Word文档</param>
    private void AddBookmarks(IWordDocument document)
    {
        // 定义书签映射
        var bookmarkMappings = new Dictionary<string, string>
        {
            { "EmployeeName", "[员工姓名]" },
            { "EmployeeId", "[员工编号]" },
            { "Department", "[部门]" },
            { "PayPeriod", "[薪资月份]" },
            { "HireDate", "[入职日期]" },
            { "PayDate", "[发放日期]" },
            { "BaseSalary", "[基本工资]" },
            { "Bonus", "[奖金]" },
            { "TotalIncome", "[总收入]" },
            { "Deductions", "[扣除项]" },
            { "NetPay", "[实发工资]" }
        };
        
        // 为每个占位符添加书签
        foreach (var mapping in bookmarkMappings)
        {
            AddBookmarkToPlaceholder(document, mapping.Key, mapping.Value);
        }
    }
    
    /// <summary>
    /// 为占位符添加书签
    /// </summary>
    /// <param name="document">Word文档</param>
    /// <param name="bookmarkName">书签名称</param>
    /// <param name="placeholder">占位符文本</param>
    private void AddBookmarkToPlaceholder(IWordDocument document, string bookmarkName, string placeholder)
    {
        try
        {
            var range = document.Content.Duplicate;
            if (range.FindAndReplace(placeholder, "") > 0)
            {
                document.Bookmarks.Add(bookmarkName, range);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"为占位符 {placeholder} 添加书签时发生错误: {ex.Message}");
        }
    }
}

完整的工资条生成系统

创建一个完整的工资条生成系统,整合数据读取、模板创建和文档生成功能。

csharp 复制代码
using MudTools.OfficeInterop;
using MudTools.OfficeInterop.Word;
using System;
using System.Collections.Generic;
using System.IO;

// 完整的工资条生成系统
public class CompletePaySlipGenerationSystem
{
    private readonly DataService _dataService;
    private readonly PaySlipTemplateCreator _templateCreator;
    private readonly DocumentGenerationService _documentService;
    
    public CompletePaySlipGenerationSystem()
    {
        _dataService = new DataService();
        _templateCreator = new PaySlipTemplateCreator();
        _documentService = new DocumentGenerationService();
    }
    
    /// <summary>
    /// 运行完整的工资条生成流程
    /// </summary>
    /// <param name="dataSourceType">数据源类型</param>
    /// <param name="dataSourcePath">数据源路径</param>
    /// <param name="outputDirectory">输出目录</param>
    public void RunPaySlipGenerationProcess(DataSourceType dataSourceType, string dataSourcePath, string outputDirectory)
    {
        try
        {
            Console.WriteLine("开始工资条生成流程...");
            
            // 1. 创建模板(如果不存在)
            string templatePath = Path.Combine(outputDirectory, "工资条模板.dotx");
            if (!File.Exists(templatePath))
            {
                _templateCreator.CreatePaySlipTemplate(templatePath);
            }
            
            // 2. 从数据源获取员工数据
            List<Employee> employees = GetEmployeeData(dataSourceType, dataSourcePath);
            if (employees == null || employees.Count == 0)
            {
                Console.WriteLine("未获取到员工数据,流程终止");
                return;
            }
            
            Console.WriteLine($"成功获取 {employees.Count} 名员工的数据");
            
            // 3. 生成工资条
            _documentService.GeneratePaySlips(templatePath, outputDirectory, employees);
            
            Console.WriteLine($"工资条生成流程完成,共生成 {employees.Count} 份工资条");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"运行工资条生成流程时发生错误: {ex.Message}");
        }
    }
    
    /// <summary>
    /// 获取员工数据
    /// </summary>
    /// <param name="dataSourceType">数据源类型</param>
    /// <param name="dataSourcePath">数据源路径</param>
    /// <returns>员工数据列表</returns>
    private List<Employee> GetEmployeeData(DataSourceType dataSourceType, string dataSourcePath)
    {
        try
        {
            return dataSourceType switch
            {
                DataSourceType.Database => _dataService.GetEmployeesFromDatabase(dataSourcePath),
                DataSourceType.Excel => _dataService.GetEmployeesFromExcel(dataSourcePath),
                DataSourceType.Json => _dataService.GetEmployeesFromJson(dataSourcePath),
                _ => throw new ArgumentException("不支持的数据源类型")
            };
        }
        catch (Exception ex)
        {
            Console.WriteLine($"获取员工数据时发生错误: {ex.Message}");
            return new List<Employee>();
        }
    }
    
    /// <summary>
    /// 创建示例数据文件
    /// </summary>
    /// <param name="outputDirectory">输出目录</param>
    public void CreateSampleDataFiles(string outputDirectory)
    {
        try
        {
            // 创建示例JSON数据文件
            var sampleEmployees = new List<Employee>
            {
                new Employee
                {
                    Id = 1001,
                    Name = "张三",
                    Department = "技术部",
                    Salary = 15000,
                    Bonus = 3000,
                    HireDate = new DateTime(2020, 1, 15)
                },
                new Employee
                {
                    Id = 1002,
                    Name = "李四",
                    Department = "销售部",
                    Salary = 12000,
                    Bonus = 5000,
                    HireDate = new DateTime(2019, 3, 22)
                },
                new Employee
                {
                    Id = 1003,
                    Name = "王五",
                    Department = "人事部",
                    Salary = 10000,
                    Bonus = 2000,
                    HireDate = new DateTime(2021, 5, 10)
                }
            };
            
            // 保存为JSON文件
            string jsonPath = Path.Combine(outputDirectory, "员工数据.json");
            var jsonContent = Newtonsoft.Json.JsonConvert.SerializeObject(sampleEmployees, Newtonsoft.Json.Formatting.Indented);
            File.WriteAllText(jsonPath, jsonContent);
            
            Console.WriteLine($"示例数据文件已创建: {jsonPath}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"创建示例数据文件时发生错误: {ex.Message}");
        }
    }
}

// 使用示例
class Program
{
    static void Main(string[] args)
    {
        var paySlipSystem = new CompletePaySlipGenerationSystem();
        
        // 创建输出目录
        string outputDirectory = @"C:\PaySlips";
        if (!Directory.Exists(outputDirectory))
        {
            Directory.CreateDirectory(outputDirectory);
        }
        
        // 创建示例数据文件
        paySlipSystem.CreateSampleDataFiles(outputDirectory);
        
        // 运行工资条生成流程
        string jsonPath = Path.Combine(outputDirectory, "员工数据.json");
        paySlipSystem.RunPaySlipGenerationProcess(DataSourceType.Json, jsonPath, outputDirectory);
        
        Console.WriteLine("工资条生成系统运行完成!");
    }
}

总结

使用MudTools.OfficeInterop.Word库实现数据驱动的文档处理,包括传统的邮件合并功能简介和更灵活的自定义数据填充方案:

  1. 传统邮件合并功能:虽然库中未直接提供,但理解其原理有助于我们设计更好的自定义方案

  2. 自定义数据填充方案

    • 从数据库(SQL Server)、Excel、JSON文件等数据源读取数据
    • 使用循环和上文技术(书签、查找替换、表格操作)将数据批量填充到Word文档的指定位置

通过实战示例,创建了一个完整的批量员工工资条生成系统,展示了这些功能在实际工作中的强大应用。这些技能在实际工作中非常有用,能够大大提高文档处理的效率和质量。

掌握了这些技巧后,将能够:

  • 快速批量生成个性化文档,节省大量人工处理时间
  • 整合来自不同数据源的信息,创建综合性的报告文档
  • 实现真正的数据驱动文档生成,确保内容的准确性和一致性
  • 构建企业级的文档自动化系统,提升整体办公效率
相关推荐
心疼你的一切5 小时前
使用Unity引擎开发Rokid主机应用的全面配置交互操作
学习·游戏·unity·c#·游戏引擎·交互
椒颜皮皮虾྅12 小时前
【DeploySharp 】基于DeploySharp 的深度学习模型部署测试平台:安装和使用流程
人工智能·深度学习·开源·c#·openvino
追逐时光者14 小时前
一个基于 ASP.NET Core 的开源、模块化、多租户应用框架和内容管理系统
后端·.net
kalvin_y_liu19 小时前
【MES架构师与C#高级工程师(设备控制方向)两大职业路径的技术】
开发语言·职场和发展·c#·mes
椒颜皮皮虾20 小时前
基于DeploySharp 的深度学习模型部署测试平台:支持YOLO全系列模型
c#
李宥小哥2 天前
C#基础10-结构体和枚举
java·开发语言·c#
SEO-狼术2 天前
.NET WPF 数据编辑器集合提供列表框控件
.net·wpf
SEO-狼术2 天前
Oxygen AI Positron Assistant Enterprise
人工智能·.net
揭老师高效办公2 天前
Word和WPS文字如何从特定的页开始编号(页码)?
word·wps