feat: 更新任务表单和任务列表组件以支持动态参数配置,添加axios依赖,修改服务器URL配置
This commit is contained in:
parent
98fe017f91
commit
6aff5dd0c8
@ -25,3 +25,5 @@ This is a React Native application for task management.
|
|||||||
- **Types**: TypeScript types, like the `Task` type, are defined in the `src/types` directory.
|
- **Types**: TypeScript types, like the `Task` type, are defined in the `src/types` directory.
|
||||||
|
|
||||||
The root component of the application is `App.tsx`, which sets up the `ThemeProvider`, `TasksProvider`, and `NavigationContainer`.
|
The root component of the application is `App.tsx`, which sets up the `ThemeProvider`, `TasksProvider`, and `NavigationContainer`.
|
||||||
|
|
||||||
|
# 请你检查 读取文件后,是否发送请求给 AI 大模型了
|
||||||
|
@ -705,5 +705,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"serverUrl": "http://localhost:3000/api"
|
"serverUrl": "http://192.168.189.206:8000"
|
||||||
}
|
}
|
||||||
|
95
package-lock.json
generated
95
package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"@react-navigation/stack": "^7.4.2",
|
"@react-navigation/stack": "^7.4.2",
|
||||||
"@rneui/base": "^4.0.0-rc.8",
|
"@rneui/base": "^4.0.0-rc.8",
|
||||||
"@rneui/themed": "^4.0.0-rc.8",
|
"@rneui/themed": "^4.0.0-rc.8",
|
||||||
|
"axios": "^1.10.0",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-native": "0.80.1",
|
"react-native": "0.80.1",
|
||||||
"react-native-gesture-handler": "^2.27.1",
|
"react-native-gesture-handler": "^2.27.1",
|
||||||
@ -4381,6 +4382,12 @@
|
|||||||
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
|
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/available-typed-arrays": {
|
"node_modules/available-typed-arrays": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
"resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||||
@ -4397,6 +4404,17 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/axios/-/axios-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-jest": {
|
"node_modules/babel-jest": {
|
||||||
"version": "29.7.0",
|
"version": "29.7.0",
|
||||||
"resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-29.7.0.tgz",
|
"resolved": "https://registry.npmmirror.com/babel-jest/-/babel-jest-29.7.0.tgz",
|
||||||
@ -4775,7 +4793,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
@ -5094,6 +5111,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/command-exists": {
|
"node_modules/command-exists": {
|
||||||
"version": "1.2.9",
|
"version": "1.2.9",
|
||||||
"resolved": "https://registry.npmmirror.com/command-exists/-/command-exists-1.2.9.tgz",
|
"resolved": "https://registry.npmmirror.com/command-exists/-/command-exists-1.2.9.tgz",
|
||||||
@ -5473,6 +5502,15 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
|
||||||
@ -5542,7 +5580,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.1",
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
@ -5721,7 +5758,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -5731,7 +5767,6 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -5769,7 +5804,6 @@
|
|||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0"
|
"es-errors": "^1.3.0"
|
||||||
@ -5782,7 +5816,6 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
@ -6717,6 +6750,26 @@
|
|||||||
"integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==",
|
"integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.9",
|
||||||
|
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||||
|
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/for-each": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz",
|
"resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz",
|
||||||
@ -6733,6 +6786,22 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"es-set-tostringtag": "^2.1.0",
|
||||||
|
"hasown": "^2.0.2",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fresh": {
|
"node_modules/fresh": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz",
|
"resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz",
|
||||||
@ -6781,7 +6850,6 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
@ -6840,7 +6908,6 @@
|
|||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.2",
|
"call-bind-apply-helpers": "^1.0.2",
|
||||||
@ -6874,7 +6941,6 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dunder-proto": "^1.0.1",
|
"dunder-proto": "^1.0.1",
|
||||||
@ -7029,7 +7095,6 @@
|
|||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -7106,7 +7171,6 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -7119,7 +7183,6 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3"
|
||||||
@ -7135,7 +7198,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
@ -9368,7 +9430,6 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
@ -10624,6 +10685,12 @@
|
|||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@react-navigation/stack": "^7.4.2",
|
"@react-navigation/stack": "^7.4.2",
|
||||||
"@rneui/base": "^4.0.0-rc.8",
|
"@rneui/base": "^4.0.0-rc.8",
|
||||||
"@rneui/themed": "^4.0.0-rc.8",
|
"@rneui/themed": "^4.0.0-rc.8",
|
||||||
|
"axios": "^1.10.0",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-native": "0.80.1",
|
"react-native": "0.80.1",
|
||||||
"react-native-gesture-handler": "^2.27.1",
|
"react-native-gesture-handler": "^2.27.1",
|
||||||
|
@ -1,41 +1,42 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, TouchableOpacity, Dimensions } 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 } from '../types/task';
|
||||||
|
|
||||||
interface TaskCardProps {
|
interface TaskCardProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
onPress: (task: Task) => void;
|
onPress: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusColors: Record<TaskStatus, string> = {
|
const statusMap: { [key: number]: { text: string; color: string } } = {
|
||||||
IDLE: 'grey',
|
0: { text: 'IDLE', color: 'grey' },
|
||||||
RUNNING: 'blue',
|
1: { text: 'RUNNING', color: 'blue' },
|
||||||
COMPLETED: 'green',
|
2: { text: 'COMPLETED', color: 'green' },
|
||||||
ERROR: 'red',
|
3: { text: 'ERROR', color: 'red' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const { width } = Dimensions.get('window');
|
const { width } = Dimensions.get('window');
|
||||||
const cardWidth = (width - 32) / 2; // 减去padding,除以2得到每个卡片的宽度
|
const cardWidth = (width - 32) / 2; // 减去padding,除以2得到每个卡片的宽度
|
||||||
|
|
||||||
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
||||||
|
const statusInfo = statusMap[task.status] || statusMap[0];
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={() => onPress(task)} style={styles.touchable}>
|
<TouchableOpacity onPress={() => onPress(task.id)} style={styles.touchable}>
|
||||||
<Card containerStyle={styles.card}>
|
<Card containerStyle={styles.card}>
|
||||||
<Card.Title style={styles.title}>{task.name}</Card.Title>
|
<Card.Title style={styles.title}>{task.label}</Card.Title>
|
||||||
<Card.Divider />
|
<Card.Divider />
|
||||||
<Chip
|
<Chip
|
||||||
title={task.status}
|
title={statusInfo.text}
|
||||||
icon={{
|
icon={{
|
||||||
name: 'information',
|
name: 'information',
|
||||||
type: 'material-community',
|
type: 'material-community',
|
||||||
size: 20,
|
size: 20,
|
||||||
color: statusColors[task.status],
|
color: statusInfo.color,
|
||||||
}}
|
}}
|
||||||
type="outline"
|
type="outline"
|
||||||
containerStyle={styles.chip}
|
containerStyle={styles.chip}
|
||||||
titleStyle={[styles.chipTitle, { color: statusColors[task.status] }]}
|
titleStyle={[styles.chipTitle, { color: statusInfo.color }]}
|
||||||
buttonStyle={{ borderColor: statusColors[task.status] }}
|
buttonStyle={{ borderColor: statusInfo.color }}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native';
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
ScrollView,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
} 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, InputParam } from '../types/task';
|
||||||
import { useTasks } from '../context/TasksContext';
|
import { useTasks } from '../context/TasksContext';
|
||||||
|
|
||||||
interface TaskFormProps {
|
interface TaskFormProps {
|
||||||
@ -16,151 +22,24 @@ const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
|||||||
const [currentItems, setCurrentItems] = useState<
|
const [currentItems, setCurrentItems] = useState<
|
||||||
{ label: string; value: string }[]
|
{ label: string; value: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
const [isQrInputFocused, setIsQrInputFocused] = useState(true);
|
|
||||||
|
|
||||||
// 创建隐藏的二维码扫描输入框的ref
|
|
||||||
const qrScanInputRef = useRef<any>(null);
|
|
||||||
|
|
||||||
// 用于防止循环更新的标志
|
|
||||||
const isUpdatingFromQrRef = useRef(false);
|
|
||||||
const isUpdatingFromFormRef = useRef(false);
|
|
||||||
|
|
||||||
// 组件挂载时自动聚焦到隐藏的扫描输入框
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = setTimeout(() => {
|
console.log('TaskForm task prop updated:', task);
|
||||||
if (qrScanInputRef.current) {
|
}, [task]);
|
||||||
qrScanInputRef.current.focus();
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 解析二维码信息对象字面量格式
|
|
||||||
const parseQrCodeInfo = (infoString: string): Partial<Task['parameters']> => {
|
|
||||||
const result: Partial<Task['parameters']> = {};
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 移除花括号和换行符,准备解析
|
|
||||||
let cleanString = infoString.trim();
|
|
||||||
if (cleanString.startsWith('{')) {
|
|
||||||
cleanString = cleanString.substring(1);
|
|
||||||
}
|
|
||||||
if (cleanString.endsWith('}')) {
|
|
||||||
cleanString = cleanString.substring(0, cleanString.length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按逗号分割各个属性
|
|
||||||
const items = cleanString.split(',');
|
|
||||||
|
|
||||||
for (const item of items) {
|
|
||||||
const trimmedItem = item.trim();
|
|
||||||
if (!trimmedItem) continue;
|
|
||||||
|
|
||||||
// 解析 "key: value" 格式
|
|
||||||
const colonIndex = trimmedItem.indexOf(':');
|
|
||||||
if (colonIndex === -1) continue;
|
|
||||||
|
|
||||||
const key = trimmedItem.substring(0, colonIndex).trim();
|
|
||||||
const value = trimmedItem.substring(colonIndex + 1).trim();
|
|
||||||
|
|
||||||
// 映射字段名
|
|
||||||
switch (key) {
|
|
||||||
case 'startLocation':
|
|
||||||
result.startLocation = value;
|
|
||||||
break;
|
|
||||||
case 'endLocation':
|
|
||||||
result.endLocation = value;
|
|
||||||
break;
|
|
||||||
case 'waypoint':
|
|
||||||
result.waypoint = value;
|
|
||||||
break;
|
|
||||||
case 'robotAction':
|
|
||||||
result.robotAction = value as RobotAction;
|
|
||||||
break;
|
|
||||||
case 'payload':
|
|
||||||
result.payload = value;
|
|
||||||
break;
|
|
||||||
case 'locationBay':
|
|
||||||
result.locationBay = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
// 解析失败时不报错,返回空对象
|
|
||||||
console.log('解析二维码信息失败:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理二维码扫描输入,更新表单字段
|
|
||||||
const handleQrCodeScan = (scanData: string) => {
|
|
||||||
if (isUpdatingFromFormRef.current || !scanData.trim()) return;
|
|
||||||
|
|
||||||
isUpdatingFromQrRef.current = true;
|
|
||||||
const parsedParams = parseQrCodeInfo(scanData);
|
|
||||||
|
|
||||||
const updatedTask = {
|
|
||||||
...task,
|
|
||||||
parameters: {
|
|
||||||
...task.parameters,
|
|
||||||
...parsedParams,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
onTaskChange(updatedTask);
|
|
||||||
|
|
||||||
// 清空扫描输入框
|
|
||||||
if (qrScanInputRef.current) {
|
|
||||||
qrScanInputRef.current.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置标志
|
|
||||||
setTimeout(() => {
|
|
||||||
isUpdatingFromQrRef.current = false;
|
|
||||||
}, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 重新扫描按钮点击处理
|
|
||||||
const handleRescan = () => {
|
|
||||||
if (qrScanInputRef.current) {
|
|
||||||
qrScanInputRef.current.focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理其他输入框获得焦点
|
|
||||||
const handleOtherInputFocus = () => {
|
|
||||||
setIsQrInputFocused(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理二维码输入框焦点事件
|
|
||||||
const handleQrInputFocus = () => {
|
|
||||||
setIsQrInputFocused(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleQrInputBlur = () => {
|
|
||||||
setIsQrInputFocused(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleParamChange = (field: string, value: string | RobotAction) => {
|
const handleParamChange = (field: string, value: string | RobotAction) => {
|
||||||
if (isUpdatingFromQrRef.current) return;
|
const currentParam = task.parameters[field] || {};
|
||||||
|
|
||||||
isUpdatingFromFormRef.current = true;
|
|
||||||
|
|
||||||
const updatedTask = {
|
const updatedTask = {
|
||||||
...task,
|
...task,
|
||||||
parameters: {
|
parameters: {
|
||||||
...task.parameters,
|
...task.parameters,
|
||||||
[field]: value,
|
[field]: {
|
||||||
|
...currentParam,
|
||||||
|
value: value,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
onTaskChange(updatedTask);
|
onTaskChange(updatedTask);
|
||||||
|
|
||||||
// 重置标志
|
|
||||||
setTimeout(() => {
|
|
||||||
isUpdatingFromFormRef.current = false;
|
|
||||||
}, 0);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const openBottomSheet = (
|
const openBottomSheet = (
|
||||||
@ -188,83 +67,48 @@ const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
|||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderFormInput = (param: InputParam) => {
|
||||||
|
const parameter = task.parameters?.[param.name];
|
||||||
|
const value = parameter?.value || param.defaultValue;
|
||||||
|
|
||||||
|
switch (param.type) {
|
||||||
|
case 'String':
|
||||||
|
case 'STRING': //
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
key={param.name}
|
||||||
|
label={param.label}
|
||||||
|
value={value as string}
|
||||||
|
onChangeText={text => handleParamChange(param.name, text)}
|
||||||
|
placeholder={param.remark}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
key={param.name}
|
||||||
|
label={param.label}
|
||||||
|
value={value as string}
|
||||||
|
onChangeText={text => handleParamChange(param.name, text)}
|
||||||
|
placeholder={param.remark}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView contentContainerStyle={styles.container}>
|
<ScrollView contentContainerStyle={styles.container}>
|
||||||
{/* 隐藏的二维码扫描输入框 */}
|
|
||||||
<Input
|
|
||||||
ref={qrScanInputRef}
|
|
||||||
style={styles.hiddenInput}
|
|
||||||
containerStyle={styles.hiddenContainer}
|
|
||||||
inputContainerStyle={styles.hiddenContainer}
|
|
||||||
onChangeText={handleQrCodeScan}
|
|
||||||
onFocus={handleQrInputFocus}
|
|
||||||
onBlur={handleQrInputBlur}
|
|
||||||
autoFocus={false}
|
|
||||||
showSoftInputOnFocus={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 扫描二维码按钮 */}
|
|
||||||
<View style={styles.scanButtonContainer}>
|
|
||||||
<Button
|
|
||||||
title={
|
|
||||||
isQrInputFocused ? '正在等待二维码扫描...' : '扫描二维码填充表单'
|
|
||||||
}
|
|
||||||
onPress={handleRescan}
|
|
||||||
icon={{
|
|
||||||
name: isQrInputFocused ? 'hourglass-empty' : 'qr-code-scanner',
|
|
||||||
type: 'material',
|
|
||||||
}}
|
|
||||||
buttonStyle={[
|
|
||||||
styles.scanButton,
|
|
||||||
isQrInputFocused && styles.waitingButton,
|
|
||||||
]}
|
|
||||||
disabled={isQrInputFocused}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
label="任务名称"
|
label="任务名称"
|
||||||
value={task.name}
|
value={task.name}
|
||||||
onChangeText={text => onTaskChange({ ...task, name: text })}
|
onChangeText={text => onTaskChange({ ...task, name: text })}
|
||||||
onFocus={handleOtherInputFocus}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{renderDropdown(
|
{task.detail && task.detail.inputParams ? (
|
||||||
'startLocation',
|
task.detail.inputParams.map(param => renderFormInput(param))
|
||||||
'起点',
|
) : (
|
||||||
task.parameters.startLocation,
|
<Text>正在加载任务参数... {task.detail}</Text>
|
||||||
locations,
|
|
||||||
)}
|
)}
|
||||||
{renderDropdown(
|
|
||||||
'endLocation',
|
|
||||||
'终点',
|
|
||||||
task.parameters.endLocation,
|
|
||||||
locations,
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Input
|
|
||||||
label="途经点 (可选)"
|
|
||||||
value={task.parameters.waypoint || ''}
|
|
||||||
onChangeText={text => handleParamChange('waypoint', text)}
|
|
||||||
onFocus={handleOtherInputFocus}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{renderDropdown(
|
|
||||||
'robotAction',
|
|
||||||
'机器人动作',
|
|
||||||
task.parameters.robotAction,
|
|
||||||
robotActions,
|
|
||||||
)}
|
|
||||||
{renderDropdown('payload', '载荷', task.parameters.payload, payloads)}
|
|
||||||
|
|
||||||
{/* 库位字段 */}
|
|
||||||
<Input
|
|
||||||
label="库位"
|
|
||||||
value={task.parameters.locationBay || ''}
|
|
||||||
onChangeText={text => handleParamChange('locationBay', text)}
|
|
||||||
placeholder="请输入库位"
|
|
||||||
onFocus={handleOtherInputFocus}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<BottomSheet
|
<BottomSheet
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
@ -294,25 +138,6 @@ const styles = StyleSheet.create({
|
|||||||
container: {
|
container: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
hiddenInput: {
|
|
||||||
height: 0,
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
hiddenContainer: {
|
|
||||||
height: 0,
|
|
||||||
margin: 0,
|
|
||||||
padding: 0,
|
|
||||||
},
|
|
||||||
scanButtonContainer: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
scanButton: {
|
|
||||||
backgroundColor: '#2196F3',
|
|
||||||
borderRadius: 8,
|
|
||||||
},
|
|
||||||
waitingButton: {
|
|
||||||
backgroundColor: '#9E9E9E', // 浅灰色,表示等待状态
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default TaskForm;
|
export default TaskForm;
|
||||||
|
@ -25,6 +25,7 @@ interface TasksContextData {
|
|||||||
locationsBays: LocationOption[];
|
locationsBays: LocationOption[];
|
||||||
payloads: PayloadOption[];
|
payloads: PayloadOption[];
|
||||||
robotActions: RobotActionOption[];
|
robotActions: RobotActionOption[];
|
||||||
|
serverUrl: string | null;
|
||||||
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;
|
||||||
@ -43,68 +44,102 @@ export const TasksProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
const [payloads, setPayloads] = useState<PayloadOption[]>([]);
|
const [payloads, setPayloads] = useState<PayloadOption[]>([]);
|
||||||
const [robotActions, setRobotActions] = useState<RobotActionOption[]>([]);
|
const [robotActions, setRobotActions] = useState<RobotActionOption[]>([]);
|
||||||
const [isConfigLoaded, setIsConfigLoaded] = useState(false);
|
const [isConfigLoaded, setIsConfigLoaded] = useState(false);
|
||||||
|
const [serverUrl, setServerUrl] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const fetchTasks = async (url: string) => {
|
||||||
|
try {
|
||||||
|
if (url) {
|
||||||
|
const fetchUrl = `${url}/api/vwed-task/list?pageNum=1&pageSize=100`;
|
||||||
|
console.log('Fetching tasks from:', fetchUrl);
|
||||||
|
const response = await fetch(fetchUrl);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseData = await response.json();
|
||||||
|
console.log('responseData', responseData);
|
||||||
|
|
||||||
|
if (responseData && responseData.code === 200) {
|
||||||
|
const fetchedTasks = responseData.data.list.map((task: any) => {
|
||||||
|
let detail = task.detail;
|
||||||
|
if (detail && typeof detail === 'string') {
|
||||||
|
try {
|
||||||
|
detail = JSON.parse(detail);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析任务详情失败 (list):', e);
|
||||||
|
detail = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...task,
|
||||||
|
name: task.label,
|
||||||
|
parameters: task.parameters || {}, // Ensure parameters object exists
|
||||||
|
detail: detail,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setTasks(fetchedTasks);
|
||||||
|
} else {
|
||||||
|
console.error('获取任务列表失败: responseData.code is not 200');
|
||||||
|
setTasks([]); //
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取任务列表失败:', error);
|
||||||
|
if (error instanceof Error) {
|
||||||
|
console.error('Error message:', error.message);
|
||||||
|
}
|
||||||
|
setTasks([]); //
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 组件初始化时加载配置
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadConfig = async () => {
|
const loadApp = async () => {
|
||||||
try {
|
try {
|
||||||
// 清除缓存以确保加载最新的配置
|
|
||||||
await clearCachedConfig();
|
await clearCachedConfig();
|
||||||
|
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
if (config) {
|
if (config) {
|
||||||
applyConfig(config);
|
applyConfig(config, false); // Don't load tasks from config
|
||||||
setIsConfigLoaded(true);
|
setIsConfigLoaded(true);
|
||||||
console.log('成功加载配置,任务数量:', config.tasks?.length || 0);
|
if (config.serverUrl) {
|
||||||
|
await fetchTasks(config.serverUrl);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('没有找到配置文件,使用空数据');
|
console.log('没有找到配置文件,使用空数据');
|
||||||
// 使用空数据而不是mock数据
|
|
||||||
applyConfig({
|
|
||||||
version: '0.0.0',
|
|
||||||
locations: [],
|
|
||||||
locationsBays: [],
|
|
||||||
payloads: [],
|
|
||||||
robotActions: [],
|
|
||||||
tasks: [],
|
|
||||||
});
|
|
||||||
setIsConfigLoaded(false);
|
setIsConfigLoaded(false);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载配置失败:', error);
|
console.error('加载配置失败:', error);
|
||||||
// 发生错误时也使用空数据
|
|
||||||
applyConfig({
|
|
||||||
version: '0.0.0',
|
|
||||||
locations: [],
|
|
||||||
locationsBays: [],
|
|
||||||
payloads: [],
|
|
||||||
robotActions: [],
|
|
||||||
tasks: [],
|
|
||||||
});
|
|
||||||
setIsConfigLoaded(false);
|
setIsConfigLoaded(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
loadConfig();
|
loadApp();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const applyConfig = (config: AppConfig) => {
|
const applyConfig = (config: AppConfig, loadTasks: boolean = true) => {
|
||||||
setTasks(config.tasks || []);
|
|
||||||
setLocations(config.locations || []);
|
setLocations(config.locations || []);
|
||||||
setLocationsBays(config.locationsBays || []);
|
setLocationsBays(config.locationsBays || []);
|
||||||
setPayloads(config.payloads || []);
|
setPayloads(config.payloads || []);
|
||||||
setRobotActions(config.robotActions || []);
|
setRobotActions(config.robotActions || []);
|
||||||
|
if (loadTasks && config.tasks) {
|
||||||
|
setTasks(config.tasks);
|
||||||
|
}
|
||||||
|
if (config.serverUrl) {
|
||||||
|
setServerUrl(config.serverUrl);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshConfig = async () => {
|
const refreshConfig = async () => {
|
||||||
try {
|
try {
|
||||||
// 刷新时也清除缓存
|
|
||||||
await clearCachedConfig();
|
await clearCachedConfig();
|
||||||
|
|
||||||
const config = await getConfig();
|
const config = await getConfig();
|
||||||
if (config) {
|
if (config) {
|
||||||
applyConfig(config);
|
applyConfig(config, false); // Don't load tasks from config
|
||||||
setIsConfigLoaded(true);
|
setIsConfigLoaded(true);
|
||||||
console.log('成功刷新配置,任务数量:', config.tasks?.length || 0);
|
if (config.serverUrl) {
|
||||||
|
await fetchTasks(config.serverUrl);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('刷新配置时没有找到配置文件');
|
console.log('刷新配置时没有找到配置文件');
|
||||||
setIsConfigLoaded(false);
|
setIsConfigLoaded(false);
|
||||||
@ -116,7 +151,51 @@ export const TasksProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getTaskById = (id: string) => {
|
const getTaskById = (id: string) => {
|
||||||
return tasks.find(task => task.id === id);
|
const task = tasks.find(task => task.id === id);
|
||||||
|
if (task && !task.detail) {
|
||||||
|
fetchTaskDetail(id);
|
||||||
|
}
|
||||||
|
return task;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchTaskDetail = async (taskId: string) => {
|
||||||
|
try {
|
||||||
|
if (serverUrl) {
|
||||||
|
const url = `${serverUrl}/api/vwed-task/${taskId}`;
|
||||||
|
console.log('Fetching task detail from:', url);
|
||||||
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const responseData = await response.json();
|
||||||
|
console.log('task detail responseData', responseData);
|
||||||
|
|
||||||
|
if (responseData && responseData.code === 200) {
|
||||||
|
let taskDetail = responseData.data.detail;
|
||||||
|
if (taskDetail && typeof taskDetail === 'string') {
|
||||||
|
try {
|
||||||
|
taskDetail = JSON.parse(taskDetail);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析任务详情失败 (detail):', e);
|
||||||
|
taskDetail = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTasks(prevTasks =>
|
||||||
|
prevTasks.map(task =>
|
||||||
|
task.id === taskId ? { ...task, detail: taskDetail } : task,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
'获取任务详情失败: responseData.code is not 200',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取任务详情失败:', error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTask = (updatedTask: Task) => {
|
const updateTask = (updatedTask: Task) => {
|
||||||
@ -127,34 +206,31 @@ export const TasksProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
|
|
||||||
const runTask = async (id: string) => {
|
const runTask = async (id: string) => {
|
||||||
const task = getTaskById(id);
|
const task = getTaskById(id);
|
||||||
if (!task) return;
|
if (!task || !serverUrl) return;
|
||||||
|
|
||||||
// 更新任务状态为运行中
|
// 更新任务状态为运行中
|
||||||
setTasks(prevTasks =>
|
setTasks(prevTasks =>
|
||||||
prevTasks.map(t => (t.id === id ? { ...t, status: 'RUNNING' } : t)),
|
prevTasks.map(t => (t.id === id ? { ...t, status: 1 } : t)),
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 获取服务器设置并发送任务执行请求
|
// 获取服务器设置并发送任务执行请求
|
||||||
const settings = await getSettings();
|
await executeTask(serverUrl, task.id, {
|
||||||
if (settings.serverUrl) {
|
name: task.name,
|
||||||
await executeTask(settings.serverUrl, task.id, {
|
parameters: task.parameters,
|
||||||
name: task.name,
|
});
|
||||||
parameters: task.parameters,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 模拟任务完成(实际项目中应该通过WebSocket或轮询获取任务状态)
|
// 模拟任务完成(实际项目中应该通过WebSocket或轮询获取任务状态)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setTasks(prevTasks =>
|
setTasks(prevTasks =>
|
||||||
prevTasks.map(t => (t.id === id ? { ...t, status: 'COMPLETED' } : t)),
|
prevTasks.map(t => (t.id === id ? { ...t, status: 2 } : t)),
|
||||||
);
|
);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('任务执行失败:', error);
|
console.error('任务执行失败:', error);
|
||||||
// 任务执行失败,更新状态为错误
|
// 任务执行失败,更新状态为错误
|
||||||
setTasks(prevTasks =>
|
setTasks(prevTasks =>
|
||||||
prevTasks.map(t => (t.id === id ? { ...t, status: 'ERROR' } : t)),
|
prevTasks.map(t => (t.id === id ? { ...t, status: 3 } : t)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -167,6 +243,7 @@ export const TasksProvider: React.FC<{ children: ReactNode }> = ({
|
|||||||
locationsBays,
|
locationsBays,
|
||||||
payloads,
|
payloads,
|
||||||
robotActions,
|
robotActions,
|
||||||
|
serverUrl,
|
||||||
getTaskById,
|
getTaskById,
|
||||||
updateTask,
|
updateTask,
|
||||||
runTask,
|
runTask,
|
||||||
|
@ -9,7 +9,7 @@ import { Task } from '../types/task';
|
|||||||
import { Dialog } from '@rneui/themed';
|
import { Dialog } from '@rneui/themed';
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
TaskEdit: { task: Task };
|
TaskEdit: { taskId: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
type TaskEditRouteProp = RouteProp<RootStackParamList, 'TaskEdit'>;
|
type TaskEditRouteProp = RouteProp<RootStackParamList, 'TaskEdit'>;
|
||||||
@ -17,20 +17,21 @@ type TaskEditRouteProp = RouteProp<RootStackParamList, 'TaskEdit'>;
|
|||||||
export default function TaskEditScreen() {
|
export default function TaskEditScreen() {
|
||||||
const route = useRoute<TaskEditRouteProp>();
|
const route = useRoute<TaskEditRouteProp>();
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { task: initialTask } = route.params;
|
const { taskId } = route.params;
|
||||||
|
|
||||||
const { updateTask, runTask } = useTasks();
|
const { getTaskById, updateTask, runTask } = useTasks();
|
||||||
|
|
||||||
const [task, setTask] = useState<Task | null>(initialTask);
|
const [task, setTask] = useState<Task | null>(null);
|
||||||
const [originalTask, setOriginalTask] = useState<Task | null>(initialTask);
|
const [originalTask, setOriginalTask] = useState<Task | null>(null);
|
||||||
const [isModified, setIsModified] = useState(false);
|
const [isModified, setIsModified] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialTask) {
|
const taskData = getTaskById(taskId);
|
||||||
setTask(initialTask);
|
if (taskData) {
|
||||||
setOriginalTask(initialTask);
|
setTask(taskData);
|
||||||
|
setOriginalTask(taskData);
|
||||||
}
|
}
|
||||||
}, [initialTask]);
|
}, [taskId, getTaskById]);
|
||||||
|
|
||||||
const handleTaskChange = (updatedTask: Task) => {
|
const handleTaskChange = (updatedTask: Task) => {
|
||||||
setTask(updatedTask);
|
setTask(updatedTask);
|
||||||
|
@ -4,11 +4,10 @@ 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: { taskId: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
type TaskListNavigationProp = StackNavigationProp<
|
type TaskListNavigationProp = StackNavigationProp<
|
||||||
@ -18,10 +17,12 @@ type TaskListNavigationProp = StackNavigationProp<
|
|||||||
|
|
||||||
export default function TaskListScreen() {
|
export default function TaskListScreen() {
|
||||||
const { tasks } = useTasks();
|
const { tasks } = useTasks();
|
||||||
|
console.log('tasks', tasks);
|
||||||
|
|
||||||
const navigation = useNavigation<TaskListNavigationProp>();
|
const navigation = useNavigation<TaskListNavigationProp>();
|
||||||
|
|
||||||
const handlePressTask = (task: Task) => {
|
const handlePressTask = (id: string) => {
|
||||||
navigation.navigate('TaskEdit', { task });
|
navigation.navigate('TaskEdit', { taskId: id });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -29,11 +30,7 @@ export default function TaskListScreen() {
|
|||||||
<ScrollView contentContainerStyle={styles.scrollContainer}>
|
<ScrollView contentContainerStyle={styles.scrollContainer}>
|
||||||
<View style={styles.tasksContainer}>
|
<View style={styles.tasksContainer}>
|
||||||
{tasks.map(task => (
|
{tasks.map(task => (
|
||||||
<TaskCard
|
<TaskCard key={task.id} task={task} onPress={handlePressTask} />
|
||||||
key={task.id}
|
|
||||||
task={task}
|
|
||||||
onPress={() => handlePressTask(task)}
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -7,7 +7,6 @@ const CONFIG_CACHE_KEY = 'cached_config';
|
|||||||
// 默认设置
|
// 默认设置
|
||||||
const DEFAULT_SETTINGS: AppSettings = {
|
const DEFAULT_SETTINGS: AppSettings = {
|
||||||
configFileName: 'config',
|
configFileName: 'config',
|
||||||
serverUrl: 'http://localhost:3000/api',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取设置
|
// 获取设置
|
||||||
|
@ -7,8 +7,6 @@ export type RobotAction =
|
|||||||
| 'CHARGE'
|
| 'CHARGE'
|
||||||
| 'CLEAN';
|
| 'CLEAN';
|
||||||
|
|
||||||
// 任务的状态
|
|
||||||
export type TaskStatus = 'IDLE' | 'RUNNING' | 'COMPLETED' | 'ERROR';
|
|
||||||
|
|
||||||
// 参数选项接口
|
// 参数选项接口
|
||||||
export interface ParameterOption {
|
export interface ParameterOption {
|
||||||
@ -43,7 +41,31 @@ export interface TaskParameters {
|
|||||||
export interface Task {
|
export interface Task {
|
||||||
id: string; // 唯一ID,例如使用 uuid
|
id: string; // 唯一ID,例如使用 uuid
|
||||||
name: string; // 任务名称, e.g., "炉前缓存区到热处理上料交接区运输"
|
name: string; // 任务名称, e.g., "炉前缓存区到热处理上料交接区运输"
|
||||||
status: TaskStatus; // 任务当前状态
|
label: string;
|
||||||
|
version: number;
|
||||||
|
templateName: string;
|
||||||
|
periodicTask: boolean;
|
||||||
|
ifEnable: number;
|
||||||
|
status: number; // 任务当前状态
|
||||||
|
createDate: string; // 创建时间
|
||||||
|
remark: string;
|
||||||
parameters: TaskParameters; // 任务的具体执行参数
|
parameters: TaskParameters; // 任务的具体执行参数
|
||||||
createdAt: string; // 创建时间
|
detail?: TaskDetail; // 任务详情
|
||||||
|
}
|
||||||
|
|
||||||
|
// 任务详情
|
||||||
|
export interface TaskDetail {
|
||||||
|
inputParams: InputParam[];
|
||||||
|
outputParams: any[]; // 根据需要定义
|
||||||
|
rootBlock: any; // 根据需要定义
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
export interface InputParam {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
label: string;
|
||||||
|
required: boolean;
|
||||||
|
defaultValue: string;
|
||||||
|
remark: string;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user