【ESP32】【微信小程序】MQTT物联网智能家居案例

案例成果

在这里插入图片描述

1.Ardino写入部分

#include <WiFi.h>          // ESP32 WiFi库
#include <PubSubClient.h>  // MQTT客户端库
#include <DHT.h>           // DHT传感器库

// WiFi配置
const char *ssid = "601B";       // WiFi名称
const char *password = "12345678"; // WiFi密码

// MQTT服务器配置
const char* mqtt_server = "bemfa.com";    // MQTT服务器地址
const int mqtt_server_port = 9501;        // MQTT服务器端口
#define ID_MQTT "0c876e1774cc3bd27de1d5d1bfc61c90" // 您的客户端ID

// 创建WiFi和MQTT客户端实例
WiFiClient espClient;
PubSubClient client(espClient);

// 定义引脚 - 注意:ESP32使用GPIO编号,而不是NodeMCU的D编号
#define ledpin 2       // LED指示灯连接的引脚,用于远程控制开关 (GPIO2)
#define eqpin 3        // 地震传感器连接的引脚,用于检测震动 (GPIO3)
#define beeppin 18      // 蜂鸣器连接的引脚,用于警报提示 
#define flapin 5       // 火灾传感器连接的引脚,用于检测火情 (GPIO5)
#define dhtpin 15      // DHT11温湿度传感器连接的引脚 (GPIO15)
#define DHTTYPE DHT11  // 定义使用的温湿度传感器类型为DHT11
#define airpin 34      // 空气质量传感器连接的模拟引脚,用于检测空气污染程度 (GPIO34 - ADC6)

// 创建DHT传感器对象
DHT dht(dhtpin, DHTTYPE);

// 定义状态变量
bool val1 = 0;  // 地震传感器状态
bool val2 = 0;  // 火灾传感器状态

// MQTT主题 - 与微信小程序匹配的命名
const char* mqtt_switch_topic = "switch";     // LED开关主题(接收控制命令)
const char* mqtt_temper_topic = "temper";     // 温度主题(发布温度数据)
const char* mqtt_humid_topic = "humid";       // 湿度主题(发布湿度数据)
const char* mqtt_air_topic = "air";           // 空气质量主题(发布空气质量数据)
const char* mqtt_earthquake_topic = "earthquake"; // 地震主题(发布地震状态)
const char* mqtt_flame_topic = "flame";       // 火灾主题(发布火灾状态)
const char* mqtt_beep_topic = "beep";         // 蜂鸣器主题(可选)

// WiFi连接函数
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

// MQTT消息接收回调函数
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("订阅的信息为 [");
  Serial.print(topic);
  Serial.print("] ");
  
  // 将接收到的字节数组转换为字符串
  String message;
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  
  Serial.println(message);
  
  // 控制LED
  if (strcmp(topic, mqtt_switch_topic) == 0) {
    if (message == "on") {
      digitalWrite(ledpin, HIGH);
      Serial.println("打开 LED 灯");
    } else if (message == "off") {
      digitalWrite(ledpin, LOW);
      Serial.println("关闭 LED 灯");
    }
  }
}

// 重连函数
void reconnect() {
  // 循环直到重新连接
  while (!client.connected()) {
    Serial.print("尝试连接MQTT...");
    
    // 尝试连接
    if (client.connect(ID_MQTT)) {
      Serial.println("connected");
      // 连接成功后,订阅LED控制主题
      client.subscribe(mqtt_switch_topic);
      Serial.print("已订阅主题: ");
      Serial.println(mqtt_switch_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

// 初始化
void setup() {
  // 初始化串口
  Serial.begin(115200);
  Serial.println("初始化系统...");
  
  // 初始化DHT传感器
  dht.begin();
  
  // 设置引脚模式
  pinMode(ledpin, OUTPUT);
  digitalWrite(ledpin, LOW);
  
  // 设置传感器引脚
  pinMode(eqpin, INPUT);
  pinMode(flapin, INPUT);
  pinMode(beeppin, OUTPUT);
  pinMode(airpin, INPUT);  // 模拟输入
  
  // 连接WiFi
  setup_wifi();
  
  // 设置MQTT服务器和回调
  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
  
  // 连接MQTT服务器
  reconnect();
  
  Serial.println("系统初始化完成!");
}

void loop() {
  // 检查MQTT连接状态
  if (!client.connected()) {
    reconnect(); // 重新连接
  }
  
  // 处理MQTT消息
  client.loop();
  
  // 读取温湿度
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  
  // 检查温湿度读取是否成功
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
  } else {
    // 输出温湿度
    Serial.print("湿度: ");
    Serial.print(h);
    Serial.print("%, 温度: ");
    Serial.print(t);
    Serial.println("°C");
    
    // 转换为字符串用于发布
    String tempMsg = String(t);
    String humidMsg = String(h);
    
    // 发布温湿度数据到MQTT
    client.publish(mqtt_temper_topic, tempMsg.c_str());
    client.publish(mqtt_humid_topic, humidMsg.c_str());
  }
  
  // 读取空气质量
  int airval = analogRead(airpin);
  Serial.print("空气质量: ");
  Serial.println(airval);
  String airMsg = String(airval);
  client.publish(mqtt_air_topic, airMsg.c_str());
  
  // 读取地震传感器状态
  val1 = digitalRead(eqpin);
  if (val1 == 0) {
    // 发布地震警报
    client.publish(mqtt_earthquake_topic, "off");
    Serial.println("无震感");
    client.publish(mqtt_beep_topic, "off"); // 前端无需显示蜂鸣器的状态
  }
  else {
    // 发布地震警报
    client.publish(mqtt_earthquake_topic, "on");
    Serial.println("有震感");
    client.publish(mqtt_beep_topic, "on"); // 前端无需显示蜂鸣器的状态
  }
  
  // 读取火灾传感器状态
  val2 = digitalRead(flapin);
  Serial.print("火灾传感器状态: ");
  Serial.println(val2);
  if (val2 == 1) {
    // 发布火灾警报
    client.publish(mqtt_flame_topic, "off");
    Serial.println("无火灾");
    digitalWrite(beeppin, HIGH);
  }
  else {
    // 发布火灾警报
    client.publish(mqtt_flame_topic, "on");
    Serial.println("有火灾");
    digitalWrite(beeppin, LOW);
  }
  
  // 延时100毫秒
  delay(100);
}

2.微信小程序JS部分

// pages/class/class.js
const app = getApp()
import mqtt from '../../utils/mqtt.min'

Page({
  data: {
    // 主题定义
    ledtopic: "switch",          // LED开关主题
    eqtopic: "earthquake",       // 地震传感器主题
    fhtopic: "flame",            // 火灾传感器主题
    wdtopic: "temper",           // 温度传感器主题
    sdtopic: "humid",            // 湿度传感器主题
    kqtopic: "air",              // 空气质量传感器主题
    beeptopic: "beep",           // 新增:蜂鸣器主题

    uid: "0c876e1774cc3bd27de1d5d1bfc61c90",  // 设备唯一ID
    
    // 传感器状态
    qustatus: "无震感",          // 地震状态
    flastatus: "无火灾",         // 火灾状态
    wdval: "未知",               // 温度值
    sdval: "未知",               // 湿度值
    airval: "未知",              // 空气质量值
    beepstatus: "关闭",          // 新增:蜂鸣器状态

    isThemeOn: false,            // 开关状态,默认关闭
    device_status: "离线",       // 设备连接状态
    client: null                 // MQTT客户端
  },

  // MQTT连接方法
  mqttConnect() {
    var that = this;
    var options = {
      keepalive: 60,             // 心跳间隔
      clean: true,               // 清除会话
      protocolVersion: 4,        // MQTT协议版本
      clientId: that.data.uid    // 客户端ID
    };

    // 连接到MQTT服务器
    that.data.client = mqtt.connect('wxs://bemfa.com:9504/wss', options);
    
    // 连接成功回调
    that.data.client.on('connect', function() {
      console.log("连接服务器成功");
      that.setData({
        device_status: "在线"
      });
      
      // 订阅所有传感器主题
      // 订阅地震传感器主题
      that.data.client.subscribe(that.data.eqtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅火灾传感器主题
      that.data.client.subscribe(that.data.fhtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅温度传感器主题
      that.data.client.subscribe(that.data.wdtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅湿度传感器主题
      that.data.client.subscribe(that.data.sdtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅空气质量传感器主题
      that.data.client.subscribe(that.data.kqtopic, function(err) {
        if(err) console.log(err);
      });
      // 新增:订阅蜂鸣器主题
      that.data.client.subscribe(that.data.beeptopic, function(err) {
        if(err) console.log(err);
      });
    });

    // 接收消息回调
    that.data.client.on('message', function(topic, message) {
      var msg = message.toString();
      
      // 处理不同主题的消息
      // 地震传感器消息
      if(topic === that.data.eqtopic) {
        that.setData({
          qustatus: msg === 'on' ? '有地震' : '无地震'
        });
      }
      
      // 火灾传感器消息
      else if(topic === that.data.fhtopic) {
        that.setData({
          flastatus: msg === 'on' ? '有火灾' : '无火灾'
        });
      }
      
      // 温度传感器消息
      else if(topic === that.data.wdtopic) {
        that.setData({
          wdval: msg
        });
      }
      
      // 湿度传感器消息
      else if(topic === that.data.sdtopic) {
        that.setData({
          sdval: msg
        });
      }
      
      // 空气质量传感器消息
      else if(topic === that.data.kqtopic) {
        that.setData({
          airval: msg
        });
      }

      // 新增:蜂鸣器消息
      else if(topic === that.data.beeptopic) {
        that.setData({
          beepstatus: msg === 'on' ? '开启' : '关闭'
        });
      }

    });

    // 重连回调
    that.data.client.on('reconnect', function() {
      console.log("重新连接");
      that.setData({
        device_status: "连接中"
      });
    });

    // 连接错误回调
    that.data.client.on('error', function(error) {
      console.log("连接失败", error);
      that.setData({
        device_status: "离线"
      });
    });
  },

  // 页面加载时连接MQTT服务器
  onLoad() {
    this.mqttConnect()
  },

  // 开关点击事件处理
  onThemeSwitchTap: function() {
    if(this.data.client && this.data.client.connected) {
      // 切换开关状态
      const message = this.data.isThemeOn ? 'off' : 'on';
      
      // 发布消息到LED开关主题
      this.data.client.publish(this.data.ledtopic, message);
      
      // 更新UI状态
      this.setData({
        isThemeOn: !this.data.isThemeOn
      });
    } else {
      console.log("MQTT未连接");
    }
  }
})

3.微信小程序xml部分

<!--pages/znjj/znjj.wxml-->
<view class="imag4_src"></view>
<image class="imag4" src="/img/znjj.png"></image>
<view class="spacer"></view>

<view class="container1">
  <view class="view1">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/wd.png"></image>
        <text>温度</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定温度数据 -->
        <text class="loading-text">{{wdval}}</text>
      </view>
    </view>
  </view>
  
  <view class="view2">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/sd.png"></image>
        <text>湿度</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定湿度数据 -->
        <text class="loading-text">{{sdval}}</text>
      </view>
    </view>
  </view>
  
  <view class="view3">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/PM2.5.png"></image>
        <text>空气</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定空气质量数据 -->
        <text class="loading-text">{{airval}}</text>
      </view>
    </view>
  </view>
</view>

<view class="spacer"></view>

<view class="container2">
  <view class="view4">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/hy.png"></image>
        <text>防火</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定火灾状态 -->
        <text class="loading-text">{{flastatus}}</text>
      </view>
    </view>
  </view>
  
  <view class="view5">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/dz.png"></image>
        <text>地震</text>
      </view>
      <view class="loading-container">
        <text class="loading-text">{{qustatus}}</text>
      </view>
    </view>
  </view>
  
  <view class="view6">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/kt.png"></image>
        <text>空调</text>
      </view>
      <view class="switch-container">
        <button class="theme-switch-button" bindtap="onThemeSwitchTap">
          {{isThemeOn ? 'on' : 'off'}}
        </button>
      </view>
    </view>
  </view>
</view>

<view class="spacer"></view>

<view class="container3">
  <view class="view7">
    <view class="img_wd">
      <view class="content-text">
        <text>设备状态</text>
        <text class="module">{{device_status}}</text>
      </view>
    </view>
  </view>
  
  <view class="view8">
    <view class="img_wd">
      <view class="content-text">
        <text>火灾告警</text>
        <view wx:if="{{flastatus == '有火灾'}}">
          <image class="img5" src="/img/hz_on.png"></image>
        </view>
        <view wx:else>
          <image class="img5" src="/img/hz_off.png"></image>
        </view>
      </view>
    </view>
  </view>
  
  <view class="view9">
    <view class="img_wd">
      <view class="content-text">
        <text>地震告警</text>
        <!-- 修改:使用qustatus而不是eqstatus -->
        <view wx:if="{{qustatus == '有地震'}}">
          <image class="img5" src="/img/dz_on.png"></image>
        </view>
        <view wx:else>
          <image class="img5" src="/img/dz_off.png"></image>
        </view>
      </view>
    </view>
  </view> 
</view>


4. 微信小程序CSS部分

/* 顶部标题图片容器样式 */
.imag4_src{
    display: block;  /* 设置为块级元素,占据整行 */
    width: 100%;     /* 宽度占满父容器 */
  }
  
  /* 顶部标题图片样式 */
  .imag4{
    width: 350px;    /* 设置固定宽度 */
    height: 200px;   /* 设置固定高度 */
    justify-content: center;  /* 水平居中对齐 */
    border: 1px solid #000;   /* 添加1像素黑色边框 */
    border-radius: 10px;      /* 设置10像素圆角 */
    margin: 20px;             /* 四周添加20像素外边距 */
    box-shadow: 5px 5px 15px rgba(0,0,0,0.3);  /* 添加阴影效果:右下偏移,模糊度,颜色 */
    transition: transform 0.3s ease;  /* 添加变换过渡效果:持续0.3秒,缓动函数ease */
  }
  
  /* 标题图片悬停效果 */
  .imag4:hover{
    transform: scale(1.05);  /* 悬停时放大图片到原尺寸的1.05倍 */
  }
  
  /* 垂直间隔元素 */
  .spacer{
    height: 10px;  /* 创建10像素高度的垂直间隔 */
  }
  
  /* 第一行和第二行容器共同样式 */
  .container1,
  .container2{
    display: flex;           /* 设置为Flex布局容器 */
    flex-direction: row;     /* 子元素水平排列(默认值) */
    justify-content: center; /* 子元素在主轴(水平)上居中对齐 */
  }
  
  /* 第一行和第二行中所有方块的共同样式 */
  .container1 .view1,
  .container1 .view2,
  .container1 .view3,
  .container2 .view4,
  .container2 .view5,
  .container2 .view6{
    width: 90px;             /* 设置宽度为90像素 */
    height: 100px;           /* 设置高度为100像素 */
    margin: 20px;            /* 四周添加20像素外边距 */
    position: relative;      /* 设置相对定位,作为内部元素的定位参考 */
    background-color: transparent;  /* 背景透明(但随后被单独的规则覆盖) */
    display: flex;           /* 设置为Flex布局容器 */
    align-items: lsft;       /* 注意:这里有拼写错误,应为'left',垂直方向左对齐 */
    justify-content: center; /* 水平居中对齐 */
    border: 2px solid rgb(291,214,214);  /* 注意:RGB值错误,291超出范围(0-255) */
    box-shadow: 0 0 10px rgba(37,37,37,0.5);  /* 添加阴影效果,模拟立体边框 */
  }
  
  /* 第一行各模块的背景颜色 */
  .container1 .view1 { background-color: #e3ece2; }  /* 温度模块:淡绿色 */
  .container1 .view2 { background-color: #ccd4cb; }  /* 湿度模块:灰绿色 */
  .container1 .view3 { background-color: #e5f3ee; }  /* 空气模块:浅蓝绿色 */
  
  /* 第二行各模块的背景颜色 */
  .container2 .view4 { background-color: #f7e7e9; }  /* 防火模块:淡粉色 */
  .container2 .view5 { background-color: #d7eef7; }  /* 地震模块:淡蓝色 */
  .container2 .view6 { background-color: #e3e4f1; }  /* 空调模块:淡紫色 */
  
  /* 模块内容容器样式 */
  .img_wd{
    justify-content: flex-start;  /* 内容在水平方向靠左对齐 */
    align-items: flex-start;      /* 内容在垂直方向靠上对齐 */
    width: 100px;                 /* 设置宽度为100像素 */
    height: 100px;                /* 设置高度为100像素 */
    position: relative;           /* 设置相对定位,供内部元素参考 */
  }
  
  /* 图标和文字行样式 */
  .content-row{
    margin-top: 1px;       /* 顶部添加1像素外边距 */
    display: flex;         /* 设置为Flex布局容器 */
    align-items: center;   /* 子元素在垂直方向居中对齐 */
    margin-left: 3px;      /* 左侧添加3像素外边距 */
  }
  
  /* 图标样式 */
  .img1{
    width: 30px;           /* 设置图标宽度为30像素 */
    height: 30px;          /* 设置图标高度为30像素 */
    border: 1px solid rgb(211,209,209);  /* 添加浅灰色边框 */
    border-radius: 10px;                 /* 设置10像素圆角 */
    margin: 3px;                         /* 四周添加3像素外边距 */
    box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3);  /* 添加阴影效果 */
    transition: transform 0.3s ease;               /* 添加变换过渡效果 */
    margin-right: 5px;                           /* 右侧添加5像素外边距,与文字分开 */
  }
  
  /* 数据加载容器样式 */
  .loading-container{
    margin-top: 20px;     /* 顶部添加20像素外边距 */
    display: flex;        /* 设置为Flex布局容器 */
    justify-content: center;  /* 水平居中对齐 */
    align-items: center;      /* 垂直居中对齐 */
  }
  
  /* 加载文本样式 */
  .loading-text{
    justify-content: center;  /* 水平居中对齐(在flex子项中) */
    align-items: center;      /* 垂直居中对齐(在flex子项中) */
    font-size: 16px;          /* 设置字体大小为16像素 */
    color: #333;              /* 设置字体颜色为深灰色 */
    height: 20px;             /* 设置高度为20像素 */
  }
  
  /* 第三行容器样式 */
  .container3{
    display: flex;           /* 设置为Flex布局容器 */
    flex-direction: row;     /* 子元素水平排列 */
    justify-content: center; /* 水平居中对齐 */
    /* 注释提到暂时移除其他样式以进行故障排除 */
  }
  
  /* 第三行各模块共同样式 */
  .container3 .view7,
  .container3 .view8,
  .container3 .view9{
    width: 90px;            /* 设置宽度为90像素 */
    height: 100px;          /* 设置高度为100像素 */
    margin: 20px;           /* 四周添加20像素外边距 */
    position: relative;     /* 设置相对定位 */
    background-color: transparent;  /* 背景透明(但随后被单独的规则覆盖) */
    display: flex;          /* 设置为Flex布局容器 */
    align-items: left;      /* 垂直方向左对齐(注意:这应为vertical-align或align-items:flex-start) */
    justify-content: center; /* 水平居中对齐 */
    border: 2px solid rgb(219, 214, 214);  /* 添加浅灰色边框 */
    box-shadow: 0 0 10px rgba(37, 37, 37, 0.5);  /* 添加阴影效果 */
    border-radius: 60px;    /* 设置60像素圆角,几乎成为圆形 */
  }
  
  /* 第三行各模块的背景颜色 */
  .container3 .view7 { background-color: #f1ecec; }  /* 设备状态模块:淡红灰色 */
  .container3 .view8 { background-color: #f3f8f6; }  /* 火灾告警模块:淡青色 */
  .container3 .view9 { background-color: #ece6f5; }  /* 地震告警模块:淡紫色 */
  
  /* 开关按钮容器样式 */
  .switch-container {
    width: 60px;           /* 设置宽度为60像素 */
    height: 30px;          /* 设置高度为30像素 */
    display: flex;         /* 设置为Flex布局容器 */
    justify-content: center;  /* 水平居中对齐 */
    align-items: center;      /* 垂直居中对齐 */
    margin-top: 20px;         /* 顶部添加20像素外边距 */
    margin-left: auto;        /* 左侧自动外边距,配合右侧自动外边距实现水平居中 */
    margin-right: auto;       /* 右侧自动外边距,配合左侧自动外边距实现水平居中 */
  }
  
  /* 开关按钮样式 */
  .theme-switch-button {
    height: 30px;          /* 设置高度为30像素 */
    line-height: 30px;     /* 设置行高等于高度,使文字垂直居中 */
    background-color: rgb(146, 198, 247);  /* 设置淡蓝色背景 */
    color: rgb(13, 13, 14);               /* 设置几乎黑色的文字颜色 */
    border: none;                         /* 移除默认边框 */
    border-radius: 20px;                  /* 设置20像素圆角,使按钮呈胶囊形 */
    text-align: center;                   /* 文字水平居中 */
    font-size: 13px;                      /* 设置字体大小为13像素 */
    border: 1px solid rgb(241, 234, 234); /* 添加浅灰色边框 */
    box-shadow: 0 0 10px rgba(2, 8, 27, 0.5);  /* 添加阴影效果 */
    padding: 0;                           /* 移除内边距,确保文字居中显示 */
  }
  
  /* 文本内容容器样式 */
  .content-text {
    display: flex;                /* 设置为Flex布局容器 */
    flex-direction: column;       /* 子元素垂直排列 */
    align-items: center;          /* 水平居中对齐 */
    justify-content: flex-start;  /* 垂直方向从顶部开始对齐 */
    margin-top: 15px;             /* 顶部添加15像素外边距 */
    width: 100%;                  /* 宽度占满父容器 */
    box-sizing: border-box;       /* 边框和内边距包含在宽度内 */
  }
  
  /* 模块状态文本样式 */
  .module {
    margin-top: 10px;     /* 顶部添加10像素外边距 */
    color: #f74d4d;       /* 设置文字颜色为鲜红色 */
    font-weight: bold;    /* 设置字体为粗体 */
  }
  
  /* 告警图标样式 */
  .img5{
    margin-top: 5px;      /* 顶部添加5像素外边距 */
    width: 50px;          /* 设置宽度为50像素 */
    height: 40px;         /* 设置高度为40像素 */
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hmywillstronger

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值