用户管理(2)---用户页面角色呈现,数据添加,修改页面数据,数据更新实现

六、用户页面角色呈现

6.1 核心业务分析

用户编辑页面呈现以后,发起异步任务从服务端获取角色信息然后呈现在页面上,其时序分析如图所示:
在这里插入图片描述

6.2 服务端关键业务及代码实现

6.2.1 Vo类定义
  • 业务描述与设计实现

定义VO对象,基于此对象封装用户角色信息。

  • 关键代码设计与实现

创建CheckBox类,基于此类对象封装角色id,角色名信息。关键代码如下:

package com.cy.pj.common.vo;
public class CheckBox implements Serializable{
	private static final long serialVersionUID = 2031967811425337153L;
	private Integer id;
	private String name;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "CheckBox [id=" + id + ", name=" + name + "]";
	}
}
6.2.2 Dao接口定义
  • 业务描述与设计实现

在角色数据层接口中添加查询角色相关信息的方法,并对查询结果进行封装。

  • 关键代码设计与实现

在SysRole添加查询角色id,name的相关方法。关键代码如下:

List<CheckBox> findObjects();
6.2.3 Mapper文件实现
  • 业务描述与设计实现

在角色数据层接口对应的映射文件中,定义角色查询对应的映射元素。

  • 关键代码设计与实现

在SysRoleMapper.xml中添加findObjects元素。关键代码如下:

  <select id="findObjects"
            resultType="com.cy.pj.common.vo.CheckBox">
           select id,name
           from sys_roles
  </select>
6.2.4 Service接口及实现类
  • 业务描述与设计实现

在角色业务层接口中添加查询角色id,name相关信息的业务方法。

  • 关键代码设计与实现

第一步:在SysRoleService接口中添加findObjects方法。关键代码如下:

  List<CheckBox> findObjects();

第二步:在SysRoleService接口中添加findObjects方法实现。关键代码如下:

@Override
    public List<CheckBox> findObjects() {
     	return sysRoleDao.findObjects();
    }
6.2.5 Controller类实现
  • 业务描述与设计实现

在角色控制层对象中添加查询角色id,name相关信息的业务方法。

  • 关键代码设计与实现

在SysRoleController中添加doFindRoles方法。关键代码如下:

 @RequestMapping("doFindRoles")
 public JsonResult doFindRoles() {
	 return new JsonResult(sysRoleService.findObjects());
 }

6.3 客户端关键业务及代码实现

6.3.1 用户编辑页面实现
  • 业务描述与设计实现

在用户编辑页面加载完成以后,异步加载角色信息,并在页面上进行呈现。

  • 关键代码设计与实现

第一步:页面加载完成以后,异步加载角色相关信息。关键代码如下:

$(document).ready(function(){
	 doLoadSysRoles();
}

第二步:定义异步加载角色信息的方法。关键代码如下:

function doLoadSysRoles(){
	 var url="role/doFindObjects";
	 $.getJSON(url,function(result){
		 if(result.state==1){
			 //初始化角色信息
			doInitDivSysRoles(result.data);
		 }else{
			alert(result.message);
		 }
	 })
 };

第三步:定义页面初始化方法,完成页面角色信息的初始化操作。关键代码如下:

//初始化表单角色数据
 function doInitDivSysRoles(data){
	 var div=$("#rolesId");
	 var checkBox=
	"<input type='checkbox' name='roleItem' value='[id]'>[name]";
	 for(var i in data){
		 div.append(
		 checkBox.replace("[id]",data[i].id)
		          .replace("[name]",data[i].name));
	 }
 }

七、用户数据添加实现

7.1 核心业务分析

用户在编辑页面点击保存按钮时,获取编辑页面用户输入的基本信息异步提交到服务端,实现用户数据的持久化操作。其时序分析,如图所示:
在这里插入图片描述

7.2 服务端关键业务及代码实现

7.2.1 Entity类定义
  • 业务描述与设计实现

负责封装用户的基本信息,然后由数据层持久化到数据库。

  • 关键代码设计与实现

定义SysUser类,并通过相关数据封装用户基本信息,关键代码如下:

package com.cy.pj.sys.entity;
public class SysUser implements Serializable{
	private static final long serialVersionUID = 177030063138338860L;
	private Integer id;
	private String username;
	private String password;
	private String salt;//盐值
	private String email;
	private String mobile;
	private Integer valid=1;
      private Integer deptId;
	private Date createdTime;
	private Date modifiedTime;
	private String createdUser;
	private String modifiedUser;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSalt() {
		return salt;
	}
	public void setSalt(String salt) {
		this.salt = salt;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
	public Integer getValid() {
		return valid;
	}
	public void setValid(Integer valid) {
		this.valid = valid;
	}
	public Date getCreatedTime() {
		return createdTime;
	}
	public void setCreatedTime(Date createdTime) {
		this.createdTime = createdTime;
	}
	public Date getModifiedTime() {
		return modifiedTime;
	}
	public void setModifiedTime(Date modifiedTime) {
		this.modifiedTime = modifiedTime;
	}
	public String getCreatedUser() {
		return createdUser;
	}
	public void setCreatedUser(String createdUser) {
		this.createdUser = createdUser;
	}
	public String getModifiedUser() {
		return modifiedUser;
	}
	public void setModifiedUser(String modifiedUser) {
		this.modifiedUser = modifiedUser;
	}
 
}
7.2.2 DAO接口定义
  • 业务描述与设计实现

负责将用户提交的用户基本信息,持久化到数据库。

  • 关键代码设计与实现

在SysUserDao接口中定义数据持久化方法:

int insertObject(SysUser entity);

在SysUserRoleDao接口中方法定义(不存在则创建)

int insertObjects(
			@Param("userId")Integer userId,
			@Param("roleIds")Integer[] roleIds);
7.2.3 Mapper映射文件定义
  • 业务描述与设计实现

基于SysUserDao中方法的定义,在对应的映射文件中添加的对应SQL元素。用于将用户信息添加到数据库。

  • 关键代码设计与实现

第一步:在SysUserMapper.xml中添加insertObject元素,用于写入用户信息。关键代码如下:

  <insert id="insertObject"
           parameterType="com.cy.pj.sys.entity.SysUser"
           useGeneratedKeys="true"
           keyProperty="id">
      insert into sys_users
      (username,password,deptId,email,mobile,salt,valid,
      createdTime,modifiedTime,createdUser,modifiedUser)
      values
    (#{username},#{password},#{deptId},#{email},#{mobile},#{salt},#{valid},
      now(),now(),#{createdUser},#{modifiedUser})
   </insert>

第二步:在SysUserRoleMapper中元素定义,关键代码如下:

   <insert id="insertObjects">
       insert into sys_user_roles
       (user_id,role_id)
       values
       <foreach collection="roleIds" separator="," item="roleId">
          (#{userId},#{roleId})
       </foreach>
    </insert>
7.2.4 Service接口定义及实现
  • 业务描述与设计实现

基于控制层请求,调用数据层对象将用户以及对应的角色信息写入到数据库中。

  • 关键代码设计与实现

第一步:在SysUserService接口中,添加用于保存用户对象的方法。关键代码如下:

int saveObject(SysUser entity,Integer[]roleIds);

第二步:在SysUserServiceImpl类中,实现用户保存操作。关键代码如下:

    @Override
    public int saveObject(SysUser entity, Integer[] roleIds) {
    	long start=System.currentTimeMillis();
    	log.info("start:"+start);
    	//1.参数校验
    	if(entity==null)
    	throw new IllegalArgumentException("保存对象不能为空");
    	if(StringUtils.isEmpty(entity.getUsername()))
    	throw new IllegalArgumentException("用户名不能为空");
    	if(StringUtils.isEmpty(entity.getPassword()))
    	throw new IllegalArgumentException("密码不能为空");
    	if(roleIds==null || roleIds.length==0)
    	throw new IllegalArgumentException("至少要为用户分配角色");
    	//2.保存用户自身信息
        //2.1对密码进行加密
    	String source=entity.getPassword();
    	String salt=UUID.randomUUID().toString();
    	SimpleHash sh=new SimpleHash(//Shiro框架
    			"MD5",//algorithmName 算法
    			 source,//原密码
    			 salt, //盐值
    			 1);//hashIterations表示加密次数
    	entity.setSalt(salt);
    	entity.setPassword(sh.toHex());
    	int rows=sysUserDao.insertObject(entity);
    	//3.保存用户角色关系数据
    	sysUserRoleDao.insertObjects(entity.getId(), roleIds);
    	long end=System.currentTimeMillis();
    	log.info("end:"+end);
    	log.info("total time :"+(end-start));
    	//4.返回结果
    	return rows;
}

说明:使用SimpleHash时,要添加一个shiro框架依赖

  <dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.4.1</version>
  </dependency>
7.2.5 Controller类定义
  • 业务描述与设计实现

接收客户端提交的用户相关数据,并对其进行封装,然后调用业务层对象进行业务处理,最后将业务层处理结果响应到客户端。

  • 关键代码设计与实现

定义Controller方法,借助此方法处理保存用户数据的请求和响应逻辑。关键代码如下:

@RequestMapping("doSaveObject")
public JsonResult doSaveObject(
		SysUser entity,
		Integer[] roleIds){
	sysUserService.saveObject(entity,roleIds);
	return new JsonResult("save ok");
}

7.3 客户端关键业务及代码实现

7.3.1 用户编辑页面部门信息呈现
  • 业务描述与设计实现

用户点击所属部门时,异步加载部门信息并以zTree结构进行呈现,然后用户可以选择对应的部门,将部门相关信息更新到页面上。

  • 关键代码设计与实现

第一步:在所有部门相关dom元素上进行事件注册,关键代码如下:

$(".form-horizontal")
	 .on("click",".load-sys-dept",doLoadZTreeNodes);

第二步:定义事件处理函数,用户呈现部门信息,关键代码如下:

function doLoadZTreeNodes(){
	  var url="dept/doFindZTreeNodes";
	  $("#treeLayer").css("display","block");
	  $.getJSON(url,function(result){
		  if(result.state==1){
			  zTree = $.fn.zTree.init($("#zTreeId"),setting,result.data);
		  }else{
			  alert(result.message);
		  }
	  });
 }

第三步:部门div容器中注册,确定和取消事件,关键代码如下:
页面加载完成以后,进行事件注册:

$("#treeLayer")
	  .on("click",".btn-cancel",doHideTree)
	  .on("click",".btn-confirm",doConfirm);

确定按钮事件处理函数定义:

 function doConfirm(){
	  //1.获取选中的记录(id,name);
	  var selectedNodes=zTree.getSelectedNodes();
	  var node=selectedNodes[0];
	  //2.将id和name填写或绑定在具体对象上
	  $("#deptId").val(node.name);
	  $("#deptId").data("deptId",node.id)
	  //3.隐藏zTree对应的Div
	  doHideTree();
 }

取消按钮事件处理函数定义:

function doHideTree(){
	  $("#treeLayer").css("display","none");
 }
7.3.2 页面cancel按钮事件处理
  • 业务描述与设计实现

点击页面cancel按钮时,加载菜单那列表页面。

  • 关键代码设计与实现

第一步:事件注册(页面加载完成以后)

  $(".box-footer")
	  .on("click",".btn-cancel",doCancel)

第二步:事件处理函数定义

function doCancel(){
	$("#mainContentId").removeData("rowData");
	$("#mainContentId").load("user/user_list");
 }
7.3.3 页面Save按钮事件处理
  • 业务描述与设计实现

点击页面save按钮时,将页面上输入的菜单信息提交到服务端。

  • 关键代码设计与实现

第一步:事件注册(页面加载完成以后)。

  $(".box-footer")
	  .on("click",".btn-save",doSaveOrUpdate)

第二步:Save按钮事件处理函数定义。关键代码如下:

function doSaveOrUpdate(){
	 //1.url
	 var insertUrl="user/doSaveObject";
	 //2.获取表单数据
	 var params=doGetEditFormData();
	 //3.发起异步请求
	 $.post(insertUrl,params,function(result){
		 if(result.state==1){
			 alert(result.message);
			 doCancel();
		 }else{
			 alert(result.message);
		 }
	 })
 }

第三步:表单数据获取及封装。关键代码如下:

function doGetEditFormData(){
	 var params={
	      "username":$("#usernameId").val(),
	      "password":$("#passwordId").val(),
	      "email":$("#emailId").val(),
	      "mobile":$("#phoneId").val(),
          "deptId":$("#deptId").data("deptId"),
	 }
	 var roleIds=new Array();
	 $("#rolesId input[type='checkbox']")
	 .each(function(){
		 if($(this).prop("checked")){
			 roleIds.push($(this).val())
		 }
	 });
	 params.roleIds=roleIds.toString();
	 console.log(params);
	 return params;
	 
 }

八、用户修改页面数据呈现

8.1 核心业务分析

基于用户id查询用户以及用户对应的部门和角色信息,并将其对应的信息呈现在用户编辑页面上,其时序图分析如图所示:
在这里插入图片描述

8.2 服务端关键业务及代码实现

8.2.1 DAO接口定义
  • 业务描述与设计实现

负责基于id执行用户和角色信息数据的查询操作。

  • 关键代码设计与实现

在SysUserDao接口中定义基于用户id查询用户相关信息的方法,关键代码如下:

SysUserDeptVo findObjectById(Integer id);

在SysUserRoleDao接口中定义基于用户id查询角色id信息的方法,关键代码如下:

List<Integer> findRoleIdsByUserId(Integer id);
8.2.2 Mapper文件定义
  • 业务描述与设计实现

基于SysUserDao,SysUserRoleDao中方法的定义,在映射文件中添加对应的用户查询元素。

  • 关键代码设计与实现

第一步:在SysUserMapper.xml中添加id为findObjectById的select元素,关键代码如下:

      <select id="findObjectById"
           parameterType="int"
           resultMap="sysUserDeptVo">
           select * 
           from sys_users   
           where id=#{id}     
   </select>

第二步:在SysUserRoleMapper.xml中添加id为findRoleIdsByUserId的select元素,关键代码如下:

<select id="findRoleIdsByUserId"
           resultType="int">
        select role_id
        from sys_user_roles
        where user_id=#{id}
</select>
8.2.3 Service接口定义及实现
  • 业务描述与设计实现

基于控制层请求,调用数据层方法,查询对应的用户及相关信息。

  • 关键代码设计与实现

第一步:在SysUserService接口中,添加基于id查询用户及相关信息的方法。关键代码如下:

Map<String,Object> findObjectById(Integer userId) ;

第二步:在SysUserService接口对应的实现类SysUserServiceImpl中添加findObjectById的具体实现。关键代码如下:

@Override
public Map<String, Object> findObjectById(Integer userId) {
		//1.合法性验证
		if(userId==null||userId<=0)
		throw new IllegalArgumentException(
		"参数数据不合法,userId="+userId);
		//2.业务查询
		SysUserDeptVo user=
		sysUserDao.findObjectById(userId);
		if(user==null)
		throw new ServiceException("此用户已经不存在");
		List<Integer> roleIds=
		sysUserRoleDao.findRoleIdsByUserId(userId);
		//3.数据封装
		Map<String,Object> map=new HashMap<>();
		map.put("user", user);
		map.put("roleIds", roleIds);
		return map;
	}
8.2.4 Controller类定义
  • 业务描述与设计实现

基于客户端请求,调用业务层方法,查询对应的用户及相关信息。

  • 关键代码设计与实现

在SysUserController类中定义基于用户ID查询用户的相关方法。关键代码如下:

@RequestMapping("doFindObjectById")
	public JsonResult doFindObjectById(
			Integer id){
		Map<String,Object> map=
		sysUserService.findObjectById(id);
		return new JsonResult(map);
	}

8.3 客户端关键业务及代码实现

8.3.1 列表页面修改按钮事件处理
  • 业务描述与设计实现

在用户列表修改按钮上进行事件注册,点击页面修改按钮时,基于用户id向服务端发起异步请求获取用户相关数据,然后加载修改页面。

  • 关键代码设计与实现

第一步:页面加载完成,进行修改按钮事件注册,关键代码如下:

$(function(){//假如是修改
		$(".input-group-btn")
.on("click","btn-update",doLoadEditUI);
  });

第二步:修改按钮事件处理函数定义或修改,关键代码如下:

function doLoadEditUI(){
	   //1.判定点击的对象
	   var title;
	   if($(this).hasClass("btn-add")){
		   title="添加用户";
		   doLoadPage(title);
	   }else if($(this).hasClass("btn-update")){
		   title="修改用户";
		   var id=$("tbody input[name='radioId']:checked").val();
		   console.log("id="+id)
		   if(!id){
			  alert("请先选择");
			  return;
		   }
		   //基于id进行查询并加载编辑页面
		   doFindObjectById(id,title);
	   }
   }

第三步:定义或修改加载编辑页面的方法。关键代码如下:

   function doLoadPage(title){
	   var url="user/user_edit"
	   $("#mainContentId").load(url,function(){
		   $(".box-title").html(title);
	   }) 
   }

第四步:定义基于id查询用户信息的方法。关键代码如下:

 function doFindObjectById(id,title){
	   //1.params
	   var params={"id":id};
	   //2.url
	   var url="user/doFindObjectById";
	   //3.ajax request
	   $.getJSON(url,params,function(result){//JsonResult
		   if(result.state==1){
			  $("#mainContentId").data("rowData",result.data); 
	          doLoadPage(title);
		   }else{
			  alert(result.message);
		   }
	   });
   }
8.3.2 编辑页面角色数据呈现
  • 业务描述与设计实现

页面加载完成,获取编辑页面数据,然后在页面指定位置进行数据呈现数据。

  • 关键代码设计与实现

第一步:在用户编辑页面中,角色数据加载完成以后,获取用户编辑页面中需要的表单数据,然后进行页面数据初始化。关键代码如下:

function doLoadRoles(){
	 var url="role/doFindRoles"
	 $.getJSON(url,function(result){
		 if(result.state==1){
		  doInitPageRoles(result.data);
		  doInitFormData();//修改时
		 }else{
		  alert(result.message);
		 }
	 })
 }

第三步:定义编辑页面数据初始化方法。关键代码如下:

function doInitFormData(){
     var data=$("#mainContentId").data("rowData");
     if(!data)return;
     $("#pwdDiv").remove();
	 console.log(data);
	 //初始化用户信息 
	 $("#usernameId").val(data.user.username);
	 $("#deptId").val(data.user.sysDept?data.user.sysDept.name:'');
	 $("#deptId").data("deptId",data.user.sysDept?data.user.sysDept.id:'');
	 $("#emailId").val(data.user.email);
	 $("#phoneId").val(data.user.mobile);
	 //初始化用户角色信息
	 var ids=data.roleIds;
	 for(var i in ids){
	  $("#rolesId input[value='"+ids[i]+"']")
	  .prop("checked",true);
	 }
 }

九、用户数据更新实现

9.1 核心业务分析

在用户编辑页面点击更新按钮时,异步提交数据到服务端,服务端要更新用户自身信息以及用户和角色关系数据,其时序图分析,如图所示:
在这里插入图片描述

9.2 服务端关键业务及代码实现

9.2.1 DAO接口实现
  • 业务描述与设计实现

获取用户编辑页面数据,然后异步提交到服务端,将用户信息以及用户对应的角色关系数据更新到数据库。

  • 关键代码设计与实现

第一步:在SysUserDao接口中添加数据更新方法,关键代码如下:

int updateObject(SysUser entity);

第二步:在SysUserRoleDao接口中添加基于用户id删除关系数据的方法,关键代码如下:

int deleteObjectsByUserId(Integer userId);
9.2.2 Mapper文件定义
  • 业务描述与设计实现

基于SysUserDao,SysUserRoleDao中方法的定义,编写用于实现用户更新的SQL元素。

  • 关键代码设计与实现

第一步:在SysUserMapper.xml中添加updateObject元素,用于更新菜单信息。关键代码如下:

   <update id="updateObject"
           parameterType="com.cy.pj.sys.entity.SysUser">
        update sys_users
        set username=#{username},
            mobile=#{mobile},
            email=#{email},
            deptId=#{deptId},
            modifiedTime=now(),
            modifiedUser=#{modifiedUser}
         where id=#{id}
   </update>

第二步:在SysUserRoleMapper.xml文件中添加基于用户id删除关系数据的元素,关键代码如下:

   <delete id="deleteObjectsByUserId"
           parameterType="int">
         delete from sys_user_roles
         where user_id=#{userId}          
   </delete>
9.2.3 Service接口及实现
  • 业务描述与设计实现

基于控制层请求,对数据进行校验并调用数据层对象将角色信息以及角色菜单关系数据更新到数据库中。

  • 关键代码设计与实现

第一步:在SysUserService接口中,添加用于更新角色对象的方法。关键代码如下:

int updateObject(SysUser entity,Integer[] roleIds)

第二步:在SysUserServiceImpl类中,实现更新角色操作。关键代码如下:

@Override
public int updateObject(SysUser entity,Integer[] roleIds) {
		//1.参数有效性验证
		if(entity==null)
			throw new IllegalArgumentException("保存对象不能为空");
		if(StringUtils.isEmpty(entity.getUsername()))
			throw new IllegalArgumentException("用户名不能为空");
		if(roleIds==null||roleIds.length==0)
			throw new IllegalArgumentException("必须为其指定角色");
		//其它验证自己实现,例如用户名已经存在,密码长度,...
		//2.更新用户自身信息
		int rows=sysUserDao.updateObject(entity);
		//3.保存用户与角色关系数据
		sysUserRoleDao.deleteObjectsByUserId(entity.getId());
		sysUserRoleDao.insertObjects(entity.getId(),
				roleIds);
		//4.返回结果
		return rows;
	}	
9.2.4 Controller类定义
  • 业务描述与设计实现

首先接收客户端提交的用户数据,并对其进行封装,然后调用业务层对象对角色信息进行更行更新,最后将业务层处理结果响应到客户端。

  • 关键代码设计与实现

在SysUserController类中定义更新角色的方法。关键代码如下:

@RequestMapping("doUpdateObject")
public JsonResult doUpdateObject(
    SysUser entity,Integer[] roleIds){
	sysUserService.updateObject(entity,roleIds);
	return new JsonResult("update ok");
}

9.3 客户端关键业务及代码实现

9.3.1 编辑页面更新按钮事件处理
  • 业务描述与设计实现

点击页面save按钮时,将页面上输入的用户编辑信息异步提交到服务端进行更新。

  • 关键代码设计与实现

修改用户编辑页面中保存表单数据的JS函数,关键代码如下:

function doSaveOrUpdate(){
	 //1.params
	 var rowData=$("#mainContentId").data("rowData");
	 var params=doGetEditFormData();
	 if(rowData){
	    params.id=rowData.user.id;
	 }
	 //1.url
	 var insertUrl="user/doSaveObject";
	 var updateUrl="user/doUpdateObject";
	 var url=rowData?updateUrl:insertUrl;
	 //2.获取表单数据
	 //3.发起异步请求
	 $.post(url,params,function(result){
		 if(result.state==1){
			 alert(result.message);
			 doCancel();
		 }else{
			 alert(result.message);
		 }
	 })
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

经理,天台风好大

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

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

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

打赏作者

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

抵扣说明:

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

余额充值