<template>
	<!-- 蓝牙连接页面 -->
  <view class="content">
    <button type="default" v-show="!shows" @click="initBle">
      初始化蓝牙模块
    </button>
    <scroll-view scroll-y="true" show-scrollbar="true">
      <radio-group>
        <view
          v-for="(item, index) in bleDevs"
          :key="index"
          v-show="item.name.length > 0 && !shows"
          style="padding: 10rpx 20rpx; border-bottom: 1rpx solid #ececec"
          v-if="Math.max(100 + item.RSSI, 0) >= 30"
        >
          <view style="font-size: 32rpx; color: #333">
            <checkbox-group
              @change="checkboxChange"
              :data-name="item.name"
              :data-deviceId="item.deviceId"
            >
              <label>
                <checkbox :value="item.deviceId">
                  {{ item.name }}
                </checkbox>
              </label>
            </checkbox-group>
          </view>
          <view style="font-size: 20rpx; padding: 10rpx 0">
            deviceId: {{ item.deviceId }} 信号强度: {{ item.RSSI }}dBm ({{
              Math.max(100 + item.RSSI, 0)
            }}%)
          </view>
        </view>
        <view class="dis">
          <view @tap="connectBle" v-if="!shows" class="pl"> 连接 </view>
          <view @tap="close" v-if="shows" class="pl"> 断开 </view>
        </view>
      </radio-group>
    </scroll-view>

    <view class="barItems" v-if="shows">
      <view class="barItem" v-for="(item, index) in testItems" :key="index">
        <view class="name">{{ item.name }}</view>
        <!-- <sliderBar
          class="bar"
          :min="item.min"
          :max="item.max"
          @change="changeBar($event, item)"
        ></sliderBar> -->
        <view class="bar">
          <view class="reduce" @click="changNums(1, item)">－</view>
          <input type="tel" v-model="item.typeNums" @input="changeBar(item)" />
          <view class="add" @click="changNums(2, item)">＋</view>
        </view>
      </view>
    </view>

    <view class="timers" v-if="shows">
      <view class="time">
        {{ titleTime }}
      </view>
      <view class="btns">
        <view @click="begin">启动</view>
        <view @click="pause">暂停</view>
        <view @click="stop">停止</view>
      </view>
    </view>

    <view v-if="shows">
      <view class="input3">
        <input type="text" v-model="input1" />
        <input type="text" v-model="input2" />
      </view>
      <button type="default" class="send" @click="send(1)">发送</button>
    </view>

    <view class="appItems">
      <viwe
        :class="[item.status ? 'item bakBlue' : 'item']"
        v-for="(item, index) in totalList"
        :key="index"
      >
        <view class="txt">{{ item.text }}</view>
        <view class="name p_hide">{{ item.name }}</view>
      </viwe>
    </view>

    <view class="items" v-if="shows">
      <view class="item" v-for="(item, index) in getData" :key="index">
        {{ item.name }}：{{ item.txt }}
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      config: {
        color: "#333",
        backgroundColor: [1, "#fff"],
        title: "多设备蓝牙连接",
        back: false,
      },
      title: "Hello",
      bleDevs: [],
      status: -2, //-2未连接  -1已连接  0连接成功
      deviceId: "",
      serviceId: "",
      characteristicId: "",

      sendData: "",
      getData: [],

      deviceIds: [],
      totalList: [], // 全部已连接的设备

      timeIndex: 0, // 默认是列表的第一个

      timeout: null,
      shows: false,

      testItems: [
        {
          index: 1,
          typeNums: 1,
          min: 0,
          max: 150,
          name: "设定频率",
          value: "F",
        },
        {
          index: 2,
          typeNums: 250,
          min: 50,
          max: 250,
          name: "设定脉宽",
          value: "W",
        },
        { index: 3, typeNums: 3, min: 0, max: 3, name: "设定类型", value: "C" },
        {
          index: 4,
          typeNums: 0,
          min: 0,
          max: 120,
          name: "设定电流",
          value: "I",
        },
        {
          index: 5,
          typeNums: 0,
          min: 1,
          max: 100,
          name: "设定方案",
          value: "M",
        },
      ],

      titleTime: "00:00:00",
      timer: "",

      hour: 0,
      minutes: 0,
      seconds: 0,

      input1: "B",
      input2: "",
    };
  },
  destroyed() {
    clearInterval(this.timer);
  },
  onLoad() {},
  mounted() {
    this.onBLEConnectionStateChange();
  },
  methods: {
    // 开始计时
    begin() {
      if (this.start) {
        return;
      }
      this.sendData = "BS1\r";
      this.start = true;
      this.timer = setInterval(this.startTimer, 1000);
      this.send();
    },
    startTimer() {
      this.seconds += 1;
      if (this.seconds >= 60) {
        this.seconds = 0;
        this.minute = this.minute + 1;
      }

      if (this.minute >= 60) {
        this.minute = 0;
        this.hour = this.hour + 1;
      }
      this.titleTime =
        (this.hour < 10 ? "0" + this.hour : this.hour) +
        ":" +
        (this.minutes < 10 ? "0" + this.minutes : this.minutes) +
        ":" +
        (this.seconds < 10 ? "0" + this.seconds : this.seconds);
    },
    // 暂停倒计时
    pause() {
      if (this.timer) {
        clearInterval(this.timer);
        this.start = false;
        this.sendData = "BS2\r";
        this.send();
        // this.timer = null
      }
    },
    stop() {
      if (this.timer) {
        clearInterval(this.timer);
        // this.timer = null
        this.sendData = "BS3\r";
        this.send();
        this.titleTime = "00:00:00";
        this.timer = "";
        this.hour = 0;
        this.minutes = 0;
        this.seconds = 0;
        this.start = false;
      }
    },
    changNums(index, item) {
      // 1为减少，2为增加
      if (index == 1) {
        if (item.typeNums <= item.min) {
          uni.showToast({
            title: "已经不能再减少了",
            icon: "none",
          });
          return;
        }
        item.typeNums--;
      } else if (index == 2) {
        if (item.typeNums >= item.max) {
          uni.showToast({
            title: "已经不能再增加了",
            icon: "none",
          });
          return;
        }
        item.typeNums++;
      }
      this.changeBar(item);
    },
    changeBar(item) {
      // 处理防抖
      if (this.timeout) {
        clearTimeout(this.timeout);
      }
      this.timeout = setTimeout(() => {
        if (item.typeNums < item.min) {
          uni.showToast({
            title: "低于最小值，已变更为最小值发送",
            icon: "none",
          });
          item.typeNums = item.min;
        } else if (item.typeNums > item.max) {
          uni.showToast({
            title: "超过最大值，已变更为最大值发送",
            icon: "none",
          });
          item.typeNums = item.max;
        }
        this.sendData = "B" + item.value + item.typeNums + "\r";
        for (let i = 0; i < this.deviceIds.length; i++) {
          this.getBLEDeviceServices(1, this.deviceIds[i]);
        }
      }, 500);
    },
    checkboxChange(e) {
      if (e.target.value[0] && e.target.dataset.name) {
        let item = {
          deviceId: e.target.value[0],
          name: e.target.dataset.name,
        };
        this.deviceIds.push(item);
      } else {
        for (let index = 0; index < this.deviceIds.length; index++) {
          let item = this.deviceIds[index];
          if (item.deviceId == e.target.dataset.deviceid) {
            this.deviceIds.splice(index, 1);
          }
        }
      }
    },
    hextoString(hex) {
      var arr = hex.split("");
      var out = "";
      for (var i = 0; i < arr.length / 2; i++) {
        var tmp = "0x" + arr[i * 2] + arr[i * 2 + 1];
        var charValue = String.fromCharCode(tmp);
        out += charValue;
      }
      return out;
    },
    send(index) {
      let that = this;
      if (index == 1) {
        that.sendData = that.input1 + that.input2 + "\r";
      }
      if (!that.sendData) {
        return uni.showToast({
          title: "发送数据不可为空",
          icon: "none",
        });
      }
      uni.showLoading({
        title: "发送中，请稍等",
        mask: true,
      });
      for (let i = 0; i < that.deviceIds.length; i++) {
        that.getBLEDeviceServices(1, that.deviceIds[i]);
      }
    },
    // ArrayBuffer转16进度字符串示例
    ab2hex(buffer) {
      const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
          return ("00" + bit.toString(16)).slice(-2);
        }
      );
      return hexArr.join("");
    },

    onBLEConnectionStateChange() {
      uni.onBLEConnectionStateChange((res) => {
        // 该方法回调中可以用于处理连接意外断开等异常情况
        if (res.connected == false) {
          uni.hideLoading();
          for (let i = 0; i < this.deviceIds.length; i++) {
            if (res.deviceId == this.deviceIds[i].deviceId) {
              uni.showToast({
                title: this.deviceIds[i].name + " 蓝牙设备断开连接",
                icon: "none",
              });
            }
          }
        }
      });
    },
    //初始化蓝牙
    initBle() {
      // console.log("初始化蓝牙>>>");
      this.bleDevs = [];
      this.deviceIds = [];
      uni.openBluetoothAdapter({
        success: (res) => {
          //已打开
          uni.getBluetoothAdapterState({
            //蓝牙的匹配状态
            success: (res1) => {
              // console.log(res1, "“本机设备的蓝牙已打开”");
              // 开始搜索蓝牙设备
              this.startBluetoothDeviceDiscovery();
            },
            fail(error) {
              uni.showToast({ icon: "none", title: "查看手机蓝牙是否打开" });
            },
          });
        },
        fail: (err) => {
          //未打开
          uni.showToast({ icon: "none", title: "查看手机蓝牙是否打开" });
        },
      });
    },
    // 开始搜索蓝牙设备
    startBluetoothDeviceDiscovery() {
      uni.startBluetoothDevicesDiscovery({
        success: (res) => {
          // console.log("启动成功", res);
          // 发现外围设备
          this.onBluetoothDeviceFound();
        },
        fail: (err) => {
          // console.log(err, "错误信息");
        },
      });
    },
    // 发现外围设备
    onBluetoothDeviceFound() {
      // console.log("执行到这--发现外围设备")
      uni.onBluetoothDeviceFound((res) => {
        // 吧搜索到的设备存储起来，方便我们在页面上展示
        if (this.bleDevs.indexOf(res.devices[0]) == -1) {
          this.bleDevs.push(res.devices[0]);
        }
        // console.log("蓝牙列表", res);
      });
    },

    // 多选然后连接
    connectBle() {
      if (this.deviceIds.length == 0) {
        uni.showToast({ title: "请选择连接的设备", icon: "none" });
        return;
      }
      this.getData = [];
      // for (let i = 0; i < this.deviceIds.length; i++) {
      //   this.createBLEConnection(this.deviceIds[i]);
      //   // this.nowLinkLis(this.deviceIds[i]);
      // }
      this.deviceIds.forEach((item) => {
        // this.createBLEConnection(item);
        this.nowLinkLis(item);
      });
    },

    //选择设备连接吧deviceId传进来
    createBLEConnection(item) {
      uni.showLoading({
        title: "连接中，请稍等",
        mask: true,
      });
      let that = this;
      //连接蓝牙
      uni.createBLEConnection({
        deviceId: item.deviceId,
        success(res) {
          that.shows = true;
          that.stopBluetoothDevicesDiscovery();
          that.getBLEDeviceServices(2, item);
        },
        fail(res) {
          console.log("蓝牙连接失败", res);
          uni.showToast({
            title: items.name + "蓝牙连接失败",
            icon: "none",
          });
        },
      });
    },
    // 停止搜寻蓝牙设备
    stopBluetoothDevicesDiscovery() {
      uni.stopBluetoothDevicesDiscovery({
        success: (e) => {
          this.loading = false;
          // console.log("停止搜索蓝牙设备:" + e.errMsg);
        },
        fail: (e) => {
          console.log("停止搜索蓝牙设备失败，错误码：" + e.errCode);
        },
      });
    },

    //获取蓝牙的所有服务
    getBLEDeviceServices(index, items) {
      setTimeout(() => {
        uni.getBLEDeviceServices({
          // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
          deviceId: items.deviceId,
          success: (res) => {
            // console.log("成功",res)
            // console.log("device services:", res);
            //这里会获取到好多个services  uuid  我们只存储我们需要用到的就行，这个uuid一般硬件厂家会给我们提供
            console.log("services", res.services);
            res.services.forEach((item) => {
              if (
                item.uuid.indexOf("0000FFE0-0000-1000-8000-00805F9B34FB") != -1
              ) {
                items["serviceId"] = item.uuid;
                //进入特征
                this.getBLEDeviceCharacteristics(index, items);
              }
            });
          },
        });
      }, 1000);
    },
    //获取蓝牙特征
    getBLEDeviceCharacteristics(index, items) {
      // console.log("进入特征");
      setTimeout(() => {
        uni.getBLEDeviceCharacteristics({
          // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
          deviceId: items.deviceId,
          // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
          serviceId: items.serviceId,
          success: (res) => {
            console.log("characteristics", res);
            res.characteristics.forEach((item) => {
              if (
                // 2 支持监听   1 支持写入
                item.uuid.indexOf(
                  index == 1
                    ? "0000FFE1-0000-1000-8000-00805F9B34FB"
                    : "0000FFE2-0000-1000-8000-00805F9B34FB"
                ) != -1
              ) {
                items["characteristicId"] = item.uuid;
                if (index == 2) {
                  this.notifyBLECharacteristicValueChange(items);
                }
              }
            });
            if (index == 1) {
              this.writeString(this.sendData, items);
            }
          },
          fail: (res) => {
            console.log(res);
          },
        });
      }, 0);
    },
    // 启用 notify 功能
    notifyBLECharacteristicValueChange(items) {
      let that = this;
      uni.notifyBLECharacteristicValueChange({
        state: true, // 启用 notify 功能
        // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
        deviceId: items.deviceId,
        // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
        serviceId: items.serviceId,
        // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
        characteristicId: items.characteristicId,
        success: (res) => {
          console.log("启用 notify 功能成功", res);
          uni.hideLoading();
          // uni.showToast({
          //   title: items.name + "连接成功",
          //   icon: "none",
          // });
          items["status"] = true;
          items["text"] = "";
          that.totalList.push(items);
          uni.onBLECharacteristicValueChange((res) => {
            // console.log("监听成功", res);
            // ArrayBuffer;
            //res.value是ArrayBuffer类型的，官方给了一个方法转16进制，我们再进行操作
            // console.log(that.ab2hex(res.value));

            for (let i = 0; i < that.deviceIds.length; i++) {
              if (res.deviceId == that.deviceIds[i].deviceId) {
                // uni.showToast({
                //   title: "接收到蓝牙" + that.deviceIds[i].name + "信息",
                //   icon: "none",
                // });
                let item = {
                  name: that.deviceIds[i].name,
                  txt: "接收到：" + that.hextoString(that.ab2hex(res.value)),
                };
                that.getData.unshift(item);
              }
            }
            for (let i = 0; i < that.totalList.length; i++) {
              if (res.deviceId == that.totalList[i].deviceId) {
                that.totalList[i].text = that.hextoString(
                  that.ab2hex(res.value)
                );
              }
            }
            that.totalList = JSON.stringify(that.totalList);
            that.totalList = JSON.parse(that.totalList);
          });
        },
        fail: (res) => {
          console.log("启用 notify 功能失败", res);
        },
      });
    },
    close() {
      let that = this;
      uni.showModal({
        title: "提示",
        content: "将断开全部蓝牙连接",
        success: function (res) {
          if (res.confirm) {
            for (let index = 0; index < that.deviceIds.length; index++) {
              let item = that.deviceIds[index];
              uni.closeBLEConnection({
                deviceId: item.deviceId,
                success(res) {
                  console.log("断开蓝牙成功", res);
                  that.shows = false;
                  that.totalList = [];
                  uni.showToast({
                    title: "断开蓝牙成功",
                  });
                },
                fail(res) {
                  console.log("断开蓝牙失败", res);
                },
              });
            }
          }
        },
      });
    },

    // 向蓝牙设备发送字符串数据 writeBLECharacteristicValueString
    writeString(str, items) {
      let that = this;
      // console.log("发送字符串数据", str);
      // 发送方式一
      let buffer = new ArrayBuffer(str.length);
      let dataView = new DataView(buffer);
      for (let i in str) {
        dataView.setUint8(i, str[i].charCodeAt() | 0);
        //打印二进制字节
        // console.log("dataView.getUint8(i)>>", dataView.getUint8(i));
      }
      //延迟发送指令
      setTimeout(() => {
        uni.writeBLECharacteristicValue({
          deviceId: items.deviceId,
          serviceId: items.serviceId,
          characteristicId: items.characteristicId,
          value: buffer,
          writeType: "write",
          success: function (res) {
            uni.hideLoading();
            // uni.showToast({
            //   title: "已成功发送",
            // });
            let item = {
              name: items.name,
              txt: "已发送：" + str,
            };
            that.getData.unshift(item);
          },
          fail: function (res) {
            uni.hideLoading();
            uni.showToast({
              title: "发送失败，可能蓝牙目前不支持写入",
              icon: "none",
            });
          },
        });
      }, 0);
    },

    // 直接启用监听功能
    nowLinkLis(items) {
      let that = this;
      console.log("items", items);
      uni.showLoading({
        title: "连接中，请稍等",
        mask: true,
      });
      //连接蓝牙
      uni.createBLEConnection({
        deviceId: items.deviceId,
        success(res) {
          that.stopBluetoothDevicesDiscovery(); // 停止搜索蓝牙
          setTimeout(() => {
            uni.notifyBLECharacteristicValueChange({
              state: true, // 启用 notify 功能
              deviceId: items.deviceId,
              serviceId: "0000FFE0-0000-1000-8000-00805F9B34FB",
              characteristicId: "0000FFE2-0000-1000-8000-00805F9B34FB",
              success: (res) => {
                console.log("启用监听了", res);
                that.shows = true;
                uni.hideLoading();
                items["status"] = true;
                items["text"] = "";
                that.totalList.push(items);
                uni.onBLECharacteristicValueChange((res) => {
                  for (let i = 0; i < that.deviceIds.length; i++) {
                    if (res.deviceId == that.deviceIds[i].deviceId) {
                      let item = {
                        name: that.deviceIds[i].name,
                        txt:
                          "接收到：" + that.hextoString(that.ab2hex(res.value)),
                      };
                      that.getData.unshift(item);
                    }
                  }
                  for (let i = 0; i < that.totalList.length; i++) {
                    if (res.deviceId == that.totalList[i].deviceId) {
                      that.totalList[i].text = that.hextoString(
                        that.ab2hex(res.value)
                      );
                    }
                  }
                  that.totalList = JSON.stringify(that.totalList);
                  that.totalList = JSON.parse(that.totalList);
                });
              },
              fail: (res) => {
                console.log("启用 notify 功能失败", res);
                uni.hideLoading();
                uni.showToast({ title: "连接失败", icon: "none" });
              },
            });
          }, 800);
        },
        fail(res) {
          console.log("蓝牙连接失败", res);
          uni.showToast({
            title: items.name + "连接失败",
            icon: "none",
          });
        },
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.input3 {
  display: flex;
  justify-content: space-around;
  input {
    border: 1rpx solid #ccc;
    margin: 20rpx;
    text-align: center;
    height: 60rpx;
    border-radius: 10rpx;
    font-size: 50rpx;
  }
  input:first-child,
  input:last-child {
    width: 200rpx;
  }
}
.bakBlue {
  background-color: #007aff !important;
}
.appItems {
  padding: 30rpx 0 30rpx 4rpx;
  display: flex;
  flex-wrap: wrap;
  .item {
    color: #333;
    width: 160rpx;
    height: 160rpx;
    border-radius: 50%;
    border: 1rpx solid #ececec;
    margin: 10rpx 15rpx;
    position: relative;
    .txt {
      position: absolute;
      font-size: 26rpx;
      top: 56rpx;
      width: 100%;
      color: #fff;
      z-index: 10;
      text-align: center;
    }
    .name {
      position: absolute;
      width: 80%;
      left: 10%;
      bottom: 30rpx;
      font-size: 20rpx;
      text-align: center;
    }
  }
}
.timers {
  text-align: center;
  margin-top: 30rpx;
  .time {
    margin-bottom: 40rpx;
    width: 100%;
    font-size: 80rpx;
    font-weight: bold;
  }
  .btns {
    display: flex;
    justify-content: space-around;
    view {
      width: 200rpx;
      height: 60rpx;
      background-color: #007aff;
      color: #fff;
      line-height: 60rpx;
      border-radius: 10rpx;
    }
    view:active {
      background-color: #2990ff;
    }
  }
}
.items {
  width: 100%;
  font-size: 32rpx;
  overflow-y: scroll;
  height: 300rpx;
  background-color: #ccc;
  margin: 40rpx 0;
  .item {
    padding: 4rpx 20rpx 0 20rpx;
  }
}
.pl {
  margin: 20rpx;
  background-color: #007aff;
  padding: 10rpx;
}
.classText {
  width: 94%;
  padding: 10rpx;
  margin: 3%;
  border: 1rpx solid #ececec;
}
.send {
  background-color: #ff3e3e;
  color: #fff;
}
.dis {
  display: flex;
  justify-content: space-between;
  color: #fff;
  text-align: center;
  flex-wrap: wrap;
  view {
    width: 100%;
    border-radius: 8rpx;
    font-size: 32rpx;
  }
}
.barItems {
  width: 100%;
  .barItem {
    display: flex;
    justify-content: space-around;
    // border: 1rpx solid #ececec;
    height: 100rpx;
    padding-top: 20rpx;
    align-items: center;
    .bar {
      width: 300rpx;
      display: flex;
      justify-content: space-around;
      view {
        border: 1rpx solid #ececec;
        width: 50rpx;
        height: 50rpx;
        text-align: center;
      }
      input {
        width: 100rpx;
        text-align: center;
      }
    }
  }
}
</style>
<style>
page {
  background-color: #fff;
}
</style>