List1 view (#697)

* style: list1-view

* Update notifications.js

* be: _onFieldValueChangeCall timer

* feat: entity-excel

* feat: entity from excel

* field-new2

* $select2MatcherAll

* select2 icon

* remove _onFieldValueChangeCall timer
This commit is contained in:
REBUILD 企业管理系统 2023-12-20 16:02:00 +08:00 committed by GitHub
parent 45d7783761
commit f3b117f864
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1078 additions and 635 deletions

2
@rbv

@ -1 +1 @@
Subproject commit 1055750e8b4add3af4d1ce51a3f1d73f1643d99a
Subproject commit 8d66ac27ecebf958e3675fd44c39a9d6670d2ed4

View file

@ -505,8 +505,8 @@ public class NavBuilder extends NavManager {
StringBuilder topNavHtml = new StringBuilder();
for (Object[] nd : topNav) {
String url = AppUtils.getContextPath("/app/home?n=" + nd[0]);
if (nd[1] != null) url += "&d=" + nd[1];
String url = AppUtils.getContextPath("/app/home?def=" + nd[0]);
if (nd[1] != null) url += ":" + nd[1];
topNavHtml.append(String.format(
"<li class=\"nav-item\" data-id=\"%s\"><a class=\"nav-link text-ellipsis\" href=\"%s\">%s</a></li>", nd[0], url, nd[2]));
}

View file

@ -56,15 +56,12 @@ public class Entity2Schema extends Field2Schema {
* @return Returns 实体名称
*/
public String createEntity(String entityName, String entityLabel, String comments, String mainEntity, boolean haveNameField, boolean haveSeriesField) {
entityName = StringUtils.trim(entityName);
entityLabel = StringUtils.trim(entityLabel);
if (!License.isCommercial() && MetadataHelper.getEntities().length >= 100) {
throw new NeedRbvException(Language.L("实体数量超出免费版限制"));
}
entityLabel = CommonsUtils.maxstr(StringUtils.trim(entityLabel), 40);
entityName = StringUtils.trim(entityName);
entityLabel = StringUtils.trim(entityLabel);
if (entityName != null) {
if (MetadataHelper.containsEntity(entityName)) {

View file

@ -0,0 +1,70 @@
package com.rebuild.core.metadata.impl;
import cn.devezhao.persist4j.Entity;
import cn.devezhao.persist4j.engine.ID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.privileges.UserHelper;
import com.rebuild.core.support.i18n.Language;
import com.rebuild.utils.JSONUtils;
import com.rebuild.utils.RbAssert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
/**
* EXCEL 导入实体
*
* @author RB
* @see CopyEntity
* @since 2023/12/18
*/
@Slf4j
public class ExcelEntity extends Entity2Schema {
/**
* @param entityName
* @param fields
* @return
*/
public String imports(String entityName, JSONArray fields) {
final ID user = getUser();
RbAssert.isAllow(UserHelper.isSuperAdmin(user), Language.L("仅超级管理员可操作"));
// 1.实体
String uniqueEntityName = createEntity(null, entityName, null, null, false, false);
Entity entityNew = MetadataHelper.getEntity(uniqueEntityName);
// 2.字段
try {
for (Object o : fields) {
JSONArray item = (JSONArray) o;
String name = item.getString(0);
String type = item.getString(1);
String refEntityOrClass = item.size() > 2 ? item.getString(2) : null;
JSON extConfig = null;
if ("CLASSIFICATION".equals(type)) {
Assert.notNull(refEntityOrClass, "[refEntityOrClass] cannot be null");
ID dataId = ID.valueOf(refEntityOrClass);
extConfig = JSONUtils.toJSONObject(EasyFieldConfigProps.CLASSIFICATION_USE, dataId);
refEntityOrClass = null;
}
createField(entityNew, name, DisplayType.valueOf(type), null, refEntityOrClass, extConfig);
}
} catch (Throwable ex) {
// DROP
dropEntity(entityNew, true);
if (ex instanceof MetadataModificationException) {
throw (MetadataModificationException) ex;
}
throw new MetadataModificationException(Language.L("无法导入实体 : %s", ex.getLocalizedMessage()));
}
return uniqueEntityName;
}
}

View file

@ -100,7 +100,7 @@ public class Field2Schema extends SetUser {
* @return
*/
public String createField(Entity entity, String fieldLabel, String fieldName, DisplayType type, String comments, String refEntity, JSON extConfig) {
fieldLabel = StringUtils.trim(fieldLabel);
fieldLabel = CommonsUtils.maxstr(StringUtils.trim(fieldLabel), 40);
fieldName = StringUtils.trim(fieldName);
if (StringUtils.length(fieldName) < 4) fieldName = toPinyinName(fieldLabel);

View file

@ -100,6 +100,7 @@ public abstract class ObservableService extends Observable implements ServiceSpe
if (countObservers() > 0) {
deleted = EntityHelper.forUpdate(recordId, currentUser, Boolean.FALSE);
deleted = recordSnap(deleted, true);
if (deleted == null) return 0;
// 删除前触发做一些状态保持
setChanged();

View file

@ -30,6 +30,7 @@ public class OverOperatorType {
* 日期加
*/
static class DateAdd extends AbstractFunction {
private static final long serialVersionUID = -7871678038170332371L;
@Override
public String getName() {
return OperatorType.ADD.getToken();
@ -54,6 +55,7 @@ public class OverOperatorType {
* 日期减
*/
static class DateSub extends AbstractFunction {
private static final long serialVersionUID = 8208361199770129766L;
@Override
public String getName() {
return OperatorType.SUB.getToken();

View file

@ -82,9 +82,8 @@ public class CommonsUtils {
* @return
*/
public static String maxstr(String text, int maxLength) {
if (text.length() > maxLength) {
return text.substring(0, maxLength);
}
if (text == null) return null;
if (text.length() > maxLength) return text.substring(0, maxLength);
return text;
}

View file

@ -93,11 +93,12 @@ public class DataImportController extends BaseController {
}
DataFileParser parser;
int count = -1;
int count;
List<Cell[]> preview;
try {
parser = new DataFileParser(tmp);
preview = parser.parse(11);
preview = parser.parse(101);
count = parser.getRowsCount();
} catch (Exception ex) {
log.error("Parse excel error : " + file, ex);
return RespBody.error(Language.L("无法解析数据,请检查数据文件格式"));

View file

@ -13,6 +13,7 @@ import cn.devezhao.persist4j.Field;
import cn.devezhao.persist4j.Record;
import cn.devezhao.persist4j.engine.ID;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rebuild.api.RespBody;
import com.rebuild.core.Application;
@ -30,6 +31,7 @@ import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.metadata.impl.CopyEntity;
import com.rebuild.core.metadata.impl.EasyEntityConfigProps;
import com.rebuild.core.metadata.impl.Entity2Schema;
import com.rebuild.core.metadata.impl.ExcelEntity;
import com.rebuild.core.metadata.impl.MetaEntityService;
import com.rebuild.core.privileges.UserHelper;
import com.rebuild.core.rbstore.MetaSchemaGenerator;
@ -356,4 +358,14 @@ public class MetaEntityController extends EntityController {
mv.getModel().put("entities", entities);
return mv;
}
@PostMapping("entity/entity-excel")
public RespBody entityExcelEvalft(HttpServletRequest request) {
final JSON post = ServletUtils.getRequestJson(request);
String entityLabel = ((JSONObject) post).getString("entityLabel");
JSONArray fields = ((JSONObject) post).getJSONArray("fields");
String entityName = new ExcelEntity().imports(entityLabel, fields);
return RespBody.ok(entityName);
}
}

View file

@ -16,11 +16,11 @@ import com.rebuild.core.support.RebuildConfiguration;
import com.rebuild.utils.AppUtils;
import com.rebuild.utils.CommonsUtils;
import com.rebuild.web.BaseController;
import com.rebuild.web.IdParam;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
@ -87,11 +87,13 @@ public class CommonPageView extends BaseController {
}
@GetMapping("/app/home")
public void appHome(@IdParam(name = "n", required = false) ID useNav,
@IdParam(name = "d", required = false) ID useDash,
public void appHome(@RequestParam(name = "def", required = false) String def,
HttpServletResponse response) throws IOException {
addCookie("AppHome.Nav", useNav, response);
addCookie("AppHome.Dash", useDash, response);
if (def != null && def.length() >= 20) {
String[] defs = def.split(":");
addCookie("AppHome.Nav", ID.isId(defs[0]) ? ID.valueOf(defs[0]) : null, response);
addCookie("AppHome.Dash", defs.length > 1 && ID.isId(defs[1]) ? ID.valueOf(defs[1]) : null, response);
}
response.sendRedirect("../dashboard/home");
}

View file

@ -70,6 +70,33 @@
.new-entity .card.entity .card-body .ml-7 .text-muted {
display: none;
}
.entity-new2 .dialog-footer {
margin: 15px -35px 10px;
padding-top: 25px;
}
.entity-new2 .init-models {
margin-left: -10px;
margin-right: -10px;
}
.table.table-excel th,
.table.table-excel td {
padding: 3px;
border-width: 1px;
color: #222;
max-width: 200px;
}
.table.table-excel th {
text-align: center;
background-color: #dee2e6;
color: #444;
}
.table.table-excel .form-control {
width: 100%;
min-width: 140px;
/* padding: 4px; */
/* height: auto !important; */
}
</style>
</head>
<body>
@ -113,6 +140,9 @@
isSuperAdmin: '[[${isSuperAdmin}]]' === 'true',
}
</script>
<script th:src="@{/assets/js/admin/init-models.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/field-type.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/entity-new2.js}" type="text/babel"></script>
<script type="text/babel">
$(document).ready(function () {
const NO_TAG = '__'
@ -138,6 +168,7 @@
if (!this.builtin) render_entity(this)
})
let _EntityNew2
const $new = render_entity({
icon: 'plus',
entityLabel: $L('添加实体'),
@ -147,9 +178,20 @@
.find('a.card')
.attr('href', 'javascript:;')
.click(function () {
if (window.__PageConfig.isSuperAdmin) RbModal.create('/p/admin/metadata/entity-new', $L('添加实体'))
else RbHighbar.error('仅超级管理员可添加实体')
if (window.__PageConfig.isSuperAdmin) {
if (_EntityNew2) {
_EntityNew2.show()
} else {
renderRbcomp(<EntityNew2 />, null, function () {
_EntityNew2 = this
})
}
} else {
RbHighbar.error('仅超级管理员可添加实体')
}
})
.find('.more-action')
.remove()
delete groups[NO_TAG]
@ -169,12 +211,13 @@
href: `entity/${item.entityName}/base`,
title: item.comments || null,
})
$t.find('.icon').addClass(`zmdi-${item.icon}`)
$t.find('.icon:eq(0)').addClass(`zmdi-${item.icon}`)
$t.find('span').text(item.entityLabel)
$t.find('p').text(item.comments || '-')
if (item.comments) $t.find('p').text(item.comments)
else $t.find('p').html('&nbsp;')
if (item.builtin) $(`<i class="badge badge-pill badge-secondary font-weight-light">${$L('内置')}</i>`).appendTo($t.find('a.card'))
if (!!item.detailEntity) $(`<i class="badge badge-pill badge-secondary font-weight-light">${$L('明细')}</i>`).appendTo($t.find('a.card'))
if (item.detailEntity) $(`<i class="badge badge-pill badge-secondary font-weight-light">${$L('明细')}</i>`).appendTo($t.find('a.card'))
return $t
}
</script>

View file

@ -1,132 +0,0 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:replace="~{/_include/header}" />
<title>[[${bundle.L('添加实体')}]]</title>
<style>
.text-muted.desc {
max-width: 80%;
}
.init-models {
margin: 0 -10px;
}
.dialog-footer {
margin: 15px -40px 0;
padding-top: 20px;
}
</style>
</head>
<body class="dialog">
<div class="main-content pt-1">
<div class="tab-container">
<ul class="nav nav-tabs">
<li class="nav-item"><a class="nav-link active" href="#MANUAL" data-toggle="tab">[[${bundle.L('手动')}]]</a></li>
<li class="nav-item">
<a class="nav-link" href="#COPY" data-toggle="tab">[[${bundle.L('复制')}]]</a>
</li>
<li class="nav-item">
<a class="nav-link J_imports" href="#IMPORTS" data-toggle="tab"> <i class="icon zmdi zmdi-cloud-outline-alt"></i> [[${bundle.L('从 RB 仓库导入')}]] </a>
</li>
</ul>
<div class="tab-content m-0 pb-0">
<div class="tab-pane active" id="MANUAL">
<div class="form">
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('实体名称')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="entityLabel" maxlength="40" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('备注')}]]</label>
<div class="col-sm-7">
<textarea class="form-control form-control-sm row2x" id="comments" maxlength="100" th:placeholder="${bundle.L('(选填)')}"></textarea>
</div>
</div>
<div class="form-group row pt-2">
<label class="col-sm-3 col-form-label text-sm-right"></label>
<div class="col-sm-7">
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input class="custom-control-input" type="checkbox" id="nameField" />
<span class="custom-control-label">[[${bundle.L('添加一个名称字段')}]]</span>
</label>
</div>
</div>
<div class="form-group row pt-0">
<label class="col-sm-3 col-form-label text-sm-right"></label>
<div class="col-sm-7">
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input class="custom-control-input" type="checkbox" id="seriesField" />
<span class="custom-control-label">[[${bundle.L('添加一个自动编号字段')}]]</span>
</label>
</div>
</div>
<div class="form-group row pt-0">
<label class="col-sm-3 col-form-label text-sm-right"></label>
<div class="col-sm-7">
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input class="custom-control-input" type="checkbox" id="isDetail" />
<span class="custom-control-label">
[[${bundle.L('这是明细实体')}]]
<i class="zmdi zmdi-help zicon" data-toggle="tooltip" th:title="${bundle.L('通过明细实体可以更好的组织业务关系。例如订单明细通常依附于订单,而非独立存在')}"></i>
</span>
</label>
</div>
</div>
<div class="form-group row J_mainEntity hide">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('选择主实体')}]]</label>
<div class="col-sm-7">
<select class="form-control form-control-sm" id="mainEntity"></select>
</div>
</div>
<div class="form-group row footer">
<div class="col-sm-7 offset-sm-3">
<button class="btn btn-primary new" type="button">[[${bundle.L('确定')}]]</button>
<button class="btn btn-link" type="button" onclick="parent.RbModal.hide()">[[${bundle.L('取消')}]]</button>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="COPY">
<div class="form">
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('复制哪个实体')}]]</label>
<div class="col-sm-7">
<select class="form-control form-control-sm" id="copySourceEntity"></select>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('实体名称')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="newEntityLabel" maxlength="40" />
</div>
</div>
<div class="form-group row hide J_newDetailLabel">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('明细实体名称')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="newDetailLabel" maxlength="40" th:placeholder="${bundle.L('(选填)')}" />
<p class="form-text">[[${bundle.L('不填写则不复制明细实体')}]]</p>
</div>
</div>
<div class="form-group row footer">
<div class="col-sm-7 offset-sm-3">
<button class="btn btn-primary copy" type="button">[[${bundle.L('确定')}]]</button>
<button class="btn btn-link" type="button" onclick="parent.RbModal.hide()">[[${bundle.L('取消')}]]</button>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="IMPORTS">
<div id="metaschemas"></div>
<div class="mt-2 text-right hide">
<a href="https://getrebuild.com/market/go/1220-rb-store" class="link" target="_blank">[[${bundle.L('提交数据到 RB 仓库')}]]</a>
</div>
</div>
</div>
</div>
</div>
<th:block th:replace="~{/_include/footer}" />
<script th:src="@{/assets/js/admin/init-models.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/entity-new.js}" type="text/babel"></script>
</body>
</html>

View file

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:replace="~{/_include/header}" />
<title>[[${bundle.L('添加字段')}]]</title>
<style>
.select2-container--default .select2-results > .select2-results__options {
max-height: 151px;
}
</style>
</head>
<body class="dialog">
<div class="main-content">
<form>
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('字段名称')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="fieldLabel" maxlength="40" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('字段类型')}]]</label>
<div class="col-sm-7">
<select class="form-control form-control-sm" id="type"></select>
</div>
</div>
<div class="form-group row hide J_dt-REFERENCE J_dt-N2NREFERENCE">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('选择引用实体')}]]</label>
<div class="col-sm-7">
<select class="form-control form-control-sm" id="refEntity"></select>
</div>
</div>
<div class="form-group row hide J_dt-CLASSIFICATION">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('选择分类数据')}]]</label>
<div class="col-sm-7">
<select class="form-control form-control-sm" id="refClassification"></select>
</div>
</div>
<div class="form-group row hide J_dt-STATE">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('状态类 (StateSpec)')}]]</label>
<div class="col-sm-7">
<input class="form-control form-control-sm" type="text" id="stateClass" placeholder="com.rebuild.core.support.state.HowtoState" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label text-sm-right">[[${bundle.L('备注')}]]</label>
<div class="col-sm-7">
<textarea class="form-control form-control-sm row2x" id="comments" maxlength="100" th:placeholder="${bundle.L('(选填)')}"></textarea>
</div>
</div>
<div class="form-group row pb-1">
<label class="col-sm-3 col-form-label text-sm-right"></label>
<div class="col-sm-7">
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input class="custom-control-input" type="checkbox" id="saveAndNew" />
<span class="custom-control-label">[[${bundle.L('继续添加下一个')}]]</span>
</label>
</div>
</div>
<div class="form-group row footer">
<div class="col-sm-7 offset-sm-3">
<button class="btn btn-primary" type="button">[[${bundle.L('确定')}]]</button>
<button class="btn btn-link" type="button" onclick="parent.RbModal.hide()">[[${bundle.L('取消')}]]</button>
</div>
</div>
</form>
</div>
<th:block th:replace="~{/_include/footer}" />
<script th:src="@{/assets/js/metadata/field-type.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/field-new.js}" type="text/babel"></script>
</body>
</html>

View file

@ -52,7 +52,7 @@
<div class="btn-group bosskey-show">
<button class="btn btn-light w-auto dropdown-toggle ml-2" type="button" data-toggle="dropdown">[[${bundle.L('更多')}]] <i class="icon zmdi zmdi-more-vert"></i></button>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item J_new2-field">[[${bundle.L('批量添加')}]]</a>
<a class="dropdown-item J_new9-field">[[${bundle.L('批量添加')}]]</a>
<a class="dropdown-item J_export-fields">[[${bundle.L('导出')}]] (CSV)</a>
</div>
</div>
@ -101,5 +101,7 @@
</script>
<script th:src="@{/assets/js/metadata/entity-switch.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/fields.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/field-type.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/field-new2.js}" type="text/babel"></script>
</body>
</html>

View file

@ -35,7 +35,7 @@
<div class="rb-right-sidebar field-aside">
<div class="rb-content">
<div class="tab-container">
<ul class="nav nav-tabs bg-transparent">
<ul class="nav nav-tabs bg-transparent" style="margin-top: 3px">
<li class="nav-item"><a class="nav-link active" href="#FIELDLIST" data-toggle="tab">[[${bundle.L('字段列表')}]]</a></li>
<li class="nav-item"><a class="nav-link" href="#FIELDNEW" data-toggle="tab">+ [[${bundle.L('添加字段')}]]</a></li>
</ul>
@ -137,8 +137,9 @@
isSuperAdmin: '[[${isSuperAdmin}]]' === 'true',
}
</script>
<script th:src="@{/assets/js/metadata/field-type.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/form-design.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/entity-switch.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/form-design.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/field-type.js}" type="text/babel"></script>
<script th:src="@{/assets/js/metadata/field-new2.js}" type="text/babel"></script>
</body>
</html>

View file

@ -10,8 +10,8 @@ See LICENSE and COMMERCIAL in the project root for license information.
}
.file-header .file-path {
height: 46px;
padding: 9px 0;
height: 44px;
padding: 8px 0;
background-color: #eee;
}

View file

@ -336,10 +336,6 @@ form.field-attr label > span {
margin-right: 1.385rem;
}
.field-aside .nav.nav-tabs {
margin-top: 7px;
}
.type-list .dd-handle {
padding-left: 38px !important;
}

View file

@ -116,22 +116,30 @@ See LICENSE and COMMERCIAL in the project root for license information.
.quick-filter-tabs {
background-color: #fff;
padding: 0 18px;
margin-bottom: 12px;
border-radius: 2px;
padding: 0 20px;
position: absolute;
top: 0;
left: 0;
width: 100%;
border-bottom: 1px solid #e6e6e6;
height: 44px;
}
.quick-filter-tabs > div {
font-size: 0;
margin-top: 6px;
}
.quick-filter-tabs > div .dropdown-item {
display: inline-block;
width: auto;
line-height: 1;
padding: 15px 18px;
padding: 9px 20px;
font-size: 1rem;
cursor: pointer;
border-radius: 6px !important;
min-width: 60px;
text-align: center;
}
.quick-filter-tabs > div .dropdown-item:active {
@ -147,3 +155,18 @@ See LICENSE and COMMERCIAL in the project root for license information.
.quick-filter-tabs > div .dropdown-item.active:active {
color: #fff;
}
.page-aside.widgets .nav.nav-tabs {
min-height: 44px;
}
.page-aside.widgets .nav.nav-tabs > li.nav-item > .nav-link {
padding-top: 12px;
padding-bottom: 10px;
}
.quick-filter-tabs + .quick-filter-pane,
.quick-filter-tabs + .card-table,
.quick-filter-tabs + .nav-tabs {
margin-top: 44px;
}

View file

@ -3711,7 +3711,6 @@ form {
}
.page-aside.widgets .tab-container {
margin-top: 2px;
min-width: 279px;
overflow: hidden;
}
@ -3806,6 +3805,7 @@ form {
#asideFilters .dropdown-item.active,
#asideCategory .dropdown-item.active {
background-color: #4285f4;
background-color: var(--rb-theme-color);
color: #fff;
}
@ -5414,4 +5414,11 @@ div.dataTables_wrapper.compact div.dataTables_oper .btn-space {
.code-viewport:hover > a.copy {
display: inline-block;
}
}
span.icon-append .icon {
float: left;
width: 22px;
font-size: 1.2rem;
padding-top: 2px;
}

View file

@ -165,80 +165,82 @@ class AppLogsViewer extends RbModal {
const dataShow = this.state.dataShow
return (
<div className="logs">
<div className="row">
<div className="col-3 logs-list">
<div className="search-logs position-relative">
<input
type="text"
placeholder={$L('搜索')}
onKeyDown={(e) => {
if (e.keyCode === 13) {
this._loadNext(true, e.target.value)
}
}}
maxLength="40"
/>
</div>
<div className="list-group list-group-flush" ref={(c) => (this._$list = c)}>
{this.state.dataLogs.map((item) => {
const respOk = this._isRespOk(item[5])
return (
<a
key={item[6]}
className={`list-group-item list-group-item-action d-flex justify-content-between align-items-center ${dataShow && dataShow[6] === item[6] && 'active'}`}
onClick={() => {
this.setState({ dataShow: item })
}}>
<div>
{item[3].split('?')[0]}
<br />
<span className="text-muted fs-12">{item[1].split('UTC')[0]}</span>
</div>
<span className={`badge badge-${respOk ? 'success' : 'danger'} badge-pill`}>{respOk ? $L('成功') : $L('失败')}</span>
<div className="modal-body m-0 p-0">
<div className="logs">
<div className="row">
<div className="col-3 logs-list">
<div className="search-logs position-relative">
<input
type="text"
placeholder={$L('搜索')}
onKeyDown={(e) => {
if (e.keyCode === 13) {
this._loadNext(true, e.target.value)
}
}}
maxLength="40"
/>
</div>
<div className="list-group list-group-flush" ref={(c) => (this._$list = c)}>
{this.state.dataLogs.map((item) => {
const respOk = this._isRespOk(item[5])
return (
<a
key={item[6]}
className={`list-group-item list-group-item-action d-flex justify-content-between align-items-center ${dataShow && dataShow[6] === item[6] && 'active'}`}
onClick={() => {
this.setState({ dataShow: item })
}}>
<div>
{item[3].split('?')[0]}
<br />
<span className="text-muted fs-12">{item[1].split('UTC')[0]}</span>
</div>
<span className={`badge badge-${respOk ? 'success' : 'danger'} badge-pill`}>{respOk ? $L('成功') : $L('失败')}</span>
</a>
)
})}
</div>
{this.state.showMore && (
<div className="text-center mt-3">
<a className="text-primary" onClick={() => this._loadNext()}>
{$L('加载更多')}
</a>
)
})}
</div>
)}
</div>
<div className="col-9">
{dataShow ? (
<div className="logs-detail">
<dl className="row">
<dt className="col-sm-3">{$L('编号')} (X-RB-RequestId)</dt>
<dd className="col-sm-9">{dataShow[6]}</dd>
<dt className="col-sm-3">{$L('来源 IP')}</dt>
<dd className="col-sm-9">{dataShow[0]}</dd>
<dt className="col-sm-3">{$L('请求时间')}</dt>
<dd className="col-sm-9">{dataShow[1].substr(0, 19)}</dd>
<dt className="col-sm-3">{$L('响应时间')}</dt>
<dd className="col-sm-9">
{dataShow[2].substr(0, 19)}
<span className="badge badge-light ml-1 up-1">{$moment(dataShow[2]).diff($moment(dataShow[1]), 'seconds')}s</span>
</dd>
<dt className="col-sm-3">{$L('请求地址')}</dt>
<dd className="col-sm-9 text-break">{dataShow[3]}</dd>
<dt className="col-sm-12">{$L('请求数据')}</dt>
<dd className="col-sm-12">{dataShow[4] && <CodeViewport code={dataShow[4]} />}</dd>
<dt className="col-sm-12">{$L('响应数据')}</dt>
<dd className="col-sm-12 mb-0">{dataShow[5] && <CodeViewport code={dataShow[5]} />}</dd>
</dl>
</div>
) : (
<div className="text-muted pt-8 pb-8 text-center">
<p style={{ fontSize: 40 }}>
<i className="mdi mdi-script-text-outline text-muted" />
</p>
{$L('暂无数据')}
</div>
)}
</div>
{this.state.showMore && (
<div className="text-center mt-3">
<a className="text-primary" onClick={() => this._loadNext()}>
{$L('加载更多')}
</a>
</div>
)}
</div>
<div className="col-9">
{dataShow ? (
<div className="logs-detail">
<dl className="row">
<dt className="col-sm-3">{$L('编号')} (X-RB-RequestId)</dt>
<dd className="col-sm-9">{dataShow[6]}</dd>
<dt className="col-sm-3">{$L('来源 IP')}</dt>
<dd className="col-sm-9">{dataShow[0]}</dd>
<dt className="col-sm-3">{$L('请求时间')}</dt>
<dd className="col-sm-9">{dataShow[1].substr(0, 19)}</dd>
<dt className="col-sm-3">{$L('响应时间')}</dt>
<dd className="col-sm-9">
{dataShow[2].substr(0, 19)}
<span className="badge badge-light ml-1 up-1">{$moment(dataShow[2]).diff($moment(dataShow[1]), 'seconds')}s</span>
</dd>
<dt className="col-sm-3">{$L('请求地址')}</dt>
<dd className="col-sm-9 text-break">{dataShow[3]}</dd>
<dt className="col-sm-12">{$L('请求数据')}</dt>
<dd className="col-sm-12">{dataShow[4] && <CodeViewport code={dataShow[4]} />}</dd>
<dt className="col-sm-12">{$L('响应数据')}</dt>
<dd className="col-sm-12 mb-0">{dataShow[5] && <CodeViewport code={dataShow[5]} />}</dd>
</dl>
</div>
) : (
<div className="text-muted pt-8 pb-8 text-center">
<p style={{ fontSize: 40 }}>
<i className="mdi mdi-script-text-outline text-muted" />
</p>
{$L('暂无数据')}
</div>
)}
</div>
</div>
</div>

View file

@ -23,6 +23,12 @@ let import_taskid
const entity = $urlp('entity')
_Config.entity = entity || null
_Config.file = $urlp('file') || null
if (_Config.file) {
_Config.file = $decode(_Config.file)
$('.J_upload-input').text($fileCutName(_Config.file))
}
$(document).ready(() => {
$.get('/commons/metadata/entities?detail=true', (res) => {
$(res.data).each(function () {
@ -288,7 +294,6 @@ const step3_import_cancel = () => {
}
const _LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
// 渲染字段映射
const _fieldsMapping = (columns, fields) => {
const canNullText = ` [${$L('必填')}]`

View file

@ -339,7 +339,6 @@ class DlgAddChart extends RbFormHandler {
this.__select2 = $entity.select2({
allowClear: false,
placeholder: $L('选择数据来源'),
matcher: $select2MatcherAll,
})
})
}

View file

@ -583,10 +583,7 @@ class FilterItem extends React.Component {
const that = this
const $s2field = $(this._filterField)
.select2({
allowClear: false,
matcher: $select2MatcherAll,
})
.select2({ allowClear: false })
.on('change', function (e) {
const fieldAndType = e.target.value.split(NT_SPLIT)
that.setState({ field: fieldAndType[0], type: fieldAndType[1] }, () => $s2op.val(that.__op[0]).trigger('change'))

View file

@ -1002,10 +1002,11 @@ class RbList extends React.Component {
if (supportFixedColumns) $scroller.find('.table').addClass('table-header-fixed')
$addResizeHandler(() => {
let mh = $(window).height() - 210 + 5
let mh = $(window).height() - (61 + 20 + 61 + 60 + 2) /* Nav, MarginTop20, TableHeader, TableFooter */
if ($('.main-content>.nav-tabs-classic')[0]) mh -= 38 // Has detail-tab
if ($('.main-content .quick-filter-pane')[0]) mh -= 75 // Has query-pane
if ($('.main-content .quick-filter-tabs')[0]) mh -= 55 // Has query-tabs
if ($('.main-content .quick-filter-tabs')[0]) mh -= 44 // Has query-tabs
$scroller.css({ maxHeight: mh })
$scroller.perfectScrollbar('update')
})()

View file

@ -586,7 +586,8 @@ class RbForm extends React.Component {
}
if (window.FrontJS) {
const ret = window.FrontJS.Form._trigger('fieldValueChange', [`${this.props.entity}.${field}`, value, this.props.id || null])
const fieldKey = `${this.props.entity}.${field}`
const ret = window.FrontJS.Form._trigger('fieldValueChange', [fieldKey, value, this.props.id || null])
if (ret === false) return false
}
}
@ -2979,7 +2980,7 @@ const __calcFormula = function (_this) {
if (res.data) _this.setValue(res.data)
else _this.setValue(null)
})
}, 400)
}, 300)
return true
})
@ -2990,5 +2991,5 @@ const __calcFormula = function (_this) {
else _this.setValue(null)
})
}
}, 400) // delay for init
}, 600) // delay for init
}

View file

@ -172,7 +172,6 @@ class DlgRuleEdit extends RbFormHandler {
const $s2target = $(this._targetField).select2({
placeholder: $L('选择字段'),
allowClear: false,
matcher: $select2MatcherAll,
})
this.__select2.push($s2target)
@ -184,7 +183,6 @@ class DlgRuleEdit extends RbFormHandler {
.select2({
placeholder: $L('选择字段'),
allowClear: false,
matcher: $select2MatcherAll,
})
.on('change', (e) => this._renderTargetFields(e.target.value))
this.__select2.push($s2source)

View file

@ -183,7 +183,7 @@ class DlgMode1Option extends RbFormHandler {
<label htmlFor="advListFilterTabs" />
</span>
</div>
<span className="ml-2 down-5 d-inline-block">{$L('常用查询')}</span>
<span className="ml-2 down-5 d-inline-block">{$L('列表视图')}</span>
</div>
<div>
<div className="switch-button switch-button-xs">

View file

@ -1,165 +0,0 @@
/*!
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.
*/
/* global InitModels */
window.__LAB_SHOWNDETAIL = false
window.bosskeyTrigger = function () {
window.__LAB_SHOWNDETAIL = true
}
$(document).ready(() => {
const $bnew = $('.btn-primary.new').on('click', () => {
const entityLabel = $val('#entityLabel'),
comments = $val('#comments')
if (!entityLabel) return RbHighbar.create($L('请输入实体名称'))
const data = {
label: entityLabel,
comments: comments,
}
if ($val('#isDetail')) {
data.mainEntity = $val('#mainEntity')
if (!data.mainEntity) return RbHighbar.create($L('请选择主实体'))
}
$bnew.button('loading')
$.post(`/admin/entity/entity-new?nameField=${$val('#nameField')}&seriesField=${$val('#seriesField')}`, JSON.stringify(data), (res) => {
if (res.error_code === 0) parent.location.href = `${rb.baseUrl}/admin/entity/${res.data}/base`
else RbHighbar.error(res.error_msg)
})
})
const $bcopy = $('.btn-primary.copy').on('click', () => {
const sourceEntity = $val('#copySourceEntity')
if (!sourceEntity) return RbHighbar.create($L('请选择从哪个实体复制'))
const entityLabel = $val('#newEntityLabel')
if (!entityLabel) return RbHighbar.create($L('请输入实体名称'))
const data = {
sourceEntity: sourceEntity,
entityName: entityLabel,
detailEntityName: $val('#newDetailLabel'),
keepConfig: [],
}
$bcopy.button('loading')
$.post('/admin/entity/entity-copy', JSON.stringify(data), (res) => {
if (res.error_code === 0) parent.location.href = `${rb.baseUrl}/admin/entity/${res.data}/base`
else RbHighbar.error(res.error_msg)
})
})
let entities
function _loadEntities(c) {
if (entities) {
typeof c === 'function' && c(entities)
} else {
$.get('/admin/entity/entity-list?detail=true', (res) => {
entities = res.data
typeof c === 'function' && c(entities)
})
}
}
_loadEntities((e) => {
e.forEach((item) => {
$(`<option value="${item.entityName}" data-detail="${item.detailEntity || ''}">${item.entityLabel}</option>`).appendTo('#copySourceEntity')
})
$('#copySourceEntity')
.on('change', function () {
const $s = $('#copySourceEntity option:selected')
if ($s.data('detail')) $('.J_newDetailLabel').removeClass('hide')
else $('.J_newDetailLabel').addClass('hide')
parent.RbModal.resize()
})
.trigger('change')
if (e.length === 0) $(`<option value="">${$L('无可用实体')}</option>`).appendTo('#copySourceEntity')
})
$('#isDetail').on('click', () => {
$('.J_mainEntity').toggleClass('hide')
parent.RbModal.resize()
if ($('#mainEntity option').length === 0) {
_loadEntities((e) => {
e.forEach((item) => {
if (!item.mainEntity) {
if (window.__LAB_SHOWNDETAIL) {
$(`<option value="${item.entityName}">${item.entityLabel}${item.detailEntity ? ' (LAB)' : ''}</option>`).appendTo('#mainEntity')
} else if (!item.detailEntity) {
$(`<option value="${item.entityName}">${item.entityLabel}</option>`).appendTo('#mainEntity')
}
}
})
if ($('#mainEntity option').length === 0) $(`<option value="">${$L('无可用实体')}</option>`).appendTo('#mainEntity')
})
}
})
let _MetaschemaList
$('.J_imports').on('click', () => {
if (_MetaschemaList) return
renderRbcomp(<MetaschemaList />, 'metaschemas', function () {
_MetaschemaList = this
})
})
$('.nav-tabs a').on('click', () => parent.RbModal.resize())
})
class MetaschemaList extends React.Component {
render() {
return (
<div>
<InitModels ref={(c) => (this._InitModels = c)} onLoad={() => parent.RbModal.resize()} />
<div className="dialog-footer">
<div className="float-right">
<button className="btn btn-primary" onClick={() => this.imports()} ref={(c) => (this._$btn = c)}>
{$L('开始导入')}
</button>
</div>
<div className="float-right">
<p className="protips mt-2 pr-2">{$L('可在导入后根据自身需求做适当调整/修改')}</p>
</div>
<div className="clearfix" />
</div>
</div>
)
}
componentDidMount() {
parent.RbModal.resize()
}
imports() {
const s = this._InitModels.getSelected()
if (s.length < 1) {
return RbHighbar.create($L('请选择要导入的实体'))
}
const $btn = $(this._$btn).button('loading')
const $mp2 = parent && parent.$mp ? parent.$mp : $mp
$mp2.start()
$.post(`/admin/metadata/imports?key=${s.join(',')}`, (res) => {
$mp2.end()
$btn.button('reset')
if (res.error_code === 0) {
RbHighbar.success($L('导入成功'))
setTimeout(() => parent.location.reload(), 1500)
} else {
RbHighbar.error(res.error_msg)
}
})
}
}

View file

@ -0,0 +1,572 @@
/*!
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.
*/
/* global InitModels, FIELD_TYPES */
window.__LAB_SHOWNDETAIL = false
window.bosskeyTrigger = function () {
window.__LAB_SHOWNDETAIL = true
}
// ~~ 新建实体
// eslint-disable-next-line no-unused-vars
class EntityNew2 extends RbModalHandler {
constructor(props) {
super(props)
this.state = { ...props }
}
render() {
return (
<RbModal ref={(c) => (this._dlg = c)} title={$L('添加实体')} className="entity-new2">
<div className="tab-container" ref={(c) => (this._$container = c)}>
<ul className="nav nav-tabs">
<li className="nav-item">
<a className="nav-link active" href="#MANUAL" data-toggle="tab">
{$L('手动')}
</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#COPY" data-toggle="tab">
{$L('复制')}
</a>
</li>
<li className="nav-item">
<a className="nav-link" href="#EXCEL" data-toggle="tab">
{$L(' EXCEL 导入')}
</a>
</li>
<li className="nav-item">
<a className="nav-link J_imports" href="#IMPORTS" data-toggle="tab">
{$L(' RB 仓库导入')}
</a>
</li>
</ul>
<div className="tab-content m-0 pb-0">
<div className="tab-pane active" id="MANUAL">
<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" type="text" maxLength="40" ref={(c) => (this._$entityLabel = c)} />
</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">
<textarea className="form-control form-control-sm row2x" maxLength="100" placeholder={$L('(选填)')} ref={(c) => (this._$comments = c)} />
</div>
</div>
<div className="form-group row pt-2">
<label className="col-sm-3 col-form-label text-sm-right"></label>
<div className="col-sm-7">
<label className="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input className="custom-control-input" type="checkbox" ref={(c) => (this._$nameField = c)} />
<span className="custom-control-label">{$L('添加一个名称字段')}</span>
</label>
</div>
</div>
<div className="form-group row pt-0">
<label className="col-sm-3 col-form-label text-sm-right"></label>
<div className="col-sm-7">
<label className="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input className="custom-control-input" type="checkbox" ref={(c) => (this._$seriesField = c)} />
<span className="custom-control-label">{$L('添加一个自动编号字段')}</span>
</label>
</div>
</div>
<div className="form-group row pt-0">
<label className="col-sm-3 col-form-label text-sm-right"></label>
<div className="col-sm-7">
<label className="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input className="custom-control-input" type="checkbox" onClick={(e) => this.setState({ newIsDetail: $val(e.target) })} ref={(c) => (this._$newIsDetail = c)} />
<span className="custom-control-label">
{$L('这是明细实体')}
<i className="zmdi zmdi-help zicon" data-toggle="tooltip" title={$L('通过明细实体可以更好的组织业务关系例如订单明细通常依附于订单而非独立存在')}></i>
</span>
</label>
</div>
</div>
<div className={`form-group row ${this.state.newIsDetail ? '' : 'hide'}`}>
<label className="col-sm-3 col-form-label text-sm-right">{$L('选择主实体')}</label>
<div className="col-sm-7">
<select className="form-control form-control-sm" ref={(c) => (this._$mainEntity = c)}>
{this.state.entities &&
this.state.entities.map((item) => {
if (item.mainEntity) return null
if (item.detailEntity && !window.__LAB_SHOWNDETAIL) return null
return (
<option key={item.entityName} value={item.entityName}>
{item.entityLabel}
{item.detailEntity ? ' (LAB)' : ''}
</option>
)
})}
</select>
</div>
</div>
<div className="form-group row footer">
<div className="col-sm-7 offset-sm-3">
<button className="btn btn-primary" type="button" onClick={() => this.postNew()}>
{$L('确定')}
</button>
<button className="btn btn-link" type="button" onClick={() => this.hide()}>
{$L('取消')}
</button>
</div>
</div>
</div>
</div>
<div className="tab-pane" id="COPY">
<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">
<select className="form-control form-control-sm" ref={(c) => (this._$copySourceEntity = c)}>
{this.state.entities &&
this.state.entities.map((item) => {
return (
<option key={item.entityName} value={item.entityName}>
{item.entityLabel}
</option>
)
})}
</select>
</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">
<input className="form-control form-control-sm" type="text" maxLength="40" ref={(c) => (this._$copyEntityLabel = c)} />
</div>
</div>
<div className={`form-group row ${this.state.copyHasDetail ? '' : 'hide'}`}>
<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" type="text" maxLength="40" placeholder={$L('(选填)')} ref={(c) => (this._$copyDetailLabel = c)} />
<p className="form-text">{$L('不填写则不复制明细实体')}</p>
</div>
</div>
<div className="form-group row footer">
<div className="col-sm-7 offset-sm-3">
<button className="btn btn-primary" type="button" onClick={() => this.postCopy()}>
{$L('确定')}
</button>
<button className="btn btn-link" type="button" onClick={() => this.hide()}>
{$L('取消')}
</button>
</div>
</div>
</div>
</div>
<div className="tab-pane" id="EXCEL">
<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="file-select">
<input type="file" className="inputfile" accept=".xlsx,.xls,.csv" data-local="temp" ref={(c) => (this._$uploadfile = c)} />
<label htmlFor="upload-input" className="btn-secondary mb-0" ref={(c) => (this._$uploadbtn = c)}>
<i className="zmdi zmdi-upload"></i>
<span>{$L('上传文件')}</span>
</label>
</div>
{this.state.excelfile && (
<div className="mt-1">
<u className="text-bold">{$fileCutName(this.state.excelfile)}</u>
</div>
)}
<p className="form-text">{$L('[点击查看](https://getrebuild.com/docs/admin/entity/#%E4%BB%8E%20EXCEL%20%E5%AF%BC%E5%85%A5) 数据文件格式要求')}</p>
</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">
<input className="form-control form-control-sm" type="text" maxLength="40" ref={(c) => (this._$excelEntityLabel = c)} />
</div>
</div>
<div className="form-group row footer">
<div className="col-sm-7 offset-sm-3">
<button className="btn btn-primary" type="button" onClick={() => this.postExcel()}>
{$L('下一步')}
</button>
<button className="btn btn-link" type="button" onClick={() => this.hide()}>
{$L('取消')}
</button>
</div>
</div>
</div>
</div>
<div className="tab-pane" id="IMPORTS">
<InitModels ref={(c) => (this._InitModels = c)} />
<div className="dialog-footer">
<div className="float-right">
<button className="btn btn-primary" onClick={() => this.postRbImports()}>
{$L('开始导入')}
</button>
</div>
<div className="float-right">
<p className="protips mt-2 pr-2">{$L('可在导入后根据自身需求做适当调整/修改')}</p>
</div>
<div className="clearfix" />
</div>
</div>
<div className="mt-2 text-right hide">
<a href="https://getrebuild.com/market/go/1220-rb-store" className="link" target="_blank">
{$L('提交数据到 RB 仓库')}
</a>
</div>
</div>
</div>
</RbModal>
)
}
componentDidMount() {
$(this._$container).find('[data-toggle="tooltip"]').tooltip()
$.get('/admin/entity/entity-list?detail=true', (res) => {
this.setState({ entities: res.data }, () => {
$(this._$mainEntity).select2({ allowClear: false })
$(this._$copySourceEntity)
.select2({ allowClear: false })
.on('change', (e) => {
const val = e.currentTarget.value
const found = this.state.entities.find((x) => x.entityName === val)
this.setState({ copyHasDetail: found && !!found.detailEntity })
})
})
})
$createUploader(
this._$uploadfile,
(res) => {
$(this._$uploadbtn).text(`${$L('上传中')} ... ${res.percent.toFixed(0)}%`)
},
(res) => {
this.setState({ excelfile: res.key })
$(this._$uploadbtn).text($L('上传文件'))
$(this._$excelEntityLabel).val($fileCutName(res.key))
}
)
$(this._$uploadbtn).on('click', () => this._$uploadfile.click())
setTimeout(() => $(this._$entityLabel).focus(), 200)
}
postNew() {
const data = {
label: $val(this._$entityLabel),
comments: $val(this._$comments),
}
if (!data.label) return RbHighbar.create($L('请输入实体名称'))
if (this.state.newIsDetail) {
data.mainEntity = $val(this._$mainEntity)
if (!data.mainEntity) return RbHighbar.create($L('请选择主实体'))
}
const $btn = $(this._$container).find('.btn').button('loading')
$.post(`/admin/entity/entity-new?nameField=${$val(this._$nameField)}&seriesField=${$val(this._$seriesField)}`, JSON.stringify(data), (res) => {
if (res.error_code === 0) {
location.href = `${rb.baseUrl}/admin/entity/${res.data}/base`
} else {
$btn.button('reset')
RbHighbar.error(res.error_msg)
}
})
}
postCopy() {
const data = {
sourceEntity: $val(this._$copySourceEntity),
entityName: $val(this._$copyEntityLabel),
detailEntityName: $val(this._$copyDetailLabel),
keepConfig: [],
}
if (!data.sourceEntity) return RbHighbar.create($L('请选择从哪个实体复制'))
if (!data.entityName) return RbHighbar.create($L('请输入实体名称'))
const $btn = $(this._$container).find('.btn').button('loading')
$.post('/admin/entity/entity-copy', JSON.stringify(data), (res) => {
if (res.error_code === 0) {
location.href = `${rb.baseUrl}/admin/entity/${res.data}/base`
} else {
$btn.button('reset')
RbHighbar.error(res.error_msg)
}
})
}
postExcel() {
const excelfile = this.state.excelfile
if (!excelfile) return RbHighbar.create($L('请上传数据文件'))
$.get(`/app/entity/data-imports/check-file?file=${$encode(excelfile)}`, (res) => {
if (res.error_code > 0) {
this.setState({ excelfile: null })
RbHighbar.create(res.error_msg)
return
}
const _data = res.data
if (_data.preview.length < 1 || _data.preview[0].length === 0) return RbHighbar.create($L('上传的文件无有效数据'))
const entityLabel = $val(this._$excelEntityLabel)
if (!entityLabel) return RbHighbar.create($L('请输入实体名称'))
renderRbcomp(<ExcelPreview datas={_data.preview} entityLabel={entityLabel} excelfile={excelfile} title={$L('导入字段配置')} maximize _maximize disposeOnHide useWhite />)
})
}
postRbImports() {
const s = this._InitModels.getSelected()
if (s.length < 1) return RbHighbar.create($L('请选择要导入的实体'))
const $btn = $(this._$container).find('.btn').button('loading')
$mp.start()
$.post(`/admin/metadata/imports?key=${s.join(',')}`, (res) => {
$mp.end()
if (res.error_code === 0) {
RbHighbar.success($L('导入成功'))
setTimeout(() => location.reload(), 1500)
} else {
$btn.button('reset')
RbHighbar.error(res.error_msg)
}
})
}
}
const _LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
class ExcelPreview extends RbModal {
renderContent() {
let colMax = 0
this.props.datas.forEach((d) => {
colMax = Math.max(colMax, d.length)
})
const colNames = []
for (let i = 0; i < colMax; i++) {
let L = _LETTERS[i]
if (i > 25) L = `A${_LETTERS[i - 26] || 'X'}` // AA
if (i > 51) L = `B${_LETTERS[i - 52] || 'X'}` // BA
colNames.push(L)
}
const ftKeys = Object.keys(FIELD_TYPES)
const dataHead = this.props.datas[0]
this.__colNames = colNames
this.__colDatas = {}
return (
<div className="modal-body m-0 p-0">
<div style={{ overflow: 'auto' }}>
<table className="table table-bordered table-excel m-0">
<thead>
<tr>
<th></th>
{colNames.map((item) => {
return <th key={item}>{item}</th>
})}
</tr>
</thead>
<tbody>
<tr ref={(c) => (this._$datahead = c)}>
<th>1</th>
{colNames.map((item, idx) => {
return (
<td key={item} className="align-text-top">
<div>
<label className="mb-0">{$L('字段名称')}</label>
<input className="form-control form-control-sm" defaultValue={dataHead[idx]} placeholder={$L('不导入')} />
</div>
<div className="mt-1 J_type">
<label className="mb-0">{$L('字段类型')}</label>
<select className="form-control form-control-sm" defaultValue={$empty(dataHead[idx]) ? '-' : 'TEXT'}>
<option value="-">{$L('不导入')}</option>
{ftKeys.map((item) => {
if (FIELD_TYPES[item][2]) return null
return (
<option key={item} value={item}>
{FIELD_TYPES[item][0]}
</option>
)
})}
</select>
</div>
<div className="mt-1 J_refEntity hide">
<label className="mb-0">{$L('选择引用实体')}</label>
<select className="form-control form-control-sm">
{this.state.refEntities &&
this.state.refEntities.map((item) => {
if (item.entityName === 'Team') return null
return (
<option key={item.entityName} value={item.entityName}>
{item.entityLabel}
</option>
)
})}
</select>
</div>
<div className="mt-1 J_refClass hide">
<label className="mb-0">{$L('选择分类数据')}</label>
<select className="form-control form-control-sm">
{this.state.refClasses &&
this.state.refClasses.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
})}
</select>
</div>
</td>
)
})}
</tr>
{this.props.datas.map((d, idx) => {
if (idx === 0 || idx > 20) return null
return (
<tr key={idx}>
<th>{idx + 1}</th>
{colNames.map((item, idx2) => {
const r = this.__colDatas[idx2] || []
r.push(d[idx2])
this.__colDatas[idx2] = r
return (
<td key={`${idx}-${idx2}`} className="text-break">
{d[idx2] || ''}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</div>
<div className="float-left">
<p className="protips m-0 p-3 pt-4">{$L('最多显示前 %d 行数据', 20)}</p>
</div>
<div className="text-right p-2 pt-3" ref={(c) => (this._$btns = c)}>
<button className="btn btn-link btn-space" type="button" onClick={() => this.hide()}>
{$L('返回')}
</button>
<button className="btn btn-primary btn-space" type="button" onClick={() => this.post2()}>
{$L('确定')}
</button>
</div>
</div>
)
}
componentDidMount() {
super.componentDidMount()
// 评估字段类型
function _evalFieldType(cols) {
let isNumber = undefined
let isDecimal = undefined
cols.forEach((item) => {
if ($empty(item)) return
if (isNumber || isNumber === undefined) isNumber = !isNaN(item)
if (isDecimal || isDecimal === undefined) {
isDecimal = isNumber && /\./g.test(item)
}
})
if (isDecimal) return 'DECIMAL'
if (isNumber) return 'NUMBER'
return null
}
$.get('/admin/entity/entity-list?detail=true', (res) => {
this.setState({ refEntities: res.data || [] })
$.get('/admin/metadata/classification/list', (res2) => {
this.setState({ refClasses: res2.data || [] }, () => {
// init
this.__colNames.forEach((item, idx) => {
const type = _evalFieldType(this.__colDatas[idx] || [])
type && $(this._$datahead).find('td').eq(idx).find('.J_type select').val(type)
})
$(this._$datahead)
.find('.J_type select')
.on('change', function () {
const $td = $(this).parents('td')
$td.find('.J_refEntity, .J_refClass').addClass('hide')
const t = $(this).val()
if (t === 'REFERENCE' || t === 'N2NREFERENCE') {
$td.find('.J_refEntity').removeClass('hide')
} else if (t === 'CLASSIFICATION') {
$td.find('.J_refClass').removeClass('hide')
}
})
$(this._$datahead).find('select').select2({ allowClear: false })
})
})
})
}
post2() {
const fieldsNew = []
$(this._$datahead)
.find('td')
.each(function () {
const name = $(this).find('input').val()
const type = $(this).find('.J_type select').val()
if (name && type && type !== '-') {
let ref2 = null
if (type === 'REFERENCE' || type === 'N2NREFERENCE') {
ref2 = $(this).find('.J_refEntity select').val()
if (!ref2) return RbHighbar.create('请选择引用实体')
} else if (type === 'CLASSIFICATION') {
ref2 = $(this).find('.J_refClass select').val()
if (!ref2) return RbHighbar.create('请选择分类数据')
}
fieldsNew.push([name, type, ref2])
}
})
if (fieldsNew.length === 0) return RbHighbar.create($L('没有配置任何导入字段'))
const that = this
const post = {
entityLabel: this.props.entityLabel,
fields: fieldsNew,
}
RbAlert.create($L('请确认导入字段配置开始导入吗'), {
onConfirm: function () {
this.disabled(true, true)
$.post('/admin/entity/entity-excel', JSON.stringify(post), (res) => {
this.hide(true)
if (res.error_code === 0) {
RbAlert.create($L('实体导入成功是否需要进行数据导入'), {
onConfirm: function () {
location.href = `${rb.baseUrl}/admin/data/data-imports?entity=${res.data}&file=${$encode(that.props.excelfile)}`
},
onCancel: function () {
location.href = `${rb.baseUrl}/admin/entity/${res.data}/fields`
},
})
} else {
RbHighbar.error(res.error_msg)
}
})
},
})
}
}

View file

@ -594,7 +594,7 @@ const _handleCalcFormula = function (formula) {
$.get(`/commons/metadata/fields?entity=${wpc.entityName}`, (res) => {
const fs = []
res.data.forEach((item) => {
if (['NUMBER', 'DECIMAL', 'DATE', 'DATETIME'].includes(item.type) && !['approvalLastTime', 'modifiedOn'].includes(item.name) && item.name !== wpc.fieldName) {
if (['NUMBER', 'DECIMAL', 'DATE', 'DATETIME'].includes(item.type) && !['approvalLastTime'].includes(item.name) && item.name !== wpc.fieldName) {
fs.push(item)
}
})

View file

@ -1,123 +0,0 @@
/*!
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.
*/
/* global FIELD_TYPES */
$(document).ready(function () {
const entity = $urlp('entity')
const $btn = $('.btn-primary').on('click', function () {
const fieldLabel = $val('#fieldLabel'),
type = $val('#type'),
comments = $val('#comments'),
refEntity = $val('#refEntity'),
refClassification = $val('#refClassification'),
stateClass = $val('#stateClass') || 'com.rebuild.core.support.state.HowtoState'
if (!fieldLabel) {
return RbHighbar.create($L('请输入字段名称'))
}
if ((type === 'REFERENCE' || type === 'N2NREFERENCE') && !refEntity) {
return RbHighbar.create($L('请选择引用实体'))
} else if (type === 'CLASSIFICATION' && !refClassification) {
return RbHighbar.create($L('请选择分类数据'))
} else if (type === 'STATE' && !stateClass) {
return RbHighbar.create($L('请输入状态类 (StateSpec)'))
}
const data = {
entity: entity,
label: fieldLabel,
type: type,
comments: comments,
refEntity: refEntity,
refClassification: refClassification,
stateClass: stateClass,
}
$btn.button('loading')
$.post('/admin/entity/field-new', JSON.stringify(data), function (res) {
$btn.button('reset')
if (res.error_code === 0) {
if ($val('#saveAndNew')) {
RbHighbar.success($L('字段已添加'))
$('#fieldLabel, #comments').val('')
// $('#type').val('TEXT').trigger('change')
$('#fieldLabel').focus()
// @see `field-new.html`
parent && parent.loadFields && parent.loadFields()
// @see `form-design.js`
parent && parent.add2Layout && parent.add2Layout(res.data)
} else {
parent.location.href = `${rb.baseUrl}/admin/entity/${entity}/field/${res.data}`
}
} else {
RbHighbar.error(res.error_msg)
}
})
})
for (let k in FIELD_TYPES) {
const t = FIELD_TYPES[k]
const $o = $(`<option value="${k}">${t[0]}</option>`).appendTo('#type')
if (t[2]) $o.addClass('bosskey-show')
}
// $('#type, #refEntity').select2({})
let referenceLoaded = false
let classificationLoaded = false
$('#type').on('change', function () {
parent.RbModal.resize()
$('.J_dt-REFERENCE, .J_dt-N2NREFERENCE, .J_dt-CLASSIFICATION, .J_dt-STATE').addClass('hide')
const dt = $(this).val()
$(`.J_dt-${dt}`).removeClass('hide')
if (dt === 'REFERENCE' || dt === 'N2NREFERENCE') {
if (referenceLoaded === false) {
referenceLoaded = true
$.get('/admin/entity/entity-list?detail=true', (res) => {
const d = res.data || []
d.push({ entityName: 'User', entityLabel: $L('用户') })
d.push({ entityName: 'Department', entityLabel: $L('部门') })
d.push({ entityName: 'Team', entityLabel: $L('团队') })
// _data.push({ entityName: 'Role', entityLabel: $L('角色') })
$(d).each(function () {
$(`<option value="${this.entityName}">${this.entityLabel}</option>`).appendTo('#refEntity')
})
})
}
} else if (dt === 'CLASSIFICATION') {
if (classificationLoaded === false) {
classificationLoaded = true
$.get('/admin/metadata/classification/list', (res) => {
let hasData = false
$(res.data).each(function () {
if (!this[2]) {
$(`<option value="${this[0]}">${this[1]}</option>`).appendTo('#refClassification')
hasData = true
}
})
if (!hasData) $(`<option value="">${$L('无可用分类数据')}</option>`).appendTo('#refClassification')
})
}
} else if (dt === 'STATE') {
// NOOP
}
})
// via form-design
const designType = $urlp('type')
if (designType) {
$('#type').val(designType).trigger('change').parents('.form-group').addClass('hide')
$('#saveAndNew').attr('checked', true).parents('.form-group').addClass('hide')
}
$('#fieldLabel')[0].focus()
})

View file

@ -0,0 +1,197 @@
/*!
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.
*/
/* global FIELD_TYPES */
// ~~ 新建实体
// eslint-disable-next-line no-unused-vars
class FieldNew2 extends RbModalHandler {
constructor(props) {
super(props)
this.state = { ...props }
}
render() {
const ftKeys = Object.keys(FIELD_TYPES)
return (
<RbModal ref={(c) => (this._dlg = c)} title={$L('添加字段')} disposeOnHide>
<div>
<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" type="text" maxLength="40" ref={(c) => (this._$fieldLabel = c)} />
</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">
<select className="form-control form-control-sm" ref={(c) => (this._$type = c)} defaultValue={this.props.fieldType}>
{ftKeys.map((key) => {
if (FIELD_TYPES[key][2]) return null
return (
<option key={key} value={key}>
{FIELD_TYPES[key][0]}
</option>
)
})}
</select>
</div>
</div>
<div className={`form-group row ${this.state.fieldType === 'REFERENCE' || this.state.fieldType === 'N2NREFERENCE' ? '' : 'hide'}`}>
<label className="col-sm-3 col-form-label text-sm-right">{$L('选择引用实体')}</label>
<div className="col-sm-7">
<select className="form-control form-control-sm" ref={(c) => (this._$refEntity = c)}>
{this.state.refEntities &&
this.state.refEntities.map((item) => {
if (item.entityName === 'Team') return null
return (
<option key={item.entityName} value={item.entityName}>
{item.entityLabel}
</option>
)
})}
</select>
</div>
</div>
<div className={`form-group row ${this.state.fieldType === 'CLASSIFICATION' ? '' : 'hide'}`}>
<label className="col-sm-3 col-form-label text-sm-right">{$L('选择分类数据')}</label>
<div className="col-sm-7">
<select className="form-control form-control-sm" ref={(c) => (this._$refClass = c)}>
{this.state.refClasses &&
this.state.refClasses.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
})}
</select>
</div>
</div>
<div className={`form-group row ${this.state.fieldType === 'STATE' ? '' : 'hide'}`}>
<label className="col-sm-3 col-form-label text-sm-right">{$L('状态类 (StateSpec)')}</label>
<div className="col-sm-7">
<input className="form-control form-control-sm" type="text" placeholder="com.rebuild.core.support.state.HowtoState" ref={(c) => (this._$stateClass = c)} />
</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">
<textarea className="form-control form-control-sm row2x" maxLength="100" placeholder={$L('(选填)')} ref={(c) => (this._$comments = c)} />
</div>
</div>
<div className="form-group row pb-1">
<label className="col-sm-3 col-form-label text-sm-right"></label>
<div className="col-sm-7">
<label className="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
<input className="custom-control-input" type="checkbox" ref={(c) => (this._$saveAndNew = c)} />
<span className="custom-control-label">{$L('继续添加下一个')}</span>
</label>
</div>
</div>
<div className="form-group row footer">
<div className="col-sm-7 offset-sm-3" ref={(c) => (this._$btns = c)}>
<button className="btn btn-primary" type="button" onClick={() => this.postNew()}>
{$L('确定')}
</button>
<button className="btn btn-link" type="button" onClick={() => this.hide()}>
{$L('取消')}
</button>
</div>
</div>
</form>
</div>
</RbModal>
)
}
componentDidMount() {
$(this._$type)
.select2({
allowClear: false,
templateResult: function (res) {
const $span = $('<span class="icon-append"></span>').attr('title', res.text).text(res.text)
$(`<i class="icon mdi ${(FIELD_TYPES[res.id] || [])[1]}"></i>`).appendTo($span)
return $span
},
})
.on('change', (e) => {
this.setState({ fieldType: e.target.value })
})
$.get('/admin/entity/entity-list?detail=true&bizz=true', (res) => {
const _entities = res.data || []
this.setState({ refEntities: _entities }, () => {
$(this._$refEntity).select2({ allowClear: false })
})
$.get('/admin/metadata/classification/list', (res2) => {
this.setState({ refClasses: res2.data || [] }, () => {
$(this._$refClass).select2({ allowClear: false })
})
})
})
if (this.props.fieldType) {
$(this._$saveAndNew).attr('checked', true)
$(this._$saveAndNew).parents('.form-group').hide()
$(this._$type).parents('.form-group').hide()
}
setTimeout(() => $(this._$fieldLabel).focus(), 200)
}
postNew() {
const fieldLabel = $val(this._$fieldLabel),
type = $val(this._$type),
comments = $val(this._$comments),
refEntity = $val(this._$refEntity),
refClassification = $val(this._$refClass),
stateClass = $val(this._$stateClass) || 'com.rebuild.core.support.state.HowtoState'
if (!fieldLabel) return RbHighbar.create($L('请输入字段名称'))
if ((type === 'REFERENCE' || type === 'N2NREFERENCE') && !refEntity) {
return RbHighbar.create($L('请选择引用实体'))
} else if (type === 'CLASSIFICATION' && !refClassification) {
return RbHighbar.create($L('请选择分类数据'))
} else if (type === 'STATE' && !stateClass) {
return RbHighbar.create($L('请输入状态类 (StateSpec)'))
}
const data = {
entity: this.props.entity,
label: fieldLabel,
type: type,
comments: comments,
refEntity: refEntity,
refClassification: refClassification,
stateClass: stateClass,
}
const $btn = $(this._$btns).find('.btn').button('loading')
$.post('/admin/entity/field-new', JSON.stringify(data), (res) => {
$btn.button('reset')
if (res.error_code === 0) {
if ($val(this._$saveAndNew)) {
RbHighbar.success($L('字段已添加'))
$([this._$fieldLabel, this._$comments]).val('')
$(this._$fieldLabel).focus()
// @see fields.html
typeof window.loadFields === 'function' && window.loadFields()
// @see `form-design.js`
typeof window.add2Layout === 'function' && window.add2Layout(res.data, this)
} else {
location.href = `${rb.baseUrl}/admin/entity/${data.entity}/field/${res.data}`
}
} else {
RbHighbar.error(res.error_msg)
}
})
}
}

View file

@ -15,12 +15,13 @@ $(document).ready(() => {
if (e.which === 13) $('.input-search .btn').trigger('click')
})
$('.J_new-field').on('click', () => {
if (wpc.isSuperAdmin) RbModal.create(`/p/admin/metadata/field-new?entity=${wpc.entityName}`, $L('添加字段'))
// eslint-disable-next-line react/jsx-no-undef
if (wpc.isSuperAdmin) renderRbcomp(<FieldNew2 entity={wpc.entityName} />)
else RbHighbar.error($L('仅超级管理员可添加字段'))
})
$('.J_new2-field').on('click', () => {
if (wpc.isSuperAdmin) RbModal.create(`/p/admin/metadata/field-new2?entity=${wpc.entityName}`, $L('批量添加字段'), { width: 1064 })
$('.J_new9-field').on('click', () => {
if (wpc.isSuperAdmin) RbModal.create(`/p/admin/metadata/field-new9?entity=${wpc.entityName}`, $L('批量添加字段'), { width: 1064 })
else RbHighbar.error($L('仅超级管理员可添加字段'))
})

View file

@ -393,7 +393,8 @@ const render_unset = function (data) {
const render_type = function (fieldType) {
const $item = $(`<li class="dd-item"><div class="dd-handle"><i class="icon mdi ${fieldType.icon || 'mdi-form-textbox'}"></i> ${$L(fieldType.label)}</div></li>`).appendTo('.type-list')
$item.on('click', function () {
if (wpc.isSuperAdmin) RbModal.create(`/p/admin/metadata/field-new?entity=${wpc.entityName}&type=${fieldType.name}`, $L('添加字段'), { disposeOnHide: true })
// eslint-disable-next-line react/jsx-no-undef
if (wpc.isSuperAdmin) renderRbcomp(<FieldNew2 entity={wpc.entityName} fieldType={fieldType.name} />)
else RbHighbar.error($L('仅超级管理员可添加字段'))
})
return $item
@ -514,7 +515,7 @@ class DlgEditRefform extends DlgEditField {
<option value="">{$L('无')}</option>
{Object.keys(_ValidFields).map((k) => {
const field = _ValidFields[k]
if (['REFERENCE', 'ANYREFERENCE'].includes(field.displayTypeName) && field.fieldName !== 'approvalId') {
if (['REFERENCE', 'ANYREFERENCE'].includes(field.displayTypeName) && field.fieldName !== 'approvalId') {
return (
<option key={field.fieldName} value={field.fieldName}>
{field.fieldLabel}
@ -537,19 +538,17 @@ class DlgEditRefform extends DlgEditField {
// 追加到布局
// eslint-disable-next-line no-unused-vars
const add2Layout = function (fieldName) {
const add2Layout = function (fieldName, dlg) {
$.get(`../list-field?entity=${wpc.entityName}`, function (res) {
$(res.data).each(function () {
if (this.fieldName === fieldName) {
render_item({ ...this, tip: this.tip || null })
_ValidFields[fieldName] = this
console.log(JSON.stringify(_ValidFields))
return false
}
})
})
RbModal.hide()
dlg && dlg.hide()
}
// 高级控制

View file

@ -32,7 +32,12 @@ $(document).ready(() => {
.select2({
placeholder: $L('选择关联项'),
allowClear: false,
matcher: $select2MatcherAll,
templateResult: function (res) {
const $span = $('<span class="icon-append"></span>').attr('title', res.text).text(res.text)
const found = _entities[res.id]
if (found) $(`<i class="icon zmdi zmdi-${found.icon}"></i>`).appendTo($span)
return $span
},
})
.on('change', () => {
if (item_current_isNew === true) {

View file

@ -90,7 +90,7 @@ class MessageList extends React.Component {
</div>
</div>
{append && (
<a title={$L('查看记录')} className="badge link" href={`${rb.baseUrl}/app/redirect?id=${item[5]}`}>
<a title={$L('查看记录')} className="badge link" href={`${rb.baseUrl}/app/redirect?id=${item[5]}&type=newtab`} target="_blank">
{$L('查看')}
</a>
)}

View file

@ -164,6 +164,9 @@ See LICENSE and COMMERCIAL in the project root for license information.
$.fn.select2.defaults.set('templateResult', function (res) {
return $('<span></span>').attr('title', res.text).text(res.text)
})
$.fn.select2.defaults.set('matcher', function (params, data) {
return $select2MatcherAll(params, data)
})
})(jQuery)
// extends Array

View file

@ -30,7 +30,7 @@ class RbModal extends React.Component {
this._rbmodal = c
this._element = c
}}>
<div className={`modal-dialog ${props.useWhite && 'modal-xl'}`} style={style2}>
<div className={`modal-dialog ${props.useWhite && 'modal-xl'} ${props.className || ''}`} style={style2}>
<div className="modal-content" style={style2}>
<div
className={`modal-header ${props.useWhite ? '' : 'modal-header-colored'}`}
@ -828,7 +828,6 @@ class AnyRecordSelector extends React.Component {
.select2({
placeholder: $L('无可用实体'),
allowClear: false,
matcher: $select2MatcherAll,
})
.on('change', () => {
$(this._record).val(null).trigger('change')

View file

@ -40,10 +40,10 @@
</div>
</div>
</aside>
<div class="main-content container-fluid">
<div class="main-content container-fluid position-relative">
<div class="quick-filter-tabs" th:if="${advListFilterTabs == 'true'}">
<div>
<div class="dropdown-item"><a>[[${bundle.L('全部数据')}]]</a></div>
<div class="dropdown-item"><a>[[${bundle.L('默认视图')}]]</a></div>
</div>
</div>
<div class="quick-filter-pane" th:if="${advListFilterPane == 'true'}">

View file

@ -40,10 +40,10 @@
</div>
</div>
</aside>
<div class="main-content container-fluid">
<div class="main-content container-fluid position-relative">
<div class="quick-filter-tabs" th:if="${advListFilterTabs == 'true'}">
<div>
<div class="dropdown-item"><a>[[${bundle.L('全部数据')}]]</a></div>
<div class="dropdown-item"><a>[[${bundle.L('默认视图')}]]</a></div>
</div>
</div>
<div class="quick-filter-pane" th:if="${advListFilterPane == 'true'}">