mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
commit
03a73ef611
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 2c48b6768082e5930ad02c16d4f25dd767d4ee97
|
||||
Subproject commit 45de87cc87af501e13783e4425d90ddaebef12b4
|
15
pom.xml
15
pom.xml
|
@ -5,14 +5,14 @@
|
|||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.6.2</version>
|
||||
<version>2.6.3</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<groupId>com.rebuild</groupId>
|
||||
<artifactId>rebuild</artifactId>
|
||||
<version>2.8.0-dev</version>
|
||||
<name>rebuild</name>
|
||||
<description>RB V2 use SpringBoot</description>
|
||||
<description>Building your business-systems freely!</description>
|
||||
<!-- UNCOMMENT USE TOMCAT -->
|
||||
<!-- <packaging>war</packaging> -->
|
||||
|
||||
|
@ -238,7 +238,6 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>5.3.15</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -289,6 +288,7 @@
|
|||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.9.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
|
@ -313,11 +313,12 @@
|
|||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>4.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>7.9.1</version>
|
||||
<version>7.9.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
|
@ -327,7 +328,7 @@
|
|||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
<artifactId>oshi-core</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<version>6.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
|
@ -403,7 +404,7 @@
|
|||
<dependency>
|
||||
<groupId>net.coobird</groupId>
|
||||
<artifactId>thumbnailator</artifactId>
|
||||
<version>0.4.15</version>
|
||||
<version>0.4.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>es.moki.ratelimitj</groupId>
|
||||
|
@ -418,7 +419,7 @@
|
|||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>3.16.7</version>
|
||||
<version>3.16.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
|
|
|
@ -31,7 +31,9 @@ import javax.management.ObjectName;
|
|||
import javax.management.Query;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.SessionTrackingMode;
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -123,6 +125,11 @@ public class BootApplication extends SpringBootServletInitializer {
|
|||
@Override
|
||||
public void onStartup(ServletContext servletContext) throws ServletException {
|
||||
CONTEXT_PATH = StringUtils.defaultIfBlank(servletContext.getContextPath(), "");
|
||||
|
||||
// Remove `jsession`
|
||||
servletContext.setSessionTrackingModes(Collections.singleton(SessionTrackingMode.COOKIE));
|
||||
servletContext.getSessionCookieConfig().setHttpOnly(true);
|
||||
|
||||
super.onStartup(servletContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.springframework.cache.ehcache.EhCacheCacheManager;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
|
@ -48,7 +49,8 @@ public class BootConfiguration implements InstallState {
|
|||
* Fake instance
|
||||
* FIXME 直接 `==` 比较不安全 ???
|
||||
*/
|
||||
public static final JedisPool USE_EHCACHE = new JedisPool();
|
||||
public static final JedisPool USE_EHCACHE = new JedisPool(
|
||||
KnownJedisPool.DEFAULT_CONFIG, "127.0.0.1", 6379);
|
||||
|
||||
@Bean
|
||||
JedisPool createJedisPool() {
|
||||
|
|
|
@ -67,7 +67,7 @@ public class BootEnvironmentPostProcessor implements EnvironmentPostProcessor, I
|
|||
try {
|
||||
Properties temp = PropertiesLoaderUtils.loadProperties(new FileSystemResource(installed));
|
||||
Properties filePs = new Properties();
|
||||
// 兼容 V1
|
||||
// compatible: v1.x
|
||||
for (String name : temp.stringPropertyNames()) {
|
||||
String value = temp.getProperty(name);
|
||||
if (name.endsWith(".aes")) {
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.rebuild.core.metadata.MetadataHelper;
|
|||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -121,7 +122,7 @@ public class ViewAddonsManager extends BaseLayoutManager {
|
|||
return JSONUtils.toJSONObject("items", useRefs);
|
||||
}
|
||||
|
||||
// fix: v2.2 兼容
|
||||
// compatible: v2.2
|
||||
JSON configJson = config.getJSON("config");
|
||||
if (configJson instanceof JSONArray) {
|
||||
configJson = JSONUtils.toJSONObject("items", configJson);
|
||||
|
@ -129,8 +130,18 @@ public class ViewAddonsManager extends BaseLayoutManager {
|
|||
|
||||
JSONArray addons = new JSONArray();
|
||||
for (Object o : ((JSONObject) configJson).getJSONArray ("items")) {
|
||||
String key;
|
||||
String label = null;
|
||||
// compatible: v2.8
|
||||
if (o instanceof JSONArray) {
|
||||
key = (String) ((JSONArray) o).get(0);
|
||||
label = (String) ((JSONArray) o).get(1);
|
||||
} else {
|
||||
key = o.toString();
|
||||
}
|
||||
|
||||
// Entity.Field (v1.9)
|
||||
String[] ef = ((String) o).split("\\.");
|
||||
String[] ef = key.split("\\.");
|
||||
if (!MetadataHelper.containsEntity(ef[0])) {
|
||||
continue;
|
||||
}
|
||||
|
@ -141,11 +152,12 @@ public class ViewAddonsManager extends BaseLayoutManager {
|
|||
}
|
||||
|
||||
if (Application.getPrivilegesManager().allow(user, addonEntity.getEntityCode(), useAction)) {
|
||||
if (ef.length > 1) {
|
||||
addons.add(getEntityShow(addonEntity.getField(ef[1]), mfRefs, applyType));
|
||||
} else {
|
||||
addons.add(EasyMetaFactory.toJSON(addonEntity));
|
||||
}
|
||||
JSONObject show = ef.length > 1
|
||||
? getEntityShow(addonEntity.getField(ef[1]), mfRefs, applyType)
|
||||
: EasyMetaFactory.toJSON(addonEntity);
|
||||
|
||||
if (StringUtils.isNotBlank(label)) show.put("entityLabel", label);
|
||||
addons.add(show);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -439,7 +439,8 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
|
||||
if (state == ApprovalState.APPROVED || state == ApprovalState.PROCESSING) {
|
||||
throw new DataSpecificationException(state == ApprovalState.APPROVED
|
||||
? Language.L("主记录已完成审批,不能添加明细") : Language.L("主记录正在审批中,不能添加明细"));
|
||||
? Language.L("主记录已完成审批,不能添加明细")
|
||||
: Language.L("主记录正在审批中,不能添加明细"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -482,7 +483,8 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
}
|
||||
|
||||
throw new DataSpecificationException(currentState == ApprovalState.APPROVED
|
||||
? Language.L("%s已完成审批,禁止操作", recordType) : Language.L("%s正在审批中,禁止操作", recordType));
|
||||
? Language.L("%s已完成审批,禁止操作", recordType)
|
||||
: Language.L("%s正在审批中,禁止操作", recordType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class FieldAggregation implements TriggerAction {
|
|||
* @param context
|
||||
*/
|
||||
public FieldAggregation(ActionContext context) {
|
||||
this(context, Boolean.TRUE, 5);
|
||||
this(context, Boolean.TRUE, 9);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -64,7 +64,7 @@ public enum ConfigurationItem {
|
|||
RecycleBinKeepingDays(180),
|
||||
|
||||
// 启用数据库备份
|
||||
DBBackupsEnable(false),
|
||||
DBBackupsEnable(true),
|
||||
|
||||
// 数据备份保留时间(0为禁用)
|
||||
DBBackupsKeepingDays(180),
|
||||
|
@ -88,6 +88,8 @@ public enum ConfigurationItem {
|
|||
AllowUsesTime,
|
||||
// 允许使用 IP
|
||||
AllowUsesIp,
|
||||
// 2FA
|
||||
Login2FAMode(0),
|
||||
|
||||
// DingTalk
|
||||
DingtalkAgentid, DingtalkAppkey, DingtalkAppsecret, DingtalkCorpid,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/*
|
||||
Copyright (c) Ruifang Tech <http://ruifang-tech.com/> and/or its owners. All rights reserved.
|
||||
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.distributed;
|
||||
|
|
|
@ -18,13 +18,20 @@ public class KnownJedisPool extends JedisPool {
|
|||
|
||||
public static final int TIMEOUT = 5000;
|
||||
|
||||
public static final JedisPoolConfig DEFAULT_CONFIG = new JedisPoolConfig() {
|
||||
@Override
|
||||
public boolean getJmxEnabled() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
private String password;
|
||||
private int database;
|
||||
|
||||
public KnownJedisPool(String host, int port, String password, int database) {
|
||||
super(new JedisPoolConfig(), host, port, TIMEOUT, password, database);
|
||||
super(DEFAULT_CONFIG, host, port, TIMEOUT, password, database);
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.password = password;
|
||||
|
|
|
@ -89,7 +89,7 @@ public class DataListBuilderImpl implements DataListBuilder {
|
|||
for (int i = 1; i < count.length; i++) {
|
||||
Map<String, Object> cfg = countFields.get(i);
|
||||
Field field = entity.getField((String) cfg.get("field"));
|
||||
String label = (String) cfg.get("label");
|
||||
String label = (String) cfg.get("label2");
|
||||
if (StringUtils.isBlank(label)) {
|
||||
String calc = (String) cfg.get("calc");
|
||||
label = String.format("%s (%s)", Language.L(field), FormatCalc.valueOf(calc).getLabel());
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/*
|
||||
Copyright (c) Ruifang Tech <http://ruifang-tech.com/> and/or its owners. All rights reserved.
|
||||
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.general;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/*
|
||||
Copyright (c) Ruifang Tech <http://ruifang-tech.com/> and/or its owners. All rights reserved.
|
||||
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.setup;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/*
|
||||
Copyright (c) Ruifang Tech <http://ruifang-tech.com/> and/or its owners. All rights reserved.
|
||||
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.setup;
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.io.InputStreamReader;
|
|||
/**
|
||||
* 数据库备份
|
||||
* - `mysqldump[.exe]` 命令必须在环境变量中
|
||||
* - 除了本库还要有全局的 `RELOAD` 权限
|
||||
* - 除了本库还要有全局的 `RELOAD` or `FLUSH_TABLES` and `PROCESS` 权限
|
||||
*
|
||||
* @author devezhao
|
||||
* @since 2020/2/4
|
||||
|
@ -62,39 +62,34 @@ public class DatabaseBackup {
|
|||
File dest = new File(backups, destName);
|
||||
|
||||
String cmd = String.format(
|
||||
"mysqldump -u%s -p%s -h%s -P%s --default-character-set=utf8 --opt --extended-insert=true --triggers -R --hex-blob -x %s>%s",
|
||||
"-u%s -p%s -h%s -P%s --default-character-set=utf8 --opt --extended-insert=true --triggers --hex-blob -R -x %s>%s",
|
||||
user, passwd, host, port, dbname, dest.getAbsolutePath());
|
||||
|
||||
Process process;
|
||||
ProcessBuilder builder = new ProcessBuilder();
|
||||
String encoding = "UTF-8";
|
||||
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
cmd = cmd.replaceFirst("mysqldump", "cmd /c mysqldump.exe");
|
||||
process = Runtime.getRuntime().exec(cmd);
|
||||
builder.command("cmd.exe", "/c", "mysqldump.exe " + cmd);
|
||||
encoding = "GBK";
|
||||
}
|
||||
// for Linux
|
||||
else {
|
||||
process = Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", cmd });
|
||||
} else {
|
||||
// for Linux/Unix
|
||||
builder.command("/bin/sh", "-c", "mysqldump " + cmd);
|
||||
}
|
||||
|
||||
BufferedReader readerError = null;
|
||||
builder.redirectErrorStream(true);
|
||||
Process process = builder.start();
|
||||
|
||||
BufferedReader reader = null;
|
||||
StringBuilder echo = new StringBuilder();
|
||||
try {
|
||||
readerError = new BufferedReader(new InputStreamReader(process.getErrorStream(), encoding));
|
||||
reader = new BufferedReader(new InputStreamReader(process.getInputStream(), encoding));
|
||||
|
||||
String line;
|
||||
while ((line = readerError.readLine()) != null) {
|
||||
echo.append(line).append("\n");
|
||||
}
|
||||
while ((line = reader.readLine()) != null) {
|
||||
echo.append(line).append("\n");
|
||||
}
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(readerError);
|
||||
IOUtils.closeQuietly(reader);
|
||||
process.destroy();
|
||||
}
|
||||
|
@ -113,7 +108,7 @@ public class DatabaseBackup {
|
|||
File zip = new File(backups, destName + ".zip");
|
||||
try {
|
||||
CompressUtils.forceZip(dest, zip, null);
|
||||
|
||||
|
||||
FileUtils.deleteQuietly(dest);
|
||||
dest = zip;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -13,6 +13,8 @@ import com.rebuild.core.Application;
|
|||
import com.rebuild.core.cache.CommonsCache;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 位置工具
|
||||
*
|
||||
|
@ -22,6 +24,9 @@ import lombok.extern.slf4j.Slf4j;
|
|||
@Slf4j
|
||||
public class LocationUtils {
|
||||
|
||||
private static final Pattern PRIVATE_IP = Pattern.compile("(localhost)|" +
|
||||
"(^127\\.)|(^10\\.)|(^172\\.1[6-9]\\.)|(^172\\.2[0-9]\\.)|(^172\\.3[0-1]\\.)|(^192\\.168\\.)");
|
||||
|
||||
/**
|
||||
* 获取 IP 所在位置
|
||||
*
|
||||
|
@ -40,6 +45,10 @@ public class LocationUtils {
|
|||
* @return
|
||||
*/
|
||||
public static JSON getLocation(String ip, boolean useCache) {
|
||||
if (PRIVATE_IP.matcher(ip).find()) {
|
||||
return JSONUtils.toJSONObject(new String[] { "ip", "country"}, new String[] { ip, "R" });
|
||||
}
|
||||
|
||||
JSONObject result;
|
||||
if (useCache) {
|
||||
result = (JSONObject) Application.getCommonsCache().getx("IPLocation2" + ip);
|
||||
|
|
|
@ -140,15 +140,15 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
String sidebarCollapsed = ServletUtils.readCookie(request, "rb.sidebarCollapsed");
|
||||
String sideCollapsedClazz = BooleanUtils.toBoolean(sidebarCollapsed) ? "rb-collapsible-sidebar-collapsed" : "";
|
||||
// Aside collapsed
|
||||
if (!(requestEntry.getRequestUri().contains("/admin/") || requestEntry.getRequestUri().contains("/setup/"))) {
|
||||
if (!(requestUri.contains("/admin/") || requestUri.contains("/setup/"))) {
|
||||
String asideCollapsed = ServletUtils.readCookie(request, "rb.asideCollapsed");
|
||||
if (BooleanUtils.toBoolean(asideCollapsed)) sideCollapsedClazz += " rb-aside-collapsed";
|
||||
}
|
||||
request.setAttribute("sideCollapsedClazz", sideCollapsedClazz);
|
||||
}
|
||||
|
||||
// 超管设置仍可访问
|
||||
skipCheckSafeUse = adminVerified || UserHelper.isSuperAdmin(requestUser);
|
||||
// 超管可访问
|
||||
skipCheckSafeUse = UserHelper.isSuperAdmin(requestUser);
|
||||
|
||||
} else if (!isIgnoreAuth(requestUri)) {
|
||||
// 外部表单特殊处理(媒体字段上传/预览)
|
||||
|
@ -169,7 +169,7 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
skipCheckSafeUse = true;
|
||||
}
|
||||
|
||||
if (!skipCheckSafeUse) checkSafeUse(ipAddr);
|
||||
if (!skipCheckSafeUse) checkSafeUse(ipAddr, requestUri);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -285,11 +285,11 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
response.sendRedirect(fullUrl);
|
||||
}
|
||||
|
||||
private void checkSafeUse(String ipAddr) throws DefinedException {
|
||||
private void checkSafeUse(String ipAddr, String requestUri) throws DefinedException {
|
||||
if (!License.isRbvAttached()) return;
|
||||
|
||||
if (ipAddr.equals("localhost") || ipAddr.equals("127.0.0.1")) {
|
||||
log.warn("Allow localhost uses ");
|
||||
log.warn("Allow localhost/127.0.0.1 use : {}", requestUri);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ public class ViewAddonsController extends BaseController {
|
|||
String applyType = getParameter(request, "type", ViewAddonsManager.TYPE_TAB);
|
||||
|
||||
ConfigBean config = ViewAddonsManager.instance.getLayout(user, entity, applyType);
|
||||
// fix: v2.2 兼容
|
||||
// compatible: v2.2
|
||||
JSON configJson = config == null ? null : config.getJSON("config");
|
||||
if (configJson instanceof JSONArray) {
|
||||
configJson = JSONUtils.toJSONObject("items", configJson);
|
||||
|
|
|
@ -51,16 +51,14 @@ public class GeneralListController extends EntityController {
|
|||
if (listEntity == null) return null;
|
||||
|
||||
final EasyEntity easyEntity = EasyMetaFactory.valueOf(listEntity);
|
||||
// 使用主实体列表配置
|
||||
final EasyEntity mainEntity = listEntity.getMainEntity() == null
|
||||
? easyEntity : EasyMetaFactory.valueOf(listEntity.getMainEntity());
|
||||
|
||||
String listPage = listEntity.getMainEntity() != null ? "/general/detail-list" : "/general/record-list";
|
||||
Integer listMode = getIntParameter(request, "forceListMode");
|
||||
if (listMode == null) {
|
||||
if (listEntity.getMainEntity() == null) {
|
||||
listMode = ObjectUtils.toInt(easyEntity.getExtraAttr(EasyEntityConfigProps.ADV_LIST_MODE), 1);
|
||||
} else {
|
||||
listMode = ObjectUtils.toInt(EasyMetaFactory.valueOf(
|
||||
listEntity.getMainEntity()).getExtraAttr(EasyEntityConfigProps.ADV_LIST_MODE), 1);
|
||||
}
|
||||
listMode = ObjectUtils.toInt(mainEntity.getExtraAttr(EasyEntityConfigProps.ADV_LIST_MODE), 1);
|
||||
}
|
||||
if (listMode == 2) {
|
||||
listPage = "/general/record-list-2"; // Mode2
|
||||
|
@ -82,8 +80,8 @@ public class GeneralListController extends EntityController {
|
|||
listConfig = DataListManager.instance.getFieldsLayout(entity, user);
|
||||
|
||||
// 扩展配置
|
||||
String advListHideFilters = easyEntity.getExtraAttr(EasyEntityConfigProps.ADV_LIST_HIDE_FILTERS);
|
||||
String advListHideCharts = easyEntity.getExtraAttr(EasyEntityConfigProps.ADV_LIST_HIDE_CHARTS);
|
||||
String advListHideFilters = mainEntity.getExtraAttr(EasyEntityConfigProps.ADV_LIST_HIDE_FILTERS);
|
||||
String advListHideCharts = mainEntity.getExtraAttr(EasyEntityConfigProps.ADV_LIST_HIDE_CHARTS);
|
||||
mv.getModel().put(EasyEntityConfigProps.ADV_LIST_HIDE_FILTERS, advListHideFilters);
|
||||
mv.getModel().put(EasyEntityConfigProps.ADV_LIST_HIDE_CHARTS, advListHideCharts);
|
||||
mv.getModel().put("hideAside",
|
||||
|
|
|
@ -2086,9 +2086,7 @@
|
|||
"其他":"其他",
|
||||
"擦除":"擦除",
|
||||
"你的 IP 地址不在允许范围内":"你的 IP 地址不在允许范围内",
|
||||
"每个时间(段)一行,如 `10` `9-18`":"每个时间(段)一行,如 `10` `9-18`",
|
||||
"日期字段格式不兼容":"日期字段格式不兼容",
|
||||
"每个 IP 一行,如 `192.168.*` `192.168.10.*`":"每个 IP 一行,如 `192.168.*` `192.168.10.*`",
|
||||
"取消置顶":"取消置顶",
|
||||
"我创建的":"我创建的",
|
||||
"请选择要添加的常用查询":"请选择要添加的常用查询",
|
||||
|
@ -2107,5 +2105,16 @@
|
|||
"免费版不支持高级功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)":"免费版不支持高级功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)",
|
||||
"常用查询方便以后使用":"常用查询方便以后使用",
|
||||
"邮编":"邮编",
|
||||
"高级":"高级"
|
||||
"高级":"高级",
|
||||
"标记已读":"标记已读",
|
||||
"仅邮箱":"仅邮箱",
|
||||
"输入名称保存":"输入名称保存",
|
||||
"手机或邮箱":"手机或邮箱",
|
||||
"请确保邮件/短信配置正确,否则无法发送/接收验证码,导致无法登录":"请确保邮件/短信配置正确,否则无法发送/接收验证码,导致无法登录",
|
||||
"仅手机":"仅手机",
|
||||
"仅指定时间可使用,每个时间一行,如 `10` `9-18` 等":"仅指定时间可使用,每个时间一行,如 `10` `9-18` 等",
|
||||
"不启用":"不启用",
|
||||
"启用两步验证":"启用两步验证",
|
||||
"仅指定 IP 可使用,每个 IP 一行,如 `192.168.*` `192.168.10.*` 等":"仅指定 IP 可使用,每个 IP 一行,如 `192.168.*` `192.168.10.*` 等",
|
||||
"或联系系统管理员":"或联系系统管理员"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<link rel="manifest" th:href="@{/assets/manifest.json}" />
|
||||
<link rel="shortcut icon" th:href="@{/assets/img/favicon.png}" />
|
||||
<link rel="apple-touch-icon" th:href="@{/assets/img/favicon.png}" />
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/assets/lib/material-design-iconic-font.min.css}" />
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
.set-items .item > span {
|
||||
margin: 0 4px;
|
||||
}
|
||||
.axis-target .ui-sortable-placeholder.ui-state-highlight {
|
||||
width: 7px;
|
||||
height: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="dialog">
|
||||
|
@ -54,6 +58,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<th:block th:replace="~{/_include/footer}" />
|
||||
<script th:src="@{/assets/js/show-styles.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/list-stats.js}" type="text/babel"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -38,49 +38,7 @@
|
|||
</div>
|
||||
<th:block th:replace="~{/_include/footer}" />
|
||||
<script th:src="@{/assets/js/sortable.js}"></script>
|
||||
<script type="text/babel">
|
||||
$(document).ready(function () {
|
||||
const entity = $urlp('entity'),
|
||||
type = $urlp('type')
|
||||
const url = `/admin/entity/${entity}/view-addons?type=${type}`
|
||||
|
||||
$.get(url, function (res) {
|
||||
$(res.data.refs).each(function () {
|
||||
render_unset(this)
|
||||
})
|
||||
|
||||
if (res.data.config) {
|
||||
$(res.data.config.items).each(function () {
|
||||
$('.unset-list li[data-key="' + this + '"]').trigger('click')
|
||||
})
|
||||
$('#relatedAutoExpand').attr('checked', res.data.config.autoExpand === true)
|
||||
$('#relatedAutoHide').attr('checked', res.data.config.autoHide === true)
|
||||
}
|
||||
|
||||
if (!res.data.refs || res.data.refs.length === 0) {
|
||||
$(`<li class="dd-item nodata">${$L('暂无数据')}</li>`).appendTo('.unset-list')
|
||||
}
|
||||
})
|
||||
|
||||
const $btn = $('.J_save').click(function () {
|
||||
let config = []
|
||||
$('.J_config>li').each(function () {
|
||||
config.push($(this).data('key'))
|
||||
})
|
||||
config = {
|
||||
items: config,
|
||||
autoExpand: $val('#relatedAutoExpand'),
|
||||
autoHide: $val('#relatedAutoHide'),
|
||||
}
|
||||
|
||||
$btn.button('loading')
|
||||
$.post(url, JSON.stringify(config), function (res) {
|
||||
$btn.button('reset')
|
||||
if (res.error_code === 0) parent.location.reload()
|
||||
else RbHighbar.error(res.error_msg)
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<script th:src="@{/assets/js/show-styles.js}" type="text/babel"></script>
|
||||
<script th:src="@{/assets/js/metadata/view-addons.js}" type="text/babel"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -160,11 +160,19 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('登录密码过期时间')}]] <sup class="rbv"></sup></td>
|
||||
<td th:data-id="${commercial > 0 ? 'PasswordExpiredDays' : ''}" th:data-value="${PasswordExpiredDays}">[[${PasswordExpiredDays}]] [[${bundle.L('天')}]]</td>
|
||||
<td th:data-id="${commercial > 0 ? 'PasswordExpiredDays' : ''}" th:data-value="${PasswordExpiredDays}">
|
||||
<th:block th:if="${PasswordExpiredDays == '0'}">[[${bundle.L('不启用')}]]</th:block>
|
||||
<th:block th:if="${PasswordExpiredDays != '0'}">[[${PasswordExpiredDays}]] [[${bundle.L('天')}]]</th:block>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('同一用户允许多地登录')}]] <sup class="rbv"></sup></td>
|
||||
<td th:data-id="${commercial > 0 ? 'MultipleSessions' : ''}" th:data-value="${MultipleSessions}">[[${MultipleSessions ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
<tr class="bosskey-show">
|
||||
<td>[[${bundle.L('启用两步验证')}]] <sup class="rbv"></sup></td>
|
||||
<td th:data-id="${commercial > 1 ? 'Login2FAMode' : ''}" th:data-value="${Login2FAMode}" th:data-form-text="${bundle.L('请确保邮件/短信配置正确,否则无法发送/接收验证码,导致无法登录')}">
|
||||
<th:block th:if="${Login2FAMode == '0'}">[[${bundle.L('不启用')}]]</th:block>
|
||||
<th:block th:if="${Login2FAMode == '1'}">[[${bundle.L('手机或邮箱')}]]</th:block>
|
||||
<th:block th:if="${Login2FAMode == '2'}">[[${bundle.L('仅手机')}]]</th:block>
|
||||
<th:block th:if="${Login2FAMode == '3'}">[[${bundle.L('仅邮箱')}]]</th:block>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('允许使用时间')}]] <sup class="rbv"></sup></td>
|
||||
|
@ -172,7 +180,7 @@
|
|||
th:data-id="${commercial > 1 ? 'AllowUsesTime' : ''}"
|
||||
th:data-value="${AllowUsesTime}"
|
||||
data-optional="true"
|
||||
th:data-form-text="${bundle.L('每个时间(段)一行,如 `10` `9-18`')}"
|
||||
th:data-form-text="${bundle.L('仅指定时间可使用,每个时间一行,如 `10` `9-18` 等')}"
|
||||
>
|
||||
<pre class="unstyle">[[${AllowUsesTime ?:bundle.L('不限')}]]</pre>
|
||||
</td>
|
||||
|
@ -183,10 +191,14 @@
|
|||
th:data-id="${commercial > 1 ? 'AllowUsesIp' : ''}"
|
||||
th:data-value="${AllowUsesIp}"
|
||||
data-optional="true"
|
||||
th:data-form-text="${bundle.L('每个 IP 一行,如 `192.168.*` `192.168.10.*`')}"
|
||||
th:data-form-text="${bundle.L('仅指定 IP 可使用,每个 IP 一行,如 `192.168.*` `192.168.10.*` 等')}"
|
||||
>
|
||||
<pre class="unstyle">[[${AllowUsesIp ?:bundle.L('不限')}]]</pre>
|
||||
</td>
|
||||
<tr class="bosskey-show">
|
||||
<td>[[${bundle.L('同一用户允许多地登录')}]] <sup class="rbv"></sup></td>
|
||||
<td th:data-id="${commercial > 0 ? 'MultipleSessions' : ''}" th:data-value="${MultipleSessions}">[[${MultipleSessions ? bundle.L('是') : bundle.L('否')}]]</td>
|
||||
</tr>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -202,15 +214,21 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('备份保留时间')}]]</td>
|
||||
<td data-id="DBBackupsKeepingDays" th:data-value="${DBBackupsKeepingDays}">[[${DBBackupsKeepingDays}]] [[${bundle.L('天')}]]</td>
|
||||
<td data-id="DBBackupsKeepingDays" th:data-value="${DBBackupsKeepingDays}">
|
||||
[[${DBBackupsKeepingDays}]] [[${bundle.L('天')}]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('变更历史保留时间')}]]</td>
|
||||
<td data-id="RevisionHistoryKeepingDays" th:data-value="${RevisionHistoryKeepingDays}">[[${RevisionHistoryKeepingDays}]] [[${bundle.L('天')}]]</td>
|
||||
<td data-id="RevisionHistoryKeepingDays" th:data-value="${RevisionHistoryKeepingDays}">
|
||||
[[${RevisionHistoryKeepingDays}]] [[${bundle.L('天')}]]
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[[${bundle.L('回收站保留时间')}]]</td>
|
||||
<td data-id="RecycleBinKeepingDays" th:data-value="${RecycleBinKeepingDays}">[[${RecycleBinKeepingDays}]] [[${bundle.L('天')}]]</td>
|
||||
<td data-id="RecycleBinKeepingDays" th:data-value="${RecycleBinKeepingDays}">
|
||||
[[${RecycleBinKeepingDays}]] [[${bundle.L('天')}]]
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -108,7 +108,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
margin-right: 3px;
|
||||
margin-bottom: 2px;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,6 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
}
|
||||
|
||||
.axis-target .dropdown-menu .dropdown-item {
|
||||
cursor: pointer;
|
||||
padding: 6px 14px;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,11 @@ code {
|
|||
color: #e83e8c;
|
||||
}
|
||||
|
||||
a,
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 1280 */
|
||||
.container-smart {
|
||||
max-width: 1160px;
|
||||
|
@ -48,6 +53,11 @@ code {
|
|||
max-width: 300px;
|
||||
}
|
||||
|
||||
.dropdown-menu .dropdown-item,
|
||||
.dropdown-menu .dropdown-item > a {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dropdown-menu.auto-scroller {
|
||||
max-height: 500px;
|
||||
overflow-x: auto;
|
||||
|
@ -621,7 +631,6 @@ div.dataTables_filter .filter-badge:hover .close {
|
|||
|
||||
.adv-search .dropdown-item {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.adv-search .dropdown-item a {
|
||||
|
@ -802,10 +811,6 @@ textarea.row3x {
|
|||
resize: none;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mlr-auto {
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
|
@ -1968,7 +1973,6 @@ th.column-fixed {
|
|||
.aside-tree li > a {
|
||||
display: block;
|
||||
padding: 8px 10px;
|
||||
cursor: pointer;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
@ -3616,11 +3620,11 @@ a.icon-link > .zmdi {
|
|||
.syscfg h5 {
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
padding: 12px 10px;
|
||||
}
|
||||
|
||||
.syscfg .table td {
|
||||
padding: 10px;
|
||||
padding: 12px 10px;
|
||||
}
|
||||
|
||||
.syscfg .table td p {
|
||||
|
@ -4563,3 +4567,7 @@ pre.unstyle {
|
|||
left: -48px;
|
||||
box-shadow: inset -10px 0 8px -8px rgb(0 0 0 / 15%);
|
||||
}
|
||||
|
||||
.pointer {
|
||||
cursor: pointer !important;
|
||||
}
|
|
@ -215,6 +215,12 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
color: #fff !important;
|
||||
}
|
||||
|
||||
.formula-calc ul li > a[data-toggle]::after {
|
||||
content: '\f2f9';
|
||||
font-family: 'Material-Design-Iconic-Font';
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.formula-calc .fields {
|
||||
max-height: 186px;
|
||||
margin-top: 1px;
|
||||
|
|
BIN
src/main/resources/web/assets/img/icon-192x192.png
Normal file
BIN
src/main/resources/web/assets/img/icon-192x192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 9 KiB After Width: | Height: | Size: 9 KiB |
BIN
src/main/resources/web/assets/img/icon-384x384.png
Normal file
BIN
src/main/resources/web/assets/img/icon-384x384.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
src/main/resources/web/assets/img/icon-512x512.png
Normal file
BIN
src/main/resources/web/assets/img/icon-512x512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -62,6 +62,15 @@ useEditComp = function (name) {
|
|||
)
|
||||
} else if ('PageFooter' === name || 'AllowUsesTime' === name || 'AllowUsesIp' === name) {
|
||||
return <textarea name={name} className="form-control form-control-sm row3x" maxLength="600" />
|
||||
} else if ('Login2FAMode' === name) {
|
||||
return (
|
||||
<select className="form-control form-control-sm">
|
||||
<option value="0">{$L('不启用')}</option>
|
||||
<option value="1">{$L('手机或邮箱')}</option>
|
||||
<option value="2">{$L('仅手机')}</option>
|
||||
<option value="3">{$L('仅邮箱')}</option>
|
||||
</select>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,14 +33,15 @@ $(document).ready(function () {
|
|||
parent.RbModal.resize()
|
||||
})
|
||||
|
||||
// // 字段排序 FIXME 拖动布局错乱
|
||||
// $('.set-items')
|
||||
// .sortable({
|
||||
// containment: 'parent',
|
||||
// cursor: 'move',
|
||||
// opacity: 0.8,
|
||||
// })
|
||||
// .disableSelection()
|
||||
// // 字段排序
|
||||
$('.set-items')
|
||||
.sortable({
|
||||
containment: 'parent',
|
||||
cursor: 'move',
|
||||
opacity: 0.8,
|
||||
placeholder: 'ui-state-highlight',
|
||||
})
|
||||
.disableSelection()
|
||||
|
||||
const $btn = $('.J_save').on('click', () => {
|
||||
if (rb.commercial < 1) {
|
||||
|
@ -51,7 +52,11 @@ $(document).ready(function () {
|
|||
const config = { items: [] }
|
||||
$('.set-items > span').each(function () {
|
||||
const $this = $(this)
|
||||
config.items.push({ field: $this.attr('data-field'), calc: $this.attr('data-calc'), label: $this.attr('data-label') })
|
||||
config.items.push({
|
||||
field: $this.attr('data-field'),
|
||||
calc: $this.attr('data-calc'),
|
||||
label2: $this.attr('data-label'),
|
||||
})
|
||||
})
|
||||
|
||||
$btn.button('loading')
|
||||
|
@ -71,6 +76,8 @@ const CALC_TYPES = {
|
|||
'MIN': $L('最小值'),
|
||||
}
|
||||
|
||||
const ShowStyles_Comps = {}
|
||||
|
||||
const render_set = function (item) {
|
||||
const len = $('.set-items > span').length
|
||||
if (len >= 3) $('.J_tips').removeClass('hide')
|
||||
|
@ -83,7 +90,7 @@ const render_set = function (item) {
|
|||
$to.find('>span.text-muted').remove()
|
||||
|
||||
const calc = item.calc || 'SUM'
|
||||
const $item = $(`<span data-field="${item.name}" data-calc="${calc}" data-label="${item.specLabel || ''}"></span>`).appendTo($to)
|
||||
const $item = $(`<span data-field="${item.name}" data-calc="${calc}" data-label="${item.label2 || ''}"></span>`).appendTo($to)
|
||||
|
||||
const $a = $(
|
||||
`<div class="item" data-toggle="dropdown"><a><i class="zmdi zmdi-chevron-down"></i></a><span>${item.label} (${CALC_TYPES[calc]})</span><a class="del"><i class="zmdi zmdi-close-circle"></i></a></div>`
|
||||
|
@ -97,11 +104,33 @@ const render_set = function (item) {
|
|||
for (let k in CALC_TYPES) {
|
||||
$(`<li class="dropdown-item" data-calc=${k}>${CALC_TYPES[k]}</li>`).appendTo($ul)
|
||||
}
|
||||
// $('<li class="dropdown-divider"></li>').appendTo($ul)
|
||||
// $(`<li class="dropdown-item" data-calc='_LABEL'>${$L('显示样式')}</li>`).appendTo($ul)
|
||||
$('<li class="dropdown-divider"></li>').appendTo($ul)
|
||||
$(`<li class="dropdown-item" data-calc='_LABEL'>${$L('显示样式')}</li>`).appendTo($ul)
|
||||
|
||||
$ul.find('.dropdown-item').on('click', function () {
|
||||
const calc = $(this).data('calc')
|
||||
$item.attr('data-calc', calc).find('.item > span').text(`${item.label} (${CALC_TYPES[calc]})`)
|
||||
if (calc === '_LABEL') {
|
||||
if (ShowStyles_Comps[item.name]) {
|
||||
ShowStyles_Comps[item.name].show()
|
||||
} else {
|
||||
renderRbcomp(
|
||||
// eslint-disable-next-line react/jsx-no-undef
|
||||
<ShowStyles
|
||||
label={item.label2}
|
||||
onConfirm={(s) => {
|
||||
$item.attr({
|
||||
'data-label': s.label || '',
|
||||
})
|
||||
}}
|
||||
/>,
|
||||
null,
|
||||
function () {
|
||||
ShowStyles_Comps[item.name] = this
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
$item.attr('data-calc', calc).find('.item > span').text(`${item.label} (${CALC_TYPES[calc]})`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
90
src/main/resources/web/assets/js/metadata/view-addons.js
Normal file
90
src/main/resources/web/assets/js/metadata/view-addons.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
const _configLabels = {}
|
||||
|
||||
$(document).ready(function () {
|
||||
const entity = $urlp('entity'),
|
||||
type = $urlp('type')
|
||||
const url = `/admin/entity/${entity}/view-addons?type=${type}`
|
||||
|
||||
$.get(url, function (res) {
|
||||
$(res.data.refs).each(function () {
|
||||
// eslint-disable-next-line no-undef
|
||||
render_unset(this)
|
||||
})
|
||||
|
||||
if (res.data.config) {
|
||||
$(res.data.config.items).each(function () {
|
||||
let key = this
|
||||
// compatible: v2.8
|
||||
if (typeof this !== 'string') {
|
||||
key = this[0]
|
||||
_configLabels[key] = this[1]
|
||||
}
|
||||
$(`.unset-list li[data-key="${key}"]`).trigger('click')
|
||||
})
|
||||
$('#relatedAutoExpand').attr('checked', res.data.config.autoExpand === true)
|
||||
$('#relatedAutoHide').attr('checked', res.data.config.autoHide === true)
|
||||
}
|
||||
|
||||
if (!res.data.refs || res.data.refs.length === 0) {
|
||||
$(`<li class="dd-item nodata">${$L('暂无数据')}</li>`).appendTo('.unset-list')
|
||||
}
|
||||
})
|
||||
|
||||
const $btn = $('.J_save').click(function () {
|
||||
let config = []
|
||||
$('.J_config>li').each(function () {
|
||||
const $this = $(this)
|
||||
config.push([$this.data('key'), $this.attr('data-label') || ''])
|
||||
})
|
||||
config = {
|
||||
items: config,
|
||||
autoExpand: $val('#relatedAutoExpand'),
|
||||
autoHide: $val('#relatedAutoHide'),
|
||||
}
|
||||
|
||||
$btn.button('loading')
|
||||
$.post(url, JSON.stringify(config), function (res) {
|
||||
$btn.button('reset')
|
||||
if (res.error_code === 0) parent.location.reload()
|
||||
else RbHighbar.error(res.error_msg)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const ShowStyles_Comps = {}
|
||||
// eslint-disable-next-line no-undef
|
||||
render_item_after = function ($item) {
|
||||
const key = $item.data('key')
|
||||
const $a = $(`<a class="mr-1" title="${$L('显示样式')}"><i class="zmdi zmdi-edit"></i></a>`)
|
||||
$item.find('.dd3-action>a').before($a)
|
||||
|
||||
$a.on('click', function () {
|
||||
if (ShowStyles_Comps[key]) {
|
||||
ShowStyles_Comps[key].show()
|
||||
} else {
|
||||
renderRbcomp(
|
||||
// eslint-disable-next-line react/jsx-no-undef
|
||||
<ShowStyles
|
||||
label={_configLabels[key]}
|
||||
onConfirm={(s) => {
|
||||
$item.attr({
|
||||
'data-label': s.label || '',
|
||||
})
|
||||
_configLabels[key] = s.label
|
||||
}}
|
||||
/>,
|
||||
null,
|
||||
function () {
|
||||
ShowStyles_Comps[key] = this
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -226,6 +226,8 @@ class AddCommonQuery extends RbFormHandler {
|
|||
|
||||
return (
|
||||
<RbModal ref={(c) => (this._dlg = c)} title={$L('添加常用查询')}>
|
||||
<RbAlertBox type="info" message={$L('可在添加后修改这些查询,以便更适合自己的使用需要')} />
|
||||
|
||||
<div ref={(c) => (this._$chks = c)}>
|
||||
{defs.map((item, idx) => {
|
||||
if (item.length === 0) return <br key={idx} />
|
||||
|
@ -237,7 +239,6 @@ class AddCommonQuery extends RbFormHandler {
|
|||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="protips mb-3 text-left">{$L('可在添加后修改这些查询,以便更适合自己的使用需要')}</div>
|
||||
<div className="dialog-footer" ref={(c) => (this._btns = c)}>
|
||||
<button className="btn btn-primary" type="button" onClick={() => this.saveAdd()}>
|
||||
{$L('确定')}
|
||||
|
|
|
@ -729,7 +729,8 @@ const RbViewPage = {
|
|||
const that = this
|
||||
$(config).each(function () {
|
||||
const e = this
|
||||
const title = $L('新建%s', e.entityLabel)
|
||||
// const title = $L('新建%s', e.entityLabel)
|
||||
const title = e.entityLabel
|
||||
const $item = $(`<a class="dropdown-item"><i class="icon zmdi zmdi-${e.icon}"></i>${title}</a>`)
|
||||
$item.on('click', function () {
|
||||
if (e.entity === 'Feeds.relatedRecord') {
|
||||
|
|
66
src/main/resources/web/assets/js/show-styles.js
Normal file
66
src/main/resources/web/assets/js/show-styles.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
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-next-line no-unused-vars
|
||||
class ShowStyles extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="modal rbalert" ref={(c) => (this._$dlg = c)} tabIndex="-1">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header pb-0">
|
||||
<button className="close" type="button" onClick={() => this.hide()}>
|
||||
<span className="zmdi zmdi-close" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="form">
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('别名')}</label>
|
||||
<div className="col-sm-7">
|
||||
<input className="form-control form-control-sm" placeholder={$L('默认')} defaultValue={this.props.label || ''} maxLength="50" ref={(c) => (this._$label = c)} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row footer">
|
||||
<div className="col-sm-7 offset-sm-3">
|
||||
<button className="btn btn-primary btn-space" type="button" onClick={() => this.saveProps()}>
|
||||
{$L('确定')}
|
||||
</button>
|
||||
<a className="btn btn-link btn-space" onClick={() => this.hide()}>
|
||||
{$L('取消')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
$(this._$dlg).modal({ show: true, keyboard: true })
|
||||
}
|
||||
|
||||
show() {
|
||||
$(this._$dlg).modal('show')
|
||||
}
|
||||
|
||||
hide() {
|
||||
$(this._$dlg).modal('hide')
|
||||
}
|
||||
|
||||
saveProps() {
|
||||
const data = {
|
||||
label: $(this._$label).val() || '',
|
||||
}
|
||||
typeof this.props.onConfirm === 'function' && this.props.onConfirm(data)
|
||||
this.hide()
|
||||
}
|
||||
}
|
|
@ -419,9 +419,9 @@ class FormulaCalcWithCode extends FormulaCalc {
|
|||
<a className="dropdown-item" onClick={() => this.handleInput('DATESUB')} title="DATESUB($DATE, $NUMBER[H|D|M|Y])">
|
||||
DATESUB
|
||||
</a>
|
||||
<div className="dropdown-divider"></div>
|
||||
<a className="dropdown-item" target="_blank" href="https://getrebuild.com/docs/admin/triggers#%E5%85%AC%E5%BC%8F%E7%BC%96%E8%BE%91%E5%99%A8">
|
||||
<i className="zmdi zmdi-help icon"></i>
|
||||
<div className="dropdown-divider" />
|
||||
<a className="dropdown-item pointer" target="_blank" href="https://getrebuild.com/docs/admin/triggers#%E5%85%AC%E5%BC%8F%E7%BC%96%E8%BE%91%E5%99%A8">
|
||||
<i className="zmdi zmdi-help icon" />
|
||||
{$L('如何使用函数')}
|
||||
</a>
|
||||
</div>
|
||||
|
|
32
src/main/resources/web/assets/manifest.json
Normal file
32
src/main/resources/web/assets/manifest.json
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/web-manifest-combined.json",
|
||||
"name": "REBUILD Web",
|
||||
"short_name": "REBUILD",
|
||||
"start_url": "/",
|
||||
"background_color": "#eeeeee",
|
||||
"theme_color": "#4285f4",
|
||||
"display": "standalone",
|
||||
"id": "id-rebuild-web",
|
||||
"icons": [
|
||||
{
|
||||
"src": "img/icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icon-256x256.png",
|
||||
"sizes": "256x256",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icon-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -145,7 +145,7 @@
|
|||
<div class="item" data-toggle="dropdown">
|
||||
<a><i class="zmdi zmdi-chevron-down"></i></a>
|
||||
<span></span>
|
||||
<a class="del"><i class="zmdi zmdi-close-circle"></i></a>
|
||||
<a class="del" th:title="${bundle.L('移除')}"><i class="zmdi zmdi-close-circle"></i></a>
|
||||
</div>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-item J_num" data-calc="SUM">[[${bundle.L('求和')}]]</li>
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-6 dash-list">
|
||||
<div class="dash-head">
|
||||
<h4 class="J_dash-select">[[${bundle.L('仪表盘')}]]</h4>
|
||||
<h4 class="J_dash-select" th:title="${bundle.L('切换仪表盘')}">[[${bundle.L('仪表盘')}]]</h4>
|
||||
<div class="dash-action">
|
||||
<a class="zicon J_dash-edit"><i class="zmdi zmdi-settings"></i></a>
|
||||
<a class="zicon J_dash-edit" th:title="${bundle.L('设置')}"><i class="zmdi zmdi-settings"></i></a>
|
||||
<a class="zicon J_dash-new" th:title="${bundle.L('添加仪表盘')}"><i class="zmdi zmdi-plus-circle-o"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
color: #fbbc05;
|
||||
font-size: 5rem;
|
||||
}
|
||||
.zmdi.err497::before {
|
||||
content: '\f119';
|
||||
}
|
||||
|
||||
.error-description > pre:empty {
|
||||
display: none;
|
||||
}
|
||||
|
@ -48,6 +52,7 @@
|
|||
<button class="btn btn-xl btn-space btn-primary" type="button" onclick="location.reload()">[[${bundle.L('重试')}]]</button>
|
||||
<div class="mt-4">
|
||||
<a th:href="${'https://getrebuild.com/report-issue?title=error-page-' + error_code}" target="_blank">[[${bundle.L('报告问题')}]]</a>
|
||||
<span>[[${bundle.L('或联系系统管理员')}]]</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
<div class="card">
|
||||
<div class="card-header" id="headingGroup">
|
||||
<button class="btn" data-toggle="collapse" data-target="#collapseGroup"><i class="icon zmdi zmdi-chevron-right"></i> [[${bundle.L('团队')}]]</button>
|
||||
<a class="add-group admin-show" th:href="@{/admin/bizuser/teams}" th:title="${bundle.L('管理团队')}"><i class="icon zmdi zmdi-settings"></i></a>
|
||||
<a class="add-group admin-show" th:href="@{/admin/bizuser/teams}" th:title="${bundle.L('管理团队')}" target="_blank"><i class="icon zmdi zmdi-settings"></i></a>
|
||||
</div>
|
||||
<div class="collapse" id="collapseGroup">
|
||||
<div class="card-body">
|
||||
|
|
|
@ -130,7 +130,7 @@ public class TestSupport {
|
|||
|
||||
if (!MetadataHelper.containsEntity(TestAllFields)) {
|
||||
Entity2Schema entity2Schema = new Entity2Schema(UserService.ADMIN_USER);
|
||||
String entityName = entity2Schema.createEntity(TestAllFields.toUpperCase(), null, null, false);
|
||||
String entityName = entity2Schema.createEntity(TestAllFields.toUpperCase(), null, null, true);
|
||||
Entity testEntity = MetadataHelper.getEntity(entityName);
|
||||
|
||||
for (DisplayType dt : DisplayType.values()) {
|
||||
|
|
|
@ -10,6 +10,7 @@ package com.rebuild.web;
|
|||
import com.rebuild.TestSupport;
|
||||
import com.rebuild.core.Application;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
@ -29,9 +30,15 @@ class BaseControllerTest extends TestSupport {
|
|||
BaseController c = new BaseController() {
|
||||
};
|
||||
|
||||
ApplicationContext context = Application.getContext();
|
||||
if (!(context instanceof WebApplicationContext)) {
|
||||
LOG.warn("None WebApplicationContext!");
|
||||
return;
|
||||
}
|
||||
|
||||
MockHttpServletRequest request = MockMvcRequestBuilders
|
||||
.get("/user/login?name=a&int=123456&id=" + SIMPLE_USER)
|
||||
.buildRequest(Objects.requireNonNull(((WebApplicationContext) Application.getContext()).getServletContext()));
|
||||
.buildRequest(Objects.requireNonNull(((WebApplicationContext) context).getServletContext()));
|
||||
|
||||
assertEquals(c.getParameter(request, "name"), "a");
|
||||
|
||||
|
|
Loading…
Reference in a new issue