作者 陈志颖

feat:栏目设置代码生成

正在显示 36 个修改的文件 包含 683 行增加1410 行删除

要显示太多修改。

为保证性能只显示 36 of 36+ 个文件。

@@ -4,21 +4,24 @@ metadata: @@ -4,21 +4,24 @@ metadata:
4 service: column_setting 4 service: column_setting
5 path: /column-settings 5 path: /column-settings
6 endpoints: 6 endpoints:
7 - - method: createColumn 7 + - method: createColumnSetting
8 route: 8 route:
9 post: / 9 post: /
10 - - method: updateColumn 10 + - method: updateColumnSetting
11 route: 11 route:
12 - post: /{columnSettingId} 12 + put: /{columnSettingId}
13 - method: getColumnSetting 13 - method: getColumnSetting
14 route: 14 route:
15 - post: /{columnSettingId} 15 + get: /{columnSettingId}
  16 + - method: removeColumnSetting
  17 + route:
  18 + delete: /{columnSettingId}
16 - method: resetColumn 19 - method: resetColumn
17 route: 20 route:
18 post: / 21 post: /
19 - - method: listColumn 22 + - method: listColumnSetting
20 route: 23 route:
21 - post: / 24 + get: /
22 params: 25 params:
23 - name: offset 26 - name: offset
24 - name: limit 27 - name: limit
@@ -2,6 +2,6 @@ version: v1 @@ -2,6 +2,6 @@ version: v1
2 kind: Attribute 2 kind: Attribute
3 metadata: 3 metadata:
4 name: value 4 name: value
5 - description: 栏目设置项 5 + description: 栏目值对象数组
6 type: 6 type:
7 array: column 7 array: column
1 -package domain  
2 -  
3 -// 栏目项  
4 -type Column struct {  
5 - // 列标记  
6 - ColumnId string `json:"columnId"`  
7 - // 列标记中文  
8 - ParamCn string `json:"paramCn"`  
9 - // 列标记是否固定,1:固定,2:不固定  
10 - ParamFix int `json:"paramFix"`  
11 -}  
@@ -4,6 +4,8 @@ metadata: @@ -4,6 +4,8 @@ metadata:
4 name: column_setting 4 name: column_setting
5 description: 栏目设置 5 description: 栏目设置
6 attributes: 6 attributes:
  7 + - ref: columnSettingId
  8 + required: true
7 - ref: companyId 9 - ref: companyId
8 required: true 10 required: true
9 - ref: createdAt 11 - ref: createdAt
@@ -12,13 +14,13 @@ metadata: @@ -12,13 +14,13 @@ metadata:
12 required: true 14 required: true
13 - ref: key 15 - ref: key
14 required: true 16 required: true
15 - - ref: settingId  
16 - required: true  
17 - ref: uid 17 - ref: uid
18 required: true 18 required: true
19 - ref: updatedAt 19 - ref: updatedAt
20 required: true 20 required: true
21 - ref: userName 21 - ref: userName
22 required: true 22 required: true
23 - - ref: value  
24 - required: true 23 + - name: value
  24 + description: 栏目数组
  25 + type:
  26 + array: column
@@ -3,32 +3,12 @@ kind: Method @@ -3,32 +3,12 @@ kind: Method
3 metadata: 3 metadata:
4 name: createColumnSetting 4 name: createColumnSetting
5 type: command 5 type: command
6 - description: 创建 6 + description: 创建栏目设置增删改查
7 payload: 7 payload:
8 - - ref: companyId  
9 - required: true  
10 - ref: description 8 - ref: description
11 required: true 9 required: true
12 - - ref: createdAt  
13 - required: true  
14 - - ref: key  
15 - required: true  
16 - - ref: settingId  
17 - required: true  
18 - - ref: uid  
19 - required: true  
20 - - ref: updatedAt  
21 - required: true  
22 - ref: userName 10 - ref: userName
23 required: true 11 required: true
24 - - ref: value  
25 - required: true  
26 - - ref: count  
27 - required: true  
28 - - ref: limit  
29 - required: true  
30 - - ref: offset  
31 - required: true  
32 result: 12 result:
33 - name: column_setting 13 - name: column_setting
34 type: 14 type:
@@ -3,7 +3,7 @@ kind: Method @@ -3,7 +3,7 @@ kind: Method
3 metadata: 3 metadata:
4 name: getColumnSetting 4 name: getColumnSetting
5 type: query 5 type: query
6 - description: 返回 6 + description: 返回栏目设置增删改查
7 payload: 7 payload:
8 - ref: columnSettingId 8 - ref: columnSettingId
9 required: true 9 required: true
@@ -3,7 +3,7 @@ kind: Method @@ -3,7 +3,7 @@ kind: Method
3 metadata: 3 metadata:
4 name: listColumnSetting 4 name: listColumnSetting
5 type: query 5 type: query
6 - description: 返回列表 6 + description: 返回栏目设置增删改查列表
7 payload: 7 payload:
8 - ref: offset 8 - ref: offset
9 required: true 9 required: true
@@ -3,7 +3,7 @@ kind: Method @@ -3,7 +3,7 @@ kind: Method
3 metadata: 3 metadata:
4 name: removeColumnSetting 4 name: removeColumnSetting
5 type: command 5 type: command
6 - description: 移除 6 + description: 移除栏目设置增删改查
7 payload: 7 payload:
8 - ref: columnSettingId 8 - ref: columnSettingId
9 required: true 9 required: true
@@ -3,7 +3,7 @@ kind: Method @@ -3,7 +3,7 @@ kind: Method
3 metadata: 3 metadata:
4 name: resetColumn 4 name: resetColumn
5 type: command 5 type: command
6 - description: 重置栏目 6 + description: 重置栏目设置
7 result: 7 result:
8 - name: column_setting 8 - name: column_setting
9 type: 9 type:
@@ -3,32 +3,8 @@ kind: Method @@ -3,32 +3,8 @@ kind: Method
3 metadata: 3 metadata:
4 name: updateColumnSetting 4 name: updateColumnSetting
5 type: command 5 type: command
6 - description: 更新 6 + description: 更新栏目设置增删改查
7 payload: 7 payload:
8 - - ref: companyId  
9 - required: true  
10 - - ref: description  
11 - required: true  
12 - - ref: createdAt  
13 - required: true  
14 - - ref: key  
15 - required: true  
16 - - ref: settingId  
17 - required: true  
18 - - ref: uid  
19 - required: true  
20 - - ref: updatedAt  
21 - required: true  
22 - - ref: userName  
23 - required: true  
24 - - ref: value  
25 - required: true  
26 - - ref: count  
27 - required: true  
28 - - ref: limit  
29 - required: true  
30 - - ref: offset  
31 - required: true  
32 - ref: columnSettingId 8 - ref: columnSettingId
33 required: true 9 required: true
34 result: 10 result:
@@ -2,4 +2,4 @@ version: v1 @@ -2,4 +2,4 @@ version: v1
2 kind: Service 2 kind: Service
3 metadata: 3 metadata:
4 name: column_setting 4 name: column_setting
5 - description: 栏目设置服务  
  5 + description: 栏目设置
@@ -13,17 +13,17 @@ require ( @@ -13,17 +13,17 @@ require (
13 github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect 13 github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect
14 github.com/fatih/structs v1.1.0 // indirect 14 github.com/fatih/structs v1.1.0 // indirect
15 github.com/gavv/httpexpect v2.0.0+incompatible 15 github.com/gavv/httpexpect v2.0.0+incompatible
  16 + github.com/go-pg/pg v8.0.6+incompatible
16 github.com/go-pg/pg/v10 v10.7.3 17 github.com/go-pg/pg/v10 v10.7.3
17 github.com/google/go-querystring v1.0.0 // indirect 18 github.com/google/go-querystring v1.0.0 // indirect
18 github.com/gorilla/websocket v1.4.2 // indirect 19 github.com/gorilla/websocket v1.4.2 // indirect
19 github.com/imkira/go-interpol v1.1.0 // indirect 20 github.com/imkira/go-interpol v1.1.0 // indirect
20 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect 21 github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
21 - github.com/linmadan/egglib-go v0.0.0-20191217144343-ca4539f95bf9 22 + github.com/linmadan/egglib-go v0.0.0-20201125083542-25358a549edb
22 github.com/mattn/go-colorable v0.1.6 // indirect 23 github.com/mattn/go-colorable v0.1.6 // indirect
23 github.com/moul/http2curl v1.0.0 // indirect 24 github.com/moul/http2curl v1.0.0 // indirect
24 github.com/onsi/ginkgo v1.14.2 25 github.com/onsi/ginkgo v1.14.2
25 github.com/onsi/gomega v1.10.3 26 github.com/onsi/gomega v1.10.3
26 - github.com/sclevine/agouti v3.0.0+incompatible // indirect  
27 github.com/sergi/go-diff v1.1.0 // indirect 27 github.com/sergi/go-diff v1.1.0 // indirect
28 github.com/shopspring/decimal v1.2.0 28 github.com/shopspring/decimal v1.2.0
29 github.com/smartystreets/goconvey v1.6.4 // indirect 29 github.com/smartystreets/goconvey v1.6.4 // indirect
  1 +package command
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type CreateColumnSettingCommand struct {
  10 + // 栏目设置描述
  11 + Description string `json:"description" valid:"Required"`
  12 + // 栏目设置关联用户名称
  13 + UserName string `json:"userName" valid:"Required"`
  14 +}
  15 +
  16 +func (createColumnSettingCommand *CreateColumnSettingCommand) Valid(validation *validation.Validation) {
  17 + validation.SetError("CustomValid", "未实现的自定义认证")
  18 +}
  19 +
  20 +func (createColumnSettingCommand *CreateColumnSettingCommand) ValidateCommand() error {
  21 + valid := validation.Validation{}
  22 + b, err := valid.Valid(createColumnSettingCommand)
  23 + if err != nil {
  24 + return err
  25 + }
  26 + if !b {
  27 + for _, validErr := range valid.Errors {
  28 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  29 + }
  30 + }
  31 + return nil
  32 +}
  1 +package command
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type RemoveColumnSettingCommand struct {
  10 + // 栏目设置id
  11 + ColumnSettingId int64 `json:"columnSettingId" valid:"Required"`
  12 +}
  13 +
  14 +func (removeColumnSettingCommand *RemoveColumnSettingCommand) Valid(validation *validation.Validation) {
  15 + validation.SetError("CustomValid", "未实现的自定义认证")
  16 +}
  17 +
  18 +func (removeColumnSettingCommand *RemoveColumnSettingCommand) ValidateCommand() error {
  19 + valid := validation.Validation{}
  20 + b, err := valid.Valid(removeColumnSettingCommand)
  21 + if err != nil {
  22 + return err
  23 + }
  24 + if !b {
  25 + for _, validErr := range valid.Errors {
  26 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  27 + }
  28 + }
  29 + return nil
  30 +}
  1 +package command
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type ResetColumnCommand struct {
  10 +}
  11 +
  12 +func (resetColumnCommand *ResetColumnCommand) Valid(validation *validation.Validation) {
  13 + validation.SetError("CustomValid", "未实现的自定义认证")
  14 +}
  15 +
  16 +func (resetColumnCommand *ResetColumnCommand) ValidateCommand() error {
  17 + valid := validation.Validation{}
  18 + b, err := valid.Valid(resetColumnCommand)
  19 + if err != nil {
  20 + return err
  21 + }
  22 + if !b {
  23 + for _, validErr := range valid.Errors {
  24 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  25 + }
  26 + }
  27 + return nil
  28 +}
  1 +package command
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type UpdateColumnSettingCommand struct {
  10 + // 栏目设置id
  11 + ColumnSettingId int64 `json:"columnSettingId" valid:"Required"`
  12 +}
  13 +
  14 +func (updateColumnSettingCommand *UpdateColumnSettingCommand) Valid(validation *validation.Validation) {
  15 + validation.SetError("CustomValid", "未实现的自定义认证")
  16 +}
  17 +
  18 +func (updateColumnSettingCommand *UpdateColumnSettingCommand) ValidateCommand() error {
  19 + valid := validation.Validation{}
  20 + b, err := valid.Valid(updateColumnSettingCommand)
  21 + if err != nil {
  22 + return err
  23 + }
  24 + if !b {
  25 + for _, validErr := range valid.Errors {
  26 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  27 + }
  28 + }
  29 + return nil
  30 +}
  1 +package query
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type GetColumnSettingQuery struct {
  10 + // 栏目设置id
  11 + ColumnSettingId int64 `json:"columnSettingId" valid:"Required"`
  12 +}
  13 +
  14 +func (getColumnSettingQuery *GetColumnSettingQuery) Valid(validation *validation.Validation) {
  15 + validation.SetError("CustomValid", "未实现的自定义认证")
  16 +}
  17 +
  18 +func (getColumnSettingQuery *GetColumnSettingQuery) ValidateQuery() error {
  19 + valid := validation.Validation{}
  20 + b, err := valid.Valid(getColumnSettingQuery)
  21 + if err != nil {
  22 + return err
  23 + }
  24 + if !b {
  25 + for _, validErr := range valid.Errors {
  26 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  27 + }
  28 + }
  29 + return nil
  30 +}
  1 +package query
  2 +
  3 +import (
  4 + "fmt"
  5 +
  6 + "github.com/astaxie/beego/validation"
  7 +)
  8 +
  9 +type ListColumnSettingQuery struct {
  10 + // 查询偏离量
  11 + Offset int `json:"offset" valid:"Required"`
  12 + // 查询限制
  13 + Limit int `json:"limit" valid:"Required"`
  14 +}
  15 +
  16 +func (listColumnSettingQuery *ListColumnSettingQuery) Valid(validation *validation.Validation) {
  17 + validation.SetError("CustomValid", "未实现的自定义认证")
  18 +}
  19 +
  20 +func (listColumnSettingQuery *ListColumnSettingQuery) ValidateQuery() error {
  21 + valid := validation.Validation{}
  22 + b, err := valid.Valid(listColumnSettingQuery)
  23 + if err != nil {
  24 + return err
  25 + }
  26 + if !b {
  27 + for _, validErr := range valid.Errors {
  28 + return fmt.Errorf("%s %s", validErr.Key, validErr.Message)
  29 + }
  30 + }
  31 + return nil
  32 +}
  1 +package service
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/linmadan/egglib-go/core/application"
  6 + "github.com/linmadan/egglib-go/utils/tool_funs"
  7 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/application/columnSetting/command"
  8 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/application/columnSetting/query"
  9 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/application/factory"
  10 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/domain"
  11 +)
  12 +
  13 +// 栏目设置
  14 +type ColumnSettingService struct {
  15 +}
  16 +
  17 +// 创建栏目设置增删改查
  18 +func (columnSettingService *ColumnSettingService) CreateColumnSetting(createColumnSettingCommand *command.CreateColumnSettingCommand) (interface{}, error) {
  19 + if err := createColumnSettingCommand.ValidateCommand(); err != nil {
  20 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  21 + }
  22 + transactionContext, err := factory.CreateTransactionContext(nil)
  23 + if err != nil {
  24 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  25 + }
  26 + if err := transactionContext.StartTransaction(); err != nil {
  27 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  28 + }
  29 + defer func() {
  30 + transactionContext.RollbackTransaction()
  31 + }()
  32 + newColumnSetting := &domain.ColumnSetting{
  33 + Description: createColumnSettingCommand.Description,
  34 + UserName: createColumnSettingCommand.UserName,
  35 + }
  36 + var columnSettingRepository domain.ColumnSettingRepository
  37 + if value, err := factory.CreateColumnSettingRepository(map[string]interface{}{
  38 + "transactionContext": transactionContext,
  39 + }); err != nil {
  40 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  41 + } else {
  42 + columnSettingRepository = value
  43 + }
  44 + if columnSetting, err := columnSettingRepository.Save(newColumnSetting); err != nil {
  45 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  46 + } else {
  47 + if err := transactionContext.CommitTransaction(); err != nil {
  48 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  49 + }
  50 + return columnSetting, nil
  51 + }
  52 +}
  53 +
  54 +// 返回栏目设置增删改查
  55 +func (columnSettingService *ColumnSettingService) GetColumnSetting(getColumnSettingQuery *query.GetColumnSettingQuery) (interface{}, error) {
  56 + if err := getColumnSettingQuery.ValidateQuery(); err != nil {
  57 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  58 + }
  59 + transactionContext, err := factory.CreateTransactionContext(nil)
  60 + if err != nil {
  61 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  62 + }
  63 + if err := transactionContext.StartTransaction(); err != nil {
  64 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  65 + }
  66 + defer func() {
  67 + transactionContext.RollbackTransaction()
  68 + }()
  69 + var columnSettingRepository domain.ColumnSettingRepository
  70 + if value, err := factory.CreateColumnSettingRepository(map[string]interface{}{
  71 + "transactionContext": transactionContext,
  72 + }); err != nil {
  73 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  74 + } else {
  75 + columnSettingRepository = value
  76 + }
  77 + columnSetting, err := columnSettingRepository.FindOne(map[string]interface{}{"column_settingId": getColumnSettingQuery.ColumnSettingId})
  78 + if err != nil {
  79 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  80 + }
  81 + if columnSetting == nil {
  82 + return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(getColumnSettingQuery.ColumnSettingId)))
  83 + } else {
  84 + if err := transactionContext.CommitTransaction(); err != nil {
  85 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  86 + }
  87 + return columnSetting, nil
  88 + }
  89 +}
  90 +
  91 +// 返回栏目设置增删改查列表
  92 +func (columnSettingService *ColumnSettingService) ListColumnSetting(listColumnSettingQuery *query.ListColumnSettingQuery) (interface{}, error) {
  93 + if err := listColumnSettingQuery.ValidateQuery(); err != nil {
  94 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  95 + }
  96 + transactionContext, err := factory.CreateTransactionContext(nil)
  97 + if err != nil {
  98 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  99 + }
  100 + if err := transactionContext.StartTransaction(); err != nil {
  101 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  102 + }
  103 + defer func() {
  104 + transactionContext.RollbackTransaction()
  105 + }()
  106 + var columnSettingRepository domain.ColumnSettingRepository
  107 + if value, err := factory.CreateColumnSettingRepository(map[string]interface{}{
  108 + "transactionContext": transactionContext,
  109 + }); err != nil {
  110 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  111 + } else {
  112 + columnSettingRepository = value
  113 + }
  114 + if count, columnSettings, err := columnSettingRepository.Find(tool_funs.SimpleStructToMap(listColumnSettingQuery)); err != nil {
  115 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  116 + } else {
  117 + if err := transactionContext.CommitTransaction(); err != nil {
  118 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  119 + }
  120 + return map[string]interface{}{
  121 + "count": count,
  122 + "column_settings": columnSettings,
  123 + }, nil
  124 + }
  125 +}
  126 +
  127 +// 移除栏目设置增删改查
  128 +func (columnSettingService *ColumnSettingService) RemoveColumnSetting(removeColumnSettingCommand *command.RemoveColumnSettingCommand) (interface{}, error) {
  129 + if err := removeColumnSettingCommand.ValidateCommand(); err != nil {
  130 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  131 + }
  132 + transactionContext, err := factory.CreateTransactionContext(nil)
  133 + if err != nil {
  134 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  135 + }
  136 + if errSt := transactionContext.StartTransaction(); errSt != nil {
  137 + return nil, application.ThrowError(application.TRANSACTION_ERROR, errSt.Error())
  138 + }
  139 + defer func() {
  140 + transactionContext.RollbackTransaction()
  141 + }()
  142 + var columnSettingRepository domain.ColumnSettingRepository
  143 + if value, errFac := factory.CreateColumnSettingRepository(map[string]interface{}{
  144 + "transactionContext": transactionContext,
  145 + }); errFac != nil {
  146 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, errFac.Error())
  147 + } else {
  148 + columnSettingRepository = value
  149 + }
  150 + columnSetting, err := columnSettingRepository.FindOne(map[string]interface{}{"column_settingId": removeColumnSettingCommand.ColumnSettingId})
  151 + if err != nil {
  152 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  153 + }
  154 + if columnSetting == nil {
  155 + return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(removeColumnSettingCommand.ColumnSettingId)))
  156 + }
  157 + if columnSettingRemoved, errRm := columnSettingRepository.Remove(columnSetting); errRm != nil {
  158 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, errRm.Error())
  159 + } else {
  160 + if errTr := transactionContext.CommitTransaction(); errTr != nil {
  161 + return nil, application.ThrowError(application.TRANSACTION_ERROR, errRm.Error())
  162 + }
  163 + return columnSettingRemoved, nil
  164 + }
  165 +}
  166 +
  167 +// 重置栏目设置
  168 +func (columnSettingService *ColumnSettingService) ResetColumn(resetColumnCommand *command.ResetColumnCommand) (interface{}, error) {
  169 + if err := resetColumnCommand.ValidateCommand(); err != nil {
  170 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  171 + }
  172 + transactionContext, err := factory.CreateTransactionContext(nil)
  173 + if err != nil {
  174 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  175 + }
  176 + if err := transactionContext.StartTransaction(); err != nil {
  177 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  178 + }
  179 + defer func() {
  180 + transactionContext.RollbackTransaction()
  181 + }()
  182 + if err := transactionContext.CommitTransaction(); err != nil {
  183 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  184 + }
  185 + return nil, nil
  186 +}
  187 +
  188 +// 更新栏目设置增删改查
  189 +func (columnSettingService *ColumnSettingService) UpdateColumnSetting(updateColumnSettingCommand *command.UpdateColumnSettingCommand) (interface{}, error) {
  190 + if err := updateColumnSettingCommand.ValidateCommand(); err != nil {
  191 + return nil, application.ThrowError(application.ARG_ERROR, err.Error())
  192 + }
  193 + transactionContext, err := factory.CreateTransactionContext(nil)
  194 + if err != nil {
  195 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  196 + }
  197 + if err := transactionContext.StartTransaction(); err != nil {
  198 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  199 + }
  200 + defer func() {
  201 + transactionContext.RollbackTransaction()
  202 + }()
  203 + var columnSettingRepository domain.ColumnSettingRepository
  204 + if value, err := factory.CreateColumnSettingRepository(map[string]interface{}{
  205 + "transactionContext": transactionContext,
  206 + }); err != nil {
  207 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  208 + } else {
  209 + columnSettingRepository = value
  210 + }
  211 + columnSetting, err := columnSettingRepository.FindOne(map[string]interface{}{"column_settingId": updateColumnSettingCommand.ColumnSettingId})
  212 + if err != nil {
  213 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  214 + }
  215 + if columnSetting == nil {
  216 + return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(updateColumnSettingCommand.ColumnSettingId)))
  217 + }
  218 + if err := columnSetting.Update(tool_funs.SimpleStructToMap(updateColumnSettingCommand)); err != nil {
  219 + return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
  220 + }
  221 + if columnSettingSaved, err := columnSettingRepository.Save(columnSetting); err != nil {
  222 + return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
  223 + } else {
  224 + if err := transactionContext.CommitTransaction(); err != nil {
  225 + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
  226 + }
  227 + return columnSettingSaved, nil
  228 + }
  229 +}
  230 +
  231 +func NewColumnSettingService(options map[string]interface{}) *ColumnSettingService {
  232 + newColumnSettingService := &ColumnSettingService{}
  233 + return newColumnSettingService
  234 +}
1 package factory 1 package factory
2 2
3 import ( 3 import (
  4 + "github.com/linmadan/egglib-go/transaction/pg"
4 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/domain" 5 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/domain"
5 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/transaction" 6 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/transaction"
6 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/repository" 7 "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/repository"
@@ -104,3 +105,11 @@ func CreateOrderLogRepository(options map[string]interface{}) (domain.OrderLogRe @@ -104,3 +105,11 @@ func CreateOrderLogRepository(options map[string]interface{}) (domain.OrderLogRe
104 } 105 }
105 return repository.NewOrderLogRepository(transactionContext) 106 return repository.NewOrderLogRepository(transactionContext)
106 } 107 }
  108 +
  109 +func CreateColumnSettingRepository(options map[string]interface{}) (domain.ColumnSettingRepository, error) {
  110 + var transactionContext *pg.TransactionContext
  111 + if value, ok := options["transactionContext"]; ok {
  112 + transactionContext = value.(*pg.TransactionContext)
  113 + }
  114 + return repository.NewColumnSettingRepository(transactionContext)
  115 +}
@@ -5,3 +5,13 @@ @@ -5,3 +5,13 @@
5 **/ 5 **/
6 6
7 package domain 7 package domain
  8 +
  9 +// 栏目项值对象
  10 +type Column struct {
  11 + // 列标记
  12 + ColumnId string `json:"columnId"`
  13 + // 列标记中文
  14 + ParamCn string `json:"paramCn"`
  15 + // 列标记是否固定,1:固定,2:不固定
  16 + ParamFix int `json:"paramFix"`
  17 +}
1 -/**  
2 - @author: stevechan  
3 - @date: 2021/1/26  
4 - @note:  
5 -**/  
6 -  
7 package domain 1 package domain
  2 +
  3 +import "time"
  4 +
  5 +// 栏目设置
  6 +type ColumnSetting struct {
  7 + // 栏目设置id
  8 + Id int64 `json:"id"`
  9 + // 栏目设置关联用户公司id
  10 + CompanyId int32 `json:"companyId"`
  11 + // 栏目设置创建时间
  12 + CreatedAt time.Time `json:"createdAt"`
  13 + // 栏目设置描述
  14 + Description string `json:"description"`
  15 + // 栏目设置模块名称
  16 + Key string `json:"key"`
  17 + // 栏目设置关联用户uid
  18 + Uid int64 `json:"uid"`
  19 + // 栏目设置更新时间
  20 + UpdatedAt time.Time `json:"updatedAt"`
  21 + // 栏目设置关联用户名称
  22 + UserName string `json:"userName"`
  23 + // 栏目数组
  24 + Value []*Column `json:"valuea"`
  25 +}
  26 +
  27 +type ColumnSettingRepository interface {
  28 + Save(columnSetting *ColumnSetting) (*ColumnSetting, error)
  29 + Remove(columnSetting *ColumnSetting) (*ColumnSetting, error)
  30 + FindOne(queryOptions map[string]interface{}) (*ColumnSetting, error)
  31 + Find(queryOptions map[string]interface{}) (int64, []*ColumnSetting, error)
  32 +}
  33 +
  34 +func (columnSetting *ColumnSetting) Identify() interface{} {
  35 + if columnSetting.Id == 0 {
  36 + return nil
  37 + }
  38 + return columnSetting.Id
  39 +}
  40 +
  41 +func (columnSetting *ColumnSetting) Update(data map[string]interface{}) error {
  42 + if columnSettingId, ok := data["columnSettingId"]; ok {
  43 + columnSetting.Id = columnSettingId.(int64)
  44 + }
  45 + if companyId, ok := data["companyId"]; ok {
  46 + columnSetting.CompanyId = companyId.(int32)
  47 + }
  48 + if createdAt, ok := data["createdAt"]; ok {
  49 + columnSetting.CreatedAt = createdAt.(time.Time)
  50 + }
  51 + if description, ok := data["description"]; ok {
  52 + columnSetting.Description = description.(string)
  53 + }
  54 + if key, ok := data["key"]; ok {
  55 + columnSetting.Key = key.(string)
  56 + }
  57 + if uid, ok := data["uid"]; ok {
  58 + columnSetting.Uid = uid.(int64)
  59 + }
  60 + if updatedAt, ok := data["updatedAt"]; ok {
  61 + columnSetting.UpdatedAt = updatedAt.(time.Time)
  62 + }
  63 + if userName, ok := data["userName"]; ok {
  64 + columnSetting.UserName = userName.(string)
  65 + }
  66 + if value, ok := data["value"]; ok {
  67 + columnSetting.Value = value.([]*Column)
  68 + }
  69 + return nil
  70 +}
  1 +package models
  2 +
  3 +import (
  4 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/domain"
  5 + "time"
  6 +)
  7 +
  8 +type ColumnSetting struct {
  9 + TableName string `pg:"column_settings,alias:column_setting"`
  10 + // 栏目设置id
  11 + Id int64
  12 + // 栏目设置关联用户公司id
  13 + CompanyId int32
  14 + // 栏目设置创建时间
  15 + CreatedAt time.Time
  16 + // 栏目设置描述
  17 + Description string
  18 + // 栏目设置模块名称
  19 + Key string
  20 + // 栏目设置关联用户uid
  21 + Uid int64
  22 + // 栏目设置更新时间
  23 + UpdatedAt time.Time
  24 + // 栏目设置关联用户名称
  25 + UserName string
  26 + // 栏目数组
  27 + Value []*domain.Column `pg:",array"`
  28 +}
  1 +package repository
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/go-pg/pg"
  6 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/domain"
  7 +
  8 + pgTransaction "github.com/linmadan/egglib-go/transaction/pg"
  9 + "gitlab.fjmaimaimai.com/mmm-go/partnermg/pkg/infrastructure/pg/models"
  10 +)
  11 +
  12 +type ColumnSettingRepository struct {
  13 + transactionContext *pgTransaction.TransactionContext
  14 +}
  15 +
  16 +func (repository *ColumnSettingRepository) nextIdentify() (int64, error) {
  17 + return 0, nil
  18 +}
  19 +func (repository *ColumnSettingRepository) Save(columnSetting *domain.ColumnSetting) (*domain.ColumnSetting, error) {
  20 + tx := repository.transactionContext.PgTx
  21 + if columnSetting.Identify() == nil {
  22 + _, err := repository.nextIdentify()
  23 + if err != nil {
  24 + return columnSetting, err
  25 + }
  26 + if _, err := tx.QueryOne(
  27 + pg.Scan(&columnSetting.Id, &columnSetting.CompanyId, &columnSetting.CreatedAt, &columnSetting.Description, &columnSetting.Key, &columnSetting.Uid, &columnSetting.UpdatedAt, &columnSetting.UserName, pg.Array(&columnSetting.Value)),
  28 + "INSERT INTO column_settings (column_setting_id, company_id, created_at, description, key, uid, updated_at, user_name, value) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING column_setting_id, company_id, created_at, description, key, uid, updated_at, user_name, value",
  29 + columnSetting.Id, columnSetting.CompanyId, columnSetting.CreatedAt, columnSetting.Description, columnSetting.Key, columnSetting.Uid, columnSetting.UpdatedAt, columnSetting.UserName, pg.Array(columnSetting.Value)); err != nil {
  30 + return columnSetting, err
  31 + }
  32 + } else {
  33 + if _, err := tx.QueryOne(
  34 + pg.Scan(&columnSetting.Id, &columnSetting.CompanyId, &columnSetting.CreatedAt, &columnSetting.Description, &columnSetting.Key, &columnSetting.Uid, &columnSetting.UpdatedAt, &columnSetting.UserName, pg.Array(&columnSetting.Value)),
  35 + "UPDATE column_settings SET column_setting_id=?, company_id=?, created_at=?, description=?, key=?, uid=?, updated_at=?, user_name=?, value=? WHERE id=? RETURNING column_setting_id, company_id, created_at, description, key, uid, updated_at, user_name, value",
  36 + columnSetting.Id, columnSetting.CompanyId, columnSetting.CreatedAt, columnSetting.Description, columnSetting.Key, columnSetting.Uid, columnSetting.UpdatedAt, columnSetting.UserName, pg.Array(columnSetting.Value), columnSetting.Identify()); err != nil {
  37 + return columnSetting, err
  38 + }
  39 + }
  40 + return columnSetting, nil
  41 +}
  42 +func (repository *ColumnSettingRepository) Remove(columnSetting *domain.ColumnSetting) (*domain.ColumnSetting, error) {
  43 + tx := repository.transactionContext.PgTx
  44 + columnSettingModel := new(models.ColumnSetting)
  45 + columnSettingModel.Id = columnSetting.Identify().(int64)
  46 + if _, err := tx.Model(columnSettingModel).WherePK().Delete(); err != nil {
  47 + return columnSetting, err
  48 + }
  49 + return columnSetting, nil
  50 +}
  51 +func (repository *ColumnSettingRepository) FindOne(queryOptions map[string]interface{}) (*domain.ColumnSetting, error) {
  52 + tx := repository.transactionContext.PgTx
  53 + columnSettingModel := new(models.ColumnSetting)
  54 + query := tx.Model(columnSettingModel)
  55 + if columnSettingId, ok := queryOptions["column_settingId"]; ok {
  56 + query = query.Where("column_setting.id = ?", columnSettingId)
  57 + }
  58 + if err := query.First(); err != nil {
  59 + if err.Error() == "pg: no rows in result set" {
  60 + return nil, fmt.Errorf("没有此资源")
  61 + } else {
  62 + return nil, err
  63 + }
  64 + }
  65 + if columnSettingModel.Id == 0 {
  66 + return nil, nil
  67 + } else {
  68 + return repository.transformPgModelToDomainModel(columnSettingModel)
  69 + }
  70 +}
  71 +func (repository *ColumnSettingRepository) Find(queryOptions map[string]interface{}) (int64, []*domain.ColumnSetting, error) {
  72 + tx := repository.transactionContext.PgTx
  73 + var columnSettingModels []*models.ColumnSetting
  74 + columnSettings := make([]*domain.ColumnSetting, 0)
  75 + query := tx.Model(&columnSettingModels)
  76 + if offset, ok := queryOptions["offset"]; ok {
  77 + offset := offset.(int)
  78 + if offset > -1 {
  79 + query = query.Offset(offset)
  80 + }
  81 + } else {
  82 + query = query.Offset(0)
  83 + }
  84 + if limit, ok := queryOptions["limit"]; ok {
  85 + limit := limit.(int)
  86 + if limit > -1 {
  87 + query = query.Limit(limit)
  88 + }
  89 + } else {
  90 + query = query.Limit(20)
  91 + }
  92 + if count, err := query.Order("id DESC").SelectAndCount(); err != nil {
  93 + return 0, columnSettings, err
  94 + } else {
  95 + for _, columnSettingModel := range columnSettingModels {
  96 + if columnSetting, err := repository.transformPgModelToDomainModel(columnSettingModel); err != nil {
  97 + return 0, columnSettings, err
  98 + } else {
  99 + columnSettings = append(columnSettings, columnSetting)
  100 + }
  101 + }
  102 + return int64(count), columnSettings, nil
  103 + }
  104 +}
  105 +func (repository *ColumnSettingRepository) transformPgModelToDomainModel(columnSettingModel *models.ColumnSetting) (*domain.ColumnSetting, error) {
  106 + return &domain.ColumnSetting{
  107 + Id: columnSettingModel.Id,
  108 + CompanyId: columnSettingModel.CompanyId,
  109 + CreatedAt: columnSettingModel.CreatedAt,
  110 + Description: columnSettingModel.Description,
  111 + Key: columnSettingModel.Key,
  112 + Uid: columnSettingModel.Uid,
  113 + UpdatedAt: columnSettingModel.UpdatedAt,
  114 + UserName: columnSettingModel.UserName,
  115 + Value: columnSettingModel.Value,
  116 + }, nil
  117 +}
  118 +func NewColumnSettingRepository(transactionContext *pgTransaction.TransactionContext) (*ColumnSettingRepository, error) {
  119 + if transactionContext == nil {
  120 + return nil, fmt.Errorf("transactionContext参数不能为nil")
  121 + } else {
  122 + return &ColumnSettingRepository{
  123 + transactionContext: transactionContext,
  124 + }, nil
  125 + }
  126 +}
1 -~$*.xlsx  
2 -test/Test*.xlsx  
3 -*.out  
4 -*.test  
5 -.idea  
1 -language: go  
2 -  
3 -install:  
4 - - go get -d -t -v ./... && go build -v ./...  
5 -  
6 -go:  
7 - - 1.11.x  
8 - - 1.12.x  
9 - - 1.13.x  
10 - - 1.14.x  
11 - - 1.15.x  
12 -  
13 -os:  
14 - - linux  
15 - - osx  
16 -  
17 -env:  
18 - jobs:  
19 - - GOARCH=amd64  
20 - - GOARCH=386  
21 -  
22 -script:  
23 - - env GO111MODULE=on go vet ./...  
24 - - env GO111MODULE=on go test -v -race ./... -coverprofile=coverage.txt -covermode=atomic  
25 -  
26 -after_success:  
27 - - bash <(curl -s https://codecov.io/bash)  
1 -# Contributor Covenant Code of Conduct  
2 -  
3 -## Our Pledge  
4 -  
5 -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.  
6 -  
7 -## Our Standards  
8 -  
9 -Examples of behavior that contributes to creating a positive environment include:  
10 -  
11 -* Using welcoming and inclusive language  
12 -* Being respectful of differing viewpoints and experiences  
13 -* Gracefully accepting constructive criticism  
14 -* Focusing on what is best for the community  
15 -* Showing empathy towards other community members  
16 -  
17 -Examples of unacceptable behavior by participants include:  
18 -  
19 -* The use of sexualized language or imagery and unwelcome sexual attention or advances  
20 -* Trolling, insulting/derogatory comments, and personal or political attacks  
21 -* Public or private harassment  
22 -* Publishing others' private information, such as a physical or electronic address, without explicit permission  
23 -* Other conduct which could reasonably be considered inappropriate in a professional setting  
24 -  
25 -## Our Responsibilities  
26 -  
27 -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.  
28 -  
29 -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.  
30 -  
31 -## Scope  
32 -  
33 -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.  
34 -  
35 -## Enforcement  
36 -  
37 -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [xuri.me](https://xuri.me). The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.  
38 -  
39 -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.  
40 -  
41 -## Attribution  
42 -  
43 -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at [https://www.contributor-covenant.org/version/2/0/code_of_conduct][version]  
44 -  
45 -[homepage]: https://www.contributor-covenant.org  
46 -[version]: https://www.contributor-covenant.org/version/2/0/code_of_conduct  
1 -# Contributing to excelize  
2 -  
3 -Want to hack on excelize? Awesome! This page contains information about reporting issues as well as some tips and  
4 -guidelines useful to experienced open source contributors. Finally, make sure  
5 -you read our [community guidelines](#community-guidelines) before you  
6 -start participating.  
7 -  
8 -## Topics  
9 -  
10 -* [Reporting Security Issues](#reporting-security-issues)  
11 -* [Design and Cleanup Proposals](#design-and-cleanup-proposals)  
12 -* [Reporting Issues](#reporting-other-issues)  
13 -* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)  
14 -* [Community Guidelines](#community-guidelines)  
15 -  
16 -## Reporting security issues  
17 -  
18 -The excelize maintainers take security seriously. If you discover a security  
19 -issue, please bring it to their attention right away!  
20 -  
21 -Please **DO NOT** file a public issue, instead send your report privately to  
22 -[xuri.me](https://xuri.me).  
23 -  
24 -Security reports are greatly appreciated and we will publicly thank you for it.  
25 -We currently do not offer a paid security bounty program, but are not  
26 -ruling it out in the future.  
27 -  
28 -## Reporting other issues  
29 -  
30 -A great way to contribute to the project is to send a detailed report when you  
31 -encounter an issue. We always appreciate a well-written, thorough bug report,  
32 -and will thank you for it!  
33 -  
34 -Check that [our issue database](https://github.com/360EntSecGroup-Skylar/excelize/issues)  
35 -doesn't already include that problem or suggestion before submitting an issue.  
36 -If you find a match, you can use the "subscribe" button to get notified on  
37 -updates. Do *not* leave random "+1" or "I have this too" comments, as they  
38 -only clutter the discussion, and don't help resolving it. However, if you  
39 -have ways to reproduce the issue or have additional information that may help  
40 -resolving the issue, please leave a comment.  
41 -  
42 -When reporting issues, always include the output of `go env`.  
43 -  
44 -Also include the steps required to reproduce the problem if possible and  
45 -applicable. This information will help us review and fix your issue faster.  
46 -When sending lengthy log-files, consider posting them as a gist [https://gist.github.com](https://gist.github.com).  
47 -Don't forget to remove sensitive data from your logfiles before posting (you can  
48 -replace those parts with "REDACTED").  
49 -  
50 -## Quick contribution tips and guidelines  
51 -  
52 -This section gives the experienced contributor some tips and guidelines.  
53 -  
54 -### Pull requests are always welcome  
55 -  
56 -Not sure if that typo is worth a pull request? Found a bug and know how to fix  
57 -it? Do it! We will appreciate it. Any significant improvement should be  
58 -documented as [a GitHub issue](https://github.com/360EntSecGroup-Skylar/excelize/issues) before  
59 -anybody starts working on it.  
60 -  
61 -We are always thrilled to receive pull requests. We do our best to process them  
62 -quickly. If your pull request is not accepted on the first try,  
63 -don't get discouraged!  
64 -  
65 -### Design and cleanup proposals  
66 -  
67 -You can propose new designs for existing excelize features. You can also design  
68 -entirely new features. We really appreciate contributors who want to refactor or  
69 -otherwise cleanup our project.  
70 -  
71 -We try hard to keep excelize lean and focused. Excelize can't do everything for  
72 -everybody. This means that we might decide against incorporating a new feature.  
73 -However, there might be a way to implement that feature *on top of* excelize.  
74 -  
75 -### Conventions  
76 -  
77 -Fork the repository and make changes on your fork in a feature branch:  
78 -  
79 -* If it's a bug fix branch, name it XXXX-something where XXXX is the number of  
80 - the issue.  
81 -* If it's a feature branch, create an enhancement issue to announce  
82 - your intentions, and name it XXXX-something where XXXX is the number of the  
83 - issue.  
84 -  
85 -Submit unit tests for your changes. Go has a great test framework built in; use  
86 -it! Take a look at existing tests for inspiration. Run the full test on your branch before  
87 -submitting a pull request.  
88 -  
89 -Update the documentation when creating or modifying features. Test your  
90 -documentation changes for clarity, concision, and correctness, as well as a  
91 -clean documentation build.  
92 -  
93 -Write clean code. Universally formatted code promotes ease of writing, reading,  
94 -and maintenance. Always run `gofmt -s -w file.go` on each changed file before  
95 -committing your changes. Most editors have plug-ins that do this automatically.  
96 -  
97 -Pull request descriptions should be as clear as possible and include a reference  
98 -to all the issues that they address.  
99 -  
100 -### Successful Changes  
101 -  
102 -Before contributing large or high impact changes, make the effort to coordinate  
103 -with the maintainers of the project before submitting a pull request. This  
104 -prevents you from doing extra work that may or may not be merged.  
105 -  
106 -Large PRs that are just submitted without any prior communication are unlikely  
107 -to be successful.  
108 -  
109 -While pull requests are the methodology for submitting changes to code, changes  
110 -are much more likely to be accepted if they are accompanied by additional  
111 -engineering work. While we don't define this explicitly, most of these goals  
112 -are accomplished through communication of the design goals and subsequent  
113 -solutions. Often times, it helps to first state the problem before presenting  
114 -solutions.  
115 -  
116 -Typically, the best methods of accomplishing this are to submit an issue,  
117 -stating the problem. This issue can include a problem statement and a  
118 -checklist with requirements. If solutions are proposed, alternatives should be  
119 -listed and eliminated. Even if the criteria for elimination of a solution is  
120 -frivolous, say so.  
121 -  
122 -Larger changes typically work best with design documents. These are focused on  
123 -providing context to the design at the time the feature was conceived and can  
124 -inform future documentation contributions.  
125 -  
126 -### Commit Messages  
127 -  
128 -Commit messages must start with a capitalized and short summary  
129 -written in the imperative, followed by an optional, more detailed explanatory  
130 -text which is separated from the summary by an empty line.  
131 -  
132 -Commit messages should follow best practices, including explaining the context  
133 -of the problem and how it was solved, including in caveats or follow up changes  
134 -required. They should tell the story of the change and provide readers  
135 -understanding of what led to it.  
136 -  
137 -In practice, the best approach to maintaining a nice commit message is to  
138 -leverage a `git add -p` and `git commit --amend` to formulate a solid  
139 -changeset. This allows one to piece together a change, as information becomes  
140 -available.  
141 -  
142 -If you squash a series of commits, don't just submit that. Re-write the commit  
143 -message, as if the series of commits was a single stroke of brilliance.  
144 -  
145 -That said, there is no requirement to have a single commit for a PR, as long as  
146 -each commit tells the story. For example, if there is a feature that requires a  
147 -package, it might make sense to have the package in a separate commit then have  
148 -a subsequent commit that uses it.  
149 -  
150 -Remember, you're telling part of the story with the commit message. Don't make  
151 -your chapter weird.  
152 -  
153 -### Review  
154 -  
155 -Code review comments may be added to your pull request. Discuss, then make the  
156 -suggested modifications and push additional commits to your feature branch. Post  
157 -a comment after pushing. New commits show up in the pull request automatically,  
158 -but the reviewers are notified only when you comment.  
159 -  
160 -Pull requests must be cleanly rebased on top of master without multiple branches  
161 -mixed into the PR.  
162 -  
163 -**Git tip**: If your PR no longer merges cleanly, use `rebase master` in your  
164 -feature branch to update your pull request rather than `merge master`.  
165 -  
166 -Before you make a pull request, squash your commits into logical units of work  
167 -using `git rebase -i` and `git push -f`. A logical unit of work is a consistent  
168 -set of patches that should be reviewed together: for example, upgrading the  
169 -version of a vendored dependency and taking advantage of its now available new  
170 -feature constitute two separate units of work. Implementing a new function and  
171 -calling it in another file constitute a single logical unit of work. The very  
172 -high majority of submissions should have a single commit, so if in doubt: squash  
173 -down to one.  
174 -  
175 -After every commit, make sure the test passes. Include documentation  
176 -changes in the same pull request so that a revert would remove all traces of  
177 -the feature or fix.  
178 -  
179 -Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that  
180 -close an issue. Including references automatically closes the issue on a merge.  
181 -  
182 -Please see the [Coding Style](#coding-style) for further guidelines.  
183 -  
184 -### Merge approval  
185 -  
186 -The excelize maintainers use LGTM (Looks Good To Me) in comments on the code review to  
187 -indicate acceptance.  
188 -  
189 -### Sign your work  
190 -  
191 -The sign-off is a simple line at the end of the explanation for the patch. Your  
192 -signature certifies that you wrote the patch or otherwise have the right to pass  
193 -it on as an open-source patch. The rules are pretty simple: if you can certify  
194 -the below (from [developercertificate.org](http://developercertificate.org/)):  
195 -  
196 -```text  
197 -Developer Certificate of Origin  
198 -Version 1.1  
199 -  
200 -Copyright (C) 2004, 2006 The Linux Foundation and its contributors.  
201 -1 Letterman Drive  
202 -Suite D4700  
203 -San Francisco, CA, 94129  
204 -  
205 -Everyone is permitted to copy and distribute verbatim copies of this  
206 -license document, but changing it is not allowed.  
207 -  
208 -Developer's Certificate of Origin 1.1  
209 -  
210 -By making a contribution to this project, I certify that:  
211 -  
212 -(a) The contribution was created in whole or in part by me and I  
213 - have the right to submit it under the open source license  
214 - indicated in the file; or  
215 -  
216 -(b) The contribution is based upon previous work that, to the best  
217 - of my knowledge, is covered under an appropriate open source  
218 - license and I have the right under that license to submit that  
219 - work with modifications, whether created in whole or in part  
220 - by me, under the same open source license (unless I am  
221 - permitted to submit under a different license), as indicated  
222 - in the file; or  
223 -  
224 -(c) The contribution was provided directly to me by some other  
225 - person who certified (a), (b) or (c) and I have not modified  
226 - it.  
227 -  
228 -(d) I understand and agree that this project and the contribution  
229 - are public and that a record of the contribution (including all  
230 - personal information I submit with it, including my sign-off) is  
231 - maintained indefinitely and may be redistributed consistent with  
232 - this project or the open source license(s) involved.  
233 -```  
234 -  
235 -Then you just add a line to every git commit message:  
236 -  
237 -```text  
238 -Signed-off-by: Ri Xu https://xuri.me  
239 -```  
240 -  
241 -Use your real name (sorry, no pseudonyms or anonymous contributions.)  
242 -  
243 -If you set your `user.name` and `user.email` git configs, you can sign your  
244 -commit automatically with `git commit -s`.  
245 -  
246 -### How can I become a maintainer  
247 -  
248 -First, all maintainers have 3 things  
249 -  
250 -* They share responsibility in the project's success.  
251 -* They have made a long-term, recurring time investment to improve the project.  
252 -* They spend that time doing whatever needs to be done, not necessarily what  
253 - is the most interesting or fun.  
254 -  
255 -Maintainers are often under-appreciated, because their work is harder to appreciate.  
256 -It's easy to appreciate a really cool and technically advanced feature. It's harder  
257 -to appreciate the absence of bugs, the slow but steady improvement in stability,  
258 -or the reliability of a release process. But those things distinguish a good  
259 -project from a great one.  
260 -  
261 -Don't forget: being a maintainer is a time investment. Make sure you  
262 -will have time to make yourself available. You don't have to be a  
263 -maintainer to make a difference on the project!  
264 -  
265 -If you want to become a meintainer, contact [xuri.me](https://xuri.me) and given a introduction of you.  
266 -  
267 -## Community guidelines  
268 -  
269 -We want to keep the community awesome, growing and collaborative. We need  
270 -your help to keep it that way. To help with this we've come up with some general  
271 -guidelines for the community as a whole:  
272 -  
273 -* Be nice: Be courteous, respectful and polite to fellow community members:  
274 - no regional, racial, gender, or other abuse will be tolerated. We like  
275 - nice people way better than mean ones!  
276 -  
277 -* Encourage diversity and participation: Make everyone in our community feel  
278 - welcome, regardless of their background and the extent of their  
279 - contributions, and do everything possible to encourage participation in  
280 - our community.  
281 -  
282 -* Keep it legal: Basically, don't get us in trouble. Share only content that  
283 - you own, do not share private or sensitive information, and don't break  
284 - the law.  
285 -  
286 -* Stay on topic: Make sure that you are posting to the correct channel and  
287 - avoid off-topic discussions. Remember when you update an issue or respond  
288 - to an email you are potentially sending to a large number of people. Please  
289 - consider this before you update. Also remember that nobody likes spam.  
290 -  
291 -* Don't send email to the maintainers: There's no need to send email to the  
292 - maintainers to ask them to investigate an issue or to take a look at a  
293 - pull request. Instead of sending an email, GitHub mentions should be  
294 - used to ping maintainers to review a pull request, a proposal or an  
295 - issue.  
296 -  
297 -### Guideline violations — 3 strikes method  
298 -  
299 -The point of this section is not to find opportunities to punish people, but we  
300 -do need a fair way to deal with people who are making our community suck.  
301 -  
302 -1. First occurrence: We'll give you a friendly, but public reminder that the  
303 - behavior is inappropriate according to our guidelines.  
304 -  
305 -2. Second occurrence: We will send you a private message with a warning that  
306 - any additional violations will result in removal from the community.  
307 -  
308 -3. Third occurrence: Depending on the violation, we may need to delete or ban  
309 - your account.  
310 -  
311 -**Notes:**  
312 -  
313 -* Obvious spammers are banned on first occurrence. If we don't do this, we'll  
314 - have spam all over the place.  
315 -  
316 -* Violations are forgiven after 6 months of good behavior, and we won't hold a  
317 - grudge.  
318 -  
319 -* People who commit minor infractions will get some education, rather than  
320 - hammering them in the 3 strikes process.  
321 -  
322 -* The rules apply equally to everyone in the community, no matter how much  
323 - you've contributed.  
324 -  
325 -* Extreme violations of a threatening, abusive, destructive or illegal nature  
326 - will be addressed immediately and are not subject to 3 strikes or forgiveness.  
327 -  
328 -* Contact [xuri.me](https://xuri.me) to report abuse or appeal violations. In the case of  
329 - appeals, we know that mistakes happen, and we'll work with you to come up with a  
330 - fair solution if there has been a misunderstanding.  
331 -  
332 -## Coding Style  
333 -  
334 -Unless explicitly stated, we follow all coding guidelines from the Go  
335 -community. While some of these standards may seem arbitrary, they somehow seem  
336 -to result in a solid, consistent codebase.  
337 -  
338 -It is possible that the code base does not currently comply with these  
339 -guidelines. We are not looking for a massive PR that fixes this, since that  
340 -goes against the spirit of the guidelines. All new contributions should make a  
341 -best effort to clean up and make the code base better than they left it.  
342 -Obviously, apply your best judgement. Remember, the goal here is to make the  
343 -code base easier for humans to navigate and understand. Always keep that in  
344 -mind when nudging others to comply.  
345 -  
346 -The rules:  
347 -  
348 -1. All code should be formatted with `gofmt -s`.  
349 -2. All code should pass the default levels of  
350 - [`golint`](https://github.com/golang/lint).  
351 -3. All code should follow the guidelines covered in [Effective  
352 - Go](http://golang.org/doc/effective_go.html) and [Go Code Review  
353 - Comments](https://github.com/golang/go/wiki/CodeReviewComments).  
354 -4. Comment the code. Tell us the why, the history and the context.  
355 -5. Document _all_ declarations and methods, even private ones. Declare  
356 - expectations, caveats and anything else that may be important. If a type  
357 - gets exported, having the comments already there will ensure it's ready.  
358 -6. Variable name length should be proportional to its context and no longer.  
359 - `noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`.  
360 - In practice, short methods will have short variable names and globals will  
361 - have longer names.  
362 -7. No underscores in package names. If you need a compound name, step back,  
363 - and re-examine why you need a compound name. If you still think you need a  
364 - compound name, lose the underscore.  
365 -8. No utils or helpers packages. If a function is not general enough to  
366 - warrant its own package, it has not been written generally enough to be a  
367 - part of a util package. Just leave it unexported and well-documented.  
368 -9. All tests should run with `go test` and outside tooling should not be  
369 - required. No, we don't need another unit testing framework. Assertion  
370 - packages are acceptable if they provide _real_ incremental value.  
371 -10. Even though we call these "rules" above, they are actually just  
372 - guidelines. Since you've read all the rules, you now know that.  
373 -  
374 -If you are having trouble getting into the mood of idiomatic Go, we recommend  
375 -reading through [Effective Go](https://golang.org/doc/effective_go.html). The  
376 -[Go Blog](https://blog.golang.org) is also a great resource. Drinking the  
377 -kool-aid is a lot easier than going thirsty.  
378 -  
379 -## Code Review Comments and Effective Go Guidelines  
380 -  
381 -[CodeLingo](https://codelingo.io) automatically checks every pull request against the following guidelines from [Effective Go](https://golang.org/doc/effective_go.html) and [Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments).  
382 -  
383 -### Package Comment  
384 -  
385 -Every package should have a package comment, a block comment preceding the package clause.  
386 -For multi-file packages, the package comment only needs to be present in one file, and any one will do.  
387 -The package comment should introduce the package and provide information relevant to the package as a  
388 -whole. It will appear first on the godoc page and should set up the detailed documentation that follows.  
389 -  
390 -### Single Method Interface Name  
391 -  
392 -By convention, one-method interfaces are named by the method name plus an -er suffix  
393 -or similar modification to construct an agent noun: Reader, Writer, Formatter, CloseNotifier etc.  
394 -  
395 -There are a number of such names and it's productive to honor them and the function names they capture.  
396 -Read, Write, Close, Flush, String and so on have canonical signatures and meanings. To avoid confusion,  
397 -don't give your method one of those names unless it has the same signature and meaning. Conversely,  
398 -if your type implements a method with the same meaning as a method on a well-known type, give it the  
399 -same name and signature; call your string-converter method String not ToString.  
400 -  
401 -### Avoid Annotations in Comments  
402 -  
403 -Comments do not need extra formatting such as banners of stars. The generated output  
404 -may not even be presented in a fixed-width font, so don't depend on spacing for alignment—godoc,  
405 -like gofmt, takes care of that. The comments are uninterpreted plain text, so HTML and other  
406 -annotations such as _this_ will reproduce verbatim and should not be used. One adjustment godoc  
407 -does do is to display indented text in a fixed-width font, suitable for program snippets.  
408 -The package comment for the fmt package uses this to good effect.  
409 -  
410 -### Comment First Word as Subject  
411 -  
412 -Doc comments work best as complete sentences, which allow a wide variety of automated presentations.  
413 -The first sentence should be a one-sentence summary that starts with the name being declared.  
414 -  
415 -### Good Package Name  
416 -  
417 -It's helpful if everyone using the package can use the same name  
418 -to refer to its contents, which implies that the package name should  
419 -be good: short, concise, evocative. By convention, packages are  
420 -given lower case, single-word names; there should be no need for  
421 -underscores or mixedCaps. Err on the side of brevity, since everyone  
422 -using your package will be typing that name. And don't worry about  
423 -collisions a priori. The package name is only the default name for  
424 -imports; it need not be unique across all source code, and in the  
425 -rare case of a collision the importing package can choose a different  
426 -name to use locally. In any case, confusion is rare because the file  
427 -name in the import determines just which package is being used.  
428 -  
429 -### Avoid Renaming Imports  
430 -  
431 -Avoid renaming imports except to avoid a name collision; good package names  
432 -should not require renaming. In the event of collision, prefer to rename the  
433 -most local or project-specific import.  
434 -  
435 -### Context as First Argument  
436 -  
437 -Values of the context.Context type carry security credentials, tracing information,  
438 -deadlines, and cancellation signals across API and process boundaries. Go programs  
439 -pass Contexts explicitly along the entire function call chain from incoming RPCs  
440 -and HTTP requests to outgoing requests.  
441 -  
442 -Most functions that use a Context should accept it as their first parameter.  
443 -  
444 -### Do Not Discard Errors  
445 -  
446 -Do not discard errors using _ variables. If a function returns an error,  
447 -check it to make sure the function succeeded. Handle the error, return it, or,  
448 -in truly exceptional situations, panic.  
449 -  
450 -### Go Error Format  
451 -  
452 -Error strings should not be capitalized (unless beginning with proper nouns  
453 -or acronyms) or end with punctuation, since they are usually printed following  
454 -other context. That is, use fmt.Errorf("something bad") not fmt.Errorf("Something bad"),  
455 -so that log.Printf("Reading %s: %v", filename, err) formats without a spurious  
456 -capital letter mid-message. This does not apply to logging, which is implicitly  
457 -line-oriented and not combined inside other messages.  
458 -  
459 -### Use Crypto Rand  
460 -  
461 -Do not use package math/rand to generate keys, even  
462 -throwaway ones. Unseeded, the generator is completely predictable.  
463 -Seeded with time.Nanoseconds(), there are just a few bits of entropy.  
464 -Instead, use crypto/rand's Reader, and if you need text, print to  
465 -hexadecimal or base64.  
1 -BSD 3-Clause License  
2 -  
3 -Copyright (c) 2016-2020 The excelize Authors.  
4 -All rights reserved.  
5 -  
6 -Redistribution and use in source and binary forms, with or without  
7 -modification, are permitted provided that the following conditions are met:  
8 -  
9 -* Redistributions of source code must retain the above copyright notice, this  
10 - list of conditions and the following disclaimer.  
11 -  
12 -* Redistributions in binary form must reproduce the above copyright notice,  
13 - this list of conditions and the following disclaimer in the documentation  
14 - and/or other materials provided with the distribution.  
15 -  
16 -* Neither the name of the copyright holder nor the names of its  
17 - contributors may be used to endorse or promote products derived from  
18 - this software without specific prior written permission.  
19 -  
20 -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
21 -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
22 -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
23 -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  
24 -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
25 -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
26 -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER  
27 -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,  
28 -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  
29 -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
1 -# PR Details  
2 -  
3 -<!--- Provide a general summary of your changes in the Title above -->  
4 -  
5 -## Description  
6 -  
7 -<!--- Describe your changes in detail -->  
8 -  
9 -## Related Issue  
10 -  
11 -<!--- This project only accepts pull requests related to open issues -->  
12 -<!--- If suggesting a new feature or change, please discuss it in an issue first -->  
13 -<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->  
14 -<!--- Please link to the issue here: -->  
15 -  
16 -## Motivation and Context  
17 -  
18 -<!--- Why is this change required? What problem does it solve? -->  
19 -  
20 -## How Has This Been Tested  
21 -  
22 -<!--- Please describe in detail how you tested your changes. -->  
23 -<!--- Include details of your testing environment, and the tests you ran to -->  
24 -<!--- see how your change affects other areas of the code, etc. -->  
25 -  
26 -## Types of changes  
27 -  
28 -<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->  
29 -  
30 -- [ ] Docs change / refactoring / dependency upgrade  
31 -- [ ] Bug fix (non-breaking change which fixes an issue)  
32 -- [ ] New feature (non-breaking change which adds functionality)  
33 -- [ ] Breaking change (fix or feature that would cause existing functionality to change)  
34 -  
35 -## Checklist  
36 -  
37 -<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->  
38 -<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->  
39 -  
40 -- [ ] My code follows the code style of this project.  
41 -- [ ] My change requires a change to the documentation.  
42 -- [ ] I have updated the documentation accordingly.  
43 -- [ ] I have read the **CONTRIBUTING** document.  
44 -- [ ] I have added tests to cover my changes.  
45 -- [ ] All new and existing tests passed.  
1 -<p align="center"><img width="650" src="./excelize.svg" alt="Excelize logo"></p>  
2 -  
3 -<p align="center">  
4 - <a href="https://travis-ci.org/360EntSecGroup-Skylar/excelize"><img src="https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master" alt="Build Status"></a>  
5 - <a href="https://codecov.io/gh/360EntSecGroup-Skylar/excelize"><img src="https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg" alt="Code Coverage"></a>  
6 - <a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a>  
7 - <a href="https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white" alt="go.dev"></a>  
8 - <a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a>  
9 - <a href="https://www.paypal.me/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a>  
10 -</p>  
11 -  
12 -# Excelize  
13 -  
14 -## Introduction  
15 -  
16 -Excelize is a library written in pure Go providing a set of functions that allow you to write to and read from XLSX / XLSM / XLTM files. Supports reading and writing spreadsheet documents generated by Microsoft Excel&trade; 2007 and later. Supports complex components by high compatibility, and provided streaming API for generating or reading data from a worksheet with huge amounts of data. This library needs Go version 1.10 or later. The full API docs can be seen using go's built-in documentation tool, or online at [go.dev](https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc) and [docs reference](https://xuri.me/excelize/).  
17 -  
18 -## Basic Usage  
19 -  
20 -### Installation  
21 -  
22 -```bash  
23 -go get github.com/360EntSecGroup-Skylar/excelize  
24 -```  
25 -  
26 -- If your package management with [Go Modules](https://blog.golang.org/using-go-modules), please install with following command.  
27 -  
28 -```bash  
29 -go get github.com/360EntSecGroup-Skylar/excelize/v2  
30 -```  
31 -  
32 -### Create spreadsheet  
33 -  
34 -Here is a minimal example usage that will create spreadsheet file.  
35 -  
36 -```go  
37 -package main  
38 -  
39 -import (  
40 - "fmt"  
41 -  
42 - "github.com/360EntSecGroup-Skylar/excelize"  
43 -)  
44 -  
45 -func main() {  
46 - f := excelize.NewFile()  
47 - // Create a new sheet.  
48 - index := f.NewSheet("Sheet2")  
49 - // Set value of a cell.  
50 - f.SetCellValue("Sheet2", "A2", "Hello world.")  
51 - f.SetCellValue("Sheet1", "B2", 100)  
52 - // Set active sheet of the workbook.  
53 - f.SetActiveSheet(index)  
54 - // Save xlsx file by the given path.  
55 - if err := f.SaveAs("Book1.xlsx"); err != nil {  
56 - fmt.Println(err)  
57 - }  
58 -}  
59 -```  
60 -  
61 -### Reading spreadsheet  
62 -  
63 -The following constitutes the bare to read a spreadsheet document.  
64 -  
65 -```go  
66 -package main  
67 -  
68 -import (  
69 - "fmt"  
70 -  
71 - "github.com/360EntSecGroup-Skylar/excelize"  
72 -)  
73 -  
74 -func main() {  
75 - f, err := excelize.OpenFile("Book1.xlsx")  
76 - if err != nil {  
77 - fmt.Println(err)  
78 - return  
79 - }  
80 - // Get value from cell by given worksheet name and axis.  
81 - cell, err := f.GetCellValue("Sheet1", "B2")  
82 - if err != nil {  
83 - fmt.Println(err)  
84 - return  
85 - }  
86 - fmt.Println(cell)  
87 - // Get all the rows in the Sheet1.  
88 - rows, err := f.GetRows("Sheet1")  
89 - for _, row := range rows {  
90 - for _, colCell := range row {  
91 - fmt.Print(colCell, "\t")  
92 - }  
93 - fmt.Println()  
94 - }  
95 -}  
96 -```  
97 -  
98 -### Add chart to spreadsheet file  
99 -  
100 -With Excelize chart generation and management is as easy as a few lines of code. You can build charts based off data in your worksheet or generate charts without any data in your worksheet at all.  
101 -  
102 -<p align="center"><img width="650" src="./test/images/chart.png" alt="Excelize"></p>  
103 -  
104 -```go  
105 -package main  
106 -  
107 -import (  
108 - "fmt"  
109 -  
110 - "github.com/360EntSecGroup-Skylar/excelize"  
111 -)  
112 -  
113 -func main() {  
114 - categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"}  
115 - values := map[string]int{"B2": 2, "C2": 3, "D2": 3, "B3": 5, "C3": 2, "D3": 4, "B4": 6, "C4": 7, "D4": 8}  
116 - f := excelize.NewFile()  
117 - for k, v := range categories {  
118 - f.SetCellValue("Sheet1", k, v)  
119 - }  
120 - for k, v := range values {  
121 - f.SetCellValue("Sheet1", k, v)  
122 - }  
123 - if err := f.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`); err != nil {  
124 - fmt.Println(err)  
125 - return  
126 - }  
127 - // Save xlsx file by the given path.  
128 - if err := f.SaveAs("Book1.xlsx"); err != nil {  
129 - fmt.Println(err)  
130 - }  
131 -}  
132 -```  
133 -  
134 -### Add picture to spreadsheet file  
135 -  
136 -```go  
137 -package main  
138 -  
139 -import (  
140 - "fmt"  
141 - _ "image/gif"  
142 - _ "image/jpeg"  
143 - _ "image/png"  
144 -  
145 - "github.com/360EntSecGroup-Skylar/excelize"  
146 -)  
147 -  
148 -func main() {  
149 - f, err := excelize.OpenFile("Book1.xlsx")  
150 - if err != nil {  
151 - fmt.Println(err)  
152 - return  
153 - }  
154 - // Insert a picture.  
155 - if err := f.AddPicture("Sheet1", "A2", "image.png", ""); err != nil {  
156 - fmt.Println(err)  
157 - }  
158 - // Insert a picture to worksheet with scaling.  
159 - if err := f.AddPicture("Sheet1", "D2", "image.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`); err != nil {  
160 - fmt.Println(err)  
161 - }  
162 - // Insert a picture offset in the cell with printing support.  
163 - if err := f.AddPicture("Sheet1", "H2", "image.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`); err != nil {  
164 - fmt.Println(err)  
165 - }  
166 - // Save the xlsx file with the origin path.  
167 - if err = f.Save(); err != nil {  
168 - fmt.Println(err)  
169 - }  
170 -}  
171 -```  
172 -  
173 -## Contributing  
174 -  
175 -Contributions are welcome! Open a pull request to fix a bug, or open an issue to discuss a new feature or change. XML is compliant with [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](http://www.ecma-international.org/publications/standards/Ecma-376.htm).  
176 -  
177 -## Licenses  
178 -  
179 -This program is under the terms of the BSD 3-Clause License. See [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause).  
180 -  
181 -The Excel logo is a trademark of [Microsoft Corporation](https://aka.ms/trademarks-usage). This artwork is an adaptation.  
182 -  
183 -gopher.{ai,svg,png} was created by [Takuya Ueda](https://twitter.com/tenntenn). Licensed under the [Creative Commons 3.0 Attributions license](http://creativecommons.org/licenses/by/3.0/).  
1 -<p align="center"><img width="650" src="./excelize.svg" alt="Excelize logo"></p>  
2 -  
3 -<p align="center">  
4 - <a href="https://travis-ci.org/360EntSecGroup-Skylar/excelize"><img src="https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master" alt="Build Status"></a>  
5 - <a href="https://codecov.io/gh/360EntSecGroup-Skylar/excelize"><img src="https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg" alt="Code Coverage"></a>  
6 - <a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a>  
7 - <a href="https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc"><img src="https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white" alt="go.dev"></a>  
8 - <a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a>  
9 - <a href="https://www.paypal.me/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a>  
10 -</p>  
11 -  
12 -# Excelize  
13 -  
14 -## 简介  
15 -  
16 -Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel&trade; 2007 及以上版本创建的电子表格文档。支持 XLSX / XLSM / XLTM 等多种文档格式,高度兼容带有样式、图片(表)、透视表、切片器等复杂组件的文档,并提供流式读写 API,用于处理包含大规模数据的工作簿。可应用于各类报表平台、云计算、边缘计算等系统。使用本类库要求使用的 Go 语言为 1.10 或更高版本,完整的 API 使用文档请访问 [go.dev](https://pkg.go.dev/github.com/360EntSecGroup-Skylar/excelize/v2?tab=doc) 或查看 [参考文档](https://xuri.me/excelize/)  
17 -  
18 -## 快速上手  
19 -  
20 -### 安装  
21 -  
22 -```bash  
23 -go get github.com/360EntSecGroup-Skylar/excelize  
24 -```  
25 -  
26 -- 如果您使用 [Go Modules](https://blog.golang.org/using-go-modules) 管理软件包,请使用下面的命令来安装最新版本。  
27 -  
28 -```bash  
29 -go get github.com/360EntSecGroup-Skylar/excelize/v2  
30 -```  
31 -  
32 -### 创建 Excel 文档  
33 -  
34 -下面是一个创建 Excel 文档的简单例子:  
35 -  
36 -```go  
37 -package main  
38 -  
39 -import (  
40 - "fmt"  
41 -  
42 - "github.com/360EntSecGroup-Skylar/excelize"  
43 -)  
44 -  
45 -func main() {  
46 - f := excelize.NewFile()  
47 - // 创建一个工作表  
48 - index := f.NewSheet("Sheet2")  
49 - // 设置单元格的值  
50 - f.SetCellValue("Sheet2", "A2", "Hello world.")  
51 - f.SetCellValue("Sheet1", "B2", 100)  
52 - // 设置工作簿的默认工作表  
53 - f.SetActiveSheet(index)  
54 - // 根据指定路径保存文件  
55 - if err := f.SaveAs("Book1.xlsx"); err != nil {  
56 - fmt.Println(err)  
57 - }  
58 -}  
59 -```  
60 -  
61 -### 读取 Excel 文档  
62 -  
63 -下面是读取 Excel 文档的例子:  
64 -  
65 -```go  
66 -package main  
67 -  
68 -import (  
69 - "fmt"  
70 -  
71 - "github.com/360EntSecGroup-Skylar/excelize"  
72 -)  
73 -  
74 -func main() {  
75 - f, err := excelize.OpenFile("Book1.xlsx")  
76 - if err != nil {  
77 - fmt.Println(err)  
78 - return  
79 - }  
80 - // 获取工作表中指定单元格的值  
81 - cell, err := f.GetCellValue("Sheet1", "B2")  
82 - if err != nil {  
83 - fmt.Println(err)  
84 - return  
85 - }  
86 - fmt.Println(cell)  
87 - // 获取 Sheet1 上所有单元格  
88 - rows, err := f.GetRows("Sheet1")  
89 - for _, row := range rows {  
90 - for _, colCell := range row {  
91 - fmt.Print(colCell, "\t")  
92 - }  
93 - fmt.Println()  
94 - }  
95 -}  
96 -```  
97 -  
98 -### 在 Excel 文档中创建图表  
99 -  
100 -使用 Excelize 生成图表十分简单,仅需几行代码。您可以根据工作表中的已有数据构建图表,或向工作表中添加数据并创建图表。  
101 -  
102 -<p align="center"><img width="650" src="./test/images/chart.png" alt="Excelize"></p>  
103 -  
104 -```go  
105 -package main  
106 -  
107 -import (  
108 - "fmt"  
109 -  
110 - "github.com/360EntSecGroup-Skylar/excelize"  
111 -)  
112 -  
113 -func main() {  
114 - categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"}  
115 - values := map[string]int{"B2": 2, "C2": 3, "D2": 3, "B3": 5, "C3": 2, "D3": 4, "B4": 6, "C4": 7, "D4": 8}  
116 - f := excelize.NewFile()  
117 - for k, v := range categories {  
118 - f.SetCellValue("Sheet1", k, v)  
119 - }  
120 - for k, v := range values {  
121 - f.SetCellValue("Sheet1", k, v)  
122 - }  
123 - if err := f.AddChart("Sheet1", "E1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`); err != nil {  
124 - fmt.Println(err)  
125 - return  
126 - }  
127 - // 根据指定路径保存文件  
128 - if err := f.SaveAs("Book1.xlsx"); err != nil {  
129 - fmt.Println(err)  
130 - }  
131 -}  
132 -```  
133 -  
134 -### 向 Excel 文档中插入图片  
135 -  
136 -```go  
137 -package main  
138 -  
139 -import (  
140 - "fmt"  
141 - _ "image/gif"  
142 - _ "image/jpeg"  
143 - _ "image/png"  
144 -  
145 - "github.com/360EntSecGroup-Skylar/excelize"  
146 -)  
147 -  
148 -func main() {  
149 - f, err := excelize.OpenFile("Book1.xlsx")  
150 - if err != nil {  
151 - fmt.Println(err)  
152 - return  
153 - }  
154 - // 插入图片  
155 - if err := f.AddPicture("Sheet1", "A2", "image.png", ""); err != nil {  
156 - fmt.Println(err)  
157 - }  
158 - // 在工作表中插入图片,并设置图片的缩放比例  
159 - if err := f.AddPicture("Sheet1", "D2", "image.jpg", `{"x_scale": 0.5, "y_scale": 0.5}`); err != nil {  
160 - fmt.Println(err)  
161 - }  
162 - // 在工作表中插入图片,并设置图片的打印属性  
163 - if err := f.AddPicture("Sheet1", "H2", "image.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`); err != nil {  
164 - fmt.Println(err)  
165 - }  
166 - // 保存文件  
167 - if err = f.Save(); err != nil {  
168 - fmt.Println(err)  
169 - }  
170 -}  
171 -```  
172 -  
173 -## 社区合作  
174 -  
175 -欢迎您为此项目贡献代码,提出建议或问题、修复 Bug 以及参与讨论对新功能的想法。 XML 符合标准: [part 1 of the 5th edition of the ECMA-376 Standard for Office Open XML](http://www.ecma-international.org/publications/standards/Ecma-376.htm)  
176 -  
177 -## 开源许可  
178 -  
179 -本项目遵循 BSD 3-Clause 开源许可协议,访问 [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) 查看许可协议文件。  
180 -  
181 -Excel 徽标是 [Microsoft Corporation](https://aka.ms/trademarks-usage) 的商标,项目的图片是一种改编。  
182 -  
183 -gopher.{ai,svg,png} 由 [Takuya Ueda](https://twitter.com/tenntenn) 创作,遵循 [Creative Commons 3.0 Attributions license](http://creativecommons.org/licenses/by/3.0/) 创作共用授权条款。  
1 -# Security Policy  
2 -  
3 -## Supported Versions  
4 -  
5 -We will dive into any security-related issue as long as your Excelize version is still supported by us. When reporting an issue, include as much information as possible, but no need to fill fancy forms or answer tedious questions. Just tell us what you found, how to reproduce it, and any concerns you have about it. We will respond as soon as possible and follow up with any missing information.  
6 -  
7 -## Reporting a Vulnerability  
8 -  
9 -Please e-mail us directly at `xuri.me@gmail.com` or use the security issue template on GitHub. In general, public disclosure is made after the issue has been fully identified and a patch is ready to be released. A security issue gets the highest priority assigned and a reply regarding the vulnerability is given within a typical 24 hours. Thank you!  
1 -// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of  
2 -// this source code is governed by a BSD-style license that can be found in  
3 -// the LICENSE file.  
4 -//  
5 -// Package excelize providing a set of functions that allow you to write to  
6 -// and read from XLSX / XLSM / XLTM files. Supports reading and writing  
7 -// spreadsheet documents generated by Microsoft Exce™ 2007 and later. Supports  
8 -// complex components by high compatibility, and provided streaming API for  
9 -// generating or reading data from a worksheet with huge amounts of data. This  
10 -// library needs Go version 1.10 or later.  
11 -  
12 -package excelize  
13 -  
14 -import (  
15 - "errors"  
16 - "strings"  
17 -)  
18 -  
19 -type adjustDirection bool  
20 -  
21 -const (  
22 - columns adjustDirection = false  
23 - rows adjustDirection = true  
24 -)  
25 -  
26 -// adjustHelper provides a function to adjust rows and columns dimensions,  
27 -// hyperlinks, merged cells and auto filter when inserting or deleting rows or  
28 -// columns.  
29 -//  
30 -// sheet: Worksheet name that we're editing  
31 -// column: Index number of the column we're inserting/deleting before  
32 -// row: Index number of the row we're inserting/deleting before  
33 -// offset: Number of rows/column to insert/delete negative values indicate deletion  
34 -//  
35 -// TODO: adjustPageBreaks, adjustComments, adjustDataValidations, adjustProtectedCells  
36 -//  
37 -func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int) error {  
38 - xlsx, err := f.workSheetReader(sheet)  
39 - if err != nil {  
40 - return err  
41 - }  
42 - if dir == rows {  
43 - f.adjustRowDimensions(xlsx, num, offset)  
44 - } else {  
45 - f.adjustColDimensions(xlsx, num, offset)  
46 - }  
47 - f.adjustHyperlinks(xlsx, sheet, dir, num, offset)  
48 - if err = f.adjustMergeCells(xlsx, dir, num, offset); err != nil {  
49 - return err  
50 - }  
51 - if err = f.adjustAutoFilter(xlsx, dir, num, offset); err != nil {  
52 - return err  
53 - }  
54 - if err = f.adjustCalcChain(dir, num, offset); err != nil {  
55 - return err  
56 - }  
57 - checkSheet(xlsx)  
58 - _ = checkRow(xlsx)  
59 -  
60 - if xlsx.MergeCells != nil && len(xlsx.MergeCells.Cells) == 0 {  
61 - xlsx.MergeCells = nil  
62 - }  
63 -  
64 - return nil  
65 -}  
66 -  
67 -// adjustColDimensions provides a function to update column dimensions when  
68 -// inserting or deleting rows or columns.  
69 -func (f *File) adjustColDimensions(xlsx *xlsxWorksheet, col, offset int) {  
70 - for rowIdx := range xlsx.SheetData.Row {  
71 - for colIdx, v := range xlsx.SheetData.Row[rowIdx].C {  
72 - cellCol, cellRow, _ := CellNameToCoordinates(v.R)  
73 - if col <= cellCol {  
74 - if newCol := cellCol + offset; newCol > 0 {  
75 - xlsx.SheetData.Row[rowIdx].C[colIdx].R, _ = CoordinatesToCellName(newCol, cellRow)  
76 - }  
77 - }  
78 - }  
79 - }  
80 -}  
81 -  
82 -// adjustRowDimensions provides a function to update row dimensions when  
83 -// inserting or deleting rows or columns.  
84 -func (f *File) adjustRowDimensions(xlsx *xlsxWorksheet, row, offset int) {  
85 - for i := range xlsx.SheetData.Row {  
86 - r := &xlsx.SheetData.Row[i]  
87 - if newRow := r.R + offset; r.R >= row && newRow > 0 {  
88 - f.ajustSingleRowDimensions(r, newRow)  
89 - }  
90 - }  
91 -}  
92 -  
93 -// ajustSingleRowDimensions provides a function to ajust single row dimensions.  
94 -func (f *File) ajustSingleRowDimensions(r *xlsxRow, num int) {  
95 - r.R = num  
96 - for i, col := range r.C {  
97 - colName, _, _ := SplitCellName(col.R)  
98 - r.C[i].R, _ = JoinCellName(colName, num)  
99 - }  
100 -}  
101 -  
102 -// adjustHyperlinks provides a function to update hyperlinks when inserting or  
103 -// deleting rows or columns.  
104 -func (f *File) adjustHyperlinks(xlsx *xlsxWorksheet, sheet string, dir adjustDirection, num, offset int) {  
105 - // short path  
106 - if xlsx.Hyperlinks == nil || len(xlsx.Hyperlinks.Hyperlink) == 0 {  
107 - return  
108 - }  
109 -  
110 - // order is important  
111 - if offset < 0 {  
112 - for i := len(xlsx.Hyperlinks.Hyperlink) - 1; i >= 0; i-- {  
113 - linkData := xlsx.Hyperlinks.Hyperlink[i]  
114 - colNum, rowNum, _ := CellNameToCoordinates(linkData.Ref)  
115 -  
116 - if (dir == rows && num == rowNum) || (dir == columns && num == colNum) {  
117 - f.deleteSheetRelationships(sheet, linkData.RID)  
118 - if len(xlsx.Hyperlinks.Hyperlink) > 1 {  
119 - xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink[:i],  
120 - xlsx.Hyperlinks.Hyperlink[i+1:]...)  
121 - } else {  
122 - xlsx.Hyperlinks = nil  
123 - }  
124 - }  
125 - }  
126 - }  
127 -  
128 - if xlsx.Hyperlinks == nil {  
129 - return  
130 - }  
131 -  
132 - for i := range xlsx.Hyperlinks.Hyperlink {  
133 - link := &xlsx.Hyperlinks.Hyperlink[i] // get reference  
134 - colNum, rowNum, _ := CellNameToCoordinates(link.Ref)  
135 -  
136 - if dir == rows {  
137 - if rowNum >= num {  
138 - link.Ref, _ = CoordinatesToCellName(colNum, rowNum+offset)  
139 - }  
140 - } else {  
141 - if colNum >= num {  
142 - link.Ref, _ = CoordinatesToCellName(colNum+offset, rowNum)  
143 - }  
144 - }  
145 - }  
146 -}  
147 -  
148 -// adjustAutoFilter provides a function to update the auto filter when  
149 -// inserting or deleting rows or columns.  
150 -func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) error {  
151 - if xlsx.AutoFilter == nil {  
152 - return nil  
153 - }  
154 -  
155 - coordinates, err := f.areaRefToCoordinates(xlsx.AutoFilter.Ref)  
156 - if err != nil {  
157 - return err  
158 - }  
159 - x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]  
160 -  
161 - if (dir == rows && y1 == num && offset < 0) || (dir == columns && x1 == num && x2 == num) {  
162 - xlsx.AutoFilter = nil  
163 - for rowIdx := range xlsx.SheetData.Row {  
164 - rowData := &xlsx.SheetData.Row[rowIdx]  
165 - if rowData.R > y1 && rowData.R <= y2 {  
166 - rowData.Hidden = false  
167 - }  
168 - }  
169 - return nil  
170 - }  
171 -  
172 - coordinates = f.adjustAutoFilterHelper(dir, coordinates, num, offset)  
173 - x1, y1, x2, y2 = coordinates[0], coordinates[1], coordinates[2], coordinates[3]  
174 -  
175 - if xlsx.AutoFilter.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {  
176 - return err  
177 - }  
178 - return nil  
179 -}  
180 -  
181 -// adjustAutoFilterHelper provides a function for adjusting auto filter to  
182 -// compare and calculate cell axis by the given adjust direction, operation  
183 -// axis and offset.  
184 -func (f *File) adjustAutoFilterHelper(dir adjustDirection, coordinates []int, num, offset int) []int {  
185 - if dir == rows {  
186 - if coordinates[1] >= num {  
187 - coordinates[1] += offset  
188 - }  
189 - if coordinates[3] >= num {  
190 - coordinates[3] += offset  
191 - }  
192 - } else {  
193 - if coordinates[2] >= num {  
194 - coordinates[2] += offset  
195 - }  
196 - }  
197 - return coordinates  
198 -}  
199 -  
200 -// areaRefToCoordinates provides a function to convert area reference to a  
201 -// pair of coordinates.  
202 -func (f *File) areaRefToCoordinates(ref string) ([]int, error) {  
203 - rng := strings.Split(ref, ":")  
204 - return areaRangeToCoordinates(rng[0], rng[1])  
205 -}  
206 -  
207 -// areaRangeToCoordinates provides a function to convert cell range to a  
208 -// pair of coordinates.  
209 -func areaRangeToCoordinates(firstCell, lastCell string) ([]int, error) {  
210 - coordinates := make([]int, 4)  
211 - var err error  
212 - coordinates[0], coordinates[1], err = CellNameToCoordinates(firstCell)  
213 - if err != nil {  
214 - return coordinates, err  
215 - }  
216 - coordinates[2], coordinates[3], err = CellNameToCoordinates(lastCell)  
217 - return coordinates, err  
218 -}  
219 -  
220 -// sortCoordinates provides a function to correct the coordinate area, such  
221 -// correct C1:B3 to B1:C3.  
222 -func sortCoordinates(coordinates []int) error {  
223 - if len(coordinates) != 4 {  
224 - return errors.New("coordinates length must be 4")  
225 - }  
226 - if coordinates[2] < coordinates[0] {  
227 - coordinates[2], coordinates[0] = coordinates[0], coordinates[2]  
228 - }  
229 - if coordinates[3] < coordinates[1] {  
230 - coordinates[3], coordinates[1] = coordinates[1], coordinates[3]  
231 - }  
232 - return nil  
233 -}  
234 -  
235 -// coordinatesToAreaRef provides a function to convert a pair of coordinates  
236 -// to area reference.  
237 -func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {  
238 - if len(coordinates) != 4 {  
239 - return "", errors.New("coordinates length must be 4")  
240 - }  
241 - firstCell, err := CoordinatesToCellName(coordinates[0], coordinates[1])  
242 - if err != nil {  
243 - return "", err  
244 - }  
245 - lastCell, err := CoordinatesToCellName(coordinates[2], coordinates[3])  
246 - if err != nil {  
247 - return "", err  
248 - }  
249 - return firstCell + ":" + lastCell, err  
250 -}  
251 -  
252 -// adjustMergeCells provides a function to update merged cells when inserting  
253 -// or deleting rows or columns.  
254 -func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) error {  
255 - if xlsx.MergeCells == nil {  
256 - return nil  
257 - }  
258 -  
259 - for i := 0; i < len(xlsx.MergeCells.Cells); i++ {  
260 - areaData := xlsx.MergeCells.Cells[i]  
261 - coordinates, err := f.areaRefToCoordinates(areaData.Ref)  
262 - if err != nil {  
263 - return err  
264 - }  
265 - x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]  
266 - if dir == rows {  
267 - if y1 == num && y2 == num && offset < 0 {  
268 - f.deleteMergeCell(xlsx, i)  
269 - i--  
270 - }  
271 - y1 = f.adjustMergeCellsHelper(y1, num, offset)  
272 - y2 = f.adjustMergeCellsHelper(y2, num, offset)  
273 - } else {  
274 - if x1 == num && x2 == num && offset < 0 {  
275 - f.deleteMergeCell(xlsx, i)  
276 - i--  
277 - }  
278 - x1 = f.adjustMergeCellsHelper(x1, num, offset)  
279 - x2 = f.adjustMergeCellsHelper(x2, num, offset)  
280 - }  
281 - if x1 == x2 && y1 == y2 {  
282 - f.deleteMergeCell(xlsx, i)  
283 - i--  
284 - }  
285 - if areaData.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {  
286 - return err  
287 - }  
288 - }  
289 - return nil  
290 -}  
291 -  
292 -// adjustMergeCellsHelper provides a function for adjusting merge cells to  
293 -// compare and calculate cell axis by the given pivot, operation axis and  
294 -// offset.  
295 -func (f *File) adjustMergeCellsHelper(pivot, num, offset int) int {  
296 - if pivot >= num {  
297 - pivot += offset  
298 - if pivot < 1 {  
299 - return 1  
300 - }  
301 - return pivot  
302 - }  
303 - return pivot  
304 -}  
305 -  
306 -// deleteMergeCell provides a function to delete merged cell by given index.  
307 -func (f *File) deleteMergeCell(sheet *xlsxWorksheet, idx int) {  
308 - if len(sheet.MergeCells.Cells) > idx {  
309 - sheet.MergeCells.Cells = append(sheet.MergeCells.Cells[:idx], sheet.MergeCells.Cells[idx+1:]...)  
310 - sheet.MergeCells.Count = len(sheet.MergeCells.Cells)  
311 - }  
312 -}  
313 -  
314 -// adjustCalcChain provides a function to update the calculation chain when  
315 -// inserting or deleting rows or columns.  
316 -func (f *File) adjustCalcChain(dir adjustDirection, num, offset int) error {  
317 - if f.CalcChain == nil {  
318 - return nil  
319 - }  
320 - for index, c := range f.CalcChain.C {  
321 - colNum, rowNum, err := CellNameToCoordinates(c.R)  
322 - if err != nil {  
323 - return err  
324 - }  
325 - if dir == rows && num <= rowNum {  
326 - if newRow := rowNum + offset; newRow > 0 {  
327 - f.CalcChain.C[index].R, _ = CoordinatesToCellName(colNum, newRow)  
328 - }  
329 - }  
330 - if dir == columns && num <= colNum {  
331 - if newCol := colNum + offset; newCol > 0 {  
332 - f.CalcChain.C[index].R, _ = CoordinatesToCellName(newCol, rowNum)  
333 - }  
334 - }  
335 - }  
336 - return nil  
337 -}