作者 yangfu

feat: calculate set

  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 {
@@ -42,7 +42,7 @@ func Must(err error) { @@ -42,7 +42,7 @@ func Must(err error) {
42 } 42 }
43 43
44 func ParseContext(c beego.BaseController) *domain.Context { 44 func ParseContext(c beego.BaseController) *domain.Context {
45 - var companyId int = 1 45 + var companyId int = 1598224576532189184
46 var userId int = 1 46 var userId int = 1
47 var userName string = "管理员" 47 var userName string = "管理员"
48 if token := c.Ctx.Input.GetData("UserToken"); token != nil { 48 if token := c.Ctx.Input.GetData("UserToken"); token != 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")