Compare commits

...

45 Commits

Author SHA1 Message Date
thinkgem
19d2399eb2 5.6.1 2024-02-18 16:01:14 +08:00
thinkgem
37b0a120c9 1、修改默认值,oracle 下默认不启用 maxPoolPreparedStatementPerConnectionSize 可根据需要开启;2、将 com.oracle.ojdbc 驱动替换为 com.oracle.database.jdbc 驱动;3、默认将 jtds 驱动替换为 sqlserver 驱动; 2024-02-02 14:03:11 +08:00
thinkgem
5fb6ab0ca6 ueditor黑暗模式下的文字 2024-01-31 12:04:34 +08:00
thinkgem
2ba8b953d3 更新路由表单组件 2024-01-30 16:53:39 +08:00
thinkgem
738fd5c552 form:fileupload组件默认加dataMap属性 2024-01-30 11:40:29 +08:00
thinkgem
745f6e88c0 新增 js.ajaxSubmitForm支持application/json提交表单;新增 js.ajaxSubmitJson 方法 2024-01-30 11:38:39 +08:00
thinkgem
3db837d6d6 代码优化 2024-01-26 14:43:03 +08:00
thinkgem
14054a964f ts type check 2024-01-23 17:53:07 +08:00
thinkgem
14581655d2 code format 2024-01-17 16:17:09 +08:00
thinkgem
f162584d1e 代码优化,方便自定义内嵌的Web服务 2024-01-15 13:44:39 +08:00
thinkgem
e57e8127b5 报表增加请求参数的例子 2024-01-10 13:08:17 +08:00
thinkgem
b7d4efa6a6 update 2024-01-10 13:04:34 +08:00
thinkgem
91a4db4eb8 增加vue无框架页面的组件类型 2024-01-09 16:42:53 +08:00
thinkgem
7ed84e48cf 存储Key增加了默认,个性化时再指定 2024-01-08 15:25:41 +08:00
thinkgem
f068bd9c90 update version 2024-01-08 10:39:18 +08:00
thinkgem
4ae907a023 update 2024-01-05 20:49:46 +08:00
thinkgem
652a242c2b 5.6.0 2024-01-04 12:06:16 +08:00
thinkgem
d242408de2 5.6.0 2024-01-03 16:58:35 +08:00
thinkgem
b8f51011ed 配置类 ShiroConfig 改为 ShiroAutoConfiguration 方便覆写 2024-01-03 08:53:55 +08:00
thinkgem
84913ab783 分号修正 2024-01-03 08:24:38 +08:00
thinkgem
b7bb765193 update 2024 2024-01-02 10:24:19 +08:00
thinkgem
d1b06c45c8 add ConditionalOnMissingBean 2024-01-02 10:23:37 +08:00
thinkgem
19fe2023a6 update 2024-01-02 10:22:57 +08:00
thinkgem
590046d90c select2 i18n fix 2023-12-29 10:56:03 +08:00
thinkgem
00c162ece1 代码优化提示 2023-12-28 09:33:20 +08:00
thinkgem
d5deb38769 优化在线用户列表数值类型的排序 2023-12-27 10:47:44 +08:00
thinkgem
b71165f73c 代码生成模板:新增Vue路由表单、新增Vue弹窗表单、新增仅后端模板 2023-12-24 21:36:09 +08:00
thinkgem
4260accf88 不设置adminPath的时候需要增加oauth2的地址认证排除 2023-12-23 23:01:37 +08:00
thinkgem
353131ab2c 用户管理增加解冻用户功能提示 2023-12-23 23:00:30 +08:00
thinkgem
acb6baa226 细节优化 2023-12-23 22:59:38 +08:00
thinkgem
5b7f7b0860 spring boot 2.7.18、jackson 2.16.0、fastjson 2.0.43、mybatis 3.5.14、shiro 1.13.0 2023-12-13 21:37:09 +08:00
thinkgem
c57238e279 spring.data.elasticsearch.enabled to spring.elasticsearch.enabled 2023-12-13 21:06:42 +08:00
thinkgem
24ea4aaed0 增加一些vue下用的路由 2023-12-12 09:42:56 +08:00
thinkgem
0af1ae18c8 update 2023-12-12 09:41:38 +08:00
thinkgem
e054df919f BpmButton.vue将提交审批信息移动到提交对话框中 2023-12-07 17:20:30 +08:00
thinkgem
a9ca557672 update 2023-12-05 16:30:31 +08:00
thinkgem
5bc76dd23d update 2023-12-05 16:12:42 +08:00
thinkgem
f337faeecc 代码优化 2023-12-03 15:55:22 +08:00
thinkgem
a6d84c59c9 vue兼容优化 2023-12-01 10:40:54 +08:00
thinkgem
b8279ffe64 优化修改密码后的操作 2023-11-28 16:15:16 +08:00
thinkgem
af44331820 优化vue生成模板 2023-11-28 15:46:05 +08:00
thinkgem
00ead34076 BasicTable子表加TextArea组件 2023-11-27 12:23:54 +08:00
thinkgem
9b07e167f7 树表的局部刷新改进,删除、停用、启用、修改父节点的情况下完美体验 2023-11-27 10:11:56 +08:00
thinkgem
0fb15e31d6 next 2023-11-27 09:06:15 +08:00
thinkgem
3e769325f8 Layer弹窗后首先关闭获取焦点,防止回车弹出多个 2023-11-22 11:14:08 +08:00
57 changed files with 766 additions and 664 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

View File

@@ -42,7 +42,7 @@ public class PropertyLoader implements org.springframework.boot.env.PropertySour
try {
// 默认开启 FastJSON 1.x 的,安全模式
ParserConfig.getGlobalInstance().setSafeMode(true);
} catch (Exception ignored) {
} catch (Throwable ignored) {
// 兼容 FastJSON 2.x 的调用,忽略异常
}
Properties properties = PropertiesUtils.getInstance().getProperties();

View File

@@ -710,6 +710,7 @@ Class.pt.callback = function(){
var that = this, layero = that.layero, config = that.config;
that.openLayer();
if(config.success){
layero.find('.layui-layer-close').focus(); // 弹窗后首先关闭获取焦点,防止回车弹出多个
if(config.type == 2){
layero.find('iframe').on('load', function(){
config.success(layero, that.index);

View File

@@ -4469,7 +4469,7 @@ S2.define('select2/dropdown/closeOnSelect',[
});
// ThinkGem 默认为中文
S2.define('select2/i18n/en',[],function () {
S2.define('select2/i18n/zh_CN',[],function () {
// English
return {
errorLoading: function () {
@@ -4549,7 +4549,7 @@ S2.define('select2/defaults',[
'./dropdown/selectOnClose',
'./dropdown/closeOnSelect',
'./i18n/en'
'./i18n/zh_CN'
], function ($, require,
ResultsList,
@@ -4763,7 +4763,7 @@ S2.define('select2/defaults',[
if ($.isArray(options.language)) {
var languages = new Translation();
options.language.push('en');
options.language.push('zh_CN');
var languageNames = options.language;
@@ -4800,7 +4800,7 @@ S2.define('select2/defaults',[
options.translations = languages;
} else {
var baseTranslation = Translation.loadPath(
this.defaults.amdLanguageBase + 'en'
this.defaults.amdLanguageBase + 'zh_CN'
);
var customTranslation = new Translation(options.language);
@@ -4952,6 +4952,8 @@ S2.define('select2/options',[
this.options.language = $e.prop('lang').toLowerCase();
} else if ($e.closest('[lang]').prop('lang')) {
this.options.language = $e.closest('[lang]').prop('lang');
} else if (window.lang) {
this.options.language = window.lang;
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>

View File

@@ -13,4 +13,6 @@
5.4.1
5.5.0
5.5.1
5.5.2
5.5.2
5.6.0
5.6.1

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>

View File

@@ -18,18 +18,7 @@ j2cache:
cmsPageCache: 100000, 7d
#spring:
# data:
# elasticsearch:
# # 开启 ES 功能
# enabled: true
#
# # 设置 ES 服务地址
# client:
# reactive:
# endpoints: 127.0.0.1:9200
#
# # 连接超时的时间
# properties:
# transport:
# tcp:
# connect_timeout: 120s
# elasticsearch:
# enabled: true
# uris: http://Win11:9200
# connection-timeout: 120s

View File

@@ -21,4 +21,6 @@
5.4.1
5.5.0
5.5.1
5.5.2
5.5.2
5.6.0
5.6.1

View File

@@ -21,7 +21,7 @@
<label class="control-label col-sm-4" title="">
<span class="required ">*</span> ${text('所属栏目')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:treeselect id="category" title="${text('所属栏目')}"
<#form:treeselect id="category" title="${text('所属栏目')}"
path="category.categoryCode" labelPath="category.categoryName"
url="${ctx}/cms/category/treeData?excludeCode=${article.category.categoryCode}"
class="required" allowClear="false" canSelectRoot="true" canSelectParent="false" />
@@ -70,145 +70,145 @@
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('数值越大排序越靠前,可设置权重过期时间')}。">
${text('权重/排序')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<div class="form-inline m0">
<#form:input path="weight" class="form-control width-90 digits" maxlength="10"/> &nbsp;
<#form:checkbox id="weightTop" label="${text('置顶')}" value="${article.weight==9999 ?'1' : ''}"
class="form-control" style="vertical-align:middle;"/>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('数值越大排序越靠前,可设置权重过期时间')}。">
${text('权重/排序')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<div class="form-inline m0">
<#form:input path="weight" class="form-control width-90 digits" maxlength="10"/> &nbsp;
<#form:checkbox id="weightTop" label="${text('置顶')}" value="${article.weight==9999 ?'1' : ''}"
class="form-control" style="vertical-align:middle;"/>
</div>
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('时间到期后权重自动恢复为0如果为空则权重永不过期')}。">
${text('权重过期时间')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:input path="weightDate" readonly="true" maxlength="20" class="form-control laydate"
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
</div>
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('时间到期后权重自动恢复为0如果为空则权重永不过期')}。">
${text('权重过期时间')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:input path="weightDate" readonly="true" maxlength="20" class="form-control laydate"
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
</div>
</div>
</div>
</div>
<div class="form-unit">${text('详细信息')}</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-1">${text('摘要')}</label>
<div class="col-sm-11">
<#form:textarea path="description" maxlength="500" class="form-control"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-1">${text('正文')}</label>
<div class="col-sm-11">
<#form:ueditor id="content" path="articleData.content" maxlength="10000" height="500" class="required" outline="${parameter.outline}"/>
</div>
</div>
</div>
</div>
<div class="form-unit">${text('其他信息')}</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('内容图片')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-10">
<#form:fileupload id="uploadImage" bizKey="${article.id}"
bizType="article_image" returnPath="true"
filePathInputId="image" uploadType="image" readonly="false"
maxUploadNum="4" isMini="false" />
<#form:input path="image" maxlength="1000" readonly="true" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="">
<span class="required hide">*</span> ${text('关键字')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:input path="keywords" maxlength="500" class="form-control"/>
</div>
</div>
</div>
<!--<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4">${text('推荐位')}</label>
<div class="col-sm-8">
<div class="checkbox-list">
<#form:checkbox path="posidList" dictType="cms_post" class="form-control" />
<div class="form-unit">${text('详细信息')}</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-1">${text('摘要')}</label>
<div class="col-sm-11">
<#form:textarea path="description" maxlength="500" class="form-control"/>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('文章的发布状态')}">${text('状态')}<i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:select path="state" dictType="sys_status" blankOption="true" class="form-control" />
</div>
</div>
</div>-->
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('可修改发布时间,不填则使用当前时间')}">
${text('发布时间')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:input path="createDate" readonly="true" maxlength="20" class="form-control laydate"
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-1">${text('正文')}</label>
<div class="col-sm-11">
<#form:ueditor id="content" path="articleData.content" maxlength="10000" height="500" class="required" outline="${parameter.outline}"/>
</div>
</div>
</div>
</div>
</div>
<div class="form-unit">${text('高级信息')}</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="">
<span class="required hide">*</span> ${text('自定义内容视图')}<i class="fa icon-question" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"></i></label>
<div class="col-sm-8">
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
<div class="form-unit">${text('其他信息')}</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('内容图片')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-10">
<#form:fileupload id="uploadImage" bizKey="${article.id}"
bizType="article_image" returnPath="true"
filePathInputId="image" uploadType="image" readonly="false"
maxUploadNum="4" isMini="false" />
<#form:input path="image" maxlength="1000" readonly="true" class="form-control" />
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('视图参数配置')}<i class="fa icon-question" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}"></i></label>
<div class="col-sm-10">
<#form:input path="viewConfig" maxlength="1000" placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" class="form-control"/>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="">
<span class="required hide">*</span> ${text('关键字')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:input path="keywords" maxlength="500" class="form-control"/>
</div>
</div>
</div>
<!--<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4">${text('推荐位')}</label>
<div class="col-sm-8">
<div class="checkbox-list">
<#form:checkbox path="posidList" dictType="cms_post" class="form-control" />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('备注信息')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-10">
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control"/>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('文章的发布状态')}">${text('状态')}<i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:select path="state" dictType="sys_status" blankOption="true" class="form-control" />
</div>
</div>
</div>-->
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('可修改发布时间,不填则使用当前时间')}">
${text('发布时间')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:input path="createDate" readonly="true" maxlength="20" class="form-control laydate"
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
</div>
</div>
</div>
</div>
<div class="form-unit">${text('页面配置')}</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="">
<span class="required hide">*</span> ${text('自定义内容视图')}<i class="fa icon-question" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"></i></label>
<div class="col-sm-8">
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('视图参数配置')}<i class="fa icon-question" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}"></i></label>
<div class="col-sm-10">
<#form:input path="viewConfig" maxlength="1000" placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" class="form-control"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('备注信息')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-10">
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control"/>
</div>
</div>
</div>
</div>
<#form:extend collapsed="true" pathPrefix="articleData"/>
</div>
<#form:extend collapsed="true" pathPrefix="articleData"/>
<div class="box-footer">
<div class="row">
<div class="col-sm-offset-2 col-sm-10">
@@ -226,7 +226,7 @@
<script src="${ctxStatic}/colorpicker/bootstrap-colorpicker.js"></script>
<script type="text/javascript">
// 颜色控件初始化
$("#inputForm .input-color").colorpicker();
$('#inputForm .input-color').colorpicker();
// 权重、排序
$('#weightTop input').on('ifChecked ifUnchecked', function(){
if ($(this).is(':checked')){
@@ -235,7 +235,7 @@ $('#weightTop input').on('ifChecked ifUnchecked', function(){
$('#weight').val('0');
}
});
$("#inputForm").validate({
$('#inputForm').validate({
submitHandler: function(form){
$('#wordCount').val(contentUE.getContentTxt().length);
js.ajaxSubmitForm($(form), function(data){

View File

@@ -11,6 +11,7 @@
</div>
<#form:form id="inputForm" model="${category}" action="${ctx}/cms/category/save" method="post" class="form-horizontal">
<div class="box-body">
<div class="form-unit">${text('基本信息')}</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
@@ -131,112 +132,112 @@
</div>
</div>
</div>
<div class="form-unit">${text('栏目配置')}</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="是否在导航中显示该栏目">
<span class="required hide">*</span> ${text('是否在导航中显示')}<i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:radio path="inMenu" dictType="sys_show_hide" class="form-control" />
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="">
<span class="required hide">*</span> ${text('是否允许评论')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:radio path="isCanComment" dictType="sys_yes_no" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="是否在分类页中显示该栏目的文章列表">
<span class="required hide">*</span> ${text('是否在分类页中显示')}<i class="fa icon-question" ></i></label>
<div class="col-sm-8">
<#form:radio path="inList" dictType="sys_show_hide" class="form-control" />
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title=""> <span class="required hide">*</span>
${text('是否需要审核')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:radio path="isNeedAudit" dictType="sys_yes_no" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="默认展现方式,首栏目内容列表,栏目第一条内容">
<span class="required hide">*</span> ${text('内容展现模式')}<i class="fa icon-question" ></i></label>
<div class="col-sm-8">
<#form:radio path="showModes" dictType="cms_show_modes" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${category_DEFAULT_TEMPLATE}'开始">
${text('自定义列表视图')}<i class="fa icon-question "></i></label>
<div class="col-sm-8">
<#form:select path="customListView" items="${listViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"> <span class="required hide">*</span>
${text('自定义内容视图')}<i class="fa icon-question "></i></label>
<div class="col-sm-8">
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}">
${text('视图参数配置')}<i class="fa icon-question"></i></label>
<div class="col-sm-10">
<#form:input path="viewConfig" maxlength="1000" class="form-control"
placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" />
<br />
<ul class="text-muted well well-lg no-shadow m0 pt10 pb10">
<li>例如视图参数设置为:{count:2,titleShow:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}。</li>
<li>设置栏目的管理地址若设置【adminUrl:false】表示无管理地址在内容发布栏目列表中不显示该栏目</li>
<li>设置【adminUrl:'/cms/guestbook'】表示有管理地址,在内容发布栏目列表中点击该栏目链接到该地址。</li>
<!-- <li>管理地址参数若设置【adminUrlParam:'fileDownload=true'】则代表链接模型为文件下载的栏目,新增链接的时候出现文件上传对话框。</li>
<li>管理地址参数若设置【adminUrlParam:'outlineView=true'】则代表文章模型开启大纲视图编辑,在线编辑器左侧显示大纲视图。</li> -->
</ul>
</div>
</div>
</div>
</div>
<div class="form-unit">${text('其他信息')}</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('备注信息')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-10">
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control" />
</div>
</div>
</div>
</div>
<#form:extend collapsed="true" />
</div>
<div class="form-unit">${text('栏目配置')}</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="是否在导航中显示该栏目">
<span class="required hide">*</span> ${text('是否在导航中显示')}<i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:radio path="inMenu" dictType="sys_show_hide" class="form-control" />
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="">
<span class="required hide">*</span> ${text('是否允许评论')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:radio path="isCanComment" dictType="sys_yes_no" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="是否在分类页中显示该栏目的文章列表">
<span class="required hide">*</span> ${text('是否在分类页中显示')}<i class="fa icon-question" ></i></label>
<div class="col-sm-8">
<#form:radio path="inList" dictType="sys_show_hide" class="form-control" />
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title=""> <span class="required hide">*</span>
${text('是否需要审核')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-8">
<#form:radio path="isNeedAudit" dictType="sys_yes_no" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="默认展现方式,首栏目内容列表,栏目第一条内容">
<span class="required hide">*</span> ${text('内容展现模式')}<i class="fa icon-question" ></i></label>
<div class="col-sm-8">
<#form:radio path="showModes" dictType="cms_show_modes" class="form-control" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${category_DEFAULT_TEMPLATE}'开始">
${text('自定义列表视图')}<i class="fa icon-question "></i></label>
<div class="col-sm-8">
<#form:select path="customListView" items="${listViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="自定义内容视图名称必须以'${article_DEFAULT_TEMPLATE}'开始"> <span class="required hide">*</span>
${text('自定义内容视图')}<i class="fa icon-question "></i></label>
<div class="col-sm-8">
<#form:select path="customContentView" items="${contentViewList}" itemLabel="id" itemValue="id" blankOption="true" class="form-control " />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}">
${text('视图参数配置')}<i class="fa icon-question"></i></label>
<div class="col-sm-10">
<#form:input path="viewConfig" maxlength="1000" class="form-control"
placeholder="视图参数例如: {count:2, title_show:'yes'} 则在视图文件中的获取方法是:${'${'}viewConfig_count}、${'${'}viewConfig_titleShow}" />
<br />
<ul class="text-muted well well-lg no-shadow m0 pt10 pb10">
<li>例如视图参数设置为:{count:2,titleShow:'yes'} 则在视图文件中的获取方法是:\${viewConfig_count}、\${viewConfig_titleShow}。</li>
<li>设置栏目的管理地址若设置【adminUrl:false】表示无管理地址在内容发布栏目列表中不显示该栏目</li>
<li>设置【adminUrl:'/cms/guestbook'】表示有管理地址,在内容发布栏目列表中点击该栏目链接到该地址。</li>
<!-- <li>管理地址参数若设置【adminUrlParam:'fileDownload=true'】则代表链接模型为文件下载的栏目,新增链接的时候出现文件上传对话框。</li>
<li>管理地址参数若设置【adminUrlParam:'outlineView=true'】则代表文章模型开启大纲视图编辑,在线编辑器左侧显示大纲视图。</li> -->
</ul>
</div>
</div>
</div>
</div>
<div class="form-unit">${text('其他信息')}</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2" title="">
<span class="required hide">*</span> ${text('备注信息')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-10">
<#form:textarea path="remarks" rows="4" maxlength="500" class="form-control" />
</div>
</div>
</div>
</div>
<#form:extend collapsed="true" />
<div class="box-footer">
<div class="row">
<div class="col-sm-offset-2 col-sm-10">
@@ -252,7 +253,7 @@
</div>
<% } %>
<script>
$("#inputForm").validate({
$('#inputForm').validate({
submitHandler : function(form) {
js.ajaxSubmitForm($(form), function(data) {
js.showMessage(data.message);

View File

@@ -1,5 +1,4 @@
<% layout('/layouts/default.html', {title: '站点管理', libs: ['validate','fileupload','ueditor','dataGrid']}){ %>
<div class="main-content">
<div class="box box-main">
<div class="box-header with-border">
@@ -71,12 +70,10 @@
<div class="form-group">
<label class="control-label col-sm-2">${text('站点logo')}</label>
<div class="col-sm-10">
<#form:fileupload id="uploadLogo" bizKey="${site.id}" bizType="site_logo" returnPath="true"
filePathInputId="logo"
uploadType="image" readonly="false" maxUploadNum="1" isMini="false"/>
<#form:input path="logo" class="form-control"/>
<#form:fileupload id="uploadLogo" bizKey="${site.id}" bizType="site_logo" returnPath="true"
filePathInputId="logo" uploadType="image" readonly="false" maxUploadNum="1" isMini="false"/>
<#form:input path="logo" class="form-control"/>
</div>
</div>
</div>
</div>
@@ -163,7 +160,7 @@
</div>
<% } %>
<script>
$("#inputForm").validate({
$('#inputForm').validate({
submitHandler: function(form){
js.ajaxSubmitForm($(form), function(data){
js.showMessage(data.message);

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>
@@ -29,6 +29,7 @@
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Oracle 11g -->
<dependency>
<groupId>com.oracle</groupId>
@@ -36,37 +37,33 @@
<version>11.2.0.3</version>
<scope>runtime</scope>
</dependency>
<!-- Oracle 12c
<!-- Oracle 12c 及以上版本
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>orai18n</artifactId>
<version>19.3.0.0</version>
<scope>runtime</scope>
</dependency> -->
<!-- SqlServer 2008 -->
<!-- SqlServer 2008
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<scope>runtime</scope>
</dependency>
<!-- SqlServer 2012
</dependency> -->
<!-- SqlServer 2012 及以上版本 -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency> -->
</dependency>
<!-- PostgreSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- H2 DB
<dependency>
<groupId>com.h2database</groupId>
@@ -87,6 +84,11 @@
<artifactId>jeesite-framework</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<!--<artifactId>spring-boot-starter-undertow</artifactId>-->
</dependency>
<!-- ELK 日志收集 -->
<dependency>

View File

@@ -2,13 +2,20 @@
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.modules.config;
import java.util.Collection;
import java.util.Map;
import javax.servlet.Filter;
package com.jeesite.autoconfigure.core;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.shiro.cas.CasOutHandler;
import com.jeesite.common.shiro.config.FilterChainDefinitionMap;
import com.jeesite.common.shiro.filter.*;
import com.jeesite.common.shiro.realm.AuthorizingRealm;
import com.jeesite.common.shiro.realm.CasAuthorizingRealm;
import com.jeesite.common.shiro.realm.LdapAuthorizingRealm;
import com.jeesite.common.shiro.session.SessionDAO;
import com.jeesite.common.shiro.session.SessionManager;
import com.jeesite.common.shiro.web.ShiroFilterFactoryBean;
import com.jeesite.common.shiro.web.WebSecurityManager;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cas.CasSubjectFactory;
import org.apache.shiro.realm.Realm;
@@ -17,49 +24,33 @@ import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.filter.InvalidRequestFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.shiro.cas.CasOutHandler;
import com.jeesite.common.shiro.config.FilterChainDefinitionMap;
import com.jeesite.common.shiro.filter.CasFilter;
import com.jeesite.common.shiro.filter.FormFilter;
import com.jeesite.common.shiro.filter.InnerFilter;
import com.jeesite.common.shiro.filter.LdapFilter;
import com.jeesite.common.shiro.filter.LogoutFilter;
import com.jeesite.common.shiro.filter.PermissionsFilter;
import com.jeesite.common.shiro.filter.RolesFilter;
import com.jeesite.common.shiro.filter.UserFilter;
import com.jeesite.common.shiro.realm.AuthorizingRealm;
import com.jeesite.common.shiro.realm.CasAuthorizingRealm;
import com.jeesite.common.shiro.realm.LdapAuthorizingRealm;
import com.jeesite.common.shiro.session.SessionDAO;
import com.jeesite.common.shiro.session.SessionManager;
import com.jeesite.common.shiro.web.ShiroFilterFactoryBean;
import com.jeesite.common.shiro.web.WebSecurityManager;
import javax.servlet.Filter;
import java.util.Collection;
import java.util.Map;
/**
* Shiro配置
* @author ThinkGem
* @version 2021-7-6
* @version 2023-12-20
*/
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@AutoConfiguration(before = SessionAutoConfiguration.class)
@ConditionalOnProperty(name="user.enabled", havingValue="true", matchIfMissing=true)
public class ShiroConfig {
public class ShiroAutoConfiguration {
/**
* Apache Shiro Filter
*/
@Bean
@Bean("shiroFilterProxy")
@Order(Ordered.HIGHEST_PRECEDENCE + 5000)
@ConditionalOnMissingBean(name="shiroFilterProxy")
public FilterRegistrationBean<Filter> shiroFilterProxy(ShiroFilterFactoryBean shiroFilter) throws Exception {
@@ -69,14 +60,14 @@ public class ShiroConfig {
bean.setOrder(Ordered.HIGHEST_PRECEDENCE + 5000);
return bean;
}
/**
* 内部系统访问过滤器
*/
private InnerFilter shiroInnerFilter() {
return new InnerFilter();
}
/**
* CAS登录过滤器
*/
@@ -85,7 +76,7 @@ public class ShiroConfig {
bean.setAuthorizingRealm(casAuthorizingRealm);
return bean;
}
/**
* LDAP登录过滤器
*/
@@ -133,7 +124,7 @@ public class ShiroConfig {
private UserFilter shiroUserFilter() {
return new UserFilter();
}
/**
* 非法请求过滤器
*/
@@ -142,12 +133,13 @@ public class ShiroConfig {
bean.setBlockNonAscii(false);
return bean;
}
/**
* Shiro认证过滤器
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager webSecurityManager, AuthorizingRealm authorizingRealm,
@Bean("shiroFilter")
@ConditionalOnMissingBean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter(WebSecurityManager webSecurityManager, AuthorizingRealm authorizingRealm,
CasAuthorizingRealm casAuthorizingRealm, LdapAuthorizingRealm ldapAuthorizingRealm) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(webSecurityManager);
@@ -169,30 +161,33 @@ public class ShiroConfig {
bean.setFilterChainDefinitionMap(chains.getObject());
return bean;
}
/**
* 系统安全认证实现类
*/
@Bean
public AuthorizingRealm authorizingRealm(SessionDAO sessionDAO) {
@Bean("authorizingRealm")
@ConditionalOnMissingBean(name="authorizingRealm")
public AuthorizingRealm authorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO) {
AuthorizingRealm bean = new AuthorizingRealm();
bean.setSessionDAO(sessionDAO);
return bean;
}
/**
* 单点登录信息句柄单点退出用
*/
@Bean
@Bean("casOutHandler")
@ConditionalOnMissingBean(name="casOutHandler")
public CasOutHandler casOutHandler() {
return new CasOutHandler();
}
/**
* CAS安全认证实现类
*/
@Bean
public CasAuthorizingRealm casAuthorizingRealm(SessionDAO sessionDAO, CasOutHandler casOutHandler) {
@Bean("casAuthorizingRealm")
@ConditionalOnMissingBean(name="casAuthorizingRealm")
public CasAuthorizingRealm casAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO, CasOutHandler casOutHandler) {
CasAuthorizingRealm bean = new CasAuthorizingRealm();
bean.setSessionDAO(sessionDAO);
bean.setCasOutHandler(casOutHandler);
@@ -200,12 +195,13 @@ public class ShiroConfig {
bean.setCasServerCallbackUrl(Global.getProperty("shiro.casClientUrl") + Global.getAdminPath() + "/login-cas");
return bean;
}
/**
* LDAP安全认证实现类
*/
@Bean
public LdapAuthorizingRealm ldapAuthorizingRealm(SessionDAO sessionDAO, CasOutHandler casOutHandler) {
@Bean("ldapAuthorizingRealm")
@ConditionalOnMissingBean(name="ldapAuthorizingRealm")
public LdapAuthorizingRealm ldapAuthorizingRealm(@Qualifier("sessionDAO") SessionDAO sessionDAO, CasOutHandler casOutHandler) {
LdapAuthorizingRealm bean = new LdapAuthorizingRealm();
JndiLdapContextFactory contextFactory = (JndiLdapContextFactory) bean.getContextFactory();
contextFactory.setUrl(Global.getProperty("shiro.ldapUrl"/*, "ldap://127.0.0.1:389"*/));
@@ -217,9 +213,10 @@ public class ShiroConfig {
/**
* 定义Shiro安全管理配置
*/
@Bean
@Bean("webSecurityManager")
@ConditionalOnMissingBean(name="webSecurityManager")
public WebSecurityManager webSecurityManager(AuthorizingRealm authorizingRealm, CasAuthorizingRealm casAuthorizingRealm,
LdapAuthorizingRealm ldapAuthorizingRealm, SessionManager sessionManager, CacheManager shiroCacheManager) {
LdapAuthorizingRealm ldapAuthorizingRealm, SessionManager sessionManager, @Qualifier("shiroCacheManager") CacheManager shiroCacheManager) {
WebSecurityManager bean = new WebSecurityManager();
Collection<Realm> realms = ListUtils.newArrayList();
realms.add(authorizingRealm); // 第一个为权限授权控制类
@@ -232,21 +229,23 @@ public class ShiroConfig {
//bean.setRememberMeManager(null); // 关闭 RememberMe
return bean;
}
/**
* Shiro 生命周期处理器实现初始化和销毁回调
*/
@Bean(name="lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
@Bean("lifecycleBeanPostProcessor")
@ConditionalOnMissingBean(name="lifecycleBeanPostProcessor")
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* Shiro 过滤器代理配置
*/
@Bean
@Bean("defaultAdvisorAutoProxyCreator")
@DependsOn({ "lifecycleBeanPostProcessor" })
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
@ConditionalOnMissingBean(name="defaultAdvisorAutoProxyCreator")
public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator bean = new DefaultAdvisorAutoProxyCreator();
bean.setProxyTargetClass(true);
return bean;
@@ -255,22 +254,11 @@ public class ShiroConfig {
/**
* 启用Shrio授权注解拦截方式AOP式方法级权限检查
*/
@Bean
@Bean("authorizationAttributeSourceAdvisor")
@ConditionalOnMissingBean(name="authorizationAttributeSourceAdvisor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(WebSecurityManager webSecurityManager) {
AuthorizationAttributeSourceAdvisor bean = new AuthorizationAttributeSourceAdvisor();
bean.setSecurityManager(webSecurityManager);
return bean;
}
// /**
// * 在方法中 注入 webSecurityManager 进行代理控制
// */
// @Bean
// public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager webSecurityManager) {
// MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
// bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
// bean.setArguments(new Object[] { webSecurityManager });
// return bean;
// }
}

View File

@@ -200,14 +200,6 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return (!isLoginRequest(request, response) && isPermissive(mappedValue)); // 不验证登录状态,只验证登录请求
}
/**
* 跳转登录页时,跳转到默认首页
*/
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsFilter.redirectToDefaultPath(request, response);
}
/**
* 地址访问接入验证
@@ -255,6 +247,14 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
boolean isLogin = WebUtils.isTrue(request, LOGIN_PARAM);
return super.isLoginSubmission(request, response) || isLogin;
}
/**
* 跳转登录页时,跳转到默认首页
*/
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsFilter.redirectToDefaultPath(request, response);
}
/**
* 执行登录方法

View File

@@ -19,15 +19,17 @@ import javax.servlet.http.HttpServletRequest;
*/
public class InnerFilter extends AccessControlFilter {
private static final String[] prefixes = Global.getPropertyToArray("shiro.innerFilterAllowRemoteAddrs", "127.0.0.1");
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
boolean result = false;
String[] prefixes = (String[])mappedValue;
if (prefixes == null){
prefixes = Global.getPropertyToArray("shiro.innerFilterAllowRemoteAddrs", "127.0.0.1");
prefixes = InnerFilter.prefixes;
}
if (prefixes != null && request instanceof HttpServletRequest){
String ip = request.getRemoteAddr();
String ip = request.getRemoteAddr() + "]";
for (String prefix : prefixes){
result = StringUtils.startsWithIgnoreCase(ip, StringUtils.trim(prefix));
if (result){

View File

@@ -29,11 +29,6 @@ import com.jeesite.common.web.http.wrapper.GetHttpServletRequestWrapper;
*/
public class PermissionsFilter extends org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter {
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsFilter.redirectToDefaultPath(request, response);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
return PermissionsFilter.redirectTo403Page(request, response);
@@ -99,5 +94,10 @@ public class PermissionsFilter extends org.apache.shiro.web.filter.authz.Permiss
WebUtils.issueRedirect(request, response, loginUrl);
}
}
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsFilter.redirectToDefaultPath(request, response);
}
}

View File

@@ -4,10 +4,9 @@
*/
package com.jeesite.common.shiro.filter;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* 角色权限过滤器
@@ -16,14 +15,14 @@ import javax.servlet.ServletResponse;
*/
public class RolesFilter extends org.apache.shiro.web.filter.authz.RolesAuthorizationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
return PermissionsFilter.redirectTo403Page(request, response);
}
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsFilter.redirectToDefaultPath(request, response);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
return PermissionsFilter.redirectTo403Page(request, response);
}
}

View File

@@ -4,10 +4,9 @@
*/
package com.jeesite.common.shiro.filter;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* 用户权限过滤器
@@ -15,15 +14,15 @@ import javax.servlet.ServletResponse;
* @version 2017-03-22
*/
public class UserFilter extends org.apache.shiro.web.filter.authc.UserFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
return PermissionsFilter.redirectTo403Page(request, response);
}
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsFilter.redirectToDefaultPath(request, response);
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
return PermissionsFilter.redirectTo403Page(request, response);
}
}

View File

@@ -16,6 +16,9 @@ import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import javax.servlet.http.HttpServletRequest;
@@ -25,13 +28,13 @@ import javax.servlet.http.HttpServletRequest;
* @version 2018-7-11
*/
public class AuthorizingRealm extends BaseAuthorizingRealm {
public static final String HASH_ALGORITHM = "SHA-1";
public static final int HASH_INTERATIONS = 1024;
public static final int SALT_SIZE = 8;
private UserService userService;
public AuthorizingRealm() {
super();
// // 设定密码校验的Hash算法与迭代次数V4.1.4及以上版本不需要了统一使用validatePassword验证密码
@@ -39,7 +42,7 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
// matcher.setHashIterations(HASH_INTERATIONS);
// this.setCredentialsMatcher(matcher);
}
/**
* 获取登录凭证,将 authcToken 转换为 FormToken参考 CAS 实现
*/
@@ -47,7 +50,7 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
protected FormToken getFormToken(AuthenticationToken authcToken) {
return super.getFormToken(authcToken);
}
/**
* 用于用户根据登录信息获取用户信息<br>
* 1、默认根据登录账号登录信息UserUtils.getByLoginCode(formToken.getUsername(), formToken.getParam("corpCode"));<br>
@@ -58,7 +61,7 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
protected User getUserInfo(FormToken formToken) {
return super.getUserInfo(formToken);
}
/**
* 校验登录凭证如密码验证token验证验证失败抛出 AuthenticationException 异常
*/
@@ -66,6 +69,14 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
protected void assertCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo authcInfo) throws AuthenticationException {
super.assertCredentialsMatch(authcToken, authcInfo);
}
/**
* 获取用户授权信息,默认返回类型 SimpleAuthorizationInfo
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(LoginInfo loginInfo, Subject subject, Session session, User user) {
return super.doGetAuthorizationInfo(loginInfo, subject, session, user);
}
/**
* 生成密文密码生成随机的16位salt并经过1024次 sha-1 hash

View File

@@ -4,23 +4,16 @@
*/
package com.jeesite.modules.config.web;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* 将请求协议转换为 https
* @author ThinkGem
@@ -34,35 +27,23 @@ public class SchemeHttpsConfig {
public FilterRegistrationBean<Filter> schemeFilterRegistrationBean() {
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
bean.setFilter(new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
bean.setFilter((request, response, chain) -> {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
@Override
public String getScheme() {
return "https";
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
@Override
public String getScheme() {
return "https";
@Override
public StringBuffer getRequestURL() {
StringBuffer sb = super.getRequestURL();
if ("http:".equals(sb.substring(0, 5))){
return sb.replace(0, 5, "https:");
}else{
return sb;
}
@Override
public StringBuffer getRequestURL() {
StringBuffer sb = super.getRequestURL();
if ("http:".equals(sb.substring(0, 5))){
return sb.replace(0, 5, "https:");
}else{
return sb;
}
}
}, response);
}
@Override
public void destroy() {}
}
}, response);
});
bean.addUrlPatterns("/*");
return bean;

View File

@@ -107,9 +107,8 @@ public class LoginController extends BaseController{
*/
@RequestMapping(value = "loginFailure")
public String loginFailure(HttpServletRequest request, HttpServletResponse response, Model model) {
LoginInfo loginInfo = UserUtils.getLoginInfo();
// 如果已经登录,则跳转到管理首页
// // 如果已经登录,则跳转到管理首页
// LoginInfo loginInfo = UserUtils.getLoginInfo();
// if(loginInfo != null){ // 注释掉,已经登录的账号,正常返回登录失败信息,方便前端判断。
// String queryString = request.getQueryString();
// queryString = queryString == null ? "" : "?" + queryString;

View File

@@ -67,7 +67,7 @@ public class OnlineController extends BaseController{
public String list(Model model) {
return "modules/sys/onlineList";
}
/**
* 在线用户列表数据
* @author ThinkGem
@@ -75,12 +75,12 @@ public class OnlineController extends BaseController{
@RequiresPermissions("sys:online:view")
@RequestMapping(value = "listData")
@ResponseBody
public List<Map<String, Object>> listData(String isAllOnline, String isVisitor, String sessionId,
public List<Map<String, Object>> listData(String isAllOnline, String isVisitor, String sessionId,
String userCode, String userName, String userType, String orderBy) {
List<Map<String, Object>> list = ListUtils.newArrayList();
boolean excludeLeave = !Global.YES.equals(isAllOnline);
boolean excludeVisitor = !Global.YES.equals(isVisitor);
Collection<Session> sessions = sessionDAO.getActiveSessions(excludeLeave,
Collection<Session> sessions = sessionDAO.getActiveSessions(excludeLeave,
excludeVisitor, null, sessionId, userCode);
long currentTime = System.currentTimeMillis();
for (Session session : sessions){
@@ -93,10 +93,11 @@ public class OnlineController extends BaseController{
Map<String, Object> map = MapUtils.newLinkedHashMap();
// 为了安全性,需要有权限的人才能看
if (UserUtils.getSubject().isPermitted("sys:online:edit")){
map.put("id", session.getId().toString());
map.put("id", session.getId().toString());
}
map.put("startTimestamp", DateUtils.formatDateTime(session.getStartTimestamp()));
map.put("lastAccessTime", DateUtils.formatDateTime(session.getLastAccessTime()));
map.put("timeoutLong", session.getTimeout()-(currentTime-session.getLastAccessTime().getTime()));
map.put("timeout", TimeUtils.formatTime(session.getTimeout()-(currentTime-session.getLastAccessTime().getTime())));
map.put("userCode", session.getAttribute("userCode"));
map.put("userName", session.getAttribute("userName"));
@@ -109,18 +110,27 @@ public class OnlineController extends BaseController{
if (StringUtils.isBlank(orderBy)){
orderBy = "lastAccessTime desc";
}
orderBy = StringUtils.replace(orderBy, "timeout", "timeoutLong");
final String[] ss = orderBy.trim().split(" ");
if (ss.length == 2){
list.sort((o1, o2) -> {
String s1 = (String) o1.get(ss[0]);
String s2 = (String) o2.get(ss[0]);
Object s1 = o1.get(ss[0]);
Object s2 = o2.get(ss[0]);
if (s1 == null || s2 == null) {
return -1;
}
if ("asc".equals(ss[1])) {
return s1.compareTo(s2);
} else {
return s2.compareTo(s1);
if (StringUtils.endsWith(ss[0], "Long")) {
if ("asc".equals(ss[1])) {
return ((Long)s1).compareTo((Long)s2);
} else {
return ((Long)s2).compareTo((Long)s1);
}
}else{
if ("asc".equals(ss[1])) {
return ((String)s1).compareTo((String)s2);
} else {
return ((String)s2).compareTo((String)s1);
}
}
});
}

View File

@@ -4,29 +4,6 @@
*/
package com.jeesite.modules.sys.web.user;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson.JSONValidator;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
@@ -41,20 +18,28 @@ import com.jeesite.common.shiro.realm.AuthorizingRealm;
import com.jeesite.common.utils.excel.ExcelExport;
import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
import com.jeesite.common.web.BaseController;
import com.jeesite.modules.sys.entity.EmpUser;
import com.jeesite.modules.sys.entity.Employee;
import com.jeesite.modules.sys.entity.Post;
import com.jeesite.modules.sys.entity.Role;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.entity.UserDataScope;
import com.jeesite.modules.sys.service.EmpUserService;
import com.jeesite.modules.sys.service.EmployeeService;
import com.jeesite.modules.sys.service.PostService;
import com.jeesite.modules.sys.service.RoleService;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.entity.*;
import com.jeesite.modules.sys.service.*;
import com.jeesite.modules.sys.utils.EmpUtils;
import com.jeesite.modules.sys.utils.ModuleUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import io.swagger.annotations.Api;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
* 员工用户Controller
@@ -279,19 +264,20 @@ public class EmpUserController extends BaseController {
@RequiresPermissions("sys:empUser:updateStatus")
@ResponseBody
@RequestMapping(value = "disable")
public String disable(EmpUser empUser) {
public String disable(EmpUser empUser, boolean freeze) {
if (User.isSuperAdmin(empUser.getUserCode())) {
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
}
if (!EmpUser.USER_TYPE_EMPLOYEE.equals(empUser.getUserType())){
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
}
String text = freeze ? "冻结" : "停用";
if (empUser.currentUser().getUserCode().equals(empUser.getUserCode())) {
return renderResult(Global.FALSE, text("停用用户失败,不允许停用当前用户"));
return renderResult(Global.FALSE, text(text + "用户失败,不允许" + text + "当前用户"));
}
empUser.setStatus(User.STATUS_DISABLE);
empUser.setStatus(freeze ? User.STATUS_FREEZE : User.STATUS_DISABLE);
empUserService.updateStatus(empUser);
return renderResult(Global.TRUE, text("停用用户''{0}''成功", empUser.getUserName()));
return renderResult(Global.TRUE, text(text + "用户''{0}''成功", empUser.getUserName()));
}
/**
@@ -302,17 +288,18 @@ public class EmpUserController extends BaseController {
@RequiresPermissions("sys:empUser:updateStatus")
@ResponseBody
@RequestMapping(value = "enable")
public String enable(EmpUser empUser) {
public String enable(EmpUser empUser, boolean freeze) {
if (User.isSuperAdmin(empUser.getUserCode())) {
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
}
if (!EmpUser.USER_TYPE_EMPLOYEE.equals(empUser.getUserType())){
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
}
String text = freeze ? "解冻" : "启用";
empUser.setStatus(User.STATUS_NORMAL);
empUserService.updateStatus(empUser);
AuthorizingRealm.isValidCodeLogin(empUser.getLoginCode(), empUser.getCorpCode_(), null, "success");
return renderResult(Global.TRUE, text("启用用户''{0}''成功", empUser.getUserName()));
return renderResult(Global.TRUE, text(text + "用户''{0}''成功", empUser.getUserName()));
}
/**

View File

@@ -1 +1,2 @@
com.jeesite.autoconfigure.core.ShiroAutoConfiguration
com.jeesite.autoconfigure.sys.SysAutoConfiguration

View File

@@ -51,7 +51,7 @@ jdbc:
removeAbandoned: false
removeAbandonedTimeout: 2100
# Oracle 下会自动开启 PSCache并指定每个连接上 PSCache 大小。若不指定,则与 maxActive 相同4.1.5+
# 是否缓存 PreparedStatement 对象的最大数量4.1.5+
maxPoolPreparedStatementPerConnectionSize: ~
# 设置连接属性,可获取到表的 remark (备注)
@@ -451,6 +451,9 @@ shiro:
/userfiles/** = anon
/validCode = anon
/static/** = anon
/oauth2/login/** = anon
/oauth2/binder/** = anon
/oauth2/callback/** = anon
/oauth2/authorize = user
/druid/** = perms[sys:state:druid]
/bpm/modeler/** = perms[bpm:modeler]

View File

@@ -1,2 +1,3 @@
/*可以在这里添加你自己的css*/
p{line-height:28px}
p {line-height:28px}
.skin-dark {background: #1a1a1a;border-color:#414141;color:#ddd}

View File

@@ -6929,7 +6929,8 @@ var fillCharReg = new RegExp(domUtils.fillChar, 'g');
container.style.zIndex = options.zIndex;
var html = ( ie && browser.version < 9 ? '' : '<!DOCTYPE html>') +
'<html xmlns=\'http://www.w3.org/1999/xhtml\' class=\'view\' ><head>' +
'<html xmlns=\'http://www.w3.org/1999/xhtml\' class=\'view '
+ $('html').attr('class') + '\' ><head>' +
'<style type=\'text/css\'>' +
//设置四周的留边
'.view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n' +

View File

@@ -5,10 +5,8 @@
<config>
<!-- 模板分类 -->
<tplCategory>
<category value="crud" label="单表/主子表 (增删改查)">
<template>category-ref:dao</template>
<template>crud/service.xml</template>
<template>crud/controller.xml</template>
<category value="crud" label="单表/主子表 (增删改查) beetl">
<template>category-ref:crud_java</template>
<template>crud/viewList.xml</template>
<template>crud/viewForm.xml</template>
<template>crud/viewIndex.xml</template>
@@ -16,10 +14,8 @@
<template>category-ref:dao</template>
</childTable>
</category>
<category value="crud_vue" label="单表/主子表 (增删改查)Vue">
<template>category-ref:dao</template>
<template>crud/service.xml</template>
<template>crud/controller.xml</template>
<category value="crud_vue" label="单表/主子表 (增删改查) vue">
<template>category-ref:crud_java</template>
<template>crud/vueApi.xml</template>
<template>crud/vueList.xml</template>
<template>crud/vueForm.xml</template>
@@ -29,95 +25,126 @@
<template>category-ref:dao</template>
</childTable>
</category>
<category value="crud_only_vue" label="单表/主子表 (增删改查)仅Vue">
<category value="crud_only_vue" label="单表/主子表 (增删改查) 仅vue">
<template>crud/vueApi.xml</template>
<template>crud/vueList.xml</template>
<template>crud/vueForm.xml</template>
<template>crud/vueIndex.xml</template>
<template>crud/vueImport.xml</template>
</category>
<category value="crud_select" label="单表/主子表 (增删改查,含 listselect 选择页面)">
<category value="crud_only_vue_modal" label="单表/主子表 (增删改查,弹窗表单) 仅vue ">
<template>category-ref:crud_only_vue</template>
</category>
<category value="crud_only_vue_modal_route" label="单表/主子表 (增删改查,路由表单) 仅vue ">
<template>crud/vueApi.xml</template>
<template>crud/vueList.xml</template>
<!--<template>crud/vueForm.xml</template>-->
<template>crud/vueFormRoute.xml</template>
<template>crud/vueIndex.xml</template>
<template>crud/vueImport.xml</template>
</category>
<category value="crud_select" label="单表/主子表 (增删改查,含 listselect 选择页面) beetl">
<template>category-ref:crud</template>
<template>crud/viewSelect.xml</template>
<childTable>
<template>category-ref:dao</template>
</childTable>
</category>
<category value="crud_select_vue" label="单表/主子表 (增删改查,含 listselect 选择页面)Vue">
<category value="crud_select_vue" label="单表/主子表 (增删改查,含 listselect 选择页面) vue">
<template>category-ref:crud_vue</template>
<template>crud/vueSelect.xml</template>
<childTable>
<template>category-ref:dao</template>
</childTable>
</category>
<category value="crud_cloud" label="单表/主子表 (增删改查 Cloud生成 Api/Client">
<template>crud_cloud/entity.xml</template>
<template>crud_cloud/mapper.xml</template>
<template>crud_cloud/dao.xml</template>
<template>crud_cloud/api.xml</template>
<template>crud_cloud/client.xml</template>
<template>crud_cloud/service.xml</template>
<template>crud_cloud/controller.xml</template>
<category value="crud_java" label="单表/主子表 (增删改查,只生成 java/mapper 仅后端 ">
<template>category-ref:dao</template>
<template>crud/service.xml</template>
<template>crud/controller.xml</template>
<childTable>
<template>category-ref:dao</template>
</childTable>
</category>
<category value="crud_cloud" label="单表/主子表 (增删改查 Cloud生成 api/client beetl">
<template>category-ref:crud_cloud_java</template>
<template>crud_cloud/viewList.xml</template>
<template>crud_cloud/viewForm.xml</template>
<template>crud_cloud/viewIndex.xml</template>
<childTable>
<template>crud_cloud/mapper.xml</template>
<template>crud_cloud/entity.xml</template>
<template>crud_cloud/dao.xml</template>
<template>category-ref:dao_cloud</template>
</childTable>
</category>
<category value="crud_cloud_vue" label="单表/主子表 (增删改查 Cloud生成 Api/ClientVue">
<template>crud_cloud/entity.xml</template>
<template>crud_cloud/mapper.xml</template>
<template>crud_cloud/dao.xml</template>
<template>crud_cloud/api.xml</template>
<template>crud_cloud/client.xml</template>
<template>crud_cloud/service.xml</template>
<template>crud_cloud/controller.xml</template>
<category value="crud_cloud_vue" label="单表/主子表 (增删改查 Cloud生成 api/client Vue">
<template>category-ref:crud_cloud_java</template>
<template>crud/vueApi.xml</template>
<template>crud/vueList.xml</template>
<template>crud/vueIndex.xml</template>
<template>crud/vueForm.xml</template>
<template>crud/vueImport.xml</template>
<childTable>
<template>crud_cloud/mapper.xml</template>
<template>crud_cloud/entity.xml</template>
<template>crud_cloud/dao.xml</template>
<template>category-ref:dao_cloud</template>
</childTable>
</category>
<category value="crud_cloud_select" label="单表/主子表 (增删改查 Cloud含 listselect 选择页面)">
<category value="crud_cloud_select" label="单表/主子表 (增删改查 Cloud含 listselect 选择页面) beetl">
<template>category-ref:crud_cloud</template>
<template>crud_cloud/viewSelect.xml</template>
<childTable>
<template>category-ref:dao</template>
<template>category-ref:dao_cloud</template>
</childTable>
</category>
<category value="treeGrid" label="表/树结构表(增删改查">
<category value="crud_cloud_select_vue" label="表/主子表 (增删改查 Cloud含 listselect 选择页面) vue">
<template>category-ref:crud_cloud</template>
<template>crud/vueSelect.xml</template>
<childTable>
<template>category-ref:dao_cloud</template>
</childTable>
</category>
<category value="crud_cloud_java" label="单表/主子表 (增删改查 Cloud只生成 java/mapper 仅后端">
<template>category-ref:dao_cloud</template>
<template>crud_cloud/api.xml</template>
<template>crud_cloud/client.xml</template>
<template>crud_cloud/service.xml</template>
<template>crud_cloud/controller.xml</template>
<childTable>
<template>category-ref:dao_cloud</template>
</childTable>
</category>
<category value="treeGrid" label="树表/树结构表(增删改查) beetl">
<template>category-ref:crud</template>
</category>
<category value="treeGrid_vue" label="树表/树结构表(增删改查)Vue">
<category value="treeGrid_vue" label="树表/树结构表(增删改查) vue">
<template>category-ref:crud_vue</template>
</category>
<category value="treeGrid_only_vue" label="树表/树结构表(增删改查)仅Vue">
<category value="treeGrid_only_vue" label="树表/树结构表(增删改查) 仅vue">
<template>category-ref:crud_only_vue</template>
</category>
<category value="treeGrid_cloud" label="树表/树结构表(增删改查 Cloud生成 Api/Client">
<category value="treeGrid_java" label="树表/树结构表(增删改查,只生成 java/mapper 仅后端">
<template>category-ref:crud_java</template>
</category>
<category value="treeGrid_cloud" label="树表/树结构表(增删改查 Cloud含 api/client beetl">
<template>category-ref:crud_cloud</template>
</category>
<category value="treeGrid_cloud_vue" label="树表/树结构表(增删改查 Cloud生成 Api/ClientVue">
<category value="treeGrid_cloud_vue" label="树表/树结构表(增删改查 Cloud含 api/client vue">
<template>category-ref:crud_cloud_vue</template>
</category>
<category value="service" label="业务层和持久层dao/service不含控制器和视图">
<category value="treeGrid_cloud_java" label="树表/树结构表(增删改查 Cloud只生成 java/mapper 仅后端">
<template>category-ref:crud_cloud_java</template>
</category>
<category value="service" label="仅持久层和业务层(只生成 java/dao层/service层">
<template>category-ref:dao</template>
<template>crud/service.xml</template>
</category>
<category value="dao" label="关系表/仅持久层(dao/mapper/entity">
<category value="dao" label="仅持久层(只生成 java/entity/mapper/dao 文件">
<template>crud/entity.xml</template>
<template>crud/mapper.xml</template>
<template>crud/dao.xml</template>
</category>
<category value="query" label="仅查询功能(不含增删改,仅数据展现">
<category value="dao_cloud" label="仅持久层(只生成 Cloud 版 java/entity/mapper/dao 文件">
<template>crud_cloud/entity.xml</template>
<template>crud_cloud/mapper.xml</template>
<template>crud_cloud/dao.xml</template>
</category>
<category value="query" label="仅查询功能(不含增删改,只生成数据查询列表和详情)">
<template>crud/entity.xml</template>
<template>crud/mapper.xml</template>
<template>query/dao.xml</template>

View File

@@ -301,6 +301,11 @@ public class ${ClassName}Controller extends BaseController {
@RequestMapping(value = "delete")
@ResponseBody
public String delete(${ClassName} ${className}) {
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
if (!${ClassName}.STATUS_DRAFT.equals(${className}.getStatus())){
return renderResult(Global.FALSE, text("只能删除草稿状态的数据!"));
}
<% } %>
${className}Service.delete(${className});
return renderResult(Global.TRUE, text("删除${functionNameSimple}成功!"));
}

View File

@@ -6,22 +6,23 @@
<filePath>${frontDir}/src/views/${urlPrefix}</filePath>
<fileName>form.vue</fileName>
<content><![CDATA[
<% var modalOrDrawer = @StringUtils.contains(table.tplCategory, '_modal') ? 'Modal' : 'Drawer'; %>
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
* @author ${functionAuthor}
-->
<template>
<BasicDrawer
<Basic${modalOrDrawer}
v-bind="$attrs"
:showFooter="true"
:okAuth="'${permissionPrefix}:edit'"
@register="registerDrawer"
@register="register${modalOrDrawer}"
@ok="handleSubmit"
width="60%"
>
<template #title>
<Icon :icon="getTitle.icon" class="pr-1 m-1" />
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
</template>
<% if (table.childList.~size > 0){ %>
@@ -50,15 +51,17 @@
bpmEntityKey="id"
formKey="${table.optionMap['bpmFormKey']}"
completeText="提交"
:completeModal="true"
:loading="loadingRef"
:auth="'oa:oaLeave:edit'"
:auth="'${permissionPrefix}:edit'"
@validate="handleValidate"
@complete="handleSubmit"
@success="handleSuccess"
@close="closeDrawer"
@close="close${modalOrDrawer}"
/>
</template>
<% } %>
</BasicDrawer>
</Basic${modalOrDrawer}>
</template>
<script lang="ts" setup name="${compNamePrefix}Form">
import { ref, unref, computed } from 'vue';
@@ -70,7 +73,7 @@
<% if (table.childList.~size > 0){ %>
import { BasicTable, useTable } from '/@/components/Table';
<% } %>
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
import { Basic${modalOrDrawer}, use${modalOrDrawer}Inner } from '/@/components/${modalOrDrawer}';
import { ${ClassName}, ${className}Save, ${className}Form<% if(table.isTreeEntity){ %>, ${className}TreeData<% } %> } from '/@/api/${moduleName}${isNotEmpty(subModuleName)?'/'+subModuleName:''}/${className}';
<%
var userselectExists = false;
@@ -104,14 +107,14 @@ for(c in table.columnList){
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const record = ref<${ClassName}>({} as ${ClassName});
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
const loadingRef = ref(false);
<% } %>
const getTitle = computed(() => ({
icon: meta.icon || 'ant-design:book-outlined',
value: record.value.isNewRecord ? t('新增${functionNameSimple}') : t('编辑${functionNameSimple}'),
}));
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
const loadingRef = ref(false);
<% } %>
const inputFormSchemas: FormSchema[] = [
<% if(table.isTreeEntity){ %>
@@ -338,6 +341,52 @@ for (c in table.columnList){
colProps: { lg: 24, md: 24 },
slot: '${@StringUtils.uncap(child.className)}List',
},
<%
}
if(false && toBoolean(table.optionMap['isBpmForm'])){
%>
{
label: t('审批意见'),
field: 'bpm.comment',
component: 'InputTextArea',
componentProps: {
maxlength: 500,
},
colProps: { lg: 24, md: 24 },
show: () => record.value.bpm.status != '2',
},
{
label: t('下一步流程信息'),
field: 'nextTaskInfo',
component: 'FormGroup',
colProps: { lg: 24, md: 24 },
},
{
label: t('要求完成时间'),
field: 'bpm.dueDate',
component: 'DatePicker',
componentProps: {
format: 'YYYY-MM-DD HH:mm',
showTime: { format: 'HH:mm' },
},
},
{
label: t('任务优先级'),
field: 'bpm.priority',
component: 'Select',
componentProps: {
dictType: 'bpm_task_priority',
allowClear: true,
},
},
{
label: t('下一步处理人'),
field: 'bpm.nextUserCodes',
component: 'ListSelect',
componentProps: {
selectType: 'empUserSelect',
},
},
<%
}
%>
@@ -438,7 +487,7 @@ for (c in table.columnList){
editComponent: 'InputNumber',
editDefaultValue: '30',
<% }else{ %>
editComponent: 'Input',
editComponent: '${c.showType == 'input' ? 'Input' : 'InputTextArea'}',
<% } %>
<% if (c.dataLength != '0'){ %>
editComponentProps: {
@@ -547,8 +596,8 @@ for (c in table.columnList){
}
<% } %>
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
setDrawerProps({ loading: true });
const [register${modalOrDrawer}, { set${modalOrDrawer}Props, close${modalOrDrawer} }] = use${modalOrDrawer}Inner(async (data) => {
set${modalOrDrawer}Props({ loading: true });
await resetFields();
const res = await ${className}Form(data);
record.value = (res.${className} || {}) as ${ClassName};
@@ -570,23 +619,39 @@ for (c in table.columnList){
} %>
]);
<% } %>
setDrawerProps({ loading: false });
set${modalOrDrawer}Props({ loading: false });
});
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
async function handleSubmit() {
async function handleValidate(_event: any, formData: any) {
try {
const data = await validate();
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
data.bpm = record.value.bpm; // 流程信息
data.status = record.value.status; // 提交状态
formData(true, data); // 将表单数据传递给 BpmButton
} catch (error: any) {
if (error && error.errorFields) {
showMessage(t('common.validateError'));
}
console.log('error', error);
}
}
<% } %>
async function handleSubmit(<% if(toBoolean(table.optionMap['isBpmForm'])){ %>event: any<% } %>) {
try {
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
loadingRef.value = true;
<% } %>
setDrawerProps({ confirmLoading: true });
const data = event?.formData || (await validate()); // 接受 BpmButton 传递过来的表单数据
data.bpm = Object.assign(data.bpm || {}, record.value.bpm); // 流程信息
data.status = record.value.status; // 提交状态
<% } else { %>
const data = await validate();
<% } %>
set${modalOrDrawer}Props({ confirmLoading: true });
const params: any = {
isNewRecord: record.value.isNewRecord,
<%
for (c in table.columnList){
if (c.isPk == '1' || c.showType == 'hidden'){ %>
if (c.isPk == '1' || c.showType == 'hidden'){ %>
${c.attrName}: record.value.${c.attrName},
<%
}
@@ -595,11 +660,14 @@ for (c in table.columnList){
};
<% for (child in table.childList){ %>
data.${@StringUtils.uncap(child.className)}List = await get${child.className}List();
<% } %>
<% if(table.isTreeEntity){ %>
data.oldParentCode = record.value.parentCode;
<% } %>
// console.log('submit', params, data, record);
const res = await ${className}Save(params, data);
showMessage(res.message);
setTimeout(closeDrawer);
setTimeout(close${modalOrDrawer});
emit('success', data);
} catch (error: any) {
if (error && error.errorFields) {
@@ -610,7 +678,7 @@ for (c in table.columnList){
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
loadingRef.value = false;
<% } %>
setDrawerProps({ confirmLoading: false });
set${modalOrDrawer}Props({ confirmLoading: false });
}
}
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>

View File

@@ -52,16 +52,18 @@
import { Icon } from '/@/components/Icon';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { ${className}ImportData } from '/@/api/${moduleName}${isNotEmpty(subModuleName)?'/'+subModuleName:''}/${className}';
import { FileType } from 'ant-design-vue/es/upload/interface';
import { AxiosProgressEvent } from 'axios';
const emit = defineEmits(['success', 'register']);
const { t } = useI18n('${moduleName}${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${className}');
const { showMessage, showMessageModal } = useMessage();
const fileList = ref([]);
const fileList = ref(FileType[]);
const uploadInfo = ref('');
const beforeUpload = (file: never) => {
const beforeUpload = (file: FileType) => {
fileList.value = [file];
return false;
};
@@ -80,8 +82,8 @@
downloadByUrl({ url: ctxAdminPath + '/${urlPrefix}/importTemplate' });
}
function onUploadProgress(progressEvent: ProgressEvent) {
const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0;
function onUploadProgress(progressEvent: AxiosProgressEvent) {
const complete = ((progressEvent.loaded / (progressEvent.total || 1)) * 100) | 0;
if (complete != 100) {
uploadInfo.value = t('正在导入,请稍后') + ' ' + complete + '%...';
} else {

View File

@@ -6,6 +6,7 @@
<filePath>${frontDir}/src/views/${urlPrefix}</filePath>
<fileName>list.vue</fileName>
<content><![CDATA[
<% var modalOrDrawer = @StringUtils.contains(table.tplCategory, '_modal') ? 'Modal' : 'Drawer'; %>
<!--
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
@@ -13,7 +14,7 @@
-->
<template>
<div>
<BasicTable @register="registerTable"<% if(table.isTreeEntity){ %> @fetchSuccess="fetchSuccess"<% } %>>
<BasicTable @register="registerTable"<% if(table.isTreeEntity){ %> @fetch-success="fetchSuccess"<% } %>>
<template #tableTitle>
<Icon :icon="getTitle.icon" class="m-1 pr-1" />
<span> {{ getTitle.value }} </span>
@@ -81,7 +82,9 @@ if(table.isTreeEntity){
%>
</template>
</BasicTable>
<InputForm @register="registerDrawer" @success="handleSuccess" />
<% if(!@StringUtils.contains(table.tplCategory, '_route')) { %>
<InputForm @register="register${modalOrDrawer}" @success="handleSuccess" />
<% } %>
<% if(toBoolean(table.optionMap['isImportExport'])){ %>
<FormImport @register="registerImportModal" @success="handleSuccess" />
<% } %>
@@ -93,6 +96,9 @@ if(table.isTreeEntity){
<script lang="ts" setup name="${compNamePrefix}List">
import { unref<% if(table.isTreeEntity || isNotBlank(table.optionMap['leftTreeRightTableFk'])){ %>, watch<% }
%><% if(table.isTreeEntity){ %>, nextTick<% } %> } from 'vue';
<% if(@StringUtils.contains(table.tplCategory, '_route')) { %>
import { useEmitter } from '/@/store/modules/user';
<% } %>
import { useI18n } from '/@/hooks/web/useI18n';
import { useMessage } from '/@/hooks/web/useMessage';
<% if(toBoolean(table.optionMap['isImportExport'])){ %>
@@ -128,28 +134,38 @@ for(c in table.columnList){
<% if(areaselectExists) { %>
import { areaTreeData } from '/@/api/sys/area';
<% } %>
<% if(modalOrDrawer == 'Drawer' && !@StringUtils.contains(table.tplCategory, '_route')){ %>
import { useDrawer } from '/@/components/Drawer';
<% if(toBoolean(table.optionMap['isBpmForm']) || toBoolean(table.optionMap['isImportExport'])){ %>
<% } %>
<% if(modalOrDrawer == 'Modal' || (toBoolean(table.optionMap['isBpmForm'])
|| toBoolean(table.optionMap['isImportExport']))){ %>
import { useModal } from '/@/components/Modal';
<% } %>
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
<% } %>
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
import { BpmRuntimeTrace } from '/@/components/Bpm';
<% } %>
<% } %>
import { FormProps } from '/@/components/Form';
<% if(!@StringUtils.contains(table.tplCategory, '_route')) { %>
import InputForm from './form.vue';
<% if(toBoolean(table.optionMap['isImportExport'])){ %>
<% } %>
<% if(toBoolean(table.optionMap['isImportExport'])){ %>
import FormImport from './formImport.vue';
<% } %>
<% } %>
<% if(table.isTreeEntity || isNotBlank(table.optionMap['leftTreeRightTableFk'])){ %>
const props = defineProps({
treeCode: String,
});
<% } %>
<% if(@StringUtils.contains(table.tplCategory, '_route')) { %>
const emitter = useEmitter();
<% } %>
const { t } = useI18n('${moduleName}${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${className}');
const { showMessage } = useMessage();
const { meta } = unref(router.currentRoute);
const getTitle = {
icon: meta.icon || 'ant-design:book-outlined',
value: meta.title || t('${functionNameSimple}管理'),
@@ -324,7 +340,7 @@ for(c in table.columnList){
title: t('停用${functionNameSimple}'),
popConfirm: {
title: t('是否确认停用${functionNameSimple}'),
confirm: handleDisable.bind(this, { ${idParam} }),
confirm: handleDisable.bind(this, record),
},
auth: '${permissionPrefix}:edit',
ifShow: () => record.status === '0',
@@ -335,7 +351,7 @@ for(c in table.columnList){
title: t('启用${functionNameSimple}'),
popConfirm: {
title: t('是否确认启用${functionNameSimple}'),
confirm: handleEnable.bind(this, { ${idParam} }),
confirm: handleEnable.bind(this, record),
},
auth: '${permissionPrefix}:edit',
ifShow: () => record.status === '2',
@@ -348,7 +364,7 @@ for(c in table.columnList){
title: t('删除${functionNameSimple}'),
popConfirm: {
title: t('是否确认删除${functionNameSimple}'),
confirm: handleDelete.bind(this, { ${idParam} }),
confirm: handleDelete.bind(this, record),
},
auth: '${permissionPrefix}:edit',
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
@@ -378,8 +394,12 @@ for(c in table.columnList){
],
};
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload<% if(table.isTreeEntity){ %>, expandAll, collapseAll, expandCollapse<% } %>, getForm }] = useTable({
<% if(!@StringUtils.contains(table.tplCategory, '_route')) { %>
const [register${modalOrDrawer}, { open${modalOrDrawer} }] = use${modalOrDrawer}();
<% } %>
const [registerTable, { reload<% if(table.isTreeEntity){ %>, expandAll, collapseAll, expandCollapse<% } %><%
if (table.isTreeEntity || isNotBlank(table.optionMap['leftTreeRightTableFk'])
|| toBoolean(table.optionMap['isImportExport'])){ %>, getForm<% } %> }] = useTable({
api: ${className}ListData,
beforeFetch: (params) => {
return params;
@@ -423,7 +443,14 @@ for(c in table.columnList){
<% } %>
function handleForm(record: Recordable) {
openDrawer(true, record);
<% if(!@StringUtils.contains(table.tplCategory, '_route')) { %>
open${modalOrDrawer}(true, record);
<% } else { %>
router.push({
path: '/${urlPrefix}/formRoute',
query: record,
});
<% } %>
}
<% if(toBoolean(table.optionMap['isImportExport'])){ %>
@@ -444,26 +471,29 @@ for(c in table.columnList){
<% if(toBoolean(table.optionMap['isHaveDisableEnable'])){ %>
async function handleDisable(record: Recordable) {
const res = await ${className}Disable(record);
const params = { ${idParam} };
const res = await ${className}Disable(params);
showMessage(res.message);
handleSuccess();
handleSuccess(record);
}
async function handleEnable(record: Recordable) {
const res = await ${className}Enable(record);
const params = { ${idParam} };
const res = await ${className}Enable(params);
showMessage(res.message);
handleSuccess();
handleSuccess(record);
}
<% } %>
async function handleDelete(record: Recordable) {
const res = await ${className}Delete(record);
const params = { ${idParam} };
const res = await ${className}Delete(params);
showMessage(res.message);
handleSuccess();
handleSuccess(record);
}
function handleSuccess() {
reload();
function handleSuccess(record: Recordable) {
reload({ record });
}
<% if(toBoolean(table.optionMap['isBpmForm'])){ %>
@@ -473,6 +503,10 @@ for(c in table.columnList){
traceModel(true, { formKey: '${table.optionMap['bpmFormKey']}', bizKey: record.id });
}
<% } %>
<% if(@StringUtils.contains(table.tplCategory, '_route')) { %>
emitter.on('${moduleName}${isNotEmpty(subModuleName)?'-'+subModuleName:''}-${className}-reload', reload, true);
<% } %>
</script>
<% %>
]]>

View File

@@ -3,8 +3,8 @@
No deletion without permission, or be held responsible to law. -->
<template>
<name>vueSelect</name>
<filePath>${frontDir}/src/components/ListSelect/src/selectType</filePath>
<fileName>${urlPrefix}Select.ts</fileName>
<filePath>${frontDir}/src/views/${urlPrefix}</filePath>
<fileName>select.ts</fileName>
<content><![CDATA[
import { useI18n } from '/@/hooks/web/useI18n';
import { BasicColumn, BasicTableProps, FormProps } from '/@/components/Table';
@@ -204,6 +204,7 @@ export default {
tableProps,
itemCode: '<% for(pk in table.pkList){ %>${pk.attrName}<% } %>',
itemName: '<% for(pk in table.pkList){ %>${pk.attrName}<% } %>',
isShowCode: false,
};
<% %>
]]>

View File

@@ -1,5 +1,5 @@
<script>
var selectData = \${isNotBlank(selectData!) ? selectData! : "{\}"},
var selectData = \"#{isNotBlank(selectData!) ? selectData! : '{}'}",
selectNum = 0, dataGrid = $('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
columnModel: [

View File

@@ -187,7 +187,7 @@
<span class="required hide">*</span> \${text('图片上传')}</label>
<div class="${txtGridRowCol[2]}">
<${'#'}form:fileupload id="uploadImage" bizKey="\${${className}.id}" bizType="${className}_image"
uploadType="image" class="" readonly="false" preview="true"/>
uploadType="image" class="" readonly="false" preview="true" dataMap="true"/>
</div>
</div>
</div>
@@ -204,7 +204,7 @@
<span class="required hide">*</span> \${text('附件上传')}</label>
<div class="${txtGridRowCol[2]}">
<${'#'}form:fileupload id="uploadFile" bizKey="\${${className}.id}" bizType="${className}_file"
uploadType="all" class="" readonly="false" preview="true"/>
uploadType="all" class="" readonly="false" preview="true" dataMap="true"/>
</div>
</div>
</div>

View File

@@ -64,13 +64,6 @@
<artifactId>jeesite-cloud-module-seata-client</artifactId>
<version>\${project.parent.version}</version>
</dependency> -->
<!-- Spring Boot Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency> -->
</dependencies>

View File

@@ -65,9 +65,9 @@ $('#dataGrid').dataGrid({
}},
{header:'${text("公司全称")}', name:'fullName', index:'a.full_name', width:200, align:"left"},
{header:'${text("排序号")}', name:'treeSort', index:'a.tree_sort', width:80, align:"center"},
{header:'${text("归属区域")}', name:'area.treeNames', index:'a.areaCode', width:200, align:"center"},
{header:'${text("归属区域")}', name:'area.treeNames', index:'a.areaCode', width:100, align:"center"},
{header:'${text("更新时间")}', name:'updateDate', index:'a.update_date', width:200, align:"center"},
{header:'${text("备注信息")}', name:'remarks', index:'a.remarks', width:200, align:"left"},
{header:'${text("备注信息")}', name:'remarks', index:'a.remarks', width:150, align:"left"},
{header:'${text("状态")}', name:'status', index:'a.status', width:80, align:"center", formatter: function(val, obj, row, act){
return js.getDictLabel("#{@DictUtils.getDictListJson('sys_status')}", val, '未知', true);
}},

View File

@@ -70,7 +70,7 @@
<label class="control-label">${text('机构')}</label>
<div class="control-inline width-90">
<#form:treeselect id="office" title="${text('机构选择')}"
path="employee.office.officeCode" labelPath="employee.office.officeName"
path="employee.office.officeCode" labelPath="employee.office.officeName"
url="${ctx}/sys/office/treeData?ctrlPermi=${ctrlPermi}"
btnClass="btn-sm" allowClear="true" canSelectRoot="true" canSelectParent="true"/>
</div>
@@ -79,7 +79,7 @@
<label class="control-label">${text('公司')}</label>
<div class="control-inline width-90">
<#form:treeselect id="company" title="${text('公司选择')}"
path="employee.company.companyCode" labelPath="employee.company.companyName"
path="employee.company.companyCode" labelPath="employee.company.companyName"
url="${ctx}/sys/company/treeData?ctrlPermi=${ctrlPermi}"
btnClass="btn-sm" allowClear="true" canSelectRoot="true" canSelectParent="true"/>
</div>
@@ -123,7 +123,7 @@
<script>
//# // 初始化DataGrid对象
$('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
searchForm: $('#searchForm'),
columnModel: [
{header:'${text("登录账号")}', name:'loginCode', index:'a.login_code', width:125, align:"center", frozen:true, fixed:true, formatter: function(val, obj, row, act){
return '<a href="${ctx}/sys/empUser/form?userCode='+row.userCode+'&op=edit" class="btnList" data-title="${text("编辑用户")}">'+(val||row.id)+'</a>';
@@ -147,8 +147,10 @@ $('#dataGrid').dataGrid({
//# if(hasPermi('sys:empUser:updateStatus')){
if (row.status == Global.STATUS_NORMAL){
actions.push('<a href="${ctx}/sys/empUser/disable?userCode='+row.userCode+'" class="btnList" title="${text("停用用户")}" data-confirm="${text("确认要停用该用户吗?")}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
}else if (row.status == Global.STATUS_DISABLE || row.status == Global.STATUS_FREEZE || row.status == Global.STATUS_AUDIT){
}else if (row.status == Global.STATUS_DISABLE || row.status == Global.STATUS_AUDIT){
actions.push('<a href="${ctx}/sys/empUser/enable?userCode='+row.userCode+'" class="btnList" title="${text("启用用户")}" data-confirm="${text("确认要启用该用户吗?")}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
}else if (row.status == Global.STATUS_FREEZE){
actions.push('<a href="${ctx}/sys/empUser/enable?userCode='+row.userCode+'&freeze=true" class="btnList" title="${text("解冻用户")}" data-confirm="${text("确认要解冻该用户吗?")}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
}
//# }
//# if(hasPermi('sys:empUser:edit')){
@@ -164,7 +166,12 @@ $('#dataGrid').dataGrid({
actions.push('<a href="${ctx}/sys/empUser/formAuthDataScope?userCode='+row.userCode+'" class="btn btn-default btn-xs btnList" title="${text("用户分配数据权限")}"><i class="fa fa-check-circle-o"></i> ${text("数据权限")}</a>&nbsp;');
//# }
//# if(hasPermi('sys:empUser:resetpwd')){
actions.push('<a href="${ctx}/sys/empUser/resetpwd?userCode='+row.userCode+'" class="btn btn-default btn-xs btnList" title="${text("用户密码重置")}" data-confirm="${text("确认要将该用户密码重置到初始状态吗?")}"><i class="fa fa-reply-all"></i> ${text("重置密码")}</a>&nbsp;');
actions.push('<a href="${ctx}/sys/empUser/resetpwd?userCode='+row.userCode+'" class="btn btn-default btn-xs btnList" title="${text("用户密码重置")}" data-confirm="${text("确认要将该用户密码重置到初始状态吗?")}"><i class="fa fa-key"></i> ${text("重置密码")}</a>&nbsp;');
//# }
//# if(hasPermi('sys:empUser:updateStatus')){
// if (row.status == Global.STATUS_NORMAL){
// actions.push('<a href="${ctx}/sys/empUser/disable?userCode='+row.userCode+'&freeze=true" class="btn btn-default btn-xs btnList" title="${text("冻结用户")}" data-confirm="${text("确认要冻结该用户吗?")}"><i class="glyphicon glyphicon-ban-circle"></i> ${text("冻结用户")}</a>&nbsp;');
// }
//# }
actions.push('</div>');
//# }
@@ -174,7 +181,7 @@ $('#dataGrid').dataGrid({
frozenCols: true,
//# // 加载成功后执行事件
ajaxSuccess: function(data){
}
});
$('#btnExport').click(function(){

View File

@@ -331,9 +331,9 @@ $("#inputFormPwd").validate({
if(data.result == Global.TRUE){
js.alert(data.message, function(){
if ('${parameter.url}'!=''){
location = '${ctxPath}${parameter.url}';
js.window.location = '${ctxPath}${parameter.url}';
}else{
location = '${ctx}/sys/user/info?op=mpd';
js.window.location = '${ctx}/sys/user/info?op=mpd';
}
});
}else{

View File

@@ -58,7 +58,7 @@
</div>
<% } %>
<script>
var selectData = ${isNotBlank(selectData!) ? selectData! : "{\}"},
var selectData = "#{isNotBlank(selectData!) ? selectData! : '{}'}",
selectNum = 0, dataGrid = $('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
columnModel: [

View File

@@ -4,8 +4,8 @@ productName: JeeSite Demo
companyName: ThinkGem
# 产品版本、版权年份
productVersion: V5.5
copyrightYear: 2023
productVersion: V5.6
copyrightYear: 2024
# 数据库连接
jdbc:

View File

@@ -5,7 +5,7 @@
<groupId>com.jeesite</groupId>
<artifactId>jeesite-modules</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite Modules</name>

View File

@@ -6,13 +6,13 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.16</version>
<version>2.7.18</version>
<relativePath />
</parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite Parent</name>
@@ -26,8 +26,8 @@
<commons-text.version>1.10.0</commons-text.version>
<commons-email.version>1.5</commons-email.version>
<jackson-bom2.version>2.13.5</jackson-bom2.version>
<fastjson.version>2.0.33</fastjson.version>
<jackson-bom2.version>2.16.0</jackson-bom2.version>
<fastjson.version>2.0.43</fastjson.version>
<fst.version>2.57</fst.version>
<snakeyaml.version>1.33</snakeyaml.version>
<activation.version>1.1.1</activation.version>
@@ -50,21 +50,21 @@
<lucene.version>8.11.1</lucene.version>
<!-- framework version setting -->
<mybatis.version>3.5.13</mybatis.version>
<mybatis.version>3.5.14</mybatis.version>
<mybatis-spring.version>2.0.7</mybatis-spring.version>
<jsqlparser.version>4.6</jsqlparser.version>
<druid.version>1.2.18</druid.version>
<shiro.version>1.12.0</shiro.version>
<druid.version>1.2.21</druid.version>
<shiro.version>1.13.0</shiro.version>
<j2cache.version>2.8.0-release</j2cache.version>
<swagger.version>1.6.6</swagger.version>
<log4j2.version>2.18.0</log4j2.version>
<!--<log4j2.version>2.21.1</log4j2.version>-->
<!-- jdbc setting -->
<h2.version>1.4.200</h2.version>
<!-- environment setting -->
<java.version>1.8</java.version>
<tomcat2.version>9.0.75</tomcat2.version>
<!--<tomcat.version>9.0.75</tomcat.version>-->
<maven.test.skip>true</maven.test.skip>
<resource.delimiter>@</resource.delimiter>
<maven.compiler.source>${java.version}</maven.compiler.source>
@@ -120,7 +120,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<!--<version>3.8.1</version>-->
<configuration>
<parameters>true</parameters>
<showWarnings>true</showWarnings>
@@ -154,7 +154,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<!--<version>3.2.2</version>-->
<configuration>
<archive>
<manifest>
@@ -192,7 +192,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<!--<version>3.3.2</version>-->
<configuration>
<warSourceExcludes>
userfiles/**
@@ -219,7 +219,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<!--<version>3.2.0</version>-->
<configuration>
<propertiesEncoding>${project.build.sourceEncoding}</propertiesEncoding>
<delimiters>
@@ -233,7 +233,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<!--<version>3.1.0</version>-->
</plugin>
<!-- springboot插件 -->

View File

@@ -5,7 +5,7 @@
<groupId>com.jeesite</groupId>
<artifactId>jeesite</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite</name>

View File

@@ -5,7 +5,7 @@
<groupId>com.jeesite</groupId>
<artifactId>jeesite-root</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite Root</name>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@@ -72,13 +72,6 @@
<artifactId>jeesite-module-filepreview</artifactId>
<version>${project.parent.version}</version>
</dependency> -->
<!-- Spring Boot Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency> -->
</dependencies>

View File

@@ -8,8 +8,8 @@ productName: JeeSite Demo
companyName: ThinkGem
# 产品版本、版权年份
productVersion: V5.5
copyrightYear: 2023
productVersion: V5.6
copyrightYear: 2024
# 是否演示模式
demoMode: false
@@ -59,7 +59,7 @@ jdbc:
password: 123456
testSql: SELECT 1
# # Oracle 数据库配置(若使用 12c,请修改 /modules/core/pom.xml 文件,打开 12c 依赖,去掉 11g 依赖
# # Oracle 数据库配置(11g若使用 12c 以上版本,请打开 /modules/core/pom.xml 文件,替换为 Oracle 12c 驱动并编译打包 core 模块
# type: oracle
# driver: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
@@ -67,7 +67,7 @@ jdbc:
# password: jeesite
# testSql: SELECT 1 FROM DUAL
# # Sql Server 数据库配置2008
# # Sql Server 数据库配置2008 版本,请打开 /modules/core/pom.xml 文件,替换为 SqlServer 2008 驱动并编译打包 core 模块
# type: mssql
# driver: net.sourceforge.jtds.jdbc.Driver
# url: jdbc:jtds:sqlserver://127.0.0.1:1433/jeesite
@@ -75,14 +75,14 @@ jdbc:
# password: jeesite
# testSql: SELECT 1
# # Sql Server 数据库配置2012以上版本)(请修改 /modules/core/pom.xml 文件,打开 SqlServer 2012 依赖并编译打包
# # Sql Server 数据库配置2012以上版本,请打开 /modules/core/pom.xml 文件,替换为 SqlServer 2021 驱动并编译打包 core 模块
# type: mssql2012
# driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=jeesite;encrypt=true;trustServerCertificate=true
# username: jeesite
# password: jeesite
# testSql: SELECT 1
# # PostgreSql 数据库配置
# type: postgresql
# driver: org.postgresql.Driver
@@ -91,7 +91,7 @@ jdbc:
# password: jeesite
# testSql: SELECT 1
# # H2 数据库配置(请修改 /modules/core/pom.xml 文件,打开 H2 DB 依赖
# # H2 数据库配置(请打开 /modules/core/pom.xml 文件,打开 H2 DB 驱动并编译打包 core 模块
# type: h2
# driver: org.h2.Driver
# url: jdbc:h2:~/jeesite-db/jeesite
@@ -143,7 +143,7 @@ jdbc:
# removeAbandoned: false
# removeAbandonedTimeout: 2100
#
# # Oracle 下会自动开启 PSCache并指定每个连接上 PSCache 大小。若不指定,则与 maxActive 相同4.1.5+
# # 是否缓存 PreparedStatement 对象的最大数量4.1.5+
# maxPoolPreparedStatementPerConnectionSize: ~
#
# # 设置连接属性,可获取到表的 remark (备注)

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@@ -81,13 +81,6 @@
<artifactId>jeesite-module-filepreview</artifactId>
<version>${project.parent.version}</version>
</dependency> -->
<!-- Spring Boot Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency> -->
</dependencies>

View File

@@ -7,7 +7,7 @@ jdbc:
# Mysql 数据库配置
type: h2
driver: org.h2.Driver
url: jdbc:h2:/data/jeesite-db/jeesite552
url: jdbc:h2:/data/jeesite-db/jeesite560
username: jeesite
password: jeesite
testSql: SELECT 1

View File

@@ -8,8 +8,8 @@ productName: JeeSite Demo
companyName: ThinkGem
# 产品版本、版权年份
productVersion: V5.5
copyrightYear: 2023
productVersion: V5.6
copyrightYear: 2024
# 是否演示模式
demoMode: false
@@ -53,7 +53,7 @@ jdbc:
# H2 数据库配置(请修改 /modules/core/pom.xml 文件,打开 H2 DB 依赖)
type: h2
driver: org.h2.Driver
url: jdbc:h2:~/jeesite-db/jeesite552
url: jdbc:h2:~/jeesite-db/jeesite560
username: jeesite
password: jeesite
testSql: SELECT 1

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.5.2-SNAPSHOT</version>
<version>5.6.1-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@@ -86,13 +86,6 @@
<artifactId>jeesite-module-filepreview</artifactId>
<version>${project.parent.version}</version>
</dependency> -->
<!-- Spring Boot Tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency> -->
</dependencies>

View File

@@ -8,8 +8,8 @@ productName: JeeSite Demo
companyName: ThinkGem
# 产品版本、版权年份
productVersion: V5.5
copyrightYear: 2023
productVersion: V5.6
copyrightYear: 2024
# 是否演示模式
demoMode: false
@@ -59,7 +59,7 @@ jdbc:
password: 123456
testSql: SELECT 1
# # Oracle 数据库配置(若使用 12c,请修改 /modules/core/pom.xml 文件,打开 12c 依赖,去掉 11g 依赖
# # Oracle 数据库配置(11g若使用 12c 以上版本,请打开 /modules/core/pom.xml 文件,替换为 Oracle 12c 驱动并编译打包 core 模块
# type: oracle
# driver: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
@@ -67,7 +67,7 @@ jdbc:
# password: jeesite
# testSql: SELECT 1 FROM DUAL
# # Sql Server 数据库配置2008
# # Sql Server 数据库配置2008 版本,请打开 /modules/core/pom.xml 文件,替换为 SqlServer 2008 驱动并编译打包 core 模块
# type: mssql
# driver: net.sourceforge.jtds.jdbc.Driver
# url: jdbc:jtds:sqlserver://127.0.0.1:1433/jeesite
@@ -75,7 +75,7 @@ jdbc:
# password: jeesite
# testSql: SELECT 1
# # Sql Server 数据库配置2012以上版本)(请修改 /modules/core/pom.xml 文件,打开 SqlServer 2012 依赖并编译打包
# # Sql Server 数据库配置2012以上版本,请打开 /modules/core/pom.xml 文件,替换为 SqlServer 2021 驱动并编译打包 core 模块
# type: mssql2012
# driver: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=jeesite;encrypt=true;trustServerCertificate=true
@@ -91,7 +91,7 @@ jdbc:
# password: jeesite
# testSql: SELECT 1
# # H2 数据库配置(请修改 /modules/core/pom.xml 文件,打开 H2 DB 依赖
# # H2 数据库配置(请打开 /modules/core/pom.xml 文件,打开 H2 DB 驱动并编译打包 core 模块
# type: h2
# driver: org.h2.Driver
# url: jdbc:h2:~/jeesite-db/jeesite
@@ -143,7 +143,7 @@ jdbc:
# removeAbandoned: false
# removeAbandonedTimeout: 2100
#
# # Oracle 下会自动开启 PSCache并指定每个连接上 PSCache 大小。若不指定,则与 maxActive 相同4.1.5+
# # 是否缓存 PreparedStatement 对象的最大数量4.1.5+
# maxPoolPreparedStatementPerConnectionSize: ~
#
# # 设置连接属性,可获取到表的 remark (备注)

View File

@@ -9,7 +9,8 @@
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
</div>
</div>
<#form:form id="inputForm" model="${testData}" action="${ctx}/test/testData/save" method="post" class="form-horizontal">
<#form:form id="inputForm" model="${testData}" action="${ctx}/test/testData/save" method="post" class="form-horizontal"
enctype="application/json" data-params="isNewRecord,id">
<div class="box-body">
<div class="form-unit">${text('基本信息')}</div>
<#form:hidden path="id"/>
@@ -154,7 +155,7 @@
<label class="control-label col-sm-2">${text('图片上传')}</label>
<div class="col-sm-10">
<#form:fileupload id="uploadImage" bizKey="${testData.id}" bizType="testData_image"
uploadType="image" class="" readonly="false" preview="true"/>
uploadType="image" class="" readonly="false" preview="true" dataMap="true"/>
</div>
</div>
</div>
@@ -165,7 +166,7 @@
<label class="control-label col-sm-2">${text('附件上传')}</label>
<div class="col-sm-10">
<#form:fileupload id="uploadFile" bizKey="${testData.id}" bizType="testData_file"
uploadType="all" class="" readonly="false" preview="true"/>
uploadType="all" class="" readonly="false" preview="true" dataMap="true"/>
</div>
</div>
</div>
@@ -201,18 +202,18 @@
<#form:listselect id="{{d.id}}" title="{{d.title}}" name="{{d.name}}" value="{{d.value}}"
labelName="{{d.labelName}}" labelValue="{{d.labelValue}}" url="{{d.url}}"
class="{{d.cssClass}}" btnClass="btn-sm" allowClear="true" readonly="{{d.readonly}}"
itemCode="{{d.itemCode}}" itemName="{{d.itemName}}"/>
itemCode="{{d.itemCode}}" itemName="{{d.itemName}}" dataMap="true"/>
</div>//--></script>
<script id="fileuploadTpl" type="text/template">//<!--<div>
<#form:fileupload id="{{d.id}}" bizKey="{{d.bizKey}}" bizType="{{d.bizType}}" uploadType="all"
class="{{d.cssClass}}" isMini="true" preview="true" readonly="{{d.readonly}}"/>
class="{{d.cssClass}}" isMini="true" preview="true" readonly="{{d.readonly}}" dataMap="true"/>
</div>//--></script>
<script>
//初始化测试数据子表DataGrid对象
$("#testDataChildDataGrid").dataGrid({
$('#testDataChildDataGrid').dataGrid({
data: "#{toJson(testData.testDataChildList)}",
datatype: "local", // 设置本地数据
datatype: 'local', // 设置本地数据
autoGridHeight: function(){return 'auto'}, // 设置自动高度
// 设置数据表格列
@@ -419,7 +420,7 @@ $("#testDataChildDataGrid").dataGrid({
},
editable: true, edittype: "custom", editoptions: {
custom_element: function(val, editOptions) {
log(val, editOptions)
// log(val, editOptions)
return js.template('fileuploadTpl', {
id: 'fileupload_'+editOptions.rowId, bizKey: editOptions.rowId,
bizType: 'testDataChild_file', cssClass: '', readonly: false
@@ -447,7 +448,7 @@ $("#testDataChildDataGrid").dataGrid({
editGridInputFormListName: 'testDataChildList', // 提交的数据列表名
editGridInputFormListAttrs: 'status,id,testSort,testData.id,testInput,testTextarea,testSelect,testSelectMultiple,'
+'testRadio,testCheckbox,testDate,testDatetime,testUser.userCode,testUser.userName,testOffice.officeCode,'
+'testOffice.officeName,testAreaCode,testAreaName,testDataChild_file,testDataChild_file__del', // 提交数据列表的属性字段
+'testOffice.officeName,testAreaCode,testAreaName,dataMap[testDataChild_file],dataMap[testDataChild_file__del]', // 提交数据列表的属性字段
//# // 加载成功后执行事件
ajaxSuccess: function(data){
@@ -463,7 +464,7 @@ $('#testDataChildDataGrid').on('click', '.uploaderFile', function(){
})
});
});
$("#inputForm").validate({
$('#inputForm').validate({
submitHandler: function(form){
js.ajaxSubmitForm($(form), function(data){
js.showMessage(data.message);

File diff suppressed because one or more lines are too long