using Furion ;
using Furion.DatabaseAccessor ;
using Furion.DependencyInjection ;
using Furion.DistributedIDGenerator ;
using Furion.FriendlyException ;
using Furion.JsonSerialization ;
using Furion.RemoteRequest.Extensions ;
using HtmlAgilityPack ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.AspNetCore.Mvc.Rendering ;
using Microsoft.Extensions.DependencyInjection ;
using Microsoft.Extensions.Logging ;
using ServiceProjectSyncWin ;
using ServiceProjectSyncWin.Entities ;
using SqlSugar ;
using System.Collections.Generic ;
using System.Collections.Specialized ;
using System.ComponentModel.DataAnnotations ;
using System.Net.Http.Headers ;
using System.Text ;
using System.Text.RegularExpressions ;
using System.Web ;
using static System . Net . Mime . MediaTypeNames ;
Serve . RunGeneric ( additional : services = >
{
services . AddRemoteRequest ( ) ;
services . AddSqlsugarSetup ( App . Configuration ) ;
} , true , true ) ;
Console . WriteLine ( "开始准备同步历史服务状态数据" ) ;
var service1 = App . GetService < ISyncHisRecord > ( ) ;
//service1.SyncServiceProjectRecord();
service1 . SyncServiceProjectRecord5 ( ) ;
Console . ReadKey ( ) ;
public interface ISyncHisRecord
{
void SyncServiceProjectRecord4 ( ) ;
void SyncServiceProjectRecord5 ( ) ;
//void SyncServiceProjectRecord2();
//void SyncServiceProjectRecord3();
}
public class SyncHisRecord : ISyncHisRecord , ITransient
{
SqlSugar . ISqlSugarClient _db ;
private readonly ILogger < SyncHisRecord > _logger ;
public SyncHisRecord ( ISqlSugarClient db , ILogger < SyncHisRecord > logger )
{
_db = db ;
_logger = logger ;
}
public void SyncServiceProjectRecord ( )
{
int totalSyncNum = 0 ;
int succSyncNum = 0 ;
long maxId = 0 ;
//349708986646597/中集世联达领鲜物流科技(山东)有限公司
long tenantId = 349708986646597 ;
string batchNo = Guid . NewGuid ( ) . ToString ( ) ;
_logger . LogInformation ( "批次={no} 触发同步货物状态 tenantId={tenantId}" , batchNo , tenantId ) ;
try
{
var tenantInfo = _db . Queryable < SysTenant > ( ) . First ( a = > a . Id = = tenantId ) ;
/ *
1 、 按 批 次 读 取 服 务 状 态 数 据 。 ( 去 掉 没 有 完 成 时 间 的 、 并 且 订 舱 数 据 是 已 删 除 的 记 录 )
2 、 写 入 历 史 记 录 表 。
3 、 单 票 生 成 触 发 报 文 , 并 推 送 状 态 。
4 、 更 新 历 史 记 录 , 标 记 同 步 状 态
* /
maxId = _db . Queryable < ServiceStatusBookingSyncHisInfo > ( ) . Max ( a = > a . ORG_STATUS_ID ) ;
_logger . LogInformation ( "批次={no} 获取最后同步服务状态的ID={maxId}" , batchNo , maxId ) ;
int takeNum = 1000 ;
while ( true )
{
var takeList = _db . Queryable < BookingGoodsStatus > ( )
. InnerJoin < BookingGoodsStatusConfig > ( ( gs , cfg ) = > gs . ConfigId = = cfg . Id )
. InnerJoin < BookingOrder > ( ( gs , cfg , bk ) = > gs . bookingId = = bk . Id )
. Where ( ( gs , cfg , bk ) = >
gs . FinishTime . HasValue & & gs . TenantId = = tenantId
& & ! bk . IsDeleted & & gs . FinishUserId ! = 142307070910551
& & ( maxId = = 0 | | gs . Id > maxId ) )
. OrderBy ( ( gs , cfg , bk ) = > gs . Id )
. Select ( ( gs , cfg , bk ) = > new { GS = gs , CFG = cfg , BK = bk } )
. Take ( takeNum ) . ToList ( ) ;
totalSyncNum + = takeList . Count ;
Console . WriteLine ( $"批次={batchNo} 同步待处理任务 totalSyncNum={totalSyncNum}" ) ;
_logger . LogInformation ( "批次={no} 同步待处理任务 totalSyncNum={totalSyncNum}" , batchNo , totalSyncNum ) ;
//没有记录跳出循环
if ( takeList . Count = = 0 )
{
Console . WriteLine ( $"没有记录跳出循环 total={succSyncNum}" ) ;
break ;
}
maxId = takeList . Max ( a = > a . GS . Id ) ;
_logger . LogInformation ( "批次={no} 获取最后同步服务状态的 maxId={maxId}" , batchNo , maxId ) ;
//写入记录表
takeList . ForEach ( async record = >
{
var entity = new ServiceStatusBookingSyncHisInfo
{
PK_ID = Guid . NewGuid ( ) . ToString ( ) ,
ORG_STATUS_ID = record . GS . Id ,
BOOKING_ID = record . BK . Id ,
FINISH_TIME = record . GS . FinishTime . Value ,
FINISH_USER_ID = record . GS . FinishUserId . Value ,
FINISH_USER_NAME = record . GS . FinishUser ,
MBL_NO = record . BK . MBLNO ,
SORT_NO = record . CFG . Sort ,
STATUS_SKU_CODE = record . CFG . SystemCode ,
STATUS_SKU_NAME = record . CFG . StatusName ,
STATUS_REMARK = record . GS . Remark ,
STATUS_VAL = record . GS . ExtData ,
TENANT_ID = record . GS . TenantId . Value ,
TENANT_NAME = tenantInfo . Name ,
VESSEL = record . BK . VESSEL ,
VOYNO = record . BK . VOYNO ,
} ;
_db . Insertable < ServiceStatusBookingSyncHisInfo > ( entity ) . ExecuteCommand ( ) ;
//await _serviceStatusBookingSyncHisInfoRepository.InsertAsync(entity);
succSyncNum + + ;
Console . WriteLine ( $"ORG_STATUS_ID={record.GS.Id} 写入成功 total={succSyncNum}" ) ;
Thread . Sleep ( 300 ) ;
} ) ;
Console . WriteLine ( $"等待500毫秒" ) ;
Thread . Sleep ( 500 ) ;
}
//停用的状态(接受委托、放箱指令、已发账单、账单确认、账单已回传)
string [ ] deletedStatusCodeArg = new string [ ] { "JSWTUO" , "FXZLING" , "YFZD" , "ZDQR" , "ZDYHC" } ;
/ *
单 票 触 发 推 送 状 态
1 、 取 状 态 是 null 的 , 并 且 每 次 取 前 100 个 订 舱 记 录 。
2 、 按 订 舱 记 录 取 所 有 的 状 态 记 录 。
3 、 生 成 触 发 脚 本 推 送 PUSH 状 态 。 ( 部 分 状 态 自 动 不 执 行 )
4 、 执 行 成 功 后 , 更 新 对 应 的 状 态 。
* /
Console . WriteLine ( $"开始推送记录 succ={succSyncNum}" ) ;
while ( true )
{
var bookingList = _db . Queryable < ServiceStatusBookingSyncHisInfo > ( )
. Where ( a = > a . TENANT_ID = = tenantId & & a . STATUS = = null )
. Take ( 100 ) . Select ( a = > a . BOOKING_ID ) . Distinct ( ) . ToList ( ) ;
//无数据跳出
if ( bookingList . Count = = 0 )
{
Console . WriteLine ( $"没有待推送记录跳出循环 succ={succSyncNum}" ) ;
break ;
}
var taskList = _db . Queryable < ServiceStatusBookingSyncHisInfo > ( )
. Where ( a = > a . TENANT_ID = = tenantId & & bookingList . Contains ( a . BOOKING_ID ) ) . ToList ( ) ;
taskList . GroupBy ( a = > a . BOOKING_ID ) . ToList ( ) . ForEach ( a = >
{
DateTime currDate = DateTime . Now ;
var currStatusList = a . ToList ( ) ;
var groupCheckList = currStatusList
. Where ( b = > ! deletedStatusCodeArg . Contains ( b . STATUS_SKU_CODE ) )
. GroupBy ( b = > b . STATUS_SKU_CODE ) . Select ( b = >
{
var currList = b . ToList ( ) ;
if ( currList . Count = = 1 )
return currList . FirstOrDefault ( ) ;
return currList . OrderByDescending ( c = > c . ORG_STATUS_ID ) . FirstOrDefault ( ) ;
} ) . ToList ( ) ;
if ( groupCheckList . Count > 0 )
{
var firstInfo = groupCheckList . FirstOrDefault ( ) ;
TrackingMessageInfo msgInfo = new TrackingMessageInfo
{
Head = new TrackingMessageHeadInfo
{
GID = IDGen . NextID ( ) . ToString ( ) ,
MessageType = "PROJECT" ,
ReceiverId = "ServiceProjectStatus" ,
ReceiverName = "服务项目和状态" ,
SenderId = "BookingOrder" ,
SenderName = "海运订舱" ,
RequestDate = DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss.fff" ) ,
Version = "2.0" ,
RequestAction = "AddOrModify" ,
} ,
Main = new TrackingMessageMainInfo
{
BusiId = firstInfo . BOOKING_ID . ToString ( ) ,
BusiSystemCode = "BOOKING_ORDER" ,
MBlNo = firstInfo . MBL_NO ,
VesselVoyno = $"{firstInfo.VESSEL}/{firstInfo.VOYNO}" ,
OrderNo = "" ,
PushType = TrackingPushTypeEnum . Status ,
OperTenantId = firstInfo . TENANT_ID ,
OperTenantName = firstInfo . TENANT_NAME ,
OpertType = TrackingOperTypeEnum . AUTO ,
OperUserId = firstInfo . FINISH_USER_ID . ToString ( ) ,
OperUserName = firstInfo . FINISH_USER_NAME ,
SourceType = TrackingSourceTypeEnum . AUTO ,
StatusList = groupCheckList . Select ( a = > new TrackingMessageMainStatusInfo
{
StatusCode = a . STATUS_SKU_CODE ,
StatusDate = a . FINISH_TIME ,
StatusVal = a . STATUS_VAL ,
Remark = a . STATUS_REMARK
} ) . ToList ( )
}
} ;
Console . WriteLine ( $"准备PUSH状态 msg={JSON.Serialize(msgInfo.Main)}" ) ;
//推送状态
var pushRlt = PushStatus ( msgInfo ) . GetAwaiter ( ) . GetResult ( ) ;
Console . WriteLine ( $"PUSH返回结果 rlt={JSON.Serialize(pushRlt)}" ) ;
groupCheckList . ForEach ( async t = > {
t . STATUS = pushRlt . succ ? "SUCC" : "FAILURE" ;
t . SYNC_TIME = currDate ;
t . SYNC_RESULT = pushRlt . msg ;
if ( deletedStatusCodeArg . Contains ( t . STATUS_SKU_CODE ) )
{
t . STATUS = "FAILURE" ;
t . SYNC_RESULT = "状态已取消不再同步" ;
}
await _db . Updateable < ServiceStatusBookingSyncHisInfo > ( t )
. UpdateColumns ( it = > new
{
it . STATUS ,
it . SYNC_TIME ,
it . SYNC_RESULT
} ) . ExecuteCommandAsync ( ) ;
} ) ;
var undoList = currStatusList . GroupJoin ( groupCheckList , l = > l . ORG_STATUS_ID ,
r = > r . ORG_STATUS_ID , ( l , r ) = >
{
var currList = r . ToList ( ) ;
if ( currList . Count = = 0 )
return new { IsUpdate = true , Obj = l } ;
return new { IsUpdate = false , Obj = l } ;
} ) . Where ( c = > c . IsUpdate )
. Select ( c = > c . Obj ) . ToList ( ) ;
if ( undoList . Count > 0 )
{
undoList . ForEach ( async t = > {
t . STATUS = "FAILURE" ;
t . SYNC_RESULT = "状态已取最后触发记录" ;
t . SYNC_TIME = currDate ;
if ( deletedStatusCodeArg . Contains ( t . STATUS_SKU_CODE ) )
{
t . SYNC_RESULT = "状态已取消不再同步" ;
}
await _db . Updateable < ServiceStatusBookingSyncHisInfo > ( t )
. UpdateColumns ( it = > new
{
it . STATUS ,
it . SYNC_TIME ,
it . SYNC_RESULT
} ) . ExecuteCommandAsync ( ) ;
} ) ;
}
Console . WriteLine ( $"更新表结束" ) ;
}
else
{
Console . WriteLine ( $"没有可用记录" ) ;
}
Thread . Sleep ( 300 ) ;
} ) ;
Thread . Sleep ( 500 ) ;
}
}
catch ( Exception ex )
{
_logger . LogInformation ( "批次={no} 同步异常ex={ex}" , batchNo , maxId ) ;
}
}
public async Task < TaskManageOrderResultDto > PushStatus ( TrackingMessageInfo info )
{
TaskManageOrderResultDto model = null ;
/ *
1 、 读 取 配 置 文 件 中 的 规 则 引 擎 URL
2 、 填 充 请 求 的 类 , 并 生 成 JSON 报 文
3 、 POST 请 求 接 口 , 并 记 录 回 执 。
4 、 返 回 信 息 。
* /
var url = App . Configuration [ "ServiceStatusPushUrl" ] ;
try
{
var res = await url . SetHttpMethod ( HttpMethod . Post )
. SetBody ( JSON . Serialize ( info ) , "application/json" )
. SetContentEncoding ( Encoding . UTF8 )
. PostAsync ( ) ;
_logger . LogInformation ( "批次={no} 对应请求报文完成 res={res}" , info . Head . GID , JSON . Serialize ( res ) ) ;
if ( res . StatusCode = = System . Net . HttpStatusCode . OK )
{
var userResult = await res . Content . ReadAsStringAsync ( ) ;
var cmRlt = JSON . Deserialize < CommonRlt > ( userResult ) ;
if ( cmRlt . success )
model = JSON . Deserialize < TaskManageOrderResultDto > ( JSON . Serialize ( cmRlt . data ) ) ;
}
}
catch ( Exception ex )
{
//写日志
if ( ex is HttpRequestException )
throw Oops . Oh ( 10000002 ) ;
}
return model ;
}
public void SyncServiceProjectRecord2 ( )
{
/ *
string fmt = "(16)PortofDischarge(17)PlaceofDelivery" ;
var fmtList = fmt . Select ( a = > a ) . ToList ( ) ;
string name = "(1P6)E PNorAt oNf GDi,scMhaArgLeA YSIA P(1E7)N PAlaNceG o,f DMeAlivLerAy YSIA" ;
List < char > array = new List < char > ( ) ;
List < char > array2 = new List < char > ( ) ;
for ( var i = 0 ; i < name . Length ; i + + )
{
bool isExists = false ;
if ( fmtList . Count > 0 )
{
if ( name [ i ] = = fmtList . First ( ) )
{
array . Add ( name [ i ] ) ;
fmtList . Remove ( fmtList [ 0 ] ) ;
isExists = true ;
}
}
if ( ! isExists )
array2 . Add ( name [ i ] ) ;
}
string s1 = string . Join ( "" , array ) ;
string s2 = string . Join ( "" , array2 ) ;
* /
string Consignee = "LOT 13/3,KAWASAN PERINDUSTRIAN, K AMPUNG KOLAM PADANG BESAR,02100 P ADANG BESAR,PERLIS. T EL;04-949 0507 FAX 94-949 2888" ;
string NotifyParty = "SHUN EE TRADING SDN BHD (1183208 U) LOT 13/3,KAWASAN PERINDUSTRIAN, K AMPUNG KOLAM PADANG BESAR,02100 P ADANG BESAR,PERLIS. T EL;04-949 0507 FAX 94-949 2888" ;
if ( Regex . IsMatch ( Consignee , "\\b[a-zA-Z]{1}\\b\\s+\\b[a-zA-Z]+\\b" ) )
{
Consignee = Regex . Replace ( Consignee , "\\b[a-zA-Z]{1}\\b\\s+\\b[a-zA-Z]+\\b" , m = > Regex . Replace ( m . Value , "\\s+" , "" ) ) ;
}
if ( Regex . IsMatch ( NotifyParty , "\\b[a-zA-Z]{1}\\b\\s+\\b[a-zA-Z]+\\b" ) )
{
NotifyParty = Regex . Replace ( NotifyParty , "\\b[a-zA-Z]{1}\\b\\s+\\b[a-zA-Z]+\\b" , m = > Regex . Replace ( m . Value , "\\s+" , "" ) ) ;
}
decimal similarity = 100 ;
for ( int i = 0 ; i < NotifyParty . Length ; i + + )
{
}
}
public void SyncServiceProjectRecord4 ( )
{
/ *
批 量 更 新 SI 截 止 时 间
1 、 更 新 任 务 台
2 、 更 新 舱 位 的 截 止 时 间 记 录
* /
var taskList = _db . Queryable < TaskBCEntity > ( ) . Where ( a = > ( a . BUSI_TYPE = = "BookingConfirmation" | | a . BUSI_TYPE = = "BookingAmendment" ) )
. OrderBy ( t = > t . CreatedTime )
. ToList ( ) ;
string batchNo = Guid . NewGuid ( ) . ToString ( ) ;
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 num={taskList.Count}" ) ;
string bcReadUrl = "http://47.104.73.97:7115/api/TaskBCParser/ExcuteBCFileRead" ;
string amendReadUrl = "http://47.104.73.97:7115/api/TaskBookingAmendmentParser/ExcuteBookingAmendmentRead" ;
//foreach (var task in taskList)
for ( int i = 0 ; i < taskList . Count ; i + + )
{
var task = taskList [ i ] ;
//BookingConfirmation、BookingAmendment
if ( task . BUSI_TYPE = = "BookingConfirmation" )
{
_logger . LogInformation ( $"批次={batchNo} 处理任务 No={i} MBLNO={task.MBL_NO} 开始" ) ;
var fileInfo = _db . Queryable < TaskFileEntities > ( ) . Where ( a = > a . TASK_PKID = = task . TASK_ID & & a . FILE_CATEGORY = = "BC" ) . First ( ) ;
if ( fileInfo ! = null )
{
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 MBLNO={task.MBL_NO} 取到文件" ) ;
string bcFileFullPath = $"D:\\djy\\backend\\wwwroot\\{fileInfo.FILE_PATH}" ;
var bcFileName = Path . GetFileName ( bcFileFullPath ) ;
if ( ! File . Exists ( bcFileFullPath ) )
{
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 MBLNO={task.MBL_NO} 取到文件不存在 path={bcFileFullPath}" ) ;
continue ;
}
TaskBCInfoReadDto BCReadInfo = GetBCReaderInfo ( bcFileFullPath , bcFileName , task . TenantId . Value , task . TASK_ID , bcReadUrl ) . GetAwaiter ( ) . GetResult ( ) ;
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 MBLNO={task.MBL_NO} 识别完文件 BCReadInfo={JSON.Serialize(BCReadInfo)}" ) ;
StringBuilder msgBuilder = new StringBuilder ( ) ;
if ( BCReadInfo ! = null )
{
//SI_CUT_DATE
if ( BCReadInfo . SICutDate . HasValue )
{
if ( ! task . SI_CUT_DATE . HasValue | | task . SI_CUT_DATE . Value ! = BCReadInfo . SICutDate . Value )
{
msgBuilder . Append ( $"SI_CUT_DATE org={task.SI_CUT_DATE} tar={BCReadInfo.SICutDate.Value}##" ) ;
task . SI_CUT_DATE = BCReadInfo . SICutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"SI_CUT_DATE org={task.SI_CUT_DATE} tar=null" ) ;
task . SI_CUT_DATE = null ;
}
//VGM_CUTOFF_TIME
if ( BCReadInfo . VGMCutoffTime . HasValue )
{
if ( ! task . VGM_CUTOFF_TIME . HasValue | | task . VGM_CUTOFF_TIME . Value ! = BCReadInfo . VGMCutoffTime . Value )
{
msgBuilder . Append ( $"VGM_CUTOFF_TIME org={task.VGM_CUTOFF_TIME} tar={BCReadInfo.VGMCutoffTime.Value}##" ) ;
task . VGM_CUTOFF_TIME = BCReadInfo . VGMCutoffTime . Value ;
}
}
else
{
msgBuilder . Append ( $"VGM_CUTOFF_TIME org={task.VGM_CUTOFF_TIME} tar=null##" ) ;
task . VGM_CUTOFF_TIME = null ;
}
//MANIFEST_CUT_DATE
if ( BCReadInfo . ManifestCutDate . HasValue )
{
if ( ! task . MANIFEST_CUT_DATE . HasValue | | task . MANIFEST_CUT_DATE . Value ! = BCReadInfo . ManifestCutDate . Value )
{
msgBuilder . Append ( $"MANIFEST_CUT_DATE org={task.MANIFEST_CUT_DATE} tar={BCReadInfo.ManifestCutDate.Value}##" ) ;
task . MANIFEST_CUT_DATE = BCReadInfo . ManifestCutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"MANIFEST_CUT_DATE org={task.MANIFEST_CUT_DATE} tar=null##" ) ;
task . MANIFEST_CUT_DATE = null ;
}
//CY_CUTOFF_TIME
if ( BCReadInfo . CYCutoffTime . HasValue )
{
if ( ! task . MANIFEST_CUT_DATE . HasValue | | task . MANIFEST_CUT_DATE . Value ! = BCReadInfo . CYCutoffTime . Value )
{
msgBuilder . Append ( $"CY_CUTOFF_TIME org={task.CY_CUTOFF_TIME} tar={BCReadInfo.CYCutoffTime.Value}##" ) ;
task . CY_CUTOFF_TIME = BCReadInfo . CYCutoffTime . Value ;
}
}
else
{
msgBuilder . Append ( $"CY_CUTOFF_TIME org={task.CY_CUTOFF_TIME} tar=null##" ) ;
task . CY_CUTOFF_TIME = null ;
}
//MDGF_CUT_DATE
if ( BCReadInfo . MDGFCutDate . HasValue )
{
if ( ! task . MDGF_CUT_DATE . HasValue | | task . MDGF_CUT_DATE . Value ! = BCReadInfo . MDGFCutDate . Value )
{
msgBuilder . Append ( $"MDGF_CUT_DATE org={task.MDGF_CUT_DATE} tar={BCReadInfo.MDGFCutDate.Value}##" ) ;
task . MDGF_CUT_DATE = BCReadInfo . MDGFCutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"MDGF_CUT_DATE org={task.MDGF_CUT_DATE} tar=null##" ) ;
task . MDGF_CUT_DATE = null ;
}
//CLOSING_DATE
if ( BCReadInfo . ClosingDate . HasValue )
{
if ( ! task . CLOSING_DATE . HasValue | | task . CLOSING_DATE . Value ! = BCReadInfo . ClosingDate . Value )
{
msgBuilder . Append ( $"CLOSING_DATE org={task.CLOSING_DATE} tar={BCReadInfo.ClosingDate.Value}##" ) ;
task . CLOSING_DATE = BCReadInfo . ClosingDate . Value ;
}
}
else
{
msgBuilder . Append ( $"CLOSING_DATE org={task.CLOSING_DATE} tar=null##" ) ;
task . CLOSING_DATE = null ;
}
//CLOSING_DATE
if ( BCReadInfo . CustomSICutDate . HasValue )
{
if ( ! task . CUSTOM_SI_CUT_DATE . HasValue | | task . CUSTOM_SI_CUT_DATE . Value ! = BCReadInfo . CustomSICutDate . Value )
{
msgBuilder . Append ( $"CUSTOM_SI_CUT_DATE org={task.CUSTOM_SI_CUT_DATE} tar={BCReadInfo.CustomSICutDate.Value}##" ) ;
task . CUSTOM_SI_CUT_DATE = BCReadInfo . CustomSICutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"CUSTOM_SI_CUT_DATE org={task.CUSTOM_SI_CUT_DATE} tar=null##" ) ;
task . CUSTOM_SI_CUT_DATE = null ;
}
_db . Updateable < TaskBCEntity > ( task ) . UpdateColumns ( it = > new
{
it . SI_CUT_DATE ,
it . CUSTOM_SI_CUT_DATE ,
it . VGM_CUTOFF_TIME ,
it . MANIFEST_CUT_DATE ,
it . CY_CUTOFF_TIME ,
it . MDGF_CUT_DATE ,
it . CLOSING_DATE
} ) . ExecuteCommand ( ) ;
}
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 MBLNO={task.MBL_NO} 识别完文件 有变更 结果={msgBuilder.ToString()}" ) ;
}
}
else if ( task . BUSI_TYPE = = "BookingAmendment" )
{
var fileInfo = _db . Queryable < TaskFileEntities > ( ) . Where ( a = > a . TASK_PKID = = task . TASK_ID & & a . FILE_CATEGORY = = "BC_MODIFY" ) . First ( ) ;
if ( fileInfo ! = null )
{
string bcFileFullPath = $"D:\\djy\\backend\\wwwroot\\{fileInfo.FILE_PATH}" ;
var bcFileName = Path . GetFileName ( bcFileFullPath ) ;
if ( ! File . Exists ( bcFileFullPath ) )
{
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 MBLNO={task.MBL_NO} 取到文件不存在 path={bcFileFullPath}" ) ;
continue ;
}
TaskBCInfoReadDto BCReadInfo = GetBCReaderInfo ( bcFileFullPath , bcFileName , task . TenantId . Value , task . TASK_ID , amendReadUrl ) . GetAwaiter ( ) . GetResult ( ) ;
StringBuilder msgBuilder = new StringBuilder ( ) ;
if ( BCReadInfo ! = null )
{
//SI_CUT_DATE
if ( BCReadInfo . SICutDate . HasValue )
{
if ( ! task . SI_CUT_DATE . HasValue | | task . SI_CUT_DATE . Value ! = BCReadInfo . SICutDate . Value )
{
msgBuilder . Append ( $"SI_CUT_DATE org={task.SI_CUT_DATE} tar={BCReadInfo.SICutDate.Value}##" ) ;
task . SI_CUT_DATE = BCReadInfo . SICutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"SI_CUT_DATE org={task.SI_CUT_DATE} tar=null" ) ;
task . SI_CUT_DATE = null ;
}
//VGM_CUTOFF_TIME
if ( BCReadInfo . VGMCutoffTime . HasValue )
{
if ( ! task . VGM_CUTOFF_TIME . HasValue | | task . VGM_CUTOFF_TIME . Value ! = BCReadInfo . VGMCutoffTime . Value )
{
msgBuilder . Append ( $"VGM_CUTOFF_TIME org={task.VGM_CUTOFF_TIME} tar={BCReadInfo.VGMCutoffTime.Value}##" ) ;
task . VGM_CUTOFF_TIME = BCReadInfo . VGMCutoffTime . Value ;
}
}
else
{
msgBuilder . Append ( $"VGM_CUTOFF_TIME org={task.VGM_CUTOFF_TIME} tar=null##" ) ;
task . VGM_CUTOFF_TIME = null ;
}
//MANIFEST_CUT_DATE
if ( BCReadInfo . ManifestCutDate . HasValue )
{
if ( ! task . MANIFEST_CUT_DATE . HasValue | | task . MANIFEST_CUT_DATE . Value ! = BCReadInfo . ManifestCutDate . Value )
{
msgBuilder . Append ( $"MANIFEST_CUT_DATE org={task.MANIFEST_CUT_DATE} tar={BCReadInfo.ManifestCutDate.Value}##" ) ;
task . MANIFEST_CUT_DATE = BCReadInfo . ManifestCutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"MANIFEST_CUT_DATE org={task.MANIFEST_CUT_DATE} tar=null##" ) ;
task . MANIFEST_CUT_DATE = null ;
}
//CY_CUTOFF_TIME
if ( BCReadInfo . CYCutoffTime . HasValue )
{
if ( ! task . MANIFEST_CUT_DATE . HasValue | | task . MANIFEST_CUT_DATE . Value ! = BCReadInfo . CYCutoffTime . Value )
{
msgBuilder . Append ( $"CY_CUTOFF_TIME org={task.CY_CUTOFF_TIME} tar={BCReadInfo.CYCutoffTime.Value}##" ) ;
task . CY_CUTOFF_TIME = BCReadInfo . CYCutoffTime . Value ;
}
}
else
{
msgBuilder . Append ( $"CY_CUTOFF_TIME org={task.CY_CUTOFF_TIME} tar=null##" ) ;
task . CY_CUTOFF_TIME = null ;
}
//MDGF_CUT_DATE
if ( BCReadInfo . MDGFCutDate . HasValue )
{
if ( ! task . MDGF_CUT_DATE . HasValue | | task . MDGF_CUT_DATE . Value ! = BCReadInfo . MDGFCutDate . Value )
{
msgBuilder . Append ( $"MDGF_CUT_DATE org={task.MDGF_CUT_DATE} tar={BCReadInfo.MDGFCutDate.Value}##" ) ;
task . MDGF_CUT_DATE = BCReadInfo . MDGFCutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"MDGF_CUT_DATE org={task.MDGF_CUT_DATE} tar=null##" ) ;
task . MDGF_CUT_DATE = null ;
}
//CLOSING_DATE
if ( BCReadInfo . ClosingDate . HasValue )
{
if ( ! task . CLOSING_DATE . HasValue | | task . CLOSING_DATE . Value ! = BCReadInfo . ClosingDate . Value )
{
msgBuilder . Append ( $"CLOSING_DATE org={task.CLOSING_DATE} tar={BCReadInfo.ClosingDate.Value}##" ) ;
task . CLOSING_DATE = BCReadInfo . ClosingDate . Value ;
}
}
else
{
msgBuilder . Append ( $"CLOSING_DATE org={task.CLOSING_DATE} tar=null##" ) ;
task . CLOSING_DATE = null ;
}
//CLOSING_DATE
if ( BCReadInfo . CustomSICutDate . HasValue )
{
if ( ! task . CUSTOM_SI_CUT_DATE . HasValue | | task . CUSTOM_SI_CUT_DATE . Value ! = BCReadInfo . CustomSICutDate . Value )
{
msgBuilder . Append ( $"CUSTOM_SI_CUT_DATE org={task.CUSTOM_SI_CUT_DATE} tar={BCReadInfo.CustomSICutDate.Value}##" ) ;
task . CUSTOM_SI_CUT_DATE = BCReadInfo . CustomSICutDate . Value ;
}
}
else
{
msgBuilder . Append ( $"CUSTOM_SI_CUT_DATE org={task.CUSTOM_SI_CUT_DATE} tar=null##" ) ;
task . CUSTOM_SI_CUT_DATE = null ;
}
_db . Updateable < TaskBCEntity > ( task ) . UpdateColumns ( it = > new
{
it . SI_CUT_DATE ,
it . CUSTOM_SI_CUT_DATE ,
it . VGM_CUTOFF_TIME ,
it . MANIFEST_CUT_DATE ,
it . CY_CUTOFF_TIME ,
it . MDGF_CUT_DATE ,
it . CLOSING_DATE
} ) . ExecuteCommand ( ) ;
}
_logger . LogInformation ( $"批次={batchNo} 提取待处理任务 MBLNO={task.MBL_NO} 识别完文件 有变更 结果={msgBuilder.ToString()}" ) ;
}
}
Thread . Sleep ( 500 ) ;
}
}
public void SyncServiceProjectRecord5 ( )
{
string strBody = File . ReadAllText ( "C:\\Users\\Administrator\\Desktop\\测试HTML.txt" , Encoding . UTF8 ) ;
//FileStream f = new FileStream("C:\\Users\\Administrator\\Desktop\\测试HTML.txt", FileMode.Create);
//StreamWriter r = new StreamWriter(f, Encoding.Default);
//r.WriteLine(strBody);
HtmlDocument html = new HtmlDocument ( ) ;
html . LoadHtml ( strBody ) ;
List < TransPlanHasChangeDto > list = new List < TransPlanHasChangeDto > ( ) ;
var divTopList = html . DocumentNode . SelectSingleNode ( "//div[@class='data__top']" ) ;
if ( divTopList = = null )
return ;
//先获取第一层的div
var rootDivNode = divTopList . ParentNode . ChildNodes . Where ( a = > a . Name . Equals ( "div" , StringComparison . OrdinalIgnoreCase )
& & a . Attributes . Contains ( "class" ) & & ( a . Attributes [ "class" ] . Value . Equals ( "data__top" ) | | a . Attributes [ "class" ] . Value . Equals ( "data" ) ) )
. ToList ( ) ;
//先遍历第一层子节点
for ( int i = 0 ; i < rootDivNode . Count ; i + + )
{
//先取top
if ( rootDivNode [ i ] . Attributes [ "class" ] . Value . Equals ( "data__top" , StringComparison . OrdinalIgnoreCase ) )
{
TransPlanHasChangeDto dto = new TransPlanHasChangeDto
{
From = new TransPlanHasChangeDetailDto
{
portList = new List < TransPlanHasChangePortDto > ( ) ,
dateList = new List < TransPlanHasChangeDateDto > ( ) ,
vesselList = new List < TransPlanHasChangeVesselVoynoDto > ( )
} ,
To = new TransPlanHasChangeDetailDto
{
portList = new List < TransPlanHasChangePortDto > ( ) ,
dateList = new List < TransPlanHasChangeDateDto > ( ) ,
vesselList = new List < TransPlanHasChangeVesselVoynoDto > ( )
} ,
Carrier = "MSK" ,
ContaNoList = new List < string > ( )
} ;
if ( i = = rootDivNode . Count - 1 )
{
var innerList = GetChildList ( rootDivNode [ i ] ) ;
if ( innerList ! = null & & innerList . Count > 0 )
{
list . AddRange ( innerList ) ;
}
}
else
{
#region 解析TOP
var ctnNode = rootDivNode [ i ] . SelectSingleNode ( "./table[not(contains(@class,'reason'))]/tbody/tr[1]/th[contains(@class,'last')]" ) ;
if ( ctnNode ! = null )
{
string s = ctnNode . SelectSingleNode ( "./table/tr/th/table/tbody/tr/th/table/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( s ) & & ( Regex . IsMatch ( s , "集装箱号码" ) | | Regex . IsMatch ( s , "Container\\(s\\)" ) ) )
{
string ctnStr = Regex . Match ( s , "(?<=集装箱号码).*" ) . Value ? . Trim ( ) ;
if ( string . IsNullOrWhiteSpace ( ctnStr ) )
{
ctnStr = Regex . Match ( s , "(?<=Container\\(s\\)).*" ) . Value ? . Trim ( ) ;
}
if ( ctnStr . IndexOf ( "," ) > = 0 )
{
dto . ContaNoList = ctnStr . Split ( new char [ ] { ',' } ) . Select ( a = > a . Trim ( ) ) . ToList ( ) ;
}
else
{
if ( ! string . IsNullOrWhiteSpace ( ctnStr ) )
dto . ContaNoList . Add ( ctnStr . Trim ( ) ) ;
}
}
}
Dictionary < int , string > labelDict = new Dictionary < int , string > ( ) ;
Dictionary < int , string > valDict = new Dictionary < int , string > ( ) ;
Dictionary < int , Tuple < string , string > > reasonDict = new Dictionary < int , Tuple < string , string > > ( ) ;
string lableXpath = "./table[not(contains(@class,'reason'))]/tbody/tr[1]/th[1]/table/tr[1]/" ;
var currLabel1 = rootDivNode [ i ] . SelectSingleNode ( $"{lableXpath}/th[1]/table/tbody/tr[1]/th[1]/table/tr[1]/th[1]" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currLabel1 ) )
{
labelDict . Add ( 1 , currLabel1 ) ;
}
var currLabel2Node = rootDivNode [ i ] . SelectSingleNode ( $"{lableXpath}/th[1]/table/tbody/tr[1]/th[1]/table/tr[2]/th[1]" ) ;
if ( currLabel2Node ! = null )
{
var currLabel2 = currLabel2Node . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currLabel2 ) )
{
labelDict . Add ( 2 , currLabel2 ) ;
}
}
var currValue1 = rootDivNode [ i ] . SelectSingleNode ( $"{lableXpath}/th[2]/table/tr[1]/th[1]" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currValue1 ) )
{
valDict . Add ( 1 , currValue1 ) ;
}
var currValue2Node = rootDivNode [ i ] . SelectSingleNode ( $"{lableXpath}/th[2]/table/tr[2]/th[1]" ) ;
if ( currValue2Node ! = null )
{
var currValue2 = currValue2Node . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currValue2 ) )
{
valDict . Add ( 2 , currValue2 ) ;
}
}
foreach ( KeyValuePair < int , string > kvp in labelDict )
{
if ( kvp . Value . Equals ( "订舱号" ) | | Regex . IsMatch ( kvp . Value , "Booking\\s+Number" , RegexOptions . IgnoreCase ) )
{
dto . BookingNo = valDict [ kvp . Key ] ;
}
else if ( kvp . Value . Equals ( "提单号码" ) | | Regex . IsMatch ( kvp . Value , "Bill\\s+of\\s+Lading" , RegexOptions . IgnoreCase ) )
{
dto . BillNo = valDict [ kvp . Key ] ;
}
}
string reason1 = string . Empty ;
string reason2 = string . Empty ;
bool isReasonNote = false ;
var reasonTables = rootDivNode [ i ] . SelectNodes ( "./table[contains(@class,'reason')]" ) ;
if ( reasonTables . Count > 0 )
{
for ( int k = 0 ; k < reasonTables . Count ; k + + )
{
var thFirstNode = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tbody/tr/th[contains(@class,'columns first')]" ) ;
if ( thFirstNode ! = null )
{
isReasonNote = true ;
}
if ( ! isReasonNote )
{
string s = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( s ) & & s . IndexOf ( "此订舱号派生自原单号" ) > = 0 )
{
reasonDict . Add ( k + 1 , new Tuple < string , string > ( s , Regex . Match ( s , "(?<=此订舱号派生自原单号\\:)\\?\\w+" ) . Value ? . Trim ( ) ) ) ;
}
}
else
{
var labelNode = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tbody/tr/th[contains(@class,'columns first')]" ) ;
var notesNode = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tbody/tr/th[contains(@class,'columns last')]" ) ;
string label = string . Empty ;
string notes = string . Empty ;
if ( labelNode ! = null )
{
label = labelNode . InnerText . ReplaceHtmlStr ( ) ;
}
if ( notesNode ! = null )
{
notes = notesNode . InnerText . ReplaceHtmlStr ( ) ;
}
if ( ! string . IsNullOrWhiteSpace ( notes ) )
{
reasonDict . Add ( k + 1 , new Tuple < string , string > ( label , notes ) ) ;
}
}
}
}
foreach ( KeyValuePair < int , Tuple < string , string > > kvp in reasonDict )
{
if ( Regex . IsMatch ( kvp . Value . Item1 , "此订舱号派生自原单号" , RegexOptions . IgnoreCase ) )
{
dto . OrigBillNo = kvp . Value . Item2 ;
}
else if ( Regex . IsMatch ( kvp . Value . Item1 , "((变更原因)|(Reason))" , RegexOptions . IgnoreCase ) )
{
dto . ChangeReasonNotes = kvp . Value . Item2 ;
}
}
# endregion
#region 解析DATA
//如果下一个节点是data表示后面是详情
if ( rootDivNode [ i + 1 ] . Attributes [ "class" ] . Value . Equals ( "data" , StringComparison . OrdinalIgnoreCase ) )
{
var title = rootDivNode [ i + 1 ] . SelectSingleNode ( "./table[1]/tbody/tr/th[1]/table/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
var title2 = rootDivNode [ i + 1 ] . SelectSingleNode ( "./table[2]/tbody/tr/th[1]/table/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
var title3 = rootDivNode [ i + 1 ] . SelectSingleNode ( ".//b[1]" ) ;
if ( title3 ! = null )
{
dto . PleaseNotes = title3 . InnerText . ReplaceHtmlStr ( ) ;
}
//From
if ( Regex . IsMatch ( title , "((出运计划)|(From))" , RegexOptions . IgnoreCase ) )
{
//port
var portNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[1]/tbody/tr/th[2]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( portNodes . Count = = 1 )
{
string s = portNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . portList . Add ( new TransPlanHasChangePortDto
{
Indx = 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( portNodes . Count > 1 )
{
for ( int t = 0 ; t < portNodes . Count ; t + + )
{
string s = portNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . portList . Add ( new TransPlanHasChangePortDto
{
Indx = t + 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
//date
var dateNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[1]/tbody/tr/th[3]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( dateNodes . Count = = 1 )
{
string s = dateNodes . FirstOrDefault ( ) . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . From . dateList . Add ( currInfo ) ;
}
else if ( dateNodes . Count > 1 )
{
for ( int t = 0 ; t < dateNodes . Count ; t + + )
{
string s = dateNodes [ t ] . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = t + 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . From . dateList . Add ( currInfo ) ;
}
}
//vessel
var vesselNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[1]/tbody/tr/th[4]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( vesselNodes . Count = = 1 )
{
string s = vesselNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( vesselNodes . Count > 1 )
{
for ( int t = 0 ; t < vesselNodes . Count ; t + + )
{
string s = vesselNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = t + 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
}
if ( Regex . IsMatch ( title2 , "((到达计划)|(To))" , RegexOptions . IgnoreCase ) )
{
//to
//port
var portNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[2]/tbody/tr/th[2]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( portNodes . Count = = 1 )
{
string s = portNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . portList . Add ( new TransPlanHasChangePortDto
{
Indx = 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( portNodes . Count > 1 )
{
for ( int t = 0 ; t < portNodes . Count ; t + + )
{
string s = portNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . portList . Add ( new TransPlanHasChangePortDto
{
Indx = t + 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
//date
var dateNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[2]/tbody/tr/th[3]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( dateNodes . Count = = 1 )
{
string s = dateNodes . FirstOrDefault ( ) . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . To . dateList . Add ( currInfo ) ;
}
else if ( dateNodes . Count > 1 )
{
for ( int t = 0 ; t < dateNodes . Count ; t + + )
{
string s = dateNodes [ t ] . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = t + 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . To . dateList . Add ( currInfo ) ;
}
}
//vessel
var vesselNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[2]/tbody/tr/th[4]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( vesselNodes . Count = = 1 )
{
string s = vesselNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( vesselNodes . Count > 1 )
{
for ( int t = 0 ; t < vesselNodes . Count ; t + + )
{
string s = vesselNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = t + 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
}
list . Add ( dto ) ;
}
# endregion
}
}
}
}
private List < TransPlanHasChangeDto > GetChildList ( HtmlNode node )
{
List < TransPlanHasChangeDto > list = new List < TransPlanHasChangeDto > ( ) ;
string firstBillNo = string . Empty ;
string firstBookingNo = string . Empty ;
//string firstCtnNo = string.Empty;
bool isDiv = false ;
for ( int i = 0 ; i < node . ChildNodes . Count ; i + + )
{
if ( node . ChildNodes [ i ] . Name . Equals ( "table" , StringComparison . OrdinalIgnoreCase ) )
{
var currLabel1 = node . ChildNodes [ i ] . SelectSingleNode ( $"./tbody/tr[1]/th[1]/table/tr[1]/th[1]/table/tbody/tr[1]/th[1]" ) . InnerText . ReplaceHtmlStr ( ) ;
var currValue2Node = node . ChildNodes [ i ] . SelectSingleNode ( "./tbody/tr[1]/th[1]/table/tr[1]/th[1]/table/tbody/tr[1]/th[2]" ) ;
if ( ! string . IsNullOrWhiteSpace ( currLabel1 ) )
{
if ( currLabel1 . Equals ( "订舱号" ) | | Regex . IsMatch ( currLabel1 , "Booking\\s+Number" , RegexOptions . IgnoreCase ) )
{
if ( currValue2Node ! = null )
{
firstBookingNo = currValue2Node . InnerText . ReplaceHtmlStr ( ) ;
}
}
else if ( currLabel1 . Equals ( "提单号码" ) | | Regex . IsMatch ( currLabel1 , "Bill\\s+of\\s+Lading" , RegexOptions . IgnoreCase ) )
{
if ( currValue2Node ! = null )
{
firstBillNo = currValue2Node . InnerText . ReplaceHtmlStr ( ) ;
}
}
}
break ;
}
else
{
if ( node . ChildNodes [ i ] . Name . Equals ( "div" , StringComparison . OrdinalIgnoreCase ) )
isDiv = true ;
}
}
//先获取第一层的div
var rootDivNode = node . ChildNodes . Where ( a = > a . Name . Equals ( "div" , StringComparison . OrdinalIgnoreCase )
& & a . Attributes . Contains ( "class" ) & & ( a . Attributes [ "class" ] . Value . Equals ( "data__top" ) | | a . Attributes [ "class" ] . Value . Equals ( "data" ) ) )
. ToList ( ) ;
for ( int i = 0 ; i < rootDivNode . Count ; i + + )
{
//先取top
if ( rootDivNode [ i ] . Attributes [ "class" ] . Value . Equals ( "data__top" , StringComparison . OrdinalIgnoreCase ) )
{
TransPlanHasChangeDto dto = new TransPlanHasChangeDto
{
From = new TransPlanHasChangeDetailDto
{
portList = new List < TransPlanHasChangePortDto > ( ) ,
dateList = new List < TransPlanHasChangeDateDto > ( ) ,
vesselList = new List < TransPlanHasChangeVesselVoynoDto > ( )
} ,
To = new TransPlanHasChangeDetailDto
{
portList = new List < TransPlanHasChangePortDto > ( ) ,
dateList = new List < TransPlanHasChangeDateDto > ( ) ,
vesselList = new List < TransPlanHasChangeVesselVoynoDto > ( )
} ,
Carrier = "MSK" ,
ContaNoList = new List < string > ( )
} ;
if ( i = = rootDivNode . Count - 1 )
{
var innerList = GetChildList ( rootDivNode [ i ] ) ;
if ( innerList ! = null & & innerList . Count > 0 )
{
list . AddRange ( innerList ) ;
}
}
else
{
#region 解析TOP
var ctnNode = rootDivNode [ i ] . SelectSingleNode ( "./table[not(contains(@class,'reason'))]/tbody/tr[1]/th[contains(@class,'last')]" ) ;
if ( ctnNode ! = null )
{
string s = ctnNode . SelectSingleNode ( "./table/tr/th/table/tbody/tr/th/table/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( s ) & & ( Regex . IsMatch ( s , "集装箱号码" ) | | Regex . IsMatch ( s , "Container\\(s\\)" ) ) )
{
string ctnStr = Regex . Match ( s , "(?<=集装箱号码).*" ) . Value ? . Trim ( ) ;
if ( string . IsNullOrWhiteSpace ( ctnStr ) )
{
ctnStr = Regex . Match ( s , "(?<=Container\\(s\\)).*" ) . Value ? . Trim ( ) ;
}
if ( ctnStr . IndexOf ( "," ) > = 0 )
{
dto . ContaNoList = ctnStr . Split ( new char [ ] { ',' } ) . Select ( a = > a . Trim ( ) ) . ToList ( ) ;
}
else
{
if ( ! string . IsNullOrWhiteSpace ( ctnStr ) )
dto . ContaNoList . Add ( ctnStr . Trim ( ) ) ;
}
}
}
Dictionary < int , string > labelDict = new Dictionary < int , string > ( ) ;
Dictionary < int , string > valDict = new Dictionary < int , string > ( ) ;
Dictionary < int , Tuple < string , string > > reasonDict = new Dictionary < int , Tuple < string , string > > ( ) ;
string lableXpath = "./table[not(contains(@class,'reason'))]/tbody/tr[1]/th[1]/table/tr[1]/" ;
var currLabel1 = rootDivNode [ i ] . SelectSingleNode ( $"{lableXpath}/th[1]/table/tbody/tr[1]/th[1]" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currLabel1 ) )
{
labelDict . Add ( 1 , currLabel1 ) ;
}
var currLabel2Node = rootDivNode [ i ] . SelectSingleNode ( "./table[not(contains(@class,'reason'))]/tbody/tr[1]/th[1]/table/tbody/tr[1]/th[1]/table/tr[2]/th[1]" ) ;
if ( currLabel2Node ! = null )
{
var currLabel2 = currLabel2Node . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currLabel2 ) )
{
labelDict . Add ( 2 , currLabel2 ) ;
}
}
var currValue1 = rootDivNode [ i ] . SelectSingleNode ( $"{lableXpath}/th[2]/table/tr[1]/th[1]" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currValue1 ) )
{
valDict . Add ( 1 , currValue1 ) ;
}
var currValue2Node = rootDivNode [ i ] . SelectSingleNode ( "./table[not(contains(@class,'reason'))]/tbody/tr[1]/th[1]/table/tbody/tr[1]/th[2]/table/tr[2]/th[1]" ) ;
if ( currValue2Node ! = null )
{
var currValue2 = currValue2Node . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( currValue2 ) )
{
valDict . Add ( 2 , currValue2 ) ;
}
}
foreach ( KeyValuePair < int , string > kvp in labelDict )
{
if ( kvp . Value . Equals ( "订舱号" ) | | Regex . IsMatch ( kvp . Value , "Booking\\s+Number" , RegexOptions . IgnoreCase ) )
{
dto . BookingNo = valDict [ kvp . Key ] ;
}
else if ( kvp . Value . Equals ( "提单号码" ) | | Regex . IsMatch ( kvp . Value , "Bill\\s+of\\s+Lading" , RegexOptions . IgnoreCase ) )
{
if ( Regex . IsMatch ( valDict [ kvp . Key ] , "BL\\s+number\\s+not\\s+yet\\s+generated" , RegexOptions . IgnoreCase ) )
{
dto . BillNotes = valDict [ kvp . Key ] ;
if ( i = = 0 )
{
dto . BillNo = firstBillNo ;
}
}
else
{
dto . BillNo = valDict [ kvp . Key ] ;
}
}
}
string reason1 = string . Empty ;
string reason2 = string . Empty ;
bool isReasonNote = false ;
var reasonTables = rootDivNode [ i ] . SelectNodes ( "./table[contains(@class,'reason')]" ) ;
if ( reasonTables . Count > 0 )
{
for ( int k = 0 ; k < reasonTables . Count ; k + + )
{
var thFirstNode = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tbody/tr/th[contains(@class,'columns first')]" ) ;
if ( thFirstNode ! = null )
{
isReasonNote = true ;
}
if ( ! isReasonNote )
{
string s = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
if ( ! string . IsNullOrWhiteSpace ( s ) & & s . IndexOf ( "此订舱号派生自原单号" ) > = 0 )
{
reasonDict . Add ( k + 1 , new Tuple < string , string > ( s , Regex . Match ( s , "(?<=此订舱号派生自原单号\\:)\\?\\w+" ) . Value ? . Trim ( ) ) ) ;
}
}
else
{
var labelNode = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tbody/tr/th[contains(@class,'columns first')]" ) ;
var notesNode = rootDivNode [ i ] . SelectSingleNode ( "./table[contains(@class,'reason')][" + ( k + 1 ) + "]/tbody/tr/th[contains(@class,'columns last')]" ) ;
string label = string . Empty ;
string notes = string . Empty ;
if ( labelNode ! = null )
{
label = labelNode . InnerText . ReplaceHtmlStr ( ) ;
}
if ( notesNode ! = null )
{
notes = notesNode . InnerText . ReplaceHtmlStr ( ) ;
}
if ( ! string . IsNullOrWhiteSpace ( notes ) )
{
reasonDict . Add ( k + 1 , new Tuple < string , string > ( label , notes ) ) ;
}
}
}
}
foreach ( KeyValuePair < int , Tuple < string , string > > kvp in reasonDict )
{
if ( Regex . IsMatch ( kvp . Value . Item1 , "此订舱号派生自原单号" , RegexOptions . IgnoreCase ) )
{
dto . OrigBillNo = kvp . Value . Item2 ;
}
else if ( Regex . IsMatch ( kvp . Value . Item1 , "((变更原因)|(Reason))" , RegexOptions . IgnoreCase ) )
{
dto . ChangeReasonNotes = kvp . Value . Item2 ;
}
}
# endregion
#region 解析DATA
//如果下一个节点是data表示后面是详情
if ( rootDivNode [ i + 1 ] . Attributes [ "class" ] . Value . Equals ( "data" , StringComparison . OrdinalIgnoreCase ) )
{
var title = rootDivNode [ i + 1 ] . SelectSingleNode ( "./table[1]/tbody/tr/th[1]/table/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
var title2 = rootDivNode [ i + 1 ] . SelectSingleNode ( "./table[2]/tbody/tr/th[1]/table/tr/th" ) . InnerText . ReplaceHtmlStr ( ) ;
var title3 = rootDivNode [ i + 1 ] . SelectSingleNode ( ".//b[1]" ) ;
if ( title3 ! = null )
{
dto . PleaseNotes = title3 . InnerText . ReplaceHtmlStr ( ) ;
}
//From
if ( Regex . IsMatch ( title , "((出运计划)|(From))" , RegexOptions . IgnoreCase ) )
{
//port
var portNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[1]/tbody/tr/th[2]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( portNodes . Count = = 1 )
{
string s = portNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . portList . Add ( new TransPlanHasChangePortDto
{
Indx = 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( portNodes . Count > 1 )
{
for ( int t = 0 ; t < portNodes . Count ; t + + )
{
string s = portNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . portList . Add ( new TransPlanHasChangePortDto
{
Indx = t + 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
//date
var dateNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[1]/tbody/tr/th[3]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( dateNodes . Count = = 1 )
{
string s = dateNodes . FirstOrDefault ( ) . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . From . dateList . Add ( currInfo ) ;
}
else if ( dateNodes . Count > 1 )
{
for ( int t = 0 ; t < dateNodes . Count ; t + + )
{
string s = dateNodes [ t ] . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = t + 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . From . dateList . Add ( currInfo ) ;
}
}
//vessel
var vesselNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[1]/tbody/tr/th[4]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( vesselNodes . Count = = 1 )
{
string s = vesselNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( vesselNodes . Count > 1 )
{
for ( int t = 0 ; t < vesselNodes . Count ; t + + )
{
string s = vesselNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . From . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = t + 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
}
if ( Regex . IsMatch ( title2 , "((到达计划)|(To))" , RegexOptions . IgnoreCase ) )
{
//to
//port
var portNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[2]/tbody/tr/th[2]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( portNodes . Count = = 1 )
{
string s = portNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . portList . Add ( new TransPlanHasChangePortDto
{
Indx = 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( portNodes . Count > 1 )
{
for ( int t = 0 ; t < portNodes . Count ; t + + )
{
string s = portNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . portList . Add ( new TransPlanHasChangePortDto
{
Indx = t + 1 ,
PortName = currArg [ 0 ] . Trim ( ) ,
IsRemoved = portNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
CountryCode = currArg [ 1 ] . Trim ( ) ,
TerminalName = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
//date
var dateNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[2]/tbody/tr/th[3]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( dateNodes . Count = = 1 )
{
string s = dateNodes . FirstOrDefault ( ) . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . To . dateList . Add ( currInfo ) ;
}
else if ( dateNodes . Count > 1 )
{
for ( int t = 0 ; t < dateNodes . Count ; t + + )
{
string s = dateNodes [ t ] . InnerText ;
var currInfo = new TransPlanHasChangeDateDto
{
Indx = t + 1 ,
OrigDateTxt = s ,
IsRemoved = dateNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
} ;
DateTime currDate = DateTime . MinValue ;
if ( ! string . IsNullOrWhiteSpace ( s ) )
{
if ( DateTime . TryParse ( s , out currDate ) )
currInfo . DateVal = currDate ;
}
dto . To . dateList . Add ( currInfo ) ;
}
}
//vessel
var vesselNodes = rootDivNode [ i + 1 ] . SelectNodes ( "./table[2]/tbody/tr/th[4]/table/tr/th//div[contains(@class,'remove') or contains(@class,'updated') or contains(@class,'no-change')]" ) ;
if ( vesselNodes . Count = = 1 )
{
string s = vesselNodes . FirstOrDefault ( ) . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ 0 ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
else if ( vesselNodes . Count > 1 )
{
for ( int t = 0 ; t < vesselNodes . Count ; t + + )
{
string s = vesselNodes [ t ] . InnerText ;
var currArg = s . Split ( new char [ ] { ',' } ) ;
dto . To . vesselList . Add ( new TransPlanHasChangeVesselVoynoDto
{
Indx = t + 1 ,
Vessel = currArg [ 0 ] . Trim ( ) ,
IsRemoved = vesselNodes [ t ] . Attributes [ "class" ] . Value . Equals ( "remove" , StringComparison . OrdinalIgnoreCase ) ,
Voyno = currArg [ 1 ] . Trim ( ) ,
Flag = currArg [ 2 ] . Trim ( ) ,
} ) ;
}
}
}
list . Add ( dto ) ;
}
# endregion
}
}
}
return list ;
}
#region 读BC详情详情
/// <summary>
/// 读BC详情详情
/// </summary>
/// <param name="attachFullName">文件完整路径</param>
/// <param name="fileName">文件名称</param>
/// <param name="tenantId">所属租户</param>
/// <param name="taskPKId">任务ID</param>
/// <param name="url">请求URL</param>
/// <returns></returns>
private async Task < TaskBCInfoReadDto > GetBCReaderInfo ( string attachFullName , string fileName , long tenantId , string taskPKId , string url )
{
TaskBCInfoReadDto taskBCInfoReadDto = null ;
try
{
DateTime nowDate = DateTime . Now ;
EmailBCReadMessageInfo messageInfo = new EmailBCReadMessageInfo
{
Head = new TaskMessageHead
{
GID = IDGen . NextID ( ) . ToString ( ) ,
MessageType = "BOOKING_AMENDMENT" ,
SenderId = "DJY" ,
SenderName = "新大简云" ,
ReceiverId = "RulesEngine" ,
ReceiverName = "大简云规则引擎" ,
Version = "1.0" ,
RequestDate = nowDate . ToString ( "yyyy-MM-dd HH:mm:ss" ) ,
RequestAction = "ReadFile" ,
} ,
Main = new EmailBCReadMessageMainInfo
{
TenantId = tenantId > 0 ? tenantId . ToString ( ) : ""
}
} ;
NameValueCollection par = new NameValueCollection ( ) ;
par . Add ( "jsonData" , JSON . Serialize ( messageInfo ) ) ;
//解析BookingAmendment
var compareRlt = await ExcuteReadFile ( par , url , new
{
file = "file" ,
fileName = fileName ,
fileBytes = File . ReadAllBytes ( attachFullName )
} ) ;
_logger . LogInformation ( $"读取BC附件详情 taskPKId={taskPKId}, compareRlt={JSON.Serialize(compareRlt)}" ) ;
if ( compareRlt . succ )
{
taskBCInfoReadDto = JSON . Deserialize < TaskBCInfoReadDto > ( JSON . Serialize ( compareRlt . extra ) ) ;
}
}
catch ( Exception ex )
{
_logger . LogError ( $"读取BC附件详情异常, 原因: {ex.Message}" ) ;
}
return taskBCInfoReadDto ;
}
# endregion
#region 请求BookingAmendment解析
/// <summary>
/// 请求BookingAmendment解析
/// </summary>
/// <param name="nameValueCollection">请求参数</param>
/// <param name="url">请求url</param>
/// <param name="fileInfo">文件</param>
/// <param name="contentType">请求类型</param>
/// <returns>返回回执</returns>
[NonAction]
private async Task < ParserReaderExcuteResultDto > ExcuteReadFile ( NameValueCollection nameValueCollection , string url , dynamic fileInfo ,
string contentType = "application/json" )
{
ParserReaderExcuteResultDto model = null ;
var result = string . Empty ;
using ( var httpClient = new HttpClient ( ) )
{
try
{
using ( var reduceAttach = new MultipartFormDataContent ( ) )
{
string [ ] allKeys = nameValueCollection . AllKeys ;
foreach ( string key in allKeys )
{
var dataContent = new ByteArrayContent ( Encoding . UTF8 . GetBytes ( nameValueCollection [ key ] ) ) ;
dataContent . Headers . ContentDisposition = new ContentDispositionHeaderValue ( $"form-data" )
{
Name = key
} ;
reduceAttach . Add ( dataContent ) ;
}
#region 文件参数
if ( fileInfo ! = null )
{
var Content = new ByteArrayContent ( fileInfo . fileBytes ) ;
//Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
//{
// Name = fileInfo.file.ToString(),
// FileName = fileInfo.fileName.ToString(),
//};
Content . Headers . Add ( "Content-Type" , contentType ) ;
reduceAttach . Add ( Content , fileInfo . file . ToString ( ) , HttpUtility . UrlEncode ( fileInfo . fileName . ToString ( ) ) ) ;
}
# endregion
//httpClient.DefaultRequestHeaders.Add("USER_KEY", App.Configuration["ApiUserKey"]);
//httpClient.DefaultRequestHeaders.Add("USER_SECRET", App.Configuration["ApiUserSecret"]);
//请求
var response = httpClient . PostAsync ( url , reduceAttach ) . Result ;
result = response . Content . ReadAsStringAsync ( ) . Result ;
model = JSON . Deserialize < ParserReaderExcuteResultDto > ( result ) ;
}
}
catch ( Exception ex )
{
_logger . LogInformation ( "请求读取BC附件详情读取详情异常, 原因: {error}" , ex . Message ) ;
throw Oops . Oh ( $"请求读取BC附件详情读取详情异常, 原因: {ex.Message}" ) ;
}
}
return model ;
}
# endregion
public class EmailBCReadMessageInfo
{
/// <summary>
/// 表头
/// </summary>
public TaskMessageHead Head { get ; set ; }
/// <summary>
/// 表体
/// </summary>
public EmailBCReadMessageMainInfo Main { get ; set ; }
}
public class EmailBCReadMessageMainInfo
{
/// <summary>
/// 所属租户ID
/// </summary>
public string TenantId { get ; set ; }
}
public class TaskMessageHead : WebAPIHeadBase
{
}
public class WebAPIHeadBase
{
/// <summary>
/// 报文惟一主键
/// </summary>
/// <example>08dab66c-96a1-4f90-8606-2626e06202ad</example>
[Required(ErrorMessage = "必填")]
public string GID { get ; set ; }
/// <summary>
/// 报文类型 BUSI_RULE-业务规则校验
/// </summary>
/// <example>BUSI_RULE</example>
[Required(ErrorMessage = "必填")]
public string MessageType { get ; set ; }
/// <summary>
/// 发送方代码
/// </summary>
/// <example>CUSTOMER1</example>
[Required(ErrorMessage = "必填")]
public string SenderId { get ; set ; }
/// <summary>
/// 发送方名称
/// </summary>
/// <example>企业A</example>
[Required(ErrorMessage = "必填")]
public string SenderName { get ; set ; }
/// <summary>
/// 接收方代码
/// </summary>
/// <example>RulesEngine</example>
[Required(ErrorMessage = "必填")]
public string ReceiverId { get ; set ; }
/// <summary>
/// 接收方名称
/// </summary>
/// <example>大简云规则引擎</example>
[Required(ErrorMessage = "必填")]
public string ReceiverName { get ; set ; }
/// <summary>
/// 请求方登录TOKEN( 可以是真实的登录人TOKEN或者是服务模拟登录人TOKEN)
/// </summary>
/// <example>eyJhbGciOiJSUzI1NiIsImtpZCI6IkQ1RTkxMDI5OUU0RURFNUZEM0EwNTJBMEFDRDUzMUQzIiwidHlwIjoiYXQrand0In0</example>
public string Token { get ; set ; }
/// <summary>
/// 版本号 默认1.0
/// </summary>
/// <example>1.0</example>
[Required(ErrorMessage = "必填")]
public string Version { get ; set ; } = "1.0" ;
/// <summary>
/// 请求时间
/// </summary>
/// <example>2022-10-10 10:00:00</example>
public string RequestDate { get ; set ; }
/// <summary>
/// 请求操作类型
/// </summary>
/// <example>Add</example>
[Required(ErrorMessage = "必填")]
public string RequestAction { get ; set ; } = "Add" ;
}
}
public class ParserReaderExcuteResultDto
{
/// <summary>
/// 是否成功 true=成功 false=失败
/// </summary>
public bool succ { get ; set ; } = false ;
/// <summary>
/// 状态 0-成功
/// </summary>
public int status { get ; set ; } = 0 ;
/// <summary>
/// 返回消息
/// </summary>
public string msg { get ; set ; }
/// <summary>
/// 总记录数
/// </summary>
public int total { get ; set ; }
/// <summary>
/// 当前页列表数据
/// </summary>
public object rows { get ; set ; }
/// <summary>
/// 合计信息
/// </summary>
public object summary { get ; set ; }
/// <summary>
/// 扩展信息
/// </summary>
public object extra { get ; set ; }
/// <summary>
/// 扩展信息2
/// </summary>
public object extra2 { get ; set ; }
/// <summary>
/// 扩展信息场站统计
/// </summary>
public object yardStatInfo { get ; set ; }
/// <summary>
/// 是否异常
/// </summary>
public bool exceptionflag { get ; set ; }
/// <summary>
/// 生成HTML
/// </summary>
public string ResultHtml { get ; set ; }
}
/// <summary>
///
/// </summary>
public class TaskBCInfoReadDto
{
/// <summary>
/// 订舱单位
/// </summary>
public string BookingParty { get ; set ; }
/// <summary>
/// 发货人
/// </summary>
public string Shipper { get ; set ; }
/// <summary>
/// 收货人
/// </summary>
public string Consignee { get ; set ; }
/// <summary>
/// 通知人
/// </summary>
public string NotifyParty { get ; set ; }
/// <summary>
/// BC更新次数
/// </summary>
public Nullable < int > BCModifyTimes { get ; set ; }
/// <summary>
/// BC更新时间
/// </summary>
public Nullable < DateTime > BCModifyDate { get ; set ; }
/// <summary>
/// 主单号
/// </summary>
public string MBLNo { get ; set ; }
/// <summary>
/// 船名
/// </summary>
public string Vessel { get ; set ; }
/// <summary>
/// 航次
/// </summary>
public string VoyNo { get ; set ; }
/// <summary>
/// 船公司
/// </summary>
public string Carrier { get ; set ; }
/// <summary>
/// 收货地
/// </summary>
public string PlaceReceipt { get ; set ; }
/// <summary>
/// 装货港
/// </summary>
public string Portload { get ; set ; }
/// <summary>
/// 截关时间
/// </summary>
public Nullable < DateTime > ClosingDate { get ; set ; }
/// <summary>
/// 截VGM时间
/// </summary>
public Nullable < DateTime > VGMCutoffTime { get ; set ; }
/// <summary>
/// ETA(预计到港时间)
/// </summary>
public Nullable < DateTime > ETA { get ; set ; }
/// <summary>
/// ETD(预计离港时间)
/// </summary>
public Nullable < DateTime > ETD { get ; set ; }
/// <summary>
/// 目的港ETA
/// </summary>
public Nullable < DateTime > PODETA { get ; set ; }
/// <summary>
/// 截单时间
/// </summary>
public Nullable < DateTime > CutSingleTime { get ; set ; }
/// <summary>
/// 卸货港
/// </summary>
public string PortDischarge { get ; set ; }
/// <summary>
/// 交货地
/// </summary>
public string PlaceDelivery { get ; set ; }
/// <summary>
/// 装运方式
/// </summary>
public string ShippingMethod { get ; set ; }
/// <summary>
/// 运输条款
/// </summary>
public string Service { get ; set ; }
/// <summary>
/// 港前运输形态
/// </summary>
public string PreTransMode { get ; set ; }
/// <summary>
/// 品名
/// </summary>
public string Description { get ; set ; }
/// <summary>
/// 签单地点
/// </summary>
public string IssuePlace { get ; set ; }
/// <summary>
/// 集港码头
/// </summary>
public string CollectionTerminal { get ; set ; }
/// <summary>
/// 约号
/// </summary>
public string ContractNo { get ; set ; }
/// <summary>
/// 预付地点
/// </summary>
public string PrepardAT { get ; set ; }
/// <summary>
/// 船代
/// </summary>
public string ShipAgent { get ; set ; }
/// <summary>
/// 场站
/// </summary>
public string Yard { get ; set ; }
/// <summary>
/// 场站联系人
/// </summary>
public string YardContactUserName { get ; set ; }
/// <summary>
/// 场站联系电话
/// </summary>
public string YardContactTel { get ; set ; }
/// <summary>
/// 一代客服姓名
/// </summary>
public string FstCustomerSerUserName { get ; set ; }
/// <summary>
/// 一代客服电话
/// </summary>
public string FstCustomerSerUserTel { get ; set ; }
/// <summary>
/// 一代客服邮箱
/// </summary>
public string FstCustomerSerUserEmail { get ; set ; }
/// <summary>
/// 备注1
/// </summary>
public string Remark1 { get ; set ; }
/// <summary>
/// 截港时间
/// </summary>
public Nullable < DateTime > CYCutoffTime { get ; set ; }
/// <summary>
/// 状态 TEMP-暂存 SUCC-已对应 ERROR-异常
/// </summary>
public string Status { get ; set ; }
/// <summary>
/// 文件MD5
/// </summary>
public string FileMD5 { get ; set ; }
/// <summary>
/// 最后对应时间,最后关联到订舱日期
/// </summary>
public Nullable < DateTime > LastToBookingDate { get ; set ; }
/// <summary>
/// 来源邮箱
/// </summary>
public string FromEmail { get ; set ; }
/// <summary>
/// 接收邮箱
/// </summary>
public string RecvEmail { get ; set ; }
/// <summary>
/// 订舱ID, 对应成功后, 订舱ID写入
/// </summary>
public Nullable < long > BookingOrderId { get ; set ; }
/// <summary>
/// 集装箱列表
/// </summary>
public List < TaskBCInfoReadCtnDto > CtnList { get ; set ; }
/// <summary>
/// 顺序号
/// </summary>
public int Indx { get ; set ; }
/// <summary>
/// 对应订舱序号
/// </summary>
public int BKOrderIndx { get ; set ; }
/// <summary>
/// 舱位主键
/// </summary>
public Nullable < long > BookingSlotId { get ; set ; }
/// <summary>
/// 船公司代号
/// </summary>
public string CarrierId { get ; set ; }
/// <summary>
/// 航线代码(船公司)
/// </summary>
public string LaneCode { get ; set ; }
/// <summary>
/// 航线名称(船公司)
/// </summary>
public string LaneName { get ; set ; }
/// <summary>
/// 承运方式 DIRECT_SHIP-直达; TRANSFER_SHIP-中转
/// </summary>
public string CarriageType { get ; set ; }
/// <summary>
/// 承运方式名称 DIRECT_SHIP-直达; TRANSFER_SHIP-中转
/// </summary>
public string CarriageTypeName { get ; set ; }
/// <summary>
/// 订舱方式 CONTRACT_ORDER-合约订舱; SPOT_ORDER-SPOT订舱
/// </summary>
public string BookingSlotType { get ; set ; }
/// <summary>
/// 订舱方式名称 CONTRACT_ORDER-合约订舱; SPOT_ORDER-SPOT订舱
/// </summary>
public string BookingSlotTypeName { get ; set ; }
/// <summary>
/// 箱型箱量
/// </summary>
public string CtnStat { get ; set ; }
/// <summary>
/// 所在周数
/// </summary>
public string WeekAt { get ; set ; }
/// <summary>
/// 箱使天数
/// </summary>
public int DetensionFreeDays { get ; set ; }
/// <summary>
/// 样单截止日期
/// </summary>
public Nullable < DateTime > SICutDate { get ; set ; }
/// <summary>
/// 舱单截止时间
/// </summary>
public Nullable < DateTime > ManifestCutDate { get ; set ; }
/// <summary>
/// MDGF提交截止时间
/// </summary>
public Nullable < DateTime > MDGFCutDate { get ; set ; }
/// <summary>
/// 中转港1
/// </summary>
public string TransferPort1 { get ; set ; }
/// <summary>
/// 中转港2
/// </summary>
public string TransferPort2 { get ; set ; }
/// <summary>
/// 二程船名
/// </summary>
public string SecondVessel { get ; set ; }
/// <summary>
/// 二程航次
/// </summary>
public string SecondVoyno { get ; set ; }
/// <summary>
/// 二程ETD
/// </summary>
public Nullable < DateTime > SecondETD { get ; set ; }
/// <summary>
/// 二程ETA
/// </summary>
public Nullable < DateTime > SecondETA { get ; set ; }
/// <summary>
/// 订舱确认时间
/// </summary>
public Nullable < DateTime > BookingConfirmDate { get ; set ; }
/// <summary>
/// 客户样单截止日期
/// </summary>
public Nullable < DateTime > CustomSICutDate { get ; set ; }
}
/// <summary>
/// 任务BC集装箱
/// </summary>
public class TaskBCInfoReadCtnDto
{
/// <summary>
/// 箱型代码
/// </summary>
public string CtnCode { get ; set ; }
/// <summary>
/// 箱型
/// </summary>
public string CtnALL { get ; set ; }
/// <summary>
/// 箱量
/// </summary>
public Nullable < int > CTNNUM { get ; set ; }
/// <summary>
/// 件数
/// </summary>
public Nullable < int > PKGS { get ; set ; }
/// <summary>
/// 尺码
/// </summary>
public Nullable < decimal > CBM { get ; set ; }
/// <summary>
/// 毛重
/// </summary>
public Nullable < decimal > KGS { get ; set ; }
/// <summary>
/// 皮重
/// </summary>
public Nullable < decimal > TareWeight { get ; set ; }
/// <summary>
/// 危品票标示
/// </summary>
public string IODGT { get ; set ; }
/// <summary>
/// 特殊装载需求
/// </summary>
public string SpecialLoadingRequire { get ; set ; }
/// <summary>
/// 提箱场站
/// </summary>
public string TakeCTNYard { get ; set ; }
/// <summary>
/// 提箱时间
/// </summary>
public Nullable < DateTime > TakeCTNTime { get ; set ; }
/// <summary>
/// 还箱场站
/// </summary>
public string ReturnCTNYard { get ; set ; }
}
/// <summary>
/// MSK 您的货物运输计划已变更
/// </summary>
public class TransPlanHasChangeDto
{
/// <summary>
/// 订舱编号
/// </summary>
public string BookingNo { get ; set ; }
/// <summary>
/// 船公司代码
/// </summary>
public string Carrier { get ; set ; }
/// <summary>
/// 提单号码
/// </summary>
public string BillNo { get ; set ; }
/// <summary>
/// 派生自原单号
/// </summary>
public string OrigBillNo { get ; set ; }
/// <summary>
/// 集装箱号列表
/// </summary>
public List < string > ContaNoList { get ; set ; }
/// <summary>
/// 变更原因
/// </summary>
public string ChangeReasonNotes { get ; set ; }
/// <summary>
/// 出运计划
/// </summary>
public TransPlanHasChangeDetailDto From { get ; set ; }
/// <summary>
/// 到达计划
/// </summary>
public TransPlanHasChangeDetailDto To { get ; set ; }
/// <summary>
/// 特别提示
/// </summary>
public string PleaseNotes { get ; set ; }
/// <summary>
/// 提单号特殊提示
/// </summary>
public string BillNotes { get ; set ; }
}
/// <summary>
/// 您的货物运输计划已变更明细
/// </summary>
public class TransPlanHasChangeDetailDto
{
/// <summary>
/// 港口变更明细
/// </summary>
public List < TransPlanHasChangePortDto > portList { get ; set ; }
/// <summary>
/// 日期变更明细( ETD或者ATD)
/// </summary>
public List < TransPlanHasChangeDateDto > dateList { get ; set ; }
/// <summary>
/// 船名航次变更
/// </summary>
public List < TransPlanHasChangeVesselVoynoDto > vesselList { get ; set ; }
}
/// <summary>
/// 您的货物运输计划已变更-港口
/// </summary>
public class TransPlanHasChangePortDto
{
/// <summary>
/// 顺序号
/// </summary>
public int Indx { get ; set ; }
/// <summary>
/// 港口名
/// </summary>
public string PortName { get ; set ; }
/// <summary>
/// 国家
/// </summary>
public string CountryCode { get ; set ; }
/// <summary>
/// 码头
/// </summary>
public string TerminalName { get ; set ; }
/// <summary>
/// 是否被作废掉了
/// </summary>
public bool IsRemoved { get ; set ; } = false ;
}
/// <summary>
/// 您的货物运输计划已变更-日期
/// </summary>
public class TransPlanHasChangeDateDto
{
/// <summary>
/// 顺序号
/// </summary>
public int Indx { get ; set ; }
/// <summary>
/// 提取日期文本
/// </summary>
public string OrigDateTxt { get ; set ; }
/// <summary>
/// 日期
/// </summary>
public DateTime DateVal { get ; set ; }
/// <summary>
/// 是否被作废掉了
/// </summary>
public bool IsRemoved { get ; set ; } = false ;
}
/// <summary>
/// 您的货物运输计划已变更-船名航次
/// </summary>
public class TransPlanHasChangeVesselVoynoDto
{
/// <summary>
/// 顺序号
/// </summary>
public int Indx { get ; set ; }
/// <summary>
/// 船名
/// </summary>
public string Vessel { get ; set ; }
/// <summary>
/// 航次
/// </summary>
public string Voyno { get ; set ; }
/// <summary>
/// 船旗
/// </summary>
public string Flag { get ; set ; }
/// <summary>
/// 是否被作废掉了
/// </summary>
public bool IsRemoved { get ; set ; } = false ;
}
public static class StringUtilsExtension
{
/// <summary>
/// 格式化文件名,去掉非法字符
/// </summary>
/// <param name="inputVal">请求参数</param>
/// <returns>返回格式化表达式值</returns>
public static string FormatFileName ( this string inputVal )
{
if ( ! string . IsNullOrWhiteSpace ( inputVal ) )
return Regex . Replace ( inputVal , "\\|\\/|\\:|\\*|\\?|\\\"|\\<|\\>|\\|" , "_" ) ;
return inputVal ;
}
/// <summary>
/// 清理HTML字符
/// </summary>
/// <param name="inputVal">请求参数</param>
/// <returns>返回格式化表达式值</returns>
public static string ReplaceHtmlStr ( this string inputVal )
{
if ( ! string . IsNullOrWhiteSpace ( inputVal ) )
return Regex . Replace ( Regex . Replace ( inputVal , "\\ \\;" , " " ) , "\\s{2,}" , " " ) ? . Trim ( ) ;
return inputVal ;
}
}