data_table.go 14.6 KB
package service

import (
	"bytes"
	"fmt"
	"github.com/beego/beego/v2/client/httplib"
	"github.com/linmadan/egglib-go/core/application"
	"github.com/linmadan/egglib-go/transaction/pg"
	"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/domainService"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/excel"
	"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
}

func (fileService *FileService) ResetHeaderRow(ctx *domain.Context, loadDataTableCommand *command.ResetTableHeaderCommand) (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()
	}()
	cache := redis.NewFileCacheService()
	temporaryFile, err := cache.Get(redis.KeyTemporaryFileInfo(loadDataTableCommand.FileId))
	if err != nil {
		return nil, factory.FastError(err)
	}
	loadDataTableService, _ := factory.CreateLoadDataTableService(transactionContext)
	data, err := loadDataTableService.RePreview(ctx, loadDataTableCommand.FileId, temporaryFile.Fields, loadDataTableCommand.Where)
	// 处理错误
	level := domain.LevelInfo
	errMsg := ""
	if err != nil {
		level = domain.LevelError
		errMsg = err.Error()
	}
	if logErr := domainService.FastLog(transactionContext.(*pg.TransactionContext),
		domain.VerifiedStepLog, temporaryFile.FileId, &domainService.ExcelTableResetHeaderLog{
			LogEntry: domain.NewLogEntry(temporaryFile.FileName, domain.VerifiedFile.ToString(), domain.FileVerify,
				ctx.WithValue(domain.ContextWithLogLevel, level).
					WithValue(domain.ContextWithLogMsg, errMsg)),
			HeaderRow: domain.GetHeaderRow(loadDataTableCommand.HeaderRow),
		}); logErr != nil {
		return nil, logErr
	}
	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("请至少保留一个数据列"))
	}
	if editDataTableCommand.Action == "rename-column" {
		targetColumn := editDataTableCommand.ProcessFieldNames[0]
		newColumnName := editDataTableCommand.Params["newColumnName"].(string)
		if len(temporaryFile.MatchFields([]string{newColumnName})) > 0 && newColumnName != targetColumn {
			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 = temporaryFile.Valid(); err != nil {
		return nil, factory.FastError(err)
	}

	if _, err := flushDataTableService.Flush(ctx, flushDataTableCommand.ObjectId, &domain.Table{
		DataFields: temporaryFile.Fields,
		RowCount:   temporaryFile.Total,
		HeaderRow:  temporaryFile.HeaderRow,
	}); 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
}

// AppendDataToTablePreflightCheck 追加数据预查
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 = FileUpload{}
	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(domain.ConvertFileUrlToInternal(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)
	}

	response, err = saveFile(file.FileInfo.Name, importer.Reader().Header().Columns, data, domain.MakeToInterfaces(table.DataFields))
	if err != nil {
		return nil, factory.FastError(err)
	}

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