Merge branch 'master' into develop

This commit is contained in:
RB 2022-11-22 00:07:02 +08:00
commit 2ef3c566f4
21 changed files with 253 additions and 138 deletions

2
@rbv

@ -1 +1 @@
Subproject commit 6d344ca5660799c7d19eea0ad55964c778a8db57
Subproject commit 09da8d287be7103eeb3bfe727cdb75d5e19e3bb1

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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 使用",
"分组":"分组",
"字段格式":"字段格式",
"分组字段":"分组字段"
}

View file

@ -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>

View file

@ -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)

View file

@ -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

View file

@ -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')
}

View file

@ -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(

View file

@ -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')

View file

@ -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()

View file

@ -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} />

View file

@ -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) {

View file

@ -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) => {

View file

@ -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')
})
})
}

View file

@ -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>

View file

@ -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">

View file

@ -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">