diff --git a/README.md b/README.md index 12470c3..81068d8 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,9 @@ -This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). +1. key秘钥的回答内容全部为ct 密码为jy888786 +2. 在untils下有自定义封装了的蓝牙操作 rpx转化 图片上传 接口封装 权限封装的内容 +3. 开发环境node版本为 20.10.0 rn版本为0.74.6 主要使用的ui库为kitten 为国外ui库 可访问 https://akveo.github.io/react-native-ui-kitten/docs/components/card/overview#card +4. 运行: + npm run android + npm run ios -# Getting Started - ->**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. - -## Step 1: Start the Metro Server - -First, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native. - -To start Metro, run the following command from the _root_ of your React Native project: - -```bash -# using npm -npm start - -# OR using Yarn -yarn start -``` - -## Step 2: Start your Application - -Let Metro Bundler run in its _own_ terminal. Open a _new_ terminal from the _root_ of your React Native project. Run the following command to start your _Android_ or _iOS_ app: - -### For Android - -```bash -# using npm -npm run android - -# OR using Yarn -yarn android -``` - -### For iOS - -```bash -# using npm -npm run ios - -# OR using Yarn -yarn ios -``` - -If everything is set up _correctly_, you should see your new app running in your _Android Emulator_ or _iOS Simulator_ shortly provided you have set up your emulator/simulator correctly. - -This is one way to run your app — you can also run it directly from within Android Studio and Xcode respectively. - -## Step 3: Modifying your App - -Now that you have successfully run the app, let's modify it. - -1. Open `App.tsx` in your text editor of choice and edit some lines. -2. For **Android**: Press the R key twice or select **"Reload"** from the **Developer Menu** (Ctrl + M (on Window and Linux) or Cmd ⌘ + M (on macOS)) to see your changes! - - For **iOS**: Hit Cmd ⌘ + R in your iOS Simulator to reload the app and see your changes! - -## Congratulations! :tada: - -You've successfully run and modified your React Native App. :partying_face: - -### Now what? - -- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). -- If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started). - -# Troubleshooting - -If you can't get this to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. - -# Learn More - -To learn more about React Native, take a look at the following resources: - -- [React Native Website](https://reactnative.dev) - learn more about React Native. -- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. -- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. -- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. -- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. + 打包: ./gradlew assembleRelease + diff --git a/src/navigation/HomeStack.tsx b/src/navigation/HomeStack.tsx index f8d2968..a8883d9 100644 --- a/src/navigation/HomeStack.tsx +++ b/src/navigation/HomeStack.tsx @@ -20,6 +20,7 @@ import ExpiredKeysScreen from '../views/device/ExpiredKeysScreen'; import deviceDetailSet from '../views/device/deviceDetailSet'; import HelpCenterPage from '../views/user/HelpCenterPage'; import XmlRenderPage from '../views/user/XmlRenderPage'; +import Feedback from '../views/user/feedback'; const Stack = createStackNavigator(); const createScreenOptions = (title: string): StackNavigationOptions => { @@ -62,6 +63,13 @@ export default function HomeStackNavigator({ navigation, route }: Props) { headerShown: false, }} /> + api.get('/app/article/' + id), + + // 获取反馈类型 + getFeedbackType: () => api.get('/appVerify/getDictData?dictType=as_feedback_type'), + // 提交反馈 + postFeedback: (data: any) => api.post('/appVerify/feedback', data), // updateKeyExpiration: (keyId: string, expirationTime: string) => api.put('/appVerify/updateKeyExpiration', { keyId, expirationTime }), }; \ No newline at end of file diff --git a/src/views/ProfileScreen.jsx b/src/views/ProfileScreen.jsx index a75b4d9..c052838 100644 --- a/src/views/ProfileScreen.jsx +++ b/src/views/ProfileScreen.jsx @@ -121,7 +121,7 @@ const ProfileScreen = () => { 意见和反馈 - {userInfo.isAuthentication === false && ( + {/* {userInfo.isAuthentication === false && ( navigation.navigate('IdVerification')} @@ -132,7 +132,7 @@ const ProfileScreen = () => { /> 实名认证 - )} + )} */} {/* {userInfo.userType === '02' && ( {item.remainingMileage}KM - 车型:{item.model} + + {item.remark ? `备注:${item.remark}` : `车型:${item.model}`} + {item.vehicleNum} {item.type == 1 ? '车主' : '临时租赁'} diff --git a/src/views/user/feedback.tsx b/src/views/user/feedback.tsx new file mode 100644 index 0000000..86f2fc2 --- /dev/null +++ b/src/views/user/feedback.tsx @@ -0,0 +1,355 @@ +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) => ( + +); + +const Feedback = () => { + const [currentCount, setCurrentCount] = useState(0); + const [textValue, setTextValue] = useState(''); + const [imglist, setImglist] = useState([]); + const [list, setList] = useState([]); + const [selectedIndex, setSelectedIndex] = useState(null); + const [contactInfo, setContactInfo] = useState(''); + const [type, setType] = useState(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 = () => ( + + ); + + return ( + + + + + 反馈类型* + + {list.map((item, index) => ( + toggleCheckbox(index, item)} + > + {item.dictLabel} + {selectedIndex === index && ( + + )} + + ))} + + + + + 问题描述* + + {!textValue && !isFocused && 请详细描述您的问题或建议} + setIsFocused(true)} + onBlur={() => setIsFocused(false)} + /> + {currentCount}/500 + + + + + 上传图片 + + {imglist.map((item, index) => ( + + + deleteImage(index)}> + + + + ))} + {imglist.length < 9 && ( + + + + )} + + + + + 联系方式* + + + + + + + 提交 + + + + + ); +}; + +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; \ No newline at end of file