Compare commits
3 Commits
8a6f0fcffe
...
288ce04983
Author | SHA1 | Date | |
---|---|---|---|
288ce04983 | |||
0cd54ba8ec | |||
52c771c22a |
86
README.md
86
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 <kbd>R</kbd> key twice or select **"Reload"** from the **Developer Menu** (<kbd>Ctrl</kbd> + <kbd>M</kbd> (on Window and Linux) or <kbd>Cmd ⌘</kbd> + <kbd>M</kbd> (on macOS)) to see your changes!
|
||||
|
||||
For **iOS**: Hit <kbd>Cmd ⌘</kbd> + <kbd>R</kbd> 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
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ import ShareDetailScreen from '../views/device/KeyDetail';
|
|||
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<HomeStackParamList>();
|
||||
|
||||
const createScreenOptions = (title: string): StackNavigationOptions => {
|
||||
|
@ -61,6 +63,13 @@ export default function HomeStackNavigator({ navigation, route }: Props) {
|
|||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Feedback"
|
||||
component={Feedback}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ShareDetailScreen"
|
||||
component={ShareDetailScreen}
|
||||
|
@ -82,6 +91,13 @@ export default function HomeStackNavigator({ navigation, route }: Props) {
|
|||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="XmlRenderPage"
|
||||
component={XmlRenderPage}
|
||||
options={{
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="HelpCenterPage"
|
||||
component={HelpCenterPage}
|
||||
|
|
|
@ -32,6 +32,8 @@ export type HomeStackParamList = {
|
|||
ExpiredKeysScreen: undefined;
|
||||
deviceDetailSet: undefined;
|
||||
HelpCenterPage: undefined;
|
||||
XmlRenderPage: undefined;
|
||||
Feedback: undefined;
|
||||
};
|
||||
|
||||
// 导航属性类型
|
||||
|
|
|
@ -140,5 +140,13 @@ export const apiService = {
|
|||
getArticleList: (classifyId: string) => api.get('/app/article/list?classifyId=' + classifyId),
|
||||
// 获取客服电话
|
||||
getServerPhone: () => api.get('/app/getServerPhone'),
|
||||
|
||||
|
||||
getArticleById: (id: string) => 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 }),
|
||||
};
|
|
@ -169,6 +169,9 @@ const NormaIndex: React.FC = () => {
|
|||
|
||||
}
|
||||
};
|
||||
const toXmlRenderPage = () => {
|
||||
navigation.navigate('XmlRenderPage', { id: 28 });
|
||||
};
|
||||
return (
|
||||
<View style={styles.pageContainer}>
|
||||
<StatusBar
|
||||
|
@ -212,7 +215,7 @@ const NormaIndex: React.FC = () => {
|
|||
<Text style={styles.KmLi_tits1}>剩余里程</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.KmLi}>
|
||||
{/* <View style={styles.KmLi}>
|
||||
<View style={styles.KmLi_top}>
|
||||
<Text style={styles.titTxt}>110</Text>
|
||||
<Text style={styles.KmLi_tits}>km</Text>
|
||||
|
@ -224,7 +227,7 @@ const NormaIndex: React.FC = () => {
|
|||
/>
|
||||
<Text style={styles.KmLi_tits1}>剩余里程</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View> */}
|
||||
</View>
|
||||
<DeviceControl defaultDevice={defaultDevice} onDeviceUpdate={handleDeviceUpdate} />
|
||||
|
||||
|
@ -252,10 +255,12 @@ const NormaIndex: React.FC = () => {
|
|||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity onPress={toXmlRenderPage}>
|
||||
<Image
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u849NsNxdtzxhUkUJnfW' }}
|
||||
style={styles.otherImg}
|
||||
/>
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
@ -461,6 +466,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
|
||||
KmLi_tits: {
|
||||
marginLeft: rpx(10),
|
||||
paddingBottom: rpx(10),
|
||||
fontSize: rpx(24),
|
||||
color: '#3D3D3D',
|
||||
|
|
|
@ -121,7 +121,7 @@ const ProfileScreen = () => {
|
|||
<Text style={styles.itemText}>意见和反馈</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{userInfo.isAuthentication === false && (
|
||||
{/* {userInfo.isAuthentication === false && (
|
||||
<TouchableOpacity
|
||||
style={styles.item}
|
||||
onPress={() => navigation.navigate('IdVerification')}
|
||||
|
@ -132,7 +132,7 @@ const ProfileScreen = () => {
|
|||
/>
|
||||
<Text style={styles.itemText}>实名认证</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
{/* {userInfo.userType === '02' && (
|
||||
<TouchableOpacity
|
||||
|
|
|
@ -109,13 +109,15 @@ export default function DeviceList() {
|
|||
</View>
|
||||
<Text style={styles.mileage}>{item.remainingMileage}KM</Text>
|
||||
</View>
|
||||
<Text style={styles.model}>车型:{item.model}</Text>
|
||||
<Text style={styles.model}>
|
||||
{item.remark ? `备注:${item.remark}` : `车型:${item.model}`}
|
||||
</Text>
|
||||
<Text style={styles.carNum}>{item.vehicleNum}</Text>
|
||||
<Text style={styles.status}>{item.type == 1 ? '车主' : '临时租赁'}</Text>
|
||||
</View>
|
||||
<View style={styles.rightContent}>
|
||||
<Image
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uB1F5aibooguILH8uB4F' }}
|
||||
source={{ uri:item.picture ? item.picture : 'https://lxnapi.ccttiot.com/bike/img/static/uB1F5aibooguILH8uB4F' }}
|
||||
style={styles.carImage}
|
||||
/>
|
||||
<View style={styles.checkboxWrapper}>
|
||||
|
|
|
@ -1,22 +1,55 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { View, StyleSheet, ScrollView, Image, TouchableOpacity, Alert } from 'react-native';
|
||||
import { TopNavigation, TopNavigationAction, Icon, Text, Button } from '@ui-kitten/components';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { View, StyleSheet, ScrollView, Image, TouchableOpacity, Modal, Text, ImageBackground, Platform, NativeModules, Linking } from 'react-native';
|
||||
import { TopNavigation, TopNavigationAction, Icon, Button } from '@ui-kitten/components';
|
||||
import { apiService } from '../../utils/api';
|
||||
import { rpx } from '../../utils/rpx';
|
||||
import RNFS from 'react-native-fs';
|
||||
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
|
||||
import { captureRef } from 'react-native-view-shot';
|
||||
import Toast from 'react-native-toast-message';
|
||||
|
||||
const BackIcon = (props) => (
|
||||
const BackIcon = (props: any) => (
|
||||
<Icon {...props} name='arrow-back' />
|
||||
);
|
||||
|
||||
const HelpCenterPage = ({ navigation }) => {
|
||||
const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
||||
const [showQrcode, setShowQrcode] = useState(false);
|
||||
const [phone, setPhone] = useState({ serverWx: '', serverPhone: '' });
|
||||
const [classifyList, setClassifyList] = useState([]);
|
||||
const [wordlist, setWordlist] = useState([]);
|
||||
const [tabindex, setTabindex] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const qrRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
fetchClassifyList();
|
||||
const initData = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const classifyResponse = await apiService.getClassifyList();
|
||||
console.log('分类数据:', classifyResponse);
|
||||
|
||||
if (classifyResponse?.data?.length > 0) {
|
||||
setClassifyList(classifyResponse.data);
|
||||
const firstClassifyId = classifyResponse.data[0].classifyId;
|
||||
console.log('第一个分类ID:', firstClassifyId);
|
||||
|
||||
const articleResponse = await apiService.getArticleList(firstClassifyId);
|
||||
console.log('文章列表数据:', articleResponse);
|
||||
|
||||
if (articleResponse?.rows) {
|
||||
setWordlist(articleResponse.rows);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error);
|
||||
setClassifyList([]);
|
||||
setWordlist([]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
initData();
|
||||
fetchPhone();
|
||||
}, []);
|
||||
|
||||
|
@ -29,21 +62,30 @@ const HelpCenterPage = ({ navigation }) => {
|
|||
);
|
||||
|
||||
const fetchPhone = async () => {
|
||||
// 模拟获取电话信息
|
||||
const response = await apiService.getServerPhone();
|
||||
setPhone(response.data);
|
||||
};
|
||||
|
||||
const fetchClassifyList = async () => {
|
||||
const response = await apiService.getClassifyList();
|
||||
console.log(response,'分类列表');
|
||||
setClassifyList(response.data);
|
||||
fetchArticleList(response.data[0].classifyId);
|
||||
};
|
||||
|
||||
const fetchArticleList = async (id) => {
|
||||
const response = await apiService.getArticleList(id);
|
||||
setWordlist(response.data.rows);
|
||||
const fetchArticleList = async (id: string) => {
|
||||
if (!id) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
console.log('获取文章列表,分类ID:', id);
|
||||
const response = await apiService.getArticleList(id);
|
||||
console.log('获取到的文章列表:', response);
|
||||
|
||||
if (response?.rows) {
|
||||
setWordlist(response.rows);
|
||||
} else {
|
||||
setWordlist([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取文章列表失败:', error);
|
||||
setWordlist([]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const showWechat = () => {
|
||||
|
@ -51,110 +93,302 @@ const HelpCenterPage = ({ navigation }) => {
|
|||
};
|
||||
|
||||
const callPhone = () => {
|
||||
Alert.alert('拨打电话', `拨打电话: ${phone.serverPhone}`);
|
||||
const phoneNumber = phone.serverPhone;
|
||||
if (phoneNumber) {
|
||||
Linking.openURL(`tel:${phoneNumber}`).catch(err =>
|
||||
console.error('拨打电话失败:', err)
|
||||
);
|
||||
} else {
|
||||
showToast('电话号码无效', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
const changeTab = (index, id) => {
|
||||
const changeTab = (index: number, id: string) => {
|
||||
setTabindex(index);
|
||||
fetchArticleList(id);
|
||||
};
|
||||
|
||||
const topage = (item) => {
|
||||
navigation.navigate('ArticlePage', { id: item.articleId });
|
||||
const topage = (item: any) => {
|
||||
navigation.navigate('XmlRenderPage', { id: item.articleId });
|
||||
};
|
||||
|
||||
const renderWordList = () => {
|
||||
console.log('当前wordlist数据:', wordlist);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<View style={styles.wordListContainer}>
|
||||
<Text style={styles.loadingText}>加载中...</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!Array.isArray(wordlist) || wordlist.length === 0) {
|
||||
return (
|
||||
<View style={styles.wordListContainer}>
|
||||
<Text style={styles.emptyText}>暂无数据</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.wordListContainer}>
|
||||
{wordlist.map((item, index) => {
|
||||
console.log('渲染列表项:', item.title);
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={item.articleId || index}
|
||||
style={[
|
||||
styles.qsLi,
|
||||
index == wordlist.length - 1 && styles.lastQsLi
|
||||
]}
|
||||
onPress={() => topage(item)}
|
||||
>
|
||||
<Text style={styles.qsLiTxt} numberOfLines={1} ellipsizeMode="tail">
|
||||
{item.title || '无标题'}
|
||||
</Text>
|
||||
<Icon name='arrow-forward' style={styles.icon} />
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const saveWechatQrcode = async () => {
|
||||
try {
|
||||
const writePermission = await request(
|
||||
Platform.select({
|
||||
android: PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE,
|
||||
default: PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE,
|
||||
})
|
||||
);
|
||||
|
||||
if (writePermission !== RESULTS.GRANTED) {
|
||||
showToast('请在设置中授予存储权限', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileName = `wechat_qrcode_${Date.now()}.jpg`;
|
||||
const tempPath = `${RNFS.CachesDirectoryPath}/${fileName}`;
|
||||
|
||||
const uri = await captureRef(qrRef, {
|
||||
format: 'jpg',
|
||||
quality: 1,
|
||||
result: 'base64',
|
||||
});
|
||||
|
||||
await RNFS.writeFile(tempPath, uri, 'base64');
|
||||
|
||||
await Promise.race([
|
||||
new Promise((resolve, reject) => {
|
||||
NativeModules.MediaScanner.scanFile(
|
||||
tempPath,
|
||||
'image/jpeg',
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.warn('MediaScanner warning:', error);
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}),
|
||||
new Promise((resolve) => setTimeout(resolve, 3000))
|
||||
]);
|
||||
|
||||
showToast('二维码已保存到相册', 'success');
|
||||
setShowQrcode(false); // 确保遮罩关闭
|
||||
|
||||
RNFS.unlink(tempPath).catch(e => {
|
||||
console.warn('清理临时文件失败:', e);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Save error:', error);
|
||||
showToast('文件可能已保存到相册,请检查', 'info');
|
||||
}
|
||||
};
|
||||
|
||||
const showToast = (message: string, type: 'success' | 'error' | 'info' = 'info') => {
|
||||
Toast.show({
|
||||
type,
|
||||
text1: message,
|
||||
position: 'top',
|
||||
topOffset: Platform.OS === 'ios' ? 60 : 20,
|
||||
visibilityTime: 2000,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TopNavigation
|
||||
title='帮助中心'
|
||||
alignment='center'
|
||||
accessoryLeft={BackAction}
|
||||
/>
|
||||
<ScrollView contentContainerStyle={styles.content}>
|
||||
<Text category='h5' style={styles.title}>Hi~有什么可以帮您!</Text>
|
||||
<Text category='s1' style={styles.text}>工作时间: 工作日8:30-11:30 13:30-18:00</Text>
|
||||
<View style={styles.helpBtnBox}>
|
||||
<TouchableOpacity style={styles.helpBtnItem} onPress={showWechat}>
|
||||
<View>
|
||||
<Text style={styles.helpBtnItemLeftTit}>微信客服</Text>
|
||||
<Text style={styles.helpBtnItemLeftContent}>为您解答疑惑</Text>
|
||||
<ImageBackground
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uYRs7Cv2Pbp95w3KjGO3' }}
|
||||
style={styles.background}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<TopNavigation
|
||||
title='帮助中心'
|
||||
alignment='center'
|
||||
accessoryLeft={BackAction}
|
||||
style={styles.navbar}
|
||||
/>
|
||||
<ScrollView>
|
||||
<View style={styles.content}>
|
||||
<View style={styles.helpTime}>
|
||||
<View style={styles.helpTimeLeft}>
|
||||
<Text style={styles.helpTimeLeftTit}>Hi~有什么可以帮您!</Text>
|
||||
<Text style={[styles.helpTimeLeftContent, { marginTop: rpx(28) }]}>工作时间:</Text>
|
||||
<Text style={[styles.helpTimeLeftContent, { marginTop: rpx(10) }]}>工作日8:30-11:30 13:30-18:00</Text>
|
||||
</View>
|
||||
<View style={styles.helpTimeRight}>
|
||||
<Image
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uD8eJCmet0KN1WOEJBKZ' }}
|
||||
style={styles.helpTimeRightImg}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<Image source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uP0sux01iWvHzofugDjW' }} style={styles.helpBtnItemRightImg} />
|
||||
</TouchableOpacity>
|
||||
<View style={styles.line}></View>
|
||||
<TouchableOpacity style={styles.helpBtnItem} onPress={callPhone}>
|
||||
<View>
|
||||
<Text style={styles.helpBtnItemLeftTit}>客服电话</Text>
|
||||
<Text style={styles.helpBtnItemLeftContent}>欢迎您拨打提问</Text>
|
||||
</View>
|
||||
<Image source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uKt6yZ7lMykYci7yITT5' }} style={styles.helpBtnItemRightImg} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.qscard}>
|
||||
<View style={styles.cardTop}>
|
||||
{classifyList.map((item, index) => (
|
||||
<TouchableOpacity key={index} style={styles.li} onPress={() => changeTab(index, item.classifyId)}>
|
||||
<Text style={styles.txt}>{item.classifyName}</Text>
|
||||
<View style={tabindex === index ? styles.botBorActive : styles.botBor}></View>
|
||||
|
||||
<View style={styles.helpBtnBox}>
|
||||
<TouchableOpacity style={styles.helpBtnItem} onPress={showWechat}>
|
||||
<View style={styles.helpBtnItemLeft}>
|
||||
<Text style={styles.helpBtnItemLeftTit}>微信客服</Text>
|
||||
<Text style={styles.helpBtnItemLeftContent}>为您解答疑惑</Text>
|
||||
</View>
|
||||
<View style={styles.helpBtnItemRight}>
|
||||
<Image
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uP0sux01iWvHzofugDjW' }}
|
||||
style={styles.helpBtnItemRightImg}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
|
||||
<View style={styles.line}></View>
|
||||
|
||||
<TouchableOpacity style={styles.helpBtnItem} onPress={callPhone}>
|
||||
<View style={styles.helpBtnItemLeft}>
|
||||
<Text style={styles.helpBtnItemLeftTit}>客服电话</Text>
|
||||
<Text style={styles.helpBtnItemLeftContent}>欢迎您拨打提问</Text>
|
||||
</View>
|
||||
<View style={styles.helpBtnItemRight}>
|
||||
<Image
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uKt6yZ7lMykYci7yITT5' }}
|
||||
style={styles.helpBtnItemRightImg}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.qscard}>
|
||||
<View style={styles.cardTop}>
|
||||
{classifyList.map((item, index) => (
|
||||
<TouchableOpacity
|
||||
key={item.classifyId || index}
|
||||
style={styles.li}
|
||||
onPress={() => changeTab(index, item.classifyId)}
|
||||
>
|
||||
<Text style={styles.txt}>{item.classifyName}</Text>
|
||||
<View style={[styles.botBor, tabindex === index && styles.botBorActive]}></View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
<View style={styles.wordListWrapper}>
|
||||
{renderWordList()}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
{wordlist.map((item, index) => (
|
||||
<TouchableOpacity key={index} style={styles.qsLi} onPress={() => topage(item)}>
|
||||
<Text style={styles.qsLiTxt}>{item.title}</Text>
|
||||
<Icon name='arrow-forward' style={styles.icon} />
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
{showQrcode && (
|
||||
<View style={styles.qrcodeContainer}>
|
||||
<Text style={styles.qrcodeTitle}>微信客服</Text>
|
||||
<Image source={{ uri: phone.serverWx }} style={styles.qrcodeImage} />
|
||||
<Button onPress={() => setShowQrcode(false)}>关闭</Button>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<Modal visible={showQrcode} transparent={true} animationType="fade">
|
||||
<TouchableOpacity
|
||||
style={styles.mask}
|
||||
activeOpacity={1}
|
||||
onPress={() => setShowQrcode(false)}
|
||||
>
|
||||
<View style={styles.qrcodeBox} >
|
||||
<Text style={styles.qrcodeTitle}>微信客服</Text>
|
||||
<Image source={{ uri: phone.serverWx }} style={styles.qrcodeImg} ref={qrRef}/>
|
||||
<TouchableOpacity style={styles.qrcodeBtn} onPress={saveWechatQrcode}>
|
||||
<Text style={styles.qrcodeBtnText}>保存二维码</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.closeBtn}
|
||||
onPress={() => setShowQrcode(false)}
|
||||
>
|
||||
<Text style={styles.closeBtnText}>×</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
</View>
|
||||
<Toast />
|
||||
</ImageBackground>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wordListWrapper: {
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
},
|
||||
background: {
|
||||
flex: 1,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#f5f5f5',
|
||||
},
|
||||
navbar: {
|
||||
backgroundColor: 'transparent',
|
||||
height: rpx(90),
|
||||
},
|
||||
content: {
|
||||
padding: rpx(16),
|
||||
paddingLeft: rpx(40),
|
||||
paddingRight: rpx(64),
|
||||
},
|
||||
title: {
|
||||
fontSize: rpx(36),
|
||||
helpTime: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
helpTimeLeft: {
|
||||
marginLeft: rpx(40),
|
||||
},
|
||||
helpTimeLeftTit: {
|
||||
fontWeight: '700',
|
||||
fontSize: rpx(36),
|
||||
color: '#3D3D3D',
|
||||
marginBottom: rpx(10),
|
||||
},
|
||||
text: {
|
||||
fontSize: rpx(24),
|
||||
helpTimeLeftContent: {
|
||||
fontWeight: '400',
|
||||
fontSize: rpx(24),
|
||||
color: '#3D3D3D',
|
||||
marginVertical: rpx(8),
|
||||
},
|
||||
helpTimeRight: {
|
||||
justifyContent: 'center',
|
||||
},
|
||||
helpTimeRightImg: {
|
||||
width: rpx(168),
|
||||
height: rpx(154),
|
||||
},
|
||||
helpBtnBox: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: rpx(50),
|
||||
width: rpx(644),
|
||||
padding: rpx(20),
|
||||
paddingHorizontal: rpx(38),
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: rpx(20),
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: rpx(6) },
|
||||
shadowOpacity: 0.08,
|
||||
shadowRadius: rpx(64),
|
||||
borderRadius: rpx(20),
|
||||
},
|
||||
helpBtnItem: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
helpBtnItemLeft: {},
|
||||
helpBtnItemLeftTit: {
|
||||
fontWeight: '700',
|
||||
fontSize: rpx(28),
|
||||
|
@ -166,22 +400,24 @@ const styles = StyleSheet.create({
|
|||
fontSize: rpx(24),
|
||||
color: '#3D3D3D',
|
||||
},
|
||||
helpBtnItemRight: {},
|
||||
helpBtnItemRightImg: {
|
||||
width: rpx(84),
|
||||
height: rpx(84),
|
||||
},
|
||||
line: {
|
||||
marginHorizontal: rpx(20),
|
||||
width: rpx(2),
|
||||
height: rpx(128),
|
||||
backgroundColor: '#D8D8D8',
|
||||
marginHorizontal: rpx(20),
|
||||
},
|
||||
qscard: {
|
||||
width: '100%',
|
||||
width: rpx(680),
|
||||
marginVertical: rpx(40),
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: rpx(40),
|
||||
padding: rpx(28),
|
||||
paddingHorizontal: rpx(30),
|
||||
shadowColor: '#2A82E4',
|
||||
shadowOffset: { width: 0, height: rpx(16) },
|
||||
shadowOpacity: 0.1,
|
||||
|
@ -190,67 +426,124 @@ const styles = StyleSheet.create({
|
|||
cardTop: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'nowrap',
|
||||
},
|
||||
li: {
|
||||
minWidth: rpx(112),
|
||||
marginRight: rpx(20),
|
||||
},
|
||||
txt: {
|
||||
width: rpx(150),
|
||||
fontWeight: '500',
|
||||
fontSize: rpx(28),
|
||||
color: '#3D3D3D',
|
||||
zIndex: 1,
|
||||
},
|
||||
botBor: {
|
||||
marginTop: rpx(-20),
|
||||
width: '90%',
|
||||
height: rpx(26),
|
||||
backgroundColor: '#fff',
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: rpx(20),
|
||||
zIndex: 0,
|
||||
},
|
||||
botBorActive: {
|
||||
marginTop: rpx(-20),
|
||||
width: '90%',
|
||||
height: rpx(26),
|
||||
backgroundColor: 'rgba(66, 151, 243, 0.55)',
|
||||
borderRadius: rpx(20),
|
||||
},
|
||||
wordListContainer: {
|
||||
marginTop: rpx(20),
|
||||
paddingHorizontal: rpx(20),
|
||||
},
|
||||
qsLi: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
borderBottomWidth: rpx(2),
|
||||
borderBottomColor: '#D8D8D870',
|
||||
borderBottomColor: 'rgba(216, 216, 216, 0.44)',
|
||||
paddingVertical: rpx(26),
|
||||
},
|
||||
lastQsLi: {
|
||||
borderBottomWidth: rpx(2),
|
||||
borderBottomColor: '#FFFFFF',
|
||||
},
|
||||
qsLiTxt: {
|
||||
flex: 1,
|
||||
fontWeight: '400',
|
||||
fontSize: rpx(28),
|
||||
color: '#3D3D3D',
|
||||
marginRight: rpx(20),
|
||||
},
|
||||
icon: {
|
||||
fontSize: rpx(32),
|
||||
color: '#3D3D3D',
|
||||
width: rpx(32),
|
||||
height: rpx(32),
|
||||
},
|
||||
qrcodeContainer: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
txtActive: {
|
||||
color: '#4297F3',
|
||||
fontWeight: '500',
|
||||
},
|
||||
mask: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
qrcodeBox: {
|
||||
width: rpx(600),
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: rpx(20),
|
||||
padding: rpx(40),
|
||||
position: 'relative',
|
||||
},
|
||||
qrcodeTitle: {
|
||||
fontSize: rpx(32),
|
||||
fontWeight: '500',
|
||||
color: '#333',
|
||||
textAlign: 'center',
|
||||
marginBottom: rpx(30),
|
||||
color: '#333',
|
||||
},
|
||||
qrcodeImage: {
|
||||
width: rpx(200),
|
||||
height: rpx(200),
|
||||
marginBottom: rpx(20),
|
||||
qrcodeImg: {
|
||||
width: rpx(400),
|
||||
height: rpx(450),
|
||||
alignSelf: 'center',
|
||||
},
|
||||
qrcodeBtn: {
|
||||
width: rpx(400),
|
||||
height: rpx(80),
|
||||
backgroundColor: '#4297F3',
|
||||
borderRadius: rpx(40),
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: rpx(40),
|
||||
alignSelf: 'center',
|
||||
},
|
||||
qrcodeBtnText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: rpx(28),
|
||||
},
|
||||
closeBtn: {
|
||||
position: 'absolute',
|
||||
right: rpx(20),
|
||||
top: rpx(20),
|
||||
width: rpx(60),
|
||||
height: rpx(60),
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
closeBtnText: {
|
||||
fontSize: rpx(40),
|
||||
color: '#999',
|
||||
},
|
||||
loadingText: {
|
||||
textAlign: 'center',
|
||||
padding: rpx(20),
|
||||
color: '#666',
|
||||
fontSize: rpx(28),
|
||||
},
|
||||
emptyText: {
|
||||
textAlign: 'center',
|
||||
padding: rpx(20),
|
||||
color: '#999',
|
||||
fontSize: rpx(28),
|
||||
},
|
||||
});
|
||||
|
||||
|
|
112
src/views/user/XmlRenderPage.tsx
Normal file
112
src/views/user/XmlRenderPage.tsx
Normal file
|
@ -0,0 +1,112 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { View, StyleSheet, ActivityIndicator } from 'react-native';
|
||||
import { WebView } from 'react-native-webview';
|
||||
import { TopNavigation, TopNavigationAction, Icon, IconElement } from '@ui-kitten/components';
|
||||
import { useRoute, useNavigation } from '@react-navigation/native';
|
||||
import { apiService } from '../../utils/api';
|
||||
import { rpx } from '../../utils/rpx';
|
||||
|
||||
const BackIcon = (props): IconElement => (
|
||||
<Icon
|
||||
{...props}
|
||||
name='arrow-back'
|
||||
fill='#000000'
|
||||
/>
|
||||
);
|
||||
|
||||
const XmlRenderPage = () => {
|
||||
const navigation = useNavigation();
|
||||
const route = useRoute();
|
||||
const [xmlContent, setXmlContent] = useState('');
|
||||
const [title, setTitle] = useState('详情');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { id } = route.params;
|
||||
|
||||
const navigateBack = () => {
|
||||
navigation.goBack();
|
||||
};
|
||||
|
||||
const BackAction = () => (
|
||||
<TopNavigationAction
|
||||
icon={BackIcon}
|
||||
onPress={navigateBack}
|
||||
/>
|
||||
);
|
||||
|
||||
const replaceImgWithImage = (content) => {
|
||||
// 替换所有的 为 \u00A0
|
||||
content = content.replace(/ /g, '\u00A0');
|
||||
|
||||
// 替换 <img> 标签的宽度和高度样式
|
||||
content = content.replace(/<img([^>]*)>/g, (match, group1) => {
|
||||
// 查找并移除可能存在的尾部斜杠
|
||||
let cleanedGroup = group1.replace(/\s*\/$/, '');
|
||||
return `<img style="width: 85vw; height: auto;" ${cleanedGroup} />`;
|
||||
});
|
||||
|
||||
return content;
|
||||
};
|
||||
|
||||
const fetchArticleById = async () => {
|
||||
console.log(id, 'id');
|
||||
const response = await apiService.getArticleById(id);
|
||||
console.log(response, '1111111111111');
|
||||
const modifiedContent = replaceImgWithImage(response.data.content);
|
||||
setXmlContent(modifiedContent);
|
||||
setTitle(response.data.title || '详情');
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchArticleById();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<TopNavigation
|
||||
title={title}
|
||||
alignment='center'
|
||||
accessoryLeft={BackAction}
|
||||
style={styles.header}
|
||||
/>
|
||||
{loading ? (
|
||||
<ActivityIndicator size="large" color="#0000ff" style={styles.loading} />
|
||||
) : (
|
||||
<WebView
|
||||
originWhitelist={['*']}
|
||||
source={{ html: xmlContent }}
|
||||
style={styles.webview}
|
||||
scalesPageToFit={false}
|
||||
injectedJavaScript={`
|
||||
const meta = document.createElement('meta');
|
||||
meta.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=1');
|
||||
meta.setAttribute('name', 'viewport');
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
backgroundColor: 'transparent',
|
||||
elevation: 0,
|
||||
shadowOpacity: 0,
|
||||
},
|
||||
webview: {
|
||||
width: rpx(750),
|
||||
flex: 1,
|
||||
},
|
||||
loading: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
export default XmlRenderPage;
|
355
src/views/user/feedback.tsx
Normal file
355
src/views/user/feedback.tsx
Normal file
|
@ -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) => (
|
||||
<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;
|
Loading…
Reference in New Issue
Block a user