美化页面

This commit is contained in:
李宇奇 2025-07-04 16:51:39 +08:00
parent 342dba7ba0
commit c0a0eed3c0
8 changed files with 950 additions and 425 deletions

11
package-lock.json generated
View File

@ -19,6 +19,7 @@
"react": "18.3.1", "react": "18.3.1",
"react-native": "0.75.5", "react-native": "0.75.5",
"react-native-chart-kit": "^6.12.0", "react-native-chart-kit": "^6.12.0",
"react-native-linear-gradient": "^2.8.3",
"react-native-safe-area-context": "^5.5.1", "react-native-safe-area-context": "^5.5.1",
"react-native-screens": "^4.5.0", "react-native-screens": "^4.5.0",
"react-native-svg": "^15.12.0", "react-native-svg": "^15.12.0",
@ -13357,6 +13358,16 @@
"react-native": "*" "react-native": "*"
} }
}, },
"node_modules/react-native-linear-gradient": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
"integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==",
"license": "MIT",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-safe-area-context": { "node_modules/react-native-safe-area-context": {
"version": "5.5.1", "version": "5.5.1",
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.5.1.tgz", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.5.1.tgz",

View File

@ -21,6 +21,7 @@
"react": "18.3.1", "react": "18.3.1",
"react-native": "0.75.5", "react-native": "0.75.5",
"react-native-chart-kit": "^6.12.0", "react-native-chart-kit": "^6.12.0",
"react-native-linear-gradient": "^2.8.3",
"react-native-safe-area-context": "^5.5.1", "react-native-safe-area-context": "^5.5.1",
"react-native-screens": "^4.5.0", "react-native-screens": "^4.5.0",
"react-native-svg": "^15.12.0", "react-native-svg": "^15.12.0",

View File

@ -0,0 +1,73 @@
import React from 'react';
import {View, StyleSheet, Dimensions} from 'react-native';
import LinearGradient from 'react-native-linear-gradient';
import Svg, {Path} from 'react-native-svg';
const {width} = Dimensions.get('window');
interface WaveBackgroundProps {
height: number;
gradientColors: string[];
}
export const WaveBackground: React.FC<WaveBackgroundProps> = ({
height,
gradientColors,
}) => {
return (
<View style={[styles.container, {height}]}>
<LinearGradient colors={gradientColors} style={StyleSheet.absoluteFill}>
<View style={styles.waveContainer}>
<Svg height={60} width={width} style={styles.wave}>
<Path
d={`M0,20
C${width * 0.25},35
${width * 0.5},5
${width * 0.75},25
C${width * 0.875},35
${width},15
${width},20
L${width},0
L0,0 Z`}
fill="rgba(255, 255, 255, 0.3)"
/>
</Svg>
<Svg height={60} width={width} style={[styles.wave, styles.wave2]}>
<Path
d={`M0,15
C${width * 0.125},5
${width * 0.25},25
${width * 0.5},15
C${width * 0.75},5
${width},25
${width},15
L${width},0
L0,0 Z`}
fill="rgba(255, 255, 255, 0.2)"
/>
</Svg>
</View>
</LinearGradient>
</View>
);
};
const styles = StyleSheet.create({
container: {
width: '100%',
overflow: 'hidden',
},
waveContainer: {
position: 'absolute',
bottom: -1,
left: 0,
right: 0,
},
wave: {
backgroundColor: 'transparent',
},
wave2: {
position: 'absolute',
bottom: 15,
},
});

View File

@ -3,19 +3,41 @@
export const theme = { export const theme = {
colors: { colors: {
primary: '#05dcef', // 主题色 (0xff05dcef) // 基础颜色
background: '#ffffff', // 背景色 (0xffffffff) primary: '#4158D0', // 主色调
text: '#333333', // 文本颜色 (0xff333333) secondary: '#C850C0', // 次要色调
accent: '#03a9f4', // 强调色 (0xff03a9f4) tertiary: '#FFCC70', // 第三色调
background: '#ffffff', // 背景色
text: '#333333', // 文本颜色
textLight: '#666666', // 次要文本颜色
border: '#dddddd', // 边框颜色
error: '#ff3b30', // 错误颜色
success: '#4cd964', // 成功颜色
warning: '#ff9500', // 警告颜色
cyan: '#00FFFF', // 青色背景
// 派生的颜色 // 渐变色配置
primaryLight: '#66e5f3', // 主题色亮色版 gradients: {
primaryDark: '#04b0be', // 主题色暗色版 primary: ['#4158D0', '#C850C0', '#FFCC70'], // 主要渐变(蓝紫金)
textLight: '#666666', // 次要文本颜色 contrast: ['#00F5A0', '#00D9F5'], // 对比渐变(绿青)
border: '#dddddd', // 边框颜色 card: ['#9795F0', '#E3C3F1'], // 卡片渐变(柔和紫色)
error: '#ff3b30', // 错误颜色 login: ['#4158D0', '#C850C0', '#FFCC70'], // 登录页面专用渐变
success: '#4cd964', // 成功颜色 loginWave: ['rgba(255, 255, 255, 0.3)', 'rgba(255, 255, 255, 0.2)'], // 登录页面波浪渐变
warning: '#ff9500', // 警告颜色 header: ['#4158D0', '#C850C0'], // 头部渐变
button: ['#4158D0', '#C850C0'], // 按钮渐变
// 波浪背景渐变
wave: {
start: 'rgba(255, 255, 255, 0.3)',
middle: 'rgba(255, 255, 255, 0.2)',
end: 'rgba(255, 255, 255, 0.1)'
}
},
// 图表颜色
chart: {
blue: '#0077B6', // 深蓝色
orange: '#FB8500', // 明亮的橙色
},
}, },
// 字体大小 // 字体大小
@ -25,6 +47,8 @@ export const theme = {
medium: 16, medium: 16,
large: 18, large: 18,
xlarge: 20, xlarge: 20,
xxlarge: 24,
title: 32,
}, },
// 间距 // 间距
@ -41,7 +65,8 @@ export const theme = {
small: 4, small: 4,
medium: 8, medium: 8,
large: 12, large: 12,
round: 999, xl: 16,
circle: 999,
}, },
// 阴影 // 阴影
@ -77,6 +102,12 @@ export const theme = {
elevation: 6, elevation: 6,
}, },
}, },
// 波浪效果配置
wave: {
height: 60,
opacity: 1,
},
}; };
// 类型定义 // 类型定义

View File

@ -5,11 +5,19 @@ import {
StyleSheet, StyleSheet,
TouchableOpacity, TouchableOpacity,
InteractionManager, InteractionManager,
Image,
Dimensions,
} from 'react-native'; } from 'react-native';
import {useNavigation, useIsFocused} from '@react-navigation/native'; import {useNavigation, useIsFocused} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack'; import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {RootStackParamList} from '../../navigation/types'; import {RootStackParamList} from '../../navigation/types';
import {Screen} from '../../components/common/Screen'; import {Screen} from '../../components/common/Screen';
import {WaveBackground} from '../../components/common/WaveBackground';
import LinearGradient from 'react-native-linear-gradient';
import Svg, {Path, Defs, LinearGradient as SvgLinearGradient, Stop} from 'react-native-svg';
import {useTheme} from '../../contexts/ThemeContext';
const {width} = Dimensions.get('window');
type LoginScreenNavigationProp = NativeStackNavigationProp< type LoginScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList, RootStackParamList,
@ -19,6 +27,7 @@ type LoginScreenNavigationProp = NativeStackNavigationProp<
export const LoginScreen: React.FC = () => { export const LoginScreen: React.FC = () => {
const navigation = useNavigation<LoginScreenNavigationProp>(); const navigation = useNavigation<LoginScreenNavigationProp>();
const isFocused = useIsFocused(); const isFocused = useIsFocused();
const theme = useTheme();
const handleLogin = useCallback(() => { const handleLogin = useCallback(() => {
if (!isFocused) return; if (!isFocused) return;
@ -32,53 +41,219 @@ export const LoginScreen: React.FC = () => {
}, [navigation, isFocused]); }, [navigation, isFocused]);
return ( return (
<Screen> <Screen style={[styles.screen, {backgroundColor: theme.colors.background}]}>
{/* 头部导航栏 */} {/* 头部背景 */}
<View style={styles.header}> <View style={styles.headerContainer}>
<Text style={styles.headerTitle}></Text> <LinearGradient
colors={theme.colors.gradients.primary}
style={[StyleSheet.absoluteFill, styles.gradientBackground]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
{/* 半透明波浪效果 */}
<View style={styles.waveOverlay}>
<Svg height="100%" width={width} style={styles.waveSvg}>
<Path
d={`M0,50
C${width * 0.2},30
${width * 0.4},70
${width * 0.6},50
C${width * 0.8},30
${width},60
${width},50`}
fill="none"
stroke="rgba(255, 255, 255, 0.2)"
strokeWidth="2"
/>
<Path
d={`M0,70
C${width * 0.2},50
${width * 0.4},90
${width * 0.6},70
C${width * 0.8},50
${width},80
${width},70`}
fill="none"
stroke="rgba(255, 255, 255, 0.15)"
strokeWidth="2"
/>
</Svg>
</View>
</LinearGradient>
<View style={styles.headerContent}>
<Text style={[styles.headerTitle, { color: theme.colors.background }]}>
</Text>
<Text style={[styles.headerSubtitle, { color: theme.colors.background }]}>
</Text>
</View>
</View>
{/* 不规则曲线背景 */}
<View style={styles.curveContainer}>
<Svg height="120" width={width} style={styles.curve}>
<Defs>
<SvgLinearGradient id="contrastGradient" x1="0" y1="0" x2="1" y2="0">
<Stop offset="0" stopColor={theme.colors.gradients.contrast[0]} />
<Stop offset="1" stopColor={theme.colors.gradients.contrast[1]} />
</SvgLinearGradient>
</Defs>
<Path
d={`M0,120
L0,50
C${width * 0.3},20 ${width * 0.7},80 ${width},30
L${width},120
Z`}
fill="url(#contrastGradient)"
/>
</Svg>
</View> </View>
{/* 主体内容 */} {/* 主体内容 */}
<View style={styles.content}> <View style={[styles.contentWrapper]}>
{/* 登录按钮 */} <LinearGradient
<TouchableOpacity colors={theme.colors.gradients.contrast}
style={styles.loginButton} style={StyleSheet.absoluteFill}
onPress={handleLogin}> start={{x: 0, y: 0}}
<Text style={styles.loginButtonText}></Text> end={{x: 1, y: 0}}
</TouchableOpacity> />
<View style={styles.content}>
{/* Logo占位 */}
<View style={styles.logoContainer}>
<LinearGradient
colors={theme.colors.gradients.contrast}
style={[styles.logoCircle, theme.shadow.medium]}>
<Text style={[styles.logoText, {color: theme.colors.primary}]}>
JW
</Text>
</LinearGradient>
</View>
{/* 登录按钮 */}
<TouchableOpacity
style={[styles.loginButtonContainer, theme.shadow.medium]}
onPress={handleLogin}>
<LinearGradient
colors={theme.colors.gradients.primary}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
style={styles.loginButton}>
<Text style={[styles.loginButtonText, {color: theme.colors.background}]}>
</Text>
</LinearGradient>
</TouchableOpacity>
</View>
{/* 底部版权信息 */}
<View style={styles.footer}>
<Text style={[styles.footerText, {color: theme.colors.textLight}]}>
© 2024
</Text>
</View>
</View> </View>
</Screen> </Screen>
); );
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
header: { screen: {
height: 56, flex: 1,
justifyContent: 'center', },
headerContainer: {
height: 280,
position: 'relative',
overflow: 'hidden',
},
headerContent: {
position: 'absolute',
top: 60,
left: 0,
right: 0,
alignItems: 'center', alignItems: 'center',
backgroundColor: '#1890ff',
}, },
headerTitle: { headerTitle: {
color: '#fff', fontSize: 32,
fontWeight: 'bold',
textShadowColor: 'rgba(0, 0, 0, 0.2)',
textShadowOffset: {width: 1, height: 1},
textShadowRadius: 3,
},
headerSubtitle: {
fontSize: 18, fontSize: 18,
fontWeight: '600', marginTop: 8,
opacity: 0.9,
},
curveContainer: {
position: 'absolute',
top: 200,
left: 0,
right: 0,
zIndex: 1,
},
curve: {
position: 'absolute',
top: 0,
},
contentWrapper: {
flex: 1,
marginTop: 160,
}, },
content: { content: {
flex: 1, flex: 1,
alignItems: 'center', alignItems: 'center',
paddingTop: 15, paddingTop: 40,
},
logoContainer: {
marginBottom: 40,
},
logoCircle: {
width: 120,
height: 120,
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
},
logoText: {
fontSize: 40,
fontWeight: 'bold',
},
loginButtonContainer: {
width: width * 0.8,
maxWidth: 300,
height: 50,
borderRadius: 25,
overflow: 'hidden',
}, },
loginButton: { loginButton: {
backgroundColor: '#1890ff', width: '100%',
width: 250, height: '100%',
height: 44,
borderRadius: 4,
alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center',
}, },
loginButtonText: { loginButtonText: {
color: '#fff', fontSize: 18,
fontSize: 16,
fontWeight: '600', fontWeight: '600',
}, },
footer: {
padding: 20,
alignItems: 'center',
},
footerText: {
fontSize: 12,
},
gradientBackground: {
opacity: 0.95,
},
waveOverlay: {
position: 'absolute',
width: '100%',
height: '100%',
opacity: 0.6,
},
waveSvg: {
position: 'absolute',
top: 0,
},
}); });

View File

@ -14,6 +14,10 @@ import { RootStackParamList } from '../../navigation/types';
import { PieChart } from 'react-native-chart-kit'; import { PieChart } from 'react-native-chart-kit';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import { useTheme } from '../../contexts/ThemeContext'; import { useTheme } from '../../contexts/ThemeContext';
import LinearGradient from 'react-native-linear-gradient';
import Svg, { Path } from 'react-native-svg';
const { width } = Dimensions.get('window');
type HomeScreenNavigationProp = NativeStackNavigationProp< type HomeScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList, RootStackParamList,
@ -33,12 +37,14 @@ export const HomeScreen: React.FC = () => {
const [fontLoaded, setFontLoaded] = useState(false); const [fontLoaded, setFontLoaded] = useState(false);
useEffect(() => { useEffect(() => {
Icon.loadFont().then(() => { Icon.loadFont()
console.log('Icon fonts loaded'); .then(() => {
setFontLoaded(true); console.log('Icon fonts loaded');
}).catch(error => { setFontLoaded(true);
console.error('Failed to load icon fonts:', error); })
}); .catch(error => {
console.error('Failed to load icon fonts:', error);
});
}, []); }, []);
const menuItems: MenuItem[] = [ const menuItems: MenuItem[] = [
@ -50,16 +56,16 @@ export const HomeScreen: React.FC = () => {
{ {
name: '空闲', name: '空闲',
population: 40, population: 40,
color: theme.colors.success || '#4CAF50', color: theme.colors.chart.blue,
legendFontColor: theme.colors.textLight, legendFontColor: theme.colors.textLight,
legendFontSize: 15, legendFontSize: theme.fontSize.regular,
}, },
{ {
name: '占用', name: '占用',
population: 60, population: 60,
color: theme.colors.warning || '#FF9800', color: theme.colors.chart.orange,
legendFontColor: theme.colors.textLight, legendFontColor: theme.colors.textLight,
legendFontSize: 15, legendFontSize: theme.fontSize.regular,
}, },
]; ];
@ -69,94 +75,162 @@ export const HomeScreen: React.FC = () => {
color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`, color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
}; };
const screenWidth = Dimensions.get('window').width;
if (!fontLoaded) { if (!fontLoaded) {
return ( return (
<View style={[styles.loadingContainer, {backgroundColor: theme.colors.background}]}> <View style={[styles.loadingContainer, { backgroundColor: theme.colors.background }]}>
<Text style={{color: theme.colors.text}}>...</Text> <Text style={{ color: theme.colors.text }}>...</Text>
</View> </View>
); );
} }
return ( return (
<SafeAreaView style={[styles.container, {backgroundColor: theme.colors.background}]}> <SafeAreaView style={[styles.container, { backgroundColor: theme.colors.background }]}>
{/* 头部导航栏 */} {/* 头部区域 */}
<View style={[styles.header, {backgroundColor: theme.colors.primary}]}> <View style={styles.headerSection}>
<TouchableOpacity {/* 渐变背景 */}
onPress={() => setIsDrawerOpen(!isDrawerOpen)} <LinearGradient
style={styles.menuButton}> colors={theme.colors.gradients.primary}
<Icon name="menu" size={24} color={theme.colors.background} /> style={StyleSheet.absoluteFill}
</TouchableOpacity> start={{ x: 0, y: 0 }}
<Text style={[styles.headerTitle, {color: theme.colors.background}]}> end={{ x: 1, y: 1 }}
WMS移动终端 >
</Text> {/* 半透明波浪效果 */}
<View style={styles.headerRight}> <View style={styles.waveOverlay}>
<Svg height="100%" width={width} style={styles.waveSvg}>
<Path
d={`M0,50
C${width * 0.2},30
${width * 0.4},70
${width * 0.6},50
C${width * 0.8},30
${width},60
${width},50`}
fill="none"
stroke="rgba(255, 255, 255, 0.2)"
strokeWidth="2"
/>
<Path
d={`M0,70
C${width * 0.2},50
${width * 0.4},90
${width * 0.6},70
C${width * 0.8},50
${width},80
${width},70`}
fill="none"
stroke="rgba(255, 255, 255, 0.15)"
strokeWidth="2"
/>
</Svg>
</View>
</LinearGradient>
{/* 头部内容 */}
<View style={styles.headerContent}>
<TouchableOpacity
onPress={() => setIsDrawerOpen(!isDrawerOpen)}
style={styles.menuButton}>
<Icon name="menu" size={24} color={theme.colors.background} />
</TouchableOpacity>
<Text style={[styles.headerTitle, { color: theme.colors.background }]}>
WMS移动终端
</Text>
<TouchableOpacity style={styles.iconButton}> <TouchableOpacity style={styles.iconButton}>
<Icon name="notifications" size={24} color={theme.colors.background} /> <Icon name="notifications" size={24} color={theme.colors.background} />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>
{/* 主体内容 */}
<View style={styles.mainContent}>
<LinearGradient
colors={theme.colors.gradients.contrast}
style={StyleSheet.absoluteFill}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
/>
<ScrollView contentContainerStyle={styles.scrollContent}>
{/* 快捷操作区 */}
<View style={styles.quickActions}>
{menuItems.map((item, index) => (
<TouchableOpacity
key={index}
style={[styles.actionCard]}
onPress={() => navigation.navigate(item.route)}>
<LinearGradient
colors={theme.colors.gradients.card}
style={[StyleSheet.absoluteFill, {borderRadius: 12}]}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
/>
<LinearGradient
colors={theme.colors.gradients.primary}
style={styles.iconGradient}>
<Icon name={item.icon} size={32} color={theme.colors.background} />
</LinearGradient>
<Text style={[styles.actionTitle, {color: theme.colors.background}]}>
{item.title}
</Text>
</TouchableOpacity>
))}
</View>
{/* 图表区域 */}
<View style={styles.chartSection}>
<Text style={[styles.chartTitle, {color: theme.colors.background}]}>
</Text>
<View style={styles.chartContainer}>
<PieChart
data={stockData}
width={width - 48}
height={220}
chartConfig={chartConfig}
accessor="population"
backgroundColor="transparent"
paddingLeft="15"
absolute
/>
</View>
</View>
</ScrollView>
</View>
{/* 侧边菜单 */} {/* 侧边菜单 */}
{isDrawerOpen && ( {isDrawerOpen && (
<View style={[styles.drawer, {backgroundColor: theme.colors.background}]}> <>
<View style={[styles.drawerHeader, {backgroundColor: theme.colors.primary}]}> <View style={[styles.drawer, { backgroundColor: theme.colors.background }]}>
<Text style={[styles.drawerTitle, {color: theme.colors.background}]}> <LinearGradient
colors={theme.colors.gradients.primary}
</Text> style={styles.drawerHeader}>
<Text style={[styles.drawerSubtitle, {color: theme.colors.background}]}> <Text style={[styles.drawerTitle, { color: theme.colors.background }]}>
使WMS移动终端
</Text>
</View>
{menuItems.map((item, index) => (
<TouchableOpacity
key={index}
style={[styles.drawerItem, {borderBottomColor: theme.colors.border}]}
onPress={() => {
setIsDrawerOpen(false);
navigation.navigate(item.route);
}}>
<View style={styles.iconContainer}>
<Icon
name={item.icon}
size={28}
color={theme.colors.primary}
/>
</View>
<Text style={[styles.drawerItemText, {color: theme.colors.text}]}>
{item.title}
</Text> </Text>
</TouchableOpacity> <Text style={[styles.drawerSubtitle, { color: theme.colors.background }]}>
))} 使WMS移动终端
</View> </Text>
)} </LinearGradient>
{menuItems.map((item, index) => (
{/* 主体内容 */} <TouchableOpacity
<ScrollView style={[styles.content, {backgroundColor: theme.colors.background}]}> key={index}
<Text style={[styles.chartTitle, {color: theme.colors.text}]}> style={[styles.drawerItem, { borderBottomColor: theme.colors.border }]}
onPress={() => {
</Text> setIsDrawerOpen(false);
<View style={styles.chartContainer}> navigation.navigate(item.route);
<PieChart }}>
data={stockData} <View style={styles.drawerIconContainer}>
width={screenWidth - 40} <Icon name={item.icon} size={28} color={theme.colors.primary} />
height={220} </View>
chartConfig={chartConfig} <Text style={[styles.drawerItemText, { color: theme.colors.text }]}>
accessor="population" {item.title}
backgroundColor="transparent" </Text>
paddingLeft="15" </TouchableOpacity>
absolute ))}
</View>
<TouchableOpacity
style={styles.overlay}
onPress={() => setIsDrawerOpen(false)}
/> />
</View> </>
</ScrollView>
{/* 遮罩层 */}
{isDrawerOpen && (
<TouchableOpacity
style={styles.overlay}
onPress={() => setIsDrawerOpen(false)}
/>
)} )}
</SafeAreaView> </SafeAreaView>
); );
@ -166,45 +240,96 @@ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
}, },
mainContent: {
flex: 1,
position: 'relative',
},
scrollContent: {
flexGrow: 1,
paddingVertical: 20,
},
loadingContainer: { loadingContainer: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
}, },
header: { headerSection: {
height: 56, height: 160,
position: 'relative',
overflow: 'hidden',
},
waveOverlay: {
position: 'absolute',
width: '100%',
height: '100%',
opacity: 0.6,
},
waveSvg: {
position: 'absolute',
top: 0,
},
headerContent: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
paddingHorizontal: 16, paddingHorizontal: 16,
paddingTop: 16,
justifyContent: 'space-between', justifyContent: 'space-between',
height: 160,
}, },
menuButton: { menuButton: {
padding: 8, padding: 8,
}, },
headerTitle: { headerTitle: {
flex: 1,
fontSize: 18, fontSize: 18,
fontWeight: '600', fontWeight: '600',
textAlign: 'center', textAlign: 'center',
}, },
headerRight: {
width: 40,
flexDirection: 'row',
justifyContent: 'flex-end',
},
iconButton: { iconButton: {
padding: 8, padding: 8,
}, },
content: { content: {
flex: 1, flex: 1,
marginTop: -20,
},
quickActions: {
flexDirection: 'row',
justifyContent: 'space-around',
paddingHorizontal: 16,
marginTop: 20,
},
actionCard: {
width: width / 2 - 24,
borderRadius: 12,
padding: 20, padding: 20,
alignItems: 'center',
overflow: 'hidden',
},
iconGradient: {
width: 64,
height: 64,
borderRadius: 32,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 12,
},
actionTitle: {
fontSize: 16,
textAlign: 'center',
},
chartSection: {
borderRadius: 12,
margin: 16,
padding: 16,
overflow: 'hidden',
}, },
chartTitle: { chartTitle: {
fontSize: 16, fontSize: 18,
marginBottom: 10, fontWeight: '600',
marginBottom: 16,
}, },
chartContainer: { chartContainer: {
alignItems: 'center', alignItems: 'center',
marginTop: 20,
}, },
drawer: { drawer: {
position: 'absolute', position: 'absolute',
@ -227,6 +352,7 @@ const styles = StyleSheet.create({
}, },
drawerSubtitle: { drawerSubtitle: {
fontSize: 14, fontSize: 14,
opacity: 0.9,
}, },
drawerItem: { drawerItem: {
flexDirection: 'row', flexDirection: 'row',
@ -234,7 +360,7 @@ const styles = StyleSheet.create({
padding: 16, padding: 16,
borderBottomWidth: 1, borderBottomWidth: 1,
}, },
iconContainer: { drawerIconContainer: {
width: 32, width: 32,
height: 32, height: 32,
justifyContent: 'center', justifyContent: 'center',

View File

@ -15,6 +15,8 @@ import {useNavigation} from '@react-navigation/native';
import {RootStackParamList} from '../../navigation/types'; import {RootStackParamList} from '../../navigation/types';
import {useTheme} from '../../contexts/ThemeContext'; import {useTheme} from '../../contexts/ThemeContext';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import LinearGradient from 'react-native-linear-gradient';
import Svg, {Path} from 'react-native-svg';
interface StockInEmptyResponse { interface StockInEmptyResponse {
code: number; code: number;
@ -83,7 +85,11 @@ export const StockInEmpty: React.FC = () => {
return ( return (
<SafeAreaView style={[styles.container, {backgroundColor: theme.colors.background}]}> <SafeAreaView style={[styles.container, {backgroundColor: theme.colors.background}]}>
{/* 头部导航栏 */} {/* 头部导航栏 */}
<View style={[styles.header, {backgroundColor: theme.colors.primary}]}> <LinearGradient
colors={[theme.colors.primary, theme.colors.secondary, theme.colors.tertiary]}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
style={styles.header}>
<TouchableOpacity <TouchableOpacity
onPress={() => navigation.goBack()} onPress={() => navigation.goBack()}
style={styles.backButton}> style={styles.backButton}>
@ -91,12 +97,33 @@ export const StockInEmpty: React.FC = () => {
</TouchableOpacity> </TouchableOpacity>
<Text style={[styles.headerTitle, {color: theme.colors.background}]}></Text> <Text style={[styles.headerTitle, {color: theme.colors.background}]}></Text>
<View style={styles.headerRight} /> <View style={styles.headerRight} />
</LinearGradient>
{/* 波浪效果 */}
<View style={styles.waveContainer}>
<Svg
height="100%"
width="100%"
viewBox="0 0 1440 320"
style={styles.waveSvg}
preserveAspectRatio="none">
<Path
fill={`${theme.colors.tertiary}40`}
d="M0,96L48,112C96,128,192,160,288,186.7C384,213,480,235,576,213.3C672,192,768,128,864,128C960,128,1056,192,1152,213.3C1248,235,1344,213,1392,202.7L1440,192L1440,0L1392,0C1344,0,1248,0,1152,0C1056,0,960,0,864,0C768,0,672,0,576,0C480,0,384,0,288,0C192,0,96,0,48,0L0,0Z"
/>
</Svg>
</View> </View>
{/* 主体内容 */} {/* 主体内容 */}
<View style={styles.content}> <View style={styles.content}>
<LinearGradient
colors={theme.colors.gradients.contrast}
style={StyleSheet.absoluteFill}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
/>
{/* 说明文字 */} {/* 说明文字 */}
<View style={styles.infoSection}> <View style={[styles.infoSection, {backgroundColor: `${theme.colors.primary}15`}]}>
<Icon name="info-outline" size={24} color={theme.colors.primary} /> <Icon name="info-outline" size={24} color={theme.colors.primary} />
<Text style={[styles.infoText, {color: theme.colors.text}]}> <Text style={[styles.infoText, {color: theme.colors.text}]}>
@ -108,7 +135,10 @@ export const StockInEmpty: React.FC = () => {
<Text style={[styles.inputLabel, {color: theme.colors.text}]}> <Text style={[styles.inputLabel, {color: theme.colors.text}]}>
<Text style={styles.required}>*</Text> <Text style={styles.required}>*</Text>
</Text> </Text>
<View style={[styles.inputWrapper, {borderColor: theme.colors.border}]}> <View style={[styles.inputWrapper, {
borderColor: theme.colors.border,
backgroundColor: `${theme.colors.background}CC`,
}]}>
<Icon name="qr-code-scanner" size={24} color={theme.colors.primary} style={styles.inputIcon} /> <Icon name="qr-code-scanner" size={24} color={theme.colors.primary} style={styles.inputIcon} />
<TextInput <TextInput
style={[styles.input, {color: theme.colors.text}]} style={[styles.input, {color: theme.colors.text}]}
@ -129,25 +159,27 @@ export const StockInEmpty: React.FC = () => {
</View> </View>
{/* 提交按钮 */} {/* 提交按钮 */}
<TouchableOpacity <LinearGradient
style={[ colors={[theme.colors.primary, theme.colors.secondary]}
styles.submitButton, start={{x: 0, y: 0}}
{backgroundColor: theme.colors.primary}, end={{x: 1, y: 0}}
loading && styles.submitButtonDisabled, style={[styles.submitButton, loading && styles.submitButtonDisabled]}>
]} <TouchableOpacity
onPress={handleEmptyIn} style={styles.submitButtonContent}
disabled={loading}> onPress={handleEmptyIn}
{loading ? ( disabled={loading}>
<ActivityIndicator color={theme.colors.background} /> {loading ? (
) : ( <ActivityIndicator color={theme.colors.background} />
<> ) : (
<Icon name="save" size={24} color={theme.colors.background} style={styles.submitIcon} /> <>
<Text style={[styles.submitButtonText, {color: theme.colors.background}]}> <Icon name="save" size={24} color={theme.colors.background} style={styles.submitIcon} />
<Text style={[styles.submitButtonText, {color: theme.colors.background}]}>
</Text>
</> </Text>
)} </>
</TouchableOpacity> )}
</TouchableOpacity>
</LinearGradient>
</View> </View>
</SafeAreaView> </SafeAreaView>
); );
@ -169,6 +201,19 @@ const styles = StyleSheet.create({
shadowOpacity: 0.2, shadowOpacity: 0.2,
shadowRadius: 2, shadowRadius: 2,
}, },
waveContainer: {
height: 100,
backgroundColor: 'transparent',
position: 'absolute',
top: 56,
left: 0,
right: 0,
zIndex: -1,
},
waveSvg: {
position: 'absolute',
top: 0,
},
backButton: { backButton: {
padding: 8, padding: 8,
}, },
@ -186,7 +231,6 @@ const styles = StyleSheet.create({
infoSection: { infoSection: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
backgroundColor: 'rgba(24, 144, 255, 0.1)',
padding: 16, padding: 16,
borderRadius: 8, borderRadius: 8,
marginBottom: 24, marginBottom: 24,
@ -214,7 +258,6 @@ const styles = StyleSheet.create({
borderRadius: 8, borderRadius: 8,
height: 48, height: 48,
paddingHorizontal: 12, paddingHorizontal: 12,
backgroundColor: 'rgba(255, 255, 255, 0.8)',
}, },
inputIcon: { inputIcon: {
marginRight: 8, marginRight: 8,
@ -231,9 +274,6 @@ const styles = StyleSheet.create({
submitButton: { submitButton: {
height: 48, height: 48,
borderRadius: 24, borderRadius: 24,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
marginTop: 32, marginTop: 32,
elevation: 2, elevation: 2,
shadowColor: '#000', shadowColor: '#000',
@ -241,6 +281,12 @@ const styles = StyleSheet.create({
shadowOpacity: 0.1, shadowOpacity: 0.1,
shadowRadius: 2, shadowRadius: 2,
}, },
submitButtonContent: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
submitButtonDisabled: { submitButtonDisabled: {
opacity: 0.6, opacity: 0.6,
}, },

View File

@ -12,6 +12,8 @@ import {
import {useNavigation} from '@react-navigation/native'; import {useNavigation} from '@react-navigation/native';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import {useTheme} from '../../contexts/ThemeContext'; import {useTheme} from '../../contexts/ThemeContext';
import LinearGradient from 'react-native-linear-gradient';
import Svg, {Path} from 'react-native-svg';
interface PackageDataItem { interface PackageDataItem {
id: string; id: string;
@ -236,7 +238,11 @@ const StockInWheelManual: React.FC = () => {
return ( return (
<View style={[styles.container, {backgroundColor: theme.colors.background}]}> <View style={[styles.container, {backgroundColor: theme.colors.background}]}>
{/* 头部导航栏 */} {/* 头部导航栏 */}
<View style={[styles.header, {backgroundColor: theme.colors.primary}]}> <LinearGradient
colors={[theme.colors.primary, theme.colors.secondary, theme.colors.tertiary]}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
style={styles.header}>
<TouchableOpacity <TouchableOpacity
style={styles.backButton} style={styles.backButton}
onPress={() => navigation.goBack()}> onPress={() => navigation.goBack()}>
@ -246,285 +252,326 @@ const StockInWheelManual: React.FC = () => {
</Text> </Text>
<View style={styles.headerRight} /> <View style={styles.headerRight} />
</LinearGradient>
{/* 波浪效果 */}
<View style={styles.waveContainer}>
<Svg
height="100%"
width="100%"
viewBox="0 0 1440 320"
style={styles.waveSvg}
preserveAspectRatio="none">
<Path
fill={`${theme.colors.tertiary}40`}
d="M0,96L48,112C96,128,192,160,288,186.7C384,213,480,235,576,213.3C672,192,768,128,864,128C960,128,1056,192,1152,213.3C1248,235,1344,213,1392,202.7L1440,192L1440,0L1392,0C1344,0,1248,0,1152,0C1056,0,960,0,864,0C768,0,672,0,576,0C480,0,384,0,288,0C192,0,96,0,48,0L0,0Z"
/>
</Svg>
</View> </View>
<ScrollView style={[styles.content, {backgroundColor: theme.colors.background}]}> <View style={styles.mainContent}>
{/* 信息提示区 */} <LinearGradient
<View style={[styles.infoSection, {backgroundColor: `${theme.colors.primary}15`}]}> colors={theme.colors.gradients.contrast}
<Icon name="info-outline" size={24} color={theme.colors.primary} /> style={StyleSheet.absoluteFill}
<Text style={[styles.infoText, {color: theme.colors.text}]}> start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
</Text> />
</View> <ScrollView contentContainerStyle={styles.scrollContent}>
{/* 信息提示区 */}
{/* 载具号输入区 */} <View style={[styles.infoSection, {backgroundColor: `${theme.colors.primary}15`}]}>
<View style={styles.inputContainer}> <Icon name="info-outline" size={24} color={theme.colors.primary} />
<Text style={[styles.label, {color: theme.colors.text}]}></Text> <Text style={[styles.infoText, {color: theme.colors.text}]}>
<View style={[styles.inputWrapper, {borderColor: theme.colors.border}]}>
<Icon name="qr-code-scanner" size={24} color={theme.colors.primary} style={styles.inputIcon} /> </Text>
<TextInput
ref={vehicleInputRef}
style={[styles.input, {color: theme.colors.text}]}
value={vehicleCode}
onChangeText={setVehicleCode}
placeholder="请扫描或输入载具号"
placeholderTextColor={theme.colors.textLight}
/>
{vehicleCode.length > 0 && (
<TouchableOpacity
onPress={() => setVehicleCode('')}
style={styles.clearButton}>
<Icon name="cancel" size={20} color={theme.colors.textLight} />
</TouchableOpacity>
)}
</View> </View>
</View>
{/* 条码输入区 */} {/* 载具号输入区 */}
<View style={styles.inputContainer}> <View style={styles.inputContainer}>
<Text style={[styles.label, {color: theme.colors.text}]}></Text> <Text style={[styles.label, {color: theme.colors.text}]}></Text>
<View style={[styles.inputWrapper, {borderColor: theme.colors.border}]}> <View style={[styles.inputWrapper, {
<Icon name="qr-code-2" size={24} color={theme.colors.primary} style={styles.inputIcon} /> borderColor: theme.colors.border,
<TextInput backgroundColor: `${theme.colors.background}CC`,
ref={goodsInputRef} }]}>
style={[styles.input, {color: theme.colors.text}]} <Icon name="qr-code-scanner" size={24} color={theme.colors.primary} style={styles.inputIcon} />
value={goodsCode} <TextInput
onChangeText={setGoodsCode} ref={vehicleInputRef}
placeholder="请扫描物料二维码" style={[styles.input, {color: theme.colors.text}]}
placeholderTextColor={theme.colors.textLight} value={vehicleCode}
/> onChangeText={setVehicleCode}
{goodsCode.length > 0 && ( placeholder="请扫描或输入载具号"
<TouchableOpacity placeholderTextColor={theme.colors.textLight}
onPress={() => setGoodsCode('')} />
style={styles.clearButton}> {vehicleCode.length > 0 && (
<Icon name="cancel" size={20} color={theme.colors.textLight} /> <TouchableOpacity
</TouchableOpacity> onPress={() => setVehicleCode('')}
)} style={styles.clearButton}>
</View> <Icon name="cancel" size={20} color={theme.colors.textLight} />
</View> </TouchableOpacity>
)}
{/* 选项区域 */}
<View style={styles.optionsContainer}>
{/* 区域选择 */}
<View style={styles.optionGroup}>
<Text style={[styles.optionLabel, {color: theme.colors.text}]}></Text>
<View style={styles.radioGroup}>
<TouchableOpacity
style={[
styles.radioButton,
{borderColor: theme.colors.border},
areaID === '有卤' && styles.radioButtonActive,
areaID === '有卤' && {backgroundColor: theme.colors.primary},
]}
onPress={() => setAreaID('有卤')}>
<Text
style={[
styles.radioText,
{color: theme.colors.text},
areaID === '有卤' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.radioButton,
{borderColor: theme.colors.border},
areaID === '无卤' && styles.radioButtonActive,
areaID === '无卤' && {backgroundColor: theme.colors.primary},
]}
onPress={() => setAreaID('无卤')}>
<Text
style={[
styles.radioText,
{color: theme.colors.text},
areaID === '无卤' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
</View> </View>
</View> </View>
{/* 工厂选择 */} {/* 条码输入区 */}
<View style={styles.optionGroup}> <View style={styles.inputContainer}>
<Text style={[styles.optionLabel, {color: theme.colors.text}]}></Text> <Text style={[styles.label, {color: theme.colors.text}]}></Text>
<View style={styles.radioGroup}> <View style={[styles.inputWrapper, {
<TouchableOpacity borderColor: theme.colors.border,
style={[ backgroundColor: `${theme.colors.background}CC`,
styles.radioButton, }]}>
{borderColor: theme.colors.border}, <Icon name="qr-code-2" size={24} color={theme.colors.primary} style={styles.inputIcon} />
factory === '二厂' && styles.radioButtonActive, <TextInput
factory === '二厂' && {backgroundColor: theme.colors.primary}, ref={goodsInputRef}
]} style={[styles.input, {color: theme.colors.text}]}
onPress={() => setFactory('二厂')}> value={goodsCode}
<Text onChangeText={setGoodsCode}
style={[ placeholder="请扫描物料二维码"
styles.radioText, placeholderTextColor={theme.colors.textLight}
{color: theme.colors.text}, />
factory === '二厂' && {color: theme.colors.background}, {goodsCode.length > 0 && (
]}> <TouchableOpacity
onPress={() => setGoodsCode('')}
</Text> style={styles.clearButton}>
</TouchableOpacity> <Icon name="cancel" size={20} color={theme.colors.textLight} />
<TouchableOpacity </TouchableOpacity>
style={[ )}
styles.radioButton,
{borderColor: theme.colors.border},
factory === '三厂' && styles.radioButtonActive,
factory === '三厂' && {backgroundColor: theme.colors.primary},
]}
onPress={() => setFactory('三厂')}>
<Text
style={[
styles.radioText,
{color: theme.colors.text},
factory === '三厂' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
</View> </View>
</View> </View>
{/* 状态选择 - 改为与区域、工厂相同的样式 */} {/* 选项区域 */}
<View style={styles.optionGroup}> <View style={styles.optionsContainer}>
<Text style={[styles.optionLabel, {color: theme.colors.text}]}></Text> {/* 区域选择 */}
<View style={styles.radioGroup}> <View style={styles.optionGroup}>
<ScrollView horizontal showsHorizontalScrollIndicator={false}> <Text style={[styles.optionLabel, {color: theme.colors.text}]}></Text>
<View style={styles.radioGroup}> <View style={styles.radioGroup}>
{['合格', '不合格', '封存', '待检', '进口物料'].map((item) => ( <TouchableOpacity
<TouchableOpacity style={[
key={item} styles.radioButton,
style={[ {borderColor: theme.colors.border},
styles.radioButton, areaID === '有卤' && styles.radioButtonActive,
{borderColor: theme.colors.border}, areaID === '有卤' && {backgroundColor: theme.colors.primary},
status === item && styles.radioButtonActive, ]}
status === item && {backgroundColor: theme.colors.primary}, onPress={() => setAreaID('有卤')}>
]} <Text
onPress={() => setStatus(item)}> style={[
<Text styles.radioText,
{color: theme.colors.text},
areaID === '有卤' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.radioButton,
{borderColor: theme.colors.border},
areaID === '无卤' && styles.radioButtonActive,
areaID === '无卤' && {backgroundColor: theme.colors.primary},
]}
onPress={() => setAreaID('无卤')}>
<Text
style={[
styles.radioText,
{color: theme.colors.text},
areaID === '无卤' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
</View>
</View>
{/* 工厂选择 */}
<View style={styles.optionGroup}>
<Text style={[styles.optionLabel, {color: theme.colors.text}]}></Text>
<View style={styles.radioGroup}>
<TouchableOpacity
style={[
styles.radioButton,
{borderColor: theme.colors.border},
factory === '二厂' && styles.radioButtonActive,
factory === '二厂' && {backgroundColor: theme.colors.primary},
]}
onPress={() => setFactory('二厂')}>
<Text
style={[
styles.radioText,
{color: theme.colors.text},
factory === '二厂' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.radioButton,
{borderColor: theme.colors.border},
factory === '三厂' && styles.radioButtonActive,
factory === '三厂' && {backgroundColor: theme.colors.primary},
]}
onPress={() => setFactory('三厂')}>
<Text
style={[
styles.radioText,
{color: theme.colors.text},
factory === '三厂' && {color: theme.colors.background},
]}>
</Text>
</TouchableOpacity>
</View>
</View>
{/* 状态选择 - 改为与区域、工厂相同的样式 */}
<View style={styles.optionGroup}>
<Text style={[styles.optionLabel, {color: theme.colors.text}]}></Text>
<View style={styles.radioGroup}>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
<View style={styles.radioGroup}>
{['合格', '不合格', '封存', '待检', '进口物料'].map((item) => (
<TouchableOpacity
key={item}
style={[ style={[
styles.radioText, styles.radioButton,
{color: theme.colors.text}, {borderColor: theme.colors.border},
status === item && {color: theme.colors.background}, status === item && styles.radioButtonActive,
]}> status === item && {backgroundColor: theme.colors.primary},
{item} ]}
</Text> onPress={() => setStatus(item)}>
</TouchableOpacity> <Text
))} style={[
</View> styles.radioText,
</ScrollView> {color: theme.colors.text},
status === item && {color: theme.colors.background},
]}>
{item}
</Text>
</TouchableOpacity>
))}
</View>
</ScrollView>
</View>
</View> </View>
</View> </View>
</View>
{/* 操作按钮区 */} {/* 操作按钮区 */}
<View style={styles.buttonGroup}> <View style={styles.buttonGroup}>
<TouchableOpacity <LinearGradient
style={[styles.button, styles.addButton, {backgroundColor: theme.colors.primary}]} colors={[theme.colors.primary, theme.colors.secondary]}
onPress={resolveCode}> start={{x: 0, y: 0}}
<Icon name="add-circle-outline" size={24} color={theme.colors.background} style={styles.buttonIcon} /> end={{x: 1, y: 0}}
<Text style={[styles.buttonText, {color: theme.colors.background}]}> style={styles.button}>
<TouchableOpacity
</Text> style={styles.buttonContent}
</TouchableOpacity> onPress={resolveCode}>
<Icon name="add-circle-outline" size={24} color={theme.colors.background} style={styles.buttonIcon} />
<Text style={[styles.buttonText, {color: theme.colors.background}]}>
</Text>
</TouchableOpacity>
</LinearGradient>
<TouchableOpacity <LinearGradient
style={[styles.button, styles.completeButton, {backgroundColor: theme.colors.success}]} colors={[theme.colors.success, theme.colors.secondary]}
onPress={wheelComplete}> start={{x: 0, y: 0}}
<Icon name="check-circle-outline" size={24} color={theme.colors.background} style={styles.buttonIcon} /> end={{x: 1, y: 0}}
<Text style={[styles.buttonText, {color: theme.colors.background}]}> style={styles.button}>
<TouchableOpacity
</Text> style={styles.buttonContent}
</TouchableOpacity> onPress={wheelComplete}>
</View> <Icon name="check-circle-outline" size={24} color={theme.colors.background} style={styles.buttonIcon} />
<Text style={[styles.buttonText, {color: theme.colors.background}]}>
{/* 物料列表 */}
<View style={styles.tableContainer}> </Text>
<View style={styles.tableHeader}> </TouchableOpacity>
<Icon name="list-alt" size={24} color={theme.colors.primary} /> </LinearGradient>
<Text style={[styles.tableTitle, {color: theme.colors.text}]}>
({packageData.length})
</Text>
</View> </View>
{packageData.map((item, index) => ( {/* 物料列表 */}
<View <View style={styles.tableContainer}>
key={item.id} <View style={styles.tableHeader}>
style={[ <Icon name="list-alt" size={24} color={theme.colors.primary} />
styles.card, <Text style={[styles.tableTitle, {color: theme.colors.text}]}>
{ ({packageData.length})
backgroundColor: theme.colors.background, </Text>
borderColor: theme.colors.border, </View>
},
]}>
{/* 卡片头部 */}
<View style={styles.cardHeader}>
<View style={styles.cardHeaderLeft}>
<Text style={[styles.cardHeaderText, {color: theme.colors.text}]}>
{item.id}
</Text>
<Text style={[styles.cardHeaderText, {color: theme.colors.textLight}]}>
{item.segment1}
</Text>
</View>
<View style={styles.cardActions}>
<TouchableOpacity
style={[styles.cardActionButton, {backgroundColor: `${theme.colors.primary}15`}]}
onPress={() => showDetails(item)}>
<Icon name="info-outline" size={20} color={theme.colors.primary} />
</TouchableOpacity>
<TouchableOpacity
style={[styles.cardActionButton, {backgroundColor: `${theme.colors.error}15`}]}
onPress={() => deleteItem(item.id)}>
<Icon name="delete-outline" size={20} color={theme.colors.error} />
</TouchableOpacity>
</View>
</View>
{/* 卡片内容 */} {packageData.map((item, index) => (
<View style={styles.cardContent}> <View
<View style={styles.cardRow}> key={item.id}
<View style={styles.cardField}> style={[styles.card]}>
<Text style={[styles.cardLabel, {color: theme.colors.textLight}]}></Text> <LinearGradient
<Text style={[styles.cardValue, {color: theme.colors.text}]}>{item.itemId}</Text> colors={theme.colors.gradients.contrast}
style={[StyleSheet.absoluteFill, {borderRadius: 12}]}
start={{x: 0, y: 0}}
end={{x: 1, y: 0}}
/>
{/* 卡片头部 */}
<View style={styles.cardHeader}>
<View style={styles.cardHeaderLeft}>
<Text style={[styles.cardHeaderText, {color: theme.colors.background}]}>
{item.id}
</Text>
<Text style={[styles.cardHeaderText, {color: theme.colors.background}]}>
{item.segment1}
</Text>
</View> </View>
<View style={styles.cardField}> <View style={styles.cardActions}>
<Text style={[styles.cardLabel, {color: theme.colors.textLight}]}></Text>
<Text style={[styles.cardValue, {color: theme.colors.text}]}>{item.batch}</Text>
</View>
</View>
<View style={styles.cardRow}>
<View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.textLight}]}></Text>
<TouchableOpacity <TouchableOpacity
style={styles.editableValue} style={[styles.cardActionButton, {backgroundColor: `${theme.colors.primary}15`}]}
onPress={() => modifyNumber(item.id)}> onPress={() => showDetails(item)}>
<Text style={[styles.cardValue, {color: theme.colors.primary}]}> <Icon name="info-outline" size={20} color={theme.colors.primary} />
{item.quantity} </TouchableOpacity>
</Text> <TouchableOpacity
<Icon name="edit" size={16} color={theme.colors.primary} /> style={[styles.cardActionButton, {backgroundColor: `${theme.colors.error}15`}]}
onPress={() => deleteItem(item.id)}>
<Icon name="delete-outline" size={20} color={theme.colors.error} />
</TouchableOpacity> </TouchableOpacity>
</View>
<View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.textLight}]}></Text>
<Text style={[styles.cardValue, {color: theme.colors.text}]}>{item.weight}</Text>
</View> </View>
</View> </View>
<View style={styles.cardRow}> {/* 卡片内容 */}
<View style={styles.cardField}> <View style={styles.cardContent}>
<Text style={[styles.cardLabel, {color: theme.colors.textLight}]}></Text> <View style={styles.cardRow}>
<Text style={[styles.cardValue, {color: theme.colors.text}]}>{item.productData}</Text> <View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.background}]}></Text>
<Text style={[styles.cardValue, {color: theme.colors.background}]}>{item.itemId}</Text>
</View>
<View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.background}]}></Text>
<Text style={[styles.cardValue, {color: theme.colors.background}]}>{item.batch}</Text>
</View>
</View>
<View style={styles.cardRow}>
<View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.background}]}></Text>
<TouchableOpacity
style={styles.editableValue}
onPress={() => modifyNumber(item.id)}>
<Text style={[styles.cardValue, {color: theme.colors.background}]}>
{item.quantity}
</Text>
<Icon name="edit" size={16} color={theme.colors.background} />
</TouchableOpacity>
</View>
<View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.background}]}></Text>
<Text style={[styles.cardValue, {color: theme.colors.background}]}>{item.weight}</Text>
</View>
</View>
<View style={styles.cardRow}>
<View style={styles.cardField}>
<Text style={[styles.cardLabel, {color: theme.colors.background}]}></Text>
<Text style={[styles.cardValue, {color: theme.colors.background}]}>{item.productData}</Text>
</View>
</View> </View>
</View> </View>
</View> </View>
</View> ))}
))} </View>
</View> </ScrollView>
</ScrollView> </View>
{loading && ( {loading && (
<View style={[styles.loadingOverlay, {backgroundColor: 'rgba(0, 0, 0, 0.7)'}]}> <View style={[styles.loadingOverlay, {backgroundColor: 'rgba(0, 0, 0, 0.7)'}]}>
@ -544,6 +591,14 @@ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
}, },
mainContent: {
flex: 1,
position: 'relative',
},
scrollContent: {
flexGrow: 1,
padding: 16,
},
header: { header: {
height: 56, height: 56,
flexDirection: 'row', flexDirection: 'row',
@ -556,6 +611,19 @@ const styles = StyleSheet.create({
shadowOpacity: 0.2, shadowOpacity: 0.2,
shadowRadius: 2, shadowRadius: 2,
}, },
waveContainer: {
height: 100,
backgroundColor: 'transparent',
position: 'absolute',
top: 56,
left: 0,
right: 0,
zIndex: -1,
},
waveSvg: {
position: 'absolute',
top: 0,
},
backButton: { backButton: {
padding: 8, padding: 8,
}, },
@ -566,10 +634,6 @@ const styles = StyleSheet.create({
headerRight: { headerRight: {
width: 40, width: 40,
}, },
content: {
flex: 1,
padding: 16,
},
infoSection: { infoSection: {
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
@ -650,15 +714,18 @@ const styles = StyleSheet.create({
flex: 1, flex: 1,
height: 48, height: 48,
borderRadius: 24, borderRadius: 24,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
elevation: 2, elevation: 2,
shadowColor: '#000', shadowColor: '#000',
shadowOffset: {width: 0, height: 2}, shadowOffset: {width: 0, height: 2},
shadowOpacity: 0.1, shadowOpacity: 0.1,
shadowRadius: 2, shadowRadius: 2,
}, },
buttonContent: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
buttonIcon: { buttonIcon: {
marginRight: 8, marginRight: 8,
}, },
@ -683,13 +750,8 @@ const styles = StyleSheet.create({
}, },
card: { card: {
borderRadius: 12, borderRadius: 12,
borderWidth: 1,
marginBottom: 12, marginBottom: 12,
elevation: 2, overflow: 'hidden',
shadowColor: '#000',
shadowOffset: {width: 0, height: 2},
shadowOpacity: 0.1,
shadowRadius: 2,
}, },
cardHeader: { cardHeader: {
flexDirection: 'row', flexDirection: 'row',