drew 5 лет назад
Родитель
Сommit
8bc56aeb4a
10 измененных файлов с 273 добавлено и 295 удалено
  1. 1 0
      package.json
  2. 8 1
      project.config.json
  3. 6 26
      src/main.js
  4. 0 82
      src/pages/hello.vue
  5. 113 60
      src/pages/home.vue
  6. 0 83
      src/pages/my/my.vue
  7. 137 0
      src/pages/search.vue
  8. 0 40
      src/pages/vuex/vuex.vue
  9. 3 3
      src/styles/common.less
  10. 5 0
      yarn.lock

+ 1 - 0
package.json

@@ -38,6 +38,7 @@
     "@megalo/api": "latest",
     "@megalo/vhtml-plugin": "latest",
     "@vant/weapp": "^1.4.4",
+    "date-fns": "^2.15.0",
     "megalo": "latest",
     "octoparse": "^0.4.2",
     "style-resources-loader": "^1.3.3",

+ 8 - 1
project.config.json

@@ -60,7 +60,14 @@
         },
         "miniprogram": {
             "current": -1,
-            "list": []
+            "list": [
+                {
+                    "id": -1,
+                    "name": "搜索",
+                    "pathName": "pages/search",
+                    "scene": null
+                }
+            ]
         }
     }
 }

+ 6 - 26
src/main.js

@@ -22,31 +22,7 @@ app.$mount();
 export default {
     config: {
         // pages 的首个页面会被编译成首页
-        pages: ['pages/home', 'pages/hello', 'pages/my/my', 'pages/vuex/vuex'],
-        tabBar: {
-            color: '#333',
-            selectedColor: '#007d37',
-            list: [
-                {
-                    pagePath: 'pages/hello',
-                    text: 'home',
-                    iconPath: 'native/tabbar/home.png',
-                    selectedIconPath: 'native/tabbar/home_on.png'
-                },
-                {
-                    pagePath: 'pages/my/my',
-                    text: 'my',
-                    iconPath: 'native/tabbar/mine.png',
-                    selectedIconPath: 'native/tabbar/mine_on.png'
-                },
-                {
-                    pagePath: 'pages/vuex/vuex',
-                    text: 'vuex',
-                    iconPath: 'native/tabbar/vue.png',
-                    selectedIconPath: 'native/tabbar/vue_on.png'
-                }
-            ]
-        },
+        pages: ['pages/home', 'pages/search'],
         window: {
             backgroundTextStyle: 'light',
             navigationBarBackgroundColor: '#fff',
@@ -60,7 +36,11 @@ export default {
             'van-notice-bar': '/native/vant/notice-bar/index',
             'van-icon': '/native/vant/icon/index',
             'van-grid-item ': '/native/vant/grid-item/index',
-            'van-dialog': '/native/vant/dialog/index'
+            'van-dialog': '/native/vant/dialog/index',
+            'van-search': '/native/vant/search/index',
+            'van-empty': '/native/vant/empty/index',
+            'van-sticky': '/native/vant/sticky/index',
+            'van-loading': '/native/vant/loading/index'
         },
         permission: {
             'scope.userLocation': {

+ 0 - 82
src/pages/hello.vue

@@ -1,82 +0,0 @@
-<template>
-    <div class="app">
-        <img class="img" src="../static/imgs/megalo_logo.png" @touchstart="changeStat" />
-        <hello-world :color="color"></hello-world>
-        <h1 class="txt" v-show="t % 2 == 1">click logo::{{ t }}</h1>
-    </div>
-</template>
-
-<script>
-import HelloWorld from '@/components/HelloWorld.vue';
-export default {
-    components: {
-        HelloWorld
-    },
-    data() {
-        return {
-            t: 1,
-            color: '#007d37'
-        };
-    },
-    beforeCreate() {
-        console.log('Page [hello] Vue beforeCreate');
-    },
-    created() {
-        console.log('Page [hello] Vue created');
-        var appInstance = getApp();
-        console.log(appInstance.globalData); // I am global data
-    },
-    beforeMount() {
-        console.log('Page [hello] Vue beforeMount');
-    },
-    mounted() {
-        console.log('Page [hello] Vue mounted');
-    },
-    onLoad(options) {
-        // Do some initialize when page load.
-        console.log('Page [hello] onLoad');
-    },
-    onReady() {
-        // Do something when page ready.
-        console.log('Page [hello] onReady');
-    },
-    onShow() {
-        // Do something when page show.
-        console.log('Page [hello] onShow');
-    },
-    onHide() {
-        // Do something when page hide.
-        console.log('Page [hello] onHide');
-    },
-    onUnload() {
-        // Do something when page close.
-        console.log('Page [hello] onUnload');
-    },
-    /**
-     * for other event handlers, please check https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/page.html
-     */
-    methods: {
-        changeStat() {
-            this.t++;
-            this.color = '#' + Math.floor(Math.random() * 0xffffff).toString(16);
-        }
-    }
-};
-</script>
-
-<style lang="less" scoped>
-.app {
-    padding-top: 100px;
-    .img {
-        display: block;
-        height: 120px;
-        width: 138px;
-        margin: 20px auto;
-    }
-    .txt {
-        color: #567567;
-        font-size: 13px;
-        text-align: center;
-    }
-}
-</style>

+ 113 - 60
src/pages/home.vue

@@ -9,11 +9,11 @@
             id="map"
             :style="{ height: mapHeight }"
             :markers="markers"
-            :latitude="center.latitude"
-            :longitude="center.longitude"
             :scale="zoom"
+            :show-location="true"
             @markertap="markerTap"
             @labeltap="markerTap"
+            @regionchange="regionChange"
         >
             <div class="menus">
                 <div class="item">
@@ -26,8 +26,10 @@
                 </div>
             </div>
             <img class="map-picker" src="/native/images/icon_picker.png" />
-            <div class="btn-locate" @click="locate">
-                <van-icon name="aim" />
+            <div class="btn-locate-wrapper" @click="locate">
+                <div class="btn-locate">
+                    <van-icon name="aim" />
+                </div>
             </div>
         </map>
         <div class="content-container">
@@ -42,10 +44,10 @@
                 <van-tab title="选我预约" :name="1"></van-tab>
             </van-tabs>
             <div class="tab-page" :style="{ height: '180px' }">
-                <div class="row">
+                <div class="row" @click="search">
                     <div class="name">
                         <div class="indicator"></div>
-                        <div class="name-content">鸡鸣寺</div>
+                        <div class="name-content">{{ statusLabel }}</div>
                         <van-icon name="arrow" />
                     </div>
                     <!-- <div class="tip">点击可手动选择更换景区</div> -->
@@ -55,7 +57,7 @@
                     <div class="name-content">预约时间 6月17日 19:00</div>
                     <van-icon name="arrow" />
                 </div>
-                <div class="row time">营业时间:09:00-18:00</div>
+                <div class="row time" v-if="openTime">{{ openTime.time }}</div>
                 <div class="nums">
                     可借眼镜:
                     <span class="num" style="margin-right:15px">1副</span>
@@ -91,15 +93,13 @@
 
 <script>
 import { mapState } from 'vuex';
+import { getDay } from 'date-fns';
 export default {
     name: 'home',
     data() {
         return {
             mapHeight: '500px',
-            center: {
-                latitude: 32.00335,
-                longitude: 118.73145
-            },
+            mapCtx: null,
             zoom: 13,
             tab: 0,
             locationStatus: 'loading',
@@ -107,28 +107,16 @@ export default {
             showGetUserInfoDialog: false,
             showLocationDialog: false,
             myLocation: null,
-            scenics: []
+            scenics: [],
+            currentScenic: null,
+            getScenicFlag: false,
+            status: 'loading'
         };
     },
     computed: {
         ...mapState(['safeAreaTop', 'safeAreaBottom']),
         markers() {
             let markers = [];
-            if (this.myLocation) {
-                markers.push({
-                    latitude: this.myLocation.latitude,
-                    longitude: this.myLocation.longitude,
-                    id: 'location',
-                    iconPath: '/native/images/icon_location.png',
-                    width: 34,
-                    height: 34,
-                    anchor: {
-                        x: 0.5,
-                        y: 0.5
-                    },
-                    rotate: this.myLocation.rotate
-                });
-            }
             this.scenics.forEach(i => {
                 markers.push({
                     id: i.id,
@@ -137,6 +125,7 @@ export default {
                     iconPath: '/native/images/icon_dot.png',
                     width: 10,
                     height: 10,
+                    anchor: { x: 0.5, y: 0.5 },
                     label: {
                         content: i.name,
                         color: '#07c160',
@@ -150,8 +139,28 @@ export default {
                     }
                 });
             });
-            console.log(markers);
             return markers;
+        },
+        statusLabel() {
+            switch (this.status) {
+                case 'success':
+                    return this.currentScenic.name;
+                case 'loading':
+                    return '正在获取附近的景区...';
+                case 'fail':
+                    return '获取附近景区失败,请手动选择';
+                default:
+                    return '获取附近景区失败,请手动选择';
+            }
+        },
+        openTime() {
+            if (!this.currentScenic) return null;
+            const weekDay = getDay(new Date());
+            let i = this.currentScenic.openTime.find(i => i.weekDay === weekDay);
+            return {
+                open: i.open,
+                time: i.open ? `营业时间:${i.startTime} - ${i.endTime}` : '今日停业'
+            };
         }
     },
     created() {
@@ -159,19 +168,11 @@ export default {
         this.mapHeight = sysInfo.windowHeight - this.safeAreaBottom - 128 - 180 + 'px';
     },
     onShow() {
-        this.locate();
-        wx.startCompass();
-        wx.onCompassChange(res => {
-            if (this.myLocation) {
-                this.myLocation = {
-                    ...this.myLocation,
-                    rotate: res.direction
-                };
-            }
-        });
-    },
-    onHide() {
-        wx.stopCompass();
+        console.log('onshow');
+        if (this.status !== 'success') {
+            this.locate();
+        }
+        this.mapCtx = wx.createMapContext('map', this);
     },
     methods: {
         onTabChange(e) {
@@ -203,22 +204,34 @@ export default {
                 });
         },
         locate() {
-            console.log('locate');
+            wx.showLoading({
+                title: '定位中'
+            });
+            this.status = 'loading';
             wx.getLocation({
+                type: 'gcj02',
                 success: res => {
-                    this.center = {
-                        latitude: res.latitude,
-                        longitude: res.longitude
-                    };
+                    wx.hideLoading();
+                    // this.center = {
+                    //     latitude: res.latitude,
+                    //     longitude: res.longitude
+                    // };
                     this.myLocation = {
                         latitude: res.latitude,
-                        longitude: res.longitude,
-                        rotate: 0
+                        longitude: res.longitude
                     };
                     this.getScenics(res.latitude, res.longitude);
+                    if (this.mapCtx) {
+                        this.mapCtx.moveToLocation({
+                            latitude: res.latitude,
+                            longitude: res.longitude
+                        });
+                    }
                 },
                 fail: e => {
                     console.log(e);
+                    this.status = 'fail';
+                    wx.hideLoading();
                     if (/auth deny/.test(e.errMsg)) {
                         this.showLocationDialog = true;
                     }
@@ -228,6 +241,16 @@ export default {
         getScenics(latitude, longitude) {
             this.$http.get('/scenic/nearby', { latitude, longitude }).then(res => {
                 this.scenics = res;
+                if (res[0]) {
+                    this.status = 'success';
+                    this.currentScenic = res[0];
+                    this.mapCtx.moveToLocation({
+                        latitude: res[0].latitude,
+                        longitude: res[0].longitude
+                    });
+                } else {
+                    this.status = 'fail';
+                }
             });
         },
         markerTap(e) {
@@ -235,6 +258,32 @@ export default {
                 icon: 'none',
                 title: e.detail.markerId + ''
             });
+        },
+        regionChange(e) {
+            if (e.type === 'end' && e.causedBy === 'drag') {
+                this.mapCtx.getCenterLocation({
+                    success: res => {
+                        this.status = 'loading';
+                        this.getScenics(res.latitude, res.longitude);
+                    }
+                });
+            }
+        },
+        search() {
+            wx.navigateTo({
+                url: '/pages/search',
+                events: {
+                    choose: data => {
+                        console.log(data);
+                        console.log(this.currentScenic);
+                        this.currentScenic = data;
+                        this.status = 'success';
+                    }
+                },
+                success: res => {
+                    res.eventChannel.emit('location', this.myLocation);
+                }
+            });
         }
     }
 };
@@ -280,20 +329,24 @@ export default {
     bottom: 34px;
     margin: auto;
 }
-.btn-locate {
-    color: @text2;
-    font-size: 18px;
-    width: 30px;
-    height: 30px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
+.btn-locate-wrapper {
     position: absolute;
-    right: 15px;
-    bottom: 15px;
-    background: white;
-    border-radius: 4px;
+    right: 0;
+    bottom: 0;
+    padding: 15px;
+    .btn-locate {
+        color: @text2;
+        font-size: 18px;
+        width: 30px;
+        height: 30px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background: white;
+        border-radius: 4px;
+    }
 }
+
 .content-container {
     background: white;
     .flex-col();

+ 0 - 83
src/pages/my/my.vue

@@ -1,83 +0,0 @@
-<template>
-    <div class="app">
-        <img class="img" :src="logo" @touchstart="changeStat" />
-        <hello-world :msg="acc" :color="color"></hello-world>
-    </div>
-</template>
-
-<script>
-import HelloWorld from '@/components/HelloWorld.vue';
-export default {
-    components: {
-        HelloWorld
-    },
-    data() {
-        return {
-            logo:
-                'https://user-images.githubusercontent.com/20720117/48262986-80e02780-e45f-11e8-8426-2872916adad9.png',
-            color: '#007d37',
-            acc: 'hello bigMeow'
-        };
-    },
-    beforeCreate() {
-        console.log('Page [my] Vue beforeCreate');
-    },
-    created() {
-        console.log('Page [my] Vue created');
-        var appInstance = getApp();
-        console.log(appInstance.globalData); // I am global data
-    },
-    beforeMount() {
-        console.log('Page [my] Vue beforeMount');
-    },
-    mounted() {
-        console.log('Page [my] Vue mounted');
-    },
-    onLoad(options) {
-        // Do some initialize when page load.
-        console.log('Page [my] onLoad');
-    },
-    onReady() {
-        // Do something when page ready.
-        console.log('Page [my] onReady');
-    },
-    onShow() {
-        // Do something when page show.
-        console.log('Page [my] onShow');
-    },
-    onHide() {
-        // Do something when page hide.
-        console.log('Page [my] onHide');
-    },
-    onUnload() {
-        // Do something when page close.
-        console.log('Page [my] onUnload');
-    },
-    /**
-     * for other event handlers, please check https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/page.html
-     */
-    methods: {
-        changeStat() {
-            this.t++;
-            this.color = '#' + Math.floor(Math.random() * 0xffffff).toString(16);
-        }
-    }
-};
-</script>
-
-<style lang="less">
-.app {
-    padding-top: 100px;
-    .img {
-        display: block;
-        height: 120px;
-        width: 138px;
-        margin: 20px auto;
-    }
-    .txt {
-        color: #567567;
-        font-size: 13px;
-        text-align: center;
-    }
-}
-</style>

+ 137 - 0
src/pages/search.vue

@@ -0,0 +1,137 @@
+<config>
+{
+    "navigationBarTitleText": "搜索"
+}
+</config>
+<template>
+    <div>
+        <van-sticky>
+            <van-search
+                placeholder="请输入景区名称搜索"
+                :value="keyword"
+                @search="search"
+                @clear="showList = false"
+                @change="change"
+            >
+            </van-search>
+        </van-sticky>
+        <div v-if="showList" class="results">
+            <div v-if="loading" style="text-align:center;margin-top:20px">
+                <van-loading size="24px">搜索中...</van-loading>
+            </div>
+            <template v-else>
+                <div v-for="item in list" :key="item.id" class="result-item" @click="clickItem(item)">
+                    <div class="name">{{ item.name }}</div>
+                </div>
+                <van-empty description="无结果" v-if="list.length === 0" />
+            </template>
+        </div>
+        <div class="history" v-else>
+            <div class="title">搜索历史</div>
+            <div class="list">
+                <div class="item" v-for="(item, i) in history" :key="i" @click="clickHistoryItem(item)">{{ item }}</div>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+export default {
+    data() {
+        return {
+            keyword: '',
+            history: [],
+            list: [],
+            showList: false,
+            loading: false,
+            eventChannel: null,
+            location: null
+        };
+    },
+    mounted() {
+        try {
+            let history = wx.getStorageSync('searchHistory');
+            if (history) {
+                this.history = JSON.parse(history);
+            }
+        } catch (e) {}
+        this.eventChannel = this.$mp.page.getOpenerEventChannel();
+        this.eventChannel.on('location', data => {
+            this.location = data;
+        });
+    },
+    methods: {
+        change(e) {
+            this.keyword = e.detail;
+            if (e.detail === '') {
+                this.showList = false;
+            }
+        },
+        search(e) {
+            if (e.detail) {
+                if (!this.history.find(i => i === e.detail)) {
+                    this.history.push(e.detail);
+                    wx.setStorageSync('searchHistory', JSON.stringify(this.history.slice(-5)));
+                }
+            }
+            this.showList = true;
+            this.loading = true;
+            this.$http
+                .get('/scenic/all', { search: e.detail })
+                .then(res => {
+                    this.list = res.content;
+                    this.loading = false;
+                })
+                .catch(e => {
+                    this.list = [];
+                    this.loading = false;
+                });
+        },
+        clickHistoryItem(item) {
+            this.keyword = item;
+            this.search({ detail: item });
+        },
+        clickItem(item) {
+            this.eventChannel.emit('choose', item);
+            wx.navigateBack();
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.top {
+    .flex();
+}
+.history {
+    padding: 0 15px;
+    .title {
+        font-weight: 500;
+        font-size: 14px;
+        margin: 10px 0;
+    }
+    .list {
+        .flex();
+        flex-wrap: wrap;
+        .item {
+            font-size: 12px;
+            height: 24px;
+            line-height: 24px;
+            border-radius: 12px;
+            padding: 0 8px;
+            background: @border2;
+            color: @text2;
+            margin-right: 10px;
+            margin-top: 8px;
+        }
+    }
+}
+.results {
+    .result-item {
+        .flex();
+        padding: 0 15px;
+        height: 44px;
+        .name {
+            font-size: 14px;
+        }
+    }
+}
+</style>

+ 0 - 40
src/pages/vuex/vuex.vue

@@ -1,40 +0,0 @@
-<config lang="json">
-{
-  navigationBarTitleText: 'vuex示例',
-  usingComponents: {
-
-  }
-}
-</config>
-
-<template>
-    <div id="app">
-        Clicked: {{ $store.state.counter.count }} times, count is {{ evenOrOdd }}.
-        <button @click="increment() | test()">+</button>
-        <button @click="decrement">-</button>
-        <button @click="incrementIfOdd">Increment if odd</button>
-        <button @click="incrementAsync">Increment async</button>
-        globalData:{{ globalData }}
-    </div>
-</template>
-
-<script>
-import { mapGetters, mapActions } from 'vuex';
-
-export default {
-    computed: mapGetters(['evenOrOdd']),
-    data() {
-        return {};
-    },
-    methods: {
-        ...mapActions(['increment', 'decrement', 'incrementIfOdd', 'incrementAsync']),
-        test: function() {
-            this.globalData['a']++;
-        }
-    },
-    created() {
-        var appInstance = getApp();
-        this.globalData = appInstance.globalData;
-    }
-};
-</script>

+ 3 - 3
src/styles/common.less

@@ -7,9 +7,9 @@
 @text3: #909399;
 @text4: #c0c4cc;
 @border1: #dcdfe6;
-@border1: #e4e7ed;
-@border1: #ebeef5;
-@border1: #f2f6fc;
+@border2: #e4e7ed;
+@border3: #ebeef5;
+@border4: #f2f6fc;
 .flex() {
     display: flex;
     align-items: center;

+ 5 - 0
yarn.lock

@@ -3143,6 +3143,11 @@ dashdash@^1.12.0:
   dependencies:
     assert-plus "^1.0.0"
 
+date-fns@^2.15.0:
+  version "2.15.0"
+  resolved "https://registry.npm.taobao.org/date-fns/download/date-fns-2.15.0.tgz?cache=0&sync_timestamp=1594999060129&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdate-fns%2Fdownload%2Fdate-fns-2.15.0.tgz#424de6b3778e4e69d3ff27046ec136af58ae5d5f"
+  integrity sha1-Qk3ms3eOTmnT/ycEbsE2r1iuXV8=
+
 de-indent@^1.0.2:
   version "1.0.2"
   resolved "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"