@idm-plugin/vessel 1.1.9 → 1.2.1
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.d.ts +1 -0
- package/dist/index.js +738 -379
- package/dist/index.umd.cjs +1 -1
- package/dist/speed/src/index.d.ts +216 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,220 +1,222 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
var Q = Object.defineProperty;
|
|
2
|
+
var X = (k, s, t) => s in k ? Q(k, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : k[s] = t;
|
|
3
|
+
var L = (k, s, t) => (X(k, typeof s != "symbol" ? s + "" : s, t), t);
|
|
4
|
+
import P from "got";
|
|
5
|
+
import K from "@log4js-node/log4js-api";
|
|
6
|
+
import y from "moment";
|
|
7
|
+
import { LngLatHelper as _, LaneHelper as R } from "@idm-plugin/geo";
|
|
8
|
+
import { MeteoHelper as tt } from "@idm-plugin/meteo";
|
|
9
|
+
const S = K.getLogger("vessel");
|
|
10
|
+
class Z {
|
|
9
11
|
/**
|
|
10
12
|
* 解析AIS状态码
|
|
11
13
|
* @param status
|
|
12
14
|
*/
|
|
13
|
-
parseStatus(
|
|
14
|
-
let
|
|
15
|
-
switch (
|
|
15
|
+
parseStatus(s) {
|
|
16
|
+
let t, r;
|
|
17
|
+
switch (s) {
|
|
16
18
|
case 0:
|
|
17
|
-
|
|
19
|
+
t = "在航(主机推动)", r = "The engine is in use";
|
|
18
20
|
break;
|
|
19
21
|
case 1:
|
|
20
|
-
|
|
22
|
+
t = "锚泊", r = "Anchored";
|
|
21
23
|
break;
|
|
22
24
|
case 2:
|
|
23
|
-
|
|
25
|
+
t = "失控", r = "Not operated";
|
|
24
26
|
break;
|
|
25
27
|
case 3:
|
|
26
|
-
|
|
28
|
+
t = "操纵受限", r = "Limited airworthiness";
|
|
27
29
|
break;
|
|
28
30
|
case 4:
|
|
29
|
-
|
|
31
|
+
t = "吃水受限", r = "Limited by ship's draft";
|
|
30
32
|
break;
|
|
31
33
|
case 5:
|
|
32
|
-
|
|
34
|
+
t = "靠泊", r = "Mooring";
|
|
33
35
|
break;
|
|
34
36
|
case 6:
|
|
35
|
-
|
|
37
|
+
t = "搁浅", r = "Stranded";
|
|
36
38
|
break;
|
|
37
39
|
case 7:
|
|
38
|
-
|
|
40
|
+
t = "捕捞作业", r = "Engaged in fishing";
|
|
39
41
|
break;
|
|
40
42
|
case 8:
|
|
41
|
-
|
|
43
|
+
t = "靠帆船提供动力", r = "Sailing";
|
|
42
44
|
break;
|
|
43
45
|
default:
|
|
44
|
-
|
|
46
|
+
t = "未定义", r = "Undefined";
|
|
45
47
|
}
|
|
46
|
-
return { labelCn:
|
|
48
|
+
return { labelCn: t, labelEn: r };
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
|
-
class
|
|
50
|
-
constructor(
|
|
51
|
+
class lt extends Z {
|
|
52
|
+
constructor(t, r) {
|
|
51
53
|
super();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.clientId =
|
|
54
|
+
L(this, "clientId");
|
|
55
|
+
L(this, "clientSecret");
|
|
56
|
+
L(this, "token");
|
|
57
|
+
this.clientId = t, this.clientSecret = r;
|
|
56
58
|
}
|
|
57
|
-
async authToken(
|
|
58
|
-
const
|
|
59
|
+
async authToken(t = {}) {
|
|
60
|
+
const r = "https://svc.data.myvessel.cn/ada/oauth/token", o = {
|
|
59
61
|
searchParams: {
|
|
60
62
|
client_id: this.clientId,
|
|
61
63
|
client_secret: this.clientSecret,
|
|
62
64
|
grant_type: "client_credentials"
|
|
63
65
|
}
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
accessToken:
|
|
67
|
-
tokenType:
|
|
68
|
-
expiresIn:
|
|
69
|
-
scope:
|
|
70
|
-
jti:
|
|
71
|
-
issuedAt:
|
|
66
|
+
}, n = await P.post(r, o).json();
|
|
67
|
+
S.info("[%s] fetch access token from: %s - %j", t.requestId, r, n), n.error || (this.token = {
|
|
68
|
+
accessToken: n.access_token,
|
|
69
|
+
tokenType: n.token_type,
|
|
70
|
+
expiresIn: n.expires_in,
|
|
71
|
+
scope: n.scope,
|
|
72
|
+
jti: n.jti,
|
|
73
|
+
issuedAt: y().utc().format()
|
|
72
74
|
});
|
|
73
75
|
}
|
|
74
|
-
async realTimePosition(
|
|
75
|
-
var
|
|
76
|
-
(!this.token ||
|
|
77
|
-
const
|
|
76
|
+
async realTimePosition(t, r = {}) {
|
|
77
|
+
var m, g, p;
|
|
78
|
+
(!this.token || y().diff(y(this.token.issuedAt), "seconds") > ((m = this.token) == null ? void 0 : m.expiresIn) - 300) && await this.authToken(r);
|
|
79
|
+
const o = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit", n = {
|
|
78
80
|
headers: {
|
|
79
|
-
Authorization: `${(
|
|
81
|
+
Authorization: `${(g = this.token) == null ? void 0 : g.tokenType} ${(p = this.token) == null ? void 0 : p.accessToken}`
|
|
80
82
|
},
|
|
81
|
-
searchParams: { mmsi:
|
|
83
|
+
searchParams: { mmsi: t }
|
|
82
84
|
};
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
86
|
-
return
|
|
87
|
-
const
|
|
88
|
-
for (const
|
|
89
|
-
!isNaN(
|
|
90
|
-
const
|
|
85
|
+
S.info("[%s] fetch realtime position from: %s - %j", r.requestId, o, n);
|
|
86
|
+
const a = await P.get(o, n).json();
|
|
87
|
+
if (a.code)
|
|
88
|
+
return S.warn("[%s] fetch realtime position failed: %j", r.requestId, o, { message: a.message, status: a.status, code: a.code }), a;
|
|
89
|
+
const e = a.data;
|
|
90
|
+
for (const f in e)
|
|
91
|
+
!isNaN(e[f]) && Number(e[f]) !== 1 / 0 && (e[f] = Number(e[f]));
|
|
92
|
+
const d = y(`${e.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
91
93
|
return {
|
|
92
|
-
mmsi:
|
|
93
|
-
name:
|
|
94
|
-
imo:
|
|
95
|
-
callSign:
|
|
96
|
-
lat:
|
|
97
|
-
lng:
|
|
98
|
-
length:
|
|
99
|
-
width:
|
|
100
|
-
draught:
|
|
101
|
-
sog:
|
|
102
|
-
cog:
|
|
103
|
-
hdg:
|
|
104
|
-
rot:
|
|
105
|
-
eta:
|
|
106
|
-
destination:
|
|
107
|
-
positionTime:
|
|
108
|
-
status:
|
|
109
|
-
labelCn:
|
|
110
|
-
labelEn:
|
|
94
|
+
mmsi: e.mmsi,
|
|
95
|
+
name: e.vesselName,
|
|
96
|
+
imo: e.imo,
|
|
97
|
+
callSign: e.callsign,
|
|
98
|
+
lat: e.lat,
|
|
99
|
+
lng: e.lon,
|
|
100
|
+
length: e.length,
|
|
101
|
+
width: e.width,
|
|
102
|
+
draught: e.currDraught,
|
|
103
|
+
sog: e.sog,
|
|
104
|
+
cog: e.cog,
|
|
105
|
+
hdg: e.hdg,
|
|
106
|
+
rot: e.rot,
|
|
107
|
+
eta: e.eta,
|
|
108
|
+
destination: e.dest,
|
|
109
|
+
positionTime: d.unix(),
|
|
110
|
+
status: e.status,
|
|
111
|
+
labelCn: e.statusNameCn,
|
|
112
|
+
labelEn: e.statusNameEn,
|
|
111
113
|
method: "position",
|
|
112
114
|
vendor: "myVessel",
|
|
113
|
-
utc:
|
|
115
|
+
utc: d.utc().format()
|
|
114
116
|
};
|
|
115
117
|
}
|
|
116
|
-
async trajectory(
|
|
117
|
-
(!this.token ||
|
|
118
|
-
const
|
|
119
|
-
for (;
|
|
120
|
-
await this.trajectoryIn30Day(
|
|
121
|
-
return await this.trajectoryIn30Day(
|
|
118
|
+
async trajectory(t, r, o, n, a = !0, e = {}) {
|
|
119
|
+
(!this.token || y().diff(y(this.token.issuedAt), "seconds") > this.token.expiresIn - 300) && await this.authToken(e);
|
|
120
|
+
const d = await this.realTimePosition(t, e), i = y(r), m = y(o), g = [];
|
|
121
|
+
for (; m.diff(i, "day", !0) > 30; )
|
|
122
|
+
await this.trajectoryIn30Day(t, i, i.clone().add(30, "day"), d, n, g, e), i.add(30, "day");
|
|
123
|
+
return await this.trajectoryIn30Day(t, i, m, d, n, g, e), g;
|
|
122
124
|
}
|
|
123
|
-
async trajectoryIn30Day(
|
|
124
|
-
var
|
|
125
|
-
const i = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/track",
|
|
125
|
+
async trajectoryIn30Day(t, r, o, n, a, e, d = {}) {
|
|
126
|
+
var l, b, I, u, c;
|
|
127
|
+
const i = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/track", m = {
|
|
126
128
|
headers: {
|
|
127
|
-
Authorization: `${(
|
|
129
|
+
Authorization: `${(l = this.token) == null ? void 0 : l.tokenType} ${(b = this.token) == null ? void 0 : b.accessToken}`
|
|
128
130
|
},
|
|
129
131
|
json: {
|
|
130
|
-
mmsi:
|
|
131
|
-
startTime:
|
|
132
|
-
endTime:
|
|
132
|
+
mmsi: t,
|
|
133
|
+
startTime: r.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),
|
|
134
|
+
endTime: o.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")
|
|
133
135
|
}
|
|
134
136
|
};
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
return
|
|
139
|
-
let
|
|
140
|
-
const
|
|
141
|
-
return (
|
|
142
|
-
for (const
|
|
143
|
-
!isNaN(
|
|
144
|
-
const
|
|
145
|
-
mmsi:
|
|
146
|
-
imo:
|
|
147
|
-
lat:
|
|
148
|
-
lng:
|
|
149
|
-
sog:
|
|
150
|
-
cog:
|
|
151
|
-
hdg:
|
|
152
|
-
draught:
|
|
153
|
-
status:
|
|
154
|
-
eta:
|
|
155
|
-
destination:
|
|
156
|
-
positionTime:
|
|
157
|
-
labelCn:
|
|
158
|
-
labelEn:
|
|
137
|
+
S.info("[%s] fetch trajectory from: %s - %j", d.requestId, i, m);
|
|
138
|
+
const g = await P.post(i, m).json();
|
|
139
|
+
if (g.code)
|
|
140
|
+
return S.warn("[%s] fetch trajectory failed: %j", d.requestId, i, { message: g.message, status: g.status, code: g.code }), g;
|
|
141
|
+
let p = -1;
|
|
142
|
+
const f = y(`${(u = (I = g.data) == null ? void 0 : I[0]) == null ? void 0 : u.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
143
|
+
return (c = g.data) == null || c.forEach((h) => {
|
|
144
|
+
for (const T in h)
|
|
145
|
+
!isNaN(h[T]) && Number(h[T]) !== 1 / 0 && (h[T] = Number(h[T]));
|
|
146
|
+
const v = y(`${h.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00"), w = h.eta ? y(`${h.eta} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00") : void 0, M = h.status, { labelCn: x, labelEn: N } = this.parseStatus(M), C = {
|
|
147
|
+
mmsi: h.mmsi,
|
|
148
|
+
imo: n == null ? void 0 : n.imo,
|
|
149
|
+
lat: h.lat,
|
|
150
|
+
lng: h.lon,
|
|
151
|
+
sog: h.sog,
|
|
152
|
+
cog: h.cog,
|
|
153
|
+
hdg: h.hdg,
|
|
154
|
+
draught: h.draught,
|
|
155
|
+
status: M,
|
|
156
|
+
eta: w == null ? void 0 : w.unix(),
|
|
157
|
+
destination: h.dest,
|
|
158
|
+
positionTime: v.unix(),
|
|
159
|
+
labelCn: x,
|
|
160
|
+
labelEn: N,
|
|
159
161
|
method: "trajectory",
|
|
160
162
|
vendor: "myVessel",
|
|
161
|
-
utc:
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
}),
|
|
163
|
+
utc: v.utc().format()
|
|
164
|
+
}, j = Math.floor(v.diff(f, "minute", !0) / (a || 1));
|
|
165
|
+
j !== p && (p = j, e.push(C));
|
|
166
|
+
}), e;
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
|
-
class
|
|
168
|
-
constructor(
|
|
169
|
+
class ft extends Z {
|
|
170
|
+
constructor(t) {
|
|
169
171
|
super();
|
|
170
|
-
|
|
171
|
-
this.token =
|
|
172
|
+
L(this, "token");
|
|
173
|
+
this.token = t;
|
|
172
174
|
}
|
|
173
|
-
async realTimePosition(
|
|
174
|
-
const
|
|
175
|
+
async realTimePosition(t, r = {}) {
|
|
176
|
+
const o = "https://api.hifleet.com/position/position/get/token", n = {
|
|
175
177
|
searchParams: {
|
|
176
|
-
mmsi:
|
|
178
|
+
mmsi: t,
|
|
177
179
|
usertoken: this.token
|
|
178
180
|
}
|
|
179
|
-
},
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
if (!
|
|
183
|
-
return
|
|
184
|
-
for (const
|
|
185
|
-
!isNaN(
|
|
186
|
-
|
|
187
|
-
const
|
|
181
|
+
}, a = await P.post(o, n).json();
|
|
182
|
+
S.info("[%s] fetch realtime position from: %s - %j", r.requestId, o, n);
|
|
183
|
+
const e = a == null ? void 0 : a.list;
|
|
184
|
+
if (!e)
|
|
185
|
+
return S.warn("[%s] fetch realtime position failed: %j", r.requestId, o, a), a;
|
|
186
|
+
for (const f in e)
|
|
187
|
+
!isNaN(e[f]) && Number(e[f]) !== 1 / 0 && (e[f] = Number(e[f]));
|
|
188
|
+
e.status = e.sp > 3 ? 0 : 1;
|
|
189
|
+
const d = e.status, { labelCn: i, labelEn: m } = this.parseStatus(d), g = y(`${e.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
188
190
|
return {
|
|
189
|
-
mmsi:
|
|
190
|
-
name:
|
|
191
|
-
imo:
|
|
192
|
-
callSign:
|
|
193
|
-
lat: Math.round(
|
|
194
|
-
lng: Math.round(
|
|
195
|
-
length:
|
|
196
|
-
width:
|
|
197
|
-
draught:
|
|
198
|
-
sog:
|
|
199
|
-
cog:
|
|
200
|
-
hdg:
|
|
201
|
-
rot: isNaN(
|
|
202
|
-
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(
|
|
203
|
-
destination:
|
|
204
|
-
positionTime:
|
|
205
|
-
utc:
|
|
206
|
-
status:
|
|
191
|
+
mmsi: e.m,
|
|
192
|
+
name: e.n,
|
|
193
|
+
imo: e.imonumber,
|
|
194
|
+
callSign: e.callsign,
|
|
195
|
+
lat: Math.round(e.la / 60 * 1e5) / 1e5,
|
|
196
|
+
lng: Math.round(e.lo / 60 * 1e5) / 1e5,
|
|
197
|
+
length: e.l,
|
|
198
|
+
width: e.w,
|
|
199
|
+
draught: e.draught,
|
|
200
|
+
sog: e.sp,
|
|
201
|
+
cog: e.co,
|
|
202
|
+
hdg: e.h,
|
|
203
|
+
rot: isNaN(e.rot) ? 0 : e.rot,
|
|
204
|
+
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e.eta) ? y(`${e.eta} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00").unix() : void 0,
|
|
205
|
+
destination: e.destination,
|
|
206
|
+
positionTime: g.unix(),
|
|
207
|
+
utc: g.utc().format(),
|
|
208
|
+
status: d,
|
|
207
209
|
labelCn: i,
|
|
208
|
-
labelEn:
|
|
210
|
+
labelEn: m,
|
|
209
211
|
method: "position",
|
|
210
212
|
vendor: "hifleet"
|
|
211
213
|
};
|
|
212
214
|
}
|
|
213
|
-
async search(
|
|
214
|
-
let
|
|
215
|
-
const
|
|
215
|
+
async search(t, r = {}) {
|
|
216
|
+
let o = "https://www.hifleet.com/hifleetapi/searchVesselOL.do";
|
|
217
|
+
const n = {
|
|
216
218
|
searchParams: {
|
|
217
|
-
keyword:
|
|
219
|
+
keyword: t
|
|
218
220
|
},
|
|
219
221
|
headers: {
|
|
220
222
|
Referer: "https://www.hifleet.com",
|
|
@@ -222,206 +224,206 @@ class J extends V {
|
|
|
222
224
|
Host: "www.hifleet.com"
|
|
223
225
|
}
|
|
224
226
|
};
|
|
225
|
-
let
|
|
226
|
-
|
|
227
|
-
for (const
|
|
228
|
-
!isNaN(
|
|
229
|
-
const
|
|
230
|
-
mmsi:
|
|
231
|
-
name:
|
|
232
|
-
imo:
|
|
233
|
-
callSign:
|
|
234
|
-
length:
|
|
235
|
-
breadth:
|
|
236
|
-
draught:
|
|
227
|
+
let a = await P.post(o, n).json();
|
|
228
|
+
S.info("[%s] fetch vessel props from: %s - %j", r.requestId, o, n), a instanceof Array && (a = a[0]);
|
|
229
|
+
for (const d in a)
|
|
230
|
+
!isNaN(a[d]) && Number(a[d]) !== 1 / 0 && (a[d] = Number(a[d]));
|
|
231
|
+
const e = {
|
|
232
|
+
mmsi: a.m,
|
|
233
|
+
name: a.n,
|
|
234
|
+
imo: a.i,
|
|
235
|
+
callSign: a.c,
|
|
236
|
+
length: a.l,
|
|
237
|
+
breadth: a.b,
|
|
238
|
+
draught: a.dr
|
|
237
239
|
};
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
async trajectory(
|
|
241
|
-
var
|
|
242
|
-
const
|
|
243
|
-
let i =
|
|
244
|
-
const
|
|
245
|
-
if (
|
|
246
|
-
let
|
|
247
|
-
|
|
240
|
+
return o = "https://www.hifleet.com/hifleetapi/sameShipSearch.do", a = await P.post(o, n).json(), S.info("[%s] fetch vessel dead weight from: %s - %j", r.requestId, o, n), a instanceof Array && (a = a[0]), a && (e.deadweight = Number(a.dwt)), e;
|
|
241
|
+
}
|
|
242
|
+
async trajectory(t, r, o, n, a = !0, e = {}) {
|
|
243
|
+
var h, v, w;
|
|
244
|
+
const d = await this.realTimePosition(t, e);
|
|
245
|
+
let i = y(r);
|
|
246
|
+
const m = y(o), g = y();
|
|
247
|
+
if (a) {
|
|
248
|
+
let M = m.diff(i, "d", !0);
|
|
249
|
+
M < 0 ? i = m.clone().subtract(40, "d") : M < 30 ? i.subtract(10, "d") : M < 60 ? i.subtract(5, "d") : i = m.clone().subtract(80, "d"), M = g.diff(m, "d", !0), m.add(M > 10 ? 240 : M * 24, "h");
|
|
248
250
|
}
|
|
249
|
-
const
|
|
251
|
+
const p = {
|
|
250
252
|
searchParams: {
|
|
251
|
-
endtime:
|
|
253
|
+
endtime: m.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),
|
|
252
254
|
starttime: i.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),
|
|
253
|
-
mmsi:
|
|
255
|
+
mmsi: t,
|
|
254
256
|
usertoken: this.token
|
|
255
257
|
}
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
let
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
let
|
|
262
|
-
const
|
|
263
|
-
for (const
|
|
264
|
-
for (const
|
|
265
|
-
!isNaN(
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
const { labelEn:
|
|
269
|
-
mmsi:
|
|
270
|
-
name:
|
|
271
|
-
imo:
|
|
272
|
-
lat:
|
|
273
|
-
lng:
|
|
274
|
-
draught:
|
|
275
|
-
sog:
|
|
276
|
-
cog:
|
|
277
|
-
hdg:
|
|
278
|
-
positionTime:
|
|
279
|
-
utc:
|
|
280
|
-
status:
|
|
281
|
-
labelCn:
|
|
282
|
-
labelEn:
|
|
258
|
+
}, f = "https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token", l = await P.get(f, p).json();
|
|
259
|
+
S.info("[%s] fetch trajectory from: %s - %j", e.requestId, f, p);
|
|
260
|
+
let b;
|
|
261
|
+
l && (b = ((v = (h = l.ships) == null ? void 0 : h.offors) == null ? void 0 : v.ship) || [], b.length || S.warn("[%s] fetch trajectory failed: %j", e.requestId, l));
|
|
262
|
+
const I = [];
|
|
263
|
+
let u = -1;
|
|
264
|
+
const c = y(`${(w = b == null ? void 0 : b[0]) == null ? void 0 : w.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
265
|
+
for (const M of b) {
|
|
266
|
+
for (const A in M)
|
|
267
|
+
!isNaN(M[A]) && Number(M[A]) !== 1 / 0 && (M[A] = Number(M[A]));
|
|
268
|
+
const x = y(`${M.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
269
|
+
M.status = M.sp > 4 ? 0 : 1;
|
|
270
|
+
const { labelEn: N, labelCn: C } = this.parseStatus(M.status), j = {
|
|
271
|
+
mmsi: M.m,
|
|
272
|
+
name: M.n,
|
|
273
|
+
imo: d == null ? void 0 : d.imo,
|
|
274
|
+
lat: M.la,
|
|
275
|
+
lng: M.lo,
|
|
276
|
+
draught: M.draught,
|
|
277
|
+
sog: M.sp,
|
|
278
|
+
cog: M.co,
|
|
279
|
+
hdg: M.hdg,
|
|
280
|
+
positionTime: x.unix(),
|
|
281
|
+
utc: x.utc().format(),
|
|
282
|
+
status: M.status,
|
|
283
|
+
labelCn: C,
|
|
284
|
+
labelEn: N,
|
|
283
285
|
method: "trajectory",
|
|
284
286
|
vendor: "hifleet"
|
|
285
|
-
},
|
|
286
|
-
|
|
287
|
+
}, T = Math.floor(x.diff(c, "minute", !0) / (n || 1));
|
|
288
|
+
T !== u && (u = T, I.push(j));
|
|
287
289
|
}
|
|
288
|
-
return
|
|
290
|
+
return I;
|
|
289
291
|
}
|
|
290
292
|
}
|
|
291
|
-
class
|
|
292
|
-
constructor(
|
|
293
|
+
class mt extends Z {
|
|
294
|
+
constructor(t) {
|
|
293
295
|
super();
|
|
294
|
-
|
|
295
|
-
this.token =
|
|
296
|
+
L(this, "token");
|
|
297
|
+
this.token = t;
|
|
296
298
|
}
|
|
297
|
-
async realTimePosition(
|
|
298
|
-
const
|
|
299
|
+
async realTimePosition(t, r = {}) {
|
|
300
|
+
const o = {
|
|
299
301
|
searchParams: {
|
|
300
|
-
id:
|
|
302
|
+
id: t,
|
|
301
303
|
k: this.token,
|
|
302
304
|
enc: 1
|
|
303
305
|
}
|
|
304
|
-
},
|
|
305
|
-
if (
|
|
306
|
-
return
|
|
307
|
-
const
|
|
308
|
-
for (const
|
|
309
|
-
!isNaN(
|
|
310
|
-
const { labelCn:
|
|
306
|
+
}, n = "https://api.shipxy.com/apicall/GetSingleShip", a = await P.get(n, o).json();
|
|
307
|
+
if (S.info("[%s] fetch realtime position from: %s - %j", r.requestId, n, o), (a == null ? void 0 : a.status) !== 0)
|
|
308
|
+
return a;
|
|
309
|
+
const e = a.data[0];
|
|
310
|
+
for (const p in e)
|
|
311
|
+
!isNaN(e[p]) && Number(e[p]) !== 1 / 0 && (e[p] = Number(e[p]));
|
|
312
|
+
const { labelCn: d, labelEn: i } = await this.parseStatus(e.navistat), m = y.unix(e.lasttime);
|
|
311
313
|
return {
|
|
312
|
-
mmsi:
|
|
313
|
-
name:
|
|
314
|
-
imo:
|
|
315
|
-
callSign:
|
|
316
|
-
lat: Math.round(
|
|
317
|
-
lng: Math.round(
|
|
318
|
-
length: Math.round(
|
|
319
|
-
width: Math.round(
|
|
320
|
-
draught: Math.round(
|
|
321
|
-
sog: Math.round(
|
|
322
|
-
cog: Math.round(
|
|
323
|
-
hdg: Math.round(
|
|
324
|
-
rot: Math.round(
|
|
325
|
-
positionTime:
|
|
326
|
-
utc:
|
|
327
|
-
status:
|
|
314
|
+
mmsi: e.ShipID,
|
|
315
|
+
name: e.name,
|
|
316
|
+
imo: e.imo,
|
|
317
|
+
callSign: e.callsign,
|
|
318
|
+
lat: Math.round(e.lat / 1e6 * 1e5) / 1e5,
|
|
319
|
+
lng: Math.round(e.lon / 1e6 * 1e5) / 1e5,
|
|
320
|
+
length: Math.round(e.length / 10 * 100) / 100,
|
|
321
|
+
width: Math.round(e.width / 10 * 100) / 100,
|
|
322
|
+
draught: Math.round(e.draught / 1e3 * 100) / 100,
|
|
323
|
+
sog: Math.round(e.sog * 3600 / 1e3 / 1852 * 100) / 100,
|
|
324
|
+
cog: Math.round(e.cog / 100 * 100) / 100,
|
|
325
|
+
hdg: Math.round(e.hdg / 100 * 100) / 100,
|
|
326
|
+
rot: Math.round(e.rot / 100 * 100) / 100,
|
|
327
|
+
positionTime: e.lasttime,
|
|
328
|
+
utc: m.utc().format(),
|
|
329
|
+
status: e.navistat,
|
|
328
330
|
labelEn: i,
|
|
329
|
-
labelCn:
|
|
331
|
+
labelCn: d,
|
|
330
332
|
method: "position",
|
|
331
333
|
vendor: "shipxy"
|
|
332
334
|
};
|
|
333
335
|
}
|
|
334
|
-
async trajectory(
|
|
335
|
-
var
|
|
336
|
-
const
|
|
336
|
+
async trajectory(t, r, o, n, a = !0, e = {}) {
|
|
337
|
+
var c;
|
|
338
|
+
const d = await this.realTimePosition(t, e), i = y(r), m = y(o), g = "https://api.shipxy.com/apicall/GetShipTrack", p = {
|
|
337
339
|
searchParams: {
|
|
338
|
-
id:
|
|
340
|
+
id: t,
|
|
339
341
|
k: this.token,
|
|
340
342
|
enc: 1,
|
|
341
343
|
cut: 0,
|
|
342
344
|
btm: i.unix(),
|
|
343
|
-
etm:
|
|
345
|
+
etm: m.unix()
|
|
344
346
|
}
|
|
345
|
-
},
|
|
346
|
-
if (
|
|
347
|
-
return
|
|
348
|
-
const
|
|
349
|
-
let
|
|
350
|
-
for (const
|
|
351
|
-
const
|
|
352
|
-
imo:
|
|
353
|
-
mmsi:
|
|
354
|
-
sog: Math.round(
|
|
355
|
-
cog: Math.round(
|
|
356
|
-
lat: Math.round(
|
|
357
|
-
lng: Math.round(
|
|
358
|
-
positionTime:
|
|
359
|
-
utc:
|
|
347
|
+
}, f = await P.get(g, p).json();
|
|
348
|
+
if (S.info("[%s] fetch trajectory from: %s - %j", e.requestId, g, p), (f == null ? void 0 : f.status) !== 0)
|
|
349
|
+
return f;
|
|
350
|
+
const l = f == null ? void 0 : f.points, b = [], I = y.unix((c = l[0]) == null ? void 0 : c.utc);
|
|
351
|
+
let u = -1;
|
|
352
|
+
for (const h of l) {
|
|
353
|
+
const v = y.unix(h.utc), w = {
|
|
354
|
+
imo: d == null ? void 0 : d.imo,
|
|
355
|
+
mmsi: t,
|
|
356
|
+
sog: Math.round(h.sog * 3600 / 1e3 / 1852 * 100) / 100,
|
|
357
|
+
cog: Math.round(h.cog / 100 * 100) / 100,
|
|
358
|
+
lat: Math.round(h.lat / 1e6 * 1e5) / 1e5,
|
|
359
|
+
lng: Math.round(h.lon / 1e6 * 1e5) / 1e5,
|
|
360
|
+
positionTime: v.unix(),
|
|
361
|
+
utc: v.utc().format(),
|
|
360
362
|
method: "trajectory",
|
|
361
363
|
vendor: "shipxy"
|
|
362
|
-
},
|
|
363
|
-
|
|
364
|
+
}, M = Math.floor(v.diff(I, "minute", !0) / (n || 1));
|
|
365
|
+
M !== u && (u = M, b.push(w));
|
|
364
366
|
}
|
|
365
|
-
return
|
|
367
|
+
return b;
|
|
366
368
|
}
|
|
367
369
|
}
|
|
368
|
-
class
|
|
369
|
-
constructor(
|
|
370
|
+
class gt extends Z {
|
|
371
|
+
constructor(t) {
|
|
370
372
|
super();
|
|
371
|
-
|
|
372
|
-
this.token =
|
|
373
|
+
L(this, "token");
|
|
374
|
+
this.token = t;
|
|
373
375
|
}
|
|
374
|
-
async getShipId(
|
|
375
|
-
const
|
|
376
|
+
async getShipId(t, r = {}) {
|
|
377
|
+
const o = {
|
|
376
378
|
headers: {
|
|
377
379
|
appKey: this.token
|
|
378
380
|
},
|
|
379
381
|
json: {
|
|
380
|
-
mmsiList:
|
|
382
|
+
mmsiList: t
|
|
381
383
|
}
|
|
382
|
-
},
|
|
383
|
-
return
|
|
384
|
+
}, n = "https://api3.myships.com/sp/ships/getShipIdByMMSI", a = await P.post(n, o).json();
|
|
385
|
+
return S.info("[%s] fetch ship id from: %s - %j", r.requestId, n, o), a.code !== "0" ? a : a.data[0].shipId;
|
|
384
386
|
}
|
|
385
|
-
async getShipInfo(
|
|
386
|
-
const
|
|
387
|
+
async getShipInfo(t, r = {}) {
|
|
388
|
+
const o = {
|
|
387
389
|
headers: {
|
|
388
390
|
appKey: this.token
|
|
389
391
|
},
|
|
390
392
|
json: {
|
|
391
|
-
shipId:
|
|
393
|
+
shipId: t
|
|
392
394
|
}
|
|
393
|
-
},
|
|
394
|
-
if (
|
|
395
|
-
return
|
|
396
|
-
const
|
|
397
|
-
let
|
|
398
|
-
return
|
|
399
|
-
mmsi:
|
|
400
|
-
name:
|
|
401
|
-
imo:
|
|
402
|
-
callSign:
|
|
403
|
-
length:
|
|
404
|
-
width:
|
|
405
|
-
draught: (
|
|
395
|
+
}, n = "https://api3.myships.com/sp/ships/aissta", a = await P.post(n, o).json();
|
|
396
|
+
if (S.info("[%s] fetch ship info from: %s - %j", r.requestId, n, o), a.code !== "0")
|
|
397
|
+
return a;
|
|
398
|
+
const e = a.data;
|
|
399
|
+
let d = e.imo;
|
|
400
|
+
return t === "407170" && (d = "9198379", S.warn("[%s] ship(%s) imo error: %s, should be %s", r.requestId, t, e.imo, d)), {
|
|
401
|
+
mmsi: e.mmsi,
|
|
402
|
+
name: e.shipnameEn,
|
|
403
|
+
imo: d,
|
|
404
|
+
callSign: e.callSign,
|
|
405
|
+
length: e.length,
|
|
406
|
+
width: e.breadth,
|
|
407
|
+
draught: (e.draught || 100) / 10
|
|
406
408
|
};
|
|
407
409
|
}
|
|
408
|
-
async realTimePosition(
|
|
409
|
-
const
|
|
410
|
+
async realTimePosition(t, r = {}) {
|
|
411
|
+
const o = await this.getShipId(t, r), n = await this.getShipInfo(o, r), a = {
|
|
410
412
|
headers: {
|
|
411
413
|
appKey: this.token
|
|
412
414
|
},
|
|
413
415
|
json: {
|
|
414
|
-
shipId:
|
|
416
|
+
shipId: o
|
|
415
417
|
}
|
|
416
|
-
},
|
|
417
|
-
|
|
418
|
-
const i =
|
|
419
|
-
for (const
|
|
420
|
-
!isNaN(i[
|
|
421
|
-
const { labelCn:
|
|
418
|
+
}, e = "https://api3.myships.com/sp/ships/position/latest", d = await P.post(e, a).json();
|
|
419
|
+
S.info("[%s] fetch realtime position from: %s - %j", r.requestId, e, a);
|
|
420
|
+
const i = d.data[0];
|
|
421
|
+
for (const l in i)
|
|
422
|
+
!isNaN(i[l]) && Number(i[l]) !== 1 / 0 && (i[l] = Number(i[l]));
|
|
423
|
+
const { labelCn: m, labelEn: g } = await this.parseStatus(i.aisNavStatus), p = y.unix(i.posTime);
|
|
422
424
|
return {
|
|
423
|
-
...
|
|
424
|
-
mmsi:
|
|
425
|
+
...n,
|
|
426
|
+
mmsi: t,
|
|
425
427
|
lat: Math.round(i.lat / 1e4 / 60 * 1e5) / 1e5,
|
|
426
428
|
lng: Math.round(i.lon / 1e4 / 60 * 1e5) / 1e5,
|
|
427
429
|
sog: Math.round(i.sog / 10 * 100) / 100,
|
|
@@ -429,62 +431,62 @@ class X extends V {
|
|
|
429
431
|
hdg: Math.round(i.heading * 100) / 100,
|
|
430
432
|
rot: Math.round(i.rot * 100) / 100,
|
|
431
433
|
positionTime: i.posTime,
|
|
432
|
-
utc:
|
|
434
|
+
utc: p.utc().format(),
|
|
433
435
|
status: i.aisNavStatus,
|
|
434
|
-
labelEn:
|
|
435
|
-
labelCn:
|
|
436
|
+
labelEn: g,
|
|
437
|
+
labelCn: m,
|
|
436
438
|
method: "position",
|
|
437
439
|
vendor: "myship"
|
|
438
440
|
};
|
|
439
441
|
}
|
|
440
|
-
async trajectory(
|
|
441
|
-
const
|
|
442
|
-
for (; i.diff(
|
|
443
|
-
await this.trajectoryIn30Day(
|
|
444
|
-
return await this.trajectoryIn30Day(
|
|
442
|
+
async trajectory(t, r, o, n, a = !0, e = {}) {
|
|
443
|
+
const d = y(r), i = y(o), m = await this.getShipId(t), g = await this.getShipInfo(m), p = [];
|
|
444
|
+
for (; i.diff(d, "day", !0) > 30; )
|
|
445
|
+
await this.trajectoryIn30Day(m, d.unix(), d.add(30, "day").unix(), g, t, n, p);
|
|
446
|
+
return await this.trajectoryIn30Day(m, d.unix(), i.unix(), g, t, n, p), p;
|
|
445
447
|
}
|
|
446
|
-
async trajectoryIn30Day(
|
|
447
|
-
var
|
|
448
|
-
const
|
|
448
|
+
async trajectoryIn30Day(t, r, o, n, a, e, d, i = {}) {
|
|
449
|
+
var I;
|
|
450
|
+
const m = {
|
|
449
451
|
headers: {
|
|
450
452
|
appKey: this.token
|
|
451
453
|
},
|
|
452
454
|
json: {
|
|
453
|
-
shipId:
|
|
454
|
-
startTime:
|
|
455
|
-
endTime:
|
|
455
|
+
shipId: t,
|
|
456
|
+
startTime: r,
|
|
457
|
+
endTime: o
|
|
456
458
|
}
|
|
457
|
-
},
|
|
458
|
-
if (
|
|
459
|
-
return
|
|
460
|
-
const
|
|
461
|
-
for (const
|
|
462
|
-
!isNaN(
|
|
463
|
-
const
|
|
464
|
-
let
|
|
465
|
-
for (const
|
|
466
|
-
const
|
|
467
|
-
imo:
|
|
468
|
-
mmsi:
|
|
469
|
-
lat: Math.round(
|
|
470
|
-
lng: Math.round(
|
|
471
|
-
sog: Math.round(
|
|
472
|
-
cog: Math.round(
|
|
473
|
-
hdg: Math.round(
|
|
474
|
-
rot: Math.round(
|
|
475
|
-
positionTime:
|
|
476
|
-
utc:
|
|
459
|
+
}, g = "https://api3.myships.com/sp/ships/position/history", p = await P.post(g, m).json();
|
|
460
|
+
if (S.info("[%s] fetch trajectory from: %s - %j", i.requestId, g, m), p.code !== "0")
|
|
461
|
+
return S.warn("[%s] invoke myship trajectory failed: %j", i.requestId, p), p;
|
|
462
|
+
const f = p.data;
|
|
463
|
+
for (const u in f)
|
|
464
|
+
!isNaN(f[u]) && Number(f[u]) !== 1 / 0 && (f[u] = Number(f[u]));
|
|
465
|
+
const l = y.unix((I = f[0]) == null ? void 0 : I.posTime);
|
|
466
|
+
let b = -1;
|
|
467
|
+
for (const u of f) {
|
|
468
|
+
const c = y.unix(u.posTime), h = {
|
|
469
|
+
imo: n == null ? void 0 : n.imo,
|
|
470
|
+
mmsi: a,
|
|
471
|
+
lat: Math.round(u.lat / 1e4 / 60 * 1e5) / 1e5,
|
|
472
|
+
lng: Math.round(u.lon / 1e4 / 60 * 1e5) / 1e5,
|
|
473
|
+
sog: Math.round(u.sog / 10 * 100) / 100,
|
|
474
|
+
cog: Math.round(u.cog / 10 * 100) / 100,
|
|
475
|
+
hdg: Math.round(u.heading * 100) / 100,
|
|
476
|
+
rot: Math.round(u.rot * 100) / 100,
|
|
477
|
+
positionTime: c.unix(),
|
|
478
|
+
utc: c.utc().format(),
|
|
477
479
|
method: "trajectory",
|
|
478
480
|
vendor: "myship"
|
|
479
|
-
},
|
|
480
|
-
|
|
481
|
+
}, v = Math.floor(c.diff(l, "minute", !0) / (e || 1));
|
|
482
|
+
v !== b && (b = v, d.push(h));
|
|
481
483
|
}
|
|
482
|
-
return
|
|
484
|
+
return d;
|
|
483
485
|
}
|
|
484
486
|
}
|
|
485
|
-
const
|
|
486
|
-
var
|
|
487
|
-
class
|
|
487
|
+
const B = K.getLogger("vessel");
|
|
488
|
+
var et = /* @__PURE__ */ ((k) => (k.NOTICE = "NOTICE", k.WARN = "WARN", k.HEAVY = "HEAVY", k.SEVERE = "SEVERE", k.ERROR = "ERROR", k.FATAL = "FATAL", k))(et || {});
|
|
489
|
+
class st {
|
|
488
490
|
/**
|
|
489
491
|
* 解析告警规则, 多规则场景
|
|
490
492
|
* @param rule
|
|
@@ -493,24 +495,24 @@ class L {
|
|
|
493
495
|
*
|
|
494
496
|
* @param options
|
|
495
497
|
*/
|
|
496
|
-
parsePrinciple(
|
|
497
|
-
var
|
|
498
|
-
|
|
499
|
-
const
|
|
500
|
-
if (!
|
|
498
|
+
parsePrinciple(s, t = {}) {
|
|
499
|
+
var e, d, i;
|
|
500
|
+
B.info("[%s] parse rule: %s", t.requestId, s);
|
|
501
|
+
const r = new RegExp("(?<=\\[)(.+)(?=])", "g"), o = s.match(r) ? (e = s.match(r)) == null ? void 0 : e[0] : void 0, n = o == null ? void 0 : o.split(";");
|
|
502
|
+
if (!n)
|
|
501
503
|
return;
|
|
502
|
-
const
|
|
503
|
-
for (let
|
|
504
|
-
const
|
|
505
|
-
if (
|
|
506
|
-
|
|
507
|
-
else if (
|
|
508
|
-
for (let
|
|
509
|
-
const
|
|
510
|
-
|
|
504
|
+
const a = {};
|
|
505
|
+
for (let m = 0; m < (n == null ? void 0 : n.length); m++) {
|
|
506
|
+
const g = (i = (d = n[m].match(r)) == null ? void 0 : d[0]) == null ? void 0 : i.split("],");
|
|
507
|
+
if (m === 0 && !g)
|
|
508
|
+
a.scope = n[0];
|
|
509
|
+
else if (g)
|
|
510
|
+
for (let p = 0, f = g.length; p < f; p++) {
|
|
511
|
+
const l = this.parseRule(g[p]);
|
|
512
|
+
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);
|
|
511
513
|
}
|
|
512
514
|
}
|
|
513
|
-
return
|
|
515
|
+
return a;
|
|
514
516
|
}
|
|
515
517
|
/**
|
|
516
518
|
* 解析单一告警规则
|
|
@@ -518,17 +520,17 @@ class L {
|
|
|
518
520
|
* @param rule
|
|
519
521
|
* @param options
|
|
520
522
|
*/
|
|
521
|
-
parseRule(
|
|
522
|
-
var
|
|
523
|
-
|
|
524
|
-
const
|
|
525
|
-
if (
|
|
523
|
+
parseRule(s, t = {}) {
|
|
524
|
+
var a;
|
|
525
|
+
B.info("[%s] parse rule: %s", t.requestId, s), s = s.startsWith("[") ? s : `[${s}`, s = s.endsWith("]") ? s : `${s}]`;
|
|
526
|
+
const r = new RegExp("(?<=\\[)(.+?)(?=])", "g"), o = (a = s == null ? void 0 : s.match(r)) == null ? void 0 : a[0], n = o == null ? void 0 : o.split(",");
|
|
527
|
+
if (n)
|
|
526
528
|
return {
|
|
527
|
-
operator:
|
|
528
|
-
number: Number.isNaN(Number(
|
|
529
|
-
level:
|
|
530
|
-
time: Number(
|
|
531
|
-
key:
|
|
529
|
+
operator: n[0],
|
|
530
|
+
number: Number.isNaN(Number(n[1])) ? n[1] : Number(n[1]),
|
|
531
|
+
level: n[2],
|
|
532
|
+
time: Number(n[3]),
|
|
533
|
+
key: n[4]
|
|
532
534
|
};
|
|
533
535
|
}
|
|
534
536
|
/**
|
|
@@ -537,25 +539,382 @@ class L {
|
|
|
537
539
|
* @param principle 告警规则
|
|
538
540
|
* @param options
|
|
539
541
|
*/
|
|
540
|
-
checkWeather(
|
|
541
|
-
var
|
|
542
|
-
let
|
|
543
|
-
const
|
|
544
|
-
for (let
|
|
545
|
-
const
|
|
546
|
-
|
|
542
|
+
checkWeather(s, t, r = {}) {
|
|
543
|
+
var l, b, I, u, c, h, v, w, M, x, N, C, j, T, A;
|
|
544
|
+
let o = 0, n = 0, a = 0, e = 0;
|
|
545
|
+
const d = Math.round(((b = (l = t == null ? void 0 : t.SEVERE) == null ? void 0 : l.sigWave) == null ? void 0 : b.number) * 1.6 * 100) / 100, i = (u = (I = t == null ? void 0 : t.SEVERE) == null ? void 0 : I.sigWave) == null ? void 0 : u.number, m = (h = (c = t == null ? void 0 : t.HEAVY) == null ? void 0 : c.sigWave) == null ? void 0 : h.number, g = Math.round((((w = (v = t == null ? void 0 : t.SEVERE) == null ? void 0 : v.wind) == null ? void 0 : w.number) + 2) * 100) / 100, p = (x = (M = t == null ? void 0 : t.SEVERE) == null ? void 0 : M.wind) == null ? void 0 : x.number, f = (C = (N = t == null ? void 0 : t.HEAVY) == null ? void 0 : N.wind) == null ? void 0 : C.number;
|
|
546
|
+
for (let O = 0; O < (s == null ? void 0 : s.length); O++) {
|
|
547
|
+
const Y = s[O], E = (T = (j = Y == null ? void 0 : Y.meteo) == null ? void 0 : j.wave) == null ? void 0 : T.sig, q = (A = Y == null ? void 0 : Y.meteo) == null ? void 0 : A.wind, W = O ? y(Y.eta).diff(y(s[O - 1].eta), "hour", !0) : 0;
|
|
548
|
+
e = W > e ? W : e, B.info("[%s] check sig.wave: %j", r.requestId, { ...E, dgThd4Wv: d, svThd4Wv: i, hvThd4Wv: m }), (E == null ? void 0 : E.height) >= d ? Y.isDangerous = !0 : (E == null ? void 0 : E.height) >= i ? Y.isSevere = !0 : (E == null ? void 0 : E.height) >= m && (Y.isHeavy = !0), B.info("[%s] check wind: %j", r.requestId, { ...q, dgThd4Wd: g, svThd4Wd: p, hvThd4Wd: f }), (q == null ? void 0 : q.scale) >= g ? (Y.isDangerous = !0, delete Y.isSevere, delete Y.isHeavy) : (q == null ? void 0 : q.scale) > p ? (Y.isDangerous || (Y.isSevere = !0), delete Y.isHeavy) : (q == null ? void 0 : q.scale) === f && !Y.isDangerous && !Y.isSevere && (Y.isHeavy = !0), o += Y.isDangerous ? W : 0, n += Y.isSevere ? W : 0, a += Y.isHeavy ? W : 0;
|
|
547
549
|
}
|
|
548
|
-
return
|
|
550
|
+
return o = Math.round(o * 100) / 100, n = Math.round(n * 100) / 100, a = Math.round(a * 100) / 100, e = Math.round(e), { sample: s, dangerous: o, severe: n, heavy: a, step: e < 3 ? 3 : e, wind: { dgThd4Wd: g, svThd4Wd: p, hvThd4Wd: f }, sig: { dgThd4Wv: d, svThd4Wv: i, hvThd4Wv: m } };
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
const pt = new st(), V = K.getLogger("vessel");
|
|
554
|
+
var at = /* @__PURE__ */ ((k) => (k.common = "common", k.container = "container", k))(at || {}), ot = /* @__PURE__ */ ((k) => (k.Ballast = "Ballast", k.Laden = "Laden", k))(ot || {}), nt = /* @__PURE__ */ ((k) => (k.Cp = "CP", k.Perf = "Basis", k.Instruct = "Other", k))(nt || {});
|
|
555
|
+
class H {
|
|
556
|
+
/**
|
|
557
|
+
* @see https://baike.baidu.com/item/%E6%96%B9%E5%BD%A2%E7%B3%BB%E6%95%B0/4965568?fr=aladdin
|
|
558
|
+
* 方形系数(block coefficient)
|
|
559
|
+
* 是指与基平面相平行的任一水线面以下的船型排水体积与对应的船长、型宽
|
|
560
|
+
* 和平均吃水的乘积所表示的长方体体积之比
|
|
561
|
+
* 方块系数介于 0.55 - 0.85
|
|
562
|
+
* @param displacement 排水 m^3
|
|
563
|
+
* @param length 水线长 m
|
|
564
|
+
* @param breadth 水线宽 m
|
|
565
|
+
* @param draught 吃水 m
|
|
566
|
+
* @return [0.55, 0.85]
|
|
567
|
+
*/
|
|
568
|
+
static blockCoefficient(s, t, r, o) {
|
|
569
|
+
let n = Math.round(s / (t * r * o) * 100) / 100;
|
|
570
|
+
n = n < 0.55 ? 0.55 : n > 0.85 ? 0.85 : n;
|
|
571
|
+
const a = [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85], e = a.map((d) => Math.abs(d - n));
|
|
572
|
+
return a[e.indexOf(Math.min(...e))];
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* @see https://baike.baidu.com/item/%E5%BC%97%E5%8A%B3%E5%BE%B7%E6%95%B0/228891?fromModule=search-result_lemma-recommend
|
|
576
|
+
* 弗劳德数 (froude number)
|
|
577
|
+
* 流体力学中表征流体惯性力和重力相对大小的一个无量纲参数,记为Fr。它表示惯性力和重力量级的比,即:Fr=sqrt(U²/(gL)) [6] ,
|
|
578
|
+
* 式中U为物体运动速度,g为重力加速度;L为物体的特征长度
|
|
579
|
+
* 佛勞德數介乎 0.05 - 0.30
|
|
580
|
+
* @param speed 速度 m/s
|
|
581
|
+
* @param length 船长 m
|
|
582
|
+
* @param g 重力加速度 9.80 m/s^2
|
|
583
|
+
* @return [0.05, 0.30]
|
|
584
|
+
*/
|
|
585
|
+
static froudeNumber(s, t, r = 9.8) {
|
|
586
|
+
let o = Math.round(Math.sqrt(s * s / (r * t)) * 100) / 100;
|
|
587
|
+
return o = o < 0.05 ? 0.05 : o > 0.3 ? 0.3 : o, o;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* 失速修正系數
|
|
591
|
+
* @param bc 方形系数 [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85]
|
|
592
|
+
* @param fr 弗劳德数 [0.05 - 0.30]
|
|
593
|
+
* @param loadCondition
|
|
594
|
+
* @private
|
|
595
|
+
*/
|
|
596
|
+
static amendFactor(s, t, r) {
|
|
597
|
+
const o = {
|
|
598
|
+
0.55: [1.7, -1.4, -7.4],
|
|
599
|
+
0.6: [2.2, -2.5, -9.7],
|
|
600
|
+
0.65: [2.6, -3.7, -11.6],
|
|
601
|
+
0.7: [3.1, -5.3, -12.4],
|
|
602
|
+
0.75: [2.4, -10.6, -9.5],
|
|
603
|
+
0.8: [2.6, -13.1, -15.1],
|
|
604
|
+
0.85: [3.1, -18.7, 28]
|
|
605
|
+
};
|
|
606
|
+
let a = {
|
|
607
|
+
0.55: [1.7, -1.4, -7.4],
|
|
608
|
+
0.6: [2.2, -2.5, -9.7],
|
|
609
|
+
0.65: [2.6, -3.7, -11.6],
|
|
610
|
+
0.7: [3.1, -5.3, -12.4],
|
|
611
|
+
0.75: [2.6, -12.5, -13.5],
|
|
612
|
+
0.8: [3, -16.3, -21.6],
|
|
613
|
+
0.85: [3.4, -20.9, 31.8]
|
|
614
|
+
}[s];
|
|
615
|
+
return r === "Laden" && (a = o[s]), a[0] + a[1] * t + a[2] * Math.pow(t, 2);
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* 失速方向因子
|
|
619
|
+
* 頂浪(不規則 波)、頂風 (0°): 2 * 𝐶𝜇 = 2
|
|
620
|
+
* 艏斜浪(不規 則波)、前迎風 (30°~60°): 2 𝐶𝜇 = 1.7 −0.03(Bn − 4)^2
|
|
621
|
+
* 橫浪(不規則 波)、橫風 (60°~150°): 2 𝐶𝜇 = 0.9 −0.06(Bn − 6)^2
|
|
622
|
+
* 順浪(不規則 波)、順風 (150°~180°): 2 𝐶𝜇 = 0.4 −0.03(Bn− 8)^2
|
|
623
|
+
*
|
|
624
|
+
* @param beta 航向与风浪的夹角
|
|
625
|
+
* @param bn
|
|
626
|
+
* @private
|
|
627
|
+
*/
|
|
628
|
+
static directionFactor(s, t = 0) {
|
|
629
|
+
let r;
|
|
630
|
+
return s > 30 && s <= 60 ? r = (1.7 - 0.03 * Math.pow(t - 4, 2)) / 2 : s > 60 && s <= 150 ? r = (0.9 - 0.06 * Math.pow(t - 6, 2)) / 2 : r = (0.4 - 0.03 * Math.pow(t - 8, 2)) / 2, Math.round(r * 1e5) / 1e5;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 失速船型因子
|
|
634
|
+
* 集装箱(普通裝載狀態): 0.7Bn + Bn^6.5/(22 * ∇^(2/3))
|
|
635
|
+
* 散货等(满载): 0.5Bn + Bn^6.5 2 /(2.7 * ∇^(2/3))
|
|
636
|
+
* 散货等(压载): 0.7Bn + Bn^6.5 2 /(2.7 * ∇^(2/3))
|
|
637
|
+
* @param displacement 排水量,m^3
|
|
638
|
+
* @param loadCondition
|
|
639
|
+
* @param tag
|
|
640
|
+
* @param bn
|
|
641
|
+
* @private
|
|
642
|
+
*/
|
|
643
|
+
static vesselTagFactor(s, t, r, o = 0) {
|
|
644
|
+
o = o > 5 ? o - 0.9 * (o - 5) : o;
|
|
645
|
+
let n;
|
|
646
|
+
return r === "container" ? n = 0.7 * o + Math.pow(o, 6.5) / (22 * Math.pow(s, 2 / 3)) : t === "Ballast" ? n = 0.7 * o + Math.pow(o, 6.5) / (2.7 * Math.pow(s, 2 / 3)) : n = 0.5 * o + Math.pow(o, 6.5) / (2.7 * Math.pow(s, 2 / 3)), n;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* 浪高影响因子
|
|
650
|
+
* @param ht 浪高,单位m
|
|
651
|
+
* @private
|
|
652
|
+
*/
|
|
653
|
+
static waveHeightFactor(s) {
|
|
654
|
+
return s = s < 1.25 ? 1.25 : s, s = s > 6 ? s - 0.9 * (s - 6) : s, Math.round((-0.144 * Math.pow(s, 2) + 0.178 * s) * 1e4) / 1e4;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* 组装船舶运行参数
|
|
658
|
+
* @param vessel 船舶基础档案
|
|
659
|
+
* @param loadCondition 装载状态
|
|
660
|
+
* @param speed 速度,kts
|
|
661
|
+
* @param bearing 方位角
|
|
662
|
+
* @private
|
|
663
|
+
*/
|
|
664
|
+
static assembleProperties(s, t, r, o) {
|
|
665
|
+
var m, g;
|
|
666
|
+
const n = 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;
|
|
667
|
+
return {
|
|
668
|
+
// @ts-ignore
|
|
669
|
+
tag: ((g = (m = s == null ? void 0 : s.type) == null ? void 0 : m.toLowerCase()) == null ? void 0 : g.indexOf("container")) > -1 ? "container" : "common",
|
|
670
|
+
lbp: n,
|
|
671
|
+
loadCondition: t,
|
|
672
|
+
draught: a,
|
|
673
|
+
breadthMoulded: e,
|
|
674
|
+
// 排水量(吨)= 载重量(吨)/ 1.025 + 吃水(米)× 船舶型宽(米)× 船舶型长(米)× 0.7
|
|
675
|
+
// 其中,1.025是指海水的密度,吨是指公吨,吃水是指船舶的最大吃水深度。船舶型宽是指船舶的最大型宽,船舶型长是指船舶的设计型长。上述公式是针对常规船舶适用的,不同类型的船舶可能会有一些差异。
|
|
676
|
+
displacement: Math.round((d / 1.025 + a * e * n * 0.7) * 1e4) / 1e4,
|
|
677
|
+
// 换算为m/s
|
|
678
|
+
speed: Math.round((r ?? 14.1382) * 1852 / 3600 * 1e4) / 1e4,
|
|
679
|
+
bearing: o || 90
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* 船舶特定时间的瞬时失速样本
|
|
684
|
+
* @param props 船舶属性
|
|
685
|
+
* @param coordinate {lat: 纬度, lng: 经度, velocity: 速度(kts, 可选,指定速度) }
|
|
686
|
+
* @param eta 位置时间
|
|
687
|
+
* @param source [CMEMS, GFS, Other]
|
|
688
|
+
* @param role 1: 船东, 2: 租家, 0: 未知
|
|
689
|
+
* @param useRouteParam true 启用设置速度
|
|
690
|
+
*/
|
|
691
|
+
static async speedLoseAt(s, t, r, o = "", n = 2, a = !1, e = {}) {
|
|
692
|
+
t.velocity && !t.noFactor && a && (s.speed = _.roundPrecision(t.velocity * 1852 / 3600, 6));
|
|
693
|
+
const d = await tt.queryPointFactor(t.lng, t.lat, r.valueOf(), "wind,wave,current,watertemp", o, e), i = H.weatherFactor(s, d), m = H.currentFactor(s.bearing, d == null ? void 0 : d.current, n), g = {
|
|
694
|
+
meteo: { ...d },
|
|
695
|
+
wxFactor: i,
|
|
696
|
+
cFactor: m,
|
|
697
|
+
speed: t.velocity && a ? t.velocity : Math.round((s.speed * 1.943844 + i + m) * 100) / 100,
|
|
698
|
+
eta: r.utc().format("YYYY-MM-DDTHH:mm[Z]"),
|
|
699
|
+
etd: r.utc().format("YYYY-MM-DDTHH:mm[Z]")
|
|
700
|
+
};
|
|
701
|
+
return delete t.meteo, delete t.wxFactor, delete t.cFactor, delete t.speed, delete t.etd, { ...g, ...t };
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* 基于步长计算失速样本
|
|
705
|
+
* @param props 船舶属性(失速模型依赖)
|
|
706
|
+
* @param etd 出发时间
|
|
707
|
+
* @param etd4Day 前行过程中动态计算加24小时的天(etd + 24 * n)
|
|
708
|
+
* @param hours 前行的步长(小时)
|
|
709
|
+
* @param distanceFromStart 与最开始起点的距离
|
|
710
|
+
* @param keypoints 剩下的航路点
|
|
711
|
+
* @param source 气象数据源: CMEMS / GFS
|
|
712
|
+
* @param useRouteParam true 启用航线上设置的参数 { suspend: 停留时长(小时), velocity: 速度(kts)}
|
|
713
|
+
* @private
|
|
714
|
+
*/
|
|
715
|
+
static async speedLoseInHoursStep(s, t, r, o, n, a, e = "", d = !1, i = {}) {
|
|
716
|
+
t.utc();
|
|
717
|
+
const m = [], g = [];
|
|
718
|
+
let p = 0, f = 0, l, b;
|
|
719
|
+
for (let I = 0; I < a.length - 1; I++) {
|
|
720
|
+
let u = a[I];
|
|
721
|
+
u.distanceFromStart = n + f;
|
|
722
|
+
const c = a[I + 1];
|
|
723
|
+
if (s.bearing = R.calculateBearing(u, c, !c.gcToPrevious), u.bearing = s.bearing, u.suspend && d) {
|
|
724
|
+
u.eta = u.eta || t.format("YYYY-MM-DDTHH:mm[Z]"), u.elapsed = u.elapsed ?? 0;
|
|
725
|
+
const w = u.suspend - u.elapsed;
|
|
726
|
+
if (o - p > w)
|
|
727
|
+
o = o - p - w, t.add(w, "hour"), u.elapsed = u.suspend;
|
|
728
|
+
else {
|
|
729
|
+
const M = o - p;
|
|
730
|
+
u.elapsed += M, t.add(M, "hour"), o = 0;
|
|
731
|
+
}
|
|
732
|
+
if (V.info(`[%s] suspend ${u.elapsed} hours at %j, and remain ${o} hours need to go...`, i.requestId, u), o === 0)
|
|
733
|
+
return u.distanceFromPrevious = f, { etd: t, from: b || u, to: u, next: a.filter((M) => M), wps: m, days: g };
|
|
734
|
+
}
|
|
735
|
+
u = await H.speedLoseAt(s, u, t, e, 0, d, i), b = b || u, u.important && m.push(u), t.isSameOrAfter(r) && (g.push(u), r.add(24, "hour"));
|
|
736
|
+
const h = R.calculateDistance(u, c, !c.gcToPrevious);
|
|
737
|
+
let v = Math.ceil(h / b.speed * 1e4) / 1e4;
|
|
738
|
+
if (p + v < o) {
|
|
739
|
+
if (p += v, t.add(v, "hour"), delete a[I], V.info(
|
|
740
|
+
`[%s] go to %j from %j with ${h}nm, and cost ${v} hours`,
|
|
741
|
+
i.requestId,
|
|
742
|
+
{ lat: c.lat, lng: c.lng },
|
|
743
|
+
{ lat: b.lat, lng: b.lng, etd: b.etd }
|
|
744
|
+
), f += h, a.filter((w) => w).length <= 1) {
|
|
745
|
+
l = c, l.eta = t.format("YYYY-MM-DDTHH:mm[Z]"), l.distanceFromPrevious = h, l.distanceFromStart = n + f, m.push(l), delete a[I + 1];
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
v = o - p, t.add(v, "hour");
|
|
750
|
+
const w = _.roundPrecision(b.speed * v, 4);
|
|
751
|
+
l = R.calculateCoordinate(u, s.bearing, w, "nauticalmiles", !c.gcToPrevious), l.eta = t.format("YYYY-MM-DDTHH:mm[Z]"), a[I] = l, V.info(
|
|
752
|
+
`[%s] go to %j from %j with ${w}nm, and cost ${v} hours`,
|
|
753
|
+
i.requestId,
|
|
754
|
+
{ lat: l.lat, lng: l.lng },
|
|
755
|
+
{ lat: u.lat, lng: u.lng, etd: u.etd }
|
|
756
|
+
), f += w, l.distanceFromPrevious = f, l.distanceFromStart = n + f;
|
|
757
|
+
break;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return { etd: t, from: b, to: l, next: a.filter((I) => I), wps: m, days: g };
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* 洋流影响因子
|
|
764
|
+
* @param bearing 船舶航行方位角
|
|
765
|
+
* @param current 洋流要素
|
|
766
|
+
* @param role 1: 船东, 2: 租家, 0: 未知
|
|
767
|
+
*/
|
|
768
|
+
static currentFactor(s, t, r = 0) {
|
|
769
|
+
const o = (s - (t == null ? void 0 : t.degree) || 0) / 180 * Math.PI;
|
|
770
|
+
if (Math.abs(o) === Math.PI / 2)
|
|
771
|
+
return 0;
|
|
772
|
+
let n = ((t == null ? void 0 : t.kts) || 0) * Math.cos(o);
|
|
773
|
+
return r & 2 ? n = Math.ceil(n * 100) / 100 : r & 1 ? n = Math.floor(n * 100) / 100 : n = Math.round(n * 100) / 100, Math.abs(n) > 5 ? 0 : n;
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* 风浪影响因子
|
|
777
|
+
* @param props 船舶档案
|
|
778
|
+
* @param wwc 气象要素
|
|
779
|
+
*/
|
|
780
|
+
static weatherFactor(s, t) {
|
|
781
|
+
var g, p, f, l, b;
|
|
782
|
+
V.debug("calculate weather factor via: %j", { ...s, ...t });
|
|
783
|
+
const r = H.blockCoefficient(s.displacement, s.lbp, s.breadthMoulded, s.draught), o = H.froudeNumber(s.speed, s.lbp), n = H.amendFactor(r, o, s.loadCondition);
|
|
784
|
+
let a = Math.abs(s.bearing % 360 - (((g = t == null ? void 0 : t.wind) == null ? void 0 : g.degree) % 360 || 0));
|
|
785
|
+
a = a > 180 ? 360 - a : a;
|
|
786
|
+
const e = H.directionFactor(a, (p = t == null ? void 0 : t.wind) == null ? void 0 : p.scale), d = H.vesselTagFactor(s.displacement, s.loadCondition, s.tag, (f = t == null ? void 0 : t.wind) == null ? void 0 : f.scale);
|
|
787
|
+
let i = e * n * d / 100 * s.speed;
|
|
788
|
+
i = Math.round(i * 1.943844 * 1e4) / 1e4 * -1;
|
|
789
|
+
const m = H.waveHeightFactor(((b = (l = t == null ? void 0 : t.wave) == null ? void 0 : l.sig) == null ? void 0 : b.height) ?? 1);
|
|
790
|
+
return i = i * 0.24 + m * 0.76, V.debug("weather factor = %s", i), Math.round(i * 100) / 100;
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* 全程失速分析(走完航程)
|
|
794
|
+
* @param from 起点 {lng, lat}
|
|
795
|
+
* @param etd 出发时间,YYYY-MM-DDTHH:mm:ssZ
|
|
796
|
+
* @param vessel 船舶属性 @see VesselAssemble, 注意吃水为船舶实时吃水,非档案中的固定吃水,一般可以从ais获取; 如获取不得,用档案吃水代替
|
|
797
|
+
* @param cp { loadCondition, speed } LoadCondition: Ballast or Laden, speed(kts)
|
|
798
|
+
* @param lane 航线 { points: { route, waypoints }}
|
|
799
|
+
* @param source 气象数据源,GFS or CMEMES, 默认CMEMS
|
|
800
|
+
* @param stepHrs 样本步长, 0表示动态计算(6 or 3 hrs)
|
|
801
|
+
* @param useRouteParam
|
|
802
|
+
*/
|
|
803
|
+
static async analyseInstant(s, t, r, o, n, a = "", e = 0, d = !1, i = {}) {
|
|
804
|
+
var E, q, W, z, G;
|
|
805
|
+
const m = y().valueOf();
|
|
806
|
+
s.lng = _.convertToStdLng(s.lng);
|
|
807
|
+
const { route: g, waypoints: p } = n.points, f = R.calculateSubRoute(s, g);
|
|
808
|
+
if (((E = f[0]) == null ? void 0 : E.length) <= 1)
|
|
809
|
+
return;
|
|
810
|
+
const { v0: l, label: b } = s.sog ? {
|
|
811
|
+
v0: s.sog,
|
|
812
|
+
label: "Other"
|
|
813
|
+
/* Instruct */
|
|
814
|
+
} : {
|
|
815
|
+
v0: o.speed,
|
|
816
|
+
label: "CP"
|
|
817
|
+
/* Cp */
|
|
818
|
+
}, I = H.assembleProperties(r, o.loadCondition, l, 0), u = p.length ? R.calculateSubWaypoints(s, p) : [], c = {
|
|
819
|
+
from: { ...s },
|
|
820
|
+
route: f,
|
|
821
|
+
waypoints: u,
|
|
822
|
+
v0: l,
|
|
823
|
+
label: b
|
|
824
|
+
}, h = {
|
|
825
|
+
hours: [],
|
|
826
|
+
days: [],
|
|
827
|
+
wps: []
|
|
828
|
+
};
|
|
829
|
+
e || (R.calculateRouteDistance(f) / o.speed <= 72 ? e = 3 : e = 6);
|
|
830
|
+
let v = R.simplifyRouteToCoordinates(f, u, 0), w = 0, M = 0, x = 0, N = 0;
|
|
831
|
+
t = y(t).utc();
|
|
832
|
+
const C = t.clone();
|
|
833
|
+
for (; v.length > 0; ) {
|
|
834
|
+
const F = e - t.hour() % e, $ = Math.ceil(t.clone().add(F, "h").set({ minute: 0, second: 0, millisecond: 0 }).diff(t, "h", !0) * 1e4) / 1e4, D = await H.speedLoseInHoursStep(I, t, C, $, w, v, a, d, i);
|
|
835
|
+
(q = D.from) != null && q.speed && (h.hours.push(D.from), h.wps.push(...D.wps), h.days.push(...D.days)), v = D == null ? void 0 : D.next, v.length || h.hours.push(D == null ? void 0 : D.to), w += ((W = D == null ? void 0 : D.to) == null ? void 0 : W.distanceFromPrevious) ?? 0;
|
|
836
|
+
}
|
|
837
|
+
const j = h.hours;
|
|
838
|
+
for (let F = 0; F < j.length - 1; F++) {
|
|
839
|
+
const $ = y(j[F + 1].eta).diff(j[F].etd, "hour", !0) || 1;
|
|
840
|
+
M += j[F].wxFactor * $, x += j[F].cFactor * $, N += $;
|
|
841
|
+
}
|
|
842
|
+
(z = h.wps) == null || z.forEach((F, $) => {
|
|
843
|
+
if ($) {
|
|
844
|
+
const D = h.wps[$ - 1], J = F.distanceFromStart - D.distanceFromStart, U = y(F.eta).diff(y(D.etd), "h", !0);
|
|
845
|
+
U < 1 ? F.avgSpd = D.speed : F.avgSpd = Math.round(J / U * 100) / 100;
|
|
846
|
+
}
|
|
847
|
+
}), c.sample = h;
|
|
848
|
+
const T = h.hours.at(-1);
|
|
849
|
+
c.distance = Math.round(T.distanceFromStart * 1e4) / 1e4, c.eta = y(T.eta).toDate(), c.wxFactor = Math.round(M / N * 1e4) / 1e4, c.cFactor = Math.round(x / N * 1e4) / 1e4, c.avgSpeed = Math.round(T.distanceFromStart / N * 1e4) / 1e4, c.totalHrs = Math.round(N * 1e4) / 1e4, c.totalFoCons = Math.round((o == null ? void 0 : o.fo) / 24 * c.totalHrs * 1e3) / 1e3, c.totalDgoCons = Math.round((o == null ? void 0 : o.dgo) / 24 * c.totalHrs * 1e3) / 1e3;
|
|
850
|
+
const O = y().valueOf() - m, Y = ((G = h == null ? void 0 : h.hours) == null ? void 0 : G.length) || 1;
|
|
851
|
+
return V.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms", i == null ? void 0 : i.requestId, O, Y, Math.round(O / Y * 1e3) / 1e3), c;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* 分段失速分析(最多走hours 小时)
|
|
855
|
+
* @param from 起点 {lng, lat}
|
|
856
|
+
* @param etd 出发时间,YYYY-MM-DDTHH:mm:ssZ
|
|
857
|
+
* @param threshed 单次所走上限时间
|
|
858
|
+
* @param vessel 船舶属性 @see VesselAssemble, 注意吃水为船舶实时吃水,非档案中的固定吃水,一般可以从ais获取; 如获取不得,用档案吃水代替
|
|
859
|
+
* @param cp { loadCondition, speed } LoadCondition: Ballast or Laden, speed(kts)
|
|
860
|
+
* @param route 航路[[[lng, lat]]]
|
|
861
|
+
* @param source 气象数据源,GFS or CMEMES, 默认CMEMS
|
|
862
|
+
* @param stepHrs
|
|
863
|
+
*/
|
|
864
|
+
static async analyseInstantWithThreshed(s, t, r, o, n, a, e = "", d = 3, i = !1, m = {}) {
|
|
865
|
+
var x, N, C;
|
|
866
|
+
s.lng = _.convertToStdLng(s.lng);
|
|
867
|
+
const g = H.assembleProperties(o, n.loadCondition, n.speed, 0), p = R.calculateSubRoute(s, a);
|
|
868
|
+
if (((x = p[0]) == null ? void 0 : x.length) <= 1)
|
|
869
|
+
return;
|
|
870
|
+
let f = R.simplifyRouteToCoordinates(p, [], 0);
|
|
871
|
+
f.forEach((j) => j.important = !0);
|
|
872
|
+
let l = 0, b = 0, I = 0, u = 0, c;
|
|
873
|
+
const h = {
|
|
874
|
+
hours: [],
|
|
875
|
+
wps: [],
|
|
876
|
+
days: []
|
|
877
|
+
};
|
|
878
|
+
for (t = y(t).utc(); f.length > 0; ) {
|
|
879
|
+
const j = d - t.hour() % d;
|
|
880
|
+
let T = Math.ceil(t.clone().add(j, "h").set({ minute: 0, second: 0, millisecond: 0 }).diff(t, "h", !0) * 1e4) / 1e4;
|
|
881
|
+
if (T = t.clone().add(T, "h").isAfter(r) ? r.diff(t, "h", !0) * 1e4 / 1e4 : T, T)
|
|
882
|
+
c = await H.speedLoseInHoursStep(g, t, r.clone(), T, l, f, e, i, m), (N = c.from) != null && N.speed && (h.hours.push(c.from), c != null && c.wps && h.wps.push(...c.wps), h.days.push(...c.days)), f = c == null ? void 0 : c.next, f.length || (h.hours.push(c == null ? void 0 : c.to), c != null && c.wps && h.wps.push(...c.wps), h.days.push(c == null ? void 0 : c.to)), l += ((C = c == null ? void 0 : c.to) == null ? void 0 : C.distanceFromPrevious) ?? 0;
|
|
883
|
+
else {
|
|
884
|
+
c && (h.hours.push(c.to), c != null && c.wps && h.wps.push(...c.wps), h.days.push(c.to));
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
const v = h.hours;
|
|
889
|
+
for (let j = 0; j < v.length - 1; j++) {
|
|
890
|
+
const T = y(v[j + 1].eta).diff(v[j].etd, "hour", !0);
|
|
891
|
+
b += v[j].wxFactor * T, I += v[j].cFactor * T, u += T;
|
|
892
|
+
}
|
|
893
|
+
const w = h.hours.at(-1);
|
|
894
|
+
return {
|
|
895
|
+
sample: h,
|
|
896
|
+
distance: Math.round(((w == null ? void 0 : w.distanceFromStart) || 0) * 1e4) / 1e4,
|
|
897
|
+
eta: y(w == null ? void 0 : w.eta).utc().format(),
|
|
898
|
+
wxFactor: Math.round(b / u * 1e4) / 1e4,
|
|
899
|
+
cFactor: Math.round(I / u * 1e4) / 1e4,
|
|
900
|
+
avgSpeed: Math.round(((w == null ? void 0 : w.distanceFromStart) || 0) / u * 1e4) / 1e4,
|
|
901
|
+
totalHrs: Math.round(u * 1e4) / 1e4,
|
|
902
|
+
to: w,
|
|
903
|
+
route: R.generateRouteAccordingToWaypoints(f)
|
|
904
|
+
};
|
|
549
905
|
}
|
|
550
906
|
}
|
|
551
|
-
const Z = new L();
|
|
552
907
|
export {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
908
|
+
Z as AISImpl,
|
|
909
|
+
st as AlertHelper,
|
|
910
|
+
et as AlertLevel,
|
|
911
|
+
ft as HifleetImpl,
|
|
912
|
+
ot as LoadCondition,
|
|
913
|
+
gt as MyShipImpl,
|
|
914
|
+
lt as MyVesselImpl,
|
|
915
|
+
mt as ShipxyImpl,
|
|
916
|
+
H as SpeedHelper,
|
|
917
|
+
nt as SpeedLabel,
|
|
918
|
+
at as VesselTag,
|
|
919
|
+
pt as alertHelper
|
|
561
920
|
};
|