微信小程序之蓝牙连接

总结: 

搜驴总结-蓝牙 | ProcessOn免费在线作图,在线流程图,在线思维导图

import alertService from "../providers/alert-service/alert-service";
import { BicycleControlTypes, DeviceTypes } from "../providers/class-service/enums";
import { decryptStringData, encryptionStringData } from "./AES128";
import { log, utilCommon } from "./util";

var eventBus = require('./js/event') // 导入event

// ArrayBuffer转16进度字符串
function ab2hex(buffer) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function (bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join('');
}
// 字符串转ArrayBuffer
function str2ad(str) {
  var typedArray = new Uint8Array(str.match(/[\da-f]{2}/gi).map(function (h) {
    return parseInt(h, 16)
  }))
  var buffer = typedArray.buffer
  return buffer;
}

/**
 * BluetoothControl
 * deviceNumber 设备编号
 */
export class BluetoothControl {

  protected deviceTypeList = {
    'zr': 'ControlDeviceKM06', 'G55': 'ControlDeviceG55', 'G26': 'ControlDeviceG26'
  };
  // protected _ASE128Key = [32, 87, 47, 82, 54, 75, 63, 71, 48, 80, 65, 88, 17, 99, 45, 43];
  // protected _ASE128Key = '2885930070353F0627567F70277E2221'; // 读写蓝牙加解密用的秘钥
  // aesSecret
  private blueToothConfigure = { aesSecret: '' };
  private scanDeviceNumber; // 扫码获得的设备号
  private deviceType = DeviceTypes.ControlDeviceUnkonw; // 根据设备号判断的当前连接的设备类型
  private deviceId = ''; // 链接上的设备id
  private deviceServiceId = ''; // 链接上的设备 ServiceId
  private deviceWriteId = ''; // 链接上的设备 WriteId
  private deviceReadId = ''; // 链接上的设备 WriteId

  private token = ''; // 蓝牙控制令牌 - 很重要 后面读写的设备的关键

  private currentOperate = BicycleControlTypes.ControlActionUnkonw; // 当前的操作类型
  // private secondConnection = false; // 是否断开重连
  // private isWriting = false; // 是否正在读写
  private tWrite: any; // 倒计时
  private tFound: any; // 倒计时

  constructor(deviceNumber, blueToothConfigure) {
    this.scanDeviceNumber = deviceNumber;
    this.blueToothConfigure = JSON.parse(blueToothConfigure) || {}
    console.log(this.scanDeviceNumber, '连接设备的设备号')
  }
  // 蓝牙链接 -------------start---------------
  // 初始化蓝牙适配器
  @log
  initBluetoothAdapert() {
    const that = this
    console.log("初始化蓝牙适配器");
    // this.setIntervalFound();
    wx.openBluetoothAdapter({
      success: function (res) {
        console.log("1.1获取自身蓝牙状态");
        that.getBluetoothAdapterState();
      },
      fail: function (err) {
        utilCommon.bluetoothOperateFail('初始化蓝牙适配器失败,请检查您的蓝牙~')
      },
      complete: function () {
        // 监听蓝牙状态改变
        that.onBluetoothAdapterStateChange();
        // clearInterval(that.tFound);
      }
    });
  }
  // 监听蓝牙状态改变
  @log
  onBluetoothAdapterStateChange() {
    wx.onBluetoothAdapterStateChange(function (res) {
      console.log('onBluetoothAdapterStateChange', res)
      // available 蓝牙适配器是否可用
      // discovering 蓝牙适配器是否处于搜索状态
      if (res.available && res.discovering) {
        // 获取蓝牙适配状态
        console.log('蓝牙状态改变-----蓝牙连接')
      } else {
        // alertService.showToast('蓝牙断开')
        console.log('蓝牙状态改变-----蓝牙断开')
      }
    })

  }
  // 获取蓝牙适配状态
  @log
  getBluetoothAdapterState() {
    console.log('2.获取本机蓝牙连接状态')
    // this.setIntervalFound();
    const that = this
    wx.getBluetoothAdapterState({
      success: function (res) {
        console.log("2.1获取本地蓝牙状态 available=true表示蓝牙已开启")
        console.log(res)
        if (res.available) {
          // 去搜索蓝牙
          that.startBluetoothDevicesDiscovery()
        } else {
          utilCommon.bluetoothOperateFail('请打开您的蓝牙后重新尝试')
        }
      },
      fail: function (res) {
        // 没有开启蓝牙 提示请打开蓝牙重新重试
        utilCommon.bluetoothOperateFail('请打开您的蓝牙后重新尝试')
      },
      complete: function () {
        // clearInterval(that.tFound);
      }
    })
  }
  // 搜索蓝牙设备
  @log
  startBluetoothDevicesDiscovery() {
    console.log('2.1搜索蓝牙')
    // this.setIntervalFound();
    var that = this;
    alertService.showLoading('正在搜索')
    wx.startBluetoothDevicesDiscovery({
      services: [],
      allowDuplicatesKey: false,
      success: function (res) {
        console.log('3.1 搜索到的蓝牙设备 然后获取列表')
        if (res.errCode == 0) {
          // 4.搜索到蓝牙
          that.onBluetoothDeviceFound(); // 获取蓝牙列表
        } else {
          // 没有搜索到蓝牙设备
          utilCommon.bluetoothOperateFail('找一个有车的地方再试试 ~')
        }
      },
      fail: function (err) {
        console.log(err);
        utilCommon.bluetoothOperateFail('找一个有车的地方再试试 ~')
      },
      complete: function () {
        // clearInterval(that.tFound);
      }
    });
  }
  // 查找当前蓝牙设备
  @log
  onBluetoothDeviceFound() {
    const that = this
    const found: any = wx.onBluetoothDeviceFound((res) => {
      console.log('查找设备', res);
      for (let index = 0; index < res.devices.length; index++) {
        const device = res.devices[index];
        if (!device.name && !device.localName) {
          continue;
        }
        const deviceCollection = this.getDeviceNumber(device);
        console.log('获取到设备号', deviceCollection)
        // deviceNumber === this.scanDeviceNumber
        // indexOf
        if (deviceCollection.deviceNumber.indexOf(this.scanDeviceNumber) > -1) {
          console.log('找到设备了')
          clearInterval(that.tFound)
          this.deviceType = deviceCollection.deviceType
          // 如果找到与当前扫码设备相匹配的蓝牙,则建立连接,停止寻找
          this.createBLEConnection(device.deviceId);
          wx.offBluetoothDeviceFound(found)
          // this.stopBluetoothDevicesDiscovery();
          console.log('设备类型', this.deviceType)
          return;
        }
        console.log('没找到设备')
      }
    })
    this.setIntervalFound(found)

  }
  // 查找已经添加过的蓝牙设备
  getBluetoothDevices() {
    const that = this;
    wx.getBluetoothDevices({
      success: function (res) {
        for (let index = 0; index < res.devices.length; index++) {
          const device = res.devices[index];
          if (!device.name && !device.localName) {
            continue;
          }
          const deviceCollection = that.getDeviceNumber(device);
          console.log('获取到设备号', deviceCollection)
          if (deviceCollection.deviceNumber.indexOf(that.scanDeviceNumber) > -1) {
            console.log('找到设备了')
            that.deviceType = deviceCollection.deviceType
            // 如果找到与当前扫码设备相匹配的蓝牙,则建立连接,停止寻找
            that.createBLEConnection(device.deviceId);
            // this.stopBluetoothDevicesDiscovery();
            console.log('设备类型', that.deviceType)
            return;
          }
        }
        console.log('没找到设备111111111111111')
        utilCommon.bluetoothOperateFail('未搜索到蓝牙设备')
      },

      fail: function () {
        console.log('没找到设备22222222222222222')

        utilCommon.bluetoothOperateFail('未搜索到蓝牙设备')
      }
    });
  }
  // 建立连接
  @log
  createBLEConnection(deviceId) {
    console.log('开始建立连接了!!')
    // this.setIntervalFound();
    wx.createBLEConnection({
      deviceId,
      success: (res) => {
        console.log('createBLEConnection', res)
        this.deviceId = deviceId;
        // 获取serviceId
        wx.getBLEDeviceServices({
          deviceId,
          success: (res) => {
            for (let i = 0; i < res.services.length; i++) {
              if (res.services[i].isPrimary) {
                console.log('getBLEDeviceCharacteristics')
                this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
                return
              }
            }
          },
          fail: () => {
            utilCommon.bluetoothOperateFail('蓝牙建立连接失败')
          },
          complete: () => {
            // clearInterval(this.tFound);
          }
        })
      }
    })
  }
  // 获取读写的UUID
  @log
  getBLEDeviceCharacteristics(deviceId, serviceId) {
    // this.setIntervalFound();
    this.deviceWriteId = ''
    this.deviceReadId = ''
    this.deviceServiceId = serviceId;
    console.log(this.deviceId, this.deviceServiceId)
    wx.getBLEDeviceCharacteristics({
      deviceId,
      serviceId,
      success: (res) => {
        for (let i = 0; i < res.characteristics.length; i++) {
          let item = res.characteristics[i]
          if (item.properties.read) {
            wx.readBLECharacteristicValue({
              deviceId,
              serviceId,
              characteristicId: item.uuid,
            })
          }
          if (item.properties.write) {
            this.deviceWriteId = item.uuid;
            // 获取令牌 - oppo手机读写后无反应是因为读写有反应,但是还没有开始监听读写返回值
            // setTimeout(() => {

            //   this.wiriteToDevice(BicycleControlTypes.ControlActionGetToken);
            // }, 100)
          }
          if (item.properties.notify || item.properties.indicate) {
            this.deviceReadId = item.uuid;
          }
        }
        // 获取令牌 - oppo手机读写后无反应是因为读写有反应,但是还没有开始监听读写返回值
        // 把读写方法放在外面保证循环内的方法走完了如果可以执行读写再去读写
        if (this.deviceWriteId && this.deviceReadId) {
          const that = this
          // this.setIntervalFound();
          wx.notifyBLECharacteristicValueChange({
            deviceId,
            serviceId,
            characteristicId: this.deviceReadId,
            state: true,
            success: function () {
              that.wiriteToDevice(BicycleControlTypes.ControlActionGetToken);
            },
            fail: function () {
              utilCommon.bluetoothOperateFail()
            },
            complete: function () {
              // clearInterval(that.tFound);
            }
          })
        }
        console.log('getBLEDeviceCharacteristics success', res, this)
      },
      fail: (res) => {
        utilCommon.bluetoothOperateFail('蓝牙建立连接失败')
        console.error('getBLEDeviceCharacteristics', res)
      },
      complete: () => {
        // clearInterval(this.tFound);
      }
    })
    // 操作之前先监听,保证第一时间获取数据
    this.getReadWriteValue();
  }
  // 关闭连接
  @log
  closeBLEConnection() {
    wx.closeBLEConnection({
      deviceId: this.deviceId
    });
    wx.closeBluetoothAdapter({
      success(res) {
      },
    })
  }
  // 停止扫描
  @log
  stopBluetoothDevicesDiscovery() {
    wx.stopBluetoothDevicesDiscovery()
  }
  // 蓝牙链接 -------------end---------------

  // 蓝牙操作 -------------start---------------

  // 监听读写的结果值
  @log
  getReadWriteValue() {
    const that = this;
    wx.onBLECharacteristicValueChange((characteristic) => {
      console.log('onBLECharacteristicValueChange', characteristic)
      clearInterval(that.tWrite)
      // 获取到的token赋值
      // const deCode = decryptData(ab2hex(characteristic.value), that._ASE128Key);
      const deCode = decryptStringData(ab2hex(characteristic.value), that.blueToothConfigure.aesSecret);
      let value: any = true;
      // 获取token
      if (that.currentOperate === BicycleControlTypes.ControlActionGetToken) {
        //  || that.secondConnection
        that.token = deCode.slice(6, 14);
        value = that.token;
        // // 如果是读写失败,重新读写
        // if (that.secondConnection) {
        //   that.wiriteToDevice(that.currentOperate)
        // }
      }
      // 获取电量
      else if (that.currentOperate === BicycleControlTypes.ControlActionGetBattery) {
        console.log(`获取电量`, deCode)
        value = {
          LVL: utilCommon.hex2int(deCode.slice(6, 8)), // 内部电池电量百分比
          EXL: utilCommon.hex2int(deCode.slice(8, 10)), // 外部电池电量百分比 - 用这个
          VOL1: utilCommon.hex2int(deCode.slice(10, 14)), // 内部电池电压,单位为 0.01v
          VOL2: utilCommon.hex2int(deCode.slice(14, 18)), // 外部电池电压,单位为 0.01v - 用这个
        }
      }
      // 设防、撤防状态
      else if (that.currentOperate === BicycleControlTypes.ControlActionGetDefence) {
        // 0 表示设防,1 表示撤防
        value = deCode.slice(6, 8)
      }
      // 电源状态
      else if (that.currentOperate === BicycleControlTypes.ControlActionGetPower) {
        // 0 表示断电,1 表示本地上电
        value = deCode.slice(6, 8)
      }
      // 设防、撤防、开电源、关电源
      else {
        const state = deCode.slice(6, 8)
        if (state != '00') {
          // 失败
          utilCommon.bluetoothOperateFail()
          return;
        }
      }
      // 设防、撤防、开电源、关电源 - 只要成功返回即可
      eventBus.emit("blueTooth", {
        type: that.currentOperate,
        value: value
      })
      console.log('onBLECharacteristicValueChange-获取token', deCode, value)
      // if (that.secondConnection) {
      //   that.secondConnection = false;
      // }
      // else {
      //   that.currentOperate = BicycleControlTypes.ControlActionUnkonw;
      // }
      // this.isWriting = false;
    })
  }
  // 设防
  // 撤防
  // 通电
  // 断电
  // 获取电源电压
  // 获取令牌 over
  @log
  wiriteToDevice(operateType) {
    // if (this.isWriting) return;
    // this.isWriting = true;
    const that = this
    this.setIntervalWrite()
    this.currentOperate = operateType;

    const sendFrame = this.getOperateTypes(operateType, this.deviceType, this.token)
    console.log('蓝牙指令获取', sendFrame, operateType, this.deviceType, this.scanDeviceNumber)
    if (!sendFrame || !this.blueToothConfigure.aesSecret) {
      utilCommon.bluetoothOperateFail()
    }
    // const key = encryptionData(sendFrame.code, this._ASE128Key)
    const key = encryptionStringData(sendFrame.code, this.blueToothConfigure.aesSecret)

    // 向蓝牙设备发送一个加密的16进制数据 key
    let buffer = str2ad(key);

    wx.writeBLECharacteristicValue({
      deviceId: that.deviceId,
      serviceId: that.deviceServiceId,
      characteristicId: that.deviceWriteId,
      writeType: 'write',
      value: buffer,
      success: function (res) {
        console.log('读写成功', that.currentOperate, res);
      },
      fail: function (res) {
        console.log('读写失败', that, that.currentOperate, res)
        if (res.errCode === 10006) {
          // 当前连接已断开,重新连接并读写
          alertService.showLoading('设备已断开')
          setTimeout(() => {
            alertService.showLoading('正在重连')
          }, 1000);
          that.createBLEConnection(that.deviceId)
          // that.secondConnection = true;
        }
        else if (res.errCode === 10000) {
          // 初始化蓝牙适配器失败
          clearInterval(that.tWrite);
          wx.closeBluetoothAdapter({
            success: function (res) {
              that.initBluetoothAdapert();
            },
          });
        }
        else {
          utilCommon.bluetoothOperateFail()
        }
      }
    })
  }
  // 10秒蓝牙没有响应,就是查找出问题了
  @log
  setIntervalFound(found?) {
    var i = 0;
    const that = this
    this.tFound = setInterval(() => {
      // console.log(i, '10秒蓝牙没有响应,就是查找出问题了')
      i++
      if (i === 10) {
        clearInterval(that.tFound);
        if (found) {
          wx.offBluetoothDeviceFound(found)
          // 获取已经连接过的设备
          that.getBluetoothDevices()
        } else {
          console.log('失败次数444444~~~~~~~~~~~~~~~~~~~~~~~~~~~')

          utilCommon.bluetoothOperateFail()
        }
      }

    }, 1000)
  }
  // 5秒蓝牙没有响应,就是读写出问题了
  @log
  setIntervalWrite() {
    var i = 0;
    const that = this
    this.tWrite = setInterval(() => {
      console.log(i, '5秒蓝牙没有响应,就是读写出问题了')
      i++
      if (i === 5) {
        utilCommon.bluetoothOperateFail('未搜索到蓝牙设备')
        clearInterval(that.tWrite)
      }

    }, 1000)
  }
  // 蓝牙操作 -------------end---------------
  // 蓝牙连接失败

  // 蓝牙操作过程中不同设备类型的的兼容
  // 根据不同的设备型号 获取deviceNumber
  @log
  getDeviceNumber(device) {
    console.log('设备名称', device.name || device.localName);
    let deviceNumber = '';
    let deviceType: any = 0;
    // 判断当前设备是不是合作商的设备
    const list = Object.keys(this.deviceTypeList);
    console.log(this.deviceTypeList)
    for (let index = 0; index < list.length; index++) {
      const it = list[index];
      if (device.name.indexOf(it) === 0) {
        console.log(this.deviceTypeList, this.deviceTypeList[it], it, DeviceTypes, DeviceTypes[this.deviceTypeList[it]])
        deviceType = DeviceTypes[this.deviceTypeList[it]];
        break;
      }
    }
    // 设备型号不同 获取设备类型不同
    switch (deviceType) {
      case DeviceTypes.ControlDeviceKM06:
        deviceNumber = (device.name || device.localName).substring(2);
        break;
      case DeviceTypes.ControlDeviceG26:
      case DeviceTypes.ControlDeviceG55:
        // 获取设备信息 转化为10进制设备号
        deviceNumber = ab2hex(device.advertisData).substring(4);
        break;

      default:
        deviceNumber = '';
        break;
    }
    console.log('deviceNumber', deviceNumber);
    return { deviceNumber, deviceType };
  }
  /**
   * 蓝牙控车指令
   * @param operateType 操作类型
   * @param deviceTypeCode 设备类型
   * @param token 蓝牙连接成功获取的token
   */
  @log
  getOperateTypes(operateType, deviceTypeCode, token?) {
    let code: any;
    token = token || '';
    switch (operateType) {
      // 获取令牌
      case BicycleControlTypes.ControlActionGetToken:
        code = {
          [DeviceTypes.ControlDeviceKM06]: { code: '222' },
          [DeviceTypes.ControlDeviceG26]: { code: '4234234324' },
          [DeviceTypes.ControlDeviceG55]: { code: '22342' }
        }
        break;
      // 设防
      case BicycleControlTypes.ControlActionFortify:
        code = {
          [DeviceTypes.ControlDeviceKM06]: { code: '' },
          [DeviceTypes.ControlDeviceG26]: { code: '55' + token + '000000' },
          [DeviceTypes.ControlDeviceG55]: { code: '555' + token + '000000' }
        }
        break;
      // 撤防
      case BicycleControlTypes.ControlActionDefence:
        code = {
          [DeviceTypes.ControlDeviceKM06]: { code: '' },
          [DeviceTypes.ControlDeviceG26]: { code: '6' + token + '000000' },
          [DeviceTypes.ControlDeviceG55]: { code: '66' + token + '000000' }
        }
        break;
      // 断电
      case BicycleControlTypes.ControlActionGOffPower:
        code = {
          [DeviceTypes.ControlDeviceKM06]: { code: '' },
          [DeviceTypes.ControlDeviceG26]: { code: '7' + token + '00' },
          [DeviceTypes.ControlDeviceG55]: { code: '777' + token + '00' }
        }
        break;
      // 默认获取令牌
      default:
        code = {
          [DeviceTypes.ControlDeviceKM06]: { code: '000' },
          [DeviceTypes.ControlDeviceG26]: { code: '002' },
          [DeviceTypes.ControlDeviceG55]: { code: '001' }
        }
        break;
    }
    return code[deviceTypeCode];
  }
}

失败的方法处理

  @log
  bluetoothOperateFail(toast?) {
    var app = getApp();
    alertService.showToast(toast || `操作失败,再试试~`)
    if(app.globalData.bluetoothConcatState) app.globalData.bluetoothConcatState.closeBLEConnection();
    app.globalData.bluetoothConcatState = null;
    eventBus.emit("blueTooth", {
      type: 'fail',
      value: true
    })
  }

初始化、调用的处理

/**
   * 蓝牙开锁 - 成功才会返回result
   * bluetoothOpenLock bluetoothRet-监听eventBus的返回值
   */
  public bluetoothOpenLock(bluetoothRet?: any) {
    var app = getApp();
    let result;
    if (bluetoothRet) {
      if (bluetoothRet.type === BicycleControlTypes.ControlActionGetToken) {
        // 获取秘钥成功 上电  ==》 上电 会同时 自动撤防
        app.globalData.bluetoothConcatState.wiriteToDevice(
          BicycleControlTypes.ControlActionGOnPower
        );
      }
      if (bluetoothRet.type === BicycleControlTypes.ControlActionGOnPower) {
        // 上电成功 && 跳骑行页面
        app.globalData.bluetoothConcatState.closeBLEConnection();
        app.globalData.bluetoothConcatState = null;
        result = bluetoothRet;
      }
    } else {
      this.bluetoothConnect(BicycleControlTypes.ControlActionGOnPower);
    }
    return result;
  }
  /**
   * 蓝牙锁车、临时锁车 - 成功才会返回result
   * bluetoothCloceLock bluetoothRet-监听eventBus的返回值
   */
  public bluetoothCloseLock(bluetoothRet?: any) {
    let result;
    var app = getApp();
    if (bluetoothRet) {
      // 设防成功  ==》设防 会同时 自动下电  - 关闭蓝牙连接,结算 
      if (bluetoothRet.type === BicycleControlTypes.ControlActionFortify) {
        console.log('蓝牙清除currentCarUserId===============================')
        app.globalData.bluetoothConcatState.closeBLEConnection();
        result = bluetoothRet;
      }

      if (bluetoothRet.type === BicycleControlTypes.ControlActionGetToken) {
        // 获取秘钥成功 设防
        app.globalData.bluetoothConcatState.wiriteToDevice(
          BicycleControlTypes.ControlActionFortify
        );
      }
    } else {
      this.bluetoothConnect(BicycleControlTypes.ControlActionFortify);
    }

    return result;
  }
  /**
   * 蓝牙连接
   * bluetoothConnect type表示如果已经连接蓝牙,需要进行的蓝牙操作
   */
  private bluetoothConnect(type?) {
    var app = getApp();

    // 如果有全局蓝牙对象 存在,即连接过蓝牙且未清缓存 直接操作
    if (type && app.globalData.bluetoothConcatState) {
      app.globalData.bluetoothConcatState.wiriteToDevice(type);
    } else {
      // 重新连接蓝牙
      // 测试号 KM06 - 14161803008
      // 测试号 KM06 - 14161803086
      // 测试号 G55 - 067221200108
      this.queryDeviceInfoItem(app.globalData.deviceNumber).then((res: any) => {
        // app.globalData.bluetoothConcatState = new BluetoothControl('067221200108');
        if (!res || res.statusCode) {
          this.bluetoothOperateFail()
          return;
        }
        app.globalData.bluetoothConcatState = new BluetoothControl(
          app.globalData.deviceNumber,
          res
        );
        app.globalData.bluetoothConcatState.initBluetoothAdapert();

      })
      console.log("this.app.globalData", app);
    }
  }

使用:

    // 开锁 
    confirmOpenLock: function () {
       utilCommon.bluetoothOpenLock()
       app.globalData.bluetoothState = BluetoothState.openLock;
    }

    // 获取监听蓝牙的状态
    receiveBlueTooth(e) {
      console.log('获取监听蓝牙的状态', e);
      if (app.globalData.bluetoothState !== BluetoothState.openLock) {
        return
      }
      if (e.type === 'fail') {
        // 蓝牙发送失败,取消订单更改车辆状态
        this.bluetoothFail()
      } else {
        const result = utilCommon.bluetoothOpenLock(e)
        console.log(result)
        if (result) {
          this.setData({
            isOpening: false
          })
          // eventBus.emit('onPower', true)
          // 蓝牙操作成功-直接跳骑行中页面
          wx.navigateTo({
            url: '/ride-management/pages/riding/riding'
          })
        }
        wx.hideLoading()
      }
    },

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值