@idm-plugin/vessel 1.5.8 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +711 -517
- package/dist/index.umd.cjs +1 -1
- package/dist/speed/src/index.d.ts +119 -33
- package/package.json +2 -2
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(k,S){typeof exports=="object"&&typeof module<"u"?S(exports,require("got"),require("@log4js-node/log4js-api"),require("moment"),require("@idm-plugin/geo"),require("@idm-plugin/meteo2"),require("@idm-plugin/meteo")):typeof define=="function"&&define.amd?define(["exports","got","@log4js-node/log4js-api","moment","@idm-plugin/geo","@idm-plugin/meteo2","@idm-plugin/meteo"],S):(k=typeof globalThis<"u"?globalThis:k||self,S(k["idm-plugin-rabbitmq"]={},k.got,k["@log4js-node/log4js-api"],k.moment,k["@idm-plugin/geo"],k["@idm-plugin/meteo2"],k["@idm-plugin/meteo"]))})(this,function(k,S,Z,g,O,G,U){"use strict";var mt=Object.defineProperty;var pt=(k,S,Z)=>S in k?mt(k,S,{enumerable:!0,configurable:!0,writable:!0,value:Z}):k[S]=Z;var K=(k,S,Z)=>(pt(k,typeof S!="symbol"?S+"":S,Z),Z);let h;try{h=Z.getLogger("vessel")}catch{}finally{}class z{parseStatus(s){let t,i;switch(s){case 0:t="在航(主机推动)",i="The engine is in use";break;case 1:t="锚泊",i="Anchored";break;case 2:t="失控",i="Not operated";break;case 3:t="操纵受限",i="Limited airworthiness";break;case 4:t="吃水受限",i="Limited by ship's draft";break;case 5:t="靠泊",i="Mooring";break;case 6:t="搁浅",i="Stranded";break;case 7:t="捕捞作业",i="Engaged in fishing";break;case 8:t="靠帆船提供动力",i="Sailing";break;default:t="未定义",i="Undefined"}return{labelCn:t,labelEn:i}}}class rt extends z{constructor(t,i){super();K(this,"clientId");K(this,"clientSecret");K(this,"token");this.clientId=t,this.clientSecret=i}async authToken(t={}){const i="https://svc.data.myvessel.cn/ada/oauth/token",n={searchParams:{client_id:this.clientId,client_secret:this.clientSecret,grant_type:"client_credentials"}},o=await S.post(i,n).json();h==null||h.info("[%s] fetch access token from: %s - %j",t.requestId,i,o),o.error||(this.token={accessToken:o.access_token,tokenType:o.token_type,expiresIn:o.expires_in,scope:o.scope,jti:o.jti,issuedAt:g().utc().format()})}async realTimePosition(t,i={}){var u,m,f;(!this.token||g().diff(g(this.token.issuedAt),"seconds")>((u=this.token)==null?void 0:u.expiresIn)-300)&&await this.authToken(i);const n="https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit",o={headers:{Authorization:`${(m=this.token)==null?void 0:m.tokenType} ${(f=this.token)==null?void 0:f.accessToken}`},searchParams:{mmsi:t}};h==null||h.info("[%s] fetch realtime position from: %s - %j",i.requestId,n,o);const a=await S.get(n,o).json();if(a.code)return h==null||h.warn("[%s] fetch realtime position failed: %j",i.requestId,n,{message:a.message,status:a.status,code:a.code}),a;const e=a.data;for(const p in e)!isNaN(e[p])&&Number(e[p])!==1/0&&(e[p]=Number(e[p]));const d=g(`${e.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:e.mmsi,name:e.vesselName,imo:e.imo,callSign:e.callsign,lat:e.lat,lng:e.lon,length:e.length,width:e.width,draught:e.currDraught,sog:e.sog,cog:e.cog,hdg:e.hdg,rot:e.rot,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e.eta)?g.utc(e.eta).format():void 0,destination:e.dest,positionTime:d.unix(),status:e.status,labelCn:e.statusNameCn,labelEn:e.statusNameEn,method:"position",vendor:"myVessel",utc:d.utc().format()}}async trajectory(t,i,n,o,a=!0,e={}){(!this.token||g().diff(g(this.token.issuedAt),"seconds")>this.token.expiresIn-300)&&await this.authToken(e);const d=await this.realTimePosition(t,e),r=g(i),u=g(n),m=[];for(;u.diff(r,"day",!0)>30;)await this.trajectoryIn30Day(t,r,r.clone().add(30,"day"),d,o,m,e),r.add(30,"day");return await this.trajectoryIn30Day(t,r,u,d,o,m,e),m}async trajectoryIn30Day(t,i,n,o,a,e,d={}){var l,w,I,v,j;const r="https://svc.data.myvessel.cn/sdc/v1/vessels/status/track",u={headers:{Authorization:`${(l=this.token)==null?void 0:l.tokenType} ${(w=this.token)==null?void 0:w.accessToken}`},json:{mmsi:t,startTime:i.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),endTime:n.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")}};h==null||h.info("[%s] fetch trajectory from: %s - %j",d.requestId,r,u);const m=await S.post(r,u).json();if(m.code)return h==null||h.warn("[%s] fetch trajectory failed: %j",d.requestId,r,{message:m.message,status:m.status,code:m.code}),m;let f=-1;const p=g(`${(v=(I=m.data)==null?void 0:I[0])==null?void 0:v.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return(j=m.data)==null||j.forEach(c=>{for(const W in c)!isNaN(c[W])&&Number(c[W])!==1/0&&(c[W]=Number(c[W]));const b=g(`${c.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00"),F=c.status,{labelCn:M,labelEn:y}=this.parseStatus(F),H={mmsi:c.mmsi,imo:o==null?void 0:o.imo,lat:c.lat,lng:c.lon,sog:c.sog,cog:c.cog,hdg:c.hdg,draught:c.draught,status:F,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(c.eta)?g(`${c.eta} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00").utc().format():void 0,destination:c.dest,positionTime:b.unix(),labelCn:M,labelEn:y,method:"trajectory",vendor:"myVessel",utc:b.utc().format()},E=Math.floor(b.diff(p,"minute",!0)/(a||1));E!==f&&(f=E,e.push(H))}),e}}class ct extends z{constructor(t){super();K(this,"token");this.token=t}async realTimePosition(t,i={}){const n="https://api.hifleet.com/position/position/get/token",o={searchParams:{mmsi:t,usertoken:this.token}},a=await S.post(n,o).json();h==null||h.info("[%s] fetch realtime position from: %s - %j",i.requestId,n,o);const e=a==null?void 0:a.list;if(!e)return h==null||h.warn("[%s] fetch realtime position failed: %j",i.requestId,n,a),a;for(const p in e)!isNaN(e[p])&&Number(e[p])!==1/0&&(e[p]=Number(e[p]));e.status=e.sp>3?0:1;const d=e.status,{labelCn:r,labelEn:u}=this.parseStatus(d),m=g(`${e.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:e.m,name:e.n,imo:e.imonumber,callSign:e.callsign,lat:Math.round(e.la/60*1e5)/1e5,lng:Math.round(e.lo/60*1e5)/1e5,length:e.l,width:e.w,draught:e.draught,sog:e.sp,cog:e.co,hdg:e.h,rot:isNaN(e.rot)?0:e.rot,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e.eta)?g.utc(e.eta).format():void 0,destination:e.destination,positionTime:m.unix(),utc:m.utc().format(),status:d,labelCn:r,labelEn:u,method:"position",vendor:"hifleet"}}async search(t,i={}){let n="https://www.hifleet.com/hifleetapi/searchVesselOL.do";const o={searchParams:{keyword:t},headers:{Referer:"https://www.hifleet.com",Origin:"https://www.hifleet.com",Host:"www.hifleet.com"}};let a=await S.post(n,o).json();h==null||h.info("[%s] fetch vessel props from: %s - %j",i.requestId,n,o),a instanceof Array&&(a=a[0]);for(const d in a)!isNaN(a[d])&&Number(a[d])!==1/0&&(a[d]=Number(a[d]));const e={mmsi:a.m,name:a.n,imo:a.i,callSign:a.c,length:a.l,breadth:a.b,draught:a.dr,type:a.t};return n="https://www.hifleet.com/hifleetapi/sameShipSearch.do",a=await S.post(n,o).json(),h==null||h.info("[%s] search vessel dead weight from: %s - %j",i.requestId,n,o),a instanceof Array&&(a=a[0]),a&&(e.deadweight=Number(a.dwt)),e}async suggest(t,i={}){const n="https://www.hifleet.com/hifleetapi/getShipSuggest.do",o={searchParams:{q:t},headers:{Referer:"https://www.hifleet.com",Origin:"https://www.hifleet.com",Host:"www.hifleet.com"}},a=await S.post(n,o).json();h==null||h.info("[%s] suggest vessel props from: %s - %j",i.requestId,n,o);const e=[];for(const d of a)e.push({mmsi:!d.mmsi||isNaN(d.mmsi)?null:Number(d.mmsi),name:d.name,callSign:d.callsign,imo:!d.imo||isNaN(d.imo)?null:Number(d.imo),score:d._score});return e.sort((d,r)=>r.score-d.score),e}async trajectory(t,i,n,o,a=!0,e={}){var c,b,F;const d=await this.realTimePosition(t,e);let r=g(i);const u=g(n),m=g();if(a){let M=u.diff(r,"d",!0);M<0?r=u.clone().subtract(40,"d"):M<30?r.subtract(10,"d"):M<60?r.subtract(5,"d"):r=u.clone().subtract(80,"d"),M=m.diff(u,"d",!0),u.add(M>10?240:M*24,"h")}const f={searchParams:{endtime:u.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),starttime:r.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),mmsi:t,usertoken:this.token}},p="https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token",l=await S.get(p,f).json();h==null||h.info("[%s] fetch trajectory from: %s - %j",e.requestId,p,f);let w;l&&(w=((b=(c=l.ships)==null?void 0:c.offors)==null?void 0:b.ship)||[],w.length||h==null||h.warn("[%s] fetch trajectory failed: %j",e.requestId,l));const I=[];let v=-1;const j=g(`${(F=w==null?void 0:w[0])==null?void 0:F.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");for(const M of w){for(const _ in M)!isNaN(M[_])&&Number(M[_])!==1/0&&(M[_]=Number(M[_]));const y=g(`${M.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");M.status=M.sp>4?0:1;const{labelEn:H,labelCn:E}=this.parseStatus(M.status),W={mmsi:M.m,name:M.n,imo:d==null?void 0:d.imo,lat:M.la,lng:M.lo,draught:M.draught,sog:M.sp,cog:M.co,hdg:M.hdg,positionTime:y.unix(),utc:y.utc().format(),status:M.status,labelCn:E,labelEn:H,method:"trajectory",vendor:"hifleet"},q=Math.floor(y.diff(j,"minute",!0)/(o||1));q!==v&&(v=q,I.push(W))}return I}}class dt extends z{constructor(t){super();K(this,"token");this.token=t}async realTimePosition(t,i={}){const n={searchParams:{id:t,k:this.token,enc:1}},o="https://api.shipxy.com/apicall/GetSingleShip",a=await S.get(o,n).json();if(h==null||h.info("[%s] fetch realtime position from: %s - %j",i.requestId,o,n),(a==null?void 0:a.status)!==0)return a;const e=a.data[0];for(const f in e)!isNaN(e[f])&&Number(e[f])!==1/0&&(e[f]=Number(e[f]));const{labelCn:d,labelEn:r}=await this.parseStatus(e.navistat),u=g.unix(e.lasttime);return{mmsi:e.ShipID,name:e.name,imo:e.imo,callSign:e.callsign,lat:Math.round(e.lat/1e6*1e5)/1e5,lng:Math.round(e.lon/1e6*1e5)/1e5,length:Math.round(e.length/10*100)/100,width:Math.round(e.width/10*100)/100,draught:Math.round(e.draught/1e3*100)/100,sog:Math.round(e.sog*3600/1e3/1852*100)/100,cog:Math.round(e.cog/100*100)/100,hdg:Math.round(e.hdg/100*100)/100,rot:Math.round(e.rot/100*100)/100,positionTime:e.lasttime,utc:u.utc().format(),status:e.navistat,labelEn:r,labelCn:d,method:"position",vendor:"shipxy"}}async trajectory(t,i,n,o,a=!0,e={}){var j;const d=await this.realTimePosition(t,e),r=g(i),u=g(n),m="https://api.shipxy.com/apicall/GetShipTrack",f={searchParams:{id:t,k:this.token,enc:1,cut:0,btm:r.unix(),etm:u.unix()}},p=await S.get(m,f).json();if(h==null||h.info("[%s] fetch trajectory from: %s - %j",e.requestId,m,f),(p==null?void 0:p.status)!==0)return p;const l=p==null?void 0:p.points,w=[],I=g.unix((j=l[0])==null?void 0:j.utc);let v=-1;for(const c of l){const b=g.unix(c.utc),F={imo:d==null?void 0:d.imo,mmsi:t,sog:Math.round(c.sog*3600/1e3/1852*100)/100,cog:Math.round(c.cog/100*100)/100,lat:Math.round(c.lat/1e6*1e5)/1e5,lng:Math.round(c.lon/1e6*1e5)/1e5,positionTime:b.unix(),utc:b.utc().format(),method:"trajectory",vendor:"shipxy"},M=Math.floor(b.diff(I,"minute",!0)/(o||1));M!==v&&(v=M,w.push(F))}return w}}class ut extends z{constructor(t){super();K(this,"token");this.token=t}async getShipId(t,i={}){const n={headers:{appKey:this.token},json:{mmsiList:t}},o="https://api3.myships.com/sp/ships/getShipIdByMMSI",a=await S.post(o,n).json();return h==null||h.info("[%s] fetch ship id from: %s - %j",i.requestId,o,n),a.code!=="0"?a:a.data[0].shipId}async getShipInfo(t,i={}){const n={headers:{appKey:this.token},json:{shipId:t}},o="https://api3.myships.com/sp/ships/aissta",a=await S.post(o,n).json();if(h==null||h.info("[%s] fetch ship info from: %s - %j",i.requestId,o,n),a.code!=="0")return a;const e=a.data;let d=e.imo;return t==="407170"&&(d="9198379",h==null||h.warn("[%s] ship(%s) imo error: %s, should be %s",i.requestId,t,e.imo,d)),{mmsi:e.mmsi,name:e.shipnameEn,imo:d,callSign:e.callSign,length:e.length,width:e.breadth,draught:(e.draught||100)/10}}async realTimePosition(t,i={}){const n=await this.getShipId(t,i),o=await this.getShipInfo(n,i),a={headers:{appKey:this.token},json:{shipId:n}},e="https://api3.myships.com/sp/ships/position/latest",d=await S.post(e,a).json();h==null||h.info("[%s] fetch realtime position from: %s - %j",i.requestId,e,a);const r=d.data[0];for(const l in r)!isNaN(r[l])&&Number(r[l])!==1/0&&(r[l]=Number(r[l]));const{labelCn:u,labelEn:m}=await this.parseStatus(r.aisNavStatus),f=g.unix(r.posTime);return{...o,mmsi:t,lat:Math.round(r.lat/1e4/60*1e5)/1e5,lng:Math.round(r.lon/1e4/60*1e5)/1e5,sog:Math.round(r.sog/10*100)/100,cog:Math.round(r.cog/10*100)/100,hdg:Math.round(r.heading*100)/100,rot:Math.round(r.rot*100)/100,positionTime:r.posTime,utc:f.utc().format(),status:r.aisNavStatus,labelEn:m,labelCn:u,method:"position",vendor:"myship"}}async trajectory(t,i,n,o,a=!0,e={}){const d=g(i),r=g(n),u=await this.getShipId(t),m=await this.getShipInfo(u),f=[];for(;r.diff(d,"day",!0)>30;)await this.trajectoryIn30Day(u,d.unix(),d.add(30,"day").unix(),m,t,o,f);return await this.trajectoryIn30Day(u,d.unix(),r.unix(),m,t,o,f),f}async trajectoryIn30Day(t,i,n,o,a,e,d,r={}){var I;const u={headers:{appKey:this.token},json:{shipId:t,startTime:i,endTime:n}},m="https://api3.myships.com/sp/ships/position/history",f=await S.post(m,u).json();if(h==null||h.info("[%s] fetch trajectory from: %s - %j",r.requestId,m,u),f.code!=="0")return h==null||h.warn("[%s] invoke myship trajectory failed: %j",r.requestId,f),f;const p=f.data;for(const v in p)!isNaN(p[v])&&Number(p[v])!==1/0&&(p[v]=Number(p[v]));const l=g.unix((I=p[0])==null?void 0:I.posTime);let w=-1;for(const v of p){const j=g.unix(v.posTime),c={imo:o==null?void 0:o.imo,mmsi:a,lat:Math.round(v.lat/1e4/60*1e5)/1e5,lng:Math.round(v.lon/1e4/60*1e5)/1e5,sog:Math.round(v.sog/10*100)/100,cog:Math.round(v.cog/10*100)/100,hdg:Math.round(v.heading*100)/100,rot:Math.round(v.rot*100)/100,positionTime:j.unix(),utc:j.utc().format(),method:"trajectory",vendor:"myship"},b=Math.floor(j.diff(l,"minute",!0)/(e||1));b!==w&&(w=b,d.push(c))}return d}}let R;try{R=Z.getLogger("vessel")}catch{}finally{}var J=(Y=>(Y.NOTICE="NOTICE",Y.WARN="WARN",Y.HEAVY="HEAVY",Y.SEVERE="SEVERE",Y.ERROR="ERROR",Y.FATAL="FATAL",Y))(J||{});class Q{parsePrinciple(s,t={}){var e,d,r;R==null||R.info("[%s] parse rule: %s",t.requestId,s);const i=new RegExp("(?<=\\[)(.+)(?=])","g"),n=s.match(i)?(e=s.match(i))==null?void 0:e[0]:void 0,o=n==null?void 0:n.split(";");if(!o)return;const a={};for(let u=0;u<(o==null?void 0:o.length);u++){const m=(r=(d=o[u].match(i))==null?void 0:d[0])==null?void 0:r.split("],");if(u===0&&!m)a.scope=o[0];else if(m)for(let f=0,p=m.length;f<p;f++){const l=this.parseRule(m[f]);l&&(a[l.level]?l.key?a[l.level][l==null?void 0:l.key]=l:a[l.level]=l:l.key?a[l.level]={[l==null?void 0:l.key]:l}:a[l.level]=l)}}return a}parseRule(s,t={}){var a;R==null||R.info("[%s] parse rule: %s",t.requestId,s),s=s.startsWith("[")?s:`[${s}`,s=s.endsWith("]")?s:`${s}]`;const i=new RegExp("(?<=\\[)(.+?)(?=])","g"),n=(a=s==null?void 0:s.match(i))==null?void 0:a[0],o=n==null?void 0:n.split(",");if(o)return{operator:o[0],number:Number.isNaN(Number(o[1]))?o[1]:Number(o[1]),level:o[2],time:Number(o[3]),key:o[4]}}checkWeather(s,t,i={}){var l,w,I,v,j,c,b,F,M,y,H,E,W,q,_;let n=0,o=0,a=0,e=0;const d=Math.round(((w=(l=t==null?void 0:t.SEVERE)==null?void 0:l.sigWave)==null?void 0:w.number)*1.6*100)/100,r=(v=(I=t==null?void 0:t.SEVERE)==null?void 0:I.sigWave)==null?void 0:v.number,u=(c=(j=t==null?void 0:t.HEAVY)==null?void 0:j.sigWave)==null?void 0:c.number,m=Math.round((((F=(b=t==null?void 0:t.SEVERE)==null?void 0:b.wind)==null?void 0:F.number)+2)*100)/100,f=(y=(M=t==null?void 0:t.SEVERE)==null?void 0:M.wind)==null?void 0:y.number,p=(E=(H=t==null?void 0:t.HEAVY)==null?void 0:H.wind)==null?void 0:E.number;for(let V=0;V<(s==null?void 0:s.length);V++){const N=s[V],C=(q=(W=N==null?void 0:N.meteo)==null?void 0:W.wave)==null?void 0:q.sig,D=(_=N==null?void 0:N.meteo)==null?void 0:_.wind,P=V?g(N.eta).diff(g(s[V-1].eta),"hour",!0):0;e=P>e?P:e,R==null||R.info("[%s] check sig.wave: %j",i.requestId,{...C,dgThd4Wv:d,svThd4Wv:r,hvThd4Wv:u}),(C==null?void 0:C.height)>=d?N.isDangerous=!0:(C==null?void 0:C.height)>=r?N.isSevere=!0:(C==null?void 0:C.height)>=u&&(N.isHeavy=!0),R==null||R.info("[%s] check wind: %j",i.requestId,{...D,dgThd4Wd:m,svThd4Wd:f,hvThd4Wd:p}),(D==null?void 0:D.scale)>=m?(N.isDangerous=!0,delete N.isSevere,delete N.isHeavy):(D==null?void 0:D.scale)>f?(N.isDangerous||(N.isSevere=!0),delete N.isHeavy):(D==null?void 0:D.scale)===p&&!N.isDangerous&&!N.isSevere&&(N.isHeavy=!0),n+=N.isDangerous?P:0,o+=N.isSevere?P:0,a+=N.isHeavy?P:0}return n=Math.round(n*100)/100,o=Math.round(o*100)/100,a=Math.round(a*100)/100,e=Math.round(e),{sample:s,dangerous:n,severe:o,heavy:a,step:e<3?3:e,wind:{dgThd4Wd:m,svThd4Wd:f,hvThd4Wd:p},sig:{dgThd4Wv:d,svThd4Wv:r,hvThd4Wv:u}}}}const ht=new Q;let T;try{T=Z.getLogger("vessel")}catch{}finally{}const lt=new G.MeteoHelper2("",!0);var X=(Y=>(Y.common="common",Y.container="container",Y.tugs="tugs",Y))(X||{}),$=(Y=>(Y.Ballast="Ballast",Y.Laden="Laden",Y))($||{}),tt=(Y=>(Y.Cp="CP",Y.Perf="Basis",Y.Instruct="Other",Y))(tt||{});class A{static blockCoefficient(s,t,i,n){let o=Math.round(s/(t*i*n)*100)/100;o=o<.55?.55:o>.85?.85:o;const a=[.55,.6,.65,.7,.75,.8,.85],e=a.map(d=>Math.abs(d-o));return a[e.indexOf(Math.min(...e))]}static froudeNumber(s,t,i=9.8){let n=Math.round(Math.sqrt(s*s/(i*t))*100)/100;return n=n<.05?.05:n>.3?.3:n,n}static amendFactor(s,t,i){const n={.55:[1.7,-1.4,-7.4],.6:[2.2,-2.5,-9.7],.65:[2.6,-3.7,-11.6],.7:[3.1,-5.3,-12.4],.75:[2.4,-10.6,-9.5],.8:[2.6,-13.1,-15.1],.85:[3.1,-18.7,28]};let a={.55:[1.7,-1.4,-7.4],.6:[2.2,-2.5,-9.7],.65:[2.6,-3.7,-11.6],.7:[3.1,-5.3,-12.4],.75:[2.6,-12.5,-13.5],.8:[3,-16.3,-21.6],.85:[3.4,-20.9,31.8]}[s];return i==="Laden"&&(a=n[s]),a[0]+a[1]*t+a[2]*Math.pow(t,2)}static directionFactor(s,t=0){let i;return s>30&&s<=60?i=(1.7-.03*Math.pow(t-4,2))/2:s>60&&s<=150?i=(.9-.06*Math.pow(t-6,2))/2:s>150&&s<=180?i=(.4-.03*Math.pow(t-8,2))/2:i=1,Math.round(i*1e5)/1e5}static vesselTagFactor(s,t,i,n=0){n=n>6?n-.9*(n-6):n;let o;return i==="container"?o=.7*n+Math.pow(n,6.5)/(22*Math.pow(s,2/3)):t==="Ballast"?o=.7*n+Math.pow(n,6.5)/(2.7*Math.pow(s,2/3)):o=.5*n+Math.pow(n,6.5)/(2.7*Math.pow(s,2/3)),o}static waveHeightFactor(s,t){s=s<0?.2:s,s=s>6?s-.9*(s-6):s,s=s>9?9:s;let i;return t>30&&t<=60?i=-.6:t>60&&t<=90?i=-.4:t>90&&t<=120?i=s<3?.4:-.3:t>120&&t<=150?i=s<3?.6:-.5:t>150&&t<=180?i=s<3?.7:-.6:i=-.7,Math.round(i*(.144*Math.pow(s,2)+.178*s)*1e4)/1e4}static assembleProperties(s,t,i,n){var f;const o=s.lbp??s.length??s.lengthOverall??198.9642,a=s.draught??8,e=s.breadthMoulded??s.breadth??s.breadthExtreme??32.4572,d=s.deadweight??67035.7773,r=((f=s==null?void 0:s.type)==null?void 0:f.toLowerCase())||"common";return{tag:r.indexOf("container")>-1?"container":r.indexOf("tugs")>-1?"tugs":"common",lbp:o,loadCondition:t,draught:a,breadthMoulded:e,displacement:Math.round((d/1.025+a*e*o*.7)*1e4)/1e4,speed:Math.round((i??14.1382)*1852/3600*1e4)/1e4,bearing:n||90}}static async speedLoseAt(s,t,i,n="",o=2,a=!0,e=!1,d={}){let r;if(t.velocity&&e&&(s.speed=O.LngLatHelper.roundPrecision(t.velocity*1852/3600,6)),a){let u;if(d.meteo2)try{const l=await lt.spotForecast(t.lat,t.lng,i.utc().format(),!1,!1,!0,d),[w]=U.Meteo2Assist.pickHourly(l,i);u=U.Meteo2Assist.toLegacy(w)}catch(l){T.warn("[%s] meteo2 spot(%j) forecast failed: %s",d.requestId,{...t,eta:i.utc().format()},l)}else u=await G.MeteoHelper.queryPointFactor(t.lng,t.lat,i.valueOf(),"wind,wave,current,watertemp",n,d);const m=A.weatherFactor(s,u),f=A.currentFactor(s.bearing,u==null?void 0:u.current,o),p=Math.round((s.speed*1.943844+m+f)*100)/100;r={meteo:{...u},wxFactor:m,cFactor:f,speed:t.velocity&&e?t.velocity:p<0?1:p,eta:i.utc().format("YYYY-MM-DDTHH:mm[Z]"),etd:i.utc().format("YYYY-MM-DDTHH:mm[Z]")}}else r={wxFactor:0,cFactor:0,speed:t.velocity&&e?t.velocity:Math.round((s.speed*1.943844+0+0)*100)/100,eta:i.utc().format("YYYY-MM-DDTHH:mm[Z]"),etd:i.utc().format("YYYY-MM-DDTHH:mm[Z]")};return delete t.meteo,delete t.wxFactor,delete t.cFactor,delete t.speed,delete t.etd,{...r,...t}}static async speedLoseInHoursStep(s,t,i,n,o,a,e="",d=!0,r=!1,u={}){t.utc();const m=g().add(14,"days"),f=[],p=[];let l=0,w=0,I,v;for(let j=0;j<a.length-1;j++){let c=a[j];c.distanceFromStart=o+w;const b=a[j+1];if(s.bearing=O.LaneHelper.calculateBearing(c,b,!b.gcToPrevious),c.bearing=s.bearing,c.suspend&&r){c.eta=c.eta||t.format("YYYY-MM-DDTHH:mm[Z]"),c.elapsed=c.elapsed??0;const y=c.suspend-c.elapsed;if(n-l>y)n=n-l-y,t.add(y,"hour"),c.elapsed=c.suspend;else{const H=n-l;c.elapsed+=H,t.add(H,"hour"),n=0}if(T==null||T.info(`[%s] suspend ${c.elapsed} hours at %j, and remain ${n} hours need to go...`,u.requestId,c),n===0)return c.distanceFromPrevious=w,{etd:t,from:v||c,to:c,next:a.filter(H=>H),wps:f,days:p}}else c.suspend=0;d=t.isAfter(m)?!1:d,c=await A.speedLoseAt(s,c,t,e,0,d,r,u),v=v||c,c.important&&f.push(c),t.isSameOrAfter(i)&&(p.push(c),i.add(24,"hour"));const F=O.LaneHelper.calculateDistance(c,b,!b.gcToPrevious);let M=Math.ceil(F/v.speed*1e4)/1e4;if(l+M<n){if(l+=M,t.add(M,"hour"),delete a[j],T==null||T.info(`[%s] go to %j from %j with ${F}nm, and cost ${M} hours`,u.requestId,{lat:b.lat,lng:b.lng},{lat:v.lat,lng:v.lng,etd:v.etd}),w+=F,a.filter(y=>y).length<=1){I=b,I.eta=t.format("YYYY-MM-DDTHH:mm[Z]"),I.distanceFromPrevious=F,I.distanceFromStart=o+w,f.push(I),delete a[j+1];break}}else{M=n-l,t.add(M,"hour");const y=O.LngLatHelper.roundPrecision(v.speed*M,4);I=O.LaneHelper.calculateCoordinate(c,s.bearing,y,"nauticalmiles",!b.gcToPrevious),I.eta=t.format("YYYY-MM-DDTHH:mm[Z]"),a[j]=I,T==null||T.info(`[%s] go to %j from %j with ${y}nm, and cost ${M} hours`,u.requestId,{lat:I.lat,lng:I.lng},{lat:c.lat,lng:c.lng,etd:c.etd}),w+=y,I.distanceFromPrevious=w,I.distanceFromStart=o+w;break}}return{etd:t,from:v,to:I,next:a.filter(j=>j),wps:f,days:p}}static currentFactor(s,t,i=0){const n=(s-(t==null?void 0:t.degree)||0)/180*Math.PI;if(Math.abs(n)===Math.PI/2)return 0;let o=((t==null?void 0:t.kts)||0)*Math.cos(n);return i&2?o=Math.ceil(o*100)/100:i&1?o=Math.floor(o*100)/100:o=Math.round(o*100)/100,Math.abs(o)>5?0:o}static weatherFactor(s,t){var m,f,p,l,w,I,v;T==null||T.debug("calculate weather factor via: %j",{...s,...t});const i=A.blockCoefficient(s.displacement,s.lbp,s.breadthMoulded,s.draught),n=A.froudeNumber(s.speed,s.lbp),o=A.amendFactor(i,n,s.loadCondition);let a=Math.abs(s.bearing%360-(((m=t==null?void 0:t.wind)==null?void 0:m.degree)%360||0));a=a>180?360-a:a;const e=A.directionFactor(a,(f=t==null?void 0:t.wind)==null?void 0:f.scale),d=A.vesselTagFactor(s.displacement,s.loadCondition,s.tag,(p=t==null?void 0:t.wind)==null?void 0:p.scale);let r=e*o*d/100*s.speed;r=Math.round(r*1.943844*1e4)/1e4*-1,s.tag==="tugs"&&Math.abs(r)>1&&(r=r/(Math.abs(Math.round(r))+1)),T==null||T.debug("wind wx factor = %d",r),a=Math.abs(s.bearing%360-(((w=(l=t==null?void 0:t.wave)==null?void 0:l.sig)==null?void 0:w.degree)%360||0));const u=A.waveHeightFactor(((v=(I=t==null?void 0:t.wave)==null?void 0:I.sig)==null?void 0:v.height)??1,a);return T==null||T.debug("wave wx factor = %d",u),r=r*.4+u,T==null||T.debug("weather factor = %d",r),r=Math.abs(r)>4?4*(Math.abs(r)/r)+Math.abs(r)/r*(Math.abs(r)-4)*.1:r,Math.round((r||0)*100)/100}static async analyseInstant(s,t,i,n,o,a="",e=0,d=!0,r=!1,u={}){var P,et,st,at,nt;const m=g().valueOf();s.lng=O.LngLatHelper.convertToStdLng(s.lng);const{route:f,waypoints:p}=o.points,l=O.LaneHelper.calculateSubRoute(s,f);if(((P=l[0])==null?void 0:P.length)<=1)return;const{v0:w,label:I}=s.sog?{v0:s.sog,label:"Other"}:{v0:n.speed,label:"CP"},v=A.assembleProperties(i,n.loadCondition,w,0),j=p.length?O.LaneHelper.calculateSubWaypoints(s,p):[];j.forEach(x=>x.important=!0);const c={from:{...s},route:l,waypoints:j,v0:w,label:I},b={hours:[],days:[],wps:[]};e||(O.LaneHelper.calculateRouteDistance(l)/n.speed<=72?e=3:e=6);let F=O.LaneHelper.simplifyRouteToCoordinates(l,j,0),M=0,y=0,H=0,E=0;t=g(t).utc();const W=t.clone();for(;F.length>0;){const x=e-t.hour()%e,B=Math.ceil(t.clone().add(x,"h").set({minute:0,second:0,millisecond:0}).diff(t,"h",!0)*1e4)/1e4,L=await A.speedLoseInHoursStep(v,t,W,B,M,F,a,d,r,u);(et=L.from)!=null&&et.speed&&(b.hours.push(L.from),b.wps.push(...L.wps),b.days.push(...L.days)),F=L==null?void 0:L.next,F.length||b.hours.push(L==null?void 0:L.to),M+=((st=L==null?void 0:L.to)==null?void 0:st.distanceFromPrevious)??0}const q=b.hours;for(let x=0;x<q.length-1;x++){const B=g(q[x+1].eta).diff(q[x].etd,"hour",!0)||1;y+=(q[x].wxFactor||0)*B,H+=(q[x].cFactor||0)*B,E+=B}(at=b.wps)==null||at.forEach((x,B)=>{if(B){const L=b.wps[B-1],ft=x.distanceFromStart-L.distanceFromStart,ot=g(x.eta).diff(g(L.etd),"h",!0);if(ot<1)x.avgSpd=L.speed;else{x.avgSpd=Math.round(ft/ot*100)/100;const it=Math.round((L.speed+x.speed)/2*100)/100;x.avgSpd=x.avgSpd>it?it:x.avgSpd}}}),c.sample=b;const _=b.hours.at(0),V=b.hours.at(-1);c.distance=Math.round(V.distanceFromStart*1e4)/1e4,c.etd=g(_.eta).utc().format(),c.eta=g(V.eta).utc().format(),c.wxFactor=Math.round(y/E*1e4)/1e4,c.cFactor=Math.round(H/E*1e4)/1e4,c.avgSpeed=Math.round(V.distanceFromStart/E*1e4)/1e4,c.totalHrs=Math.round(E*1e4)/1e4,c.totalFoCons=Math.round((n==null?void 0:n.fo)/24*c.totalHrs*1e3)/1e3,c.totalDgoCons=Math.round((n==null?void 0:n.dgo)/24*c.totalHrs*1e3)/1e3;const C=g().valueOf()-m,D=((nt=b==null?void 0:b.hours)==null?void 0:nt.length)||1;return T==null||T.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms",u==null?void 0:u.requestId,C,D,Math.round(C/D*1e3)/1e3),c}static async analyseInstantWithThreshed(s,t,i,n,o,a,e,d="",r=3,u=!0,m=!1,f={}){var V,N,C;s.lng=O.LngLatHelper.convertToStdLng(s.lng);const{v0:p,label:l}=s.sog?{v0:s.sog,label:"Other"}:{v0:o.speed,label:"CP"},w=A.assembleProperties(n,o.loadCondition,p,0),I=O.LaneHelper.calculateSubRoute(s,a);if(((V=I[0])==null?void 0:V.length)<=1)return;const v=e.length?O.LaneHelper.calculateSubWaypoints(s,e):[];v.forEach(D=>D.important=!0);let j=O.LaneHelper.simplifyRouteToCoordinates(I,v,0),c=0,b=0,F=0,M=0,y;const H={hours:[],wps:[],days:[]};for(t=g(t).utc();j.length>0;){const D=r-t.hour()%r;let P=Math.ceil(t.clone().add(D,"h").set({minute:0,second:0,millisecond:0}).diff(t,"h",!0)*1e4)/1e4;if(P=t.clone().add(P,"h").isAfter(i)?i.diff(t,"h",!0)*1e4/1e4:P,P)y=await A.speedLoseInHoursStep(w,t,i.clone(),P,c,j,d,u,m,f),(N=y.from)!=null&&N.speed&&(H.hours.push(y.from),y!=null&&y.wps&&H.wps.push(...y.wps),H.days.push(...y.days)),j=y==null?void 0:y.next,j.length||(H.hours.push(y==null?void 0:y.to),y!=null&&y.wps&&H.wps.push(...y.wps),H.days.push(y==null?void 0:y.to)),c+=((C=y==null?void 0:y.to)==null?void 0:C.distanceFromPrevious)??0;else{y&&(H.hours.push(y.to),y!=null&&y.wps&&H.wps.push(...y.wps),H.days.push(y.to));break}}const E=H.hours;for(let D=0;D<E.length-1;D++){const P=g(E[D+1].eta).diff(E[D].etd,"hour",!0);b+=E[D].wxFactor*P,F+=E[D].cFactor*P,M+=P}const W=H.hours.at(0),q=H.hours.at(-1);return{sample:H,distance:Math.round(((q==null?void 0:q.distanceFromStart)||0)*1e4)/1e4,etd:g(W.eta).utc().format(),eta:g(q==null?void 0:q.eta).utc().format(),wxFactor:Math.round(b/M*1e4)/1e4,cFactor:Math.round(F/M*1e4)/1e4,avgSpeed:Math.round(((q==null?void 0:q.distanceFromStart)||0)/M*1e4)/1e4,totalHrs:Math.round(M*1e4)/1e4,from:s,to:q,route:I,waypoints:v,v0:p,label:l}}static async analyseCost(s,t,i,n,o={}){}}k.AISImpl=z,k.AlertHelper=Q,k.AlertLevel=J,k.HifleetImpl=ct,k.LoadCondition=$,k.MyShipImpl=ut,k.MyVesselImpl=rt,k.ShipxyImpl=dt,k.SpeedHelper=A,k.SpeedLabel=tt,k.VesselTag=X,k.alertHelper=ht,Object.defineProperty(k,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
(function(T,N){typeof exports=="object"&&typeof module<"u"?N(exports,require("got"),require("@log4js-node/log4js-api"),require("moment"),require("@idm-plugin/geo"),require("@idm-plugin/meteo2"),require("@idm-plugin/meteo")):typeof define=="function"&&define.amd?define(["exports","got","@log4js-node/log4js-api","moment","@idm-plugin/geo","@idm-plugin/meteo2","@idm-plugin/meteo"],N):(T=typeof globalThis<"u"?globalThis:T||self,N(T["idm-plugin-rabbitmq"]={},T.got,T["@log4js-node/log4js-api"],T.moment,T["@idm-plugin/geo"],T["@idm-plugin/meteo2"],T["@idm-plugin/meteo"]))})(this,function(T,N,K,I,R,X,$){"use strict";var mt=Object.defineProperty;var yt=(T,N,K)=>N in T?mt(T,N,{enumerable:!0,configurable:!0,writable:!0,value:K}):T[N]=K;var _=(T,N,K)=>(yt(T,typeof N!="symbol"?N+"":N,K),K);let M;try{M=K.getLogger("vessel")}catch{}finally{}class G{parseStatus(e){let t,o;switch(e){case 0:t="在航(主机推动)",o="The engine is in use";break;case 1:t="锚泊",o="Anchored";break;case 2:t="失控",o="Not operated";break;case 3:t="操纵受限",o="Limited airworthiness";break;case 4:t="吃水受限",o="Limited by ship's draft";break;case 5:t="靠泊",o="Mooring";break;case 6:t="搁浅",o="Stranded";break;case 7:t="捕捞作业",o="Engaged in fishing";break;case 8:t="靠帆船提供动力",o="Sailing";break;default:t="未定义",o="Undefined"}return{labelCn:t,labelEn:o}}}class rt extends G{constructor(t,o){super();_(this,"clientId");_(this,"clientSecret");_(this,"token");this.clientId=t,this.clientSecret=o}async authToken(t={}){const o="https://svc.data.myvessel.cn/ada/oauth/token",i={searchParams:{client_id:this.clientId,client_secret:this.clientSecret,grant_type:"client_credentials"}},a=await N.post(o,i).json();M==null||M.info("[%s] fetch access token from: %s - %j",t.requestId,o,a),a.error||(this.token={accessToken:a.access_token,tokenType:a.token_type,expiresIn:a.expires_in,scope:a.scope,jti:a.jti,issuedAt:I().utc().format()})}async realTimePosition(t,o={}){var l,m,f;(!this.token||I().diff(I(this.token.issuedAt),"seconds")>((l=this.token)==null?void 0:l.expiresIn)-300)&&await this.authToken(o);const i="https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit",a={headers:{Authorization:`${(m=this.token)==null?void 0:m.tokenType} ${(f=this.token)==null?void 0:f.accessToken}`},searchParams:{mmsi:t}};M==null||M.info("[%s] fetch realtime position from: %s - %j",o.requestId,i,a);const n=await N.get(i,a).json();if(n.code)return M==null||M.warn("[%s] fetch realtime position failed: %j",o.requestId,i,{message:n.message,status:n.status,code:n.code}),n;const s=n.data;for(const h in s)!isNaN(s[h])&&Number(s[h])!==1/0&&(s[h]=Number(s[h]));const d=I(`${s.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:s.mmsi,name:s.vesselName,imo:s.imo,callSign:s.callsign,lat:s.lat,lng:s.lon,length:s.length,width:s.width,draught:s.currDraught,sog:s.sog,cog:s.cog,hdg:s.hdg,rot:s.rot,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(s.eta)?I.utc(s.eta).format():void 0,destination:s.dest,positionTime:d.unix(),status:s.status,labelCn:s.statusNameCn,labelEn:s.statusNameEn,method:"position",vendor:"myVessel",utc:d.utc().format()}}async trajectory(t,o,i,a,n=!0,s={}){(!this.token||I().diff(I(this.token.issuedAt),"seconds")>this.token.expiresIn-300)&&await this.authToken(s);const d=await this.realTimePosition(t,s),r=I(o),l=I(i),m=[];for(;l.diff(r,"day",!0)>30;)await this.trajectoryIn30Day(t,r,r.clone().add(30,"day"),d,a,m,s),r.add(30,"day");return await this.trajectoryIn30Day(t,r,l,d,a,m,s),m}async trajectoryIn30Day(t,o,i,a,n,s,d={}){var u,g,j,y,p;const r="https://svc.data.myvessel.cn/sdc/v1/vessels/status/track",l={headers:{Authorization:`${(u=this.token)==null?void 0:u.tokenType} ${(g=this.token)==null?void 0:g.accessToken}`},json:{mmsi:t,startTime:o.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),endTime:i.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")}};M==null||M.info("[%s] fetch trajectory from: %s - %j",d.requestId,r,l);const m=await N.post(r,l).json();if(m.code)return M==null||M.warn("[%s] fetch trajectory failed: %j",d.requestId,r,{message:m.message,status:m.status,code:m.code}),m;let f=-1;const h=I(`${(y=(j=m.data)==null?void 0:j[0])==null?void 0:y.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return(p=m.data)==null||p.forEach(c=>{for(const L in c)!isNaN(c[L])&&Number(c[L])!==1/0&&(c[L]=Number(c[L]));const b=I(`${c.postime} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00"),D=c.status,{labelCn:w,labelEn:k}=this.parseStatus(D),S={mmsi:c.mmsi,imo:a==null?void 0:a.imo,lat:c.lat,lng:c.lon,sog:c.sog,cog:c.cog,hdg:c.hdg,draught:c.draught,status:D,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(c.eta)?I(`${c.eta} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00").utc().format():void 0,destination:c.dest,positionTime:b.unix(),labelCn:w,labelEn:k,method:"trajectory",vendor:"myVessel",utc:b.utc().format()},x=Math.floor(b.diff(h,"minute",!0)/(n||1));x!==f&&(f=x,s.push(S))}),s}}class ct extends G{constructor(t){super();_(this,"token");this.token=t}async realTimePosition(t,o={}){const i="https://api.hifleet.com/position/position/get/token",a={searchParams:{mmsi:t,usertoken:this.token}},n=await N.post(i,a).json();M==null||M.info("[%s] fetch realtime position from: %s - %j",o.requestId,i,a);const s=n==null?void 0:n.list;if(!s)return M==null||M.warn("[%s] fetch realtime position failed: %j",o.requestId,i,n),n;for(const h in s)!isNaN(s[h])&&Number(s[h])!==1/0&&(s[h]=Number(s[h]));s.status=s.sp>3?0:1;const d=s.status,{labelCn:r,labelEn:l}=this.parseStatus(d),m=I(`${s.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");return{mmsi:s.m,name:s.n,imo:s.imonumber,callSign:s.callsign,lat:Math.round(s.la/60*1e5)/1e5,lng:Math.round(s.lo/60*1e5)/1e5,length:s.l,width:s.w,draught:s.draught,sog:s.sp,cog:s.co,hdg:s.h,rot:isNaN(s.rot)?0:s.rot,eta:/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(s.eta)?I.utc(s.eta).format():void 0,destination:s.destination,positionTime:m.unix(),utc:m.utc().format(),status:d,labelCn:r,labelEn:l,method:"position",vendor:"hifleet"}}async search(t,o={}){let i="https://www.hifleet.com/hifleetapi/searchVesselOL.do";const a={searchParams:{keyword:t},headers:{Referer:"https://www.hifleet.com",Origin:"https://www.hifleet.com",Host:"www.hifleet.com"}};let n=await N.post(i,a).json();M==null||M.info("[%s] fetch vessel props from: %s - %j",o.requestId,i,a),n instanceof Array&&(n=n[0]);for(const d in n)!isNaN(n[d])&&Number(n[d])!==1/0&&(n[d]=Number(n[d]));const s={mmsi:n.m,name:n.n,imo:n.i,callSign:n.c,length:n.l,breadth:n.b,draught:n.dr,type:n.t};return i="https://www.hifleet.com/hifleetapi/sameShipSearch.do",n=await N.post(i,a).json(),M==null||M.info("[%s] search vessel dead weight from: %s - %j",o.requestId,i,a),n instanceof Array&&(n=n[0]),n&&(s.deadweight=Number(n.dwt)),s}async suggest(t,o={}){const i="https://www.hifleet.com/hifleetapi/getShipSuggest.do",a={searchParams:{q:t},headers:{Referer:"https://www.hifleet.com",Origin:"https://www.hifleet.com",Host:"www.hifleet.com"}},n=await N.post(i,a).json();M==null||M.info("[%s] suggest vessel props from: %s - %j",o.requestId,i,a);const s=[];for(const d of n)s.push({mmsi:!d.mmsi||isNaN(d.mmsi)?null:Number(d.mmsi),name:d.name,callSign:d.callsign,imo:!d.imo||isNaN(d.imo)?null:Number(d.imo),score:d._score});return s.sort((d,r)=>r.score-d.score),s}async trajectory(t,o,i,a,n=!0,s={}){var c,b,D;const d=await this.realTimePosition(t,s);let r=I(o);const l=I(i),m=I();if(n){let w=l.diff(r,"d",!0);w<0?r=l.clone().subtract(40,"d"):w<30?r.subtract(10,"d"):w<60?r.subtract(5,"d"):r=l.clone().subtract(80,"d"),w=m.diff(l,"d",!0),l.add(w>10?240:w*24,"h")}const f={searchParams:{endtime:l.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),starttime:r.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),mmsi:t,usertoken:this.token}},h="https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token",u=await N.get(h,f).json();M==null||M.info("[%s] fetch trajectory from: %s - %j",s.requestId,h,f);let g;u&&(g=((b=(c=u.ships)==null?void 0:c.offors)==null?void 0:b.ship)||[],g.length||M==null||M.warn("[%s] fetch trajectory failed: %j",s.requestId,u));const j=[];let y=-1;const p=I(`${(D=g==null?void 0:g[0])==null?void 0:D.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");for(const w of g){for(const E in w)!isNaN(w[E])&&Number(w[E])!==1/0&&(w[E]=Number(w[E]));const k=I(`${w.ti} +08:00`,"YYYY-MM-DD HH:mm:ss +08:00");w.status=w.sp>4?0:1;const{labelEn:S,labelCn:x}=this.parseStatus(w.status),L={mmsi:w.m,name:w.n,imo:d==null?void 0:d.imo,lat:w.la,lng:w.lo,draught:w.draught,sog:w.sp,cog:w.co,hdg:w.hdg,positionTime:k.unix(),utc:k.utc().format(),status:w.status,labelCn:x,labelEn:S,method:"trajectory",vendor:"hifleet"},W=Math.floor(k.diff(p,"minute",!0)/(a||1));W!==y&&(y=W,j.push(L))}return j}}class dt extends G{constructor(t){super();_(this,"token");this.token=t}async realTimePosition(t,o={}){const i={searchParams:{id:t,k:this.token,enc:1}},a="https://api.shipxy.com/apicall/GetSingleShip",n=await N.get(a,i).json();if(M==null||M.info("[%s] fetch realtime position from: %s - %j",o.requestId,a,i),(n==null?void 0:n.status)!==0)return n;const s=n.data[0];for(const f in s)!isNaN(s[f])&&Number(s[f])!==1/0&&(s[f]=Number(s[f]));const{labelCn:d,labelEn:r}=await this.parseStatus(s.navistat),l=I.unix(s.lasttime);return{mmsi:s.ShipID,name:s.name,imo:s.imo,callSign:s.callsign,lat:Math.round(s.lat/1e6*1e5)/1e5,lng:Math.round(s.lon/1e6*1e5)/1e5,length:Math.round(s.length/10*100)/100,width:Math.round(s.width/10*100)/100,draught:Math.round(s.draught/1e3*100)/100,sog:Math.round(s.sog*3600/1e3/1852*100)/100,cog:Math.round(s.cog/100*100)/100,hdg:Math.round(s.hdg/100*100)/100,rot:Math.round(s.rot/100*100)/100,positionTime:s.lasttime,utc:l.utc().format(),status:s.navistat,labelEn:r,labelCn:d,method:"position",vendor:"shipxy"}}async trajectory(t,o,i,a,n=!0,s={}){var p;const d=await this.realTimePosition(t,s),r=I(o),l=I(i),m="https://api.shipxy.com/apicall/GetShipTrack",f={searchParams:{id:t,k:this.token,enc:1,cut:0,btm:r.unix(),etm:l.unix()}},h=await N.get(m,f).json();if(M==null||M.info("[%s] fetch trajectory from: %s - %j",s.requestId,m,f),(h==null?void 0:h.status)!==0)return h;const u=h==null?void 0:h.points,g=[],j=I.unix((p=u[0])==null?void 0:p.utc);let y=-1;for(const c of u){const b=I.unix(c.utc),D={imo:d==null?void 0:d.imo,mmsi:t,sog:Math.round(c.sog*3600/1e3/1852*100)/100,cog:Math.round(c.cog/100*100)/100,lat:Math.round(c.lat/1e6*1e5)/1e5,lng:Math.round(c.lon/1e6*1e5)/1e5,positionTime:b.unix(),utc:b.utc().format(),method:"trajectory",vendor:"shipxy"},w=Math.floor(b.diff(j,"minute",!0)/(a||1));w!==y&&(y=w,g.push(D))}return g}}class ut extends G{constructor(t){super();_(this,"token");this.token=t}async getShipId(t,o={}){const i={headers:{appKey:this.token},json:{mmsiList:t}},a="https://api3.myships.com/sp/ships/getShipIdByMMSI",n=await N.post(a,i).json();return M==null||M.info("[%s] fetch ship id from: %s - %j",o.requestId,a,i),n.code!=="0"?n:n.data[0].shipId}async getShipInfo(t,o={}){const i={headers:{appKey:this.token},json:{shipId:t}},a="https://api3.myships.com/sp/ships/aissta",n=await N.post(a,i).json();if(M==null||M.info("[%s] fetch ship info from: %s - %j",o.requestId,a,i),n.code!=="0")return n;const s=n.data;let d=s.imo;return t==="407170"&&(d="9198379",M==null||M.warn("[%s] ship(%s) imo error: %s, should be %s",o.requestId,t,s.imo,d)),{mmsi:s.mmsi,name:s.shipnameEn,imo:d,callSign:s.callSign,length:s.length,width:s.breadth,draught:(s.draught||100)/10}}async realTimePosition(t,o={}){const i=await this.getShipId(t,o),a=await this.getShipInfo(i,o),n={headers:{appKey:this.token},json:{shipId:i}},s="https://api3.myships.com/sp/ships/position/latest",d=await N.post(s,n).json();M==null||M.info("[%s] fetch realtime position from: %s - %j",o.requestId,s,n);const r=d.data[0];for(const u in r)!isNaN(r[u])&&Number(r[u])!==1/0&&(r[u]=Number(r[u]));const{labelCn:l,labelEn:m}=await this.parseStatus(r.aisNavStatus),f=I.unix(r.posTime);return{...a,mmsi:t,lat:Math.round(r.lat/1e4/60*1e5)/1e5,lng:Math.round(r.lon/1e4/60*1e5)/1e5,sog:Math.round(r.sog/10*100)/100,cog:Math.round(r.cog/10*100)/100,hdg:Math.round(r.heading*100)/100,rot:Math.round(r.rot*100)/100,positionTime:r.posTime,utc:f.utc().format(),status:r.aisNavStatus,labelEn:m,labelCn:l,method:"position",vendor:"myship"}}async trajectory(t,o,i,a,n=!0,s={}){const d=I(o),r=I(i),l=await this.getShipId(t),m=await this.getShipInfo(l),f=[];for(;r.diff(d,"day",!0)>30;)await this.trajectoryIn30Day(l,d.unix(),d.add(30,"day").unix(),m,t,a,f);return await this.trajectoryIn30Day(l,d.unix(),r.unix(),m,t,a,f),f}async trajectoryIn30Day(t,o,i,a,n,s,d,r={}){var j;const l={headers:{appKey:this.token},json:{shipId:t,startTime:o,endTime:i}},m="https://api3.myships.com/sp/ships/position/history",f=await N.post(m,l).json();if(M==null||M.info("[%s] fetch trajectory from: %s - %j",r.requestId,m,l),f.code!=="0")return M==null||M.warn("[%s] invoke myship trajectory failed: %j",r.requestId,f),f;const h=f.data;for(const y in h)!isNaN(h[y])&&Number(h[y])!==1/0&&(h[y]=Number(h[y]));const u=I.unix((j=h[0])==null?void 0:j.posTime);let g=-1;for(const y of h){const p=I.unix(y.posTime),c={imo:a==null?void 0:a.imo,mmsi:n,lat:Math.round(y.lat/1e4/60*1e5)/1e5,lng:Math.round(y.lon/1e4/60*1e5)/1e5,sog:Math.round(y.sog/10*100)/100,cog:Math.round(y.cog/10*100)/100,hdg:Math.round(y.heading*100)/100,rot:Math.round(y.rot*100)/100,positionTime:p.unix(),utc:p.utc().format(),method:"trajectory",vendor:"myship"},b=Math.floor(p.diff(u,"minute",!0)/(s||1));b!==g&&(g=b,d.push(c))}return d}}let V;try{V=K.getLogger("vessel")}catch{}finally{}var tt=(Y=>(Y.NOTICE="NOTICE",Y.WARN="WARN",Y.HEAVY="HEAVY",Y.SEVERE="SEVERE",Y.ERROR="ERROR",Y.FATAL="FATAL",Y))(tt||{});class et{parsePrinciple(e,t={}){var s,d,r;V==null||V.info("[%s] parse rule: %s",t.requestId,e);const o=new RegExp("(?<=\\[)(.+)(?=])","g"),i=e.match(o)?(s=e.match(o))==null?void 0:s[0]:void 0,a=i==null?void 0:i.split(";");if(!a)return;const n={};for(let l=0;l<(a==null?void 0:a.length);l++){const m=(r=(d=a[l].match(o))==null?void 0:d[0])==null?void 0:r.split("],");if(l===0&&!m)n.scope=a[0];else if(m)for(let f=0,h=m.length;f<h;f++){const u=this.parseRule(m[f]);u&&(n[u.level]?u.key?n[u.level][u==null?void 0:u.key]=u:n[u.level]=u:u.key?n[u.level]={[u==null?void 0:u.key]:u}:n[u.level]=u)}}return n}parseRule(e,t={}){var n;V==null||V.info("[%s] parse rule: %s",t.requestId,e),e=e.startsWith("[")?e:`[${e}`,e=e.endsWith("]")?e:`${e}]`;const o=new RegExp("(?<=\\[)(.+?)(?=])","g"),i=(n=e==null?void 0:e.match(o))==null?void 0:n[0],a=i==null?void 0:i.split(",");if(a)return{operator:a[0],number:Number.isNaN(Number(a[1]))?a[1]:Number(a[1]),level:a[2],time:Number(a[3]),key:a[4]}}checkWeather(e,t,o={}){var u,g,j,y,p,c,b,D,w,k,S,x,L,W,E;let i=0,a=0,n=0,s=0;const d=Math.round(((g=(u=t==null?void 0:t.SEVERE)==null?void 0:u.sigWave)==null?void 0:g.number)*1.6*100)/100,r=(y=(j=t==null?void 0:t.SEVERE)==null?void 0:j.sigWave)==null?void 0:y.number,l=(c=(p=t==null?void 0:t.HEAVY)==null?void 0:p.sigWave)==null?void 0:c.number,m=Math.round((((D=(b=t==null?void 0:t.SEVERE)==null?void 0:b.wind)==null?void 0:D.number)+2)*100)/100,f=(k=(w=t==null?void 0:t.SEVERE)==null?void 0:w.wind)==null?void 0:k.number,h=(x=(S=t==null?void 0:t.HEAVY)==null?void 0:S.wind)==null?void 0:x.number;for(let B=0;B<(e==null?void 0:e.length);B++){const q=e[B],P=(W=(L=q==null?void 0:q.meteo)==null?void 0:L.wave)==null?void 0:W.sig,A=(E=q==null?void 0:q.meteo)==null?void 0:E.wind,Z=B?I(q.eta).diff(I(e[B-1].eta),"hour",!0):0;s=Z>s?Z:s,V==null||V.info("[%s] check sig.wave: %j",o.requestId,{...P,dgThd4Wv:d,svThd4Wv:r,hvThd4Wv:l}),(P==null?void 0:P.height)>=d?q.isDangerous=!0:(P==null?void 0:P.height)>=r?q.isSevere=!0:(P==null?void 0:P.height)>=l&&(q.isHeavy=!0),V==null||V.info("[%s] check wind: %j",o.requestId,{...A,dgThd4Wd:m,svThd4Wd:f,hvThd4Wd:h}),(A==null?void 0:A.scale)>=m?(q.isDangerous=!0,delete q.isSevere,delete q.isHeavy):(A==null?void 0:A.scale)>f?(q.isDangerous||(q.isSevere=!0),delete q.isHeavy):(A==null?void 0:A.scale)===h&&!q.isDangerous&&!q.isSevere&&(q.isHeavy=!0),i+=q.isDangerous?Z:0,a+=q.isSevere?Z:0,n+=q.isHeavy?Z:0}return i=Math.round(i*100)/100,a=Math.round(a*100)/100,n=Math.round(n*100)/100,s=Math.round(s),{sample:e,dangerous:i,severe:a,heavy:n,step:s<3?3:s,wind:{dgThd4Wd:m,svThd4Wd:f,hvThd4Wd:h},sig:{dgThd4Wv:d,svThd4Wv:r,hvThd4Wv:l}}}}const ht=new et;let v;try{v=K.getLogger("vessel")}catch{}finally{}const lt=new X.MeteoHelper2("",!0);var st=(Y=>(Y.common="common",Y.container="container",Y.tugs="tugs",Y))(st||{}),at=(Y=>(Y.Ballast="Ballast",Y.Laden="Laden",Y))(at||{}),ot=(Y=>(Y.Cp="CP",Y.Perf="Basis",Y.Instruct="Other",Y))(ot||{});class C{static blockCoefficient(e,t,o,i){let a=Math.round(e/(t*o*i)*100)/100;a=a<.55?.55:a>.85?.85:a;const n=[.55,.6,.65,.7,.75,.8,.85],s=n.map(d=>Math.abs(d-a));return n[s.indexOf(Math.min(...s))]}static froudeNumber(e,t,o=9.8){let i=Math.round(Math.sqrt(e*e/(o*t))*100)/100;return i=i<.05?.05:i>.3?.3:i,i}static amendFactor(e,t,o){const i={.55:[1.7,-1.4,-7.4],.6:[2.2,-2.5,-9.7],.65:[2.6,-3.7,-11.6],.7:[3.1,-5.3,-12.4],.75:[2.4,-10.6,-9.5],.8:[2.6,-13.1,-15.1],.85:[3.1,-18.7,28]};let n={.55:[1.7,-1.4,-7.4],.6:[2.2,-2.5,-9.7],.65:[2.6,-3.7,-11.6],.7:[3.1,-5.3,-12.4],.75:[2.6,-12.5,-13.5],.8:[3,-16.3,-21.6],.85:[3.4,-20.9,31.8]}[e];return o==="Laden"&&(n=i[e]),n[0]+n[1]*t+n[2]*Math.pow(t,2)}static directionFactor(e,t=0){let o;return e>30&&e<=60?o=(1.7-.03*Math.pow(t-4,2))/2:e>60&&e<=150?o=(.9-.06*Math.pow(t-6,2))/2:e>150&&e<=180?o=(.4-.03*Math.pow(t-8,2))/2:o=1,Math.round(o*1e5)/1e5}static vesselTagFactor(e,t,o,i=0){i=i>6?i-.9*(i-6):i;let a;return o==="container"?a=.7*i+Math.pow(i,6.5)/(22*Math.pow(e,2/3)):t==="Ballast"?a=.7*i+Math.pow(i,6.5)/(2.7*Math.pow(e,2/3)):a=.5*i+Math.pow(i,6.5)/(2.7*Math.pow(e,2/3)),a}static waveHeightFactor(e,t){e=e<0?.2:e,e=e>6?e-.9*(e-6):e,e=e>9?9:e;let o;return t>30&&t<=60?o=-.6:t>60&&t<=90?o=-.4:t>90&&t<=120?o=e<3?.4:-.3:t>120&&t<=150?o=e<3?.6:-.5:t>150&&t<=180?o=e<3?.7:-.6:o=-.7,Math.round(o*(.144*Math.pow(e,2)+.178*e)*1e4)/1e4}static assembleProperties(e,t,o,i){var f;const a=e.lbp??e.length??e.lengthOverall??198.9642,n=e.draught??8,s=e.breadthMoulded??e.breadth??e.breadthExtreme??32.4572,d=e.deadweight??67035.7773,r=((f=e==null?void 0:e.type)==null?void 0:f.toLowerCase())||"common";return{tag:r.indexOf("container")>-1?"container":r.indexOf("tugs")>-1?"tugs":"common",lbp:a,loadCondition:t,draught:n,breadthMoulded:s,displacement:Math.round((d/1.025+n*s*a*.7)*1e4)/1e4,speed:Math.round((o??14.1382)*1852/3600*1e4)/1e4,bearing:i||90}}static async speedLoseAt(e,t,o,i="",a=2,n=!0,s=!1,d={}){let r;if(t.velocity&&s&&(e.speed=R.LngLatHelper.roundPrecision(t.velocity*1852/3600,6)),n){let l;if(d.meteo2)try{const u=await lt.spotForecast(t.lat,t.lng,o.utc().format(),!1,!1,!0,d),[g]=$.Meteo2Assist.pickHourly(u,o);l=$.Meteo2Assist.toLegacy(g)}catch(u){v.warn("[%s] meteo2 spot(%j) forecast failed: %s",d.requestId,{...t,eta:o.utc().format()},u)}else l=await X.MeteoHelper.queryPointFactor(t.lng,t.lat,o.valueOf(),"wind,wave,current,watertemp",i,d);const m=C.weatherFactor(e,l),f=C.currentFactor(e.bearing,l==null?void 0:l.current,a),h=Math.round((e.speed*1.943844+m+f)*100)/100;r={meteo:{...l},wxFactor:m,cFactor:f,speed:t.velocity&&s?t.velocity:h<0?1:h,eta:o.utc().format("YYYY-MM-DDTHH:mm[Z]"),etd:o.utc().format("YYYY-MM-DDTHH:mm[Z]")}}else r={wxFactor:0,cFactor:0,speed:t.velocity&&s?t.velocity:Math.round((e.speed*1.943844+0+0)*100)/100,eta:o.utc().format("YYYY-MM-DDTHH:mm[Z]"),etd:o.utc().format("YYYY-MM-DDTHH:mm[Z]")};return delete t.meteo,delete t.wxFactor,delete t.cFactor,delete t.speed,delete t.etd,{...r,...t}}static async speedLoseInHoursStep(e,t,o,i,a,n,s="",d=!0,r=!1,l={}){t.utc();const m=t.clone().add(14,"days"),f=[],h=[];let u=0,g=0,j,y;for(let p=0;p<n.length-1;p++){let c=n[p];c.distanceFromStart=Math.round((a+g)*1e4)/1e4;const b=n[p+1];if(e.bearing=R.LaneHelper.calculateBearing(c,b,!b.gcToPrevious),c.bearing=e.bearing,c.suspend&&r){c.eta=c.eta||t.format("YYYY-MM-DDTHH:mm[Z]"),c.elapsed=c.elapsed??0;const k=c.suspend-c.elapsed;if(i-u>k)i=i-u-k,t.add(k,"hour"),c.elapsed=c.suspend;else{const S=i-u;c.elapsed+=S,t.add(S,"hour"),i=0}if(v==null||v.info(`[%s] suspend ${c.elapsed} hours at %j, and remain ${i} hours need to go...`,l.requestId,c),i===0)return c.distanceFromPrevious=g,{etd:t,from:y||c,to:c,next:n.filter(S=>S),wps:f,days:h}}else c.suspend=0;d=t.isAfter(m)?!1:d,c=await C.speedLoseAt(e,c,t,s,0,d,r,l),y=y||c,c.important&&f.push(c),t.isSameOrAfter(o)&&(h.push(c),o.add(24,"hour"));const D=R.LaneHelper.calculateDistance(c,b,!b.gcToPrevious);let w=Math.ceil(D/y.speed*1e4)/1e4;if(u+w<i){if(u+=w,t.add(w,"hour"),delete n[p],v==null||v.debug(`[%s] go to %j from %j with ${D}nm, and cost ${w} hours`,l.requestId,{lat:b.lat,lng:b.lng},{lat:y.lat,lng:y.lng,etd:y.etd}),g+=D,n.filter(k=>k).length<=1){j=b,j.eta=t.format("YYYY-MM-DDTHH:mm[Z]"),j.distanceFromPrevious=D,j.distanceFromStart=Math.round((a+g)*1e4)/1e4,f.push(j),delete n[p+1];break}}else{w=i-u,t.add(w,"hour");const k=R.LngLatHelper.roundPrecision(y.speed*w,4);j=R.LaneHelper.calculateCoordinate(c,e.bearing,k,"nauticalmiles",!b.gcToPrevious),j.eta=t.format("YYYY-MM-DDTHH:mm[Z]"),n[p]=j,v==null||v.debug(`[%s] go to %j from %j with ${k}nm, and cost ${w} hours`,l.requestId,{lat:j.lat,lng:j.lng},{lat:c.lat,lng:c.lng,etd:c.etd}),g+=k,j.distanceFromPrevious=Math.round(g*1e4)/1e4,j.distanceFromStart=Math.round((a+g)*1e4)/1e4;break}}return{etd:t,from:y,to:j,next:n.filter(p=>p),wps:f,days:h}}static currentFactor(e,t,o=0){const i=(e-(t==null?void 0:t.degree)||0)/180*Math.PI;if(Math.abs(i)===Math.PI/2)return 0;let a=((t==null?void 0:t.kts)||0)*Math.cos(i);return o&2?a=Math.ceil(a*100)/100:o&1?a=Math.floor(a*100)/100:a=Math.round(a*100)/100,Math.abs(a)>5?0:a}static weatherFactor(e,t){var m,f,h,u,g,j,y;v==null||v.debug("calculate weather factor via: %j",{...e,...t});const o=C.blockCoefficient(e.displacement,e.lbp,e.breadthMoulded,e.draught),i=C.froudeNumber(e.speed,e.lbp),a=C.amendFactor(o,i,e.loadCondition);let n=Math.abs(e.bearing%360-(((m=t==null?void 0:t.wind)==null?void 0:m.degree)%360||0));n=n>180?360-n:n;const s=C.directionFactor(n,(f=t==null?void 0:t.wind)==null?void 0:f.scale),d=C.vesselTagFactor(e.displacement,e.loadCondition,e.tag,(h=t==null?void 0:t.wind)==null?void 0:h.scale);let r=s*a*d/100*e.speed;r=Math.round(r*1.943844*1e4)/1e4*-1,e.tag==="tugs"&&Math.abs(r)>1&&(r=r/(Math.abs(Math.round(r))+1)),v==null||v.debug("wind wx factor = %d",r),n=Math.abs(e.bearing%360-(((g=(u=t==null?void 0:t.wave)==null?void 0:u.sig)==null?void 0:g.degree)%360||0));const l=C.waveHeightFactor(((y=(j=t==null?void 0:t.wave)==null?void 0:j.sig)==null?void 0:y.height)??1,n);return v==null||v.debug("wave wx factor = %d",l),r=r*.4+l,v==null||v.debug("weather factor = %d",r),r=Math.abs(r)>4?4*(Math.abs(r)/r)+Math.abs(r)/r*(Math.abs(r)-4)*.1:r,Math.round((r||0)*100)/100}static async analyseInstant(e,t,o,i,a,n="",s=0,d=!0,r=!1,l={}){var Z,z,U,Q,J;const m=I().valueOf();e.lng=R.LngLatHelper.convertToStdLng(e.lng);const{route:f,waypoints:h}=a.points,u=R.LaneHelper.calculateSubRoute(e,f);if(((Z=u[0])==null?void 0:Z.length)<=1)return;const{v0:g,label:j}=e.sog?{v0:e.sog,label:"Other"}:{v0:i.speed,label:"CP"},y=C.assembleProperties(o,i.loadCondition,g,0),p=h.length?R.LaneHelper.calculateSubWaypoints(e,h):[];p.forEach(H=>H.important=!0);const c={from:{...e},route:u,waypoints:p,v0:g,label:j},b={hours:[],days:[],wps:[]};s||(R.LaneHelper.calculateRouteDistance(u)/i.speed<=72?s=3:s=6);let D=R.LaneHelper.simplifyRouteToCoordinates(u,p,0),w=0,k=0,S=0,x=0;t=I(t).utc();const L=t.clone();for(;D.length>0;){const H=s-t.hour()%s,F=Math.ceil(t.clone().add(H,"h").set({minute:0,second:0,millisecond:0}).diff(t,"h",!0)*1e4)/1e4,O=await C.speedLoseInHoursStep(y,t,L,F,w,D,n,d,r,l);(z=O.from)!=null&&z.speed&&(b.hours.push(O.from),b.wps.push(...O.wps),b.days.push(...O.days)),D=O==null?void 0:O.next,D.length||b.hours.push(O==null?void 0:O.to),w+=Math.round((((U=O==null?void 0:O.to)==null?void 0:U.distanceFromPrevious)??0)*1e4)/1e4}const W=b.hours;for(let H=0;H<W.length-1;H++){const F=I(W[H+1].eta).diff(W[H].etd,"hour",!0)||1;k+=(W[H].wxFactor||0)*F,S+=(W[H].cFactor||0)*F,x+=F}(Q=b.wps)==null||Q.forEach((H,F)=>{if(F){const O=b.wps[F-1],ft=H.distanceFromStart-O.distanceFromStart,nt=I(H.eta).diff(I(O.etd),"h",!0);if(nt<1)H.avgSpd=O.speed;else{H.avgSpd=Math.round(ft/nt*100)/100;const it=Math.round((O.speed+H.speed)/2*100)/100;H.avgSpd=H.avgSpd>it?it:H.avgSpd}}}),c.sample=b;const E=b.hours.at(0),B=b.hours.at(-1);c.distance=Math.round(B.distanceFromStart*1e4)/1e4,c.etd=I(E.eta).utc().format(),c.eta=I(B.eta).utc().format(),c.wxFactor=Math.round(k/x*1e4)/1e4,c.cFactor=Math.round(S/x*1e4)/1e4,c.avgSpeed=Math.round(B.distanceFromStart/x*1e4)/1e4,c.totalHrs=Math.round(x*1e4)/1e4,c.totalFoCons=Math.round((i==null?void 0:i.fo)/24*c.totalHrs*1e3)/1e3,c.totalDgoCons=Math.round((i==null?void 0:i.dgo)/24*c.totalHrs*1e3)/1e3;const P=I().valueOf()-m,A=((J=b==null?void 0:b.hours)==null?void 0:J.length)||1;return v==null||v.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms",l==null?void 0:l.requestId,P,A,Math.round(P/A*1e3)/1e3),c}static async analyseInstantWithThreshed(e,t,o,i,a,n,s,d="",r=3,l=!0,m=!1,f={}){var Z,z,U,Q;const h=I().valueOf();e.lng=R.LngLatHelper.convertToStdLng(e.lng);const{v0:u,label:g}=e.sog?{v0:e.sog,label:"Other"}:{v0:a.speed,label:"CP"},j=C.assembleProperties(i,a.loadCondition,u,0),y=R.LaneHelper.calculateSubRoute(e,n);if(((Z=y[0])==null?void 0:Z.length)<=1)return;const p=s.length?R.LaneHelper.calculateSubWaypoints(e,s):[];p.forEach(J=>J.important=!0);let c=R.LaneHelper.simplifyRouteToCoordinates(y,p,0),b=0,D=0,w=0,k=0;const S={hours:[],wps:[],days:[]};t=I(t).utc();const x=t.clone();for(;c.length>0;){const J=r-t.hour()%r;let H=Math.ceil(t.clone().add(J,"h").set({minute:0,second:0,millisecond:0}).diff(t,"h",!0)*1e4)/1e4;if(H=t.clone().add(H,"h").isAfter(o)?o.diff(t,"h",!0)*1e4/1e4:H,H){const F=await C.speedLoseInHoursStep(j,t,x,H,b,c,d,l,m,f);(z=F.from)!=null&&z.speed&&(S.hours.push(F.from),F!=null&&F.wps&&S.wps.push(...F.wps),S.days.push(...F.days)),c=F==null?void 0:F.next,c.length||S.hours.push(F==null?void 0:F.to),b+=Math.round((((U=F==null?void 0:F.to)==null?void 0:U.distanceFromPrevious)??0)*1e4)/1e4}else break}const L=S.hours;for(let J=0;J<L.length-1;J++){const H=I(L[J+1].eta).diff(L[J].etd,"hour",!0);D+=L[J].wxFactor*H,w+=L[J].cFactor*H,k+=H}const W=S.hours.at(0),E=S.hours.at(-1),B={sample:S,distance:Math.round(((E==null?void 0:E.distanceFromStart)||0)*1e4)/1e4,etd:I(W.eta).utc().format(),eta:I(E==null?void 0:E.eta).utc().format(),wxFactor:Math.round(D/k*1e4)/1e4,cFactor:Math.round(w/k*1e4)/1e4,avgSpeed:Math.round(((E==null?void 0:E.distanceFromStart)||0)/k*1e4)/1e4,totalHrs:Math.round(k*1e4)/1e4,totalFoCons:Math.round((a==null?void 0:a.fo)/24*k*1e3)/1e3,totalDgoCons:Math.round((a==null?void 0:a.dgo)/24*k*1e3)/1e3,from:W,to:E,route:y,waypoints:p,v0:u,label:g},P=I().valueOf()-h,A=((Q=S==null?void 0:S.hours)==null?void 0:Q.length)||1;return v==null||v.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms",f==null?void 0:f.requestId,P,A,Math.round(P/A*1e3)/1e3),B}static async analyseCost(e,t,o,i,a={}){var g,j;const n=I().valueOf(),s=[];a.meteo2=!0,e.speedStep=e.speedStep||3;const d=I.utc(e.etd).add(14,"day");let r=1;for(const y of o){v==null||v.info("[%s][L%d-%d] analyse from %s to %s",a.requestId,1,r,e.etd,d.format()),v==null||v.info("[%s][L%d-%d] analyse with cp: ",a.requestId,1,r,y);const p=JSON.parse(JSON.stringify(i.route)),c=JSON.parse(JSON.stringify(i.waypoints)),b=await C.analyseInstantWithThreshed({lat:e.lat,lng:e.lng},e.etd,d,t,y,p,c,e.meteoVendor,e.speedStep,!1,e.useRouteParam,a);b&&(await C.calculateCost(b,y,e,a),s.push(b),v==null||v.info("[%s][L%d-%d] cost: %j",a.requestId,1,r,{distance:b.distance,totalHrs:b.totalHrs,totalFoCons:b.totalFoCons,totalDgoCons:b.totalDgoCons,etd:b.etd,eta:b.eta,cost:b.cost})),r++}s.sort((y,p)=>y.cost.total-p.cost.total);const l=s.at(0),m=s.at(1),f=[];if(f.push({combined:!1,speeds:[l],cost:(g=l.cost)==null?void 0:g.total}),m){const y=l.cost.cp,p=m.cost.cp,c=I(l.eta),b=I(l.etd),D=c.diff(b,"days",!0);let w=Math.ceil(D/2);w=w>7?7:w;let k=2,S={combined:!1,speeds:[m],cost:(j=m.cost)==null?void 0:j.total},x;for(;w>=1&&(x=await C.combinedAnalyse(e,t,d,[y,p],i,w,{...a,level:k}),!(S.cost<x.cost));){const L=S;if(S=x,w===1){x=L;break}x=void 0,w=Math.ceil(w/2),k+=1}f.push(S),x&&f.push(x)}const u=I().valueOf()-n;return v==null||v.info("[%s] analyse elapsed: %d ms",a==null?void 0:a.requestId,u),f.sort((y,p)=>y.cost-p.cost)}static async combinedAnalyse(e,t,o,i,a,n,s={}){v==null||v.info("[%s][L%d] analyse with alternate cp in every %d days",s.requestId,s.level,n);const d=await C.alternateAnalyse(e,t,o,i,0,a,n,s),r=d.reduce((f,h)=>f+h.cost.total,0);v==null||v.info("[%s][L%d] cost with alternate cp a first: %j",s.requestId,s.level,{cost:r});const l=await C.alternateAnalyse(e,t,o,i,1,a,n,s),m=l.reduce((f,h)=>f+h.cost.total,0);return v==null||v.info("[%s][L%d] cost with alternate cp b first: %j",s.requestId,s.level,{cost:m}),r<m?{combined:!0,cost:Math.round(r*1e3)/1e3,speeds:d}:{combined:!0,cost:Math.round(m*1e3)/1e3,speeds:l}}static async alternateAnalyse(e,t,o,i,a,n,s,d={}){var h,u;let r=I.utc(e.etd),l=1;const m={lat:e.lat,lng:e.lng},f=[];for(;r.isBefore(o);){const g=r.clone().add(s,"day");v==null||v.info("[%s][L%d-%d] analyse from %s to %s",d.requestId,d.level,l,e.etd,g.format()),v==null||v.info("[%s][L%d-%d] analyse with cp: ",d.requestId,d.level,l,i[a]);const j=JSON.parse(JSON.stringify(n.route)),y=JSON.parse(JSON.stringify(n.waypoints)),p=await C.analyseInstantWithThreshed(m,r.format(),g,t,i[a],j,y,e.meteoVendor,e.speedStep,!1,e.useRouteParam,d);p&&(await C.calculateCost(p,i[a],e,d),v==null||v.info("[%s][L%d-%d] cost: %j",d.requestId,d.level,l,{distance:p.distance,totalHrs:p.totalHrs,totalFoCons:p.totalFoCons,totalDgoCons:p.totalDgoCons,etd:p.etd,eta:p.eta,cost:p.cost}));const c=(u=(h=p==null?void 0:p.sample)==null?void 0:h.hours)==null?void 0:u.at(-1);if(c)m.lat=c.lat,m.lng=c.lng,r=I(c.eta),f.push(p),l+=1,a=a?0:1;else break}return f}static async calculateCost(e,t,o,i={}){if(e){const a=Math.round(e.totalHrs/24*(o.dailyHire||0)*(1-(o.addComm||0))*1e3)/1e3,n=Math.round(e.totalFoCons*(o.priceFO||0)*1e3)/1e3,s=Math.round(e.totalDgoCons*(o.priceDGO||0)*1e3)/1e3;e.cost={total:Math.round((a+n+s)*1e3)/1e3,hire:a,bunker:Math.round((n+s)*1e3)/1e3,cp:t}}return e}static async mergeSpeeds(e,t={}){const o={hours:[],wps:[],days:[]},i=e.reduce((h,u)=>h+u.distance,0),a=e.reduce((h,u)=>h+u.totalHrs,0),n=e.reduce((h,u)=>h+u.wxFactor*u.totalHrs/a,0),s=e.reduce((h,u)=>h+u.cFactor*u.totalHrs/a,0),d=e.reduce((h,u)=>h+u.totalFoCons,0),r=e.reduce((h,u)=>h+u.totalDgoCons,0),l=e.reduce((h,u)=>h+u.cost.total,0),m=e.reduce((h,u)=>h+u.cost.hire,0),f=e.reduce((h,u)=>h+u.cost.bunker,0);for(const h of e){const u=h.sample.hours,g=h.sample.wps,j=h.sample.days;u.forEach(y=>{var c;((c=o.hours)==null?void 0:c.findIndex(b=>b.eta===y.eta))===-1&&o.hours.push(y)}),g.forEach(y=>{var c;((c=o.wps)==null?void 0:c.findIndex(b=>b.eta===y.eta))===-1&&o.wps.push(y)}),j.forEach(y=>{var c;((c=o==null?void 0:o.days)==null?void 0:c.findIndex(b=>b.eta===y.eta))===-1&&o.days.push(y)})}return{sample:o,etd:e.at(0).etd,eta:e.at(-1).eta,from:e.at(0).from,to:e.at(-1).to,label:"combined",distance:Math.round(i*1e4)/1e4,totalHrs:Math.round(a*1e3)/1e3,avgSpeed:Math.round(i/a*1e3)/1e3,wxFactor:Math.round(n/a*1e3)/1e3,cFactor:Math.round(s/a*1e3)/1e3,totalFoCons:Math.round(d*1e3)/1e3,totalDgoCons:Math.round(r*1e3)/1e3,cost:{total:Math.round(l*1e3)/1e3,hire:Math.round(m*1e3)/1e3,bunker:Math.round(f*1e3)/1e3}}}}T.AISImpl=G,T.AlertHelper=et,T.AlertLevel=tt,T.HifleetImpl=ct,T.LoadCondition=at,T.MyShipImpl=ut,T.MyVesselImpl=rt,T.ShipxyImpl=dt,T.SpeedHelper=C,T.SpeedLabel=ot,T.VesselTag=st,T.alertHelper=ht,Object.defineProperty(T,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -51,22 +51,36 @@ export interface VesselProperties {
|
|
|
51
51
|
speed: number;
|
|
52
52
|
bearing: number;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* 成本参数
|
|
56
|
+
*/
|
|
57
|
+
export interface CostProps {
|
|
58
|
+
addComm?: number;
|
|
59
|
+
dailyHire?: number;
|
|
60
|
+
priceFO?: number;
|
|
61
|
+
priceDGO?: number;
|
|
62
|
+
}
|
|
54
63
|
/**
|
|
55
64
|
* 速度计算参数
|
|
56
65
|
*/
|
|
57
|
-
export interface SpeedProps {
|
|
66
|
+
export interface SpeedProps extends CostProps {
|
|
58
67
|
usePerfSpeed?: boolean;
|
|
59
68
|
useRouteParam?: boolean;
|
|
60
69
|
lat?: number;
|
|
61
70
|
lng?: number;
|
|
62
71
|
etd?: string;
|
|
63
|
-
speedStep?:
|
|
64
|
-
forecastDay?:
|
|
65
|
-
meteoVendor?:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
speedStep?: number;
|
|
73
|
+
forecastDay?: number;
|
|
74
|
+
meteoVendor?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Cp参数
|
|
78
|
+
*/
|
|
79
|
+
export interface CpProps {
|
|
80
|
+
loadCondition: string | LoadCondition;
|
|
81
|
+
speed: number;
|
|
82
|
+
fo: number;
|
|
83
|
+
dgo: number;
|
|
70
84
|
}
|
|
71
85
|
export declare class SpeedHelper {
|
|
72
86
|
/**
|
|
@@ -194,17 +208,11 @@ export declare class SpeedHelper {
|
|
|
194
208
|
* @param useMeteo true 启用气象分析
|
|
195
209
|
* @param useRouteParam
|
|
196
210
|
*/
|
|
197
|
-
static analyseInstant(from: any, etd:
|
|
198
|
-
loadCondition: string;
|
|
199
|
-
speed: number;
|
|
200
|
-
fo: number;
|
|
201
|
-
dgo: number;
|
|
202
|
-
}, lane: {
|
|
211
|
+
static analyseInstant(from: any, etd: string | number | moment.Moment, vessel: VesselAssemble, cp: CpProps, lane: {
|
|
203
212
|
points: {
|
|
204
213
|
route: number[][][];
|
|
205
214
|
waypoints: any[];
|
|
206
215
|
};
|
|
207
|
-
voyage: any;
|
|
208
216
|
}, source?: string, stepHrs?: number, useMeteo?: boolean, useRouteParam?: boolean, options?: {
|
|
209
217
|
requestId?: string;
|
|
210
218
|
meteo2?: boolean;
|
|
@@ -222,12 +230,7 @@ export declare class SpeedHelper {
|
|
|
222
230
|
* @param useMeteo true 启用气象分析
|
|
223
231
|
* @param useRouteParam
|
|
224
232
|
*/
|
|
225
|
-
static analyseInstantWithThreshed(from: any, etd:
|
|
226
|
-
loadCondition: string;
|
|
227
|
-
speed: number;
|
|
228
|
-
fo?: number;
|
|
229
|
-
dgo?: number;
|
|
230
|
-
}, route: number[][][], waypoints: any[], source?: string, stepHrs?: number, useMeteo?: boolean, useRouteParam?: boolean, options?: {
|
|
233
|
+
static analyseInstantWithThreshed(from: any, etd: string | moment.Moment | number, threshed: moment.Moment, vessel: VesselAssemble, cp: CpProps, route: number[][][], waypoints: any[], source?: string, stepHrs?: number, useMeteo?: boolean, useRouteParam?: boolean, options?: {
|
|
231
234
|
requestId?: string;
|
|
232
235
|
meteo2?: boolean;
|
|
233
236
|
}): Promise<{
|
|
@@ -239,6 +242,8 @@ export declare class SpeedHelper {
|
|
|
239
242
|
cFactor: number;
|
|
240
243
|
avgSpeed: number;
|
|
241
244
|
totalHrs: number;
|
|
245
|
+
totalFoCons: number;
|
|
246
|
+
totalDgoCons: number;
|
|
242
247
|
from: any;
|
|
243
248
|
to: any;
|
|
244
249
|
route: any;
|
|
@@ -246,18 +251,99 @@ export declare class SpeedHelper {
|
|
|
246
251
|
v0: any;
|
|
247
252
|
label: SpeedLabel;
|
|
248
253
|
} | undefined>;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
254
|
+
/**
|
|
255
|
+
* 在指定航线条件下,基于多CP,动态计算最优成本(租金+油费)方案
|
|
256
|
+
* 1)首先分别计算单CP下的成本方案,基于成本排序,保留最省成本的两个方案,分别用 a, b 表示;
|
|
257
|
+
* 2) 选择步骤1)中a,b的CP,分别用 cpa, cpb 表示;
|
|
258
|
+
* 3) 基于当前有效天气预报时长(14天),按步长多次减半,分别用7,4,2,1天步长及cpa,cpb交替计算各种组合下的成本;
|
|
259
|
+
* 4)保留步骤3)中的最省成本的两个方案,并与步骤1)合并按成本排序,获取成本较优的三个方案;
|
|
260
|
+
* 5) 基于步骤4),同客户沟通后,最终基于时间和成本,选择最合适的方案;
|
|
261
|
+
*
|
|
262
|
+
*
|
|
263
|
+
* @param props 基础属性(位置,出发时间等)
|
|
264
|
+
* @param vessel 船舶档案(长、宽、吃水、船舶类型等)
|
|
265
|
+
* @param cps CP条款(装载状态,速度、油耗等)
|
|
266
|
+
* @param lane 基础航线(重要转向点)
|
|
267
|
+
* @param options
|
|
268
|
+
*/
|
|
269
|
+
static analyseCost(props: SpeedProps, vessel: VesselAssemble, cps: CpProps[], lane: {
|
|
270
|
+
route: number[][][];
|
|
271
|
+
waypoints: any[];
|
|
260
272
|
}, options?: {
|
|
261
273
|
requestId?: string;
|
|
262
|
-
|
|
274
|
+
meteo2?: boolean;
|
|
275
|
+
}): Promise<any[]>;
|
|
276
|
+
/**
|
|
277
|
+
* 按步长多次减半,分别用7,4,2,1天步长及cpa,cpb交替计算各种组合下的成本
|
|
278
|
+
* @param props 基础属性(位置,出发时间,日租金,FO/DO/GO单价等)
|
|
279
|
+
* @param vessel 船舶档案(长、宽、吃水、船舶类型等)
|
|
280
|
+
* @param cps CP条款(装载状态,速度、油耗等)
|
|
281
|
+
* @param max 最长分析未来14天
|
|
282
|
+
* @param lane 基础航线(重要转向点)
|
|
283
|
+
* @param step 步长,7,4,2,1
|
|
284
|
+
* @param options
|
|
285
|
+
*/
|
|
286
|
+
static combinedAnalyse(props: SpeedProps, vessel: VesselAssemble, max: moment.Moment, cps: CpProps[], lane: {
|
|
287
|
+
route: number[][][];
|
|
288
|
+
waypoints: any[];
|
|
289
|
+
}, step: number, options?: {
|
|
290
|
+
requestId?: string;
|
|
291
|
+
meteo2?: boolean;
|
|
292
|
+
level?: number;
|
|
293
|
+
}): Promise<{
|
|
294
|
+
combined: boolean;
|
|
295
|
+
cost: number;
|
|
296
|
+
speeds: any[];
|
|
297
|
+
}>;
|
|
298
|
+
/**
|
|
299
|
+
* 基于cp索引,交替计算指定步长下的成本
|
|
300
|
+
* @param props 基础属性(位置,出发时间等)
|
|
301
|
+
* @param vessel 船舶档案(长、宽、吃水、船舶类型等)
|
|
302
|
+
* @param cps CP条款(装载状态,速度、油耗等)
|
|
303
|
+
* @param cpIndex cp索引
|
|
304
|
+
* @param max 最长分析未来14天
|
|
305
|
+
* @param lane 基础航线(重要转向点)
|
|
306
|
+
* @param step 步长,7,4,2,1
|
|
307
|
+
* @param options
|
|
308
|
+
*/
|
|
309
|
+
static alternateAnalyse(props: SpeedProps, vessel: VesselAssemble, max: moment.Moment, cps: CpProps[], cpIndex: number, lane: {
|
|
310
|
+
route: number[][][];
|
|
311
|
+
waypoints: any[];
|
|
312
|
+
}, step: number, options?: {
|
|
313
|
+
requestId?: string;
|
|
314
|
+
meteo2?: boolean;
|
|
315
|
+
level?: number;
|
|
316
|
+
}): Promise<any[]>;
|
|
317
|
+
/**
|
|
318
|
+
* 计算Speed的cost
|
|
319
|
+
* @param speed
|
|
320
|
+
* @param cp
|
|
321
|
+
* @param props
|
|
322
|
+
* @param options
|
|
323
|
+
*/
|
|
324
|
+
static calculateCost(speed: any, cp: CpProps, props: CostProps, options?: {
|
|
325
|
+
requestId?: string;
|
|
326
|
+
}): Promise<any>;
|
|
327
|
+
static mergeSpeeds(speeds: any[], options?: {
|
|
328
|
+
requestId?: string;
|
|
329
|
+
}): Promise<{
|
|
330
|
+
sample: any;
|
|
331
|
+
etd: any;
|
|
332
|
+
eta: any;
|
|
333
|
+
from: any;
|
|
334
|
+
to: any;
|
|
335
|
+
label: string;
|
|
336
|
+
distance: number;
|
|
337
|
+
totalHrs: number;
|
|
338
|
+
avgSpeed: number;
|
|
339
|
+
wxFactor: number;
|
|
340
|
+
cFactor: number;
|
|
341
|
+
totalFoCons: number;
|
|
342
|
+
totalDgoCons: number;
|
|
343
|
+
cost: {
|
|
344
|
+
total: number;
|
|
345
|
+
hire: number;
|
|
346
|
+
bunker: number;
|
|
347
|
+
};
|
|
348
|
+
}>;
|
|
263
349
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idm-plugin/vessel",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"description": "idm plugin for vessel",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"keywords": [
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@idm-plugin/geo": "^1.5.7",
|
|
31
31
|
"@idm-plugin/meteo": "^0.2.6",
|
|
32
|
-
"@idm-plugin/meteo2": "^0.1.
|
|
32
|
+
"@idm-plugin/meteo2": "^0.1.5",
|
|
33
33
|
"@log4js-node/log4js-api": "^1.0.2",
|
|
34
34
|
"got": "11",
|
|
35
35
|
"moment": "^2.30.1"
|