<!--连接蓝牙 并打印  传入 打印格式 printMsg={strArr[]:,imgArr:[]}-->
<template>
  <view class="bluetooth-template">
    <!--uni-app-->
    <tui-loading v-if="loading"
                 :fixed="true"
                 text="请等待"></tui-loading>
    <tui-dialog :buttons="buttons"
                :show="show"
                title="打印内容"
                @close="close"
                @click="buttonTap">
      <template v-slot:content>
        <view class="boxButtoth">
          <view v-for="item,index in printMsg.strArr"
                :key="index">
            <view class="textStr">{{ (item.indexOf('---')　>=0 || item.indexOf('===')>=0)?"  " : item  }}</view>
          </view>
        </view>
      </template>
    </tui-dialog>
    <bluetoothJoinDigVue v-if="showJoio"
                         @close="clickShowJoio"
                         :blueDeviceList="blueDeviceList"
                         @connect="connect"
                         :loading="loading"></bluetoothJoinDigVue>
    <canvas canvas-id="myCanvas"
            class="canvas"></canvas>
  </view>
</template>
<script>
import { mapState, mapMutations } from "vuex";
import bluetoothJoinDigVue from "./bluetoothJoinDig.vue";
import { toGbkBytes, overwriteImageData, base64src } from "@/utils/util.js";
import ESC from "./ESC.js";
import tuiLoading from "@/components/thorui/tui-loading/tui-loading.vue";
// <script src="./gbk.js">
export default {
  components: {
    bluetoothJoinDigVue,
    tuiLoading,
  },
  data() {
    return {
      show: false,
      showJoio: false,
      time: null,
      buttons: [
        {
          text: "取消",
        },
        {
          text: "开始打印",
          color: "#586c94",
        },
      ],
      blueDeviceList: [],
      getServicesIndex: 0, //获取服务数组下标 //遍历服务时使用
      loading: false,
      joioBlueCount: 0,
      imgStrMsgData: new Array(),
    };
  },
  props: ["printMsg"],
  created() {
    this.shown();
  },
  methods: {
    ...mapMutations(["setBluetooth"]),
    showToast: function (e) {
      let params = {
        title: "操作成功",
        imgUrl: "/static/images/toast/check-circle.png",
        icon: true,
      };
      this.$refs.toast && this.$refs.toast.show(params);
    },
    shown() {
      this.show = true;
    },
    close() {
      this.$emit("close");
      this.show = false;
    },

    bluetoothReconnection() {
      this.joioBlueCount++;
      if (this.joioBlueCount > 2) {
        uni.showToast({
          icon: "none",
          title: "连接失败过多,请重新选择蓝牙连接!",
        });
        this.loading = false;
        this.setBluetooth({
          deviceId: "", 
          serviceId: "", 
          characteristicId: "", 
        });
        clearInterval(this.time);
        this.time = null;
        return;
      }
      console.log("读取vuex 速连");
      this.initBlue(false); 
    },
    buttonTap(e) {
      if (this.loading) return;
      if (e.index == 1) {
        if (!!this.bluetooth?.deviceId) {
          this.loading = true;
          console.log("已获得deviceId,获取服务 准备打印");
          this.getServices(); 
          return;
        }
        console.log("未连接  初始化");
        this.initBlue();
        this.showJoio = true; 
        return;
      }
      //点击取消按钮
      this.close();
    },
    //连接  外层
    clickShowJoio() {
      this.showJoio = !this.showJoio;
    },
    /**true 会搜寻设备 反之 只会初始化蓝牙 */
    initBlue(code = true) {
      let _this = this;
      uni.openBluetoothAdapter({
        success(res) {
          //搜寻设备
          console.log("初始化成功，搜寻蓝牙中");
          _this.discovery();
        },
        fail(err) {
          console.log("初始化蓝牙失败");
          uni.showToast({
            icon: "error",
            title: "初始化蓝牙失败",
          });
          _this.loading = false;
        },
      });
    },
    // 【2】开始搜寻附近设备
    discovery() {
      const _this = this;
      this.blueDeviceList = [];
      uni.startBluetoothDevicesDiscovery({
        success(res) {
          // 开启监听回调
          // console.log('传入值:',this.found);
          uni.onBluetoothDeviceFound((res) => {
            if (!!res.devices[0].name) {
              // 在未关闭搜索时，随时可能会开始搜索;
              console.log("监听到新设备", res);
              _this.blueDeviceList.push(res.devices[0]);
            }
          });
        },
        fail(err) {
          console.log("搜索失败");
          uni.showToast({
            icon: "error",
            title: "蓝牙搜索失败",
          });
          _this.loading = false;
          console.log(err);
        },
      });
    },
    // 【4】连接设备
    connect(data) {
      if (this.loading) return;
      this.loading = true;
      let deviceId = "";
      const _this = this;
      deviceId = data.deviceId;
      uni.createBLEConnection({
        deviceId,
        success(res) {
          _this.setBluetooth({ deviceId }); //存储deviceId
          _this.loading = false;
          // 停止搜索
          uni.showToast({
            icon: "success",
            title: "连接成功!",
          });
          _this.stopDiscovery(); //停止搜索
        },
        fail(err) {
          console.log("连接失败");
          _this.loading = false;
          uni.showToast({
            icon: "none",
            title: "拒绝连接!请检查是否已连接!或是手动断开连接",
          });
          uni.closeBluetoothAdapter({
            success(res) {
              console.log("端开连接");
              console.log(res);
            },
          });
          clearInterval(_this.time);
          _this.time = null;
          console.log(err);
        },
      });
    },

    // 【5】停止搜索
    stopDiscovery() {
      uni.stopBluetoothDevicesDiscovery({
        success(res) {
          console.log("停止成功");
          console.log(res);
        },
        fail(err) {
          _this.loading = false;
          uni.showToast({
            icon: "error",
            title: "连接失败!",
          });
          console.log("停止失败");
          console.log(err);
        },
      });
    },

    //获取蓝牙设备服务
    // 【6】获取服务 通过 蓝牙设备的deviceId 来 获取服务
    getServices() {
      let _this = this;
      uni.getBLEDeviceServices({
        deviceId: _this.bluetooth.deviceId, // 设备ID，在上一步【4】里获取
        success(res) {
          console.log("获取服务中res:", res);
          //获取成功 设置服务id  |-|  getServicesIndex下标从0开始
          if (_this.getServicesIndex >= res.services.length) {
            //检索服务完毕后仍未获得可写服务 则代表此设备不支持打印
            _this.getServicesIndex = 0; //重置获取
            _this.setBluetooth({
              deviceId: "", // 设备ID，在【4】里获取到
              serviceId: "", // 服务UUID，在【6】里能获取到
              characteristicId: "", //特征值
            });
            uni.showToast({
              icon: "error",
              title: "该设备不支持此服务!",
            });
            uni.closeBluetoothAdapter({
              success(res) {
                console.log("断开连接!");
              },
            });
            this.loading = false;
            return;
          }
          _this.setBluetooth({
            serviceId: res.services[_this.getServicesIndex].uuid,
          });
          //使用服务id  获取提供服务
          clearInterval(_this.time);
          _this.time = null;
          _this.time = setInterval(
            (_this) => {
              if (!!_this.bluetooth.serviceId) {
                clearInterval(_this.time);
                _this.time = null;
                _this.getCharacteristics();
              }
            },
            1000,
            _this
          );
        },
        fail(err) {
          _this.loading = false;
          uni.showToast({
            icon: "error",
            title: "获取服务失败!",
          });
          _this.getServicesIndex = 0; //重置获取
          _this.setBluetooth({
            deviceId: "", // 设备ID，在【4】里获取到
            serviceId: "", // 服务UUID，在【6】里能获取到
            characteristicId: "", //特征值
          });
          console.log("打印失败 断开连接初始化");
          console.log(_this.bluetooth);
          uni.closeBluetoothAdapter({
            success(res) {
              uni.showToast({
                icon: "error",
                title: "断开连接成功!",
              });
            },
          });
          console.log(err);
        },
      });
    },
    // 【7】获取提供的服务 特征值  以此使用服务
    getCharacteristics() {
      let _this = this;
      uni.getBLEDeviceCharacteristics({
        deviceId: _this.bluetooth.deviceId, // 设备ID，在【4】里获取到
        serviceId: _this.bluetooth.serviceId, // 服务UUID，在【6】里能获取到
        success(res) {
          console.log("获取到该服务的特征值:", res);
          res.characteristics.forEach((item, index) => {
            if (
              !!item?.properties?.write &&
              !!item?.properties?.read &&
              !!item?.properties?.notify
            ) {
              //提供 写服务
              console.log("获得提供写服务,如下:", item);
              _this.showJoio = false;
              _this.setBluetooth({
                characteristicId: res.characteristics[index].uuid,
              });
              clearInterval(_this.time);
              _this.time = null;
              _this.time = setInterval(
                (_this) => {
                  if (!!_this.bluetooth.characteristicId) {
                    clearInterval(_this.time);
                    _this.time = null;
                    _this.loading = false;
                    uni.showToast({
                      icon: "success",
                      title: "蓝牙连接成功",
                    });
                    console.log("开始打印!!", _this.printMsg);
                    _this.send(_this.printMsg);
                  }
                },
                1000,
                _this
              );
            }
          });
          if (!_this.bluetooth.characteristicId) {
            _this.getServicesIndex += 1;
            _this.getServices();
          }
        },
        fail(err) {
          _this.loading = false;
          _this.getServicesIndex = 0; 
          _this.setBluetooth({
            deviceId: "", 
            serviceId: "", 
            characteristicId: "",
          });
          uni.showToast({
            icon: "error",
            title: "连接失败!",
          });
          console.log(err);
        },
      });
    },

    notify() {
      let _this = this;
      console.log("开启消息监听");
      uni.notifyBLECharacteristicValueChange({
        deviceId: _this.bluetooth.deviceId, 
        serviceId: _this.bluetooth.serviceId,
        characteristicId: _this.bluetooth.characteristicId,
        success(res) {
          console.log(res);
          // 接受消息的方法
          _this.listenValueChange();
        },
        fail(err) {
          _this.loading = false;
          uni.showToast({
            icon: "error",
            title: "监听消息失败!",
          });
          console.log(err);
        },
      });
    },

    ab2hex: function (buffer) {
      const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
          return ("00" + bit.toString(16)).slice(-2);
        }
      );
      return hexArr.join("");
    },

    hexCharCodeToStr(hexCharCodeStr) {
      var trimedStr = hexCharCodeStr.trim();
      var rawStr =
        trimedStr.substr(0, 2).toLowerCase() === "0x"
          ? trimedStr.substr(2)
          : trimedStr;
      var len = rawStr.length;
      if (len % 2 !== 0) {
        alert("存在非法字符!");
        return "";
      }
      var curCharCode;
      var resultStr = [];
      for (var i = 0; i < len; i = i + 2) {
        curCharCode = parseInt(rawStr.substr(i, 2), 16);
        resultStr.push(String.fromCharCode(curCharCode));
      }
      return resultStr.join("");
    },


    listenValueChange() {
      uni.onBLECharacteristicValueChange((res) => {
        let resHex = ab2hex(res.value);
        console.log(resHex);
        let result = hexCharCodeToStr(resHex);
        console.log(result);
      });
    },
    send(msg) {
      // 做一个 msg 检查 只能为字符串
      let _this = this;
      let strMsg = null;
      this.imgStrMsgData.push(...ESC.Padd(1));
      msg.strArr.forEach((item, index) => {
        this.imgStrMsgData.push(...toGbkBytes(item));
      });
      this.sendImageData(this.imgStrMsgData);
      return;
      if (msg?.imgArr?.length > 0) {
        console.log("图片数量");
        this.getImgDataUint8(msg.imgArr);
      } else {
        this.sendImageData(this.imgStrMsgData);
      }
    },
    sendImageData(data) {
      if (this.loading) return;
      this.loading = true;
      const chunkSize = 20; // 每个数据块的大小
      let index = 0;
      let _this = this;
      function sendChunk() {
        if (!_this.loading) return; 
        const chunk = data.slice(index, index + chunkSize);
        _this.wrtePrintBluetooth(chunk);
        index += chunkSize;
        if (index < data.length) {
          setTimeout(sendChunk, 1000); // 延时1秒后发送下一个数据块
        } else {
          _this.loading = false;
        }
      }
      sendChunk(); // 开始发送第一个数据块
    },
    wrtePrintBluetooth(msg) {
      console.log("执行打印操作！！！！");
      let _this = this;
      uni.writeBLECharacteristicValue({
        deviceId: _this.bluetooth.deviceId, // 设备ID，在【4】里获取到
        serviceId: _this.bluetooth.serviceId, // 服务UUID，在【6】里能获取到
        characteristicId: _this.bluetooth.characteristicId, // 特征值，在【7】里能获取到
        value: msg,
        success(res) {},
        fail(err) {
          console.log("打印失败 断开连接初始化");
          console.log(_this.bluetooth);
          // _this.loading = true;
          uni.closeBluetoothAdapter({
            success(res) {
              console.log("断开连接");
              console.log(res);
              // _this.bluetoothReconnection();
            },
          });
          console.log(err);
          uni.showToast({
            icon: "error",
            title: "打印失败",
          });
          _this.loading = false;
        },
      });
    },
    // 【11】发送读取数据命令  读取数据在 onBLECharacteristicValueChange 获取数据
    read() {
      let _this = thsi;
      uni.readBLECharacteristicValue({
        deviceId: _this.bluetooth.deviceId, // 设备ID，在【4】里获取到
        serviceId: _this.bluetooth.serviceId, // 服务UUID，在【6】里能获取到
        characteristicId: _this.bluetooth.characteristicId, // 特征值，在【7】里能获取到
        success(res) {
          console.log("读取指令发送成功");
          console.log(res);
        },
        fail(err) {
          _this.loading = false;
          uni.showToast({
            icon: "error",
            title: "读取命令失败!",
          });
          console.log("读取指令发送失败");
          console.log(err);
        },
      });
    },
    //获取蓝牙 已连接的 设备
    getJoinBlue() {
      const _this = this;
      uni.getBluetoothDevices({
        success(res) {
          console.log("获取已连接的设备：");
          console.log(res);
          // _this.blueDeviceList.push(...JSON.parse(JSON.stringify(res.devices)));
        },
      });
    },
    /**打印数据数据处理 */
    setCanvas() {
      uni.createCanvasContext("canvas-id", this);
    },
    /**
     *
     * @param {图片数据} imgData
     */
    getImgDataUint8(imgArr) {
      console.log("处理图片数据中1");
      let canvas = uni.createCanvasContext("myCanvas", this);
      // let images = [imgData1, imgData2, imgData3]; // 假设有三张图片的数据
      let loadedCount = 0; // 记录已加载完成的图片数量
      let height = 0;
      // 遍历每张图片数据
      console.log("处理图片数据中2");
      for (let i = 0; i < imgArr.length; i++) {
        let base64Img = null;
        base64src(imgArr[i], i, (path, _this = this) => {
          console.log("路径:", path);
          _this.base64Img = path;
        });
        console.log("是否改变:", base64Img);
        let _this = this;
        // 使用闭包来保存当前图片的索引
        (function (index) {
          // let arrayBuffer = uni.base64ToArrayBuffer(base64Data);
          let canvasWidth = canvas.width;
          let imgWidth = 70;
          let imgHeight = 70;
          let scaleRatio = canvasWidth / imgWidth; // 计算缩放比例
          if (canvasWidth > imgWidth) {
            canvasWidth = imgWidth;
            scaleRatio = 1;
          }
          // 根据图片索引计算绘制的位置
          // let x = widthAll;
          let x = 0; //x位置不变
          let y = height;
          canvas.drawImage(
            base64Img,
            0,
            0,
            imgWidth,
            imgHeight,
            x,
            y,
            canvasWidth,
            imgHeight * scaleRatio
          ); // 绘制并缩放图片
          // canvas.draw();
          loadedCount++;
          // 更新已加载完成的图片数量;
          // 如果所有图片都加载完成，执行其他操作
          if (loadedCount === imgArr.length) {
            console.log("处理数据完成");
            uni.canvasGetImageData(
              {
                canvasId: "myCanvas",
                x: 0,
                y: 0,
                width: 100,
                height: height,
                success: (res) => {
                  console.log(res.width); // 100
                  console.log(res.height); // 100
                  console.log(res.data instanceof Uint8ClampedArray); // true
                  console.log(res.data.length); // 100 * 100 * 4
                  console.log("object");
                  console.log(res.data);
                  let op = overwriteImageData({
                    width: 100,
                    height: height,
                    ImageData: res.data,
                  });
                  _this.imgStrMsgData.push(...op.array);
                  // _this.wrtePrintBluetooth(_this.imgStrMsgData);
                  _this.sendImageData(_this.imgStrMsgData);
                },
                fail: (err) => {
                  _this.loading = false;
                  uni.showToast({
                    icon: "error",
                    title: "处理图片失败!",
                  });
                  console.log("失败o.o");
                  console.log(err);
                },
              },
              this
            );
          }
          // uni.getImageInfo({
          //   src: base64Img,
          //   success: function (res) {
          //   },
          //   fail: function (err) {
          //     console.log(err);
          //     console.log("绘图失败");
          //   },
          // });
        })(i);
        // 更新下一张图片的绘制位置
        // widthAll += canvas.canvas.width;
        // height += img.height;
        height += 100;
      }
    },
    setHEX(str) {
      var byteArr = new Array();
      for (var i = 0; i < str.length; i++) {
        var ch = str.charAt(i);
        if (ch == "%") {
          var num = str.charAt(i + 1) + str.charAt(i + 2);
          num = parseInt(num, 16);
          num = num | (-1 << 8);
          byteArr.push(num);
          i += 2;
        } else {
          byteArr.push(ch.charCodeAt());
        }
      }
      byteArr.push(0x0d, 0x0a);
      return byteArr;
    },
    //失败重置
  },
  computed: {
    ...mapState(["bluetooth"]),
  },
  mounted() {},
  beforeDestroy() {
    //---- 清空信息  是  该设备  不允许直接连接需要输入密钥
    //清空 vue 蓝牙连接信息
    // this.setBluetooth({
    //   deviceId: "", // 设备ID，在【4】里获取到
    //   serviceId: "", // 服务UUID，在【6】里能获取到
    //   characteristicId: "", //特征值
    // });
    //---------
    clearInterval(this.time);
    this.time = null;
  },
};
</script>
<style lang="scss" scoped>
.bluetooth-template {
  // width: 100vw;
  // overflow: scroll;
  // position: absolute;
  // top: 0;
  // left: 0;
  .boxButtoth {
    max-height: 40vh;
    overflow: scroll;
    padding-bottom: 1vh;
    padding-left: 20%;

    margin: 0 auto;
    .textStr {
      margin-top: 8rpx;
      text-align: left;
      font-size: 20rpx;
    }
  }
  .canvas {
    width: 100px;
    height: 100px;
  }
}
</style>
