基础平台项目之树形菜单权限配置实现

举报
yd_273762914 发表于 2020/12/02 22:27:08 2020/12/02
【摘要】 计划在开源项目里加入权限配置的功能,打算加入zTree实现树形结构。 Team的Github开源项目链接:https://github.com/u014427391/jeeplatform 欢迎star(收藏) zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。 zTree下载...

计划在开源项目里加入权限配置的功能,打算加入zTree实现树形结构。

Team的Github开源项目链接:https://github.com/u014427391/jeeplatform
欢迎star(收藏)

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。

zTree下载链接:http://www.treejs.cn/v3/main.php#_zTreeInfo

这里写图片描述

角色信息实体类:

package org.muses.jeeplatform.core.entity.admin;

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * @description 角色信息实体类
 * @author Nicky
 * @date 2017年3月16日
 */
@Table(name="sys_role")
@Entity
public class Role implements Serializable{

	/** 角色Id**/
	private int roleId;

	/** 角色描述**/
	private String roleDesc;

	/** 角色名称**/
	private String roleName;

	/** 角色标志**/
	private String role;

	private Set<Permission> permissions = new HashSet<Permission>();

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public int getRoleId() {
		return roleId;
	}

	public void setRoleId(int roleId) {
		this.roleId = roleId;
	}

	@Column(length=100)
	public String getRoleDesc() {
		return roleDesc;
	}

	public void setRoleDesc(String roleDesc) {
		this.roleDesc = roleDesc;
	}

	@Column(length=100)
	public String getRoleName() {
		return roleName;
	}

	public void setRoleName(String roleName) {
		this.roleName = roleName;
	}

	@Column(length=100)
	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	//修改cascade策略为级联关系
	@OneToMany(targetEntity=Permission.class,cascade=CascadeType.MERGE,fetch=FetchType.EAGER)
	@JoinTable(name="sys_role_permission", joinColumns=@JoinColumn(name="roleId",referencedColumnName="roleId"), inverseJoinColumns=@JoinColumn(name="permissionId",referencedColumnName="id",unique=true))
	public Set<Permission> getPermissions() {
		return permissions;
	}

	public void setPermissions(Set<Permission> permissions) {
		this.permissions = permissions;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Role) { Role role = (Role) obj; return this.roleId==(role.getRoleId()) && this.roleName.equals(role.getRoleName()) && this.roleDesc.equals(role.getRoleDesc()) && this.role.equals(role.getRole());
		}
		return super.equals(obj);
	}
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

权限信息实体类:

package org.muses.jeeplatform.core.entity.admin;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

/**
 * @description 权限操作的Vo类
 * @author Nicky
 * @date 2017年3月6日
 */
@Table(name="sys_permission")
@Entity
public class Permission implements Serializable {

	private int id;
	private String pdesc;
	private String name;
	private static final long serialVersionUID = 1L;

	private Menu menu;

	private Set<Operation> operations = new HashSet<Operation>();

	public Permission() {
		super();
	}

	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Id
	public int getId() {
		return this.id;
	}

	public void setId(int id) {
		this.id = id;
	}

	@Column(length=100)
	public String getPdesc() {
		return this.pdesc;
	}

	public void setPdesc(String pdesc) {
		this.pdesc = pdesc;
	}

	@Column(length=100)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@OneToOne(targetEntity=Menu.class,cascade=CascadeType.REFRESH,fetch=FetchType.EAGER)
	@JoinColumn(name="menuId",referencedColumnName="menuId")
	public Menu getMenu() {
		return menu;
	}

	public void setMenu(Menu menu) {
		this.menu = menu;
	}

	@ManyToMany(targetEntity=Operation.class,cascade=CascadeType.MERGE,fetch=FetchType.EAGER)
	@JoinTable(name="sys_permission_operation",joinColumns=@JoinColumn(name="permissionId",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="operationId",referencedColumnName="id"))
	public Set<Operation> getOperations() {
		return operations;
	}

	public void setOperations(Set<Operation> operations) {
		this.operations = operations;
	}
}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

实现菜单信息实体类,用JPA来实现

package org.muses.jeeplatform.core.entity.admin;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

/**
 * @description 菜单信息实体
 * @author Nicky
 * @date 2017年3月17日
 */
@Table(name="sys_menu")
@Entity
public class Menu implements Serializable {

	/** 菜单Id**/
	private int menuId; /** 上级Id**/
	private int parentId; /** 菜单名称**/
	private String menuName; /** 菜单图标**/
	private String menuIcon; /** 菜单URL**/
	private String menuUrl; /** 菜单类型**/
	private String menuType; /** 菜单排序**/
	private String menuOrder;

	/**菜单状态**/
	private String menuStatus;

	private List<Menu> subMenu;

	private String target;

	private boolean hasSubMenu = false;

	public Menu() {
		super();
	} @Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	public int getMenuId() {
		return this.menuId;
	}

	public void setMenuId(int menuId) {
		this.menuId = menuId;
	}

	@Column(length=100)
	public int getParentId() {
		return parentId;
	}

	public void setParentId(int parentId) {
		this.parentId = parentId;
	}

	@Column(length=100)
	public String getMenuName() {
		return this.menuName;
	}

	public void setMenuName(String menuName) {
		this.menuName = menuName;
	} @Column(length=30)
	public String getMenuIcon() {
		return this.menuIcon;
	}

	public void setMenuIcon(String menuIcon) {
		this.menuIcon = menuIcon;
	} @Column(length=100)
	public String getMenuUrl() {
		return this.menuUrl;
	}

	public void setMenuUrl(String menuUrl) {
		this.menuUrl = menuUrl;
	} @Column(length=100)
	public String getMenuType() {
		return this.menuType;
	}

	public void setMenuType(String menuType) {
		this.menuType = menuType;
	}

	@Column(length=10)
	public String getMenuOrder() {
		return menuOrder;
	}

	public void setMenuOrder(String menuOrder) {
		this.menuOrder = menuOrder;
	}

	@Column(length=10)
	public String getMenuStatus(){
		return menuStatus;
	}

	public void setMenuStatus(String menuStatus){
		this.menuStatus = menuStatus;
	}

	@Transient
	public List<Menu> getSubMenu() {
		return subMenu;
	}

	public void setSubMenu(List<Menu> subMenu) {
		this.subMenu = subMenu;
	}

	public void setTarget(String target){
		this.target = target;
	}

	@Transient
	public String getTarget(){
		return target;
	}

	public void setHasSubMenu(boolean hasSubMenu){
		this.hasSubMenu = hasSubMenu;
	}

	@Transient
	public boolean getHasSubMenu(){
		return hasSubMenu;
	}

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151

实现JpaRepository接口

package org.muses.jeeplatform.core.dao.repository.admin;

import org.muses.jeeplatform.core.entity.admin.Role;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by Nicky on 2017/12/2.
 */
public interface RoleRepository extends JpaRepository<Role,Integer> {

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

实现JpaRepository接口

package org.muses.jeeplatform.core.dao.repository.admin;

import org.muses.jeeplatform.core.entity.admin.Menu;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by Nicky on 2017/6/17.
 */
public interface MenuTreeRepository extends JpaRepository<Menu,Integer>{

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

角色Service类:

package org.muses.jeeplatform.service;


import com.google.common.collect.Lists;
import org.muses.jeeplatform.core.dao.repository.admin.RolePageRepository;
import org.muses.jeeplatform.core.entity.admin.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * Created by Nicky on 2017/7/30.
 */
@Service
public class RolePageService { @Autowired RolePageRepository roleRepository; /** * 构建PageRequest对象 * @param num * @param size * @param asc * @param string * @return */ private PageRequest buildPageRequest(int num, int size, Sort.Direction asc, String string) { return new PageRequest(num-1, size,null,string); } /** * 获取所有的菜单信息并分页显示 * @param pageNo * 当前页面数 * @param pageSize * 每一页面的页数 * @return */ public Page<Role> findAll(int pageNo, int pageSize, Sort.Direction dir, String str){ PageRequest pageRequest = buildPageRequest(pageNo, pageSize, dir, str); Page<Role> roles = roleRepository.findAll(pageRequest); return roles; } public List<Role> findAllRole(){ Iterable<Role> roles = roleRepository.findAll(); List<Role> myList = Lists.newArrayList(roles); return myList; } /** * 根据角色id查找角色信息 * @param roleId * @return */ public Role findByRoleId(String roleId){ return roleRepository.findOne(Integer.parseInt(roleId)); } /** * 保存角色信息 * @param role */ public void doSave(Role role){ roleRepository.save(role); } }


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

菜单Service类:

package org.muses.jeeplatform.service;

import org.muses.jeeplatform.annotation.RedisCache;
import org.muses.jeeplatform.common.RedisCacheNamespace;
import org.muses.jeeplatform.core.dao.repository.admin.MenuTreeRepository;
import org.muses.jeeplatform.core.entity.admin.Menu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * Created by Nicky on 2017/6/17.
 */
@Service
public class MenuTreeService { @Autowired MenuTreeRepository menuTreeRepository; /** * 查询所有的菜单 * @return */ @Transactional //@RedisCache public List<Menu> findAll(){ return menuTreeRepository.findAll(); }

}


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

在Controller类里通过角色id获取该角色可以查看的菜单:

/** * 跳转到角色授权页面 * @param roleId * @param model * @return */ @RequestMapping(value = "/goAuthorise" ) public String goAuth(@RequestParam String roleId, Model model){ List<Menu> menuList = menuTreeService.findAll(); Role role = roleService.findByRoleId(roleId); Set<Permission> hasPermissions = null; if(role != null){ hasPermissions = role.getPermissions(); } for (Menu m : menuList) { for(Permission p : hasPermissions){ if(p.getMenu().getMenuId()==m.getMenuId()){ m.setHasSubMenu(true); } } } model.addAttribute("roleId" , roleId); JSONArray jsonArray = JSONArray.fromObject(menuList); String json = jsonArray.toString(); json = json.replaceAll("menuId","id").replaceAll("parentId","pId"). replaceAll("menuName","name").replaceAll("hasSubMenu","checked"); model.addAttribute("menus",json); return "admin/role/role_auth"; }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在前端通过zTree实现树形菜单展示,通过勾选然后实现角色授权:

<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html lang="zh-CN">
<head> <base href="<%=basePath %>"> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Insert title here</title> <!-- 引入JQuery库 start --> <script type="text/javascript" src="${basePath}static/js/jquery-1.8.3.js"></script> <!-- 引入JQuery库 end --> <script type="text/javascript" src="<%=basePath%>plugins/zDialog/zDialog.js"></script> <script type="text/javascript" src="<%=basePath%>plugins/zDialog/zDrag.js"></script> <script type="text/javascript" src="<%=basePath%>plugins/zDialog/zProgress.js"></script> <link rel="stylesheet" href="<%=basePath%>plugins/zTree/3.5/zTreeStyle.css" type="text/css"> <script type="text/javascript" src="<%=basePath%>plugins/zTree/3.5/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="<%=basePath%>plugins/zTree/3.5/jquery.ztree.core.js"></script> <script type="text/javascript" src="<%=basePath%>plugins/zTree/3.5/jquery.ztree.excheck.js"></script> <script type="text/javascript"> <!-- var setting = { check: { enable: true }, data: { simpleData: { enable: true } }, callback:{ onClick: { } } }; /*[ { id:1, pId:0, name:"随意勾选 1", open:true}, { id:11, pId:1, name:"随意勾选 1-1", open:true}, { id:12, pId:1, name:"随意勾选 1-2", open:true} ];*/ var json = ${menus}; var zNodes = eval(json); var code; function setCheck() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"), py = $("#py").attr("checked")? "p":"", sy = $("#sy").attr("checked")? "s":"", pn = $("#pn").attr("checked")? "p":"", sn = $("#sn").attr("checked")? "s":"", type = { "Y":py + sy, "N":pn + sn}; zTree.setting.check.chkboxType = type; showCode('setting.check.chkboxType = { "Y" : "' + type.Y + '", "N" : "' + type.N + '" };'); } function showCode(str) { if (!code) code = $("#code"); code.empty(); code.append("<li>"+str+"</li>"); } $(document).ready(function(){ $.fn.zTree.init($("#treeDemo"), setting, zNodes); setCheck(); $("#py").bind("change", setCheck); $("#sy").bind("change", setCheck); $("#pn").bind("change", setCheck); $("#sn").bind("change", setCheck); }); //--> function dialogClose() { parentDialog.close(); } function doSave() { var zTree = $.fn.zTree.getZTreeObj("treeDemo"); var nodes = zTree.getCheckedNodes(); var tmpNode; var ids = ""; for(var i=0; i<nodes.length; i++){ tmpNode = nodes[i]; if(i!=nodes.length-1){ ids += tmpNode.id+","; }else{ ids += tmpNode.id; } } var roleId = ${roleId}; var params = roleId +";"+ids; alert(ids); $.ajax({ type: "POST", url: 'role/authorise.do', data: {params:params,tm:new Date().getTime()}, dataType:'json', cache: false, success: function(data){ if("success" == data.result){ alert('授权成功!请重新登录!'); parent.location.reload(); doDialogClose(); }else{ alert("授权失败!"); } } }); } </script>
</head>
<body >
<div class="content_wrap"> <div class="zTreeDemoBackground left"> <ul id="treeDemo" class="ztree"></ul> </div>
</div>
&nbsp;&nbsp;
<input type="button" onClick="doSave()" value="保存" class="buttonStyle" />
<input onClick="dialogClose();" class="buttonStyle" type="button" value="关闭" />
</body>
</html>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

这里写图片描述

Team的Github开源项目链接:https://github.com/u014427391/jeeplatform
欢迎star(收藏)

文章来源: smilenicky.blog.csdn.net,作者:smileNicky,版权归原作者所有,如需转载,请联系作者。

原文链接:smilenicky.blog.csdn.net/article/details/78889378

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。