Merge branch 'feat_set' into test
正在显示
11 个修改的文件
包含
610 行增加
和
5 行删除
1 | +package service | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/linmadan/egglib-go/core/application" | ||
6 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory" | ||
7 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/querySet/command" | ||
8 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/dto" | ||
9 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | ||
10 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel" | ||
11 | + "time" | ||
12 | +) | ||
13 | + | ||
14 | +func (querySetService *QuerySetService) CalculateSetPreview(ctx *domain.Context, updateQuerySetCommand *command.UpdateQuerySetCommand) (interface{}, error) { | ||
15 | + if err := updateQuerySetCommand.ValidateCommand(); err != nil { | ||
16 | + return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | ||
17 | + } | ||
18 | + transactionContext, err := factory.CreateTransactionContext(nil) | ||
19 | + if err != nil { | ||
20 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
21 | + } | ||
22 | + if err := transactionContext.StartTransaction(); err != nil { | ||
23 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
24 | + } | ||
25 | + defer func() { | ||
26 | + transactionContext.RollbackTransaction() | ||
27 | + }() | ||
28 | + | ||
29 | + var querySet *domain.QuerySet | ||
30 | + _, querySet, err = factory.FastPgQuerySet(transactionContext, updateQuerySetCommand.QuerySetId) | ||
31 | + if err != nil { | ||
32 | + return nil, factory.FastError(err) | ||
33 | + } | ||
34 | + | ||
35 | + svr, _ := factory.FastQuerySetServices(transactionContext) | ||
36 | + var dataTable *domain.DataTable | ||
37 | + dataTable, err = svr.LoadCalculateSetData(ctx, querySet, updateQuerySetCommand.QueryComponents) | ||
38 | + if err != nil { | ||
39 | + return nil, factory.FastError(err) | ||
40 | + } | ||
41 | + response := (&dto.TablePreviewDto{}) | ||
42 | + response.ObjectType = querySet.Type | ||
43 | + response.Name = querySet.Name | ||
44 | + response.Fields = dataTable.Fields | ||
45 | + response.Data = domain.GripData(domain.ToFieldData(dataTable.Fields, dataTable.Data, false), int64(len(dataTable.Data))) | ||
46 | + | ||
47 | + if err := transactionContext.CommitTransaction(); err != nil { | ||
48 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
49 | + } | ||
50 | + return response, nil | ||
51 | +} | ||
52 | + | ||
53 | +func (querySetService *QuerySetService) CalculateSetExport(ctx *domain.Context, updateQuerySetCommand *command.UpdateQuerySetCommand) (interface{}, error) { | ||
54 | + if err := updateQuerySetCommand.ValidateCommand(); err != nil { | ||
55 | + return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | ||
56 | + } | ||
57 | + transactionContext, err := factory.CreateTransactionContext(nil) | ||
58 | + if err != nil { | ||
59 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
60 | + } | ||
61 | + if err := transactionContext.StartTransaction(); err != nil { | ||
62 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
63 | + } | ||
64 | + defer func() { | ||
65 | + transactionContext.RollbackTransaction() | ||
66 | + }() | ||
67 | + | ||
68 | + var querySet *domain.QuerySet | ||
69 | + _, querySet, err = factory.FastPgQuerySet(transactionContext, updateQuerySetCommand.QuerySetId) | ||
70 | + if err != nil { | ||
71 | + return nil, factory.FastError(err) | ||
72 | + } | ||
73 | + | ||
74 | + svr, _ := factory.FastQuerySetServices(transactionContext) | ||
75 | + var dataTable *domain.DataTable | ||
76 | + dataTable, err = svr.LoadCalculateSetData(ctx, querySet, updateQuerySetCommand.QueryComponents) | ||
77 | + if err != nil { | ||
78 | + return nil, factory.FastError(err) | ||
79 | + } | ||
80 | + | ||
81 | + var fields []string | ||
82 | + //for i := range dataTable.Fields { | ||
83 | + // fields = append(fields, dataTable.Fields[i].Name) | ||
84 | + //} | ||
85 | + | ||
86 | + filename := fmt.Sprintf("%v_%v.xlsx", querySet.Name, time.Now().Format("060102150405")) | ||
87 | + path := fmt.Sprintf("public/%v", filename) | ||
88 | + excelWriter := excel.NewXLXSWriterTo(fields, dataTable.Data) | ||
89 | + excelWriter.IgnoreTitle = true | ||
90 | + if err = excelWriter.Save(path); err != nil { | ||
91 | + return nil, factory.FastError(err) | ||
92 | + } | ||
93 | + | ||
94 | + if err := transactionContext.CommitTransaction(); err != nil { | ||
95 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
96 | + } | ||
97 | + return map[string]interface{}{ | ||
98 | + "url": domain.DownloadUrl(filename), | ||
99 | + }, err | ||
100 | +} |
1 | +package service | ||
2 | + | ||
3 | +import ( | ||
4 | + "github.com/linmadan/egglib-go/core/application" | ||
5 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory" | ||
6 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/command" | ||
7 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/table/dto" | ||
8 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | ||
9 | +) | ||
10 | + | ||
11 | +func (tableService *TableService) CalculateTablePreview(ctx *domain.Context, cmd *command.TablePreviewCommand) (interface{}, error) { | ||
12 | + if err := cmd.ValidateCommand(); err != nil { | ||
13 | + return nil, application.ThrowError(application.ARG_ERROR, err.Error()) | ||
14 | + } | ||
15 | + transactionContext, err := factory.CreateTransactionContext(nil) | ||
16 | + if err != nil { | ||
17 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
18 | + } | ||
19 | + if err := transactionContext.StartTransaction(); err != nil { | ||
20 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
21 | + } | ||
22 | + defer func() { | ||
23 | + transactionContext.RollbackTransaction() | ||
24 | + }() | ||
25 | + | ||
26 | + var table *domain.QuerySet | ||
27 | + _, table, err = factory.FastPgQuerySet(transactionContext, cmd.TableId) | ||
28 | + if err != nil { | ||
29 | + return nil, factory.FastError(err) | ||
30 | + } | ||
31 | + | ||
32 | + svr, _ := factory.FastQuerySetServices(transactionContext) | ||
33 | + var dataTable *domain.DataTable | ||
34 | + dataTable, err = svr.LoadCalculateSetData(ctx, table, table.QueryComponents) | ||
35 | + if err != nil { | ||
36 | + return nil, factory.FastError(err) | ||
37 | + } | ||
38 | + response := (&dto.TablePreviewDto{}) | ||
39 | + response.Fields = dataTable.Fields | ||
40 | + response.Data = domain.GripData(domain.ToFieldData(dataTable.Fields, dataTable.Data, false), int64(len(dataTable.Data))) | ||
41 | + if err := transactionContext.CommitTransaction(); err != nil { | ||
42 | + return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error()) | ||
43 | + } | ||
44 | + return response, nil | ||
45 | +} |
@@ -70,6 +70,29 @@ func (t *DataTable) OptionalValue() []string { | @@ -70,6 +70,29 @@ func (t *DataTable) OptionalValue() []string { | ||
70 | return values | 70 | return values |
71 | } | 71 | } |
72 | 72 | ||
73 | +func (t *DataTable) Values(f *Field) []string { | ||
74 | + var res = make([]string, 0) | ||
75 | + index := -1 | ||
76 | + for i := range t.Fields { | ||
77 | + if t.Fields[i].SQLName == f.SQLName { | ||
78 | + index = i | ||
79 | + break | ||
80 | + } | ||
81 | + } | ||
82 | + if index < 0 { | ||
83 | + return res | ||
84 | + } | ||
85 | + for i := range t.Data { | ||
86 | + for j := range t.Data[i] { | ||
87 | + if j == index { | ||
88 | + res = append(res, t.Data[i][j]) | ||
89 | + break | ||
90 | + } | ||
91 | + } | ||
92 | + } | ||
93 | + return res | ||
94 | +} | ||
95 | + | ||
73 | func (t *DataTable) MatchFields(from []*Field) []*Field { | 96 | func (t *DataTable) MatchFields(from []*Field) []*Field { |
74 | return from | 97 | return from |
75 | } | 98 | } |
@@ -112,6 +112,7 @@ var ObjectTypeMap = map[string]string{ | @@ -112,6 +112,7 @@ var ObjectTypeMap = map[string]string{ | ||
112 | SubProcessTable.ToString(): "子过程", | 112 | SubProcessTable.ToString(): "子过程", |
113 | CalculateItem.ToString(): "计算项", | 113 | CalculateItem.ToString(): "计算项", |
114 | CalculateTable.ToString(): "计算表", | 114 | CalculateTable.ToString(): "计算表", |
115 | + CalculateSet.ToString(): "计算集", | ||
115 | } | 116 | } |
116 | 117 | ||
117 | var ( | 118 | var ( |
@@ -35,6 +35,7 @@ type QueryComponent struct { | @@ -35,6 +35,7 @@ type QueryComponent struct { | ||
35 | Description string `json:"description"` | 35 | Description string `json:"description"` |
36 | Formula *FieldFormulaExpr `json:"formula"` | 36 | Formula *FieldFormulaExpr `json:"formula"` |
37 | Aggregation *AggregationRule `json:"aggregation"` | 37 | Aggregation *AggregationRule `json:"aggregation"` |
38 | + Layout *LayoutRule `json:"layout"` | ||
38 | } | 39 | } |
39 | 40 | ||
40 | func (qc QueryComponent) AllSelectExpr() []SelectExpr { | 41 | func (qc QueryComponent) AllSelectExpr() []SelectExpr { |
1 | +package domain | ||
2 | + | ||
3 | +const ( | ||
4 | + CellTypeTable = "Table" | ||
5 | + CellTypeTableField = "TableField" | ||
6 | + CellTypeText = "Text" | ||
7 | + CellTypeNull = "Null" | ||
8 | +) | ||
9 | + | ||
10 | +const ( | ||
11 | + DirectionNone = "Null" | ||
12 | + DirectionRight = "Right" | ||
13 | + DirectionDown = "Down" | ||
14 | +) | ||
15 | + | ||
16 | +type LayoutRule struct { | ||
17 | + Layout | ||
18 | +} | ||
19 | + | ||
20 | +type Layout struct { | ||
21 | + Cells [][]*LayoutCell `json:"cells"` | ||
22 | +} | ||
23 | + | ||
24 | +type LayoutCell struct { | ||
25 | + Type string `json:"type,omitempty"` // Table TableField Text Null | ||
26 | + Data *LayoutCellData `json:"data,omitempty"` | ||
27 | + Direction string `json:"direction,omitempty"` // 向右:Right 向下:Down | ||
28 | + X int `json:"-,omitempty"` | ||
29 | + Y int `json:"-,omitempty"` | ||
30 | + Length int `json:"-"` | ||
31 | +} | ||
32 | + | ||
33 | +type LayoutCellData struct { | ||
34 | + //Table *Table `json:"table,omitempty"` | ||
35 | + //Field *Field `json:"field,omitempty"` | ||
36 | + TableField *TableField `json:"tableField"` | ||
37 | + Text string `json:"text,omitempty"` | ||
38 | +} | ||
39 | + | ||
40 | +func (l *Layout) LayoutCells() []*LayoutCell { | ||
41 | + var cells = make([]*LayoutCell, 0) | ||
42 | + for i, rows := range l.Cells { | ||
43 | + for j, item := range rows { | ||
44 | + if item.Type == CellTypeNull || item.Type == "" { | ||
45 | + continue | ||
46 | + } | ||
47 | + item.X = i | ||
48 | + item.Y = j | ||
49 | + cells = append(cells, item) | ||
50 | + } | ||
51 | + } | ||
52 | + return cells | ||
53 | +} |
@@ -104,6 +104,9 @@ func (ptr *QuerySetService) Update(ctx *domain.Context, querySetId int, queryCom | @@ -104,6 +104,9 @@ func (ptr *QuerySetService) Update(ctx *domain.Context, querySetId int, queryCom | ||
104 | if qs.Type == domain.CalculateTable.ToString() { | 104 | if qs.Type == domain.CalculateTable.ToString() { |
105 | return ptr.UpdateCalculateTable(ctx, qs, queryComponents) | 105 | return ptr.UpdateCalculateTable(ctx, qs, queryComponents) |
106 | } | 106 | } |
107 | + if qs.Type == domain.CalculateSet.ToString() { | ||
108 | + return ptr.UpdateCalculateSet(ctx, qs, queryComponents) | ||
109 | + } | ||
107 | return nil | 110 | return nil |
108 | } | 111 | } |
109 | 112 | ||
@@ -235,6 +238,31 @@ func (ptr *QuerySetService) UpdateCalculateTable(ctx *domain.Context, qs *domain | @@ -235,6 +238,31 @@ func (ptr *QuerySetService) UpdateCalculateTable(ctx *domain.Context, qs *domain | ||
235 | return nil | 238 | return nil |
236 | } | 239 | } |
237 | 240 | ||
241 | +func (ptr *QuerySetService) UpdateCalculateSet(ctx *domain.Context, qs *domain.QuerySet, queryComponents []*domain.QueryComponent) error { | ||
242 | + //var err error | ||
243 | + res, err := ptr.LoadCalculateSetData(ctx, qs, queryComponents) | ||
244 | + if err != nil { | ||
245 | + return err | ||
246 | + } | ||
247 | + querySetRepository, _ := repository.NewQuerySetRepository(ptr.transactionContext) | ||
248 | + table, err := ptr.CreateOrUpdateCalculateSet(ctx, qs, res, queryComponents) | ||
249 | + if err != nil { | ||
250 | + return err | ||
251 | + } | ||
252 | + | ||
253 | + // 生成日志 | ||
254 | + //if err = ptr.UpdateQuerySetLog(ctx, qs, queryComponents); err != nil { | ||
255 | + // return err | ||
256 | + //} | ||
257 | + //保存 | ||
258 | + qs.Update(queryComponents, table.TableId) | ||
259 | + _, err = querySetRepository.Save(qs) | ||
260 | + if err != nil { | ||
261 | + return err | ||
262 | + } | ||
263 | + return nil | ||
264 | +} | ||
265 | + | ||
238 | func (ptr *QuerySetService) PreviewPrepare(ctx *domain.Context, querySetId int, queryComponents []*domain.QueryComponent) (*domain.Table, error) { | 266 | func (ptr *QuerySetService) PreviewPrepare(ctx *domain.Context, querySetId int, queryComponents []*domain.QueryComponent) (*domain.Table, error) { |
239 | querySetRepository, _ := repository.NewQuerySetRepository(ptr.transactionContext) | 267 | querySetRepository, _ := repository.NewQuerySetRepository(ptr.transactionContext) |
240 | querySet, err := querySetRepository.FindOne(map[string]interface{}{"querySetId": querySetId}) | 268 | querySet, err := querySetRepository.FindOne(map[string]interface{}{"querySetId": querySetId}) |
@@ -771,6 +799,32 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateTable(ctx *domain.Context, qu | @@ -771,6 +799,32 @@ func (ptr *QuerySetService) CreateOrUpdateCalculateTable(ctx *domain.Context, qu | ||
771 | return table, nil | 799 | return table, nil |
772 | } | 800 | } |
773 | 801 | ||
802 | +// CreateOrUpdateCalculateSet 计算集 | ||
803 | +func (ptr *QuerySetService) CreateOrUpdateCalculateSet(ctx *domain.Context, querySet *domain.QuerySet, dataTable *domain.DataTable, queryComponents []*domain.QueryComponent) (*domain.Table, error) { | ||
804 | + var ( | ||
805 | + err error | ||
806 | + ) | ||
807 | + dependencyTables := querySet.GetDependencyTables(queryComponents) | ||
808 | + tableRepository, _ := repository.NewTableRepository(ptr.transactionContext) | ||
809 | + var table *domain.Table = NewCopyTable(domain.TableType(querySet.Type), querySet.Name, dataTable.Fields, 0).WithContext(ctx).WithPrefix(strings.ToLower(querySet.Type)) | ||
810 | + if querySet.QuerySetInfo.BindTableId > 0 { | ||
811 | + table, err = tableRepository.FindOne(map[string]interface{}{"context": ctx, "tableId": querySet.QuerySetInfo.BindTableId}) | ||
812 | + if err != nil { | ||
813 | + return nil, err | ||
814 | + } | ||
815 | + table.DataFields = dataTable.Fields | ||
816 | + table.UpdatedAt = time.Now() | ||
817 | + } | ||
818 | + | ||
819 | + table.TableInfo.ApplyOnModule = domain.ModuleAll | ||
820 | + table.TableInfo.DependencyTables = dependencyTables | ||
821 | + table, err = tableRepository.Save(table) | ||
822 | + if err != nil { | ||
823 | + return nil, err | ||
824 | + } | ||
825 | + return table, nil | ||
826 | +} | ||
827 | + | ||
774 | func (ptr *QuerySetService) Rename(ctx *domain.Context, querySetId int, name string) error { | 828 | func (ptr *QuerySetService) Rename(ctx *domain.Context, querySetId int, name string) error { |
775 | querySetRepository, _ := repository.NewQuerySetRepository(ptr.transactionContext) | 829 | querySetRepository, _ := repository.NewQuerySetRepository(ptr.transactionContext) |
776 | qs, err := querySetRepository.FindOne(map[string]interface{}{"querySetId": querySetId}) | 830 | qs, err := querySetRepository.FindOne(map[string]interface{}{"querySetId": querySetId}) |
1 | +package domainService | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "github.com/zeromicro/go-zero/core/collection" | ||
6 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain" | ||
7 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/repository" | ||
8 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/starrocks" | ||
9 | + "gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/log" | ||
10 | + "strings" | ||
11 | +) | ||
12 | + | ||
13 | +const DefaultExpandNum = 10000 | ||
14 | +const MaxExpandNum = 50000 | ||
15 | + | ||
16 | +func (ptr *QuerySetService) LoadCalculateSetData(ctx *domain.Context, qs *domain.QuerySet, queryComponents []*domain.QueryComponent) (*domain.DataTable, error) { | ||
17 | + var ( | ||
18 | + res = &domain.DataTable{} | ||
19 | + dataTables = make(map[int]*domain.DataTable) | ||
20 | + err error | ||
21 | + ) | ||
22 | + | ||
23 | + if len(queryComponents) == 0 { | ||
24 | + return res, nil | ||
25 | + } | ||
26 | + // 加载Tables数据 | ||
27 | + q := queryComponents[0] | ||
28 | + cells := q.Layout.LayoutCells() | ||
29 | + dataTables = ptr.LoadDataTables(ctx, cells) | ||
30 | + // 数据布局 | ||
31 | + res, err = DataLayout(res, dataTables, cells) | ||
32 | + if err != nil { | ||
33 | + return nil, err | ||
34 | + } | ||
35 | + // 数据持久化 | ||
36 | + return res, nil | ||
37 | +} | ||
38 | + | ||
39 | +func FastTable(table *domain.Table) (*domain.DataTable, error) { | ||
40 | + var err error | ||
41 | + var options = starrocks.QueryOptions{ | ||
42 | + Table: table, | ||
43 | + TableName: table.SQLName, | ||
44 | + Select: table.Fields(false), | ||
45 | + } | ||
46 | + var dataTable *domain.DataTable | ||
47 | + dataTable, err = FastDataTable(options) | ||
48 | + if err != nil { | ||
49 | + return nil, err | ||
50 | + } | ||
51 | + return dataTable, nil | ||
52 | +} | ||
53 | + | ||
54 | +func FastDataTable(options starrocks.QueryOptions) (*domain.DataTable, error) { | ||
55 | + var err error | ||
56 | + // 待优化分批下载,压缩 | ||
57 | + var dataTable *domain.DataTable | ||
58 | + dataTable, err = starrocks.Query(options, starrocks.WrapQueryFuncWithDB(starrocks.DB)) | ||
59 | + if err != nil { | ||
60 | + return nil, err | ||
61 | + } | ||
62 | + | ||
63 | + dataTable.Total, err = starrocks.WrapQueryCountWithDB(options, starrocks.DB)() | ||
64 | + if err != nil { | ||
65 | + return nil, err | ||
66 | + } | ||
67 | + return dataTable, nil | ||
68 | +} | ||
69 | + | ||
70 | +func (ptr *QuerySetService) LoadDataTables(ctx *domain.Context, cells []*domain.LayoutCell) map[int]*domain.DataTable { | ||
71 | + var ( | ||
72 | + dataTables = make(map[int]*domain.DataTable) | ||
73 | + tableRepository, _ = repository.NewTableRepository(ptr.transactionContext) | ||
74 | + ) | ||
75 | + tableIds := collection.NewSet() | ||
76 | + for _, cell := range cells { | ||
77 | + if cell.Data == nil || cell.Data.TableField == nil || cell.Data.TableField.TableId == 0 { | ||
78 | + continue | ||
79 | + } | ||
80 | + tableIds.AddInt(cell.Data.TableField.TableId) | ||
81 | + } | ||
82 | + if len(tableIds.KeysInt()) > 0 { | ||
83 | + _, tables, err := tableRepository.Find(map[string]interface{}{"context": ctx, "tableIds": tableIds.KeysInt()}) | ||
84 | + if err != nil { | ||
85 | + return nil | ||
86 | + } | ||
87 | + for _, t := range tables { | ||
88 | + if _, ok := dataTables[t.TableId]; ok { | ||
89 | + continue | ||
90 | + } | ||
91 | + dataTable, e := FastTable(t) | ||
92 | + if e != nil { | ||
93 | + log.Logger.Error(e.Error()) | ||
94 | + continue | ||
95 | + } | ||
96 | + dataTable.Fields = t.DataFields | ||
97 | + dataTables[t.TableId] = dataTable | ||
98 | + } | ||
99 | + } | ||
100 | + return dataTables | ||
101 | +} | ||
102 | + | ||
103 | +func DataLayout(res *domain.DataTable, dataTables map[int]*domain.DataTable, cells []*domain.LayoutCell) (*domain.DataTable, error) { | ||
104 | + dt := &DataLayoutDataTable{ | ||
105 | + DataTable: res, | ||
106 | + MapDataTables: dataTables, | ||
107 | + unprocessed: cells, | ||
108 | + } | ||
109 | + dt.Init(DefaultExpandNum) | ||
110 | + for { | ||
111 | + if len(dt.unprocessed) == 0 { | ||
112 | + break | ||
113 | + } | ||
114 | + cell := dt.unprocessed[0] | ||
115 | + dt.unprocessed = dt.unprocessed[1:] | ||
116 | + blockData, length := dt.BlockData(cell) | ||
117 | + if err := dt.Expand(cell, length); err != nil { | ||
118 | + return nil, err | ||
119 | + } | ||
120 | + dt.addByLocation(cell, blockData) | ||
121 | + // 当前单元格子 影响其他格子坐标 | ||
122 | + dt.changeUnProcessedLocation(cell, length) | ||
123 | + dt.processed = append(dt.processed, cell) | ||
124 | + dt.LastCell = cell | ||
125 | + } | ||
126 | + dt.Shrink() | ||
127 | + return dt.DataTable, nil | ||
128 | +} | ||
129 | + | ||
130 | +type DataLayoutDataTable struct { | ||
131 | + PointBegin *Location | ||
132 | + PointEnd *Location | ||
133 | + MaxX int | ||
134 | + MaxY int | ||
135 | + DataTable *domain.DataTable | ||
136 | + MapDataTables map[int]*domain.DataTable | ||
137 | + processed []*domain.LayoutCell | ||
138 | + unprocessed []*domain.LayoutCell | ||
139 | + LastCell *domain.LayoutCell | ||
140 | +} | ||
141 | + | ||
142 | +type Location struct { | ||
143 | + X int | ||
144 | + Y int | ||
145 | +} | ||
146 | + | ||
147 | +func NewLocation(x, y int) *Location { | ||
148 | + return &Location{ | ||
149 | + X: x, | ||
150 | + Y: y, | ||
151 | + } | ||
152 | +} | ||
153 | + | ||
154 | +func (l *Location) UpdateX(x int) { | ||
155 | + if l.X <= x { | ||
156 | + l.X = x | ||
157 | + } | ||
158 | +} | ||
159 | + | ||
160 | +func (l *Location) UpdateY(y int) { | ||
161 | + if l.Y <= y { | ||
162 | + l.Y = y | ||
163 | + } | ||
164 | +} | ||
165 | + | ||
166 | +func (d *DataLayoutDataTable) StartCell() { | ||
167 | + | ||
168 | +} | ||
169 | + | ||
170 | +func (d *DataLayoutDataTable) addByLocation(cell *domain.LayoutCell, blockData []string) { | ||
171 | + if d.PointBegin == nil { | ||
172 | + d.PointBegin = NewLocation(cell.X, cell.Y) | ||
173 | + d.PointEnd = NewLocation(cell.X, cell.Y) | ||
174 | + } | ||
175 | + switch cell.Direction { | ||
176 | + case domain.DirectionRight: | ||
177 | + for i := range blockData { | ||
178 | + d.DataTable.Data[cell.X][cell.Y+i] = blockData[i] | ||
179 | + } | ||
180 | + d.PointEnd.UpdateX(cell.X) | ||
181 | + d.PointEnd.UpdateY(cell.Y + len(blockData) - 1) | ||
182 | + case domain.DirectionDown: | ||
183 | + for i := range blockData { | ||
184 | + d.DataTable.Data[cell.X+i][cell.Y] = blockData[i] | ||
185 | + } | ||
186 | + d.PointEnd.UpdateX(cell.X + len(blockData) - 1) | ||
187 | + d.PointEnd.UpdateY(cell.Y) | ||
188 | + case domain.DirectionNone: | ||
189 | + d.DataTable.Data[cell.X][cell.Y] = blockData[0] | ||
190 | + d.PointEnd.UpdateX(cell.X) | ||
191 | + d.PointEnd.UpdateY(cell.Y) | ||
192 | + } | ||
193 | +} | ||
194 | + | ||
195 | +func (d *DataLayoutDataTable) changeUnProcessedLocation(lastCell *domain.LayoutCell, length int) { | ||
196 | + // log.Logger.Info("修改定位点") | ||
197 | + for _, cell := range d.unprocessed { | ||
198 | + switch lastCell.Direction { | ||
199 | + case domain.DirectionRight: | ||
200 | + if cell.X >= lastCell.X && cell.Y > lastCell.Y { | ||
201 | + cell.Y += length - 1 | ||
202 | + } | ||
203 | + case domain.DirectionDown: | ||
204 | + if cell.X > lastCell.X && cell.Y >= lastCell.Y { | ||
205 | + cell.X += length - 1 | ||
206 | + } | ||
207 | + } | ||
208 | + // log.Logger.Info(fmt.Sprintf("%s %s X:%d Y:%d", cell.Data.Field.SQLName, cell.Direction, cell.X, cell.Y)) | ||
209 | + } | ||
210 | +} | ||
211 | + | ||
212 | +func (d *DataLayoutDataTable) BlockData(cells *domain.LayoutCell) ([]string, int) { | ||
213 | + var block []string | ||
214 | + if cells.Type == domain.CellTypeText { | ||
215 | + data := []string{cells.Data.Text} | ||
216 | + return data, 1 | ||
217 | + } | ||
218 | + table, ok := d.MapDataTables[cells.Data.TableField.TableId] | ||
219 | + if !ok { | ||
220 | + return block, 0 | ||
221 | + } | ||
222 | + values := table.Values(&domain.Field{SQLName: cells.Data.TableField.FieldSqlName}) | ||
223 | + if len(values) == 0 { | ||
224 | + return block, 0 | ||
225 | + } | ||
226 | + if cells.Data.TableField != nil && strings.HasPrefix(cells.Data.TableField.TableSqlName, strings.ToLower(domain.CalculateItem.ToString())) { | ||
227 | + return values[:1], 1 | ||
228 | + } | ||
229 | + if cells.Direction == domain.DirectionNone { | ||
230 | + return values[:1], 1 | ||
231 | + } | ||
232 | + return values, len(values) | ||
233 | +} | ||
234 | + | ||
235 | +func (d *DataLayoutDataTable) Shrink() { | ||
236 | + x := d.PointEnd.X - d.PointBegin.X | ||
237 | + y := d.PointEnd.Y - d.PointBegin.Y | ||
238 | + data := make([][]string, x+1) | ||
239 | + for i := range data { | ||
240 | + data[i] = make([]string, y+1) | ||
241 | + } | ||
242 | + iData := 0 | ||
243 | + for i := d.PointBegin.X; i <= d.PointEnd.X; i++ { | ||
244 | + jData := 0 | ||
245 | + for j := d.PointBegin.Y; j <= d.PointEnd.Y; j++ { | ||
246 | + data[iData][jData] = d.DataTable.Data[i][j] | ||
247 | + jData++ | ||
248 | + } | ||
249 | + iData++ | ||
250 | + } | ||
251 | + d.DataTable.Data = data | ||
252 | + for i := 0; i <= y; i++ { | ||
253 | + d.DataTable.Fields = append(d.DataTable.Fields, &domain.Field{ | ||
254 | + Name: fmt.Sprintf("列%d", i), | ||
255 | + SQLName: fmt.Sprintf("col%d", i), | ||
256 | + SQLType: domain.String.ToString(), | ||
257 | + }) | ||
258 | + } | ||
259 | +} | ||
260 | + | ||
261 | +func (d *DataLayoutDataTable) Expand(cell *domain.LayoutCell, length int) error { | ||
262 | + if !d.CellOutRange(cell, length) { | ||
263 | + return nil | ||
264 | + } | ||
265 | + expandLength := DefaultExpandNum | ||
266 | + if expandLength < length { | ||
267 | + expandLength = length | ||
268 | + } | ||
269 | + if d.MaxX+expandLength > MaxExpandNum { | ||
270 | + return fmt.Errorf("布局元素超过限制 %d", MaxExpandNum) | ||
271 | + } | ||
272 | + copyData := make([][]string, d.MaxX+length) | ||
273 | + for i := range copyData { | ||
274 | + copyData[i] = make([]string, d.MaxY+length) | ||
275 | + } | ||
276 | + copy(copyData, d.DataTable.Data) | ||
277 | + d.DataTable.Data = copyData | ||
278 | + return nil | ||
279 | +} | ||
280 | + | ||
281 | +func (d *DataLayoutDataTable) Init(length int) { | ||
282 | + initData := make([][]string, length) | ||
283 | + for i := range initData { | ||
284 | + initData[i] = make([]string, length) | ||
285 | + } | ||
286 | + d.DataTable.Data = initData | ||
287 | + d.AddRange(length) | ||
288 | +} | ||
289 | + | ||
290 | +func (d *DataLayoutDataTable) AddRange(length int) { | ||
291 | + d.MaxY += length | ||
292 | + d.MaxX += length | ||
293 | +} | ||
294 | + | ||
295 | +func (d *DataLayoutDataTable) CellOutRange(cell *domain.LayoutCell, length int) bool { | ||
296 | + if cell.X+length > d.MaxX { | ||
297 | + return true | ||
298 | + } | ||
299 | + if cell.Y+length > d.MaxY { | ||
300 | + return true | ||
301 | + } | ||
302 | + return false | ||
303 | +} |
@@ -14,6 +14,7 @@ type XLXSWriterTo struct { | @@ -14,6 +14,7 @@ type XLXSWriterTo struct { | ||
14 | data [][]string | 14 | data [][]string |
15 | title []string | 15 | title []string |
16 | ToInterfaces func([]string) []interface{} | 16 | ToInterfaces func([]string) []interface{} |
17 | + IgnoreTitle bool | ||
17 | } | 18 | } |
18 | 19 | ||
19 | func (wt *XLXSWriterTo) WriteTo(w io.Writer) (n int64, err error) { | 20 | func (wt *XLXSWriterTo) WriteTo(w io.Writer) (n int64, err error) { |
@@ -33,7 +34,7 @@ func (wt *XLXSWriterTo) Save(fileName string) error { | @@ -33,7 +34,7 @@ func (wt *XLXSWriterTo) Save(fileName string) error { | ||
33 | } | 34 | } |
34 | file, err = wt.newFile() | 35 | file, err = wt.newFile() |
35 | if err != nil { | 36 | if err != nil { |
36 | - return nil | 37 | + return err |
37 | } | 38 | } |
38 | return file.SaveAs(fileName) | 39 | return file.SaveAs(fileName) |
39 | } | 40 | } |
@@ -68,12 +69,18 @@ func (wt *XLXSWriterTo) newFile() (*excelize.File, error) { | @@ -68,12 +69,18 @@ func (wt *XLXSWriterTo) newFile() (*excelize.File, error) { | ||
68 | } | 69 | } |
69 | 70 | ||
70 | if len(wt.title) == 0 { | 71 | if len(wt.title) == 0 { |
71 | - return nil, fmt.Errorf("未设置数据表头") | ||
72 | - } | ||
73 | - if err := streamWriter.SetRow("A1", stringsToInterfaces(wt.title)); err != nil { | ||
74 | - return nil, err | 72 | + if !wt.IgnoreTitle { |
73 | + return nil, fmt.Errorf("未设置数据表头") | ||
74 | + } | ||
75 | + } else { | ||
76 | + if err := streamWriter.SetRow("A1", stringsToInterfaces(wt.title)); err != nil { | ||
77 | + return nil, err | ||
78 | + } | ||
75 | } | 79 | } |
76 | var rowID = 2 | 80 | var rowID = 2 |
81 | + if wt.IgnoreTitle { | ||
82 | + rowID = 1 | ||
83 | + } | ||
77 | for i := 0; i < len(wt.data); i++ { | 84 | for i := 0; i < len(wt.data); i++ { |
78 | row := stringsToInterfaces(wt.data[i]) | 85 | row := stringsToInterfaces(wt.data[i]) |
79 | if wt.ToInterfaces != nil { | 86 | if wt.ToInterfaces != nil { |
@@ -130,3 +130,19 @@ func (controller *QuerySetController) SearchQuerySet() { | @@ -130,3 +130,19 @@ func (controller *QuerySetController) SearchQuerySet() { | ||
130 | data, err := querySetService.SearchQuerySet(ParseContext(controller.BaseController), searchQuerySetQuery) | 130 | data, err := querySetService.SearchQuerySet(ParseContext(controller.BaseController), searchQuerySetQuery) |
131 | controller.Response(data, err) | 131 | controller.Response(data, err) |
132 | } | 132 | } |
133 | + | ||
134 | +func (controller *QuerySetController) CalculateSetPreview() { | ||
135 | + querySetService := service.NewQuerySetService(nil) | ||
136 | + updateQuerySetCommand := &command.UpdateQuerySetCommand{} | ||
137 | + Must(controller.Unmarshal(updateQuerySetCommand)) | ||
138 | + data, err := querySetService.CalculateSetPreview(ParseContext(controller.BaseController), updateQuerySetCommand) | ||
139 | + controller.Response(data, err) | ||
140 | +} | ||
141 | + | ||
142 | +func (controller *QuerySetController) CalculateSetExport() { | ||
143 | + querySetService := service.NewQuerySetService(nil) | ||
144 | + updateQuerySetCommand := &command.UpdateQuerySetCommand{} | ||
145 | + Must(controller.Unmarshal(updateQuerySetCommand)) | ||
146 | + data, err := querySetService.CalculateSetExport(ParseContext(controller.BaseController), updateQuerySetCommand) | ||
147 | + controller.Response(data, err) | ||
148 | +} |
@@ -31,6 +31,8 @@ func init() { | @@ -31,6 +31,8 @@ func init() { | ||
31 | web.Router("/data/query-sets/formula/rename", &controllers.QuerySetController{}, "Post:Rename") | 31 | web.Router("/data/query-sets/formula/rename", &controllers.QuerySetController{}, "Post:Rename") |
32 | web.Router("/data/query-sets/formula/search", &controllers.QuerySetController{}, "Post:SearchQuerySet") | 32 | web.Router("/data/query-sets/formula/search", &controllers.QuerySetController{}, "Post:SearchQuerySet") |
33 | web.Router("/data/query-sets/formula/calculate-table-preview-prepare", &controllers.QuerySetController{}, "Post:PreviewPrepare") | 33 | web.Router("/data/query-sets/formula/calculate-table-preview-prepare", &controllers.QuerySetController{}, "Post:PreviewPrepare") |
34 | + web.Router("/data/query-sets/formula/calculate-set-preview", &controllers.QuerySetController{}, "Post:CalculateSetPreview") | ||
35 | + web.Router("/data/query-sets/formula/calculate-set-export", &controllers.QuerySetController{}, "Post:CalculateSetExport") | ||
34 | 36 | ||
35 | web.Router("/data/query-sets/formula/calculate-item-preview", &controllers.QuerySetController{}, "Post:CalculateItemPreview") | 37 | web.Router("/data/query-sets/formula/calculate-item-preview", &controllers.QuerySetController{}, "Post:CalculateItemPreview") |
36 | web.Router("/data/query-sets/formula/calculate-item-export", &controllers.QuerySetController{}, "Post:CalculateItemExport") | 38 | web.Router("/data/query-sets/formula/calculate-item-export", &controllers.QuerySetController{}, "Post:CalculateItemExport") |
-
请 注册 或 登录 后发表评论