BikeApp_demo/src/views/user/feedback.tsx
2024-12-31 14:53:01 +08:00

355 lines
9.5 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, TouchableOpacity, Image, StyleSheet, ScrollView, ImageBackground } from 'react-native';
import { TopNavigation, TopNavigationAction, Icon } from '@ui-kitten/components';
import { useNavigation } from '@react-navigation/native';
import { apiService } from '../../utils/api';
import { rpx } from '../../utils/rpx';
import { uploadImageService } from '../../utils/uploadImg';
import Toast from 'react-native-toast-message';
const BackIcon = (props: any) => (
<Icon {...props} name='arrow-back' />
);
const Feedback = () => {
const [currentCount, setCurrentCount] = useState(0);
const [textValue, setTextValue] = useState('');
const [imglist, setImglist] = useState<string[]>([]);
const [list, setList] = useState<any[]>([]);
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [contactInfo, setContactInfo] = useState('');
const [type, setType] = useState<number | null>(null);
const [isFocused, setIsFocused] = useState(false);
const navigation = useNavigation();
useEffect(() => {
getlist();
}, []);
const toggleCheckbox = (index: number, item: any) => {
setSelectedIndex(index);
setType(item.dictSort);
};
const deleteImage = (index: number) => {
Toast.show({
type: 'info',
text1: '提示',
text2: '确定要删除这张图片吗?',
onPress: () => setImglist(prev => prev.filter((_, i) => i !== index)),
});
};
const sub = () => {
if (selectedIndex === null) {
Toast.show({ type: 'error', text1: '请选择反馈类型' });
return;
}
if (contactInfo === '') {
Toast.show({ type: 'error', text1: '请输入联系方式' });
return;
}
if (!textValue.trim()) {
Toast.show({ type: 'error', text1: '请填写问题描述' });
return;
}
const data = {
issueDescription: textValue,
uploadedImage: imglist.join(','),
type,
contactInfo,
};
apiService.postFeedback(data).then((res) => {
if (res.code == 200) {
Toast.show({ type: 'success', text1: '提交成功' });
navigation.goBack();
} else {
Toast.show({ type: 'error', text1: res.msg });
}
});
};
const getlist = async () => {
const res = await apiService.getFeedbackType();
if (res.code === 200) {
setList(res.data);
} else {
Toast.show({ type: 'error', text1: '获取反馈类型失败' });
}
};
const updateWordCount = (text: string) => {
const count = text.trim().replace(/\s+/g, '').length;
if (count > 500) {
setTextValue(text.slice(0, 500));
setCurrentCount(500);
Toast.show({ type: 'info', text1: '字数已达到500字上限' });
} else {
setTextValue(text);
setCurrentCount(count);
}
};
const handleImageUpload = async () => {
const urls = await uploadImageService.uploadImage({ multiple: true });
if (urls.length > 0) {
setImglist(prev => [...prev, ...urls]);
}
};
const navigateBack = () => {
navigation.goBack();
};
const BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={navigateBack} />
);
return (
<ImageBackground
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uYRs7Cv2Pbp95w3KjGO3' }}
style={styles.background}
>
<TopNavigation
title='意见与反馈'
alignment='center'
accessoryLeft={BackAction}
style={styles.topNavigation}
/>
<ScrollView style={styles.page}>
<View style={styles.cardbox}>
<Text style={styles.tip}><Text style={styles.ipnt}>*</Text></Text>
<View style={styles.checkbox}>
{list.map((item, index) => (
<TouchableOpacity
key={index}
style={[styles.check_li, selectedIndex === index && styles.act1]}
onPress={() => toggleCheckbox(index, item)}
>
<Text style={styles.check_li_text}>{item.dictLabel}</Text>
{selectedIndex === index && (
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u2jYgqIRlFcHjt20uA90' }}
style={styles.checkIcon}
/>
)}
</TouchableOpacity>
))}
</View>
</View>
<View style={styles.cardbox}>
<Text style={styles.tip}><Text style={styles.ipnt}>*</Text></Text>
<View style={styles.inputContainer}>
{!textValue && !isFocused && <Text style={styles.placeholder}></Text>}
<TextInput
style={styles.customTextarea}
value={textValue}
onChangeText={updateWordCount}
multiline
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
<Text style={styles.wordCount}>{currentCount}/500</Text>
</View>
</View>
<View style={styles.cardbox}>
<Text style={styles.tip}></Text>
<View style={styles.icon}>
{imglist.map((item, index) => (
<View key={index} style={styles.imgbox}>
<Image source={{ uri: item }} style={styles.image} />
<TouchableOpacity style={styles.deleteBtn} onPress={() => deleteImage(index)}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/smartmeter/img/static/ui63BrTf8rlk4VAGx8Tf' }}
style={styles.deleteIcon}
/>
</TouchableOpacity>
</View>
))}
{imglist.length < 9 && (
<TouchableOpacity style={[styles.imgbox, styles.addBtn]} onPress={handleImageUpload}>
<Image
source={{ uri: 'https://api.ccttiot.com/smartmeter/img/static/uY8CPw9YE6JxPzcHUaqf' }}
style={styles.image}
/>
</TouchableOpacity>
)}
</View>
</View>
<View style={styles.cardbox}>
<Text style={styles.tip}><Text style={styles.ipnt}>*</Text></Text>
<View style={styles.inputBox}>
<TextInput
style={styles.input}
placeholder="请留下手机号/邮箱/微信号,以便我们回复您"
value={contactInfo}
onChangeText={setContactInfo}
/>
</View>
</View>
<TouchableOpacity style={styles.btn} onPress={sub}>
<Text style={styles.btnText}></Text>
</TouchableOpacity>
</ScrollView>
<Toast />
</ImageBackground>
);
};
const styles = StyleSheet.create({
background: {
flex: 1,
},
topNavigation: {
backgroundColor: 'transparent',
},
page: {
flex: 1,
paddingBottom: rpx(80),
},
cardbox: {
margin: rpx(30),
padding: rpx(20),
backgroundColor: '#FFFFFF',
borderRadius: rpx(20),
shadowColor: '#000',
shadowOffset: { width: 0, height: rpx(10) },
shadowOpacity: 0.08,
shadowRadius: rpx(10),
elevation: 2,
},
tip: {
fontWeight: '700',
fontSize: rpx(32),
color: '#3D3D3D',
marginBottom: rpx(10),
},
ipnt: {
color: '#FF4444',
fontSize: rpx(48),
},
checkbox: {
flexDirection: 'row',
flexWrap: 'wrap',
},
check_li: {
marginRight: rpx(10),
marginTop: rpx(18),
padding: rpx(18),
borderRadius: rpx(25),
borderWidth: rpx(2),
borderColor: '#C4C4C4',
flexDirection: 'row',
alignItems: 'center',
},
act1: {
borderColor: '#4297F3',
},
check_li_text: {
fontSize: rpx(28),
},
checkIcon: {
position: 'absolute',
right: rpx(0),
bottom: rpx(0),
width: rpx(40),
height: rpx(20),
marginLeft: rpx(5),
borderBottomRightRadius: rpx(20),
},
inputContainer: {
position: 'relative',
height: rpx(248),
borderWidth: rpx(2),
borderColor: '#C7C7C7',
borderRadius: rpx(20),
padding: rpx(10),
marginTop: rpx(40),
},
placeholder: {
position: 'absolute',
top: rpx(18),
left: rpx(38),
color: '#999',
},
customTextarea: {
flex: 1,
textAlignVertical: 'top',
paddingTop: rpx(18),
paddingLeft: rpx(38),
},
wordCount: {
position: 'absolute',
right: rpx(10),
bottom: rpx(10),
fontSize: rpx(12),
color: '#999',
},
icon: {
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
marginTop: rpx(40),
},
imgbox: {
position: 'relative',
width: '30%',
marginBottom: rpx(20),
marginRight: rpx(10),
},
image: {
width: rpx(142),
height: rpx(142),
borderRadius: rpx(10),
},
deleteBtn: {
position: 'absolute',
top: rpx(-16),
right: rpx(-16),
width: rpx(32),
height: rpx(32),
backgroundColor: '#DCEDFF',
borderRadius: rpx(16),
justifyContent: 'center',
alignItems: 'center',
},
deleteIcon: {
width: rpx(20),
height: rpx(20),
},
addBtn: {
justifyContent: 'center',
alignItems: 'center',
},
inputBox: {
marginTop: rpx(40),
borderWidth: rpx(2),
borderColor: '#C7C7C7',
borderRadius: rpx(20),
padding: rpx(10),
},
input: {
height: rpx(80),
paddingLeft: rpx(20),
},
btn: {
margin: rpx(34),
padding: rpx(15),
backgroundColor: '#4297F3',
borderRadius: rpx(54),
alignItems: 'center',
},
btnText: {
color: '#FFFFFF',
fontSize: rpx(40),
fontWeight: '500',
},
});
export default Feedback;