mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 23:45:55 +08:00
Merge branch 'develop' into field-sign
This commit is contained in:
commit
d06e3a6cec
|
@ -17,8 +17,6 @@ const revHash = require('rev-hash')
|
|||
const replace = require('gulp-replace')
|
||||
const filter = require('gulp-filter')
|
||||
|
||||
// const jsObfuscator = require('gulp-javascript-obfuscator')
|
||||
|
||||
const BABEL_OPTIONS = {
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
|
@ -33,7 +31,6 @@ function compileJs(m) {
|
|||
return (
|
||||
src(`${m || WEB_ROOT}/assets/js/**/*.js`)
|
||||
.pipe(babel(BABEL_OPTIONS))
|
||||
// .pipe(jsObfuscator({ compact: true }))
|
||||
.pipe(
|
||||
debug({
|
||||
title: 'Compiled .js : ',
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
"gulp-clean-css": "^4.3.0",
|
||||
"gulp-debug": "^4.0.0",
|
||||
"gulp-filter": "^7.0.0",
|
||||
"gulp-javascript-obfuscator": "^1.1.6",
|
||||
"gulp-replace": "^1.1.3",
|
||||
"rev-hash": "^3.0.0"
|
||||
}
|
||||
|
|
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 124928a57816827e75c01f81e6d3cda6d59475d7
|
||||
Subproject commit 85c5ae2c04a9014fbce35bf89084c30f6fe4f7c1
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
## 项目特色
|
||||
|
||||
REBUILD 更侧重于业务需求实现,而非基础的技术框架或项目启动模板。通过 REBUILD 可以真正实现零代码快速搭建业务系统,无需编程、无需编译代码,甚至无需了解技术。
|
||||
REBUILD 通过领先的业务流程引擎为你快速搭建企业管理系统。REBUILD 更侧重于业务需求实现,而非基础的技术框架或项目启动模板,通过 REBUILD 可以真正实现零代码快速搭建,无需编程、无需编译代码,甚至无需了解技术。
|
||||
|
||||
更多详情介绍 [https://getrebuild.com/](https://getrebuild.com/)
|
||||
|
||||
|
@ -35,13 +35,13 @@ REBUILD 更侧重于业务需求实现,而非基础的技术框架或项目启
|
|||
|
||||
## 使用
|
||||
|
||||
开始使用 REBUILD 非常简单,不需要搭建复杂的运行环境,零依赖快速部署,就是那么简单!
|
||||
开始使用 REBUILD 非常简单,不需要搭建复杂的运行环境,零依赖快速部署,超简单!
|
||||
|
||||
#### 1. 使用已发布版本
|
||||
|
||||
_生产环境强烈推荐使用此方式 !!!_
|
||||
|
||||
首先 [下载](https://getrebuild.com/download) 安装包,我们同时提供 `standalone` 与 `boot` 两种安装包。`standalone` 为集成安装包,`boot` 为 SpringBoot 的 `jar` 包,两种安装包在功能上没有区别。
|
||||
首先 [下载](https://getrebuild.com/download) 安装包,我们同时提供 `standalone` 与 `boot` 两种安装包。`standalone` 为集成安装包(推荐),`boot` 为 SpringBoot 的 `jar` 包,两种安装包在功能上没有区别。
|
||||
|
||||
下载后解压(集成安装包),双击/运行 `start-rebuild.bat` 或 `start-rebuild.sh` 启动, 打开浏览器输入 [http://127.0.0.1:18080/](http://127.0.0.1:18080/) 开始体验!
|
||||
|
||||
|
@ -89,4 +89,4 @@ REBUILD uses both open source ([GPL-3.0](LICENSE)) and [commercial](COMMERCIAL)
|
|||
|
||||
## 购买商业版
|
||||
|
||||
从 2.0 版本开始,RB 将推出商业版增值功能计划。如果 REBUILD 对贵公司业务有帮助,可以考虑 [购买商业授权](https://getrebuild.com/#pricing-plans) 以支持 RB 的日常运营及发展。除了增值功能,还可以得到更好的技术支持服务。非常感谢!
|
||||
从 2.0 版本开始,RB 将推出商业版增值功能计划。如果 REBUILD 对贵公司业务有帮助,请考虑 [购买商业授权](https://getrebuild.com/#pricing-plans) 支持 RB 可持续发展。除了增值功能,还可以得到更好的技术支持服务。非常感谢!
|
||||
|
|
14
pom.xml
14
pom.xml
|
@ -10,7 +10,7 @@
|
|||
</parent>
|
||||
<groupId>com.rebuild</groupId>
|
||||
<artifactId>rebuild</artifactId>
|
||||
<version>2.7.0-beta1</version>
|
||||
<version>2.8.0-dev</version>
|
||||
<name>rebuild</name>
|
||||
<description>RB V2 use SpringBoot</description>
|
||||
<!-- UNCOMMENT USE TOMCAT -->
|
||||
|
@ -317,7 +317,7 @@
|
|||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>7.9.0</version>
|
||||
<version>7.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
|
@ -359,6 +359,11 @@
|
|||
<artifactId>okhttp</artifactId>
|
||||
<version>4.9.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
|
@ -370,11 +375,6 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
|
|
|
@ -64,11 +64,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
|
|||
/**
|
||||
* Rebuild Version
|
||||
*/
|
||||
public static final String VER = "2.7.0-beta1";
|
||||
public static final String VER = "2.8.0-dev";
|
||||
/**
|
||||
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
|
||||
*/
|
||||
public static final int BUILD = 2070001;
|
||||
public static final int BUILD = 2080001;
|
||||
|
||||
static {
|
||||
// Driver for DB
|
||||
|
@ -135,7 +135,20 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
|
|||
" Local : " + localUrl,
|
||||
" External : " + localUrl.replace("localhost", OshiUtils.getLocalIp()),
|
||||
" Public : " + RebuildConfiguration.getHomeUrl());
|
||||
log.info(banner);
|
||||
|
||||
if (License.isCommercial()) {
|
||||
System.out.println(banner);
|
||||
} else {
|
||||
System.out.print(banner);
|
||||
|
||||
String thanks = RebuildBanner.formatSimple(
|
||||
"**********",
|
||||
"感谢使用 REBUILD!",
|
||||
"您当前使用的是免费版本,如果 REBUILD 对贵公司业务有帮助,请考虑购买商业授权版本,帮助我们可持续发展!",
|
||||
"查看详情 https://getrebuild.com/#pricing-plans",
|
||||
"**********");
|
||||
System.out.println(thanks);
|
||||
}
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,12 @@ import com.rebuild.core.Application;
|
|||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
import com.rebuild.core.metadata.MetadataSorter;
|
||||
import com.rebuild.core.metadata.easymeta.DisplayType;
|
||||
import com.rebuild.core.metadata.easymeta.EasyEntity;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.support.License;
|
||||
import com.rebuild.core.support.NeedRbvException;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
@ -66,6 +68,10 @@ public class Entity2Schema extends Field2Schema {
|
|||
* @return returns 实体名称
|
||||
*/
|
||||
public String createEntity(String entityName, String entityLabel, String comments, String mainEntity, boolean haveNameField) {
|
||||
if (License.isCommercial() && MetadataHelper.getEntities().length > 100) {
|
||||
throw new NeedRbvException("实体数量超出免费版限制");
|
||||
}
|
||||
|
||||
if (entityName != null) {
|
||||
if (MetadataHelper.containsEntity(entityName)) {
|
||||
throw new MetadataModificationException(Language.L("实体已存在 : %s", entityName));
|
||||
|
@ -92,9 +98,6 @@ public class Entity2Schema extends Field2Schema {
|
|||
"select min(typeCode) from MetaEntity").unique();
|
||||
int typeCode = maxTypeCode == null || ObjectUtils.toInt(maxTypeCode[0]) == 0
|
||||
? 999 : (ObjectUtils.toInt(maxTypeCode[0]) - 1);
|
||||
if (typeCode <= (License.isCommercial() ? 399 : 949)) {
|
||||
throw new MetadataModificationException("ENTITY CODE EXCEEDS SYSTEM LIMIT : " + typeCode);
|
||||
}
|
||||
|
||||
// 名称字段
|
||||
String nameFiled = EntityHelper.CreatedOn;
|
||||
|
|
|
@ -27,6 +27,8 @@ import com.rebuild.core.metadata.easymeta.DisplayType;
|
|||
import com.rebuild.core.metadata.easymeta.EasyField;
|
||||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.support.License;
|
||||
import com.rebuild.core.support.NeedRbvException;
|
||||
import com.rebuild.core.support.SetUser;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.core.support.setup.Installer;
|
||||
|
@ -79,9 +81,20 @@ public class Field2Schema extends SetUser {
|
|||
* @return
|
||||
*/
|
||||
public String createField(Entity entity, String fieldLabel, DisplayType type, String comments, String refEntity, JSON extConfig) {
|
||||
long count;
|
||||
if ((count = checkRecordCount(entity)) > 100000) {
|
||||
throw new MetadataModificationException(Language.L("实体记录过多 (%d),增加/删除字段可能导致表损坏", count));
|
||||
if (!License.isCommercial()) {
|
||||
if (entity.getFields().length >= 50) {
|
||||
throw new NeedRbvException("字段数量超出免费版限制");
|
||||
}
|
||||
|
||||
if (type == DisplayType.LOCATION) {
|
||||
Object[] limit = Application.createQueryNoFilter(
|
||||
"select count(fieldId) from MetaField where displayType = ?")
|
||||
.setParameter(1, type.name())
|
||||
.unique();
|
||||
if (ObjectUtils.toInt(limit[0]) >= 1) {
|
||||
throw new NeedRbvException("位置字段超出免费版限制");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String fieldName = toPinyinName(fieldLabel);
|
||||
|
|
|
@ -43,8 +43,10 @@ public enum ConfigurationItem {
|
|||
// 开放注册
|
||||
OpenSignUp(true),
|
||||
|
||||
// 登录背景图
|
||||
// 动态登录背景图
|
||||
LiveWallpaper(true),
|
||||
// 自定登录背景图
|
||||
CustomWallpaper,
|
||||
|
||||
// 启用文件分享
|
||||
FileSharable(true),
|
||||
|
@ -82,6 +84,11 @@ public enum ConfigurationItem {
|
|||
// 登录密码过期时间(0为不过期)
|
||||
PasswordExpiredDays(0),
|
||||
|
||||
// 允许使用时间
|
||||
AllowUsesTime,
|
||||
// 允许使用 IP
|
||||
AllowUsesIp,
|
||||
|
||||
// DingTalk
|
||||
DingtalkAgentid, DingtalkAppkey, DingtalkAppsecret, DingtalkCorpid,
|
||||
DingtalkPushAeskey, DingtalkPushToken,
|
||||
|
|
22
src/main/java/com/rebuild/core/support/NeedRbvException.java
Normal file
22
src/main/java/com/rebuild/core/support/NeedRbvException.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and/or its owners. All rights reserved.
|
||||
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
package com.rebuild.core.support;
|
||||
|
||||
import com.rebuild.core.DefinedException;
|
||||
|
||||
/**
|
||||
* @author devezhao
|
||||
* @since 2021/12/30
|
||||
*/
|
||||
public class NeedRbvException extends DefinedException {
|
||||
private static final long serialVersionUID = -5539922471794653867L;
|
||||
|
||||
public NeedRbvException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ package com.rebuild.utils;
|
|||
|
||||
import cn.devezhao.commons.ObjectUtils;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.RebuildException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
@ -16,6 +17,7 @@ import org.springframework.core.io.ClassPathResource;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.URI;
|
||||
|
@ -166,4 +168,28 @@ public class CommonsUtils {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param desc
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
public static Object invokeMethod(String desc, Object... args) {
|
||||
String[] classAndMethod = desc.split("#");
|
||||
try {
|
||||
Class<?> clazz = Class.forName(classAndMethod[0]);
|
||||
|
||||
Class<?>[] paramTypes = new Class<?>[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
paramTypes[i] = args[i].getClass();
|
||||
}
|
||||
|
||||
Method method = clazz.getMethod(classAndMethod[1], paramTypes);
|
||||
return method.invoke(null, args);
|
||||
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
log.error("Invalid method invoke : {}", desc);
|
||||
throw new RebuildException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ public class RebuildBanner {
|
|||
* @return
|
||||
*/
|
||||
public static String formatSimple(String... texts) {
|
||||
StringBuilder banner = new StringBuilder("\n\n");
|
||||
StringBuilder banner = new StringBuilder("\n");
|
||||
for (String t : texts) {
|
||||
banner.append(" ").append(t).append("\n");
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ package com.rebuild.web;
|
|||
|
||||
import cn.devezhao.commons.ThrowableUtils;
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.DefinedException;
|
||||
|
@ -92,7 +92,8 @@ public class RebuildWebConfigurer implements WebMvcConfigurer, ErrorViewResolver
|
|||
|
||||
@Override
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
converters.add(0, new FastJsonHttpMessageConverter4());
|
||||
// converters.add(0, new FastJsonHttpMessageConverter4());
|
||||
converters.add(0, new FastJsonHttpMessageConverter());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
package com.rebuild.web;
|
||||
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import cn.devezhao.commons.CodecUtils;
|
||||
import cn.devezhao.commons.web.ServletUtils;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
|
@ -16,15 +17,20 @@ import com.rebuild.core.DefinedException;
|
|||
import com.rebuild.core.ServerStatus;
|
||||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.cache.CommonsCache;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.privileges.bizz.ZeroEntry;
|
||||
import com.rebuild.core.support.ConfigurationItem;
|
||||
import com.rebuild.core.support.CsrfToken;
|
||||
import com.rebuild.core.support.License;
|
||||
import com.rebuild.core.support.RebuildConfiguration;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.core.support.setup.InstallState;
|
||||
import com.rebuild.utils.AppUtils;
|
||||
import com.rebuild.utils.CommonsUtils;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.MimeType;
|
||||
|
@ -50,16 +56,20 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
|
||||
private static final ThreadLocal<RequestEntry> REQUEST_ENTRY = new NamedThreadLocal<>("RequestEntry");
|
||||
|
||||
private static final int CODE_STARTING = 600;
|
||||
private static final int CODE_NOT_ALLOW_USE = 610;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
response.addHeader("X-RB-Server", ServerStatus.STARTUP_ONCE + "/" + Application.BUILD);
|
||||
|
||||
if (Application.isWaitLoad()) {
|
||||
throw new DefinedException(600, "Please wait while REBUILD starting up ...");
|
||||
throw new DefinedException(CODE_STARTING, "Please wait while REBUILD starting up ...");
|
||||
}
|
||||
|
||||
UserContextHolder.setReqip(ServletUtils.getRemoteAddr(request));
|
||||
final String ipAddr = ServletUtils.getRemoteAddr(request);
|
||||
UserContextHolder.setReqip(ipAddr);
|
||||
|
||||
// Locale
|
||||
final String locale = detectLocale(request, response);
|
||||
|
@ -100,11 +110,14 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
|
||||
final ID requestUser = requestEntry.getRequestUser();
|
||||
|
||||
boolean skipCheckSafeUse;
|
||||
|
||||
// 用户验证
|
||||
if (requestUser != null) {
|
||||
|
||||
boolean adminVerified = AppUtils.isAdminVerified(request);
|
||||
// 管理中心
|
||||
if (requestUri.contains("/admin/") && !AppUtils.isAdminVerified(request)) {
|
||||
if (requestUri.contains("/admin/") && !adminVerified) {
|
||||
if (isHtmlRequest(request)) {
|
||||
sendRedirect(response, "/user/admin-verify", requestUri);
|
||||
} else {
|
||||
|
@ -124,17 +137,20 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
// Last active
|
||||
Application.getSessionStore().storeLastActive(request);
|
||||
|
||||
// Side collapsed
|
||||
// Nav collapsed
|
||||
String sidebarCollapsed = ServletUtils.readCookie(request, "rb.sidebarCollapsed");
|
||||
String sideCollapsedClazz = "false".equals(sidebarCollapsed) ? "" : "rb-collapsible-sidebar-collapsed";
|
||||
// Aside
|
||||
String sideCollapsedClazz = BooleanUtils.toBoolean(sidebarCollapsed) ? "rb-collapsible-sidebar-collapsed" : "";
|
||||
// Aside collapsed
|
||||
if (!(requestEntry.getRequestUri().contains("/admin/") || requestEntry.getRequestUri().contains("/setup/"))) {
|
||||
String asideCollapsed = ServletUtils.readCookie(request, "rb.asideCollapsed");
|
||||
if (!"false".equals(asideCollapsed)) sideCollapsedClazz += " rb-aside-collapsed";
|
||||
if (BooleanUtils.toBoolean(asideCollapsed)) sideCollapsedClazz += " rb-aside-collapsed";
|
||||
}
|
||||
request.setAttribute("sideCollapsedClazz", sideCollapsedClazz);
|
||||
}
|
||||
|
||||
// 超管设置仍可访问
|
||||
skipCheckSafeUse = adminVerified || UserHelper.isSuperAdmin(requestUser);
|
||||
|
||||
} else if (!isIgnoreAuth(requestUri)) {
|
||||
// 外部表单特殊处理(媒体字段上传/预览)
|
||||
if (requestUri.contains("/filex/") && CsrfToken.verify(request, false)) {
|
||||
|
@ -150,8 +166,12 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
skipCheckSafeUse = true;
|
||||
}
|
||||
|
||||
if (!skipCheckSafeUse) checkSafeUse(ipAddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -175,14 +195,6 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
UserContextHolder.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 语言探测
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @see AppUtils#getReuqestLocale(HttpServletRequest)
|
||||
*/
|
||||
private String detectLocale(HttpServletRequest request, HttpServletResponse response) {
|
||||
String rbmobLocale = request.getHeader(AppUtils.HF_LOCALE);
|
||||
if (rbmobLocale != null) return rbmobLocale;
|
||||
|
@ -222,12 +234,6 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
return havingLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略认证的资源
|
||||
*
|
||||
* @param requestUri
|
||||
* @return
|
||||
*/
|
||||
private boolean isIgnoreAuth(String requestUri) {
|
||||
if (requestUri.contains("/user/") && !requestUri.contains("/user/admin")) {
|
||||
return true;
|
||||
|
@ -253,12 +259,6 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
|| requestUri.startsWith("/rbmob/env");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否 HTML 请求
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private boolean isHtmlRequest(HttpServletRequest request) {
|
||||
String requestUri = request.getRequestURI();
|
||||
if (ServletUtils.isAjaxRequest(request)
|
||||
|
@ -280,21 +280,33 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param response
|
||||
* @param url
|
||||
* @param nexturl
|
||||
* @throws IOException
|
||||
*/
|
||||
private void sendRedirect(HttpServletResponse response, String url, String nexturl) throws IOException {
|
||||
String fullUrl = AppUtils.getContextPath(url);
|
||||
if (nexturl != null) fullUrl += "?nexturl=" + CodecUtils.urlEncode(nexturl);
|
||||
response.sendRedirect(fullUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数封装
|
||||
*/
|
||||
private void checkSafeUse(String ipAddr) throws DefinedException {
|
||||
if (!License.isRbvAttached()) return;
|
||||
|
||||
if (ipAddr.equals("localhost") || ipAddr.equals("127.0.0.1")) {
|
||||
log.warn("Allow localhost uses ");
|
||||
return;
|
||||
}
|
||||
|
||||
Object allowIp = CommonsUtils.invokeMethod(
|
||||
"com.rebuild.rbv.commons.SafeUses#checkIp", ipAddr);
|
||||
if (!(Boolean) allowIp) {
|
||||
throw new DefinedException(CODE_NOT_ALLOW_USE, Language.L("你的 IP 地址不在允许范围内"));
|
||||
}
|
||||
|
||||
Object allowTime = CommonsUtils.invokeMethod(
|
||||
"com.rebuild.rbv.commons.SafeUses#checkTime", CalendarUtils.now());
|
||||
if (!(Boolean) allowTime) {
|
||||
throw new DefinedException(CODE_NOT_ALLOW_USE, Language.L("当前时间不允许使用"));
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class RequestEntry {
|
||||
final long requestTime;
|
||||
|
|
|
@ -54,6 +54,9 @@ import java.util.Map;
|
|||
@RequestMapping("/admin/")
|
||||
public class ConfigurationController extends BaseController {
|
||||
|
||||
public static final String ETAG_DIMGLOGOTIME = "dimgLogoTime";
|
||||
public static final String ETAG_DIMGBGIMGTIME = "dimgBgimgTime";
|
||||
|
||||
@GetMapping("systems")
|
||||
public ModelAndView pageSystems() {
|
||||
ModelAndView mv = createModelAndView("/admin/system-cfg");
|
||||
|
@ -93,11 +96,14 @@ public class ConfigurationController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
String dLOGO = data.getString("LOGO");
|
||||
String dLOGOWhite = data.getString("LOGOWhite");
|
||||
String dLOGO = data.getString(ConfigurationItem.LOGO.name());
|
||||
String dLOGOWhite = data.getString(ConfigurationItem.LOGOWhite.name());
|
||||
if (dLOGO != null || dLOGOWhite != null) {
|
||||
// @see UseThemeController#useLogo
|
||||
Application.getCommonsCache().evict("dimgLogoTime");
|
||||
Application.getCommonsCache().evict(ETAG_DIMGLOGOTIME);
|
||||
}
|
||||
String dCustomWallpaper = data.getString(ConfigurationItem.CustomWallpaper.name());
|
||||
if (dCustomWallpaper != null) {
|
||||
Application.getCommonsCache().evict(ETAG_DIMGBGIMGTIME);
|
||||
}
|
||||
|
||||
setValues(data);
|
||||
|
|
|
@ -24,7 +24,6 @@ import com.rebuild.web.BaseController;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.coobird.thumbnailator.Thumbnails;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
|
@ -63,7 +62,9 @@ public class FileDownloader extends BaseController {
|
|||
return;
|
||||
}
|
||||
|
||||
final boolean temp = BooleanUtils.toBoolean(request.getParameter("temp"));
|
||||
final boolean temp = getBoolParameter(request, "temp");
|
||||
final boolean local = temp || getBoolParameter(request, "local"); // 强制本地
|
||||
|
||||
String imageView2 = request.getQueryString();
|
||||
if (imageView2 != null && imageView2.contains("imageView2/")) {
|
||||
imageView2 = "imageView2/" + imageView2.split("imageView2/")[1].split("&")[0];
|
||||
|
@ -73,8 +74,8 @@ public class FileDownloader extends BaseController {
|
|||
|
||||
ServletUtils.addCacheHead(response, 60);
|
||||
|
||||
// Local storage || temp
|
||||
if (!QiniuCloud.instance().available() || temp) {
|
||||
// Local storage || temp || local
|
||||
if (!QiniuCloud.instance().available() || local) {
|
||||
String fileName = QiniuCloud.parseFileName(filePath);
|
||||
String mimeType = request.getServletContext().getMimeType(fileName);
|
||||
if (mimeType != null) {
|
||||
|
@ -163,7 +164,8 @@ public class FileDownloader extends BaseController {
|
|||
filePath = filePath.split("/filex/download/")[1];
|
||||
}
|
||||
|
||||
boolean temp = getBoolParameter(request, "temp");
|
||||
final boolean temp = getBoolParameter(request, "temp");
|
||||
|
||||
String attname = getParameter(request, "attname");
|
||||
if (StringUtils.isBlank(attname)) attname = QiniuCloud.parseFileName(filePath);
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import eu.bitwalker.useragentutils.UserAgent;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -229,7 +228,7 @@ public class LoginController extends BaseController {
|
|||
|
||||
// Tour 显示规则
|
||||
Object[] initLoginTimes = Application.createQueryNoFilter(
|
||||
"select count(loginTime) from LoginLog where user = ? and loginTime > '2021-12-01'")
|
||||
"select count(loginTime) from LoginLog where user = ? and loginTime > '2022-01-01'")
|
||||
.setParameter(1, user)
|
||||
.unique();
|
||||
if (ObjectUtils.toLong(initLoginTimes[0]) <= 10
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
CREATE DATABASE rebuild20 COLLATE utf8mb4_general_ci;
|
||||
CREATE USER 'rebuild'@'127.0.0.1' IDENTIFIED BY 'rebuild';
|
||||
GRANT ALL PRIVILEGES ON rebuild20.* TO 'rebuild'@'127.0.0.1';
|
||||
GRANT RELOAD ON *.* TO 'rebuild'@'127.0.0.1';
|
||||
FLUSH PRIVILEGES;
|
||||
USE rebuild20;
|
||||
*/
|
||||
|
|
|
@ -3,17 +3,48 @@
|
|||
<head>
|
||||
<th:block th:replace="~{/_include/header}" />
|
||||
<title>[[${bundle.L('通用配置')}]]</title>
|
||||
<style type="text/css">
|
||||
<style>
|
||||
.syscfg a.img-thumbnail {
|
||||
display: inline-block;
|
||||
padding: 0.4rem 0.5rem;
|
||||
background-color: #fff;
|
||||
cursor: default;
|
||||
position: relative;
|
||||
}
|
||||
.applogo.edit a.img-thumbnail,
|
||||
.applogo.edit a.img-thumbnail .logo-img {
|
||||
.syscfg.edit a.img-thumbnail {
|
||||
cursor: pointer;
|
||||
}
|
||||
.syscfg a.img-thumbnail b {
|
||||
position: absolute;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
font-size: 1.4rem;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.syscfg.edit a.img-thumbnail:hover b {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.bgimg-img {
|
||||
display: inline-block;
|
||||
width: 192px;
|
||||
height: 108px;
|
||||
background: #eee url(../assets/img/bg.jpg) repeat 0 0;
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
<style th:if="${commercial > 1}">
|
||||
.bgimg-img {
|
||||
background-image: url(../commons/theme/use-bgimg);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -40,10 +71,16 @@
|
|||
<tr>
|
||||
<td>LOGO <sup class="rbv"></sup></td>
|
||||
<td class="fs-0 applogo">
|
||||
<a class="img-thumbnail"><i class="logo-img"></i></a>
|
||||
<a class="img-thumbnail bg-primary ml-1"><i class="logo-img white"></i></a>
|
||||
<a class="img-thumbnail" data-id="LOGO">
|
||||
<i class="logo-img"></i>
|
||||
<b th:title="${bundle.L('还原')}"><span class="zmdi zmdi-replay"></span></b>
|
||||
</a>
|
||||
<a class="img-thumbnail bg-primary ml-1" data-id="LOGOWhite">
|
||||
<i class="logo-img white"></i>
|
||||
<b th:title="${bundle.L('还原')}"><span class="zmdi zmdi-replay"></span></b>
|
||||
</a>
|
||||
<input type="file" class="hide" accept="image/*" data-maxsize="5000000" data-local="true" />
|
||||
<p class="mt-2 text-dark hide">[[${bundle.L('请分别上传深色与白色 LOGO,透明背景,宽高为 268 × 54')}]]</p>
|
||||
<p class="mt-2 text-dark hide">[[${bundle.L('请分别上传深色与白色 LOGO,透明背景,建议尺寸 268 × 54')}]]</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -53,6 +90,10 @@
|
|||
</td>
|
||||
<td data-id="HomeURL" th:data-value="${HomeURL}">[[${HomeURL}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('默认语言')}]]</td>
|
||||
<td data-id="DefaultLanguage" th:data-value="${DefaultLanguage}" id="_DefaultLanguage">[[${DefaultLanguage}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
[[${bundle.L('页脚')}]]
|
||||
|
@ -61,14 +102,33 @@
|
|||
<td data-id="PageFooter" th:data-value="${PageFooter}" data-optional="true"><pre class="unstyle">[[${PageFooter ?:bundle.L('无')}]]</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('默认语言')}]]</td>
|
||||
<td data-id="DefaultLanguage" th:data-value="${DefaultLanguage}" id="_DefaultLanguage">[[${DefaultLanguage}]]</td>
|
||||
<td>[[${bundle.L('登录页每日一图')}]]</td>
|
||||
<td data-id="LiveWallpaper" th:data-value="${LiveWallpaper}">[[${LiveWallpaper ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('自定义登录页图')}]] <sup class="rbv"></sup></td>
|
||||
<td class="fs-0 bgimg">
|
||||
<a class="img-thumbnail p-0 border-0" data-id="CustomWallpaper">
|
||||
<i class="bgimg-img"></i>
|
||||
<b th:title="${bundle.L('还原')}"><span class="zmdi zmdi-replay"></span></b>
|
||||
</a>
|
||||
<input type="file" class="hide" accept="image/*" data-maxsize="5000000" data-local="true" />
|
||||
<p class="mt-2 text-dark hide">[[${bundle.L('建议尺寸 1920 × 1080')}]]</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>[[${bundle.L('系统选项')}]]</h5>
|
||||
<h5>[[${bundle.L('安全使用')}]]</h5>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>[[${bundle.L('显示页面水印')}]]</td>
|
||||
<td data-id="MarkWatermark" th:data-value="${MarkWatermark}">[[${MarkWatermark ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('允许分享文件')}]]</td>
|
||||
<td data-id="FileSharable" th:data-value="${FileSharable}">[[${FileSharable ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%">[[${bundle.L('公开注册')}]]</td>
|
||||
<td data-id="OpenSignUp" th:data-value="${OpenSignUp}">[[${OpenSignUp ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
|
@ -100,20 +160,16 @@
|
|||
<td th:data-id="${commercial > 0 ? 'MultipleSessions' : ''}" th:data-value="${MultipleSessions}">[[${MultipleSessions ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('登录页每日一图')}]]</td>
|
||||
<td data-id="LiveWallpaper" th:data-value="${LiveWallpaper}">[[${LiveWallpaper ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
<td>[[${bundle.L('允许使用时间')}]] <sup class="rbv"></sup></td>
|
||||
<td th:data-id="${commercial > 1 ? 'AllowUsesTime' : ''}" th:data-value="${AllowUsesTime}" data-optional="true">
|
||||
<pre class="unstyle">[[${AllowUsesTime ?:bundle.L('不限')}]]</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('显示页面水印')}]]</td>
|
||||
<td data-id="MarkWatermark" th:data-value="${MarkWatermark}">[[${MarkWatermark ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('允许分享文件')}]]</td>
|
||||
<td data-id="FileSharable" th:data-value="${FileSharable}">[[${FileSharable ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('在视图页显示修改历史')}]]</td>
|
||||
<td data-id="ShowViewHistory" th:data-value="${ShowViewHistory}">[[${ShowViewHistory ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
<td>[[${bundle.L('允许使用 IP')}]] <sup class="rbv"></sup></td>
|
||||
<td th:data-id="${commercial > 1 ? 'AllowUsesIp' : ''}" th:data-value="${AllowUsesIp}" data-optional="true">
|
||||
<pre class="unstyle">[[${AllowUsesIp ?:bundle.L('不限')}]]</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -141,6 +197,16 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h5>[[${bundle.L('其他')}]]</h5>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<td width="40%">[[${bundle.L('在视图页显示修改历史')}]]</td>
|
||||
<td data-id="ShowViewHistory" th:data-value="${ShowViewHistory}">[[${ShowViewHistory ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="edit-footer">
|
||||
<button class="btn btn-link">[[${bundle.L('取消')}]]</button>
|
||||
<button class="btn btn-primary">[[${bundle.L('保存')}]]</button>
|
||||
|
|
|
@ -109,8 +109,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
html,
|
||||
body {
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI',
|
||||
'Microsoft YaHei', sans-serif;
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
|
@ -4020,9 +4019,8 @@ input[type='submit'].btn-block {
|
|||
line-height: 1.428571;
|
||||
color: #404040;
|
||||
vertical-align: middle;
|
||||
background: #fff
|
||||
url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%233d3c3c' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E")
|
||||
no-repeat right 0.75rem center;
|
||||
background: #fff url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%233d3c3c' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") no-repeat
|
||||
right 0.75rem center;
|
||||
background-size: 8px 10px;
|
||||
border: 1px solid #d5d8de;
|
||||
border-radius: 2px;
|
||||
|
@ -5637,16 +5635,7 @@ input[type='submit'].btn-block {
|
|||
}
|
||||
|
||||
.progress-bar-striped {
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
rgba(255, 255, 255, 0.15) 25%,
|
||||
transparent 25%,
|
||||
transparent 50%,
|
||||
rgba(255, 255, 255, 0.15) 50%,
|
||||
rgba(255, 255, 255, 0.15) 75%,
|
||||
transparent 75%,
|
||||
transparent
|
||||
);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-size: 3.077rem 3.077rem;
|
||||
}
|
||||
|
||||
|
@ -6124,8 +6113,7 @@ button.close {
|
|||
z-index: 1070;
|
||||
display: block;
|
||||
margin: 0;
|
||||
font-family: Roboto, 'Hiragina Sans GB', San Francisco, 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'WenQuanYi Micro Hei', 'Microsoft YaHei UI',
|
||||
'Microsoft YaHei', sans-serif;
|
||||
font-family: Roboto, 'Hiragina Sans GB', San Francisco, 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'WenQuanYi Micro Hei', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.428571;
|
||||
|
@ -6253,8 +6241,7 @@ button.close {
|
|||
z-index: 1060;
|
||||
display: block;
|
||||
max-width: 276px;
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI',
|
||||
'Microsoft YaHei', sans-serif;
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.428571;
|
||||
|
@ -12633,7 +12620,7 @@ a.avatar.x48 img {
|
|||
padding-left: 55px;
|
||||
}
|
||||
|
||||
.rb-collapsible-sidebar-collapsed .rb-left-sidebar .sidebar-elements > li ul.visible .nav-items .content > ul > li > ul > li > ul> li > ul > li > ul > li> a {
|
||||
.rb-collapsible-sidebar-collapsed .rb-left-sidebar .sidebar-elements > li ul.visible .nav-items .content > ul > li > ul > li > ul > li > ul > li > ul > li > a {
|
||||
padding-left: 65px;
|
||||
}
|
||||
}
|
||||
|
@ -14313,8 +14300,7 @@ a.avatar.x48 img {
|
|||
}
|
||||
|
||||
.rb-sub-header .navbar-nav > .nav-item > .nav-link {
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI',
|
||||
'Microsoft YaHei', sans-serif;
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
|
||||
font-size: 1.1rem;
|
||||
line-height: 40px;
|
||||
min-width: 100px;
|
||||
|
@ -21181,6 +21167,109 @@ fieldset[disabled] .full-calendar .fc-button:hover {
|
|||
width: 6px;
|
||||
}
|
||||
|
||||
/* jquery.gritter.css */
|
||||
#gritter-notice-wrapper {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
width: 301px;
|
||||
z-index: 9999;
|
||||
}
|
||||
#gritter-notice-wrapper.top-left {
|
||||
left: 20px;
|
||||
right: auto;
|
||||
}
|
||||
#gritter-notice-wrapper.bottom-right {
|
||||
top: auto;
|
||||
left: auto;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
#gritter-notice-wrapper.bottom-left {
|
||||
top: auto;
|
||||
right: auto;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
}
|
||||
.gritter-item-wrapper {
|
||||
position: relative;
|
||||
margin: 0 0 10px 0;
|
||||
background: url('../images/ie-spacer.gif'); /* ie7/8 fix */
|
||||
}
|
||||
.gritter-top {
|
||||
background: url(../images/gritter.png) no-repeat left -30px;
|
||||
height: 10px;
|
||||
}
|
||||
.hover .gritter-top {
|
||||
background-position: right -30px;
|
||||
}
|
||||
.gritter-bottom {
|
||||
background: url(../images/gritter.png) no-repeat left bottom;
|
||||
height: 8px;
|
||||
margin: 0;
|
||||
}
|
||||
.hover .gritter-bottom {
|
||||
background-position: bottom right;
|
||||
}
|
||||
.gritter-item {
|
||||
display: block;
|
||||
background: url(../images/gritter.png) no-repeat left -40px;
|
||||
color: #eee;
|
||||
padding: 2px 11px 8px 11px;
|
||||
font-size: 11px;
|
||||
font-family: verdana;
|
||||
}
|
||||
.hover .gritter-item {
|
||||
background-position: right -40px;
|
||||
}
|
||||
.gritter-item p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.gritter-close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 3px;
|
||||
background: url(../images/gritter.png) no-repeat left top;
|
||||
cursor: pointer;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-indent: -9999em;
|
||||
}
|
||||
.gritter-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding: 0 0 7px 0;
|
||||
display: block;
|
||||
text-shadow: 1px 1px 0 #000; /* Not supported by IE :( */
|
||||
}
|
||||
.gritter-image {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
float: left;
|
||||
}
|
||||
.gritter-with-image,
|
||||
.gritter-without-image {
|
||||
padding: 0;
|
||||
}
|
||||
.gritter-with-image {
|
||||
width: 220px;
|
||||
float: right;
|
||||
}
|
||||
/* for the light (white) version of the gritter notice */
|
||||
.gritter-light .gritter-item,
|
||||
.gritter-light .gritter-bottom,
|
||||
.gritter-light .gritter-top,
|
||||
.gritter-light .gritter-close {
|
||||
background-image: url(../images/gritter-light.png);
|
||||
color: #222;
|
||||
}
|
||||
.gritter-light .gritter-title {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#gritter-notice-wrapper {
|
||||
width: 360px;
|
||||
top: 82px;
|
||||
|
@ -21543,8 +21632,7 @@ fieldset[disabled] .full-calendar .fc-button:hover {
|
|||
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
|
||||
line-height: 2rem;
|
||||
font-family: Roboto, Arial, sans-serif;
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI',
|
||||
'Microsoft YaHei', sans-serif;
|
||||
font-family: Roboto, 'Hiragina Sans GB', 'San Francisco', 'Helvetica Neue', Helvetica, Arial, PingFangSC-Light, 'Noto Sans SC', 'Microsoft YaHei UI', 'Microsoft YaHei', sans-serif;
|
||||
font-size: 1rem;
|
||||
color: #999;
|
||||
}
|
||||
|
@ -21807,8 +21895,7 @@ fieldset[disabled] .full-calendar .fc-button:hover {
|
|||
border: 1px dashed #bbb;
|
||||
min-height: 100px;
|
||||
background-color: #e5e5e5;
|
||||
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff),
|
||||
linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
|
||||
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
|
||||
background-size: 60px 60px;
|
||||
background-position: 0 0, 30px 30px;
|
||||
}
|
||||
|
@ -22780,15 +22867,7 @@ div.table-responsive > div.dataTables_wrapper > div.row > div[class^='col-']:las
|
|||
margin-left: -250%;
|
||||
-webkit-animation: phAnimation 0.8s linear infinite;
|
||||
animation: phAnimation 0.8s linear infinite;
|
||||
background: -webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
right top,
|
||||
color-stop(46%, rgba(255, 255, 255, 0)),
|
||||
color-stop(50%, rgba(255, 255, 255, 0.35)),
|
||||
color-stop(54%, rgba(255, 255, 255, 0))
|
||||
)
|
||||
50% 50%;
|
||||
background: -webkit-gradient(linear, left top, right top, color-stop(46%, rgba(255, 255, 255, 0)), color-stop(50%, rgba(255, 255, 255, 0.35)), color-stop(54%, rgba(255, 255, 255, 0))) 50% 50%;
|
||||
background: linear-gradient(to right, rgba(255, 255, 255, 0) 46%, rgba(255, 255, 255, 0.35) 50%, rgba(255, 255, 255, 0) 54%) 50% 50%;
|
||||
}
|
||||
|
||||
|
|
|
@ -3019,6 +3019,7 @@ form {
|
|||
top: 9px;
|
||||
font-size: 1.55rem;
|
||||
color: #878787;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
@ -3077,6 +3078,7 @@ form {
|
|||
.search-container > .global-create > .dropdown.show > a {
|
||||
background: #4285f4;
|
||||
color: #fff;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.preview-modal {
|
||||
|
@ -4328,4 +4330,23 @@ pre.unstyle {
|
|||
|
||||
.bg-market {
|
||||
background-image: linear-gradient(135deg, #2973d7 0%, #26acb9 100%);
|
||||
}
|
||||
}
|
||||
|
||||
#gritter-notice-wrapper {
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
z-index: 1099;
|
||||
}
|
||||
|
||||
.gritter-item-wrapper .gritter-image > .icon {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.gritter-item-wrapper.color .gritter-item .gritter-img-container {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.gritter-item-wrapper.faster {
|
||||
-webkit-animation-duration: 200ms;
|
||||
animation-duration: 200ms;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/* eslint-disable no-undef */
|
||||
/*
|
||||
Copyright (c) REBUILD <https://getrebuild.com/> and/or its owners. All rights reserved.
|
||||
|
||||
rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
||||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
/* eslint-disable no-undef, react/display-name */
|
||||
|
||||
const wpc = window.__PageConfig
|
||||
|
||||
|
@ -31,7 +31,12 @@ useEditComp = function (name) {
|
|||
)
|
||||
} else if ('DefaultLanguage' === name) {
|
||||
// 借用贵宝地
|
||||
if (rb.commercial >= 10) _toggleLogo()
|
||||
if (rb.commercial >= 10) {
|
||||
_toggleImage('.applogo')
|
||||
_toggleImage('.bgimg')
|
||||
} else {
|
||||
$('.applogo b, .bgimg b').remove()
|
||||
}
|
||||
|
||||
const options = []
|
||||
for (let k in wpc._LANGS) {
|
||||
|
@ -49,24 +54,34 @@ useEditComp = function (name) {
|
|||
<option value="2">{$L('总是显示')}</option>
|
||||
</select>
|
||||
)
|
||||
} else if ('PageFooter' === name) {
|
||||
} else if ('PageFooter' === name || 'AllowUsesTime' === name || 'AllowUsesIp' === name) {
|
||||
return <textarea name={name} className="form-control form-control-sm row3x" maxLength="600" />
|
||||
}
|
||||
}
|
||||
|
||||
const _toggleLogo = function () {
|
||||
const $logo = $('.applogo').addClass('edit')
|
||||
$logo.find('p').removeClass('hide')
|
||||
const _toggleImage = function (el) {
|
||||
const $img = $(el).addClass('edit')
|
||||
$img.find('p').removeClass('hide')
|
||||
|
||||
let $current
|
||||
const $input = $logo.find('input')
|
||||
const $input = $img.find('input')
|
||||
$initUploader($input, null, (res) => {
|
||||
const $img = $current.find('i').css('background-image', `url(${rb.baseUrl}/filex/img/${res.key})`)
|
||||
changeValue({ target: { name: $img.hasClass('white') ? 'LOGOWhite' : 'LOGO', value: res.key } })
|
||||
$current.find('>i').css('background-image', `url(${rb.baseUrl}/filex/img/${res.key}?local=true)`)
|
||||
changeValue({ target: { name: $current.data('id'), value: res.key } })
|
||||
})
|
||||
|
||||
$logo.find('a').click(function () {
|
||||
$current = $(this)
|
||||
$input[0].click()
|
||||
$img
|
||||
.find('a')
|
||||
.attr('title', $L('点击上传'))
|
||||
.on('click', function () {
|
||||
$current = $(this)
|
||||
$input[0].click()
|
||||
})
|
||||
$img.find('a>b').on('click', function (e) {
|
||||
$stopEvent(e, true)
|
||||
$current = $(this).parent()
|
||||
|
||||
$current.find('>i').css('background-image', `url(${rb.baseUrl}/assets/img/s.gif)`)
|
||||
changeValue({ target: { name: $current.data('id'), value: '' } })
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
// 公共部分
|
||||
|
||||
$(document).ready(() => {
|
||||
$('.card-header>a').click((e) => {
|
||||
$('.card-header>a').on('click', (e) => {
|
||||
$stopEvent(e, true)
|
||||
enableEditMode()
|
||||
})
|
||||
|
||||
$('.edit-footer>.btn-link').click(() => location.reload())
|
||||
$('.edit-footer>.btn-primary').click(() => post(__data))
|
||||
$('.edit-footer>.btn-link').on('click', () => location.reload())
|
||||
$('.edit-footer>.btn-primary').on('click', () => post(__data))
|
||||
|
||||
if (window.ClipboardJS) {
|
||||
$('a[data-clipboard-text]').each(function () {
|
||||
|
@ -54,8 +54,8 @@ const enableEditMode = function () {
|
|||
const post = function (data) {
|
||||
for (let name in data) {
|
||||
if (!data[name]) {
|
||||
const $field = $('td[data-id=' + name + ']')
|
||||
if ($field.data('optional')) continue // 可选值
|
||||
const $field = $(`.syscfg td[data-id=${name}]`)
|
||||
if ($field.length === 0 || $field.data('optional')) continue // 可选值
|
||||
|
||||
const $c = $field.prev().clone()
|
||||
$c.find('p').remove()
|
||||
|
|
|
@ -125,7 +125,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
watermark_width: 200,
|
||||
watermark_font: 'arial',
|
||||
watermark_fontsize: '15px',
|
||||
watermark_alpha: 0.06,
|
||||
watermark_alpha: 0.1,
|
||||
watermark_parent_width: $(window).width(),
|
||||
watermark_parent_height: $(window).height(),
|
||||
monitor: true,
|
||||
|
|
|
@ -974,6 +974,85 @@ UserPopup.create = function (el) {
|
|||
// ~~ HTML 内容
|
||||
const WrapHtml = (htmlContent) => <div dangerouslySetInnerHTML={{ __html: htmlContent }} />
|
||||
|
||||
class RbGritter extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { ...props }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="gritter-notice-wrapper" className="gritter-main-wrapper">
|
||||
{this.state.items}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
_addItem(message, options) {
|
||||
const itemid = `gritter-item-${$random()}`
|
||||
|
||||
const type = options.type || 'success'
|
||||
const icon = type === 'success' ? 'check' : type === 'danger' ? 'close-circle-o' : 'info-outline'
|
||||
|
||||
const item = (
|
||||
<div key={itemid} id={itemid} className={`gritter-item-wrapper color ${type} animated faster fadeInRight`}>
|
||||
<div className="gritter-item">
|
||||
<div className="gritter-img-container">
|
||||
<span className="gritter-image">
|
||||
<i className={`icon zmdi zmdi-${icon}`} />
|
||||
</span>
|
||||
</div>
|
||||
<div className="gritter-content gritter-with-image">
|
||||
<a
|
||||
className="gritter-close"
|
||||
tabIndex="1"
|
||||
onClick={(e) => {
|
||||
$stopEvent(e, true)
|
||||
this._removeItem(itemid)
|
||||
}}
|
||||
/>
|
||||
{options.title && <span className="gritter-title">{options.title}</span>}
|
||||
<p>{message}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const itemsNew = this.state.items || []
|
||||
itemsNew.push(item)
|
||||
this.setState({ items: itemsNew }, () => {
|
||||
setTimeout(() => this._removeItem(itemid), options.timeout || 6000)
|
||||
})
|
||||
}
|
||||
|
||||
_removeItem(itemid) {
|
||||
const itemsNew = this.state.items.filter((item) => itemid !== item.key)
|
||||
console.log(itemsNew)
|
||||
this.setState({ items: itemsNew })
|
||||
}
|
||||
|
||||
// -- Usage
|
||||
/**
|
||||
* @param {*} message
|
||||
* @param {*} options
|
||||
*/
|
||||
static create(message, options = {}) {
|
||||
if (top !== self && parent.RbGritter) {
|
||||
parent.RbGritter.create(message, options)
|
||||
} else {
|
||||
if (this.__$wrapper) {
|
||||
this.__$wrapper._addItem(message, options)
|
||||
} else {
|
||||
const that = this
|
||||
renderRbcomp(<RbGritter />, null, function () {
|
||||
that.__$wrapper = this
|
||||
that.__$wrapper._addItem(message, options)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSX 组件渲染
|
||||
*
|
||||
|
|
|
@ -488,7 +488,7 @@ const CellRenders = {
|
|||
},
|
||||
|
||||
render(value, type, width, key) {
|
||||
const style = { width: (width || COLUMN_MIN_WIDTH) + 'px' }
|
||||
const style = { width: width || COLUMN_MIN_WIDTH }
|
||||
if (!value) return this.renderSimple(value, style, key)
|
||||
else return (this.__renders[type] || this.renderSimple)(value, style, key)
|
||||
},
|
||||
|
@ -955,7 +955,7 @@ class RbViewModal extends React.Component {
|
|||
<div className="modal-wrapper">
|
||||
<div className="modal rbview" ref={(c) => (this._rbview = c)}>
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content" style={{ width: this.mcWidth + 'px' }}>
|
||||
<div className="modal-content" style={{ width: this.mcWidth }}>
|
||||
<div className={'modal-body iframe rb-loading ' + (this.state.inLoad === true && 'rb-loading-active')}>
|
||||
<iframe ref={(c) => (this._iframe = c)} className={this.state.isHide ? 'invisible' : ''} src={this.state.showAfterUrl || 'about:blank'} frameBorder="0" scrolling="no" />
|
||||
<RbSpinner />
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
color: #fbbc05;
|
||||
font-size: 5rem;
|
||||
}
|
||||
.zmdi.err610::before {
|
||||
content: '\f1e7';
|
||||
content: '\f21b';
|
||||
color: #fbbc05;
|
||||
}
|
||||
.error-description > pre:empty {
|
||||
display: none;
|
||||
}
|
||||
|
@ -47,7 +52,7 @@
|
|||
<a class="btn btn-xl btn-space btn-secondary" th:href="@{/dashboard/home}" id="goHome">[[${bundle.L('返回首页')}]]</a>
|
||||
<button class="btn btn-xl btn-space btn-primary" type="button" onclick="location.reload()">[[${bundle.L('重试')}]]</button>
|
||||
<div class="mt-4">
|
||||
<a href="https://getrebuild.com/report-issue?title=error-page" target="_blank">[[${bundle.L('报告问题')}]]</a>
|
||||
<a th:href="${'https://getrebuild.com/report-issue?title=error-page-' + error_code}" target="_blank">[[${bundle.L('报告问题')}]]</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<th:block th:replace="~{/_include/header}" />
|
||||
<title>[[${bundle.L('用户登录')}]]</title>
|
||||
<style type="text/css">
|
||||
<style>
|
||||
#login-form > .row {
|
||||
margin-left: -15px !important;
|
||||
margin-right: -15px !important;
|
||||
|
@ -99,6 +99,11 @@
|
|||
background-color: #eee;
|
||||
}
|
||||
</style>
|
||||
<style th:if="${commercial > 1}">
|
||||
.rb-bgimg {
|
||||
background-image: url(../commons/theme/use-bgimg);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="rb-splash-screen">
|
||||
<div class="rb-wrapper rb-login">
|
||||
|
|
Loading…
Reference in a new issue