tremble il y a 3 ans
commit
cf41415895

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+# Windows
+[Dd]esktop.ini
+Thumbs.db
+$RECYCLE.BIN/
+
+# macOS
+.DS_Store
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+
+# Node.js
+node_modules/

+ 19 - 0
app.js

@@ -0,0 +1,19 @@
+// app.js
+App({
+  onLaunch() {
+    // 展示本地存储能力
+    const logs = wx.getStorageSync('logs') || []
+    logs.unshift(Date.now())
+    wx.setStorageSync('logs', logs)
+
+    // 登录
+    wx.login({
+      success: res => {
+        // 发送 res.code 到后台换取 openId, sessionKey, unionId
+      }
+    })
+  },
+  globalData: {
+    userInfo: null
+  }
+})

+ 13 - 0
app.json

@@ -0,0 +1,13 @@
+{
+  "pages": [
+    "pages/index/index"
+  ],
+  "window": {
+    "backgroundTextStyle": "light",
+    "navigationBarBackgroundColor": "#EDEDED",
+    "navigationBarTitleText": "音频讲解",
+    "navigationBarTextStyle": "black"
+  },
+  "style": "v2",
+  "sitemapLocation": "sitemap.json"
+}

+ 9 - 0
app.wxss

@@ -0,0 +1,9 @@
+/**app.wxss**/
+page {
+  height: 100%;
+  width: 100%;
+  background-image:linear-gradient(135deg, #38A2D7 0%, #1C2E4C 100%);
+}
+
+
+

+ 131 - 0
components/audio-play/audio-play.js

@@ -0,0 +1,131 @@
+// components/audio-play.js
+import { CDN_URL,API_BASE_URL,G_AUDIO } from '../../config/index';
+var AllExample = [];
+Component({
+  /**
+   * 组件的属性列表
+   */
+  properties: {
+    audio: {
+      type: Number
+    }
+  },
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    cdn_url:CDN_URL,
+    durationTime: '00:00',
+    currentTime: '00:00',
+    isPlay: false,
+    audioExample: null,
+    G_AUDIO,
+    progress: 0,
+    allAudio: [],
+    api_base_url:API_BASE_URL,
+    targetUrl:API_BASE_URL+'/data/'
+  },
+
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+
+    toggleMusic() {
+      // 全部暂停
+      if (!this.data.isPlay) {
+        AllExample.forEach(simpleAudio => {
+          simpleAudio.pause();
+        })
+  
+        this.data.audioExample.autoplay = true;
+        this.data.audioExample.src = G_AUDIO[this.properties.audio] && G_AUDIO[this.properties.audio].audio;
+        this.data.audioExample.play();
+        this.setData({
+          isPlay: true
+        })
+        this.loadProgress()
+      }
+      else{
+        this.data.audioExample.pause();
+        console.log('结束音乐')
+        this.setData({
+          isPlay: false
+        })
+      }
+    },
+    // 播放中
+    loadProgress() {
+      this.data.audioExample.onCanplay((e) => {
+        this.data.audioExample.duration; //必须写,不然获取不到。。。
+        var timer = setInterval(() => {
+          // 只要音频暂停了,定时器(假的)不执行
+          if (this.data.audioExample.paused) return;
+          var currentime = this.data.audioExample.currentTime;
+          var duration = this.data.audioExample.duration;
+          var currTimeStr = this.formatTime(currentime);
+          var duraTimeStr = this.formatTime(duration);
+          var progress = parseInt((this.data.audioExample.currentTime / this.data.audioExample.duration) * 100)
+          if (progress === 100 || isNaN(this.data.progress)) {
+            clearInterval(timer)
+            console.log('停止了')
+            this.setData({
+              isPlay: false,
+              progress: 0,
+              currentTime: "00:00",
+            })
+          } else {
+            this.setData({
+              progress,
+              currentTime: currTimeStr,
+              durationTime: duraTimeStr
+            })
+          }
+        }, 1000);
+      });
+    },
+    
+    formatTime: function (num) { //格式化时间格式
+      num = num.toFixed(0);
+      let second = (num % 60);
+      if (second < 10) second = '0' + second;
+      let min = Math.floor(num / 60);
+      if (min < 10) min = '0' + min;
+      return min + ":" + second;
+    }
+  },
+  attached: function () {
+    //组件显示初始化函数
+    this.data.audioExample = wx.createInnerAudioContext();
+    //所有组件实例都放在一个容器AllExample里
+    AllExample.push(this.data.audioExample);
+    this.data.audioExample.onPlay(function () {
+      console.log('播放中。。。')
+    })
+    this.data.audioExample.onTimeUpdate(function () {
+      console.log('监听进度。。')
+    })
+    //控制单个实例的isPlay
+    this.data.audioExample.onPause( ()=> {
+      this.setData({
+        isPlay: false
+      })
+    })
+    // 每个组件实例播放结束
+    this.data.audioExample.onEnded(() => {
+      this.setData({
+        currentTime: "00:00",
+        isPlay: false,
+        progress: 0,
+      })
+    })
+    // 在组件实例进入页面节点树时执行
+  },
+  detached: function () {
+    // 在组件实例被从页面节点树移除时执行
+    // 卸载
+    this.data.audioExample.destroy();
+    AllExample = [];
+  }
+})

+ 4 - 0
components/audio-play/audio-play.json

@@ -0,0 +1,4 @@
+{
+  "component": true,
+  "usingComponents": {}
+}

+ 23 - 0
components/audio-play/audio-play.wxml

@@ -0,0 +1,23 @@
+<!--components/audio-play.wxml-->
+<view>
+  <view class="audio">
+    <image class="bg-img" mode="aspectFill" src="{{cdn_url}}/project/audio_guide/audio_thumb.jpg"></image>
+
+    <image class="icon-img"
+    bindtap="toggleMusic"
+    src="{{cdn_url}}/project/audio_guide/{{isPlay?'start':'pause'}}.png">
+    </image>
+
+    <view class="free-MusicProgress">
+      <view class="before-progress">
+        <view class="progress" style="width:{{progress}}%;"></view>
+      </view>
+      <view class="durationTime">{{currentTime}}</view>
+    </view>
+</view>  
+  <view class="title">{{G_AUDIO[audio].name}}</view>
+
+</view>
+  
+
+

+ 64 - 0
components/audio-play/audio-play.wxss

@@ -0,0 +1,64 @@
+/* components/audio-play.wxss */
+.audio {
+  position: relative;
+  display:inline-block;
+  font-size: 0;
+  width:220rpx;
+  height: 220rpx;
+  border-radius: 6rpx;
+}
+.audio .bg-img {
+  width: 100%;
+  height: 100%;
+}
+.audio .icon-img {
+  width:80rpx;
+  height:80rpx;
+  position:absolute;
+  top:50%;
+  left:50%;
+  transform: translate(-50%,-50%);
+}
+
+.audio .free-MusicProgress {
+  position: absolute;
+  width: 100%;
+  height: 52rpx;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.6);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.audio .free-MusicProgress .before-progress {
+  width:50%;
+  height:8rpx;
+  background: rgba(255,255,255,0.3);
+  border-radius: 6rpx;
+  margin-right: 16rpx;
+  position: relative;
+}
+.audio .free-MusicProgress .progress {
+  background: #38A2D7;
+  height:100%;
+  overflow: hidden;
+  border-radius: 6rpx;
+  position: absolute;
+  left: 0;
+  top: 0;
+}
+
+
+.audio .free-MusicProgress .durationTime {
+  width: 20%;
+  font-size: 20rpx;
+  color: rgba(255,255,255,0.67);
+}
+
+.title{
+  font-size: 24rpx;
+  text-align: center;
+  margin-top: 10rpx;
+  width: 100%;
+  display: inline-block;
+}

+ 79 - 0
components/big-pic/big-pic.js

@@ -0,0 +1,79 @@
+import { CDN_URL,API_BASE_URL,DISTRIBUTION } from '../../config/index';
+import http from '../../utils/http';
+
+
+Component({
+  /**
+   * 组件的属性列表
+   */
+  properties: {
+
+  },
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    cdn_url:CDN_URL,
+    audioList:DISTRIBUTION,
+    api_base_url:API_BASE_URL
+  },
+
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+    getAudiosList(){
+      http.get('/api/web/audio/list').then(res=>{
+        let {data} = res;
+        let target = [];
+        for(let [key,value] of Object.entries(data)) {
+            switch (key) {
+            case '1':
+              let obj1 = {};
+              obj1['title'] = '主厅';
+              obj1['list'] = value
+              target = [...target,obj1]
+              break;
+            case '2':
+              let obj2 = {};
+              obj2['title'] = '附厅';
+              obj2['list'] = value;
+              target = [...target,obj2]
+              break;
+            case '3':
+              let obj3 = {};
+              obj3['title'] = '序厅';
+              obj3['list'] = value;
+              target = [...target, obj3];
+              break;
+            default:
+              break
+          }
+        }
+        this.setData({
+          audioList:target
+        })
+      })
+    },
+
+    tapTitle(e){
+      let {tag,index} = e.mark;
+      let data = this.data.audioList
+
+      if (data[index]['tag'] == tag) {
+        tag = ''
+      }
+
+      data[index]['tag'] = tag
+      this.setData({
+        audioList:data
+      })
+    }
+  },
+  attached: function () {
+    //获取语音
+    // this.getAudiosList();
+  },
+  detached: function () {}
+})

+ 6 - 0
components/big-pic/big-pic.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "audio-play": "../../components/audio-play/audio-play"
+  }
+}

+ 13 - 0
components/big-pic/big-pic.wxml

@@ -0,0 +1,13 @@
+<view class="content">
+  <view class="column {{item.tag==item.id?'hide_col':''}}" wx:for='{{audioList}}' wx:key="index">
+    <view class="title" mark:tag="{{item.id}}" mark:index="{{index}}">
+      <text class="txt" bindtap="tapTitle">{{item.title}}</text>
+      <image class="title-img" bindtap="tapTitle" mode="aspectFit" src="{{cdn_url}}/project/icon-bottom.png"></image>
+    </view>
+    <view class="con-list">
+      <view class="citem" wx:for='{{item.position}}' wx:for-item="sub" wx:key="index">
+        <audio-play audio="{{sub}}"></audio-play>
+      </view>
+    </view>
+  </view>
+</view>

+ 66 - 0
components/big-pic/big-pic.wxss

@@ -0,0 +1,66 @@
+.content {
+  width: 100%;
+  height: 962rpx;
+  background: #FFFFFF;
+  box-shadow: 0rpx 6rpx 12rpx rgba(0, 0, 0, 0.65);
+  opacity: 1;
+  border-radius: 0 0 10rpx;
+  margin: 0 auto;
+  overflow: scroll;
+}
+
+
+.content {
+  box-sizing: border-box;
+}
+
+.content .main {
+  box-sizing: border-box;
+  width: 100%;
+}
+
+.content .column {
+  width: 100%;
+}
+
+.content .column .title {
+  width: 100%;
+  height: 100%;
+  font-size: 26rpx;
+  color: #38A2D7;
+  background: linear-gradient(180deg, #D4D4D4 0%, rgba(212, 212, 212, 0) 100%);
+  padding: 5% 4%;
+  box-sizing: border-box;
+}
+.content .column .title .title-img {
+  width:24rpx;
+  height: 24rpx;
+  margin-left: 16rpx;
+}
+
+.content .column .con-list {
+  margin: 0 4%;
+  border-top: 1px solid rgba(112, 112, 112, 0.25);
+  display: flex;
+  justify-content: space-between;
+  width: 92%;
+  padding: 32rpx 32rpx 0 32rpx;
+  box-sizing: border-box;
+  flex-wrap: wrap;
+  overflow: hidden;
+}
+
+
+.content .hide_col .con-list{
+  height: 0;
+  padding: 0;
+  border-top: 0;
+}
+
+
+
+.con-list  .citem{
+  width: 44%;
+  font-size: 0;
+  margin-bottom: 32rpx;
+}

+ 131 - 0
components/list-audio/list-audio.js

@@ -0,0 +1,131 @@
+// components/audio-play.js
+import { CDN_URL,API_BASE_URL,G_AUDIO } from '../../config/index';
+var AllExample = [];
+Component({
+  /**
+   * 组件的属性列表
+   */
+  properties: {
+    audio: {
+      type: Number
+    }
+  },
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    cdn_url:CDN_URL,
+    durationTime: '00:00',
+    currentTime: '00:00',
+    isPlay: false,
+    audioExample: null,
+    progress: 0,
+    allAudio: [],
+    G_AUDIO,
+    api_base_url:API_BASE_URL,
+    targetUrl:API_BASE_URL+'/data/'
+  },
+
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+
+    toggleMusic() {
+      // 全部暂停
+      if (!this.data.isPlay) {
+        AllExample.forEach(simpleAudio => {
+          simpleAudio.pause();
+        })
+  
+        this.data.audioExample.autoplay = true;
+        this.data.audioExample.src = G_AUDIO[this.properties.audio].audio;
+        this.data.audioExample.play();
+        this.setData({
+          isPlay: true
+        })
+        this.loadProgress()
+      }
+      else{
+        this.data.audioExample.pause();
+        console.log('结束音乐')
+        this.setData({
+          isPlay: false
+        })
+      }
+    },
+    // 播放中
+    loadProgress() {
+      this.data.audioExample.onCanplay((e) => {
+        this.data.audioExample.duration; //必须写,不然获取不到。。。
+        var timer = setInterval(() => {
+          // 只要音频暂停了,定时器(假的)不执行
+          if (this.data.audioExample.paused) return;
+          var currentime = this.data.audioExample.currentTime;
+          var duration = this.data.audioExample.duration;
+          var currTimeStr = this.formatTime(currentime);
+          var duraTimeStr = this.formatTime(duration);
+          var progress = parseInt((this.data.audioExample.currentTime / this.data.audioExample.duration) * 100)
+          if (progress === 100 || isNaN(this.data.progress)) {
+            clearInterval(timer)
+            console.log('停止了')
+            this.setData({
+              isPlay: false,
+              progress: 0,
+              currentTime: "00:00",
+            })
+          } else {
+            this.setData({
+              progress,
+              currentTime: currTimeStr,
+              durationTime: duraTimeStr
+            })
+          }
+        }, 1000);
+      });
+    },
+    
+    formatTime: function (num) { //格式化时间格式
+      num = num.toFixed(0);
+      let second = (num % 60);
+      if (second < 10) second = '0' + second;
+      let min = Math.floor(num / 60);
+      if (min < 10) min = '0' + min;
+      return min + ":" + second;
+    }
+  },
+  attached: function () {
+    //组件显示初始化函数
+    this.data.audioExample = wx.createInnerAudioContext();
+    //所有组件实例都放在一个容器AllExample里
+    AllExample.push(this.data.audioExample);
+    this.data.audioExample.onPlay(function () {
+      console.log('播放中。。。')
+    })
+    this.data.audioExample.onTimeUpdate(function () {
+      console.log('监听进度。。')
+    })
+    //控制单个实例的isPlay
+    this.data.audioExample.onPause( ()=> {
+      this.setData({
+        isPlay: false
+      })
+    })
+    // 每个组件实例播放结束
+    this.data.audioExample.onEnded(() => {
+      this.setData({
+        currentTime: "00:00",
+        isPlay: false,
+        progress: 0,
+      })
+    })
+    // 在组件实例进入页面节点树时执行
+  },
+  detached: function () {
+    // 在组件实例被从页面节点树移除时执行
+    // 卸载
+    this.data.audioExample.destroy();
+    AllExample = [];
+  }
+})

+ 4 - 0
components/list-audio/list-audio.json

@@ -0,0 +1,4 @@
+{
+  "component": true,
+  "usingComponents": {}
+}

+ 14 - 0
components/list-audio/list-audio.wxml

@@ -0,0 +1,14 @@
+<!--components/list-audio/list-audio.wxml-->
+<view class="list">
+  <view class="title">{{G_AUDIO[audio].name}}</view>
+  <view class="audio">
+    <image class="audio-img"
+    bindtap="toggleMusic"
+    src="{{cdn_url}}/project/audio_guide/list-{{isPlay?'stop':'start'}}.png">
+    </image>
+    <view class="free-MusicProgress">
+        <view class="progress" style="width:{{progress}}%;"></view>
+    </view>
+    <view class="durationTime">{{currentTime}}</view>
+  </view>
+</view>

+ 43 - 0
components/list-audio/list-audio.wxss

@@ -0,0 +1,43 @@
+/* components/list-audio/list-audio.wxss */
+.list {
+  position: relative;
+  margin-bottom: 32rpx;
+}
+
+.list .title {
+  font-size: 24rpx;
+}
+
+
+.audio {
+  position: relative;
+  margin: 18rpx 0 10rpx;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.audio .audio-img {
+  width:40rpx;
+  height:40rpx;
+}
+
+.audio .free-MusicProgress {
+  width:72%;
+  height:8rpx;
+  background: rgba(112, 112, 112, 0.5);
+  border-radius: 6rpx;
+  margin-right: 16rpx;
+  position: relative;
+  overflow: hidden;
+}
+
+.audio .free-MusicProgress .progress {
+  height: 100%;
+  background: #38A2D7;
+}
+
+.list .durationTime {
+  font-size: 20rpx;
+  color: #2F2414;
+}

+ 79 - 0
components/list/list.js

@@ -0,0 +1,79 @@
+import { CDN_URL,API_BASE_URL,DISTRIBUTION } from '../../config/index';
+import http from '../../utils/http';
+
+
+Component({
+  /**
+   * 组件的属性列表
+   */
+  properties: {
+
+  },
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    cdn_url:CDN_URL,
+    audioList:DISTRIBUTION,
+    api_base_url:API_BASE_URL
+  },
+
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+    getAudiosList(){
+      http.get('/api/web/audio/list').then(res=>{
+        let {data} = res;
+        let target = [];
+        for(let [key,value] of Object.entries(data)) {
+            switch (key) {
+            case '1':
+              let obj1 = {};
+              obj1['title'] = '主厅';
+              obj1['list'] = value
+              target = [...target,obj1]
+              break;
+            case '2':
+              let obj2 = {};
+              obj2['title'] = '附厅';
+              obj2['list'] = value;
+              target = [...target,obj2]
+              break;
+            case '3':
+              let obj3 = {};
+              obj3['title'] = '序厅';
+              obj3['list'] = value;
+              target = [...target, obj3];
+              break;
+            default:
+              break
+          }
+        }
+        this.setData({
+          audioList:target
+        })
+      })
+    },
+
+    tapTitle(e){
+      let {tag,index} = e.mark;
+      let data = this.data.audioList
+
+      if (data[index]['tag'] == tag) {
+        tag = ''
+      }
+
+      data[index]['tag'] = tag
+      this.setData({
+        audioList:data
+      })
+    }
+  },
+  attached: function () {
+    //获取语音
+    // this.getAudiosList();
+  },
+  detached: function () {}
+})

+ 6 - 0
components/list/list.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "list-audio": "../../components/list-audio/list-audio"
+  }
+}

+ 14 - 0
components/list/list.wxml

@@ -0,0 +1,14 @@
+<!--components/list/list.wxml-->
+<view class="content">
+  <view class="column {{item.tag==item.id?'hide_col':''}}" wx:for='{{audioList}}' wx:key="index">
+    <view class="title" mark:tag="{{item.id}}" mark:index="{{index}}">
+      <text class="txt" bindtap="tapTitle">{{item.title}}</text>
+      <image class="title-img" bindtap="tapTitle" mode="aspectFit" src="{{cdn_url}}/project/icon-bottom.png"></image>
+    </view>
+    <view class="con-list">
+      <view class="citem" wx:for='{{item.position}}' wx:for-item="sub" wx:key="index">
+        <list-audio audio="{{sub}}"></list-audio>
+      </view>
+    </view>
+  </view>
+</view>

+ 65 - 0
components/list/list.wxss

@@ -0,0 +1,65 @@
+.content {
+  width: 100%;
+  height: 962rpx;
+  background: #FFFFFF;
+  box-shadow: 0rpx 6rpx 12rpx rgba(0, 0, 0, 0.65);
+  opacity: 1;
+  border-radius: 0 0 10rpx;
+  margin: 0 auto;
+  overflow: scroll;
+}
+
+
+.content {
+  box-sizing: border-box;
+}
+
+.content .main {
+  box-sizing: border-box;
+  width: 100%;
+}
+
+.content .column {
+  width: 100%;
+}
+
+.content .column .title {
+  width: 100%;
+  height: 100%;
+  font-size: 26rpx;
+  color: #38A2D7;
+  background: linear-gradient(180deg, #D4D4D4 0%, rgba(212, 212, 212, 0) 100%);
+  padding: 5% 4%;
+  box-sizing: border-box;
+}
+.content .column .title .title-img {
+  width:24rpx;
+  height: 24rpx;
+  margin-left: 16rpx;
+}
+
+.content .column .con-list {
+  margin: 0 4%;
+  border-top: 1px solid rgba(112, 112, 112, 0.25);
+  display: flex;
+  justify-content: space-between;
+  width: 92%;
+  padding: 32rpx 32rpx 0 32rpx;
+  box-sizing: border-box;
+  flex-wrap: wrap;
+  overflow: hidden;
+}
+
+
+.content .hide_col .con-list{
+  height: 0;
+  padding: 0;
+  border-top: 0;
+}
+
+
+
+.con-list  .citem{
+  width: 100%;
+  font-size: 0;
+}

+ 489 - 0
components/map-sense/map-sense.js

@@ -0,0 +1,489 @@
+// components/map-sense.js
+
+let innerAudioContext = wx.createInnerAudioContext({
+  useWebAudioImplement: true
+});
+import http from "../../utils/http";
+import { promisify, BeaconUtils } from "../../utils/util";
+let openBluetoothAdapter = promisify(wx.openBluetoothAdapter);
+let closeBluetoothAdapter = promisify(wx.closeBluetoothAdapter);
+let startBeaconDiscovery = promisify(wx.startBeaconDiscovery);
+let stopBeaconDiscovery = promisify(wx.stopBeaconDiscovery);
+
+
+import {
+  CDN_URL,
+  CONNECT_STATUS,
+  STATUS_TEXT,
+  API_BASE_URL,
+  DISTRIBUTION,
+} from "../../config/index";
+
+const STATUS_PIC = {
+  0: "default",
+  1: "loading",
+  2: "success",
+  3: "fail",
+};
+
+let audioInterruptionCb = ()=>{}
+let bluetoothAdapterStateChangeCb = ()=>{}
+
+let isCollect = false
+
+let changeTO = null
+
+// 选择6档
+const TXPOWER = -55;
+var result = 0,
+  oldResult = -1;
+// 距离经验值(调试所得)
+const N = 3.3;
+
+const R = 3.4; //设定感应范围半径
+
+const RSSIVAL = 70; //rssi信号过滤临界点
+
+
+let AveLength = 10;
+
+let group = [
+  ["10001", "10002"],
+  ["10003"],
+  ["10004"],
+  ["10005"],
+  ["10006"],
+  ["10007"],
+  ["10008"],
+  ["10009"],
+  ["10010"],
+  ["10011"],
+  ["10012", "10013"],
+  ["10014"],
+  ["10015"],
+  ["10016"],
+  ["10017"],
+  ["10018"],
+  ["10019"],
+  ["10020", "10021"],
+  ["10022"],
+  ["10023"],
+  ["10024"],
+];
+
+// 1:['10001','10002'],2:['10003'],
+// 3:['10004'],4:['10005'],5:['10006'],
+// 6:['10007'],7:['10008'],8:['10009'],
+// 9:['10010'],10:['10011'],11:['10012','10013'],
+// 12:['10014'],13:['10015'],14:['10016'],
+// 15:['10017'],16:['10018'],17:['10019'],
+// 18:['10020','10021'],19:['10022'],
+// 20:['10023'],21:['10024']
+
+let AudioAddress = {
+  0: "https://culture.4dage.com/demo/audio/1.2.mp3",
+  1: "https://culture.4dage.com/demo/audio/3.mp3",
+  2: "https://culture.4dage.com/demo/audio/4.mp3",
+  3: "https://culture.4dage.com/demo/audio/5.mp3",
+  4: "https://culture.4dage.com/demo/audio/6.mp3",
+  5: "https://culture.4dage.com/demo/audio/7.mp3",
+  6: "https://culture.4dage.com/demo/audio/8.mp3",
+  7: "https://culture.4dage.com/demo/audio/9.mp3",
+  8: "https://culture.4dage.com/demo/audio/10.mp3",
+  9: "https://culture.4dage.com/demo/audio/11.mp3",
+  10: "https://culture.4dage.com/demo/audio/12.13.mp3",
+  11: "https://culture.4dage.com/demo/audio/14.mp3",
+  12: "https://culture.4dage.com/demo/audio/15.mp3",
+  13: "https://culture.4dage.com/demo/audio/16.mp3",
+  14: "https://culture.4dage.com/demo/audio/17.mp3",
+  15: "https://culture.4dage.com/demo/audio/18.mp3",
+  16: "https://culture.4dage.com/demo/audio/19.mp3",
+  17: "https://culture.4dage.com/demo/audio/20.21.mp3",
+  18: "https://culture.4dage.com/demo/audio/22.mp3",
+  19: "https://culture.4dage.com/demo/audio/23.mp3",
+  20: "https://culture.4dage.com/demo/audio/24.mp3",
+};
+
+Component({
+  /**
+   * 组件的属性列表
+   */
+  properties: {},
+
+  /**
+   * 组件的初始数据
+   */
+  data: {
+    status: "0",
+    cdn_url: CDN_URL,
+    connect_status: CONNECT_STATUS,
+    status_text: STATUS_TEXT,
+    status_pic: STATUS_PIC,
+    targetObj: {},
+    audio_address: {},
+    api_base_url: API_BASE_URL,
+    // 是否是扫码播放
+    isScanPlay: false,
+    cdn_url: CDN_URL,
+    classfiy: {},
+  },
+
+  /**
+   * 组件的方法列表
+   */
+  methods: {
+    openBluetooth(cb) {
+      wx.showLoading({
+        title: "正在打开蓝牙…",
+        mask: true,
+      });
+
+      openBluetoothAdapter().then(
+        (res) => {
+          wx.hideLoading({fail(){}});
+          cb(res);
+        },
+        () => {
+          wx.hideLoading({fail(){}});
+          wx.showToast({
+            title: "请打开蓝牙",
+            icon: "error",
+            duration: 2000,
+          });
+        }
+      );
+    },
+    toHandle() {
+      if (this.data.status == "2") {
+        this.stopBeaconDiscovery();
+        return;
+      }
+      let aveArr = [];
+
+      this.openBluetooth(() => {
+        wx.showLoading({
+          title: "正在连接…",
+          mask: true,
+        });
+        startBeaconDiscovery({
+          uuids: ["FDA50693-A4E2-4FB1-AFCF-C6EB07647825"],
+        })
+          .then(() => {
+            wx.hideLoading({fail(){}});
+            this.setData({
+              status: "2",
+            });
+            isCollect = true
+            wx.onBeaconUpdate((data) => {
+              if (!isCollect) {
+                return
+              }
+              console.log('还在收集…………');
+              // 需要收集十组数据,索引号最大的组是最旧的
+              if (!aveArr.includes(data.beacons)) {
+                if (aveArr.length >= AveLength) {
+                  //当超过十组时,应该将索引号大的组淘汰掉
+                  aveArr.pop()
+                }
+                aveArr.unshift(BeaconUtils.clone(data.beacons)); //在队列前面插入
+              }
+              
+              let all = []; //获取所有data.beacons数据
+              for (let i = 0; i < aveArr.length; i++) {
+                let ele = aveArr[i];
+                for (let j = 0; j < ele.length; j++) {
+                  let item = ele[j];
+                  //过滤信号弱的数据
+                  if (!(item.proximity === 0 && item.rssi === 0)) {
+                    if (Math.abs(item.rssi) < RSSIVAL) {
+                      // console.log(item.proximity,item.rssi);
+                      if (!all.includes(item)) {
+                        all.push(BeaconUtils.clone(item))
+                      }
+                    }
+                  }
+                }
+              }
+
+              let accuracyList = {};
+              // classfiy = {10003:[{},{},···],10002:[{},{},···],10001:[{},{},···]}
+              let classfiy = BeaconUtils.classification(all, "major");
+
+              // console.log(classfiy,'classfiy');
+
+              Object.keys(classfiy).forEach((key) => {
+                //每个major的AveLength个元素数组,元素为rssi
+                let arr = classfiy[key].map((item) => {
+                  return item.rssi;
+                });
+
+                //每个major的rssi平均值
+                let ave = BeaconUtils.arrayAverage(arr);
+
+                //计算平均差
+                let meanDeviation = BeaconUtils.getMeanDeviation(arr, ave);
+
+                //计算各rssi的高斯模糊权重
+                let guassionArr = []; //存放权重数组
+                for (let i = 0; i < arr.length; ++i) {
+                  guassionArr.push(
+                    BeaconUtils.getOneGuassionArray(
+                      arr.length,
+                      i,
+                      meanDeviation
+                    )
+                  );
+                }
+
+
+                //计算高斯模糊后的rssi值
+                let rssiArr = []; //模糊后的rssi数组
+                for (let i = 0; i < arr.length; ++i) {
+                  let sum = 0;
+                  for (let j = 0; j < arr.length; ++j) {
+                    if (guassionArr[i].length == 0) {
+                      sum = arr[j];
+                      break;
+                    }
+                    sum += guassionArr[i][j] * arr[j];
+                  }
+                  rssiArr.push(sum);
+                }
+
+
+
+                //时间加权后求rssi平均值
+                let aveOnTime = BeaconUtils.arrayAverage(
+                  rssiArr
+                    .slice(0, Math.floor(rssiArr.length / 3))
+                    .concat(rssiArr)
+                );
+
+
+
+                //测距,根据时间加权后的rssi计算距离
+                // classfiy[key].forEach((item) => {
+                  let tmp = BeaconUtils.calculateAccuracy(
+                    TXPOWER,
+                    aveOnTime,
+                    N
+                  );
+
+              
+                  if (!accuracyList[key]) {
+                    //如果还没有对应的“信标号”
+                    accuracyList[key] = [tmp];
+                  }else{
+                    accuracyList[key].push(tmp);
+                  }
+                // });
+
+
+              });
+
+
+              // Object.keys(accuracyList).forEach(item=>{
+              //   console.log(accuracyList[item]+'---------'+item);
+              // })
+              
+              // console.log('--------分隔--------');
+
+              // 筛选器,筛选出配对的一组信标
+              let signSelect = new Array(21).fill(0); //记录各组的信标出现数量,投票选择最多的,依次是prologue,annexHall,mainHall
+              // const prologue = ['10001','10002']                    //序厅
+              // const annexHall = ['10003','10004','10005','10006','10007']                    //附厅
+              // const mainHall = ['10008']                     //主厅
+
+        
+
+              Object.keys(accuracyList).forEach((key) => {
+                let aveAccuracy = BeaconUtils.arrayAverage(accuracyList[key]);
+
+                if (aveAccuracy < R) {
+                  for (let i = 0; i < group.length; i++) {
+                    if (group[i].includes(key)) {
+                      signSelect[i] += 1/(aveAccuracy+0.01); //取距离的反比例函数值,距离越近,值越大,+0.01是为了防止除数为0
+                    }
+                  }
+                }
+              });
+              // console.log(signSelect);
+              //对小于预设半径的信号进行数量投票
+              result = BeaconUtils.maxIndex(signSelect);
+
+              // console.log("result", result);
+              if (result != null && result !== oldResult) {
+                wx.hideLoading({fail(){}})
+                this.playAudio(AudioAddress[result])
+                oldResult = result;
+              }
+              if (result === null && oldResult!=-1) {
+                wx.showLoading({
+                  title: "音频切换中…",
+                  mask: true,
+                });
+                changeTO && clearTimeout(changeTO)
+                changeTO = setTimeout(() => {
+                  wx.hideLoading({fail(){}})
+                }, 4000);
+                this.stopAndDestroyAudio()
+              }
+
+              let temp = DISTRIBUTION.find((item) => {
+                return item.position.some((sub) => sub == result);
+              });
+
+              this.setData({
+                classfiy,
+                targetObj: temp || {},
+                result
+              });
+            });
+          })
+          .catch(() => {
+            wx.showToast({
+              title: "连接失败",
+              icon: "error",
+              duration: 500,
+            });
+          });
+      });
+    },
+
+    stopAndDestroyAudio() {
+      console.log(innerAudioContext,'innerAudioContext');
+      if (!innerAudioContext) {
+        return
+      }
+     
+      innerAudioContext.pause()
+      innerAudioContext.stop();
+      innerAudioContext.src = null
+      innerAudioContext.destroy();
+      innerAudioContext = null
+      oldResult = -1
+    },
+
+
+    playAudio(src) {
+      if (!innerAudioContext) {
+        innerAudioContext = wx.createInnerAudioContext({
+          useWebAudioImplement: true
+        })
+      }
+
+
+      innerAudioContext.src = src;
+      innerAudioContext.loop = true;
+      innerAudioContext.onCanplay(()=>{
+        innerAudioContext.play();
+      })
+      // innerAudioContext.play();
+    },
+
+    stopBeaconDiscovery(notips=null) {
+      console.log("这是取消连接");
+      // 取消连接 停止播放音乐 目标对象置为{} 设置为第一次进入
+      
+      this.stopAndDestroyAudio();
+      this.reset();
+      isCollect = false
+      stopBeaconDiscovery().then(() => {
+        !notips && wx.showToast({
+          title: "取消连接成功",
+          icon: "error",
+          duration: 1000,
+        });
+        
+      })
+      .catch((err) => {
+        console.log(err);
+      });
+    },
+
+    reset(){
+      this.setData({
+        status: "0",
+        targetObj: {},
+      });
+    },
+
+    // 扫一扫
+    toScanCode() {
+      this.setData({
+        isScanPlay: true,
+      });
+      wx.scanCode({
+        success: res=> {
+          this.stopBeaconDiscovery(true)
+          this.playAudio(res["result"])
+        },
+        fail:  ()=> {
+          console.log("fail innerAudioContext", innerAudioContext);
+          this.setData({
+            isScanPlay: false,
+          });
+          return;
+        },
+        complete() {
+          this.setData({
+            isScanPlay: false,
+          });
+        },
+      });
+    },
+
+    resetPage(){
+      this.stopBeaconDiscovery(true);
+    },
+
+    getAudios() {
+      http.get("/api/web/getAudioIndex").then((res) => {
+        let { data } = res,
+          target = {};
+        data.forEach((item) => {
+          switch (item.type) {
+            case 1:
+              target["10001"] = `${this.data.api_base_url}/data/${item.audio}`;
+              break;
+            case 2:
+              target["10002"] = `${this.data.api_base_url}/data/${item.audio}`;
+              break;
+            case 3:
+              target["10003"] = `${this.data.api_base_url}/data/${item.audio}`;
+              break;
+            default:
+              break;
+          }
+        });
+        this.setData({
+          audio_address: target,
+        });
+      });
+    },
+  },
+  lifetimes: {
+    attached: function () {
+      audioInterruptionCb = ()=>{
+        console.log(innerAudioContext);
+        if (innerAudioContext) {
+          this.resetPage()
+        }
+      }
+      bluetoothAdapterStateChangeCb=(res)=>{
+        if (!Boolean(res.available)) {
+            this.resetPage()
+        }
+      }
+      wx.onAudioInterruptionEnd(audioInterruptionCb)
+      wx.onBluetoothAdapterStateChange(bluetoothAdapterStateChangeCb)
+      wx.onAppShow(audioInterruptionCb)
+    },
+    detached: function () {
+      this.resetPage()
+      wx.offAudioInterruptionEnd(audioInterruptionCb)
+      wx.offBluetoothAdapterStateChange(bluetoothAdapterStateChangeCb)
+      wx.offAppShow(audioInterruptionCb)
+    }
+  },
+});

+ 4 - 0
components/map-sense/map-sense.json

@@ -0,0 +1,4 @@
+{
+  "component": true,
+  "usingComponents": {}
+}

+ 53 - 0
components/map-sense/map-sense.wxml

@@ -0,0 +1,53 @@
+<!--components/map-sense.wxml-->
+<view class="content">
+  <view class="top">
+    <view class="top-bottom">
+      <image class="top-bottom-img" src="{{cdn_url}}/project/big-bg-{{targetObj.id === 'zhuting'? 'brown':'blue'}}.png">
+      </image>
+      <view class="{{targetObj.id === 'zhuting' ?'light-sound':''}} small-sound">
+        <image class="sound-img" src="{{cdn_url}}/project/sound.png"></image>
+      </view>
+      <view class="txt">主厅</view>
+    </view>
+
+
+    <view class="right-bottom">
+      <image class="right-bottom-img" src="{{cdn_url}}/project/right-{{targetObj.id === 'futing'? 'brown':'blue'}}.png">
+      </image>
+      <view class="{{targetObj.id === 'futing' ?'light-sound':''}} small-sound" >
+        <image class="sound-img" src="{{cdn_url}}/project/sound.png"></image>
+      </view>
+      <view class="txt">附厅</view>
+    </view>
+
+
+    <view class="center-bottom">
+      <image class="center-bottom-img" src="{{cdn_url}}/project/xt-{{targetObj.id === 'xuting'? 'brown':'blue'}}.png">
+      </image>
+      <view class="{{targetObj.id === 'xuting' ?'light-sound':''}} small-sound">
+        <image class="sound-img" src="{{cdn_url}}/project/sound.png"></image>
+      </view>
+      <view class="txt">序厅</view>
+    </view>
+  </view>
+
+  
+  <view class="center">
+    <image class="center-img" src="{{cdn_url}}/project/{{status_pic[status]}}.png"></image>
+    <view class="promptText">
+      {{connect_status[status]}}
+    </view>
+  </view>
+  <view class="text">
+    蓝牙成功连接后,走到相应区域则会播放不同的音频
+    注:请确保蓝牙保持打开状态。
+  </view>
+  <view style="text-align:center;">
+    <view class="bottom">
+      <view class="txt" bindtap="toScanCode">扫一扫</view>
+    </view>
+    <view class="bottom">
+      <view class="txt" bindtap="toHandle">{{status_text[status]}}</view>
+    </view>
+  </view>
+</view>

+ 207 - 0
components/map-sense/map-sense.wxss

@@ -0,0 +1,207 @@
+/* components/map-sense.wxss */
+.content {
+  width: 100%;
+  height: 962rpx;
+  background: #FFFFFF;
+  box-shadow: 0rpx 6rpx 12rpx rgba(0, 0, 0, 0.65);
+  opacity: 1;
+  border-radius: 0 0 10rpx 10rpx;
+  margin: 0 auto;
+  overflow: scroll;
+}
+
+.content {
+  box-sizing: border-box;
+  padding: 24rpx 22rpx;
+}
+
+.content .top {
+  width: 100%;
+  height: 342rpx;
+  position: relative;
+}
+
+.content .top .top-bottom .top-bottom-img,
+.content .top .right-bottom .right-bottom-img,
+.content .top .center-bottom .center-bottom-img,
+.content .center .center-img {
+  width: 100%;
+  height: 100%;
+}
+
+.content .top .top-bottom {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+
+.content .top .right-bottom {
+  width: 44%;
+  height: 43%;
+  position: absolute;
+  right: 1%;
+  bottom: 2%;
+}
+
+.content .top .center-bottom {
+  width: 37%;
+  height: 54%;
+  position: absolute;
+  text-align: center;
+  bottom: 2%;
+  left: 20%;
+}
+
+.content .top .center-bottom .small-sound {
+  width: 44rpx;
+  height: 44rpx;
+  background: #B4DCF0;
+  border-radius: 50%;
+  position: absolute;
+  top: 30%;
+  left: 38%;
+}
+
+.content .top .center-bottom .small-sound .sound-img {
+  width: 22rpx;
+  height: 20rpx;
+  display: inline-block;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+}
+
+
+
+
+.content .top .top-bottom .light-sound {
+  width: 60rpx;
+  height: 60rpx;
+  display: inline-block;
+  background: radial-gradient(circle, #1C2E4C 0%, #38A2D7 68%, #FFFFFF 100%);
+  box-shadow: 0px 2rpx 22rpx rgba(255, 255, 255, 0.8);
+  border-radius: 50%;
+  position: absolute;
+  top: 17%;
+  right: 56%;
+  text-align: center;
+}
+
+.content .top .top-bottom .txt, .content .top .right-bottom .txt, .content .top .center-bottom .txt {
+  display: inline;
+  width: 48rpx;
+  height: 32rpx;
+  font-size: 24rpx;
+  font-weight: 400;
+  line-height: 200rpx;
+  color: #2F2414;
+  opacity: 0.8;
+  position: absolute;
+  top: 20%;
+  right: 40%;
+}
+
+.content .center {
+  width: 190rpx;
+  height: 190rpx;
+  margin: 10% auto;
+}
+
+.content .center .promptText {
+  text-align: center;
+  font-size: 19px;
+  font-weight: 300;
+  line-height: 25px;
+  color: rgba(47, 36, 20, 0.8);
+}
+
+.content .text {
+  width: 460rpx;
+  height: 60rpx;
+  font-size: 20rpx;
+  font-weight: 400;
+  line-height: 32rpx;
+  color: #2F2414;
+  opacity: 0.45;
+  text-align: center;
+  margin: 12% auto;
+}
+
+.content .bottom {
+  width: 378rpx;
+  height: 76rpx;
+  background: #FFFFFF;
+  border: 2rpx solid #38A2D7;
+  opacity: 1;
+  border-radius: 19px;
+  text-align: center;
+  display: inline;
+  padding: 2% 10%;
+  margin: 0 1%;
+}
+
+.content .bottom .txt {
+  display: inline;
+  width: 152rpx;
+  height: 76rpx;
+  font-size: 38rpx;
+  font-weight: 300;
+  line-height: 76rpx;
+  color: #38A2D7;
+}
+
+.content .top .top-bottom .txt {
+  left: 10%;
+  top: 5%;
+}
+.content .top .right-bottom .txt{
+  right: 12%;
+  top: 5%;
+}
+
+.content .top .small-sound {
+  width: 44rpx;
+  height: 44rpx;
+  background: #B4DCF0;
+  border-radius: 50%;
+  position: absolute;
+  top: 19%;
+  left: 36%;
+}
+
+.content .top .small-sound .sound-img {
+  width: 22rpx;
+  height: 20rpx;
+  display: inline-block;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+}
+
+.content .top .right-bottom .small-sound {
+  width: 44rpx;
+  height: 44rpx;
+  background: #B4DCF0;
+  border-radius: 50%;
+  position: absolute;
+  top: 60rpx;
+  left: 100rpx;
+}
+
+.content .top .right-bottom .small-sound .sound-img {
+  width: 22rpx;
+  height: 20rpx;
+  display: inline-block;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+}
+
+
+.content .top .light-sound {
+  background: radial-gradient(circle, #1C2E4C 0%, #38A2D7 68%, #FFFFFF 100%)!important;
+  box-shadow: 0px 2rpx 22rpx rgba(255, 255, 255, 0.8)!important;
+}

+ 120 - 0
config/index.js

@@ -0,0 +1,120 @@
+export const API_BASE_URL = "http://192.168.0.44:8110";
+export const CDN_URL = 'https://houseoss.4dkankan.com';
+export const TYPE = {};
+export const CONNECT_STATUS = {
+  '0':'未连接',
+  '1':'正在连接',
+  '2':'已连接',
+  '3':'连接失败'
+}
+export const STATUS_TEXT = {
+  '0':'确认连接',
+  '1':'取消连接',
+  '2':'取消连接',
+  '3':'重新连接'
+}
+
+export const DISTRIBUTION = [
+  {
+    id:'xuting',
+    title:'序厅',
+    position:[0,19]
+  },
+  {
+    id:'zhuting',
+    title:'主厅',
+    position:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,20]
+  },
+  {
+    id:'futing',
+    title:'附厅',
+    position:[17,18]
+  }
+]
+
+export const G_AUDIO={
+  0:{
+    name:'序厅',
+    audio:'https://culture.4dage.com/demo/audio/1.2.mp3'
+  },
+  1:{
+    name:'第一部分 胜利回归,奉命组建',
+    audio:'https://culture.4dage.com/demo/audio/3.mp3'
+  },
+  2:{
+    name:'伟大决策',
+    audio:'https://culture.4dage.com/demo/audio/4.mp3'
+  },
+  3:{
+    name:'筹备组建',
+    audio:'https://culture.4dage.com/demo/audio/5.mp3'
+  },
+  4:{
+    name:'公开亮相',
+    audio:'https://culture.4dage.com/demo/audio/6.mp3'
+  },
+  5:{
+    name:'第二部分 神圣进驻,不辱使命',
+    audio:'https://culture.4dage.com/demo/audio/7.mp3'
+  },
+  6:{
+    name:'第二部分 神圣进驻,不辱使命',
+    audio:'https://culture.4dage.com/demo/audio/8.mp3'
+  },
+  7:{
+    name:'龙成激情岁月',
+    audio:'https://culture.4dage.com/demo/audio/9.mp3'
+  },
+  8:{
+    name:'锻造濠江卫士',
+    audio:'https://culture.4dage.com/demo/audio/10.mp3'
+  },
+  9:{
+    name:'树立文明形象',
+    audio:'https://culture.4dage.com/demo/audio/11.mp3'
+  },
+  10:{
+    name:'第三部分 强军兴军,定海神针',
+    audio:'https://culture.4dage.com/demo/audio/12.13.mp3'
+  },
+  11:{
+    name:'聚力练兵备战 锻造防务精兵',
+    audio:'https://culture.4dage.com/demo/audio/14.mp3'
+  },
+  12:{
+    name:'走出国门对外交流',
+    audio:'https://culture.4dage.com/demo/audio/15.mp3'
+  },
+  13:{
+    name:'风雨同舟 守望相助',
+    audio:'https://culture.4dage.com/demo/audio/16.mp3'
+  },
+  14:{
+    name:'严守法规纪律 树好窗口形象',
+    audio:'https://culture.4dage.com/demo/audio/17.mp3'
+  },
+  15:{
+    name:'瞄准一流抓建 夯实部队根基',
+    audio:'https://culture.4dage.com/demo/audio/18.mp3'
+  },
+  16:{
+    name:'真情爱澳亲民 热心公益事业',
+    audio:'https://culture.4dage.com/demo/audio/19.mp3'
+  },
+  17:{
+    name:'亲切关怀 巨大鼓舞',
+    audio:'https://culture.4dage.com/demo/audio/20.21.mp3'
+  },
+  18:{
+    name:'功勋荣誉',
+    audio:'https://culture.4dage.com/demo/audio/22.mp3'
+  },
+  19:{
+    name:'驻澳门部队精神',
+    audio:'https://culture.4dage.com/demo/audio/23.mp3'
+  },
+  20:{
+    name:'大型景观《进驻澳门》',
+    audio:'https://culture.4dage.com/demo/audio/24.mp3'
+  }
+}

+ 27 - 0
pages/index/index.js

@@ -0,0 +1,27 @@
+// index.js
+// 获取应用实例
+const app = getApp();
+
+Page({
+  data: {
+    type: 'map',
+    navList:[{
+      id:'list',
+      name:'列表'
+    },{
+      id:'big-pic',
+      name:'大图'
+    },{
+      id:'map',
+      name:'地图'
+    }]
+  },
+  onLoad() {
+  },
+  switchType(e) {
+    let type = e.target.dataset && e.target.dataset.type || 'map';
+    this.setData({
+      type
+    })
+  }
+})

+ 7 - 0
pages/index/index.json

@@ -0,0 +1,7 @@
+{
+  "usingComponents": {
+    "map-sense": "../../components/map-sense/map-sense",
+    "big-pic": "../../components/big-pic/big-pic",
+    "list": "../../components/list/list"
+  }
+}

+ 18 - 0
pages/index/index.wxml

@@ -0,0 +1,18 @@
+<!--index.wxml-->
+<view class="container">
+  <view class="con">
+    <view class="nav">
+      <block wx:for="{{navList}}" wx:key="index">
+        <view bindtap="switchType" class="list {{type === item.id? 'cur':''}}"  data-type="{{item.id}}">
+          {{item.name}}
+        </view>
+        <view class="line" wx:if="{{index<navList.length}}"></view>
+      </block>
+    </view>
+
+    <list wx:if="{{type === 'list'}}"></list>
+    <big-pic wx:elif="{{type === 'big-pic'}}"></big-pic>
+    <map-sense wx:else="{{type === 'map'}}"></map-sense>
+  </view>
+    
+</view>

+ 51 - 0
pages/index/index.wxss

@@ -0,0 +1,51 @@
+/**index.wxss**/
+.container {
+  width: 100%;
+  height: 100%;
+  position: relative;
+}
+
+.con{
+  width: 80%;
+  position: absolute;
+  top: 45%;
+  left: 50%;
+  transform: translate(-50%,-50%);
+}
+
+.nav {
+  width: 100%;
+  height: 82rpx;
+  display: flex;
+  justify-content: center;
+  background: #FFFFFF;
+  overflow: hidden;
+  box-shadow: 0rpx 6rpx 12rpx rgba(0, 0, 0, 0.65);
+  margin-top: 10%;
+  border-radius: 10rpx 10rpx 0rpx 0rpx;
+}
+
+.line{
+  width: 1rpx;
+  height: 100%;
+  background: #1C2E4C;
+  opacity: 0.4;
+}
+
+
+.nav .cur {
+  background: linear-gradient(to top, #1C2E4C 0%, #38A2D7 100%);
+  color: #FFFFFF;
+}
+
+
+.list {
+  box-sizing: border-box;
+  width: 100%;
+  font-size: 28rpx;
+  font-weight: 400;
+  line-height: 82rpx;
+  text-align: center;
+  color: #1C2E4C;
+}
+

+ 79 - 0
project.config.json

@@ -0,0 +1,79 @@
+{
+  "description": "项目配置文件",
+  "packOptions": {
+    "ignore": []
+  },
+  "setting": {
+    "urlCheck": false,
+    "es6": true,
+    "enhance": false,
+    "postcss": true,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "newFeature": false,
+    "coverView": true,
+    "nodeModules": false,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "scopeDataCheck": false,
+    "uglifyFileName": false,
+    "checkInvalidKey": true,
+    "checkSiteMap": true,
+    "uploadWithSourceMap": true,
+    "compileHotReLoad": false,
+    "lazyloadPlaceholderEnable": false,
+    "useMultiFrameRuntime": true,
+    "useApiHook": true,
+    "useApiHostProcess": true,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    },
+    "enableEngineNative": false,
+    "useIsolateContext": true,
+    "userConfirmedBundleSwitch": false,
+    "packNpmManually": false,
+    "packNpmRelationList": [],
+    "minifyWXSS": true,
+    "disableUseStrict": false,
+    "minifyWXML": true,
+    "showES6CompileOption": false,
+    "useCompilerPlugins": false
+  },
+  "compileType": "miniprogram",
+  "libVersion": "2.17.0",
+  "appid": "wxb4c0527aa20a6e9a",
+  "projectname": "macaoApplets",
+  "debugOptions": {
+    "hidedInDevtools": []
+  },
+  "scripts": {},
+  "staticServerOptions": {
+    "baseURL": "",
+    "servePath": ""
+  },
+  "isGameTourist": false,
+  "simulatorType": "wechat",
+  "simulatorPluginLibVersion": {},
+  "condition": {
+    "search": {
+      "list": []
+    },
+    "conversation": {
+      "list": []
+    },
+    "game": {
+      "list": []
+    },
+    "plugin": {
+      "list": []
+    },
+    "gamePlugin": {
+      "list": []
+    },
+    "miniprogram": {
+      "list": []
+    }
+  }
+}

+ 0 - 0
readme.md


+ 7 - 0
sitemap.json

@@ -0,0 +1,7 @@
+{
+  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
+  "rules": [{
+  "action": "allow",
+  "page": "*"
+  }]
+}

+ 43 - 0
utils/http.js

@@ -0,0 +1,43 @@
+import { API_BASE_URL } from '../config/index';
+const BASE_URL = `${API_BASE_URL}`;
+function request (url, options) {
+  return new Promise((resolve, reject) => {
+    wx.request(Object.assign({
+      url: url.indexOf('://') == -1 ? BASE_URL + url : url,
+      method: options.method,
+      data: options.data,
+      header: options.header || {},
+      success (res) {
+        if (res.data.code == 0 || res.data.code == 200 || res.data.errno === 0) {
+          resolve(res.data)
+        } else {
+          reject(res)
+        }
+      },
+      fail (err) {
+        console.log(err, '请求失败')
+        reject(err)
+      }
+    }, options))
+    
+    setTimeout(() => reject('time out'), 5000)
+  })
+}
+
+function get (url, data, options = {}) {
+  options.method = 'GET'
+  options.data = data
+  return request(url, options)
+}
+
+function post (url, data = {}, options = {}) {
+  options.method = 'POST'
+  options.data = Object.assign({}, data)
+  return request(url, options)
+}
+
+export default {
+  request,
+  get,
+  post
+}

+ 169 - 0
utils/util.js

@@ -0,0 +1,169 @@
+function forEach(array, cloneTarget) {
+  let index = -1;
+  const length = array.length;
+  while (++index < length) {
+    cloneTarget(array[index], index);
+  }
+  return array;
+}
+
+
+const formatTime = date => {
+  const year = date.getFullYear()
+  const month = date.getMonth() + 1
+  const day = date.getDate()
+  const hour = date.getHours()
+  const minute = date.getMinutes()
+  const second = date.getSeconds()
+  return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
+}
+
+const formatNumber = n => {
+  n = n.toString()
+  return n[1] ? n : `0${n}`
+}
+
+const promisify =  (api) => {
+  return (options, ...params) => {
+      return new Promise((resolve, reject) => {
+          api(Object.assign({}, options, { success: resolve, fail: reject }), ...params);
+      });
+  }
+}
+
+const BeaconUtils = {
+// 深拷贝
+clone: function(target, map = new WeakMap()) {
+  if (typeof target === 'object') {
+    const isArray = Array.isArray(target);
+    let cloneTarget = isArray ? [] : {};
+    if (map.get(target)) {
+      return target;
+    }
+    map.set(target, cloneTarget);
+    const keys = isArray ? undefined : Object.keys(target);
+    forEach(keys || target, (value, key) => {
+      if (keys) key = value
+      cloneTarget[key] = BeaconUtils.clone(target[key], map);
+    });
+    return cloneTarget;
+  } else {
+    return target;
+  }
+},
+
+// 计算距离
+calculateAccuracy:function(txPower, rssi, n) {
+  // return (0.89976) * Math.pow(rssi / txPower, 7.7095) + 0.111
+
+  return Math.pow(10, Math.abs(rssi - txPower) / (10 * n))
+},
+
+//求数组平均值
+arrayAverage:function (arr) {
+   let tmp = arr.reduce((acc, val) => acc + val, 0) / arr.length
+   return tmp
+},
+
+//数组分类:按照关键词key
+//data = {10003:[{},{},···],10002:[{},{},···],10001:[{},{},···]}
+classification:function (list,key) {
+  let data = {}
+  for(let i = 0; i < list.length; i++) {
+      if(!data[list[i][key]]) {
+          data[list[i][key]] = [list[i]];
+      }else {
+          data[list[i][key]].push(list[i])
+      }
+
+  }
+
+
+  return data
+},
+
+
+//求一维队列某点的高斯模糊权重 @param(队列长度,目标位置, 平均差)
+getOneGuassionArray: function(size, kerR, sigma) {
+    // if (size % 2 > 0) {
+    //   size -= 1
+    // }
+    // if (!size) {
+    //   return []
+    // }
+    // if (kerR > size-1){
+    //   return []
+    // }
+    let sum = 0;
+    let arr = new Array(size);
+    //进来的列表的元素可能是一样的,防止平均差为0的情况
+    if(sigma == 0){
+      let weight = 1 / size;
+      return arr.fill(weight)
+    }
+    for (let i = 0; i < size; i++) {
+      arr[i] = Math.exp(-((i - kerR) * (i - kerR)) / (2 * sigma * sigma))
+      sum += arr[i];
+    }
+
+    return arr.map(e => e / sum);
+  },
+
+  //计算数组平均差
+  //list:rssi数组
+  //average:rssi平均值
+  getMeanDeviation: function(list,average){
+    let length = list.length;
+    //数组的每一个数都要减去一个平均数,结果取绝对值
+    let arr = list.map(num=>Math.abs(num-average))
+    return arr.reduce((prev,curr)=>prev+curr) / length;
+  },
+
+  //计算数组方差
+  // list:待计算数组
+  // average:数组元素平均值
+  getVariance:function(list,average){
+    let sum = 0;
+    for(let element of list){
+      sum += Math.pow((element - average),2)
+    }
+    return sum / list.length
+  },
+
+  //js实现字符串重复的repeat函数
+  repeat:function(src, n) {
+    return (new Array(n + 1)).join(src);
+  },
+
+  //计算椭圆长度
+  //R是预设的有效范围半径
+  //L是椭圆长度
+  getLR:function(R,L){
+    let d = L - R 
+    let r = (R - d) / 2
+    let h = r + d
+    return 2*Math.pow((R*R - h*h),0.5)
+  },
+
+  //返回数组中最大值的下标
+  maxIndex:function(arr){
+    let index = -1,max = arr[0];
+    
+    for(let i = 0;i < arr.length; i++){
+      if(arr[i] >= max){
+        index = i;
+        max = arr[i];
+      }
+    }
+    if(arr[index] == 0){
+      return null;
+    }
+    return index;
+  }
+}
+
+module.exports = {
+  formatTime,
+  promisify,
+  BeaconUtils
+}