data_table.go 12.4 KB
package service

import (
	"bytes"
	"fmt"
	"github.com/beego/beego/v2/client/httplib"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel"
	"time"

	"github.com/linmadan/egglib-go/core/application"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/command"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/file/dto"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/redis"
)

// FilePreview 加载表格数据
func (fileService *FileService) FilePreview(ctx *domain.Context, loadDataTableCommand *command.LoadDataTableCommand) (interface{}, error) {
	if err := loadDataTableCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	loadDataTableService, _ := factory.CreateLoadDataTableService(transactionContext)
	data, err := loadDataTableService.Preview(ctx, loadDataTableCommand.FileId, loadDataTableCommand.Fields, loadDataTableCommand.Where)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}

	return data, nil
}

// PrepareTemporaryFile 准备临时文件
func (fileService *FileService) PrepareTemporaryFile(ctx *domain.Context, cmd *command.PrepareTemporaryFileCommand) (interface{}, error) {
	if err := cmd.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	loadDataTableService, _ := factory.CreateLoadDataTableService(transactionContext)
	data, err := loadDataTableService.CreateTemporaryFile(ctx, cmd.FileId)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}

	fileDto := &dto.FileDto{}
	fileDto.Load(data)
	return fileDto, nil
}

// EditDataTable 编辑表格数据
func (fileService *FileService) EditDataTable(ctx *domain.Context, editDataTableCommand *command.EditDataTableCommand) (interface{}, error) {
	if err := editDataTableCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	cache := redis.NewFileCacheService()
	temporaryFile, err := cache.Get(redis.KeyTemporaryFileInfo(editDataTableCommand.FileId))
	if err != nil {
		return nil, factory.FastError(err)
	}
	editDataTableCommand.Fields = temporaryFile.Fields
	editDataTableCommand.ProcessFields = temporaryFile.MatchFields(editDataTableCommand.ProcessFieldNames)
	if len(editDataTableCommand.ProcessFields) == 0 {
		return nil, factory.FastError(fmt.Errorf("请至少选择一个数据列"))
	}
	if editDataTableCommand.Action == "remove-column" && len(temporaryFile.Fields) == len(editDataTableCommand.ProcessFields) {
		return nil, factory.FastError(fmt.Errorf("请至少保留一个数据列"))
	}
	// allowAction := func(fields []*domain.Field, action string) error {
	// 	for _, f := range fields {
	// 		if f.SQLType != string(domain.String) &&
	// 			!(action == domain.RemoveColumn || action == domain.CopyColumn || action == domain.RenameColumn || action == domain.ConvertColumnType) {
	// 			return fmt.Errorf("列【%v】必须先转字符串类型",f.Name)
	// 		}
	// 	}
	// 	return nil
	// }
	// if err = allowAction(editDataTableCommand.ProcessFields, editDataTableCommand.Action); err != nil {
	// 	return nil, factory.FastError(err)
	// }
	editDataTableService, _ := factory.CreateEditDataTableService(transactionContext)
	response, err := editDataTableService.Edit(ctx, editDataTableCommand.EditTableRequest)
	if err != nil {
		return nil, factory.FastError(err)
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return (&dto.EditDataTableDto{}).Load(response), nil
}

// FlushDataTable 持久化表格数据
func (fileService *FileService) FlushDataTable(ctx *domain.Context, flushDataTableCommand *command.FlushDataTableCommand) (interface{}, error) {
	if err := flushDataTableCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	flushDataTableService, _ := factory.CreateFlushDataTableService(transactionContext)
	cache := redis.NewFileCacheService()
	temporaryFile, err := cache.Get(redis.KeyTemporaryFileInfo(flushDataTableCommand.ObjectId))
	if err != nil {
		return nil, factory.FastError(err)
	}

	if _, err := flushDataTableService.Flush(ctx, flushDataTableCommand.ObjectId, &domain.Table{
		DataFields: temporaryFile.Fields,
		RowCount:   temporaryFile.Total,
	}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return struct{}{}, nil
}

// GenerateMainTable 生成主表
func (fileService *FileService) GenerateMainTable(ctx *domain.Context, generateMainTableCommand *command.GenerateMainTableCommand) (interface{}, error) {
	if err := generateMainTableCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	generateMainTableService, _ := factory.CreateGenerateMainTableService(transactionContext)
	_, err = generateMainTableService.GenerateTable(ctx, generateMainTableCommand.FileId, generateMainTableCommand.TableName)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return struct{}{}, nil
}

// AppendDataToTable 追加数据
func (fileService *FileService) AppendDataToTable(ctx *domain.Context, cmd *command.AppendDataToTableCommand) (interface{}, error) {
	if err := cmd.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	if len(cmd.MappingFields) == 0 {
		return nil, factory.FastError(fmt.Errorf("请选择对应字段"))
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	generateMainTableService, _ := factory.CreateAppendDataToTableService(transactionContext)
	result, err := generateMainTableService.AppendData(ctx, cmd.FileId, cmd.TableId, cmd.MappingFields)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return result, nil
}

// AppendDataToTable 追加数据
func (fileService *FileService) AppendDataToTablePreflightCheck(ctx *domain.Context, cmd *command.AppendDataToTableCommand) (interface{}, error) {
	if err := cmd.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	generateMainTableService, _ := factory.CreateAppendDataToTableService(transactionContext)
	result, err := generateMainTableService.PreflightCheck(ctx, cmd.FileId, cmd.TableId, cmd.MappingFields)
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return result, nil
}

// ExportFile 文件下载
func (fileService *FileService) ExportFile(ctx *domain.Context, cmd *command.ExportFileCommand) (interface{}, error) {
	if err := cmd.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	_, file, err := factory.FastPgFile(transactionContext, cmd.FileId)
	if err != nil {
		return nil, factory.FastError(err)
	}

	var response = struct {
		Url      string `json:"url"`
		Ext      string `json:"ext"`
		FileName string `json:"fileName"`
	}{}
	if file.FileType == domain.SourceFile.ToString() {
		response.Url = file.FileInfo.Url
		response.Ext = domain.XLSX
		response.FileName = file.FileInfo.Name
		return response, nil
	}
	_, table, err := factory.FastPgTable(transactionContext, file.FileInfo.TableId)
	if err != nil {
		return nil, factory.FastError(err)
	}

	f, err := httplib.Get(file.FileInfo.Url).Bytes()
	if err != nil {
		return nil, factory.FastError(err)
	}
	reader := bytes.NewReader(f)
	var importer *excel.Importer = excel.NewExcelImportByFile(file.FileInfo.Ext)
	data, err := importer.OpenExcelFromIoReader(reader)
	if err != nil {
		return nil, factory.FastError(err)
	}
	filename := fmt.Sprintf("%v_%v.xlsx", file.FileInfo.Name, time.Now().Format("060102150405"))
	path := fmt.Sprintf("public/%v", filename)
	writerTo := excel.NewXLXSWriterTo(importer.Reader().Header().Columns, data)
	writerTo.ToInterfaces = domain.MakeToInterfaces(table.DataFields)
	if err := writerTo.Save(path); err != nil {
		return nil, factory.FastError(err)
	}

	response.Url = domain.DownloadUrl(filename)
	response.FileName = file.FileInfo.Name
	response.Ext = domain.XLSX

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return response, nil
}