|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using DS.Module.Core;
|
|
|
|
|
using DS.Module.Core.Data;
|
|
|
|
|
using DS.Module.Core.Helpers;
|
|
|
|
|
using DS.WMS.Core.Flow.Dtos;
|
|
|
|
|
using DS.WMS.Core.Flow.Entity;
|
|
|
|
|
using DS.WMS.Core.Flow.Interface;
|
|
|
|
|
using DS.WMS.Core.Flow.Method;
|
|
|
|
|
using DS.WMS.Core.Info.Interface;
|
|
|
|
|
using DS.WMS.Core.Op.Dtos.TaskInteraction;
|
|
|
|
|
using DS.WMS.Core.Op.Entity;
|
|
|
|
|
using DS.WMS.Core.Op.Entity.TaskInteraction;
|
|
|
|
|
using DS.WMS.Core.Op.Interface;
|
|
|
|
|
using DS.WMS.Core.Op.Interface.TaskInteraction;
|
|
|
|
|
using DS.WMS.Core.Sys.Entity;
|
|
|
|
|
using DS.WMS.Core.TaskPlat;
|
|
|
|
|
using DS.WMS.Core.TaskPlat.Dtos;
|
|
|
|
|
using DS.WMS.Core.TaskPlat.Entity;
|
|
|
|
|
using DS.WMS.Core.TaskPlat.Interface;
|
|
|
|
|
using Masuit.Tools;
|
|
|
|
|
using Masuit.Tools.Systems;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using SqlSugar;
|
|
|
|
|
using static DS.WMS.Core.Op.Method.TaskInteraction.ActionSelector.BookingSelector;
|
|
|
|
|
|
|
|
|
|
namespace DS.WMS.Core.Op.Method.TaskInteraction
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 任务交互服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract class TaskService : ServiceBase, ITaskService
|
|
|
|
|
{
|
|
|
|
|
const long PERMISSION_ID = 1815294400855674880;
|
|
|
|
|
static readonly TaskBaseTypeEnum[] AuditTaskTypes = [TaskBaseTypeEnum.WAIT_ORDER_AUDIT, TaskBaseTypeEnum.RETURN_CABIN];
|
|
|
|
|
static readonly Dictionary<TaskBaseTypeEnum, AuditType> TypeMappings = new()
|
|
|
|
|
{
|
|
|
|
|
{ TaskBaseTypeEnum.WAIT_ORDER_AUDIT, AuditType.SeaExport },
|
|
|
|
|
{ TaskBaseTypeEnum.RETURN_CABIN, AuditType.SeaExportReturn }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 任务管理服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected ITaskManageService ManagerService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 日志服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected ITaskLogService LogService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 任务分配
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected ITaskAllocationService TaskAllocationService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 工作流服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected IClientFlowInstanceService FlowService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 动作服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected IActionManagerService ActionService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 订单服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected ISeaExportService OpService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 客户端参数服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected IClientParamService ClientParamService { get; private set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="provider"></param>
|
|
|
|
|
public TaskService(IServiceProvider provider) : base(provider)
|
|
|
|
|
{
|
|
|
|
|
ManagerService = provider.GetRequiredService<ITaskManageService>();
|
|
|
|
|
LogService = provider.GetRequiredService<ITaskLogService>();
|
|
|
|
|
TaskAllocationService = provider.GetRequiredService<ITaskAllocationService>();
|
|
|
|
|
FlowService = provider.GetRequiredService<IClientFlowInstanceService>();
|
|
|
|
|
ActionService = provider.GetRequiredService<IActionManagerService>();
|
|
|
|
|
OpService = provider.GetRequiredService<ISeaExportService>();
|
|
|
|
|
ClientParamService = provider.GetRequiredService<IClientParamService>();
|
|
|
|
|
|
|
|
|
|
TenantDb.QueryFilter.Clear<IOrgId>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取给定任务的下一任务类型
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="current"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<TaskBaseTypeEnum?> GetNextTypeAsync(BusinessTask current)
|
|
|
|
|
{
|
|
|
|
|
var order = await ActionService.GetBusinessDataAsync(current.BusinessId, current.BusinessType);
|
|
|
|
|
TaskFlowRuner flowRuner = new(TenantDb, ServiceProvider);
|
|
|
|
|
var result = await flowRuner.GetWorkFlowNextConfig(TaskBaseTypeEnum.WORK_FLOW_MAIN, new TaskFlowDataContext(
|
|
|
|
|
(TaskFlowDataNameConst.Business, order)
|
|
|
|
|
), current.NextId);
|
|
|
|
|
|
|
|
|
|
if (result.HasValue)
|
|
|
|
|
{
|
|
|
|
|
current.NextId = result.Value.configId;
|
|
|
|
|
return result.Value.taskType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取业务的任务信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="types">任务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult<List<BusinessTaskDto>>> GetTasks(long id, BusinessType businessType, params TaskBaseTypeEnum[] types)
|
|
|
|
|
{
|
|
|
|
|
var list = await TenantDb.Queryable<BusinessTask>().Where(x => x.BusinessId == id && x.BusinessType == businessType)
|
|
|
|
|
.WhereIF(types != null && types.Length > 0, x => types.Contains(x.TaskType))
|
|
|
|
|
.Select<BusinessTaskDto>().ToListAsync();
|
|
|
|
|
|
|
|
|
|
var result = DataResult<List<BusinessTaskDto>>.Success(list);
|
|
|
|
|
result.Count = list.Count;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 返回指定类型的任务是否已存在
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="type">任务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult<bool>> ExistsAsync(long id, BusinessType businessType, TaskBaseTypeEnum type)
|
|
|
|
|
{
|
|
|
|
|
var value = await TenantDb.Queryable<BusinessTask>().AnyAsync(x =>
|
|
|
|
|
x.BusinessId == id && x.BusinessType == businessType && x.TaskType == type);
|
|
|
|
|
return DataResult<bool>.Success(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 确保任务交互模块已授权
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual async Task<bool> EnsureModuleAuthorized()
|
|
|
|
|
{
|
|
|
|
|
long tid = long.Parse(User.TenantId);
|
|
|
|
|
var authStr = await Db.Queryable<SysTenantPermissionAuth>().Where(x => x.PermissionId == PERMISSION_ID && x.TenantId == tid &&
|
|
|
|
|
SqlFunc.Subqueryable<SysPermissionTenant>().Where(spt => spt.PermissionId == x.PermissionId).Any())
|
|
|
|
|
.Select(x => x.AuthNum).FirstAsync();
|
|
|
|
|
if (authStr.IsNullOrEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var appSecret = await Db.Queryable<SysTenant>().Where(x => x.Id == tid).Select(x => x.AppSecret).FirstAsync();
|
|
|
|
|
return int.TryParse(EncrypteHelper.DecryptData(authStr, appSecret), out int authNum) && authNum > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 发起任务审核
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> SubmitAuditAsync(TaskRequest request)
|
|
|
|
|
{
|
|
|
|
|
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
|
|
|
|
|
if (task == null)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Complete)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Pending || task.TaskStatus == TaskStatusEnum.Create)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var req = new TaskUpdateRequest
|
|
|
|
|
{
|
|
|
|
|
AutoCreateNext = false,
|
|
|
|
|
BusinessId = request.BusinessId,
|
|
|
|
|
BusinessType = request.BusinessType,
|
|
|
|
|
TaskStatus = TaskStatusEnum.Create,
|
|
|
|
|
TaskTypeName = request.TaskTypeName
|
|
|
|
|
};
|
|
|
|
|
//重置任务为待处理
|
|
|
|
|
var result = await SetTaskStatusAsync(req, false);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return DataResult.Failed(result.Message, result.MultiCode);
|
|
|
|
|
|
|
|
|
|
//创建&启动工作流
|
|
|
|
|
var result2 = await CreateAndStartWorkflow(task, false);
|
|
|
|
|
if (!result2.Succeeded)
|
|
|
|
|
return result2;
|
|
|
|
|
|
|
|
|
|
await TenantDb.Updateable<BusinessTask>().SetColumns(x => x.TaskStatus == TaskStatusEnum.Create)
|
|
|
|
|
.Where(x => x.BusinessId == request.BusinessId && x.BusinessType == request.BusinessType && x.TaskType == request.TaskType)
|
|
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
//记录日志
|
|
|
|
|
await LogService.WriteLogAsync(req, "重新审批");
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
return result2;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskStatusNotSupported));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 撤销审核任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> WithdrawAsync(TaskRequest request)
|
|
|
|
|
{
|
|
|
|
|
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).Select(x => new
|
|
|
|
|
{
|
|
|
|
|
x.Id,
|
|
|
|
|
x.TaskStatus
|
|
|
|
|
}).FirstAsync();
|
|
|
|
|
if (task == null)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Complete)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
|
|
|
|
|
|
|
|
|
|
return await Delete(request.BusinessId, request.BusinessType, "用户撤销审核", request.TaskType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 任务审核
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> AuditAsync(TaskAuditRequest request)
|
|
|
|
|
{
|
|
|
|
|
long id = request.Ids[0];
|
|
|
|
|
var task = await GetQuery(id, request.BusinessType.GetValueOrDefault(), request.TaskType).FirstAsync();
|
|
|
|
|
if (task == null)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Complete)
|
|
|
|
|
{
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
|
|
|
|
|
}
|
|
|
|
|
else if (task.TaskStatus != TaskStatusEnum.Create && task.TaskStatus != TaskStatusEnum.Pending)
|
|
|
|
|
{
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskAuditStatusError));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (task.FlowId == null)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FlowNotFound));
|
|
|
|
|
|
|
|
|
|
var result = FlowService.AuditFlowInstance(new FlowAuditInfo
|
|
|
|
|
{
|
|
|
|
|
AuditNote = request.Remark,
|
|
|
|
|
Status = request.Result,
|
|
|
|
|
Instance = await Db.Queryable<FlowInstance>().FirstAsync(x => x.Id == task.FlowId.Value)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var flow = await Db.Queryable<FlowInstance>().Where(x => x.Id == task.FlowId.Value).Select(x => new FlowInstance
|
|
|
|
|
{
|
|
|
|
|
FlowStatus = x.FlowStatus,
|
|
|
|
|
MakerList = x.MakerList,
|
|
|
|
|
}).FirstAsync();
|
|
|
|
|
|
|
|
|
|
result.Data = new { flow.IsCompleted, flow.FlowStatus };
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建关联任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> CreateTaskAsync(TaskCreationRequest request, bool useTransaction = true)
|
|
|
|
|
{
|
|
|
|
|
if (!await EnsureModuleAuthorized())
|
|
|
|
|
return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
|
|
|
|
|
|
|
|
|
|
var task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
|
|
|
|
|
if (task != null && task.TaskStatus != TaskStatusEnum.Cancel)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskExists));
|
|
|
|
|
|
|
|
|
|
long tenatId = long.Parse(User.TenantId);
|
|
|
|
|
string tenatName = Db.Queryable<SysTenant>().Where(x => x.Id == tenatId).Select(x => x.Name).First();
|
|
|
|
|
var info = new TaskManageOrderMessageInfo
|
|
|
|
|
{
|
|
|
|
|
Head = new TaskManageOrderMessageHeadInfo
|
|
|
|
|
{
|
|
|
|
|
GID = Guid.NewGuid().ToString(),
|
|
|
|
|
BSNO = request.BusinessId,
|
|
|
|
|
MessageType = "WORK_FLOW_TASK",
|
|
|
|
|
SenderId = "WorkFlow",
|
|
|
|
|
SenderName = "工作流平台",
|
|
|
|
|
ReceiverId = "TaskManage",
|
|
|
|
|
ReceiverName = "任务管理平台",
|
|
|
|
|
Version = "1.0",
|
|
|
|
|
RequestDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
|
|
|
RequestAction = "Add"
|
|
|
|
|
},
|
|
|
|
|
Main = new TaskManageOrderMessageMainInfo
|
|
|
|
|
{
|
|
|
|
|
TaskType = request.TaskType,
|
|
|
|
|
TaskSource = TaskSourceEnum.WORK_FLOW,
|
|
|
|
|
TaskTitle = request.TaskTitle,
|
|
|
|
|
TaskDesp = request.TaskDescription,
|
|
|
|
|
TaskUserId = User.UserId,
|
|
|
|
|
TaskUserName = User.UserName,
|
|
|
|
|
TaskTenatId = tenatId,
|
|
|
|
|
TaskTenatName = tenatName,
|
|
|
|
|
IsCheckExistsByTaskType = true
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (request.RecvUserIdList == null || request.RecvUserIdList.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
//根据配置获取默认接收人
|
|
|
|
|
info.Main.RecvUserInfoList = await GetRecvUsersAsync(request.BusinessId, request.BusinessType, request.TaskType);
|
|
|
|
|
if (info.Main.RecvUserInfoList == null || info.Main.RecvUserInfoList.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
if (AuditTaskTypes.Contains(request.TaskType))
|
|
|
|
|
info.Main.RecvUserInfoList = await GetRecvUsersAsync(long.Parse(User.UserId));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info.Main.RecvUserInfoList = await GetRecvUsersAsync(request.RecvUserIdList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (info.Main.RecvUserInfoList == null || info.Main.RecvUserInfoList.Count == 0)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskReceiverNotFound));
|
|
|
|
|
|
|
|
|
|
if (info.Main.TaskTitle.IsNullOrEmpty())
|
|
|
|
|
{
|
|
|
|
|
var biz = await TenantDb.Queryable<SeaExport>().Select(x => new
|
|
|
|
|
{
|
|
|
|
|
x.Id,
|
|
|
|
|
x.CustomerNo,
|
|
|
|
|
x.MBLNO,
|
|
|
|
|
x.Vessel,
|
|
|
|
|
x.Voyno,
|
|
|
|
|
x.ETD,
|
|
|
|
|
}).FirstAsync(x => x.Id == request.BusinessId);
|
|
|
|
|
|
|
|
|
|
info.Main.TaskDesp = info.Main.TaskTitle = $"【{request.TaskType.GetDescription()}】{biz?.CustomerNo} {biz?.Vessel} {biz?.Voyno} ETD:{biz?.ETD?.ToString("yyyy-MM-dd")}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (useTransaction)
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
DataResult result = await ManagerService.InitTaskJob(info);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
task = new BusinessTask
|
|
|
|
|
{
|
|
|
|
|
BusinessId = request.BusinessId,
|
|
|
|
|
BusinessType = request.BusinessType,
|
|
|
|
|
TaskType = request.TaskType,
|
|
|
|
|
TaskStatus = TaskStatusEnum.Create,
|
|
|
|
|
RecvUsers = string.Join(',', info.Main.RecvUserInfoList.Select(x => x.RecvUserId)),
|
|
|
|
|
CreateBy = long.Parse(User.UserId),
|
|
|
|
|
CreateTime = DateTime.Now,
|
|
|
|
|
NextType = request.NextType,
|
|
|
|
|
NextId = request.NextId
|
|
|
|
|
};
|
|
|
|
|
if (!task.NextType.HasValue)
|
|
|
|
|
task.NextType = await GetNextTypeAsync(task);
|
|
|
|
|
|
|
|
|
|
await TenantDb.Insertable(task).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
//审核任务需创建工作流
|
|
|
|
|
if (AuditTaskTypes.Contains(request.TaskType))
|
|
|
|
|
{
|
|
|
|
|
result = await CreateAndStartWorkflow(task);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = await OnTaskCreated(task);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
//记录日志
|
|
|
|
|
await LogService.WriteLogAsync(task);
|
|
|
|
|
|
|
|
|
|
if (useTransaction)
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
if (useTransaction)
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 创建并启动审批工作流
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="task"></param>
|
|
|
|
|
/// <param name="changeMarker">同时变更任务执行人</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected internal async Task<DataResult> CreateAndStartWorkflow(BusinessTask task, bool changeMarker = true)
|
|
|
|
|
{
|
|
|
|
|
var auditType = TypeMappings[task.TaskType];
|
|
|
|
|
var template = await FindTemplateAsync(auditType);
|
|
|
|
|
if (template == null)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
|
|
|
|
|
|
var result = FlowService.CreateFlowInstance(new CreateFlowInstanceReq
|
|
|
|
|
{
|
|
|
|
|
BusinessId = task.BusinessId,
|
|
|
|
|
BusinessType = task.BusinessType,
|
|
|
|
|
TemplateId = template.Id
|
|
|
|
|
});
|
|
|
|
|
//创建并启动实例
|
|
|
|
|
if (result.Succeeded)
|
|
|
|
|
{
|
|
|
|
|
var instance = result.Data as FlowInstance;
|
|
|
|
|
task.FlowId = instance.Id;
|
|
|
|
|
await TenantDb.Updateable(task).UpdateColumns(x => x.FlowId).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
result = FlowService.StartFlowInstance(instance.Id.ToString());
|
|
|
|
|
instance = result.Data as FlowInstance;
|
|
|
|
|
|
|
|
|
|
if (result.Succeeded && changeMarker)
|
|
|
|
|
{
|
|
|
|
|
string[] ids = FlowInstanceService.GetMarkers(instance);
|
|
|
|
|
//变更任务接收人为所有审批执行人
|
|
|
|
|
var users = await GetRecvUsersAsync(ids.Select(long.Parse).ToArray());
|
|
|
|
|
result = await ManagerService.TransferTask(task.BusinessId, task.TaskType, users);
|
|
|
|
|
if (result.Succeeded)
|
|
|
|
|
{
|
|
|
|
|
task.RecvUsers = string.Join(",", ids);
|
|
|
|
|
await TenantDb.Updateable(task).UpdateColumns(x => x.RecvUsers).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当任务创建时调用
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="task"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual Task<DataResult> OnTaskCreated(BusinessTask task)
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(DataResult.Success);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置任务状态
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <param name="useTransaction">是否使用事务</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult<TaskBaseTypeEnum?>> SetTaskStatusAsync(TaskUpdateRequest request, bool useTransaction = true)
|
|
|
|
|
{
|
|
|
|
|
if (!await EnsureModuleAuthorized())
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.SuccessMsg(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.ModuleUnauthorized)), MultiLanguageConst.ModuleUnauthorized);
|
|
|
|
|
|
|
|
|
|
if (useTransaction)
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
BusinessTask task = await GetQuery(request.BusinessId, request.BusinessType, request.TaskType).FirstAsync();
|
|
|
|
|
if (task == null)
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Complete)
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.FailedWithDesc(nameof(MultiLanguageConst.TaskCompleted));
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Cancel)
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.FailedWithDesc(nameof(MultiLanguageConst.TaskCancelled));
|
|
|
|
|
|
|
|
|
|
var result = await ManagerService.SetTaskStatus(request.BusinessId, request.TaskType, request.TaskStatus, DateTime.Now);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.Failed(result.Message, result.MultiCode);
|
|
|
|
|
|
|
|
|
|
//触发任务状态变更通知
|
|
|
|
|
if (task.TaskStatus != request.TaskStatus)
|
|
|
|
|
await OnTaskStatusChanged(request);
|
|
|
|
|
|
|
|
|
|
task.RejectReason = request.RejectReason;
|
|
|
|
|
//更新当前任务状态
|
|
|
|
|
task.TaskStatus = request.TaskStatus;
|
|
|
|
|
if (AuditTaskTypes.Contains(task.TaskType))
|
|
|
|
|
task.FlowId = null;
|
|
|
|
|
|
|
|
|
|
await TenantDb.Updateable(task).UpdateColumns(x => new { x.TaskStatus, x.FlowId, x.RejectReason }).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Complete)
|
|
|
|
|
{
|
|
|
|
|
//若存在下一任务,则继续创建
|
|
|
|
|
if (task.NextType.HasValue && request.AutoCreateNext)
|
|
|
|
|
{
|
|
|
|
|
var req = new TaskCreationRequest
|
|
|
|
|
{
|
|
|
|
|
BusinessId = request.BusinessId,
|
|
|
|
|
BusinessType = request.BusinessType,
|
|
|
|
|
TaskTypeName = task.NextType.ToString(),
|
|
|
|
|
RecvUserIdList = task.RecvUserIdArray,
|
|
|
|
|
NextId = task.NextId
|
|
|
|
|
};
|
|
|
|
|
result = await CreateTaskAsync(req, false);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.Failed("创建下一关联任务时返回错误:" + result.Message, result.MultiCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//记录日志
|
|
|
|
|
await LogService.WriteLogAsync(request);
|
|
|
|
|
|
|
|
|
|
if (useTransaction)
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus == TaskStatusEnum.Complete)//目前限制任务完成才触发
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, object>? dic = null;
|
|
|
|
|
if (request.TaskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT)
|
|
|
|
|
{
|
|
|
|
|
dic = new Dictionary<string, object>();
|
|
|
|
|
var param = await ClientParamService.GetParamAsync<string>(task.BusinessId, Booking_Route,
|
|
|
|
|
(x, y) => x.CustomerId == y.ForwarderId);
|
|
|
|
|
dic[TaskFlowDataNameConst.ClientParam] = param;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ActionService.TriggerActionAsync(task, additionalData: dic);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.Success(task.TaskStatus == TaskStatusEnum.Complete ? await GetNextTypeAsync(task) : null);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
if (useTransaction)
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult<TaskBaseTypeEnum?>.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 当任务状态发生变化时调用
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual Task OnTaskStatusChanged(TaskUpdateRequest request)
|
|
|
|
|
{
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 通知审批执行人变更
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="callback">回调信息</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="callback"/>为null时引发</exception>
|
|
|
|
|
public virtual async Task MarkerChangedAsync(MarkerChangedCallback callback)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
|
|
|
|
|
|
|
|
|
|
long userId = long.Parse(User.UserId);
|
|
|
|
|
var users = await GetRecvUsersAsync(userId);
|
|
|
|
|
var dt = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
var taskType = TypeMappings.Where(x => x.Value == callback.Type.GetValueOrDefault()).Select(x => x.Key).FirstOrDefault();
|
|
|
|
|
await ManagerService.SetTaskUserStatus(
|
|
|
|
|
callback.BusinessId,
|
|
|
|
|
taskType,
|
|
|
|
|
TaskStatusEnum.Complete,
|
|
|
|
|
//callback.Status == FlowStatusEnum.Approve ? TaskStatusEnum.Complete : TaskStatusEnum.Pending
|
|
|
|
|
dt,
|
|
|
|
|
users);
|
|
|
|
|
|
|
|
|
|
//记录日志
|
|
|
|
|
await LogService.WriteLogAsync(new BusinessTaskLog
|
|
|
|
|
{
|
|
|
|
|
ActionType = ActionType.Audit,
|
|
|
|
|
AuditStatus = callback.Status,
|
|
|
|
|
BusinessId = callback.BusinessId,
|
|
|
|
|
BusinessType = callback.BusinessType.Value,
|
|
|
|
|
CreateBy = userId,
|
|
|
|
|
CreateTime = dt,
|
|
|
|
|
TaskStatus = TaskStatusEnum.Complete,
|
|
|
|
|
TaskType = taskType,
|
|
|
|
|
RecvUsers = users.Count > 0 ? users[0].RecvUserName : null
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 审批完成回调更新
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="callback">回调信息</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
/// <exception cref="ArgumentNullException"><paramref name="callback"/>为null时引发</exception>
|
|
|
|
|
public virtual async Task UpdateBusinessAsync(FlowCallback callback)
|
|
|
|
|
{
|
|
|
|
|
ArgumentNullException.ThrowIfNull(callback, nameof(callback));
|
|
|
|
|
|
|
|
|
|
var taskType = TypeMappings.Where(x => x.Value == callback.Type.GetValueOrDefault()).Select(x => x.Key).FirstOrDefault();
|
|
|
|
|
var req = new TaskUpdateRequest
|
|
|
|
|
{
|
|
|
|
|
BusinessId = callback.BusinessId,
|
|
|
|
|
BusinessType = callback.BusinessType.Value,
|
|
|
|
|
TaskTypeName = taskType.ToString(),
|
|
|
|
|
TaskStatus = callback.FlowStatus == FlowStatusEnum.Approve ? TaskStatusEnum.Complete : TaskStatusEnum.Pending,
|
|
|
|
|
AutoCreateNext = false //审批完成后需根据业务需要自定义任务类型,因此设置为不自动创建下一任务
|
|
|
|
|
};
|
|
|
|
|
//根据审批结果更新任务状态
|
|
|
|
|
await SetTaskStatusAsync(req);
|
|
|
|
|
|
|
|
|
|
long userId = long.Parse(User.UserId);
|
|
|
|
|
var users = await GetRecvUsersAsync(userId);
|
|
|
|
|
string remark = "终审完成,审批结果为:" + callback.FlowStatus.GetDescription();
|
|
|
|
|
|
|
|
|
|
if (callback.FlowStatus == FlowStatusEnum.Reject)
|
|
|
|
|
{
|
|
|
|
|
var task = await GetQuery(callback.BusinessId, callback.BusinessType.Value, taskType).FirstAsync();
|
|
|
|
|
//创建驳回任务以进行通知
|
|
|
|
|
await CreateTaskAsync(new TaskCreationRequest
|
|
|
|
|
{
|
|
|
|
|
BusinessId = callback.BusinessId,
|
|
|
|
|
BusinessType = callback.BusinessType.GetValueOrDefault(),
|
|
|
|
|
TaskTypeName = (taskType == TaskBaseTypeEnum.WAIT_ORDER_AUDIT ?
|
|
|
|
|
TaskBaseTypeEnum.ORDER_AUDIT_REJECTED : TaskBaseTypeEnum.RETURN_CABIN_REJECTED).ToString(),
|
|
|
|
|
RecvUserIdList = [task.CreateBy] //通知任务发起人
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
remark += ";驳回理由:" + callback.RejectReason;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//记录日志
|
|
|
|
|
await LogService.WriteLogAsync(new BusinessTaskLog
|
|
|
|
|
{
|
|
|
|
|
ActionType = ActionType.Audit,
|
|
|
|
|
AuditStatus = callback.FlowStatus,
|
|
|
|
|
BusinessId = callback.BusinessId,
|
|
|
|
|
BusinessType = callback.BusinessType.Value,
|
|
|
|
|
CreateBy = userId,
|
|
|
|
|
CreateTime = DateTime.Now,
|
|
|
|
|
TaskStatus = req.TaskStatus,
|
|
|
|
|
TaskType = req.TaskType,
|
|
|
|
|
RecvUsers = users.Count > 0 ? users[0].RecvUserName : null,
|
|
|
|
|
Remark = remark
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取指定类型的业务关联任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="taskTypes">任务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected internal ISugarQueryable<BusinessTask> GetQuery(long id, BusinessType businessType, params TaskBaseTypeEnum[] taskTypes)
|
|
|
|
|
{
|
|
|
|
|
return TenantDb.Queryable<BusinessTask>().Where(x => x.BusinessId == id && x.BusinessType == businessType)
|
|
|
|
|
.WhereIF(taskTypes != null && taskTypes.Length > 0, x => taskTypes.Contains(x.TaskType));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从任务配置中获取接收用户列表
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="taskType">任务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected internal async Task<List<RecvUserInfo>> GetRecvUsersAsync(long id, BusinessType businessType, TaskBaseTypeEnum taskType)
|
|
|
|
|
{
|
|
|
|
|
var dic = await GetRecvUsersAsync(id, businessType, [taskType]);
|
|
|
|
|
return dic?.Count > 0 ? dic.FirstOrDefault().Value : [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 从任务配置中获取接收用户列表
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="taskTypes">任务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected internal async Task<Dictionary<TaskBaseTypeEnum, List<RecvUserInfo>>> GetRecvUsersAsync(long id, BusinessType businessType, List<TaskBaseTypeEnum> taskTypes)
|
|
|
|
|
{
|
|
|
|
|
var biz = await ActionService.GetBusinessDataAsync(id, businessType);
|
|
|
|
|
var result = await TaskAllocationService.GetAllotUserBySeaExportId(taskTypes, id, new TaskFlowDataContext(
|
|
|
|
|
(TaskFlowDataNameConst.Business, biz)
|
|
|
|
|
));
|
|
|
|
|
return result.Succeeded ? result.Data : [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取任务接收用户列表
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ids">用户ID</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected internal async Task<List<RecvUserInfo>> GetRecvUsersAsync(params long[] ids)
|
|
|
|
|
{
|
|
|
|
|
return await Db.Queryable<SysUser>().Where(x => ids.Contains(x.Id)).Select(
|
|
|
|
|
x => new RecvUserInfo { RecvUserId = x.Id, RecvUserName = x.UserName }).ToListAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 删除任务
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">业务ID</param>
|
|
|
|
|
/// <param name="businessType">业务类型</param>
|
|
|
|
|
/// <param name="remark">备注</param>
|
|
|
|
|
/// <param name="taskTypes">任务类型,不指定任务类型则删除全部任务</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> Delete(long id, BusinessType businessType, string? remark = null, params TaskBaseTypeEnum[] taskTypes)
|
|
|
|
|
{
|
|
|
|
|
if (!await EnsureModuleAuthorized())
|
|
|
|
|
return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.ModuleUnauthorized));
|
|
|
|
|
|
|
|
|
|
string[]? typeNames = taskTypes?.Select(x => x.ToString()).ToArray();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
List<AuditType> auditTypes = [];
|
|
|
|
|
if (taskTypes != null && taskTypes.Contains(TaskBaseTypeEnum.WAIT_ORDER_AUDIT))
|
|
|
|
|
auditTypes.Add(AuditType.SeaExport);
|
|
|
|
|
if (taskTypes != null && taskTypes.Contains(TaskBaseTypeEnum.RETURN_CABIN))
|
|
|
|
|
auditTypes.Add(AuditType.SeaExportReturn);
|
|
|
|
|
|
|
|
|
|
if (auditTypes.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
//long userId = long.Parse(User.UserId);
|
|
|
|
|
//await Db.Updateable(new FlowInstance
|
|
|
|
|
//{
|
|
|
|
|
// Id = task.FlowId.Value,
|
|
|
|
|
// DeleteBy = long.Parse(User.UserId),
|
|
|
|
|
// DeleteTime = DateTime.Now,
|
|
|
|
|
// Deleted = true
|
|
|
|
|
//}).UpdateColumns(x => new { x.DeleteBy, x.DeleteTime, x.Deleted }).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await Db.Deleteable<FlowInstance>().Where(x => x.BusinessId == id && x.BusinessType == businessType && auditTypes.Contains(x.Type.Value))
|
|
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await TenantDb.Deleteable<TaskBaseAllocation>().Where(x => SqlFunc.Subqueryable<TaskBaseInfo>().Where(
|
|
|
|
|
y => x.TaskId == y.Id && y.TASK_SOURCE == "WORK_FLOW" && y.OUT_BS_NO == id)
|
|
|
|
|
.WhereIF(typeNames != null && typeNames.Length > 0, x => typeNames.Contains(x.TASK_TYPE))
|
|
|
|
|
.Any()).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Deleteable<TaskBaseInfo>().Where(x => x.TASK_SOURCE == "WORK_FLOW" && x.OUT_BS_NO == id)
|
|
|
|
|
.WhereIF(typeNames != null && typeNames.Length > 0, x => typeNames.Contains(x.TASK_TYPE))
|
|
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Deleteable<BusinessTask>().Where(x => x.BusinessId == id && x.BusinessType == businessType)
|
|
|
|
|
.WhereIF(typeNames != null && typeNames.Length > 0, x => taskTypes.Contains(x.TaskType))
|
|
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(remark))
|
|
|
|
|
remark = "删除任务" + (typeNames != null && typeNames.Length > 0 ? $"【{string.Join(",", typeNames)}】" : string.Empty);
|
|
|
|
|
|
|
|
|
|
await LogService.WriteLogAsync(new BusinessTaskLog
|
|
|
|
|
{
|
|
|
|
|
BusinessId = id,
|
|
|
|
|
BusinessType = businessType,
|
|
|
|
|
ActionType = ActionType.Delete,
|
|
|
|
|
CreateBy = long.Parse(User.UserId),
|
|
|
|
|
CreateTime = DateTime.Now,
|
|
|
|
|
TaskType = TaskBaseTypeEnum.NOT_SPECIFIED,
|
|
|
|
|
Remark = remark
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|