升级到 Spring Boot 2.0.5 以及相关依赖库全面升级,采用J2Cache作为缓存。

This commit is contained in:
thinkgem
2018-09-22 21:12:45 +08:00
parent c9ecd3cfc8
commit d9e18a70c7
71 changed files with 3664 additions and 1138 deletions

View File

@@ -1,8 +1,8 @@
# 温馨提示:不建议直接修改此文件,为了平台升级方便,建议将需要修改的参数值,复制到jeesite.yml里进行覆盖该参数值。
# 温馨提示:不建议直接修改此文件,为了平台升级方便,建议将需要修改的参数值,复制到application.yml里进行覆盖该参数值。
#============================#
#===== Database sttings =====#
#============================#
#======================================#
#========== Database sttings ==========#
#======================================#
# 数据库连接
jdbc:
@@ -73,38 +73,46 @@ jdbc:
stat:
enabled: true
# Redis 配置
redis:
enabled: false
# Redis 连接参数
host: 127.0.0.1
port: 6379
isSSL: false
timeout: 2000
password: 1234
database: 0
clientName: ~
# Redis 连接池配置
pool:
maxIdle: 3
maxTotal: 20
# 是否启用Redis系统缓存及会话专业版
cacheAndSession: false
# 定义Key的前缀标识
keyPrefix: ${jdbc.tablePrefix}
#======================================#
#========== Spring settings ===========#
#======================================#
#============================#
#===== System settings ======#
#============================#
spring:
# Redis 连接参数 RedisProperties
redis:
host: 127.0.0.1
port: 6379
ssl: false
database: 0
password: 1234
timeout: 2000
lettuce:
pool:
# 最大空闲连接数
maxIdle: 3
# 最大活动连接数
maxActive: 20
# 缓存配置
cache:
# 缓存及会话共享(专业版)
isClusterMode: false
# 清理全部缓存按钮所清理的缓存列表
clearNames: sysCache,corpCache,userCache,cmsCache
# 关闭 Spring Boot Banner 打印
main:
bannerMode: "off"
#======================================#
#========== System settings ===========#
#======================================#
#管理基础路径
# 管理基础路径
adminPath: /a
#前端基础路径
# 前端基础路径
frontPath: /f
# 分页配置
@@ -232,15 +240,15 @@ job:
trigger:
enabled: false
# 内容管理
cms:
# 内容管理主站点编码
mainSiteCode: main
## 内容管理
#cms:
#
# # 内容管理主站点编码
# mainSiteCode: main
#============================#
#==== Framework settings ====#
#============================#
#======================================#
#========= Framework settings =========#
#======================================#
# Shiro 相关配置
shiro:
@@ -296,7 +304,7 @@ shiro:
isAllowExternalSiteIframe: true
# 是否允许跨域访问,如果允许,设置允许的域名,全部域名设置*号,如果不允许,此设置应该为空
# accessControlAllowOrigin: http://demo.jeesite.net
# accessControlAllowOrigin: http://demo.jeesite.com
# accessControlAllowOrigin: '*'
# 是否在登录后生成新的Session默认false
@@ -339,19 +347,19 @@ shiro:
# Session 相关
session:
#全局会话超时,单位:毫秒, 20m=1200000ms, 30m=1800000ms, 60m=3600000ms, 12h=43200000ms, 1day=86400000ms
# 全局会话超时,单位:毫秒, 20m=1200000ms, 30m=1800000ms, 60m=3600000ms, 12h=43200000ms, 1day=86400000ms
sessionTimeout: 1800000
#手机APP设备会话超时参数设置登录请求参数加 param_deviceType=mobileApp 时有效
# 手机APP设备会话超时参数设置登录请求参数加 param_deviceType=mobileApp 时有效
mobileAppSessionTimeout: 43200000
#定时清理失效会话,清理用户直接关闭浏览器造成的孤立会话
# 定时清理失效会话,清理用户直接关闭浏览器造成的孤立会话
sessionTimeoutClean: 1200000
#会话唯一标识SessionId在Cookie中的名称。
# 会话唯一标识SessionId在Cookie中的名称。
sessionIdCookieName: jeesite.session.id
#共享的SessionId的Cookie名称保存到跟路径下第三方应用获取。同一域名下多个项目时需设置共享Cookie的名称。
# 共享的SessionId的Cookie名称保存到跟路径下第三方应用获取。同一域名下多个项目时需设置共享Cookie的名称。
#shareSessionIdCookieName: ${session.sessionIdCookieName}
# MyBatis 相关
@@ -371,21 +379,6 @@ mybatis:
sleepSeconds: 3
mappingPath: mappings
# 缓存设置
ehcache:
# 缓存配置文件路径
configFile: cache/ehcache-local.xml
# configFile: cache/ehcache-rmi.xml
# 清理缓存的缓存名称
clearNames: sysCache,userCache,corpCache,cmsCache,pageCachingFilter
# 页面缓存配置
pageCaching:
enabled: false
urlPatterns: "*.html"
# Web 相关
web:
@@ -431,21 +424,25 @@ web:
# 自定义正则表达式验证(主键、登录名)
validator:
id: '[a-zA-Z0-9_\-/\u4e00-\u9fa5]{0,64}'
id: '[a-zA-Z0-9_\-/#\u4e00-\u9fa5]{0,64}'
user.loginCode: '[a-zA-Z0-9_\u4e00-\u9fa5]{4,20}'
# 关闭核心模块的Web功能仅作为微服务时设为false
core:
enabled: true
# 在线API文档工具
swagger:
enabled: true
# 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false
error:
page:
printErrorInfo: true
#============================#
#=== FileUpload settings ====#
#============================#
#======================================#
#======== FileUpload settings =========#
#======================================#
file:
enabled: true
@@ -470,13 +467,14 @@ file:
# application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,
# application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml.presentation
#============================#
#===== Message settings =====#
#============================#
#======================================#
#========== Message settings ==========#
#======================================#
# 消息提醒中心(专业版)
msg:
enabled: true
# 是否开启实时发送消息(保存消息后立即检查未读消息并发送),分布式部署下请单独配置消息发送服务,不建议开启此选项。
realtime:
# 是否开启
@@ -521,11 +519,11 @@ msg:
debug: true
# 微信OAuth登录授权回调地址
oauth:
redirectUri: http://demo.jeesite.com/jeesite
redirectUri: http://demo.jeesite.com/js
#============================#
#===== Video settings =======#
#============================#
#======================================#
#========== Video settings ============#
#======================================#
video:
@@ -538,8 +536,3 @@ video:
# 将mp4视频的元数据信息转到视频第一帧
qtFaststartFile: d:/tools/video/qt-faststart/qt-faststart.exe
#============================#
#===== Project settings =====#
#============================#

View File

@@ -1,15 +1,23 @@
<included>
<!-- https://github.com/spring-projects/spring-boot/blob/v2.0.4.RELEASE/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml -->
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<logger name="org.apache.catalina.webresources.Cache" level="ERROR" />
<logger name="net.oschina.j2cache.caffeine.CaffeineProvider" level="ERROR" />
<logger name="org.springframework.boot.context.embedded" level="INFO" />
<logger name="org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer" level="INFO" />
<!-- <logger name="org.apache.ibatis" level="DEBUG" /> -->
<!-- <logger name="org.mybatis.spring" level="DEBUG" /> -->
<!-- <logger name="org.springframework.jdbc" level="DEBUG" /> -->
<logger name="org.mybatis.spring.transaction" level="DEBUG" />
<logger name="org.apache.catalina.webresources.Cache" level="ERROR" />
<logger name="org.springframework.boot.context.embedded" level="INFO" />
<logger name="org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer" level="INFO" />
<logger name="com.atomikos.icatch.config.UserTransactionServiceImp" level="ERROR" />
<logger name="com.atomikos.jdbc.AbstractDataSourceBean" level="ERROR" />
<!-- <logger name="io.swagger" level="DEBUG" /> -->
<!-- <logger name="springfox" level="DEBUG" /> -->
<logger name="com.jeesite" level="DEBUG" />
<logger name="com.jeesite.common.i18n" level="INFO" />
<logger name="com.jeesite.common.shiro" level="INFO" />
@@ -19,5 +27,5 @@
<logger name="com.jeesite.common.cache.JedisUtils" level="INFO" />
<logger name="com.jeesite.common.web.view.JstlView" level="INFO" />
<logger name="com.jeesite.modules.job.service.JobService" level="INFO" />
</included>

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<!-- 模板分类 -->
<tplCategory>
<category value="crud" label="单表/主子表 (增删改查)">
<template>category-ref:dao</template>
<template>crud/service.xml</template>
<template>crud/controller.xml</template>
<template>crud/viewList.xml</template>
<template>crud/viewForm.xml</template>
<childTable>
<template>category-ref:dao</template>
</childTable>
</category>
<category value="treeGrid" label="树表/树结构表(增删改查)">
<template>category-ref:crud</template>
</category>
<category value="service" label="业务层和持久层(增删改查)">
<template>category-ref:dao</template>
<template>crud/service.xml</template>
</category>
<category value="dao" label="仅持久层dao/mapper/entity">
<template>crud/dao.xml</template>
<template>crud/mapper.xml</template>
<template>crud/entity.xml</template>
</category>
<!-- <category value="tableForm" label="单表 - 表格表单(增删改查)"> -->
<!-- <template>category-ref:dao</template> -->
<!-- <template>crud/service.xml</template> -->
<!-- <template>crud/controller.xml</template> -->
<!-- <template>crud/viewList.xml</template> -->
<!-- <template>crud/viewTableForm.xml</template> -->
<!-- </category> -->
<!-- <category value="treeTableAndList" name="树结构表(左树右表)"> -->
<!-- <template>category-ref:dao</template> -->
<!-- </category> -->
<!-- <category value="query" label="仅查询功能"> -->
<!-- <template>query/entity.xml</template> -->
<!-- <template>query/mapper.xml</template> -->
<!-- <template>query/dao.xml</template> -->
<!-- <template>query/service.xml</template> -->
<!-- <template>query/controller.xml</template> -->
<!-- <template>query/viewList.xml</template> -->
<!-- <template>query/viewView.xml</template> -->
<!-- </category> -->
</tplCategory>
<!-- 属性类型 -->
<attrType>
<dict value="String" label="String"/>
<dict value="Long" label="Long"/>
<dict value="Integer" label="Integer"/>
<dict value="Double" label="Double"/>
<dict value="java.util.Date" label="Date"/>
<dict value="com.jeesite.modules.sys.entity.User" label="User"/>
<dict value="com.jeesite.modules.sys.entity.Office" label="Office"/>
<dict value="This" label="This" description="生成当前对象"/>
</attrType>
<!-- 查询类型 -->
<queryType>
<dict value="EQ" label="="/>
<dict value="NE" label="!="/>
<dict value="GT" label="&gt;"/>
<dict value="GTE" label="&gt;="/>
<dict value="LT" label="&lt;"/>
<dict value="LTE" label="&lt;="/>
<dict value="BETWEEN" label="Between"/>
<dict value="LIKE" label="Like"/>
<dict value="LEFT_LIKE" label="左 Like"/>
<dict value="RIGHT_LIKE" label="右 Like"/>
</queryType>
<!-- 字段显示类型 -->
<showType>
<dict value="input" label="单行文本框"/>
<dict value="textarea" label="多行文本框"/>
<dict value="hidden" label="隐藏域字段"/>
<dict value="select" label="单选下拉框"/>
<dict value="select_multiple" label="多选下拉框"/>
<dict value="radio" label="单选按钮"/>
<dict value="checkbox" label="复选框"/>
<dict value="date" label="日期选择"/>
<dict value="datetime" label="日期时间"/>
<dict value="userselect" label="人员选择"/>
<dict value="officeselect" label="机构选择"/>
<dict value="areaselect" label="区域选择"/>
</showType>
<!-- 字段验证 -->
<fieldValid>
<dict value="email" label="电子邮件"/>
<dict value="url" label="网址"/>
<dict value="date" label="日期"/>
<dict value="number" label="数值"/>
<dict value="integer" label="整数"/>
<dict value="digits" label="正整数"/>
<dict value="userName" label="登录账号"/>
<dict value="realName" label="真实姓名"/>
<dict value="abc" label="字母数字下划线"/>
<dict value="mobile" label="手机号"/>
<dict value="simplePhone" label="固定电话"/>
<dict value="phone" label="手机或电话"/>
<dict value="zipCode" label="邮政编码"/>
<dict value="ipv4" label="IPv4"/>
<dict value="ipv6" label="IPv6"/>
<dict value="qq" label="QQ"/>
<dict value="idcard" label="身份证"/>
</fieldValid>
</config>

View File

@@ -0,0 +1,268 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>controller</name>
<filePath>src/main/java/${packageName}/${moduleName}/web/${subModuleName}</filePath>
<fileName>${ClassName}Controller.java</fileName>
<content><![CDATA[
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package ${packageName}.${moduleName}.web${isNotEmpty(subModuleName)?'.'+subModuleName:''};
<% if(table.isTreeEntity){ %>
import java.util.List;
import java.util.Map;
<% }else{ %>
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
<% } %>
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
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.ResponseBody;
import com.jeesite.common.config.Global;
<% if(table.isTreeEntity){ %>
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.idgen.IdGen;
import com.jeesite.modules.sys.utils.UserUtils;
<% }else{ %>
import com.jeesite.common.entity.Page;
<% } %>
import com.jeesite.common.web.BaseController;
import ${packageName}.${moduleName}.entity${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${ClassName};
import ${packageName}.${moduleName}.service${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${ClassName}Service;
/**
* ${functionName}Controller
* @author ${functionAuthor}
* @version ${functionVersion}
*/
@Controller
@RequestMapping(value = "\${adminPath}/${urlPrefix}")
public class ${ClassName}Controller extends BaseController {
@Autowired
private ${ClassName}Service ${className}Service;
/**
* 获取数据
*/
@ModelAttribute
public ${ClassName} get(<% for(pk in table.pkList){ %>${pkLP.index!=1?', ':''}${pk.simpleAttrType} ${pk.simpleAttrName}<% } %>, boolean isNewRecord) {
<% if (table.pkList.~size == 1){ %>
return ${className}Service.get(<% for(pk in table.pkList){ %>${pkLP.index!=1?', ':''}${pk.simpleAttrName}<% } %>, isNewRecord);
<% }else{ %>
return ${className}Service.get(new Class<?>[]{<% for(pk in table.pkList){ %>${pkLP.index!=1?', ':''}${pk.simpleAttrType}.class<% } %>},
new Object[]{<% for(pk in table.pkList){ %>${pkLP.index!=1?', ':''}${pk.simpleAttrName}<% } %>}, isNewRecord);
<% } %>
}
/**
* 查询列表
*/
@RequiresPermissions("${permissionPrefix}:view")
@RequestMapping(value = {"list", ""})
public String list(${ClassName} ${className}, Model model) {
model.addAttribute("${className}", ${className});
return "${lastPackageName}/${viewPrefix}List";
}
/**
* 查询列表数据
*/
@RequiresPermissions("${permissionPrefix}:view")
@RequestMapping(value = "listData")
@ResponseBody
<% if(table.isTreeEntity){ %>
public List<${ClassName}> listData(${ClassName} ${className}) {
if (StringUtils.isBlank(${className}.getParentCode())) {
${className}.setParentCode(${ClassName}.ROOT_CODE);
}
<% for(c in table.columnList){ %>
<% if(c.isQuery == "1" && !c.isTreeEntityColumn){ %>
if (StringUtils.isNotBlank(${className}.${c.attrNameForGetMethod})){
${className}.setParentCode(null);
}
<% } %>
<% } %>
List<${ClassName}> list = ${className}Service.findList(${className});
return list;
}
<% }else{ %>
public Page<${ClassName}> listData(${ClassName} ${className}, HttpServletRequest request, HttpServletResponse response) {
Page<${ClassName}> page = ${className}Service.findPage(new Page<${ClassName}>(request, response), ${className});
return page;
}
<% } %>
/**
* 查看编辑表单
*/
@RequiresPermissions("${permissionPrefix}:view")
@RequestMapping(value = "form")
public String form(${ClassName} ${className}, Model model) {
<% if(table.isTreeEntity){ %>
// 创建并初始化下一个节点信息
${className} = createNextNode(${className});
<% } %>
model.addAttribute("${className}", ${className});
return "${lastPackageName}/${viewPrefix}Form";
}
<% if(table.isTreeEntity){ %>
/**
* 创建并初始化下一个节点信息,如:排序号、默认值
*/
@RequiresPermissions("${permissionPrefix}:edit")
@RequestMapping(value = "createNextNode")
@ResponseBody
public ${ClassName} createNextNode(${ClassName} ${className}) {
if (StringUtils.isNotBlank(${className}.getParentCode())){
${className}.setParent(${className}Service.get(${className}.getParentCode()));
}
if (${className}.getIsNewRecord()) {
${ClassName} where = new ${ClassName}();
where.setParentCode(${className}.getParentCode());
${ClassName} last = ${className}Service.getLastByParentCode(where);
// 获取到下级最后一个节点
if (last != null){
${className}.setTreeSort(last.getTreeSort() + 30);
<% if(table.isPkCustom){ %>
${className}.set${@StringUtils.cap(table.treeViewCodeAttrName)}(IdGen.nextCode(last.get${@StringUtils.cap(table.treeViewCodeAttrName)}()));
}else if (${className}.getParent() != null){
${className}.set${@StringUtils.cap(table.treeViewCodeAttrName)}(${className}.getParent().get${@StringUtils.cap(table.treeViewCodeAttrName)}() + "001");
<% } %>
}
}
// 以下设置表单默认数据
if (${className}.getTreeSort() == null){
${className}.setTreeSort(${ClassName}.DEFAULT_TREE_SORT);
}
return ${className};
}
<% } %>
/**
* 保存${functionNameSimple}
*/
@RequiresPermissions("${permissionPrefix}:edit")
@PostMapping(value = "save")
@ResponseBody
public String save(@Validated ${ClassName} ${className}) {
${className}Service.save(${className});
return renderResult(Global.TRUE, text("保存${functionNameSimple}成功!"));
}
<% if(@ObjectUtils.toBoolean(table.optionMap['isHaveDisableEnable'])){ %>
/**
* 停用${functionNameSimple}
*/
@RequiresPermissions("${permissionPrefix}:edit")
@RequestMapping(value = "disable")
@ResponseBody
public String disable(${ClassName} ${className}) {
<% if(table.isTreeEntity){ %>
${ClassName} where = new ${ClassName}();
where.setStatus(${ClassName}.STATUS_NORMAL);
where.setParentCodes("," + ${className}.getId() + ",");
long count = ${className}Service.findCount(where);
if (count > 0) {
return renderResult(Global.FALSE, text("该${functionNameSimple}包含未停用的子${functionNameSimple}"));
}
<% } %>
${className}.setStatus(${ClassName}.STATUS_DISABLE);
${className}Service.updateStatus(${className});
return renderResult(Global.TRUE, text("停用${functionNameSimple}成功"));
}
/**
* 启用${functionNameSimple}
*/
@RequiresPermissions("${permissionPrefix}:edit")
@RequestMapping(value = "enable")
@ResponseBody
public String enable(${ClassName} ${className}) {
${className}.setStatus(${ClassName}.STATUS_NORMAL);
${className}Service.updateStatus(${className});
return renderResult(Global.TRUE, text("启用${functionNameSimple}成功"));
}
<% } %>
<% if(@ObjectUtils.toBoolean(table.optionMap['isHaveDelete'])){ %>
/**
* 删除${functionNameSimple}
*/
@RequiresPermissions("${permissionPrefix}:edit")
@RequestMapping(value = "delete")
@ResponseBody
public String delete(${ClassName} ${className}) {
${className}Service.delete(${className});
return renderResult(Global.TRUE, text("删除${functionNameSimple}成功!"));
}
<% } %>
<% if(table.isTreeEntity){ %>
/**
* 获取树结构数据
* @param excludeCode 排除的Code
* @param isShowCode 是否显示编码true or 1显示在左侧2显示在右侧false or null不显示
* @return
*/
@RequiresPermissions("${permissionPrefix}:view")
@RequestMapping(value = "treeData")
@ResponseBody
public List<Map<String, Object>> treeData(String excludeCode, String isShowCode) {
List<Map<String, Object>> mapList = ListUtils.newArrayList();
List<${ClassName}> list = ${className}Service.findList(new ${ClassName}());
for (int i=0; i<list.size(); i++){
${ClassName} e = list.get(i);
// 过滤非正常的数据
if (!${ClassName}.STATUS_NORMAL.equals(e.getStatus())){
continue;
}
// 过滤被排除的编码(包括所有子级)
if (StringUtils.isNotBlank(excludeCode)){
if (e.getId().equals(excludeCode)){
continue;
}
if (e.getParentCodes().contains("," + excludeCode + ",")){
continue;
}
}
Map<String, Object> map = MapUtils.newHashMap();
map.put("id", e.getId());
map.put("pId", e.getParentCode());
map.put("name", StringUtils.getTreeNodeName(isShowCode, e.get${@StringUtils.cap(table.treeViewCodeAttrName)}(), e.get${@StringUtils.cap(table.treeViewNameAttrName)}()));
mapList.add(map);
}
return mapList;
}
/**
* 修复表结构相关数据
*/
@RequiresPermissions("${permissionPrefix}:edit")
@RequestMapping(value = "fixTreeData")
@ResponseBody
public String fixTreeData(${ClassName} ${className}){
if (!UserUtils.getUser().isAdmin()){
return renderResult(Global.FALSE, "操作失败,只有管理员才能进行修复!");
}
${className}Service.fixTreeData();
return renderResult(Global.TRUE, "数据修复成功");
}
<% } %>
}]]>
</content>
</template>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>dao</name>
<filePath>src/main/java/${packageName}/${moduleName}/dao/${subModuleName}</filePath>
<fileName>${ClassName}Dao.java</fileName>
<content><![CDATA[
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package ${packageName}.${moduleName}.dao${isNotEmpty(subModuleName)?'.'+subModuleName:''};
import com.jeesite.common.dao.${table.isTreeEntity?'Tree':'Crud'}Dao;
import com.jeesite.common.mybatis.annotation.MyBatisDao;
import ${packageName}.${moduleName}.entity${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${ClassName};
/**
* ${functionName}DAO接口
* @author ${functionAuthor}
* @version ${functionVersion}
*/
@MyBatisDao
public interface ${ClassName}Dao extends ${table.isTreeEntity?'Tree':'Crud'}Dao<${ClassName}> {
}]]>
</content>
</template>

View File

@@ -0,0 +1,343 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>entity</name>
<filePath>src/main/java/${packageName}/${moduleName}/entity/${subModuleName}</filePath>
<fileName>${ClassName}.java</fileName>
<content><![CDATA[
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package ${packageName}.${moduleName}.entity${isNotBlank(subModuleName)?'.'+subModuleName:''};
<% for(i in table.importList){ %>
import ${i};
<% } %>
import com.jeesite.common.entity.DataEntity;
<% if(table.isTreeEntity){ %>
import com.jeesite.common.entity.TreeEntity;
<% } %>
import com.jeesite.common.mybatis.annotation.Column;
import com.jeesite.common.mybatis.annotation.Table;
import com.jeesite.common.mybatis.mapper.query.QueryType;
/**
* ${functionName}Entity
* @author ${functionAuthor}
* @version ${functionVersion}
*/
@Table(name="${table.genTableName}", alias="a", columns={
<%
var isBase = false, isData = false,
isTree = false, isExtend = false;
// 生成字段属性
for(c in table.columnList){
// 如果是BaseEntity类属性
if(c.isBaseEntityColumn){
if(!isBase){
isBase = true;
%>
@Column(includeEntity=BaseEntity.class),
<%
}
// 如果是DataEntity类属性
}else if(c.isDataEntityColumn){
if(!isData){
isData = true;
%>
@Column(includeEntity=DataEntity.class),
<%
}
// 如果是TreeEntity类属性
}else if(c.isTreeEntityColumn){
if(!isTree){
isTree = true;
%>
@Column(includeEntity=TreeEntity.class),
<%
}
// 如果是Extend类属性
}else if(c.isExtendColumn){
if(!isExtend){
isExtend = true;
%>
@Column(includeEntity=Extend.class, attrName="extend"),
<%
}
// 其它情况下
}else{
// 容错,如果没有设置父表的主键属性,则设置
if(!@StringUtils.contains(c.attrName, ".")){
if (table.parentExists && table.parentTableFkName == c.columnName){
for (pk in table.parent.pkList){
c.fullAttrName = c.fullAttrName + '.' + pk.attrName;
break;
}
}
}
%>
@Column(name="${c.columnName}", attrName="${c.attrName}", label="${c.columnLabel}"<%
if (c.comments != c.columnLabel){
print(', comment="'+c.comments+'"');
}
if (c.isPk == @Global.YES){
print(', isPK=true');
}else{
if (c.isInsert == @Global.NO){
print(', isInsert=false');
}
if (c.isUpdate == @Global.NO){
print(', isUpdate=false');
}
if (c.isQuery == @Global.YES && @StringUtils.inString(c.queryType,
'NE', 'GT', 'GTE', 'LT', 'LTE', 'LIKE', 'LEFT_LIKE', 'RIGHT_LIKE')){
print(', queryType=QueryType.'+c.queryType);
}
if (c.isQuery == @Global.NO){
print(', isQuery=false');
}
if (c.attrName == table.treeViewNameAttrName){
print(', isTreeName=true');
}
}
%>),
<%
}
}
%>
}, <%
// 关联系统表
var joinTables = '';
for(c in table.columnList){
if (c.attrType == 'com.jeesite.modules.sys.entity.User'){
var joinTable = {
%>
@JoinTable(type=Type.LEFT_JOIN, entity=User.class, attrName="${c.simpleAttrName}", alias="u${cLP.index}",
on="u${cLP.index}.user_code = a.${c.columnName}", columns={
@Column(name="user_code", label="用户编码", isPK=true),
@Column(name="user_name", label="用户名称", isQuery=false),
}),
<%
};
joinTables = joinTables + joinTable;
}
else if (c.attrType == 'com.jeesite.modules.sys.entity.Office'){
var joinTable = {
%>
@JoinTable(type=Type.LEFT_JOIN, entity=Office.class, attrName="${c.simpleAttrName}", alias="u${cLP.index}",
on="u${cLP.index}.office_code = a.${c.columnName}", columns={
@Column(name="office_code", label="机构编码", isPK=true),
@Column(name="office_name", label="机构名称", isQuery=false),
}),
<%
};
joinTables = joinTables + joinTable;
}
}
if (isNotBlank(joinTables)){
print('joinTable={\n');
print(joinTables);
print('\t}, ');
}
%>orderBy="<% if (isTree){
%>a.tree_sorts<%
for(pk in table.pkList){
%>, a.${pk.columnName}<%
}
}else if(table.parentExists && table.createDateExists){
%>a.create_date ASC<%
}else if(table.updateDateExists){
%>a.update_date DESC<%
}else{
for(pk in table.pkList){
%>${pkLP.index!=1?', ':''}a.${pk.columnName} ${table.parentExists?'ASC':'DESC'}<%
}
} %>"
)
public class ${ClassName} extends ${table.isTreeEntity?'Tree':'Data'}Entity<${ClassName}> {
private static final long serialVersionUID = 1L;
<%
isExtend = false;
// 生成字段属性
for(c in table.columnList){
// 如果是Extend类属性
if(c.isExtendColumn){
if(!isExtend){
isExtend = true;
%>
private Extend extend; // 扩展字段
<%
}
}
// 如果不是基类属性
else if(c.columnName != 'id' && !c.isSuperColumn){
// 父类对象
if(table.parentExists && table.parentTableFkName == c.columnName){
%>
private ${@StringUtils.cap(table.parent.className)} ${c.simpleAttrName}; <% if (isNotBlank(c.comments)){ %>// ${c.comments} 父类<% } %>
<%
// 其它字段
}else{
%>
private ${c.simpleAttrType} ${c.simpleAttrName}; <%if(isNotBlank(c.comments)){%>// ${c.comments}<%}%>
<%
}
}
}
// 生成子表列表字段
for(child in table.childList){
%>
private List<${@StringUtils.cap(child.className)}> ${@StringUtils.uncap(child.className)}List = ListUtils.newArrayList(); // 子表列表
<%
}
// 生成构造方法
%>
public ${ClassName}() {
this(null);
}
<%
// 生成带主键参数的构造
if (!table.parentExists){
if (table.pkList.~size == 1){ %>
public ${ClassName}(String id){
super(id);
}
<% }else{ %>
public ${ClassName}(<% for(pk in table.pkList){ %>${pkLP.index!=1?', ':''}${pk.simpleAttrType} ${pk.simpleAttrName}<% } %>){
<% for(pk in table.pkList){ %>
this.${pk.simpleAttrName} = ${pk.simpleAttrName};
<% } %>
}
<%
}
}
// 生成父表参数的构造
else{
for(c in table.columnList){
if(table.parentExists && table.parentTableFkName == c.columnName){
%>
public ${ClassName}(${@StringUtils.cap(table.parent.className)} ${c.simpleAttrName}){
this.${c.simpleAttrName} = ${c.simpleAttrName};
}
<%
}
}
}
// 如果是树实体,则输出相应方法
if (table.isTreeEntity){
%>
@Override
public ${ClassName} getParent() {
return parent;
}
@Override
public void setParent(${ClassName} parent) {
this.parent = parent;
}
<%
}
// 生成属性的get和set方法
isExtend = false;
for(c in table.columnList){
// 如果是Extend类属性
if(c.isExtendColumn){
if(!isExtend){
isExtend = true;
%>
public Extend getExtend() {
return extend;
}
public void setExtend(Extend extend) {
this.extend = extend;
}
<%
}
// 如果不是基类属性
}else if(c.columnName != 'id' && !c.isSuperColumn){
%>
<%
for(a in c.simpleAnnotationList){
%>
@${a}
<%
}
// 父类对象
if(table.parentExists && table.parentTableFkName == c.columnName){
%>
public ${@StringUtils.cap(table.parent.className)} get${@StringUtils.cap(c.simpleAttrName)}() {
return ${c.simpleAttrName};
}
public void set${@StringUtils.cap(c.simpleAttrName)}(${@StringUtils.cap(table.parent.className)} ${c.simpleAttrName}) {
this.${c.simpleAttrName} = ${c.simpleAttrName};
}
<%
// 其它字段
}else{
%>
public ${c.simpleAttrType} get${@StringUtils.cap(c.simpleAttrName)}() {
return ${c.simpleAttrName};
}
public void set${@StringUtils.cap(c.simpleAttrName)}(${c.simpleAttrType} ${c.simpleAttrName}) {
this.${c.simpleAttrName} = ${c.simpleAttrName};
}
<%
}
}
}
// 生成条件字段get和set方法范围类型
for(c in table.columnList){
if(c.isQuery == "1" && c.queryType == "BETWEEN"){
%>
public ${c.simpleAttrType} get${@StringUtils.cap(c.simpleAttrName)}_gte() {
return sqlMap.getWhere().getValue("${c.columnName}", QueryType.GTE);
}
public void set${@StringUtils.cap(c.simpleAttrName)}_gte(${c.simpleAttrType} ${c.simpleAttrName}) {
sqlMap.getWhere().and("${c.columnName}", QueryType.GTE, ${c.simpleAttrName});
}
public ${c.simpleAttrType} get${@StringUtils.cap(c.simpleAttrName)}_lte() {
return sqlMap.getWhere().getValue("${c.columnName}", QueryType.LTE);
}
public void set${@StringUtils.cap(c.simpleAttrName)}_lte(${c.simpleAttrType} ${c.simpleAttrName}) {
sqlMap.getWhere().and("${c.columnName}", QueryType.LTE, ${c.simpleAttrName});
}
<%
}
}
// 生成子表列表get和set方法
for(child in table.childList){
%>
public List<${@StringUtils.cap(child.className)}> get${@StringUtils.cap(child.className)}List() {
return ${@StringUtils.uncap(child.className)}List;
}
public void set${@StringUtils.cap(child.className)}List(List<${@StringUtils.cap(child.className)}> ${@StringUtils.uncap(child.className)}List) {
this.${@StringUtils.uncap(child.className)}List = ${@StringUtils.uncap(child.className)}List;
}
<% } %>
}]]>
</content>
</template>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>mapper</name>
<filePath>src/main/resources/mappings/${lastPackageName}/${moduleName}/${subModuleName}</filePath>
<fileName>${ClassName}Dao.xml</fileName>
<content><![CDATA[
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${packageName}.${moduleName}.dao${isNotBlank(subModuleName)?'.'+subModuleName:''}.${ClassName}Dao">
<!-- 查询数据
<select id="findList" resultType="${ClassName}">
SELECT \${sqlMap.column.toSql()}
FROM \${sqlMap.table.toSql()}
<where>
\${sqlMap.where.toSql()}
</where>
ORDER BY \${sqlMap.order.toSql()}
</select> -->
</mapper>]]>
</content>
</template>

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>service</name>
<filePath>src/main/java/${packageName}/${moduleName}/service/${subModuleName}</filePath>
<fileName>${ClassName}Service.java</fileName>
<content><![CDATA[
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
*/
package ${packageName}.${moduleName}.service${isNotEmpty(subModuleName)?'.'+subModuleName:''};
import java.util.List;
<% if (table.childList.~size > 0){ %>
import org.springframework.beans.factory.annotation.Autowired;
<% } %>
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jeesite.common.entity.Page;
import com.jeesite.common.service.${table.isTreeEntity?'Tree':'Crud'}Service;
import ${packageName}.${moduleName}.entity${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${ClassName};
import ${packageName}.${moduleName}.dao${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${ClassName}Dao;
<% if(@ObjectUtils.toBoolean(table.optionMap['isImageUpload']) || @ObjectUtils.toBoolean(table.optionMap['isFileUpload'])){ %>
import com.jeesite.modules.file.utils.FileUploadUtils;
<% } %>
<% for (child in table.childList){ %>
import ${packageName}.${moduleName}.entity${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${@StringUtils.cap(child.className)};
import ${packageName}.${moduleName}.dao${isNotEmpty(subModuleName)?'.'+subModuleName:''}.${@StringUtils.cap(child.className)}Dao;
<% } %>
/**
* ${functionName}Service
* @author ${functionAuthor}
* @version ${functionVersion}
*/
@Service
@Transactional(readOnly=true)
public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Crud'}Service<${ClassName}Dao, ${ClassName}> {
<% for (child in table.childList){ %>
@Autowired
private ${@StringUtils.cap(child.className)}Dao ${@StringUtils.uncap(child.className)}Dao;
<% } %>
/**
* 获取单条数据
* @param ${className}
* @return
*/
@Override
public ${ClassName} get(${ClassName} ${className}) {
<% if (table.childList.~size > 0){ %>
${ClassName} entity = super.get(${className});
if (entity != null){
<% for (child in table.childList){ %>
${@StringUtils.cap(child.className)} ${@StringUtils.uncap(child.className)} = new ${@StringUtils.cap(child.className)}(entity);
${@StringUtils.uncap(child.className)}.setStatus(${@StringUtils.cap(child.className)}.STATUS_NORMAL);
entity.set${@StringUtils.cap(child.className)}List(${@StringUtils.uncap(child.className)}Dao.findList(${@StringUtils.uncap(child.className)}));
<% } %>
}
return entity;
<% }else{ %>
return super.get(${className});
<% } %>
}
<% if(!table.isTreeEntity){ %>
/**
* 查询分页数据
* @param page 分页对象
* @param ${className}
* @return
*/
@Override
public Page<${ClassName}> findPage(Page<${ClassName}> page, ${ClassName} ${className}) {
return super.findPage(page, ${className});
}
<% }else{ %>
/**
* 查询列表数据
* @param ${className}
* @return
*/
@Override
public List<${ClassName}> findList(${ClassName} ${className}) {
return super.findList(${className});
}
<% } %>
/**
* 保存数据(插入或更新)
* @param ${className}
*/
@Override
@Transactional(readOnly=false)
public void save(${ClassName} ${className}) {
super.save(${className});
<% if(@ObjectUtils.toBoolean(table.optionMap['isImageUpload'])){ %>
// 保存上传图片
FileUploadUtils.saveFileUpload(${className}.getId(), "${className}_image");
<% } %>
<% if(@ObjectUtils.toBoolean(table.optionMap['isFileUpload'])){ %>
// 保存上传附件
FileUploadUtils.saveFileUpload(${className}.getId(), "${className}_file");
<% } %>
<% for (child in table.childList) { %>
// 保存 ${ClassName}子表
for (${@StringUtils.cap(child.className)} ${@StringUtils.uncap(child.className)} : ${className}.get${@StringUtils.cap(child.className)}List()){
if (!${@StringUtils.cap(child.className)}.STATUS_DELETE.equals(${@StringUtils.uncap(child.className)}.getStatus())){
<%
for(c in child.columnList){
if (child.parentExists && child.parentTableFkName == c.columnName){
%>
${@StringUtils.uncap(child.className)}.set${@StringUtils.cap(c.simpleAttrName)}(${className});
<%
}
}
%>
if (${@StringUtils.uncap(child.className)}.getIsNewRecord()){
${@StringUtils.uncap(child.className)}.preInsert();
${@StringUtils.uncap(child.className)}Dao.insert(${@StringUtils.uncap(child.className)});
}else{
${@StringUtils.uncap(child.className)}.preUpdate();
${@StringUtils.uncap(child.className)}Dao.update(${@StringUtils.uncap(child.className)});
}
}else{
${@StringUtils.uncap(child.className)}Dao.delete(${@StringUtils.uncap(child.className)});
}
}
<% } %>
}
/**
* 更新状态
* @param ${className}
*/
@Override
@Transactional(readOnly=false)
public void updateStatus(${ClassName} ${className}) {
super.updateStatus(${className});
}
/**
* 删除数据
* @param ${className}
*/
@Override
@Transactional(readOnly=false)
public void delete(${ClassName} ${className}) {
super.delete(${className});
<% for (child in table.childList) { %>
${@StringUtils.cap(child.className)} ${@StringUtils.uncap(child.className)} = new ${@StringUtils.cap(child.className)}();
<%
for(c in child.columnList){
if (child.parentExists && child.parentTableFkName == c.columnName){
%>
${@StringUtils.uncap(child.className)}.set${@StringUtils.cap(c.simpleAttrName)}(${className});
<%
}
}
%>
${@StringUtils.uncap(child.className)}Dao.delete(${@StringUtils.uncap(child.className)});
<% } %>
}
}]]>
</content>
</template>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>viewForm</name>
<filePath>src/main/resources/views/${lastPackageName}/${moduleName}/${subModuleName}</filePath>
<fileName>${className}Form.html</fileName>
<content><![CDATA[
<%
var extLibs = '';
if(@ObjectUtils.toBoolean(table.optionMap['isImageUpload']) || @ObjectUtils.toBoolean(table.optionMap['isFileUpload'])){
extLibs = extLibs + ',\'fileupload\'';
}
if(table.childList.~size > 0){
extLibs = extLibs + ',\'dataGrid\'';
}
%>
\<% layout('/layouts/default.html', {title: '${functionNameSimple}管理', libs: ['validate'${extLibs}]}){ %>
<div class="main-content">
<div class="box box-main">
<div class="box-header with-border">
<div class="box-title">
<i class="fa fa-list-alt"></i> \${text(${className}.isNewRecord ? '新增${functionNameSimple}' : '编辑${functionNameSimple}')}
</div>
<div class="box-tools pull-right">
<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="\${${className}}" action="\${ctx}/${urlPrefix}/save" method="post" class="form-horizontal">
<div class="box-body">
<div class="form-unit">\${text('基本信息')}</div>
<% if(table.isTreeEntity){ %>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4">\${text('上级${functionNameSimple}')}</label>
<div class="col-sm-8">
<${'#'}form:treeselect id="parent" title="\${text('上级${functionNameSimple}')}"
path="parent.id" labelPath="parent.${table.treeViewNameAttrName}"
url="\${ctx}/${urlPrefix}/treeData?excludeCode=\${${className}.id}"
class="" allowClear="true" canSelectRoot="true" canSelectParent="true"/>
</div>
</div>
</div>
</div>
<% } %>
<% include('/templates/modules/gen/include/formControl.html'){} %>
<% include('/templates/modules/gen/include/formChildTable.html'){} %>
</div>
<div class="box-footer">
<div class="row">
<div class="col-sm-offset-2 col-sm-10">
\<% if (hasPermi('${permissionPrefix}:edit')){ %>
<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> \${text('保 存')}</button>&nbsp;
\<% } %>
<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="js.closeCurrentTabPage()"><i class="fa fa-reply-all"></i> \${text('关 闭')}</button>
</div>
</div>
</div>
</${'#'}form:form>
</div>
</div>
\<% } %>
<% include('/templates/modules/gen/include/formChildTableScript.html'){} %>
<script>
$("#inputForm").validate({
submitHandler: function(form){
js.ajaxSubmitForm($(form), function(data){
js.showMessage(data.message);
if(data.result == Global.TRUE){
js.closeCurrentTabPage(function(contentWindow){
<% if(table.isTreeEntity){ %>
contentWindow.$('#dataGrid').dataGrid('refreshTreeChildren',
$('#parentCode').val(), '\${${className}.id}');
<% }else{ %>
contentWindow.page();
<% } %>
});
}
}, "json");
}
});
<% if(table.isTreeEntity){ %>
// 选择父级菜单回调方法
function treeselectCallback(id, act, index, layero){
if (id == 'parent' && (act == 'ok' || act == 'clear')){
// 创建并初始化下一个节点信息,如:排序号、默认值
$.get('\${ctx}/${urlPrefix}/createNextNode?parentCode='
+$('#parentCode').val(), function(data){
$('#treeSort').val(data.treeSort);
});
}
}
<% } %>
</script>]]>
</content>
</template>

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<name>viewList</name>
<filePath>src/main/resources/views/${lastPackageName}/${moduleName}/${subModuleName}</filePath>
<fileName>${className}List.html</fileName>
<content><![CDATA[
\<% layout('/layouts/default.html', {title: '${functionNameSimple}管理', libs: ['dataGrid']}){ %>
<div class="main-content">
<div class="box box-main">
<div class="box-header">
<div class="box-title">
<i class="fa fa-list-alt"></i> \${text('${functionNameSimple}管理')}
</div>
<div class="box-tools pull-right">
<a href="#" class="btn btn-default" id="btnSearch" title="\${text('查询')}"><i class="fa fa-filter"></i> \${text('查询')}</a>
<% if(table.isTreeEntity){ %>
<a href="#" class="btn btn-default" id="btnRefreshTree" title="\${text('刷新')}"><i class="fa fa-refresh"></i> \${text('刷新')}</a>
<a href="#" class="btn btn-default" id="btnExpandTreeNode" title="\${text('展开一级')}"><i class="fa fa-angle-double-down"></i> \${text('展开')}</a>
<a href="#" class="btn btn-default" id="btnCollapseTreeNode" title="\${text('折叠全部')}"><i class="fa fa-angle-double-up"></i> \${text('折叠')}</a>
<% } %>
\<% if(hasPermi('${permissionPrefix}:edit')){ %>
<a href="\${ctx}/${urlPrefix}/form" class="btn btn-default btnTool" title="\${text('新增${functionNameSimple}')}"><i class="fa fa-plus"></i> \${text('新增')}</a>
\<% } %>
</div>
</div>
<div class="box-body">
<% include('/templates/modules/gen/include/searchForm.html'){} %>
<table id="dataGrid"></table>
<% if(!table.isTreeEntity){ %>
<div id="dataGridPage"></div>
<% } %>
</div>
</div>
</div>
\<% } %>
<script>
// 初始化DataGrid对象
$('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
columnModel: [
<%
// 是否是第一列
var firstColumn = true;
// 获取到唯一ID的url参数字符串
var idParam = '';
for(pk in table.pkList){
idParam = idParam + (pkLP.index!=1?'&':'') + pk.attrName + '=\'+row.' + pk.attrName + '+\'';
}
// 生成树表的节点列
if(table.isTreeEntity){
for(c in table.columnList){
if(c.attrName == table.treeViewNameAttrName){
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', index:'a.${c.columnName}', width:250, align:"left", frozen:true, formatter: function(val, obj, row, act){
return '( '+row.${table.treeViewCodeAttrName}+' ) '+'<a href="\${ctx}/${urlPrefix}/form?${idParam}" class="btnList" data-title="\${text('编辑${functionNameSimple}')}">'+(val||row.id)+'</a>';
}},
<%
firstColumn = false;
break;
}
}
}
%>
<%
for(c in table.columnList){
if(c.isList == "1"){
// 如果是树结构的字段,则自动忽略
if(table.isTreeEntity && @StringUtils.inString(c.columnName, 'parent_code',
'parent_codes', 'tree_sorts', 'tree_leaf', 'tree_level', 'tree_names')
&& c.attrName != table.treeViewCodeAttrName
&& c.attrName != table.treeViewNameAttrName){
}
// 如果是首列,则输出带链接的列
else if(firstColumn){
firstColumn = false;
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', index:'a.${c.columnName}', width:150, align:"left", frozen:true, formatter: function(val, obj, row, act){
return '<a href="\${ctx}/${urlPrefix}/form?${idParam}" class="btnList" data-title="\${text('编辑${functionNameSimple}')}">'+(val||row.id)+'</a>';
}},
<% }else if(c.showType == 'select' || c.showType == 'select_multiple' || c.showType == 'checkbox' || c.showType == 'radio'){ %>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', index:'a.${c.columnName}', width:150, align:"center", formatter: function(val, obj, row, act){
return js.getDictLabel(\${@DictUtils.getDictListJson('${c.optionMap['dictType']}')}, val, '\${text('未知')}', true);
}},
<% }else if(c.showType == "userselect" || c.showType == "officeselect" || c.showType == "areaselect"){ %>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName2}', index:'a.${c.columnName}', width:150, align:"center"},
<% }else{
if (@StringUtils.inString(c.attrType, 'java.util.Date', 'Integer', 'Long')){
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', index:'a.${c.columnName}', width:150, align:"center"},
<%
}else if (@StringUtils.inString(c.attrType, 'Float', 'Double')){
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', index:'a.${c.columnName}', width:150, align:"right", formatter: function(val, obj, row, act){
return js.formatNumber(val, 2, false, ''); // 数值类型格式化 (原始数值, 小数位数, 是否千分位, 默认值金额情况下设置0.00);
}},
<%
}else {
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', index:'a.${c.columnName}', width:150, align:"left"},
<%
}
}
}
}
%>
{header:'\${text('操作')}', name:'actions', width:120, sortable:false, title:false, formatter: function(val, obj, row, act){
var actions = [];
\<% if(hasPermi('${permissionPrefix}:edit')){ %>
actions.push('<a href="\${ctx}/${urlPrefix}/form?${idParam}" class="btnList" title="\${text('编辑${functionNameSimple}')}"><i class="fa fa-pencil"></i></a>&nbsp;');
<% if(@ObjectUtils.toBoolean(table.optionMap['isHaveDisableEnable'])){ %>
if (row.status == Global.STATUS_NORMAL){
actions.push('<a href="\${ctx}/${urlPrefix}/disable?${idParam}" class="btnList" title="\${text('停用${functionNameSimple}')}" data-confirm="\${text('确认要停用该${functionNameSimple}吗?')}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
}
if (row.status == Global.STATUS_DISABLE){
actions.push('<a href="\${ctx}/${urlPrefix}/enable?${idParam}" class="btnList" title="\${text('启用${functionNameSimple}')}" data-confirm="\${text('确认要启用该${functionNameSimple}吗?')}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
}
<% } %>
<% if(@ObjectUtils.toBoolean(table.optionMap['isHaveDelete'])){ %>
actions.push('<a href="\${ctx}/${urlPrefix}/delete?${idParam}" class="btnList" title="\${text('删除${functionNameSimple}')}" data-confirm="\${text('确认要删除该${functionNameSimple}<% if(table.isTreeEntity){ %>及所有子${functionNameSimple}<% } %>吗?')}"<% if(table.isTreeEntity){ %> data-deltreenode="'+row.id+'"<% } %>><i class="fa fa-trash-o"></i></a>&nbsp;');
<% } %>
<% if(table.isTreeEntity){ %>
actions.push('<a href="\${ctx}/${urlPrefix}/form?parentCode='+row.id+'" class="btnList" title="\${text('新增下级${functionNameSimple}')}"><i class="fa fa-plus-square"></i></a>&nbsp;');
<% } %>
\<% } %>
return actions.join('');
}}
],
<% if(table.isTreeEntity){ %>
treeGrid: true, // 启用树结构表格
defaultExpandLevel: 0, // 默认展开的层次
expandNodeClearPostData: '<%
for(c in table.columnList){
if(c.isQuery == "1" && !c.isTreeEntityColumn){
print(c.attrName + ',');
}
} %>', // 展开节点清理请求参数数据(一般设置查询条件的字段属性,否则在查询后,不能展开子节点数据)
<% } %>
// 加载成功后执行事件
ajaxSuccess: function(data){
}
});
</script>]]>
</content>
</template>

View File

@@ -0,0 +1,14 @@
<%
// 输出子表控件
for (child in table.childList){
%>
<h4 class="form-unit">\${text('${child.comments}')}</h4>
<div class="ml10 mr10">
<table id="${@StringUtils.uncap(child.className)}DataGrid"></table>
\<% if (hasPermi('${permissionPrefix}:edit')){ %>
<a href="#" id="${@StringUtils.uncap(child.className)}DataGridAddRowBtn" class="btn btn-primary btn-sm mt10 mb10"><i class="fa fa-plus"></i> \${text('增行')}</a>
\<% } %>
</div>
<%
}
%>

View File

@@ -0,0 +1,172 @@
<% // 输出子表 Script脚本
if (table.childList.~size > 0){ %>
<script>
<%
var treeselectExists = false;
for(child in table.childList){
%>
//初始化${child.comments}DataGrid对象
$("#${@StringUtils.uncap(child.className)}DataGrid").dataGrid({
data: \${toJson(${className}.${@StringUtils.uncap(child.className)}List)},
datatype: "local", // 设置本地数据
autoGridHeight: function(){return 'auto'}, // 设置自动高度
// 设置数据表格列
columnModel: [
{header:'状态', name:'status', editable:true, hidden:true},
{header:'主键', name:'<% for(pk in child.pkList){ %>${pk.attrName}<% break; }%>', editable:true, hidden:true},
<%
// 遍历子表字段
for (c in child.columnList){
// 如果不是编辑字段,则跳过
if (c.isEdit != '1'){
continue;
}
// 如果是外键,父级的主键
if(child.parentExists && child.parentTableFkName == c.columnName){
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', editable:true, hidden:true},
<%
continue;
}
// 生成控件属性
var attrs = '';
if (c.dataLength != '0'){
var s = { %>'maxlength':'${c.dataLength}', <% };
attrs = attrs + s;
}
// 生成控件样式
var cssClass = '';
if (c.isNull != '1'){
cssClass = cssClass + ' required';
}
if (c.attrType == 'Long' || c.attrType == 'Integer'){
cssClass = cssClass + ' digits';
}
if (c.attrType == 'Double'){
cssClass = cssClass + ' number';
}
// 输出列字段
if(c.showType == 'input'){
%> {header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', width:150, editable:true, edittype:'text', editoptions:{${attrs}'class':'form-control${cssClass}'}},
<%
}else if(c.showType == 'textarea'){
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', width:150, editable:true, edittype:'textarea', editoptions:{${attrs}'class':'form-control${cssClass}', 'rows':'1'}},
<%
}else if(c.showType == 'select' || c.showType == 'select_multiple' || c.showType == 'radio' || c.showType == 'checkbox'){
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', width:100,
editable:true, edittype:'select', editoptions:{<%if (c.showType == 'select_multiple' || c.showType == 'checkbox'){ %>multiple:true, <% } %>'class':'form-control${cssClass}',
items: $.merge([<%if (!(c.showType == 'select_multiple' || c.showType == 'checkbox')){ %>{dictLabel:'&nbsp;',dictValue:''}<% } %>], \${@DictUtils.getDictListJson('${c.optionMap['dictType']}')}),
itemLabel: 'dictLabel', itemValue: 'dictValue', dataInit: function(element){
$(element).select2().on("change",function(){$(this).valid()});
}
}
},
<%
}else if(c.showType == 'date' || c.showType == 'datetime'){
var isTime = (c.showType == 'datetime');
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.attrName}', width:150,
formatter:'date', formatoptions:{srcformat:'Y-m-d H:i:s',newformat:'Y-m-d${isTime?' H:i:s':''}'},
editable:true, edittype:'text', editoptions:{'class':'form-control Wdate${cssClass}', 'readonly':'true',
dataInit: function(element){ $(element).on('focus', function(){
WdatePicker({dateFmt:'yyyy-MM-dd${isTime?' HH:mm':''}',isShowClear:false});
});
}}
},
<%
}else if(c.showType == 'userselect'){
treeselectExists = true; %>
{header:'\${text('${c.columnLabel}')}', name:'${c.simpleAttrName}', width:150,
formatter: function(val, obj, row, act){
return js.val(row, '${c.attrName}')+'|'+js.val(row, '${c.attrName2}');
}, editable: true, edittype: "custom", editoptions: {
custom_element: function(val, editOptions) {
return js.template('treeselectTpl', {
id: 'user_'+editOptions.id, title: '用户选择',
name: '${c.attrName}', value: val.split('|')[0],
labelName: '${c.attrName2}', labelValue: val.split('|')[1],
url: '\${ctx}/sys/office/treeData?isLoadUser=true', cssClass: '${cssClass}'
});
}
}
},
<%
}else if(c.showType == 'officeselect'){
treeselectExists = true;
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.simpleAttrName}', width:150,
formatter: function(val, obj, row, act){
return js.val(row, '${c.attrName}')+'|'+js.val(row, '${c.attrName2}');
}, editable: true, edittype: "custom", editoptions: {
custom_element: function(val, editOptions) {
return js.template('treeselectTpl', {
id: 'office_'+editOptions.id, title: '机构选择',
name: '${c.attrName}', value: val.split('|')[0],
labelName: '${c.attrName2}', labelValue: val.split('|')[1],
url: '\${ctx}/sys/office/treeData?officeTypes=1,2', cssClass: '${cssClass}'
});
}
}
},
<%
}else if(c.showType == 'areaselect'){
treeselectExists = true;
%>
{header:'\${text('${c.columnLabel}')}', name:'${c.simpleAttrName}', width:150,
formatter: function(val, obj, row, act){
return js.val(row, '${c.attrName}')+'|'+js.val(row, '${c.attrName2}');
}, editable: true, edittype: "custom", editoptions: {
custom_element: function(val, editOptions) {
return js.template('treeselectTpl', {
id: 'area_'+editOptions.id, title: '区域选择',
name: '${c.attrName}', value: val.split('|')[0],
labelName: '${c.attrName2}', labelValue: val.split('|')[1],
url: '\${ctx}/sys/area/treeData', cssClass: '${cssClass}'
});
}
}
},
<%
}
}
%>
{header:'\${text('操作')}', name:'actions', width:80, sortable:false, fixed:true, formatter: function(val, obj, row, act){
var actions = [];
if (val == 'new'){
actions.push('<a href="#" onclick="js.confirm(\'\${text('你确认要删除这条数据吗')}\', function(){$(\'#${@StringUtils.uncap(child.className)}DataGrid\').dataGrid(\'delRowData\',\''+obj.rowId+'\')});return false;"><i class="fa fa-trash-o"></i></a>&nbsp;');
}else{
actions.push('<a href="#" onclick="js.confirm(\'\${text('你确认要删除这条数据吗')}\', function(){$(\'#${@StringUtils.uncap(child.className)}DataGrid\').dataGrid(\'setRowData\',\''+obj.rowId+'\',null,{display:\'none\'})});$(\'#'+obj.rowId+'_status\').val(\''+Global.STATUS_DELETE+'\');return false;"><i class="fa fa-trash-o"></i></a>&nbsp;');
}
return actions.join('');
}, editoptions: {defaultValue: 'new'}}
],
// 编辑表格参数
editGrid: true, // 是否是编辑表格
editGridInitRowNum: 1, // 编辑表格的初始化新增行数
editGridAddRowBtn: $('#${@StringUtils.uncap(child.className)}DataGridAddRowBtn'), // 子表增行按钮
editGridAddRowInitData: {<% for(pk in child.pkList){ %>${pk.attrName}<% break; }%>: '', status: Global.STATUS_NORMAL}, // 新增行的时候初始化的数据
// 编辑表格的提交数据参数
editGridInputFormListName: '${@StringUtils.uncap(child.className)}List', // 提交的数据列表名
editGridInputFormListAttrs: 'status,<% for(c in child.columnList){if(c.attrName!="status"){%>${c.attrName},<% }} %>', // 提交数据列表的属性字段
// 加载成功后执行事件
ajaxSuccess: function(data){
}
});
<% } %>
</script>
<% if(treeselectExists){ %>
<script id="treeselectTpl" type="text/template">//<!--<div>
<${'#'}form:treeselect 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"/>
</div>//--></script>
<% } %>
<% } %>

View File

@@ -0,0 +1,213 @@
<%
var rowFlag = -1, preGridRowCol;
for (c in table.columnList){
if (c.isEdit == '1'){
// 如果是树结构的字段,则自动忽略
if(table.isTreeEntity && @StringUtils.inString(c.columnName, 'parent_code',
'parent_codes', 'tree_sorts', 'tree_leaf', 'tree_level', 'tree_names')){
}
// 如果是隐藏域
else if (c.showType == 'hidden'){
%>
<${'#'}form:hidden path="${c.attrName}"/>
<%
}
// 输出表单字段
else{
// 栅格参数获取
var gridRowCol = @StringUtils.split(c.optionMap['gridRowCol'], '/');
if (isBlank(gridRowCol) || gridRowCol.~size != 3){
if (c.showType == 'textarea'){
gridRowCol = @StringUtils.split('12/2/10', '/');
}else{
gridRowCol = @StringUtils.split('6/4/8', '/');
}
}
// 是否强制新行获取,生成字段界面用户设定的
var isNewLine = @Global.YES.equals(c.optionMap['isNewLine']);
if (isBlank(c.optionMap['isNewLine'])){
if (c.showType == 'textarea'){
isNewLine = true;
}
}
// 如果上一个控件占12列则强制新行算了
if (isNotEmpty(preGridRowCol) && preGridRowCol[0] == '12'){
isNewLine = true;
}
// 保存上一个控件输出栅格对象
preGridRowCol = gridRowCol;
// 如果完成输出2列则换行
if(rowFlag == 2){
isNewLine = true;
}
// 如果是扩展字段,则输出子标题,并且强制换行
if (c.columnName == 'extend_s1'){
isNewLine = true;
}
// 如果是第一个控件
if (rowFlag == -1){
%>
<div class="row">
<%
}
// 如果不是第一个控件,并且是新行,或者是扩展字段,则输出结束符
else if(isNewLine){
%>
</div>
<%
}
// 如果是扩展字段,则输出子标题,并且强制换行
if (c.columnName == 'extend_s1'){
%>
<div class="form-unit">\${text('扩展字段')}</div>
<%
}
// 如果是新行,则换行
if(isNewLine){
rowFlag = 0; // 输出行标记清零
%>
<div class="row">
<%
}
// 开始输出控件
%>
<div class="col-xs-${gridRowCol[0]}">
<div class="form-group">
<label class="control-label col-sm-${gridRowCol[1]}" title="">
<span class="required ${c.isNull == '1' ? 'hide' : ''}">*</span> \${text('${c.columnLabel}')}<i class="fa icon-question hide"></i></label>
<div class="col-sm-${gridRowCol[2]}">
<%
var attrs = '';
if (c.dataLength != '0'){
var s = { %> maxlength="${c.dataLength}"<% };
attrs = attrs + s;
}
if (c.isPk == '1'){
var s = { %> readonly="\${!${className}.isNewRecord}"<% };
attrs = attrs + s;
}
var cssClass = '';
if (c.isRequired == '1'){
cssClass = cssClass + ' required';
}
var fieldValid = c.optionMap['fieldValid'];
if (isNotEmpty(fieldValid)){
if (type.name(fieldValid) == 'String[]'){
for (var fv in fieldValid){
cssClass = cssClass + ' ' + fv;
}
}else if(isNotBlank(fieldValid)){
cssClass = cssClass + ' ' + fieldValid;
}
}
if (c.showType == 'input'){
// 如果为自定义主键则第一个pk字段需输出isNewRecord
if (c.isPk == '1' && table.pkList[0].columnName == c.columnName){
%>
<${'#'}form:hidden path="isNewRecord"/>
<%
}
%>
<${'#'}form:input path="${c.attrName}"${attrs} class="form-control${cssClass}"/>
<%
} else if (c.showType == 'textarea') {
%>
<${'#'}form:textarea path="${c.attrName}" rows="4"${attrs} class="form-control${cssClass}"/>
<%
} else if (c.showType == 'select' || c.showType == 'select_multiple') {
var isMultiple = (c.showType == 'select_multiple');
%>
<${'#'}form:select path="${c.attrName}" dictType="${c.optionMap['dictType']}"${isMultiple?' multiple="true"':''}${c.isRequired != '1'?' blankOption="true"':''} class="form-control${cssClass}" />
<%
} else if (c.showType == 'radio') {
%>
<${'#'}form:radio path="${c.attrName}" dictType="${c.optionMap['dictType']}" class="form-control${cssClass}" />
<%
} else if (c.showType == 'checkbox') {
%>
<${'#'}form:checkbox path="${c.attrName}" dictType="${c.optionMap['dictType']}" class="form-control${cssClass}" />
<%
} else if (c.showType == 'date' || c.showType == 'datetime') {
var isTime = (c.showType == 'datetime');
%>
<${'#'}form:input path="${c.attrName}" readonly="true" maxlength="20" class="form-control Wdate${cssClass}"
dataFormat="date${isTime?'time':''}" onclick="WdatePicker({dateFmt:'yyyy-MM-dd${isTime?' HH:mm':''}',isShowClear:false});"/>
<%
} else if (c.showType == 'userselect') {
%>
<${'#'}form:treeselect id="${c.simpleAttrName}" title="\${text('用户选择')}"
path="${c.attrName}" labelPath="${c.attrName2}"
url="\${ctx}/sys/office/treeData?isLoadUser=true"
class="${cssClass}" allowClear="true"/>
<%
} else if (c.showType == 'officeselect') {
%>
<${'#'}form:treeselect id="${c.simpleAttrName}" title="\${text('机构选择')}"
path="${c.attrName}" labelPath="${c.attrName2}"
url="\${ctx}/sys/office/treeData"
class="${cssClass}" allowClear="true"/>
<%
} else if (c.showType == 'areaselect') {
%>
<${'#'}form:treeselect id="${c.simpleAttrName}" title="\${text('区域选择')}"
path="${c.attrName}" labelPath="${c.attrName2}"
url="\${ctx}/sys/area/treeData"
class="${cssClass}" allowClear="true"/>
<%
}
%>
</div>
</div>
</div>
<%
// 如果是第一个控件输出
if (rowFlag == -1){
rowFlag = 1;
}
// 行标记+1代表完成输出1列
else{
rowFlag = rowFlag + 1;
}
}
// 输出控件 End
}
}
// 如果没有输出row结束符则输出
if (rowFlag > 0){
%>
</div>
<%
}
// 输出上传图片控件
if(@ObjectUtils.toBoolean(table.optionMap['isImageUpload'])){
%>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2">\${text('图片上传')}</label>
<div class="col-sm-10">
<${'#'}form:fileupload id="uploadImage" bizKey="\${${className}.id}" bizType="${className}_image"
uploadType="image" class="" readonly="false"/>
</div>
</div>
</div>
</div>
<%
}
// 输出上传附件控件
if(@ObjectUtils.toBoolean(table.optionMap['isFileUpload'])){
%>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-sm-2">\${text('附件上传')}</label>
<div class="col-sm-10">
<${'#'}form:fileupload id="uploadFile" bizKey="\${${className}.id}" bizType="${className}_file"
uploadType="all" class="" readonly="false"/>
</div>
</div>
</div>
</div>
<%
}
%>

View File

@@ -0,0 +1,72 @@
<% /* 查询表单 begin // 此行是为了去除空行 */ %>
<${'#'}form:form id="searchForm" model="\${${className}}" action="\${ctx}/${urlPrefix}/listData" method="post" class="form-inline hide"
data-page-no="\${parameter.pageNo}" data-page-size="\${parameter.pageSize}" data-order-by="\${parameter.orderBy}">
<% for(c in table.columnList){ %>
<% if(c.isQuery == "1" && !c.isTreeEntityColumn){ %>
<div class="form-group">
<label class="control-label">\${text('${c.columnLabel}')}</label>
<% if(c.showType == 'input' || c.showType == 'textarea'){ %>
<div class="control-inline">
<% if (c.queryType == 'BETWEEN'){ %>
<${'#'}form:input path="${c.attrName}_gte"${c.dataLength != "0" ? ' maxlength="'+c.dataLength+'"' : ''} class="form-control width-60"/>
&nbsp;--&nbsp;
<${'#'}form:input path="${c.attrName}_lte"${c.dataLength != "0" ? ' maxlength="'+c.dataLength+'"' : ''} class="form-control width-60"/>
<% } else { %>
<${'#'}form:input path="${c.attrName}"${c.dataLength != "0" ? ' maxlength="'+c.dataLength+'"' : ''} class="form-control width-120"/>
<% } %>
</div>
<% }else if(c.showType == 'select' || c.showType == 'select_multiple'){
var isMultiple = (c.showType == 'select_multiple'); %>
<div class="control-inline width-120">
<${'#'}form:select path="${c.attrName}" dictType="${c.optionMap['dictType']}"${isMultiple?' multiple="true"':''} blankOption="true" class="form-control"/>
</div>
<% }else if(c.showType == 'radio'){ %>
<div class="control-inline">
<${'#'}form:radio path="${c.attrName}" dictType="${c.optionMap['dictType']}" blankOption="true" class="form-control"/>
</div>
<% }else if(c.showType == 'checkbox'){ %>
<div class="control-inline">
<${'#'}form:checkbox path="${c.attrName}" dictType="${c.optionMap['dictType']}" blankOption="true" class="form-control"/>
</div>
<% }else if(c.showType == 'date' || c.showType == 'datetime'){
var isTime = (c.showType == 'datetime'); %>
<div class="control-inline">
<% if (c.queryType == 'BETWEEN'){ %>
<${'#'}form:input path="${c.attrName}_gte" readonly="true" maxlength="20" class="form-control Wdate-date${isTime?'time':''}"
dataFormat="date${isTime?'time':''}" onclick="WdatePicker({dateFmt:'yyyy-MM-dd${isTime?' HH:mm':''}',isShowClear:false,onpicked:function(){${c.attrName}_lte.click()}});"/>
&nbsp;--&nbsp;
<${'#'}form:input path="${c.attrName}_lte" readonly="true" maxlength="20" class="form-control Wdate-date${isTime?'time':''}"
dataFormat="date${isTime?'time':''}" onclick="WdatePicker({dateFmt:'yyyy-MM-dd${isTime?' HH:mm':''}',isShowClear:false});"/>
<% } else { %>
<${'#'}form:input path="${c.attrName}" readonly="true" maxlength="20" class="form-control Wdate-date${isTime?'time':''}"
dataFormat="date${isTime?'time':''}" onclick="WdatePicker({dateFmt:'yyyy-MM-dd${isTime?' HH:mm':''}',isShowClear:false});"/>
<% } %>
</div>
<% }else if(c.showType == 'userselect'){ %>
<div class="control-inline width-120" >
<${'#'}form:treeselect id="${c.simpleAttrName}" title="\${text('用户选择')}"
path="${c.attrName}" labelPath="${c.attrName2}"
url="\${ctx}/sys/office/treeData?isLoadUser=true" allowClear="true"/>
</div>
<% }else if(c.showType == 'officeselect'){ %>
<div class="control-inline width-120" >
<${'#'}form:treeselect id="${c.simpleAttrName}" title="\${text('机构选择')}"
path="${c.attrName}" labelPath="${c.attrName2}"
url="\${ctx}/sys/office/treeData" allowClear="true"/>
</div>
<% }else if(c.showType == 'areaselect'){ %>
<div class="control-inline width-120" >
<${'#'}form:treeselect id="${c.simpleAttrName}" title="\${text('区域选择')}"
path="${c.attrName}" labelPath="${c.attrName2}"
url="\${ctx}/sys/area/treeData" allowClear="true"/>
</div>
<% } %>
</div>
<% } %>
<% } %>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">\${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">\${text('重置')}</button>
</div>
</${'#'}form:form>
<% /* 查询表单 end // 此行是为了去除空行 */ %>

View File

@@ -1,3 +1,4 @@
<% if(@Global.getPropertyToBoolean('msg.enabled', 'true')){ %>
<li class="dropdown messages-menu">
<a href="javascript:" class="dropdown-toggle" data-hover="dropdown">
<i class="fa fa-envelope-o"></i>
@@ -41,4 +42,5 @@
onclick="readMsg(this, '${text('消息详情')}', '{{d.id}}')">${text('查看')}</button>&nbsp;
</div>
</script>
</li>
</li>
<% } %>