mirror of
https://github.com/getrebuild/rebuild.git
synced 2025-09-30 02:28:49 +08:00
Merge branch 'master' into develop
This commit is contained in:
commit
2ef3c566f4
21 changed files with 253 additions and 138 deletions
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 6d344ca5660799c7d19eea0ad55964c778a8db57
|
||||
Subproject commit 09da8d287be7103eeb3bfe727cdb75d5e19e3bb1
|
|
@ -7,6 +7,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
package com.rebuild.core.configuration.general;
|
||||
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.Query;
|
||||
|
@ -16,59 +17,67 @@ import com.alibaba.fastjson.JSONArray;
|
|||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.configuration.ConfigBean;
|
||||
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.metadata.impl.EasyEntityConfigProps;
|
||||
import com.rebuild.core.support.general.FieldValueHelper;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 列表字段分类数据
|
||||
* 列表字段分类(分组)数据
|
||||
*
|
||||
* @author ZHAO
|
||||
* @since 07/23/2022
|
||||
*/
|
||||
public class DataListCategory {
|
||||
|
||||
public static final DataListCategory instance = new DataListCategory();
|
||||
|
||||
private DataListCategory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity
|
||||
* @param user
|
||||
* @return
|
||||
*/
|
||||
public static JSON datas(Entity entity, ID user) {
|
||||
public JSON datas(Entity entity, ID user) {
|
||||
final Field categoryField = getFieldOfCategory(entity);
|
||||
if (categoryField == null) return null;
|
||||
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(categoryField);
|
||||
EasyField easyField = EasyMetaFactory.valueOf(categoryField);
|
||||
DisplayType dt = easyField.getDisplayType();
|
||||
|
||||
List<Object[]> clist = new ArrayList<>();
|
||||
List<Object[]> dataList = new ArrayList<>();
|
||||
|
||||
if (dt == DisplayType.MULTISELECT || dt == DisplayType.PICKLIST) {
|
||||
ConfigBean[] entries = MultiSelectManager.instance.getPickListRaw(categoryField, true);
|
||||
for (ConfigBean e : entries) {
|
||||
Object id = e.getID("id");
|
||||
if (dt == DisplayType.MULTISELECT) id = e.getLong("mask");
|
||||
|
||||
clist.add(new Object[] { e.getString("text"), id });
|
||||
dataList.add(new Object[] { e.getString("text"), id });
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// TODO 考虑支持更多分组字段类型,例如日期(但要考虑日期格式)
|
||||
|
||||
String sql;
|
||||
if (dt == DisplayType.N2NREFERENCE) {
|
||||
sql = MessageFormat.format(
|
||||
"select distinct referenceId from NreferenceItem where belongEntity = ''{0}'' and belongField = ''{1}''",
|
||||
entity.getName(), categoryField.getName());
|
||||
} else {
|
||||
String wrapField = categoryField.getName();
|
||||
if (dt == DisplayType.DATETIME) {
|
||||
wrapField = String.format("DATE_FORMAT(%s, '%%Y-%%m-%%d')", wrapField);
|
||||
}
|
||||
|
||||
sql = MessageFormat.format(
|
||||
"select distinct {0} from {1} where {0} is not null", categoryField.getName(), entity.getName());
|
||||
"select {0} from {1} where {2} is not null group by {0}",
|
||||
wrapField, entity.getName(), categoryField.getName());
|
||||
}
|
||||
|
||||
Query query = user == null
|
||||
|
@ -76,18 +85,38 @@ public class DataListCategory {
|
|||
: Application.getQueryFactory().createQuery(sql, user);
|
||||
Object[][] array = query.array();
|
||||
|
||||
String cf = EasyMetaFactory.valueOf(entity).getExtraAttr(EasyEntityConfigProps.ADV_LIST_SHOWCATEGORY);
|
||||
String[] ff = cf.split(":");
|
||||
String format = ff.length > 1 ? ff[1] : null;
|
||||
|
||||
Set<Object> unique = new HashSet<>();
|
||||
|
||||
for (Object[] o : array) {
|
||||
Object id = o[0];
|
||||
Object label = FieldValueHelper.getLabelNotry((ID) id);
|
||||
clist.add(new Object[] { label, id });
|
||||
}
|
||||
Object label;
|
||||
|
||||
// TODO 分类数据 code 排序
|
||||
clist.sort(Comparator.comparing(o -> o[0].toString()));
|
||||
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME) {
|
||||
format = StringUtils.defaultIfBlank(format, CalendarUtils.UTC_DATE_FORMAT);
|
||||
if (id instanceof Date) {
|
||||
label = CalendarUtils.format(format, (Date) id);
|
||||
} else {
|
||||
label = id.toString().substring(0, format.length());
|
||||
}
|
||||
id = label;
|
||||
|
||||
} else {
|
||||
label = FieldValueHelper.getLabelNotry((ID) id);
|
||||
}
|
||||
|
||||
if (unique.contains(id)) continue;
|
||||
unique.add(id);
|
||||
|
||||
dataList.add(new Object[] { label, id });
|
||||
}
|
||||
}
|
||||
|
||||
JSONArray res = new JSONArray();
|
||||
for (Object[] o : clist) {
|
||||
for (Object[] o : dataList) {
|
||||
res.add(JSONUtils.toJSONObject(
|
||||
new String[] { "label", "id", "count" },
|
||||
new Object[] { o[0], o[1], 0 } ));
|
||||
|
@ -102,9 +131,10 @@ public class DataListCategory {
|
|||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public static Field getFieldOfCategory(Entity entity) {
|
||||
public Field getFieldOfCategory(Entity entity) {
|
||||
String categoryField = EasyMetaFactory.valueOf(entity).getExtraAttr(EasyEntityConfigProps.ADV_LIST_SHOWCATEGORY);
|
||||
if (StringUtils.isBlank(categoryField) || !entity.containsField(categoryField)) return null;
|
||||
return entity.getField(categoryField);
|
||||
if (categoryField != null) categoryField = categoryField.split(":")[0];
|
||||
if (categoryField != null && entity.containsField(categoryField)) return entity.getField(categoryField);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,22 +189,22 @@ public class ProtocolFilterParser {
|
|||
*/
|
||||
protected String parseCategory(String entity, String value) {
|
||||
Entity rootEntity = MetadataHelper.getEntity(entity);
|
||||
Field classField = DataListCategory.getFieldOfCategory(rootEntity);
|
||||
if (classField == null) return "(9=9)";
|
||||
Field categoryField = DataListCategory.instance.getFieldOfCategory(rootEntity);
|
||||
if (categoryField == null) return "(9=9)";
|
||||
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(classField);
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(categoryField);
|
||||
|
||||
if (dt == DisplayType.MULTISELECT) {
|
||||
return String.format("%s && %d", classField.getName(), ObjectUtils.toInt(value));
|
||||
return String.format("%s && %d", categoryField.getName(), ObjectUtils.toInt(value));
|
||||
} else if (dt == DisplayType.N2NREFERENCE) {
|
||||
return String.format(
|
||||
"exists (select recordId from NreferenceItem where ^%s = recordId and belongField = '%s' and referenceId = '%s')",
|
||||
rootEntity.getPrimaryField().getName(), classField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
rootEntity.getPrimaryField().getName(), categoryField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
} else {
|
||||
return String.format("%s = '%s'", classField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
return String.format("%s = '%s'", categoryField.getName(), StringEscapeUtils.escapeSql(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param relatedExpr
|
||||
* @param mainid
|
||||
|
|
|
@ -57,6 +57,7 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
|
||||
private static final int CODE_STARTING = 600;
|
||||
private static final int CODE_DENIEDMSG = 601;
|
||||
@SuppressWarnings("unused")
|
||||
private static final int CODE_MAINTAIN = 602;
|
||||
private static final int CODE_UNSAFE_USE = 603;
|
||||
|
||||
|
@ -86,11 +87,11 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
request.setAttribute(WebConstants.LOCALE, requestEntry.getLocale());
|
||||
request.setAttribute(WebConstants.$BUNDLE, Application.getLanguage().getBundle(requestEntry.getLocale()));
|
||||
|
||||
final String requestUrl = requestEntry.getRequestUrl();
|
||||
final String requestUri = requestEntry.getRequestUri();
|
||||
|
||||
// 服务暂不可用
|
||||
if (!Application.isReady()) {
|
||||
final boolean isError = requestUrl.endsWith("/error") || requestUrl.contains("/error/");
|
||||
final boolean isError = requestUri.endsWith("/error") || requestUri.contains("/error/");
|
||||
|
||||
// 已安装
|
||||
if (checkInstalled()) {
|
||||
|
@ -104,7 +105,7 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
}
|
||||
}
|
||||
// 未安装
|
||||
else if (!(requestUrl.contains("/setup/") || requestUrl.contains("/commons/theme/") || isError)) {
|
||||
else if (!(requestUri.contains("/setup/") || requestUri.contains("/commons/theme/") || isError)) {
|
||||
sendRedirect(response, "/setup/install", null);
|
||||
return false;
|
||||
} else {
|
||||
|
@ -120,9 +121,9 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
if (requestUser != null) {
|
||||
|
||||
// 管理中心二次验证
|
||||
if (requestUrl.contains("/admin/") && !AppUtils.isAdminVerified(request)) {
|
||||
if (isHtmlRequest(request)) {
|
||||
sendRedirect(response, "/user/admin-verify", requestEntry.getRequestUri());
|
||||
if (requestUri.contains("/admin/") && !AppUtils.isAdminVerified(request)) {
|
||||
if (isHtmlRequest(requestUri, request)) {
|
||||
sendRedirect(response, "/user/admin-verify", requestEntry.getRequestUriWithQuery());
|
||||
} else {
|
||||
response.sendError(HttpStatus.FORBIDDEN.value());
|
||||
}
|
||||
|
@ -134,7 +135,7 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
// User
|
||||
request.setAttribute(WebConstants.$USER, Application.getUserStore().getUser(requestUser));
|
||||
|
||||
if (isHtmlRequest(request)) {
|
||||
if (isHtmlRequest(requestUri, request)) {
|
||||
// Last active
|
||||
Application.getSessionStore().storeLastActive(request);
|
||||
|
||||
|
@ -142,7 +143,7 @@ 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 (!(requestUrl.contains("/admin/") || requestUrl.contains("/setup/"))) {
|
||||
if (!(requestUri.contains("/admin/") || requestUri.contains("/setup/"))) {
|
||||
String asideCollapsed = ServletUtils.readCookie(request, "rb.asideCollapsed");
|
||||
if (BooleanUtils.toBoolean(asideCollapsed)) sideCollapsedClazz += " rb-aside-collapsed";
|
||||
}
|
||||
|
@ -156,14 +157,14 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
if (RebuildConfiguration.getBool(ConfigurationItem.SecurityEnhanced)) skipCheckSafeUse = false;
|
||||
else skipCheckSafeUse = UserHelper.isSuperAdmin(requestUser);
|
||||
|
||||
} else if (!isIgnoreAuth(requestUrl)) {
|
||||
} else if (!isIgnoreAuth(requestUri)) {
|
||||
// 独立验证逻辑
|
||||
if (requestUrl.contains("/filex/")) return true;
|
||||
if (requestUri.contains("/filex/")) return true;
|
||||
|
||||
log.warn("Unauthorized access {}", RebuildWebConfigurer.getRequestUrls(request));
|
||||
|
||||
if (isHtmlRequest(request)) {
|
||||
sendRedirect(response, "/user/login", requestEntry.getRequestUri());
|
||||
if (isHtmlRequest(requestUri, request)) {
|
||||
sendRedirect(response, "/user/login", requestEntry.getRequestUriWithQuery());
|
||||
} else {
|
||||
response.sendError(HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
|
@ -190,7 +191,7 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
|
||||
// 打印处理时间
|
||||
long time = requestEntry == null ? 0 : (System.currentTimeMillis() - requestEntry.getRequestTime());
|
||||
if (time > 1000) {
|
||||
if (time > 1500) {
|
||||
log.warn("Method handle time {} ms. Request URL(s) {}", time, RebuildWebConfigurer.getRequestUrls(request));
|
||||
}
|
||||
|
||||
|
@ -203,38 +204,38 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
if (rbmobLocale != null) return rbmobLocale;
|
||||
|
||||
// 0. Session
|
||||
String havingLocale = (String) ServletUtils.getSessionAttribute(request, AppUtils.SK_LOCALE);
|
||||
String useLocale = (String) ServletUtils.getSessionAttribute(request, AppUtils.SK_LOCALE);
|
||||
|
||||
String urlLocale = request.getParameter("locale");
|
||||
if (StringUtils.isNotBlank(urlLocale) && !urlLocale.equals(havingLocale)) {
|
||||
if (StringUtils.isNotBlank(urlLocale) && !urlLocale.equals(useLocale)) {
|
||||
urlLocale = Application.getLanguage().available(urlLocale);
|
||||
|
||||
if (urlLocale != null) {
|
||||
havingLocale = urlLocale;
|
||||
useLocale = urlLocale;
|
||||
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, havingLocale);
|
||||
ServletUtils.addCookie(response, AppUtils.CK_LOCALE, havingLocale,
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, useLocale);
|
||||
ServletUtils.addCookie(response, AppUtils.CK_LOCALE, useLocale,
|
||||
CommonsCache.TS_DAY * 90, null, StringUtils.defaultIfBlank(AppUtils.getContextPath(), "/"));
|
||||
|
||||
if (Application.devMode()) Application.getLanguage().refresh();
|
||||
}
|
||||
}
|
||||
if (havingLocale != null) return havingLocale;
|
||||
if (useLocale != null) return useLocale;
|
||||
|
||||
// 1. Cookie
|
||||
havingLocale = ServletUtils.readCookie(request, AppUtils.CK_LOCALE);
|
||||
if (havingLocale == null) {
|
||||
useLocale = ServletUtils.readCookie(request, AppUtils.CK_LOCALE);
|
||||
if (useLocale == null) {
|
||||
// 2. User-Local
|
||||
havingLocale = request.getLocale().toString();
|
||||
useLocale = request.getLocale().toString();
|
||||
}
|
||||
|
||||
// 3. Default
|
||||
if ((havingLocale = Application.getLanguage().available(havingLocale)) == null) {
|
||||
havingLocale = RebuildConfiguration.get(ConfigurationItem.DefaultLanguage);
|
||||
if ((useLocale = Application.getLanguage().available(useLocale)) == null) {
|
||||
useLocale = RebuildConfiguration.get(ConfigurationItem.DefaultLanguage);
|
||||
}
|
||||
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, havingLocale);
|
||||
return havingLocale;
|
||||
ServletUtils.setSessionAttribute(request, AppUtils.SK_LOCALE, useLocale);
|
||||
return useLocale;
|
||||
}
|
||||
|
||||
private boolean isIgnoreAuth(String requestUri) {
|
||||
|
@ -242,14 +243,15 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
return true;
|
||||
}
|
||||
|
||||
requestUri = requestUri.split("\\?")[0];
|
||||
requestUri = requestUri.replaceFirst(AppUtils.getContextPath(), "");
|
||||
|
||||
return requestUri.length() < 3
|
||||
|| requestUri.endsWith("/error") || requestUri.contains("/error/")
|
||||
|| requestUri.startsWith("/f/") || requestUri.startsWith("/s/")
|
||||
|| requestUri.startsWith("/setup/")
|
||||
|| requestUri.endsWith("/logout")
|
||||
|| requestUri.startsWith("/f/")
|
||||
|| requestUri.startsWith("/s/")
|
||||
|| requestUri.startsWith("/gw/")
|
||||
|| requestUri.startsWith("/setup/")
|
||||
|| requestUri.startsWith("/language/")
|
||||
|| requestUri.startsWith("/filex/access/")
|
||||
|| requestUri.startsWith("/filex/download/")
|
||||
|
@ -259,12 +261,10 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
|| requestUri.startsWith("/commons/barcode/render")
|
||||
|| requestUri.startsWith("/commons/theme/")
|
||||
|| requestUri.startsWith("/account/user-avatar/")
|
||||
|| requestUri.startsWith("/rbmob/env")
|
||||
|| requestUri.endsWith("/logout");
|
||||
|| requestUri.startsWith("/rbmob/env");
|
||||
}
|
||||
|
||||
private boolean isHtmlRequest(HttpServletRequest request) {
|
||||
String requestUri = request.getRequestURI();
|
||||
private boolean isHtmlRequest(String requestUri, HttpServletRequest request) {
|
||||
if (ServletUtils.isAjaxRequest(request)
|
||||
|| requestUri.contains("/assets/")
|
||||
|| requestUri.contains("/commons/frontjs/")
|
||||
|
@ -285,9 +285,9 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
}
|
||||
|
||||
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);
|
||||
String redirectUrl = AppUtils.getContextPath(url);
|
||||
if (nexturl != null) redirectUrl += "?nexturl=" + CodecUtils.urlEncode(nexturl);
|
||||
response.sendRedirect(redirectUrl);
|
||||
}
|
||||
|
||||
private void checkSafeUse(String ipAddr, String requestUri) throws DefinedException {
|
||||
|
@ -315,22 +315,21 @@ public class RebuildWebInterceptor implements AsyncHandlerInterceptor, InstallSt
|
|||
private static class RequestEntry {
|
||||
final long requestTime;
|
||||
final String requestUri;
|
||||
final String requestUrl;
|
||||
final String requestUriWithQuery;
|
||||
final ID requestUser;
|
||||
final String locale;
|
||||
|
||||
RequestEntry(HttpServletRequest request, String locale) {
|
||||
this.requestTime = System.currentTimeMillis();
|
||||
this.requestUri = request.getRequestURI()
|
||||
+ (request.getQueryString() != null ? ("?" + request.getQueryString()) : "");
|
||||
this.requestUrl = request.getRequestURI();
|
||||
this.requestUri = request.getRequestURI();
|
||||
this.requestUriWithQuery = this.requestUri + (request.getQueryString() == null ? "" : "?" + request.getQueryString());
|
||||
this.requestUser = AppUtils.getRequestUser(request, true);
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return requestUri;
|
||||
return requestUriWithQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ public class ConfigurationController extends BaseController {
|
|||
mv.getModel().put("LicenseType",
|
||||
auth.getString("authType") + " (" + auth.getString("authObject") + ")");
|
||||
mv.getModel().put("Version", Application.VER);
|
||||
mv.getModel().put("SN", "***" + License.SN().substring(12));
|
||||
|
||||
return mv;
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class WidgetController extends BaseController implements ShareTo {
|
|||
|
||||
@GetMapping("widget-category-data")
|
||||
public RespBody getCategoryData(@PathVariable String entity, HttpServletRequest request) {
|
||||
JSON data = DataListCategory.datas(
|
||||
JSON data = DataListCategory.instance.datas(
|
||||
MetadataHelper.getEntity(entity), getRequestUser(request));
|
||||
return RespBody.ok(data);
|
||||
}
|
||||
|
|
|
@ -2216,7 +2216,6 @@
|
|||
"请至少添加 1 个查询字段":"请至少添加 1 个查询字段",
|
||||
"请填写固定值":"请填写固定值",
|
||||
"@%s 退回了你的 %s 审批,请重新审核":"@%s 退回了你的 %s 审批,请重新审核",
|
||||
"显示侧栏分类":"显示侧栏分类",
|
||||
"转换明细记录需选择主记录":"转换明细记录需选择主记录",
|
||||
"@%s 驳回了你的 %s 审批,请重新提交":"@%s 驳回了你的 %s 审批,请重新提交",
|
||||
"如有多个类型请使用逗号或空格分开":"如有多个类型请使用逗号或空格分开",
|
||||
|
@ -2265,7 +2264,7 @@
|
|||
"退回至":"退回至",
|
||||
"提交模式":"提交模式",
|
||||
"启用提交模式必须选择审批流程":"启用提交模式必须选择审批流程",
|
||||
"显示侧栏“分类”":"显示侧栏“分类”",
|
||||
"显示侧栏“分组”":"显示侧栏“分组”",
|
||||
"显示侧栏“常用查询”":"显示侧栏“常用查询”",
|
||||
"仅提交不审批。选择的审批流程至少配置一个审批人,否则会提交失败":"仅提交不审批。选择的审批流程至少配置一个审批人,否则会提交失败",
|
||||
"需要先添加 [记录转换](../transforms) 才能在此处选择":"需要先添加 [记录转换](../transforms) 才能在此处选择",
|
||||
|
@ -2273,7 +2272,6 @@
|
|||
"显示侧栏“图表”":"显示侧栏“图表”",
|
||||
"选择的审批流程至少配置一个审批人":"选择的审批流程至少配置一个审批人",
|
||||
"需要先添加 [审批流程](../approvals) 才能在此处选择":"需要先添加 [审批流程](../approvals) 才能在此处选择",
|
||||
"Category":"分类",
|
||||
"管理员撤销":"管理员撤销",
|
||||
"部分功能可能需要商业版才能正常运行":"部分功能可能需要商业版才能正常运行",
|
||||
"默认大小":"默认大小",
|
||||
|
@ -2379,5 +2377,8 @@
|
|||
"APP SECRET 已重置":"APP SECRET 已重置",
|
||||
"修改 API 秘钥":"修改 API 秘钥",
|
||||
"自动合并单元格":"自动合并单元格",
|
||||
"重置后第三方应用需更换新的 APP SECRET 使用":"重置后第三方应用需更换新的 APP SECRET 使用"
|
||||
"重置后第三方应用需更换新的 APP SECRET 使用":"重置后第三方应用需更换新的 APP SECRET 使用",
|
||||
"分组":"分组",
|
||||
"字段格式":"字段格式",
|
||||
"分组字段":"分组字段"
|
||||
}
|
||||
|
|
|
@ -44,6 +44,12 @@
|
|||
.form-group .switch-button-xs {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.advListShowCategory-set {
|
||||
border-radius: 2px;
|
||||
border: 1px solid #eee;
|
||||
padding: 15px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -247,8 +247,12 @@ const _fieldsMapping = (columns, fields) => {
|
|||
|
||||
const $tbody = $('#fieldsMapping tbody').empty()
|
||||
$(columns).each(function (idx, item) {
|
||||
let L = _LETTERS[idx]
|
||||
if (idx > 25) L = `A${_LETTERS[idx - 26] || 'X'}` // AA
|
||||
if (idx > 51) L = `B${_LETTERS[idx - 52] || 'X'}` // BA
|
||||
|
||||
const $tr = $(`<tr data-col="${idx}"></tr>`).appendTo($tbody)
|
||||
$(`<td><em>${_LETTERS[idx] || _LETTERS[idx - 26]}1</em> ${item || $L('空')}<i class="zmdi zmdi-arrow-right"></i></td>`).appendTo($tr)
|
||||
$(`<td><em>${L}</em> ${item || $L('空')}<i class="zmdi zmdi-arrow-right"></i></td>`).appendTo($tr)
|
||||
const $td = $('<td></td>').appendTo($tr)
|
||||
const $clone = $fieldSelect.clone().appendTo($td)
|
||||
$('<td class="pl-3"></td>').appendTo($tr)
|
||||
|
|
|
@ -12,10 +12,10 @@ const _ENTITIES = {
|
|||
|
||||
$(document).ready(() => {
|
||||
$.get('/commons/metadata/entities?detail=true', (res) => {
|
||||
$(res.data).each(function () {
|
||||
$(`<option value="${this.name}">${this.label}</option>`).appendTo('#belongEntity')
|
||||
_ENTITIES[this.name] = this.label
|
||||
})
|
||||
res.data && res.data.forEach((item) => (_ENTITIES[item.name] = item.label))
|
||||
for (let name in _ENTITIES) {
|
||||
$(`<option value="${name}">${_ENTITIES[name]}</option>`).appendTo('#belongEntity')
|
||||
}
|
||||
|
||||
renderRbcomp(<DataList />, 'react-list', function () {
|
||||
RbListPage._RbList = this._List
|
||||
|
|
|
@ -12,10 +12,7 @@ const _ENTITIES = {
|
|||
|
||||
$(document).ready(() => {
|
||||
$.get('/commons/metadata/entities?detail=true', (res) => {
|
||||
$(res.data).each(function () {
|
||||
_ENTITIES[this.name] = this.label
|
||||
})
|
||||
|
||||
res.data && res.data.forEach((item) => (_ENTITIES[item.name] = item.label))
|
||||
for (let name in _ENTITIES) {
|
||||
$(`<option value="${name}">${_ENTITIES[name]}</option>`).appendTo('#belongEntity')
|
||||
}
|
||||
|
|
|
@ -44,6 +44,10 @@ useEditComp = function (name) {
|
|||
</select>
|
||||
)
|
||||
} else if ('PasswordPolicy' === name) {
|
||||
// 借用贵宝地
|
||||
_toggleImage('.applogo')
|
||||
_toggleImage('.bgimg')
|
||||
|
||||
return (
|
||||
<select className="form-control form-control-sm">
|
||||
<option value="1">{$L('低 (最低6位,无字符类型限制)')}</option>
|
||||
|
@ -52,10 +56,6 @@ useEditComp = function (name) {
|
|||
</select>
|
||||
)
|
||||
} else if ('DefaultLanguage' === name) {
|
||||
// 借用贵宝地
|
||||
_toggleImage('.applogo')
|
||||
_toggleImage('.bgimg')
|
||||
|
||||
const options = []
|
||||
for (let k in wpc._LANGS) {
|
||||
options.push(
|
||||
|
|
|
@ -162,7 +162,7 @@ class ChartIndex extends BaseChart {
|
|||
|
||||
_resize() {
|
||||
const ch = $(this._$chart).height()
|
||||
const zoom = ch > 100 ? (ch > 330 ? 2.831 : 1.3) : 1
|
||||
const zoom = ch > 100 ? (ch > 330 ? 2 : 1.3) : 1
|
||||
$(this._$chart).find('strong').css('zoom', zoom)
|
||||
|
||||
// const $text = $(this._$chart).find('strong')
|
||||
|
|
|
@ -99,7 +99,8 @@ function modeSave(newOption, next) {
|
|||
})
|
||||
}
|
||||
|
||||
const CLASS_TYPES = ['PICKLIST', 'MULTISELECT', 'CLASSIFICATION', 'REFERENCE', 'N2NREFERENCE']
|
||||
// const CATE_TYPES = ['PICKLIST', 'MULTISELECT', 'CLASSIFICATION', 'DATE', 'DATETIME', 'REFERENCE', 'N2NREFERENCE']
|
||||
const CATE_TYPES = ['PICKLIST', 'MULTISELECT', 'CLASSIFICATION', 'REFERENCE', 'N2NREFERENCE']
|
||||
|
||||
// 模式选项
|
||||
class DlgMode1Option extends RbFormHandler {
|
||||
|
@ -109,7 +110,7 @@ class DlgMode1Option extends RbFormHandler {
|
|||
<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">
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListHideFilters" defaultChecked={wpc.extConfig && !wpc.extConfig.advListHideFilters} />
|
||||
<span>
|
||||
|
@ -119,8 +120,8 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</div>
|
||||
</div>
|
||||
<div className="form-group row bosskey-show">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“分类”')}</label>
|
||||
<div className="col-sm-7">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“分组”')}</label>
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListShowCategory" defaultChecked={wpc.extConfig && wpc.extConfig.advListShowCategory} />
|
||||
<span>
|
||||
|
@ -128,23 +129,41 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</span>
|
||||
</div>
|
||||
<div className="clearfix"></div>
|
||||
<div className={`J_advListShowCategory mt-2 ${this.state.advListShowCategory ? '' : 'hide'}`}>
|
||||
<select className="form-control form-control-sm">
|
||||
{this.state.advListShowCategoryFields &&
|
||||
this.state.advListShowCategoryFields.map((item) => {
|
||||
return (
|
||||
<option key={item.name} value={item.name}>
|
||||
{item.label}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
<div className={`advListShowCategory-set ${this.state.advListShowCategory ? '' : 'hide'}`}>
|
||||
<div className="row">
|
||||
<div className="col-8">
|
||||
<label className="mb-1">{$L('分组字段')}</label>
|
||||
<select className="form-control form-control-sm">
|
||||
{this.state.advListShowCategoryFields &&
|
||||
this.state.advListShowCategoryFields.map((item) => {
|
||||
return (
|
||||
<option key={item.name} value={item.name}>
|
||||
{item.label}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
<div className={`col-4 pl-0 ${this.state.advListShowCategoryFormats ? '' : 'hide'}`}>
|
||||
<label className="mb-1">{$L('字段格式')}</label>
|
||||
<select className="form-control form-control-sm" disabled>
|
||||
{this.state.advListShowCategoryFormats &&
|
||||
this.state.advListShowCategoryFormats.map((item) => {
|
||||
return (
|
||||
<option key={item[0]} value={item[0]}>
|
||||
{item[1]}
|
||||
</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示侧栏“图表”')}</label>
|
||||
<div className="col-sm-7">
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListHideCharts" defaultChecked={wpc.extConfig && !wpc.extConfig.advListHideCharts} />
|
||||
<span>
|
||||
|
@ -155,7 +174,7 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</div>
|
||||
<div className="form-group row bosskey-show">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('显示顶部查询面板')}</label>
|
||||
<div className="col-sm-7">
|
||||
<div className="col-sm-9">
|
||||
<div className="switch-button switch-button-xs">
|
||||
<input type="checkbox" id="advListFilterPane" defaultChecked={wpc.extConfig && wpc.extConfig.advListFilterPane} />
|
||||
<span>
|
||||
|
@ -165,7 +184,7 @@ class DlgMode1Option extends RbFormHandler {
|
|||
</div>
|
||||
</div>
|
||||
<div className="form-group row footer">
|
||||
<div className="col-sm-7 offset-sm-3" ref={(c) => (this._btns = c)}>
|
||||
<div className="col-sm-9 offset-sm-3" ref={(c) => (this._btns = c)}>
|
||||
<button className="btn btn-primary" type="button" onClick={this.save}>
|
||||
{$L('确定')}
|
||||
</button>
|
||||
|
@ -180,8 +199,9 @@ class DlgMode1Option extends RbFormHandler {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
let $catFields, $catFormats
|
||||
|
||||
const that = this
|
||||
let $class2
|
||||
$('#advListShowCategory').on('change', function () {
|
||||
if ($val(this)) {
|
||||
that.setState({ advListShowCategory: true })
|
||||
|
@ -189,19 +209,63 @@ class DlgMode1Option extends RbFormHandler {
|
|||
that.setState({ advListShowCategory: null })
|
||||
}
|
||||
|
||||
if (!$class2) {
|
||||
$class2 = $('.J_advListShowCategory select')
|
||||
if (!$catFields) {
|
||||
$catFields = $('.advListShowCategory-set select:eq(0)')
|
||||
$catFormats = $('.advListShowCategory-set select:eq(1)')
|
||||
|
||||
$.get(`/commons/metadata/fields?entity=${wpc.entityName}&deep=2`, (res) => {
|
||||
const _data = []
|
||||
res.data.forEach((item) => {
|
||||
if (CLASS_TYPES.includes(item.type)) _data.push(item)
|
||||
})
|
||||
res.data &&
|
||||
res.data.forEach((item) => {
|
||||
if (CATE_TYPES.includes(item.type) && !(item.name.includes('owningDept.') || item.name.includes('owningUser.'))) {
|
||||
_data.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
// FIELD:[FORMAT]
|
||||
let set = wpc.extConfig && wpc.extConfig.advListShowCategory ? wpc.extConfig.advListShowCategory : null
|
||||
if (set) set = set.split(':')
|
||||
|
||||
wpc.extConfig.advListShowCategory
|
||||
that.setState({ advListShowCategoryFields: _data }, () => {
|
||||
$class2
|
||||
.select2({ placeholder: $L('选择分类字段') })
|
||||
.val((wpc.extConfig && wpc.extConfig.advListShowCategory) || null)
|
||||
.trigger('change')
|
||||
$catFields
|
||||
.select2({
|
||||
placeholder: $L('选择分类字段'),
|
||||
allowClear: false,
|
||||
})
|
||||
.on('change', () => {
|
||||
const s = $catFields.val()
|
||||
const found = _data.find((x) => x.name === s)
|
||||
|
||||
let formats
|
||||
if (found && found.type === 'CLASSIFICATION') {
|
||||
formats = [
|
||||
[0, $L('%d 级分类', 1)],
|
||||
[1, $L('%d 级分类', 2)],
|
||||
[2, $L('%d 级分类', 3)],
|
||||
[3, $L('%d 级分类', 4)],
|
||||
]
|
||||
} else if (found && (found.type === 'DATE' || found.type === 'DATETIME')) {
|
||||
formats = [
|
||||
['yyyy', 'YYYY'],
|
||||
['yyyy-MM', 'YYYY-MM'],
|
||||
['yyyy-MM-dd', 'YYYY-MM-DD'],
|
||||
]
|
||||
}
|
||||
|
||||
that.setState({ advListShowCategoryFormats: formats }, () => {
|
||||
$catFormats.val(null).trigger('change')
|
||||
})
|
||||
})
|
||||
|
||||
$catFormats.select2({ placeholder: $L('默认') })
|
||||
|
||||
if (set) {
|
||||
$catFields.val(set[0]).trigger('change')
|
||||
setTimeout(() => {
|
||||
if (set[1]) $catFormats.val(set[1]).trigger('change')
|
||||
}, 200)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -216,10 +280,13 @@ class DlgMode1Option extends RbFormHandler {
|
|||
const o = {
|
||||
advListHideFilters: !$val('#advListHideFilters'),
|
||||
advListHideCharts: !$val('#advListHideCharts'),
|
||||
advListShowCategory: this.state.advListShowCategory ? $val('.J_advListShowCategory select') : null,
|
||||
advListFilterPane: $val('#advListFilterPane'),
|
||||
}
|
||||
|
||||
if (this.state.advListShowCategory) {
|
||||
o.advListShowCategory = `${$val('.advListShowCategory-set select:eq(0)')}:${$val('.advListShowCategory-set select:eq(1)') || ''}`
|
||||
}
|
||||
|
||||
this.disabled(true)
|
||||
modeSave(o, () => {
|
||||
this.hide()
|
||||
|
|
|
@ -112,7 +112,7 @@ class RbFormModal extends React.Component {
|
|||
const FORM = (
|
||||
<RbForm entity={entity} id={id} rawModel={formModel} $$$parent={this}>
|
||||
{formModel.elements.map((item) => {
|
||||
return detectElement(item)
|
||||
return detectElement(item, entity)
|
||||
})}
|
||||
</RbForm>
|
||||
)
|
||||
|
@ -265,8 +265,7 @@ class RbForm extends React.Component {
|
|||
let _ProTable
|
||||
if (window._CustomizedForms) {
|
||||
_ProTable = window._CustomizedForms.useProTable(this.props.entity, this)
|
||||
// 不显示
|
||||
if (_ProTable === false) return null
|
||||
if (_ProTable === false) return null // 不显示
|
||||
}
|
||||
|
||||
const that = this
|
||||
|
@ -2402,8 +2401,13 @@ class RbFormDivider extends React.Component {
|
|||
}
|
||||
|
||||
// 确定元素类型
|
||||
var detectElement = function (item) {
|
||||
if (!item.key) item.key = 'field-' + (item.field === TYPE_DIVIDER ? $random() : item.field)
|
||||
var detectElement = function (item, entity) {
|
||||
if (!item.key) item.key = `field-${item.field === TYPE_DIVIDER ? $random() : item.field}`
|
||||
|
||||
if (entity && window._CustomizedForms) {
|
||||
const c = window._CustomizedForms.useFormElement(entity, item)
|
||||
if (c) return c
|
||||
}
|
||||
|
||||
if (item.type === 'TEXT' || item.type === 'SERIES') {
|
||||
return <RbFormText {...item} />
|
||||
|
|
|
@ -278,14 +278,17 @@ var _initNav = function () {
|
|||
$sub.toggleClass('visible')
|
||||
$currsntSubnav = $this
|
||||
$this.find('a').eq(0).tooltip('hide')
|
||||
$('.left-sidebar-scroll').perfectScrollbar('update')
|
||||
|
||||
if ($sub.hasClass('visible')) $this.addClass('open')
|
||||
else $this.removeClass('open')
|
||||
|
||||
$('.left-sidebar-scroll').perfectScrollbar('update')
|
||||
})
|
||||
|
||||
$('.sidebar-elements li.parent .sub-menu').on('click', function (e) {
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
$(document.body).on('click', function () {
|
||||
closeSubnav()
|
||||
if (isOffcanvas) {
|
||||
|
|
|
@ -58,7 +58,7 @@ class RbViewForm extends React.Component {
|
|||
{res.data.elements.map((item) => {
|
||||
if (item.field !== TYPE_DIVIDER) viewData[item.field] = item.value
|
||||
item.$$$parent = this
|
||||
return detectViewElement(item)
|
||||
return detectViewElement(item, this.props.entity)
|
||||
})}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
@ -163,12 +163,11 @@ class RbViewForm extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
const detectViewElement = function (item) {
|
||||
const detectViewElement = function (item, entity) {
|
||||
if (!window.detectElement) throw 'detectElement undef'
|
||||
item.onView = true
|
||||
item.editMode = false
|
||||
// item.key = `col-${item.field === TYPE_DIVIDER ? $random() : item.field}`
|
||||
return window.detectElement(item)
|
||||
return window.detectElement(item, entity)
|
||||
}
|
||||
|
||||
const _renderError = (message) => {
|
||||
|
|
|
@ -250,10 +250,18 @@ class ContentFieldWriteback extends ActionContentSpec {
|
|||
}
|
||||
})
|
||||
|
||||
// fix: GitHub#491
|
||||
let sfLast = $(this._$sourceField).val()
|
||||
sfLast = sourceFields.find((x) => x.name === sfLast)
|
||||
|
||||
this.setState({ targetField: null, sourceFields: sourceFields }, () => {
|
||||
if (sourceFields.length > 0) $(this._$sourceField).val(sourceFields[0].name)
|
||||
if (!sfLast && sourceFields.length > 0) sfLast = sourceFields[0]
|
||||
|
||||
// 强制销毁后再渲染
|
||||
this.setState({ targetField: targetField })
|
||||
this.setState({ targetField: targetField }, () => {
|
||||
if (sfLast) $(this._$sourceField).val(sfLast.name)
|
||||
$(this._$sourceField).trigger('change')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -71,11 +71,7 @@
|
|||
<table class="table table-bordered table-sm table-hover">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="30%">SN</th>
|
||||
<td>[[${T(com.rebuild.core.support.License).SN()}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th width="30%">Version</th>
|
||||
<td>[[${T(com.rebuild.core.Application).VER}]]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class="tab-container">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item" th:if="${advListHideFilters != 'true'}"><a class="nav-link" href="#asideFilters" data-toggle="tab">[[${bundle.L('常用查询')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('Category')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('分组')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListHideCharts != 'true'}"><a class="nav-link J_load-charts" href="#asideWidgets" data-toggle="tab">[[${bundle.L('图表')}]]</a></li>
|
||||
</ul>
|
||||
<div class="tab-content rb-scroller">
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class="tab-container">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item" th:if="${advListHideFilters != 'true'}"><a class="nav-link" href="#asideFilters" data-toggle="tab">[[${bundle.L('常用查询')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('Category')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListShowCategory}"><a class="nav-link J_load-category" href="#asideCategory" data-toggle="tab">[[${bundle.L('分组')}]]</a></li>
|
||||
<li class="nav-item" th:if="${advListHideCharts != 'true'}"><a class="nav-link J_load-charts" href="#asideWidgets" data-toggle="tab">[[${bundle.L('图表')}]]</a></li>
|
||||
</ul>
|
||||
<div class="tab-content rb-scroller">
|
||||
|
|
Loading…
Add table
Reference in a new issue