feat: 添加 @react-native-async-storage/async-storage 依赖,重构任务上下文以支持动态参数配置,更新任务表单和任务列表组件以使用新功能,移除 mock 数据文件
This commit is contained in:
parent
0e0cef6eba
commit
087fc9e0aa
709
config.json
Normal file
709
config.json
Normal file
@ -0,0 +1,709 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"locations": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
],
|
||||||
|
"locationsBays": [
|
||||||
|
{ "label": "AS2_2_001", "value": "AS2_2_001" },
|
||||||
|
{ "label": "AS2_2_002", "value": "AS2_2_002" },
|
||||||
|
{ "label": "AS2_2_003", "value": "AS2_2_003" },
|
||||||
|
{ "label": "AS2_2_004", "value": "AS2_2_004" },
|
||||||
|
{ "label": "AS2_2_005", "value": "AS2_2_005" }
|
||||||
|
],
|
||||||
|
"payloads": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
],
|
||||||
|
"robotActions": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
],
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"id": "task-001",
|
||||||
|
"name": "炉前缓存区到热处理上料交接区运输",
|
||||||
|
"status": "IDLE",
|
||||||
|
"createdAt": "2024-01-15T08:30:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "FURNACE_BUFFER",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "HEAT_TREATMENT_LOADING",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "TRANSPORT",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "满料架-A1",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locationBay": {
|
||||||
|
"label": "库位",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AS2_2_001",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AS2_2_001", "value": "AS2_2_001" },
|
||||||
|
{ "label": "AS2_2_002", "value": "AS2_2_002" },
|
||||||
|
{ "label": "AS2_2_003", "value": "AS2_2_003" },
|
||||||
|
{ "label": "AS2_2_004", "value": "AS2_2_004" },
|
||||||
|
{ "label": "AS2_2_005", "value": "AS2_2_005" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-002",
|
||||||
|
"name": "原料仓库到质检区取货",
|
||||||
|
"status": "IDLE",
|
||||||
|
"createdAt": "2024-01-15T09:15:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "RAW_MATERIAL_WAREHOUSE",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "QUALITY_INSPECTION",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "PICKUP",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "钢材-Q235",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locationBay": {
|
||||||
|
"label": "库位",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AS2_2_002",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AS2_2_001", "value": "AS2_2_001" },
|
||||||
|
{ "label": "AS2_2_002", "value": "AS2_2_002" },
|
||||||
|
{ "label": "AS2_2_003", "value": "AS2_2_003" },
|
||||||
|
{ "label": "AS2_2_004", "value": "AS2_2_004" },
|
||||||
|
{ "label": "AS2_2_005", "value": "AS2_2_005" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-003",
|
||||||
|
"name": "质检区到成品存储区卸货",
|
||||||
|
"status": "COMPLETED",
|
||||||
|
"createdAt": "2024-01-15T10:00:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "QUALITY_INSPECTION",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "FINISHED_STORAGE",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "DROPOFF",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "铝合金-6061",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locationBay": {
|
||||||
|
"label": "库位",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AS2_2_003",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AS2_2_001", "value": "AS2_2_001" },
|
||||||
|
{ "label": "AS2_2_002", "value": "AS2_2_002" },
|
||||||
|
{ "label": "AS2_2_003", "value": "AS2_2_003" },
|
||||||
|
{ "label": "AS2_2_004", "value": "AS2_2_004" },
|
||||||
|
{ "label": "AS2_2_005", "value": "AS2_2_005" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-004",
|
||||||
|
"name": "AP-1到AP-2空车运输",
|
||||||
|
"status": "IDLE",
|
||||||
|
"createdAt": "2024-01-15T11:30:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-1",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-2",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "TRANSPORT",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "空车",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locationBay": {
|
||||||
|
"label": "库位",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AS2_2_004",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AS2_2_001", "value": "AS2_2_001" },
|
||||||
|
{ "label": "AS2_2_002", "value": "AS2_2_002" },
|
||||||
|
{ "label": "AS2_2_003", "value": "AS2_2_003" },
|
||||||
|
{ "label": "AS2_2_004", "value": "AS2_2_004" },
|
||||||
|
{ "label": "AS2_2_005", "value": "AS2_2_005" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-005",
|
||||||
|
"name": "机器人充电任务",
|
||||||
|
"status": "IDLE",
|
||||||
|
"createdAt": "2024-01-15T12:00:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-3",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-3",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "CHARGE",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "空车",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-006",
|
||||||
|
"name": "成品存储区清洁任务",
|
||||||
|
"status": "RUNNING",
|
||||||
|
"createdAt": "2024-01-15T13:15:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "FINISHED_STORAGE",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "FINISHED_STORAGE",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "CLEAN",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "空车",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-007",
|
||||||
|
"name": "满料架A2从原料仓库到AP-4运输",
|
||||||
|
"status": "IDLE",
|
||||||
|
"createdAt": "2024-01-15T14:20:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "RAW_MATERIAL_WAREHOUSE",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-4",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"waypoint": {
|
||||||
|
"label": "途经点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "QUALITY_INSPECTION",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "TRANSPORT",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "满料架-A2",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locationBay": {
|
||||||
|
"label": "库位",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AS2_2_005",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AS2_2_001", "value": "AS2_2_001" },
|
||||||
|
{ "label": "AS2_2_002", "value": "AS2_2_002" },
|
||||||
|
{ "label": "AS2_2_003", "value": "AS2_2_003" },
|
||||||
|
{ "label": "AS2_2_004", "value": "AS2_2_004" },
|
||||||
|
{ "label": "AS2_2_005", "value": "AS2_2_005" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "task-008",
|
||||||
|
"name": "AP-5等待任务",
|
||||||
|
"status": "ERROR",
|
||||||
|
"createdAt": "2024-01-15T15:45:00.000Z",
|
||||||
|
"parameters": {
|
||||||
|
"startLocation": {
|
||||||
|
"label": "起点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-5",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"endLocation": {
|
||||||
|
"label": "终点",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "AP-5",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "AP-1", "value": "AP-1" },
|
||||||
|
{ "label": "AP-2", "value": "AP-2" },
|
||||||
|
{ "label": "AP-3", "value": "AP-3" },
|
||||||
|
{ "label": "AP-4", "value": "AP-4" },
|
||||||
|
{ "label": "AP-5", "value": "AP-5" },
|
||||||
|
{ "label": "炉前缓存区", "value": "FURNACE_BUFFER" },
|
||||||
|
{ "label": "热处理上料交接区", "value": "HEAT_TREATMENT_LOADING" },
|
||||||
|
{ "label": "成品存储区", "value": "FINISHED_STORAGE" },
|
||||||
|
{ "label": "原料仓库", "value": "RAW_MATERIAL_WAREHOUSE" },
|
||||||
|
{ "label": "质检区", "value": "QUALITY_INSPECTION" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"robotAction": {
|
||||||
|
"label": "机器人动作",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "WAIT",
|
||||||
|
"required": true,
|
||||||
|
"options": [
|
||||||
|
{ "label": "运输", "value": "TRANSPORT" },
|
||||||
|
{ "label": "取货", "value": "PICKUP" },
|
||||||
|
{ "label": "卸货", "value": "DROPOFF" },
|
||||||
|
{ "label": "等待", "value": "WAIT" },
|
||||||
|
{ "label": "充电", "value": "CHARGE" },
|
||||||
|
{ "label": "清洁", "value": "CLEAN" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"label": "载荷",
|
||||||
|
"type": "Select",
|
||||||
|
"value": "空料架-B1",
|
||||||
|
"required": false,
|
||||||
|
"options": [
|
||||||
|
{ "label": "满料架-A1", "value": "满料架-A1" },
|
||||||
|
{ "label": "满料架-A2", "value": "满料架-A2" },
|
||||||
|
{ "label": "空料架-B1", "value": "空料架-B1" },
|
||||||
|
{ "label": "空料架-B2", "value": "空料架-B2" },
|
||||||
|
{ "label": "空车", "value": "空车" },
|
||||||
|
{ "label": "钢材-Q235", "value": "钢材-Q235" },
|
||||||
|
{ "label": "铝合金-6061", "value": "铝合金-6061" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"serverUrl": "http://localhost:3000/api"
|
||||||
|
}
|
34
package-lock.json
generated
34
package-lock.json
generated
@ -8,6 +8,7 @@
|
|||||||
"name": "MyReactNativeApp",
|
"name": "MyReactNativeApp",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
||||||
"@react-native/new-app-screen": "0.80.1",
|
"@react-native/new-app-screen": "0.80.1",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.2",
|
"@react-navigation/bottom-tabs": "^7.4.2",
|
||||||
"@react-navigation/native": "^7.1.14",
|
"@react-navigation/native": "^7.1.14",
|
||||||
@ -2742,6 +2743,18 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-native-async-storage/async-storage": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"merge-options": "^3.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "^0.0.0-0 || >=0.65 <1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-native-community/cli": {
|
"node_modules/@react-native-community/cli": {
|
||||||
"version": "19.0.0",
|
"version": "19.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@react-native-community/cli/-/cli-19.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@react-native-community/cli/-/cli-19.0.0.tgz",
|
||||||
@ -7677,6 +7690,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-plain-obj": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-regex": {
|
"node_modules/is-regex": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz",
|
||||||
@ -9368,6 +9390,18 @@
|
|||||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/merge-options": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/merge-options/-/merge-options-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-plain-obj": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-native-async-storage/async-storage": "^2.2.0",
|
||||||
"@react-native/new-app-screen": "0.80.1",
|
"@react-native/new-app-screen": "0.80.1",
|
||||||
"@react-navigation/bottom-tabs": "^7.4.2",
|
"@react-navigation/bottom-tabs": "^7.4.2",
|
||||||
"@react-navigation/native": "^7.1.14",
|
"@react-navigation/native": "^7.1.14",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, TouchableOpacity } from 'react-native';
|
import { StyleSheet, TouchableOpacity, Dimensions } from 'react-native';
|
||||||
import { Card, Chip } from '@rneui/themed';
|
import { Card, Chip } from '@rneui/themed';
|
||||||
import { Task, TaskStatus } from '../types/task';
|
import { Task, TaskStatus } from '../types/task';
|
||||||
|
|
||||||
@ -15,8 +15,10 @@ const statusColors: Record<TaskStatus, string> = {
|
|||||||
ERROR: 'red',
|
ERROR: 'red',
|
||||||
};
|
};
|
||||||
|
|
||||||
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
const { width } = Dimensions.get('window');
|
||||||
|
const cardWidth = (width - 32) / 2; // 减去padding,除以2得到每个卡片的宽度
|
||||||
|
|
||||||
|
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={() => onPress(task)} style={styles.touchable}>
|
<TouchableOpacity onPress={() => onPress(task)} style={styles.touchable}>
|
||||||
<Card containerStyle={styles.card}>
|
<Card containerStyle={styles.card}>
|
||||||
@ -42,12 +44,13 @@ const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
touchable: {
|
touchable: {
|
||||||
flex: 1,
|
width: cardWidth,
|
||||||
width: '50%',
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
margin: 4,
|
margin: 4,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
|
width: cardWidth - 8, // 减去margin
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
|
@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect } from 'react';
|
|||||||
import { StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native';
|
import { StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native';
|
||||||
import { Input, BottomSheet, ListItem, Button } from '@rneui/themed';
|
import { Input, BottomSheet, ListItem, Button } from '@rneui/themed';
|
||||||
import { Task, RobotAction } from '../types/task';
|
import { Task, RobotAction } from '../types/task';
|
||||||
import { LOCATIONS, ROBOT_ACTIONS, PAYLOADS } from '../data/mockData';
|
import { useTasks } from '../context/TasksContext';
|
||||||
|
|
||||||
interface TaskFormProps {
|
interface TaskFormProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
@ -10,6 +10,7 @@ interface TaskFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
||||||
|
const { locations, payloads, robotActions } = useTasks();
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
const [currentField, setCurrentField] = useState('');
|
const [currentField, setCurrentField] = useState('');
|
||||||
const [currentItems, setCurrentItems] = useState<
|
const [currentItems, setCurrentItems] = useState<
|
||||||
@ -232,13 +233,13 @@ const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
|||||||
'startLocation',
|
'startLocation',
|
||||||
'起点',
|
'起点',
|
||||||
task.parameters.startLocation,
|
task.parameters.startLocation,
|
||||||
LOCATIONS,
|
locations,
|
||||||
)}
|
)}
|
||||||
{renderDropdown(
|
{renderDropdown(
|
||||||
'endLocation',
|
'endLocation',
|
||||||
'终点',
|
'终点',
|
||||||
task.parameters.endLocation,
|
task.parameters.endLocation,
|
||||||
LOCATIONS,
|
locations,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
@ -252,9 +253,9 @@ const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
|||||||
'robotAction',
|
'robotAction',
|
||||||
'机器人动作',
|
'机器人动作',
|
||||||
task.parameters.robotAction,
|
task.parameters.robotAction,
|
||||||
ROBOT_ACTIONS,
|
robotActions,
|
||||||
)}
|
)}
|
||||||
{renderDropdown('payload', '载荷', task.parameters.payload, PAYLOADS)}
|
{renderDropdown('payload', '载荷', task.parameters.payload, payloads)}
|
||||||
|
|
||||||
{/* 库位字段 */}
|
{/* 库位字段 */}
|
||||||
<Input
|
<Input
|
||||||
|
@ -1,18 +1,119 @@
|
|||||||
import React, { createContext, useState, useContext, ReactNode } from 'react';
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useState,
|
||||||
|
useContext,
|
||||||
|
ReactNode,
|
||||||
|
useEffect,
|
||||||
|
} from 'react';
|
||||||
import { Task } from '../types/task';
|
import { Task } from '../types/task';
|
||||||
import { MOCK_TASKS } from '../data/mockData';
|
import {
|
||||||
|
AppConfig,
|
||||||
|
LocationOption,
|
||||||
|
PayloadOption,
|
||||||
|
RobotActionOption,
|
||||||
|
} from '../types/config';
|
||||||
|
import {
|
||||||
|
getConfig,
|
||||||
|
getSettings,
|
||||||
|
executeTask,
|
||||||
|
clearCachedConfig,
|
||||||
|
} from '../services/configService';
|
||||||
|
|
||||||
interface TasksContextData {
|
interface TasksContextData {
|
||||||
tasks: Task[];
|
tasks: Task[];
|
||||||
|
locations: LocationOption[];
|
||||||
|
locationsBays: LocationOption[];
|
||||||
|
payloads: PayloadOption[];
|
||||||
|
robotActions: RobotActionOption[];
|
||||||
getTaskById: (id: string) => Task | undefined;
|
getTaskById: (id: string) => Task | undefined;
|
||||||
updateTask: (updatedTask: Task) => void;
|
updateTask: (updatedTask: Task) => void;
|
||||||
runTask: (id: string) => void;
|
runTask: (id: string) => void;
|
||||||
|
refreshConfig: () => Promise<void>;
|
||||||
|
isConfigLoaded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TasksContext = createContext<TasksContextData>({} as TasksContextData);
|
const TasksContext = createContext<TasksContextData>({} as TasksContextData);
|
||||||
|
|
||||||
export const TasksProvider: React.FC<{children: ReactNode}> = ({ children }) => {
|
export const TasksProvider: React.FC<{ children: ReactNode }> = ({
|
||||||
const [tasks, setTasks] = useState<Task[]>(MOCK_TASKS);
|
children,
|
||||||
|
}) => {
|
||||||
|
const [tasks, setTasks] = useState<Task[]>([]);
|
||||||
|
const [locations, setLocations] = useState<LocationOption[]>([]);
|
||||||
|
const [locationsBays, setLocationsBays] = useState<LocationOption[]>([]);
|
||||||
|
const [payloads, setPayloads] = useState<PayloadOption[]>([]);
|
||||||
|
const [robotActions, setRobotActions] = useState<RobotActionOption[]>([]);
|
||||||
|
const [isConfigLoaded, setIsConfigLoaded] = useState(false);
|
||||||
|
|
||||||
|
// 组件初始化时加载配置
|
||||||
|
useEffect(() => {
|
||||||
|
const loadConfig = async () => {
|
||||||
|
try {
|
||||||
|
// 清除缓存以确保加载最新的配置
|
||||||
|
await clearCachedConfig();
|
||||||
|
|
||||||
|
const config = await getConfig();
|
||||||
|
if (config) {
|
||||||
|
applyConfig(config);
|
||||||
|
setIsConfigLoaded(true);
|
||||||
|
console.log('成功加载配置,任务数量:', config.tasks?.length || 0);
|
||||||
|
} else {
|
||||||
|
console.log('没有找到配置文件,使用空数据');
|
||||||
|
// 使用空数据而不是mock数据
|
||||||
|
applyConfig({
|
||||||
|
version: '0.0.0',
|
||||||
|
locations: [],
|
||||||
|
locationsBays: [],
|
||||||
|
payloads: [],
|
||||||
|
robotActions: [],
|
||||||
|
tasks: [],
|
||||||
|
});
|
||||||
|
setIsConfigLoaded(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载配置失败:', error);
|
||||||
|
// 发生错误时也使用空数据
|
||||||
|
applyConfig({
|
||||||
|
version: '0.0.0',
|
||||||
|
locations: [],
|
||||||
|
locationsBays: [],
|
||||||
|
payloads: [],
|
||||||
|
robotActions: [],
|
||||||
|
tasks: [],
|
||||||
|
});
|
||||||
|
setIsConfigLoaded(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadConfig();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const applyConfig = (config: AppConfig) => {
|
||||||
|
setTasks(config.tasks || []);
|
||||||
|
setLocations(config.locations || []);
|
||||||
|
setLocationsBays(config.locationsBays || []);
|
||||||
|
setPayloads(config.payloads || []);
|
||||||
|
setRobotActions(config.robotActions || []);
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshConfig = async () => {
|
||||||
|
try {
|
||||||
|
// 刷新时也清除缓存
|
||||||
|
await clearCachedConfig();
|
||||||
|
|
||||||
|
const config = await getConfig();
|
||||||
|
if (config) {
|
||||||
|
applyConfig(config);
|
||||||
|
setIsConfigLoaded(true);
|
||||||
|
console.log('成功刷新配置,任务数量:', config.tasks?.length || 0);
|
||||||
|
} else {
|
||||||
|
console.log('刷新配置时没有找到配置文件');
|
||||||
|
setIsConfigLoaded(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('刷新配置失败:', error);
|
||||||
|
setIsConfigLoaded(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getTaskById = (id: string) => {
|
const getTaskById = (id: string) => {
|
||||||
return tasks.find(task => task.id === id);
|
return tasks.find(task => task.id === id);
|
||||||
@ -20,28 +121,59 @@ export const TasksProvider: React.FC<{children: ReactNode}> = ({ children }) =>
|
|||||||
|
|
||||||
const updateTask = (updatedTask: Task) => {
|
const updateTask = (updatedTask: Task) => {
|
||||||
setTasks(prevTasks =>
|
setTasks(prevTasks =>
|
||||||
prevTasks.map(task => (task.id === updatedTask.id ? updatedTask : task))
|
prevTasks.map(task => (task.id === updatedTask.id ? updatedTask : task)),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const runTask = (id: string) => {
|
const runTask = async (id: string) => {
|
||||||
|
const task = getTaskById(id);
|
||||||
|
if (!task) return;
|
||||||
|
|
||||||
|
// 更新任务状态为运行中
|
||||||
setTasks(prevTasks =>
|
setTasks(prevTasks =>
|
||||||
prevTasks.map(task =>
|
prevTasks.map(t => (t.id === id ? { ...t, status: 'RUNNING' } : t)),
|
||||||
task.id === id ? { ...task, status: 'RUNNING' } : task
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
// 模拟任务完成
|
|
||||||
setTimeout(() => {
|
try {
|
||||||
|
// 获取服务器设置并发送任务执行请求
|
||||||
|
const settings = await getSettings();
|
||||||
|
if (settings.serverUrl) {
|
||||||
|
await executeTask(settings.serverUrl, task.id, {
|
||||||
|
name: task.name,
|
||||||
|
parameters: task.parameters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟任务完成(实际项目中应该通过WebSocket或轮询获取任务状态)
|
||||||
|
setTimeout(() => {
|
||||||
setTasks(prevTasks =>
|
setTasks(prevTasks =>
|
||||||
prevTasks.map(task =>
|
prevTasks.map(t => (t.id === id ? { ...t, status: 'COMPLETED' } : t)),
|
||||||
task.id === id ? { ...task, status: 'COMPLETED' } : task
|
);
|
||||||
)
|
}, 5000);
|
||||||
);
|
} catch (error) {
|
||||||
}, 5000);
|
console.error('任务执行失败:', error);
|
||||||
|
// 任务执行失败,更新状态为错误
|
||||||
|
setTasks(prevTasks =>
|
||||||
|
prevTasks.map(t => (t.id === id ? { ...t, status: 'ERROR' } : t)),
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TasksContext.Provider value={{ tasks, getTaskById, updateTask, runTask }}>
|
<TasksContext.Provider
|
||||||
|
value={{
|
||||||
|
tasks,
|
||||||
|
locations,
|
||||||
|
locationsBays,
|
||||||
|
payloads,
|
||||||
|
robotActions,
|
||||||
|
getTaskById,
|
||||||
|
updateTask,
|
||||||
|
runTask,
|
||||||
|
refreshConfig,
|
||||||
|
isConfigLoaded,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</TasksContext.Provider>
|
</TasksContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
import { Task, RobotAction } from '../types/task';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
|
|
||||||
export const LOCATIONS = Array.from({ length: 100 }, (_, i) => ({
|
|
||||||
label: `AP-${i + 1}`,
|
|
||||||
value: `AP-${i + 1}`,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ROBOT_ACTIONS: { label: string; value: RobotAction }[] = [
|
|
||||||
{ label: '运输', value: 'TRANSPORT' },
|
|
||||||
{ label: '取货', value: 'PICKUP' },
|
|
||||||
{ label: '卸货', value: 'DROPOFF' },
|
|
||||||
{ label: '等待', value: 'WAIT' },
|
|
||||||
{ label: '充电', value: 'CHARGE' },
|
|
||||||
{ label: '清洁', value: 'CLEAN' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const LOCATIONS_BAYS = Array.from({ length: 100 }, (_, i) => ({
|
|
||||||
label: `AS2_2_${String(i + 1).padStart(3, '0')}`,
|
|
||||||
value: `AS2_2_${String(i + 1).padStart(3, '0')}`,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const PAYLOADS = [
|
|
||||||
{ label: '满料架-A1', value: '满料架-A1' },
|
|
||||||
{ label: '空料架-B2', value: '空料架-B2' },
|
|
||||||
{ label: '空料架-C3', value: '空料架-C3' },
|
|
||||||
{ label: '空车', value: '空车' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const getRandomElement = <T>(arr: T[]): T =>
|
|
||||||
arr[Math.floor(Math.random() * arr.length)];
|
|
||||||
|
|
||||||
export const MOCK_TASKS: Task[] = Array.from({ length: 15 }, (_, i) => {
|
|
||||||
const startLocation = getRandomElement(LOCATIONS);
|
|
||||||
const endLocation = getRandomElement(
|
|
||||||
LOCATIONS.filter(l => l.value !== startLocation.value),
|
|
||||||
);
|
|
||||||
const robotAction = getRandomElement(ROBOT_ACTIONS);
|
|
||||||
const payload = getRandomElement(PAYLOADS);
|
|
||||||
const statusOptions: Task['status'][] = [
|
|
||||||
'IDLE',
|
|
||||||
'RUNNING',
|
|
||||||
'COMPLETED',
|
|
||||||
'ERROR',
|
|
||||||
];
|
|
||||||
const status = getRandomElement(statusOptions);
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: uuidv4(),
|
|
||||||
name: `任务 ${i + 1}: 从 ${startLocation.label} 到 ${endLocation.label}`,
|
|
||||||
status: status,
|
|
||||||
createdAt: new Date(
|
|
||||||
new Date().getTime() - Math.random() * 1000 * 60 * 60 * 24,
|
|
||||||
).toISOString(),
|
|
||||||
parameters: {
|
|
||||||
startLocation: startLocation.value,
|
|
||||||
endLocation: endLocation.value,
|
|
||||||
robotAction: robotAction.value,
|
|
||||||
payload: payload.value,
|
|
||||||
locationBay: '', // 库位初始值为空
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
||||||
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||||
import TaskListScreen from '../screens/TaskListScreen';
|
import TaskListScreen from '../screens/TaskListScreen';
|
||||||
import TaskEditScreen from '../screens/TaskEditScreen';
|
import TaskEditScreen from '../screens/TaskEditScreen';
|
||||||
import RunScreen from '../screens/RunScreen';
|
import RunScreen from '../screens/RunScreen';
|
||||||
@ -13,16 +14,50 @@ const Tab = createBottomTabNavigator();
|
|||||||
function HomeStackNavigator() {
|
function HomeStackNavigator() {
|
||||||
return (
|
return (
|
||||||
<HomeStack.Navigator>
|
<HomeStack.Navigator>
|
||||||
<HomeStack.Screen name="TaskList" component={TaskListScreen} options={{ title: '任务列表' }} />
|
<HomeStack.Screen
|
||||||
<HomeStack.Screen name="TaskEdit" component={TaskEditScreen} options={{ title: '编辑任务' }} />
|
name="TaskList"
|
||||||
|
component={TaskListScreen}
|
||||||
|
options={{ title: '任务列表' }}
|
||||||
|
/>
|
||||||
|
<HomeStack.Screen
|
||||||
|
name="TaskEdit"
|
||||||
|
component={TaskEditScreen}
|
||||||
|
options={{ title: '编辑任务' }}
|
||||||
|
/>
|
||||||
</HomeStack.Navigator>
|
</HomeStack.Navigator>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AppNavigator() {
|
export default function AppNavigator() {
|
||||||
return (
|
return (
|
||||||
<Tab.Navigator>
|
<Tab.Navigator
|
||||||
<Tab.Screen name="主页" component={HomeStackNavigator} options={{ headerShown: false }} />
|
screenOptions={({ route }) => ({
|
||||||
|
tabBarIcon: ({ color, size }) => {
|
||||||
|
let iconName: string;
|
||||||
|
|
||||||
|
if (route.name === '主页') {
|
||||||
|
iconName = 'home';
|
||||||
|
} else if (route.name === '运行') {
|
||||||
|
iconName = 'play-arrow';
|
||||||
|
} else if (route.name === '编辑') {
|
||||||
|
iconName = 'edit';
|
||||||
|
} else if (route.name === '设置') {
|
||||||
|
iconName = 'settings';
|
||||||
|
} else {
|
||||||
|
iconName = 'help';
|
||||||
|
}
|
||||||
|
|
||||||
|
return <MaterialIcons name={iconName} size={size} color={color} />;
|
||||||
|
},
|
||||||
|
tabBarActiveTintColor: '#2196F3',
|
||||||
|
tabBarInactiveTintColor: 'gray',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Tab.Screen
|
||||||
|
name="主页"
|
||||||
|
component={HomeStackNavigator}
|
||||||
|
options={{ headerShown: false }}
|
||||||
|
/>
|
||||||
<Tab.Screen name="运行" component={RunScreen} />
|
<Tab.Screen name="运行" component={RunScreen} />
|
||||||
<Tab.Screen name="编辑" component={EditScreen} />
|
<Tab.Screen name="编辑" component={EditScreen} />
|
||||||
<Tab.Screen name="设置" component={SettingsScreen} />
|
<Tab.Screen name="设置" component={SettingsScreen} />
|
||||||
|
@ -1,18 +1,467 @@
|
|||||||
import React from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
Alert,
|
||||||
|
ActivityIndicator,
|
||||||
|
ScrollView,
|
||||||
|
} from 'react-native';
|
||||||
|
import { AppSettings } from '../types/config';
|
||||||
|
import {
|
||||||
|
getSettings,
|
||||||
|
saveSettings,
|
||||||
|
downloadConfig,
|
||||||
|
getConfig,
|
||||||
|
clearCachedConfig,
|
||||||
|
} from '../services/configService';
|
||||||
|
import { useTasks } from '../context/TasksContext';
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
|
const { refreshConfig } = useTasks();
|
||||||
|
const [settings, setSettings] = useState<AppSettings>({
|
||||||
|
configFileName: '',
|
||||||
|
serverUrl: '',
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [configStatus, setConfigStatus] = useState<string>('未加载');
|
||||||
|
|
||||||
|
// 组件加载时获取设置
|
||||||
|
useEffect(() => {
|
||||||
|
loadSettings();
|
||||||
|
checkConfigStatus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadSettings = async () => {
|
||||||
|
try {
|
||||||
|
const currentSettings = await getSettings();
|
||||||
|
setSettings(currentSettings);
|
||||||
|
} catch (error) {
|
||||||
|
Alert.alert('错误', '加载设置失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkConfigStatus = async () => {
|
||||||
|
const config = await getConfig();
|
||||||
|
if (config) {
|
||||||
|
setConfigStatus(
|
||||||
|
`已加载 (版本: ${config.version}, 任务数: ${
|
||||||
|
config.tasks?.length || 0
|
||||||
|
})`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setConfigStatus('未加载');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveSettings = async () => {
|
||||||
|
if (!settings.configFileName.trim()) {
|
||||||
|
Alert.alert('错误', '请输入配置文件名');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!settings.serverUrl.trim()) {
|
||||||
|
Alert.alert('错误', '请输入服务器地址');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await saveSettings(settings);
|
||||||
|
Alert.alert('成功', '设置已保存');
|
||||||
|
} catch (error) {
|
||||||
|
Alert.alert('错误', '保存设置失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRefreshLocalConfig = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
// 清除缓存并重新加载本地配置
|
||||||
|
await clearCachedConfig();
|
||||||
|
await refreshConfig();
|
||||||
|
await checkConfigStatus();
|
||||||
|
|
||||||
|
Alert.alert('成功', '本地配置已刷新!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('刷新本地配置失败:', error);
|
||||||
|
Alert.alert('错误', '刷新本地配置失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDownloadConfig = async () => {
|
||||||
|
if (!settings.configFileName.trim()) {
|
||||||
|
Alert.alert('错误', '请先输入配置文件名');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!settings.serverUrl.trim()) {
|
||||||
|
Alert.alert('错误', '请先输入服务器地址');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
// 先保存设置
|
||||||
|
await saveSettings(settings);
|
||||||
|
|
||||||
|
// 下载配置文件
|
||||||
|
const config = await downloadConfig(
|
||||||
|
settings.serverUrl,
|
||||||
|
settings.configFileName,
|
||||||
|
);
|
||||||
|
|
||||||
|
Alert.alert(
|
||||||
|
'成功',
|
||||||
|
`配置文件下载成功!\n版本: ${config.version}\n任务数量: ${
|
||||||
|
config.tasks?.length || 0
|
||||||
|
}`,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: '确定',
|
||||||
|
onPress: async () => {
|
||||||
|
await refreshConfig();
|
||||||
|
checkConfigStatus();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
Alert.alert(
|
||||||
|
'下载失败',
|
||||||
|
error instanceof Error ? error.message : '未知错误',
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClearCache = async () => {
|
||||||
|
Alert.alert(
|
||||||
|
'确认清除',
|
||||||
|
'确定要清除缓存的配置文件吗?系统将重新加载本地 config.json 文件。',
|
||||||
|
[
|
||||||
|
{ text: '取消', style: 'cancel' },
|
||||||
|
{
|
||||||
|
text: '确定',
|
||||||
|
onPress: async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
await clearCachedConfig();
|
||||||
|
await refreshConfig();
|
||||||
|
checkConfigStatus();
|
||||||
|
Alert.alert('成功', '缓存已清除,已重新加载配置');
|
||||||
|
} catch (error) {
|
||||||
|
Alert.alert('错误', '清除缓存失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTestConnection = async () => {
|
||||||
|
if (!settings.serverUrl.trim()) {
|
||||||
|
Alert.alert('错误', '请先输入服务器地址');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
||||||
|
|
||||||
|
const response = await fetch(`${settings.serverUrl}/health`, {
|
||||||
|
method: 'GET',
|
||||||
|
signal: controller.signal,
|
||||||
|
});
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
Alert.alert('连接成功', '服务器连接正常');
|
||||||
|
} else {
|
||||||
|
Alert.alert('连接失败', `HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
Alert.alert('连接失败', '无法连接到服务器');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.screenContainer}>
|
<ScrollView style={styles.container}>
|
||||||
<Text>设置!</Text>
|
<View style={styles.content}>
|
||||||
</View>
|
{loading && (
|
||||||
|
<View style={styles.loadingOverlay}>
|
||||||
|
<ActivityIndicator size="large" color="#007AFF" />
|
||||||
|
<Text style={styles.loadingText}>处理中...</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 配置状态 */}
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>配置状态</Text>
|
||||||
|
<Text style={styles.statusText}>{configStatus}</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 配置文件设置 */}
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>配置文件</Text>
|
||||||
|
|
||||||
|
<View style={styles.inputGroup}>
|
||||||
|
<Text style={styles.label}>配置文件名:</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
value={settings.configFileName}
|
||||||
|
onChangeText={text =>
|
||||||
|
setSettings(prev => ({ ...prev, configFileName: text }))
|
||||||
|
}
|
||||||
|
placeholder="config"
|
||||||
|
placeholderTextColor="#999"
|
||||||
|
autoCapitalize="none"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.buttonRow}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.button, styles.downloadButton]}
|
||||||
|
onPress={handleDownloadConfig}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>下载配置文件</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.button, styles.refreshButton]}
|
||||||
|
onPress={handleRefreshLocalConfig}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>刷新本地配置</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.buttonRow}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.button, styles.clearButton]}
|
||||||
|
onPress={handleClearCache}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>清除缓存</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 服务器设置 */}
|
||||||
|
<View style={styles.section}>
|
||||||
|
<Text style={styles.sectionTitle}>服务器设置</Text>
|
||||||
|
|
||||||
|
<View style={styles.inputGroup}>
|
||||||
|
<Text style={styles.label}>服务器地址:</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
value={settings.serverUrl}
|
||||||
|
onChangeText={text =>
|
||||||
|
setSettings(prev => ({ ...prev, serverUrl: text }))
|
||||||
|
}
|
||||||
|
placeholder="http://localhost:3000/api"
|
||||||
|
placeholderTextColor="#999"
|
||||||
|
autoCapitalize="none"
|
||||||
|
keyboardType="url"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.buttonRow}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.button, styles.testButton]}
|
||||||
|
onPress={handleTestConnection}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>测试连接</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[styles.button, styles.saveButton]}
|
||||||
|
onPress={handleSaveSettings}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<Text style={styles.buttonText}>保存设置</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 说明信息 */}
|
||||||
|
<View style={styles.infoSection}>
|
||||||
|
<Text style={styles.infoTitle}>使用说明</Text>
|
||||||
|
<Text style={styles.infoText}>配置文件加载优先级:</Text>
|
||||||
|
<Text style={styles.infoText}>
|
||||||
|
1. 缓存的服务器配置(从服务器下载的配置)
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.infoText}>2. 本地 config.json 文件</Text>
|
||||||
|
<Text style={styles.infoText}>3. 空数据(如果都没有找到)</Text>
|
||||||
|
<Text style={styles.infoText}>
|
||||||
|
• 点击"下载配置文件"从服务器获取最新配置
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.infoText}>
|
||||||
|
• 点击"清除缓存"强制重新加载本地配置文件
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
screenContainer: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
backgroundColor: '#f5f5f5',
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
padding: 20,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textAlign: 'center',
|
||||||
|
marginBottom: 30,
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 20,
|
||||||
|
marginBottom: 20,
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 3.84,
|
||||||
|
elevation: 5,
|
||||||
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 15,
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
inputGroup: {
|
||||||
|
marginBottom: 15,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
fontSize: 16,
|
||||||
|
marginBottom: 8,
|
||||||
|
color: '#333',
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
inputRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
textInput: {
|
||||||
|
flex: 1,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#ddd',
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 12,
|
||||||
|
fontSize: 16,
|
||||||
|
backgroundColor: '#fafafa',
|
||||||
|
},
|
||||||
|
extension: {
|
||||||
|
marginLeft: 8,
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#666',
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
statusRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: 15,
|
||||||
|
},
|
||||||
|
statusLabel: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#333',
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
statusText: {
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#007AFF',
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 12,
|
||||||
|
alignItems: 'center',
|
||||||
|
minHeight: 48,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
downloadButton: {
|
||||||
|
backgroundColor: '#007AFF',
|
||||||
|
flex: 1,
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
refreshButton: {
|
||||||
|
backgroundColor: '#32D74B',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
testButton: {
|
||||||
|
backgroundColor: '#34C759',
|
||||||
|
flex: 1,
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
saveButton: {
|
||||||
|
backgroundColor: '#FF9500',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
color: 'white',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
buttonRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
marginTop: 10,
|
||||||
|
},
|
||||||
|
infoSection: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 20,
|
||||||
|
marginBottom: 20,
|
||||||
|
},
|
||||||
|
infoTitle: {
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 15,
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
infoText: {
|
||||||
|
fontSize: 14,
|
||||||
|
lineHeight: 20,
|
||||||
|
color: '#666',
|
||||||
|
marginBottom: 5,
|
||||||
|
},
|
||||||
|
loadingOverlay: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.8)',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
loadingText: {
|
||||||
|
marginTop: 10,
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#007AFF',
|
||||||
|
},
|
||||||
|
clearButton: {
|
||||||
|
backgroundColor: '#FF3B30',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, FlatList, StyleSheet } from 'react-native';
|
import { View, ScrollView, StyleSheet } from 'react-native';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation } from '@react-navigation/native';
|
||||||
import { StackNavigationProp } from '@react-navigation/stack';
|
import { StackNavigationProp } from '@react-navigation/stack';
|
||||||
import { useTasks } from '../context/TasksContext';
|
import { useTasks } from '../context/TasksContext';
|
||||||
import TaskCard from '../components/TaskCard';
|
import TaskCard from '../components/TaskCard';
|
||||||
|
import { Task } from '../types/task';
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
TaskList: undefined;
|
TaskList: undefined;
|
||||||
TaskEdit: { task: Task };
|
TaskEdit: { task: Task };
|
||||||
};
|
};
|
||||||
|
|
||||||
type TaskListNavigationProp = StackNavigationProp<RootStackParamList, 'TaskList'>;
|
type TaskListNavigationProp = StackNavigationProp<
|
||||||
|
RootStackParamList,
|
||||||
|
'TaskList'
|
||||||
|
>;
|
||||||
|
|
||||||
export default function TaskListScreen() {
|
export default function TaskListScreen() {
|
||||||
const { tasks } = useTasks();
|
const { tasks } = useTasks();
|
||||||
@ -22,13 +26,17 @@ export default function TaskListScreen() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<FlatList
|
<ScrollView contentContainerStyle={styles.scrollContainer}>
|
||||||
data={tasks}
|
<View style={styles.tasksContainer}>
|
||||||
renderItem={({ item }) => <TaskCard task={item} onPress={() => handlePressTask(item)} />}
|
{tasks.map(task => (
|
||||||
keyExtractor={item => item.id}
|
<TaskCard
|
||||||
numColumns={2}
|
key={task.id}
|
||||||
contentContainerStyle={styles.list}
|
task={task}
|
||||||
/>
|
onPress={() => handlePressTask(task)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -37,6 +45,12 @@ const styles = StyleSheet.create({
|
|||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
list: {
|
scrollContainer: {
|
||||||
paddingHorizontal: 8,
|
padding: 16,
|
||||||
}});
|
},
|
||||||
|
tasksContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
175
src/services/configService.ts
Normal file
175
src/services/configService.ts
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
import { AppConfig, AppSettings } from '../types/config';
|
||||||
|
|
||||||
|
const SETTINGS_KEY = 'app_settings';
|
||||||
|
const CONFIG_CACHE_KEY = 'cached_config';
|
||||||
|
|
||||||
|
// 默认设置
|
||||||
|
const DEFAULT_SETTINGS: AppSettings = {
|
||||||
|
configFileName: 'config',
|
||||||
|
serverUrl: 'http://localhost:3000/api',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取设置
|
||||||
|
export const getSettings = async (): Promise<AppSettings> => {
|
||||||
|
try {
|
||||||
|
const stored = await AsyncStorage.getItem(SETTINGS_KEY);
|
||||||
|
if (stored) {
|
||||||
|
return { ...DEFAULT_SETTINGS, ...JSON.parse(stored) };
|
||||||
|
}
|
||||||
|
return DEFAULT_SETTINGS;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取设置失败:', error);
|
||||||
|
return DEFAULT_SETTINGS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存设置
|
||||||
|
export const saveSettings = async (settings: AppSettings): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await AsyncStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存设置失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载本地配置文件
|
||||||
|
export const loadLocalConfig = async (): Promise<AppConfig | null> => {
|
||||||
|
try {
|
||||||
|
// 尝试加载项目根目录下的 config.json 文件
|
||||||
|
const localConfig = require('../../config.json');
|
||||||
|
console.log('成功加载本地配置文件:', localConfig);
|
||||||
|
|
||||||
|
return localConfig as AppConfig;
|
||||||
|
} catch (error) {
|
||||||
|
console.log('本地配置文件不存在或加载失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 从服务器下载配置文件
|
||||||
|
export const downloadConfig = async (
|
||||||
|
serverUrl: string,
|
||||||
|
configFileName: string,
|
||||||
|
): Promise<AppConfig> => {
|
||||||
|
try {
|
||||||
|
const url = `${serverUrl.replace(/\/$/, '')}/${configFileName}.json`;
|
||||||
|
console.log('下载配置文件:', url);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const config: AppConfig = await response.json();
|
||||||
|
|
||||||
|
// 缓存服务器配置文件(标记为服务器来源)
|
||||||
|
const configWithSource = { ...config, _source: 'server' };
|
||||||
|
await AsyncStorage.setItem(
|
||||||
|
CONFIG_CACHE_KEY,
|
||||||
|
JSON.stringify(configWithSource),
|
||||||
|
);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('下载配置文件失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取缓存的配置文件
|
||||||
|
export const getCachedConfig = async (): Promise<AppConfig | null> => {
|
||||||
|
try {
|
||||||
|
const cached = await AsyncStorage.getItem(CONFIG_CACHE_KEY);
|
||||||
|
if (cached) {
|
||||||
|
const config = JSON.parse(cached);
|
||||||
|
// 移除内部标记字段
|
||||||
|
delete config._source;
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取缓存配置失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取配置文件(优先级:缓存的服务器配置 > 本地config.json > 空数据)
|
||||||
|
export const getConfig = async (): Promise<AppConfig | null> => {
|
||||||
|
try {
|
||||||
|
// 1. 先尝试获取缓存的配置(通常是从服务器下载的)
|
||||||
|
const cachedConfig = await getCachedConfig();
|
||||||
|
if (cachedConfig) {
|
||||||
|
console.log('使用缓存的配置文件');
|
||||||
|
return cachedConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 如果没有缓存,尝试加载本地配置文件
|
||||||
|
const localConfig = await loadLocalConfig();
|
||||||
|
if (localConfig) {
|
||||||
|
console.log('使用本地 config.json 文件');
|
||||||
|
// 将本地配置也缓存起来,但标记为本地来源
|
||||||
|
const configWithSource = { ...localConfig, _source: 'local' };
|
||||||
|
await AsyncStorage.setItem(
|
||||||
|
CONFIG_CACHE_KEY,
|
||||||
|
JSON.stringify(configWithSource),
|
||||||
|
);
|
||||||
|
return localConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('没有找到任何配置文件');
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取配置文件失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清除缓存配置(用于强制重新加载)
|
||||||
|
export const clearCachedConfig = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await AsyncStorage.removeItem(CONFIG_CACHE_KEY);
|
||||||
|
console.log('已清除缓存配置');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清除缓存配置失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 向服务器发送任务执行请求
|
||||||
|
export const executeTask = async (
|
||||||
|
serverUrl: string,
|
||||||
|
taskId: string,
|
||||||
|
taskData: any,
|
||||||
|
): Promise<any> => {
|
||||||
|
try {
|
||||||
|
const url = `${serverUrl.replace(/\/$/, '')}/execute-task`;
|
||||||
|
console.log('执行任务请求:', url, taskData);
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
taskId,
|
||||||
|
...taskData,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('执行任务失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
36
src/types/config.ts
Normal file
36
src/types/config.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Task, RobotAction } from './task';
|
||||||
|
|
||||||
|
// 配置文件中的位置选项
|
||||||
|
export interface LocationOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置文件中的载荷选项
|
||||||
|
export interface PayloadOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置文件中的机器人动作选项
|
||||||
|
export interface RobotActionOption {
|
||||||
|
label: string;
|
||||||
|
value: RobotAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完整的配置文件结构
|
||||||
|
export interface AppConfig {
|
||||||
|
version: string;
|
||||||
|
locations: LocationOption[];
|
||||||
|
locationsBays: LocationOption[];
|
||||||
|
payloads: PayloadOption[];
|
||||||
|
robotActions: RobotActionOption[];
|
||||||
|
tasks: Task[];
|
||||||
|
serverUrl?: string; // 服务器地址
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置存储接口
|
||||||
|
export interface AppSettings {
|
||||||
|
configFileName: string;
|
||||||
|
serverUrl: string;
|
||||||
|
}
|
@ -10,14 +10,33 @@ export type RobotAction =
|
|||||||
// 任务的状态
|
// 任务的状态
|
||||||
export type TaskStatus = 'IDLE' | 'RUNNING' | 'COMPLETED' | 'ERROR';
|
export type TaskStatus = 'IDLE' | 'RUNNING' | 'COMPLETED' | 'ERROR';
|
||||||
|
|
||||||
// 任务参数
|
// 参数选项接口
|
||||||
|
export interface ParameterOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态参数配置接口
|
||||||
|
export interface DynamicParameter {
|
||||||
|
label: string;
|
||||||
|
type: 'Simple' | 'Select' | 'MultiSelect' | 'Text' | 'Number';
|
||||||
|
value: string | string[] | number;
|
||||||
|
required: boolean;
|
||||||
|
options?: ParameterOption[];
|
||||||
|
placeholder?: string;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务参数 - 支持动态配置
|
||||||
export interface TaskParameters {
|
export interface TaskParameters {
|
||||||
startLocation: string; // 起点
|
startLocation: DynamicParameter; // 起点
|
||||||
endLocation: string; // 终点
|
endLocation: DynamicParameter; // 终点
|
||||||
waypoint?: string; // 途经点 (可选)
|
waypoint?: DynamicParameter; // 途经点 (可选)
|
||||||
robotAction: RobotAction; // 机器人动作
|
robotAction: DynamicParameter; // 机器人动作
|
||||||
payload: string; // 载荷,比如 '空料架' 或具体的物料ID
|
payload: DynamicParameter; // 载荷,比如 '空料架' 或具体的物料ID
|
||||||
locationBay?: string; // 库位 (可选)
|
locationBay?: DynamicParameter; // 库位 (可选)
|
||||||
|
[key: string]: DynamicParameter | undefined; // 支持扩展参数
|
||||||
}
|
}
|
||||||
|
|
||||||
// 核心任务对象
|
// 核心任务对象
|
||||||
|
Loading…
x
Reference in New Issue
Block a user