diff --git a/jing-common/jing-common-core/src/main/java/com/jing/common/core/constant/ServiceNameConstants.java b/jing-common/jing-common-core/src/main/java/com/jing/common/core/constant/ServiceNameConstants.java
new file mode 100644
index 0000000..15cc632
--- /dev/null
+++ b/jing-common/jing-common-core/src/main/java/com/jing/common/core/constant/ServiceNameConstants.java
@@ -0,0 +1,24 @@
+package com.jing.common.core.constant;
+
+/**
+ * 服务名称
+ *
+ * @author ruoyi
+ */
+public class ServiceNameConstants
+{
+ /**
+ * 认证服务的serviceid
+ */
+ public static final String AUTH_SERVICE = "jing-auth";
+
+ /**
+ * 系统模块的serviceid
+ */
+ public static final String SYSTEM_SERVICE = "jing-system";
+
+ /**
+ * 文件服务的serviceid
+ */
+ public static final String FILE_SERVICE = "jing-file";
+}
diff --git a/jing-common/jing-common-core/src/main/java/com/jing/common/core/exception/ServiceException.java b/jing-common/jing-common-core/src/main/java/com/jing/common/core/exception/ServiceException.java
new file mode 100644
index 0000000..efd9f4b
--- /dev/null
+++ b/jing-common/jing-common-core/src/main/java/com/jing/common/core/exception/ServiceException.java
@@ -0,0 +1,74 @@
+package com.jing.common.core.exception;
+
+/**
+ * 业务异常
+ *
+ * @author ruoyi
+ */
+public final class ServiceException extends RuntimeException
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 错误码
+ */
+ private Integer code;
+
+ /**
+ * 错误提示
+ */
+ private String message;
+
+ /**
+ * 错误明细,内部调试错误
+ *
+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计
+ */
+ private String detailMessage;
+
+ /**
+ * 空构造方法,避免反序列化问题
+ */
+ public ServiceException()
+ {
+ }
+
+ public ServiceException(String message)
+ {
+ this.message = message;
+ }
+
+ public ServiceException(String message, Integer code)
+ {
+ this.message = message;
+ this.code = code;
+ }
+
+ public String getDetailMessage()
+ {
+ return detailMessage;
+ }
+
+ @Override
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public Integer getCode()
+ {
+ return code;
+ }
+
+ public ServiceException setMessage(String message)
+ {
+ this.message = message;
+ return this;
+ }
+
+ public ServiceException setDetailMessage(String detailMessage)
+ {
+ this.detailMessage = detailMessage;
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/uuid/Seq.java b/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/uuid/Seq.java
new file mode 100644
index 0000000..94d68b9
--- /dev/null
+++ b/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/uuid/Seq.java
@@ -0,0 +1,86 @@
+package com.jing.common.core.utils.uuid;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import com.jing.common.core.utils.DateUtils;
+import com.jing.common.core.utils.StringUtils;
+
+/**
+ * @author ruoyi 序列生成类
+ */
+public class Seq
+{
+ // 通用序列类型
+ public static final String commSeqType = "COMMON";
+
+ // 上传序列类型
+ public static final String uploadSeqType = "UPLOAD";
+
+ // 通用接口序列数
+ private static AtomicInteger commSeq = new AtomicInteger(1);
+
+ // 上传接口序列数
+ private static AtomicInteger uploadSeq = new AtomicInteger(1);
+
+ // 机器标识
+ private static final String machineCode = "A";
+
+ /**
+ * 获取通用序列号
+ *
+ * @return 序列值
+ */
+ public static String getId()
+ {
+ return getId(commSeqType);
+ }
+
+ /**
+ * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
+ *
+ * @return 序列值
+ */
+ public static String getId(String type)
+ {
+ AtomicInteger atomicInt = commSeq;
+ if (uploadSeqType.equals(type))
+ {
+ atomicInt = uploadSeq;
+ }
+ return getId(atomicInt, 3);
+ }
+
+ /**
+ * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
+ *
+ * @param atomicInt 序列数
+ * @param length 数值长度
+ * @return 序列值
+ */
+ public static String getId(AtomicInteger atomicInt, int length)
+ {
+ String result = DateUtils.dateTimeNow();
+ result += machineCode;
+ result += getSeq(atomicInt, length);
+ return result;
+ }
+
+ /**
+ * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
+ *
+ * @return 序列值
+ */
+ private synchronized static String getSeq(AtomicInteger atomicInt, int length)
+ {
+ // 先取值再+1
+ int value = atomicInt.getAndIncrement();
+
+ // 如果更新后值>=10 的 (length)幂次方则重置为1
+ int maxSeq = (int) Math.pow(10, length);
+ if (atomicInt.get() >= maxSeq)
+ {
+ atomicInt.set(1);
+ }
+ // 转字符串,用0左补齐
+ return StringUtils.padl(value, length);
+ }
+}
diff --git a/jing-common/jing-common-security/src/main/java/com/jing/common/security/utils/SecurityUtils.java b/jing-common/jing-common-security/src/main/java/com/jing/common/security/utils/SecurityUtils.java
new file mode 100644
index 0000000..ab588d6
--- /dev/null
+++ b/jing-common/jing-common-security/src/main/java/com/jing/common/security/utils/SecurityUtils.java
@@ -0,0 +1,117 @@
+package com.jing.common.security.utils;
+
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import com.jing.common.core.constant.SecurityConstants;
+import com.jing.common.core.constant.TokenConstants;
+import com.jing.common.core.context.SecurityContextHolder;
+import com.jing.common.core.utils.ServletUtils;
+import com.jing.common.core.utils.StringUtils;
+import com.jing.system.api.model.LoginUser;
+
+/**
+ * 权限获取工具类
+ *
+ * @author ruoyi
+ */
+public class SecurityUtils
+{
+ /**
+ * 获取用户ID
+ */
+ public static Long getUserId()
+ {
+ return SecurityContextHolder.getUserId();
+ }
+
+ /**
+ * 获取用户名称
+ */
+ public static String getUsername()
+ {
+ return SecurityContextHolder.getUserName();
+ }
+
+ /**
+ * 获取用户key
+ */
+ public static String getUserKey()
+ {
+ return SecurityContextHolder.getUserKey();
+ }
+
+ /**
+ * 获取登录用户信息
+ */
+ public static LoginUser getLoginUser()
+ {
+ return SecurityContextHolder.get(SecurityConstants.LOGIN_USER, LoginUser.class);
+ }
+
+ /**
+ * 获取请求token
+ */
+ public static String getToken()
+ {
+ return getToken(ServletUtils.getRequest());
+ }
+
+ /**
+ * 根据request获取请求token
+ */
+ public static String getToken(HttpServletRequest request)
+ {
+ // 从header获取token标识
+ String token = request.getHeader(TokenConstants.AUTHENTICATION);
+ return replaceTokenPrefix(token);
+ }
+
+ /**
+ * 裁剪token前缀
+ */
+ public static String replaceTokenPrefix(String token)
+ {
+ // 如果前端设置了令牌前缀,则裁剪掉前缀
+ if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
+ {
+ token = token.replaceFirst(TokenConstants.PREFIX, "");
+ }
+ return token;
+ }
+
+ /**
+ * 是否为管理员
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public static boolean isAdmin(Long userId)
+ {
+ return userId != null && 1L == userId;
+ }
+
+ /**
+ * 生成BCryptPasswordEncoder密码
+ *
+ * @param password 密码
+ * @return 加密字符串
+ */
+ public static String encryptPassword(String password)
+ {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.encode(password);
+ }
+
+ /**
+ * 判断密码是否相同
+ *
+ * @param rawPassword 真实密码
+ * @param encodedPassword 加密后字符
+ * @return 结果
+ */
+ public static boolean matchesPassword(String rawPassword, String encodedPassword)
+ {
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ return passwordEncoder.matches(rawPassword, encodedPassword);
+ }
+}
diff --git a/jing-modules/jing-gen/src/main/resources/vm/java/service.java.vm b/jing-modules/jing-gen/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 0000000..264882b
--- /dev/null
+++ b/jing-modules/jing-gen/src/main/resources/vm/java/service.java.vm
@@ -0,0 +1,61 @@
+package ${packageName}.service;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+
+/**
+ * ${functionName}Service接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service
+{
+ /**
+ * 查询${functionName}
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return ${functionName}
+ */
+ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+ /**
+ * 查询${functionName}列表
+ *
+ * @param ${className} ${functionName}
+ * @return ${functionName}集合
+ */
+ public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
+
+ /**
+ * 新增${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+ public int insert${ClassName}(${ClassName} ${className});
+
+ /**
+ * 修改${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+ public int update${ClassName}(${ClassName} ${className});
+
+ /**
+ * 批量删除${functionName}
+ *
+ * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合
+ * @return 结果
+ */
+ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+
+ /**
+ * 删除${functionName}信息
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return 结果
+ */
+ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+}
diff --git a/jing-modules/jing-gen/src/main/resources/vm/java/serviceImpl.java.vm b/jing-modules/jing-gen/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 0000000..1f2c6e4
--- /dev/null
+++ b/jing-modules/jing-gen/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +1,169 @@
+package ${packageName}.service.impl;
+
+import java.util.List;
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
+import com.jing.common.core.utils.DateUtils;
+#break
+#end
+#end
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+#if($table.sub)
+import java.util.ArrayList;
+import com.jing.common.core.utils.StringUtils;
+import org.springframework.transaction.annotation.Transactional;
+import ${packageName}.domain.${subClassName};
+#end
+import ${packageName}.mapper.${ClassName}Mapper;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+
+/**
+ * ${functionName}Service业务层处理
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service
+{
+ @Autowired
+ private ${ClassName}Mapper ${className}Mapper;
+
+ /**
+ * 查询${functionName}
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return ${functionName}
+ */
+ @Override
+ public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+ {
+ return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+ }
+
+ /**
+ * 查询${functionName}列表
+ *
+ * @param ${className} ${functionName}
+ * @return ${functionName}
+ */
+ @Override
+ public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
+ {
+ return ${className}Mapper.select${ClassName}List(${className});
+ }
+
+ /**
+ * 新增${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int insert${ClassName}(${ClassName} ${className})
+ {
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime')
+ ${className}.setCreateTime(DateUtils.getNowDate());
+#end
+#end
+#if($table.sub)
+ int rows = ${className}Mapper.insert${ClassName}(${className});
+ insert${subClassName}(${className});
+ return rows;
+#else
+ return ${className}Mapper.insert${ClassName}(${className});
+#end
+ }
+
+ /**
+ * 修改${functionName}
+ *
+ * @param ${className} ${functionName}
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int update${ClassName}(${ClassName} ${className})
+ {
+#foreach ($column in $columns)
+#if($column.javaField == 'updateTime')
+ ${className}.setUpdateTime(DateUtils.getNowDate());
+#end
+#end
+#if($table.sub)
+ ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
+ insert${subClassName}(${className});
+#end
+ return ${className}Mapper.update${ClassName}(${className});
+ }
+
+ /**
+ * 批量删除${functionName}
+ *
+ * @param ${pkColumn.javaField}s 需要删除的${functionName}主键
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
+ {
+#if($table.sub)
+ ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
+#end
+ return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
+ }
+
+ /**
+ * 删除${functionName}信息
+ *
+ * @param ${pkColumn.javaField} ${functionName}主键
+ * @return 结果
+ */
+#if($table.sub)
+ @Transactional
+#end
+ @Override
+ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+ {
+#if($table.sub)
+ ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
+#end
+ return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+ }
+#if($table.sub)
+
+ /**
+ * 新增${subTable.functionName}信息
+ *
+ * @param ${className} ${functionName}对象
+ */
+ public void insert${subClassName}(${ClassName} ${className})
+ {
+ List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
+ ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
+ if (StringUtils.isNotNull(${subclassName}List))
+ {
+ List<${subClassName}> list = new ArrayList<${subClassName}>();
+ for (${subClassName} ${subclassName} : ${subclassName}List)
+ {
+ ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
+ list.add(${subclassName});
+ }
+ if (list.size() > 0)
+ {
+ ${className}Mapper.batch${subClassName}(list);
+ }
+ }
+ }
+#end
+}
diff --git a/jing-ui/src/assets/icons/svg/select.svg b/jing-ui/src/assets/icons/svg/select.svg
new file mode 100644
index 0000000..d628382
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/select.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/assets/icons/svg/sentinel.svg b/jing-ui/src/assets/icons/svg/sentinel.svg
new file mode 100644
index 0000000..1f00040
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/sentinel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/assets/icons/svg/server.svg b/jing-ui/src/assets/icons/svg/server.svg
new file mode 100644
index 0000000..eb287e3
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/server.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/views/system/role/selectUser.vue b/jing-ui/src/views/system/role/selectUser.vue
new file mode 100644
index 0000000..b2b072f
--- /dev/null
+++ b/jing-ui/src/views/system/role/selectUser.vue
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ parseTime(scope.row.createTime) }}
+
+
+
+
+
+
+
+
+
+