Compare commits
2 Commits
e18d0314e6
...
c03df200ab
Author | SHA1 | Date | |
---|---|---|---|
c03df200ab | |||
4ee7e9af54 |
@ -9,7 +9,9 @@
|
||||
"apiEndpoints": {
|
||||
"getTasks": "/api/vwed-task/list",
|
||||
"getTaskDetail": "/api/vwed-task/{taskId}",
|
||||
"runTask": "/api/vwed-task-edit/run"
|
||||
"runTask": "/api/vwed-task-edit/run",
|
||||
"getLocationList": "/api/vwed-operate-point/list",
|
||||
"batchUpdateLocation": "/api/vwed-operate-point/batch-status"
|
||||
},
|
||||
"taskApiEndpoints": {
|
||||
"getTaskList": "/task",
|
||||
|
16
gemini.md
Normal file
16
gemini.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Gemini Project: MyReactNativeApp
|
||||
|
||||
This is a React Native application built with TypeScript.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `src/`: Contains the main source code for the application.
|
||||
- `components/`: Reusable React components.
|
||||
- `context/`: React context for state management.
|
||||
- `hooks/`: Custom React hooks.
|
||||
- `navigation/`: Navigation logic using React Navigation.
|
||||
- `screens/`: Application screens.
|
||||
- `services/`: Services for API calls and other business logic.
|
||||
- `types/`: TypeScript type definitions.
|
||||
- `android/`: Android specific code.
|
||||
- `ios/`: iOS specific code.
|
2
index.js
2
index.js
@ -8,4 +8,6 @@ import { AppRegistry } from 'react-native';
|
||||
import App from './App';
|
||||
import { name as appName } from './app.json';
|
||||
|
||||
|
||||
|
||||
AppRegistry.registerComponent(appName, () => App);
|
||||
|
85
package-lock.json
generated
85
package-lock.json
generated
@ -19,6 +19,7 @@
|
||||
"axios": "^1.11.0",
|
||||
"react": "19.1.0",
|
||||
"react-native": "0.80.1",
|
||||
"react-native-elements": "^3.4.3",
|
||||
"react-native-gesture-handler": "^2.27.1",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-safe-area-context": "^5.5.2",
|
||||
@ -9203,6 +9204,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
|
||||
"deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
@ -10297,6 +10305,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/opencollective-postinstall": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
|
||||
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"opencollective-postinstall": "index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz",
|
||||
@ -10938,6 +10955,74 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-elements": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmmirror.com/react-native-elements/-/react-native-elements-3.4.3.tgz",
|
||||
"integrity": "sha512-VtZc25EecPZyUBER85zFK9ZbY6kkUdcm1ZwJ9hdoGSCr1R/GFgxor4jngOcSYeMvQ+qimd5No44OVJW3rSJECA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react-native-vector-icons": "^6.4.6",
|
||||
"color": "^3.1.2",
|
||||
"deepmerge": "^4.2.2",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"opencollective-postinstall": "^2.0.3",
|
||||
"react-native-ratings": "8.0.4",
|
||||
"react-native-size-matters": "^0.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react-native-safe-area-context": ">= 3.0.0",
|
||||
"react-native-vector-icons": ">7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-elements/node_modules/color": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
|
||||
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.3",
|
||||
"color-string": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-elements/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-elements/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-native-elements/node_modules/react-native-ratings": {
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/react-native-ratings/-/react-native-ratings-8.0.4.tgz",
|
||||
"integrity": "sha512-Xczu5lskIIRD6BEdz9A0jDRpEck/SFxRqiglkXi0u67yAtI1/pcJC76P4MukCbT8K4BPVl+42w83YqXBoBRl7A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-elements/node_modules/react-native-size-matters": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
|
||||
"integrity": "sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-gesture-handler": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmmirror.com/react-native-gesture-handler/-/react-native-gesture-handler-2.27.1.tgz",
|
||||
|
@ -21,6 +21,7 @@
|
||||
"axios": "^1.11.0",
|
||||
"react": "19.1.0",
|
||||
"react-native": "0.80.1",
|
||||
"react-native-elements": "^3.4.3",
|
||||
"react-native-gesture-handler": "^2.27.1",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-safe-area-context": "^5.5.2",
|
||||
|
@ -7,6 +7,7 @@ import TaskEditScreen from '../screens/TaskEditScreen';
|
||||
import RunScreen from '../screens/RunScreen';
|
||||
import EditScreen from '../screens/EditScreen';
|
||||
import SettingsScreen from '../screens/SettingsScreen';
|
||||
import LocationScreen from '../screens/LocationScreen';
|
||||
|
||||
const HomeStack = createStackNavigator();
|
||||
const Tab = createBottomTabNavigator();
|
||||
@ -74,7 +75,7 @@ export default function AppNavigator() {
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
<Tab.Screen name="任务列表" component={RunScreen} />
|
||||
<Tab.Screen name="编辑" component={EditScreen} />
|
||||
<Tab.Screen name="库位" component={LocationScreen} />
|
||||
<Tab.Screen name="设置" component={SettingsScreen} />
|
||||
</Tab.Navigator>
|
||||
);
|
||||
|
@ -1,18 +0,0 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
export default function EditScreen() {
|
||||
return (
|
||||
<View style={styles.screenContainer}>
|
||||
<Text>编辑!</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
screenContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
403
src/screens/LocationScreen.tsx
Normal file
403
src/screens/LocationScreen.tsx
Normal file
@ -0,0 +1,403 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
FlatList,
|
||||
Text,
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
RefreshControl,
|
||||
} from 'react-native';
|
||||
import { SearchBar, CheckBox, Button, Overlay, ListItem } from '@rneui/themed';
|
||||
import api from '../services/api';
|
||||
import { getConfig } from '../services/configService';
|
||||
|
||||
interface Location {
|
||||
id: string;
|
||||
layer_name: string;
|
||||
is_occupied: boolean;
|
||||
is_locked: boolean;
|
||||
is_empty_tray: boolean;
|
||||
is_disabled: boolean;
|
||||
}
|
||||
|
||||
const LocationScreen = () => {
|
||||
const [locations, setLocations] = useState<Location[]>([]);
|
||||
const [search, setSearch] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [selectedLocations, setSelectedLocations] = useState<string[]>([]);
|
||||
const [isOverlayVisible, setOverlayVisible] = useState(false);
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
|
||||
const fetchData = useCallback(async (query = '') => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const config = await getConfig();
|
||||
const endpoint =
|
||||
(config?.apiEndpoints as any)?.getLocationList ||
|
||||
'/api/vwed-operate-point/list';
|
||||
|
||||
const response = await api.get(endpoint, {
|
||||
params: { layer_name: query },
|
||||
});
|
||||
console.log('API Response:', response); // 调试日志
|
||||
// API 拦截器已经处理了响应,直接使用返回的数据
|
||||
const data = response as any;
|
||||
if (data && data.storage_locations) {
|
||||
setLocations(data.storage_locations);
|
||||
} else if (Array.isArray(data)) {
|
||||
setLocations(data);
|
||||
} else {
|
||||
console.warn('Unexpected response format:', data);
|
||||
setLocations([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Alert.alert('错误', '加载库位列表失败。');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
const handleSearch = () => {
|
||||
fetchData(search);
|
||||
};
|
||||
|
||||
const handleRefresh = useCallback(async () => {
|
||||
setIsRefreshing(true);
|
||||
try {
|
||||
await fetchData(search);
|
||||
} catch (error) {
|
||||
console.error('刷新失败:', error);
|
||||
} finally {
|
||||
setIsRefreshing(false);
|
||||
}
|
||||
}, [fetchData, search]);
|
||||
|
||||
const toggleSelection = (id: string) => {
|
||||
setSelectedLocations(prev =>
|
||||
prev.includes(id) ? prev.filter(item => item !== id) : [...prev, id],
|
||||
);
|
||||
};
|
||||
|
||||
const handleBatchUpdate = async (action: string) => {
|
||||
if (selectedLocations.length === 0) {
|
||||
Alert.alert('未选择', '请选择要操作的库位。');
|
||||
return;
|
||||
}
|
||||
setOverlayVisible(false);
|
||||
try {
|
||||
const config = await getConfig();
|
||||
const endpoint =
|
||||
(config?.apiEndpoints as any)?.batchUpdateLocation ||
|
||||
'/api/vwed-operate-point/batch-status';
|
||||
|
||||
const response = await api.put(endpoint, {
|
||||
layer_names: selectedLocations,
|
||||
action: action,
|
||||
});
|
||||
|
||||
console.log('Batch Update Response:', response); // 调试日志
|
||||
// API 拦截器已经处理了响应,直接使用返回的数据
|
||||
const { success_count, failed_count, results } = response as any;
|
||||
let message = `批量操作完成:\n成功 ${success_count} 个, 失败 ${failed_count} 个。\n\n`;
|
||||
if (failed_count > 0) {
|
||||
message += '失败详情:\n';
|
||||
results.forEach((res: any) => {
|
||||
if (!res.success) {
|
||||
message += `${res.layer_name}: ${res.message}\n`;
|
||||
}
|
||||
});
|
||||
}
|
||||
Alert.alert('操作结果', message);
|
||||
|
||||
fetchData(search);
|
||||
setSelectedLocations([]);
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
Alert.alert('错误', `批量操作失败: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const actions = [
|
||||
{ title: '禁用', action: 'disable' },
|
||||
{ title: '启用', action: 'enable' },
|
||||
{ title: '占用', action: 'occupy' },
|
||||
{ title: '释放', action: 'release' },
|
||||
{ title: '锁定', action: 'lock' },
|
||||
{ title: '解锁', action: 'unlock' },
|
||||
];
|
||||
|
||||
const renderItem = ({ item }: { item: Location }) => (
|
||||
<View style={styles.itemContainer}>
|
||||
<CheckBox
|
||||
checked={selectedLocations.includes(item.id)}
|
||||
onPress={() => toggleSelection(item.id)}
|
||||
containerStyle={styles.checkboxContainer}
|
||||
checkedColor="#4CAF50"
|
||||
uncheckedColor="#666"
|
||||
/>
|
||||
<Text style={styles.itemText}>{item.layer_name}</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.itemText,
|
||||
{ color: item.is_occupied ? '#F44336' : '#4CAF50' },
|
||||
]}
|
||||
>
|
||||
{item.is_occupied ? '是' : '否'}
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.itemText,
|
||||
{ color: item.is_locked ? '#F44336' : '#4CAF50' },
|
||||
]}
|
||||
>
|
||||
{item.is_locked ? '是' : '否'}
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.itemText,
|
||||
{ color: item.is_empty_tray ? '#FF9800' : '#4CAF50' },
|
||||
]}
|
||||
>
|
||||
{item.is_empty_tray ? '是' : '否'}
|
||||
</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.itemText,
|
||||
{ color: item.is_disabled ? '#F44336' : '#4CAF50' },
|
||||
]}
|
||||
>
|
||||
{item.is_disabled ? '是' : '否'}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View style={styles.loader}>
|
||||
<ActivityIndicator size="large" color="#4CAF50" />
|
||||
<Text style={styles.loadingText}>加载中...</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.searchContainer}>
|
||||
<SearchBar
|
||||
placeholder="搜索库位..."
|
||||
onChangeText={setSearch}
|
||||
value={search}
|
||||
containerStyle={styles.searchBarContainer}
|
||||
inputContainerStyle={styles.searchInputContainer}
|
||||
inputStyle={styles.searchInput}
|
||||
placeholderTextColor="#999"
|
||||
searchIcon={{ color: '#999' }}
|
||||
clearIcon={{ color: '#999' }}
|
||||
/>
|
||||
<Button
|
||||
title="搜索"
|
||||
onPress={handleSearch}
|
||||
buttonStyle={styles.searchButton}
|
||||
titleStyle={styles.searchButtonText}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Button
|
||||
title="批量操作"
|
||||
onPress={() => setOverlayVisible(true)}
|
||||
containerStyle={styles.batchButtonContainer}
|
||||
buttonStyle={styles.batchButton}
|
||||
titleStyle={styles.batchButtonText}
|
||||
/>
|
||||
|
||||
<Overlay
|
||||
isVisible={isOverlayVisible}
|
||||
onBackdropPress={() => setOverlayVisible(false)}
|
||||
overlayStyle={styles.overlay}
|
||||
>
|
||||
<View style={styles.overlayContainer}>
|
||||
<Text style={styles.overlayTitle}>选择操作</Text>
|
||||
{actions.map((item, index) => (
|
||||
<ListItem
|
||||
key={index}
|
||||
onPress={() => handleBatchUpdate(item.action)}
|
||||
bottomDivider
|
||||
containerStyle={styles.listItemContainer}
|
||||
>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title style={styles.listItemTitle}>
|
||||
{item.title}
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
))}
|
||||
</View>
|
||||
</Overlay>
|
||||
|
||||
<View style={styles.headerContainer}>
|
||||
<Text style={styles.headerText}>库位名称</Text>
|
||||
<Text style={styles.headerText}>是否占用</Text>
|
||||
<Text style={styles.headerText}>是否锁定</Text>
|
||||
<Text style={styles.headerText}>空托盘</Text>
|
||||
<Text style={styles.headerText}>是否禁用</Text>
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={locations}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={item => item.id}
|
||||
ItemSeparatorComponent={() => <View style={styles.separator} />}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isRefreshing}
|
||||
onRefresh={handleRefresh}
|
||||
colors={['#4CAF50']}
|
||||
tintColor="#4CAF50"
|
||||
title="下拉刷新"
|
||||
titleColor="#999"
|
||||
/>
|
||||
}
|
||||
showsVerticalScrollIndicator={false}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#1a1a1a',
|
||||
},
|
||||
loader: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#1a1a1a',
|
||||
},
|
||||
loadingText: {
|
||||
color: '#999',
|
||||
marginTop: 10,
|
||||
fontSize: 16,
|
||||
},
|
||||
searchContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#2a2a2a',
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 5,
|
||||
},
|
||||
searchBarContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: 'transparent',
|
||||
borderTopWidth: 0,
|
||||
borderBottomWidth: 0,
|
||||
paddingHorizontal: 0,
|
||||
},
|
||||
searchInputContainer: {
|
||||
backgroundColor: '#333',
|
||||
borderRadius: 8,
|
||||
},
|
||||
searchInput: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
},
|
||||
searchButton: {
|
||||
backgroundColor: '#4CAF50',
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 12,
|
||||
marginLeft: 10,
|
||||
},
|
||||
searchButtonText: {
|
||||
color: '#fff',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
batchButtonContainer: {
|
||||
margin: 15,
|
||||
},
|
||||
batchButton: {
|
||||
backgroundColor: '#2196F3',
|
||||
borderRadius: 8,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
batchButtonText: {
|
||||
color: '#fff',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
},
|
||||
overlay: {
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderRadius: 12,
|
||||
padding: 0,
|
||||
},
|
||||
overlayContainer: {
|
||||
minWidth: 250,
|
||||
paddingVertical: 10,
|
||||
},
|
||||
overlayTitle: {
|
||||
color: '#fff',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
paddingVertical: 15,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#444',
|
||||
},
|
||||
listItemContainer: {
|
||||
backgroundColor: 'transparent',
|
||||
paddingVertical: 15,
|
||||
paddingHorizontal: 20,
|
||||
borderBottomColor: '#444',
|
||||
},
|
||||
listItemTitle: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
color: '#fff',
|
||||
},
|
||||
itemContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 10,
|
||||
backgroundColor: '#2a2a2a',
|
||||
},
|
||||
checkboxContainer: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
padding: 0,
|
||||
marginLeft: 0,
|
||||
marginRight: 5,
|
||||
},
|
||||
itemText: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
fontSize: 14,
|
||||
color: '#fff',
|
||||
},
|
||||
headerContainer: {
|
||||
flexDirection: 'row',
|
||||
padding: 12,
|
||||
backgroundColor: '#333',
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: '#444',
|
||||
},
|
||||
headerText: {
|
||||
flex: 1,
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
color: '#fff',
|
||||
},
|
||||
separator: {
|
||||
height: 1,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
});
|
||||
|
||||
export default LocationScreen;
|
@ -24,6 +24,7 @@ export default function SettingsScreen() {
|
||||
const [settings, setSettings] = useState<AppSettings>({
|
||||
configFileName: '',
|
||||
serverUrl: '',
|
||||
taskServerUrl: '',
|
||||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [configStatus, setConfigStatus] = useState<string>('未加载');
|
||||
@ -251,14 +252,29 @@ export default function SettingsScreen() {
|
||||
<Text style={styles.sectionTitle}>服务器设置</Text>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>服务器地址:</Text>
|
||||
<Text style={styles.label}>库位管理服务器地址:</Text>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
value={settings.serverUrl}
|
||||
onChangeText={text =>
|
||||
setSettings(prev => ({ ...prev, serverUrl: text }))
|
||||
}
|
||||
placeholder="http://localhost:3000/api"
|
||||
placeholder="http://192.168.189.206:8000"
|
||||
placeholderTextColor="#999"
|
||||
autoCapitalize="none"
|
||||
keyboardType="url"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>任务管理服务器地址:</Text>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
value={settings.taskServerUrl}
|
||||
onChangeText={text =>
|
||||
setSettings(prev => ({ ...prev, taskServerUrl: text }))
|
||||
}
|
||||
placeholder="http://192.168.189.206:8080/jeecg-boot"
|
||||
placeholderTextColor="#999"
|
||||
autoCapitalize="none"
|
||||
keyboardType="url"
|
||||
@ -308,7 +324,7 @@ export default function SettingsScreen() {
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#f5f5f5',
|
||||
backgroundColor: '#1a1a1a',
|
||||
},
|
||||
content: {
|
||||
padding: 20,
|
||||
@ -318,10 +334,10 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
marginBottom: 30,
|
||||
color: '#333',
|
||||
color: '#fff',
|
||||
},
|
||||
section: {
|
||||
backgroundColor: 'white',
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderRadius: 10,
|
||||
padding: 20,
|
||||
marginBottom: 20,
|
||||
@ -330,7 +346,7 @@ const styles = StyleSheet.create({
|
||||
width: 0,
|
||||
height: 2,
|
||||
},
|
||||
shadowOpacity: 0.1,
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 3.84,
|
||||
elevation: 5,
|
||||
},
|
||||
@ -338,7 +354,7 @@ const styles = StyleSheet.create({
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 15,
|
||||
color: '#333',
|
||||
color: '#fff',
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: 15,
|
||||
@ -346,7 +362,7 @@ const styles = StyleSheet.create({
|
||||
label: {
|
||||
fontSize: 16,
|
||||
marginBottom: 8,
|
||||
color: '#333',
|
||||
color: '#fff',
|
||||
fontWeight: '500',
|
||||
},
|
||||
inputRow: {
|
||||
@ -356,16 +372,17 @@ const styles = StyleSheet.create({
|
||||
textInput: {
|
||||
flex: 1,
|
||||
borderWidth: 1,
|
||||
borderColor: '#ddd',
|
||||
borderColor: '#444',
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
fontSize: 16,
|
||||
backgroundColor: '#fafafa',
|
||||
backgroundColor: '#333',
|
||||
color: '#fff',
|
||||
},
|
||||
extension: {
|
||||
marginLeft: 8,
|
||||
fontSize: 16,
|
||||
color: '#666',
|
||||
color: '#999',
|
||||
fontWeight: '500',
|
||||
},
|
||||
statusRow: {
|
||||
@ -375,12 +392,12 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
statusLabel: {
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
color: '#fff',
|
||||
fontWeight: '500',
|
||||
},
|
||||
statusText: {
|
||||
fontSize: 16,
|
||||
color: '#007AFF',
|
||||
color: '#4CAF50',
|
||||
marginLeft: 8,
|
||||
},
|
||||
button: {
|
||||
@ -418,7 +435,7 @@ const styles = StyleSheet.create({
|
||||
marginTop: 10,
|
||||
},
|
||||
infoSection: {
|
||||
backgroundColor: 'white',
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderRadius: 10,
|
||||
padding: 20,
|
||||
marginBottom: 20,
|
||||
@ -427,12 +444,12 @@ const styles = StyleSheet.create({
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 15,
|
||||
color: '#333',
|
||||
color: '#fff',
|
||||
},
|
||||
infoText: {
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
color: '#666',
|
||||
color: '#999',
|
||||
marginBottom: 5,
|
||||
},
|
||||
loadingOverlay: {
|
||||
@ -441,7 +458,7 @@ const styles = StyleSheet.create({
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.8)',
|
||||
backgroundColor: 'rgba(26, 26, 26, 0.8)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 1,
|
||||
@ -449,7 +466,7 @@ const styles = StyleSheet.create({
|
||||
loadingText: {
|
||||
marginTop: 10,
|
||||
fontSize: 16,
|
||||
color: '#007AFF',
|
||||
color: '#4CAF50',
|
||||
},
|
||||
clearButton: {
|
||||
backgroundColor: '#FF3B30',
|
||||
|
@ -11,7 +11,18 @@ api.interceptors.request.use(
|
||||
async config => {
|
||||
const appConfig = await getConfig();
|
||||
const settings = await getSettings();
|
||||
const serverUrl = settings.serverUrl || appConfig?.serverUrl;
|
||||
|
||||
// 优先使用设置中的服务器地址,然后是配置文件中的地址
|
||||
let serverUrl = '';
|
||||
|
||||
// 根据请求的URL判断使用哪个服务器地址
|
||||
if (config.url?.includes('/task')) {
|
||||
// 任务管理相关的API使用taskServerUrl
|
||||
serverUrl = settings.taskServerUrl || appConfig?.taskServerUrl || '';
|
||||
} else {
|
||||
// 其他API使用普通的serverUrl(库位管理等)
|
||||
serverUrl = settings.serverUrl || appConfig?.serverUrl || '';
|
||||
}
|
||||
|
||||
if (!serverUrl) {
|
||||
const error = new Error('服务器地址未配置');
|
||||
|
@ -8,6 +8,7 @@ const CONFIG_CACHE_KEY = 'cached_config';
|
||||
const DEFAULT_SETTINGS: AppSettings = {
|
||||
configFileName: 'config.json',
|
||||
serverUrl: '',
|
||||
taskServerUrl: '',
|
||||
};
|
||||
|
||||
// 获取设置
|
||||
|
@ -28,4 +28,5 @@ export interface AppConfig {
|
||||
export interface AppSettings {
|
||||
configFileName: string;
|
||||
serverUrl: string;
|
||||
taskServerUrl?: string; // 任务管理服务器地址
|
||||
}
|
||||
|
1017
库位管理接口文档.md
Normal file
1017
库位管理接口文档.md
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user