You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
BookingHeChuan/Myshipping.Application/Service/TaskManagePlat/TaskManageShareLinkService.cs

598 lines
26 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Furion;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Myshipping.Application.ConfigOption;
using Myshipping.Application.Entity;
using Myshipping.Core;
using Myshipping.Core.Service;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Myshipping.Application.Service.TaskManagePlat
{
/// <summary>
/// 任务分享链接服务
/// </summary>
[ApiDescriptionSettings("Application", Name = "TaskManageShareLink", Order = 10)]
public class TaskManageShareLinkService : ITaskManageShareLinkService, IDynamicApiController, ITransient
{
private readonly ISysCacheService _cache;
private readonly ILogger<TaskManageShareLinkService> _logger;
private readonly SqlSugarRepository<TaskShareLinkInfo> _taskShareLinkInfoRepository;
private readonly SqlSugarRepository<TaskShareLinkDynamicDataInfo> _taskShareLinkDynamicDataInfoRepository;
private readonly SqlSugarRepository<TaskBaseInfo> _taskBaseRepository;
private readonly SqlSugarRepository<TaskRollingNominationInfo> _taskRollingNominationInfoRepository;
private readonly SqlSugarRepository<TaskRollingNominationDispatchInfo> _taskRollingNominationDispatchInfoRepository;
private readonly SqlSugarRepository<TaskRollingNominationShipInfo> _taskRollingNominationShipInfoRepository;
private readonly SqlSugarRepository<TaskRollingNominationDetailInfo> _taskRollingNominationDetailInfoRepository;
private const string SHARE_LINK_CACHE_KEY_TEMPLATE = "ShareLinkKeyIncrement";
public TaskManageShareLinkService(ISysCacheService cache, ILogger<TaskManageShareLinkService> logger,
SqlSugarRepository<TaskShareLinkInfo> taskShareLinkInfoRepository,
SqlSugarRepository<TaskShareLinkDynamicDataInfo> taskShareLinkDynamicDataInfoRepository,
SqlSugarRepository<TaskBaseInfo> taskBaseRepository,
SqlSugarRepository<TaskRollingNominationInfo> taskRollingNominationInfoRepository,
SqlSugarRepository<TaskRollingNominationDispatchInfo> taskRollingNominationDispatchInfoRepository,
SqlSugarRepository<TaskRollingNominationShipInfo> taskRollingNominationShipInfoRepository,
SqlSugarRepository<TaskRollingNominationDetailInfo> taskRollingNominationDetailInfoRepository)
{
_cache = cache;
_logger = logger;
_taskShareLinkInfoRepository = taskShareLinkInfoRepository;
_taskShareLinkDynamicDataInfoRepository = taskShareLinkDynamicDataInfoRepository;
_taskBaseRepository = taskBaseRepository;
_taskRollingNominationInfoRepository = taskRollingNominationInfoRepository;
_taskRollingNominationDispatchInfoRepository = taskRollingNominationDispatchInfoRepository;
_taskRollingNominationShipInfoRepository = taskRollingNominationShipInfoRepository;
_taskRollingNominationDetailInfoRepository = taskRollingNominationDetailInfoRepository;
}
#region 生成访问链接
/// <summary>
/// 生成访问链接
/// </summary>
/// <param name="model">创建分享链接请求</param>
/// <returns>返回回执</returns>
[HttpPost("/TaskManageShareLink/CreateShareLink")]
public async Task<TaskManageOrderResultDto> CreateShareLink([FromBody] ShareLinkRequestDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
/*
1、判断当前businessId是否有STATUS=ACTIVE的记录如果有记录不允许重复分享。
2、创建分享记录并生成动态数据预甩需要生成免责声明
3、判断有效期是否小于等于当前日期如果是不能生成分享。
4、创建完记录后把生成后的SHARE_LINK_KEY写入redis并用expireDate作为失效日期。
5、返回SHARE_LINK_KEY。
*/
try
{
string shareKey = string.Empty;
if (string.IsNullOrWhiteSpace(model.businessId))
throw Oops.Oh($"业务ID不能为空");
if (string.IsNullOrWhiteSpace(model.taskType))
throw Oops.Oh($"任务类型不能为空");
if (string.IsNullOrWhiteSpace(model.businessType))
throw Oops.Oh($"业务类型不能为空");
if (string.IsNullOrWhiteSpace(model.expireDate))
throw Oops.Oh($"失效时间不能为空");
DateTime expireDateTime = DateTime.MinValue;
DateTime nowDate = DateTime.Now;
if(!DateTime.TryParse(model.expireDate, out expireDateTime))
throw Oops.Oh($"失效时间格式错误请参考格式yyyy-MM-dd HH:mm:ss");
if(expireDateTime <= DateTime.Now)
throw Oops.Oh($"失效时间不能早于或等于当前时间");
if (!model.businessType.Equals("NOMI_DISPATCH", StringComparison.OrdinalIgnoreCase))
{
throw Oops.Oh($"当前只支持预甩调度分享");
}
var nomDispatchList = _taskRollingNominationDispatchInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin<TaskRollingNominationDetailInfo>((dispatch,detail) => dispatch.DETAIL_ID == detail.PK_ID)
.Where((dispatch,detail) => dispatch.BATCH_ID == model.businessId
&& detail.IsDeleted == false && dispatch.IsDeleted == false)
.Select((dispatch, detail) => new { Detail = detail, Dispatch = dispatch }).ToList();
if (nomDispatchList.Count == 0)
throw Oops.Oh($"预甩调度获取详情失败,已删除或不存在");
if (nomDispatchList.Any(a => !string.IsNullOrWhiteSpace(a.Dispatch.USER_OPINION)))
throw Oops.Oh($"当前预甩调度已有用户反馈,不能创建分享");
var shareInfo = _taskShareLinkInfoRepository.AsQueryable()
.First(a => a.BUSI_ID == model.businessId && a.TASK_TYPE == model.taskType
&& a.STATUS == TaskShareLinkStatusEnum.ACTIVE.ToString() && a.IsDeleted == false);
if (!model.isRenew)
{
if (shareInfo != null)
{
throw Oops.Oh($"已有分享记录不能重复生成");
}
}
else
{
shareInfo.IsDeleted = true;
shareInfo.UpdatedTime = nowDate;
shareInfo.UpdatedUserId = UserManager.UserId;
shareInfo.UpdatedUserName = UserManager.Name;
await _taskShareLinkInfoRepository.AsUpdateable(shareInfo)
.UpdateColumns(it => new
{
it.IsDeleted,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommandAsync();
}
TaskShareLinkInfo taskShareLinkInfo = new TaskShareLinkInfo {
EXPIRE_DATE = expireDateTime,
STATUS = TaskShareLinkStatusEnum.ACTIVE.ToString(),
BUSI_ID = model.businessId,
IS_MANUAL = false,
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name,
TASK_TYPE = model.taskType,
IS_USER_FEEDBACK = model.isUserFeedBack,
};
//写入分享记录
await _taskShareLinkInfoRepository.InsertAsync(taskShareLinkInfo);
_logger.LogInformation($"写入分享记录表完成id={taskShareLinkInfo.Id}");
var autoIncrementKey = RedisHelper.IncrBy(SHARE_LINK_CACHE_KEY_TEMPLATE);
//生成分享KEY
SuperShortLinkHelper codeHelper = new SuperShortLinkHelper();
shareKey = codeHelper.Confuse(autoIncrementKey);
_logger.LogInformation($"生成分享KEY完成id={taskShareLinkInfo.Id} shareKey={shareKey}");
//更新分享表
var shareEntity = _taskShareLinkInfoRepository.AsQueryable().First(a => a.Id == taskShareLinkInfo.Id);
string taskId = nomDispatchList.FirstOrDefault().Dispatch.TASK_ID;
var taskInfo = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == taskId);
//写入redis缓存
string cacheVal = $"{taskShareLinkInfo.Id}_{taskInfo.TASK_TYPE}_{taskInfo.TASK_NO}_{nomDispatchList.FirstOrDefault().Detail.SHIPMENT}_{taskInfo.TenantName}_{model.expireDate}";
var expireTimeSpan = expireDateTime.Subtract(nowDate).Duration();
//new DateTimeOffset(expireDateTime).ToUnixTimeSeconds();
if (_cache.Exists(shareKey))
{
shareEntity.SHARE_LINK_KEY = shareKey;
shareEntity.STATUS = "REPEAT_KEY";//REPEAT_KEY-重复KEY被取消
shareEntity.INCREMENT_KEY = autoIncrementKey;
await _taskShareLinkInfoRepository.AsUpdateable(shareEntity)
.UpdateColumns(it => new
{
it.SHARE_LINK_KEY,
it.STATUS,
it.INCREMENT_KEY
}).ExecuteCommandAsync();
_logger.LogInformation($"分享KEY存在重复终止生成分享(cache)id={taskShareLinkInfo.Id} shareKey={shareKey} cache={_cache.Get<string>(shareKey)}");
throw Oops.Oh($"已有分享记录不能重复生成");
}
else
{
shareEntity.SHARE_LINK_KEY = shareKey;
shareEntity.INCREMENT_KEY = autoIncrementKey;
await _taskShareLinkInfoRepository.AsUpdateable(shareEntity)
.UpdateColumns(it => new
{
it.SHARE_LINK_KEY,
it.INCREMENT_KEY
}).ExecuteCommandAsync();
await _cache.SetTimeoutAsync(shareKey, cacheVal, expireTimeSpan);
_logger.LogInformation($"分享KEY写入cache完成id={taskShareLinkInfo.Id} shareKey={shareKey} cache={cacheVal}");
//这里生成动态数据
if (taskInfo.TASK_BASE_TYPE == TaskBaseTypeEnum.ROLLING_NOMINATION.ToString() ||
taskInfo.TASK_BASE_TYPE == TaskBaseTypeEnum.TRANSFER_NOMINATION.ToString())
{
var shareTxt = GenerateShareDynamicData(expireDateTime, taskInfo.TenantName);
TaskShareLinkDynamicDataInfo dataInfo = new TaskShareLinkDynamicDataInfo {
SHARE_ID = shareEntity.Id,
DATA_TYPE = "DISCLAIMERS",
DATA_MSG = shareTxt,
DATA_MSG_TYPE = "HTML",
CreatedTime = nowDate,
UpdatedTime = nowDate,
CreatedUserId = UserManager.UserId,
CreatedUserName = UserManager.Name,
};
await _taskShareLinkDynamicDataInfoRepository.InsertAsync(dataInfo);
}
}
result.succ = true;
result.ext = shareKey;
}
catch (Exception ex)
{
_logger.LogError($"获取预甩详情异常,原因:{ex.Message}");
result.succ = false;
result.msg = $"获取预甩详情异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 取消访问链接
/// <summary>
/// 取消访问链接
/// </summary>
/// <param name="busiId">访问链接业务主键</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskManageShareLink/CancelShareLink")]
public async Task<TaskManageOrderResultDto> CancelShareLink(string busiId)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
try
{
var shareInfo = _taskShareLinkInfoRepository.AsQueryable()
.First(a => a.BUSI_ID == busiId && a.IsDeleted == false);
if(shareInfo == null)
throw Oops.Oh($"分享链接不存在或已删除");
var statusArg = new string[] {
RollingNominationDispatchStatusEnum.COMPLETE.ToString(),
RollingNominationDispatchStatusEnum.EXPIRE.ToString(),
RollingNominationDispatchStatusEnum.CANCEL.ToString()
};
if(statusArg.Any(a=>a.Equals(shareInfo.STATUS,StringComparison.OrdinalIgnoreCase)))
throw Oops.Oh($"分享链接状态{shareInfo.STATUS} 不需要取消");
shareInfo.STATUS = RollingNominationDispatchStatusEnum.CANCEL.ToString();
shareInfo.UpdatedTime = DateTime.Now;
shareInfo.UpdatedUserId = UserManager.UserId;
shareInfo.UpdatedUserName = UserManager.Name;
await _taskShareLinkInfoRepository.AsUpdateable(shareInfo)
.UpdateColumns(it => new
{
it.STATUS,
it.UpdatedTime,
it.UpdatedUserId,
it.UpdatedUserName
}).ExecuteCommandAsync();
if (_cache.Exists(shareInfo.SHARE_LINK_KEY))
await _cache.DelAsync(shareInfo.SHARE_LINK_KEY);
result.succ = true;
result.msg = "成功";
}
catch (Exception ex)
{
_logger.LogError($"取消访问链接异常,原因:{ex.Message}");
result.succ = false;
result.msg = $"取消访问链接异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 校验成访问链接
/// <summary>
/// 校验成访问链接
/// </summary>
/// <param name="Url">请求链接</param>
/// <returns>返回回执</returns>
[HttpGet("/TaskManageShareLink/ValidateShareLink")]
public async Task<TaskManageOrderResultDto> ValidateShareLink(string Url)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
return result;
}
#endregion
#region 访问链接
/// <summary>
/// 访问链接
/// </summary>
/// <param name="Url">请求链接</param>
/// <returns>返回回执</returns>
public async Task<TaskManageOrderResultDto> QueryShareLink(string Url)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
return result;
}
#endregion
#region 获取分享详情
/// <summary>
/// 获取分享详情
/// </summary>
/// <param name="shareKey">链接分享KEY</param>
/// <returns>返回回执</returns>
[AllowAnonymous,HttpGet("/TaskManageShareLink/GetInfo")]
public async Task<TaskManageOrderResultDto> GetInfo([FromQuery] string shareKey)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
/*
1、先验证shareKey是否在缓存存在存在继续不存在返回错误。
2、获取分享的表记录根据任务类型调取不同的接口返回详情数据。
3、查看是否存在分享的声明内容如果存在需要返回。
*/
try
{
if (string.IsNullOrWhiteSpace(shareKey))
throw Oops.Oh($"链接分享KEY不能为空");
if (!_cache.Exists(shareKey))
throw Oops.Oh($"链接分享已失效");
var cacheVal = _cache.Get<string>(shareKey);
long shareId = long.Parse(cacheVal.Split(new char[]{ '_'}).FirstOrDefault());
var shareEntity = _taskShareLinkInfoRepository.AsQueryable().Filter(null, true)
.First(a => a.Id == shareId);
if (shareEntity == null)
throw Oops.Oh($"链接分享不存在");
var showModel = await InnerGetInfo(shareEntity.BUSI_ID);
var list = _taskShareLinkDynamicDataInfoRepository.AsQueryable().Filter(null, true)
.Where(a => a.SHARE_ID == shareEntity.Id).ToList();
if (list.Count > 0)
{
var dyData = list.FirstOrDefault(a => a.DATA_TYPE == "DISCLAIMERS");
if (dyData != null)
showModel.DynamicData = dyData.DATA_MSG;
}
result.succ = true;
result.ext = showModel;
}
catch(Exception ex)
{
_logger.LogError($"获取分享详情异常,原因:{ex.Message}");
result.succ = false;
result.msg = $"获取分享详情异常,原因:{ex.Message}";
}
return result;
}
#endregion
#region 生成分享的动态数据
/// <summary>
/// 生成分享的动态数据
/// </summary>
/// <param name="expireDateTime">最后失效时间</param>
/// <param name="TenantCompanyName">企业名称</param>
/// <returns>返回填充模板后文本</returns>
private string GenerateShareDynamicData(DateTime expireDateTime,string TenantCompanyName)
{
string result = string.Empty;
try
{
//调取模板
string templatePath = App.Configuration["EmailTemplateFilePath"];
var opt = App.GetOptions<BookingAttachOptions>();
var dirAbs = opt.basePath;
if (string.IsNullOrEmpty(dirAbs))
{
dirAbs = App.WebHostEnvironment.WebRootPath;
}
templatePath = $"{dirAbs}{templatePath}\\NominationShareTemplate.html";
result = File.ReadAllText(templatePath);
if (!string.IsNullOrWhiteSpace(result))
{
if (Regex.IsMatch(result, "#DeadLineDate#"))
result = Regex.Replace(result, "#DeadLineDate#", expireDateTime.ToString("yyyy-MM-dd HH:mm:ss"));
if (Regex.IsMatch(result, "#TenantCompanyName#"))
result = Regex.Replace(result, "#TenantCompanyName#", TenantCompanyName);
}
}
catch (Exception ex)
{
_logger.LogError($"生成分享动态数据异常,原因:{ex.Message}");
}
return result;
}
#endregion
#region 获取预甩详情
/// <summary>
/// 获取预甩详情
/// </summary>
/// <param name="dispatchBatchId">预甩货详调度批次号</param>
/// <returns>返回详情</returns>
private async Task<TaskRollingNominationShowDto> InnerGetInfo(string dispatchBatchId)
{
TaskRollingNominationShowDto model = null;
try
{
List<string> rollingPlanList = new List<string>();
var list = _taskRollingNominationInfoRepository.AsQueryable().Filter(null, true)
.InnerJoin<TaskRollingNominationDispatchInfo>((nom, dispatch) => nom.PK_ID == dispatch.NOM_ID)
.InnerJoin<TaskRollingNominationDetailInfo>((nom, dispatch, detail)
=> dispatch.DETAIL_ID == detail.PK_ID)
.Where((nom, dispatch, detail) => dispatch.BATCH_ID == dispatchBatchId
&& nom.IsDeleted == false && detail.IsDeleted == false && dispatch.IsDeleted == false)
.Select((nom, dispatch, detail) => new { Nom = nom, Detail = detail, Dispatch = dispatch }).ToList();
var rollModel = list.FirstOrDefault().Nom;
if (!string.IsNullOrWhiteSpace(rollModel.PLAN_TXT))
{
rollingPlanList = rollModel.PLAN_TXT.Split("\\n").ToList();
}
model = new TaskRollingNominationShowDto
{
PlanType = rollModel.PLAN_TYPE,
CarrierId = rollModel.CARRIERID,
Carrier = rollModel.CARRIER,
ConfirmDeadLine = rollModel.CONFIRM_DEAD_LINE,
CreateTime = rollModel.READ_CREATE_TIME,
RollingTouchDoubleRollRemark = rollModel.ROLL_DOUBLE_REMARK,
LoadDetailList = new List<TaskRollingNominationShipDetailShowDto>(),
RollingPlanList = rollingPlanList,
PreBillList = new List<TaskRollingNominationShipPreBillShowDto>()
};
var shipList = _taskRollingNominationShipInfoRepository.AsQueryable().Filter(null, true)
.Where(a => a.NOM_ID == rollModel.PK_ID && a.GROUP_INDX == 1 && !a.IsDeleted).ToList();
var fromEntity = shipList.FirstOrDefault(a =>
a.SHIP_TYPE.Equals("From", StringComparison.OrdinalIgnoreCase));
if (fromEntity != null)
model.From = fromEntity.Adapt<TaskRollingNominationShipDto>();
var toEntity = shipList.FirstOrDefault(a =>
a.SHIP_TYPE.Equals("To", StringComparison.OrdinalIgnoreCase));
if (toEntity != null)
model.To = toEntity.Adapt<TaskRollingNominationShipDto>();
List<Tuple<string, int>> tuples = new List<Tuple<string, int>>();
model.LoadDetailList = list.Select(a => a.Detail.Adapt<TaskRollingNominationShipDetailShowDto>()).ToList();
if (model.LoadDetailList.Count > 0)
{
model.TotalLoadCtnStat = string.Join(",", model.LoadDetailList.GroupBy(x => x.CtnAll)
.Select(x =>
$"{x.Key}*{x.Sum(t => t.CtnNum)}").ToArray());
}
}
catch (Exception ex)
{
_logger.LogError($"获取预甩详情异常,原因:{ex.Message}");
throw ex;
}
return model;
}
#endregion
/// <summary>
/// 推送分享链接反馈意见
/// </summary>
/// <param name="model">推送分享链接反馈意见请求</param>
/// <returns>返回回执</returns>
[AllowAnonymous, HttpPost("/TaskManageShareLink/PushShareLinkFeedBack")]
public async Task<TaskManageOrderResultDto> PushShareLinkFeedBack(PushShareLinkFeedBackDto model)
{
TaskManageOrderResultDto result = new TaskManageOrderResultDto();
/*
1、验证shareKey是否有效。
2、查看分享记录找到对应的预甩调度详情。
3、更新用户反馈意见。
4、返回成功
*/
try
{
if (string.IsNullOrWhiteSpace(model.shareKey))
throw Oops.Oh($"链接分享KEY不能为空");
if (!_cache.Exists(model.shareKey))
throw Oops.Oh($"链接分享已失效");
var shareEntity = _taskShareLinkInfoRepository.AsQueryable()
.First(a => a.SHARE_LINK_KEY == model.shareKey);
if (shareEntity == null)
throw Oops.Oh($"链接分享不存在");
shareEntity.USER_OPINION = model.userOpinion;
shareEntity.USER_OPINION_TXT = model.userOpinionTxt;
shareEntity.CONFIRM_DATE = DateTime.Now;
await _taskShareLinkInfoRepository.AsUpdateable(shareEntity)
.UpdateColumns(it => new
{
it.USER_OPINION,
it.USER_OPINION_TXT,
it.CONFIRM_DATE,
}).ExecuteCommandAsync();
result.succ = true;
result.msg = "成功";
}
catch (Exception ex)
{
_logger.LogError($"推送分享链接反馈意见异常,原因:{ex.Message}");
result.succ = false;
result.msg = $"推送分享链接反馈意见异常,原因:{ex.Message}";
}
return result;
}
}
}