sync: 同步 v1.0.4 并脱敏配置与镜像
This commit is contained in:
@@ -2,6 +2,8 @@ package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -11,6 +13,7 @@ import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/allocationunits"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/rabbitmq"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/hook"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
@@ -20,6 +23,7 @@ import (
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
@@ -94,6 +98,17 @@ func (s *sCommonBatchExecutionLog) ossModel(ctx context.Context, option ...*hand
|
||||
return handler.Model(dao.SysOss.Ctx(ctx), option...)
|
||||
}
|
||||
|
||||
// exportTaskModel 导出任务表;导出批次的结果文件只登记在这里。
|
||||
func (s *sCommonBatchExecutionLog) exportTaskModel(ctx context.Context, option ...*handler.Option) *gdb.Model {
|
||||
if len(option) == 0 {
|
||||
option = append(option, &handler.Option{
|
||||
FilterTenant: true,
|
||||
FilterAuth: false,
|
||||
})
|
||||
}
|
||||
return handler.Model(dao.TExportTask.Ctx(ctx), option...)
|
||||
}
|
||||
|
||||
func (s *sCommonBatchExecutionLog) List(ctx context.Context, in *model.BatchExecutionLogListParam) (list []*model.BatchExecutionLogListModel, totalCount int, err error) {
|
||||
mod := s.batchModel(ctx).
|
||||
Fields(model.BatchExecutionLogListModel{})
|
||||
@@ -142,6 +157,8 @@ func (s *sCommonBatchExecutionLog) List(ctx context.Context, in *model.BatchExec
|
||||
}
|
||||
fields := []*allocationunits.Fields{}
|
||||
for _, item := range list {
|
||||
item.UnknownCount = batchExecutionLogUnknownCount(item.UnitInfo)
|
||||
item.RestartPhase, item.RestartResumeAt = batchRestartPhase(item.UnitInfo)
|
||||
if item.BatchType == consts.BatchTypeAllocate {
|
||||
item.Fields = allocationunits.Resolve(item.UnitInfo, item.CreatedDept, item.StoredTargetDeptId)
|
||||
fields = append(fields, &item.Fields)
|
||||
@@ -187,9 +204,11 @@ func (s *sCommonBatchExecutionLog) Summary(ctx context.Context, in *model.BatchE
|
||||
RunResult: batch.RunResult,
|
||||
FailReason: batch.FailReason,
|
||||
TotalCount: batch.TotalCount,
|
||||
UnknownCount: batchExecutionLogUnknownCount(batch.BatchInfo),
|
||||
StartTime: batch.StartTime,
|
||||
EndTime: batch.EndTime,
|
||||
}
|
||||
res.RestartPhase, res.RestartResumeAt = batchRestartPhase(batch.BatchInfo)
|
||||
|
||||
if batch.BatchType == consts.BatchTypeAllocate {
|
||||
res.Fields = allocationunits.Resolve(batch.BatchInfo, batch.CreatedDept, batch.TargetDeptId)
|
||||
@@ -204,11 +223,17 @@ func (s *sCommonBatchExecutionLog) Summary(ctx context.Context, in *model.BatchE
|
||||
res.SourceFile = sourceFile
|
||||
}
|
||||
|
||||
if resultFile, err := s.getResultFile(ctx, batch.BatchNo, batch.ResultOssId, batch.BatchInfo); err != nil {
|
||||
return nil, err
|
||||
// 导出任务的成品文件落在 t_export_task,不写 t_resource_batch_download,须分开取。
|
||||
var resultFile *model.BatchExecutionLogResultFileModel
|
||||
if batch.BatchType == consts.BatchTypeExport {
|
||||
resultFile, err = s.getExportResultFile(ctx, batch.BatchNo, batch.ResultOssId)
|
||||
} else {
|
||||
res.ResultFile = resultFile
|
||||
resultFile, err = s.getResultFile(ctx, batch.BatchNo, batch.ResultOssId, batch.BatchInfo)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.ResultFile = resultFile
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -263,7 +288,7 @@ func (s *sCommonBatchExecutionLog) DetailList(ctx context.Context, in *model.Bat
|
||||
}
|
||||
|
||||
var details []*entity.BatchDetail
|
||||
mod = mod.Page(in.Page, in.PageSize).OrderAsc(columns.RowNo)
|
||||
mod = orderBatchCards(mod.Page(in.Page, in.PageSize), batch.BatchType)
|
||||
if err = mod.ScanAndCount(&details, &totalCount, false); err != nil {
|
||||
return nil, 0, gerror.Wrap(err, "获取批次执行明细列表失败,请稍后重试")
|
||||
}
|
||||
@@ -328,6 +353,65 @@ func (s *sCommonBatchExecutionLog) DetailList(ctx context.Context, in *model.Bat
|
||||
return
|
||||
}
|
||||
|
||||
// dataReviewQueryMessage 通知 Worker 对既有 operationId 做一次只读补查。
|
||||
type dataReviewQueryMessage struct {
|
||||
BatchNo string `json:"batchNo"`
|
||||
RequestedBy string `json:"requestedBy,omitempty"`
|
||||
}
|
||||
|
||||
var publishDataReviewQuery = rabbitmq.Publish
|
||||
|
||||
// SyncReview 手动同步待核查批次的上游执行结果。
|
||||
// 只重查既有受理号(jobId),不重发办理请求、不清零自动补查计数;
|
||||
// 上游仍无结论的明细继续保持待核查。
|
||||
func (s *sCommonBatchExecutionLog) SyncReview(ctx context.Context, in *model.BatchExecutionLogSyncReviewParam) (res *model.BatchExecutionLogSyncReviewModel, err error) {
|
||||
if in == nil {
|
||||
in = &model.BatchExecutionLogSyncReviewParam{}
|
||||
}
|
||||
batchNo := strings.TrimSpace(in.BatchNo)
|
||||
reason := strings.TrimSpace(in.Reason)
|
||||
if batchNo == "" {
|
||||
return nil, gerror.New("批次编号不能为空")
|
||||
}
|
||||
|
||||
columns := dao.BatchMain.Columns()
|
||||
batch := &entity.BatchMain{}
|
||||
// 沿用执行日志列表的可见性口径(部门权限过滤)。
|
||||
if err = s.batchModel(ctx).
|
||||
Fields(columns.Id, columns.BatchNo, columns.BatchType, columns.BatchAsyncStatus, columns.RunResult, columns.BatchInfo).
|
||||
Where(columns.BatchNo, batchNo).
|
||||
Scan(batch); err != nil {
|
||||
return nil, gerror.Wrap(err, "查询批次信息失败")
|
||||
}
|
||||
if batch.Id == 0 {
|
||||
return nil, gerror.New("批次不存在或无权限")
|
||||
}
|
||||
if batch.BatchAsyncStatus != consts.BatchAsyncStatusReview {
|
||||
return nil, gerror.New("仅待核查批次支持手动同步上游结果")
|
||||
}
|
||||
unknownCount := batchExecutionLogUnknownCount(batch.BatchInfo)
|
||||
if unknownCount <= 0 {
|
||||
return nil, gerror.New("该批次没有待核查明细")
|
||||
}
|
||||
|
||||
message := dataReviewQueryMessage{BatchNo: batch.BatchNo, RequestedBy: contexts.GetUserName(ctx)}
|
||||
if err = publishDataReviewQuery(ctx, consts.QueueDataReviewQuery, message); err != nil {
|
||||
g.Log().Errorf(ctx, "手动同步上游结果消息发布失败, batchNo=%s, tenantId=%s, userId=%d, reason=%s, err=%+v",
|
||||
batch.BatchNo, contexts.GetTenantId(ctx), contexts.GetUserId(ctx), reason, err)
|
||||
return nil, gerror.Wrap(err, "发布上游结果同步消息失败")
|
||||
}
|
||||
g.Log().Infof(ctx, "手动同步上游结果消息已发布, batchNo=%s, batchType=%d, unknownCount=%d, tenantId=%s, userId=%d, reason=%s",
|
||||
batch.BatchNo, batch.BatchType, unknownCount, contexts.GetTenantId(ctx), contexts.GetUserId(ctx), reason)
|
||||
|
||||
return &model.BatchExecutionLogSyncReviewModel{
|
||||
BatchNo: batch.BatchNo,
|
||||
BatchType: batch.BatchType,
|
||||
BatchAsyncStatus: batch.BatchAsyncStatus,
|
||||
UnknownCount: unknownCount,
|
||||
Queued: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *sCommonBatchExecutionLog) getDetailBatch(ctx context.Context, batchNo string, batchType *int) (*entity.BatchMain, error) {
|
||||
if batchNo == "" {
|
||||
return nil, gerror.New("批次号不能为空")
|
||||
@@ -471,11 +555,13 @@ func (s *sCommonBatchExecutionLog) getSourceFile(ctx context.Context, sourceOssI
|
||||
|
||||
func (s *sCommonBatchExecutionLog) getResultFile(ctx context.Context, batchNo string, resultOssId int64, batchInfo *gjson.Json) (*model.BatchExecutionLogResultFileModel, error) {
|
||||
download := &entity.TResourceBatchDownload{}
|
||||
// 出库/划拨/导出等批次不写 t_resource_batch_download,查不到记录按「无结果文件」处理,
|
||||
// 不能当异常抛给页面(否则详情弹窗整体报 sql: no rows in result set)。
|
||||
if err := s.downloadModel(ctx).
|
||||
Where(dao.TResourceBatchDownload.Columns().BatchNo, batchNo).
|
||||
OrderDesc(dao.TResourceBatchDownload.Columns().Id).
|
||||
Limit(1).
|
||||
Scan(download); err != nil {
|
||||
Scan(download); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, gerror.Wrap(err, "获取结果文件信息失败,请稍后重试!")
|
||||
}
|
||||
ossId := resultOssId
|
||||
@@ -490,14 +576,16 @@ func (s *sCommonBatchExecutionLog) getResultFile(ctx context.Context, batchNo st
|
||||
}
|
||||
|
||||
url := batchExecutionLogFileURL(ctx, download.FileUrl, download.FilePath)
|
||||
originalName := ""
|
||||
if ossId > 0 {
|
||||
oss := &entity.SysOss{}
|
||||
if err := s.ossModel(ctx).
|
||||
if scanErr := s.ossModel(ctx).
|
||||
Where(dao.SysOss.Columns().OssId, ossId).
|
||||
Scan(oss); err != nil {
|
||||
return nil, gerror.Wrap(err, "获取结果文件OSS信息失败,请稍后重试!")
|
||||
Scan(oss); scanErr != nil && !errors.Is(scanErr, sql.ErrNoRows) {
|
||||
return nil, gerror.Wrap(scanErr, "获取结果文件OSS信息失败,请稍后重试!")
|
||||
}
|
||||
if oss.OssId > 0 {
|
||||
originalName = oss.OriginalName
|
||||
if ossUrl := batchExecutionLogFileURL(ctx, oss.Url, oss.Path); ossUrl != "" {
|
||||
url = ossUrl
|
||||
}
|
||||
@@ -508,10 +596,49 @@ func (s *sCommonBatchExecutionLog) getResultFile(ctx context.Context, batchNo st
|
||||
DownloadId: download.Id,
|
||||
OssId: ossId,
|
||||
Url: url,
|
||||
OriginalName: originalName,
|
||||
DownloadStatus: resultDownloadStatus(download),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getExportResultFile 只暴露任务 ID;文件必须经下载中心重新校验本人、权限和有效期。
|
||||
func (s *sCommonBatchExecutionLog) getExportResultFile(ctx context.Context, taskNo string, _ int64) (*model.BatchExecutionLogResultFileModel, error) {
|
||||
task := &entity.TExportTask{}
|
||||
if err := s.exportTaskModel(ctx).
|
||||
Where(dao.TExportTask.Columns().TaskNo, taskNo).
|
||||
Where(dao.TExportTask.Columns().OwnerUserId, contexts.GetUserId(ctx)).
|
||||
Scan(task); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, gerror.Wrap(err, "获取结果文件信息失败,请稍后重试!")
|
||||
}
|
||||
if task.Id <= 0 || task.DeletedTime != nil || task.Status != consts.DownloadStatusGenerated || task.OssId <= 0 ||
|
||||
(task.ExpireTime != nil && task.ExpireTime.Before(gtime.Now())) || !hasExportPermission(ctx, task.PermCode) {
|
||||
return nil, nil
|
||||
}
|
||||
return &model.BatchExecutionLogResultFileModel{
|
||||
ExportTaskId: task.Id,
|
||||
OriginalName: task.FileName,
|
||||
DownloadStatus: consts.DownloadStatusGenerated,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func batchExecutionLogUnknownCount(batchInfo *gjson.Json) int {
|
||||
if batchInfo == nil {
|
||||
return 0
|
||||
}
|
||||
return batchInfo.Get("apnUnknownCount").Int()
|
||||
}
|
||||
|
||||
// batchRestartPhase 从 batch_info 取出重启阶段与计划复机时间。
|
||||
// 重启批次停机完成后要等待若干分钟再复机,这段时间主状态仍是处理中,
|
||||
// 明细却已落终态;前端据此显示「等待复机」,避免误以为卡住或已办结。
|
||||
func batchRestartPhase(batchInfo *gjson.Json) (phase, resumeAt string) {
|
||||
if batchInfo == nil {
|
||||
return "", ""
|
||||
}
|
||||
return strings.TrimSpace(batchInfo.Get("restart.phase").String()),
|
||||
strings.TrimSpace(batchInfo.Get("restart.resumeAt").String())
|
||||
}
|
||||
|
||||
func legacySourceOssId(batchInfo *gjson.Json) int64 {
|
||||
if batchInfo == nil {
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user