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