67 Commits
v3.1 ... v3.2

Author SHA1 Message Date
d872c66d19 若依3.2 2019-01-16 23:14:37 +08:00
1042b40cfc !65 代码生成包名修改
Merge pull request !65 from yutel/master
2019-01-16 18:08:19 +08:00
070f7bc6bd 更新 Controller.java.vm
解决代码生成时找不到ExcelUtil.java类的问题
2019-01-16 18:02:16 +08:00
4f1c99293f pom 3.2 2019-01-16 15:28:32 +08:00
57fa243747 若依3.2 2019-01-16 14:56:27 +08:00
04f2607398 !64 去掉注释中多余参数说明
Merge pull request !64 from GeBron/master
2019-01-16 13:24:46 +08:00
01caa02f5e 去掉注释中多余参数说明 2019-01-16 12:58:21 +08:00
e37ec9f8fa 用户管理移动端默认隐藏左侧布局 2019-01-13 12:26:09 +08:00
122e8b61a0 详细信息弹出层显示在顶层 2019-01-12 12:08:41 +08:00
2345dfdf42 调整初始密码位置 2019-01-11 10:34:34 +08:00
77550e2f11 用户导入初始密码 2019-01-11 10:14:31 +08:00
ca5b4bc852 用户导入 2019-01-11 09:50:16 +08:00
5fc9a63231 新增用户导入权限 2019-01-10 19:51:31 +08:00
958be505c9 !62 修改样式文件小BUG及改用接口ISysUserOnlineService
Merge pull request !62 from ziry/master
2019-01-10 19:09:55 +08:00
ec8c7f1d79 支持用户数据导入 2019-01-10 19:06:15 +08:00
030b61bc37 修改样式文件小BUG 2019-01-10 15:50:43 +08:00
619e1d241a 升级summernote到最新版本v0.8.11 2019-01-09 16:22:45 +08:00
dc07b97cdb 字典数据根据选择下拉新增 2019-01-08 19:30:24 +08:00
dd37524b04 修复个人信息修改漏洞 2019-01-08 15:56:49 +08:00
8c0ebd008e 更新 SysUserOnlineController.java ,改用接口ISysUserOnlineService 2019-01-08 15:42:08 +08:00
0c76d45349 新增修改全屏/确认取消按钮 2019-01-04 11:37:35 +08:00
6237ddb3dc !60 SysJobMapper.deleteJobById改为通过ID删除及修改注释与方法参数对应
Merge pull request !60 from ziry/master
2018-12-29 17:47:01 +08:00
8643dde074 改为通过ID删除 2018-12-29 16:32:17 +08:00
d22fa29b65 修改注释与方法参数对应 2018-12-29 16:28:54 +08:00
b66097c004 更新 banner.txt
修复启动佛祖保佑图小瑕疵
2018-12-29 15:25:32 +08:00
d30dc35e59 代码格式化 2018-12-29 15:18:28 +08:00
87c38706cd Merge branch 'master' of https://gitee.com/y_project/RuoYi 2018-12-29 15:05:53 +08:00
f04c1fed50 线程池代码优化 2018-12-29 15:05:29 +08:00
4474c533e6 !59 修复驼峰转下划线拼接时,简称缩写作为前缀时,转换后首字母后追加了下划线,同时做了代码优化,利于阅读
Merge pull request !59 from xjt283525476/master
2018-12-29 14:25:47 +08:00
4374a24f79 修复驼峰转下划线拼接时,简称缩写作为前缀时,转换后首字母后追加了下划线 2018-12-29 14:04:16 +08:00
383d082194 类位置迁移 2018-12-29 12:25:46 +08:00
e9a7cc7bc7 去除序号居中 2018-12-29 12:04:53 +08:00
8b07f8925f !57 因笔误导致无意义的判断,同时还会出现空指针异常
Merge pull request !57 from xjt283525476/master
2018-12-29 10:21:58 +08:00
2af817d8dc !58 解决tomcat无法退出问题
Merge pull request !58 from j3east/j3east
2018-12-29 10:21:17 +08:00
cj
0e240cb244 代码风格和项目保持一致 2018-12-28 23:05:53 +08:00
cj
fc834b35cb 一键打war包 2018-12-28 22:55:31 +08:00
cj
4fa795dee9 确保应用退出时能关闭后台线程 2018-12-28 22:54:38 +08:00
33788ecd02 ry-ui新增序列号生成方法 2018-12-28 17:33:15 +08:00
3d3017804d Excel注解支持多级获取 2018-12-28 16:15:56 +08:00
63ee2ba2e7 修复会出现空指针异常 2018-12-28 14:23:23 +08:00
aac46aa353 修复明显笔误 2018-12-27 19:41:56 +08:00
c6e4daedd4 摸版edit缺少; 2018-12-27 11:43:16 +08:00
6b9b8ed889 !56 修改注释中的参数名称
Merge pull request !56 from GeBron/master
2018-12-25 23:29:09 +08:00
1f000d9f84 Merge branch 'master' of https://gitee.com/y_project/RuoYi 2018-12-25 23:26:52 +08:00
9d5a702e1f 新增方法$.operate.get(url) 2018-12-25 23:24:38 +08:00
bb1831f609 修改注释中的参数名称 2018-12-25 20:35:18 +08:00
c628cf7ee7 去掉多余; 2018-12-25 17:16:27 +08:00
1de73da333 会话检查优化 2018-12-25 11:56:16 +08:00
c404de1773 reset 2018-12-20 19:41:56 +08:00
cfcd48b6b2 取消配置文件配置从数据源,改为直接从数据库中直接读取 2018-12-20 14:24:02 +08:00
a87e1d019d 修正getSubject命名 2018-12-19 18:10:44 +08:00
ef91e71d7b 修正登录必填项位置偏移 2018-12-19 14:58:06 +08:00
3bacfc5951 !55 模板
Merge pull request !55 from zhangmrit/ruoyi
2018-12-19 14:54:18 +08:00
b5cd54da66 时区 2018-12-19 14:51:08 +08:00
0e9925a481 mysql时区和模板修复 2018-12-19 13:55:27 +08:00
7943b765ca 升级MYSQL驱动 2018-12-18 18:16:29 +08:00
a74e58f7d5 升级SpringBoot到最新版本2.1.1 2018-12-17 22:32:37 +08:00
ea58f8db9c 添加群号 2018-12-14 17:25:04 +08:00
89e21eecea 验证码配置补齐注释 2018-12-14 12:43:31 +08:00
35df1dbcdf 验证码文本字符间距修正 2018-12-14 12:30:33 +08:00
0972bba763 Merge branch 'master' of https://gitee.com/y_project/RuoYi 2018-12-12 13:26:16 +08:00
583b06ca9a 登录界面去除iCheck插件改为自定义css(提升响应速度及部分背景图不适应) 2018-12-12 13:26:01 +08:00
6a4b1898b1 Merge branch 'master' of https://gitee.com/y_project/RuoYi 2018-12-08 23:11:16 +08:00
268f0a6321 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴
(2核8G云服务器5M带宽)
2018-12-08 23:11:02 +08:00
e56a7e7e57 磁盘(光驱)验证除数不为零 2018-12-06 11:44:20 +08:00
9d225fecb9 修正部门菜单排序字段无效 2018-12-03 20:47:33 +08:00
d24481f9a5 部门修改不允许最后层级节点选择 2018-12-01 18:39:54 +08:00
127 changed files with 11279 additions and 15426 deletions

View File

@ -2,13 +2,13 @@
一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA。所有前端后台代码封装过后十分精简易上手出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
寓意:你若不离不弃,我必生死相依
性别男,若依是给还没有出生女儿取的名字(寓意:你若不离不弃,我必生死相依
若依基于hplus和inspinia两套后台系统模板开发。有需要可自行到群内下载。
> RuoYi从3.0开始,进行模块拆分,将原先的单应用转变为多模块,如需单应用,请移步 [RuoYi-fast](https://gitee.com/y_project/RuoYi-fast)
> 推荐使用阿里云部署,通用云产品代金券 [点我领取](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof)
> 推荐使用阿里云部署,通用云产品代金券 [点我领取](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof)
## 内置功能
@ -26,10 +26,12 @@
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
13. 代码生成前后端代码的生成java、html、xml、sql)支持CRUD下载 。
14. 系统接口根据业务代码自动生成相关的api接口文档。
15. 在线构建器拖动表单元素生成相应的HTML代码
16. 连接池监视监视当期系统数据库连接池状态可进行分析SQL找出系统性能瓶颈
15. 服务监控监视当前系统CPU、内存、磁盘、堆栈等相关信息
16. 在线构建器拖动表单元素生成相应的HTML代码
17. 连接池监视监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。
## 在线体验
> admin/admin123
> admin/admin123
> 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
演示地址http://ruoyi.vip
@ -40,31 +42,31 @@
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/25b5e333768d013d45a990c152dbe4d9d6e.jpg"/></td>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194326_GBIJ_1438828.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/dfadf4d864242745486aa0167110dfcbeb8.jpg"/></td>
</tr>
<tr>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194443_Qyuq_1438828.png"/></td>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194501_U7gT_1438828.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/2e1ed87df9b476ed73ed650df20cf009b78.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/91bef110740ba9e36ff00804f8748a787fb.jpg"/></td>
</tr>
<tr>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194525_PApp_1438828.png"/></td>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194535_3EM0_1438828.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/9a2851988f4e7433c9322154534865f57d7.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/396293f80b1e8cce8671f56c296bee78a3a.jpg"/></td>
</tr>
<tr>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194612_kJ4F_1438828.png"/></td>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194623_YEXO_1438828.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/787b3b06430a403655b48b9bcd1fa829555.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/a51820009836276b778bc89d4d0e217e26d.jpg"/></td>
</tr>
<tr>
<td><img src="https://static.oschina.net/uploads/space/2018/0902/132548_ne4U_1438828.png"/></td>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194643_MsxF_1438828.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/5fb138478adeda6825e206d21f67ecd0625.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/fa2f027a10707a4eb4fc47d5ea1c3d2b772.jpg"/></td>
</tr>
<tr>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194658_40L4_1438828.png"/></td>
<td><img src="https://static.oschina.net/uploads/space/2018/1005/194712_2ma3_1438828.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/a714056081523b7dfa782cda866e8be4adc.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/ab4b5797dfb2bc68c4974ad5458bd5f5bcf.jpg"/></td>
</tr>
</table>
## 若依交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/QQ群-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) 点击按钮入群。
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/QQ群-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) 点击按钮入群。

View File

@ -6,14 +6,14 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.1</version>
<version>3.2</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依管理系统</description>
<properties>
<ruoyi.version>3.1</ruoyi.version>
<ruoyi.version>3.2</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
@ -33,7 +33,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.0.5.RELEASE</version>
<version>2.1.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.1</version>
<version>3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>

View File

@ -6,10 +6,17 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.config.Global;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
import com.ruoyi.framework.util.FileUploadUtils;
/**
* 通用请求处理
@ -21,7 +28,21 @@ public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@RequestMapping("common/download")
/**
* 文件上传路径
*/
public static final String UPLOAD_PATH = "/profile/upload/";
@Autowired
private ServerConfig serverConfig;
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@GetMapping("common/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
@ -31,7 +52,8 @@ public class CommonController
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
response.setHeader("Content-Disposition", "attachment;fileName=" + setFileDownloadHeader(request, realFileName));
response.setHeader("Content-Disposition",
"attachment;fileName=" + setFileDownloadHeader(request, realFileName));
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
@ -44,6 +66,31 @@ public class CommonController
}
}
/**
* 通用上传请求
*/
@PostMapping("/common/upload")
@ResponseBody
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径
String filePath = Global.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + UPLOAD_PATH + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", fileName);
ajax.put("url", url);
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
public String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
{
final String agent = request.getHeader("USER-AGENT");

View File

@ -13,9 +13,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.quartz.domain.SysJob;
import com.ruoyi.quartz.service.ISysJobService;
import com.ruoyi.framework.web.base.BaseController;
@ -59,7 +59,7 @@ public class SysJobController extends BaseController
{
List<SysJob> list = jobService.selectJobList(job);
ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
return util.exportExcel(list, "job");
return util.exportExcel(list, "定时任务");
}
@Log(title = "定时任务", businessType = BusinessType.DELETE)

View File

@ -13,9 +13,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.base.BaseController;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.quartz.domain.SysJobLog;
import com.ruoyi.quartz.service.ISysJobLogService;
@ -58,7 +58,7 @@ public class SysJobLogController extends BaseController
{
List<SysJobLog> list = jobLogService.selectJobLogList(jobLog);
ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
return util.exportExcel(list, "jobLog");
return util.exportExcel(list, "调度日志");
}
@Log(title = "调度日志", businessType = BusinessType.DELETE)

View File

@ -11,8 +11,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.SysLogininfor;
import com.ruoyi.system.service.ISysLogininforService;
import com.ruoyi.framework.web.base.BaseController;
@ -56,7 +56,7 @@ public class SysLogininforController extends BaseController
{
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
return util.exportExcel(list, "logininfor");
return util.exportExcel(list, "登陆日志");
}
@RequiresPermissions("monitor:logininfor:remove")

View File

@ -13,8 +13,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.SysOperLog;
import com.ruoyi.system.service.ISysOperLogService;
import com.ruoyi.framework.web.base.BaseController;
@ -58,7 +58,7 @@ public class SysOperlogController extends BaseController
{
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
return util.exportExcel(list, "operLog");
return util.exportExcel(list, "操作日志");
}
@RequiresPermissions("monitor:operlog:remove")

View File

@ -13,12 +13,12 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.OnlineStatus;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.framework.shiro.session.OnlineSession;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.impl.SysUserOnlineServiceImpl;
import com.ruoyi.system.service.ISysUserOnlineService;
import com.ruoyi.framework.web.base.BaseController;
/**
@ -33,7 +33,7 @@ public class SysUserOnlineController extends BaseController
private String prefix = "monitor/online";
@Autowired
private SysUserOnlineServiceImpl userOnlineService;
private ISysUserOnlineService userOnlineService;
@Autowired
private OnlineSessionDAO onlineSessionDAO;

View File

@ -13,9 +13,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.framework.web.base.BaseController;
@ -62,7 +62,7 @@ public class SysConfigController extends BaseController
{
List<SysConfig> list = configService.selectConfigList(config);
ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
return util.exportExcel(list, "config");
return util.exportExcel(list, "参数数据");
}
/**

View File

@ -149,7 +149,7 @@ public class SysDeptController extends BaseController
@ResponseBody
public List<Map<String, Object>> treeData()
{
List<Map<String, Object>> tree = deptService.selectDeptTree();
List<Map<String, Object>> tree = deptService.selectDeptTree(new SysDept());
return tree;
}

View File

@ -13,9 +13,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysDictData;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.framework.web.base.BaseController;
@ -59,7 +59,7 @@ public class SysDictDataController extends BaseController
{
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
return util.exportExcel(list, "dictData");
return util.exportExcel(list, "字典数据");
}
/**

View File

@ -13,9 +13,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysDictType;
import com.ruoyi.system.service.ISysDictTypeService;
import com.ruoyi.framework.web.base.BaseController;
@ -60,7 +60,7 @@ public class SysDictTypeController extends BaseController
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
return util.exportExcel(list, "dictType");
return util.exportExcel(list, "字典类型");
}
/**

View File

@ -13,8 +13,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysNotice;
import com.ruoyi.system.service.ISysNoticeService;
import com.ruoyi.framework.web.base.BaseController;

View File

@ -13,9 +13,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.framework.web.base.BaseController;
@ -59,7 +59,7 @@ public class SysPostController extends BaseController
{
List<SysPost> list = postService.selectPostList(post);
ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
return util.exportExcel(list, "post");
return util.exportExcel(list, "岗位数据");
}
@RequiresPermissions("system:post:remove")

View File

@ -1,13 +1,11 @@
package com.ruoyi.web.controller.system;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -17,6 +15,7 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.config.Global;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.shiro.service.SysPasswordService;
import com.ruoyi.framework.util.FileUploadUtils;
import com.ruoyi.framework.util.ShiroUtils;
@ -66,54 +65,63 @@ public class SysProfileController extends BaseController
public boolean checkPassword(String password)
{
SysUser user = getSysUser();
String encrypt = new Md5Hash(user.getLoginName() + password + user.getSalt()).toHex().toString();
if (user.getPassword().equals(encrypt))
if (passwordService.matches(user, password))
{
return true;
}
return false;
}
@GetMapping("/resetPwd/{userId}")
public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap)
@GetMapping("/resetPwd")
public String resetPwd(ModelMap mmap)
{
mmap.put("user", userService.selectUserById(userId));
SysUser user = getSysUser();
mmap.put("user", userService.selectUserById(user.getUserId()));
return prefix + "/resetPwd";
}
@Log(title = "重置密码", businessType = BusinessType.UPDATE)
@PostMapping("/resetPwd")
@ResponseBody
public AjaxResult resetPwd(SysUser user)
public AjaxResult resetPwd(String oldPassword, String newPassword)
{
user.setSalt(ShiroUtils.randomSalt());
user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt()));
int rows = userService.resetUserPwd(user);
if (rows > 0)
SysUser user = getSysUser();
if (StringUtils.isNotEmpty(newPassword) && passwordService.matches(user, oldPassword))
{
setSysUser(userService.selectUserById(user.getUserId()));
return success();
user.setSalt(ShiroUtils.randomSalt());
user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
if (userService.resetUserPwd(user) > 0)
{
setSysUser(userService.selectUserById(user.getUserId()));
return success();
}
return error();
}
else
{
return error("修改密码失败,旧密码错误");
}
return error();
}
/**
* 修改用户
*/
@GetMapping("/edit/{userId}")
public String edit(@PathVariable("userId") Long userId, ModelMap mmap)
@GetMapping("/edit")
public String edit(ModelMap mmap)
{
mmap.put("user", userService.selectUserById(userId));
SysUser user = getSysUser();
mmap.put("user", userService.selectUserById(user.getUserId()));
return prefix + "/edit";
}
/**
* 修改头像
*/
@GetMapping("/avatar/{userId}")
public String avatar(@PathVariable("userId") Long userId, ModelMap mmap)
@GetMapping("/avatar")
public String avatar(ModelMap mmap)
{
mmap.put("user", userService.selectUserById(userId));
SysUser user = getSysUser();
mmap.put("user", userService.selectUserById(user.getUserId()));
return prefix + "/avatar";
}
@ -125,9 +133,14 @@ public class SysProfileController extends BaseController
@ResponseBody
public AjaxResult update(SysUser user)
{
if (userService.updateUserInfo(user) > 0)
SysUser currentUser = getSysUser();
currentUser.setUserName(user.getUserName());
currentUser.setEmail(user.getEmail());
currentUser.setPhonenumber(user.getPhonenumber());
currentUser.setSex(user.getSex());
if (userService.updateUserInfo(currentUser) > 0)
{
setSysUser(userService.selectUserById(user.getUserId()));
setSysUser(userService.selectUserById(currentUser.getUserId()));
return success();
}
return error();
@ -139,17 +152,18 @@ public class SysProfileController extends BaseController
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PostMapping("/updateAvatar")
@ResponseBody
public AjaxResult updateAvatar(SysUser user, @RequestParam("avatarfile") MultipartFile file)
public AjaxResult updateAvatar(@RequestParam("avatarfile") MultipartFile file)
{
SysUser currentUser = getSysUser();
try
{
if (!file.isEmpty())
{
String avatar = FileUploadUtils.upload(Global.getAvatarPath(), file);
user.setAvatar(avatar);
if (userService.updateUserInfo(user) > 0)
currentUser.setAvatar(avatar);
if (userService.updateUserInfo(currentUser) > 0)
{
setSysUser(userService.selectUserById(user.getUserId()));
setSysUser(userService.selectUserById(currentUser.getUserId()));
return success();
}
}

View File

@ -14,9 +14,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.system.domain.SysRole;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.framework.web.base.BaseController;
@ -60,7 +60,7 @@ public class SysRoleController extends BaseController
{
List<SysRole> list = roleService.selectRoleList(role);
ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
return util.exportExcel(list, "role");
return util.exportExcel(list, "角色数据");
}
/**
@ -181,4 +181,16 @@ public class SysRoleController extends BaseController
{
return prefix + "/tree";
}
/**
* 角色状态修改
*/
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@RequiresPermissions("system:role:edit")
@PostMapping("/changeStatus")
@ResponseBody
public AjaxResult changeStatus(SysRole role)
{
return toAjax(roleService.changeStatus(role));
}
}

View File

@ -11,19 +11,20 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.ExcelUtil;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.shiro.service.SysPasswordService;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.framework.web.base.BaseController;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.framework.web.base.BaseController;
/**
* 用户信息
@ -73,7 +74,29 @@ public class SysUserController extends BaseController
{
List<SysUser> list = userService.selectUserList(user);
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
return util.exportExcel(list, "user");
return util.exportExcel(list, "用户数据");
}
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
@RequiresPermissions("system:user:import")
@PostMapping("/importData")
@ResponseBody
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
{
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
List<SysUser> userList = util.importExcel(file.getInputStream());
String operName = getSysUser().getLoginName();
String message = userService.importUser(userList, updateSupport, operName);
return AjaxResult.success(message);
}
@RequiresPermissions("system:user:view")
@GetMapping("/importTemplate")
@ResponseBody
public AjaxResult importTemplate()
{
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
return util.importTemplateExcel("用户数据");
}
/**
@ -202,4 +225,16 @@ public class SysUserController extends BaseController
{
return userService.checkEmailUnique(user);
}
/**
* 用户状态修改
*/
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@RequiresPermissions("system:user:edit")
@PostMapping("/changeStatus")
@ResponseBody
public AjaxResult changeStatus(SysUser user)
{
return toAjax(userService.changeStatus(user));
}
}

View File

@ -14,8 +14,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.support.Convert;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.generator.domain.TableInfo;
import com.ruoyi.generator.service.IGenService;
import com.ruoyi.framework.web.base.BaseController;

View File

@ -2,11 +2,11 @@
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true
url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: password
# 从库数据源
@ -17,32 +17,33 @@ spring:
username:
password:
# 初始连接数
initial-size: 10
# 最大连接池数量
max-active: 100
initialSize: 5
# 最小连接池数量
min-idle: 10
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
max-wait: 60000
# 打开PSCache并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1 FROM DUAL
test-while-idle: true
test-on-borrow: false
test-on-return: false
stat-view-servlet:
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
statViewServlet:
enabled: true
url-pattern: /monitor/druid/*
filter:
stat:
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
merge-sql: true
wall:
config:
multi-statement-allow: true

View File

@ -3,9 +3,9 @@ ruoyi:
# 名称
name: RuoYi
# 版本
version: 3.1.0
version: 3.2.0
# 版权年份
copyrightYear: 2018
copyrightYear: 2019
# 文件上传路径
profile: D:/profile/
# 获取ip地址开关

View File

@ -20,5 +20,5 @@ Spring Boot Version: ${spring-boot.version}
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="ruoyi">
<ehcache name="ruoyi" updateCheck="false">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir"/>

View File

@ -6,8 +6,8 @@ user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次帐户锁定10分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,原因:{0}
role.blocked=角色已封禁,原因:{0}
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间

View File

@ -1,44 +1,35 @@
/**
* @author: Dennis Hernández
* @webSite: http://djhvscf.github.io/Blog
* @version: v1.1.0
* 基于bootstrap-table-mobile修改
* 修正部分iPhone手机不显示卡片视图
* Copyright (c) 2019 ruoyi
*/
!function ($) {
'use strict';
var showHideColumns = function (that, checked) {
if (that.options.columnsHidden.length > 0 ) {
$.each(that.columns, function (i, column) {
if (that.options.columnsHidden.indexOf(column.field) !== -1) {
if (column.visible !== checked) {
that.toggleColumn($.fn.bootstrapTable.utils.getFieldIndex(that.columns, column.field), checked, true);
}
}
});
}
};
var resetView = function (that) {
if (that.options.height || that.options.showFooter) {
setTimeout(function(){
that.resetView.call(that);
}, 1);
setTimeout(that.resetView(), 1);
}
};
// 判断是否 iphone
var isIPhone = function () {
let browserName = navigator.userAgent.toLowerCase();
return /(iphone)/i.test(browserName);
};
var changeView = function (that, width, height) {
if (that.options.minHeight) {
if ((width <= that.options.minWidth) && (height <= that.options.minHeight)) {
if (checkValuesLessEqual(width, that.options.minWidth) && checkValuesLessEqual(height, that.options.minHeight)) {
conditionCardView(that);
} else if ((width > that.options.minWidth) && (height > that.options.minHeight)) {
} else if (checkValuesGreater(width, that.options.minWidth) && checkValuesGreater(height, that.options.minHeight)) {
conditionFullView(that);
}
} else {
if (width <= that.options.minWidth) {
if (checkValuesLessEqual(width, that.options.minWidth) || isIPhone()) {
conditionCardView(that);
} else if (width > that.options.minWidth) {
} else if (checkValuesGreater(width, that.options.minWidth)) {
conditionFullView(that);
}
}
@ -46,14 +37,20 @@
resetView(that);
};
var checkValuesLessEqual = function (currentValue, targetValue) {
return currentValue <= targetValue;
};
var checkValuesGreater = function (currentValue, targetValue) {
return currentValue > targetValue;
};
var conditionCardView = function (that) {
changeTableView(that, false);
showHideColumns(that, false);
};
var conditionFullView = function (that) {
changeTableView(that, true);
showHideColumns(that, true);
};
var changeTableView = function (that, cardViewState) {
@ -61,27 +58,12 @@
that.toggleView();
};
var debounce = function(func,wait) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
func.apply(context,args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};
$.extend($.fn.bootstrapTable.defaults, {
mobileResponsive: false,
minWidth: 562,
minHeight: undefined,
heightThreshold: 100, // just slightly larger than mobile chrome's auto-hiding toolbar
checkOnInit: true,
columnsHidden: []
toggled: false
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
@ -98,39 +80,13 @@
return;
}
if (this.options.minWidth < 100 && this.options.resizable) {
console.log("The minWidth when the resizable extension is active should be greater or equal than 100");
this.options.minWidth = 100;
}
var that = this,
old = {
width: $(window).width(),
height: $(window).height()
};
$(window).on('resize orientationchange',debounce(function (evt) {
// reset view if height has only changed by at least the threshold.
var height = $(this).height(),
width = $(this).width();
if (Math.abs(old.height - height) > that.options.heightThreshold || old.width != width) {
changeView(that, width, height);
old = {
width: width,
height: height
};
}
},200));
var that = this;
$(window).resize(function () {
changeView(that, $(this).width(), $(this).height())
});
if (this.options.checkOnInit) {
var height = $(window).height(),
width = $(window).width();
changeView(this, width, height);
old = {
width: width,
height: height
};
changeView(this, $(window).width(), $(window).height());
}
};
}(jQuery);

View File

@ -1,7 +0,0 @@
/*
* bootstrap-table - v1.11.0 - 2016-07-02
* https://github.com/wenzhixin/bootstrap-table
* Copyright (c) 2016 zhixin wen
* Licensed MIT License
*/
!function(a){"use strict";var b=function(b,c){b.options.columnsHidden.length>0&&a.each(b.columns,function(d,e){-1!==b.options.columnsHidden.indexOf(e.field)&&e.visible!==c&&b.toggleColumn(a.fn.bootstrapTable.utils.getFieldIndex(b.columns,e.field),c,!0)})},c=function(a){(a.options.height||a.options.showFooter)&&setTimeout(function(){a.resetView.call(a)},1)},d=function(a,b,d){a.options.minHeight?b<=a.options.minWidth&&d<=a.options.minHeight?e(a):b>a.options.minWidth&&d>a.options.minHeight&&f(a):b<=a.options.minWidth?e(a):b>a.options.minWidth&&f(a),c(a)},e=function(a){g(a,!1),b(a,!1)},f=function(a){g(a,!0),b(a,!0)},g=function(a,b){a.options.cardView=b,a.toggleView()},h=function(a,b){var c;return function(){var d=this,e=arguments,f=function(){c=null,a.apply(d,e)};clearTimeout(c),c=setTimeout(f,b)}};a.extend(a.fn.bootstrapTable.defaults,{mobileResponsive:!1,minWidth:562,minHeight:void 0,heightThreshold:100,checkOnInit:!0,columnsHidden:[]});var i=a.fn.bootstrapTable.Constructor,j=i.prototype.init;i.prototype.init=function(){if(j.apply(this,Array.prototype.slice.apply(arguments)),this.options.mobileResponsive&&this.options.minWidth){this.options.minWidth<100&&this.options.resizable&&(console.log("The minWidth when the resizable extension is active should be greater or equal than 100"),this.options.minWidth=100);var b=this,c={width:a(window).width(),height:a(window).height()};if(a(window).on("resize orientationchange",h(function(){var e=a(this).height(),f=a(this).width();(Math.abs(c.height-e)>b.options.heightThreshold||c.width!=f)&&(d(b,f,e),c={width:f,height:e})},200)),this.options.checkOnInit){var e=a(window).height(),f=a(window).width();d(this,f,e),c={width:f,height:e}}}}}(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,138 @@
/**
* layer皮肤
* Copyright (c) 2019 ruoyi
*/
html #layui_layer_skinmoonstylecss {
display: none;
position: absolute;
width: 1989px;
}
body .layer-ext-moon[type="dialog"] {
min-width: 320px;
}
body .layer-ext-moon-msg[type="dialog"]{min-width:200px;}
body .layer-ext-moon .layui-layer-title {
background: #F8F8F8;
color: #333;
font-size: 14px;
height: 42px;
line-height: 42px;
border-bottom: 1px solid #eee;
}
body .layer-ext-moon .layui-layer-content .layui-layer-ico {
height: 32px;
width: 32px;
top:18.5px;
}
body .layer-ext-moon .layui-layer-ico0 {
background: url(default.png) no-repeat -96px 0;
;
}
body .layer-ext-moon .layui-layer-ico1 {
background: url(default.png) no-repeat -224px 0;
;
}
body .layer-ext-moon .layui-layer-ico2 {
background: url(default.png) no-repeat -192px 0;
}
body .layer-ext-moon .layui-layer-ico3 {
background: url(default.png) no-repeat -160px 0;
}
body .layer-ext-moon .layui-layer-ico4 {
background: url(default.png) no-repeat -320px 0;
}
body .layer-ext-moon .layui-layer-ico5 {
background: url(default.png) no-repeat -288px 0;
}
body .layer-ext-moon .layui-layer-ico6 {
background: url(default.png) -256px 0;
}
body .layer-ext-moon .layui-layer-ico7 {
background: url(default.png) no-repeat -128px 0;
}
body .layer-ext-moon .layui-layer-setwin {
top: 15px;
right: 15px;
}
body .layer-ext-moon .layui-layer-setwin a {
width: 16px;
height: 16px;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-min cite:hover {
background-color: #56abe4;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-max {
background: url(default.png) no-repeat -80px 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-max:hover {
background: url(default.png) no-repeat -64px 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-maxmin {
background: url(default.png) no-repeat -32px 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-maxmin:hover {
background: url(default.png) no-repeat -16px 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-close1,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2 {
background: url(default.png) 0 0;
}
body .layer-ext-moon .layui-layer-setwin .layui-layer-close1:hover,body .layer-ext-moon .layui-layer-setwin .layui-layer-close2:hover {
background: url(default.png) -48px 0;
}
body .layer-ext-moon .layui-layer-padding{padding-top: 24px;}
body .layer-ext-moon .layui-layer-btn {
text-align: right;
padding: 10px 15px 12px;
background: #f0f4f7;
border-top: 1px #c7c7c7 solid;
}
body .layer-ext-moon .layui-layer-btn a {
font-size: 12px;
font-weight: normal;
margin: 0 3px;
margin-right: 7px;
margin-left: 7px;
padding: 0 15px;
color: #fff;
border: 1px solid #0064b6;
background: #0071ce;
border-radius: 3px;
display: inline-block;
height: 30px;
line-height: 30px;
text-align: center;
vertical-align: middle;
background-repeat: no-repeat;
text-decoration: none;
outline: none;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
body .layer-ext-moon .layui-layer-btn .layui-layer-btn0 {
background: #0071ce;
}
body .layer-ext-moon .layui-layer-btn .layui-layer-btn1 {
background: #fff;
color: #404a58;
border: 1px solid #c0c4cd;
border-radius: 3px;
}
body .layer-ext-moon .layui-layer-btn .layui-layer-btn2 {
background: #f60;
color: #fff;
border: 1px solid #f60;
border-radius: 3px;
}
body .layer-ext-moon .layui-layer-btn .layui-layer-btn3 {
background: #f00;
color: #fff;
border: 1px solid #f00;
border-radius: 3px;
}
body .layer-ext-moon .layui-layer-title span.layui-layer-tabnow{
height:47px;
}

File diff suppressed because one or more lines are too long

View File

@ -1,28 +1,46 @@
(function ($) {
(function($) {
$.extend($.summernote.lang, {
'zh-CN': {
font: {
bold: '粗体',
italic: '斜体',
underline: '下划线',
strikethrough: '删除线',
clear: '清除格式',
height: '行高',
name: '字体',
strikethrough: '删除线',
subscript: '下标',
superscript: '上标',
size: '字号'
},
image: {
image: '图片',
insert: '插入图片',
resizeFull: '调整至 100%',
resizeHalf: '调整至 50%',
resizeQuarter: '调整至 25%',
floatLeft: '左浮动',
floatRight: '右浮动',
floatNone: '浮动',
dragImageHere: '将图片拖至此处',
resizeFull: '缩放至 100%',
resizeHalf: '缩放至 50%',
resizeQuarter: '缩放至 25%',
floatLeft: '左浮动',
floatRight: '右浮动',
floatNone: '取消浮动',
shapeRounded: '形状: 圆角',
shapeCircle: '形状: 圆',
shapeThumbnail: '形状: 缩略图',
shapeNone: '形状: 无',
dragImageHere: '将图片拖拽至此处',
dropImage: '拖拽图片或文本',
selectFromFiles: '从本地上传',
url: '图片地址'
maximumFileSize: '文件大小最大值',
maximumFileSizeError: '文件大小超出最大值。',
url: '图片地址',
remove: '移除图片',
original: '原始图片'
},
video: {
video: '视频',
videoLink: '视频链接',
insert: '插入视频',
url: '视频地址',
providers: '(优酷, 腾讯, Instagram, DailyMotion, Youtube等)'
},
link: {
link: '链接',
@ -33,22 +51,22 @@
url: '链接地址',
openInNewWindow: '在新窗口打开'
},
video: {
video: '视频',
videoLink: '视频链接',
insert: '插入视频',
url: '视频地址',
providers: '(优酷, Instagram, DailyMotion, Youtube等)'
},
table: {
table: '表格'
table: '表格',
addRowAbove: '在上方插入行',
addRowBelow: '在下方插入行',
addColLeft: '在左侧插入列',
addColRight: '在右侧插入列',
delRow: '删除行',
delCol: '删除列',
delTable: '删除表格'
},
hr: {
insert: '水平线'
},
style: {
style: '样式',
normal: '普通',
p: '普通',
blockquote: '引用',
pre: '代码',
h1: '标题 1',
@ -92,11 +110,45 @@
textFormatting: '文本格式',
action: '动作',
paragraphFormatting: '段落格式',
documentStyle: '文档样式'
documentStyle: '文档样式',
extraKeys: '额外按键'
},
help: {
insertParagraph: '插入段落',
undo: '撤销',
redo: '重做',
tab: '增加缩进',
untab: '减少缩进',
bold: '粗体',
italic: '斜体',
underline: '下划线',
strikethrough: '删除线',
removeFormat: '清除格式',
justifyLeft: '左对齐',
justifyCenter: '居中对齐',
justifyRight: '右对齐',
justifyFull: '两端对齐',
insertUnorderedList: '无序列表',
insertOrderedList: '有序列表',
outdent: '减少缩进',
indent: '增加缩进',
formatPara: '设置选中内容样式为 普通',
formatH1: '设置选中内容样式为 标题1',
formatH2: '设置选中内容样式为 标题2',
formatH3: '设置选中内容样式为 标题3',
formatH4: '设置选中内容样式为 标题4',
formatH5: '设置选中内容样式为 标题5',
formatH6: '设置选中内容样式为 标题6',
insertHorizontalRule: '插入水平线',
'linkDialog.show': '显示链接对话框'
},
history: {
undo: '撤销',
redo: '重做'
},
specialChar: {
specialChar: '特殊字符',
select: '选取特殊字符'
}
}
});

View File

@ -1,3 +1,3 @@
/*! Summernote v0.8.8 | (c) 2013- Alan Hong and other contributors | MIT license */
/*! Summernote v0.8.11 | (c) 2013- Alan Hong and other contributors | MIT license */
!function(a){a.extend(a.summernote.lang,{"zh-CN":{font:{bold:"粗体",italic:"斜体",underline:"下划线",clear:"清除格式",height:"行高",name:"字体",strikethrough:"删除线",subscript:"下标",superscript:"上标",size:"字号"},image:{image:"图片",insert:"插入图片",resizeFull:"缩放至 100%",resizeHalf:"缩放至 50%",resizeQuarter:"缩放至 25%",floatLeft:"靠左浮动",floatRight:"靠右浮动",floatNone:"取消浮动",shapeRounded:"形状: 圆角",shapeCircle:"形状: 圆",shapeThumbnail:"形状: 缩略图",shapeNone:"形状: 无",dragImageHere:"将图片拖拽至此处",selectFromFiles:"从本地上传",maximumFileSize:"文件大小最大值",maximumFileSizeError:"文件大小超出最大值。",url:"图片地址",remove:"移除图片"},video:{video:"视频",videoLink:"视频链接",insert:"插入视频",url:"视频地址",providers:"(优酷, 腾讯, Instagram, DailyMotion, Youtube等)"},link:{link:"链接",insert:"插入链接",unlink:"去除链接",edit:"编辑链接",textToDisplay:"显示文本",url:"链接地址",openInNewWindow:"在新窗口打开"},table:{table:"表格"},hr:{insert:"水平线"},style:{style:"样式",p:"普通",blockquote:"引用",pre:"代码",h1:"标题 1",h2:"标题 2",h3:"标题 3",h4:"标题 4",h5:"标题 5",h6:"标题 6"},lists:{unordered:"无序列表",ordered:"有序列表"},options:{help:"帮助",fullscreen:"全屏",codeview:"源代码"},paragraph:{paragraph:"段落",outdent:"减少缩进",indent:"增加缩进",left:"左对齐",center:"居中对齐",right:"右对齐",justify:"两端对齐"},color:{recent:"最近使用",more:"更多",background:"背景",foreground:"前景",transparent:"透明",setTransparent:"透明",reset:"重置",resetToDefault:"默认"},shortcut:{shortcuts:"快捷键",close:"关闭",textFormatting:"文本格式",action:"动作",paragraphFormatting:"段落格式",documentStyle:"文档样式",extraKeys:"额外按键"},history:{undo:"撤销",redo:"重做"},help:{insertParagraph:"插入段落",undo:"撤销",redo:"重做",tab:"增加缩进",untab:"减少缩进",bold:"粗体",italic:"斜体",underline:"下划线",strikethrough:"删除线",removeFormat:"清除格式",justifyLeft:"左对齐",justifyCenter:"居中对齐",justifyRight:"右对齐",justifyFull:"两端对齐",insertUnorderedList:"无序列表",insertOrderedList:"有序列表",outdent:"减少缩进",indent:"增加缩进",formatPara:"设置选中内容样式为 普通",formatH1:"设置选中内容样式为 标题1",formatH2:"设置选中内容样式为 标题2",formatH3:"设置选中内容样式为 标题3",formatH4:"设置选中内容样式为 标题4",formatH5:"设置选中内容样式为 标题5",formatH6:"设置选中内容样式为 标题6",insertHorizontalRule:"插入水平线","linkDialog.show":"显示链接对话框"}}})}(jQuery);
!function(e){e.extend(e.summernote.lang,{"zh-CN":{font:{bold:"粗体",italic:"斜体",underline:"下划线",clear:"清除格式",height:"行高",name:"字体",strikethrough:"删除线",subscript:"下标",superscript:"上标",size:"字号"},image:{image:"图片",insert:"插入图片",resizeFull:"缩放至 100%",resizeHalf:"缩放至 50%",resizeQuarter:"缩放至 25%",floatLeft:"靠左浮动",floatRight:"靠右浮动",floatNone:"取消浮动",shapeRounded:"形状: 圆角",shapeCircle:"形状: 圆",shapeThumbnail:"形状: 缩略图",shapeNone:"形状: 无",dragImageHere:"将图片拖拽至此处",dropImage:"拖拽图片或文本",selectFromFiles:"从本地上传",maximumFileSize:"文件大小最大值",maximumFileSizeError:"文件大小超出最大值。",url:"图片地址",remove:"移除图片",original:"原始图片"},video:{video:"视频",videoLink:"视频链接",insert:"插入视频",url:"视频地址",providers:"(优酷, 腾讯, Instagram, DailyMotion, Youtube等)"},link:{link:"链接",insert:"插入链接",unlink:"去除链接",edit:"编辑链接",textToDisplay:"显示文本",url:"链接地址",openInNewWindow:"在新窗口打开"},table:{table:"表格",addRowAbove:"在上方插入行",addRowBelow:"在下方插入行",addColLeft:"在左侧插入列",addColRight:"在右侧插入列",delRow:"删除行",delCol:"删除列",delTable:"删除表格"},hr:{insert:"水平线"},style:{style:"样式",p:"普通",blockquote:"引用",pre:"代码",h1:"标题 1",h2:"标题 2",h3:"标题 3",h4:"标题 4",h5:"标题 5",h6:"标题 6"},lists:{unordered:"无序列表",ordered:"有序列表"},options:{help:"帮助",fullscreen:"全屏",codeview:"源代码"},paragraph:{paragraph:"段落",outdent:"减少缩进",indent:"增加缩进",left:"左对齐",center:"居中对齐",right:"右对齐",justify:"两端对齐"},color:{recent:"最近使用",more:"更多",background:"背景",foreground:"前景",transparent:"透明",setTransparent:"透明",reset:"重置",resetToDefault:"默认"},shortcut:{shortcuts:"快捷键",close:"关闭",textFormatting:"文本格式",action:"动作",paragraphFormatting:"段落格式",documentStyle:"文档样式",extraKeys:"额外按键"},help:{insertParagraph:"插入段落",undo:"撤销",redo:"重做",tab:"增加缩进",untab:"减少缩进",bold:"粗体",italic:"斜体",underline:"下划线",strikethrough:"删除线",removeFormat:"清除格式",justifyLeft:"左对齐",justifyCenter:"居中对齐",justifyRight:"右对齐",justifyFull:"两端对齐",insertUnorderedList:"无序列表",insertOrderedList:"有序列表",outdent:"减少缩进",indent:"增加缩进",formatPara:"设置选中内容样式为 普通",formatH1:"设置选中内容样式为 标题1",formatH2:"设置选中内容样式为 标题2",formatH3:"设置选中内容样式为 标题3",formatH4:"设置选中内容样式为 标题4",formatH5:"设置选中内容样式为 标题5",formatH6:"设置选中内容样式为 标题6",insertHorizontalRule:"插入水平线","linkDialog.show":"显示链接对话框"},history:{undo:"撤销",redo:"重做"},specialChar:{specialChar:"特殊字符",select:"选取特殊字符"}}})}(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -84,3 +84,65 @@ body.signin {
width:auto
}
}
/*
<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD>check<EFBFBD><EFBFBD>ʽ
*/
.checkbox-custom {
position: relative;
padding: 0 15px 0 25px;
margin-bottom: 7px;
margin-top: 0;
display: inline-block;
}
/*
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>checkbox<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD>ı<EFBFBD>
*/
.checkbox-custom input[type="checkbox"] {
opacity: 0;/*<2A><><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>checkbox<6F><78><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
position: absolute;
cursor: pointer;
z-index: 2;
margin: -6px 0 0 0;
top: 50%;
left: 3px;
}
/*
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>checkbox<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
*/
.checkbox-custom label:before {
content: '';
position: absolute;
top: 50%;
left: 0;
margin-top: -9px;
width: 18px;
height: 17px;
display: inline-block;
border-radius: 2px;
border: 1px solid #bbb;
background: #fff;
}
/*
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>checkbox<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>checkbox<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
.checkbox-custom input[type="checkbox"]:checked +label:after {
position: absolute;
display: inline-block;
font-family: 'Glyphicons Halflings';
content: "\e013";
top: 42%;
left: 3px;
margin-top: -5px;
font-size: 11px;
line-height: 1;
width: 16px;
height: 16px;
color: #333;
}
.checkbox-custom label {
cursor: pointer;
line-height: 1.2;
font-weight: normal;/*<2A>ı<EFBFBD><C4B1><EFBFBD>rememberme<6D><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
margin-bottom: 0;
text-align: left;
}

View File

@ -1 +1 @@
html{height:100%}body.signin{height:auto;background:url(../img/login-background.jpg) no-repeat center fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;color:rgba(255,255,255,.95)}.signinpanel{width:750px;margin:10% auto 0}.signinpanel .logopanel{float:none;width:auto;padding:0;background:0 0}.signinpanel .signin-info ul{list-style:none;padding:0;margin:20px 0}.signinpanel .form-control{display:block;margin-top:15px}.signinpanel .uname{background:#fff url(../img/user.png) no-repeat 95% center;color:#333}.signinpanel .pword{background:#fff url(../img/locked.png) no-repeat 95% center;color:#333}.signinpanel .code{background:#fff no-repeat 95% center;color:#333;margin:0 0 15px 0}.signinpanel .btn{margin-top:15px}.signinpanel form{background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.3);-moz-box-shadow:0 3px 0 rgba(12,12,12,.03);-webkit-box-shadow:0 3px 0 rgba(12,12,12,.03);box-shadow:0 3px 0 rgba(12,12,12,.03);-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:30px}.signup-footer{border-top:solid 1px rgba(255,255,255,.3);margin:20px 0;padding-top:15px}@media screen and (max-width:768px){.signinpanel,.signuppanel{margin:0 auto;width:420px!important;padding:20px}.signinpanel form{margin-top:20px}.signup-footer,.signuppanel .form-control{margin-bottom:10px}.signup-footer .pull-left,.signup-footer .pull-right{float:none!important;text-align:center}.signinpanel .signin-info ul{display:none}}@media screen and (max-width:320px){.signinpanel,.signuppanel{margin:0 20px;width:auto}}
html{height:100%}body.signin{height:auto;background:url(../img/login-background.jpg) no-repeat center fixed;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;color:rgba(255,255,255,.95)}.signinpanel{width:750px;margin:10% auto 0}.signinpanel .logopanel{float:none;width:auto;padding:0;background:0}.signinpanel .signin-info ul{list-style:none;padding:0;margin:20px 0}.signinpanel .form-control{display:block;margin-top:15px}.signinpanel .uname{background:#fff url(../img/user.png) no-repeat 95% center;color:#333}.signinpanel .pword{background:#fff url(../img/locked.png) no-repeat 95% center;color:#333}.signinpanel .code{background:#fff no-repeat 95% center;color:#333;margin:0 0 15px 0}.signinpanel .btn{margin-top:15px}.signinpanel form{background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.3);-moz-box-shadow:0 3px 0 rgba(12,12,12,.03);-webkit-box-shadow:0 3px 0 rgba(12,12,12,.03);box-shadow:0 3px 0 rgba(12,12,12,.03);-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:30px}.signup-footer{border-top:solid 1px rgba(255,255,255,.3);margin:20px 0;padding-top:15px}@media screen and (max-width:768px){.signinpanel,.signuppanel{margin:0 auto;width:420px!important;padding:20px}.signinpanel form{margin-top:20px}.signup-footer,.signuppanel .form-control{margin-bottom:10px}.signup-footer .pull-left,.signup-footer .pull-right{float:none!important;text-align:center}.signinpanel .signin-info ul{display:none}}@media screen and (max-width:320px){.signinpanel,.signuppanel{margin:0 20px;width:auto}}.checkbox-custom{position:relative;padding:0 15px 0 25px;margin-bottom:7px;margin-top:0;display:inline-block}.checkbox-custom input[type="checkbox"]{opacity:0;position:absolute;cursor:pointer;z-index:2;margin:-6px 0 0 0;top:50%;left:3px}.checkbox-custom label:before{content:'';position:absolute;top:50%;left:0;margin-top:-9px;width:18px;height:17px;display:inline-block;border-radius:2px;border:1px solid #bbb;background:#fff}.checkbox-custom input[type="checkbox"]:checked+label:after{position:absolute;display:inline-block;font-family:'Glyphicons Halflings';content:"\e013";top:42%;left:3px;margin-top:-5px;font-size:11px;line-height:1;width:16px;height:16px;color:#333}.checkbox-custom label{cursor:pointer;line-height:1.2;font-weight:normal;margin-bottom:0;text-align:left}

View File

@ -0,0 +1,822 @@
/*
*
* SKIN blue 若依管理系统
* NAME - blue/green/purple/red/yellow
*
*/
/** 蓝色主题 skin-blue **/
.skin-blue .navbar {
background-color: #3c8dbc
}
.skin-blue .navbar .nav>li>a {
color: #fff
}
.skin-blue .navbar .nav>li>a:hover,
.skin-blue .navbar .nav>li>a:active,
.skin-blue .navbar .nav>li>a:focus,
.skin-blue .navbar .nav .open>a,
.skin-blue .navbar .nav .open>a:hover,
.skin-blue .navbar .nav .open>a:focus,
.skin-blue .navbar .nav>.active>a {
background: rgba(0, 0, 0, 0.1);
color: #f6f6f6
}
.skin-blue .navbar .sidebar-toggle {
color: #fff
}
.skin-blue .navbar .sidebar-toggle:hover {
color: #f6f6f6;
background: rgba(0, 0, 0, 0.1)
}
.skin-blue .navbar .sidebar-toggle {
color: #fff
}
.skin-blue .navbar .sidebar-toggle:hover {
background-color: #367fa9
}
@media ( max-width :767px) {
.skin-blue .navbar .dropdown-menu li.divider {
background-color: rgba(255, 255, 255, 0.1)
}
.skin-blue .navbar .dropdown-menu li a {
color: #fff
}
.skin-blue .navbar .dropdown-menu li a:hover {
background: #367fa9
}
}
.skin-blue .logo {
background-color: #367fa9;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-blue .logo:hover {
background-color: #357ca5
}
.skin-blue li.user-header {
background-color: #3c8dbc
}
.skin-blue .content-header {
background: transparent
}
.skin-blue .wrapper,
.skin-blue .main-sidebar,
.skin-blue .left-side {
background-color: #222d32
}
.skin-blue .user-panel>.info,
.skin-blue .user-panel>.info>a {
color: #fff
}
.skin-blue .nav>li.header {
color: #4b646f;
background: #1a2226
}
.skin-blue .nav>li.active {
color: #fff;
background: #293846;
border-left: 3px solid #3c8dbc;
}
.skin-blue .nav>li.active:last-child {
border-left: none;
}
.skin-blue .nav>li>.treeview-menu {
margin: 0 1px;
background: #2c3b41
}
.skin-blue .sidebar a {
color: #b8c7ce
}
.skin-blue .sidebar a:hover {
text-decoration: none
}
.skin-blue .treeview-menu>li>a {
color: #8aa4af
}
.skin-blue .treeview-menu>li.active>a,
.skin-blue .treeview-menu>li>a:hover {
color: #fff
}
.skin-blue .sidebar-form {
border-radius: 3px;
border: 1px solid #374850;
margin: 10px 10px
}
.skin-blue .sidebar-form input[type="text"],
.skin-blue .sidebar-form .btn {
box-shadow: none;
background-color: #374850;
border: 1px solid transparent;
height: 35px
}
.skin-blue .sidebar-form input[type="text"] {
color: #666;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px
}
.skin-blue .sidebar-form input[type="text"]:focus,
.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
background-color: #fff;
color: #666
}
.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
border-left-color: #fff
}
.skin-blue .sidebar-form .btn {
color: #999;
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0
}
.skin-blue.layout-top-nav>.logo {
background-color: #3c8dbc;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-blue.layout-top-nav>.logo:hover {
background-color: #3b8ab8
}
.skin-blue .content-tabs {
border-bottom: solid 2px #e7eaec;
}
.skin-blue.layout-top-nav>.logo {
background-color: #3c8dbc;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-blue.layout-top-nav>.logo:hover {
background-color: #3b8ab8
}
/** 绿色主题 skin-green **/
.skin-green .navbar {
background-color: #00a65a;
}
.skin-green .content-tabs {
border-bottom: solid 2px #e7eaec;
}
.skin-green .navbar .nav>li>a {
color: #fff
}
.skin-green .navbar .nav>li>a:hover,
.skin-green .navbar .nav>li>a:active,
.skin-green .navbar .nav>li>a:focus,
.skin-green .navbar .nav .open>a,
.skin-green .navbar .nav .open>a:hover,
.skin-green .navbar .nav .open>a:focus,
.skin-green .navbar .nav>.active>a {
background: rgba(0, 0, 0, 0.1);
color: #f6f6f6
}
.skin-green .navbar .sidebar-toggle {
color: #fff
}
.skin-green .navbar .sidebar-toggle:hover {
color: #f6f6f6;
background: rgba(0, 0, 0, 0.1)
}
.skin-green .navbar .sidebar-toggle {
color: #fff
}
.skin-green .navbar .sidebar-toggle:hover {
background-color: #008d4c
}
@media ( max-width :767px) {
.skin-green .navbar .dropdown-menu li.divider {
background-color: rgba(255, 255, 255, 0.1)
}
.skin-green .navbar .dropdown-menu li a {
color: #fff
}
.skin-green .navbar .dropdown-menu li a:hover {
background: #008d4c
}
}
.skin-green .logo {
background-color: #008d4c;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-green .logo:hover {
background-color: #008749
}
.skin-green li.user-header {
background-color: #00a65a
}
.skin-green .content-header {
background: transparent
}
.skin-green .wrapper,
.skin-green .main-sidebar,
.skin-green .left-side {
background-color: #222d32
}
.skin-green .user-panel>.info,
.skin-green .user-panel>.info>a {
color: #fff
}
.skin-green .nav>li.header {
color: #4b646f;
background: #1a2226;
}
.skin-green .nav>li.active {
color: #fff;
background: #293846;
border-left: 3px solid #00a65a;
}
.skin-green .nav>li.active:last-child {
border-left: none;
}
.skin-green .nav>li>.treeview-menu {
margin: 0 1px;
background: #2c3b41
}
.skin-green .sidebar a {
color: #b8c7ce
}
.skin-green .sidebar a:hover {
text-decoration: none
}
.skin-green .treeview-menu>li>a {
color: #8aa4af
}
.skin-green .treeview-menu>li.active>a,
.skin-green .treeview-menu>li>a:hover {
color: #fff
}
.skin-green .sidebar-form {
border-radius: 3px;
border: 1px solid #374850;
margin: 10px 10px
}
.skin-green .sidebar-form input[type="text"],
.skin-green .sidebar-form .btn {
box-shadow: none;
background-color: #374850;
border: 1px solid transparent;
height: 35px
}
.skin-green .sidebar-form input[type="text"] {
color: #666;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px
}
.skin-green .sidebar-form input[type="text"]:focus,
.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
background-color: #fff;
color: #666
}
.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
border-left-color: #fff
}
.skin-green .sidebar-form .btn {
color: #999;
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0
}
/** 红色主题 skin-red **/
.skin-red .navbar {
background-color: #dd4b39
}
.skin-red .navbar .nav>li>a {
color: #fff
}
.skin-red .navbar .nav>li>a:hover,
.skin-red .navbar .nav>li>a:active,
.skin-red .navbar .nav>li>a:focus,
.skin-red .navbar .nav .open>a,
.skin-red .navbar .nav .open>a:hover,
.skin-red .navbar .nav .open>a:focus,
.skin-red .navbar .nav>.active>a {
background: rgba(0, 0, 0, 0.1);
color: #f6f6f6
}
.skin-red .navbar .sidebar-toggle {
color: #fff
}
.skin-red .navbar .sidebar-toggle:hover {
color: #f6f6f6;
background: rgba(0, 0, 0, 0.1)
}
.skin-red .navbar .sidebar-toggle {
color: #fff
}
.skin-red .navbar .sidebar-toggle:hover {
background-color: #d73925
}
@media ( max-width :767px) {
.skin-red .navbar .dropdown-menu li.divider {
background-color: rgba(255, 255, 255, 0.1)
}
.skin-red .navbar .dropdown-menu li a {
color: #fff
}
.skin-red .navbar .dropdown-menu li a:hover {
background: #d73925
}
}
.skin-red .logo {
background-color: #d73925;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-red .logo:hover {
background-color: #d33724
}
.skin-red li.user-header {
background-color: #dd4b39
}
.skin-red .content-header {
background: transparent
}
.skin-red .wrapper,
.skin-red .main-sidebar,
.skin-red .left-side {
background-color: #222d32
}
.skin-red .user-panel>.info,
.skin-red .user-panel>.info>a {
color: #fff
}
.skin-red .nav>li.header {
color: #4b646f;
background: #1a2226
}
.skin-red .nav>li.active {
color: #fff;
border-left: 3px solid #dd4b39;
background: #293846;
}
.skin-red .nav>li.active:last-child {
border-left: none;
}
.skin-red .content-tabs {
border-bottom: solid 2px #e7eaec;
}
.skin-red .nav>li>.treeview-menu {
margin: 0 1px;
background: #2c3b41
}
.skin-red .sidebar a {
color: #b8c7ce
}
.skin-red .sidebar a:hover {
text-decoration: none
}
.skin-red .treeview-menu>li>a {
color: #8aa4af
}
.skin-red .treeview-menu>li.active>a,
.skin-red .treeview-menu>li>a:hover {
color: #fff
}
.skin-red .sidebar-form {
border-radius: 3px;
border: 1px solid #374850;
margin: 10px 10px
}
.skin-red .sidebar-form input[type="text"],
.skin-red .sidebar-form .btn {
box-shadow: none;
background-color: #374850;
border: 1px solid transparent;
height: 35px
}
.skin-red .sidebar-form input[type="text"] {
color: #fff;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px
}
.skin-red .sidebar-form input[type="text"]:focus,
.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
background-color: #fff;
color: #666
}
.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
border-left-color: #fff
}
.skin-red .sidebar-form .btn {
color: #999;
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0
}
/** 黄色主题 skin-red **/
.skin-yellow .navbar {
background-color: #f39c12
}
.skin-yellow .navbar .nav>li>a {
color: #fff
}
.skin-yellow .navbar .nav>li>a:hover,
.skin-yellow .navbar .nav>li>a:active,
.skin-yellow .navbar .nav>li>a:focus,
.skin-yellow .navbar .nav .open>a,
.skin-yellow .navbar .nav .open>a:hover,
.skin-yellow .navbar .nav .open>a:focus,
.skin-yellow .navbar .nav>.active>a {
background: rgba(0, 0, 0, 0.1);
color: #f6f6f6
}
.skin-yellow .navbar .sidebar-toggle {
color: #fff
}
.skin-yellow .navbar .sidebar-toggle:hover {
color: #f6f6f6;
background: rgba(0, 0, 0, 0.1)
}
.skin-yellow .navbar .sidebar-toggle {
color: #fff
}
.skin-yellow .navbar .sidebar-toggle:hover {
background-color: #e08e0b
}
@media ( max-width :767px) {
.skin-yellow .navbar .dropdown-menu li.divider {
background-color: rgba(255, 255, 255, 0.1)
}
.skin-yellow .navbar .dropdown-menu li a {
color: #fff
}
.skin-yellow .navbar .dropdown-menu li a:hover {
background: #e08e0b
}
}
.skin-yellow .logo {
background-color: #e08e0b;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-yellow .logo:hover {
background-color: #db8b0b
}
.skin-yellow li.user-header {
background-color: #f39c12
}
.skin-yellow .content-header {
background: transparent
}
.skin-yellow .wrapper,
.skin-yellow .main-sidebar,
.skin-yellow .left-side {
background-color: #222d32
}
.skin-yellow .user-panel>.info,
.skin-yellow .user-panel>.info>a {
color: #fff
}
.skin-yellow .nav>li.header {
color: #4b646f;
background: #1a2226
}
.skin-yellow .nav>li.active {
color: #fff;
background: #293846;
border-left: 3px solid #f39c12;
}
.skin-yellow .nav>li.active:last-child {
border-left: none;
}
.skin-yellow .content-tabs {
border-bottom: solid 2px #e7eaec;
}
.skin-yellow .nav>li>.treeview-menu {
margin: 0 1px;
background: #2c3b41
}
.skin-yellow .sidebar a {
color: #b8c7ce
}
.skin-yellow .sidebar a:hover {
text-decoration: none
}
.skin-yellow .treeview-menu>li>a {
color: #8aa4af
}
.skin-yellow .treeview-menu>li.active>a,
.skin-yellow .treeview-menu>li>a:hover {
color: #fff
}
.skin-yellow .sidebar-form {
border-radius: 3px;
border: 1px solid #374850;
margin: 10px 10px
}
.skin-yellow .sidebar-form input[type="text"],
.skin-yellow .sidebar-form .btn {
box-shadow: none;
background-color: #374850;
border: 1px solid transparent;
height: 35px
}
.skin-yellow .sidebar-form input[type="text"] {
color: #666;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px
}
.skin-yellow .sidebar-form input[type="text"]:focus,
.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
background-color: #fff;
color: #666
}
.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
border-left-color: #fff
}
.skin-yellow .sidebar-form .btn {
color: #999;
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0
}
/** 紫色主题 skin-purple **/
.skin-purple .navbar {
background-color: #605ca8
}
.skin-purple .navbar .nav>li>a {
color: #fff
}
.skin-purple .navbar .nav>li>a:hover,
.skin-purple .navbar .nav>li>a:active,
.skin-purple .navbar .nav>li>a:focus,
.skin-purple .navbar .nav .open>a,
.skin-purple .navbar .nav .open>a:hover,
.skin-purple .navbar .nav .open>a:focus,
.skin-purple .navbar .nav>.active>a {
background: rgba(0, 0, 0, 0.1);
color: #f6f6f6
}
.skin-purple .navbar .sidebar-toggle {
color: #fff
}
.skin-purple .navbar .sidebar-toggle:hover {
color: #f6f6f6;
background: rgba(0, 0, 0, 0.1)
}
.skin-purple .navbar .sidebar-toggle {
color: #fff
}
.skin-purple .navbar .sidebar-toggle:hover {
background-color: #555299
}
@media ( max-width :767px) {
.skin-purple .navbar .dropdown-menu li.divider {
background-color: rgba(255, 255, 255, 0.1)
}
.skin-purple .navbar .dropdown-menu li a {
color: #fff
}
.skin-purple .navbar .dropdown-menu li a:hover {
background: #555299
}
}
.skin-purple .logo {
background-color: #555299;
color: #fff;
border-bottom: 0 solid transparent
}
.skin-purple .logo:hover {
background-color: #545096
}
.skin-purple li.user-header {
background-color: #605ca8
}
.skin-purple .content-header {
background: transparent
}
.skin-purple .wrapper,
.skin-purple .main-sidebar,
.skin-purple .left-side {
background-color: #222d32
}
.skin-purple .user-panel>.info,
.skin-purple .user-panel>.info>a {
color: #fff
}
.skin-purple .nav>li.header {
color: #4b646f;
background: #1a2226
}
.skin-purple .nav>li.active {
color: #fff;
background: #293846;
border-left: 3px solid #605ca8;
}
.skin-purple .nav>li.active:last-child {
border-left: none;
}
.skin-purple .content-tabs {
border-bottom: solid 2px #e7eaec;
}
.skin-purple .nav>li>.treeview-menu {
margin: 0 1px;
background: #2c3b41
}
.skin-purple .sidebar a {
color: #b8c7ce
}
.skin-purple .sidebar a:hover {
text-decoration: none
}
.skin-purple .treeview-menu>li>a {
color: #8aa4af
}
.skin-purple .treeview-menu>li.active>a,
.skin-purple .treeview-menu>li>a:hover {
color: #fff
}
.skin-purple .sidebar-form {
border-radius: 3px;
border: 1px solid #374850;
margin: 10px 10px
}
.skin-purple .sidebar-form input[type="text"],
.skin-purple .sidebar-form .btn {
box-shadow: none;
background-color: #374850;
border: 1px solid transparent;
height: 35px
}
.skin-purple .sidebar-form input[type="text"] {
color: #666;
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px
}
.skin-purple .sidebar-form input[type="text"]:focus,
.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
background-color: #fff;
color: #666
}
.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
border-left-color: #fff
}
.skin-purple .sidebar-form .btn {
color: #999;
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0
}

View File

@ -47,28 +47,44 @@ a:focus {
}
.nav.navbar-right>li>a {
color: #999c9e;
color: #fff;
font-size: 14px;
height: 50px;
padding: 18px 15px;
}
.nav>li.active>a {
color: #ffffff;
}
.navbar-default .nav>li>a:hover, .navbar-default .nav>li>a:focus {
background-color: #293846;
color: white;
.nav.navbar-right>li>a>.label {
position: absolute;
top: 9px;
right: 5px;
text-align: center;
font-size: 9px;
padding: 2px 4px;
line-height: .9;
}
.nav.navbar-right>li>a:hover {
background-color: #367fa9;
color: #fff;
}
.nav .open>a, .nav .open>a:hover, .nav .open>a:focus {
background: #fff;
.navbar-default .nav>li>a:hover,
.navbar-default .nav>li>a:focus {
background-color: #293846;
color: white;
}
.nav>li>a i {
margin-right: 6px;
.nav .open>a,
.nav .open>a:hover,
.nav .open>a:focus {
background: #fff;
}
.navbar {
border: 0;
border: 0;
}
.navbar-default {
@ -77,12 +93,12 @@ a:focus {
position: relative;
}
.navbar-top-links li {
display: inline-block;
.nav.navbar-top-links li {
display: inline-block;
}
.navbar-top-links li:last-child {
margin-right: 30px;
margin-right: 16px;
}
body.body-small .navbar-top-links li:last-child {
@ -179,7 +195,7 @@ body.body-small .navbar-top-links li:last-child {
}
.nav-header {
padding: 33px 25px;
padding: 34px 25px 20px 25px;
background: url("patterns/header-profile.png") no-repeat;
}
@ -211,7 +227,7 @@ body.body-small .navbar-top-links li:last-child {
.minimalize-styl-2 {
padding: 4px 12px;
margin: 14px 5px 5px 20px;
margin: 12px 5px 5px 15px;
font-size: 14px;
float: left;
}
@ -368,10 +384,6 @@ body.mini-navbar .navbar-default .nav>li>.nav-second-level li a {
z-index: 2030;
}
.navbar-fixed-top, .navbar-static-top {
background: #f3f3f4;
}
.fixed-nav #wrapper {
padding-top: 60px;
box-sizing: border-box;
@ -460,18 +472,6 @@ body.body-small.fixed-sidebar.mini-navbar .navbar-static-side {
.fixed-sidebar.mini-navbar .nav li.active {
border-left-width: 0;
}
/*.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level, .canvas-menu.mini-navbar .nav li:hover>.nav-second-level*/
/*{*/
/*position: absolute;*/
/*left: 70px;*/
/*top: 40px;*/
/*background-color: #2f4050;*/
/*padding: 10px 10px 0 10px;*/
/*font-size: 12px;*/
/*display: block;*/
/*min-width: 140px;*/
/*border-radius: 2px;*/
/*}*/
/*伸缩菜单*/
.fixed-sidebar.mini-navbar .nav li:hover>a> span.nav-label {
@ -485,7 +485,6 @@ body.body-small.fixed-sidebar.mini-navbar .navbar-static-side {
.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level {
top: 40px;
font-size: 12px;
/*padding: 10px 10px 0 10px;*/
background-color: #2f4050;
}
@ -5507,8 +5506,8 @@ del {
}
20% {
-webkit-transform: scaleY (1);
transform: scaleY (1);
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
}
@ -5567,20 +5566,20 @@ del {
transform: translateX(42px) translateY(42px) rotate(-179deg);
}
50 .1 % {
-webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);
transform: translateX(42px) translateY(42px) rotate(-180deg);
}
50.1% {
-webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);
transform: translateX(42px) translateY(42px) rotate(-180deg);
}
75% {
-webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0 .5 );
transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0 .5 );
}
75% {
-webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0 .5 );
transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0 .5 );
}
100% {
-webkit-transform: rotate(-360deg);
transform: rotate(-360deg);
}
100% {
-webkit-transform: rotate(-360deg);
transform: rotate(-360deg);
}
}
@keyframes sk-wanderingCubeMove {
@ -6567,391 +6566,24 @@ body.rtls .top-navigation .footer.fixed, body.rtls.top-navigation .footer.fixed
.rtls .ltr-support {
direction: ltr;
}
/*
*
* This is style for skin config
* Use only in demo theme
*
*/
.skin-setttings .title {
background: #efefef;
text-align: center;
text-transform: uppercase;
font-weight: 600;
display: block;
padding: 10px 15px;
font-size: 12px;
}
.setings-item {
padding: 10px 30px;
}
.setings-item.nb {
border: none;
}
.setings-item.skin {
text-align: center;
}
.setings-item .switch {
float: right;
}
.skin-name a {
text-transform: uppercase;
}
.setings-item a {
color: #fff;
}
.default-skin, .blue-skin, .ultra-skin, .yellow-skin {
text-align: center;
}
.default-skin {
font-weight: 600;
background: #1ab394;
}
.default-skin:hover {
background: #199d82;
}
.blue-skin {
font-weight: 600;
background: url("patterns/header-profile-skin-blue.png") repeat scroll 0 0;
}
.blue-skin:hover {
background: #0d8ddb;
}
.yellow-skin {
font-weight: 600;
background: url("patterns/header-profile-skin-yellow.png") repeat scroll 0 100%;
}
.yellow-skin:hover {
background: #ce8735;
}
.content-tabs {
border-bottom: solid 2px #2f4050;
}
.page-tabs a {
color: #999;
}
.page-tabs a i {
color: #ccc;
margin-left: 2px;
font-size: 13px;
}
.page-tabs a.active {
background: #2f4050;
color: #a7b1c2;
background: #eaedf1;
color: #23508e;
}
.page-tabs a.active:hover, .page-tabs a.active i:hover {
background: #293846;
color: #fff;
}
/*
*
* SKIN blue 若依管理系统
* NAME - blue/purple
*
*/
.skin-blue .minimalize-styl-2 {
margin: 14px 5px 5px 30px;
}
.skin-blue .navbar-top-links li:last-child {
margin-right: 30px;
}
.skin-blue.fixed-nav .minimalize-styl-2 {
margin: 14px 5px 5px 15px;
}
.skin-blue .spin-icon {
background: #0e9aef !important;
}
.skin-blue .nav-header {
background: #0e9aef;
background: url('patterns/header-profile-skin-blue.png');
}
.skin-blue.mini-navbar .nav-second-level {
background: #3e495f;
}
.skin-blue .breadcrumb {
background: transparent;
}
.skin-blue .page-heading {
border: none;
}
.skin-blue .nav>li.active {
background: #3a4459;
}
.skin-blue .nav>li>a {
color: #9ea6b9;
}
.skin-blue .nav>li.active>a {
color: #fff;
}
.skin-blue .navbar-minimalize {
background: #0e9aef;
border-color: #0e9aef;
}
body.skin-blue {
background: #3e495f;
}
.skin-blue .navbar-static-top {
background: #ffffff;
}
.skin-blue .dashboard-header {
background: transparent;
border-bottom: none !important;
border-top: none;
padding: 20px 30px 10px 30px;
}
.fixed-nav.skin-blue .navbar-fixed-top {
background: #fff;
}
.skin-blue .wrapper-content {
padding: 30px 15px;
}
.skin-blue #page-wrapper {
background: #f4f6fa;
}
.skin-blue .ibox-title, .skin-blue .ibox-content {
border-width: 1px;
}
.skin-blue .ibox-content:last-child {
border-style: solid solid solid solid;
}
.skin-blue .nav>li.active {
border: none;
}
.skin-blue .nav-header {
padding: 35px 25px 25px 25px;
}
.skin-blue .nav-header a.dropdown-toggle {
color: #fff;
margin-top: 10px;
}
.skin-blue .nav-header a.dropdown-toggle .text-muted {
color: #fff;
opacity: 0.8;
}
.skin-blue .profile-element {
text-align: center;
}
.skin-blue .img-circle {
border-radius: 5px;
}
.skin-blue .navbar-default .nav>li>a:hover, .skin-blue .navbar-default .nav>li>a:focus {
background: #39aef5;
color: #fff;
}
.skin-blue .nav.nav-tabs>li.active>a {
color: #555;
}
.skin-blue .content-tabs {
border-bottom: solid 2px #39aef5;
}
.skin-blue .nav.nav-tabs>li.active {
background: transparent;
}
.skin-blue .page-tabs a.active {
background: #39aef5;
color: #fff;
}
.skin-blue .page-tabs a.active:hover, .skin-blue .page-tabs a.active i:hover {
background: #0e9aef;
color: #fff;
}
/*
*
* SKIN Yellow 若依管理系统
* NAME - Yellow/purple
*
*/
.skin-yellow .minimalize-styl-2 {
margin: 14px 5px 5px 30px;
}
.skin-yellow .navbar-top-links li:last-child {
margin-right: 30px;
}
.skin-yellow.fixed-nav .minimalize-styl-2 {
margin: 14px 5px 5px 15px;
}
.skin-yellow .spin-icon {
background: #ecba52 !important;
}
body.boxed-layout.skin-yellow #wrapper {
background: #3e2c42;
}
.skin-yellow .nav-header {
background: #ecba52;
background: url('patterns/header-profile-skin-yellow.png');
}
.skin-yellow.mini-navbar .nav-second-level {
background: #3e2c42;
}
.skin-yellow .breadcrumb {
background: transparent;
}
.skin-yellow .page-heading {
border: none;
}
.skin-yellow .nav>li.active {
background: #38283c;
}
.fixed-nav.skin-yellow .navbar-fixed-top {
background: #fff;
}
.skin-yellow .nav>li>a {
color: #948b96;
}
.skin-yellow .nav>li.active>a {
color: #fff;
}
.skin-yellow .navbar-minimalize {
background: #ecba52;
border-color: #ecba52;
}
body.skin-yellow {
background: #3e2c42;
}
.skin-yellow .navbar-static-top {
background: #ffffff;
}
.skin-yellow .dashboard-header {
background: transparent;
border-bottom: none !important;
border-top: none;
padding: 20px 30px 10px 30px;
}
.skin-yellow .wrapper-content {
padding: 30px 15px;
}
.skin-yellow #page-wrapper {
background: #f4f6fa;
}
.skin-yellow .ibox-title, .skin-yellow .ibox-content {
border-width: 1px;
}
.skin-yellow .ibox-content:last-child {
border-style: solid solid solid solid;
}
.skin-yellow .nav>li.active {
border: none;
}
.skin-yellow .nav-header {
padding: 35px 25px 25px 25px;
}
.skin-yellow .nav-header a.dropdown-toggle {
color: #fff;
margin-top: 10px;
}
.skin-yellow .nav-header a.dropdown-toggle .text-muted {
color: #fff;
opacity: 0.8;
}
.skin-yellow .profile-element {
text-align: center;
}
.skin-yellow .img-circle {
border-radius: 5px;
}
.skin-yellow .navbar-default .nav>li>a:hover, .skin-yellow .navbar-default .nav>li>a:focus {
background: #38283c;
color: #fff;
}
.skin-yellow .nav.nav-tabs>li.active>a {
color: #555;
}
.skin-yellow .nav.nav-tabs>li.active {
background: transparent;
}
.skin-yellow .content-tabs {
border-bottom: solid 2px #3e2c42;
}
.skin-yellow .nav.nav-tabs>li.active {
background: transparent;
}
.skin-yellow .page-tabs a.active {
background: #3e2c42;
color: #fff;
}
.skin-yellow .page-tabs a.active:hover, .skin-yellow .page-tabs a.active i:hover {
background: #38283c;
color: #fff;
.page-tabs a.active:hover,
.page-tabs a.active i:hover {
background: #eaedf1;
color: #23508e;
}
@media ( min-width : 768px) {
@ -7279,7 +6911,8 @@ body.skin-yellow {
}
.navbar-header {
width: 60%;
width: 10%;
height: 50px;
}
.bs-glyphicons {
@ -7347,3 +6980,99 @@ body.skin-yellow {
border-color: #cccccc!important;
}
.folder-list li.active a {
color: #2791df;
background: #f5f5f5;
}
.nav .logo {
background-color: #367fa9;
color: #fff;
border-bottom: 0 solid transparent;
-webkit-transition: width .3s ease-in-out;
-o-transition: width .3s ease-in-out;
transition: width .3s ease-in-out;
display: block;
height: 50px;
font-size: 20px;
line-height: 50px;
text-align: center;
width: 220px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 0 15px;
font-weight: 300;
overflow: hidden
}
.logo-mini {
display: none;
}
.logo-lg {
display: block;
}
.roleList {
color: #d5d5d5;
margin-right: 10px;
padding-top: 10px;
line-height: 1;
white-space: nowrap;
overflow: hidden;
width: 110px;
}
.sidebar-collapse .user-panel {
white-space: nowrap;
position: relative;
width: 100%;
padding: 15px;
overflow: hidden;
}
.sidebar-collapse .user-panel .image>img {
width: 100%;
max-width: 45px;
height: auto;
}
.sidebar-collapse .user-panel>.info {
padding: 5px 5px 5px 15px;
line-height: 1;
position: absolute;
left: 55px;
}
.sidebar-collapse .user-panel>.info a {
color: #fff;
font-size: 12px;
}
.sidebar-collapse .user-panel>.info>p {
font-weight: 600;
margin-bottom: 9px;
color: #fff;
font-size: 12px;
}
.user-panel>.info>a>.fa,
.user-panel>.info>a>.ion,
.user-panel>.info>a>.glyphicon {
margin-right: 3px;
}
.nav>li:hover .dropdown-menu {
display: block;
}
#content-main.max {
height: calc(100% - 110px);
overflow: hidden;
width: 100%;
height: 100%;
left: 0px;
position: absolute;
top: 0px;
z-index: 9998;
margin: 0;
}

View File

@ -1,9 +1,64 @@
/**
* 通用css样式布局处理
* Copyright (c) 2018 ruoyi
* Copyright (c) 2019 ruoyi
*/
/** 用户管理 样式布局 */
/** 基础通用 **/
.pt5 {
padding-top: 5px;
}
.pr5 {
padding-right: 5px;
}
.pb5 {
padding-bottom: 5px;
}
.mt5 {
margin-top: 5px;
}
.mr5 {
margin-right: 5px;
}
.mb5 {
margin-bottom: 5px;
}
.ml5 {
margin-left: 5px;
}
.mt10 {
margin-top: 10px;
}
.mr10 {
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px;
}
.ml0 {
margin-left: 10px;
}
.mt20 {
margin-top: 20px;
}
.mr20 {
margin-right: 20px;
}
.mb20 {
margin-bottom: 20px;
}
.ml20 {
margin-left: 20px;
}
/** 弹层组件 禁用样式 **/
.layer-disabled {
border: 1px #dedede solid !important;
background-color: #f1f1f1 !important;
color: #333 !important;
pointer-events: none;
}
/** 用户管理 样式布局 **/
.box {
position: relative;
border-radius: 3px;
@ -91,7 +146,7 @@
margin: 5px 0 5px -25px
}
/** select2 样式修改 */
/** select2 样式修改 **/
.select2-container--default .select2-selection--multiple .select2-selection__choice {
background-color: #1AB394;
border-color: #1AB394;
@ -112,7 +167,7 @@
padding-right: 10px
}
/** 表单验证 样式布局 */
/** 表单验证 样式布局 **/
label.error {
position: absolute;
right: 18px;
@ -143,7 +198,7 @@ label.error {
max-width: none;
}
/** 复选框&单选框 */
/** 复选框&单选框 **/
.check-box,.radio-box {
display: inline-block;
box-sizing: border-box;
@ -160,7 +215,7 @@ label.error {
left: 0
}
/* iCheck */
/** iCheck **/
.icheckbox-blue,.iradio-blue {
display: block;
margin: 0;
@ -214,7 +269,7 @@ label.error {
background-position: -180px 0
}
/** 遮罩层 */
/** 遮罩层 **/
.loaderbox {
display: inline-block;
min-width: 125px;
@ -281,7 +336,7 @@ label.error {
}
}
/** 表单查询条件 */
/** 表单查询条件 **/
ul {
margin: 0;
padding: 0;
@ -409,7 +464,7 @@ label {
cursor: pointer;
}
/** 表格查询数据 */
/** 表格查询数据 **/
.table-striped {
min-height: 75%;
}
@ -437,7 +492,7 @@ label {
border: 1px solid #ddd!important
}
/** 首页样式 */
/** 首页样式 **/
.ax_close_max {
position: fixed;
top: 5px;
@ -446,3 +501,35 @@ label {
display: none;
color: #ccc;
}
.navbar-right > .user-menu > .dropdown-menu {
border-top-right-radius:0;
border-top-left-radius:0;
padding:1px 0 0 0;
border-top-width:0;
width:138px;
}
.navbar-right > .user-menu .user-image {
float:left;
width:27px;
height:27px;
border-radius:50%;
margin-right:8px;
margin-top:-3px;
}
@media (max-width:767px) {
.navbar-right > .user-menu .user-image {
float:none;
margin-right:0;
margin-top:-8px;
line-height:10px;
}
}.dropdown-menu > li > a > .glyphicon,.dropdown-menu > li > a > .fa,.dropdown-menu > li > a > .ion {
margin-right:10px;
}
.dropdown-menu > li > a:hover {
background-color:#e1e3e9;
color:#333;
}
.dropdown-menu > .divider {
background-color:#eee;
}

View File

@ -1,6 +1,12 @@
/**
* 菜单处理
* 首页方法封装处理
* Copyright (c) 2019 ruoyi
*/
layer.config({
extend: 'moon/style.css',
skin: 'layer-ext-moon'
});
$(function() {
// MetsiMenu
$('#side-menu').metisMenu();
@ -45,6 +51,7 @@ function() {
if ($(this).width() < 769) {
$('body').addClass('mini-navbar');
$('.navbar-static-side').fadeIn();
$(".sidebar-collapse .logo").addClass("hide");
}
});
@ -55,12 +62,14 @@ function NavToggle() {
function SmoothlyMenu() {
if (!$('body').hasClass('mini-navbar')) {
$('#side-menu').hide();
$(".sidebar-collapse .logo").removeClass("hide");
setTimeout(function() {
$('#side-menu').fadeIn(500);
},
100);
} else if ($('body').hasClass('fixed-sidebar')) {
$('#side-menu').hide();
$(".sidebar-collapse .logo").addClass("hide");
setTimeout(function() {
$('#side-menu').fadeIn(500);
},

View File

@ -1,8 +1,7 @@
/**
* 通用方法封装处理
* Copyright (c) 2018 ruoyi
* Copyright (c) 2019 ruoyi
*/
$(function() {
// select2复选框事件绑定
if ($.fn.select2 !== undefined) {
@ -101,7 +100,7 @@ $(function() {
$("#bootstrap-table").on("check.bs.table uncheck.bs.table check-all.bs.table uncheck-all.bs.table", function () {
var ids = $("#bootstrap-table").bootstrapTable("getSelections");
$('#toolbar .btn-del').toggleClass('disabled', !ids.length);
$('#toolbar .btn-edit').toggleClass('disabled', ids.length!=1);;
$('#toolbar .btn-edit').toggleClass('disabled', ids.length!=1);
});
// tree表格树 展开/折叠
var expandFlag = false;
@ -191,3 +190,7 @@ $.ajaxSetup({
}
}
});
layer.config({
extend: 'moon/style.css',
skin: 'layer-ext-moon'
});

View File

@ -1,6 +1,6 @@
/**
* 通用js方法封装处理
* Copyright (c) 2018 ruoyi
* Copyright (c) 2019 ruoyi
*/
(function ($) {
$.extend({
@ -18,6 +18,7 @@
_sortName = $.common.isEmpty(options.sortName) ? "" : options.sortName;
_striped = $.common.isEmpty(options.striped) ? false : options.striped;
_escape = $.common.isEmpty(options.escape) ? false : options.escape;
_showFooter = $.common.isEmpty(options.showFooter) ? false : options.showFooter;
$('#bootstrap-table').bootstrapTable({
url: options.url, // 请求后台的URL*
contentType: "application/x-www-form-urlencoded", // 编码类型
@ -33,6 +34,7 @@
pageSize: 10, // 每页的记录行数(*
pageList: [10, 25, 50], // 可供选择的每页的行数(*
escape: _escape, // 转义HTML字符串
showFooter: _showFooter, // 是否显示表尾
iconSize: 'outline', // 图标大小undefined默认的按钮尺寸 xs超小按钮sm小按钮lg大按钮
toolbar: '#toolbar', // 指定工作栏
sidePagination: "server", // 启用服务端分页
@ -67,6 +69,13 @@
return { rows: [], total: 0 };
}
},
// 序列号生成
serialNumber: function (index) {
var table = $('#bootstrap-table').bootstrapTable('getOptions');
var pageSize = table.pageSize;
var pageNumber = table.pageNumber;
return pageSize * (pageNumber - 1) + index + 1;
},
// 搜索-默认第一个form
search: function(formId) {
var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;
@ -85,7 +94,7 @@
}
$("#bootstrap-table").bootstrapTable('refresh', params);
},
// 下载-默认第一个form
// 导出数据
exportExcel: function(formId) {
var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId;
$.modal.loading("正在导出数据,请稍后...");
@ -98,6 +107,63 @@
$.modal.closeLoading();
});
},
// 下载模板
importTemplate: function() {
$.get($.table._option.importTemplateUrl, function(result) {
if (result.code == web_status.SUCCESS) {
window.location.href = ctx + "common/download?fileName=" + result.msg + "&delete=" + true;
} else {
$.modal.alertError(result.msg);
}
});
},
// 导入数据
importExcel: function(formId) {
var currentId = $.common.isEmpty(formId) ? 'importForm' : formId;
$.form.reset(currentId);
layer.open({
type: 1,
area: ['400px', '230px'],
fix: false,
//不固定
maxmin: true,
shade: 0.3,
title: '导入' + $.table._option.modalName + '数据',
content: $('#' + currentId),
btn: ['<i class="fa fa-check"></i> 导入', '<i class="fa fa-remove"></i> 取消'],
// 弹层外区域关闭
shadeClose: true,
btn1: function(index, layero){
var file = layero.find('#file').val();
if (file == '' || (!$.common.endWith(file, '.xls') && !$.common.endWith(file, '.xlsx'))){
$.modal.msgWarning("请选择后缀为 “xls”或“xlsx”的文件。");
return false;
}
var index = layer.load(2, {shade: false});
var formData = new FormData();
formData.append("file", $('#file')[0].files[0]);
formData.append("updateSupport", $("input[name='updateSupport']").is(':checked'));
$.ajax({
url: $.table._option.importUrl,
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function (result) {
if (result.code == web_status.SUCCESS) {
$.modal.closeAll();
$.modal.alertSuccess(result.msg);
$.table.refresh();
} else {
layer.close(index);
$.modal.alertError(result.msg);
}
}
});
}
});
},
// 刷新表格
refresh: function() {
$("#bootstrap-table").bootstrapTable('refresh', {
@ -281,6 +347,10 @@
var index = parent.layer.getFrameIndex(window.name);
parent.layer.close(index);
},
// 关闭全部窗体
closeAll: function () {
layer.closeAll();
},
// 确认窗体
confirm: function (content, callBack) {
layer.confirm(content, {
@ -384,11 +454,27 @@
shade: 0.3,
title: title,
content: url,
btn: ['确定', '关闭'],
// 弹层外区域关闭
shadeClose: true
shadeClose: true,
yes: function(index, layero) {
var iframeWin = layero.find('iframe')[0];
iframeWin.contentWindow.submitHandler();
},
cancel: function(index) {
return true;
}
});
layer.full(index);
},
// 禁用按钮
disable: function() {
$("a[class*=layui-layer-btn]", window.parent.document).addClass("layer-disabled");
},
// 启用按钮
enable: function() {
$("a[class*=layui-layer-btn]", window.parent.document).removeClass("layer-disabled");
},
// 打开遮罩层
loading: function (message) {
$.blockUI({ message: '<div class="loaderbox"><div class="loading-activity"></div> ' + message + '</div>' });
@ -408,12 +494,14 @@
operate: {
// 提交数据
submit: function(url, type, dataType, data) {
$.modal.loading("正在处理中,请稍后...");
var config = {
url: url,
type: type,
dataType: dataType,
data: data,
beforeSend: function () {
$.modal.loading("正在处理中,请稍后...");
},
success: function(result) {
$.operate.ajaxSuccess(result);
}
@ -424,6 +512,10 @@
post: function(url, data) {
$.operate.submit(url, "post", "json", data);
},
// get请求传输
get: function(url) {
$.operate.submit(url, "get", "json", "");
},
// 详细信息
detail: function(id, width, height) {
var _url = $.common.isEmpty(id) ? $.table._option.detailUrl : $.table._option.detailUrl.replace("{id}", id);
@ -434,7 +526,7 @@
_width = 'auto';
_height = 'auto';
}
layer.open({
top.layer.open({
type: 2,
area: [_width + 'px', _height + 'px'],
fix: false,
@ -443,15 +535,12 @@
shade: 0.3,
title: $.table._option.modalName + "详细",
content: _url,
btn: '关闭',
btn: ['关闭'],
// 弹层外区域关闭
shadeClose: true,
success: function(layer) {
layer[0].childNodes[3].childNodes[0].attributes[0].value='layui-layer-btn1';
},
btn1: function(index) {
layer.close(index);
}
cancel: function(index){
return true;
}
});
},
// 删除信息
@ -530,12 +619,15 @@
},
// 保存信息
save: function(url, data) {
$.modal.loading("正在处理中,请稍后...");
var config = {
url: url,
type: "post",
dataType: "json",
data: data,
beforeSend: function () {
$.modal.loading("正在处理中,请稍后...");
$.modal.disable();
},
success: function(result) {
$.operate.successCallback(result);
}
@ -579,6 +671,7 @@
$.modal.alertError(result.msg);
}
$.modal.closeLoading();
$.modal.enable();
}
},
// 校验封装处理
@ -744,6 +837,17 @@
}
return true;
},
// 不允许最后层级节点选择
notAllowLastLevel: function(_tree) {
var nodes = _tree.getSelectedNodes();
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].level == nodes.length + 1) {
$.modal.msgError("不能选择最后层级节点(" + nodes[i].name + "");
return false;
}
}
return true;
},
// 隐藏/显示搜索栏
toggleSearch: function() {
$('#search').slideToggle(200);

View File

@ -1,7 +1,6 @@
$(function() {
validateRule();
$(".i-checks").iCheck({checkboxClass:"icheckbox_square-green-login"});
$('.imgcode').click(function() {
var url = ctx + "captcha/captchaImage?type=" + captchaType + "&s=" + Math.random();
$(".imgcode").attr("src", url);

View File

@ -22,7 +22,7 @@
<!-- bootstrap-table 表格插件 -->
<script th:src="@{/ajax/libs/bootstrap-table/bootstrap-table.min.js}"></script>
<script th:src="@{/ajax/libs/bootstrap-table/locale/bootstrap-table-zh-CN.min.js}"></script>
<script th:src="@{/ajax/libs/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js}"></script>
<script th:src="@{/ajax/libs/bootstrap-table/extensions/mobile/bootstrap-table-mobile.js}"></script>
<script th:src="@{/ajax/libs/bootstrap-table/extensions/toolbar/bootstrap-table-toolbar.min.js}"></script>
<!-- jquery-validate 表单验证插件 -->
<script th:src="@{/ajax/libs/validate/jquery.validate.min.js}"></script>
@ -38,8 +38,8 @@
<script th:src="@{/ajax/libs/iCheck/icheck.min.js}"></script>
<script th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script th:src="@{/ajax/libs/layui/layui.js}"></script>
<script th:src="@{/ruoyi/js/common.js?v=3.1.0}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=3.1.0}"></script>
<script th:src="@{/ruoyi/js/common.js?v=3.2.0}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=3.2.0}"></script>
<script src="http://tajs.qq.com/stats?sId=62048022"></script>
<script th:inline="javascript"> var ctx = [[@{/}]]; </script>
</div>

View File

@ -15,7 +15,8 @@
<link th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
<link th:href="@{/css/animate.css}" rel="stylesheet"/>
<link th:href="@{/css/style.css}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=3.1.0}" rel="stylesheet"/>
<link th:href="@{/css/skins.css}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=3.2.0}" rel="stylesheet"/>
<style type="text/css">
.nav > li:hover .dropdown-menu {display: block;}
#content-main.max { height: calc(100% - 110px); overflow: hidden; width: 100%; height: 100%; left: 0px; position: absolute; top: 0px; z-index: 9998; margin: 0; }
@ -31,19 +32,24 @@
</div>
<div class="sidebar-collapse">
<ul class="nav" id="side-menu">
<li class="nav-header">
<div class="dropdown profile-element"> <span>
<img th:src="(${user.avatar} == '') ? @{/img/profile.jpg} : @{/profile/avatar/} + ${user.avatar}" alt="image" class="img-circle" height="60" width="60"/></span>
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear"><span class="block m-t-xs"><strong class="font-bold" th:text="${user.userName}">用户</strong></span>
<span class="text-muted text-xs block"><span th:text="${user.dept?.deptName}">部门</span> <b class="caret"></b></span> </span> </a>
<ul class="dropdown-menu animated fadeInRight m-t-xs">
<li><a class="menuItem" th:href="@{/system/user/profile}">个人信息</a></li>
<li class="divider"></li>
<li><a th:href="@{logout}">退出</a></li>
</ul>
</div>
</li>
<li class="logo">
<span class="logo-lg">RuoYi</span>
</li>
<li>
<div class="user-panel">
<a class="menuItem" title="个人中心" th:href="@{/system/user/profile}">
<div class="hide" th:text="个人中心"></div>
<div class="pull-left image">
<img th:src="(${user.avatar} == '') ? @{/img/profile.jpg} : @{/profile/avatar/} + ${user.avatar}" class="img-circle" alt="User Image">
</div>
</a>
<div class="pull-left info">
<p>[[${user.loginName}]]</p>
<a href="#"><i class="fa fa-circle text-success"></i> 在线</a>
<a th:href="@{logout}" style="padding-left:5px;"><i class="fa fa-sign-out text-danger"></i> 注销</a>
</div>
</div>
</li>
<li class="active">
<a href="index.html"><i class="fa fa-home"></i> <span class="nav-label">主页</span> <span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
@ -74,20 +80,35 @@
<!--右侧部分开始-->
<div id="page-wrapper" class="gray-bg dashbard-1">
<div class="row border-bottom">
<nav class="navbar navbar-static-top" role="navigation"
style="margin-bottom: 0">
<nav class="navbar navbar-static-top" role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<a class="navbar-minimalize minimalize-styl-2 btn btn-default " href="#" title="收起菜单">
<a class="navbar-minimalize minimalize-styl-2" style="color:#FFF;" href="#" title="收起菜单">
<i class="fa fa-bars"></i>
</a>
</div>
<ul class="nav navbar-top-links navbar-right welcome-message">
<li>
<span class="m-r-sm text-muted">欢迎来到若依管理后台.</span>
</li>
<li><a id="fullScreen"><i class="fa fa-arrows-alt"></i>全屏</a></li>
<li><a th:href="@{logout}"><i class="fa fa-sign-out"></i>退出</a></li>
<li><a title="全屏显示" id="fullScreen"><i class="fa fa-arrows-alt"></i> 全屏显示</a></li>
<li class="dropdown user-menu">
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown">
<img th:src="(${user.avatar} == '') ? @{/img/profile.jpg} : @{/profile/avatar/} + ${user.avatar}" class="user-image">
<span class="hidden-xs">[[${user.userName}]]</span>
</a>
<ul class="dropdown-menu">
<li class="mt5">
<a th:href="@{/system/user/profile}" class="menuItem">
<i class="fa fa-user"></i> 个人中心</a>
</li>
<li>
<a onclick="resetPwd()" class="menuItem">
<i class="fa fa-key"></i> 修改密码</a>
</li>
<li class="divider"></li>
<li>
<a th:href="@{logout}">
<i class="fa fa-sign-out"></i> 退出登录</a>
</li>
</ul>
</li>
</ul>
</nav>
</div>
@ -135,9 +156,18 @@
<script th:src="@{/js/plugins/metisMenu/jquery.metisMenu.js}"></script>
<script th:src="@{/js/plugins/slimscroll/jquery.slimscroll.min.js}"></script>
<script th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script src="http://tajs.qq.com/stats?sId=62048022"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=3.1.0}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=3.2.0}"></script>
<script th:src="@{/ruoyi/index.js}"></script>
<script th:src="@{/ajax/libs/fullscreen/jquery.fullscreen.js}"></script>
<script th:inline="javascript">
var ctx = [[@{/}]];
/*用户管理-重置密码*/
function resetPwd() {
var url = ctx + 'system/user/profile/resetPwd';
$.modal.open("重置密码", url, '800', '500');
}
</script>
</body>
</html>

View File

@ -11,8 +11,7 @@
<link href="../static/css/font-awesome.min.css" th:href="@{css/font-awesome.min.css}" rel="stylesheet"/>
<link href="../static/css/style.css" th:href="@{css/style.css}" rel="stylesheet"/>
<link href="../static/css/login.min.css" th:href="@{css/login.min.css}" rel="stylesheet"/>
<link href="../static/ajax/libs/iCheck/custom.css" th:href="@{/ajax/libs/iCheck/custom.css}" rel="stylesheet"/>
<link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=3.1.0}" rel="stylesheet"/>
<link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=3.2.0}" rel="stylesheet"/>
<!--[if lt IE 9]>
<meta http-equiv="refresh" content="0;ie.html" />
<![endif]-->
@ -49,8 +48,8 @@
<h4 class="no-margins">登录:</h4>
<p class="m-t-md">你若不离不弃,我必生死相依</p>
<input type="text" name="username" class="form-control uname" placeholder="用户名" value="admin" />
<input type="password" name="password" class="form-control pword m-b" placeholder="密码" value="admin123" />
<div class="row" th:if="${captchaEnabled==true}">
<input type="password" name="password" class="form-control pword" placeholder="密码" value="admin123" />
<div class="row m-t" th:if="${captchaEnabled==true}">
<div class="col-xs-6">
<input type="text" name="validateCode" class="form-control code" placeholder="验证码" maxlength="5">
</div>
@ -60,7 +59,9 @@
</a>
</div>
</div>
<input class="i-checks" type="checkbox" name="rememberme" />&nbsp;&nbsp;记住我
<div class="checkbox-custom">
<input type="checkbox" id="rememberme" name="rememberme"> <label for="rememberme">记住我</label>
</div>
<button class="btn btn-success btn-block" id="btnSubmit" data-loading="正在验证登录,请稍后...">登录</button>
</form>
</div>
@ -80,10 +81,9 @@
<script src="../static/ajax/libs/validate/jquery.validate.min.js" th:src="@{/ajax/libs/validate/jquery.validate.min.js}"></script>
<script src="../static/ajax/libs/validate/messages_zh.min.js" th:src="@{/ajax/libs/validate/messages_zh.min.js}"></script>
<script src="../static/ajax/libs/layer/layer.min.js" th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script src="../static/ajax/libs/iCheck/icheck.min.js" th:src="@{/ajax/libs/iCheck/icheck.min.js}"></script>
<script src="../static/ajax/libs/blockUI/jquery.blockUI.js" th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script src="http://tajs.qq.com/stats?sId=62048022"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=3.1.0}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=3.2.0}"></script>
<script src="../static/ruoyi/login.js" th:src="@{/ruoyi/login.js}"></script>
</body>
</html>

View File

@ -77,7 +77,7 @@
<div class="ibox-content">
<p><i class="fa fa-send-o"></i> 官网:<a href="http://www.ruoyi.vip" target="_blank">http://www.ruoyi.vip</a>
</p>
<p><i class="fa fa-qq"></i> QQ群<s>满1389287</s> <a href="https://jq.qq.com/?_wv=1027&k=5cHeRVW" target="_blank">1679294</a>
<p><i class="fa fa-qq"></i> QQ群<s>满1389287</s> <s>满1679294</s> <a href="https://jq.qq.com/?_wv=1027&k=5YW0wjE" target="_blank">1529866</a>
</p>
<p><i class="fa fa-weixin"></i> 微信:<a href="javascript:;">/ *若依</a>
</p>
@ -94,13 +94,53 @@
<div class="ibox-content no-padding">
<div class="panel-body">
<div class="panel-group" id="version">
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title">
<a data-toggle="collapse" data-parent="#version" href="#v32">v3.2.0</a><code class="pull-right">2019.01.18</code>
</h5>
</div>
<div id="v32" class="panel-collapse collapse in">
<div class="panel-body">
<ol>
<li>部门修改时不允许选择最后节点</li>
<li>修复部门菜单排序字段无效</li>
<li>修复光驱磁盘导致服务监控异常</li>
<li>登录界面去除check插件</li>
<li>验证码文本字符间距修正</li>
<li>升级SpringBoot到最新版本2.1.1</li>
<li>升级MYSQL驱动</li>
<li>修正登录必填项位置偏移</li>
<li>Session会话检查优化</li>
<li>Excel注解支持多级获取</li>
<li>新增序列号生成方法</li>
<li>修复WAR部署tomcat退出线程异常</li>
<li>全屏操作增加默认确认/关闭</li>
<li>修复个人信息可能导致漏洞</li>
<li>字典数据根据下拉选择新增类型</li>
<li>升级Summernote到最新版本v0.8.11</li>
<li>新增用户数据导入</li>
<li>首页主题样式更换</li>
<li>layer扩展主题更换</li>
<li>用户管理移动端默认隐藏左侧布局</li>
<li>详细信息弹出层显示在顶层</li>
<li>表格支持切换状态(用户/角色/定时任务)</li>
<li>Druid数据源支持配置继承</li>
<li>修正部分iPhone手机端表格适配问题</li>
<li>新增防止重复提交表单方法</li>
<li>新增表格数据统计汇总方法</li>
<li>支持富文本上传图片文件</li>
</ol>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title">
<a data-toggle="collapse" data-parent="#version" href="#v31">v3.1.0</a><code class="pull-right">2018.12.03</code>
</h5>
</div>
<div id="v31" class="panel-collapse collapse in">
<div id="v31" class="panel-collapse collapse">
<div class="panel-body">
<ol>
<li>新增内网不获取IP地址</li>

View File

@ -107,12 +107,12 @@
title: '执行表达式'
},
{
field: 'status',
title: '任务状态',
align: 'center',
formatter: function(value, row, index) {
return $.table.selectDictLabel(datas, value);
}
visible: statusFlag == 'hidden' ? false : true,
title: '任务状态',
align: 'center',
formatter: function (value, row, index) {
return statusTools(row);
}
},
{
field: 'createTime',
@ -124,7 +124,6 @@
align: 'center',
formatter: function(value, row, index) {
var actions = [];
actions.push(statusTools(row));
actions.push('<a class="btn btn-primary btn-xs ' + statusFlag + '" href="#" onclick="run(\'' + row.jobId + '\')"><i class="fa fa-play-circle-o"></i> 执行</a> ');
actions.push('<a class="btn btn-warning btn-xs ' + detailFlag + '" href="#" onclick="$.operate.detail(\'' + row.jobId + '\')"><i class="fa fa-search"></i>详细</a> ');
return actions.join('');
@ -133,37 +132,38 @@
};
$.table.init(options);
});
/* 调度任务状态显示 */
function statusTools(row) {
if (row.status == 1) {
return '<a class="btn btn-info btn-xs ' + statusFlag + '" href="#" onclick="start(\'' + row.jobId + '\')"><i class="fa fa-play"></i>启用</a> ';
} else {
return '<a class="btn btn-danger btn-xs ' + statusFlag + '" href="#" onclick="stop(\'' + row.jobId + '\')"><i class="fa fa-pause"></i>暂停</a> ';
}
return '<i class=\"fa fa-toggle-off text-info fa-2x\" onclick="start(\'' + row.jobId + '\')"></i> ';
} else {
return '<i class=\"fa fa-toggle-on text-info fa-2x\" onclick="stop(\'' + row.jobId + '\')"></i> ';
}
}
/*立即执行一次*/
/* 立即执行一次 */
function run(jobId) {
$.modal.confirm("确认要立即执行任务吗?", function() {
$.operate.post(prefix + "/run", { "jobId": jobId});
})
}
/*调度任务-停用*/
/* 调度任务-停用 */
function stop(jobId) {
$.modal.confirm("确认要停用任务吗?", function() {
$.operate.post(prefix + "/changeStatus", { "jobId": jobId, "status": 1 });
})
}
/*调度任务-启用*/
/* 调度任务-启用 */
function start(jobId) {
$.modal.confirm("确认要启用任务吗?", function() {
$.operate.post(prefix + "/changeStatus", { "jobId": jobId, "status": 0 });
})
}
//调度日志查询
/* 调度日志查询 */
function jobLog(id) {
var url = ctx + 'monitor/jobLog';
createMenuItem(url, "调度日志");

View File

@ -53,6 +53,12 @@
columns: [{
checkbox: true
},
{
title: "序号",
formatter: function (value, row, index) {
return $.table.serialNumber(index);
}
},
{
field: 'sessionId',
title: '会话编号'

View File

@ -123,10 +123,13 @@
}
function doSubmit(index, layero){
var body = layer.getChildFrame('body', index);
$("#treeId").val(body.find('#treeId').val());
$("#treeName").val(body.find('#treeName').val());
layer.close(index);
var tree = layero.find("iframe")[0].contentWindow.$._tree;
if ($.tree.notAllowLastLevel(tree)) {
var body = layer.getChildFrame('body', index);
$("#treeId").val(body.find('#treeId').val());
$("#treeName").val(body.find('#treeName').val());
layer.close(index);
}
}
</script>
</body>

View File

@ -35,7 +35,7 @@
</div>
<div class="btn-group-sm hidden-xs" id="toolbar" role="group">
<a class="btn btn-success" th:onclick="'javascript:$.operate.add(\''+${dict.dictType}+'\')'" shiro:hasPermission="system:dict:add">
<a class="btn btn-success" onclick="add()" shiro:hasPermission="system:dict:add">
<i class="fa fa-plus"></i> 新增
</a>
<a class="btn btn-primary btn-edit disabled" onclick="$.operate.edit()" shiro:hasPermission="system:dict:edit">
@ -135,6 +135,12 @@
isAsc: params.order
};
}
/*字典数据-新增字典*/
function add() {
var dictType = $("#dictType option:selected").val();
$.operate.add(dictType);
}
</script>
</body>
</html>

View File

@ -37,12 +37,6 @@
</div>
</div>
</div>
<div class="form-group">
<div class="form-control-static col-sm-offset-9">
<button type="submit" class="btn btn-primary">提交</button>
<button onclick="$.modal.close()" class="btn btn-danger" type="button">关闭</button>
</div>
</div>
</form>
</div>
<div th:include="include::footer"></div>
@ -50,24 +44,57 @@
<script th:src="@{/ajax/libs/summernote/summernote-zh-CN.js}"></script>
<script type="text/javascript">
var prefix = ctx + "system/notice";
$('.summernote').summernote({
height : '220px',
lang : 'zh-CN'
lang : 'zh-CN',
callbacks: {
onImageUpload: function (files) {
sendFile(files[0], this);
}
}
});
// 上传文件
function sendFile(file, obj) {
var data = new FormData();
data.append("file", file);
$.ajax({
type: "POST",
url: ctx + "common/upload",
data: data,
cache: false,
contentType: false,
processData: false,
dataType: 'json',
success: function(result) {
if (result.code == web_status.SUCCESS) {
$(obj).summernote('editor.insertImage', result.url, result.fileName);
} else {
$.modal.alertError(result.msg);
}
},
error: function(error) {
$.modal.alertWarning("图片上传失败。");
}
});
}
$("#form-notice-add").validate({
rules:{
noticeTitle:{
required:true,
}
},
submitHandler: function(form) {
var sHTML = $('.summernote').code();
$("#noticeContent").val(sHTML);
$.operate.save(prefix + "/add", $('#form-notice-add').serialize());
}
});
function submitHandler() {
if ($.validate.form()) {
var sHTML = $('.summernote').summernote('code');
$("#noticeContent").val(sHTML);
$.operate.save(prefix + "/add", $('#form-notice-add').serialize());
}
}
</script>
</body>
</html>

View File

@ -38,12 +38,6 @@
</div>
</div>
</div>
<div class="form-group">
<div class="form-control-static col-sm-offset-9">
<button type="submit" class="btn btn-primary">提交</button>
<button onclick="$.modal.close()" class="btn btn-danger" type="button">关闭</button>
</div>
</div>
</form>
</div>
<div th:include="include::footer"></div>
@ -54,25 +48,58 @@
$(function() {
$('.summernote').summernote({
height : '220px',
lang : 'zh-CN'
height : '220px',
lang : 'zh-CN',
callbacks: {
onImageUpload: function (files) {
sendFile(files[0], this);
}
}
});
var content = $("#noticeContent").val();
$('#editor').code(content);
$('#editor').summernote('code', content);
});
// 上传文件
function sendFile(file, obj) {
var data = new FormData();
data.append("file", file);
$.ajax({
type: "POST",
url: ctx + "common/upload",
data: data,
cache: false,
contentType: false,
processData: false,
dataType: 'json',
success: function(result) {
if (result.code == web_status.SUCCESS) {
$(obj).summernote('editor.insertImage', result.url, result.fileName);
} else {
$.modal.alertError(result.msg);
}
},
error: function(error) {
$.modal.alertWarning("图片上传失败。");
}
});
}
$("#form-notice-edit").validate({
rules:{
xxxx:{
noticeTitle:{
required:true,
},
},
submitHandler: function(form) {
var sHTML = $('.summernote').code();
$("#noticeContent").val(sHTML);
$.operate.save(prefix + "/edit", $('#form-notice-edit').serialize());
}
}
});
function submitHandler() {
if ($.validate.form()) {
var sHTML = $('.summernote').summernote('code');
$("#noticeContent").val(sHTML);
$.operate.save(prefix + "/edit", $('#form-notice-edit').serialize());
}
}
</script>
</body>
</html>

View File

@ -100,12 +100,12 @@
sortable: true
},
{
field: 'status',
title: '状态',
align: 'center',
formatter: function(value, row, index) {
return $.table.selectDictLabel(datas, value);
}
visible: editFlag == 'hidden' ? false : true,
title: '角色状态',
align: 'center',
formatter: function (value, row, index) {
return statusTools(row);
}
},
{
field: 'createTime',
@ -127,11 +127,34 @@
$.table.init(options);
});
/*角色管理-分配数据权限*/
/* 角色管理-分配数据权限 */
function rule(roleId) {
var url = prefix + '/rule/' + roleId;
$.modal.open("分配数据权限", url);
}
/* 角色状态显示 */
function statusTools(row) {
if (row.status == 1) {
return '<i class=\"fa fa-toggle-off text-info fa-2x\" onclick="enable(\'' + row.roleId + '\')"></i> ';
} else {
return '<i class=\"fa fa-toggle-on text-info fa-2x\" onclick="disable(\'' + row.roleId + '\')"></i> ';
}
}
/* 角色管理-停用 */
function disable(roleId) {
$.modal.confirm("确认要停用角色吗?", function() {
$.operate.post(prefix + "/changeStatus", { "roleId": roleId, "status": 1 });
})
}
/* 角色管理启用 */
function enable(roleId) {
$.modal.confirm("确认要启用角色吗?", function() {
$.operate.post(prefix + "/changeStatus", { "roleId": roleId, "status": 0 });
})
}
</script>
</body>
</html>

View File

@ -184,7 +184,7 @@
/*用户管理-修改-选择部门树*/
function selectDeptTree() {
var deptId = $("#treeId").val();
var deptId = $.common.isEmpty($("#treeId").val()) ? "100" : $("#treeId").val();
var url = ctx + "system/dept/selectDeptTree/" + deptId;
var options = {
title: '选择部门',

View File

@ -4,7 +4,6 @@
<title>用户头像修改</title>
<link th:href="@{/ajax/libs/cropbox/cropbox.css}" rel="stylesheet"/>
<body class="white-bg">
<input name="userId" id="userId" type="hidden" th:value="${user.userId}" />
<div class="container">
<div class="imageBox">
<div class="thumbBox"></div>
@ -39,7 +38,7 @@ $(window).load(function() {
options.imgSrc = e.target.result;
//根据MIME判断上传的文件是不是图片类型
if((options.imgSrc).indexOf("image/")==-1){
parent.layer.alert("文件格式错误,请上传图片类型,如JPG,JEPGPNG后缀的文件。", {icon: 2,title:"系统提示"});
$.modal.alertWarning("文件格式错误,请上传图片类型,如JPG,JEPGPNG后缀的文件。");
} else {
cropper = $('.imageBox').cropbox(options);
}
@ -68,7 +67,6 @@ function submitHandler() {
var img = cropper.getBlob();
var formdata = new FormData();
formdata.append("avatarfile", img);
formdata.append("userId", $("#userId").val());
$.ajax({
url: ctx + "system/user/profile/updateAvatar",
data: formdata,

View File

@ -58,20 +58,19 @@
<div th:include="include::footer"></div>
<script>
var userId = [[${user.userId}]];
/*用户信息-修改*/
function edit() {
var url = ctx + "system/user/profile/edit/" + userId;
var url = ctx + 'system/user/profile/edit';
$.modal.open("修改用户", url);
}
/*用户管理-重置密码*/
function resetPwd() {
var url = ctx + 'system/user/profile/resetPwd/' + userId;
var url = ctx + 'system/user/profile/resetPwd';
$.modal.open("重置密码", url, '800', '500');
}
/*用户管理-头像*/
function avatar() {
var url = ctx + 'system/user/profile/avatar/' + userId;
var url = ctx + 'system/user/profile/avatar';
$.modal.open("修改头像", url);
}
</script>

View File

@ -21,7 +21,7 @@
<div class="form-group">
<label class="col-sm-3 control-label">新密码:</label>
<div class="col-sm-8">
<input class="form-control" type="password" name="password" id="password">
<input class="form-control" type="password" name="newPassword" id="newPassword">
</div>
</div>
<div class="form-group">
@ -51,14 +51,14 @@
}
}
},
password: {
newPassword: {
required: true,
minlength: 5,
maxlength: 20
},
confirm: {
required: true,
equalTo: "#password"
equalTo: "#newPassword"
}
},
messages: {
@ -66,7 +66,7 @@
required: "请输入原密码",
remote: "原密码错误"
},
password: {
newPassword: {
required: "请输入新密码",
minlength: "密码不能小于6个字符",
maxlength: "密码不能大于20个字符"

View File

@ -73,6 +73,9 @@
<a class="btn btn-danger btn-del disabled" onclick="$.operate.removeAll()" shiro:hasPermission="system:user:remove">
<i class="fa fa-remove"></i> 删除
</a>
<a class="btn btn-info" onclick="$.table.importExcel()" shiro:hasPermission="system:user:import">
<i class="fa fa-download"></i> 导入
</a>
<a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="system:user:export">
<i class="fa fa-download"></i> 导出
</a>
@ -83,6 +86,7 @@
</div>
</div>
</div>
<div th:include="include :: footer"></div>
<script th:src="@{/ajax/libs/jquery-layout/jquery.layout-latest.js}"></script>
<script th:src="@{/ajax/libs/jquery-ztree/3.5/js/jquery.ztree.all-3.5.js}"></script>
@ -94,9 +98,13 @@
var prefix = ctx + "system/user";
$(function() {
$('body').layout({ west__size: 185 });
queryUserList();
queryDeptTree();
var panehHidden = false;
if ($(this).width() < 769) {
panehHidden = true;
}
$('body').layout({ initClosed: panehHidden, west__size: 185 });
queryUserList();
queryDeptTree();
});
function queryUserList() {
@ -106,6 +114,8 @@
updateUrl: prefix + "/edit/{id}",
removeUrl: prefix + "/remove",
exportUrl: prefix + "/export",
importUrl: prefix + "/importData",
importTemplateUrl: prefix + "/importTemplate",
sortName: "createTime",
sortOrder: "desc",
modalName: "用户",
@ -141,12 +151,12 @@
title: '手机'
},
{
field: 'status',
title: '状态',
align: 'center',
formatter: function(value, row, index) {
return $.table.selectDictLabel(datas, value);
}
visible: editFlag == 'hidden' ? false : true,
title: '用户状态',
align: 'center',
formatter: function (value, row, index) {
return statusTools(row);
}
},
{
field: 'createTime',
@ -201,17 +211,52 @@
queryDeptTree();
});
/*用户管理-部门*/
/* 用户管理-部门 */
function dept() {
var url = ctx + "system/dept";
createMenuItem(url, "部门管理");
}
/*用户管理-重置密码*/
/* 用户管理-重置密码 */
function resetPwd(userId) {
var url = prefix + '/resetPwd/' + userId;
$.modal.open("重置密码", url, '800', '300');
}
/* 用户状态显示 */
function statusTools(row) {
if (row.status == 1) {
return '<i class=\"fa fa-toggle-off text-info fa-2x\" onclick="enable(\'' + row.userId + '\')"></i> ';
} else {
return '<i class=\"fa fa-toggle-on text-info fa-2x\" onclick="disable(\'' + row.userId + '\')"></i> ';
}
}
/* 用户管理-停用 */
function disable(userId) {
$.modal.confirm("确认要停用用户吗?", function() {
$.operate.post(prefix + "/changeStatus", { "userId": userId, "status": 1 });
})
}
/* 用户管理启用 */
function enable(userId) {
$.modal.confirm("确认要启用用户吗?", function() {
$.operate.post(prefix + "/changeStatus", { "userId": userId, "status": 0 });
})
}
</script>
</body>
<form id="importForm" enctype="multipart/form-data" class="mt20 mb10" style="display: none;">
<div class="col-xs-offset-1">
<input type="file" id="file" name="file"/>
<div class="mt10 pt5">
<input type="checkbox" id="updateSupport" name="updateSupport" title="如果登录账户已经存在,更新这条数据。"> 是否更新已经存在的用户数据
&nbsp; <a onclick="$.table.importTemplate()" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> 下载模板</a>
</div>
<font color="red" class="pull-left mt10">
提示仅允许导入“xls”或“xlsx”格式文件
</font>
</div>
</form>
</html>

View File

@ -55,6 +55,12 @@
columns: [{
checkbox: true
},
{
title: "序号",
formatter: function (value, row, index) {
return $.table.serialNumber(index);
}
},
{
field: 'tableName',
title: '表名称',

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.1</version>
<version>3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -37,7 +37,7 @@ public @interface Excel
/**
* 导出时在excel中每个列的宽 单位为字符
*/
public double width() default 20;
public double width() default 16;
/**
* 文字后缀,如% 90 变成90%
@ -63,4 +63,30 @@ public @interface Excel
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
public boolean isExport() default true;
/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
public String targetAttr() 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;
}
}
}

View File

@ -86,7 +86,7 @@ public class Global
*/
public static String getVersion()
{
return StringUtils.nvl(getConfig("ruoyi.version"), "3.0.0");
return StringUtils.nvl(getConfig("ruoyi.version"), "3.2.0");
}
/**
@ -122,13 +122,21 @@ public class Global
}
/**
* 获取下载上传路径
* 获取下载路径
*/
public static String getDownloadPath()
{
return getConfig("ruoyi.profile") + "download/";
}
/**
* 获取上传路径
*/
public static String getUploadPath()
{
return getConfig("ruoyi.profile") + "upload/";
}
/**
* 获取作者
*/

View File

@ -0,0 +1,24 @@
package com.ruoyi.common.exception;
/**
* 业务异常
*
* @author ruoyi
*/
public class BusinessException extends RuntimeException
{
private static final long serialVersionUID = 1L;
protected final String message;
public BusinessException(String message)
{
this.message = message;
}
@Override
public String getMessage()
{
return message;
}
}

View File

@ -1,4 +1,4 @@
package com.ruoyi.framework.web.page;
package com.ruoyi.common.page;
import com.ruoyi.common.utils.StringUtils;

View File

@ -1,4 +1,4 @@
package com.ruoyi.framework.web.page;
package com.ruoyi.common.page;
import java.io.Serializable;
import java.util.List;

View File

@ -0,0 +1,406 @@
package com.ruoyi.common.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.support.Convert;
import com.ruoyi.common.utils.DateUtils;
/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
*
* @author ruoyi
*/
@SuppressWarnings("rawtypes")
public class ReflectUtils
{
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
/**
* 调用Getter方法.
* 支持多级,如:对象名.对象名.方法
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName)
{
Object object = obj;
for (String name : StringUtils.split(propertyName, "."))
{
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
return (E) object;
}
/**
* 调用Setter方法, 仅匹配方法名。
* 支持多级,如:对象名.对象名.方法
*/
public static <E> void invokeSetter(Object obj, String propertyName, E value)
{
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i = 0; i < names.length; i++)
{
if (i < names.length - 1)
{
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
else
{
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
}
}
}
/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue(final Object obj, final String fieldName)
{
Field field = getAccessibleField(obj, fieldName);
if (field == null)
{
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return null;
}
E result = null;
try
{
result = (E) field.get(obj);
}
catch (IllegalAccessException e)
{
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}
/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
{
Field field = getAccessibleField(obj, fieldName);
if (field == null)
{
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try
{
field.set(obj, value);
}
catch (IllegalAccessException e)
{
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型,
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args)
{
if (obj == null || methodName == null)
{
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null)
{
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try
{
return (E) method.invoke(obj, args);
}
catch (Exception e)
{
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名,如果有多个同名函数调用第一个。
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
{
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null)
{
// 如果为空不报错,直接返回空。
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try
{
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i = 0; i < cs.length; i++)
{
if (args[i] != null && !args[i].getClass().equals(cs[i]))
{
if (cs[i] == String.class)
{
args[i] = Convert.toStr(args[i]);
if (StringUtils.endsWith((String) args[i], ".0"))
{
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
}
else if (cs[i] == Integer.class)
{
args[i] = Convert.toInt(args[i]);
}
else if (cs[i] == Long.class)
{
args[i] = Convert.toLong(args[i]);
}
else if (cs[i] == Double.class)
{
args[i] = Convert.toDouble(args[i]);
}
else if (cs[i] == Float.class)
{
args[i] = Convert.toFloat(args[i]);
}
else if (cs[i] == Date.class)
{
if (args[i] instanceof String)
{
args[i] = DateUtils.parseDate(args[i]);
}
else
{
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
}
}
}
return (E) method.invoke(obj, args);
}
catch (Exception e)
{
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName)
{
// 为空不报错。直接返回 null
if (obj == null)
{
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
{
try
{
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
}
catch (NoSuchFieldException e)
{
continue;
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes)
{
// 为空不报错。直接返回 null
if (obj == null)
{
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
{
try
{
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
}
catch (NoSuchMethodException e)
{
continue;
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名。
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
{
// 为空不报错。直接返回 null
if (obj == null)
{
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
{
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods)
{
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
{
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 改变private/protected的方法为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Method method)
{
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible())
{
method.setAccessible(true);
}
}
/**
* 改变private/protected的成员变量为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨。
*/
public static void makeAccessible(Field field)
{
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
{
field.setAccessible(true);
}
}
/**
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
* 如无法找到, 返回Object.class.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz)
{
return getClassGenricType(clazz, 0);
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*/
public static Class getClassGenricType(final Class clazz, final int index)
{
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType))
{
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0)
{
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class))
{
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
public static Class<?> getUserClass(Object instance)
{
if (instance == null)
{
throw new RuntimeException("Instance must not be null");
}
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
{
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass))
{
return superClass;
}
}
return clazz;
}
/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
{
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException)
{
return new IllegalArgumentException(msg, e);
}
else if (e instanceof InvocationTargetException)
{
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);
}
}

View File

@ -290,7 +290,7 @@ public class Convert
/**
* 转换为Integer数组<br>
*
* @param split 被转换的值
* @param str 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String str)
@ -301,7 +301,7 @@ public class Convert
/**
* 转换为Long数组<br>
*
* @param split 被转换的值
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String str)
@ -335,8 +335,8 @@ public class Convert
/**
* 转换为Long数组<br>
*
* @param isIgnoreConvertError 是否忽略转换错误忽略则给值null
* @param values 被转换的值
* @param split 分隔符
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String split, String str)
@ -358,7 +358,7 @@ public class Convert
/**
* 转换为String数组<br>
*
* @param split 被转换的值
* @param str 被转换的值
* @return 结果
*/
public static String[] toStrArray(String str)

View File

@ -10,10 +10,10 @@ import java.math.BigDecimal;
public class Arith
{
// 默认除法运算精度
/** 默认除法运算精度 */
private static final int DEF_DIV_SCALE = 10;
// 这个类不能实例化
/** 这个类不能实例化 */
private Arith()
{
}
@ -86,6 +86,10 @@ public class Arith
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
if (b1.compareTo(BigDecimal.ZERO) == 0)
{
return BigDecimal.ZERO.doubleValue();
}
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}

View File

@ -1,511 +0,0 @@
package com.ruoyi.common.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.config.Global;
/**
* Excel相关处理
*
* @author ruoyi
*/
public class ExcelUtil<T>
{
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
public Class<T> clazz;
public ExcelUtil(Class<T> clazz)
{
this.clazz = clazz;
}
/**
* 对excel表单默认第一个索引名转换成list
*
* @param input 输入流
* @return 转换后集合
*/
public List<T> importExcel(InputStream input) throws Exception
{
return importExcel(StringUtils.EMPTY, input);
}
/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 表格索引名
* @param input 输入流
* @return 转换后集合
*/
public List<T> importExcel(String sheetName, InputStream input) throws Exception
{
List<T> list = new ArrayList<T>();
Workbook workbook = WorkbookFactory.create(input);
Sheet sheet = null;
if (StringUtils.isNotEmpty(sheetName))
{
// 如果指定sheet名,则取指定sheet中的内容.
sheet = workbook.getSheet(sheetName);
}
else
{
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = workbook.getSheetAt(0);
}
if (sheet == null)
{
throw new IOException("文件sheet不存在");
}
int rows = sheet.getPhysicalNumberOfRows();
if (rows > 0)
{
// 默认序号
int serialNum = 0;
// 有数据时才处理 得到类的所有field.
Field[] allFields = clazz.getDeclaredFields();
// 定义一个map用于存放列的序号和field.
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
for (int col = 0; col < allFields.length; col++)
{
Field field = allFields[col];
// 将有注解的field存放到map中.
if (field.isAnnotationPresent(Excel.class))
{
// 设置类的私有字段属性可访问.
field.setAccessible(true);
fieldsMap.put(++serialNum, field);
}
}
for (int i = 1; i < rows; i++)
{
// 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i);
int cellNum = serialNum;
T entity = null;
for (int j = 0; j < cellNum; j++)
{
Cell cell = row.getCell(j);
if (cell == null)
{
continue;
}
else
{
// 先设置Cell的类型然后就可以把纯数字作为String类型读进来了
row.getCell(j).setCellType(CellType.STRING);
cell = row.getCell(j);
}
String c = cell.getStringCellValue();
if (StringUtils.isEmpty(c))
{
continue;
}
// 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field.
Field field = fieldsMap.get(j + 1);
// 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType();
if (String.class == fieldType)
{
field.set(entity, String.valueOf(c));
}
else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
{
field.set(entity, Integer.parseInt(c));
}
else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
{
field.set(entity, Long.valueOf(c));
}
else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
{
field.set(entity, Float.valueOf(c));
}
else if ((Short.TYPE == fieldType) || (Short.class == fieldType))
{
field.set(entity, Short.valueOf(c));
}
else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
{
field.set(entity, Double.valueOf(c));
}
else if (Character.TYPE == fieldType)
{
if ((c != null) && (c.length() > 0))
{
field.set(entity, Character.valueOf(c.charAt(0)));
}
}
else if (java.util.Date.class == fieldType)
{
if (cell.getCellTypeEnum() == CellType.NUMERIC)
{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
cell.setCellValue(sdf.format(cell.getNumericCellValue()));
c = sdf.format(cell.getNumericCellValue());
}
else
{
c = cell.getStringCellValue();
}
}
else if (java.math.BigDecimal.class == fieldType)
{
c = cell.getStringCellValue();
}
}
if (entity != null)
{
list.add(entity);
}
}
}
return list;
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult exportExcel(List<T> list, String sheetName)
{
OutputStream out = null;
HSSFWorkbook workbook = null;
try
{
// 得到所有定义字段
Field[] allFields = clazz.getDeclaredFields();
List<Field> fields = new ArrayList<Field>();
// 得到所有field并存放到一个list中.
for (Field field : allFields)
{
if (field.isAnnotationPresent(Excel.class))
{
fields.add(field);
}
}
// 产生工作薄对象
workbook = new HSSFWorkbook();
// excel2003中每个sheet中最多有65536行
int sheetSize = 65536;
// 取出一共有多少个sheet.
double sheetNo = Math.ceil(list.size() / sheetSize);
for (int index = 0; index <= sheetNo; index++)
{
// 产生工作表对象
HSSFSheet sheet = workbook.createSheet();
if (sheetNo == 0)
{
workbook.setSheetName(index, sheetName);
}
else
{
// 设置工作表的名称.
workbook.setSheetName(index, sheetName + index);
}
HSSFRow row;
HSSFCell cell; // 产生单元格
// 产生一行
row = sheet.createRow(0);
// 写入各个字段的列头名称
for (int i = 0; i < fields.size(); i++)
{
Field field = fields.get(i);
Excel attr = field.getAnnotation(Excel.class);
// 创建列
cell = row.createCell(i);
// 设置列中写入内容为String类型
cell.setCellType(CellType.STRING);
HSSFCellStyle cellStyle = workbook.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
if (attr.name().indexOf("注:") >= 0)
{
HSSFFont font = workbook.createFont();
font.setColor(HSSFFont.COLOR_RED);
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
sheet.setColumnWidth(i, 6000);
}
else
{
HSSFFont font = workbook.createFont();
// 粗体显示
font.setBold(true);
// 选择需要用到的字体格式
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
// 设置列宽
sheet.setColumnWidth(i, (int) ((attr.width() + 0.72) * 256));
row.setHeight((short) (attr.height() * 20));
}
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setWrapText(true);
cell.setCellStyle(cellStyle);
// 写入列名
cell.setCellValue(attr.name());
// 如果设置了提示信息则鼠标放上去提示.
if (StringUtils.isNotEmpty(attr.prompt()))
{
// 这里默认设了2-101列提示.
setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, i, i);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0)
{
// 这里默认设了2-101列只能选择不能输入.
setHSSFValidation(sheet, attr.combo(), 1, 100, i, i);
}
}
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
// 写入各条记录,每条记录对应excel表中的一行
HSSFCellStyle cs = workbook.createCellStyle();
cs.setAlignment(HorizontalAlignment.CENTER);
cs.setVerticalAlignment(VerticalAlignment.CENTER);
for (int i = startNo; i < endNo; i++)
{
row = sheet.createRow(i + 1 - startNo);
// 得到导出对象.
T vo = (T) list.get(i);
for (int j = 0; j < fields.size(); j++)
{
// 获得field.
Field field = fields.get(j);
// 设置实体类私有属性可访问
field.setAccessible(true);
Excel attr = field.getAnnotation(Excel.class);
try
{
// 设置行高
row.setHeight((short) (attr.height() * 20));
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport())
{
// 创建cell
cell = row.createCell(j);
cell.setCellStyle(cs);
if (vo == null)
{
// 如果数据存在就填入,不存在填入空格.
cell.setCellValue("");
continue;
}
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
if (StringUtils.isNotEmpty(dateFormat))
{
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) field.get(vo)));
}
else if (StringUtils.isNotEmpty(readConverterExp))
{
cell.setCellValue(convertByExp(String.valueOf(field.get(vo)), readConverterExp));
}
else
{
cell.setCellType(CellType.STRING);
// 如果数据存在就填入,不存在填入空格.
cell.setCellValue(StringUtils.isNull(field.get(vo)) ? attr.defaultValue() : field.get(vo) + attr.suffix());
}
}
}
catch (Exception e)
{
log.error("导出Excel失败{}", e.getMessage());
}
}
}
}
String filename = encodingFilename(sheetName);
out = new FileOutputStream(getAbsoluteFile(filename));
workbook.write(out);
return AjaxResult.success(filename);
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
return AjaxResult.error("导出Excel失败请联系网站管理员");
}
finally
{
if (workbook != null)
{
try
{
workbook.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (out != null)
{
try
{
out.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 设置单元格上提示
*
* @param sheet 要设置的sheet.
* @param promptTitle 标题
* @param promptContent 内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public static HSSFSheet setHSSFPrompt(HSSFSheet sheet, String promptTitle, String promptContent, int firstRow,
int endRow, int firstCol, int endCol)
{
// 构造constraint对象
DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");
// 四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
HSSFDataValidation dataValidationView = new HSSFDataValidation(regions, constraint);
dataValidationView.createPromptBox(promptTitle, promptContent);
sheet.addValidationData(dataValidationView);
return sheet;
}
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public static HSSFSheet setHSSFValidation(HSSFSheet sheet, String[] textlist, int firstRow, int endRow,
int firstCol, int endCol)
{
// 加载下拉列表内容
DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist);
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
HSSFDataValidation dataValidationList = new HSSFDataValidation(regions, constraint);
sheet.addValidationData(dataValidationList);
return sheet;
}
/**
* 解析导出值 0=男,1=女,2=未知
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String convertByExp(String propertyValue, String converterExp) throws Exception
{
try
{
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (itemArray[0].equals(propertyValue))
{
return itemArray[1];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
}
/**
* 编码文件名
*/
public String encodingFilename(String filename)
{
filename = UUID.randomUUID().toString() + "_" + filename + ".xls";
return filename;
}
/**
* 获取下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename)
{
String downloadPath = Global.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
return downloadPath;
}
}

View File

@ -85,7 +85,7 @@ public class IpUtils
/**
* 将IPv4地址转换成字节
*
* @param IPv4地址
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text)

View File

@ -259,38 +259,46 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 下划线转驼峰命名
*/
public static String toUnderScoreCase(String s)
public static String toUnderScoreCase(String str)
{
if (s == null)
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
boolean upperCase = false;
for (int i = 0; i < s.length(); i++)
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = s.charAt(i);
boolean nextUpperCase = true;
if (i < (s.length() - 1))
char c = str.charAt(i);
if (i > 0)
{
nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
}
if ((i > 0) && Character.isUpperCase(c))
{
if (!upperCase || !nextUpperCase)
{
sb.append(SEPARATOR);
}
upperCase = true;
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
upperCase = false;
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}

View File

@ -0,0 +1,62 @@
package com.ruoyi.common.utils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 线程相关工具类.
*
* @author ruoyi
*/
public class Threads
{
private static final Logger logger = LoggerFactory.getLogger("sys-user");
/**
* sleep等待,单位为毫秒
*/
public static void sleep(long milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
return;
}
}
/**
* 停止线程池
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
* 如果仍人超時,則強制退出.
* 另对在shutdown时线程本身被调用中断做了处理.
*/
public static void shutdownAndAwaitTermination(ExecutorService pool)
{
if (pool != null && !pool.isShutdown())
{
pool.shutdown();
try
{
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
pool.shutdownNow();
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
logger.info("Pool did not terminate");
}
}
}
catch (InterruptedException ie)
{
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}

View File

@ -16,7 +16,8 @@ public class FileUtils
/**
* 输出指定文件的byte数组
*
* @param filename 文件
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException

View File

@ -0,0 +1,752 @@
package com.ruoyi.common.utils.poi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.annotation.Excel.Type;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.config.Global;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.reflect.ReflectUtils;
import com.ruoyi.common.support.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
/**
* Excel相关处理
*
* @author ruoyi
*/
public class ExcelUtil<T>
{
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
/**
* Excel sheet最大行数默认65536
*/
public static final int sheetSize = 65536;
/**
* 工作表名称
*/
private String sheetName;
/**
* 导出类型EXPORT:导出数据IMPORT导入模板
*/
private Type type;
/**
* 工作薄对象
*/
private Workbook wb;
/**
* 工作表对象
*/
private Sheet sheet;
/**
* 导入导出数据列表
*/
private List<T> list;
/**
* 注解列表
*/
private List<Field> fields;
/**
* 实体对象
*/
public Class<T> clazz;
public ExcelUtil(Class<T> clazz)
{
this.clazz = clazz;
}
public void init(List<T> list, String sheetName, Type type)
{
if (list == null)
{
list = new ArrayList<T>();
}
this.list = list;
this.sheetName = sheetName;
this.type = type;
createExcelField();
createWorkbook();
}
/**
* 对excel表单默认第一个索引名转换成list
*
* @param input 输入流
* @return 转换后集合
*/
public List<T> importExcel(InputStream is) throws Exception
{
return importExcel(StringUtils.EMPTY, is);
}
/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 表格索引名
* @param input 输入流
* @return 转换后集合
*/
public List<T> importExcel(String sheetName, InputStream is) throws Exception
{
this.type = Type.IMPORT;
this.wb = WorkbookFactory.create(is);
List<T> list = new ArrayList<T>();
Sheet sheet = null;
if (StringUtils.isNotEmpty(sheetName))
{
// 如果指定sheet名,则取指定sheet中的内容.
sheet = wb.getSheet(sheetName);
}
else
{
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = wb.getSheetAt(0);
}
if (sheet == null)
{
throw new IOException("文件sheet不存在");
}
int rows = sheet.getPhysicalNumberOfRows();
if (rows > 0)
{
// 默认序号
int serialNum = 0;
// 有数据时才处理 得到类的所有field.
Field[] allFields = clazz.getDeclaredFields();
// 定义一个map用于存放列的序号和field.
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
for (int col = 0; col < allFields.length; col++)
{
Field field = allFields[col];
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
// 设置类的私有字段属性可访问.
field.setAccessible(true);
fieldsMap.put(++serialNum, field);
}
}
for (int i = 1; i < rows; i++)
{
// 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i);
int cellNum = serialNum;
T entity = null;
for (int column = 0; column < cellNum; column++)
{
Object val = this.getCellValue(row, column);
// 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field.
Field field = fieldsMap.get(column + 1);
// 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType();
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0"))
{
val = StringUtils.substringBefore(s, ".0");
}
else
{
val = Convert.toStr(val);
}
}
else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
{
val = Convert.toInt(val);
}
else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
{
val = Convert.toLong(val);
}
else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
{
val = Convert.toDouble(val);
}
else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
{
val = Convert.toFloat(val);
}
else if (Date.class == fieldType)
{
if (val instanceof String)
{
val = DateUtils.parseDate(val);
}
else if (val instanceof Double)
{
val = DateUtil.getJavaDate((Double) val);
}
}
if (StringUtils.isNotNull(fieldType))
{
Excel attr = field.getAnnotation(Excel.class);
String propertyName = field.getName();
if (StringUtils.isNotEmpty(attr.targetAttr()))
{
propertyName = field.getName() + "." + attr.targetAttr();
}
else if (StringUtils.isNotEmpty(attr.readConverterExp()))
{
val = reverseByExp(String.valueOf(val), attr.readConverterExp());
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
}
list.add(entity);
}
}
return list;
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult exportExcel(List<T> list, String sheetName)
{
this.init(list, sheetName, Type.EXPORT);
return exportExcel();
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult importTemplateExcel(String sheetName)
{
this.init(null, sheetName, Type.IMPORT);
return exportExcel();
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @return 结果
*/
public AjaxResult exportExcel()
{
OutputStream out = null;
try
{
// 取出一共有多少个sheet.
double sheetNo = Math.ceil(list.size() / sheetSize);
for (int index = 0; index <= sheetNo; index++)
{
createSheet(sheetNo, index);
Cell cell = null; // 产生单元格
// 产生一行
Row row = sheet.createRow(0);
// 写入各个字段的列头名称
for (int i = 0; i < fields.size(); i++)
{
Field field = fields.get(i);
Excel attr = field.getAnnotation(Excel.class);
// 创建列
cell = row.createCell(i);
// 设置列中写入内容为String类型
cell.setCellType(CellType.STRING);
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
if (attr.name().indexOf("注:") >= 0)
{
Font font = wb.createFont();
font.setColor(HSSFFont.COLOR_RED);
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
sheet.setColumnWidth(i, 6000);
}
else
{
Font font = wb.createFont();
// 粗体显示
font.setBold(true);
// 选择需要用到的字体格式
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
// 设置列宽
sheet.setColumnWidth(i, (int) ((attr.width() + 0.72) * 256));
row.setHeight((short) (attr.height() * 20));
}
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setWrapText(true);
cell.setCellStyle(cellStyle);
// 写入列名
cell.setCellValue(attr.name());
// 如果设置了提示信息则鼠标放上去提示.
if (StringUtils.isNotEmpty(attr.prompt()))
{
// 这里默认设了2-101列提示.
setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, i, i);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0)
{
// 这里默认设了2-101列只能选择不能输入.
setHSSFValidation(sheet, attr.combo(), 1, 100, i, i);
}
}
if (Type.EXPORT.equals(type))
{
fillExcelData(index, row, cell);
}
}
String filename = encodingFilename(sheetName);
out = new FileOutputStream(getAbsoluteFile(filename));
wb.write(out);
return AjaxResult.success(filename);
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
throw new BusinessException("导出Excel失败请联系网站管理员");
}
finally
{
if (wb != null)
{
try
{
wb.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (out != null)
{
try
{
out.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 填充excel数据
*
* @param index 序号
* @param row 单元格行
* @param cell 类型单元格
*/
public void fillExcelData(int index, Row row, Cell cell)
{
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
// 写入各条记录,每条记录对应excel表中的一行
CellStyle cs = wb.createCellStyle();
cs.setAlignment(HorizontalAlignment.CENTER);
cs.setVerticalAlignment(VerticalAlignment.CENTER);
for (int i = startNo; i < endNo; i++)
{
row = sheet.createRow(i + 1 - startNo);
// 得到导出对象.
T vo = (T) list.get(i);
for (int j = 0; j < fields.size(); j++)
{
// 获得field.
Field field = fields.get(j);
// 设置实体类私有属性可访问
field.setAccessible(true);
Excel attr = field.getAnnotation(Excel.class);
try
{
// 设置行高
row.setHeight((short) (attr.height() * 20));
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport())
{
// 创建cell
cell = row.createCell(j);
cell.setCellStyle(cs);
if (vo == null)
{
// 如果数据存在就填入,不存在填入空格.
cell.setCellValue("");
continue;
}
// 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
if (StringUtils.isNotEmpty(dateFormat))
{
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
}
else if (StringUtils.isNotEmpty(readConverterExp))
{
cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
}
else
{
cell.setCellType(CellType.STRING);
// 如果数据存在就填入,不存在填入空格.
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
}
}
}
catch (Exception e)
{
log.error("导出Excel失败{}", e.getMessage());
}
}
}
}
/**
* 设置单元格上提示
*
* @param sheet 要设置的sheet.
* @param promptTitle 标题
* @param promptContent 内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public static Sheet setHSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
int firstCol, int endCol)
{
// 构造constraint对象
DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");
// 四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
HSSFDataValidation dataValidationView = new HSSFDataValidation(regions, constraint);
dataValidationView.createPromptBox(promptTitle, promptContent);
sheet.addValidationData(dataValidationView);
return sheet;
}
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public static Sheet setHSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol,
int endCol)
{
// 加载下拉列表内容
DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist);
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
HSSFDataValidation dataValidationList = new HSSFDataValidation(regions, constraint);
sheet.addValidationData(dataValidationList);
return sheet;
}
/**
* 解析导出值 0=男,1=女,2=未知
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String convertByExp(String propertyValue, String converterExp) throws Exception
{
try
{
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (itemArray[0].equals(propertyValue))
{
return itemArray[1];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
}
/**
* 反向解析值 男=0,女=1,未知=2
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String reverseByExp(String propertyValue, String converterExp) throws Exception
{
try
{
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (itemArray[1].equals(propertyValue))
{
return itemArray[0];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
}
/**
* 编码文件名
*/
public String encodingFilename(String filename)
{
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
return filename;
}
/**
* 获取下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename)
{
String downloadPath = Global.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
return downloadPath;
}
/**
* 获取bean中的属性值
*
* @param vo 实体对象
* @param field 字段
* @param excel 注解
* @return 最终的属性值
* @throws Exception
*/
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{
Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr()))
{
String target = excel.targetAttr();
if (target.indexOf(".") > -1)
{
String[] targets = target.split("[.]");
for (String name : targets)
{
o = getValue(o, name);
}
}
else
{
o = getValue(o, target);
}
}
return o;
}
/**
* 以类的属性的get方法方法形式获取值
*
* @param o
* @param name
* @return value
* @throws Exception
*/
private Object getValue(Object o, String name) throws Exception
{
if (StringUtils.isNotEmpty(name))
{
Class<?> clazz = o.getClass();
String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method method = clazz.getMethod(methodName);
o = method.invoke(o);
}
return o;
}
/**
* 得到所有定义字段
*/
private void createExcelField()
{
this.fields = new ArrayList<Field>();
Field[] allFields = clazz.getDeclaredFields();
// 得到所有field并存放到一个list中.
for (Field field : allFields)
{
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
fields.add(field);
}
}
}
/**
* 创建一个工作簿
*/
public void createWorkbook()
{
this.wb = new SXSSFWorkbook(500);
}
/**
* 创建工作表
*
* @param sheetName指定Sheet名称
* @param sheetNo sheet数量
* @param index 序号
*/
public void createSheet(double sheetNo, int index)
{
this.sheet = wb.createSheet();
// 设置工作表的名称.
if (sheetNo == 0)
{
wb.setSheetName(index, sheetName);
}
else
{
wb.setSheetName(index, sheetName + index);
}
}
/**
* 获取单元格值
*
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
*/
public Object getCellValue(Row row, int column)
{
if (row == null)
{
return row;
}
Object val = "";
try
{
Cell cell = row.getCell(column);
if (cell != null)
{
if (cell.getCellTypeEnum() == CellType.NUMERIC)
{
val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell))
{
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
}
else
{
if ((Double) val % 1 > 0)
{
val = new DecimalFormat("0.00").format(val);
}
else
{
val = new DecimalFormat("0").format(val);
}
}
}
else if (cell.getCellTypeEnum() == CellType.STRING)
{
val = cell.getStringCellValue();
}
else if (cell.getCellTypeEnum() == CellType.BOOLEAN)
{
val = cell.getBooleanCellValue();
}
else if (cell.getCellTypeEnum() == CellType.ERROR)
{
val = cell.getErrorCellValue();
}
}
}
catch (Exception e)
{
return val;
}
return val;
}
}

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.1</version>
<version>3.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -73,9 +73,9 @@ public class DataScopeAspect
/**
* 数据范围过滤
*
* @param da 部门表别名
* @return 标准连接条件对象
* @param joinPoint 切点
* @param user 用户
* @param alias 别名
*/
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String alias)
{

View File

@ -121,8 +121,8 @@ public class LogAspect
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
public void getControllerMethodDescription(Log log, SysOperLog operLog) throws Exception

View File

@ -19,16 +19,27 @@ public class CaptchaConfig
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty("kaptcha.border", "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty("kaptcha.border.color", "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty("kaptcha.textproducer.font.color", "blue");
// 验证码图片宽度 默认为200
properties.setProperty("kaptcha.image.width", "160");
// 验证码图片高度 默认为50
properties.setProperty("kaptcha.image.height", "60");
properties.setProperty("kaptcha.textproducer.font.size", "28");
// 验证码文本字符大小 默认为40
properties.setProperty("kaptcha.textproducer.font.size", "30");
// KAPTCHA_SESSION_KEY
properties.setProperty("kaptcha.session.key", "kaptchaCode");
properties.setProperty("kaptcha.textproducer.char.spac", "35");
// 验证码文本字符间距 默认为2
properties.setProperty("kaptcha.textproducer.char.space", "3");
// 验证码文本字符长度 默认为5
properties.setProperty("kaptcha.textproducer.char.length", "5");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty("kaptcha.noise.color", "white");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
@ -40,19 +51,33 @@ public class CaptchaConfig
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty("kaptcha.border", "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty("kaptcha.border.color", "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty("kaptcha.textproducer.font.color", "blue");
// 验证码图片宽度 默认为200
properties.setProperty("kaptcha.image.width", "160");
// 验证码图片高度 默认为50
properties.setProperty("kaptcha.image.height", "60");
properties.setProperty("kaptcha.textproducer.font.size", "38");
// 验证码文本字符大小 默认为40
properties.setProperty("kaptcha.textproducer.font.size", "35");
// KAPTCHA_SESSION_KEY
properties.setProperty("kaptcha.session.key", "kaptchaCodeMath");
// 验证码文本生成器
properties.setProperty("kaptcha.textproducer.impl", "com.ruoyi.framework.config.KaptchaTextCreator");
properties.setProperty("kaptcha.textproducer.char.spac", "5");
// 验证码文本字符间距 默认为2
properties.setProperty("kaptcha.textproducer.char.space", "3");
// 验证码文本字符长度 默认为5
properties.setProperty("kaptcha.textproducer.char.length", "6");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty("kaptcha.noise.color", "white");
// 干扰实现类
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);

View File

@ -8,8 +8,10 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.framework.config.properties.DruidProperties;
import com.ruoyi.framework.datasource.DynamicDataSource;
/**
@ -22,17 +24,19 @@ public class DruidConfig
{
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource masterDataSource()
public DataSource masterDataSource(DruidProperties druidProperties)
{
return DruidDataSourceBuilder.create().build();
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource()
public DataSource slaveDataSource(DruidProperties druidProperties)
{
return DruidDataSourceBuilder.create().build();
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean(name = "dynamicDataSource")

View File

@ -0,0 +1,40 @@
package com.ruoyi.framework.config;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 服务相关配置
*
* @author ruoyi
*
*/
@Component
public class ServerConfig implements ApplicationListener<WebServerInitializedEvent>
{
private int serverPort;
public String getUrl()
{
InetAddress address = null;
try
{
address = InetAddress.getLocalHost();
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
return "http://" + address.getHostAddress() + ":" + this.serverPort;
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event)
{
this.serverPort = event.getWebServer().getPort();
}
}

View File

@ -0,0 +1,77 @@
package com.ruoyi.framework.config.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
/**
* druid 配置属性
*
* @author ruoyi
*/
@Configuration
public class DruidProperties
{
@Value("${spring.datasource.druid.initialSize}")
private int initialSize;
@Value("${spring.datasource.druid.minIdle}")
private int minIdle;
@Value("${spring.datasource.druid.maxActive}")
private int maxActive;
@Value("${spring.datasource.druid.maxWait}")
private int maxWait;
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
private int maxEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.druid.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.druid.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.druid.testOnReturn}")
private boolean testOnReturn;
public DruidDataSource dataSource(DruidDataSource datasource)
{
/** 配置初始化大小、最小、最大 */
datasource.setInitialSize(initialSize);
datasource.setMaxActive(maxActive);
datasource.setMinIdle(minIdle);
/** 配置获取连接等待超时的时间 */
datasource.setMaxWait(maxWait);
/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
/** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
/**
* 用来检测连接是否有效的sql要求是一个查询语句常用select 'x'。如果validationQuery为nulltestOnBorrow、testOnReturn、testWhileIdle都不会起作用。
*/
datasource.setValidationQuery(validationQuery);
/** 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。 */
datasource.setTestWhileIdle(testWhileIdle);
/** 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。 */
datasource.setTestOnBorrow(testOnBorrow);
/** 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。 */
datasource.setTestOnReturn(testOnReturn);
return datasource;
}
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.framework.manager;
import java.util.TimerTask;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.ruoyi.common.utils.Threads;
/**
* 异步任务管理器
@ -34,10 +35,18 @@ public class AsyncManager
/**
* 执行任务
*
* @param 任务task
* @param task 任务
*/
public void execute(TimerTask task)
{
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
}
/**
* 停止任务线程池
*/
public void shutdown()
{
Threads.shutdownAndAwaitTermination(executor);
}
}

View File

@ -0,0 +1,64 @@
package com.ruoyi.framework.manager;
import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
/**
* 确保应用退出时能关闭后台线程
*
* @author cj
*/
@Component
public class ShutdownManager
{
private static final Logger logger = LoggerFactory.getLogger("sys-user");
@Autowired(required = false)
private SpringSessionValidationScheduler springSessionValidationScheduler;
@PreDestroy
public void destroy()
{
shutdownSpringSessionValidationScheduler();
shutdownAsyncManager();
}
/**
* 停止Seesion会话检查
*/
private void shutdownSpringSessionValidationScheduler()
{
if (springSessionValidationScheduler != null && springSessionValidationScheduler.isEnabled())
{
try
{
logger.info("====关闭会话验证任务====");
springSessionValidationScheduler.disableSessionValidation();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
}
}
}
/**
* 停止异步执行任务
*/
private void shutdownAsyncManager()
{
try
{
logger.info("====关闭后台任务任务线程池====");
AsyncManager.me().shutdown();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
}
}
}

View File

@ -96,7 +96,7 @@ public class SysLoginService
if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRemark())));
throw new UserBlockedException(user.getRemark());
throw new UserBlockedException();
}
passwordService.validate(user, password);

View File

@ -0,0 +1,62 @@
package com.ruoyi.framework.shiro.service;
import java.io.Serializable;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.shiro.session.OnlineSession;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysUserOnlineService;
/**
* 会话db操作处理
*
* @author ruoyi
*/
@Component
public class SysShiroService
{
@Autowired
private ISysUserOnlineService onlineService;
/**
* 删除会话
*
* @param onlineSession 会话信息
*/
public void deleteSession(OnlineSession onlineSession)
{
onlineService.deleteOnlineById(String.valueOf(onlineSession.getId()));
}
/**
* 获取会话信息
*
* @param sessionId
* @return
*/
public Session getSession(Serializable sessionId)
{
SysUserOnline userOnline = onlineService.selectOnlineById(String.valueOf(sessionId));
return StringUtils.isNull(userOnline) ? null : createSession(userOnline);
}
public Session createSession(SysUserOnline userOnline)
{
OnlineSession onlineSession = new OnlineSession();
if (StringUtils.isNotNull(userOnline))
{
onlineSession.setId(userOnline.getSessionId());
onlineSession.setHost(userOnline.getIpaddr());
onlineSession.setBrowser(userOnline.getBrowser());
onlineSession.setOs(userOnline.getOs());
onlineSession.setDeptName(userOnline.getDeptName());
onlineSession.setLoginName(userOnline.getLoginName());
onlineSession.setStartTimestamp(userOnline.getStartTimestamp());
onlineSession.setLastAccessTime(userOnline.getLastAccessTime());
onlineSession.setTimeout(userOnline.getExpireTime());
}
return onlineSession;
}
}

View File

@ -9,8 +9,7 @@ import org.springframework.beans.factory.annotation.Value;
import com.ruoyi.common.enums.OnlineStatus;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysUserOnlineService;
import com.ruoyi.framework.shiro.service.SysShiroService;
/**
* 针对自定义的ShiroSession的db操作
@ -31,7 +30,7 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
private static final String LAST_SYNC_DB_TIMESTAMP = OnlineSessionDAO.class.getName() + "LAST_SYNC_DB_TIMESTAMP";
@Autowired
private ISysUserOnlineService onlineService;
private SysShiroService sysShiroService;
public OnlineSessionDAO()
{
@ -52,12 +51,7 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
@Override
protected Session doReadSession(Serializable sessionId)
{
SysUserOnline userOnline = onlineService.selectOnlineById(String.valueOf(sessionId));
if (userOnline == null)
{
return null;
}
return super.doReadSession(sessionId);
return sysShiroService.getSession(sessionId);
}
/**
@ -109,6 +103,6 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
return;
}
onlineSession.setStatus(OnlineStatus.off_line);
onlineService.deleteOnlineById(String.valueOf(onlineSession.getId()));
sysShiroService.deleteSession(onlineSession);
}
}

View File

@ -83,7 +83,7 @@ public class OnlineSessionFilter extends AccessControlFilter
subject.logout();
}
saveRequestAndRedirectToLogin(request, response);
return true;
return false;
}
// 跳转到登录页

View File

@ -8,6 +8,7 @@ import org.apache.shiro.session.mgt.SessionValidationScheduler;
import org.apache.shiro.session.mgt.ValidatingSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.utils.Threads;
/**
* 自定义任务调度器完成
@ -17,7 +18,7 @@ import org.slf4j.LoggerFactory;
public class SpringSessionValidationScheduler implements SessionValidationScheduler
{
private static final Logger log = LoggerFactory.getLogger(SpringSessionValidationScheduler.class);
public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL;
/**
@ -134,6 +135,10 @@ public class SpringSessionValidationScheduler implements SessionValidationSchedu
log.debug("Stopping Spring Scheduler session validation job...");
}
if (this.enabled)
{
Threads.shutdownAndAwaitTermination(executorService);
}
this.enabled = false;
}
}

View File

@ -91,7 +91,6 @@ public class FileUploadUtils
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param needDatePathAndRandomName 是否需要日期目录和随机文件名前缀
* @param extension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小

View File

@ -13,7 +13,7 @@ public class PermissionUtils
/**
* 权限错误消息提醒
*
* @param errorMsg 错误信息
* @param permissionsStr 错误信息
* @return
*/
public static String getMsg(String permissionsStr)

View File

@ -19,7 +19,7 @@ import com.ruoyi.system.domain.SysUser;
*/
public class ShiroUtils
{
public static Subject getSubjct()
public static Subject getSubject()
{
return SecurityUtils.getSubject();
}
@ -31,13 +31,13 @@ public class ShiroUtils
public static void logout()
{
getSubjct().logout();
getSubject().logout();
}
public static SysUser getSysUser()
{
SysUser user = null;
Object obj = getSubjct().getPrincipal();
Object obj = getSubject().getPrincipal();
if (StringUtils.isNotNull(obj))
{
user = new SysUser();
@ -48,7 +48,7 @@ public class ShiroUtils
public static void setSysUser(SysUser user)
{
Subject subject = getSubjct();
Subject subject = getSubject();
PrincipalCollection principalCollection = subject.getPrincipals();
String realmName = principalCollection.getRealmNames().iterator().next();
PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(user, realmName);
@ -75,12 +75,12 @@ public class ShiroUtils
public static String getIp()
{
return getSubjct().getSession().getHost();
return getSubject().getSession().getHost();
}
public static String getSessionId()
{
return String.valueOf(getSubjct().getSession().getId());
return String.valueOf(getSubject().getSession().getId());
}
/**

View File

@ -8,11 +8,11 @@ import org.springframework.web.bind.annotation.InitBinder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.page.PageDomain;
import com.ruoyi.common.page.TableDataInfo;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.framework.web.page.PageDomain;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.framework.web.page.TableSupport;
import com.ruoyi.system.domain.SysUser;
@ -79,6 +79,17 @@ public class BaseController
return rows > 0 ? success() : error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 返回成功
*/

View File

@ -28,6 +28,9 @@ import oshi.util.Util;
*/
public class Server
{
private static final int OSHI_WAIT_SECOND = 1000;
/**
* CPU相关信息
*/
@ -126,7 +129,7 @@ public class Server
{
// CPU信息
long[] prevTicks = processor.getSystemCpuLoadTicks();
Util.sleep(500);
Util.sleep(OSHI_WAIT_SECOND);
long[] ticks = processor.getSystemCpuLoadTicks();
long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];

View File

@ -7,6 +7,7 @@ import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.ruoyi.common.base.AjaxResult;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.exception.DemoModeException;
import com.ruoyi.framework.util.PermissionUtils;
@ -19,7 +20,7 @@ import com.ruoyi.framework.util.PermissionUtils;
public class DefaultExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class);
/**
* 权限校验失败
*/
@ -59,7 +60,17 @@ public class DefaultExceptionHandler
log.error(e.getMessage(), e);
return AjaxResult.error("服务器错误,请联系管理员");
}
/**
* 业务异常
*/
@ExceptionHandler(BusinessException.class)
public AjaxResult businessException(BusinessException e)
{
log.error(e.getMessage(), e);
return AjaxResult.error(e.getMessage());
}
/**
* 演示模式异常
*/

Some files were not shown because too many files have changed in this diff Show More