sgerp-frontend-lib 0.1.5 → 0.2.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/constants/timezones.d.ts +7 -2
- package/dist/constants/timezones.d.ts.map +1 -1
- package/dist/constants/timezones.js +17 -2
- package/dist/locales/locale_en.d.ts.map +1 -1
- package/dist/locales/locale_en.js +159 -0
- package/dist/locales/locale_ja.d.ts.map +1 -1
- package/dist/locales/locale_ja.js +112 -0
- package/dist/sgerp/index.d.ts +2 -2
- package/dist/sgerp/index.d.ts.map +1 -1
- package/dist/sgerp/index.js +8 -2
- package/dist/sgerp/simulation-logic/fetchUtils.d.ts +18 -0
- package/dist/sgerp/simulation-logic/fetchUtils.d.ts.map +1 -1
- package/dist/sgerp/simulation-logic/fetchUtils.js +194 -0
- package/dist/sgerp/simulation-logic/index.d.ts +4 -1
- package/dist/sgerp/simulation-logic/index.d.ts.map +1 -1
- package/dist/sgerp/simulation-logic/index.js +9 -1
- package/dist/sgerp/simulation-logic/vrpStatsCalculator.d.ts +52 -0
- package/dist/sgerp/simulation-logic/vrpStatsCalculator.d.ts.map +1 -0
- package/dist/sgerp/simulation-logic/vrpStatsCalculator.js +247 -0
- package/dist/sgerp/simulation-logic/vrpStatsUtils.d.ts +17 -0
- package/dist/sgerp/simulation-logic/vrpStatsUtils.d.ts.map +1 -0
- package/dist/sgerp/simulation-logic/vrpStatsUtils.js +48 -0
- package/dist/sgerp/utils/timezone.d.ts +15 -0
- package/dist/sgerp/utils/timezone.d.ts.map +1 -0
- package/dist/sgerp/utils/timezone.js +19 -0
- package/dist/sgerp/vrptoolbox-analyzer.d.ts +39 -0
- package/dist/sgerp/vrptoolbox-analyzer.d.ts.map +1 -0
- package/dist/sgerp/vrptoolbox-analyzer.js +210 -0
- package/dist/vrptoolbox/index.d.ts +1 -0
- package/dist/vrptoolbox/index.d.ts.map +1 -1
- package/dist/vrptoolbox/index.js +16 -0
- package/dist/vrptoolbox/vrptoolbox-utils.d.ts +133 -0
- package/dist/vrptoolbox/vrptoolbox-utils.d.ts.map +1 -0
- package/dist/vrptoolbox/vrptoolbox-utils.js +207 -0
- package/package.json +3 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Timezone utility functions
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getEffectiveTimezone = getEffectiveTimezone;
|
|
7
|
+
/**
|
|
8
|
+
* Get the effective timezone based on the current mode
|
|
9
|
+
* In VRPToolbox mode, uses the VRP timezone selector
|
|
10
|
+
* Otherwise, uses the project timezone (or falls back to UTC)
|
|
11
|
+
*
|
|
12
|
+
* @param mode - The current effective mode ('vrptoolbox' or other)
|
|
13
|
+
* @param vrpTimezone - The timezone selected in VRPToolbox mode
|
|
14
|
+
* @param projectTimezone - The project's configured timezone
|
|
15
|
+
* @returns The effective timezone string (e.g., 'UTC', 'Asia/Singapore')
|
|
16
|
+
*/
|
|
17
|
+
function getEffectiveTimezone(mode, vrpTimezone, projectTimezone) {
|
|
18
|
+
return mode === 'vrptoolbox' ? vrpTimezone : (projectTimezone || 'UTC');
|
|
19
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
interface Vehicle {
|
|
2
|
+
agent_id: string;
|
|
3
|
+
characteristics?: Record<string, any>;
|
|
4
|
+
start_time?: number;
|
|
5
|
+
end_time?: number;
|
|
6
|
+
geofence_ids: any[];
|
|
7
|
+
assigned_nodes: any[];
|
|
8
|
+
labels?: string[];
|
|
9
|
+
capacity: number | Record<string, number>;
|
|
10
|
+
}
|
|
11
|
+
interface Node {
|
|
12
|
+
node_type: string;
|
|
13
|
+
vehicle_characteristics: Record<string, any>;
|
|
14
|
+
open_time_ts: number;
|
|
15
|
+
close_time_ts: number;
|
|
16
|
+
geofence_id: any[];
|
|
17
|
+
geofence_ids?: any[];
|
|
18
|
+
demand: number | Record<string, number>;
|
|
19
|
+
vehicle_labels?: {
|
|
20
|
+
or?: string[];
|
|
21
|
+
and?: string[];
|
|
22
|
+
};
|
|
23
|
+
booking_uid: string;
|
|
24
|
+
}
|
|
25
|
+
interface PipelineObject {
|
|
26
|
+
request: {
|
|
27
|
+
vehicles: Vehicle[];
|
|
28
|
+
nodes: Node[];
|
|
29
|
+
};
|
|
30
|
+
result: {
|
|
31
|
+
rejected_bookings: {
|
|
32
|
+
uid: string;
|
|
33
|
+
}[];
|
|
34
|
+
vehicles: Record<string, any>;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export declare function analyzePipelineObject(pipelineObject: PipelineObject): Record<string, any>;
|
|
38
|
+
export type { PipelineObject, Vehicle, Node };
|
|
39
|
+
//# sourceMappingURL=vrptoolbox-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vrptoolbox-analyzer.d.ts","sourceRoot":"","sources":["../../sgerplib/sgerp/vrptoolbox-analyzer.ts"],"names":[],"mappings":"AAAA,UAAU,OAAO;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,GAAG,EAAE,CAAC;IACpB,cAAc,EAAE,GAAG,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED,UAAU,IAAI;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,GAAG,EAAE,CAAC;IACnB,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE;QACf,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;KAChB,CAAC;IACF,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,OAAO,EAAE;QACP,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,KAAK,EAAE,IAAI,EAAE,CAAC;KACf,CAAC;IACF,MAAM,EAAE;QACN,iBAAiB,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACrC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC/B,CAAC;CACH;AAwQD,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,cAAc,GAC7B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkCrB;AAED,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.analyzePipelineObject = analyzePipelineObject;
|
|
4
|
+
const DEFAULT_SEAT_TYPE = "passenger";
|
|
5
|
+
function getCapacity(value, defaultSeatType = DEFAULT_SEAT_TYPE) {
|
|
6
|
+
return typeof value === "object" ? value : { [DEFAULT_SEAT_TYPE]: value };
|
|
7
|
+
}
|
|
8
|
+
function checkCharacteristics(node, vehicle) {
|
|
9
|
+
const reasons = [];
|
|
10
|
+
const messages = [];
|
|
11
|
+
if (!vehicle.characteristics) {
|
|
12
|
+
return [reasons, messages];
|
|
13
|
+
}
|
|
14
|
+
const vehicleChars = vehicle.characteristics;
|
|
15
|
+
const agentId = vehicle.agent_id;
|
|
16
|
+
const nodeType = node.node_type;
|
|
17
|
+
Object.entries(node.vehicle_characteristics).forEach(([char, value]) => {
|
|
18
|
+
const vehicleVar = vehicleChars[char];
|
|
19
|
+
if (vehicleVar === undefined) {
|
|
20
|
+
reasons.push({
|
|
21
|
+
violation: `${char}_availability_violation`,
|
|
22
|
+
vehicle_value: vehicleVar,
|
|
23
|
+
char: char,
|
|
24
|
+
vehicle_characteristics: vehicleChars,
|
|
25
|
+
});
|
|
26
|
+
messages.push(`${nodeType} can not be assigned to vehicle ${agentId} because characteristic ${char} is not available in vehicle ${JSON.stringify(vehicleChars)}`);
|
|
27
|
+
}
|
|
28
|
+
else if (typeof value === "object") {
|
|
29
|
+
const minVal = value.min;
|
|
30
|
+
const maxVal = value.max;
|
|
31
|
+
if (minVal !== undefined && vehicleVar < minVal) {
|
|
32
|
+
reasons.push({
|
|
33
|
+
violation: `${char}_min_violation`,
|
|
34
|
+
vehicle_value: vehicleVar,
|
|
35
|
+
required_min: minVal,
|
|
36
|
+
vehicle: agentId,
|
|
37
|
+
});
|
|
38
|
+
messages.push(`${nodeType} can not be assigned to vehicle ${agentId} because of ${char}.min violation: ${vehicleVar} < ${minVal}`);
|
|
39
|
+
}
|
|
40
|
+
if (maxVal !== undefined && vehicleVar > maxVal) {
|
|
41
|
+
reasons.push({
|
|
42
|
+
violation: `${char}_max_violation`,
|
|
43
|
+
vehicle_value: vehicleVar,
|
|
44
|
+
required_max: maxVal,
|
|
45
|
+
vehicle: agentId,
|
|
46
|
+
});
|
|
47
|
+
messages.push(`${nodeType} can not be assigned to vehicle ${agentId} because of ${char}.max violation: ${vehicleVar} > ${maxVal}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (value !== vehicleVar) {
|
|
51
|
+
reasons.push({
|
|
52
|
+
violation: `${char}_value_violation`,
|
|
53
|
+
required_value: value,
|
|
54
|
+
vehicle_value: vehicleVar,
|
|
55
|
+
});
|
|
56
|
+
messages.push(`can not be assigned to vehicle ${agentId} - ${char}_value_violation`);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return [reasons, messages];
|
|
60
|
+
}
|
|
61
|
+
function checkStartTimeEndTimeConstraints(node, vehicle) {
|
|
62
|
+
const reasons = [];
|
|
63
|
+
const messages = [];
|
|
64
|
+
const agentId = vehicle.agent_id;
|
|
65
|
+
const nodeType = node.node_type;
|
|
66
|
+
if (vehicle.start_time !== undefined) {
|
|
67
|
+
if (vehicle.start_time > node.close_time_ts) {
|
|
68
|
+
reasons.push({
|
|
69
|
+
violation: "start_time_violation",
|
|
70
|
+
node_close_time: node.close_time_ts,
|
|
71
|
+
vehicle_start_time: vehicle.start_time,
|
|
72
|
+
});
|
|
73
|
+
messages.push(`${nodeType} can not be assigned to vehicle ${agentId} - start_time_violation: ${vehicle.start_time} > ${node.close_time_ts}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (vehicle.end_time !== undefined) {
|
|
77
|
+
if (vehicle.end_time < node.open_time_ts) {
|
|
78
|
+
reasons.push({
|
|
79
|
+
violation: "end_time_violation",
|
|
80
|
+
node_open_time: node.open_time_ts,
|
|
81
|
+
vehicle_end_time: vehicle.end_time,
|
|
82
|
+
});
|
|
83
|
+
messages.push(`${nodeType} can not be assigned to vehicle ${agentId} - end_time_violation: ${vehicle.end_time} < ${node.open_time_ts}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return [reasons, messages];
|
|
87
|
+
}
|
|
88
|
+
function checkGeofenceConstraints(node, vehicle) {
|
|
89
|
+
const reasons = [];
|
|
90
|
+
const messages = [];
|
|
91
|
+
const agentId = vehicle.agent_id;
|
|
92
|
+
if (node.geofence_ids === undefined && node.geofence_id) {
|
|
93
|
+
node.geofence_ids = [node.geofence_id];
|
|
94
|
+
}
|
|
95
|
+
if (node.geofence_ids && node.geofence_ids.length > 0 && node.geofence_ids[0] !== null) {
|
|
96
|
+
const vehicleGeofenceIds = new Set(vehicle.geofence_ids);
|
|
97
|
+
const nodeGeofenceIds = new Set(node.geofence_ids);
|
|
98
|
+
if (vehicleGeofenceIds.size > 0 &&
|
|
99
|
+
!Array.from(nodeGeofenceIds).some((id) => vehicleGeofenceIds.has(id))) {
|
|
100
|
+
reasons.push({
|
|
101
|
+
violation: "geofence_violation",
|
|
102
|
+
node_geofence_ids: node.geofence_ids,
|
|
103
|
+
vehicle_geofence_ids: vehicle.geofence_ids,
|
|
104
|
+
});
|
|
105
|
+
messages.push(`can not be assigned to vehicle ${agentId} - geofence violations: ${JSON.stringify([...vehicleGeofenceIds])} vs ${JSON.stringify([...nodeGeofenceIds])}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return [reasons, messages];
|
|
109
|
+
}
|
|
110
|
+
function checkVehicleAssignedNodes(node, vehicle) {
|
|
111
|
+
const reasons = [];
|
|
112
|
+
const messages = [];
|
|
113
|
+
const agentId = vehicle.agent_id;
|
|
114
|
+
if (vehicle.assigned_nodes.length > 0) {
|
|
115
|
+
reasons.push({
|
|
116
|
+
violation: "vehicle_has_assigned_nodes",
|
|
117
|
+
});
|
|
118
|
+
messages.push(`vehicle ${agentId} has assigned nodes. Possibly change the first solution strategy to 16 or clear vehicles`);
|
|
119
|
+
}
|
|
120
|
+
return [reasons, messages];
|
|
121
|
+
}
|
|
122
|
+
function checkVehicleLabels(node, vehicle) {
|
|
123
|
+
const reasons = [];
|
|
124
|
+
const messages = [];
|
|
125
|
+
const agentId = vehicle.agent_id;
|
|
126
|
+
const nodeLabels = node.vehicle_labels;
|
|
127
|
+
if (!nodeLabels) {
|
|
128
|
+
return [reasons, messages];
|
|
129
|
+
}
|
|
130
|
+
const labelOrValues = new Set(nodeLabels.or || []);
|
|
131
|
+
const labelAndValues = new Set(nodeLabels.and || []);
|
|
132
|
+
const vehicleLabels = new Set(vehicle.labels || []);
|
|
133
|
+
if (labelOrValues.size > 0) {
|
|
134
|
+
if (!Array.from(labelOrValues).some((label) => vehicleLabels.has(label))) {
|
|
135
|
+
reasons.push({
|
|
136
|
+
violation: "vehicle and booking labels do not satisfy each other",
|
|
137
|
+
});
|
|
138
|
+
messages.push(`vehicle ${agentId} has labels ${JSON.stringify([...vehicleLabels])}. Booking: ${JSON.stringify(nodeLabels)}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (labelAndValues.size > 0) {
|
|
142
|
+
if (!Array.from(labelAndValues).every((label) => vehicleLabels.has(label))) {
|
|
143
|
+
reasons.push({
|
|
144
|
+
violation: "vehicle and booking labels do not satisfy each other",
|
|
145
|
+
});
|
|
146
|
+
messages.push(`vehicle ${agentId} has labels ${JSON.stringify([...vehicleLabels])}. Booking: ${JSON.stringify(nodeLabels)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return [reasons, messages];
|
|
150
|
+
}
|
|
151
|
+
function analyzeVehicles(nodeGroup, vehicles) {
|
|
152
|
+
const possibleReasons = {
|
|
153
|
+
messages: [],
|
|
154
|
+
impossibleVehicles: new Set(),
|
|
155
|
+
comments: [],
|
|
156
|
+
};
|
|
157
|
+
nodeGroup.forEach((node) => {
|
|
158
|
+
vehicles.forEach((vehicle) => {
|
|
159
|
+
const [reasons1, messages1] = checkCharacteristics(node, vehicle);
|
|
160
|
+
const [reasons2, messages2] = checkStartTimeEndTimeConstraints(node, vehicle);
|
|
161
|
+
const [reasons3, messages3] = checkGeofenceConstraints(node, vehicle);
|
|
162
|
+
const [reasons4, messages4] = checkVehicleAssignedNodes(node, vehicle);
|
|
163
|
+
const [reasons5, messages5] = checkVehicleLabels(node, vehicle);
|
|
164
|
+
if (reasons1.length > 0 ||
|
|
165
|
+
reasons2.length > 0 ||
|
|
166
|
+
reasons3.length > 0 ||
|
|
167
|
+
reasons4.length > 0 ||
|
|
168
|
+
reasons5.length > 0) {
|
|
169
|
+
possibleReasons.messages.push(...messages1, ...messages2, ...messages3, ...messages4, ...messages5);
|
|
170
|
+
possibleReasons.impossibleVehicles.add(vehicle.agent_id);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
possibleReasons.impossibleVehicles = Array.from(possibleReasons.impossibleVehicles);
|
|
175
|
+
possibleReasons.impossibleVehiclesCount =
|
|
176
|
+
possibleReasons.impossibleVehicles.length;
|
|
177
|
+
if (possibleReasons.impossibleVehiclesCount === vehicles.length) {
|
|
178
|
+
possibleReasons.comments.push("all vehicles are impossible");
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const possibleVehicles = vehicles
|
|
182
|
+
.filter((vehicle) => !possibleReasons.impossibleVehicles.includes(vehicle.agent_id))
|
|
183
|
+
.map((vehicle) => vehicle.agent_id);
|
|
184
|
+
possibleReasons.comments.push({ possibleVehicles });
|
|
185
|
+
}
|
|
186
|
+
return possibleReasons;
|
|
187
|
+
}
|
|
188
|
+
function analyzePipelineObject(pipelineObject) {
|
|
189
|
+
const { vehicles, nodes } = pipelineObject.request;
|
|
190
|
+
const { rejected_bookings, vehicles: resultedVehicles } = pipelineObject.result;
|
|
191
|
+
const rejectedUids = new Set(rejected_bookings.map((b) => b.uid));
|
|
192
|
+
const rejectedNodes = nodes.filter((node) => rejectedUids.has(node.booking_uid));
|
|
193
|
+
const emptyVehicleUids = new Set(Object.entries(resultedVehicles)
|
|
194
|
+
.filter(([_, item]) => !item)
|
|
195
|
+
.map(([key, _]) => key));
|
|
196
|
+
const emptyVehicles = vehicles; // .filter(v => emptyVehicleUids.has(v.agent_id));
|
|
197
|
+
const possibleReasons = {};
|
|
198
|
+
const bookingNodes = {};
|
|
199
|
+
rejectedNodes.forEach((node) => {
|
|
200
|
+
const { booking_uid } = node;
|
|
201
|
+
if (!bookingNodes[booking_uid]) {
|
|
202
|
+
bookingNodes[booking_uid] = [];
|
|
203
|
+
}
|
|
204
|
+
bookingNodes[booking_uid].push(node);
|
|
205
|
+
});
|
|
206
|
+
Object.entries(bookingNodes).forEach(([booking_uid, node_group]) => {
|
|
207
|
+
possibleReasons[booking_uid] = analyzeVehicles(node_group, emptyVehicles);
|
|
208
|
+
});
|
|
209
|
+
return possibleReasons;
|
|
210
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../sgerplib/vrptoolbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../sgerplib/vrptoolbox/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,cAAc,oBAAoB,CAAC"}
|
package/dist/vrptoolbox/index.js
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* VRP Toolbox library exports
|
|
4
4
|
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
5
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
20
|
exports.OptimizationJobCollection = void 0;
|
|
7
21
|
var collection_1 = require("./collection");
|
|
8
22
|
Object.defineProperty(exports, "OptimizationJobCollection", { enumerable: true, get: function () { return collection_1.OptimizationJobCollection; } });
|
|
23
|
+
// VRPToolbox data processing utilities
|
|
24
|
+
__exportStar(require("./vrptoolbox-utils"), exports);
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VRPToolbox data processing utilities
|
|
3
|
+
* Converts VRPToolbox API response to simulation-like state for visualization
|
|
4
|
+
*/
|
|
5
|
+
export interface VRPSimulation {
|
|
6
|
+
id: number;
|
|
7
|
+
name: string;
|
|
8
|
+
project_id: number;
|
|
9
|
+
stateless_api_request_data?: any;
|
|
10
|
+
result?: any;
|
|
11
|
+
}
|
|
12
|
+
export interface VRPVehicle {
|
|
13
|
+
id: number;
|
|
14
|
+
agent_id: string;
|
|
15
|
+
simulation_id: number;
|
|
16
|
+
registration_number?: string;
|
|
17
|
+
color?: string;
|
|
18
|
+
assigned_nodes: string[];
|
|
19
|
+
completed_nodes: string[];
|
|
20
|
+
capacity?: any;
|
|
21
|
+
shift_start?: string;
|
|
22
|
+
shift_end?: string;
|
|
23
|
+
start_lat?: number;
|
|
24
|
+
start_lon?: number;
|
|
25
|
+
end_lat?: number;
|
|
26
|
+
end_lon?: number;
|
|
27
|
+
vehicle_type_id?: number;
|
|
28
|
+
routing_engine_settings?: any;
|
|
29
|
+
is_active?: boolean;
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
}
|
|
32
|
+
export interface VRPNode {
|
|
33
|
+
id: number;
|
|
34
|
+
uid: string;
|
|
35
|
+
simulation_id: number;
|
|
36
|
+
booking_id?: number;
|
|
37
|
+
booking_uid?: string;
|
|
38
|
+
lat: number;
|
|
39
|
+
lon: number;
|
|
40
|
+
node_type: string;
|
|
41
|
+
status: string;
|
|
42
|
+
scheduled_ts?: string | null;
|
|
43
|
+
assigned_vehicle_id?: number | null;
|
|
44
|
+
location_name?: string;
|
|
45
|
+
display_name?: string;
|
|
46
|
+
service_time?: number;
|
|
47
|
+
time_window_start?: string;
|
|
48
|
+
time_window_end?: string;
|
|
49
|
+
priority?: number;
|
|
50
|
+
[key: string]: any;
|
|
51
|
+
}
|
|
52
|
+
export interface VRPBooking {
|
|
53
|
+
id: number;
|
|
54
|
+
uid: string;
|
|
55
|
+
simulation_id: number;
|
|
56
|
+
pickup_lat?: number;
|
|
57
|
+
pickup_lon?: number;
|
|
58
|
+
dropoff_lat?: number;
|
|
59
|
+
dropoff_lon?: number;
|
|
60
|
+
pickup_location_name?: string;
|
|
61
|
+
dropoff_location_name?: string;
|
|
62
|
+
passenger_count?: number;
|
|
63
|
+
status?: string;
|
|
64
|
+
assigned_vehicle_id?: number | null;
|
|
65
|
+
[key: string]: any;
|
|
66
|
+
}
|
|
67
|
+
export interface SimulationLiveUpdateData {
|
|
68
|
+
simulation: VRPSimulation;
|
|
69
|
+
vehicles: VRPVehicle[];
|
|
70
|
+
nodes: VRPNode[];
|
|
71
|
+
bookings: VRPBooking[];
|
|
72
|
+
vehicleRoutes: Map<number, any>;
|
|
73
|
+
nodesByVehicle: Map<number, VRPNode[]>;
|
|
74
|
+
bookingsByVehicle: Map<number, VRPBooking[]>;
|
|
75
|
+
vehicleIndex: Map<number, VRPVehicle>;
|
|
76
|
+
nodeIndex: Map<number, VRPNode>;
|
|
77
|
+
bookingIndex: Map<number, VRPBooking>;
|
|
78
|
+
}
|
|
79
|
+
export interface VRPToolboxPayload {
|
|
80
|
+
vehicles: Array<{
|
|
81
|
+
agent_id: string;
|
|
82
|
+
assigned_nodes?: any[];
|
|
83
|
+
completed_nodes?: any[];
|
|
84
|
+
routing_engine?: any;
|
|
85
|
+
[key: string]: any;
|
|
86
|
+
}>;
|
|
87
|
+
nodes: Array<{
|
|
88
|
+
uid: string;
|
|
89
|
+
booking_uid?: string;
|
|
90
|
+
lat: number;
|
|
91
|
+
lon: number;
|
|
92
|
+
node_type?: string;
|
|
93
|
+
[key: string]: any;
|
|
94
|
+
}>;
|
|
95
|
+
engine_settings?: {
|
|
96
|
+
routing_engine?: any;
|
|
97
|
+
[key: string]: any;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export interface VRPToolboxResult {
|
|
101
|
+
vehicles: {
|
|
102
|
+
[vehicleAgentId: string]: Array<{
|
|
103
|
+
uid: string;
|
|
104
|
+
scheduled_ts?: string;
|
|
105
|
+
[key: string]: any;
|
|
106
|
+
}>;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export interface VRPToolboxResponse {
|
|
110
|
+
payload: VRPToolboxPayload;
|
|
111
|
+
result: VRPToolboxResult;
|
|
112
|
+
}
|
|
113
|
+
export interface VRPToolboxSimulationState {
|
|
114
|
+
simulation: VRPSimulation;
|
|
115
|
+
vehicles: VRPVehicle[];
|
|
116
|
+
nodes: VRPNode[];
|
|
117
|
+
bookings: VRPBooking[];
|
|
118
|
+
liveUpdateData: SimulationLiveUpdateData;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Fetches VRPToolbox job result with payload
|
|
122
|
+
*/
|
|
123
|
+
export declare function fetchVRPToolboxJobData(vrpServer: string, taskId: string): Promise<VRPToolboxResponse>;
|
|
124
|
+
/**
|
|
125
|
+
* Converts VRPToolbox response to simulation-like state
|
|
126
|
+
* Based on the logic from dashviewer's createStateFromCommuteOffers
|
|
127
|
+
*/
|
|
128
|
+
export declare function convertVRPToolboxToSimulationState(data: VRPToolboxResponse, taskId: string): VRPToolboxSimulationState;
|
|
129
|
+
/**
|
|
130
|
+
* Fetches and processes VRPToolbox data into simulation state
|
|
131
|
+
*/
|
|
132
|
+
export declare function loadVRPToolboxSimulation(vrpServer: string, taskId: string): Promise<VRPToolboxSimulationState>;
|
|
133
|
+
//# sourceMappingURL=vrptoolbox-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vrptoolbox-utils.d.ts","sourceRoot":"","sources":["../../sgerplib/vrptoolbox/vrptoolbox-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B,CAAC,EAAE,GAAG,CAAC;IACjC,MAAM,CAAC,EAAE,GAAG,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,CAAC,EAAE,GAAG,CAAC;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAGD,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACvC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;IAC7C,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACtC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,KAAK,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC;QACvB,eAAe,CAAC,EAAE,GAAG,EAAE,CAAC;QACxB,cAAc,CAAC,EAAE,GAAG,CAAC;QACrB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC,CAAC;IACH,KAAK,EAAE,KAAK,CAAC;QACX,GAAG,EAAE,MAAM,CAAC;QACZ,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC,CAAC;IACH,eAAe,CAAC,EAAE;QAChB,cAAc,CAAC,EAAE,GAAG,CAAC;QACrB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE;QACR,CAAC,cAAc,EAAE,MAAM,GAAG,KAAK,CAAC;YAC9B,GAAG,EAAE,MAAM,CAAC;YACZ,YAAY,CAAC,EAAE,MAAM,CAAC;YACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;SACpB,CAAC,CAAC;KACJ,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,cAAc,EAAE,wBAAwB,CAAC;CAC1C;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,CAAC,CAS7B;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,MAAM,GACb,yBAAyB,CA+L3B;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,yBAAyB,CAAC,CAGpC"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* VRPToolbox data processing utilities
|
|
4
|
+
* Converts VRPToolbox API response to simulation-like state for visualization
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.fetchVRPToolboxJobData = fetchVRPToolboxJobData;
|
|
8
|
+
exports.convertVRPToolboxToSimulationState = convertVRPToolboxToSimulationState;
|
|
9
|
+
exports.loadVRPToolboxSimulation = loadVRPToolboxSimulation;
|
|
10
|
+
/**
|
|
11
|
+
* Fetches VRPToolbox job result with payload
|
|
12
|
+
*/
|
|
13
|
+
async function fetchVRPToolboxJobData(vrpServer, taskId) {
|
|
14
|
+
const url = `${vrpServer}/jobs/${taskId}/result_with_payload`;
|
|
15
|
+
const response = await fetch(url);
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
throw new Error(`Failed to fetch VRPToolbox data: ${response.statusText}`);
|
|
18
|
+
}
|
|
19
|
+
return await response.json();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Converts VRPToolbox response to simulation-like state
|
|
23
|
+
* Based on the logic from dashviewer's createStateFromCommuteOffers
|
|
24
|
+
*/
|
|
25
|
+
function convertVRPToolboxToSimulationState(data, taskId) {
|
|
26
|
+
const { payload, result } = data;
|
|
27
|
+
// Create assigned nodes cache from result
|
|
28
|
+
const assignedNodesCache = {};
|
|
29
|
+
Object.entries(result.vehicles).forEach(([vehicleAgentId, vehicleNodes]) => {
|
|
30
|
+
vehicleNodes.forEach((node) => {
|
|
31
|
+
assignedNodesCache[node.uid] = Object.assign(Object.assign({}, node), { assigned_vehicle_id: vehicleAgentId, status: 'assigned' });
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
// Process vehicles
|
|
35
|
+
const vehicles = payload.vehicles.map((vehicle) => {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
const assignedNodes = vehicle.assigned_nodes || [];
|
|
38
|
+
const completedNodes = vehicle.completed_nodes || [];
|
|
39
|
+
// Map assigned node UIDs from the result
|
|
40
|
+
const assignedNodeIds = ((_a = result.vehicles[vehicle.agent_id]) === null || _a === void 0 ? void 0 : _a.map((n) => n.uid)) || [];
|
|
41
|
+
return {
|
|
42
|
+
id: parseInt(vehicle.agent_id),
|
|
43
|
+
agent_id: vehicle.agent_id,
|
|
44
|
+
simulation_id: parseInt(taskId),
|
|
45
|
+
assigned_nodes: assignedNodeIds,
|
|
46
|
+
completed_nodes: completedNodes.map((n) => n.uid),
|
|
47
|
+
routing_engine_settings: vehicle.routing_engine ||
|
|
48
|
+
((_b = payload.engine_settings) === null || _b === void 0 ? void 0 : _b.routing_engine) ||
|
|
49
|
+
{ routing_engine_name: 'osrm' },
|
|
50
|
+
// Map other vehicle fields
|
|
51
|
+
registration_number: vehicle.registration_number || vehicle.agent_id,
|
|
52
|
+
color: vehicle.color || '#4A90E2',
|
|
53
|
+
capacity: vehicle.capacity || {},
|
|
54
|
+
shift_start: vehicle.shift_start,
|
|
55
|
+
shift_end: vehicle.shift_end,
|
|
56
|
+
start_lat: vehicle.start_lat,
|
|
57
|
+
start_lon: vehicle.start_lon,
|
|
58
|
+
end_lat: vehicle.end_lat,
|
|
59
|
+
end_lon: vehicle.end_lon,
|
|
60
|
+
// Add other required vehicle fields with defaults
|
|
61
|
+
vehicle_type_id: vehicle.vehicle_type_id || 1,
|
|
62
|
+
is_active: true,
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
// Process nodes
|
|
66
|
+
const nodes = [];
|
|
67
|
+
const bookingsMap = new Map();
|
|
68
|
+
payload.nodes.forEach((node) => {
|
|
69
|
+
const assignedData = assignedNodesCache[node.uid];
|
|
70
|
+
const processedNode = {
|
|
71
|
+
id: parseInt(node.uid),
|
|
72
|
+
uid: node.uid,
|
|
73
|
+
simulation_id: parseInt(taskId),
|
|
74
|
+
booking_id: parseInt(node.booking_uid || '0'),
|
|
75
|
+
booking_uid: node.booking_uid,
|
|
76
|
+
lat: node.lat,
|
|
77
|
+
lon: node.lon,
|
|
78
|
+
node_type: node.node_type || 'pickup',
|
|
79
|
+
status: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.status) || 'rejected_by_system',
|
|
80
|
+
scheduled_ts: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.scheduled_ts) || null,
|
|
81
|
+
assigned_vehicle_id: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.assigned_vehicle_id) ?
|
|
82
|
+
parseInt(assignedData.assigned_vehicle_id) : null,
|
|
83
|
+
// Map other node fields
|
|
84
|
+
location_name: node.location_name || node.display_name || '',
|
|
85
|
+
display_name: node.display_name || '',
|
|
86
|
+
service_time: node.service_time || 0,
|
|
87
|
+
time_window_start: node.time_window_start,
|
|
88
|
+
time_window_end: node.time_window_end,
|
|
89
|
+
priority: node.priority || 1,
|
|
90
|
+
};
|
|
91
|
+
nodes.push(processedNode);
|
|
92
|
+
// Create or update booking
|
|
93
|
+
if (node.booking_uid) {
|
|
94
|
+
if (!bookingsMap.has(node.booking_uid)) {
|
|
95
|
+
bookingsMap.set(node.booking_uid, {
|
|
96
|
+
id: parseInt(node.booking_uid),
|
|
97
|
+
uid: node.booking_uid,
|
|
98
|
+
simulation_id: parseInt(taskId),
|
|
99
|
+
pickup_lat: node.node_type === 'pickup' ? node.lat : 0,
|
|
100
|
+
pickup_lon: node.node_type === 'pickup' ? node.lon : 0,
|
|
101
|
+
dropoff_lat: node.node_type === 'dropoff' ? node.lat : 0,
|
|
102
|
+
dropoff_lon: node.node_type === 'dropoff' ? node.lon : 0,
|
|
103
|
+
pickup_location_name: '',
|
|
104
|
+
dropoff_location_name: '',
|
|
105
|
+
passenger_count: 1,
|
|
106
|
+
status: assignedData ? 'assigned' : 'unassigned',
|
|
107
|
+
assigned_vehicle_id: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.assigned_vehicle_id) ?
|
|
108
|
+
parseInt(assignedData.assigned_vehicle_id) : null,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const booking = bookingsMap.get(node.booking_uid);
|
|
113
|
+
if (node.node_type === 'pickup') {
|
|
114
|
+
booking.pickup_lat = node.lat;
|
|
115
|
+
booking.pickup_lon = node.lon;
|
|
116
|
+
booking.pickup_location_name = node.location_name || '';
|
|
117
|
+
}
|
|
118
|
+
else if (node.node_type === 'dropoff') {
|
|
119
|
+
booking.dropoff_lat = node.lat;
|
|
120
|
+
booking.dropoff_lon = node.lon;
|
|
121
|
+
booking.dropoff_location_name = node.location_name || '';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
// Add partial route nodes that weren't in the main nodes list
|
|
127
|
+
payload.vehicles.forEach((vehicle) => {
|
|
128
|
+
const assignedNodes = vehicle.assigned_nodes || [];
|
|
129
|
+
assignedNodes.forEach((vehicleNode) => {
|
|
130
|
+
const nodeId = vehicleNode.uid;
|
|
131
|
+
if (!nodes.find(n => n.uid === nodeId)) {
|
|
132
|
+
const assignedData = assignedNodesCache[nodeId];
|
|
133
|
+
nodes.push({
|
|
134
|
+
id: parseInt(nodeId),
|
|
135
|
+
uid: nodeId,
|
|
136
|
+
simulation_id: parseInt(taskId),
|
|
137
|
+
booking_id: parseInt(vehicleNode.booking_uid || '0'),
|
|
138
|
+
booking_uid: vehicleNode.booking_uid,
|
|
139
|
+
lat: vehicleNode.lat || 0,
|
|
140
|
+
lon: vehicleNode.lon || 0,
|
|
141
|
+
node_type: vehicleNode.node_type || 'pickup',
|
|
142
|
+
status: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.status) || 'assigned',
|
|
143
|
+
scheduled_ts: (assignedData === null || assignedData === void 0 ? void 0 : assignedData.scheduled_ts) || null,
|
|
144
|
+
assigned_vehicle_id: vehicle.agent_id ? parseInt(vehicle.agent_id) : null,
|
|
145
|
+
location_name: vehicleNode.location_name || '',
|
|
146
|
+
display_name: vehicleNode.display_name || '',
|
|
147
|
+
service_time: vehicleNode.service_time || 0,
|
|
148
|
+
priority: vehicleNode.priority || 1,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
const bookings = Array.from(bookingsMap.values());
|
|
154
|
+
// Create simulation object
|
|
155
|
+
const simulation = {
|
|
156
|
+
id: parseInt(taskId),
|
|
157
|
+
name: `VRPToolbox Job ${taskId}`,
|
|
158
|
+
project_id: 0,
|
|
159
|
+
stateless_api_request_data: payload,
|
|
160
|
+
result: result,
|
|
161
|
+
};
|
|
162
|
+
// Create live update data structure
|
|
163
|
+
const liveUpdateData = {
|
|
164
|
+
simulation,
|
|
165
|
+
vehicles,
|
|
166
|
+
nodes,
|
|
167
|
+
bookings,
|
|
168
|
+
vehicleRoutes: new Map(),
|
|
169
|
+
nodesByVehicle: new Map(),
|
|
170
|
+
bookingsByVehicle: new Map(),
|
|
171
|
+
vehicleIndex: new Map(vehicles.map(v => [v.id, v])),
|
|
172
|
+
nodeIndex: new Map(nodes.map(n => [n.id, n])),
|
|
173
|
+
bookingIndex: new Map(bookings.map(b => [b.id, b])),
|
|
174
|
+
};
|
|
175
|
+
// Group nodes by vehicle
|
|
176
|
+
nodes.forEach(node => {
|
|
177
|
+
if (node.assigned_vehicle_id) {
|
|
178
|
+
if (!liveUpdateData.nodesByVehicle.has(node.assigned_vehicle_id)) {
|
|
179
|
+
liveUpdateData.nodesByVehicle.set(node.assigned_vehicle_id, []);
|
|
180
|
+
}
|
|
181
|
+
liveUpdateData.nodesByVehicle.get(node.assigned_vehicle_id).push(node);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
// Group bookings by vehicle
|
|
185
|
+
bookings.forEach(booking => {
|
|
186
|
+
if (booking.assigned_vehicle_id) {
|
|
187
|
+
if (!liveUpdateData.bookingsByVehicle.has(booking.assigned_vehicle_id)) {
|
|
188
|
+
liveUpdateData.bookingsByVehicle.set(booking.assigned_vehicle_id, []);
|
|
189
|
+
}
|
|
190
|
+
liveUpdateData.bookingsByVehicle.get(booking.assigned_vehicle_id).push(booking);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return {
|
|
194
|
+
simulation,
|
|
195
|
+
vehicles,
|
|
196
|
+
nodes,
|
|
197
|
+
bookings,
|
|
198
|
+
liveUpdateData,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Fetches and processes VRPToolbox data into simulation state
|
|
203
|
+
*/
|
|
204
|
+
async function loadVRPToolboxSimulation(vrpServer, taskId) {
|
|
205
|
+
const data = await fetchVRPToolboxJobData(vrpServer, taskId);
|
|
206
|
+
return convertVRPToolboxToSimulationState(data, taskId);
|
|
207
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sgerp-frontend-lib",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TypeScript/React library for interacting with the SGERP API, providing client SDK, Backbone.js-style Collections, and pre-built React components",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -95,6 +95,8 @@
|
|
|
95
95
|
"react-day-picker": "^9.11.1",
|
|
96
96
|
"react-dom": "^19.0.1",
|
|
97
97
|
"react-markdown": "^10.1.0",
|
|
98
|
+
"react-resizable-panels": "^3.0.6",
|
|
99
|
+
"recharts": "^2.15.4",
|
|
98
100
|
"rehype-highlight": "^7.0.2",
|
|
99
101
|
"rehype-slug": "^6.0.0",
|
|
100
102
|
"remark-gfm": "^4.0.1",
|