帮助中心已经xml文档
This commit is contained in:
parent
52c771c22a
commit
0cd54ba8ec
|
@ -19,6 +19,7 @@ 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';
|
||||
const Stack = createStackNavigator<HomeStackParamList>();
|
||||
|
||||
const createScreenOptions = (title: string): StackNavigationOptions => {
|
||||
|
@ -82,6 +83,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,7 @@ export type HomeStackParamList = {
|
|||
ExpiredKeysScreen: undefined;
|
||||
deviceDetailSet: undefined;
|
||||
HelpCenterPage: undefined;
|
||||
XmlRenderPage: undefined;
|
||||
};
|
||||
|
||||
// 导航属性类型
|
||||
|
|
|
@ -140,5 +140,8 @@ 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),
|
||||
// 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',
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { View, StyleSheet, ScrollView, Image, TouchableOpacity, Alert, Modal, Text, ImageBackground } from 'react-native';
|
||||
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: any) => (
|
||||
<Icon {...props} name='arrow-back' />
|
||||
|
@ -15,21 +19,22 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
const [wordlist, setWordlist] = useState([]);
|
||||
const [tabindex, setTabindex] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const qrRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
const initData = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const classifyResponse = await apiService.getClassifyList();
|
||||
console.log('分类数据:', classifyResponse); // 添加日志
|
||||
console.log('分类数据:', classifyResponse);
|
||||
|
||||
if (classifyResponse?.data?.length > 0) {
|
||||
setClassifyList(classifyResponse.data);
|
||||
const firstClassifyId = classifyResponse.data[0].classifyId;
|
||||
console.log('第一个分类ID:', firstClassifyId); // 添加日志
|
||||
console.log('第一个分类ID:', firstClassifyId);
|
||||
|
||||
const articleResponse = await apiService.getArticleList(firstClassifyId);
|
||||
console.log('文章列表数据:', articleResponse); // 添加日志
|
||||
console.log('文章列表数据:', articleResponse);
|
||||
|
||||
if (articleResponse?.rows) {
|
||||
setWordlist(articleResponse.rows);
|
||||
|
@ -66,9 +71,9 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
console.log('获取文章列表,分类ID:', id); // 添加日志
|
||||
console.log('获取文章列表,分类ID:', id);
|
||||
const response = await apiService.getArticleList(id);
|
||||
console.log('获取到的文章列表:', response); // 添加日志
|
||||
console.log('获取到的文章列表:', response);
|
||||
|
||||
if (response?.rows) {
|
||||
setWordlist(response.rows);
|
||||
|
@ -88,7 +93,14 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
};
|
||||
|
||||
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: number, id: string) => {
|
||||
|
@ -97,11 +109,11 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
};
|
||||
|
||||
const topage = (item: any) => {
|
||||
navigation.navigate('ArticlePage', { id: item.articleId });
|
||||
navigation.navigate('XmlRenderPage', { id: item.articleId });
|
||||
};
|
||||
|
||||
const renderWordList = () => {
|
||||
console.log('当前wordlist数据:', wordlist); // 添加日志
|
||||
console.log('当前wordlist数据:', wordlist);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
|
@ -122,7 +134,7 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
return (
|
||||
<View style={styles.wordListContainer}>
|
||||
{wordlist.map((item, index) => {
|
||||
console.log('渲染列表项:', item.title); // 添加日志
|
||||
console.log('渲染列表项:', item.title);
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={item.articleId || index}
|
||||
|
@ -143,6 +155,72 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<ImageBackground
|
||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uYRs7Cv2Pbp95w3KjGO3' }}
|
||||
|
@ -210,7 +288,6 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
onPress={() => changeTab(index, item.classifyId)}
|
||||
>
|
||||
<Text style={styles.txt}>{item.classifyName}</Text>
|
||||
{/* <Text style={styles.txt}>{wordlist[0].title}</Text> */}
|
||||
<View style={[styles.botBor, tabindex === index && styles.botBorActive]}></View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
|
@ -228,10 +305,10 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
activeOpacity={1}
|
||||
onPress={() => setShowQrcode(false)}
|
||||
>
|
||||
<View style={styles.qrcodeBox}>
|
||||
<View style={styles.qrcodeBox} >
|
||||
<Text style={styles.qrcodeTitle}>微信客服</Text>
|
||||
<Image source={{ uri: phone.serverWx }} style={styles.qrcodeImg} />
|
||||
<TouchableOpacity style={styles.qrcodeBtn}>
|
||||
<Image source={{ uri: phone.serverWx }} style={styles.qrcodeImg} ref={qrRef}/>
|
||||
<TouchableOpacity style={styles.qrcodeBtn} onPress={saveWechatQrcode}>
|
||||
<Text style={styles.qrcodeBtnText}>保存二维码</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
|
@ -244,15 +321,16 @@ const HelpCenterPage = ({ navigation }: { navigation: any }) => {
|
|||
</TouchableOpacity>
|
||||
</Modal>
|
||||
</View>
|
||||
<Toast />
|
||||
</ImageBackground>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wordListWrapper: {
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
},
|
||||
wordListWrapper: {
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
},
|
||||
background: {
|
||||
flex: 1,
|
||||
},
|
||||
|
@ -374,27 +452,26 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
wordListContainer: {
|
||||
marginTop: rpx(20),
|
||||
paddingHorizontal: rpx(20), // 添加水平内边距
|
||||
paddingHorizontal: rpx(20),
|
||||
},
|
||||
qsLi: {
|
||||
qsLi: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
borderBottomWidth: rpx(2),
|
||||
borderBottomColor: 'rgba(216, 216, 216, 0.44)',
|
||||
paddingVertical: rpx(26),
|
||||
// 移除 width: '100%'
|
||||
},
|
||||
lastQsLi: {
|
||||
borderBottomWidth: rpx(2),
|
||||
borderBottomColor: '#FFFFFF',
|
||||
},
|
||||
qsLiTxt: {
|
||||
flex: 1, // 让文本占据剩余空间
|
||||
flex: 1,
|
||||
fontWeight: '400',
|
||||
fontSize: rpx(28),
|
||||
color: '#3D3D3D',
|
||||
marginRight: rpx(20), // 改用 marginRight 替代 paddingRight
|
||||
marginRight: rpx(20),
|
||||
},
|
||||
icon: {
|
||||
width: rpx(32),
|
||||
|
|
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;
|
Loading…
Reference in New Issue
Block a user