微信 JS-SDK 多图上传,并上传到到七牛云服务器

1. 引入微信 JS-SDK js文件

<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

2. 绑定域名

(1)先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

    备注:登录后可在“开发者中心”查看对应的接口权限。

(2)先登录微信公众平台进入“公众号设置”的“基本设置”里填写“JS接口安全域名”。

3. 通过config接口注入权限验证配置

wx.config({

    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。

    appId: '', // 必填,公众号的唯一标识

    timestamp: , // 必填,生成签名的时间戳

    nonceStr: '', // 必填,生成签名的随机串

    signature: '',// 必填,签名,见附录1

    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2

});

注,1.  所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用。

        2. 上传图片有效期3天,可用微信多媒体接口下载图片到自己的服务器,此处获得的 serverId 即 media_id。

4. 通过config接口注入权限验证配置--- morePictureUpload.js

var staffid=GetQueryString('staffid');
var sessionid=GetQueryString('sessionid');
var flag=GetQueryString('flag');

//获取URL地址参数
function GetQueryString(name){
	var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
	var r = window.location.search.substr(1).match(reg);
	if(r!=null)return  unescape(r[2]); return null;
}

$(function(){
	
	getEchoPicture(staffid);
	$.ajax({
		type : "post",
		url : "/admin/weixinToken/getJsApiTicket",
		dataType : "json",
		async : false,
		success : function(data) {
			var jsApiTicket = data.ticket;
			var url = location.href.split('#').toString();//url不能写死

			$.ajax({
				type : "post",
				url : "/admin/weixinToken/makeWXTicket",
				dataType : "json",
				async : false,
				data:{
					jsApiTicket:jsApiTicket,
					url:url
				},
				success : function(data) {
					wx.config({
						debug: false,//生产环境需要关闭debug模式
						appId: data.appid,//appId通过微信服务号后台查看
						timestamp: data.timestamp,//生成签名的时间戳
						nonceStr: data.nonceStr,//生成签名的随机字符串
						signature: data.signature,//签名
						jsApiList: [//需要调用的JS接口列表
							'chooseImage',
							'previewImage',
							'uploadImage'
							]
					});
				},
				error: function(xhr, status, error) {
					//alert(status);
					//alert(xhr.responseText);
				}
			});
		},
		error: function(xhr, status, error) {

		}
	})
});

wx.ready(function(){
	//页面加载时就调用相关接口
});

var images = {
		localId : [],
		serverId : []
};
$('.chooseImage').on('click', function() {
	images.serverId = [];//清空serverid集合
	wx.chooseImage({
		count : 9, // 默认9   
		sizeType : [ 'compressed' ], // 压缩图
		sourceType : [ 'album', 'camera' ], // 可以指定来源是相册还是相机,默认二者都有   
		success : function(res) {
			$('.wxChooseImages ').remove();
			var localIds = res.localIds;
			if(localIds != ""){
				for(var i = 0;i<localIds .length;i++){
					var imgDivStr = '<div class="bankPage wxChooseImages multiselect"><img src="'+localIds[i]+'" class="pageImg" /></div>';
					$(".chooseImage").before(imgDivStr);
				}
			}

			images.localId = res.localIds;
			uploadImage(res.localIds);

		}
	});
});

var uploadImage = function(localIds) {
	
	var localId = localIds.pop();
	wx.uploadImage({
		localId : localId,
		isShowProgressTips : 1,
		success : function(res) {
			var serverId = res.serverId; // 返回图片的服务器端ID
			
			images.serverId.push(serverId);

			//其他对serverId做处理的代码
			if (localIds.length > 0) {
				uploadImage(localIds);

			}else if(localIds.length == 0 && images.serverId != ""){
				var serverId = images.serverId;
				var serverIdStr = "";
				for(var i = 0;i<serverId.length;i++){
					serverIdStr += serverId[i]+",";
				}
				
				uploadToQiniu(staffid,serverIdStr);

			}
		}
	});
};

//页面回显数据
function getEchoPicture(staffid){
	$.ajax({
		type : "post",
		url : "/admin/weixinToken/getEchoPictureList",
		dataType : "json",
		async : false,
		data:{
			staffId:staffid,
			type:$("#CredentialsEnum_OLDUS").val()
		},
		success : function(data) {
			if(data != ""){
				var imgDivStr = '';
				$.each($.parseJSON(data),function(i,item){  
				    var url = item.url;
				    imgDivStr += '<div class="householdPage wxChooseImages multiselect"><img src="'+url+'" class="pageImg" /></div>'; 
				}); 
				$(".chooseImage").before(imgDivStr);
			}
			
		},
		error: function(xhr, status, error) {

		}
	});
}

//从微信服务器保存到七牛云服务器 
function uploadToQiniu(staffid,serverIds){
	
	$.ajax({
		type : "post",
		url : "/admin/weixinToken/wechatJsSDKUploadToQiniu",
		dataType : "json",
		async : false,
		data:{
			staffId:staffid,
			mediaIds:serverIds,
			sessionid:sessionid,
			type:$("#CredentialsEnum_OLDUS").val()
		},
		success : function(data) {

		},
		error: function(xhr, status, error) {

		}
	});
}

//删除同类型的其他兄弟节点
function deleteBrotherEle(obj){
	obj.nextAll().remove();
}

//返回前一页
function returnPage(){
	window.location.href='/appmobileus/USFilming.html?staffid='+ staffid+'&sessionid='+sessionid+'&flag='+flag;
}


5.前端页面

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>过期美签上传</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
   		<meta name="format-detection" content="telephone=no">
   		<!--公共样式-->
		<link rel="stylesheet" href="css/common.css" />
		<!--本页css-->
		<link rel="stylesheet" href="css/filming.css" />
	</head>
	<body>
		<header>
			<div class="filming">
			    <a onclick="returnPage()"><i>  </i><span>过期美签上传</span></a>
			</div>

		</header>
		<section>
			<div class="household">
				<div class="householdPage householdExpain">
					<img alt="" src="img/icon-overdue.jpeg" width="100%" height="100%">
					<div class="signdialog"></div>
					<span class="digntitle">图例</span>
				</div>
				<!-- 过期美签 图片类型枚举 -->
				<input id="CredentialsEnum_OLDUS" type="hidden" value=11>
				<!--可多选上传-->
				<div class="householdPage multiselect chooseImage">
					<span class="homePageTitle">可多选上传</span> 
					<img src="img/camera.png" class="camera" /> 
					<img src="" class="pageImg" />
				</div>
				
			</div>
			<div class="savetitle">
				<a class="savebutton">保存</a>
			</div>
		</section>
	<script type="text/javascript" src="js/jquery-1.10.2.js"></script>
	<script type="text/javascript" src="js/rem(750).js"></script>
	<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
	<script type="text/javascript" src="js/saveButton.js" ></script>
	<!-- 微信多图上传 js -->
	<script type="text/javascript" src="js/morePictureUpload.js"></script>
	</body>
</html>

6. 后端java代码

(1)Module层---WeiXinTokenModule.java

package com.juyo.visa.admin.weixinToken.module;

import java.util.Map;

import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Filters;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;

import com.alibaba.fastjson.JSONObject;
import com.juyo.visa.admin.weixinToken.service.WeXinTokenViewService;

@IocBean
@Filters
@At("admin/weixinToken")
public class WeiXinTokenModule {

	@Inject
	private WeXinTokenViewService weXinTokenViewService;

	/**
	 *获取 AccessToken
	 * <p>
	 */
	@At
	@POST
	public Object getAccessToken() {
		return weXinTokenViewService.getAccessToken();
	}

	//获取ticket
	@At
	@POST
	public JSONObject getJsApiTicket() {
		return weXinTokenViewService.getJsApiTicket();
	}

	//生成微信权限验证的参数
	@At
	@POST
	public Map<String, String> makeWXTicket(@Param("jsApiTicket") String jsApiTicket, @Param("url") String url) {
		return weXinTokenViewService.makeWXTicket(jsApiTicket, url);
	}

	//微信JSSDK上传的文件需要重新下载后上传到七牛云
	@At
	@POST
	public Object wechatJsSDKUploadToQiniu(@Param("staffId") Integer staffId, @Param("mediaIds") String mediaIds, @Param("sessionid") String sessionid, @Param("type")Integer type) {
		return weXinTokenViewService.wechatJsSDKUploadToQiniu(staffId,mediaIds,sessionid,type);
	}

	//获取图片集合
	@At
	@POST
	public Object getEchoPictureList(@Param("staffId") Integer staffId, @Param("type") Integer type) {
		return weXinTokenViewService.getEchoPictureList(staffId, type);
	}

}


(2)Service层---WeXinTokenViewService.java

package com.juyo.visa.admin.weixinToken.service;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.springframework.web.socket.TextMessage;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.fastjson.JSONObject;
import com.juyo.visa.admin.weixinToken.module.WeiXinTokenModule;
import com.juyo.visa.common.base.UploadService;
import com.juyo.visa.common.comstants.CommonConstants;
import com.juyo.visa.common.util.HttpUtil;
import com.juyo.visa.common.util.SpringContextUtil;
import com.juyo.visa.entities.TAppStaffCredentialsEntity;
import com.juyo.visa.entities.TConfWxEntity;
import com.juyo.visa.websocket.SimpleSendInfoWSHandler;
import com.uxuexi.core.common.util.DateUtil;
import com.uxuexi.core.common.util.JsonUtil;
import com.uxuexi.core.common.util.Util;
import com.uxuexi.core.redis.RedisDao;
import com.uxuexi.core.web.base.service.BaseService;
import com.uxuexi.core.web.chain.support.JsonResult;

public class WeXinTokenViewService extends BaseService<TConfWxEntity> {

	@Inject
	private RedisDao redisDao;

	@Inject
	private UploadService qiniuUploadService;//文件上传
	
	private SimpleSendInfoWSHandler simpleSendInfoWSHandler = (SimpleSendInfoWSHandler) SpringContextUtil.getBean(
			"mySimpleSendInfoWSHandler", SimpleSendInfoWSHandler.class);

	public static Log logger = LogFactory.getLog(WeiXinTokenModule.class);

	//获取accessToken
	public Object getAccessToken() {

		TConfWxEntity wx = dbDao.fetch(TConfWxEntity.class, 1);
		String WX_APPID = wx.getAppid();
		String WX_APPSECRET = wx.getAppsecret();
		String WX_TOKENKEY = wx.getAccesstokenkey();

		String accessTokenUrl;
		if (wx == null) {
			accessTokenUrl = "请联系管理员配置微信公众号!";
		} else {
			accessTokenUrl = redisDao.get(WX_TOKENKEY);
			if (Util.isEmpty(accessTokenUrl)) {
				accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
				String requestUrl = accessTokenUrl.replace("APPID", WX_APPID).replace("APPSECRET", WX_APPSECRET);
				JSONObject result = HttpUtil.doGet(requestUrl);
				//redis中设置 access_token
				accessTokenUrl = result.getString("access_token");
				redisDao.set(WX_TOKENKEY, accessTokenUrl);
				redisDao.expire(WX_TOKENKEY, 5000);

				accessTokenUrl = requestUrl;

			}
		}

		return accessTokenUrl;
	}

	//获取ticket
	public JSONObject getJsApiTicket() {
		String accessToken = (String) getAccessToken();
		String apiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
		String requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);
		JSONObject result = HttpUtil.doGet(requestUrl);
		return result;
	}

	//生成微信权限验证的参数
	public Map<String, String> makeWXTicket(String jsApiTicket, String url) {

		TConfWxEntity wx = dbDao.fetch(TConfWxEntity.class, 1);
		String WX_APPID = wx.getAppid();
		String WX_APPSECRET = wx.getAppsecret();
		String WX_TOKENKEY = wx.getAccesstokenkey();

		Map<String, String> ret = new HashMap<String, String>();
		String nonceStr = createNonceStr();
		String timestamp = createTimestamp();
		String string1;
		String signature = "";

		//注意这里参数名必须全部小写,且必须有序
		string1 = "jsapi_ticket=" + jsApiTicket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + url;
		try {
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(string1.getBytes("UTF-8"));
			signature = byteToHex(crypt.digest());
			//logger.info("signature=====>" + signature);
		} catch (NoSuchAlgorithmException e) {
			logger.error("WeChatController.makeWXTicket=====Start");
			logger.error(e.getMessage(), e);
			logger.error("WeChatController.makeWXTicket=====End");
		} catch (UnsupportedEncodingException e) {
			logger.error("WeChatController.makeWXTicket=====Start");
			logger.error(e.getMessage(), e);
			logger.error("WeChatController.makeWXTicket=====End");
		}

		ret.put("url", url);
		ret.put("jsapi_ticket", jsApiTicket);
		ret.put("nonceStr", nonceStr);
		ret.put("timestamp", timestamp);
		ret.put("signature", signature);
		ret.put("appid", WX_APPID);

		return ret;
	}

	/**
	 * 微信JSSDK上传的文件需要重新下载后上传到七牛云
	 *
	 * @param 
	 * @param 
	 * @param mediaIds
	 * @param 
	 * @return
	 */
	public Object wechatJsSDKUploadToQiniu(Integer staffId, String mediaIds, String sessionid, Integer type) {
		Date nowDate = DateUtil.nowDate();
		List<TAppStaffCredentialsEntity> celist_old = dbDao.query(TAppStaffCredentialsEntity.class, Cnd.where("staffid","=",staffId).and("type", "=", type), null);
		if(!Util.isEmpty(celist_old)) {
			dbDao.delete(celist_old);
		}

		List<TAppStaffCredentialsEntity> celist_new = new ArrayList<TAppStaffCredentialsEntity>();

		String[] split = mediaIds.split(",");
		if (!Util.isEmpty(split)) {
			for (String mediaId : split) {
				String accessToken = (String) getAccessToken();
				String extName = getExtName(accessToken, mediaId);//获取扩展名
				InputStream inputStream = getInputStream(accessToken, mediaId);//获取输入流
				String url = CommonConstants.IMAGES_SERVER_ADDR
						+ qiniuUploadService.uploadImage(inputStream, extName, mediaId);

				TAppStaffCredentialsEntity credentialEntity = new TAppStaffCredentialsEntity();
				credentialEntity.setStaffid(staffId);
				credentialEntity.setUrl(url);
				credentialEntity.setType(type);
				credentialEntity.setCreatetime(nowDate);
				credentialEntity.setUpdatetime(nowDate);

				celist_new.add(credentialEntity);

			}
		}
		if (!Util.isEmpty(celist_new)) {
			dbDao.insert(celist_new);
		}
		
		//webSocket发消息
		try {
			simpleSendInfoWSHandler.sendMsg(new TextMessage("200"), sessionid);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return JsonResult.success("SUCCESS");
	}

	/**
	 * 
	 * @param staffId 人员id
	 * @param type 图片枚举类型
	 * @return
	 */
	public Object getEchoPictureList(Integer staffId, Integer type) {
		List<TAppStaffCredentialsEntity> celist = dbDao.query(TAppStaffCredentialsEntity.class,
				Cnd.where("staffid", "=", staffId).and("type", "=", type), null);
		String jsonStr = "";
		if (!Util.isEmpty(celist)) {
			jsonStr = JsonUtil.toJson(celist);
		}

		return jsonStr;
	}

	/**
	 * 获取媒体文件
	 * @param accessToken 接口访问凭证
	 * @param mediaId 媒体文件id
	 * @param savePath 文件在本地服务器上的存储路径
	 * */
	public static String downloadMedia(String accessToken, String mediaId, String savePath) {
		String filePath = null;
		// 拼接请求地址
		String requestUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
		requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("MEDIA_ID", mediaId);
		try {
			URL url = new URL(requestUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setDoInput(true);
			conn.setRequestMethod("GET");

			if (!savePath.endsWith("/")) {
				savePath += "/";
			}
			// 根据内容类型获取扩展名
			String fileExt = getFileexpandedName(conn.getHeaderField("Content-Type"));
			// 将mediaId作为文件名
			filePath = savePath + mediaId + fileExt;
			BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
			FileOutputStream fos = new FileOutputStream(new File(filePath));
			byte[] buf = new byte[8096];
			int size = 0;
			while ((size = bis.read(buf)) != -1)
				fos.write(buf, 0, size);
			fos.close();
			bis.close();

			conn.disconnect();
			String info = String.format("下载媒体文件成功,filePath=" + filePath);
			System.out.println(info);
		} catch (Exception e) {
			filePath = null;
			String error = String.format("下载媒体文件失败:%s", e);
			System.out.println(error);
		}
		return filePath;
	}

	/**
	 * 获取扩展名
	 */
	public static String getExtName(String accessToken, String mediaId) {
		String fileExt = null;
		// 拼接请求地址
		String requestUrl = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID";
		requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("MEDIA_ID", mediaId);

		HttpURLConnection conn;
		try {
			URL url = new URL(requestUrl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setDoInput(true);
			conn.setRequestMethod("GET");

			// 根据内容类型获取扩展名
			fileExt = getFileexpandedName(conn.getHeaderField("Content-Type"));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return fileExt;
	}

	/**
	 * 根据内容类型判断文件扩展名
	 *
	 * @param contentType 内容类型
	 * @return
	 */
	public static String getFileexpandedName(String contentType) {
		String fileEndWitsh = "";
		if ("image/jpeg".equals(contentType)) {
			fileEndWitsh = ".jpeg";
		} else if ("application/x-jpg".equals(contentType)) {
			fileEndWitsh = ".jpg";
		} else if ("application/x-png".equals(contentType)) {
			fileEndWitsh = ".png";
		} else if ("image/gif".equals(contentType)) {
			fileEndWitsh = ".gif";
		} else if ("application/x-bmp".equals(contentType)) {
			fileEndWitsh = ".bmp";
		} else if ("image/fax".equals(contentType)) {
			fileEndWitsh = ".fax";
		} else if ("image/x-icon".equals(contentType)) {
			fileEndWitsh = ".ico";
		} else if ("image/pnetvue".equals(contentType)) {
			fileEndWitsh = ".net";
		}

		return fileEndWitsh;
	}

	/** 
	 *  
	 * 根据文件id下载文件 
	 * @param mediaId 媒体id 
	 *  
	 * @throws Exception 
	 */

	public static InputStream getInputStream(String accessToken, String mediaId) {
		InputStream is = null;
		String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + accessToken + "&media_id="
				+ mediaId;
		try {
			URL urlGet = new URL(url);
			HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
			http.setRequestMethod("GET"); // 必须是get方式请求  
			http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			http.setDoOutput(true);
			http.setDoInput(true);
			System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒  
			System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒  
			http.connect();
			// 获取文件转化为byte流  
			is = http.getInputStream();

		} catch (Exception e) {
			e.printStackTrace();
		}

		return is;

	}

	//字节数组转换为十六进制字符串
	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	//生成随机字符串
	private static String createNonceStr() {
		return UUID.randomUUID().toString();
	}

	//生成时间戳
	private static String createTimestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}
}

7. 微信公众号配置信息,数据库设计

要在uni-app中上传图片到七牛云,可以按照以下步骤进行: 1. 在七牛云上创建一个存储空间,并获取该空间的Access Key和Secret Key。 2. 安装uni-app的官方插件uni-upload,并在项目根目录下的vue.config.js中进行配置,添加以下代码: ``` const qiniuUploader = require('uniapp-qiniu-sdk'); const qiniuOptions = { region: 'your region', // 七牛云存储区域 uptokenURL: 'your uptokenURL', // 服务端提供获取上传凭证的接口 domain: 'your domain', // 七牛云存储空间绑定的域名 }; module.exports = { configureWebpack: { plugins: [ { apply: (compiler) => { compiler.hooks.afterEmit.tapPromise('afterEmit', (compilation) => { return new Promise((resolve, reject) => { qiniuUploader.upload(compilation.assets['your upload file name'].existsAt, 'your key', qiniuOptions, (res) => { console.log(res); resolve(); }, (error) => { console.log(error); reject(); }); }); }); }, }, ], }, }; ``` 3. 在需要上传图片的页面中,添加以下代码: ``` <template> <view> <input type="file" @change="upload"> </view> </template> <script> export default { methods: { upload(event) { const file = event.target.files[0]; qiniuUploader.upload(file, (res) => { console.log(res); }, (error) => { console.log(error); }); }, }, }; </script> ``` 其中,qiniuUploader.upload函数的第一个参数为要上传的文件,第二个参数为上传成功后的回调函数,第三个参数为上传失败后的回调函数。 以上就是在uni-app中上传图片到七牛云的基本步骤,具体使用细节可以根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值