Fix v3.5 beta3 (#686)

* Update @rbv

* be: upload

* enh: 表单回填源字段支持ID

* be: uc

* be: word 上传判断

* fix: 文件移除

* fix: 1.Switch topnav; 2.N details recycle

* fix: ID连接

* be:优化分组聚合回填执行效率

* feat: filter {@CURRENT}

* enh: 记录转换源字段支持ID

* v3.5-beta3

* _placeholderw

* EncodeHintType.ERROR_CORRECTION: L

* lang

---------

Co-authored-by: devezhao <zhaofang123@gmail.com>
This commit is contained in:
REBUILD 企业管理系统 2023-12-02 14:22:04 +08:00 committed by GitHub
parent 6ddfd6e82a
commit f94926ae24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 264 additions and 118 deletions

2
@rbv

@ -1 +1 @@
Subproject commit 2e44d4228c89b993077d9a407f08f4a9c85af11b
Subproject commit 2ab2c88a6c5750feb36c13d3d35358a85fc78501

View file

@ -10,7 +10,7 @@
</parent>
<groupId>com.rebuild</groupId>
<artifactId>rebuild</artifactId>
<version>3.5.0-beta2</version>
<version>3.5.0-beta3</version>
<name>rebuild</name>
<description>Building your business-systems freely!</description>
<!-- UNCOMMENT USE TOMCAT -->

View file

@ -74,11 +74,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
/**
* Rebuild Version
*/
public static final String VER = "3.5.0-beta2";
public static final String VER = "3.5.0-beta3";
/**
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
*/
public static final int BUILD = 3050002;
public static final int BUILD = 3050003;
static {
// Driver for DB

View file

@ -25,9 +25,12 @@ import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyField;
import com.rebuild.core.metadata.easymeta.EasyFile;
import com.rebuild.core.metadata.easymeta.EasyID;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.metadata.easymeta.EasyN2NReference;
import com.rebuild.core.metadata.easymeta.MixValue;
import com.rebuild.core.metadata.impl.EasyFieldConfigProps;
import com.rebuild.core.support.general.FieldValueHelper;
import com.rebuild.utils.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
@ -294,6 +297,8 @@ public class AutoFillinManager implements ConfigManager {
if (!(newValue instanceof String) || sourceEasy instanceof EasyFile) {
newValue = sourceEasy.wrapValue(newValue);
}
} else if (sourceEasy instanceof EasyID && targetEasy instanceof EasyN2NReference) {
newValue = FieldValueHelper.wrapFieldValue(newValue, targetEasy);
}
return newValue;

View file

@ -474,8 +474,8 @@ public class FormsBuilder extends FormsManager {
// 默认值
if (el.get("value") == null) {
if (dt == DisplayType.SERIES
/*|| EntityHelper.ApprovalLastTime.equals(fieldName) || EntityHelper.ApprovalLastRemark.equals(fieldName)*/) {
if (dt == DisplayType.SERIES || EntityHelper.ApprovalLastTime.equals(fieldName)
|| EntityHelper.ApprovalLastRemark.equals(fieldName) || EntityHelper.ApprovalLastUser.equals(fieldName)) {
el.put("readonlyw", READONLYW_RO);
} else {
Object defaultValue = easyField.exprDefaultValue();

View file

@ -21,8 +21,10 @@ import org.springframework.util.Assert;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* 元数据辅助类注意此类返回的数据会过滤和排序
@ -159,14 +161,14 @@ public class MetadataSorter {
*/
static Field[] sortByLevel(List<BaseMeta> fields) {
List<BaseMeta> othersFields = new ArrayList<>();
List<BaseMeta> commonsFields = new ArrayList<>();
List<BaseMeta> approvalFields = new ArrayList<>();
Map<String, BaseMeta> commonsFieldsMap = new HashMap<>();
for (BaseMeta field : fields) {
if (MetadataHelper.isApprovalField(field.getName())) {
approvalFields.add(field);
} else if (MetadataHelper.isCommonsField((Field) field)) {
commonsFields.add(field);
commonsFieldsMap.put(field.getName(), field);
} else {
othersFields.add(field);
}
@ -175,12 +177,20 @@ public class MetadataSorter {
sortByLabel(othersFields);
List<BaseMeta> allFields = new ArrayList<>(othersFields);
sortByLabel(commonsFields);
allFields.addAll(commonsFields);
sortByLabel(approvalFields);
allFields.addAll(approvalFields);
// v35 特殊排序
final String[] SPEC_SORTS = new String[] {
EntityHelper.CreatedBy, EntityHelper.CreatedOn, EntityHelper.ModifiedBy, EntityHelper.ModifiedOn, EntityHelper.OwningUser, EntityHelper.OwningDept
};
List<BaseMeta> commonsFields = new ArrayList<>();
for (String s : SPEC_SORTS) {
BaseMeta b = commonsFieldsMap.get(s);
if (b != null) commonsFields.add(b);
}
allFields.addAll(commonsFields);
return allFields.toArray(new Field[0]);
}

View file

@ -140,7 +140,7 @@ public abstract class EasyField extends BaseEasyMeta<Field> {
/**
* 转换返回值输出用默认实现为原值返回
*
* @param value 原值
* @param value 原值必须符合值类型
* @return
* @see com.rebuild.core.support.general.FieldValueHelper
*/

View file

@ -63,19 +63,21 @@ public class RecycleBean implements Serializable {
JSONObject s = (JSONObject) queryed.serialize();
Entity detailEntity = entity.getDetailEntity();
if (detailEntity == null) {
return s;
}
if (detailEntity == null) return s;
// 明细
String detailSql = buildBaseSql(detailEntity)
.append(MetadataHelper.getDetailToMainField(detailEntity).getName())
.append(" = ?")
.toString();
List<Record> detailQueryed = Application.createQueryNoFilter(detailSql).setParameter(1, this.recordId).list();
// v36 多明细
JSONArray detailList = new JSONArray();
for (Record r : detailQueryed) {
detailList.add(r.serialize());
for (Entity de : entity.getDetialEntities()) {
String detailSql = buildBaseSql(de)
.append(MetadataHelper.getDetailToMainField(de).getName())
.append(" = ?")
.toString();
List<Record> detailQueryed = Application.createQueryNoFilter(detailSql).setParameter(1, this.recordId).list();
for (Record r : detailQueryed) {
JSONObject item = (JSONObject) r.serialize();
item.put(RestoreRecordCreator.META_FIELD, de.getName());
detailList.add(item);
}
}
s.put(NAME_DETAILLIST, detailList);

View file

@ -187,10 +187,22 @@ public class RecycleRestore {
Record record = new RestoreRecordCreator(entity, content).create(true);
records.add(record);
// v36 多明细
Entity detailEntity = entity.getDetailEntity();
if (detailList != null && detailEntity != null) {
for (Object o : detailList) {
Record detail = new RestoreRecordCreator(detailEntity, (JSONObject) o).create(true);
JSONObject item = (JSONObject) o;
Entity de = detailEntity;
if (item.containsKey(RestoreRecordCreator.META_FIELD)) {
String _entity = (String) item.remove(RestoreRecordCreator.META_FIELD);
if (!MetadataHelper.containsEntity(_entity)) {
log.warn("Detail entity not longer exists : {}", _entity);
continue;
}
de = MetadataHelper.getEntity(_entity);
}
Record detail = new RestoreRecordCreator(de, item).create(true);
records.add(detail);
}
}

View file

@ -20,6 +20,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rebuild.core.Application;
import com.rebuild.core.UserContextHolder;
import com.rebuild.core.metadata.EntityHelper;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.easymeta.DisplayType;
@ -46,6 +47,7 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static cn.devezhao.commons.CalendarUtils.addDay;
@ -251,8 +253,7 @@ public class AdvFilterParser extends SetUser {
DisplayType dt = EasyMetaFactory.getDisplayType(lastFieldMeta);
if (dt == DisplayType.CLASSIFICATION
|| (dt == DisplayType.PICKLIST && hasNameFlag) /* 快速查询 */) {
if (dt == DisplayType.CLASSIFICATION || (dt == DisplayType.PICKLIST && hasNameFlag) /* 快速查询 */) {
field = NAME_FIELD_PREFIX + field;
} else if (hasNameFlag) {
if (!(dt == DisplayType.REFERENCE || dt == DisplayType.N2NREFERENCE)) {
@ -717,6 +718,7 @@ public class AdvFilterParser extends SetUser {
private static final String CURRENT_ANY = "CURRENT";
private static final String CURRENT_DATE = "NOW";
// 获取字段变量值
private String useValueOfVarRecord(String value, Field queryField) {
if (StringUtils.isBlank(value) || !value.matches(PATT_FIELDVAR)) return value;
@ -730,6 +732,15 @@ public class AdvFilterParser extends SetUser {
DisplayType dt = EasyMetaFactory.getDisplayType(queryField);
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME || dt == DisplayType.TIME) {
useValue = CalendarUtils.now();
} else if (dt == DisplayType.REFERENCE) {
if (queryField.getReferenceEntity().getEntityCode() == EntityHelper.User) {
useValue = UserContextHolder.getUser();
} else if (queryField.getReferenceEntity().getEntityCode() == EntityHelper.Department) {
Department dept = UserHelper.getDepartment(UserContextHolder.getUser());
if (dept != null) useValue = dept.getIdentity();
}
} else {
log.warn("Cannot use `CURRENT` in `{}` (None date fields)", queryField);
return StringUtils.EMPTY;

View file

@ -232,7 +232,7 @@ public class AggregationEvaluator {
CollectionUtils.addAll(nvList, (ID[]) n);
} else if (n instanceof ID) {
if (field.getType() == FieldType.PRIMARY) {
nvList.add(n.toString()); // 保持主键
nvList.add(n.toString()); // 保持主键为文本
} else {
nvList.add(n);
}

View file

@ -85,7 +85,7 @@ public class FieldAggregation extends TriggerAction {
protected String followSourceWhere;
public FieldAggregation(ActionContext context) {
this(context, Boolean.FALSE);
this(context, Boolean.TRUE);
}
protected FieldAggregation(ActionContext context, boolean ignoreSame) {
@ -215,7 +215,10 @@ public class FieldAggregation extends TriggerAction {
} else if (dt == DisplayType.N2NREFERENCE) {
// 强制去重
Set<ID> idSet = new LinkedHashSet<>();
for (Object id : oArray) idSet.add((ID) id);
for (Object id : oArray) {
if (id instanceof ID) idSet.add((ID) id);
else idSet.add(ID.valueOf((String) id)); // 主键会保持文本
}
targetRecord.setIDArray(targetField, idSet.toArray(new ID[0]));
} else {
@ -274,19 +277,19 @@ public class FieldAggregation extends TriggerAction {
// 回填 (v3.1)
// 仅分组聚合有此配置
String fillbackField = ((JSONObject) actionContext.getActionContent()).getString("fillbackField");
if (fillbackField != null && MetadataHelper.checkAndWarnField(sourceEntity, fillbackField)) {
String sql = String.format("select %s from %s where %s",
sourceEntity.getPrimaryField().getName(), sourceEntity.getName(), filterSql);
String sql = String.format("select %s,%s from %s where %s",
sourceEntity.getPrimaryField().getName(), fillbackField, sourceEntity.getName(), filterSql);
Object[][] fillbacks = Application.createQueryNoFilter(sql).array();
for (Object[] to : fillbacks) {
Record fbRecord = EntityHelper.forUpdate((ID) to[0], UserService.SYSTEM_USER, false);
fbRecord.setID(fillbackField, targetRecordId);
for (Object[] o : fillbacks) {
if (CommonsUtils.isSame(o[1], targetRecordId)) continue;
// FIXME 回填仅更新无业务规则
Application.getCommonsService().update(fbRecord, false);
Record r = EntityHelper.forUpdate((ID) o[0], UserService.SYSTEM_USER, false);
r.setID(fillbackField, targetRecordId);
Application.getCommonsService().update(r, false);
}
}

View file

@ -55,6 +55,7 @@ public class GroupAggregation extends FieldAggregation {
this(context, Boolean.FALSE);
}
// ignoreSame 本触发器有回填忽略同值会导致无法回填
public GroupAggregation(ActionContext context, boolean ignoreSame) {
super(context, ignoreSame);
}

View file

@ -146,7 +146,7 @@ public class BarCodeSupport {
protected static BitMatrix createBarCodeImage(String content, BarcodeFormat format, int width, int height) {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, AppUtils.UTF8);
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 高级别导致空白边框???
hints.put(EncodeHintType.MARGIN, 0);
try {

View file

@ -13,6 +13,7 @@ import cn.devezhao.persist4j.engine.NullValue;
import com.rebuild.core.Application;
import com.rebuild.core.RebuildException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
@ -26,6 +27,7 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
@ -258,17 +260,37 @@ public class CommonsUtils {
* @param b
* @return
*/
@SuppressWarnings("unchecked")
public static boolean isSame(Object a, Object b) {
boolean e = Objects.equals(a, b);
if (!e) {
if (a instanceof Number && b instanceof Number) {
// FIXME 有精度问题
e = ObjectUtils.toDouble(a) == ObjectUtils.toDouble(b);
}
}
return e;
}
if (a == null && b != null) return false;
if (a != null && b == null) return false;
if (Objects.equals(a, b)) return true;
// 数字
if (a instanceof Number && b instanceof Number) {
// FIXME 有精度问题
return ObjectUtils.toDouble(a) == ObjectUtils.toDouble(b);
}
// 集合/数组
if ((a instanceof Collection || a instanceof Object[]) && (b instanceof Collection || b instanceof Object[])) {
Collection<Object> aColl;
if (a instanceof Object[]) aColl = Arrays.asList((Object[]) a);
else aColl = (Collection<Object>) a;
Collection<Object> bColl;
if (b instanceof Object[]) bColl = Arrays.asList((Object[]) b);
else bColl = (Collection<Object>) b;
if (aColl.size() != bColl.size()) return false;
if (aColl.isEmpty()) return true;
return CollectionUtils.containsAll(aColl, bColl) && CollectionUtils.containsAll(bColl, aColl);
}
// 其他
// FIXME 完善不同值类型的比较
return StringUtils.equals(a.toString(), b.toString());
}
/**
* 指定范围的随机数
*

View file

@ -106,6 +106,13 @@ public class ReportTemplateController extends BaseController {
final String file = getParameterNotNull(request, "file");
final int type = getIntParameter(request, "type", DataReportManager.TYPE_RECORD);
boolean isDocx = file.toLowerCase().endsWith(".docx");
if (type == DataReportManager.TYPE_WORD) {
if (!isDocx) return RespBody.errorl("上传 WORD 文件请选择 WORD 模板类型");
} else {
if (isDocx) return RespBody.errorl("上传 EXCEL 文件请选择 EXCEL 模板类型");
}
File template = RebuildConfiguration.getFileOfData(file);
Map<String, String> vars = null;
try {
@ -121,7 +128,7 @@ public class ReportTemplateController extends BaseController {
} catch (Exception ex) {
Log.error(null, ex);
return RespBody.error(Language.L("无效模板文件 (无法读取模板文件)"));
return RespBody.error(Language.L("无效模板文件 (无法读取文件内容)"));
}
if (vars == null || vars.isEmpty()) {

View file

@ -56,7 +56,7 @@ public class FileUploader extends BaseController {
break;
}
if (file == null || file.isEmpty()) {
if (file == null) {
writeFailure(response, "No file found");
return;
}

View file

@ -62,10 +62,12 @@ public class MetadataGetting extends BaseController {
@GetMapping("fields")
public JSON fields(HttpServletRequest request) {
Entity entity = MetadataHelper.getEntity(getParameterNotNull(request, "entity"));
// 返回引用实体的字段
// 返回引用实体的字段层级
int appendRefFields = getIntParameter(request, "deep", 0);
// 返回ID主键字段
boolean forceWithId = getBoolParameter(request, "withid");
return MetaFormatter.buildFieldsWithRefs(entity, appendRefFields, true, field -> {
return MetaFormatter.buildFieldsWithRefs(entity, appendRefFields, true, forceWithId, field -> {
if (!field.isQueryable()) return true;
if (field instanceof Field) {

View file

@ -79,6 +79,7 @@ public class MetaFormatter {
* @param deep
* @param filter
* @return
* @see #buildFieldsWithRefs(Entity, int, boolean, boolean, Predicate)
*/
public static JSONArray buildFieldsWithRefs(Entity entity, int deep, Predicate<BaseMeta> filter) {
return buildFieldsWithRefs(entity, deep, false, filter);
@ -90,8 +91,23 @@ public class MetaFormatter {
* @param riching
* @param filter
* @return
* @see #buildFieldsWithRefs(Entity, int, boolean, boolean, Predicate)
*/
public static JSONArray buildFieldsWithRefs(Entity entity, int deep, boolean riching, Predicate<BaseMeta> filter) {
return buildFieldsWithRefs(entity, deep, riching, false, filter);
}
/**
* 获取字段列表
*
* @param entity
* @param deep 几级
* @param riching
* @param forceWithId 带有主键ID
* @param filter
* @return
*/
public static JSONArray buildFieldsWithRefs(Entity entity, int deep, boolean riching, boolean forceWithId, Predicate<BaseMeta> filter) {
JSONArray res = new JSONArray();
// 一级
@ -101,6 +117,10 @@ public class MetaFormatter {
res.add(buildField(easyField, null, riching));
}
if (forceWithId) {
res.add(buildField(EasyMetaFactory.valueOf(entity.getPrimaryField()), null, false));
}
if (deep < 2) return res;
List<Object[]> deep3Refs = new ArrayList<>();

View file

@ -60,6 +60,8 @@ import java.util.Set;
@RequestMapping({"/commons/search/","/app/entity/"})
public class ReferenceSearchController extends EntityController {
private static final String _SELF = "{@CURRENT}";
// 引用字段-快速搜索
@GetMapping({"reference", "quick"})
public JSON referenceSearch(@EntityParam Entity entity, HttpServletRequest request) {
@ -153,6 +155,14 @@ public class ReferenceSearchController extends EntityController {
}
List<Object> result = resultSearch(searchWhere, searchEntity, maxResults);
// v35 本人/本部门
if ("self".equals(q)) {
if (sec == EntityHelper.User || sec == EntityHelper.Department) {
result.add(JSONUtils.toJSONObject(
new String[]{ "id", "text" }, new Object[] { _SELF, Language.L("本人/本部门") }));
}
}
return (JSON) JSON.toJSON(result);
}
@ -240,17 +250,20 @@ public class ReferenceSearchController extends EntityController {
Map<String, String> labels = new HashMap<>();
for (String id : ids.split("[|,]")) {
if (!ID.isId(id)) continue;
if (!ID.isId(id)) {
if (_SELF.equals(id)) {
labels.put(_SELF, Language.L("本人/本部门"));
}
continue;
}
ID recordId = ID.valueOf(id);
final ID recordId = ID.valueOf(id);
if (checkPrivileges && !Application.getPrivilegesManager().allowRead(user, recordId)) continue;
if (ignoreMiss) {
try {
labels.put(id, FieldValueHelper.getLabel(recordId));
} catch (NoRecordFoundException ignored) {
}
} catch (NoRecordFoundException ignored) {}
} else {
labels.put(id, FieldValueHelper.getLabelNotry(recordId));
}

View file

@ -157,7 +157,7 @@ public class TransformConfigController extends BaseController {
JSONArray fields;
//
if (sourceType) {
fields = MetaFormatter.buildFieldsWithRefs(entity, 3, true, field -> {
fields = MetaFormatter.buildFieldsWithRefs(entity, 3, true, true, field -> {
if (field instanceof EasyField) {
EasyField easyField = (EasyField) field;
int c = easyField.getDisplayType() == DisplayType.REFERENCE

View file

@ -2832,5 +2832,14 @@
"仅更新不要新建":"仅更新不要新建",
"输入内容":"输入内容",
"定位中":"定位中",
"查看 PDF":"查看 PDF"
"查看 PDF":"查看 PDF",
"数据库字段违反约束":"数据库字段违反约束",
"上传 EXCEL 文件请选择 EXCEL 模板类型":"上传 EXCEL 文件请选择 EXCEL 模板类型",
"本人/本部门":"本人/本部门",
"查看原图":"查看原图",
"去重连接*N":"去重连接*N",
"无效模板文件 (无法读取文件内容)":"无效模板文件 (无法读取文件内容)",
"请正确填写目标实体/记录匹配规则":"请正确填写目标实体/记录匹配规则",
"上传 WORD 文件请选择 WORD 模板类型":"上传 WORD 文件请选择 WORD 模板类型",
"APP 安装包":"APP 安装包"
}

View file

@ -41,6 +41,7 @@
text-shadow: 0 1px #fff;
border-radius: 4px;
padding: 15px;
font-family: ui-monospace, 'Cascadia Mono', 'Segoe UI Mono', 'Liberation Mono', Menlo, Monaco, Consolas, monospace !important;
}
.search-logs > input {
appearance: none !important;

View file

@ -338,11 +338,11 @@
<div class="card mt-3 J_cloudAccount hide">
<div class="card-header card-header-divider">REBUILD [[${bundle.L('云账号')}]]</div>
<div class="card-body">
<div class="J_not-bind">
<div class="J_not-bind hide">
<p>[[${bundle.L('绑定 REBUILD 云账号,获取更多专享服务与资源,还有免费系统安全与健康检测。')}]]</p>
<button class="btn btn-primary btn-sm pl-3 pr-3" type="button">[[${bundle.L('点击绑定')}]]</button>
</div>
<div class="J_has-bind">
<div class="J_has-bind hide">
<p class="mb-1 mt-1 text-bold">
<i class="mdi mdi-shield-check icon up-3"></i>
[[${bundle.L('当前已绑定云账号')}]] <a href="https://getrebuild.com/ucenter/account" target="_blank" class="text-uppercase"></a>
@ -362,7 +362,7 @@
}
</script>
<script th:src="@{/assets/js/admin/syscfg.js}" type="text/babel"></script>
<script th:src="@{/assets/js/admin/syscfg-g.js}" type="text/babel"></script>
<script th:src="@{/assets/js/admin/system-cfg.js}" type="text/babel"></script>
<script th:src="@{/assets/js/rebuild-ucenter.js}" type="text/babel"></script>
</body>
</html>

View file

@ -1163,7 +1163,7 @@ a.link.link-icon::after {
position: absolute;
right: 0;
top: 0;
font-size: 1.1rem;
font-size: 1.15rem;
color: #fff;
cursor: default;
background-color: rgba(0, 0, 0, 0.3);

View file

@ -133,7 +133,7 @@ class ReportEditor extends ConfigFormDlg {
<span className="custom-control-label">{$L('EXCEL 列表')}</span>
</label>
<label className="custom-control custom-control-sm custom-radio custom-control-inline mb-0">
<input className="custom-control-input" type="radio" value="4" name="reportType" onChange={() => this.checkTemplate()} />
<input className="custom-control-input J_word4" type="radio" value="4" name="reportType" onChange={() => this.checkTemplate()} />
<span className="custom-control-label">
WORD <sup className="rbv" />
</span>
@ -244,6 +244,8 @@ class ReportEditor extends ConfigFormDlg {
$mp.end()
that.__lastFile = res.key
if (this.__select2) {
// 自动选择 WORD
if (that.__lastFile.toLowerCase().endsWith('.docx')) $('.J_word4').attr('checked', true)
that.checkTemplate()
} else {
const fileName = $fileCutName(this.__lastFile)

View file

@ -27,12 +27,13 @@ $(document).ready(() => {
// UC
UCenter.query((res) => {
const bindAccount = res.bindAccount
$('.J_cloudAccount').removeClass('hide')
if (bindAccount) {
$('.J_not-bind').addClass('hide')
$('.J_cloudAccount').removeClass('hide')
$('.J_has-bind').removeClass('hide')
$('.J_has-bind a').text(bindAccount)
} else if (rb.commercial === 10 || rb.commercial === 20) {
$('.J_has-bind').addClass('hide')
$('.J_cloudAccount').removeClass('hide')
$('.J_not-bind').removeClass('hide')
$('.J_not-bind .btn').on('click', () => {
if (res.canBind) UCenter.bind()
else RbHighbar.create($L('仅超级管理员可操作'))

View file

@ -121,7 +121,7 @@ class RbPreview extends React.Component {
<a className="arrow float-left" onClick={this._rotateImage} title={$L('旋转')}>
<i className="mdi mdi-rotate-right" />
</a>
<a className="arrow float-right" onClick={this._screenImage} title={$L('适合页面')}>
<a className="arrow float-right" onClick={this._screenImage} title={$L('查看原图')}>
<i className="mdi mdi-fit-to-screen-outline" />
</a>
</div>

View file

@ -177,7 +177,7 @@ class DlgRuleEdit extends RbFormHandler {
this.__select2.push($s2target)
// #2
$.get(`/commons/metadata/fields?entity=${this.props.sourceEntity}&deep=2`, (res) => {
$.get(`/commons/metadata/fields?entity=${this.props.sourceEntity}&deep=2&withid=true`, (res) => {
this.__sourceFieldsCache = res.data
this.setState({ sourceFields: res.data }, () => {
const $s2source = $(this._sourceField)

View file

@ -469,7 +469,7 @@ class FilterItem extends React.Component {
]
} else if (fieldType === 'TIME') {
op = ['GT', 'LT', 'EQ', 'BW']
} else if (fieldType === 'FILE' || fieldType === 'IMAGE' || fieldType === 'AVATAR' || fieldType === 'SIGN') {
} else if (fieldType === 'FILE' || fieldType === 'IMAGE' || fieldType === 'AVATAR' || fieldType === 'SIGN' || fieldType === 'ANYREFERENCE') {
op = []
} else if (fieldType === 'PICKLIST' || fieldType === 'STATE' || fieldType === 'MULTISELECT') {
op = ['IN', 'NIN']

View file

@ -1408,7 +1408,7 @@ class RbListPagination extends React.Component {
`/p/admin/metadata/list-stats?entity=${this._entity}`,
<RF>
{$L('配置统计列')}
<sup className="rbv" title={$L('增值功能')} />
<sup className="rbv" />
</RF>
)
}>

View file

@ -261,7 +261,7 @@ class RbForm extends React.Component {
for (let k in iv) {
let val = iv[k]
// array, object, simple
val = typeof val === 'object' ? val.id || val : val
val = val && typeof val === 'object' ? val.id || val : val
this.__FormData[k] = { value: val, error: null }
}
}
@ -783,6 +783,16 @@ class RbFormElement extends React.Component {
constructor(props) {
super(props)
this.state = { ...props }
// v35
this._isNew = props.$$$parent.isNew
if (props.readonly) {
if (this._isNew) {
this._placeholderw = props.readonlyw >= 2 ? $L('自动值') : null
} else if (!this.state.value) {
this._placeholderw = $L('无')
}
}
}
render() {
@ -855,7 +865,7 @@ class RbFormElement extends React.Component {
onChange={(e) => this.handleChange(e, this.props.readonly ? false : true)}
// onBlur={this.props.readonly ? null : () => this.checkValue()}
readOnly={this.props.readonly}
placeholder={this.props.readonlyw > 0 ? $L('自动值') : null}
placeholder={this._placeholderw}
maxLength={this.props.maxLength || 200}
/>
)
@ -903,7 +913,7 @@ class RbFormElement extends React.Component {
this.setState({ hasError: err || null })
const errMsg = err ? this.props.label + ' ' + err : null
if (this.isValueUnchanged() && !this.props.$$$parent.isNew) {
if (this.isValueUnchanged() && !this._isNew) {
if (err) this.props.$$$parent.setFieldValue(this.props.field, this.state.value, errMsg)
else this.props.$$$parent.setFieldUnchanged(this.props.field, this.state.value)
} else {
@ -1135,7 +1145,7 @@ class RbFormNumber extends RbFormText {
onChange={(e) => this.handleChange(e, !this.props.readonly)}
// onBlur={this.props.readonly ? null : () => this.checkValue()}
readOnly={this.props.readonly}
placeholder={this.props.readonlyw > 0 ? $L('自动值') : null}
placeholder={this._placeholderw}
maxLength="29"
/>
{this.__valueFlag && <em className="vflag">{this.__valueFlag}</em>}
@ -1287,7 +1297,7 @@ class RbFormTextarea extends RbFormElement {
onChange={(e) => this.handleChange(e, !this.props.readonly)}
// onBlur={this.props.readonly ? null : () => this.checkValue()}
readOnly={this.props.readonly}
placeholder={this.props.readonlyw > 0 ? $L('自动值') : null}
placeholder={this._placeholderw}
maxLength="6000"
/>
{this.props.useMdedit && !this.props.readonly && <input type="file" className="hide" accept="image/*" data-noname="true" ref={(c) => (this._fieldValue__upload = c)} />}
@ -1435,7 +1445,7 @@ class RbFormDateTime extends RbFormElement {
value={this.state.value || ''}
onChange={(e) => this.handleChange(e, !this.props.readonly)}
// onBlur={this.props.readonly ? null : () => this.checkValue()}
placeholder={this.props.readonlyw > 0 ? $L('自动值') : null}
placeholder={this._placeholderw}
maxLength="20"
/>
<span className={'zmdi zmdi-close clean ' + (this.state.value ? '' : 'hide')} onClick={() => this.handleClear()} />
@ -1566,12 +1576,7 @@ class RbFormImage extends RbFormElement {
<a title={$fileCutName(item)} className="img-thumbnail img-upload" onClick={() => this._filePreview(value, idx)}>
<img src={this._formatUrl(item)} alt="IMG" />
{!this.props.readonly && (
<b
title={$L('移除')}
onClick={(e) => {
$stopEvent(e)
this.removeItem(item)
}}>
<b title={$L('移除')} onClick={(e) => this.removeItem(item, e)}>
<span className="zmdi zmdi-close" />
</b>
)}
@ -1660,7 +1665,8 @@ class RbFormImage extends RbFormElement {
}
}
removeItem(item) {
removeItem(item, e) {
e && $stopEvent(e, true)
const paths = this.state.value || []
paths.remove(item)
this.handleChange({ target: { value: paths } }, true)
@ -1697,7 +1703,7 @@ class RbFormFile extends RbFormImage {
<i className="file-icon" data-type={$fileExtName(fileName)} />
<span>{fileName}</span>
{!this.props.readonly && (
<b title={$L('移除')} onClick={() => this.removeItem(item)}>
<b title={$L('移除')} onClick={(e) => this.removeItem(item, e)}>
<span className="zmdi zmdi-close" />
</b>
)}
@ -1802,12 +1808,12 @@ class RbFormPickList extends RbFormElement {
}
isValueUnchanged() {
if (this.props.$$$parent.isNew === true) return false
if (this._isNew === true) return false
return super.isValueUnchanged()
}
setValue(val) {
if (typeof val === 'object') val = val.id
if (val && typeof val === 'object') val = val.id
this.__select2.val(val).trigger('change')
}
}
@ -1866,7 +1872,7 @@ class RbFormReference extends RbFormElement {
// 新建记录时触发回填
const props = this.props
if (props.$$$parent.isNew && props.value && props.value.id) {
if (this._isNew && props.value && props.value.id) {
setTimeout(() => this.triggerAutoFillin(props.value.id), 500)
}
}
@ -1885,7 +1891,7 @@ class RbFormReference extends RbFormElement {
const cascadingValue = this._getCascadingFieldValue()
return cascadingValue ? { cascadingValue, ...query } : query
},
placeholder: this.props.readonlyw === 3 ? $L('自动值') : null,
placeholder: this._placeholderw,
})
const val = this.state.value
@ -2115,7 +2121,7 @@ class RbFormN2NReference extends RbFormReference {
handleChange(e, checkValue) {
let val = e.target.value
if (typeof val === 'object') val = val.join(',')
if (val && typeof val === 'object') val = val.join(',')
this.setState({ value: val }, () => checkValue === true && this.checkValue())
}
@ -2315,9 +2321,9 @@ class RbFormMultiSelect extends RbFormElement {
}
_getMaskValue() {
const value = this.state.value
if (!value) return 0
return typeof value === 'object' ? value.id : value
const val = this.state.value
if (!val) return 0
return typeof val === 'object' ? val.id : val
}
}
@ -2474,7 +2480,7 @@ class RbFormAvatar extends RbFormElement {
class RbFormLocation extends RbFormElement {
constructor(props) {
super(props)
this._autoLocation = props.locationAutoLocation && props.$$$parent.isNew && !props.value
this._autoLocation = props.locationAutoLocation && this._isNew && !props.value
}
renderElement() {
@ -2502,7 +2508,7 @@ class RbFormLocation extends RbFormElement {
value={lnglat ? lnglat.text || '' : ''}
onChange={(e) => this.handleChange(e)}
readOnly
placeholder={this.props.readonlyw > 0 ? $L('自动值') : null}
placeholder={this._placeholderw}
onClick={() => this._showMap(lnglat)}
/>
@ -2541,11 +2547,11 @@ class RbFormLocation extends RbFormElement {
)
}
_parseLnglat(value) {
if (!value) return null
if (typeof value === 'object') return value
_parseLnglat(val) {
if (!val) return null
if (typeof val === 'object') return val
const vals = value.split('$$$$')
const vals = val.split('$$$$')
const lnglat = vals[1] ? vals[1].split(',') : null // 无坐标
return {
text: vals[0],
@ -2691,7 +2697,7 @@ class RbFormTag extends RbFormElement {
let options = [...props.options]
let selected = []
if (props.$$$parent.isNew) {
if (this._isNew) {
props.options.forEach((item) => {
if (item.default) selected.push(item.name)
})
@ -2715,7 +2721,7 @@ class RbFormTag extends RbFormElement {
this._initOptions()
} else {
this.__select2 = $(this._fieldValue).select2({
placeholder: this.props.readonlyw === 3 ? $L('自动值') : $L('输入%s', this.props.label),
placeholder: this.props.readonlyw > 0 ? this._placeholderw : $L('输入%s', this.props.label),
maximumSelectionLength: this.__maxSelect,
tags: true,
language: {
@ -2737,7 +2743,7 @@ class RbFormTag extends RbFormElement {
}
setValue(val) {
if (typeof val === 'object') val = val.join('$$$$')
if (val && typeof val === 'object') val = val.join('$$$$')
super.setValue(val)
// fix: v3.4.4

View file

@ -8,7 +8,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
/* !!! KEEP IT ES5 COMPATIBLE !!! */
// GA
(function () {
;(function () {
var gaScript = document.createElement('script')
gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-ZCZHJPMEG7'
gaScript.async = true
@ -180,21 +180,20 @@ $(function () {
})
})
if (window.sessionStorage) {
$('.navbar .navbar-collapse>.navbar-nav a').on('click', function (e) {
sessionStorage.setItem('AppHome._InTab', e.target.href.split('?')[1])
})
var $topNavs = $('.navbar .navbar-collapse>.navbar-nav a')
if ($topNavs.length > 1) {
document.onvisibilitychange = function () {
if (document.visibilityState !== 'visible') return
var tabHome = sessionStorage.getItem('AppHome._InTab')
tabHome &&
$(tabHome.split('&')).each(function () {
var active = $('.navbar .navbar-collapse>.navbar-nav li.active>a').attr('href')
if (active) {
active = active.split('?')[1].split('&')
$(active).each(function () {
var nv = this.split('=')
if (nv[0] === 'n') $.cookie('AppHome.Nav', nv[1], { expires: null })
if (nv[0] === 'd') $.cookie('AppHome.Dash', nv[1], { expires: null })
if (nv[0] === 'n') $.cookie('AppHome.Nav', nv[1], { expires: 30 })
if (nv[0] === 'd') $.cookie('AppHome.Dash', nv[1], { expires: 30 })
})
}
console.log('Switch on visibilityState ...', $.cookie('AppHome.Nav'), $.cookie('AppHome.Dash'))
}
}
@ -742,23 +741,24 @@ var $unmount = function (container, delay, keepContainer) {
/**
* 初始化引用字段搜索
*/
var $initReferenceSelect2 = function (el, options) {
var $initReferenceSelect2 = function (el, option) {
console.log(option)
var search_input = null
var $el = $(el).select2({
placeholder: options.placeholder || $L('选择%s', options.label),
placeholder: option.placeholder || $L('选择%s', option.label),
minimumInputLength: 0,
maximumSelectionLength: $(el).attr('multiple') ? 999 : 2,
ajax: {
url: '/commons/search/' + (options.searchType || 'reference'),
url: '/commons/search/' + (option.searchType || 'reference'),
delay: 300,
data: function (params) {
search_input = params.term
var query = {
entity: options.entity,
field: options.name,
entity: option.entity,
field: option.name,
q: params.term,
}
if (options && typeof options.wrapQuery === 'function') return options.wrapQuery(query)
if (option && typeof option.wrapQuery === 'function') return option.wrapQuery(query)
else return query
},
processResults: function (data) {
@ -782,7 +782,7 @@ var $initReferenceSelect2 = function (el, options) {
return $L('清除')
},
},
theme: 'default ' + (options.appendClass || ''),
theme: 'default ' + (option.appendClass || ''),
})
return $el
@ -1119,3 +1119,22 @@ var $pages = function (tp, cp) {
if (end <= tp) pages.push(tp)
return pages
}
// 格式化代码
var $formattedCode = function (c, type) {
if (typeof c === 'object') c = JSON.stringify(c)
if (!window.prettier) return c
try {
// eslint-disable-next-line no-undef
return prettier.format(c, {
parser: type || 'json',
// eslint-disable-next-line no-undef
plugins: prettierPlugins,
printWidth: 10,
})
} catch (err) {
console.log('Cannot format code :', err)
return c
}
}