|
|
@@ -0,0 +1,290 @@
|
|
|
+/**
|
|
|
+ * V3版搜索页
|
|
|
+ * @邠心vbe on 2024/05/11
|
|
|
+ */
|
|
|
+import React, { Component } from 'react';
|
|
|
+import { View, Text, StyleSheet, TextInput, FlatList, Image } from 'react-native';
|
|
|
+import apiStation from '../../api/apiStation';
|
|
|
+import Dialog from '../../components/Dialog';
|
|
|
+import utils from '../../utils/utils';
|
|
|
+import { PageList } from '../Router';
|
|
|
+import ListViewV3 from './ListViewV3';
|
|
|
+
|
|
|
+export default class SearchV3 extends Component {
|
|
|
+ constructor(props) {
|
|
|
+ super(props);
|
|
|
+ this.state = {
|
|
|
+ isSearch: false,
|
|
|
+ searchResult: [{id:0}],
|
|
|
+ searchWorld: "",
|
|
|
+ latlng: {
|
|
|
+ lat: 0.00001,
|
|
|
+ lng: 0.00001
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ componentDidMount() {
|
|
|
+ this.getGeoLocation();
|
|
|
+ }
|
|
|
+
|
|
|
+ changeWord(word) {
|
|
|
+ this.setState({
|
|
|
+ searchWorld: word
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ getGeoLocation() {
|
|
|
+ navigator.geolocation.getCurrentPosition(location => {
|
|
|
+ let latlng = {
|
|
|
+ lat: location.coords.latitude,
|
|
|
+ lng: location.coords.longitude
|
|
|
+ }
|
|
|
+ this.setState({
|
|
|
+ latlng: latlng
|
|
|
+ })
|
|
|
+ this.searchStation(latlng);
|
|
|
+ }, error => {
|
|
|
+ console.info("[Search] getGeoLocation", error);
|
|
|
+ this.searchStation(this.state.latlng);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ searchStation(latlng, time=100) {
|
|
|
+ this.setState({
|
|
|
+ isSearch: true
|
|
|
+ });
|
|
|
+ latlng.siteName = this.state.searchWorld
|
|
|
+ apiStation.searchStation(latlng).then(res => {
|
|
|
+ if (res.data.sites) {
|
|
|
+ const list = [];
|
|
|
+ res.data.sites.forEach(item => {
|
|
|
+ list.push({
|
|
|
+ id: item.sitePk,
|
|
|
+ name: item.siteName,
|
|
|
+ address: item.siteAddress,
|
|
|
+ latitude: item.locationLatitude,
|
|
|
+ longitude: item.locationLongitude,
|
|
|
+ acConnector: item.acConnector,
|
|
|
+ allConnector: item.allConnector,
|
|
|
+ dcConnector: item.dcConnector,
|
|
|
+ siteType: item.siteType,
|
|
|
+ favorite: item.favorite,
|
|
|
+ upcoming: item.upcoming,
|
|
|
+ labels: item.siteLabels,
|
|
|
+ distance: utils.getDistance(item.distance),
|
|
|
+ serviceProvider: item.serviceProvider
|
|
|
+ });
|
|
|
+ });
|
|
|
+ setTimeout(() => {
|
|
|
+ this.setState({
|
|
|
+ isSearch: false,
|
|
|
+ searchResult: list
|
|
|
+ });
|
|
|
+ }, time);
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ console.log('searchStation-err', err);
|
|
|
+ this.setState({
|
|
|
+ isSearch: false,
|
|
|
+ searchResult: []
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ favoriteSite(index, info) {
|
|
|
+ if (info?.id) {
|
|
|
+ Dialog.showProgressDialog();
|
|
|
+ apiStation.bookmarkSite(info.id).then(res => {
|
|
|
+ if (index >= 0) {
|
|
|
+ const list = [...this.state.searchResult];
|
|
|
+ list[index].favorite = !info.favorite;
|
|
|
+ this.setState({
|
|
|
+ searchResult: list
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ toastShort(err);
|
|
|
+ }).finally(() => {
|
|
|
+ Dialog.dismissLoading();
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ intoStation(info) {
|
|
|
+ if (info.upcoming) {
|
|
|
+ toastShort($t("home.upcoming"))
|
|
|
+ } else {
|
|
|
+ utils.toChargeDetailPage(info.id, 'search', PageList.search);
|
|
|
+ //startPage(PageList.chargeDetailPage, {stationInfo: info, action: 'search', from: PageList.search});
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ listItem = (props) => {
|
|
|
+ return (
|
|
|
+ <ListViewV3
|
|
|
+ {...props}
|
|
|
+ onPress={() => this.intoStation(props.item)}
|
|
|
+ onFavorite={() => this.favoriteSite(props.index, props.item)}/>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+ return (
|
|
|
+ <View style={styles.container}>
|
|
|
+ <View style={styles.searchView}>
|
|
|
+ <Feather
|
|
|
+ name={'search'}
|
|
|
+ size={20}
|
|
|
+ color={textSecondary}/>
|
|
|
+ <TextInput
|
|
|
+ style={styles.searchInput}
|
|
|
+ autoFocus={true}
|
|
|
+ maxLength={50}
|
|
|
+ numberOfLines={1}
|
|
|
+ returnKeyType={'search'}
|
|
|
+ clearButtonMode={'while-editing'}
|
|
|
+ placeholder={"Search by Postal Code, Address, Site Name"}
|
|
|
+ placeholderTextColor={textPlacehoder}
|
|
|
+ value={this.state.searchWorld}
|
|
|
+ onChangeText={text => this.changeWord(text)}
|
|
|
+ onSubmitEditing={() => {
|
|
|
+ //this.getGeoLocation();
|
|
|
+ this.searchStation(this.state.latlng, 300);
|
|
|
+ }}/>
|
|
|
+ { utils.isNotEmpty(this.state.searchWorld) &&
|
|
|
+ <MaterialCommunityIcons
|
|
|
+ name="close-circle"
|
|
|
+ size={20}
|
|
|
+ color={textCancel}
|
|
|
+ onPress={() => this.changeWord("")}/>
|
|
|
+ }
|
|
|
+ </View>
|
|
|
+ { this.state.isSearch
|
|
|
+ ? <View style={styles.searchingView}>
|
|
|
+ <Image
|
|
|
+ style={styles.seachingIcon}
|
|
|
+ source={require('../../images/icon/search-loading.gif')}/>
|
|
|
+ </View>
|
|
|
+ : <FlatList
|
|
|
+ style={styles.listView}
|
|
|
+ data={this.state.searchResult}
|
|
|
+ renderItem={this.listItem}
|
|
|
+ keyExtractor={item => item.id}
|
|
|
+ keyboardShouldPersistTaps="always"
|
|
|
+ ListEmptyComponent={<Text style={styles.noResult}>{$t('home.noSearch')}</Text>}
|
|
|
+ />
|
|
|
+ }
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const styles = StyleSheet.create({
|
|
|
+ container: {
|
|
|
+ flex: 1,
|
|
|
+ backgroundColor: pageBackground
|
|
|
+ },
|
|
|
+ searchView: {
|
|
|
+ margin: 16,
|
|
|
+ ...$padding(2, 16),
|
|
|
+ borderRadius: 60,
|
|
|
+ borderWidth: 1,
|
|
|
+ borderColor: '#E5E5E5',
|
|
|
+ alignItems: 'center',
|
|
|
+ flexDirection: 'row',
|
|
|
+ backgroundColor: '#F5F5F5'
|
|
|
+ },
|
|
|
+ searchInput: {
|
|
|
+ flex: 1,
|
|
|
+ color: textPrimary,
|
|
|
+ ...$padding(6, 8),
|
|
|
+ fontSize: 15,
|
|
|
+ marginLeft: 4,
|
|
|
+ lineHeight: 20
|
|
|
+ },
|
|
|
+ searchingView: {
|
|
|
+ padding: 16,
|
|
|
+ alignItems: 'center'
|
|
|
+ },
|
|
|
+ seachingIcon: {
|
|
|
+ width: 60,
|
|
|
+ height: 60
|
|
|
+ },
|
|
|
+ noResult: {
|
|
|
+ color: '#999',
|
|
|
+ fontSize: 14,
|
|
|
+ padding: 20,
|
|
|
+ textAlign: 'center',
|
|
|
+ },
|
|
|
+ listView: {
|
|
|
+ flex: 1
|
|
|
+ },
|
|
|
+ itemView: {
|
|
|
+ alignItems: 'center',
|
|
|
+ flexDirection: 'row',
|
|
|
+ borderBottomWidth: 1,
|
|
|
+ borderBottomColor: '#eee'
|
|
|
+ },
|
|
|
+ stationInfo: {
|
|
|
+ flex: 1,
|
|
|
+ padding: 16
|
|
|
+ },
|
|
|
+ nameView: {
|
|
|
+ paddingTop: 3,
|
|
|
+ alignItems: 'center',
|
|
|
+ flexDirection: 'row'
|
|
|
+ },
|
|
|
+ stationName: {
|
|
|
+ color: textPrimary,
|
|
|
+ fontSize: 18,
|
|
|
+ fontWeight: 'bold'
|
|
|
+ },
|
|
|
+ stationAddress: {
|
|
|
+ color: '#666',
|
|
|
+ fontSize: 14,
|
|
|
+ paddingBottom: 8
|
|
|
+ },
|
|
|
+ infoStatus: {
|
|
|
+ fontSize: 10,
|
|
|
+ paddingTop: 3,
|
|
|
+ paddingLeft: 8,
|
|
|
+ paddingRight: 8,
|
|
|
+ paddingBottom: 3,
|
|
|
+ borderRadius: 5,
|
|
|
+ marginLeft: 12,
|
|
|
+ },
|
|
|
+ selected: {
|
|
|
+ color: textPrimary,
|
|
|
+ backgroundColor: colorAccent
|
|
|
+ },
|
|
|
+ available: {
|
|
|
+ color: textLight,
|
|
|
+ backgroundColor: '#90DB0A'
|
|
|
+ },
|
|
|
+ unavailable: {
|
|
|
+ color: '#999',
|
|
|
+ fontSize: 10.5,
|
|
|
+ paddingTop: 7,
|
|
|
+ paddingLeft: 9,
|
|
|
+ paddingRight: 9,
|
|
|
+ paddingBottom: 7,
|
|
|
+ backgroundColor: '#CCC'
|
|
|
+ },
|
|
|
+ connectView: {
|
|
|
+ paddingTop: 4,
|
|
|
+ paddingBottom: 4,
|
|
|
+ alignItems: 'center',
|
|
|
+ flexDirection: 'row'
|
|
|
+ },
|
|
|
+ directView: {
|
|
|
+ zIndex: 1,
|
|
|
+ paddingRight: 16,
|
|
|
+ alignItems: 'center'
|
|
|
+ },
|
|
|
+ distanceText: {
|
|
|
+ color: textPrimary,
|
|
|
+ fontSize: 12,
|
|
|
+ paddingTop: 2
|
|
|
+ }
|
|
|
+});
|