@idm-plugin/vessel 2.2.9 → 2.3.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/ais/src/index.d.ts +68 -0
- package/dist/index.js +748 -649
- package/dist/index.umd.cjs +1 -1
- package/dist/speed/src/index.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
var ht = Object.defineProperty;
|
|
2
|
-
var lt = (
|
|
3
|
-
var
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import { LngLatHelper as
|
|
8
|
-
import { MeteoHelper2 as
|
|
2
|
+
var lt = (E, e, t) => e in E ? ht(E, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : E[e] = t;
|
|
3
|
+
var U = (E, e, t) => (lt(E, typeof e != "symbol" ? e + "" : e, t), t);
|
|
4
|
+
import L from "got";
|
|
5
|
+
import ct from "@log4js-node/log4js-api";
|
|
6
|
+
import w from "moment";
|
|
7
|
+
import { LngLatHelper as _, LaneHelper as W } from "@idm-plugin/geo2";
|
|
8
|
+
import { MeteoHelper2 as mt } from "@idm-plugin/meteo2";
|
|
9
9
|
import { Meteo2Assist as it } from "@idm-plugin/meteo";
|
|
10
|
-
let
|
|
10
|
+
let M;
|
|
11
11
|
try {
|
|
12
|
-
|
|
12
|
+
M = ct.getLogger("vessel");
|
|
13
13
|
} catch {
|
|
14
14
|
} finally {
|
|
15
15
|
}
|
|
@@ -18,85 +18,182 @@ class st {
|
|
|
18
18
|
* 解析AIS状态码
|
|
19
19
|
* @param status
|
|
20
20
|
*/
|
|
21
|
-
parseStatus(
|
|
22
|
-
let
|
|
23
|
-
switch (
|
|
21
|
+
parseStatus(e) {
|
|
22
|
+
let t, a;
|
|
23
|
+
switch (e) {
|
|
24
24
|
case 0:
|
|
25
|
-
|
|
25
|
+
t = "在航(主机推动)", a = "Underway Using Engine";
|
|
26
26
|
break;
|
|
27
27
|
case 1:
|
|
28
|
-
|
|
28
|
+
t = "锚泊", a = "Anchored";
|
|
29
29
|
break;
|
|
30
30
|
case 2:
|
|
31
|
-
|
|
31
|
+
t = "失控", a = "Not under command";
|
|
32
32
|
break;
|
|
33
33
|
case 3:
|
|
34
|
-
|
|
34
|
+
t = "操纵受限", a = "Limited airworthiness";
|
|
35
35
|
break;
|
|
36
36
|
case 4:
|
|
37
|
-
|
|
37
|
+
t = "吃水受限", a = "Limited by ship's draft";
|
|
38
38
|
break;
|
|
39
39
|
case 5:
|
|
40
|
-
|
|
40
|
+
t = "靠泊", a = "Mooring";
|
|
41
41
|
break;
|
|
42
42
|
case 6:
|
|
43
|
-
|
|
43
|
+
t = "搁浅", a = "Stranded";
|
|
44
44
|
break;
|
|
45
45
|
case 7:
|
|
46
|
-
|
|
46
|
+
t = "捕捞作业", a = "Engaged in fishing";
|
|
47
47
|
break;
|
|
48
48
|
case 8:
|
|
49
|
-
|
|
49
|
+
t = "靠帆船提供动力", a = "Sailing";
|
|
50
50
|
break;
|
|
51
51
|
default:
|
|
52
|
-
|
|
52
|
+
t = "未定义", a = "Undefined";
|
|
53
53
|
}
|
|
54
|
-
return { labelCn:
|
|
54
|
+
return { labelCn: t, labelEn: a };
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
class
|
|
58
|
-
constructor(
|
|
57
|
+
class jt extends st {
|
|
58
|
+
constructor(t, a) {
|
|
59
59
|
super();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.clientId =
|
|
60
|
+
U(this, "clientId");
|
|
61
|
+
U(this, "clientSecret");
|
|
62
|
+
U(this, "token");
|
|
63
|
+
this.clientId = t, this.clientSecret = a;
|
|
64
64
|
}
|
|
65
|
-
async authToken(
|
|
65
|
+
async authToken(t = {}) {
|
|
66
66
|
const a = "https://svc.data.myvessel.cn/ada/oauth/token", i = {
|
|
67
67
|
searchParams: {
|
|
68
68
|
client_id: this.clientId,
|
|
69
69
|
client_secret: this.clientSecret,
|
|
70
70
|
grant_type: "client_credentials"
|
|
71
71
|
}
|
|
72
|
-
}, o = await
|
|
73
|
-
|
|
72
|
+
}, o = await L.post(a, i).json();
|
|
73
|
+
M == null || M.info("[%s] fetch access token from: %s - %j", t.requestId, a, o), o.error || (this.token = {
|
|
74
74
|
accessToken: o.access_token,
|
|
75
75
|
tokenType: o.token_type,
|
|
76
76
|
expiresIn: o.expires_in,
|
|
77
77
|
scope: o.scope,
|
|
78
78
|
jti: o.jti,
|
|
79
|
-
issuedAt:
|
|
79
|
+
issuedAt: w().utc().format()
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
async
|
|
83
|
-
var
|
|
84
|
-
(!this.token ||
|
|
82
|
+
async checkToken(t = {}) {
|
|
83
|
+
var a;
|
|
84
|
+
return (!this.token || w().diff(w(this.token.issuedAt), "seconds") > (((a = this.token) == null ? void 0 : a.expiresIn) || 0) - 300) && await this.authToken(t), this.token;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 模糊查询
|
|
88
|
+
* @param kw
|
|
89
|
+
* @param options
|
|
90
|
+
*/
|
|
91
|
+
async suggest(t, a = {}) {
|
|
92
|
+
var s, r;
|
|
93
|
+
await this.checkToken(a);
|
|
94
|
+
const i = "https://market.myvessel.cn/sdc/v1/mkt/vessels/fuzzy", o = {
|
|
95
|
+
headers: {
|
|
96
|
+
Authorization: `${(s = this.token) == null ? void 0 : s.tokenType} ${(r = this.token) == null ? void 0 : r.accessToken}`
|
|
97
|
+
},
|
|
98
|
+
json: {
|
|
99
|
+
kw: t,
|
|
100
|
+
recordNum: a.ps || 10
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
M == null || M.info("[%s] fetch suggest vessels from: %s - %j", a.requestId, i, o);
|
|
104
|
+
const n = await L.post(i, o).json();
|
|
105
|
+
return n.code ? (M == null || M.warn("[%s] fetch suggest vessels failed: %j", a.requestId, { message: n.message, status: n.status, code: n.code }), []) : n.data.map((u) => ({
|
|
106
|
+
mmsi: u.mmsi,
|
|
107
|
+
name: u.nameEn,
|
|
108
|
+
nameCn: u.nameCn,
|
|
109
|
+
imo: Number.isNaN(u.imo) ? null : Number(u.imo),
|
|
110
|
+
callSign: u.callsign,
|
|
111
|
+
type: u.vesselTypeNameEn,
|
|
112
|
+
flagName: u.flagCtry,
|
|
113
|
+
vendor: "myvessel",
|
|
114
|
+
raw: u
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* imo/mmsi 精确查询
|
|
119
|
+
* @param imo
|
|
120
|
+
* @param options
|
|
121
|
+
*/
|
|
122
|
+
async search(t, a = {}) {
|
|
123
|
+
var c, u;
|
|
124
|
+
await this.checkToken(a);
|
|
125
|
+
const i = /^\d{7}$/.test(t.toString()), o = i ? "https://market.myvessel.cn/sdc/v1/mkt/vessels/detail/imo" : "https://market.myvessel.cn/sdc/v1/mkt/vessels/detail/mmsi", n = i ? { imo: t } : { mmsi: t }, s = {
|
|
126
|
+
headers: {
|
|
127
|
+
Authorization: `${(c = this.token) == null ? void 0 : c.tokenType} ${(u = this.token) == null ? void 0 : u.accessToken}`
|
|
128
|
+
},
|
|
129
|
+
searchParams: n
|
|
130
|
+
};
|
|
131
|
+
M == null || M.info("[%s] fetch vessel from: %s - %j", a.requestId, o, s);
|
|
132
|
+
const r = await L.get(o, s).json();
|
|
133
|
+
if (r.status !== 200)
|
|
134
|
+
return M == null || M.warn("[%s] fetch suggest vessels failed: %j", a.requestId, { message: r.message, status: r.status, code: r.code }), {};
|
|
135
|
+
{
|
|
136
|
+
const l = r.data;
|
|
137
|
+
if (l)
|
|
138
|
+
return {
|
|
139
|
+
mmsi: l.mmsi,
|
|
140
|
+
imo: Number.isNaN(l.imo) ? null : Number(l.imo),
|
|
141
|
+
callSign: l.callsign,
|
|
142
|
+
name: l.nameEn,
|
|
143
|
+
nameCn: l.nameCn,
|
|
144
|
+
type: l.vesselTypeNameEn,
|
|
145
|
+
flagName: l.flagCtry,
|
|
146
|
+
clasz: l.classSociety,
|
|
147
|
+
dateOfBuild: l.buildYearMonth,
|
|
148
|
+
deadweight: l.dwt,
|
|
149
|
+
grossTonnage: l.grt,
|
|
150
|
+
netTonnage: l.net,
|
|
151
|
+
teu: l.teu,
|
|
152
|
+
length: l.length,
|
|
153
|
+
breadth: l.width,
|
|
154
|
+
height: l.height,
|
|
155
|
+
draught: l.draught,
|
|
156
|
+
speed: l.speed,
|
|
157
|
+
passengerCapacity: l.passengercapacity,
|
|
158
|
+
vendor: "myvessel",
|
|
159
|
+
raw: l
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
async archives(t, a = {}) {
|
|
165
|
+
var s, r;
|
|
166
|
+
await this.checkToken(a);
|
|
167
|
+
const i = "https://svc.data.myvessel.cn/sdc/v1/ship/info/batch", o = {
|
|
168
|
+
headers: {
|
|
169
|
+
Authorization: `${(s = this.token) == null ? void 0 : s.tokenType} ${(r = this.token) == null ? void 0 : r.accessToken}`
|
|
170
|
+
},
|
|
171
|
+
json: {
|
|
172
|
+
mmsiList: typeof t == "number" ? [t] : t
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
M == null || M.info("[%s] fetch vessel archive from: %s - %j", a.requestId, i, o);
|
|
176
|
+
const n = await L.post(i, o).json();
|
|
177
|
+
return n.status !== 200 ? (M == null || M.warn("[%s] fetch vessel archive failed: %j", a.requestId, { message: n.message, status: n.status, code: n.code }), {}) : n.data;
|
|
178
|
+
}
|
|
179
|
+
async realTimePosition(t, a = {}) {
|
|
180
|
+
var r, c;
|
|
181
|
+
await this.checkToken(a);
|
|
85
182
|
const i = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/location/unit", o = {
|
|
86
183
|
headers: {
|
|
87
|
-
Authorization: `${(r = this.token) == null ? void 0 : r.tokenType} ${(
|
|
184
|
+
Authorization: `${(r = this.token) == null ? void 0 : r.tokenType} ${(c = this.token) == null ? void 0 : c.accessToken}`
|
|
88
185
|
},
|
|
89
|
-
searchParams: { mmsi:
|
|
186
|
+
searchParams: { mmsi: t }
|
|
90
187
|
};
|
|
91
|
-
|
|
92
|
-
const n = await
|
|
188
|
+
M == null || M.info("[%s] fetch realtime position from: %s - %j", a.requestId, i, o);
|
|
189
|
+
const n = await L.get(i, o).json();
|
|
93
190
|
if (n.code)
|
|
94
|
-
return
|
|
191
|
+
return M == null || M.warn("[%s] fetch realtime position failed: %j", a.requestId, { message: n.message, status: n.status, code: n.code }), n;
|
|
95
192
|
const s = n.data;
|
|
96
|
-
for (const
|
|
97
|
-
!isNaN(s[
|
|
193
|
+
for (const u in s)
|
|
194
|
+
!isNaN(s[u]) && Number(s[u]) !== 1 / 0 && (s[u] = Number(s[u]));
|
|
98
195
|
if (s) {
|
|
99
|
-
const
|
|
196
|
+
const u = w(`${s.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
100
197
|
return {
|
|
101
198
|
mmsi: s.mmsi,
|
|
102
199
|
name: s.vesselName || s.aisVesselName,
|
|
@@ -111,9 +208,9 @@ class Et extends st {
|
|
|
111
208
|
cog: s.cog,
|
|
112
209
|
hdg: s.hdg,
|
|
113
210
|
rot: s.rot,
|
|
114
|
-
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(s.eta) ?
|
|
211
|
+
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(s.eta) ? w.utc(s.eta).format() : void 0,
|
|
115
212
|
destination: s.dest,
|
|
116
|
-
positionTime:
|
|
213
|
+
positionTime: u.unix(),
|
|
117
214
|
status: s.status,
|
|
118
215
|
labelCn: s.statusNameCn,
|
|
119
216
|
labelEn: s.statusNameEn,
|
|
@@ -126,83 +223,83 @@ class Et extends st {
|
|
|
126
223
|
net: s.net,
|
|
127
224
|
method: "position",
|
|
128
225
|
vendor: "myVessel",
|
|
129
|
-
utc:
|
|
226
|
+
utc: u.utc().format()
|
|
130
227
|
};
|
|
131
228
|
} else
|
|
132
229
|
return {};
|
|
133
230
|
}
|
|
134
|
-
async trajectory(
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
for (;
|
|
138
|
-
await this.trajectoryIn30Day(
|
|
139
|
-
return await this.trajectoryIn30Day(
|
|
231
|
+
async trajectory(t, a, i, o, n = !0, s = {}) {
|
|
232
|
+
await this.checkToken(s);
|
|
233
|
+
const r = await this.realTimePosition(t, s), c = w(a), u = w(i), l = [];
|
|
234
|
+
for (; u.diff(c, "day", !0) > 30; )
|
|
235
|
+
await this.trajectoryIn30Day(t, c, c.clone().add(30, "day"), r, o, l, s), c.add(30, "day");
|
|
236
|
+
return await this.trajectoryIn30Day(t, c, u, r, o, l, s), l;
|
|
140
237
|
}
|
|
141
|
-
async trajectoryIn30Day(
|
|
142
|
-
var
|
|
143
|
-
const
|
|
238
|
+
async trajectoryIn30Day(t, a, i, o, n, s, r = {}) {
|
|
239
|
+
var y, F, I, p, v;
|
|
240
|
+
const c = "https://svc.data.myvessel.cn/sdc/v1/vessels/status/track", u = {
|
|
144
241
|
headers: {
|
|
145
|
-
Authorization: `${(
|
|
242
|
+
Authorization: `${(y = this.token) == null ? void 0 : y.tokenType} ${(F = this.token) == null ? void 0 : F.accessToken}`
|
|
146
243
|
},
|
|
147
244
|
json: {
|
|
148
|
-
mmsi:
|
|
245
|
+
mmsi: t,
|
|
149
246
|
startTime: a.utcOffset(8).format("YYYY-MM-DD HH:mm:ss"),
|
|
150
247
|
endTime: i.utcOffset(8).format("YYYY-MM-DD HH:mm:ss")
|
|
151
248
|
}
|
|
152
249
|
};
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
156
|
-
return
|
|
157
|
-
let
|
|
158
|
-
const b =
|
|
159
|
-
return (
|
|
160
|
-
for (const
|
|
161
|
-
!isNaN(
|
|
162
|
-
const
|
|
163
|
-
mmsi:
|
|
250
|
+
M == null || M.info("[%s] fetch trajectory from: %s - %j", r.requestId, c, u);
|
|
251
|
+
const l = await L.post(c, u).json();
|
|
252
|
+
if (l.code)
|
|
253
|
+
return M == null || M.warn("[%s] fetch trajectory failed: %j", r.requestId, c, { message: l.message, status: l.status, code: l.code }), l;
|
|
254
|
+
let f = -1;
|
|
255
|
+
const b = w(`${(p = (I = l.data) == null ? void 0 : I[0]) == null ? void 0 : p.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
256
|
+
return (v = l.data) == null || v.forEach((d) => {
|
|
257
|
+
for (const P in d)
|
|
258
|
+
!isNaN(d[P]) && Number(d[P]) !== 1 / 0 && (d[P] = Number(d[P]));
|
|
259
|
+
const g = w(`${d.postime} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00"), m = d.status, { labelCn: h, labelEn: k } = this.parseStatus(m), S = {
|
|
260
|
+
mmsi: d.mmsi,
|
|
164
261
|
imo: o == null ? void 0 : o.imo,
|
|
165
|
-
lat:
|
|
166
|
-
lng:
|
|
167
|
-
sog:
|
|
168
|
-
cog:
|
|
169
|
-
hdg:
|
|
170
|
-
draught:
|
|
171
|
-
status:
|
|
172
|
-
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(
|
|
173
|
-
destination:
|
|
174
|
-
positionTime:
|
|
175
|
-
labelCn:
|
|
176
|
-
labelEn:
|
|
262
|
+
lat: d.lat,
|
|
263
|
+
lng: d.lon,
|
|
264
|
+
sog: d.sog,
|
|
265
|
+
cog: d.cog,
|
|
266
|
+
hdg: d.hdg,
|
|
267
|
+
draught: d.draught,
|
|
268
|
+
status: m,
|
|
269
|
+
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(d.eta) ? w(`${d.eta} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00").utc().format() : void 0,
|
|
270
|
+
destination: d.dest,
|
|
271
|
+
positionTime: g.unix(),
|
|
272
|
+
labelCn: h,
|
|
273
|
+
labelEn: k,
|
|
177
274
|
method: "trajectory",
|
|
178
275
|
vendor: "myVessel",
|
|
179
|
-
utc:
|
|
180
|
-
}, D = Math.floor(
|
|
181
|
-
D !==
|
|
276
|
+
utc: g.utc().format()
|
|
277
|
+
}, D = Math.floor(g.diff(b, "minute", !0) / (n || 1));
|
|
278
|
+
D !== f && (f = D, s.push(S));
|
|
182
279
|
}), s;
|
|
183
280
|
}
|
|
184
281
|
}
|
|
185
|
-
class
|
|
186
|
-
constructor(
|
|
282
|
+
class Et extends st {
|
|
283
|
+
constructor(t) {
|
|
187
284
|
super();
|
|
188
|
-
|
|
189
|
-
this.token =
|
|
285
|
+
U(this, "token");
|
|
286
|
+
this.token = t;
|
|
190
287
|
}
|
|
191
|
-
async realTimePosition(
|
|
288
|
+
async realTimePosition(t, a = {}) {
|
|
192
289
|
const i = "https://api.hifleet.com/position/position/get/token", o = {
|
|
193
290
|
searchParams: {
|
|
194
|
-
mmsi:
|
|
291
|
+
mmsi: t,
|
|
195
292
|
usertoken: this.token
|
|
196
293
|
}
|
|
197
|
-
}, n = await
|
|
198
|
-
|
|
294
|
+
}, n = await L.post(i, o).json();
|
|
295
|
+
M == null || M.info("[%s] fetch realtime position from: %s - %j", a.requestId, i, o);
|
|
199
296
|
const s = n == null ? void 0 : n.list;
|
|
200
297
|
if (!s)
|
|
201
|
-
return
|
|
298
|
+
return M == null || M.warn("[%s] fetch realtime position failed: %j", a.requestId, i, n), n;
|
|
202
299
|
for (const b in s)
|
|
203
300
|
!isNaN(s[b]) && Number(s[b]) !== 1 / 0 && (s[b] = Number(s[b]));
|
|
204
301
|
s.status = s.sp > 3 ? 0 : 1;
|
|
205
|
-
const
|
|
302
|
+
const r = s.status, { labelCn: c, labelEn: u } = this.parseStatus(r), l = w(`${s.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
206
303
|
return {
|
|
207
304
|
mmsi: s.m,
|
|
208
305
|
name: s.n,
|
|
@@ -217,26 +314,26 @@ class xt extends st {
|
|
|
217
314
|
cog: s.co,
|
|
218
315
|
hdg: s.h,
|
|
219
316
|
rot: isNaN(s.rot) ? 0 : s.rot,
|
|
220
|
-
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(s.eta) ?
|
|
317
|
+
eta: /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(s.eta) ? w.utc(s.eta).format() : void 0,
|
|
221
318
|
destination: s.destination,
|
|
222
319
|
vesselType: s.type,
|
|
223
320
|
dwt: s.dwt,
|
|
224
321
|
build: s.buildyear,
|
|
225
322
|
flag: s.fn,
|
|
226
|
-
positionTime:
|
|
227
|
-
utc:
|
|
228
|
-
status:
|
|
229
|
-
labelCn:
|
|
230
|
-
labelEn:
|
|
323
|
+
positionTime: l.unix(),
|
|
324
|
+
utc: l.utc().format(),
|
|
325
|
+
status: r,
|
|
326
|
+
labelCn: c,
|
|
327
|
+
labelEn: u,
|
|
231
328
|
method: "position",
|
|
232
329
|
vendor: "hifleet"
|
|
233
330
|
};
|
|
234
331
|
}
|
|
235
|
-
async search(
|
|
332
|
+
async search(t, a = {}) {
|
|
236
333
|
let i = "https://www.hifleet.com/hifleetapi/searchVesselOL.do";
|
|
237
334
|
const o = {
|
|
238
335
|
searchParams: {
|
|
239
|
-
keyword:
|
|
336
|
+
keyword: t
|
|
240
337
|
},
|
|
241
338
|
headers: {
|
|
242
339
|
Referer: "https://www.hifleet.com",
|
|
@@ -244,10 +341,10 @@ class xt extends st {
|
|
|
244
341
|
Host: "www.hifleet.com"
|
|
245
342
|
}
|
|
246
343
|
};
|
|
247
|
-
let n = await
|
|
248
|
-
|
|
249
|
-
for (const
|
|
250
|
-
!isNaN(n[
|
|
344
|
+
let n = await L.post(i, o).json();
|
|
345
|
+
M == null || M.info("[%s] fetch vessel props from: %s - %j", a.requestId, i, o), n instanceof Array && (n = n[0]);
|
|
346
|
+
for (const r in n)
|
|
347
|
+
!isNaN(n[r]) && Number(n[r]) !== 1 / 0 && (n[r] = Number(n[r]));
|
|
251
348
|
const s = {
|
|
252
349
|
mmsi: n.m,
|
|
253
350
|
name: n.n,
|
|
@@ -258,102 +355,102 @@ class xt extends st {
|
|
|
258
355
|
draught: n.dr,
|
|
259
356
|
type: n.t
|
|
260
357
|
};
|
|
261
|
-
return i = "https://www.hifleet.com/hifleetapi/sameShipSearch.do", n = await
|
|
358
|
+
return i = "https://www.hifleet.com/hifleetapi/sameShipSearch.do", n = await L.post(i, o).json(), M == null || M.info("[%s] search vessel dead weight from: %s - %j", a.requestId, i, o), n instanceof Array && (n = n[0]), n && (s.deadweight = Number(n.dwt)), s;
|
|
262
359
|
}
|
|
263
|
-
async suggest(
|
|
360
|
+
async suggest(t, a = {}) {
|
|
264
361
|
const i = "https://www.hifleet.com/hifleetapi/getShipSuggest.do", o = {
|
|
265
362
|
searchParams: {
|
|
266
|
-
q:
|
|
363
|
+
q: t
|
|
267
364
|
},
|
|
268
365
|
headers: {
|
|
269
366
|
Referer: "https://www.hifleet.com",
|
|
270
367
|
Origin: "https://www.hifleet.com",
|
|
271
368
|
Host: "www.hifleet.com"
|
|
272
369
|
}
|
|
273
|
-
}, n = await
|
|
274
|
-
|
|
370
|
+
}, n = await L.post(i, o).json();
|
|
371
|
+
M == null || M.info("[%s] suggest vessel props from: %s - %j", a.requestId, i, o);
|
|
275
372
|
const s = [];
|
|
276
|
-
for (const
|
|
373
|
+
for (const r of n)
|
|
277
374
|
s.push({
|
|
278
|
-
mmsi: !
|
|
279
|
-
name:
|
|
280
|
-
callSign:
|
|
281
|
-
imo: !
|
|
282
|
-
score:
|
|
375
|
+
mmsi: !r.mmsi || isNaN(r.mmsi) ? null : Number(r.mmsi),
|
|
376
|
+
name: r.name,
|
|
377
|
+
callSign: r.callsign,
|
|
378
|
+
imo: !r.imo || isNaN(r.imo) ? null : Number(r.imo),
|
|
379
|
+
score: r._score
|
|
283
380
|
});
|
|
284
|
-
return s.sort((
|
|
381
|
+
return s.sort((r, c) => c.score - r.score), s;
|
|
285
382
|
}
|
|
286
|
-
async trajectory(
|
|
287
|
-
var
|
|
288
|
-
const
|
|
289
|
-
let
|
|
290
|
-
const
|
|
383
|
+
async trajectory(t, a, i, o, n = !0, s = {}) {
|
|
384
|
+
var d, g, m;
|
|
385
|
+
const r = await this.realTimePosition(t, s);
|
|
386
|
+
let c = w(a);
|
|
387
|
+
const u = w(i), l = w();
|
|
291
388
|
if (n) {
|
|
292
|
-
let
|
|
293
|
-
|
|
389
|
+
let h = u.diff(c, "d", !0);
|
|
390
|
+
h < 0 ? c = u.clone().subtract(40, "d") : h < 30 ? c.subtract(10, "d") : h < 60 ? c.subtract(5, "d") : c = u.clone().subtract(80, "d"), h = l.diff(u, "d", !0), u.add(h > 10 ? 240 : h * 24, "h");
|
|
294
391
|
}
|
|
295
|
-
const
|
|
392
|
+
const f = {
|
|
296
393
|
searchParams: {
|
|
297
|
-
endtime:
|
|
298
|
-
starttime:
|
|
299
|
-
mmsi:
|
|
394
|
+
endtime: u.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),
|
|
395
|
+
starttime: c.utcOffset("+8:00").format("YYYY-MM-DD HH:mm:ss"),
|
|
396
|
+
mmsi: t,
|
|
300
397
|
usertoken: this.token
|
|
301
398
|
}
|
|
302
|
-
}, b = "https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token",
|
|
303
|
-
|
|
304
|
-
let
|
|
305
|
-
|
|
306
|
-
const
|
|
399
|
+
}, b = "https://api.hifleet.com/position/trajectory/nocompressed/withstatic/token", y = await L.get(b, f).json();
|
|
400
|
+
M == null || M.info("[%s] fetch trajectory from: %s - %j", s.requestId, b, f);
|
|
401
|
+
let F;
|
|
402
|
+
y && (F = ((g = (d = y.ships) == null ? void 0 : d.offors) == null ? void 0 : g.ship) || [], F.length || M == null || M.warn("[%s] fetch trajectory failed: %j", s.requestId, y));
|
|
403
|
+
const I = [];
|
|
307
404
|
let p = -1;
|
|
308
|
-
const
|
|
309
|
-
for (const
|
|
310
|
-
for (const A in
|
|
311
|
-
!isNaN(
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
const { labelEn:
|
|
315
|
-
mmsi:
|
|
316
|
-
name:
|
|
317
|
-
imo:
|
|
318
|
-
lat:
|
|
319
|
-
lng:
|
|
320
|
-
draught:
|
|
321
|
-
sog:
|
|
322
|
-
cog:
|
|
323
|
-
hdg:
|
|
324
|
-
positionTime:
|
|
325
|
-
utc:
|
|
326
|
-
status:
|
|
405
|
+
const v = w(`${(m = F == null ? void 0 : F[0]) == null ? void 0 : m.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
406
|
+
for (const h of F) {
|
|
407
|
+
for (const A in h)
|
|
408
|
+
!isNaN(h[A]) && Number(h[A]) !== 1 / 0 && (h[A] = Number(h[A]));
|
|
409
|
+
const k = w(`${h.ti} +08:00`, "YYYY-MM-DD HH:mm:ss +08:00");
|
|
410
|
+
h.status = h.sp > 4 ? 0 : 1;
|
|
411
|
+
const { labelEn: S, labelCn: D } = this.parseStatus(h.status), P = {
|
|
412
|
+
mmsi: h.m,
|
|
413
|
+
name: h.n,
|
|
414
|
+
imo: r == null ? void 0 : r.imo,
|
|
415
|
+
lat: h.la,
|
|
416
|
+
lng: h.lo,
|
|
417
|
+
draught: h.draught,
|
|
418
|
+
sog: h.sp,
|
|
419
|
+
cog: h.co,
|
|
420
|
+
hdg: h.hdg,
|
|
421
|
+
positionTime: k.unix(),
|
|
422
|
+
utc: k.utc().format(),
|
|
423
|
+
status: h.status,
|
|
327
424
|
labelCn: D,
|
|
328
|
-
labelEn:
|
|
425
|
+
labelEn: S,
|
|
329
426
|
method: "trajectory",
|
|
330
427
|
vendor: "hifleet"
|
|
331
|
-
},
|
|
332
|
-
|
|
428
|
+
}, N = Math.floor(k.diff(v, "minute", !0) / (o || 1));
|
|
429
|
+
N !== p && (p = N, I.push(P));
|
|
333
430
|
}
|
|
334
|
-
return
|
|
431
|
+
return I;
|
|
335
432
|
}
|
|
336
433
|
}
|
|
337
|
-
class
|
|
338
|
-
constructor(
|
|
434
|
+
class Nt extends st {
|
|
435
|
+
constructor(t) {
|
|
339
436
|
super();
|
|
340
|
-
|
|
341
|
-
this.token =
|
|
437
|
+
U(this, "token");
|
|
438
|
+
this.token = t;
|
|
342
439
|
}
|
|
343
|
-
async realTimePosition(
|
|
440
|
+
async realTimePosition(t, a = {}) {
|
|
344
441
|
const i = {
|
|
345
442
|
searchParams: {
|
|
346
|
-
id:
|
|
443
|
+
id: t,
|
|
347
444
|
k: this.token,
|
|
348
445
|
enc: 1
|
|
349
446
|
}
|
|
350
|
-
}, o = "https://api.shipxy.com/apicall/GetSingleShip", n = await
|
|
351
|
-
if (
|
|
447
|
+
}, o = "https://api.shipxy.com/apicall/GetSingleShip", n = await L.get(o, i).json();
|
|
448
|
+
if (M == null || M.info("[%s] fetch realtime position from: %s - %j", a.requestId, o, i), (n == null ? void 0 : n.status) !== 0)
|
|
352
449
|
return n;
|
|
353
450
|
const s = n.data[0];
|
|
354
|
-
for (const
|
|
355
|
-
!isNaN(s[
|
|
356
|
-
const { labelCn:
|
|
451
|
+
for (const f in s)
|
|
452
|
+
!isNaN(s[f]) && Number(s[f]) !== 1 / 0 && (s[f] = Number(s[f]));
|
|
453
|
+
const { labelCn: r, labelEn: c } = await this.parseStatus(s.navistat), u = w.unix(s.lasttime);
|
|
357
454
|
return {
|
|
358
455
|
mmsi: s.ShipID,
|
|
359
456
|
name: s.name,
|
|
@@ -369,147 +466,147 @@ class jt extends st {
|
|
|
369
466
|
hdg: Math.round(s.hdg / 100 * 100) / 100,
|
|
370
467
|
rot: Math.round(s.rot / 100 * 100) / 100,
|
|
371
468
|
positionTime: s.lasttime,
|
|
372
|
-
utc:
|
|
469
|
+
utc: u.utc().format(),
|
|
373
470
|
status: s.navistat,
|
|
374
|
-
labelEn:
|
|
375
|
-
labelCn:
|
|
471
|
+
labelEn: c,
|
|
472
|
+
labelCn: r,
|
|
376
473
|
method: "position",
|
|
377
474
|
vendor: "shipxy"
|
|
378
475
|
};
|
|
379
476
|
}
|
|
380
|
-
async trajectory(
|
|
381
|
-
var
|
|
382
|
-
const
|
|
477
|
+
async trajectory(t, a, i, o, n = !0, s = {}) {
|
|
478
|
+
var v;
|
|
479
|
+
const r = await this.realTimePosition(t, s), c = w(a), u = w(i), l = "https://api.shipxy.com/apicall/GetShipTrack", f = {
|
|
383
480
|
searchParams: {
|
|
384
|
-
id:
|
|
481
|
+
id: t,
|
|
385
482
|
k: this.token,
|
|
386
483
|
enc: 1,
|
|
387
484
|
cut: 0,
|
|
388
|
-
btm:
|
|
389
|
-
etm:
|
|
485
|
+
btm: c.unix(),
|
|
486
|
+
etm: u.unix()
|
|
390
487
|
}
|
|
391
|
-
}, b = await
|
|
392
|
-
if (
|
|
488
|
+
}, b = await L.get(l, f).json();
|
|
489
|
+
if (M == null || M.info("[%s] fetch trajectory from: %s - %j", s.requestId, l, f), (b == null ? void 0 : b.status) !== 0)
|
|
393
490
|
return b;
|
|
394
|
-
const
|
|
491
|
+
const y = b == null ? void 0 : b.points, F = [], I = w.unix((v = y[0]) == null ? void 0 : v.utc);
|
|
395
492
|
let p = -1;
|
|
396
|
-
for (const
|
|
397
|
-
const
|
|
398
|
-
imo:
|
|
399
|
-
mmsi:
|
|
400
|
-
sog: Math.round(
|
|
401
|
-
cog: Math.round(
|
|
402
|
-
lat: Math.round(
|
|
403
|
-
lng: Math.round(
|
|
404
|
-
positionTime:
|
|
405
|
-
utc:
|
|
493
|
+
for (const d of y) {
|
|
494
|
+
const g = w.unix(d.utc), m = {
|
|
495
|
+
imo: r == null ? void 0 : r.imo,
|
|
496
|
+
mmsi: t,
|
|
497
|
+
sog: Math.round(d.sog * 3600 / 1e3 / 1852 * 100) / 100,
|
|
498
|
+
cog: Math.round(d.cog / 100 * 100) / 100,
|
|
499
|
+
lat: Math.round(d.lat / 1e6 * 1e5) / 1e5,
|
|
500
|
+
lng: Math.round(d.lon / 1e6 * 1e5) / 1e5,
|
|
501
|
+
positionTime: g.unix(),
|
|
502
|
+
utc: g.utc().format(),
|
|
406
503
|
method: "trajectory",
|
|
407
504
|
vendor: "shipxy"
|
|
408
|
-
},
|
|
409
|
-
|
|
505
|
+
}, h = Math.floor(g.diff(I, "minute", !0) / (o || 1));
|
|
506
|
+
h !== p && (p = h, F.push(m));
|
|
410
507
|
}
|
|
411
|
-
return
|
|
508
|
+
return F;
|
|
412
509
|
}
|
|
413
510
|
}
|
|
414
|
-
class
|
|
415
|
-
constructor(
|
|
511
|
+
class Tt extends st {
|
|
512
|
+
constructor(t) {
|
|
416
513
|
super();
|
|
417
|
-
|
|
418
|
-
this.token =
|
|
514
|
+
U(this, "token");
|
|
515
|
+
this.token = t;
|
|
419
516
|
}
|
|
420
|
-
async getShipId(
|
|
517
|
+
async getShipId(t, a = {}) {
|
|
421
518
|
const i = {
|
|
422
519
|
headers: {
|
|
423
520
|
appKey: this.token
|
|
424
521
|
},
|
|
425
522
|
json: {
|
|
426
|
-
mmsiList:
|
|
523
|
+
mmsiList: t
|
|
427
524
|
}
|
|
428
|
-
}, o = "https://api3.myships.com/sp/ships/getShipIdByMMSI", n = await
|
|
429
|
-
return
|
|
525
|
+
}, o = "https://api3.myships.com/sp/ships/getShipIdByMMSI", n = await L.post(o, i).json();
|
|
526
|
+
return M == null || M.info("[%s] fetch ship id from: %s - %j", a.requestId, o, i), n.code !== "0" ? n : n.data[0].shipId;
|
|
430
527
|
}
|
|
431
|
-
async getShipInfo(
|
|
528
|
+
async getShipInfo(t, a = {}) {
|
|
432
529
|
const i = {
|
|
433
530
|
headers: {
|
|
434
531
|
appKey: this.token
|
|
435
532
|
},
|
|
436
533
|
json: {
|
|
437
|
-
shipId:
|
|
534
|
+
shipId: t
|
|
438
535
|
}
|
|
439
|
-
}, o = "https://api3.myships.com/sp/ships/aissta", n = await
|
|
440
|
-
if (
|
|
536
|
+
}, o = "https://api3.myships.com/sp/ships/aissta", n = await L.post(o, i).json();
|
|
537
|
+
if (M == null || M.info("[%s] fetch ship info from: %s - %j", a.requestId, o, i), n.code !== "0")
|
|
441
538
|
return n;
|
|
442
539
|
const s = n.data;
|
|
443
|
-
let
|
|
444
|
-
return
|
|
540
|
+
let r = s.imo;
|
|
541
|
+
return t === "407170" && (r = "9198379", M == null || M.warn("[%s] ship(%s) imo error: %s, should be %s", a.requestId, t, s.imo, r)), {
|
|
445
542
|
mmsi: s.mmsi,
|
|
446
543
|
name: s.shipnameEn,
|
|
447
|
-
imo:
|
|
544
|
+
imo: r,
|
|
448
545
|
callSign: s.callSign,
|
|
449
546
|
length: s.length,
|
|
450
547
|
width: s.breadth,
|
|
451
548
|
draught: (s.draught || 100) / 10
|
|
452
549
|
};
|
|
453
550
|
}
|
|
454
|
-
async realTimePosition(
|
|
455
|
-
const i = await this.getShipId(
|
|
551
|
+
async realTimePosition(t, a = {}) {
|
|
552
|
+
const i = await this.getShipId(t, a), o = await this.getShipInfo(i, a), n = {
|
|
456
553
|
headers: {
|
|
457
554
|
appKey: this.token
|
|
458
555
|
},
|
|
459
556
|
json: {
|
|
460
557
|
shipId: i
|
|
461
558
|
}
|
|
462
|
-
}, s = "https://api3.myships.com/sp/ships/position/latest",
|
|
463
|
-
|
|
464
|
-
const
|
|
465
|
-
for (const
|
|
466
|
-
!isNaN(
|
|
467
|
-
const { labelCn:
|
|
559
|
+
}, s = "https://api3.myships.com/sp/ships/position/latest", r = await L.post(s, n).json();
|
|
560
|
+
M == null || M.info("[%s] fetch realtime position from: %s - %j", a.requestId, s, n);
|
|
561
|
+
const c = r.data[0];
|
|
562
|
+
for (const y in c)
|
|
563
|
+
!isNaN(c[y]) && Number(c[y]) !== 1 / 0 && (c[y] = Number(c[y]));
|
|
564
|
+
const { labelCn: u, labelEn: l } = await this.parseStatus(c.aisNavStatus), f = w.unix(c.posTime);
|
|
468
565
|
return {
|
|
469
566
|
...o,
|
|
470
|
-
mmsi:
|
|
471
|
-
lat: Math.round(
|
|
472
|
-
lng: Math.round(
|
|
473
|
-
sog: Math.round(
|
|
474
|
-
cog: Math.round(
|
|
475
|
-
hdg: Math.round(
|
|
476
|
-
rot: Math.round(
|
|
477
|
-
positionTime:
|
|
478
|
-
utc:
|
|
479
|
-
status:
|
|
480
|
-
labelEn:
|
|
481
|
-
labelCn:
|
|
567
|
+
mmsi: t,
|
|
568
|
+
lat: Math.round(c.lat / 1e4 / 60 * 1e5) / 1e5,
|
|
569
|
+
lng: Math.round(c.lon / 1e4 / 60 * 1e5) / 1e5,
|
|
570
|
+
sog: Math.round(c.sog / 10 * 100) / 100,
|
|
571
|
+
cog: Math.round(c.cog / 10 * 100) / 100,
|
|
572
|
+
hdg: Math.round(c.heading * 100) / 100,
|
|
573
|
+
rot: Math.round(c.rot * 100) / 100,
|
|
574
|
+
positionTime: c.posTime,
|
|
575
|
+
utc: f.utc().format(),
|
|
576
|
+
status: c.aisNavStatus,
|
|
577
|
+
labelEn: l,
|
|
578
|
+
labelCn: u,
|
|
482
579
|
method: "position",
|
|
483
580
|
vendor: "myship"
|
|
484
581
|
};
|
|
485
582
|
}
|
|
486
|
-
async trajectory(
|
|
487
|
-
const
|
|
488
|
-
for (;
|
|
489
|
-
await this.trajectoryIn30Day(
|
|
490
|
-
return await this.trajectoryIn30Day(
|
|
583
|
+
async trajectory(t, a, i, o, n = !0, s = {}) {
|
|
584
|
+
const r = w(a), c = w(i), u = await this.getShipId(t), l = await this.getShipInfo(u), f = [];
|
|
585
|
+
for (; c.diff(r, "day", !0) > 30; )
|
|
586
|
+
await this.trajectoryIn30Day(u, r.unix(), r.add(30, "day").unix(), l, t, o, f);
|
|
587
|
+
return await this.trajectoryIn30Day(u, r.unix(), c.unix(), l, t, o, f), f;
|
|
491
588
|
}
|
|
492
|
-
async trajectoryIn30Day(
|
|
493
|
-
var
|
|
494
|
-
const
|
|
589
|
+
async trajectoryIn30Day(t, a, i, o, n, s, r, c = {}) {
|
|
590
|
+
var I;
|
|
591
|
+
const u = {
|
|
495
592
|
headers: {
|
|
496
593
|
appKey: this.token
|
|
497
594
|
},
|
|
498
595
|
json: {
|
|
499
|
-
shipId:
|
|
596
|
+
shipId: t,
|
|
500
597
|
startTime: a,
|
|
501
598
|
endTime: i
|
|
502
599
|
}
|
|
503
|
-
},
|
|
504
|
-
if (
|
|
505
|
-
return
|
|
506
|
-
const b =
|
|
600
|
+
}, l = "https://api3.myships.com/sp/ships/position/history", f = await L.post(l, u).json();
|
|
601
|
+
if (M == null || M.info("[%s] fetch trajectory from: %s - %j", c.requestId, l, u), f.code !== "0")
|
|
602
|
+
return M == null || M.warn("[%s] invoke myship trajectory failed: %j", c.requestId, f), f;
|
|
603
|
+
const b = f.data;
|
|
507
604
|
for (const p in b)
|
|
508
605
|
!isNaN(b[p]) && Number(b[p]) !== 1 / 0 && (b[p] = Number(b[p]));
|
|
509
|
-
const
|
|
510
|
-
let
|
|
606
|
+
const y = w.unix((I = b[0]) == null ? void 0 : I.posTime);
|
|
607
|
+
let F = -1;
|
|
511
608
|
for (const p of b) {
|
|
512
|
-
const
|
|
609
|
+
const v = w.unix(p.posTime), d = {
|
|
513
610
|
imo: o == null ? void 0 : o.imo,
|
|
514
611
|
mmsi: n,
|
|
515
612
|
lat: Math.round(p.lat / 1e4 / 60 * 1e5) / 1e5,
|
|
@@ -518,23 +615,23 @@ class Nt extends st {
|
|
|
518
615
|
cog: Math.round(p.cog / 10 * 100) / 100,
|
|
519
616
|
hdg: Math.round(p.heading * 100) / 100,
|
|
520
617
|
rot: Math.round(p.rot * 100) / 100,
|
|
521
|
-
positionTime:
|
|
522
|
-
utc:
|
|
618
|
+
positionTime: v.unix(),
|
|
619
|
+
utc: v.utc().format(),
|
|
523
620
|
method: "trajectory",
|
|
524
621
|
vendor: "myship"
|
|
525
|
-
},
|
|
526
|
-
|
|
622
|
+
}, g = Math.floor(v.diff(y, "minute", !0) / (s || 1));
|
|
623
|
+
g !== F && (F = g, r.push(d));
|
|
527
624
|
}
|
|
528
|
-
return
|
|
625
|
+
return r;
|
|
529
626
|
}
|
|
530
627
|
}
|
|
531
|
-
let
|
|
628
|
+
let z;
|
|
532
629
|
try {
|
|
533
|
-
|
|
630
|
+
z = ct.getLogger("vessel");
|
|
534
631
|
} catch {
|
|
535
632
|
} finally {
|
|
536
633
|
}
|
|
537
|
-
var
|
|
634
|
+
var ft = /* @__PURE__ */ ((E) => (E.NOTICE = "NOTICE", E.WARN = "WARN", E.HEAVY = "HEAVY", E.SEVERE = "SEVERE", E.ERROR = "ERROR", E.FATAL = "FATAL", E))(ft || {});
|
|
538
635
|
class yt {
|
|
539
636
|
/**
|
|
540
637
|
* 解析告警规则, 多规则场景
|
|
@@ -544,21 +641,21 @@ class yt {
|
|
|
544
641
|
*
|
|
545
642
|
* @param options
|
|
546
643
|
*/
|
|
547
|
-
parsePrinciple(
|
|
548
|
-
var s,
|
|
549
|
-
|
|
550
|
-
const a = new RegExp("(?<=\\[)(.+)(?=])", "g"), i =
|
|
644
|
+
parsePrinciple(e, t = {}) {
|
|
645
|
+
var s, r, c;
|
|
646
|
+
z == null || z.debug("[%s] parse rule: %s", t.requestId, e);
|
|
647
|
+
const a = new RegExp("(?<=\\[)(.+)(?=])", "g"), i = e.match(a) ? (s = e.match(a)) == null ? void 0 : s[0] : void 0, o = i == null ? void 0 : i.split(";");
|
|
551
648
|
if (!o)
|
|
552
649
|
return;
|
|
553
650
|
const n = {};
|
|
554
|
-
for (let
|
|
555
|
-
const
|
|
556
|
-
if (
|
|
651
|
+
for (let u = 0; u < (o == null ? void 0 : o.length); u++) {
|
|
652
|
+
const l = (c = (r = o[u].match(a)) == null ? void 0 : r[0]) == null ? void 0 : c.split("],");
|
|
653
|
+
if (u === 0 && !l)
|
|
557
654
|
n.scope = o[0];
|
|
558
|
-
else if (
|
|
559
|
-
for (let
|
|
560
|
-
const
|
|
561
|
-
|
|
655
|
+
else if (l)
|
|
656
|
+
for (let f = 0, b = l.length; f < b; f++) {
|
|
657
|
+
const y = this.parseRule(l[f]);
|
|
658
|
+
y && (n[y.level] ? y.key ? n[y.level][y == null ? void 0 : y.key] = y : n[y.level] = y : y.key ? n[y.level] = { [y == null ? void 0 : y.key]: y } : n[y.level] = y);
|
|
562
659
|
}
|
|
563
660
|
}
|
|
564
661
|
return n;
|
|
@@ -569,10 +666,10 @@ class yt {
|
|
|
569
666
|
* @param rule
|
|
570
667
|
* @param options
|
|
571
668
|
*/
|
|
572
|
-
parseRule(
|
|
669
|
+
parseRule(e, t = {}) {
|
|
573
670
|
var n;
|
|
574
|
-
|
|
575
|
-
const a = new RegExp("(?<=\\[)(.+?)(?=])", "g"), i = (n =
|
|
671
|
+
z == null || z.debug("[%s] parse rule: %s", t.requestId, e), e = e.startsWith("[") ? e : `[${e}`, e = e.endsWith("]") ? e : `${e}]`;
|
|
672
|
+
const a = new RegExp("(?<=\\[)(.+?)(?=])", "g"), i = (n = e == null ? void 0 : e.match(a)) == null ? void 0 : n[0], o = i == null ? void 0 : i.split(",");
|
|
576
673
|
if (o) {
|
|
577
674
|
let s = o[3] === "Number.MAX_VALUE" ? 100 : Number(o[3]);
|
|
578
675
|
return s = isNaN(s) ? 1 : s, {
|
|
@@ -590,26 +687,26 @@ class yt {
|
|
|
590
687
|
* @param principle 告警规则
|
|
591
688
|
* @param options
|
|
592
689
|
*/
|
|
593
|
-
checkWeather(
|
|
594
|
-
var
|
|
690
|
+
checkWeather(e, t, a = {}) {
|
|
691
|
+
var y, F, I, p, v, d, g, m, h, k, S, D, P, N, A;
|
|
595
692
|
let i = 0, o = 0, n = 0, s = 0;
|
|
596
|
-
const
|
|
597
|
-
for (let
|
|
598
|
-
const
|
|
599
|
-
s =
|
|
693
|
+
const r = Math.round(((F = (y = t == null ? void 0 : t.SEVERE) == null ? void 0 : y.sigWave) == null ? void 0 : F.number) * 1.6 * 100) / 100, c = (p = (I = t == null ? void 0 : t.SEVERE) == null ? void 0 : I.sigWave) == null ? void 0 : p.number, u = (d = (v = t == null ? void 0 : t.HEAVY) == null ? void 0 : v.sigWave) == null ? void 0 : d.number, l = Math.round((((m = (g = t == null ? void 0 : t.SEVERE) == null ? void 0 : g.wind) == null ? void 0 : m.number) + 2) * 100) / 100, f = (k = (h = t == null ? void 0 : t.SEVERE) == null ? void 0 : h.wind) == null ? void 0 : k.number, b = (D = (S = t == null ? void 0 : t.HEAVY) == null ? void 0 : S.wind) == null ? void 0 : D.number;
|
|
694
|
+
for (let x = 0; x < (e == null ? void 0 : e.length); x++) {
|
|
695
|
+
const T = e[x], q = (N = (P = T == null ? void 0 : T.meteo) == null ? void 0 : P.wave) == null ? void 0 : N.sig, R = (A = T == null ? void 0 : T.meteo) == null ? void 0 : A.wind, J = x ? w(T.eta).diff(w(e[x - 1].eta), "hour", !0) : 0;
|
|
696
|
+
s = J > s ? J : s, z == null || z.debug("[%s] check sig.wave: %j", a.requestId, { ...q, dgThd4Wv: r, svThd4Wv: c, hvThd4Wv: u }), (q == null ? void 0 : q.height) >= r ? T.isDangerous = !0 : (q == null ? void 0 : q.height) >= c ? T.isSevere = !0 : (q == null ? void 0 : q.height) >= u && (T.isHeavy = !0), z == null || z.debug("[%s] check wind: %j", a.requestId, { ...R, dgThd4Wd: l, svThd4Wd: f, hvThd4Wd: b }), (R == null ? void 0 : R.scale) >= l ? (T.isDangerous = !0, delete T.isSevere, delete T.isHeavy) : (R == null ? void 0 : R.scale) > f ? (T.isDangerous || (T.isSevere = !0), delete T.isHeavy) : (R == null ? void 0 : R.scale) === b && !T.isDangerous && !T.isSevere && (T.isHeavy = !0), i += T.isDangerous ? J : 0, o += T.isSevere ? J : 0, n += T.isHeavy ? J : 0;
|
|
600
697
|
}
|
|
601
|
-
return i = Math.round(i * 100) / 100, o = Math.round(o * 100) / 100, n = Math.round(n * 100) / 100, s = Math.round(s), { sample:
|
|
698
|
+
return i = Math.round(i * 100) / 100, o = Math.round(o * 100) / 100, n = Math.round(n * 100) / 100, s = Math.round(s), { sample: e, dangerous: i, severe: o, heavy: n, step: s < 3 ? 3 : s, wind: { dgThd4Wd: l, svThd4Wd: f, hvThd4Wd: b }, sig: { dgThd4Wv: r, svThd4Wv: c, hvThd4Wv: u } };
|
|
602
699
|
}
|
|
603
700
|
}
|
|
604
|
-
const
|
|
605
|
-
let
|
|
701
|
+
const xt = new yt();
|
|
702
|
+
let C;
|
|
606
703
|
try {
|
|
607
|
-
|
|
704
|
+
C = ct.getLogger("vessel");
|
|
608
705
|
} catch {
|
|
609
706
|
} finally {
|
|
610
707
|
}
|
|
611
|
-
const Mt = new
|
|
612
|
-
var
|
|
708
|
+
const Mt = new mt("", !0);
|
|
709
|
+
var gt = /* @__PURE__ */ ((E) => (E.common = "common", E.container = "container", E.tugs = "tugs", E))(gt || {}), bt = /* @__PURE__ */ ((E) => (E.Ballast = "Ballast", E.Laden = "Laden", E))(bt || {}), vt = /* @__PURE__ */ ((E) => (E.Cp = "CP", E.Perf = "Basis", E.Instruct = "Other", E))(vt || {});
|
|
613
710
|
class O {
|
|
614
711
|
/**
|
|
615
712
|
* @see https://baike.baidu.com/item/%E6%96%B9%E5%BD%A2%E7%B3%BB%E6%95%B0/4965568?fr=aladdin
|
|
@@ -623,10 +720,10 @@ class O {
|
|
|
623
720
|
* @param draught 吃水 m
|
|
624
721
|
* @return [0.55, 0.85]
|
|
625
722
|
*/
|
|
626
|
-
static blockCoefficient(
|
|
627
|
-
let o = Math.round(
|
|
723
|
+
static blockCoefficient(e, t, a, i) {
|
|
724
|
+
let o = Math.round(e / (t * a * i) * 100) / 100;
|
|
628
725
|
o = o < 0.55 ? 0.55 : o > 0.85 ? 0.85 : o;
|
|
629
|
-
const n = [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85], s = n.map((
|
|
726
|
+
const n = [0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85], s = n.map((r) => Math.abs(r - o));
|
|
630
727
|
return n[s.indexOf(Math.min(...s))];
|
|
631
728
|
}
|
|
632
729
|
/**
|
|
@@ -640,8 +737,8 @@ class O {
|
|
|
640
737
|
* @param g 重力加速度 9.80 m/s^2
|
|
641
738
|
* @return [0.05, 0.30]
|
|
642
739
|
*/
|
|
643
|
-
static froudeNumber(
|
|
644
|
-
let i = Math.round(Math.sqrt(
|
|
740
|
+
static froudeNumber(e, t, a = 9.8) {
|
|
741
|
+
let i = Math.round(Math.sqrt(e * e / (a * t)) * 100) / 100;
|
|
645
742
|
return i = i < 0.05 ? 0.05 : i > 0.3 ? 0.3 : i, i;
|
|
646
743
|
}
|
|
647
744
|
/**
|
|
@@ -651,7 +748,7 @@ class O {
|
|
|
651
748
|
* @param loadCondition
|
|
652
749
|
* @private
|
|
653
750
|
*/
|
|
654
|
-
static amendFactor(
|
|
751
|
+
static amendFactor(e, t, a) {
|
|
655
752
|
const i = {
|
|
656
753
|
0.55: [1.7, -1.4, -7.4],
|
|
657
754
|
0.6: [2.2, -2.5, -9.7],
|
|
@@ -669,8 +766,8 @@ class O {
|
|
|
669
766
|
0.75: [2.6, -12.5, -13.5],
|
|
670
767
|
0.8: [3, -16.3, -21.6],
|
|
671
768
|
0.85: [3.4, -20.9, 31.8]
|
|
672
|
-
}[
|
|
673
|
-
return a === "Laden" && (n = i[
|
|
769
|
+
}[e];
|
|
770
|
+
return a === "Laden" && (n = i[e]), n[0] + n[1] * t + n[2] * Math.pow(t, 2);
|
|
674
771
|
}
|
|
675
772
|
/**
|
|
676
773
|
* 失速方向因子
|
|
@@ -683,9 +780,9 @@ class O {
|
|
|
683
780
|
* @param bn
|
|
684
781
|
* @private
|
|
685
782
|
*/
|
|
686
|
-
static directionFactor(
|
|
783
|
+
static directionFactor(e, t = 0) {
|
|
687
784
|
let a;
|
|
688
|
-
return
|
|
785
|
+
return e > 30 && e <= 60 ? a = (1.7 - 0.03 * Math.pow(t - 4, 2)) / 2 : e > 60 && e <= 150 ? a = (0.9 - 0.06 * Math.pow(t - 6, 2)) / 2 : e > 150 && e <= 180 ? a = (0.4 - 0.03 * Math.pow(t - 8, 2)) / 2 : a = 1, Math.round(a * 1e5) / 1e5;
|
|
689
786
|
}
|
|
690
787
|
/**
|
|
691
788
|
* 失速船型因子
|
|
@@ -698,20 +795,20 @@ class O {
|
|
|
698
795
|
* @param bn
|
|
699
796
|
* @private
|
|
700
797
|
*/
|
|
701
|
-
static vesselTagFactor(
|
|
798
|
+
static vesselTagFactor(e, t, a, i = 0) {
|
|
702
799
|
i = i > 6 ? i - 0.9 * (i - 6) : i;
|
|
703
800
|
let o;
|
|
704
|
-
return a === "container" ? o = 0.7 * i + Math.pow(i, 6.5) / (22 * Math.pow(
|
|
801
|
+
return a === "container" ? o = 0.7 * i + Math.pow(i, 6.5) / (22 * Math.pow(e, 2 / 3)) : t === "Ballast" ? o = 0.7 * i + Math.pow(i, 6.5) / (2.7 * Math.pow(e, 2 / 3)) : o = 0.5 * i + Math.pow(i, 6.5) / (2.7 * Math.pow(e, 2 / 3)), o;
|
|
705
802
|
}
|
|
706
803
|
/**
|
|
707
804
|
* 浪高影响因子
|
|
708
805
|
* @param ht 浪高,单位m
|
|
709
806
|
* @private
|
|
710
807
|
*/
|
|
711
|
-
static waveHeightFactor(
|
|
712
|
-
|
|
808
|
+
static waveHeightFactor(e, t) {
|
|
809
|
+
e = e < 3 ? e * 0.7 : e, e = e < 0 ? 0.2 : e, e = e > 6 ? e - 0.9 * (e - 6) : e, e = e > 9 ? 9 : e;
|
|
713
810
|
let a;
|
|
714
|
-
return
|
|
811
|
+
return t > 30 && t <= 60 ? a = -0.6 : t > 60 && t <= 90 ? a = -0.4 : t > 90 && t <= 120 ? a = e < 3 ? 0.4 : -0.3 : t > 120 && t <= 150 ? a = e < 3 ? 0.6 : -0.5 : t > 150 && t <= 180 ? a = e < 3 ? 0.7 : -0.6 : a = -0.7, Math.round(a * (0.144 * Math.pow(e, 2) + 0.278 * e) * 1e4) / 1e4;
|
|
715
812
|
}
|
|
716
813
|
/**
|
|
717
814
|
* 组装船舶运行参数
|
|
@@ -721,18 +818,18 @@ class O {
|
|
|
721
818
|
* @param bearing 方位角
|
|
722
819
|
* @private
|
|
723
820
|
*/
|
|
724
|
-
static assembleProperties(
|
|
725
|
-
var
|
|
726
|
-
const o =
|
|
821
|
+
static assembleProperties(e, t, a, i) {
|
|
822
|
+
var f;
|
|
823
|
+
const o = e.lbp ?? e.length ?? e.lengthOverall ?? 198.9642, n = e.draught ?? 8, s = e.breadthMoulded ?? e.breadth ?? e.breadthExtreme ?? 32.4572, r = e.deadweight ?? 67035.7773, c = ((f = e == null ? void 0 : e.type) == null ? void 0 : f.toLowerCase()) || "common";
|
|
727
824
|
return {
|
|
728
|
-
tag:
|
|
825
|
+
tag: c.indexOf("container") > -1 ? "container" : c.indexOf("tugs") > -1 ? "tugs" : "common",
|
|
729
826
|
lbp: o,
|
|
730
|
-
loadCondition:
|
|
827
|
+
loadCondition: t,
|
|
731
828
|
draught: n,
|
|
732
829
|
breadthMoulded: s,
|
|
733
830
|
// 排水量(吨)= 载重量(吨)/ 1.025 + 吃水(米)× 船舶型宽(米)× 船舶型长(米)× 0.7
|
|
734
831
|
// 其中,1.025是指海水的密度,吨是指公吨,吃水是指船舶的最大吃水深度。船舶型宽是指船舶的最大型宽,船舶型长是指船舶的设计型长。上述公式是针对常规船舶适用的,不同类型的船舶可能会有一些差异。
|
|
735
|
-
displacement: Math.round((
|
|
832
|
+
displacement: Math.round((r / 1.025 + n * s * o * 0.7) * 1e4) / 1e4,
|
|
736
833
|
// 换算为m/s
|
|
737
834
|
speed: Math.round((a ?? 14.1382) * 1852 / 3600 * 1e4) / 1e4,
|
|
738
835
|
bearing: i || 90
|
|
@@ -749,41 +846,41 @@ class O {
|
|
|
749
846
|
* @param useRouteParam true 启用设置速度
|
|
750
847
|
* @param options
|
|
751
848
|
*/
|
|
752
|
-
static async speedLoseAt(
|
|
753
|
-
let
|
|
754
|
-
if (
|
|
755
|
-
let
|
|
849
|
+
static async speedLoseAt(e, t, a, i = "", o = 2, n = !0, s = !1, r = {}) {
|
|
850
|
+
let c;
|
|
851
|
+
if (t.velocity && s && (e.speed = _.roundPrecision(t.velocity * 1852 / 3600, 6)), n) {
|
|
852
|
+
let u;
|
|
756
853
|
try {
|
|
757
854
|
i = (i == null ? void 0 : i.toUpperCase()) === "CMEMS" ? "ECMWF" : i, i = (i == null ? void 0 : i.toUpperCase()) === "METEO2" ? "best_match" : i;
|
|
758
|
-
const { weatherModels:
|
|
759
|
-
...
|
|
855
|
+
const { weatherModels: y, marineModels: F } = await it.autoPickMeteoModel(i), I = await Mt.spotForecast(t.lat, t.lng, a.utc().format(), !1, !1, !0, {
|
|
856
|
+
...r,
|
|
760
857
|
pastDays: 1,
|
|
761
858
|
forecastDays: 1,
|
|
762
|
-
weatherModels:
|
|
763
|
-
marineModels:
|
|
764
|
-
}), [p] = it.pickHourly(
|
|
765
|
-
|
|
766
|
-
} catch (
|
|
767
|
-
|
|
859
|
+
weatherModels: y,
|
|
860
|
+
marineModels: F
|
|
861
|
+
}), [p] = it.pickHourly(I, a);
|
|
862
|
+
u = it.toLegacy(p);
|
|
863
|
+
} catch (y) {
|
|
864
|
+
C.warn("[%s] meteo2 spot(%j) forecast failed: %s", r.requestId, { ...t, eta: a.utc().format(), source: i }, y);
|
|
768
865
|
}
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
meteo: { ...
|
|
772
|
-
wxFactor:
|
|
773
|
-
cFactor:
|
|
774
|
-
speed:
|
|
866
|
+
const l = O.weatherFactor(e, u), f = O.currentFactor(e.bearing, u == null ? void 0 : u.current, o), b = Math.round((e.speed * 1.943844 + l + f) * 100) / 100;
|
|
867
|
+
c = {
|
|
868
|
+
meteo: { ...u },
|
|
869
|
+
wxFactor: l,
|
|
870
|
+
cFactor: f,
|
|
871
|
+
speed: t.velocity && s ? t.velocity : b < 0 ? 1 : b,
|
|
775
872
|
eta: a.utc().format(),
|
|
776
873
|
etd: a.utc().format()
|
|
777
874
|
};
|
|
778
875
|
} else
|
|
779
|
-
|
|
876
|
+
c = {
|
|
780
877
|
wxFactor: 0,
|
|
781
878
|
cFactor: 0,
|
|
782
|
-
speed:
|
|
879
|
+
speed: t.velocity && s ? t.velocity : Math.round((e.speed * 1.943844 + 0 + 0) * 100) / 100,
|
|
783
880
|
eta: a.utc().format(),
|
|
784
881
|
etd: a.utc().format()
|
|
785
882
|
};
|
|
786
|
-
return delete
|
|
883
|
+
return delete t.meteo, delete t.wxFactor, delete t.cFactor, delete t.speed, delete t.etd, { ...c, ...t };
|
|
787
884
|
}
|
|
788
885
|
/**
|
|
789
886
|
* 基于步长计算失速样本
|
|
@@ -799,53 +896,53 @@ class O {
|
|
|
799
896
|
* @param options
|
|
800
897
|
* @private
|
|
801
898
|
*/
|
|
802
|
-
static async speedLoseInHoursStep(
|
|
803
|
-
|
|
804
|
-
const
|
|
805
|
-
let
|
|
806
|
-
for (let
|
|
807
|
-
let
|
|
808
|
-
|
|
809
|
-
const
|
|
810
|
-
if (
|
|
811
|
-
|
|
812
|
-
const
|
|
813
|
-
if (i -
|
|
814
|
-
i = i -
|
|
899
|
+
static async speedLoseInHoursStep(e, t, a, i, o, n, s = "", r = !0, c = !1, u = {}) {
|
|
900
|
+
t.utc();
|
|
901
|
+
const l = t.clone().add(14, "days"), f = [], b = [];
|
|
902
|
+
let y = 0, F = 0, I, p;
|
|
903
|
+
for (let v = 0; v < n.length - 1; v++) {
|
|
904
|
+
let d = n[v];
|
|
905
|
+
d.distanceFromStart = Math.round((o + F) * 1e3) / 1e3;
|
|
906
|
+
const g = n[v + 1];
|
|
907
|
+
if (e.bearing = W.calculateBearing(d, g, !g.gcToPrevious), d.bearing = e.bearing, d.suspend && c) {
|
|
908
|
+
d.eta = d.eta || t.utc().format(), d.elapsed = d.elapsed ?? 0;
|
|
909
|
+
const k = d.suspend - d.elapsed;
|
|
910
|
+
if (i - y > k)
|
|
911
|
+
i = i - y - k, t.add(k, "hour"), d.elapsed = d.suspend;
|
|
815
912
|
else {
|
|
816
|
-
const
|
|
817
|
-
|
|
913
|
+
const S = i - y;
|
|
914
|
+
d.elapsed += S, t.add(S, "hour"), i = 0;
|
|
818
915
|
}
|
|
819
|
-
if (
|
|
820
|
-
return
|
|
916
|
+
if (C == null || C.info(`[%s] suspend ${d.elapsed} hours at %j, and remain ${i} hours need to go...`, u.requestId, d), i === 0)
|
|
917
|
+
return d.distanceFromPrevious = F, { etd: t, from: p || d, to: d, next: n.filter((S) => S), wps: f, days: b };
|
|
821
918
|
} else
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
let
|
|
826
|
-
if (
|
|
827
|
-
if (
|
|
828
|
-
`[%s] go to %j from %j with ${
|
|
829
|
-
|
|
830
|
-
{ lat:
|
|
919
|
+
d.suspend = 0;
|
|
920
|
+
r = t.isAfter(l) ? !1 : r, d = await O.speedLoseAt(e, d, t, s, 0, r, c, u), p = p || d, d.important && f.push(d), t.isSameOrAfter(a) && (b.push(d), a.add(24, "hour"));
|
|
921
|
+
const m = W.calculateDistance(d, g, !g.gcToPrevious);
|
|
922
|
+
let h = Math.round(m / p.speed * 1e5) / 1e5;
|
|
923
|
+
if (y + h < i) {
|
|
924
|
+
if (y += h, t.add(h, "hour"), delete n[v], C == null || C.debug(
|
|
925
|
+
`[%s] go to %j from %j with ${m}nm, and cost ${h} hours`,
|
|
926
|
+
u.requestId,
|
|
927
|
+
{ lat: g.lat, lng: g.lng },
|
|
831
928
|
{ lat: p.lat, lng: p.lng, etd: p.etd }
|
|
832
|
-
),
|
|
833
|
-
|
|
929
|
+
), F += m, n.filter((k) => k).length <= 1) {
|
|
930
|
+
I = g, I.eta = t.utc().format(), I.distanceFromPrevious = m, I.distanceFromStart = Math.round((o + F) * 1e4) / 1e4, f.push(I), delete n[v + 1];
|
|
834
931
|
break;
|
|
835
932
|
}
|
|
836
933
|
} else {
|
|
837
|
-
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
`[%s] go to %j from %j with ${
|
|
841
|
-
|
|
842
|
-
{ lat:
|
|
843
|
-
{ lat:
|
|
844
|
-
),
|
|
934
|
+
h = i - y, t.add(h, "hour");
|
|
935
|
+
const k = _.roundPrecision(p.speed * h, 5);
|
|
936
|
+
I = W.calculateCoordinate(d, e.bearing, k, "nauticalmiles", !g.gcToPrevious), I.eta = t.utc().format(), n[v] = I, C == null || C.debug(
|
|
937
|
+
`[%s] go to %j from %j with ${k}nm, and cost ${h} hours`,
|
|
938
|
+
u.requestId,
|
|
939
|
+
{ lat: I.lat, lng: I.lng },
|
|
940
|
+
{ lat: d.lat, lng: d.lng, etd: d.etd }
|
|
941
|
+
), F += k, I.distanceFromPrevious = Math.round(F * 1e4) / 1e4, I.distanceFromStart = Math.round((o + F) * 1e4) / 1e4;
|
|
845
942
|
break;
|
|
846
943
|
}
|
|
847
944
|
}
|
|
848
|
-
return { etd:
|
|
945
|
+
return { etd: t, from: p, to: I, next: n.filter((v) => v), wps: f, days: b };
|
|
849
946
|
}
|
|
850
947
|
/**
|
|
851
948
|
* 洋流影响因子
|
|
@@ -853,11 +950,11 @@ class O {
|
|
|
853
950
|
* @param current 洋流要素
|
|
854
951
|
* @param role 1: 船东, 2: 租家, 0: 未知
|
|
855
952
|
*/
|
|
856
|
-
static currentFactor(
|
|
857
|
-
const i = (
|
|
953
|
+
static currentFactor(e, t, a = 0) {
|
|
954
|
+
const i = (e - (t == null ? void 0 : t.degree) || 0) / 180 * Math.PI;
|
|
858
955
|
if (Math.abs(i) === Math.PI / 2)
|
|
859
956
|
return 0;
|
|
860
|
-
let o = ((
|
|
957
|
+
let o = ((t == null ? void 0 : t.kts) || 0) * Math.cos(i);
|
|
861
958
|
return a & 2 ? o = Math.ceil(o * 100) / 100 : a & 1 ? o = Math.floor(o * 100) / 100 : o = Math.round(o * 100) / 100, Math.abs(o) > 5 ? 0 : o;
|
|
862
959
|
}
|
|
863
960
|
/**
|
|
@@ -865,17 +962,17 @@ class O {
|
|
|
865
962
|
* @param props 船舶档案
|
|
866
963
|
* @param wwc 气象要素
|
|
867
964
|
*/
|
|
868
|
-
static weatherFactor(
|
|
869
|
-
var
|
|
870
|
-
|
|
871
|
-
const a = O.blockCoefficient(
|
|
872
|
-
let n = Math.abs(
|
|
965
|
+
static weatherFactor(e, t) {
|
|
966
|
+
var l, f, b, y, F, I, p;
|
|
967
|
+
C == null || C.debug("calculate weather factor via: %j", { ...e, ...t });
|
|
968
|
+
const a = O.blockCoefficient(e.displacement, e.lbp, e.breadthMoulded, e.draught), i = O.froudeNumber(e.speed, e.lbp), o = O.amendFactor(a, i, e.loadCondition);
|
|
969
|
+
let n = Math.abs(e.bearing % 360 - (((l = t == null ? void 0 : t.wind) == null ? void 0 : l.degree) % 360 || 0));
|
|
873
970
|
n = n > 180 ? 360 - n : n;
|
|
874
|
-
const s = O.directionFactor(n, (
|
|
875
|
-
let
|
|
876
|
-
|
|
877
|
-
const
|
|
878
|
-
return
|
|
971
|
+
const s = O.directionFactor(n, (f = t == null ? void 0 : t.wind) == null ? void 0 : f.scale), r = O.vesselTagFactor(e.displacement, e.loadCondition, e.tag, (b = t == null ? void 0 : t.wind) == null ? void 0 : b.scale);
|
|
972
|
+
let c = s * o * r / 100 * e.speed;
|
|
973
|
+
c = Math.round(c * 1.943844 * 1e4) / 1e4 * -1, e.tag === "tugs" && Math.abs(c) > 1 && (c = c / (Math.abs(Math.round(c)) + 1)), C == null || C.debug("wind wx factor = %d", c), n = Math.abs(e.bearing % 360 - (((F = (y = t == null ? void 0 : t.wave) == null ? void 0 : y.sig) == null ? void 0 : F.degree) % 360 || 0));
|
|
974
|
+
const u = O.waveHeightFactor(((p = (I = t == null ? void 0 : t.wave) == null ? void 0 : I.sig) == null ? void 0 : p.height) ?? 1, n);
|
|
975
|
+
return C == null || C.debug("wave wx factor = %d", u), c = Math.abs(c) > Math.abs(u) ? c : c * 0.3 + u * 0.7, C == null || C.debug("weather factor = %d", c), c = Math.abs(c) > 3 ? 3 * (Math.abs(c) / c) + Math.abs(c) / c * (Math.abs(c) - 2) * 0.1 : c, Math.round((c || 0) * 100) / 100;
|
|
879
976
|
}
|
|
880
977
|
/**
|
|
881
978
|
* 全程失速分析(走完航程)
|
|
@@ -890,77 +987,77 @@ class O {
|
|
|
890
987
|
* @param useRouteParam
|
|
891
988
|
* @param options
|
|
892
989
|
*/
|
|
893
|
-
static async analyseInstant(
|
|
894
|
-
var
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
const { route:
|
|
898
|
-
if (((
|
|
990
|
+
static async analyseInstant(e, t, a, i, o, n = "", s = 0, r = !0, c = !1, u = {}) {
|
|
991
|
+
var K, G, X, Q, Z, $;
|
|
992
|
+
const l = w().valueOf();
|
|
993
|
+
e.lng = _.convertToStdLng(e.lng);
|
|
994
|
+
const { route: f, waypoints: b } = o.points, y = W.calculateSubRoute(e, f);
|
|
995
|
+
if (((K = y[0]) == null ? void 0 : K.length) <= 1)
|
|
899
996
|
return;
|
|
900
|
-
const { v0:
|
|
901
|
-
v0:
|
|
902
|
-
label:
|
|
997
|
+
const { v0: F, label: I } = e.sog ? {
|
|
998
|
+
v0: e.sog,
|
|
999
|
+
label: e.label || "Other"
|
|
903
1000
|
/* Instruct */
|
|
904
1001
|
} : {
|
|
905
1002
|
v0: i.speed,
|
|
906
1003
|
label: "CP"
|
|
907
1004
|
/* Cp */
|
|
908
|
-
}, p = O.assembleProperties(a, i.loadCondition,
|
|
909
|
-
|
|
910
|
-
const
|
|
911
|
-
from: { ...
|
|
912
|
-
route:
|
|
913
|
-
waypoints:
|
|
914
|
-
v0:
|
|
915
|
-
label:
|
|
916
|
-
},
|
|
1005
|
+
}, p = O.assembleProperties(a, i.loadCondition, F, 0), v = b.length ? W.calculateSubWaypoints(e, b) : [];
|
|
1006
|
+
v.forEach((Y) => Y.important = !0);
|
|
1007
|
+
const d = {
|
|
1008
|
+
from: { ...e },
|
|
1009
|
+
route: y,
|
|
1010
|
+
waypoints: v,
|
|
1011
|
+
v0: F,
|
|
1012
|
+
label: I
|
|
1013
|
+
}, g = {
|
|
917
1014
|
hours: [],
|
|
918
1015
|
days: [],
|
|
919
1016
|
wps: []
|
|
920
1017
|
};
|
|
921
|
-
s || (W.calculateRouteDistance(
|
|
922
|
-
let
|
|
923
|
-
|
|
924
|
-
const
|
|
925
|
-
for (;
|
|
926
|
-
const
|
|
1018
|
+
s || (W.calculateRouteDistance(y) / i.speed <= 72 ? s = 3 : s = 6);
|
|
1019
|
+
let m = W.simplifyRouteToCoordinates(y, v, 0), h = 0, k = 0, S = 0, D = 0;
|
|
1020
|
+
t = w(t).utc();
|
|
1021
|
+
const P = t.clone();
|
|
1022
|
+
for (; m.length > 0; ) {
|
|
1023
|
+
const Y = s - t.hour() % s, B = Math.ceil(t.clone().add(Y, "h").set({ minute: 0, second: 0, millisecond: 0 }).diff(t, "h", !0) * 1e4) / 1e4, j = await O.speedLoseInHoursStep(
|
|
927
1024
|
p,
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
u,
|
|
1025
|
+
t,
|
|
1026
|
+
P,
|
|
1027
|
+
B,
|
|
932
1028
|
h,
|
|
1029
|
+
m,
|
|
933
1030
|
n,
|
|
934
|
-
d,
|
|
935
1031
|
r,
|
|
936
|
-
|
|
1032
|
+
c,
|
|
1033
|
+
u
|
|
937
1034
|
);
|
|
938
|
-
(G =
|
|
1035
|
+
(G = j.from) != null && G.speed && (g.hours.push(j.from), g.wps.push(...j.wps), g.days.push(...j.days)), m = j == null ? void 0 : j.next, m.length || g.hours.push(j == null ? void 0 : j.to), h += Math.round((((X = j == null ? void 0 : j.to) == null ? void 0 : X.distanceFromPrevious) ?? 0) * 1e4) / 1e4;
|
|
939
1036
|
}
|
|
940
|
-
const
|
|
941
|
-
for (let
|
|
942
|
-
const
|
|
943
|
-
|
|
1037
|
+
const N = g.hours;
|
|
1038
|
+
for (let Y = 0; Y < N.length - 1; Y++) {
|
|
1039
|
+
const B = w(N[Y + 1].eta).diff(N[Y].etd, "hour", !0) || 1;
|
|
1040
|
+
k += (N[Y].wxFactor || 0) * B, S += (N[Y].cFactor || 0) * B, D += B;
|
|
944
1041
|
}
|
|
945
|
-
(Q =
|
|
946
|
-
|
|
947
|
-
const
|
|
948
|
-
if (
|
|
949
|
-
const
|
|
950
|
-
|
|
1042
|
+
(Q = g.wps) == null || Q.forEach((Y, B) => {
|
|
1043
|
+
Y.positionTime = w.utc(Y.etd || Y.eta).unix();
|
|
1044
|
+
const j = g.wps[B - 1];
|
|
1045
|
+
if (j) {
|
|
1046
|
+
const V = Y.distanceFromStart - j.distanceFromStart, H = w(Y.eta || Y.etd).diff(w(j.etd || j.eta), "h", !0);
|
|
1047
|
+
Y.avgSpd = Math.round(V / H * 100) / 100, j.bearing = W.calculateBearing(j, Y);
|
|
951
1048
|
}
|
|
952
|
-
}),
|
|
953
|
-
const A =
|
|
954
|
-
|
|
955
|
-
const { distanceInECA:
|
|
956
|
-
|
|
957
|
-
eca:
|
|
958
|
-
distanceInECA:
|
|
959
|
-
hoursInECA:
|
|
1049
|
+
}), g.wps = (Z = g.wps) == null ? void 0 : Z.reduce((Y, B) => (Y.some((j) => Math.round(j.positionTime / 60) === Math.round(B.positionTime / 60)) || Y.push(B), Y), []), d.sample = g;
|
|
1050
|
+
const A = g.hours.at(0), x = g.hours.at(-1);
|
|
1051
|
+
d.distance = Math.round(x.distanceFromStart * 1e3) / 1e3, d.etd = w(A.eta).utc().format(), d.eta = w(x.eta).utc().format(), d.wxFactor = Math.round(k / D * 1e3) / 1e3, d.cFactor = Math.round(S / D * 1e3) / 1e3, d.avgSpeed = Math.round(x.distanceFromStart / D * 1e3) / 1e3, d.totalHrs = Math.round(D * 1e3) / 1e3;
|
|
1052
|
+
const { distanceInECA: T, hoursInECA: q, totalDgoConsInECA: R, eca: J } = await this.calculateECA(d, i, u), tt = _.roundPrecision(i.fo / 24 * (D - q), 3), at = _.roundPrecision(i.dgo / 24 * D, 3);
|
|
1053
|
+
d.extend = {
|
|
1054
|
+
eca: J,
|
|
1055
|
+
distanceInECA: T,
|
|
1056
|
+
hoursInECA: q,
|
|
960
1057
|
totalDgoConsInECA: R
|
|
961
|
-
},
|
|
962
|
-
const et =
|
|
963
|
-
return
|
|
1058
|
+
}, d.totalFoCons = tt < 0 ? 0 : tt, d.totalDgoCons = at;
|
|
1059
|
+
const et = w().valueOf() - l, ot = (($ = g == null ? void 0 : g.hours) == null ? void 0 : $.length) || 1;
|
|
1060
|
+
return C == null || C.info("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms", u == null ? void 0 : u.requestId, et, ot, Math.round(et / ot * 1e3) / 1e3), d;
|
|
964
1061
|
}
|
|
965
1062
|
/**
|
|
966
1063
|
* 分段失速分析(最多走hours 小时)
|
|
@@ -970,83 +1067,85 @@ class O {
|
|
|
970
1067
|
* @param vessel 船舶属性 @see VesselAssemble, 注意吃水为船舶实时吃水,非档案中的固定吃水,一般可以从ais获取; 如获取不得,用档案吃水代替
|
|
971
1068
|
* @param cp { loadCondition, speed } LoadCondition: Ballast or Laden, speed(kts)
|
|
972
1069
|
* @param route 航路[[[lng, lat]]]
|
|
1070
|
+
* @param waypoints
|
|
973
1071
|
* @param source 气象数据源,GFS or CMEMES, 默认CMEMS
|
|
974
1072
|
* @param stepHrs
|
|
975
1073
|
* @param useMeteo true 启用气象分析
|
|
976
1074
|
* @param useRouteParam
|
|
1075
|
+
* @param options
|
|
977
1076
|
*/
|
|
978
|
-
static async analyseInstantWithThreshed(
|
|
979
|
-
var X, Q, Z, $,
|
|
980
|
-
const b =
|
|
981
|
-
|
|
982
|
-
const { v0:
|
|
983
|
-
v0:
|
|
984
|
-
label:
|
|
1077
|
+
static async analyseInstantWithThreshed(e, t, a, i, o, n, s, r = "", c = 3, u = !0, l = !1, f = {}) {
|
|
1078
|
+
var X, Q, Z, $, Y, B;
|
|
1079
|
+
const b = w().valueOf();
|
|
1080
|
+
e.lng = _.convertToStdLng(e.lng);
|
|
1081
|
+
const { v0: y, label: F } = e.sog ? {
|
|
1082
|
+
v0: e.sog,
|
|
1083
|
+
label: e.label || "Other"
|
|
985
1084
|
/* Instruct */
|
|
986
1085
|
} : {
|
|
987
1086
|
v0: o.speed,
|
|
988
1087
|
label: "CP"
|
|
989
1088
|
/* Cp */
|
|
990
|
-
},
|
|
1089
|
+
}, I = O.assembleProperties(i, o.loadCondition, y, 0), p = W.calculateSubRoute(e, n);
|
|
991
1090
|
if (((X = p[0]) == null ? void 0 : X.length) <= 1)
|
|
992
1091
|
return;
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
let
|
|
996
|
-
const
|
|
1092
|
+
const v = s.length ? W.calculateSubWaypoints(e, s) : [];
|
|
1093
|
+
v.forEach((j) => j.important = !0);
|
|
1094
|
+
let d = W.simplifyRouteToCoordinates(p, v, 0), g = 0, m = 0, h = 0, k = 0;
|
|
1095
|
+
const S = {
|
|
997
1096
|
hours: [],
|
|
998
1097
|
wps: [],
|
|
999
1098
|
days: []
|
|
1000
1099
|
};
|
|
1001
|
-
|
|
1002
|
-
const D =
|
|
1003
|
-
for (;
|
|
1004
|
-
const
|
|
1005
|
-
let
|
|
1006
|
-
|
|
1007
|
-
const H = await O.speedLoseInHoursStep(
|
|
1008
|
-
if ((Q = H.from) != null && Q.speed && (
|
|
1100
|
+
t = w(t).utc();
|
|
1101
|
+
const D = t.clone();
|
|
1102
|
+
for (; d.length > 0; ) {
|
|
1103
|
+
const j = c - t.hour() % c;
|
|
1104
|
+
let V = Math.ceil(t.clone().add(j, "h").set({ minute: 0, second: 0, millisecond: 0 }).diff(t, "h", !0) * 1e4) / 1e4;
|
|
1105
|
+
V = t.clone().add(V, "h").isSameOrAfter(a) ? a.diff(t, "h", !0) * 1e4 / 1e4 : V;
|
|
1106
|
+
const H = await O.speedLoseInHoursStep(I, t, D, V, g, d, r, u, l, f);
|
|
1107
|
+
if ((Q = H.from) != null && Q.speed && (S.hours.push(H.from), H != null && H.wps && S.wps.push(...H.wps), S.days.push(...H.days)), d = H == null ? void 0 : H.next, d.length || S.hours.push(H == null ? void 0 : H.to), g += Math.round((((Z = H == null ? void 0 : H.to) == null ? void 0 : Z.distanceFromPrevious) ?? 0) * 1e4) / 1e4, !V)
|
|
1009
1108
|
break;
|
|
1010
1109
|
}
|
|
1011
|
-
|
|
1012
|
-
const H =
|
|
1110
|
+
S.wps = ($ = S.wps) == null ? void 0 : $.reduce((j, V) => (j.some((H) => Math.round(w(H.etd).unix() / 60) === Math.round(w(V.etd).unix() / 60)) || j.push(V), j), []), (Y = S.wps) == null || Y.forEach((j, V) => {
|
|
1111
|
+
const H = S.wps[V - 1];
|
|
1013
1112
|
if (H) {
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
const ut = W.calculateBearing(H,
|
|
1113
|
+
const rt = j.distanceFromStart - H.distanceFromStart, dt = w(j.eta || j.etd).diff(w(H.etd || H.eta), "h", !0);
|
|
1114
|
+
j.avgSpd = Math.round(rt / dt * 100) / 100;
|
|
1115
|
+
const ut = W.calculateBearing(H, j);
|
|
1017
1116
|
H.bearing = ut;
|
|
1018
1117
|
}
|
|
1019
1118
|
});
|
|
1020
|
-
const
|
|
1021
|
-
for (let
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1119
|
+
const P = S.hours;
|
|
1120
|
+
for (let j = 0; j < P.length - 1; j++) {
|
|
1121
|
+
const V = w(P[j + 1].eta).diff(P[j].etd, "hour", !0);
|
|
1122
|
+
m += P[j].wxFactor * V, h += P[j].cFactor * V, k += V;
|
|
1024
1123
|
}
|
|
1025
|
-
const
|
|
1026
|
-
sample:
|
|
1124
|
+
const N = S.hours.at(0), A = S.hours.at(-1), x = await W.calculateRangeRoute(N, A, p), T = await W.calculateRangeWaypoints(N, A, p, v), q = {
|
|
1125
|
+
sample: S,
|
|
1027
1126
|
distance: Math.round(((A == null ? void 0 : A.distanceFromStart) || 0) * 1e4) / 1e4,
|
|
1028
1127
|
// 注意,可能会在first节点Drift,所有采用eta做为初始出发时间
|
|
1029
|
-
etd:
|
|
1030
|
-
eta:
|
|
1031
|
-
wxFactor: Math.round(
|
|
1032
|
-
cFactor: Math.round(
|
|
1033
|
-
avgSpeed: Math.round(((A == null ? void 0 : A.distanceFromStart) || 0) /
|
|
1034
|
-
totalHrs: Math.round(
|
|
1035
|
-
from:
|
|
1128
|
+
etd: w(N.eta).utc().format(),
|
|
1129
|
+
eta: w(A == null ? void 0 : A.eta).utc().format(),
|
|
1130
|
+
wxFactor: Math.round(m / k * 1e3) / 1e3,
|
|
1131
|
+
cFactor: Math.round(h / k * 1e3) / 1e3,
|
|
1132
|
+
avgSpeed: Math.round(((A == null ? void 0 : A.distanceFromStart) || 0) / k * 1e3) / 1e3,
|
|
1133
|
+
totalHrs: Math.round(k * 1e3) / 1e3,
|
|
1134
|
+
from: N,
|
|
1036
1135
|
to: A,
|
|
1037
|
-
route:
|
|
1038
|
-
waypoints:
|
|
1039
|
-
v0:
|
|
1040
|
-
label:
|
|
1041
|
-
}, { distanceInECA: R, hoursInECA:
|
|
1042
|
-
|
|
1136
|
+
route: x,
|
|
1137
|
+
waypoints: T,
|
|
1138
|
+
v0: y,
|
|
1139
|
+
label: F
|
|
1140
|
+
}, { distanceInECA: R, hoursInECA: J, totalDgoConsInECA: tt, eca: at } = await this.calculateECA(q, o, f), nt = _.roundPrecision(o.fo / 24 * (k - J), 3), et = _.roundPrecision(o.dgo / 24 * k, 3);
|
|
1141
|
+
q.extend = {
|
|
1043
1142
|
eca: at,
|
|
1044
1143
|
distanceInECA: R,
|
|
1045
|
-
hoursInECA:
|
|
1144
|
+
hoursInECA: J,
|
|
1046
1145
|
totalDgoConsInECA: tt
|
|
1047
|
-
},
|
|
1048
|
-
const
|
|
1049
|
-
return
|
|
1146
|
+
}, q.totalDgoCons = et, q.totalFoCons = nt < 0 ? 0 : nt;
|
|
1147
|
+
const K = w().valueOf() - b, G = ((B = S == null ? void 0 : S.hours) == null ? void 0 : B.length) || 1;
|
|
1148
|
+
return C == null || C.debug("[%s] each hour-sample speed analyse cost: (%d / %d = %d) ms", f == null ? void 0 : f.requestId, K, G, Math.round(K / G * 1e3) / 1e3), q;
|
|
1050
1149
|
}
|
|
1051
1150
|
/**
|
|
1052
1151
|
* 在指定航线条件下,基于多CP,动态计算最优成本(租金+油费)方案
|
|
@@ -1063,59 +1162,59 @@ class O {
|
|
|
1063
1162
|
* @param lane 基础航线(重要转向点)
|
|
1064
1163
|
* @param options
|
|
1065
1164
|
*/
|
|
1066
|
-
static async analyseCost(
|
|
1067
|
-
var p,
|
|
1068
|
-
const n =
|
|
1069
|
-
|
|
1070
|
-
const
|
|
1071
|
-
let
|
|
1072
|
-
a.forEach((
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1075
|
-
}),
|
|
1076
|
-
const
|
|
1077
|
-
let
|
|
1078
|
-
for (const
|
|
1079
|
-
const
|
|
1080
|
-
{ lat:
|
|
1081
|
-
|
|
1165
|
+
static async analyseCost(e, t, a, i, o = {}) {
|
|
1166
|
+
var p, v;
|
|
1167
|
+
const n = w().valueOf(), s = [];
|
|
1168
|
+
e.speedStep = e.speedStep || 3, e.alterStep = e.alterStep ?? 1;
|
|
1169
|
+
const r = W.calculateRouteDistance(i.route);
|
|
1170
|
+
let c = 0;
|
|
1171
|
+
a.forEach((d) => {
|
|
1172
|
+
const g = Math.ceil(r / d.speed / 24);
|
|
1173
|
+
c = c < g ? g : c;
|
|
1174
|
+
}), c = c * 1.3;
|
|
1175
|
+
const u = w.utc(e.etd).add(c ?? 14, "day");
|
|
1176
|
+
let l = 1;
|
|
1177
|
+
for (const d of a) {
|
|
1178
|
+
const g = JSON.parse(JSON.stringify(i.route)), m = JSON.parse(JSON.stringify(i.waypoints)), h = await O.analyseInstantWithThreshed(
|
|
1179
|
+
{ lat: e.lat, lng: e.lng },
|
|
1180
|
+
e.etd,
|
|
1181
|
+
u,
|
|
1182
|
+
t,
|
|
1183
|
+
d,
|
|
1184
|
+
g,
|
|
1082
1185
|
m,
|
|
1083
|
-
e,
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
t.meteoVendor,
|
|
1088
|
-
t.speedStep,
|
|
1089
|
-
t.useMeteo,
|
|
1090
|
-
t.useRouteParam,
|
|
1186
|
+
e.meteoVendor,
|
|
1187
|
+
e.speedStep,
|
|
1188
|
+
e.useMeteo,
|
|
1189
|
+
e.useRouteParam,
|
|
1091
1190
|
o
|
|
1092
1191
|
);
|
|
1093
|
-
|
|
1094
|
-
cost:
|
|
1095
|
-
hire:
|
|
1096
|
-
bunker:
|
|
1097
|
-
distance:
|
|
1098
|
-
hours:
|
|
1099
|
-
cp: `${
|
|
1100
|
-
})),
|
|
1192
|
+
h && (await O.calculateCost(h, d, e, o), s.push(h), C == null || C.info("[%s][L%d-%d] analyse from %s to %s cost: %j", o.requestId, 1, l, e.etd, u.format(), {
|
|
1193
|
+
cost: h.cost.total,
|
|
1194
|
+
hire: h.cost.hire,
|
|
1195
|
+
bunker: h.cost.bunker,
|
|
1196
|
+
distance: h.distance,
|
|
1197
|
+
hours: h.totalHrs,
|
|
1198
|
+
cp: `${d.speed}/${d.fo}/${d.dgo}`
|
|
1199
|
+
})), l++;
|
|
1101
1200
|
}
|
|
1102
|
-
s.sort((
|
|
1103
|
-
const
|
|
1104
|
-
if (
|
|
1105
|
-
const
|
|
1106
|
-
let
|
|
1107
|
-
|
|
1108
|
-
let D = 2,
|
|
1109
|
-
for (;
|
|
1110
|
-
const A = await O.combinedAnalyse(
|
|
1111
|
-
if (
|
|
1201
|
+
s.sort((d, g) => d.cost.total - g.cost.total);
|
|
1202
|
+
const f = s.at(0), b = s.at(1), y = [];
|
|
1203
|
+
if (y.push({ combined: !1, speeds: [f], cost: (p = f.cost) == null ? void 0 : p.total }), b) {
|
|
1204
|
+
const d = f.cost.cp, g = b.cost.cp, m = w(f.eta), h = w(f.etd), k = m.diff(h, "days", !0);
|
|
1205
|
+
let S = Math.ceil(k / 2);
|
|
1206
|
+
S = S > 7 ? 7 : S < e.alterStep ? e.alterStep : S;
|
|
1207
|
+
let D = 2, P = { combined: !1, speeds: [b], cost: (v = b.cost) == null ? void 0 : v.total }, N;
|
|
1208
|
+
for (; S >= e.alterStep; ) {
|
|
1209
|
+
const A = await O.combinedAnalyse(e, t, u, [d, g], i, S, { ...o, level: D });
|
|
1210
|
+
if (P.cost > A.cost ? N ? (N == null ? void 0 : N.cost) > A.cost && (N = A) : (N = P, P = A) : (!N || (N == null ? void 0 : N.cost) > A.cost) && (N = A), S <= e.alterStep)
|
|
1112
1211
|
break;
|
|
1113
|
-
|
|
1212
|
+
S = Math.ceil(S / 2), D += 1;
|
|
1114
1213
|
}
|
|
1115
|
-
|
|
1214
|
+
y.push(P), N && y.push(N);
|
|
1116
1215
|
}
|
|
1117
|
-
const
|
|
1118
|
-
return
|
|
1216
|
+
const I = w().valueOf() - n;
|
|
1217
|
+
return C == null || C.info("[%s] analyse elapsed: %d ms", o == null ? void 0 : o.requestId, I), y.sort((d, g) => d.cost - g.cost);
|
|
1119
1218
|
}
|
|
1120
1219
|
/**
|
|
1121
1220
|
* 按步长多次减半,分别用7,4,2,1天步长及cpa,cpb交替计算各种组合下的成本
|
|
@@ -1127,24 +1226,24 @@ class O {
|
|
|
1127
1226
|
* @param step 步长,7,4,2,1
|
|
1128
1227
|
* @param options
|
|
1129
1228
|
*/
|
|
1130
|
-
static async combinedAnalyse(
|
|
1131
|
-
s.counter = 1,
|
|
1132
|
-
const
|
|
1133
|
-
|
|
1134
|
-
cost:
|
|
1135
|
-
hire:
|
|
1136
|
-
bunker:
|
|
1137
|
-
distance:
|
|
1229
|
+
static async combinedAnalyse(e, t, a, i, o, n, s = {}) {
|
|
1230
|
+
s.counter = 1, C == null || C.info("[%s][L%d] analyse with alternate cp in every %d days", s.requestId, s.level, n);
|
|
1231
|
+
const r = await O.alternateAnalyse(e, t, a, i, 0, o, n, s), c = r.reduce((g, m) => g + m.cost.total, 0), u = r.reduce((g, m) => g + m.cost.hire, 0), l = r.reduce((g, m) => g + m.cost.bunker, 0), f = r.reduce((g, m) => g + m.distance, 0), b = r.reduce((g, m) => g + m.totalHrs, 0);
|
|
1232
|
+
C == null || C.info("[%s][L%d] cost with cpa/cpb turn: %j", s.requestId, s.level, {
|
|
1233
|
+
cost: c,
|
|
1234
|
+
hire: u,
|
|
1235
|
+
bunker: l,
|
|
1236
|
+
distance: f,
|
|
1138
1237
|
hours: b
|
|
1139
1238
|
});
|
|
1140
|
-
const
|
|
1141
|
-
return
|
|
1142
|
-
cost:
|
|
1143
|
-
hire:
|
|
1239
|
+
const y = await O.alternateAnalyse(e, t, a, i, 1, o, n, s), F = y.reduce((g, m) => g + m.cost.total, 0), I = y.reduce((g, m) => g + m.cost.hire, 0), p = y.reduce((g, m) => g + m.cost.bunker, 0), v = y.reduce((g, m) => g + m.distance, 0), d = y.reduce((g, m) => g + m.totalHrs, 0);
|
|
1240
|
+
return C == null || C.info("[%s][L%d] cost with cpb/cpa turn: %j", s.requestId, s.level, {
|
|
1241
|
+
cost: F,
|
|
1242
|
+
hire: I,
|
|
1144
1243
|
bunker: p,
|
|
1145
|
-
distance:
|
|
1146
|
-
hours:
|
|
1147
|
-
}),
|
|
1244
|
+
distance: v,
|
|
1245
|
+
hours: d
|
|
1246
|
+
}), c < F ? { combined: !0, cost: Math.round(c * 1e3) / 1e3, speeds: r, step: n } : { combined: !0, cost: Math.round(F * 1e3) / 1e3, speeds: y, step: n };
|
|
1148
1247
|
}
|
|
1149
1248
|
/**
|
|
1150
1249
|
* 基于cp索引,交替计算指定步长下的成本
|
|
@@ -1157,48 +1256,48 @@ class O {
|
|
|
1157
1256
|
* @param step 步长,7,4,2,1
|
|
1158
1257
|
* @param options
|
|
1159
1258
|
*/
|
|
1160
|
-
static async alternateAnalyse(
|
|
1161
|
-
var
|
|
1162
|
-
let
|
|
1163
|
-
const
|
|
1164
|
-
for (;
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1259
|
+
static async alternateAnalyse(e, t, a, i, o, n, s, r = {}) {
|
|
1260
|
+
var f, b;
|
|
1261
|
+
let c = w.utc(e.etd);
|
|
1262
|
+
const u = { lat: e.lat, lng: e.lng }, l = [];
|
|
1263
|
+
for (; c.isBefore(a); ) {
|
|
1264
|
+
const y = c.clone().utc().add(s, "day"), F = JSON.parse(JSON.stringify(n.route)), I = JSON.parse(JSON.stringify(n.waypoints)), p = i[o], v = await O.analyseInstantWithThreshed(
|
|
1265
|
+
u,
|
|
1266
|
+
c.utc().format(),
|
|
1267
|
+
y,
|
|
1268
|
+
t,
|
|
1170
1269
|
p,
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1270
|
+
F,
|
|
1271
|
+
I,
|
|
1272
|
+
e.meteoVendor,
|
|
1273
|
+
e.speedStep,
|
|
1274
|
+
e.useMeteo,
|
|
1275
|
+
e.useRouteParam,
|
|
1276
|
+
r
|
|
1178
1277
|
);
|
|
1179
|
-
|
|
1278
|
+
v && (await O.calculateCost(v, p, e, r), C == null || C.info(
|
|
1180
1279
|
"[%s][L%d-%d] analyse from %s to %s cost: %j",
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1280
|
+
r.requestId,
|
|
1281
|
+
r.level,
|
|
1282
|
+
r.counter,
|
|
1283
|
+
c.utc().format(),
|
|
1284
|
+
y.utc().format(),
|
|
1186
1285
|
{
|
|
1187
|
-
cost:
|
|
1188
|
-
hire:
|
|
1189
|
-
bunker:
|
|
1190
|
-
distance:
|
|
1191
|
-
hours:
|
|
1286
|
+
cost: v.cost.total,
|
|
1287
|
+
hire: v.cost.hire,
|
|
1288
|
+
bunker: v.cost.bunker,
|
|
1289
|
+
distance: v.distance,
|
|
1290
|
+
hours: v.totalHrs,
|
|
1192
1291
|
cp: `${p.speed}/${p.fo}/${p.dgo}`
|
|
1193
1292
|
}
|
|
1194
|
-
)),
|
|
1195
|
-
const
|
|
1196
|
-
if (
|
|
1197
|
-
|
|
1293
|
+
)), r.counter = r.counter + 1;
|
|
1294
|
+
const d = (b = (f = v == null ? void 0 : v.sample) == null ? void 0 : f.hours) == null ? void 0 : b.at(-1);
|
|
1295
|
+
if (d)
|
|
1296
|
+
u.lat = d.lat, u.lng = d.lng, c = w(d.eta), l.push(v), o = o ? 0 : 1;
|
|
1198
1297
|
else
|
|
1199
1298
|
break;
|
|
1200
1299
|
}
|
|
1201
|
-
return
|
|
1300
|
+
return l;
|
|
1202
1301
|
}
|
|
1203
1302
|
/**
|
|
1204
1303
|
* 计算Speed的cost
|
|
@@ -1207,36 +1306,36 @@ class O {
|
|
|
1207
1306
|
* @param props
|
|
1208
1307
|
* @param options
|
|
1209
1308
|
*/
|
|
1210
|
-
static async calculateCost(
|
|
1309
|
+
static async calculateCost(e, t, a, i = {}) {
|
|
1211
1310
|
var o;
|
|
1212
|
-
if (
|
|
1213
|
-
const n = (a.addComm || 0) >= 1 ? (a.addComm || 0) / 100 : a.addComm || 0, s = Math.round(
|
|
1214
|
-
|
|
1215
|
-
total: Math.round((s +
|
|
1311
|
+
if (e) {
|
|
1312
|
+
const n = (a.addComm || 0) >= 1 ? (a.addComm || 0) / 100 : a.addComm || 0, s = Math.round(e.totalHrs / 24 * (a.dailyHire || 0) * (1 - n) * 1e3) / 1e3, r = Math.round(e.totalFoCons * (a.priceFO || 0) * 1e3) / 1e3, c = Math.round((e.totalDgoCons + (((o = e.extend) == null ? void 0 : o.totalDgoConsInECA) || 0)) * (a.priceDGO || 0) * 1e3) / 1e3;
|
|
1313
|
+
e.cost = {
|
|
1314
|
+
total: Math.round((s + r + c) * 1e3) / 1e3,
|
|
1216
1315
|
hire: s,
|
|
1217
|
-
bunker: Math.round((
|
|
1218
|
-
cp:
|
|
1316
|
+
bunker: Math.round((r + c) * 1e3) / 1e3,
|
|
1317
|
+
cp: t
|
|
1219
1318
|
};
|
|
1220
1319
|
}
|
|
1221
|
-
return
|
|
1320
|
+
return e;
|
|
1222
1321
|
}
|
|
1223
1322
|
/**
|
|
1224
1323
|
* 计算单cp模式下的ECA属性
|
|
1225
1324
|
*
|
|
1226
1325
|
*/
|
|
1227
|
-
static async calculateECA(
|
|
1228
|
-
var
|
|
1229
|
-
const i = await W.intersectInECA((
|
|
1326
|
+
static async calculateECA(e, t, a = {}) {
|
|
1327
|
+
var r, c, u, l;
|
|
1328
|
+
const i = await W.intersectInECA((e == null ? void 0 : e.route) || []);
|
|
1230
1329
|
let o = 0, n = 0, s = 0;
|
|
1231
|
-
(
|
|
1232
|
-
|
|
1330
|
+
(c = (r = e == null ? void 0 : e.sample) == null ? void 0 : r.wps) == null || c.forEach((f) => {
|
|
1331
|
+
f.positionTime = w.utc(f.etd || f.eta).unix();
|
|
1233
1332
|
});
|
|
1234
|
-
for (const
|
|
1235
|
-
o +=
|
|
1236
|
-
const b = await W.deadReckoningTime((
|
|
1237
|
-
|
|
1333
|
+
for (const f of i) {
|
|
1334
|
+
o += f.distance;
|
|
1335
|
+
const b = await W.deadReckoningTime((u = f.waypoints) == null ? void 0 : u.at(0), e.sample.wps), y = await W.deadReckoningTime((l = f.waypoints) == null ? void 0 : l.at(-1), e.sample.wps);
|
|
1336
|
+
f.in = b, f.out = y, f.totalHrs = _.roundPrecision((y.positionTime - b.positionTime) / 3600, 3), f.totalDgoCons = _.roundPrecision(t.fo / 24 * f.totalHrs, 3), n += f.totalHrs, s += f.totalDgoCons;
|
|
1238
1337
|
}
|
|
1239
|
-
return o =
|
|
1338
|
+
return o = _.roundPrecision(o, 3), n = _.roundPrecision(n, 3), s = _.roundPrecision(s, 3), {
|
|
1240
1339
|
distanceInECA: o,
|
|
1241
1340
|
hoursInECA: n,
|
|
1242
1341
|
totalDgoConsInECA: s,
|
|
@@ -1248,84 +1347,84 @@ class O {
|
|
|
1248
1347
|
* @param speeds
|
|
1249
1348
|
* @param options
|
|
1250
1349
|
*/
|
|
1251
|
-
static async mergeSpeeds(
|
|
1252
|
-
var
|
|
1350
|
+
static async mergeSpeeds(e, t = {}) {
|
|
1351
|
+
var d, g;
|
|
1253
1352
|
const a = {
|
|
1254
1353
|
hours: [],
|
|
1255
1354
|
wps: [],
|
|
1256
1355
|
days: []
|
|
1257
|
-
}, i =
|
|
1258
|
-
var
|
|
1259
|
-
return
|
|
1260
|
-
}, 0), n =
|
|
1261
|
-
var
|
|
1262
|
-
return
|
|
1263
|
-
}, 0),
|
|
1264
|
-
var
|
|
1265
|
-
return
|
|
1266
|
-
}, 0),
|
|
1267
|
-
let
|
|
1268
|
-
for (const
|
|
1269
|
-
p.push(...((
|
|
1270
|
-
const
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
}),
|
|
1274
|
-
|
|
1275
|
-
}),
|
|
1276
|
-
|
|
1277
|
-
})), D.cp =
|
|
1278
|
-
const
|
|
1279
|
-
|
|
1280
|
-
var
|
|
1281
|
-
((
|
|
1282
|
-
}),
|
|
1283
|
-
var
|
|
1284
|
-
((
|
|
1285
|
-
}),
|
|
1286
|
-
var
|
|
1287
|
-
((
|
|
1356
|
+
}, i = e.reduce((m, h) => m + h.distance, 0), o = e.reduce((m, h) => {
|
|
1357
|
+
var k;
|
|
1358
|
+
return m + (((k = h.extend) == null ? void 0 : k.distanceInECA) || 0);
|
|
1359
|
+
}, 0), n = e.reduce((m, h) => m + h.totalHrs, 0), s = e.reduce((m, h) => {
|
|
1360
|
+
var k;
|
|
1361
|
+
return m + (((k = h.extend) == null ? void 0 : k.hoursInECA) || 0);
|
|
1362
|
+
}, 0), r = e.reduce((m, h) => {
|
|
1363
|
+
var k;
|
|
1364
|
+
return m + (((k = h.extend) == null ? void 0 : k.totalDgoConsInECA) || 0);
|
|
1365
|
+
}, 0), c = e.reduce((m, h) => m + h.wxFactor * h.totalHrs / n, 0), u = e.reduce((m, h) => m + h.cFactor * h.totalHrs / n, 0), l = e.reduce((m, h) => m + h.totalFoCons, 0), f = e.reduce((m, h) => m + h.totalDgoCons, 0), b = e.reduce((m, h) => m + h.cost.total, 0), y = e.reduce((m, h) => m + h.cost.hire, 0), F = e.reduce((m, h) => m + h.cost.bunker, 0), I = [], p = [];
|
|
1366
|
+
let v;
|
|
1367
|
+
for (const m of e) {
|
|
1368
|
+
p.push(...((d = m.extend) == null ? void 0 : d.eca) || []);
|
|
1369
|
+
const h = m.sample.hours, k = m.sample.wps, S = m.sample.days, D = h.at(0);
|
|
1370
|
+
v && (D.distanceFromPrevious = v.distanceFromPrevious, D.distanceFromStart = v.distanceFromStart, h.forEach((x, T) => {
|
|
1371
|
+
T && (x.distanceFromStart = x.distanceFromStart + v.distanceFromStart);
|
|
1372
|
+
}), k.at(0).distanceFromPrevious = v.distanceFromPrevious, k.at(0).distanceFromStart = v.distanceFromStart, k.forEach((x, T) => {
|
|
1373
|
+
T && (x.distanceFromStart = x.distanceFromStart + v.distanceFromStart);
|
|
1374
|
+
}), S.at(0).distanceFromPrevious = v.distanceFromPrevious, S.at(0).distanceFromStart = v.distanceFromStart, S.forEach((x, T) => {
|
|
1375
|
+
T && (x.distanceFromStart = x.distanceFromStart + v.distanceFromStart);
|
|
1376
|
+
})), D.cp = m.cost.cp;
|
|
1377
|
+
const P = [m.etd, m.eta], N = I.findIndex((x) => x.id === D.cp.id);
|
|
1378
|
+
N === -1 ? (D.cp.segment = [P], I.push(D.cp)) : I[N].segment.push(P), h.forEach((x) => {
|
|
1379
|
+
var q;
|
|
1380
|
+
((q = a.hours) == null ? void 0 : q.findIndex((R) => R.eta === x.eta)) === -1 && a.hours.push(x);
|
|
1381
|
+
}), k.forEach((x) => {
|
|
1382
|
+
var q;
|
|
1383
|
+
((q = a.wps) == null ? void 0 : q.findIndex((R) => R.eta === x.eta)) === -1 && a.wps.push(x);
|
|
1384
|
+
}), S.forEach((x) => {
|
|
1385
|
+
var q;
|
|
1386
|
+
((q = a == null ? void 0 : a.days) == null ? void 0 : q.findIndex((R) => R.eta === x.eta)) === -1 && a.days.push(x);
|
|
1288
1387
|
});
|
|
1289
|
-
const A = (
|
|
1290
|
-
A === -1 ? a.wps.push(D) : a.wps[A] = D,
|
|
1388
|
+
const A = (g = a.wps) == null ? void 0 : g.findIndex((x) => x.eta === D.eta);
|
|
1389
|
+
A === -1 ? a.wps.push(D) : a.wps[A] = D, v = h.at(-1);
|
|
1291
1390
|
}
|
|
1292
|
-
return a.wps.sort((
|
|
1293
|
-
|
|
1294
|
-
}), a.wps.forEach((
|
|
1295
|
-
const
|
|
1296
|
-
if (
|
|
1297
|
-
const
|
|
1298
|
-
|
|
1299
|
-
const
|
|
1300
|
-
|
|
1391
|
+
return a.wps.sort((m, h) => {
|
|
1392
|
+
w(m.etd).unix() - w(h.etd).unix();
|
|
1393
|
+
}), a.wps.forEach((m, h) => {
|
|
1394
|
+
const k = a.wps[h - 1];
|
|
1395
|
+
if (k) {
|
|
1396
|
+
const S = m.distanceFromStart - (k.distanceFromStart || 0), D = w(m.eta || m.etd).diff(w(k.etd || k.eta), "hour", !0), P = Math.round(S / D * 100) / 100;
|
|
1397
|
+
m.avgSpd = P;
|
|
1398
|
+
const N = W.calculateBearing(k, m);
|
|
1399
|
+
k.bearing = N;
|
|
1301
1400
|
}
|
|
1302
1401
|
}), {
|
|
1303
1402
|
sample: a,
|
|
1304
|
-
etd:
|
|
1305
|
-
eta:
|
|
1306
|
-
from:
|
|
1307
|
-
to:
|
|
1308
|
-
v0:
|
|
1403
|
+
etd: e.at(0).etd,
|
|
1404
|
+
eta: e.at(-1).eta,
|
|
1405
|
+
from: e.at(0).from,
|
|
1406
|
+
to: e.at(-1).to,
|
|
1407
|
+
v0: e.at(0).v0,
|
|
1309
1408
|
label: "Combined",
|
|
1310
1409
|
distance: Math.round(i * 1e3) / 1e3,
|
|
1311
1410
|
totalHrs: Math.round(n * 1e3) / 1e3,
|
|
1312
1411
|
avgSpeed: Math.round(i / n * 1e3) / 1e3,
|
|
1313
|
-
wxFactor: Math.round(
|
|
1314
|
-
cFactor: Math.round(
|
|
1315
|
-
totalFoCons: Math.round(
|
|
1316
|
-
totalDgoCons: Math.round(
|
|
1412
|
+
wxFactor: Math.round(c * 1e3) / 1e3,
|
|
1413
|
+
cFactor: Math.round(u * 1e3) / 1e3,
|
|
1414
|
+
totalFoCons: Math.round(l * 1e3) / 1e3,
|
|
1415
|
+
totalDgoCons: Math.round(f * 1e3) / 1e3,
|
|
1317
1416
|
cost: {
|
|
1318
1417
|
total: Math.round(b * 1e3) / 1e3,
|
|
1319
|
-
hire: Math.round(
|
|
1320
|
-
bunker: Math.round(
|
|
1418
|
+
hire: Math.round(y * 1e3) / 1e3,
|
|
1419
|
+
bunker: Math.round(F * 1e3) / 1e3
|
|
1321
1420
|
},
|
|
1322
1421
|
extend: {
|
|
1323
|
-
cps:
|
|
1422
|
+
cps: I,
|
|
1324
1423
|
eca: p,
|
|
1325
1424
|
distanceInECA: Math.round(o * 1e3) / 1e3,
|
|
1326
1425
|
hoursInECA: Math.round(s * 1e3) / 1e3,
|
|
1327
|
-
totalDgoConsInECA: Math.round(
|
|
1328
|
-
speeds:
|
|
1426
|
+
totalDgoConsInECA: Math.round(r * 1e3) / 1e3,
|
|
1427
|
+
speeds: e
|
|
1329
1428
|
}
|
|
1330
1429
|
};
|
|
1331
1430
|
}
|
|
@@ -1333,14 +1432,14 @@ class O {
|
|
|
1333
1432
|
export {
|
|
1334
1433
|
st as AISImpl,
|
|
1335
1434
|
yt as AlertHelper,
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1435
|
+
ft as AlertLevel,
|
|
1436
|
+
Et as HifleetImpl,
|
|
1437
|
+
bt as LoadCondition,
|
|
1438
|
+
Tt as MyShipImpl,
|
|
1439
|
+
jt as MyVesselImpl,
|
|
1440
|
+
Nt as ShipxyImpl,
|
|
1342
1441
|
O as SpeedHelper,
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1442
|
+
vt as SpeedLabel,
|
|
1443
|
+
gt as VesselTag,
|
|
1444
|
+
xt as alertHelper
|
|
1346
1445
|
};
|