phonegap SQLite 插件

插件下载地址: https://github.com/ApplicationCraft/PGSQLitePlugin


package com.sai.plugin;

import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Context;

import org.apache.cordova.api.Plugin;
import org.apache.cordova.api.PluginResult;

import android.os.Environment;
import android.os.StatFs;
import android.util.Log;
import android.content.ContentValues;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class PGSQLitePlugin extends Plugin {

/** List Action */
private static final String ACTION_EXECUTE="backgroundExecuteSql";
private static final String ACTION_OPEN="open";
private static final String ACTION_CLOSE="close";
private static final String ACTION_INSERT="insert";
private static final String ACTION_DELETE="delete";
private static final String ACTION_UPDATE="update";
private static final String ACTION_QUERY="query";
private static final String ACTION_REMOVE="remove";
private static final String ACTION_BATCHEXECUTE="backgroundExecuteSqlBatch";
private static final String ACTION_TRANSACTION="transactionExecuteSqlBatch";

private static final String USE_INTERNAL="internal";
private static final String USE_EXTERNAL="external";

private Hashtable<String,SQLiteDatabase> openDbs = new Hashtable<String,SQLiteDatabase>();

@Override
public PluginResult execute(String action, JSONArray data, String callbackId) {

Log.e("PGSQLitePlugin", "Plugin Called");
PluginResult result = null;
if (action.equals(PGSQLitePlugin.ACTION_EXECUTE)) {
result = rawQuery(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_TRANSACTION)) {
result = batchRawQuery(data, true);
}
else if (action.equals(PGSQLitePlugin.ACTION_INSERT)) {
result = insertQuery(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_DELETE)) {
result = deleteQuery(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_UPDATE)) {
result = updateQuery(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_QUERY)) {
result = query(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_OPEN)) {
result = openDatabese(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_CLOSE)) {
result = closeDatabese(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_REMOVE)) {
result = remove(data);
}
else if (action.equals(PGSQLitePlugin.ACTION_BATCHEXECUTE)) {
result = batchRawQuery(data);
}
else {
result = new PluginResult(PluginResult.Status.NO_RESULT);
Log.e("PGSQLitePlugin", "Invalid action : "+action+" passed");
}

return result;
}

private SQLiteDatabase getDb(String path){
SQLiteDatabase db = (SQLiteDatabase)openDbs.get(path);
return db;
}

private String getStringAt(JSONArray data, int position, String dret){
String ret = getStringAt(data, position);
return (ret == null) ? dret : ret;
}

private String getStringAt(JSONArray data, int position){
String ret = null;
try{
ret = data.getString(position);
//JSONArray convert JavaScript undefined|null to string "null", fix it
ret = ( ret.equals("null") ) ? null : ret;
}
catch(Exception er){};
return ret;
}

private JSONArray getJSONArrayAt(JSONArray data, int position){
JSONArray ret = null;
try{
ret = (JSONArray)data.get(position);
}
catch(Exception er){};
return ret;
}

private JSONObject getJSONObjectAt(JSONArray data, int position){
JSONObject ret = null;
try{
ret = (JSONObject)data.get(position);
}
catch(Exception er){};
return ret;
}

private PluginResult query(JSONArray data){
PluginResult result = null;
try {
Log.e("PGSQLitePlugin", "query");
String dbName = data.getString(0);
String tableName = data.getString(1);
JSONArray columns = getJSONArrayAt(data, 2);
String where = getStringAt(data, 3);
JSONArray whereArgs = getJSONArrayAt(data, 4);
String groupBy = getStringAt(data, 5);
String having = getStringAt(data, 6);
String orderBy = getStringAt(data, 7);
String limit = getStringAt(data, 8);

String[] _whereArgs = null;
if (whereArgs != null){
int vLen = whereArgs.length();
_whereArgs = new String[vLen];
for (int i = 0; i < vLen; i++){
_whereArgs[i] = whereArgs.getString(i);
}
}

String[] _columns = null;
if (columns != null){
int vLen = columns.length();
_columns = new String[vLen];
for (int i = 0; i < vLen; i++){
_columns[i] = columns.getString(i);
}
}

SQLiteDatabase db = getDb(dbName);
// if (db == null){
// db=getDb("www/db/" + dbName);
// }
Cursor cs = db.query(tableName, _columns, where, _whereArgs, groupBy, having, orderBy, limit);
if (cs != null){
JSONObject res = new JSONObject();
JSONArray rows = new JSONArray();

if (cs.moveToFirst()) {
String[] names = cs.getColumnNames();
int namesCoint = names.length;
do {
JSONObject row = new JSONObject();
for (int i = 0; i < namesCoint; i++){
String name = names[i];
row.put(name, cs.getString(cs.getColumnIndex( name )));
}
rows.put( row );
} while (cs.moveToNext());
}
res.put("rows", rows);
cs.close();
Log.e("PGSQLitePlugin", "query::count="+rows.length());
result = new PluginResult(PluginResult.Status.OK, res);
}
else {
result = new PluginResult(PluginResult.Status.ERROR, "Error execute query");
}
} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult updateQuery(JSONArray data){
PluginResult result = null;
try {
Log.e("PGSQLitePlugin", "updateQuery");
String dbName = data.getString(0);
String tableName = data.getString(1);
JSONObject values = (JSONObject)data.get(2);
String where = getStringAt(data, 3, "1");
JSONArray whereArgs = getJSONArrayAt(data, 4);

String[] _whereArgs = null;
if (whereArgs != null){
int vLen = whereArgs.length();
_whereArgs = new String[vLen];
for (int i = 0; i < vLen; i++){
_whereArgs[i] = whereArgs.getString(i);
}
}

JSONArray names = values.names();
int vLenVal = names.length();
ContentValues _values = new ContentValues();
for (int i = 0; i < vLenVal; i++){
String name = names.getString(i);
_values.put( name, values.getString( name ) );
}

SQLiteDatabase db = getDb(dbName);
long count = db.update(tableName, _values, where, _whereArgs);
result = new PluginResult(PluginResult.Status.OK, count);
Log.e("PGSQLitePlugin", "updateQuery::count=" + count);


} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult deleteQuery(JSONArray data){
PluginResult result = null;
try {
Log.e("PGSQLitePlugin", "deleteQuery");
String dbName = data.getString(0);
String tableName = data.getString(1);
String where = getStringAt(data, 2);
JSONArray whereArgs = getJSONArrayAt(data, 3);
String[] _whereArgs = null;
if (whereArgs != null){
int vLen = whereArgs.length();
_whereArgs = new String[vLen];
for (int i = 0; i < vLen; i++){
_whereArgs[i] = whereArgs.getString(i);
}
}
SQLiteDatabase db = getDb(dbName);
long count = db.delete(tableName, where, _whereArgs);
result = new PluginResult(PluginResult.Status.OK, count);
Log.e("PGSQLitePlugin", "deleteQuery::count=" + count);

} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult insertQuery(JSONArray data){
PluginResult result = null;
try {
Log.e("PGSQLitePlugin", "insertQuery");
String dbName = data.getString(0);
String tableName = data.getString(1);
JSONObject values = (JSONObject)data.get(2);
JSONArray names = values.names();
int vLen = names.length();
SQLiteDatabase db = getDb(dbName);
ContentValues _values = new ContentValues();
for (int i = 0; i < vLen; i++){
String name = names.getString(i);
_values.put( name, values.getString( name ) );
}
long id = db.insert(tableName, null, _values);
if (id == -1){
result = new PluginResult(PluginResult.Status.ERROR, "Insert error");
}
else {
result = new PluginResult(PluginResult.Status.OK, id);
}
Log.e("PGSQLitePlugin", "insertQuery::id=" + id);


} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult batchRawQuery(JSONArray data){
return batchRawQuery(data, false);
}

private PluginResult batchRawQuery(JSONArray data, boolean transaction){
PluginResult result = null;
SQLiteDatabase db = null;
try {
Log.e("PGSQLitePlugin", "batchRawQuery");
String dbName = data.getString(0);
db = getDb(dbName);
JSONArray batch = (JSONArray)data.get(1);
int len = batch.length();
if (transaction){
db.beginTransaction();
}
for (int i = 0; i < len; i++){
JSONObject el = (JSONObject)batch.get(i);
String type = el.getString("type");
JSONArray args = (JSONArray)el.get("opts");
int len1 = args.length();
JSONArray rData = new JSONArray();
rData.put(dbName);
for (int j = 0; j < len1; j++){
rData.put(args.get(j) );
}

Log.e("PGSQLitePlugin", "batchRawQuery::type="+type);

if (type.equals("raw")){
result = rawQuery(rData);
}
else if (type.equals("insert") ){
result = insertQuery(rData);
}
else if (type.equals("del") ){
result = deleteQuery(rData);
}
else if (type.equals("query") ){
result = query(rData);
}
else if (type.equals("update" ) ){
result = updateQuery(rData);
}
if (result == null ){
result = new PluginResult(PluginResult.Status.ERROR, "Unknow action");
if (transaction){
db.endTransaction();
}
break;
}
else if (result.getStatus() != 1){
if (transaction){
db.endTransaction();
}
result = new PluginResult(PluginResult.Status.ERROR, result.getMessage());
break;
}
}
if (transaction){
db.setTransactionSuccessful();
db.endTransaction();
}
} catch (Exception e) {
if (db != null && db.inTransaction()){
db.endTransaction();
}
Log.e("PGSQLitePlugin", "error batch" + e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult rawQuery(JSONArray data){
PluginResult result = null;
try {
String dbName = data.getString(0);
String sql = data.getString(1);
SQLiteDatabase db = getDb(dbName);

Log.e("PGSQLitePlugin", "rawQuery action::sql="+sql);

Cursor cs = db.rawQuery(sql, new String [] {});
JSONObject res = new JSONObject();
JSONArray rows = new JSONArray();

if (cs != null && cs.moveToFirst()) {
String[] names = cs.getColumnNames();
int namesCoint = names.length;
do {
JSONObject row = new JSONObject();
for (int i = 0; i < namesCoint; i++){
String name = names[i];
row.put(name, cs.getString(cs.getColumnIndex( name )));
}
rows.put( row );
} while (cs.moveToNext());
cs.close();
}
res.put("rows", rows);
Log.e("PGSQLitePlugin", "rawQuery action::count="+rows.length());
result = new PluginResult(PluginResult.Status.OK, res);

} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult remove(JSONArray data){
PluginResult result = null;
JSONObject ret = new JSONObject();
try {

Log.i("PGSQLitePlugin", "remove action");
ret.put("status", 1);
String dbName = data.getString(0);
File dbFile=null;
SQLiteDatabase db = getDb(dbName);
if (db != null){
db.close();
openDbs.remove(dbName);
}
dbFile = new File( ((Context)this.ctx).getExternalFilesDir(null), dbName);
if (!dbFile.exists()){

dbFile = ((Context)this.ctx).getDatabasePath(dbName);
if (!dbFile.exists()){
ret.put("message", "Database not exist");
ret.put("status", 0);
result = new PluginResult(PluginResult.Status.ERROR, ret);
}
else {
if (dbFile.delete()){
Log.i("PGSQLitePlugin", "remove action::remove from internal");
result = new PluginResult(PluginResult.Status.OK);
}
else {
ret.put("message", "Can't remove db");
ret.put("status", 2);
result = new PluginResult(PluginResult.Status.ERROR, ret);
}
}
}
else {
if (dbFile.delete()){
result = new PluginResult(PluginResult.Status.OK);
Log.i("PGSQLitePlugin", "remove action::remove from sdcard");
}
else {
ret.put("message", "Can't remove db");
ret.put("status", 2);
result = new PluginResult(PluginResult.Status.ERROR, ret);
}
}
} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, ret);
}

return result;
}

private PluginResult openDatabese(JSONArray data){
PluginResult result = null;
try {
String storage = PGSQLitePlugin.USE_INTERNAL;
String dbName = data.getString(0);
JSONObject options = getJSONObjectAt(data, 1);
if (options != null){
storage = options.getString("storage");
}

if (storage.equals(PGSQLitePlugin.USE_EXTERNAL) && !Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
return new PluginResult(PluginResult.Status.ERROR, "SDCard not mounted");
}

Log.i("PGSQLitePlugin", "open action::storage"+storage);

String _dbName = null;
SQLiteDatabase db = getDb(dbName);
File dbFile=null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) && !storage.equals(PGSQLitePlugin.USE_INTERNAL) ) {
if (storage.equals(PGSQLitePlugin.USE_EXTERNAL)){
dbFile = new File(((Context)this.ctx).getExternalFilesDir(null), dbName);
}
else {
dbFile = ((Context)this.ctx).getDatabasePath(dbName);
if (!dbFile.exists()){
dbFile = new File(((Context)this.ctx).getExternalFilesDir(null), dbName);
if (!dbFile.exists()){
StatFs stat = new StatFs("/data/");
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getBlockCount();
long size = blockSize * availableBlocks;
if (size >= 1024*1024*1024){ //more then 1 Gb
dbFile = ((Context)this.ctx).getDatabasePath(dbName);
}
else {
dbFile = new File(((Context)this.ctx).getExternalFilesDir(null), dbName);
}
Log.i("blockSize * availableBlocks", Long.toString(size) );
}
}
}
}
else{
dbFile = ((Context)this.ctx).getDatabasePath(dbName);
}
_dbName = dbFile.getPath();

Log.i("PGSQLitePlugin", "open action::"+dbName);

int status = 0;

if (db == null){
if (!dbFile.exists()){
status = 1;
try{

InputStream assetsDB = this.ctx.getActivity().getAssets().open( "www/db/" + dbName );
OutputStream dbOut = new FileOutputStream( _dbName );

byte[] buffer = new byte[1024];
int length;
while ((length = assetsDB.read(buffer))>0){
dbOut.write(buffer, 0, length);
}

dbOut.flush();
dbOut.close();
assetsDB.close();
status = 2;
}
catch(Exception e){
Log.e("PGSQLitePlugin", "error get db from assets=" + e.getMessage());
}
}
db = SQLiteDatabase.openDatabase(_dbName, null, SQLiteDatabase.CREATE_IF_NECESSARY );
openDbs.put(dbName, db);
}

JSONObject ret = new JSONObject();
ret.put( "status", status );
ret.put( "version", db.getVersion() );
ret.put( "systemPath", _dbName );

result = new PluginResult(PluginResult.Status.OK, ret);
} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

private PluginResult closeDatabese(JSONArray data){
PluginResult result = null;
try {
Log.e("PGSQLitePlugin", "close action");
String dbName = data.getString(0);
SQLiteDatabase db = getDb(dbName);
if (db != null){
db.close();
openDbs.remove(dbName);
}
result = new PluginResult(PluginResult.Status.OK);
} catch (Exception e) {
Log.e("PGSQLitePlugin", e.getMessage());
result = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
}

return result;
}

}

在 plugins.xml 加上

<plugin name="PGSQLitePlugin" value="com.sai.plugin.PGSQLitePlugin"/>



(function(gap) {

var isAndroid = (/android/gi).test(navigator.appVersion);
if (!isAndroid){
return;
}

var root = this;

root.PGSQLitePlugin = (function() {

PGSQLitePlugin.prototype.openDBs = {};
function PGSQLitePlugin(dbPath, success, error, options) {
this.dbPath = dbPath;
if (!dbPath) {
throw new Error("Cannot create a PGSQLitePlugin instance without a dbPath");
}
this.open(success, error, options);
}

PGSQLitePlugin.prototype.open = function(success, error, options) {
var self = this;
if (!(this.dbPath in this.openDBs)) {
gap.exec(function(result){
self.openDBs[self.dbPath] = { self : self, result : result};
if (typeof success == "function"){
success(result, self);
}
}, error, 'PGSQLitePlugin', 'open', [this.dbPath, options])
}
else {
if (typeof success == "function"){
success(self.openDBs[self.dbPath].result, self.openDBs[self.dbPath].self);
}
}
};

PGSQLitePlugin.prototype.close = function(success, error) {
if (this.dbPath in this.openDBs) {
delete this.openDBs[this.dbPath];
return gap.exec(success, error, 'PGSQLitePlugin', 'close', [this.dbPath]);
}
};

PGSQLitePlugin.prototype.remove = function(dbName, success, error) {
PGSQLitePlugin.remove(dbName, success, error);
};

PGSQLitePlugin.prototype.executeSql = function(sql, success, error) {
return gap.exec(success, error, 'PGSQLitePlugin', 'backgroundExecuteSql', [this.dbPath, sql]);
};

PGSQLitePlugin.prototype.insert = function(table, values, success, error) {
return gap.exec(success, error, 'PGSQLitePlugin', 'insert', [this.dbPath, table, values]);
};

PGSQLitePlugin.prototype.del = function(table, where, whereArgs, success, error) {
return gap.exec(success, error, 'PGSQLitePlugin', 'delete', [this.dbPath, table, where, whereArgs]);
};

PGSQLitePlugin.prototype.update = function(table, values, where, whereArgs, success, error) {
return gap.exec(success, error, 'PGSQLitePlugin', 'update', [this.dbPath, table, values, where, whereArgs]);
};

PGSQLitePlugin.prototype.query = function(table, columns, where, whereArgs, groupBy, having, orderBy, limit, success, error) {
return gap.exec(success, error, 'PGSQLitePlugin', 'query', [this.dbPath, table, columns, where, whereArgs, groupBy, having, orderBy, limit]);
};

PGSQLitePlugin.prototype.transaction = function(fn, success, error) {
var t = new root.PGSQLitePluginTransaction(this.dbPath, this);
try{
fn(t);
return t.complete(success, error);
}
catch(er){
if (error) error(er);
}
};

PGSQLitePlugin.remove = function(dbName, success, error) {
delete PGSQLitePlugin.prototype.openDBs[dbName];
return gap.exec(success, error, 'PGSQLitePlugin', 'remove', [dbName]);
};

return PGSQLitePlugin;
})();

root.PGSQLitePluginTransaction = (function() {
function PGSQLitePluginTransaction(dbPath, db) {
this.dbPath = dbPath;
this.executes = [];
this.db = db;
}
PGSQLitePluginTransaction.prototype.executeSql = function(sql) {
this.executes.push( { opts : [sql], type : "raw" } );
};
PGSQLitePluginTransaction.prototype.insert = function(table, values) {
this.executes.push({opts : [table, values] , type : "insert"});
};
PGSQLitePluginTransaction.prototype.del = function(table, where, whereArgs) {
this.executes.push({opts : [table, where, whereArgs], type : "del"});
};
PGSQLitePluginTransaction.prototype.query = function(table, columns, where, whereArgs, groupBy, having, orderBy, limit) {
this.executes.push({opts : [table, columns, where, whereArgs, groupBy, having, orderBy, limit], type : "query"});
};
PGSQLitePluginTransaction.prototype.update = function(table, values, where, whereArgs) {
this.executes.push({opts : [table, values, where, whereArgs], type : "update"});
};

PGSQLitePluginTransaction.prototype.complete = function(success, error) {
gap.exec(success, error, 'PGSQLitePlugin', 'transactionExecuteSqlBatch', [this.dbPath, this.executes]);
};
return PGSQLitePluginTransaction;
})();

}).call(this, window.Cordova || window.PhoneGap || window.cordova);

function PGSQLiteHelper(){
this.DATABASE_NAME = "addressBook.db";
this.DATABASE_VERSION = 1;
this.DATABASE_STORAGE = "auto";
this.db = null;
this.CREATE_BATCH = [];
this.UPDATE_BATCH = [];

this.openDatabase = function(success, error, options){
var __self = this;
options = (typeof options == "object") ? options : {};
options.storage = __self.DATABASE_STORAGE;
__self.db = new PGSQLitePlugin(__self.DATABASE_NAME, function(result){
var _version = __self.DATABASE_VERSION + "";
if (result.status == 1){
__self.onCreate(function(){
__self.db.executeSql("PRAGMA user_version='"+_version + "'", function(res){
if (typeof success == "function"){
success( __self.db, _version, result.systemPath);
}
}, error);
}, error);
}
else {
if (result.version != _version){
__self.onUpdate(result.version, function(){
__self.db.executeSql("PRAGMA user_version='"+_version + "'" , function(res){
if (typeof success == "function"){
success( __self.db, _version, result.systemPath);
}
}, error);
}, error);
}
else {
if (typeof success == "function"){
success( __self.db, _version, result.systemPath);
}
}
}
}, function(err){
if (typeof error == "function"){
error(err);
}
}, options );
return this.db;
}

this.onCreate = function(success, error) {
var ___self = this;
___self.db.transaction(function(tr){
for (var i in ___self.CREATE_BATCH){
tr.executeSql(___self.CREATE_BATCH[i]);
}
}, success, error);
}

this.onUpdate = function(version, success, error) {
var ___self = this;
version = parseInt(version, 10) - 1;
var currVersion = parseInt(this.DATABASE_VERSION, 10) - 1;
if (version < 1){
___self.onCreate(function(){
___self.db.executeSql("PRAGMA user_version='"+ (currVersion + 1 ) + "'", function(res){
if (typeof success == "function"){
success( ___self.db, (currVersion + 1 ) + "");
}
}, error);
}, error);
return;
}


___self.db.transaction(function(tr){
for (var j = version; j < currVersion; j++){
for (var i in ___self.UPDATE_BATCH[j]){
tr.executeSql(___self.UPDATE_BATCH[j][i]);
}
}
}, success, error);
}

this.getDB = function(){
return this.db;
}
}


Sencha Touch 调用


var list= Ext.create('Ext.List', {
fullscreen: true,
itemTpl: '{USER_NAME}{MOBILE}',
indexBar :true
});


var db = new PGSQLitePlugin("addressBook.db", function(dbResult, dbObject){

db = dbObject;
db.executeSql("select * from KM_USER where USER_NAME like '%张%'", function(data){
// alert(data.rows[0].MOBILE);
list.setData(data.rows);
}, function(err){
console.log( err);
});
}, function(err){
console.log( err);
});

忘了说了 我用的是phonegap 1.9
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值