mirror of
https://github.com/ZeroHawkeye/wordZero.git
synced 2025-10-06 00:06:55 +08:00
更新README.md,完善表格操作功能。
This commit is contained in:
599
README.md
599
README.md
@@ -18,6 +18,59 @@ WordZero 是一个使用 Golang 实现的 Word 文档操作库,提供基础的
|
|||||||
- ⚡ **高性能**: 零依赖的纯Go实现,内存占用低
|
- ⚡ **高性能**: 零依赖的纯Go实现,内存占用低
|
||||||
- 🔧 **易于使用**: 简洁的API设计,链式调用支持
|
- 🔧 **易于使用**: 简洁的API设计,链式调用支持
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/ZeroHawkeye/wordZero
|
||||||
|
```
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
wordZero/
|
||||||
|
├── pkg/ # 公共包
|
||||||
|
│ ├── document/ # 文档核心操作
|
||||||
|
│ │ ├── document.go # 主要文档操作API
|
||||||
|
│ │ ├── table.go # 表格操作功能
|
||||||
|
│ │ ├── errors.go # 错误定义和处理
|
||||||
|
│ │ ├── logger.go # 日志系统
|
||||||
|
│ │ ├── doc.go # 包文档
|
||||||
|
│ │ ├── document_test.go # 文档操作单元测试
|
||||||
|
│ │ └── table_test.go # 表格功能单元测试
|
||||||
|
│ └── style/ # 样式管理系统
|
||||||
|
│ ├── style.go # 样式核心定义
|
||||||
|
│ ├── api.go # 快速API接口
|
||||||
|
│ ├── predefined.go # 预定义样式常量
|
||||||
|
│ ├── api_test.go # API测试
|
||||||
|
│ ├── style_test.go # 样式系统测试
|
||||||
|
│ └── README.md # 样式系统详细文档
|
||||||
|
├── examples/ # 使用示例
|
||||||
|
│ ├── basic/ # 基础功能示例
|
||||||
|
│ │ └── basic_example.go
|
||||||
|
│ ├── formatting/ # 格式化示例
|
||||||
|
│ │ └── text_formatting_example.go
|
||||||
|
│ ├── style_demo/ # 样式系统演示
|
||||||
|
│ │ └── style_demo.go
|
||||||
|
│ ├── table/ # 表格功能示例
|
||||||
|
│ │ └── table_example.go
|
||||||
|
│ ├── table_layout/ # 表格布局和尺寸示例
|
||||||
|
│ │ └── main.go
|
||||||
|
│ ├── table_style/ # 表格样式和外观示例
|
||||||
|
│ │ └── main.go
|
||||||
|
│ ├── cell_advanced/ # 单元格高级功能示例
|
||||||
|
│ │ └── main.go
|
||||||
|
│ ├── basic_usage.go # 基础使用示例
|
||||||
|
│ └── output/ # 示例输出文件目录
|
||||||
|
├── test/ # 集成测试文件
|
||||||
|
│ ├── document_test.go # 文档操作集成测试
|
||||||
|
│ ├── text_formatting_test.go # 文本格式化集成测试
|
||||||
|
│ └── table_style_test.go # 表格样式功能集成测试
|
||||||
|
├── .gitignore # Git忽略文件配置
|
||||||
|
├── go.mod # Go模块定义
|
||||||
|
├── LICENSE # MIT许可证
|
||||||
|
└── README.md # 项目说明文档
|
||||||
|
```
|
||||||
|
|
||||||
## 功能特性
|
## 功能特性
|
||||||
|
|
||||||
### ✅ 已实现功能
|
### ✅ 已实现功能
|
||||||
@@ -53,8 +106,6 @@ WordZero 是一个使用 Golang 实现的 Word 文档操作库,提供基础的
|
|||||||
|
|
||||||
> **样式数量说明:** 系统内置18个预定义样式(15个段落样式 + 3个字符样式)。演示程序中显示的21个样式是因为动态创建了3个自定义样式进行功能展示。
|
> **样式数量说明:** 系统内置18个预定义样式(15个段落样式 + 3个字符样式)。演示程序中显示的21个样式是因为动态创建了3个自定义样式进行功能展示。
|
||||||
|
|
||||||
### 🚧 规划中功能
|
|
||||||
|
|
||||||
#### 表格功能
|
#### 表格功能
|
||||||
|
|
||||||
##### 表格基础操作
|
##### 表格基础操作
|
||||||
@@ -85,52 +136,63 @@ WordZero 是一个使用 Golang 实现的 Word 文档操作库,提供基础的
|
|||||||
- [x] 单元格文字方向和旋转
|
- [x] 单元格文字方向和旋转
|
||||||
- [x] 单元格内边距设置
|
- [x] 单元格内边距设置
|
||||||
|
|
||||||
##### 表格样式和外观
|
|
||||||
- [ ] 表格整体样式
|
|
||||||
- [ ] 预定义表格样式模板
|
|
||||||
- [ ] 自定义表格样式创建
|
|
||||||
- [ ] 表格主题色彩应用
|
|
||||||
- [ ] 表格样式继承和覆盖
|
|
||||||
- [ ] 表格边框设置
|
|
||||||
- [ ] 外边框样式(线型、颜色、粗细)
|
|
||||||
- [ ] 内边框样式(网格线设置)
|
|
||||||
- [ ] 单元格边框独立设置
|
|
||||||
- [ ] 边框部分应用(顶部、底部、左右)
|
|
||||||
- [ ] 无边框表格支持
|
|
||||||
- [ ] 表格背景和填充
|
|
||||||
- [ ] 表格背景色设置
|
|
||||||
- [ ] 单元格背景色设置
|
|
||||||
- [ ] 奇偶行颜色交替
|
|
||||||
- [ ] 渐变背景支持(基础渐变)
|
|
||||||
- [ ] 图案填充支持
|
|
||||||
|
|
||||||
##### 表格布局和尺寸
|
##### 表格布局和尺寸
|
||||||
- [x] 表格尺寸控制
|
- [x] 表格尺寸控制
|
||||||
- [x] 表格总宽度设置(固定宽度、相对宽度、自动宽度)
|
- [x] 表格总宽度设置(固定宽度、相对宽度、自动宽度)
|
||||||
- [x] 列宽设置(固定宽度、相对宽度、自动调整)
|
- [x] 列宽设置(固定宽度、相对宽度、自动调整)
|
||||||
- [ ] 行高设置(固定高度、最小高度、自动调整)
|
- [x] 行高设置(固定高度、最小高度、自动调整)
|
||||||
- [x] 单元格尺寸精确控制
|
- [x] 单元格尺寸精确控制
|
||||||
- [ ] 表格对齐和定位
|
- [x] 表格对齐和定位
|
||||||
- [x] 表格页面对齐(左对齐、居中、右对齐)
|
- [x] 表格页面对齐(左对齐、居中、右对齐)
|
||||||
- [ ] 表格文字环绕设置
|
- [x] 表格文字环绕设置
|
||||||
- [ ] 表格相对定位
|
- [x] 表格相对定位
|
||||||
- [ ] 表格分页控制
|
- [x] 表格分页控制
|
||||||
- [ ] 表格跨页处理
|
- [x] 表格跨页处理
|
||||||
- [ ] 标题行重复显示
|
- [x] 标题行重复显示
|
||||||
- [ ] 表格分页符控制
|
- [x] 表格分页符控制
|
||||||
- [ ] 避免分页的行设置
|
- [x] 避免分页的行设置
|
||||||
|
|
||||||
##### 表格数据处理
|
##### 表格数据处理
|
||||||
- [x] 数据导入导出
|
- [x] 数据导入导出
|
||||||
- [x] 二维数组数据绑定
|
- [x] 二维数组数据绑定
|
||||||
- [x] 表格数据提取为数组
|
- [x] 表格数据提取为数组
|
||||||
- [x] 批量数据填充
|
- [x] 批量数据填充
|
||||||
|
|
||||||
|
##### 表格访问和查询
|
||||||
|
- [x] 表格查找和定位
|
||||||
|
- [x] 按索引获取表格
|
||||||
|
- [x] 表格位置信息获取
|
||||||
|
- [x] 单元格访问接口
|
||||||
|
- [x] 按行列索引访问
|
||||||
|
|
||||||
|
##### 表格样式和外观
|
||||||
|
- [x] 表格整体样式
|
||||||
|
- [x] 预定义表格样式模板
|
||||||
|
- [x] 自定义表格样式创建
|
||||||
|
- [x] 表格主题色彩应用
|
||||||
|
- [x] 表格样式继承和覆盖
|
||||||
|
- [x] 表格边框设置
|
||||||
|
- [x] 外边框样式(线型、颜色、粗细)
|
||||||
|
- [x] 内边框样式(网格线设置)
|
||||||
|
- [x] 单元格边框独立设置
|
||||||
|
- [x] 边框部分应用(顶部、底部、左右)
|
||||||
|
- [x] 无边框表格支持
|
||||||
|
- [x] 表格背景和填充
|
||||||
|
- [x] 表格背景色设置
|
||||||
|
- [x] 单元格背景色设置
|
||||||
|
- [x] 奇偶行颜色交替
|
||||||
|
- [x] 渐变背景支持(基础渐变)
|
||||||
|
- [x] 图案填充支持
|
||||||
|
|
||||||
|
### 🚧 规划中功能
|
||||||
|
|
||||||
|
#### 表格功能完善
|
||||||
|
|
||||||
|
##### 高级表格功能
|
||||||
- [ ] 表格排序功能(Word内置排序)
|
- [ ] 表格排序功能(Word内置排序)
|
||||||
- [ ] 单列排序(升序、降序)
|
- [ ] 单列排序(升序、降序)
|
||||||
- [ ] 多列排序
|
- [ ] 多列排序
|
||||||
- [ ] 保持标题行不参与排序
|
- [ ] 保持标题行不参与排序
|
||||||
|
|
||||||
##### 高级表格功能
|
|
||||||
- [ ] 表格标题和说明
|
- [ ] 表格标题和说明
|
||||||
- [ ] 表格标题设置(表格上方、下方)
|
- [ ] 表格标题设置(表格上方、下方)
|
||||||
- [ ] 表格标题编号自动生成
|
- [ ] 表格标题编号自动生成
|
||||||
@@ -142,14 +204,8 @@ WordZero 是一个使用 Golang 实现的 Word 文档操作库,提供基础的
|
|||||||
- [ ] 常用表格模板库
|
- [ ] 常用表格模板库
|
||||||
- [ ] 自定义模板保存
|
- [ ] 自定义模板保存
|
||||||
- [ ] 模板快速应用
|
- [ ] 模板快速应用
|
||||||
|
- [ ] 表格访问增强
|
||||||
##### 表格访问和查询
|
|
||||||
- [x] 表格查找和定位
|
|
||||||
- [x] 按索引获取表格
|
|
||||||
- [ ] 按标题查找表格
|
- [ ] 按标题查找表格
|
||||||
- [x] 表格位置信息获取
|
|
||||||
- [x] 单元格访问接口
|
|
||||||
- [x] 按行列索引访问
|
|
||||||
- [ ] 按范围批量访问
|
- [ ] 按范围批量访问
|
||||||
- [ ] 单元格遍历迭代器
|
- [ ] 单元格遍历迭代器
|
||||||
|
|
||||||
@@ -174,463 +230,52 @@ WordZero 是一个使用 Golang 实现的 Word 文档操作库,提供基础的
|
|||||||
- [ ] 列表和编号
|
- [ ] 列表和编号
|
||||||
- [ ] 脚注和尾注
|
- [ ] 脚注和尾注
|
||||||
|
|
||||||
## 安装
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go get github.com/ZeroHawkeye/wordZero
|
|
||||||
```
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 基础文档创建
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"github.com/ZeroHawkeye/wordZero/pkg/document"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// 创建新文档
|
|
||||||
doc := document.New()
|
|
||||||
|
|
||||||
// 添加段落
|
|
||||||
doc.AddParagraph("Hello, World!")
|
|
||||||
doc.AddParagraph("这是使用 WordZero 创建的文档。")
|
|
||||||
|
|
||||||
// 保存文档
|
|
||||||
err := doc.Save("output.docx")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 使用标题样式(支持导航窗格)
|
|
||||||
|
|
||||||
```go
|
|
||||||
doc := document.New()
|
|
||||||
|
|
||||||
// 添加文档标题
|
|
||||||
doc.AddParagraph("WordZero 使用指南").SetAlignment(document.AlignCenter)
|
|
||||||
|
|
||||||
// 使用标题样式 - 这些标题将出现在Word导航窗格中
|
|
||||||
doc.AddHeadingParagraph("第一章:概述", 1) // Heading1
|
|
||||||
doc.AddHeadingParagraph("1.1 项目介绍", 2) // Heading2
|
|
||||||
doc.AddHeadingParagraph("1.1.1 核心特性", 3) // Heading3
|
|
||||||
|
|
||||||
// 添加正文内容
|
|
||||||
doc.AddParagraph("WordZero是一个功能强大的Word文档操作库...")
|
|
||||||
|
|
||||||
doc.AddHeadingParagraph("第二章:安装和配置", 1) // Heading1
|
|
||||||
doc.AddHeadingParagraph("2.1 环境要求", 2) // Heading2
|
|
||||||
|
|
||||||
doc.Save("guide.docx")
|
|
||||||
```
|
|
||||||
|
|
||||||
### 高级文本格式化
|
|
||||||
|
|
||||||
```go
|
|
||||||
doc := document.New()
|
|
||||||
|
|
||||||
// 创建格式化标题
|
|
||||||
titleFormat := &document.TextFormat{
|
|
||||||
Bold: true,
|
|
||||||
FontSize: 18,
|
|
||||||
FontColor: "FF0000", // 红色
|
|
||||||
FontName: "微软雅黑",
|
|
||||||
}
|
|
||||||
title := doc.AddFormattedParagraph("格式化标题", titleFormat)
|
|
||||||
title.SetAlignment(document.AlignCenter)
|
|
||||||
|
|
||||||
// 设置段落间距
|
|
||||||
spacingConfig := &document.SpacingConfig{
|
|
||||||
LineSpacing: 1.5, // 1.5倍行距
|
|
||||||
BeforePara: 12, // 段前12磅
|
|
||||||
AfterPara: 6, // 段后6磅
|
|
||||||
FirstLineIndent: 24, // 首行缩进24磅
|
|
||||||
}
|
|
||||||
para := doc.AddParagraph("这个段落有特定的间距设置")
|
|
||||||
para.SetSpacing(spacingConfig)
|
|
||||||
para.SetAlignment(document.AlignJustify) // 两端对齐
|
|
||||||
|
|
||||||
// 混合格式段落
|
|
||||||
mixed := doc.AddParagraph("这段文字包含")
|
|
||||||
mixed.AddFormattedText("粗体蓝色", &document.TextFormat{
|
|
||||||
Bold: true, FontColor: "0000FF"})
|
|
||||||
mixed.AddFormattedText(",普通文本,", nil)
|
|
||||||
mixed.AddFormattedText("斜体绿色", &document.TextFormat{
|
|
||||||
Italic: true, FontColor: "00FF00"})
|
|
||||||
|
|
||||||
doc.Save("formatted.docx")
|
|
||||||
```
|
|
||||||
|
|
||||||
### 样式系统使用
|
|
||||||
|
|
||||||
```go
|
|
||||||
import "github.com/ZeroHawkeye/wordZero/pkg/style"
|
|
||||||
|
|
||||||
doc := document.New()
|
|
||||||
styleManager := doc.GetStyleManager()
|
|
||||||
quickAPI := style.NewQuickStyleAPI(styleManager)
|
|
||||||
|
|
||||||
// 查看所有可用样式
|
|
||||||
allStyles := quickAPI.GetAllStylesInfo()
|
|
||||||
for _, styleInfo := range allStyles {
|
|
||||||
fmt.Printf("样式: %s (%s) - %s\n",
|
|
||||||
styleInfo.Name, styleInfo.ID, styleInfo.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用预定义样式创建段落
|
|
||||||
para := doc.AddParagraph("这是引用文本")
|
|
||||||
para.SetStyle("Quote") // 应用引用样式
|
|
||||||
|
|
||||||
// 创建自定义样式
|
|
||||||
config := style.QuickStyleConfig{
|
|
||||||
ID: "MyCustomStyle",
|
|
||||||
Name: "我的自定义样式",
|
|
||||||
Type: style.StyleTypeParagraph,
|
|
||||||
BasedOn: "Normal",
|
|
||||||
ParagraphConfig: &style.QuickParagraphConfig{
|
|
||||||
Alignment: "center",
|
|
||||||
LineSpacing: 2.0,
|
|
||||||
SpaceBefore: 15,
|
|
||||||
},
|
|
||||||
RunConfig: &style.QuickRunConfig{
|
|
||||||
FontName: "华文宋体",
|
|
||||||
FontSize: 14,
|
|
||||||
FontColor: "2F5496",
|
|
||||||
Bold: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
customStyle, err := quickAPI.CreateQuickStyle(config)
|
|
||||||
if err == nil {
|
|
||||||
// 应用自定义样式
|
|
||||||
customPara := doc.AddParagraph("使用自定义样式的段落")
|
|
||||||
customPara.SetStyle("MyCustomStyle")
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.Save("styled.docx")
|
|
||||||
```
|
|
||||||
|
|
||||||
### 高级表格功能
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"github.com/ZeroHawkeye/wordZero/pkg/document"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
doc := document.New()
|
|
||||||
|
|
||||||
// 1. 创建基础表格
|
|
||||||
config := &document.TableConfig{
|
|
||||||
Rows: 4,
|
|
||||||
Cols: 4,
|
|
||||||
Width: 8000,
|
|
||||||
Data: [][]string{
|
|
||||||
{"学号", "姓名", "语文", "数学"},
|
|
||||||
{"001", "张三", "85", "92"},
|
|
||||||
{"002", "李四", "78", "88"},
|
|
||||||
{"003", "王五", "90", "85"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
table := doc.AddTable(config)
|
|
||||||
|
|
||||||
// 2. 设置表头格式
|
|
||||||
headerFormat := &document.CellFormat{
|
|
||||||
TextFormat: &document.TextFormat{
|
|
||||||
Bold: true,
|
|
||||||
FontSize: 14,
|
|
||||||
FontColor: "FFFFFF", // 白色文字
|
|
||||||
FontName: "微软雅黑",
|
|
||||||
},
|
|
||||||
HorizontalAlign: document.CellAlignCenter,
|
|
||||||
VerticalAlign: document.CellVAlignCenter,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为第一行设置表头格式
|
|
||||||
for col := 0; col < 4; col++ {
|
|
||||||
table.SetCellFormat(0, col, headerFormat)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 单元格富文本
|
|
||||||
table.SetCellFormattedText(1, 1, "张三", &document.TextFormat{
|
|
||||||
Bold: true,
|
|
||||||
FontColor: "FF0000",
|
|
||||||
})
|
|
||||||
|
|
||||||
// 在同一单元格添加不同格式的文本
|
|
||||||
table.AddCellFormattedText(1, 1, " (优秀)", &document.TextFormat{
|
|
||||||
Italic: true,
|
|
||||||
FontColor: "00FF00",
|
|
||||||
FontSize: 10,
|
|
||||||
})
|
|
||||||
|
|
||||||
// 4. 单元格合并
|
|
||||||
// 水平合并
|
|
||||||
table.MergeCellsHorizontal(0, 2, 3) // 合并表头的"语文"和"数学"列
|
|
||||||
table.SetCellText(0, 2, "成绩")
|
|
||||||
|
|
||||||
// 垂直合并
|
|
||||||
table.MergeCellsVertical(1, 3, 0) // 合并学号列
|
|
||||||
table.SetCellText(1, 0, "2024级")
|
|
||||||
|
|
||||||
// 区域合并(2x2区域)
|
|
||||||
mergeTable := doc.AddTable(&document.TableConfig{Rows: 4, Cols: 4, Width: 6000})
|
|
||||||
mergeTable.MergeCellsRange(1, 2, 1, 2) // 合并中间2x2区域
|
|
||||||
mergeTable.SetCellText(1, 1, "合并区域")
|
|
||||||
|
|
||||||
// 5. 检查和取消合并
|
|
||||||
isMerged, _ := table.IsCellMerged(0, 2)
|
|
||||||
if isMerged {
|
|
||||||
// 获取合并信息
|
|
||||||
mergeInfo, _ := table.GetMergedCellInfo(0, 2)
|
|
||||||
log.Printf("合并信息: %+v", mergeInfo)
|
|
||||||
|
|
||||||
// 可以选择取消合并
|
|
||||||
// table.UnmergeCells(0, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. 内容和格式操作
|
|
||||||
// 清空内容但保留格式
|
|
||||||
table.ClearCellContent(1, 2)
|
|
||||||
table.SetCellText(1, 2, "90")
|
|
||||||
|
|
||||||
// 清空格式但保留内容
|
|
||||||
table.ClearCellFormat(1, 3)
|
|
||||||
|
|
||||||
// 7. 设置单元格内边距
|
|
||||||
table.SetCellPadding(0, 0, 10) // 10磅内边距
|
|
||||||
|
|
||||||
// 8. 设置单元格文字方向
|
|
||||||
// 设置垂直文字(从上到下)
|
|
||||||
table.SetCellTextDirection(1, 0, document.TextDirectionTB)
|
|
||||||
|
|
||||||
// 通过CellFormat设置完整格式,包括文字方向
|
|
||||||
verticalFormat := &document.CellFormat{
|
|
||||||
TextFormat: &document.TextFormat{
|
|
||||||
Bold: true,
|
|
||||||
FontSize: 14,
|
|
||||||
},
|
|
||||||
HorizontalAlign: document.CellAlignCenter,
|
|
||||||
VerticalAlign: document.CellVAlignCenter,
|
|
||||||
TextDirection: document.TextDirectionTB, // 从上到下
|
|
||||||
}
|
|
||||||
table.SetCellFormat(1, 1, verticalFormat)
|
|
||||||
table.SetCellText(1, 1, "竖排文字")
|
|
||||||
|
|
||||||
doc.Save("advanced_table.docx")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 项目结构
|
|
||||||
|
|
||||||
```
|
|
||||||
wordZero/
|
|
||||||
├── pkg/ # 公共包
|
|
||||||
│ ├── document/ # 文档核心操作
|
|
||||||
│ │ ├── document.go # 主要文档操作API
|
|
||||||
│ │ ├── errors.go # 错误定义和处理
|
|
||||||
│ │ ├── logger.go # 日志系统
|
|
||||||
│ │ ├── doc.go # 包文档
|
|
||||||
│ │ └── document_test.go # 单元测试
|
|
||||||
│ └── style/ # 样式管理系统
|
|
||||||
│ ├── style.go # 样式核心定义
|
|
||||||
│ ├── api.go # 快速API接口
|
|
||||||
│ ├── predefined.go # 预定义样式常量
|
|
||||||
│ ├── api_test.go # API测试
|
|
||||||
│ ├── style_test.go # 样式系统测试
|
|
||||||
│ └── README.md # 样式系统详细文档
|
|
||||||
├── examples/ # 使用示例
|
|
||||||
│ ├── basic/ # 基础功能示例
|
|
||||||
│ │ └── basic_example.go
|
|
||||||
│ ├── formatting/ # 格式化示例
|
|
||||||
│ ├── style_demo/ # 样式系统演示
|
|
||||||
│ │ └── style_demo.go
|
|
||||||
│ └── output/ # 示例输出文件
|
|
||||||
├── test/ # 测试文件
|
|
||||||
├── go.mod # Go模块定义
|
|
||||||
├── LICENSE # MIT许可证
|
|
||||||
└── README.md # 项目说明文档
|
|
||||||
```
|
|
||||||
|
|
||||||
## 使用示例
|
## 使用示例
|
||||||
|
|
||||||
### 基础功能演示
|
查看 `examples/` 目录下的示例代码:
|
||||||
|
|
||||||
运行基础示例:
|
- `examples/basic/` - 基础功能演示
|
||||||
|
- `examples/style_demo/` - 样式系统演示
|
||||||
|
- `examples/table/` - 表格功能演示
|
||||||
|
- `examples/table_layout/` - 表格布局和尺寸演示
|
||||||
|
- `examples/formatting/` - 格式化演示
|
||||||
|
|
||||||
|
运行示例:
|
||||||
```bash
|
```bash
|
||||||
go run ./examples/basic/
|
|
||||||
```
|
|
||||||
|
|
||||||
这个示例展示了:
|
|
||||||
- 文档和标题创建
|
|
||||||
- 各种预定义样式的使用
|
|
||||||
- 文本格式化和混合格式
|
|
||||||
- 代码块和引用样式
|
|
||||||
- 列表段落的创建
|
|
||||||
|
|
||||||
### 完整样式系统演示
|
|
||||||
|
|
||||||
运行完整样式演示:
|
|
||||||
```bash
|
|
||||||
go run ./examples/style_demo/
|
|
||||||
```
|
|
||||||
|
|
||||||
这个示例展示了:
|
|
||||||
- 所有18种预定义样式
|
|
||||||
- 样式继承机制演示
|
|
||||||
- 自定义样式创建
|
|
||||||
- 样式查询和管理功能
|
|
||||||
- XML转换演示
|
|
||||||
|
|
||||||
### 读取现有文档
|
|
||||||
|
|
||||||
```go
|
|
||||||
doc, err := document.Open("existing.docx")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 读取段落内容
|
|
||||||
fmt.Printf("文档包含 %d 个段落\n", len(doc.Body.Paragraphs))
|
|
||||||
for i, para := range doc.Body.Paragraphs {
|
|
||||||
fmt.Printf("段落 %d: ", i+1)
|
|
||||||
for _, run := range para.Runs {
|
|
||||||
fmt.Print(run.Text.Content)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 命令行使用
|
|
||||||
|
|
||||||
运行演示程序:
|
|
||||||
```bash
|
|
||||||
# 运行完整演示
|
|
||||||
go run main.go
|
|
||||||
|
|
||||||
# 运行基础功能演示
|
# 运行基础功能演示
|
||||||
go run ./examples/basic/
|
go run ./examples/basic/
|
||||||
|
|
||||||
# 运行样式演示
|
# 运行样式演示
|
||||||
go run ./examples/style_demo/
|
go run ./examples/style_demo/
|
||||||
|
|
||||||
|
# 运行表格演示
|
||||||
|
go run ./examples/table/
|
||||||
|
|
||||||
|
# 运行表格布局和尺寸演示
|
||||||
|
go run ./examples/table_layout/
|
||||||
|
|
||||||
# 运行格式化演示
|
# 运行格式化演示
|
||||||
go run ./examples/formatting/
|
go run ./examples/formatting/
|
||||||
```
|
```
|
||||||
|
|
||||||
## 测试
|
## 开发指南
|
||||||
|
|
||||||
### 运行测试
|
### 项目开发规则
|
||||||
|
|
||||||
```bash
|
1. **项目结构**: 符合golang依赖库的项目结构,完善的测试流程
|
||||||
# 运行所有测试
|
2. **模块化设计**: 规范的项目结构,避免文件循环依赖和过渡耦合
|
||||||
go test ./...
|
3. **测试规范**: 测试用例尽量放在test目录下
|
||||||
|
4. **文档维护**: 每次完成一个功能点需更新README文件的待办列表
|
||||||
|
|
||||||
# 运行特定包测试
|
### 贡献指南
|
||||||
go test ./pkg/document/
|
|
||||||
go test ./pkg/style/
|
|
||||||
|
|
||||||
# 运行测试并显示覆盖率
|
欢迎提交 Issue 和 Pull Request!在提交代码前请确保:
|
||||||
go test -cover ./...
|
|
||||||
|
|
||||||
# 生成详细的测试报告
|
1. 代码符合 Go 代码规范
|
||||||
go test -v -coverprofile=coverage.out ./...
|
2. 添加必要的测试用例
|
||||||
go tool cover -html=coverage.out
|
3. 更新相关文档
|
||||||
```
|
4. 确保所有测试通过
|
||||||
|
|
||||||
### 测试覆盖
|
|
||||||
|
|
||||||
- **文档操作**: 基础CRUD操作、文本格式化、段落属性
|
|
||||||
- **样式系统**: 预定义样式、自定义样式、样式继承
|
|
||||||
- **文件处理**: ZIP压缩/解压、XML序列化/反序列化
|
|
||||||
- **错误处理**: 各种异常情况和边界条件
|
|
||||||
|
|
||||||
## API 文档
|
|
||||||
|
|
||||||
详细的API文档请参考:
|
|
||||||
- [文档操作API](pkg/document/) - 核心文档操作功能
|
|
||||||
- [样式系统API](pkg/style/) - 完整的样式管理系统
|
|
||||||
|
|
||||||
## 开发进度
|
|
||||||
|
|
||||||
### 当前版本: v0.3.0
|
|
||||||
|
|
||||||
#### v0.3.0 新增功能
|
|
||||||
- ✅ 完整的标题样式系统(Heading1-9)
|
|
||||||
- ✅ Word导航窗格支持
|
|
||||||
- ✅ 18种预定义样式(系统内置样式)
|
|
||||||
- ✅ 自定义样式创建和管理
|
|
||||||
- ✅ 样式继承机制
|
|
||||||
- ✅ 快速样式API
|
|
||||||
|
|
||||||
#### v0.2.0 功能
|
|
||||||
- ✅ 基础文档创建和读取
|
|
||||||
- ✅ 文本格式化支持
|
|
||||||
- ✅ 段落属性设置
|
|
||||||
- ✅ 混合格式文本
|
|
||||||
|
|
||||||
#### v0.1.0 功能
|
|
||||||
- ✅ 项目初始化
|
|
||||||
- ✅ OOXML基础架构
|
|
||||||
- ✅ ZIP文件处理
|
|
||||||
|
|
||||||
### 下一版本计划: v0.4.0
|
|
||||||
- 🚧 表格功能
|
|
||||||
- 🚧 图片插入
|
|
||||||
- 🚧 列表和编号
|
|
||||||
- 🚧 页面设置
|
|
||||||
|
|
||||||
## 贡献指南
|
|
||||||
|
|
||||||
欢迎贡献代码!请确保:
|
|
||||||
|
|
||||||
1. 所有新功能都有相应的单元测试
|
|
||||||
2. 代码符合Go语言规范
|
|
||||||
3. 提交前运行完整测试套件
|
|
||||||
4. 更新相关文档
|
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|
||||||
本项目采用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件
|
本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。
|
||||||
|
|
||||||
## 更新日志
|
|
||||||
|
|
||||||
### 2025-05-29 单元格文字方向功能实现
|
|
||||||
- ✅ 实现单元格文字方向设置功能,支持6种方向:
|
|
||||||
- `TextDirectionLR`:从左到右(默认)
|
|
||||||
- `TextDirectionTB`:从上到下
|
|
||||||
- `TextDirectionBT`:从下到上
|
|
||||||
- `TextDirectionRL`:从右到左
|
|
||||||
- `TextDirectionTBV`:从上到下,垂直显示
|
|
||||||
- `TextDirectionBTV`:从下到上,垂直显示
|
|
||||||
- ✅ 添加 `SetCellTextDirection()` 和 `GetCellTextDirection()` 方法
|
|
||||||
- ✅ 扩展 `CellFormat` 结构支持文字方向属性
|
|
||||||
- ✅ 添加完整的测试用例和演示程序
|
|
||||||
- ✅ 更新README文档和使用示例
|
|
||||||
|
|
||||||
### 2025-05-29 测试修复
|
|
||||||
- ✅ 修复 `TestComplexDocument` 测试:调整期望段落数量从7改为6,与实际创建的段落数量一致
|
|
||||||
- ✅ 修复 `TestErrorHandling` 测试:改进无效路径测试策略,确保在不同操作系统下都能正确测试错误处理
|
|
||||||
- ✅ 验证所有测试用例均通过,确保代码质量和功能稳定性
|
|
||||||
- ✅ 问题根因:测试用例期望值与实际实现不符,已修正测试逻辑
|
|
||||||
|
|
||||||
### 测试状态总结
|
|
||||||
- **总测试数量**: 20+ 个测试用例
|
|
||||||
- **覆盖模块**: document操作、style管理、格式化功能、错误处理
|
|
||||||
- **通过率**: 100%
|
|
||||||
- **测试结论**: 代码实现正确,测试用例已修复
|
|
||||||
|
|
||||||
## 致谢
|
|
||||||
|
|
||||||
- Office Open XML 规范
|
|
||||||
- Go语言社区的优秀库和工具
|
|
@@ -111,7 +111,7 @@ doc.Save("example.docx")`
|
|||||||
stylesInfo.SetStyle(style.StyleNormal)
|
stylesInfo.SetStyle(style.StyleNormal)
|
||||||
|
|
||||||
// 确保输出目录存在
|
// 确保输出目录存在
|
||||||
outputFile := "../output/basic_example.docx"
|
outputFile := "examples/output/basic_example.docx"
|
||||||
outputDir := filepath.Dir(outputFile)
|
outputDir := filepath.Dir(outputFile)
|
||||||
|
|
||||||
fmt.Printf("📁 检查输出目录: %s\n", outputDir)
|
fmt.Printf("📁 检查输出目录: %s\n", outputDir)
|
||||||
|
@@ -26,7 +26,7 @@ func main() {
|
|||||||
doc.AddParagraph("• 打开现有文档")
|
doc.AddParagraph("• 打开现有文档")
|
||||||
|
|
||||||
// 保存文档
|
// 保存文档
|
||||||
outputFile := "output/example_document.docx"
|
outputFile := "examples/output/example_document.docx"
|
||||||
err := doc.Save(outputFile)
|
err := doc.Save(outputFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("保存文档失败: %v", err)
|
log.Fatalf("保存文档失败: %v", err)
|
||||||
@@ -41,11 +41,11 @@ func main() {
|
|||||||
log.Fatalf("打开文档失败: %v", err)
|
log.Fatalf("打开文档失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("文档包含 %d 个段落\n", len(openedDoc.Body.Paragraphs))
|
fmt.Printf("文档包含 %d 个段落\n", len(openedDoc.Body.GetParagraphs()))
|
||||||
|
|
||||||
// 打印所有段落内容
|
// 打印所有段落内容
|
||||||
fmt.Println("\n文档内容:")
|
fmt.Println("\n文档内容:")
|
||||||
for i, para := range openedDoc.Body.Paragraphs {
|
for i, para := range openedDoc.Body.GetParagraphs() {
|
||||||
if len(para.Runs) > 0 {
|
if len(para.Runs) > 0 {
|
||||||
fmt.Printf("段落 %d: %s\n", i+1, para.Runs[0].Text.Content)
|
fmt.Printf("段落 %d: %s\n", i+1, para.Runs[0].Text.Content)
|
||||||
}
|
}
|
||||||
|
@@ -66,7 +66,7 @@ func main() {
|
|||||||
p5.SetAlignment(document.AlignRight)
|
p5.SetAlignment(document.AlignRight)
|
||||||
|
|
||||||
// 保存文档
|
// 保存文档
|
||||||
err := doc.Save("../output/formatted_document.docx")
|
err := doc.Save("examples/output/formatted_document.docx")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("保存文档失败: %v", err)
|
log.Fatalf("保存文档失败: %v", err)
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ func main() {
|
|||||||
demonstrateStyleManagement(quickAPI)
|
demonstrateStyleManagement(quickAPI)
|
||||||
|
|
||||||
// 保存文档
|
// 保存文档
|
||||||
outputFile := "../output/styled_document_demo.docx"
|
outputFile := "examples/output/styled_document_demo.docx"
|
||||||
err := doc.Save(outputFile)
|
err := doc.Save(outputFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("保存文档失败: %v", err)
|
log.Fatalf("保存文档失败: %v", err)
|
||||||
|
@@ -206,7 +206,7 @@ func demonstrateTableCopyAndClear(doc *document.Document) {
|
|||||||
copiedTable.SetCellText(1, 1, "复制4")
|
copiedTable.SetCellText(1, 1, "复制4")
|
||||||
|
|
||||||
// 将复制的表格添加到文档
|
// 将复制的表格添加到文档
|
||||||
doc.Body.Tables = append(doc.Body.Tables, *copiedTable)
|
doc.Body.AddElement(copiedTable)
|
||||||
fmt.Println(" 复制的表格已添加到文档")
|
fmt.Println(" 复制的表格已添加到文档")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
283
examples/table_layout/main.go
Normal file
283
examples/table_layout/main.go
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/ZeroHawkeye/wordZero/pkg/document"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("WordZero 表格布局和尺寸功能演示")
|
||||||
|
fmt.Println("==============================")
|
||||||
|
|
||||||
|
// 创建新文档
|
||||||
|
doc := document.New()
|
||||||
|
|
||||||
|
// 添加文档标题
|
||||||
|
title := doc.AddParagraph("表格布局和尺寸功能演示")
|
||||||
|
title.SetAlignment(document.AlignCenter)
|
||||||
|
titleFormat := &document.TextFormat{
|
||||||
|
Bold: true,
|
||||||
|
FontSize: 18,
|
||||||
|
FontColor: "2F5496",
|
||||||
|
FontName: "微软雅黑",
|
||||||
|
}
|
||||||
|
title.AddFormattedText("", titleFormat)
|
||||||
|
|
||||||
|
// 1. 行高设置演示
|
||||||
|
fmt.Println("1. 创建行高设置演示表格...")
|
||||||
|
doc.AddParagraph("1. 行高设置演示").SetStyle("Heading1")
|
||||||
|
|
||||||
|
heightTable := doc.AddTable(&document.TableConfig{
|
||||||
|
Rows: 4,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 8000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"行类型", "高度设置", "说明"},
|
||||||
|
{"自动行高", "默认", "根据内容自动调整高度"},
|
||||||
|
{"固定行高", "40磅", "精确的固定高度"},
|
||||||
|
{"最小行高", "30磅", "至少30磅,内容多时可以更高"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置表头格式
|
||||||
|
headerFormat := &document.CellFormat{
|
||||||
|
TextFormat: &document.TextFormat{
|
||||||
|
Bold: true,
|
||||||
|
FontSize: 12,
|
||||||
|
FontColor: "FFFFFF",
|
||||||
|
FontName: "微软雅黑",
|
||||||
|
},
|
||||||
|
HorizontalAlign: document.CellAlignCenter,
|
||||||
|
VerticalAlign: document.CellVAlignCenter,
|
||||||
|
}
|
||||||
|
|
||||||
|
for col := 0; col < 3; col++ {
|
||||||
|
heightTable.SetCellFormat(0, col, headerFormat)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用不同的行高设置
|
||||||
|
// 第2行:固定高度40磅
|
||||||
|
heightTable.SetRowHeight(2, &document.RowHeightConfig{
|
||||||
|
Height: 40,
|
||||||
|
Rule: document.RowHeightExact,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 第3行:最小高度30磅
|
||||||
|
heightTable.SetRowHeight(3, &document.RowHeightConfig{
|
||||||
|
Height: 30,
|
||||||
|
Rule: document.RowHeightMinimum,
|
||||||
|
})
|
||||||
|
|
||||||
|
fmt.Println(" - 设置了不同的行高规则")
|
||||||
|
|
||||||
|
// 2. 表格对齐演示
|
||||||
|
fmt.Println("2. 创建表格对齐演示...")
|
||||||
|
doc.AddParagraph("2. 表格对齐演示").SetStyle("Heading1")
|
||||||
|
|
||||||
|
// 左对齐表格
|
||||||
|
doc.AddParagraph("2.1 左对齐表格").SetStyle("Heading2")
|
||||||
|
leftTable := doc.AddTable(&document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"左对齐", "表格"},
|
||||||
|
{"Left", "Aligned"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
leftTable.SetTableAlignment(document.TableAlignLeft)
|
||||||
|
|
||||||
|
// 居中对齐表格
|
||||||
|
doc.AddParagraph("2.2 居中对齐表格").SetStyle("Heading2")
|
||||||
|
centerTable := doc.AddTable(&document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"居中对齐", "表格"},
|
||||||
|
{"Center", "Aligned"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
centerTable.SetTableAlignment(document.TableAlignCenter)
|
||||||
|
|
||||||
|
// 右对齐表格
|
||||||
|
doc.AddParagraph("2.3 右对齐表格").SetStyle("Heading2")
|
||||||
|
rightTable := doc.AddTable(&document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"右对齐", "表格"},
|
||||||
|
{"Right", "Aligned"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
rightTable.SetTableAlignment(document.TableAlignRight)
|
||||||
|
|
||||||
|
fmt.Println(" - 创建了左对齐、居中、右对齐三种表格")
|
||||||
|
|
||||||
|
// 3. 分页控制演示
|
||||||
|
fmt.Println("3. 创建分页控制演示表格...")
|
||||||
|
doc.AddParagraph("3. 分页控制演示").SetStyle("Heading1")
|
||||||
|
|
||||||
|
pageBreakTable := doc.AddTable(&document.TableConfig{
|
||||||
|
Rows: 6,
|
||||||
|
Cols: 4,
|
||||||
|
Width: 9000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"序号", "姓名", "部门", "职位"},
|
||||||
|
{"001", "张三", "技术部", "工程师"},
|
||||||
|
{"002", "李四", "产品部", "产品经理"},
|
||||||
|
{"003", "王五", "设计部", "UI设计师"},
|
||||||
|
{"004", "赵六", "市场部", "市场专员"},
|
||||||
|
{"005", "钱七", "人事部", "HR专员"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置表头格式
|
||||||
|
for col := 0; col < 4; col++ {
|
||||||
|
pageBreakTable.SetCellFormat(0, col, &document.CellFormat{
|
||||||
|
TextFormat: &document.TextFormat{
|
||||||
|
Bold: true,
|
||||||
|
FontSize: 12,
|
||||||
|
FontColor: "FFFFFF",
|
||||||
|
},
|
||||||
|
HorizontalAlign: document.CellAlignCenter,
|
||||||
|
VerticalAlign: document.CellVAlignCenter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置第一行为重复的标题行
|
||||||
|
pageBreakTable.SetRowAsHeader(0, true)
|
||||||
|
fmt.Println(" - 设置第一行为重复标题行")
|
||||||
|
|
||||||
|
// 设置某些行禁止跨页分割
|
||||||
|
pageBreakTable.SetRowKeepTogether(1, true)
|
||||||
|
pageBreakTable.SetRowKeepTogether(2, true)
|
||||||
|
fmt.Println(" - 设置前两个数据行禁止跨页分割")
|
||||||
|
|
||||||
|
// 设置表格分页配置
|
||||||
|
pageBreakTable.SetTablePageBreak(&document.TablePageBreakConfig{
|
||||||
|
KeepWithNext: false,
|
||||||
|
KeepLines: true,
|
||||||
|
PageBreakBefore: false,
|
||||||
|
WidowControl: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 4. 复杂布局演示
|
||||||
|
fmt.Println("4. 创建复杂布局演示表格...")
|
||||||
|
doc.AddParagraph("4. 复杂布局演示").SetStyle("Heading1")
|
||||||
|
|
||||||
|
complexTable := doc.AddTable(&document.TableConfig{
|
||||||
|
Rows: 5,
|
||||||
|
Cols: 4,
|
||||||
|
Width: 9000,
|
||||||
|
ColWidths: []int{1500, 3000, 2000, 2500},
|
||||||
|
Data: [][]string{
|
||||||
|
{"项目", "描述", "状态", "负责人"},
|
||||||
|
{"WordZero核心", "Word文档操作库核心功能", "进行中", "开发团队"},
|
||||||
|
{"表格功能", "完整的表格操作和格式化", "已完成", "张工程师"},
|
||||||
|
{"样式系统", "18种预定义样式和自定义样式", "已完成", "李设计师"},
|
||||||
|
{"测试套件", "完整的单元测试和集成测试", "进行中", "QA团队"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置表头为重复标题行
|
||||||
|
complexTable.SetHeaderRows(0, 0)
|
||||||
|
|
||||||
|
// 设置不同的行高
|
||||||
|
complexTable.SetRowHeight(0, &document.RowHeightConfig{
|
||||||
|
Height: 35,
|
||||||
|
Rule: document.RowHeightExact,
|
||||||
|
}) // 表头固定高度
|
||||||
|
|
||||||
|
// 批量设置数据行为最小高度
|
||||||
|
complexTable.SetRowHeightRange(1, 4, &document.RowHeightConfig{
|
||||||
|
Height: 25,
|
||||||
|
Rule: document.RowHeightMinimum,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置表头格式
|
||||||
|
for col := 0; col < 4; col++ {
|
||||||
|
complexTable.SetCellFormat(0, col, &document.CellFormat{
|
||||||
|
TextFormat: &document.TextFormat{
|
||||||
|
Bold: true,
|
||||||
|
FontSize: 14,
|
||||||
|
FontColor: "FFFFFF",
|
||||||
|
FontName: "微软雅黑",
|
||||||
|
},
|
||||||
|
HorizontalAlign: document.CellAlignCenter,
|
||||||
|
VerticalAlign: document.CellVAlignCenter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置状态列的特殊格式
|
||||||
|
for row := 1; row <= 4; row++ {
|
||||||
|
status, _ := complexTable.GetCellText(row, 2)
|
||||||
|
var color string
|
||||||
|
switch status {
|
||||||
|
case "已完成":
|
||||||
|
color = "00AA00" // 绿色
|
||||||
|
case "进行中":
|
||||||
|
color = "FF8800" // 橙色
|
||||||
|
default:
|
||||||
|
color = "666666" // 灰色
|
||||||
|
}
|
||||||
|
|
||||||
|
complexTable.SetCellFormat(row, 2, &document.CellFormat{
|
||||||
|
TextFormat: &document.TextFormat{
|
||||||
|
Bold: true,
|
||||||
|
FontColor: color,
|
||||||
|
FontSize: 11,
|
||||||
|
},
|
||||||
|
HorizontalAlign: document.CellAlignCenter,
|
||||||
|
VerticalAlign: document.CellVAlignCenter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置表格居中对齐
|
||||||
|
complexTable.SetTableAlignment(document.TableAlignCenter)
|
||||||
|
|
||||||
|
fmt.Println(" - 设置了自定义列宽")
|
||||||
|
fmt.Println(" - 应用了不同的行高规则")
|
||||||
|
fmt.Println(" - 添加了状态标识颜色")
|
||||||
|
|
||||||
|
// 5. 输出统计信息
|
||||||
|
fmt.Println("5. 生成统计信息...")
|
||||||
|
doc.AddParagraph("5. 表格统计信息").SetStyle("Heading1")
|
||||||
|
|
||||||
|
// 获取分页信息
|
||||||
|
breakInfo := pageBreakTable.GetTableBreakInfo()
|
||||||
|
infoText := fmt.Sprintf("分页控制表格统计:总行数 %d,标题行数 %d,禁止分割行数 %d",
|
||||||
|
breakInfo["total_rows"], breakInfo["header_rows"], breakInfo["keep_together_rows"])
|
||||||
|
doc.AddParagraph(infoText)
|
||||||
|
|
||||||
|
// 获取表格布局信息
|
||||||
|
layout := complexTable.GetTableLayout()
|
||||||
|
layoutText := fmt.Sprintf("复杂表格布局:对齐方式 %s,环绕类型 %s,定位类型 %s",
|
||||||
|
layout.Alignment, layout.TextWrap, layout.Position)
|
||||||
|
doc.AddParagraph(layoutText)
|
||||||
|
|
||||||
|
// 验证行高设置
|
||||||
|
heightConfig, _ := complexTable.GetRowHeight(0)
|
||||||
|
heightText := fmt.Sprintf("表头行高设置:%d磅,规则 %s", heightConfig.Height, heightConfig.Rule)
|
||||||
|
doc.AddParagraph(heightText)
|
||||||
|
|
||||||
|
// 6. 保存文档
|
||||||
|
outputPath := filepath.Join("examples", "output", "table_layout_demo.docx")
|
||||||
|
err := doc.Save(outputPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("保存文档失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("6. 文档已保存到: %s\n", outputPath)
|
||||||
|
fmt.Println("\n演示完成!")
|
||||||
|
fmt.Println("\n新实现的功能包括:")
|
||||||
|
fmt.Println("✅ 行高设置(固定高度、最小高度、自动调整)")
|
||||||
|
fmt.Println("✅ 表格对齐方式(左对齐、居中、右对齐)")
|
||||||
|
fmt.Println("✅ 分页控制(标题行重复、禁止跨页分割)")
|
||||||
|
fmt.Println("✅ 表格布局配置和查询")
|
||||||
|
fmt.Println("✅ 批量行高设置和统计信息获取")
|
||||||
|
}
|
677
examples/table_style/main.go
Normal file
677
examples/table_style/main.go
Normal file
@@ -0,0 +1,677 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/ZeroHawkeye/wordZero/pkg/document"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 创建输出目录
|
||||||
|
if err := os.MkdirAll("examples/output", 0755); err != nil {
|
||||||
|
log.Fatalf("创建输出目录失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
log.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加标题
|
||||||
|
doc.AddParagraph("WordZero - 表格样式和外观功能演示")
|
||||||
|
doc.AddParagraph("")
|
||||||
|
|
||||||
|
// 演示1:基础表格边框
|
||||||
|
demonstrateBorders(doc)
|
||||||
|
|
||||||
|
// 演示2:单元格边框
|
||||||
|
demonstrateCellBorders(doc)
|
||||||
|
|
||||||
|
// 演示3:表格背景
|
||||||
|
demonstrateTableShading(doc)
|
||||||
|
|
||||||
|
// 演示4:单元格背景
|
||||||
|
demonstrateCellShading(doc)
|
||||||
|
|
||||||
|
// 演示5:奇偶行颜色交替
|
||||||
|
demonstrateAlternatingRows(doc)
|
||||||
|
|
||||||
|
// 演示6:预定义样式模板
|
||||||
|
demonstrateStyleTemplates(doc)
|
||||||
|
|
||||||
|
// 演示7:自定义表格样式
|
||||||
|
demonstrateCustomStyle(doc)
|
||||||
|
|
||||||
|
// 演示8:复杂样式组合
|
||||||
|
demonstrateComplexStyle(doc)
|
||||||
|
|
||||||
|
// 演示9:无边框表格
|
||||||
|
demonstrateNoBorders(doc)
|
||||||
|
|
||||||
|
// 演示10:各种边框样式
|
||||||
|
demonstrateBorderStyles(doc)
|
||||||
|
|
||||||
|
// 保存文档
|
||||||
|
outputFile := "examples/output/table_style_demo.docx"
|
||||||
|
if err := doc.Save(outputFile); err != nil {
|
||||||
|
log.Fatalf("保存文档失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("表格样式演示文档已保存到: %s\n", outputFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateBorders 演示表格边框设置
|
||||||
|
func demonstrateBorders(doc *document.Document) {
|
||||||
|
doc.AddParagraph("1. 表格边框设置演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 5000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"姓名", "年龄", "职业"},
|
||||||
|
{"张三", "25", "工程师"},
|
||||||
|
{"李四", "30", "设计师"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置不同的边框样式
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 12,
|
||||||
|
Color: "FF0000", // 红色粗上边框
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "0000FF", // 蓝色左边框
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 6,
|
||||||
|
Color: "00FF00", // 绿色双线下边框
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDashed,
|
||||||
|
Width: 6,
|
||||||
|
Color: "FF00FF", // 紫色虚线右边框
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDotted,
|
||||||
|
Width: 4,
|
||||||
|
Color: "808080", // 灰色点线内部水平边框
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "808080", // 灰色内部垂直边框
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateCellBorders 演示单元格边框设置
|
||||||
|
func demonstrateCellBorders(doc *document.Document) {
|
||||||
|
doc.AddParagraph("2. 单元格边框设置演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"单元格A", "单元格B", "单元格C"},
|
||||||
|
{"数据1", "数据2", "数据3"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为第一个单元格设置特殊边框
|
||||||
|
cellBorderConfig := &document.CellBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 8,
|
||||||
|
Color: "FF0000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "0000FF",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 6,
|
||||||
|
Color: "00FF00",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDashed,
|
||||||
|
Width: 4,
|
||||||
|
Color: "FF00FF",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
DiagDown: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 2,
|
||||||
|
Color: "FFFF00", // 黄色对角线
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetCellBorders(0, 0, cellBorderConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置单元格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateTableShading 演示表格背景设置
|
||||||
|
func demonstrateTableShading(doc *document.Document) {
|
||||||
|
doc.AddParagraph("3. 表格背景设置演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"产品", "价格"},
|
||||||
|
{"产品A", "¥100"},
|
||||||
|
{"产品B", "¥200"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置表格整体背景
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternPct25,
|
||||||
|
ForegroundColor: "000000",
|
||||||
|
BackgroundColor: "E0E0E0",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableShading(shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置表格背景失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateCellShading 演示单元格背景设置
|
||||||
|
func demonstrateCellShading(doc *document.Document) {
|
||||||
|
doc.AddParagraph("4. 单元格背景设置演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"红色", "绿色", "蓝色"},
|
||||||
|
{"黄色", "紫色", "青色"},
|
||||||
|
{"橙色", "粉色", "灰色"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为不同单元格设置不同颜色
|
||||||
|
colors := [][]string{
|
||||||
|
{"FF0000", "00FF00", "0000FF"}, // 红绿蓝
|
||||||
|
{"FFFF00", "FF00FF", "00FFFF"}, // 黄紫青
|
||||||
|
{"FFA500", "FFC0CB", "808080"}, // 橙粉灰
|
||||||
|
}
|
||||||
|
|
||||||
|
patterns := [][]document.ShadingPattern{
|
||||||
|
{document.ShadingPatternSolid, document.ShadingPatternPct50, document.ShadingPatternPct25},
|
||||||
|
{document.ShadingPatternSolid, document.ShadingPatternPct75, document.ShadingPatternPct10},
|
||||||
|
{document.ShadingPatternPct60, document.ShadingPatternPct40, document.ShadingPatternSolid},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: patterns[i][j],
|
||||||
|
BackgroundColor: colors[i][j],
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetCellShading(i, j, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置单元格(%d,%d)背景失败: %v", i, j, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateAlternatingRows 演示奇偶行颜色交替
|
||||||
|
func demonstrateAlternatingRows(doc *document.Document) {
|
||||||
|
doc.AddParagraph("5. 奇偶行颜色交替演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 6,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"序号", "姓名", "分数"},
|
||||||
|
{"1", "张三", "85"},
|
||||||
|
{"2", "李四", "92"},
|
||||||
|
{"3", "王五", "78"},
|
||||||
|
{"4", "赵六", "95"},
|
||||||
|
{"5", "钱七", "88"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置奇偶行颜色交替
|
||||||
|
err := table.SetAlternatingRowColors("F0F0F0", "FFFFFF")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置奇偶行颜色交替失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateStyleTemplates 演示预定义样式模板
|
||||||
|
func demonstrateStyleTemplates(doc *document.Document) {
|
||||||
|
doc.AddParagraph("6. 预定义样式模板演示")
|
||||||
|
|
||||||
|
// 演示Grid样式
|
||||||
|
config1 := &document.TableConfig{
|
||||||
|
Rows: 4,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"项目", "预算", "实际"},
|
||||||
|
{"开发", "10000", "9500"},
|
||||||
|
{"测试", "5000", "5200"},
|
||||||
|
{"总计", "15000", "14700"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table1 := doc.AddTable(config1)
|
||||||
|
if table1 == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
styleConfig1 := &document.TableStyleConfig{
|
||||||
|
Template: document.TableStyleTemplateGrid,
|
||||||
|
FirstRowHeader: true,
|
||||||
|
LastRowTotal: true,
|
||||||
|
BandedRows: true,
|
||||||
|
BandedColumns: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table1.ApplyTableStyle(styleConfig1)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("应用Grid样式失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
|
||||||
|
// 演示Colorful样式
|
||||||
|
config2 := &document.TableConfig{
|
||||||
|
Rows: 4,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"部门", "人数", "预算"},
|
||||||
|
{"技术部", "20", "500万"},
|
||||||
|
{"销售部", "15", "300万"},
|
||||||
|
{"市场部", "10", "200万"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table2 := doc.AddTable(config2)
|
||||||
|
if table2 == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
styleConfig2 := &document.TableStyleConfig{
|
||||||
|
Template: document.TableStyleTemplateColorful1,
|
||||||
|
FirstRowHeader: true,
|
||||||
|
FirstColumnHeader: true,
|
||||||
|
BandedRows: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table2.ApplyTableStyle(styleConfig2)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("应用Colorful样式失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateCustomStyle 演示自定义表格样式
|
||||||
|
func demonstrateCustomStyle(doc *document.Document) {
|
||||||
|
doc.AddParagraph("7. 自定义表格样式演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 4,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"功能", "状态", "备注"},
|
||||||
|
{"登录", "完成", "已测试"},
|
||||||
|
{"注册", "开发中", "50%"},
|
||||||
|
{"支付", "计划中", "下个版本"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建自定义边框配置
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 12,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 12,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "D0D0D0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "D0D0D0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建自定义背景配置
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternPct10,
|
||||||
|
BackgroundColor: "E7F3FF",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用自定义样式
|
||||||
|
err := table.CreateCustomTableStyle("CustomBlue", "蓝色主题", borderConfig, shadingConfig, true)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("创建自定义表格样式失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateComplexStyle 演示复杂样式组合
|
||||||
|
func demonstrateComplexStyle(doc *document.Document) {
|
||||||
|
doc.AddParagraph("8. 复杂样式组合演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 5,
|
||||||
|
Cols: 4,
|
||||||
|
Width: 6000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"部门", "Q1", "Q2", "Q3"},
|
||||||
|
{"销售部", "120万", "135万", "150万"},
|
||||||
|
{"技术部", "80万", "90万", "95万"},
|
||||||
|
{"市场部", "60万", "70万", "85万"},
|
||||||
|
{"总计", "260万", "295万", "330万"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用基础样式
|
||||||
|
styleConfig := &document.TableStyleConfig{
|
||||||
|
Template: document.TableStyleTemplateColorful2,
|
||||||
|
FirstRowHeader: true,
|
||||||
|
LastRowTotal: true,
|
||||||
|
FirstColumnHeader: true,
|
||||||
|
BandedRows: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.ApplyTableStyle(styleConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("应用基础样式失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置特殊边框
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 8,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 8,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "B0B0B0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "B0B0B0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为标题行设置特殊背景
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternSolid,
|
||||||
|
BackgroundColor: "2E75B6",
|
||||||
|
ForegroundColor: "FFFFFF",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellShading(0, j, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置标题行背景失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为总计行设置特殊背景
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternSolid,
|
||||||
|
BackgroundColor: "FFFF99",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellShading(4, j, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置总计行背景失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateNoBorders 演示无边框表格
|
||||||
|
func demonstrateNoBorders(doc *document.Document) {
|
||||||
|
doc.AddParagraph("9. 无边框表格演示")
|
||||||
|
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"项目A", "项目B", "项目C"},
|
||||||
|
{"说明1", "说明2", "说明3"},
|
||||||
|
{"结果1", "结果2", "结果3"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除所有边框
|
||||||
|
err := table.RemoveTableBorders()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("移除表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置轻微的背景色以区分单元格
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
var bgColor string
|
||||||
|
if (i+j)%2 == 0 {
|
||||||
|
bgColor = "F8F8F8"
|
||||||
|
} else {
|
||||||
|
bgColor = "FFFFFF"
|
||||||
|
}
|
||||||
|
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternSolid,
|
||||||
|
BackgroundColor: bgColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellShading(i, j, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置单元格背景失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// demonstrateBorderStyles 演示各种边框样式
|
||||||
|
func demonstrateBorderStyles(doc *document.Document) {
|
||||||
|
doc.AddParagraph("10. 各种边框样式演示")
|
||||||
|
|
||||||
|
borderStyles := []struct {
|
||||||
|
style document.BorderStyle
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{document.BorderStyleSingle, "单线"},
|
||||||
|
{document.BorderStyleThick, "粗线"},
|
||||||
|
{document.BorderStyleDouble, "双线"},
|
||||||
|
{document.BorderStyleDotted, "点线"},
|
||||||
|
{document.BorderStyleDashed, "虚线"},
|
||||||
|
{document.BorderStyleDotDash, "点划线"},
|
||||||
|
{document.BorderStyleWave, "波浪线"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, styleInfo := range borderStyles {
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 3000,
|
||||||
|
Data: [][]string{
|
||||||
|
{fmt.Sprintf("样式%d", i+1), styleInfo.name},
|
||||||
|
{"演示", "数据"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
log.Fatalf("创建表格%d失败", i+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: styleInfo.style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: styleInfo.style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: styleInfo.style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: styleInfo.style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("设置表格%d边框失败: %v", i+1, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < len(borderStyles)-1 {
|
||||||
|
doc.AddParagraph("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
go.mod
3
go.mod
@@ -1,6 +1,3 @@
|
|||||||
module github.com/ZeroHawkeye/wordZero
|
module github.com/ZeroHawkeye/wordZero
|
||||||
|
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
require (
|
|
||||||
)
|
|
||||||
|
@@ -31,9 +31,26 @@ type Document struct {
|
|||||||
|
|
||||||
// Body 表示文档主体
|
// Body 表示文档主体
|
||||||
type Body struct {
|
type Body struct {
|
||||||
XMLName xml.Name `xml:"w:body"`
|
XMLName xml.Name `xml:"w:body"`
|
||||||
Paragraphs []Paragraph `xml:"w:p"`
|
Elements []interface{} `xml:"-"` // 不序列化此字段,使用自定义方法
|
||||||
Tables []Table `xml:"w:tbl"`
|
}
|
||||||
|
|
||||||
|
// MarshalXML 自定义XML序列化,按照元素顺序输出
|
||||||
|
func (b *Body) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||||
|
// 开始元素
|
||||||
|
if err := e.EncodeToken(start); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 序列化每个元素,保持顺序
|
||||||
|
for _, element := range b.Elements {
|
||||||
|
if err := e.Encode(element); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束元素
|
||||||
|
return e.EncodeToken(start.End())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BodyElement 文档主体元素接口
|
// BodyElement 文档主体元素接口
|
||||||
@@ -218,7 +235,7 @@ func New() *Document {
|
|||||||
|
|
||||||
doc := &Document{
|
doc := &Document{
|
||||||
Body: &Body{
|
Body: &Body{
|
||||||
Paragraphs: make([]Paragraph, 0),
|
Elements: make([]interface{}, 0),
|
||||||
},
|
},
|
||||||
styleManager: style.NewStyleManager(),
|
styleManager: style.NewStyleManager(),
|
||||||
parts: make(map[string][]byte),
|
parts: make(map[string][]byte),
|
||||||
@@ -283,6 +300,9 @@ func Open(filename string) (*Document, error) {
|
|||||||
Debugf("已读取文件部件: %s (%d 字节)", file.Name, len(data))
|
Debugf("已读取文件部件: %s (%d 字节)", file.Name, len(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化样式管理器
|
||||||
|
doc.styleManager = style.NewStyleManager()
|
||||||
|
|
||||||
// 解析主文档
|
// 解析主文档
|
||||||
if err := doc.parseDocument(); err != nil {
|
if err := doc.parseDocument(); err != nil {
|
||||||
Errorf("解析文档失败: %s", filename)
|
Errorf("解析文档失败: %s", filename)
|
||||||
@@ -400,7 +420,7 @@ func (d *Document) Save(filename string) error {
|
|||||||
// })
|
// })
|
||||||
func (d *Document) AddParagraph(text string) *Paragraph {
|
func (d *Document) AddParagraph(text string) *Paragraph {
|
||||||
Debugf("添加段落: %s", text)
|
Debugf("添加段落: %s", text)
|
||||||
p := Paragraph{
|
p := &Paragraph{
|
||||||
Runs: []Run{
|
Runs: []Run{
|
||||||
{
|
{
|
||||||
Text: Text{
|
Text: Text{
|
||||||
@@ -411,8 +431,8 @@ func (d *Document) AddParagraph(text string) *Paragraph {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Body.Paragraphs = append(d.Body.Paragraphs, p)
|
d.Body.Elements = append(d.Body.Elements, p)
|
||||||
return &d.Body.Paragraphs[len(d.Body.Paragraphs)-1]
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddFormattedParagraph 向文档添加一个格式化段落。
|
// AddFormattedParagraph 向文档添加一个格式化段落。
|
||||||
@@ -468,7 +488,7 @@ func (d *Document) AddFormattedParagraph(text string, format *TextFormat) *Parag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p := Paragraph{
|
p := &Paragraph{
|
||||||
Runs: []Run{
|
Runs: []Run{
|
||||||
{
|
{
|
||||||
Properties: runProps,
|
Properties: runProps,
|
||||||
@@ -480,8 +500,8 @@ func (d *Document) AddFormattedParagraph(text string, format *TextFormat) *Parag
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Body.Paragraphs = append(d.Body.Paragraphs, p)
|
d.Body.Elements = append(d.Body.Elements, p)
|
||||||
return &d.Body.Paragraphs[len(d.Body.Paragraphs)-1]
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAlignment 设置段落的对齐方式。
|
// SetAlignment 设置段落的对齐方式。
|
||||||
@@ -725,7 +745,7 @@ func (d *Document) AddHeadingParagraph(text string, level int) *Paragraph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建段落
|
// 创建段落
|
||||||
p := Paragraph{
|
p := &Paragraph{
|
||||||
Properties: paraProps,
|
Properties: paraProps,
|
||||||
Runs: []Run{
|
Runs: []Run{
|
||||||
{
|
{
|
||||||
@@ -738,8 +758,8 @@ func (d *Document) AddHeadingParagraph(text string, level int) *Paragraph {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Body.Paragraphs = append(d.Body.Paragraphs, p)
|
d.Body.Elements = append(d.Body.Elements, p)
|
||||||
return &d.Body.Paragraphs[len(d.Body.Paragraphs)-1]
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetStyle 设置段落的样式。
|
// SetStyle 设置段落的样式。
|
||||||
@@ -824,7 +844,11 @@ func (d *Document) parseDocument() error {
|
|||||||
Paragraphs []struct {
|
Paragraphs []struct {
|
||||||
XMLName xml.Name `xml:"p"`
|
XMLName xml.Name `xml:"p"`
|
||||||
Properties *struct {
|
Properties *struct {
|
||||||
XMLName xml.Name `xml:"pPr"`
|
XMLName xml.Name `xml:"pPr"`
|
||||||
|
ParagraphStyle *struct {
|
||||||
|
XMLName xml.Name `xml:"pStyle"`
|
||||||
|
Val string `xml:"val,attr"`
|
||||||
|
} `xml:"pStyle,omitempty"`
|
||||||
Spacing *struct {
|
Spacing *struct {
|
||||||
XMLName xml.Name `xml:"spacing"`
|
XMLName xml.Name `xml:"spacing"`
|
||||||
Before string `xml:"before,attr,omitempty"`
|
Before string `xml:"before,attr,omitempty"`
|
||||||
@@ -882,18 +906,24 @@ func (d *Document) parseDocument() error {
|
|||||||
|
|
||||||
// 转换为内部结构
|
// 转换为内部结构
|
||||||
d.Body = &Body{
|
d.Body = &Body{
|
||||||
Paragraphs: make([]Paragraph, len(doc.Body.Paragraphs)),
|
Elements: make([]interface{}, len(doc.Body.Paragraphs)),
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, p := range doc.Body.Paragraphs {
|
for i, p := range doc.Body.Paragraphs {
|
||||||
paragraph := Paragraph{
|
paragraph := &Paragraph{
|
||||||
Runs: make([]Run, len(p.Runs)),
|
Runs: make([]Run, len(p.Runs)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制段落属性
|
// 转换段落属性
|
||||||
if p.Properties != nil {
|
if p.Properties != nil {
|
||||||
paragraph.Properties = &ParagraphProperties{}
|
paragraph.Properties = &ParagraphProperties{}
|
||||||
|
|
||||||
|
if p.Properties.ParagraphStyle != nil {
|
||||||
|
paragraph.Properties.ParagraphStyle = &ParagraphStyle{
|
||||||
|
Val: p.Properties.ParagraphStyle.Val,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if p.Properties.Spacing != nil {
|
if p.Properties.Spacing != nil {
|
||||||
paragraph.Properties.Spacing = &Spacing{
|
paragraph.Properties.Spacing = &Spacing{
|
||||||
Before: p.Properties.Spacing.Before,
|
Before: p.Properties.Spacing.Before,
|
||||||
@@ -917,16 +947,13 @@ func (d *Document) parseDocument() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制运行和运行属性
|
|
||||||
for j, r := range p.Runs {
|
for j, r := range p.Runs {
|
||||||
run := Run{
|
run := Run{
|
||||||
Text: Text{
|
Text: Text{
|
||||||
Space: r.Text.Space,
|
|
||||||
Content: r.Text.Content,
|
Content: r.Text.Content,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制运行属性
|
|
||||||
if r.Properties != nil {
|
if r.Properties != nil {
|
||||||
run.Properties = &RunProperties{}
|
run.Properties = &RunProperties{}
|
||||||
|
|
||||||
@@ -960,10 +987,10 @@ func (d *Document) parseDocument() error {
|
|||||||
paragraph.Runs[j] = run
|
paragraph.Runs[j] = run
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Body.Paragraphs[i] = paragraph
|
d.Body.Elements[i] = paragraph
|
||||||
}
|
}
|
||||||
|
|
||||||
Infof("解析完成,共 %d 个段落", len(d.Body.Paragraphs))
|
Infof("解析完成,共 %d 个元素", len(d.Body.Elements))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,12 +1002,12 @@ func (d *Document) serializeDocument() error {
|
|||||||
type documentXML struct {
|
type documentXML struct {
|
||||||
XMLName xml.Name `xml:"w:document"`
|
XMLName xml.Name `xml:"w:document"`
|
||||||
Xmlns string `xml:"xmlns:w,attr"`
|
Xmlns string `xml:"xmlns:w,attr"`
|
||||||
Body Body `xml:"w:body"`
|
Body *Body `xml:"w:body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
doc := documentXML{
|
doc := documentXML{
|
||||||
Xmlns: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
Xmlns: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
Body: *d.Body,
|
Body: d.Body,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 序列化为XML
|
// 序列化为XML
|
||||||
@@ -1118,3 +1145,30 @@ func (d *Document) ToBytes() ([]byte, error) {
|
|||||||
|
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetParagraphs 获取所有段落
|
||||||
|
func (b *Body) GetParagraphs() []*Paragraph {
|
||||||
|
paragraphs := make([]*Paragraph, 0)
|
||||||
|
for _, element := range b.Elements {
|
||||||
|
if p, ok := element.(*Paragraph); ok {
|
||||||
|
paragraphs = append(paragraphs, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paragraphs
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTables 获取所有表格
|
||||||
|
func (b *Body) GetTables() []*Table {
|
||||||
|
tables := make([]*Table, 0)
|
||||||
|
for _, element := range b.Elements {
|
||||||
|
if t, ok := element.(*Table); ok {
|
||||||
|
tables = append(tables, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tables
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddElement 添加元素到文档主体
|
||||||
|
func (b *Body) AddElement(element interface{}) {
|
||||||
|
b.Elements = append(b.Elements, element)
|
||||||
|
}
|
||||||
|
@@ -25,8 +25,8 @@ func TestNewDocument(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证初始状态
|
// 验证初始状态
|
||||||
if len(doc.Body.Paragraphs) != 0 {
|
if len(doc.Body.GetParagraphs()) != 0 {
|
||||||
t.Errorf("Expected 0 paragraphs, got %d", len(doc.Body.Paragraphs))
|
t.Errorf("Expected 0 paragraphs, got %d", len(doc.Body.GetParagraphs()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证样式管理器初始化
|
// 验证样式管理器初始化
|
||||||
@@ -44,8 +44,8 @@ func TestAddParagraph(t *testing.T) {
|
|||||||
para := doc.AddParagraph(text)
|
para := doc.AddParagraph(text)
|
||||||
|
|
||||||
// 验证段落添加
|
// 验证段落添加
|
||||||
if len(doc.Body.Paragraphs) != 1 {
|
if len(doc.Body.GetParagraphs()) != 1 {
|
||||||
t.Errorf("Expected 1 paragraph, got %d", len(doc.Body.Paragraphs))
|
t.Errorf("Expected 1 paragraph, got %d", len(doc.Body.GetParagraphs()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证段落内容
|
// 验证段落内容
|
||||||
@@ -58,7 +58,8 @@ func TestAddParagraph(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证返回的指针是否正确
|
// 验证返回的指针是否正确
|
||||||
if &doc.Body.Paragraphs[0] != para {
|
paragraphs := doc.Body.GetParagraphs()
|
||||||
|
if paragraphs[0] != para {
|
||||||
t.Error("Returned paragraph pointer is incorrect")
|
t.Error("Returned paragraph pointer is incorrect")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,7 +136,7 @@ func TestAddFormattedParagraph(t *testing.T) {
|
|||||||
para := doc.AddFormattedParagraph(text, format)
|
para := doc.AddFormattedParagraph(text, format)
|
||||||
|
|
||||||
// 验证段落添加
|
// 验证段落添加
|
||||||
if len(doc.Body.Paragraphs) != 1 {
|
if len(doc.Body.GetParagraphs()) != 1 {
|
||||||
t.Error("Failed to add formatted paragraph")
|
t.Error("Failed to add formatted paragraph")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,8 +380,8 @@ func TestComplexDocument(t *testing.T) {
|
|||||||
mixed.AddFormattedText("文本。", nil)
|
mixed.AddFormattedText("文本。", nil)
|
||||||
|
|
||||||
// 验证文档结构
|
// 验证文档结构
|
||||||
if len(doc.Body.Paragraphs) != 6 {
|
if len(doc.Body.GetParagraphs()) != 6 {
|
||||||
t.Errorf("Expected 6 paragraphs, got %d", len(doc.Body.Paragraphs))
|
t.Errorf("Expected 6 paragraphs, got %d", len(doc.Body.GetParagraphs()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存并验证
|
// 保存并验证
|
||||||
@@ -416,13 +417,13 @@ func TestDocumentOpen(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证文档内容
|
// 验证文档内容
|
||||||
if len(loadedDoc.Body.Paragraphs) != 3 {
|
if len(loadedDoc.Body.GetParagraphs()) != 3 {
|
||||||
t.Errorf("Expected 3 paragraphs, got %d", len(loadedDoc.Body.Paragraphs))
|
t.Errorf("Expected 3 paragraphs, got %d", len(loadedDoc.Body.GetParagraphs()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证第一段内容
|
// 验证第一段内容
|
||||||
if len(loadedDoc.Body.Paragraphs[0].Runs) > 0 {
|
if len(loadedDoc.Body.GetParagraphs()[0].Runs) > 0 {
|
||||||
content := loadedDoc.Body.Paragraphs[0].Runs[0].Text.Content
|
content := loadedDoc.Body.GetParagraphs()[0].Runs[0].Text.Content
|
||||||
if content != "第一段" {
|
if content != "第一段" {
|
||||||
t.Errorf("Expected '第一段', got '%s'", content)
|
t.Errorf("Expected '第一段', got '%s'", content)
|
||||||
}
|
}
|
||||||
@@ -565,8 +566,8 @@ func TestMemoryUsage(t *testing.T) {
|
|||||||
doc.AddParagraph("内存测试段落")
|
doc.AddParagraph("内存测试段落")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(doc.Body.Paragraphs) != numParagraphs {
|
if len(doc.Body.GetParagraphs()) != numParagraphs {
|
||||||
t.Errorf("Expected %d paragraphs, got %d", numParagraphs, len(doc.Body.Paragraphs))
|
t.Errorf("Expected %d paragraphs, got %d", numParagraphs, len(doc.Body.GetParagraphs()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 测试保存大文档
|
// 测试保存大文档
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -100,15 +100,15 @@ func TestAddTable(t *testing.T) {
|
|||||||
Width: 6000,
|
Width: 6000,
|
||||||
}
|
}
|
||||||
|
|
||||||
initialTableCount := len(doc.Body.Tables)
|
initialTableCount := len(doc.Body.GetTables())
|
||||||
table := doc.AddTable(config)
|
table := doc.AddTable(config)
|
||||||
|
|
||||||
if table == nil {
|
if table == nil {
|
||||||
t.Fatal("添加表格失败")
|
t.Fatal("添加表格失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(doc.Body.Tables) != initialTableCount+1 {
|
if len(doc.Body.GetTables()) != initialTableCount+1 {
|
||||||
t.Errorf("期望表格数量%d,实际%d", initialTableCount+1, len(doc.Body.Tables))
|
t.Errorf("期望表格数量%d,实际%d", initialTableCount+1, len(doc.Body.GetTables()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1221,3 +1221,292 @@ func TestTextDirectionConstants(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRowHeight 测试行高设置功能
|
||||||
|
func TestRowHeight(t *testing.T) {
|
||||||
|
doc := New()
|
||||||
|
|
||||||
|
config := &TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.CreateTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置固定行高
|
||||||
|
heightConfig := &RowHeightConfig{
|
||||||
|
Height: 30,
|
||||||
|
Rule: RowHeightExact,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetRowHeight(0, heightConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置行高失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试获取行高
|
||||||
|
retrievedConfig, err := table.GetRowHeight(0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("获取行高失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if retrievedConfig.Height != 30 {
|
||||||
|
t.Errorf("期望行高30,实际%d", retrievedConfig.Height)
|
||||||
|
}
|
||||||
|
|
||||||
|
if retrievedConfig.Rule != RowHeightExact {
|
||||||
|
t.Errorf("期望行高规则%s,实际%s", RowHeightExact, retrievedConfig.Rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试批量设置行高
|
||||||
|
batchConfig := &RowHeightConfig{
|
||||||
|
Height: 25,
|
||||||
|
Rule: RowHeightMinimum,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetRowHeightRange(1, 2, batchConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("批量设置行高失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证批量设置结果
|
||||||
|
for i := 1; i <= 2; i++ {
|
||||||
|
config, err := table.GetRowHeight(i)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("获取第%d行高度失败: %v", i, err)
|
||||||
|
}
|
||||||
|
if config.Height != 25 {
|
||||||
|
t.Errorf("第%d行期望高度25,实际%d", i, config.Height)
|
||||||
|
}
|
||||||
|
if config.Rule != RowHeightMinimum {
|
||||||
|
t.Errorf("第%d行期望规则%s,实际%s", i, RowHeightMinimum, config.Rule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试无效索引
|
||||||
|
err = table.SetRowHeight(10, heightConfig)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("期望设置无效行索引失败,但成功了")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = table.GetRowHeight(10)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("期望获取无效行索引失败,但成功了")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTableLayout 测试表格布局和定位功能
|
||||||
|
func TestTableLayout(t *testing.T) {
|
||||||
|
doc := New()
|
||||||
|
|
||||||
|
config := &TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.CreateTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置表格布局
|
||||||
|
layoutConfig := &TableLayoutConfig{
|
||||||
|
Alignment: TableAlignCenter,
|
||||||
|
TextWrap: TextWrapNone,
|
||||||
|
Position: PositionInline,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableLayout(layoutConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置表格布局失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试获取表格布局
|
||||||
|
retrievedLayout := table.GetTableLayout()
|
||||||
|
if retrievedLayout.Alignment != TableAlignCenter {
|
||||||
|
t.Errorf("期望对齐方式%s,实际%s", TableAlignCenter, retrievedLayout.Alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试快捷方法设置对齐
|
||||||
|
err = table.SetTableAlignment(TableAlignRight)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置表格对齐失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retrievedLayout = table.GetTableLayout()
|
||||||
|
if retrievedLayout.Alignment != TableAlignRight {
|
||||||
|
t.Errorf("期望对齐方式%s,实际%s", TableAlignRight, retrievedLayout.Alignment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTablePageBreak 测试表格分页控制功能
|
||||||
|
func TestTablePageBreak(t *testing.T) {
|
||||||
|
doc := New()
|
||||||
|
|
||||||
|
config := &TableConfig{
|
||||||
|
Rows: 4,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.CreateTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置行禁止跨页分割
|
||||||
|
err := table.SetRowKeepTogether(0, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置行禁止跨页分割失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试检查行是否禁止跨页分割
|
||||||
|
keepTogether, err := table.IsRowKeepTogether(0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("检查行跨页分割设置失败: %v", err)
|
||||||
|
}
|
||||||
|
if !keepTogether {
|
||||||
|
t.Error("期望行禁止跨页分割为true,实际为false")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置标题行
|
||||||
|
err = table.SetRowAsHeader(0, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置标题行失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试检查是否为标题行
|
||||||
|
isHeader, err := table.IsRowHeader(0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("检查标题行设置失败: %v", err)
|
||||||
|
}
|
||||||
|
if !isHeader {
|
||||||
|
t.Error("期望第0行为标题行,实际不是")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置标题行范围
|
||||||
|
err = table.SetHeaderRows(0, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置标题行范围失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证标题行范围设置
|
||||||
|
for i := 0; i <= 1; i++ {
|
||||||
|
isHeader, err := table.IsRowHeader(i)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("检查第%d行标题行设置失败: %v", i, err)
|
||||||
|
}
|
||||||
|
if !isHeader {
|
||||||
|
t.Errorf("期望第%d行为标题行,实际不是", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试表格分页信息
|
||||||
|
breakInfo := table.GetTableBreakInfo()
|
||||||
|
if breakInfo["total_rows"] != 4 {
|
||||||
|
t.Errorf("期望总行数4,实际%v", breakInfo["total_rows"])
|
||||||
|
}
|
||||||
|
if breakInfo["header_rows"] != 2 {
|
||||||
|
t.Errorf("期望标题行数2,实际%v", breakInfo["header_rows"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试表格分页配置
|
||||||
|
pageBreakConfig := &TablePageBreakConfig{
|
||||||
|
KeepWithNext: true,
|
||||||
|
KeepLines: true,
|
||||||
|
PageBreakBefore: false,
|
||||||
|
WidowControl: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetTablePageBreak(pageBreakConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置表格分页配置失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试行与下一行保持在同一页
|
||||||
|
err = table.SetRowKeepWithNext(1, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("设置行与下一行保持在同一页失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试无效索引
|
||||||
|
err = table.SetRowKeepTogether(10, true)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("期望设置无效行索引失败,但成功了")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetRowAsHeader(10, true)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("期望设置无效行索引失败,但成功了")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = table.IsRowHeader(10)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("期望检查无效行索引失败,但成功了")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = table.IsRowKeepTogether(10)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("期望检查无效行索引失败,但成功了")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRowHeightConstants 测试行高规则常量
|
||||||
|
func TestRowHeightConstants(t *testing.T) {
|
||||||
|
// 验证行高规则常量定义正确
|
||||||
|
if RowHeightAuto != "auto" {
|
||||||
|
t.Errorf("期望RowHeightAuto为'auto',实际'%s'", RowHeightAuto)
|
||||||
|
}
|
||||||
|
if RowHeightMinimum != "atLeast" {
|
||||||
|
t.Errorf("期望RowHeightMinimum为'atLeast',实际'%s'", RowHeightMinimum)
|
||||||
|
}
|
||||||
|
if RowHeightExact != "exact" {
|
||||||
|
t.Errorf("期望RowHeightExact为'exact',实际'%s'", RowHeightExact)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTableAlignmentConstants 测试表格对齐常量
|
||||||
|
func TestTableAlignmentConstants(t *testing.T) {
|
||||||
|
// 验证表格对齐常量定义正确
|
||||||
|
if TableAlignLeft != "left" {
|
||||||
|
t.Errorf("期望TableAlignLeft为'left',实际'%s'", TableAlignLeft)
|
||||||
|
}
|
||||||
|
if TableAlignCenter != "center" {
|
||||||
|
t.Errorf("期望TableAlignCenter为'center',实际'%s'", TableAlignCenter)
|
||||||
|
}
|
||||||
|
if TableAlignRight != "right" {
|
||||||
|
t.Errorf("期望TableAlignRight为'right',实际'%s'", TableAlignRight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTableRowPropertiesExtensions 测试TableRowProperties扩展方法
|
||||||
|
func TestTableRowPropertiesExtensions(t *testing.T) {
|
||||||
|
trp := &TableRowProperties{}
|
||||||
|
|
||||||
|
// 测试SetCantSplit方法
|
||||||
|
trp.SetCantSplit(true)
|
||||||
|
if trp.CantSplit == nil || trp.CantSplit.Val != "1" {
|
||||||
|
t.Error("设置CantSplit失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
trp.SetCantSplit(false)
|
||||||
|
if trp.CantSplit != nil {
|
||||||
|
t.Error("清除CantSplit失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试SetTblHeader方法
|
||||||
|
trp.SetTblHeader(true)
|
||||||
|
if trp.TblHeader == nil || trp.TblHeader.Val != "1" {
|
||||||
|
t.Error("设置TblHeader失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
trp.SetTblHeader(false)
|
||||||
|
if trp.TblHeader != nil {
|
||||||
|
t.Error("清除TblHeader失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -50,11 +50,12 @@ func TestOpenDocument(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证内容
|
// 验证内容
|
||||||
if len(openedDoc.Body.Paragraphs) != 1 {
|
paragraphs := openedDoc.Body.GetParagraphs()
|
||||||
t.Fatalf("Expected 1 paragraph, got %d", len(openedDoc.Body.Paragraphs))
|
if len(paragraphs) != 1 {
|
||||||
|
t.Fatalf("Expected 1 paragraph, got %d", len(paragraphs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if openedDoc.Body.Paragraphs[0].Runs[0].Text.Content != "Test paragraph" {
|
if paragraphs[0].Runs[0].Text.Content != "Test paragraph" {
|
||||||
t.Fatalf("Paragraph content mismatch")
|
t.Fatalf("Paragraph content mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
779
test/table_style_test.go
Normal file
779
test/table_style_test.go
Normal file
@@ -0,0 +1,779 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ZeroHawkeye/wordZero/pkg/document"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestTableBorders 测试表格边框功能
|
||||||
|
func TestTableBorders(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 5000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"姓名", "年龄", "职业"},
|
||||||
|
{"张三", "25", "工程师"},
|
||||||
|
{"李四", "30", "设计师"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置表格边框
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 12,
|
||||||
|
Color: "FF0000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "0000FF",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 6,
|
||||||
|
Color: "00FF00",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDashed,
|
||||||
|
Width: 6,
|
||||||
|
Color: "FF00FF",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDotted,
|
||||||
|
Width: 4,
|
||||||
|
Color: "808080",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "808080",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("表格边框设置成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCellBorders 测试单元格边框功能
|
||||||
|
func TestCellBorders(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 3000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"A1", "B1"},
|
||||||
|
{"A2", "B2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置单元格边框
|
||||||
|
cellBorderConfig := &document.CellBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 8,
|
||||||
|
Color: "FF0000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "0000FF",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 6,
|
||||||
|
Color: "00FF00",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDashed,
|
||||||
|
Width: 4,
|
||||||
|
Color: "FF00FF",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
DiagDown: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 2,
|
||||||
|
Color: "FFFF00",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetCellBorders(0, 0, cellBorderConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置单元格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("单元格边框设置成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTableShading 测试表格背景功能
|
||||||
|
func TestTableShading(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 4000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"产品", "价格"},
|
||||||
|
{"产品A", "100"},
|
||||||
|
{"产品B", "200"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置表格背景
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternPct25,
|
||||||
|
ForegroundColor: "000000",
|
||||||
|
BackgroundColor: "E0E0E0",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableShading(shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置表格背景失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("表格背景设置成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCellShading 测试单元格背景功能
|
||||||
|
func TestCellShading(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"A", "B", "C"},
|
||||||
|
{"1", "2", "3"},
|
||||||
|
{"X", "Y", "Z"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置单元格背景
|
||||||
|
testCases := []struct {
|
||||||
|
row int
|
||||||
|
col int
|
||||||
|
backgroundColor string
|
||||||
|
pattern document.ShadingPattern
|
||||||
|
}{
|
||||||
|
{0, 0, "FF0000", document.ShadingPatternSolid}, // 红色实色
|
||||||
|
{0, 1, "00FF00", document.ShadingPatternPct50}, // 绿色50%
|
||||||
|
{0, 2, "0000FF", document.ShadingPatternPct25}, // 蓝色25%
|
||||||
|
{1, 0, "FFFF00", document.ShadingPatternSolid}, // 黄色实色
|
||||||
|
{1, 1, "FF00FF", document.ShadingPatternPct75}, // 紫色75%
|
||||||
|
{1, 2, "00FFFF", document.ShadingPatternPct10}, // 青色10%
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: tc.pattern,
|
||||||
|
BackgroundColor: tc.backgroundColor,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetCellShading(tc.row, tc.col, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置单元格(%d,%d)背景失败: %v", tc.row, tc.col, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("单元格背景设置成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAlternatingRowColors 测试奇偶行颜色交替
|
||||||
|
func TestAlternatingRowColors(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 5,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"序号", "姓名", "分数"},
|
||||||
|
{"1", "张三", "85"},
|
||||||
|
{"2", "李四", "92"},
|
||||||
|
{"3", "王五", "78"},
|
||||||
|
{"4", "赵六", "95"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试设置奇偶行颜色交替
|
||||||
|
err := table.SetAlternatingRowColors("F0F0F0", "FFFFFF")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置奇偶行颜色交替失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("奇偶行颜色交替设置成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTableStyleTemplates 测试表格样式模板
|
||||||
|
func TestTableStyleTemplates(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 4,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 5000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"项目", "预算", "实际"},
|
||||||
|
{"开发", "10000", "9500"},
|
||||||
|
{"测试", "5000", "5200"},
|
||||||
|
{"总计", "15000", "14700"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试应用表格样式模板
|
||||||
|
styleConfig := &document.TableStyleConfig{
|
||||||
|
Template: document.TableStyleTemplateGrid,
|
||||||
|
FirstRowHeader: true,
|
||||||
|
LastRowTotal: true,
|
||||||
|
BandedRows: true,
|
||||||
|
BandedColumns: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.ApplyTableStyle(styleConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("应用表格样式模板失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("表格样式模板应用成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCustomTableStyle 测试自定义表格样式
|
||||||
|
func TestCustomTableStyle(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 3,
|
||||||
|
Cols: 3,
|
||||||
|
Width: 4500,
|
||||||
|
Data: [][]string{
|
||||||
|
{"功能", "状态", "备注"},
|
||||||
|
{"登录", "完成", "已测试"},
|
||||||
|
{"注册", "开发中", "50%"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建自定义边框配置
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 12,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleThick,
|
||||||
|
Width: 12,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "D0D0D0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "D0D0D0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建自定义背景配置
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternPct10,
|
||||||
|
BackgroundColor: "E7F3FF",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试创建自定义表格样式
|
||||||
|
err := table.CreateCustomTableStyle("CustomStyle1", "自定义样式1", borderConfig, shadingConfig, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("创建自定义表格样式失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("自定义表格样式创建成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRemoveBorders 测试移除边框功能
|
||||||
|
func TestRemoveBorders(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 3000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"A", "B"},
|
||||||
|
{"C", "D"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先设置边框
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试移除表格边框
|
||||||
|
err = table.RemoveTableBorders()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("移除表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试移除单元格边框
|
||||||
|
err = table.RemoveCellBorders(0, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("移除单元格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("移除边框功能测试成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestComplexTableStyle 测试复杂表格样式组合
|
||||||
|
func TestComplexTableStyle(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 5,
|
||||||
|
Cols: 4,
|
||||||
|
Width: 6000,
|
||||||
|
Data: [][]string{
|
||||||
|
{"部门", "Q1", "Q2", "Q3"},
|
||||||
|
{"销售部", "120", "135", "150"},
|
||||||
|
{"技术部", "80", "90", "95"},
|
||||||
|
{"市场部", "60", "70", "85"},
|
||||||
|
{"总计", "260", "295", "330"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用样式模板
|
||||||
|
styleConfig := &document.TableStyleConfig{
|
||||||
|
Template: document.TableStyleTemplateColorful1,
|
||||||
|
FirstRowHeader: true,
|
||||||
|
LastRowTotal: true,
|
||||||
|
FirstColumnHeader: true,
|
||||||
|
BandedRows: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.ApplyTableStyle(styleConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("应用表格样式失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置自定义边框
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 8,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleDouble,
|
||||||
|
Width: 8,
|
||||||
|
Color: "2E75B6",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "B0B0B0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "B0B0B0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为标题行设置特殊背景
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternSolid,
|
||||||
|
BackgroundColor: "2E75B6",
|
||||||
|
ForegroundColor: "FFFFFF",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellShading(0, j, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置标题行背景失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为总计行设置特殊背景
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: document.ShadingPatternSolid,
|
||||||
|
BackgroundColor: "FFFF99",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellShading(4, j, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置总计行背景失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("复杂表格样式组合测试成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
// BenchmarkTableStyleOperations 表格样式操作性能测试
|
||||||
|
func BenchmarkTableStyleOperations(b *testing.B) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
b.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 10,
|
||||||
|
Cols: 5,
|
||||||
|
Width: 7500,
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
b.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideH: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "C0C0C0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
InsideV: &document.BorderConfig{
|
||||||
|
Style: document.BorderStyleSingle,
|
||||||
|
Width: 4,
|
||||||
|
Color: "C0C0C0",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err := table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
b.Fatalf("设置表格边框失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestBorderStyles 测试各种边框样式
|
||||||
|
func TestBorderStyles(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试边框样式
|
||||||
|
borderStyles := []document.BorderStyle{
|
||||||
|
document.BorderStyleNone,
|
||||||
|
document.BorderStyleSingle,
|
||||||
|
document.BorderStyleThick,
|
||||||
|
document.BorderStyleDouble,
|
||||||
|
document.BorderStyleDotted,
|
||||||
|
document.BorderStyleDashed,
|
||||||
|
document.BorderStyleDotDash,
|
||||||
|
document.BorderStyleWave,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, style := range borderStyles {
|
||||||
|
// 为每种样式创建一个表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: 2,
|
||||||
|
Cols: 2,
|
||||||
|
Width: 2000,
|
||||||
|
Data: [][]string{
|
||||||
|
{fmt.Sprintf("样式%d", i+1), string(style)},
|
||||||
|
{"测试", "数据"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatalf("创建表格%d失败", i+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
borderConfig := &document.TableBorderConfig{
|
||||||
|
Top: &document.BorderConfig{
|
||||||
|
Style: style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Left: &document.BorderConfig{
|
||||||
|
Style: style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Bottom: &document.BorderConfig{
|
||||||
|
Style: style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
Right: &document.BorderConfig{
|
||||||
|
Style: style,
|
||||||
|
Width: 6,
|
||||||
|
Color: "000000",
|
||||||
|
Space: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := table.SetTableBorders(borderConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置表格%d边框失败: %v", i+1, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("边框样式测试完成")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestShadingPatterns 测试各种底纹图案
|
||||||
|
func TestShadingPatterns(t *testing.T) {
|
||||||
|
// 创建文档
|
||||||
|
doc := document.New()
|
||||||
|
if doc == nil {
|
||||||
|
t.Fatal("创建文档失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试底纹图案
|
||||||
|
patterns := []document.ShadingPattern{
|
||||||
|
document.ShadingPatternClear,
|
||||||
|
document.ShadingPatternSolid,
|
||||||
|
document.ShadingPatternPct25,
|
||||||
|
document.ShadingPatternPct50,
|
||||||
|
document.ShadingPatternPct75,
|
||||||
|
document.ShadingPatternHorzStripe,
|
||||||
|
document.ShadingPatternVertStripe,
|
||||||
|
document.ShadingPatternDiagStripe,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建表格
|
||||||
|
config := &document.TableConfig{
|
||||||
|
Rows: len(patterns),
|
||||||
|
Cols: 2,
|
||||||
|
Width: 3000,
|
||||||
|
}
|
||||||
|
|
||||||
|
table := doc.AddTable(config)
|
||||||
|
if table == nil {
|
||||||
|
t.Fatal("创建表格失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, pattern := range patterns {
|
||||||
|
// 设置单元格内容
|
||||||
|
err := table.SetCellText(i, 0, fmt.Sprintf("图案%d", i+1))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置单元格文本失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellText(i, 1, string(pattern))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置单元格文本失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置单元格背景
|
||||||
|
shadingConfig := &document.ShadingConfig{
|
||||||
|
Pattern: pattern,
|
||||||
|
BackgroundColor: "C0C0C0",
|
||||||
|
ForegroundColor: "000000",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = table.SetCellShading(i, 1, shadingConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("设置单元格背景失败: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("底纹图案测试完成")
|
||||||
|
}
|
@@ -30,15 +30,16 @@ func TestTextFormatting(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查段落是否被正确添加
|
// 检查段落是否被正确添加
|
||||||
if len(doc.Body.Paragraphs) != 1 {
|
paragraphs := doc.Body.GetParagraphs()
|
||||||
t.Errorf("预期1个段落,但得到了 %d 个", len(doc.Body.Paragraphs))
|
if len(paragraphs) != 1 {
|
||||||
|
t.Errorf("预期1个段落,但得到了 %d 个", len(paragraphs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查运行属性
|
// 检查运行属性
|
||||||
if len(doc.Body.Paragraphs[0].Runs) == 0 {
|
if len(paragraphs[0].Runs) == 0 {
|
||||||
t.Error("段落中没有运行")
|
t.Error("段落中没有运行")
|
||||||
} else {
|
} else {
|
||||||
run := doc.Body.Paragraphs[0].Runs[0]
|
run := paragraphs[0].Runs[0]
|
||||||
if run.Properties == nil {
|
if run.Properties == nil {
|
||||||
t.Error("运行属性为空")
|
t.Error("运行属性为空")
|
||||||
} else {
|
} else {
|
||||||
@@ -199,12 +200,13 @@ func TestDocumentSaveAndOpen(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证内容
|
// 验证内容
|
||||||
if len(openedDoc.Body.Paragraphs) != 1 {
|
paragraphs := openedDoc.Body.GetParagraphs()
|
||||||
t.Errorf("预期1个段落,但得到了 %d 个", len(openedDoc.Body.Paragraphs))
|
if len(paragraphs) != 1 {
|
||||||
|
t.Errorf("预期1个段落,但得到了 %d 个", len(paragraphs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(openedDoc.Body.Paragraphs) > 0 {
|
if len(paragraphs) > 0 {
|
||||||
para := openedDoc.Body.Paragraphs[0]
|
para := paragraphs[0]
|
||||||
|
|
||||||
// 检查对齐方式
|
// 检查对齐方式
|
||||||
if para.Properties == nil || para.Properties.Justification == nil {
|
if para.Properties == nil || para.Properties.Justification == nil {
|
||||||
|
48
test_runner.go
Normal file
48
test_runner.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("Running tests for WordZero project...")
|
||||||
|
|
||||||
|
// 运行pkg包的测试
|
||||||
|
fmt.Println("\n=== Testing pkg packages ===")
|
||||||
|
cmd := exec.Command("go", "test", "./pkg/...", "-v")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("pkg tests failed: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("pkg tests passed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行test包的测试
|
||||||
|
fmt.Println("\n=== Testing test package ===")
|
||||||
|
cmd = exec.Command("go", "test", "./test", "-v")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("test package failed: %v\n", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("test package passed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行所有测试
|
||||||
|
fmt.Println("\n=== Running all tests ===")
|
||||||
|
cmd = exec.Command("go", "test", "./...", "-cover")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Overall tests failed: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Println("All tests passed!")
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user