feat: 更新应用版本和集成腾讯云 COS 上传功能
- 将应用版本更新至 1.0.2,修改相关配置文件 - 集成腾讯云 COS 上传功能,新增相关服务和钩子 - 更新 AI 体态评估页面,支持照片上传和评估结果展示 - 添加雷达图组件以展示评估结果 - 更新样式以适应新功能的展示和交互 - 修改登录页面背景效果,提升用户体验
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import ImageViewing from 'react-native-image-viewing';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
@@ -31,17 +32,17 @@ type Sample = { uri: string; correct: boolean };
|
||||
|
||||
const SAMPLES: Record<PoseView, Sample[]> = {
|
||||
front: [
|
||||
{ uri: 'https://images.unsplash.com/photo-1594737625785-c6683fc87c73?w=400&q=80&auto=format', correct: true },
|
||||
{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/imagedemo.jpeg', correct: true },
|
||||
{ uri: 'https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?w=400&q=80&auto=format', correct: false },
|
||||
{ uri: 'https://images.unsplash.com/photo-1571019614242-c5c5dee9f50b?w=400&q=80&auto=format', correct: false },
|
||||
],
|
||||
side: [
|
||||
{ uri: 'https://images.unsplash.com/photo-1554463529-e27854014799?w=400&q=80&auto=format', correct: true },
|
||||
{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/imagedemo.jpeg', correct: true },
|
||||
{ uri: 'https://images.unsplash.com/photo-1596357395104-5bcae0b1a5eb?w=400&q=80&auto=format', correct: false },
|
||||
{ uri: 'https://images.unsplash.com/photo-1526506118085-60ce8714f8c5?w=400&q=80&auto=format', correct: false },
|
||||
],
|
||||
back: [
|
||||
{ uri: 'https://images.unsplash.com/photo-1517836357463-d25dfeac3438?w=400&q=80&auto=format', correct: true },
|
||||
{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/imagedemo.jpeg', correct: true },
|
||||
{ uri: 'https://images.unsplash.com/photo-1571721797421-f4c9f2b13107?w=400&q=80&auto=format', correct: false },
|
||||
{ uri: 'https://images.unsplash.com/photo-1518611012118-696072aa579a?w=400&q=80&auto=format', correct: false },
|
||||
],
|
||||
@@ -50,7 +51,7 @@ const SAMPLES: Record<PoseView, Sample[]> = {
|
||||
export default function AIPostureAssessmentScreen() {
|
||||
const router = useRouter();
|
||||
const insets = useSafeAreaInsets();
|
||||
const theme = Colors.dark;
|
||||
const theme = Colors.light;
|
||||
|
||||
const [uploadState, setUploadState] = useState<UploadState>({});
|
||||
const canStart = useMemo(
|
||||
@@ -167,13 +168,13 @@ export default function AIPostureAssessmentScreen() {
|
||||
|
||||
function handleStart() {
|
||||
if (!canStart) return;
|
||||
// TODO: 调用后端或进入分析页面
|
||||
Alert.alert('开始测评', '已收集三视角照片,准备开始AI体态分析');
|
||||
// 进入评估中间页面
|
||||
router.push('/ai-posture-processing');
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.screen, { backgroundColor: theme.background }]}>
|
||||
<HeaderBar title="AI体态测评" onBack={() => router.back()} tone="dark" transparent />
|
||||
<View style={[styles.screen, { backgroundColor: Colors.light.pageBackgroundEmphasis }]}>
|
||||
<HeaderBar title="AI体态测评" onBack={() => router.back()} tone="light" transparent />
|
||||
|
||||
<ScrollView
|
||||
contentContainerStyle={{ paddingBottom: insets.bottom + 120 }}
|
||||
@@ -207,10 +208,8 @@ export default function AIPostureAssessmentScreen() {
|
||||
|
||||
{/* Intro */}
|
||||
<View style={styles.introBox}>
|
||||
<Text style={styles.title}>上传标准姿势照片</Text>
|
||||
<Text style={styles.description}>
|
||||
请依次上传正面、侧面与背面全身照。保持光线均匀、背景简洁,身体立正自然放松。
|
||||
</Text>
|
||||
<Text style={[styles.title, { color: '#192126' }]}>上传标准姿势照片</Text>
|
||||
<Text style={[styles.description, { color: '#5E6468' }]}>请依次上传正面、侧面与背面全身照。保持光线均匀、背景简洁,身体立正自然放松。</Text>
|
||||
</View>
|
||||
|
||||
{/* Upload sections */}
|
||||
@@ -272,6 +271,10 @@ function UploadTile({
|
||||
onPickLibrary: () => void;
|
||||
samples: Sample[];
|
||||
}) {
|
||||
const [viewerVisible, setViewerVisible] = React.useState(false);
|
||||
const [viewerIndex, setViewerIndex] = React.useState(0);
|
||||
const imagesForViewer = React.useMemo(() => samples.map((s) => ({ uri: s.uri })), [samples]);
|
||||
|
||||
return (
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
@@ -294,7 +297,7 @@ function UploadTile({
|
||||
) : (
|
||||
<View style={styles.placeholder}>
|
||||
<View style={styles.plusBadge}>
|
||||
<Ionicons name="camera" size={16} color="#192126" />
|
||||
<Ionicons name="camera" size={16} color="#BBF246" />
|
||||
</View>
|
||||
<Text style={styles.placeholderTitle}>拍摄或选择照片</Text>
|
||||
<Text style={styles.placeholderDesc}>点击拍摄,长按从相册选择</Text>
|
||||
@@ -302,19 +305,27 @@ function UploadTile({
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<BlurView intensity={18} tint="dark" style={styles.sampleBox}>
|
||||
<BlurView intensity={12} tint="light" style={styles.sampleBox}>
|
||||
<Text style={styles.sampleTitle}>示例</Text>
|
||||
<View style={styles.sampleRow}>
|
||||
{samples.map((s, idx) => (
|
||||
<View key={idx} style={styles.sampleItem}>
|
||||
<Image source={{ uri: s.uri }} style={styles.sampleImg} />
|
||||
<View style={[styles.sampleTag, { backgroundColor: s.correct ? '#2BCC7F' : '#E24D4D' }]}>
|
||||
<TouchableOpacity activeOpacity={0.9} onPress={() => { setViewerIndex(idx); setViewerVisible(true); }}>
|
||||
<Image source={{ uri: s.uri }} style={styles.sampleImg} />
|
||||
</TouchableOpacity>
|
||||
<View style={[styles.sampleTag, { backgroundColor: s.correct ? '#2BCC7F' : 'rgba(25,33,38,0.08)' }]}>
|
||||
<Text style={styles.sampleTagText}>{s.correct ? '正确示范' : '错误示范'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</BlurView>
|
||||
<ImageViewing
|
||||
images={imagesForViewer}
|
||||
imageIndex={viewerIndex}
|
||||
visible={viewerVisible}
|
||||
onRequestClose={() => setViewerVisible(false)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -328,15 +339,15 @@ const styles = StyleSheet.create({
|
||||
marginHorizontal: 16,
|
||||
padding: 14,
|
||||
borderRadius: 16,
|
||||
backgroundColor: 'rgba(255,255,255,0.04)'
|
||||
backgroundColor: 'rgba(25,33,38,0.06)'
|
||||
},
|
||||
permTitle: {
|
||||
color: '#ECEDEE',
|
||||
color: '#192126',
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
},
|
||||
permDesc: {
|
||||
color: 'rgba(255,255,255,0.75)',
|
||||
color: '#5E6468',
|
||||
marginTop: 6,
|
||||
fontSize: 13,
|
||||
},
|
||||
@@ -367,10 +378,10 @@ const styles = StyleSheet.create({
|
||||
height: 40,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: 'rgba(255,255,255,0.18)',
|
||||
borderColor: 'rgba(25,33,38,0.14)',
|
||||
},
|
||||
permSecondaryText: {
|
||||
color: 'rgba(255,255,255,0.85)',
|
||||
color: '#384046',
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
},
|
||||
@@ -420,12 +431,12 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
sectionTitle: {
|
||||
color: '#ECEDEE',
|
||||
color: '#192126',
|
||||
fontSize: 18,
|
||||
fontWeight: '700',
|
||||
},
|
||||
retakeHint: {
|
||||
color: 'rgba(255,255,255,0.55)',
|
||||
color: '#888F92',
|
||||
fontSize: 13,
|
||||
},
|
||||
uploader: {
|
||||
@@ -433,8 +444,8 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 18,
|
||||
borderWidth: 1,
|
||||
borderStyle: 'dashed',
|
||||
borderColor: 'rgba(255,255,255,0.18)',
|
||||
backgroundColor: '#1E262C',
|
||||
borderColor: 'rgba(25,33,38,0.14)',
|
||||
backgroundColor: '#FFFFFF',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
preview: {
|
||||
@@ -453,25 +464,27 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 18,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#BBF246',
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderWidth: 2,
|
||||
borderColor: '#BBF246',
|
||||
},
|
||||
placeholderTitle: {
|
||||
color: '#ECEDEE',
|
||||
color: '#192126',
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
},
|
||||
placeholderDesc: {
|
||||
color: 'rgba(255,255,255,0.65)',
|
||||
color: '#888F92',
|
||||
fontSize: 12,
|
||||
},
|
||||
sampleBox: {
|
||||
marginTop: 8,
|
||||
borderRadius: 16,
|
||||
padding: 12,
|
||||
backgroundColor: 'rgba(255,255,255,0.04)',
|
||||
backgroundColor: 'rgba(255,255,255,0.72)',
|
||||
},
|
||||
sampleTitle: {
|
||||
color: 'rgba(255,255,255,0.8)',
|
||||
color: '#192126',
|
||||
fontSize: 14,
|
||||
marginBottom: 8,
|
||||
fontWeight: '600',
|
||||
@@ -487,7 +500,7 @@ const styles = StyleSheet.create({
|
||||
width: '100%',
|
||||
height: 90,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '#111',
|
||||
backgroundColor: '#F2F4F5',
|
||||
},
|
||||
sampleTag: {
|
||||
alignSelf: 'flex-start',
|
||||
|
||||
Reference in New Issue
Block a user