diff --git a/jing-common/jing-common-core/src/main/java/com/jing/common/core/annotation/Excel.java b/jing-common/jing-common-core/src/main/java/com/jing/common/core/annotation/Excel.java
new file mode 100644
index 0000000..9e68929
--- /dev/null
+++ b/jing-common/jing-common-core/src/main/java/com/jing/common/core/annotation/Excel.java
@@ -0,0 +1,182 @@
+package com.jing.common.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import com.jing.common.core.utils.poi.ExcelHandlerAdapter;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel
+{
+ /**
+ * 导出时在excel中排序
+ */
+ public int sort() default Integer.MAX_VALUE;
+
+ /**
+ * 导出到Excel中的名字.
+ */
+ public String name() default "";
+
+ /**
+ * 日期格式, 如: yyyy-MM-dd
+ */
+ public String dateFormat() default "";
+
+ /**
+ * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+ */
+ public String readConverterExp() default "";
+
+ /**
+ * 分隔符,读取字符串组内容
+ */
+ public String separator() default ",";
+
+ /**
+ * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+ */
+ public int scale() default -1;
+
+ /**
+ * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+ */
+ public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+ /**
+ * 导出时在excel中每个列的高度
+ */
+ public double height() default 14;
+
+ /**
+ * 导出时在excel中每个列的宽度
+ */
+ public double width() default 16;
+
+ /**
+ * 文字后缀,如% 90 变成90%
+ */
+ public String suffix() default "";
+
+ /**
+ * 当值为空时,字段的默认值
+ */
+ public String defaultValue() default "";
+
+ /**
+ * 提示信息
+ */
+ public String prompt() default "";
+
+ /**
+ * 设置只能选择不能输入的列内容.
+ */
+ public String[] combo() default {};
+
+ /**
+ * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+ */
+ public boolean needMerge() default false;
+
+ /**
+ * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+ */
+ public boolean isExport() default true;
+
+ /**
+ * 另一个类中的属性名称,支持多级获取,以小数点隔开
+ */
+ public String targetAttr() default "";
+
+ /**
+ * 是否自动统计数据,在最后追加一行统计数据总和
+ */
+ public boolean isStatistics() default false;
+
+ /**
+ * 导出类型(0数字 1字符串)
+ */
+ public ColumnType cellType() default ColumnType.STRING;
+
+ /**
+ * 导出列头背景颜色
+ */
+ public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+ /**
+ * 导出列头字体颜色
+ */
+ public IndexedColors headerColor() default IndexedColors.WHITE;
+
+ /**
+ * 导出单元格背景颜色
+ */
+ public IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+ /**
+ * 导出单元格字体颜色
+ */
+ public IndexedColors color() default IndexedColors.BLACK;
+
+ /**
+ * 导出字段对齐方式
+ */
+ public HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+ /**
+ * 自定义数据处理器
+ */
+ public Class> handler() default ExcelHandlerAdapter.class;
+
+ /**
+ * 自定义数据处理器参数
+ */
+ public String[] args() default {};
+
+ /**
+ * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+ */
+ Type type() default Type.ALL;
+
+ public enum Type
+ {
+ ALL(0), EXPORT(1), IMPORT(2);
+ private final int value;
+
+ Type(int value)
+ {
+ this.value = value;
+ }
+
+ public int value()
+ {
+ return this.value;
+ }
+ }
+
+ public enum ColumnType
+ {
+ NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
+ private final int value;
+
+ ColumnType(int value)
+ {
+ this.value = value;
+ }
+
+ public int value()
+ {
+ return this.value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/ExceptionUtil.java b/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/ExceptionUtil.java
new file mode 100644
index 0000000..be38720
--- /dev/null
+++ b/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/ExceptionUtil.java
@@ -0,0 +1,39 @@
+package com.jing.common.core.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
+/**
+ * 错误信息处理类。
+ *
+ * @author ruoyi
+ */
+public class ExceptionUtil
+{
+ /**
+ * 获取exception的详细错误信息。
+ */
+ public static String getExceptionMessage(Throwable e)
+ {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw, true));
+ return sw.toString();
+ }
+
+ public static String getRootErrorMessage(Exception e)
+ {
+ Throwable root = ExceptionUtils.getRootCause(e);
+ root = (root == null ? e : root);
+ if (root == null)
+ {
+ return "";
+ }
+ String msg = root.getMessage();
+ if (msg == null)
+ {
+ return "null";
+ }
+ return StringUtils.defaultString(msg);
+ }
+}
diff --git a/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/html/EscapeUtil.java b/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/html/EscapeUtil.java
new file mode 100644
index 0000000..94f9b0b
--- /dev/null
+++ b/jing-common/jing-common-core/src/main/java/com/jing/common/core/utils/html/EscapeUtil.java
@@ -0,0 +1,167 @@
+package com.jing.common.core.utils.html;
+
+import com.jing.common.core.utils.StringUtils;
+
+/**
+ * 转义和反转义工具类
+ *
+ * @author ruoyi
+ */
+public class EscapeUtil
+{
+ public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
+
+ private static final char[][] TEXT = new char[64][];
+
+ static
+ {
+ for (int i = 0; i < 64; i++)
+ {
+ TEXT[i] = new char[] { (char) i };
+ }
+
+ // special HTML characters
+ TEXT['\''] = "'".toCharArray(); // 单引号
+ TEXT['"'] = """.toCharArray(); // 双引号
+ TEXT['&'] = "&".toCharArray(); // &符
+ TEXT['<'] = "<".toCharArray(); // 小于号
+ TEXT['>'] = ">".toCharArray(); // 大于号
+ }
+
+ /**
+ * 转义文本中的HTML字符为安全的字符
+ *
+ * @param text 被转义的文本
+ * @return 转义后的文本
+ */
+ public static String escape(String text)
+ {
+ return encode(text);
+ }
+
+ /**
+ * 还原被转义的HTML特殊字符
+ *
+ * @param content 包含转义符的HTML内容
+ * @return 转换后的字符串
+ */
+ public static String unescape(String content)
+ {
+ return decode(content);
+ }
+
+ /**
+ * 清除所有HTML标签,但是不删除标签内的内容
+ *
+ * @param content 文本
+ * @return 清除标签后的文本
+ */
+ public static String clean(String content)
+ {
+ return new HTMLFilter().filter(content);
+ }
+
+ /**
+ * Escape编码
+ *
+ * @param text 被编码的文本
+ * @return 编码后的字符
+ */
+ private static String encode(String text)
+ {
+ if (StringUtils.isEmpty(text))
+ {
+ return StringUtils.EMPTY;
+ }
+
+ final StringBuilder tmp = new StringBuilder(text.length() * 6);
+ char c;
+ for (int i = 0; i < text.length(); i++)
+ {
+ c = text.charAt(i);
+ if (c < 256)
+ {
+ tmp.append("%");
+ if (c < 16)
+ {
+ tmp.append("0");
+ }
+ tmp.append(Integer.toString(c, 16));
+ }
+ else
+ {
+ tmp.append("%u");
+ if (c <= 0xfff)
+ {
+ // issue#I49JU8@Gitee
+ tmp.append("0");
+ }
+ tmp.append(Integer.toString(c, 16));
+ }
+ }
+ return tmp.toString();
+ }
+
+ /**
+ * Escape解码
+ *
+ * @param content 被转义的内容
+ * @return 解码后的字符串
+ */
+ public static String decode(String content)
+ {
+ if (StringUtils.isEmpty(content))
+ {
+ return content;
+ }
+
+ StringBuilder tmp = new StringBuilder(content.length());
+ int lastPos = 0, pos = 0;
+ char ch;
+ while (lastPos < content.length())
+ {
+ pos = content.indexOf("%", lastPos);
+ if (pos == lastPos)
+ {
+ if (content.charAt(pos + 1) == 'u')
+ {
+ ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
+ tmp.append(ch);
+ lastPos = pos + 6;
+ }
+ else
+ {
+ ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
+ tmp.append(ch);
+ lastPos = pos + 3;
+ }
+ }
+ else
+ {
+ if (pos == -1)
+ {
+ tmp.append(content.substring(lastPos));
+ lastPos = content.length();
+ }
+ else
+ {
+ tmp.append(content.substring(lastPos, pos));
+ lastPos = pos;
+ }
+ }
+ }
+ return tmp.toString();
+ }
+
+ public static void main(String[] args)
+ {
+ String html = "";
+ String escape = EscapeUtil.escape(html);
+ // String html = "ipt>alert(\"XSS\")ipt>";
+ // String html = "<123";
+ // String html = "123>";
+ System.out.println("clean: " + EscapeUtil.clean(html));
+ System.out.println("escape: " + escape);
+ System.out.println("unescape: " + EscapeUtil.unescape(escape));
+ }
+}
diff --git a/jing-common/jing-common-security/src/main/java/com/jing/common/security/feign/FeignAutoConfiguration.java b/jing-common/jing-common-security/src/main/java/com/jing/common/security/feign/FeignAutoConfiguration.java
new file mode 100644
index 0000000..e5c9b8e
--- /dev/null
+++ b/jing-common/jing-common-security/src/main/java/com/jing/common/security/feign/FeignAutoConfiguration.java
@@ -0,0 +1,20 @@
+package com.jing.common.security.feign;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import feign.RequestInterceptor;
+
+/**
+ * Feign 配置注册
+ *
+ * @author ruoyi
+ **/
+@Configuration
+public class FeignAutoConfiguration
+{
+ @Bean
+ public RequestInterceptor requestInterceptor()
+ {
+ return new FeignRequestInterceptor();
+ }
+}
diff --git a/jing-common/jing-common-security/src/main/java/com/jing/common/security/feign/FeignRequestInterceptor.java b/jing-common/jing-common-security/src/main/java/com/jing/common/security/feign/FeignRequestInterceptor.java
new file mode 100644
index 0000000..5d7a08d
--- /dev/null
+++ b/jing-common/jing-common-security/src/main/java/com/jing/common/security/feign/FeignRequestInterceptor.java
@@ -0,0 +1,54 @@
+package com.jing.common.security.feign;
+
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import com.jing.common.core.constant.SecurityConstants;
+import com.jing.common.core.utils.ServletUtils;
+import com.jing.common.core.utils.StringUtils;
+import com.jing.common.core.utils.ip.IpUtils;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+
+/**
+ * feign 请求拦截器
+ *
+ * @author ruoyi
+ */
+@Component
+public class FeignRequestInterceptor implements RequestInterceptor
+{
+ @Override
+ public void apply(RequestTemplate requestTemplate)
+ {
+ HttpServletRequest httpServletRequest = ServletUtils.getRequest();
+ if (StringUtils.isNotNull(httpServletRequest))
+ {
+ Map headers = ServletUtils.getHeaders(httpServletRequest);
+ // 传递用户信息请求头,防止丢失
+ String userId = headers.get(SecurityConstants.DETAILS_USER_ID);
+ if (StringUtils.isNotEmpty(userId))
+ {
+ requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);
+ }
+ String userKey = headers.get(SecurityConstants.USER_KEY);
+ if (StringUtils.isNotEmpty(userKey))
+ {
+ requestTemplate.header(SecurityConstants.USER_KEY, userKey);
+ }
+ String userName = headers.get(SecurityConstants.DETAILS_USERNAME);
+ if (StringUtils.isNotEmpty(userName))
+ {
+ requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);
+ }
+ String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);
+ if (StringUtils.isNotEmpty(authentication))
+ {
+ requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);
+ }
+
+ // 配置客户端IP
+ requestTemplate.header("X-Forwarded-For", IpUtils.getIpAddr());
+ }
+ }
+}
\ No newline at end of file
diff --git a/jing-modules/jing-file/src/main/java/com/jing/file/service/FastDfsSysFileServiceImpl.java b/jing-modules/jing-file/src/main/java/com/jing/file/service/FastDfsSysFileServiceImpl.java
new file mode 100644
index 0000000..eab196d
--- /dev/null
+++ b/jing-modules/jing-file/src/main/java/com/jing/file/service/FastDfsSysFileServiceImpl.java
@@ -0,0 +1,46 @@
+package com.jing.file.service;
+
+import java.io.InputStream;
+import com.alibaba.nacos.common.utils.IoUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import com.github.tobato.fastdfs.domain.fdfs.StorePath;
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
+import com.jing.common.core.utils.file.FileTypeUtils;
+
+/**
+ * FastDFS 文件存储
+ *
+ * @author ruoyi
+ */
+@Service
+public class FastDfsSysFileServiceImpl implements ISysFileService
+{
+ /**
+ * 域名或本机访问地址
+ */
+ @Value("${fdfs.domain}")
+ public String domain;
+
+ @Autowired
+ private FastFileStorageClient storageClient;
+
+ /**
+ * FastDfs文件上传接口
+ *
+ * @param file 上传的文件
+ * @return 访问地址
+ * @throws Exception
+ */
+ @Override
+ public String uploadFile(MultipartFile file) throws Exception
+ {
+ InputStream inputStream = file.getInputStream();
+ StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(),
+ FileTypeUtils.getExtension(file), null);
+ IoUtils.closeQuietly(inputStream);
+ return domain + "/" + storePath.getFullPath();
+ }
+}
diff --git a/jing-ui/src/assets/icons/svg/example.svg b/jing-ui/src/assets/icons/svg/example.svg
new file mode 100644
index 0000000..46f42b5
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/example.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/assets/icons/svg/exit-fullscreen.svg b/jing-ui/src/assets/icons/svg/exit-fullscreen.svg
new file mode 100644
index 0000000..485c128
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/exit-fullscreen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/assets/icons/svg/eye-open.svg b/jing-ui/src/assets/icons/svg/eye-open.svg
new file mode 100644
index 0000000..88dcc98
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/eye-open.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/assets/icons/svg/eye.svg b/jing-ui/src/assets/icons/svg/eye.svg
new file mode 100644
index 0000000..16ed2d8
--- /dev/null
+++ b/jing-ui/src/assets/icons/svg/eye.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/jing-ui/src/utils/errorCode.js b/jing-ui/src/utils/errorCode.js
new file mode 100644
index 0000000..d2111ee
--- /dev/null
+++ b/jing-ui/src/utils/errorCode.js
@@ -0,0 +1,6 @@
+export default {
+ '401': '认证失败,无法访问系统资源',
+ '403': '当前操作没有权限',
+ '404': '访问资源不存在',
+ 'default': '系统未知错误,请反馈给管理员'
+}