From f9564796ab6c6232b79ed973cc2c221d032e2f2e Mon Sep 17 00:00:00 2001 From: xudan Date: Wed, 23 Jul 2025 15:05:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=BB=84=E4=BB=B6=E4=BB=A5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=89=A7=E8=A1=8C=E5=92=8C=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=8F=8D=E9=A6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.tsx | 13 ++- config.json | 2 +- src/components/BottomActionBar.tsx | 27 ++++++- src/navigation/AppNavigator.tsx | 6 +- src/screens/RunScreen.tsx | 14 +++- src/screens/TaskEditScreen.tsx | 85 +++++++++++++++---- src/services/taskService.ts | 126 +++++++++++++++++++++++++++++ src/types/task.ts | 30 +++++++ 8 files changed, 278 insertions(+), 25 deletions(-) create mode 100644 src/services/taskService.ts diff --git a/App.tsx b/App.tsx index 2d4a3a5..6a1916f 100644 --- a/App.tsx +++ b/App.tsx @@ -1,11 +1,22 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { NavigationContainer } from '@react-navigation/native'; import AppNavigator from './src/navigation/AppNavigator'; import { TasksProvider } from './src/context/TasksContext'; import { ThemeProvider } from '@rneui/themed'; +import { clearCachedConfig } from './src/services/configService'; export default function App() { + useEffect(() => { + const clearCacheOnStart = async () => { + console.log('正在清除缓存的配置文件...'); + await clearCachedConfig(); + console.log('缓存已清除,将使用最新的 config.json。'); + }; + + clearCacheOnStart(); + }, []); + return ( diff --git a/config.json b/config.json index da0e297..f13371c 100644 --- a/config.json +++ b/config.json @@ -40,6 +40,6 @@ "apiEndpoints": { "getTasks": "/api/vwed-task/list", "getTaskDetail": "/api/vwed-task/{taskId}", - "runTask": "/api/vwed-task/execute/{taskId}" + "runTask": "/api/vwed-task-edit/run" } } diff --git a/src/components/BottomActionBar.tsx b/src/components/BottomActionBar.tsx index 8cc9f4e..9113a72 100644 --- a/src/components/BottomActionBar.tsx +++ b/src/components/BottomActionBar.tsx @@ -1,5 +1,11 @@ import React from 'react'; -import { View, StyleSheet, TouchableOpacity, Text } from 'react-native'; +import { + View, + StyleSheet, + TouchableOpacity, + Text, + ActivityIndicator, +} from 'react-native'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; interface BottomActionBarProps { @@ -8,6 +14,7 @@ interface BottomActionBarProps { onUndo: () => void; onBack: () => void; isSaveDisabled?: boolean; + isRunLoading?: boolean; } const BottomActionBar: React.FC = ({ @@ -16,6 +23,7 @@ const BottomActionBar: React.FC = ({ onUndo, onBack, isSaveDisabled = true, + isRunLoading = false, }) => { return ( @@ -48,10 +56,21 @@ const BottomActionBar: React.FC = ({ - - 运行 + {isRunLoading ? ( + + ) : ( + <> + + 运行 + + )} ); diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index c87d635..2795401 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -51,8 +51,8 @@ export default function AppNavigator() { if (route.name === '主页') { iconName = 'home'; - } else if (route.name === '运行') { - iconName = 'play-arrow'; + } else if (route.name === '任务列表') { + iconName = 'view-list'; } else if (route.name === '编辑') { iconName = 'edit'; } else if (route.name === '设置') { @@ -73,7 +73,7 @@ export default function AppNavigator() { component={HomeStackNavigator} options={{ headerShown: false }} /> - + diff --git a/src/screens/RunScreen.tsx b/src/screens/RunScreen.tsx index 4a7dbda..f09d2b9 100644 --- a/src/screens/RunScreen.tsx +++ b/src/screens/RunScreen.tsx @@ -4,7 +4,8 @@ import { StyleSheet, Text, View } from 'react-native'; export default function RunScreen() { return ( - 运行! + 任务运行状态列表 + 此功能正在开发中... ); } @@ -14,5 +15,16 @@ const styles = StyleSheet.create({ flex: 1, justifyContent: 'center', alignItems: 'center', + backgroundColor: '#121212', + }, + text: { + fontSize: 22, + fontWeight: 'bold', + color: '#ffffff', + marginBottom: 10, + }, + subText: { + fontSize: 16, + color: '#b0b0b0', }, }); diff --git a/src/screens/TaskEditScreen.tsx b/src/screens/TaskEditScreen.tsx index 46ac44b..1bc3bb4 100644 --- a/src/screens/TaskEditScreen.tsx +++ b/src/screens/TaskEditScreen.tsx @@ -5,13 +5,15 @@ import { Alert, ScrollView, ActivityIndicator, + Text, } from 'react-native'; import { useRoute, useNavigation } from '@react-navigation/native'; import { RouteProp } from '@react-navigation/native'; import { useTasks } from '../context/TasksContext'; import TaskForm from '../components/TaskForm'; import BottomActionBar from '../components/BottomActionBar'; -import { Task } from '../types/task'; +import { Task, RunTaskRequest, RunTaskApiResponse } from '../types/task'; +import { runTask as runTaskService } from '../services/taskService'; type RootStackParamList = { TaskEdit: { taskId: string }; @@ -24,19 +26,21 @@ export default function TaskEditScreen() { const navigation = useNavigation(); const { taskId } = route.params; - const { getTaskById, updateTask, runTask, tasks, fetchTaskDetail } = - useTasks(); + const { getTaskById, updateTask, tasks, fetchTaskDetail } = useTasks(); const [task, setTask] = useState(null); const [originalTask, setOriginalTask] = useState(null); const [isModified, setIsModified] = useState(false); + const [isRunLoading, setIsRunLoading] = useState(false); + const [runResponse, setRunResponse] = useState( + null, + ); useEffect(() => { const loadTask = async () => { let taskData = getTaskById(taskId); if (taskData && !taskData.detail) { await fetchTaskDetail(taskId); - // Re-fetch task data after details are loaded taskData = getTaskById(taskId); } if (taskData) { @@ -63,10 +67,40 @@ export default function TaskEditScreen() { } }; - const handleRun = () => { - if (task) { - runTask(task.id); - navigation.goBack(); + const handleRun = async () => { + if (!task || !task.detail || !task.detail.inputParams) { + Alert.alert('错误', '任务数据不完整,无法运行。'); + return; + } + + setIsRunLoading(true); + setRunResponse(null); + + try { + const params = task.detail.inputParams.map(p => ({ + name: p.name, + type: p.type, + label: p.label, + required: p.required, + defaultValue: p.defaultValue, + remark: p.remark, + })); + + const request: RunTaskRequest = { + taskId: task.id, + params: params, + source_type: 1, + source_system: 'SYSTEM', + source_device: '666', + }; + + const result = await runTaskService(request); + setRunResponse(result); + Alert.alert('成功', `任务已启动, 记录ID: ${result.data.taskRecordId}`); + } catch (error: any) { + Alert.alert('运行失败', error.message || '发生未知错误'); + } finally { + setIsRunLoading(false); } }; @@ -75,11 +109,6 @@ export default function TaskEditScreen() { setIsModified(false); }; - const handleRestore = () => { - setTask(originalTask); - setIsModified(false); - }; - if (!task) { return ( @@ -92,14 +121,22 @@ export default function TaskEditScreen() { + {runResponse && ( + + 运行结果: + + {JSON.stringify(runResponse, null, 2)} + + + )} navigation.goBack()} isSaveDisabled={!isModified} + isRunLoading={isRunLoading} /> ); @@ -108,7 +145,7 @@ export default function TaskEditScreen() { const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: '#1a1a1a', // 深色背景 + backgroundColor: '#1a1a1a', }, loadingContainer: { flex: 1, @@ -118,5 +155,23 @@ const styles = StyleSheet.create({ }, scrollContainer: { padding: 16, + paddingBottom: 80, + }, + responseContainer: { + marginTop: 20, + padding: 15, + backgroundColor: '#2c2c2c', + borderRadius: 8, + }, + responseTitle: { + fontSize: 16, + fontWeight: 'bold', + color: '#ffffff', + marginBottom: 10, + }, + responseText: { + fontSize: 14, + color: '#e0e0e0', + fontFamily: 'monospace', }, }); diff --git a/src/services/taskService.ts b/src/services/taskService.ts new file mode 100644 index 0000000..2b68a11 --- /dev/null +++ b/src/services/taskService.ts @@ -0,0 +1,126 @@ +import { getSettings, getConfig } from './configService'; +import { RunTaskRequest, RunTaskApiResponse, Task } from '../types/task'; + +// 获取任务列表 +export const getTasks = async (): Promise => { + try { + const config = await getConfig(); + const endpoint = config?.apiEndpoints?.getTasks; + + if (!endpoint) { + throw new Error('获取任务列表的API端点未配置'); + } + + const settings = await getSettings(); + const serverUrl = settings.serverUrl || config?.serverUrl; + + if (!serverUrl) { + throw new Error('服务器地址未配置'); + } + + const url = `${serverUrl.replace(/\/$/, '')}${endpoint}`; + console.log('获取任务列表:', url); + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const result = await response.json(); + if (result.code !== 200) { + throw new Error(`API 错误: ${result.message}`); + } + + return result.data; + } catch (error) { + console.error('获取任务列表失败:', error); + throw error; + } +}; + +// 获取任务详情 +export const getTaskDetail = async (taskId: string): Promise => { + try { + const config = await getConfig(); + let endpoint = config?.apiEndpoints?.getTaskDetail; + + if (!endpoint) { + throw new Error('获取任务详情的API端点未配置'); + } + endpoint = endpoint.replace('{taskId}', taskId); + + const settings = await getSettings(); + const serverUrl = settings.serverUrl || config?.serverUrl; + + if (!serverUrl) { + throw new Error('服务器地址未配置'); + } + + const url = `${serverUrl.replace(/\/$/, '')}${endpoint}`; + console.log('获取任务详情:', url); + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const result = await response.json(); + if (result.code !== 200) { + throw new Error(`API 错误: ${result.message}`); + } + + return result.data; + } catch (error) { + console.error(`获取任务详情失败 (ID: ${taskId}):`, error); + throw error; + } +}; + +// 运行任务 +export const runTask = async ( + taskData: RunTaskRequest, +): Promise => { + try { + const config = await getConfig(); + const endpoint = config?.apiEndpoints?.runTask; + + if (!endpoint) { + throw new Error('运行任务的API端点未配置'); + } + + const settings = await getSettings(); + const serverUrl = settings.serverUrl || config?.serverUrl; + + if (!serverUrl) { + throw new Error('服务器地址未配置'); + } + + const url = `${serverUrl.replace(/\/$/, '')}${endpoint}`; + console.log('运行任务请求:', url, JSON.stringify(taskData, null, 2)); + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(taskData), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`HTTP ${response.status}: ${errorText}`); + } + + const result: RunTaskApiResponse = await response.json(); + console.log('运行任务响应:', result); + + if (result.code !== 200) { + throw new Error(`API 错误: ${result.message}`); + } + + return result; + } catch (error) { + console.error('运行任务失败:', error); + throw error; + } +}; diff --git a/src/types/task.ts b/src/types/task.ts index 0812c67..0f69267 100644 --- a/src/types/task.ts +++ b/src/types/task.ts @@ -63,3 +63,33 @@ export interface InputParam { max?: number; step?: number; } + +// 运行任务请求体 +export interface RunTaskRequest { + taskId: string; + params: Array<{ + name: string; + type: string; + label: string; + required: boolean; + defaultValue: string; + remark: string; + }>; + source_type: number; + source_system: string; + source_device: string; +} + +// 运行任务响应数据 +export interface RunTaskResponseData { + taskRecordId: string; + status: number; + createTime: string; +} + +// 运行任务API响应 +export interface RunTaskApiResponse { + code: number; + message: string; + data: RunTaskResponseData; +}