mirror of
https://github.com/ZeroHawkeye/wordZero.git
synced 2025-10-05 15:56:57 +08:00
更新README.md,完善表格操作功能。
This commit is contained in:
599
README.md
599
README.md
@@ -18,6 +18,59 @@ WordZero 是一个使用 Golang 实现的 Word 文档操作库,提供基础的
|
||||
- ⚡ **高性能**: 零依赖的纯Go实现,内存占用低
|
||||
- 🔧 **易于使用**: 简洁的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个自定义样式进行功能展示。
|
||||
|
||||
### 🚧 规划中功能
|
||||
|
||||
#### 表格功能
|
||||
|
||||
##### 表格基础操作
|
||||
@@ -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] 图案填充支持
|
||||
|
||||
### 🚧 规划中功能
|
||||
|
||||
#### 表格功能完善
|
||||
|
||||
##### 高级表格功能
|
||||
- [ ] 表格排序功能(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
|
||||
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/style_demo/
|
||||
|
||||
# 运行表格演示
|
||||
go run ./examples/table/
|
||||
|
||||
# 运行表格布局和尺寸演示
|
||||
go run ./examples/table_layout/
|
||||
|
||||
# 运行格式化演示
|
||||
go run ./examples/formatting/
|
||||
```
|
||||
|
||||
## 测试
|
||||
## 开发指南
|
||||
|
||||
### 运行测试
|
||||
### 项目开发规则
|
||||
|
||||
```bash
|
||||
# 运行所有测试
|
||||
go test ./...
|
||||
1. **项目结构**: 符合golang依赖库的项目结构,完善的测试流程
|
||||
2. **模块化设计**: 规范的项目结构,避免文件循环依赖和过渡耦合
|
||||
3. **测试规范**: 测试用例尽量放在test目录下
|
||||
4. **文档维护**: 每次完成一个功能点需更新README文件的待办列表
|
||||
|
||||
# 运行特定包测试
|
||||
go test ./pkg/document/
|
||||
go test ./pkg/style/
|
||||
### 贡献指南
|
||||
|
||||
# 运行测试并显示覆盖率
|
||||
go test -cover ./...
|
||||
欢迎提交 Issue 和 Pull Request!在提交代码前请确保:
|
||||
|
||||
# 生成详细的测试报告
|
||||
go test -v -coverprofile=coverage.out ./...
|
||||
go tool cover -html=coverage.out
|
||||
```
|
||||
|
||||
### 测试覆盖
|
||||
|
||||
- **文档操作**: 基础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. 更新相关文档
|
||||
1. 代码符合 Go 代码规范
|
||||
2. 添加必要的测试用例
|
||||
3. 更新相关文档
|
||||
4. 确保所有测试通过
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目采用 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语言社区的优秀库和工具
|
||||
本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。
|
@@ -111,7 +111,7 @@ doc.Save("example.docx")`
|
||||
stylesInfo.SetStyle(style.StyleNormal)
|
||||
|
||||
// 确保输出目录存在
|
||||
outputFile := "../output/basic_example.docx"
|
||||
outputFile := "examples/output/basic_example.docx"
|
||||
outputDir := filepath.Dir(outputFile)
|
||||
|
||||
fmt.Printf("📁 检查输出目录: %s\n", outputDir)
|
||||
|
@@ -26,7 +26,7 @@ func main() {
|
||||
doc.AddParagraph("• 打开现有文档")
|
||||
|
||||
// 保存文档
|
||||
outputFile := "output/example_document.docx"
|
||||
outputFile := "examples/output/example_document.docx"
|
||||
err := doc.Save(outputFile)
|
||||
if err != nil {
|
||||
log.Fatalf("保存文档失败: %v", err)
|
||||
@@ -41,11 +41,11 @@ func main() {
|
||||
log.Fatalf("打开文档失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("文档包含 %d 个段落\n", len(openedDoc.Body.Paragraphs))
|
||||
fmt.Printf("文档包含 %d 个段落\n", len(openedDoc.Body.GetParagraphs()))
|
||||
|
||||
// 打印所有段落内容
|
||||
fmt.Println("\n文档内容:")
|
||||
for i, para := range openedDoc.Body.Paragraphs {
|
||||
for i, para := range openedDoc.Body.GetParagraphs() {
|
||||
if len(para.Runs) > 0 {
|
||||
fmt.Printf("段落 %d: %s\n", i+1, para.Runs[0].Text.Content)
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ func main() {
|
||||
p5.SetAlignment(document.AlignRight)
|
||||
|
||||
// 保存文档
|
||||
err := doc.Save("../output/formatted_document.docx")
|
||||
err := doc.Save("examples/output/formatted_document.docx")
|
||||
if err != nil {
|
||||
log.Fatalf("保存文档失败: %v", err)
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ func main() {
|
||||
demonstrateStyleManagement(quickAPI)
|
||||
|
||||
// 保存文档
|
||||
outputFile := "../output/styled_document_demo.docx"
|
||||
outputFile := "examples/output/styled_document_demo.docx"
|
||||
err := doc.Save(outputFile)
|
||||
if err != nil {
|
||||
log.Fatalf("保存文档失败: %v", err)
|
||||
|
@@ -206,7 +206,7 @@ func demonstrateTableCopyAndClear(doc *document.Document) {
|
||||
copiedTable.SetCellText(1, 1, "复制4")
|
||||
|
||||
// 将复制的表格添加到文档
|
||||
doc.Body.Tables = append(doc.Body.Tables, *copiedTable)
|
||||
doc.Body.AddElement(copiedTable)
|
||||
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("")
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,9 +31,26 @@ type Document struct {
|
||||
|
||||
// Body 表示文档主体
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"w:body"`
|
||||
Paragraphs []Paragraph `xml:"w:p"`
|
||||
Tables []Table `xml:"w:tbl"`
|
||||
XMLName xml.Name `xml:"w:body"`
|
||||
Elements []interface{} `xml:"-"` // 不序列化此字段,使用自定义方法
|
||||
}
|
||||
|
||||
// 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 文档主体元素接口
|
||||
@@ -218,7 +235,7 @@ func New() *Document {
|
||||
|
||||
doc := &Document{
|
||||
Body: &Body{
|
||||
Paragraphs: make([]Paragraph, 0),
|
||||
Elements: make([]interface{}, 0),
|
||||
},
|
||||
styleManager: style.NewStyleManager(),
|
||||
parts: make(map[string][]byte),
|
||||
@@ -283,6 +300,9 @@ func Open(filename string) (*Document, error) {
|
||||
Debugf("已读取文件部件: %s (%d 字节)", file.Name, len(data))
|
||||
}
|
||||
|
||||
// 初始化样式管理器
|
||||
doc.styleManager = style.NewStyleManager()
|
||||
|
||||
// 解析主文档
|
||||
if err := doc.parseDocument(); err != nil {
|
||||
Errorf("解析文档失败: %s", filename)
|
||||
@@ -400,7 +420,7 @@ func (d *Document) Save(filename string) error {
|
||||
// })
|
||||
func (d *Document) AddParagraph(text string) *Paragraph {
|
||||
Debugf("添加段落: %s", text)
|
||||
p := Paragraph{
|
||||
p := &Paragraph{
|
||||
Runs: []Run{
|
||||
{
|
||||
Text: Text{
|
||||
@@ -411,8 +431,8 @@ func (d *Document) AddParagraph(text string) *Paragraph {
|
||||
},
|
||||
}
|
||||
|
||||
d.Body.Paragraphs = append(d.Body.Paragraphs, p)
|
||||
return &d.Body.Paragraphs[len(d.Body.Paragraphs)-1]
|
||||
d.Body.Elements = append(d.Body.Elements, p)
|
||||
return p
|
||||
}
|
||||
|
||||
// AddFormattedParagraph 向文档添加一个格式化段落。
|
||||
@@ -468,7 +488,7 @@ func (d *Document) AddFormattedParagraph(text string, format *TextFormat) *Parag
|
||||
}
|
||||
}
|
||||
|
||||
p := Paragraph{
|
||||
p := &Paragraph{
|
||||
Runs: []Run{
|
||||
{
|
||||
Properties: runProps,
|
||||
@@ -480,8 +500,8 @@ func (d *Document) AddFormattedParagraph(text string, format *TextFormat) *Parag
|
||||
},
|
||||
}
|
||||
|
||||
d.Body.Paragraphs = append(d.Body.Paragraphs, p)
|
||||
return &d.Body.Paragraphs[len(d.Body.Paragraphs)-1]
|
||||
d.Body.Elements = append(d.Body.Elements, p)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetAlignment 设置段落的对齐方式。
|
||||
@@ -725,7 +745,7 @@ func (d *Document) AddHeadingParagraph(text string, level int) *Paragraph {
|
||||
}
|
||||
|
||||
// 创建段落
|
||||
p := Paragraph{
|
||||
p := &Paragraph{
|
||||
Properties: paraProps,
|
||||
Runs: []Run{
|
||||
{
|
||||
@@ -738,8 +758,8 @@ func (d *Document) AddHeadingParagraph(text string, level int) *Paragraph {
|
||||
},
|
||||
}
|
||||
|
||||
d.Body.Paragraphs = append(d.Body.Paragraphs, p)
|
||||
return &d.Body.Paragraphs[len(d.Body.Paragraphs)-1]
|
||||
d.Body.Elements = append(d.Body.Elements, p)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetStyle 设置段落的样式。
|
||||
@@ -824,7 +844,11 @@ func (d *Document) parseDocument() error {
|
||||
Paragraphs []struct {
|
||||
XMLName xml.Name `xml:"p"`
|
||||
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 {
|
||||
XMLName xml.Name `xml:"spacing"`
|
||||
Before string `xml:"before,attr,omitempty"`
|
||||
@@ -882,18 +906,24 @@ func (d *Document) parseDocument() error {
|
||||
|
||||
// 转换为内部结构
|
||||
d.Body = &Body{
|
||||
Paragraphs: make([]Paragraph, len(doc.Body.Paragraphs)),
|
||||
Elements: make([]interface{}, len(doc.Body.Paragraphs)),
|
||||
}
|
||||
|
||||
for i, p := range doc.Body.Paragraphs {
|
||||
paragraph := Paragraph{
|
||||
paragraph := &Paragraph{
|
||||
Runs: make([]Run, len(p.Runs)),
|
||||
}
|
||||
|
||||
// 复制段落属性
|
||||
// 转换段落属性
|
||||
if p.Properties != nil {
|
||||
paragraph.Properties = &ParagraphProperties{}
|
||||
|
||||
if p.Properties.ParagraphStyle != nil {
|
||||
paragraph.Properties.ParagraphStyle = &ParagraphStyle{
|
||||
Val: p.Properties.ParagraphStyle.Val,
|
||||
}
|
||||
}
|
||||
|
||||
if p.Properties.Spacing != nil {
|
||||
paragraph.Properties.Spacing = &Spacing{
|
||||
Before: p.Properties.Spacing.Before,
|
||||
@@ -917,16 +947,13 @@ func (d *Document) parseDocument() error {
|
||||
}
|
||||
}
|
||||
|
||||
// 复制运行和运行属性
|
||||
for j, r := range p.Runs {
|
||||
run := Run{
|
||||
Text: Text{
|
||||
Space: r.Text.Space,
|
||||
Content: r.Text.Content,
|
||||
},
|
||||
}
|
||||
|
||||
// 复制运行属性
|
||||
if r.Properties != nil {
|
||||
run.Properties = &RunProperties{}
|
||||
|
||||
@@ -960,10 +987,10 @@ func (d *Document) parseDocument() error {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -975,12 +1002,12 @@ func (d *Document) serializeDocument() error {
|
||||
type documentXML struct {
|
||||
XMLName xml.Name `xml:"w:document"`
|
||||
Xmlns string `xml:"xmlns:w,attr"`
|
||||
Body Body `xml:"w:body"`
|
||||
Body *Body `xml:"w:body"`
|
||||
}
|
||||
|
||||
doc := documentXML{
|
||||
Xmlns: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
Body: *d.Body,
|
||||
Body: d.Body,
|
||||
}
|
||||
|
||||
// 序列化为XML
|
||||
@@ -1118,3 +1145,30 @@ func (d *Document) ToBytes() ([]byte, error) {
|
||||
|
||||
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 {
|
||||
t.Errorf("Expected 0 paragraphs, got %d", len(doc.Body.Paragraphs))
|
||||
if len(doc.Body.GetParagraphs()) != 0 {
|
||||
t.Errorf("Expected 0 paragraphs, got %d", len(doc.Body.GetParagraphs()))
|
||||
}
|
||||
|
||||
// 验证样式管理器初始化
|
||||
@@ -44,8 +44,8 @@ func TestAddParagraph(t *testing.T) {
|
||||
para := doc.AddParagraph(text)
|
||||
|
||||
// 验证段落添加
|
||||
if len(doc.Body.Paragraphs) != 1 {
|
||||
t.Errorf("Expected 1 paragraph, got %d", len(doc.Body.Paragraphs))
|
||||
if len(doc.Body.GetParagraphs()) != 1 {
|
||||
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")
|
||||
}
|
||||
}
|
||||
@@ -135,7 +136,7 @@ func TestAddFormattedParagraph(t *testing.T) {
|
||||
para := doc.AddFormattedParagraph(text, format)
|
||||
|
||||
// 验证段落添加
|
||||
if len(doc.Body.Paragraphs) != 1 {
|
||||
if len(doc.Body.GetParagraphs()) != 1 {
|
||||
t.Error("Failed to add formatted paragraph")
|
||||
}
|
||||
|
||||
@@ -379,8 +380,8 @@ func TestComplexDocument(t *testing.T) {
|
||||
mixed.AddFormattedText("文本。", nil)
|
||||
|
||||
// 验证文档结构
|
||||
if len(doc.Body.Paragraphs) != 6 {
|
||||
t.Errorf("Expected 6 paragraphs, got %d", len(doc.Body.Paragraphs))
|
||||
if len(doc.Body.GetParagraphs()) != 6 {
|
||||
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 {
|
||||
t.Errorf("Expected 3 paragraphs, got %d", len(loadedDoc.Body.Paragraphs))
|
||||
if len(loadedDoc.Body.GetParagraphs()) != 3 {
|
||||
t.Errorf("Expected 3 paragraphs, got %d", len(loadedDoc.Body.GetParagraphs()))
|
||||
}
|
||||
|
||||
// 验证第一段内容
|
||||
if len(loadedDoc.Body.Paragraphs[0].Runs) > 0 {
|
||||
content := loadedDoc.Body.Paragraphs[0].Runs[0].Text.Content
|
||||
if len(loadedDoc.Body.GetParagraphs()[0].Runs) > 0 {
|
||||
content := loadedDoc.Body.GetParagraphs()[0].Runs[0].Text.Content
|
||||
if content != "第一段" {
|
||||
t.Errorf("Expected '第一段', got '%s'", content)
|
||||
}
|
||||
@@ -565,8 +566,8 @@ func TestMemoryUsage(t *testing.T) {
|
||||
doc.AddParagraph("内存测试段落")
|
||||
}
|
||||
|
||||
if len(doc.Body.Paragraphs) != numParagraphs {
|
||||
t.Errorf("Expected %d paragraphs, got %d", numParagraphs, len(doc.Body.Paragraphs))
|
||||
if len(doc.Body.GetParagraphs()) != numParagraphs {
|
||||
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,
|
||||
}
|
||||
|
||||
initialTableCount := len(doc.Body.Tables)
|
||||
initialTableCount := len(doc.Body.GetTables())
|
||||
table := doc.AddTable(config)
|
||||
|
||||
if table == nil {
|
||||
t.Fatal("添加表格失败")
|
||||
}
|
||||
|
||||
if len(doc.Body.Tables) != initialTableCount+1 {
|
||||
t.Errorf("期望表格数量%d,实际%d", initialTableCount+1, len(doc.Body.Tables))
|
||||
if len(doc.Body.GetTables()) != initialTableCount+1 {
|
||||
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 {
|
||||
t.Fatalf("Expected 1 paragraph, got %d", len(openedDoc.Body.Paragraphs))
|
||||
paragraphs := openedDoc.Body.GetParagraphs()
|
||||
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")
|
||||
}
|
||||
|
||||
|
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 {
|
||||
t.Errorf("预期1个段落,但得到了 %d 个", len(doc.Body.Paragraphs))
|
||||
paragraphs := doc.Body.GetParagraphs()
|
||||
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("段落中没有运行")
|
||||
} else {
|
||||
run := doc.Body.Paragraphs[0].Runs[0]
|
||||
run := paragraphs[0].Runs[0]
|
||||
if run.Properties == nil {
|
||||
t.Error("运行属性为空")
|
||||
} else {
|
||||
@@ -199,12 +200,13 @@ func TestDocumentSaveAndOpen(t *testing.T) {
|
||||
}
|
||||
|
||||
// 验证内容
|
||||
if len(openedDoc.Body.Paragraphs) != 1 {
|
||||
t.Errorf("预期1个段落,但得到了 %d 个", len(openedDoc.Body.Paragraphs))
|
||||
paragraphs := openedDoc.Body.GetParagraphs()
|
||||
if len(paragraphs) != 1 {
|
||||
t.Errorf("预期1个段落,但得到了 %d 个", len(paragraphs))
|
||||
}
|
||||
|
||||
if len(openedDoc.Body.Paragraphs) > 0 {
|
||||
para := openedDoc.Body.Paragraphs[0]
|
||||
if len(paragraphs) > 0 {
|
||||
para := paragraphs[0]
|
||||
|
||||
// 检查对齐方式
|
||||
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