mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 07:25:54 +08:00
Fix 3.6 beta4 (#729)
* fix: case TEXT to NTEXT * fix: getReplacedUser * be: view show * fix: 字段类型转换属性冲突 * fix: *N * CommonsUtils.DEVLOG * feat: filter token: REP * feat: advfilter valuesPlus * lang * fix: toJSONObject * fix: DataList2Chart * style --------- Co-authored-by: devezhao <zhaofang123@gmail.com>
This commit is contained in:
parent
ea86c421a9
commit
8504946d76
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit a2b338694068b3bfa059af4e83f669686515ef00
|
||||
Subproject commit c24b2e835e839341f850de2161cff51525ee6cfc
|
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
|||
</parent>
|
||||
<groupId>com.rebuild</groupId>
|
||||
<artifactId>rebuild</artifactId>
|
||||
<version>3.6.0-beta3</version>
|
||||
<version>3.6.0-beta4</version>
|
||||
<name>rebuild</name>
|
||||
<description>Building your business-systems freely!</description>
|
||||
<url>https://getrebuild.com/</url>
|
||||
|
|
|
@ -74,11 +74,11 @@ public class Application implements ApplicationListener<ApplicationStartedEvent>
|
|||
/**
|
||||
* Rebuild Version
|
||||
*/
|
||||
public static final String VER = "3.6.0-beta3";
|
||||
public static final String VER = "3.6.0-beta4";
|
||||
/**
|
||||
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
|
||||
*/
|
||||
public static final int BUILD = 3060003;
|
||||
public static final int BUILD = 3060004;
|
||||
|
||||
static {
|
||||
// Driver for DB
|
||||
|
|
|
@ -44,8 +44,10 @@ public class UserContextHolder {
|
|||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户
|
||||
*
|
||||
* @param user
|
||||
* @see #clearUser()
|
||||
* @see #replaceUser(ID)
|
||||
*/
|
||||
public static void setUser(ID user) {
|
||||
Assert.notNull(user, "[user] cannot be null");
|
||||
|
@ -119,20 +121,37 @@ public class UserContextHolder {
|
|||
}
|
||||
|
||||
/**
|
||||
* 设置当前用户,并保持原始用户(如有)
|
||||
*
|
||||
* @param user
|
||||
* @see #getReplacedUser()
|
||||
* @see #restoreUser()
|
||||
* @see #setUser(ID)
|
||||
*/
|
||||
public static void replaceUser(ID user) {
|
||||
Assert.notNull(user, "[user] cannot be null");
|
||||
|
||||
ID e = getUser(Boolean.TRUE);
|
||||
// Keep origin
|
||||
ID e = CALLER_PREV.get();
|
||||
if (e == null) e = getUser(Boolean.TRUE);
|
||||
|
||||
if (e != null) CALLER_PREV.set(e);
|
||||
else CALLER_PREV.remove();
|
||||
|
||||
CALLER.set(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始用户
|
||||
*
|
||||
* @return
|
||||
* @see #replaceUser(ID)
|
||||
*/
|
||||
public static ID getReplacedUser() {
|
||||
ID prev = CALLER_PREV.get();
|
||||
if (prev != null) return prev;
|
||||
return getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see #replaceUser(ID)
|
||||
|
@ -147,16 +166,6 @@ public class UserContextHolder {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see #replaceUser(ID)
|
||||
*/
|
||||
public static ID getRestoreUser() {
|
||||
ID prev = CALLER_PREV.get();
|
||||
if (prev != null) return prev;
|
||||
return getUser();
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,6 +13,7 @@ import cn.devezhao.persist4j.Entity;
|
|||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.dialect.Dialect;
|
||||
import cn.devezhao.persist4j.dialect.FieldType;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import cn.devezhao.persist4j.metadata.CascadeModel;
|
||||
import cn.devezhao.persist4j.metadata.impl.AnyEntity;
|
||||
|
@ -20,6 +21,7 @@ import cn.devezhao.persist4j.metadata.impl.FieldImpl;
|
|||
import cn.devezhao.persist4j.util.StringHelper;
|
||||
import cn.devezhao.persist4j.util.support.Table;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.hankcs.hanlp.HanLP;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
|
@ -38,12 +40,16 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.apache.commons.lang.CharSet;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.sql.DataTruncation;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.rebuild.core.metadata.impl.EasyFieldConfigProps.NUMBER_CALCFORMULA;
|
||||
import static com.rebuild.core.metadata.impl.EasyFieldConfigProps.NUMBER_NOTNEGATIVE;
|
||||
|
||||
/**
|
||||
* 创建字段
|
||||
*
|
||||
|
@ -421,9 +427,9 @@ public class Field2Schema extends SetUser {
|
|||
* @return
|
||||
*/
|
||||
public boolean castType(Field field, DisplayType toType, boolean force) {
|
||||
EasyField easyMeta = EasyMetaFactory.valueOf(field);
|
||||
ID metaRecordId = easyMeta.getMetaId();
|
||||
if (easyMeta.isBuiltin() || metaRecordId == null) {
|
||||
EasyField fieldEasy = EasyMetaFactory.valueOf(field);
|
||||
ID metaRecordId = fieldEasy.getMetaId();
|
||||
if (fieldEasy.isBuiltin() || metaRecordId == null) {
|
||||
throw new MetadataModificationException(Language.L("系统内置,不允许转换"));
|
||||
}
|
||||
|
||||
|
@ -434,9 +440,27 @@ public class Field2Schema extends SetUser {
|
|||
}
|
||||
}
|
||||
|
||||
Record meta = EntityHelper.forUpdate(metaRecordId, getUser(), false);
|
||||
meta.setString("displayType", toType.name());
|
||||
Application.getCommonsService().update(meta, false);
|
||||
Record fieldMeta = EntityHelper.forUpdate(metaRecordId, getUser(), false);
|
||||
fieldMeta.setString("displayType", toType.name());
|
||||
// 长度
|
||||
if (toType.getMaxLength() != FieldType.NO_NEED_LENGTH) {
|
||||
fieldMeta.setInt("maxLength", toType.getMaxLength());
|
||||
}
|
||||
// 保留部分扩展配置,其余移除避免冲突
|
||||
JSONObject extraAttrs = fieldEasy.getExtraAttrs();
|
||||
if (!extraAttrs.isEmpty()) {
|
||||
Object notNegative = extraAttrs.remove(NUMBER_NOTNEGATIVE);
|
||||
Object calcFormula = extraAttrs.remove(NUMBER_CALCFORMULA);
|
||||
|
||||
extraAttrs.clear();
|
||||
if (notNegative != null) extraAttrs.put(NUMBER_NOTNEGATIVE, notNegative);
|
||||
if (calcFormula != null) extraAttrs.put(NUMBER_CALCFORMULA, calcFormula);
|
||||
|
||||
if (!extraAttrs.isEmpty()) {
|
||||
fieldMeta.setString("extConfig", extraAttrs.toJSONString());
|
||||
}
|
||||
}
|
||||
Application.getCommonsService().update(fieldMeta, false);
|
||||
|
||||
// 类型生效
|
||||
DynamicMetadataContextHolder.setSkipLanguageRefresh();
|
||||
|
@ -452,18 +476,25 @@ public class Field2Schema extends SetUser {
|
|||
|
||||
alterTypeSql = String.format("alter table `%s` change column `%s` ",
|
||||
field.getOwnEntity().getPhysicalName(), field.getPhysicalName());
|
||||
alterTypeSql += ddl.toString().trim().replace(" ", "");
|
||||
alterTypeSql += ddl.toString().trim().replace(" ", " ");
|
||||
|
||||
Application.getSqlExecutor().executeBatch(new String[]{alterTypeSql}, DDL_TIMEOUT);
|
||||
log.info("Cast field type : {}", alterTypeSql);
|
||||
|
||||
} catch (Throwable ex) {
|
||||
// 还原
|
||||
meta.setString("displayType", EasyMetaFactory.getDisplayType(field).name());
|
||||
Application.getCommonsService().update(meta, false);
|
||||
fieldMeta.setString("displayType", EasyMetaFactory.getDisplayType(field).name());
|
||||
Application.getCommonsService().update(fieldMeta, false);
|
||||
|
||||
log.error("DDL ERROR : \n" + alterTypeSql, ex);
|
||||
throw new MetadataModificationException(ThrowableUtils.getRootCause(ex).getLocalizedMessage());
|
||||
|
||||
Throwable cause = ThrowableUtils.getRootCause(ex);
|
||||
String causeMsg = cause.getLocalizedMessage();
|
||||
if (cause instanceof DataTruncation) {
|
||||
causeMsg = Language.L("已有数据内容长度超出限制,无法完成转换");
|
||||
}
|
||||
throw new MetadataModificationException(causeMsg);
|
||||
|
||||
} finally {
|
||||
MetadataHelper.getMetadataFactory().refresh();
|
||||
DynamicMetadataContextHolder.isSkipLanguageRefresh(true);
|
||||
|
|
|
@ -351,7 +351,7 @@ public class ApprovalProcessor extends SetUser {
|
|||
|
||||
int bLength = nextNodes.size();
|
||||
for (FlowNode node : nextNodes) {
|
||||
// 匹配最后一个
|
||||
// 匹配最后一个分支
|
||||
if (--bLength == 0) {
|
||||
return getNextNode(node.getNodeId());
|
||||
}
|
||||
|
|
|
@ -60,15 +60,17 @@ public class DataList2Chart extends ChartData {
|
|||
}
|
||||
|
||||
int pageSize = config.getJSONObject("option").getIntValue("pageSize");
|
||||
if (pageSize == 0) pageSize = 40;
|
||||
if (pageSize <= 0) pageSize = 40;
|
||||
if (pageSize >= 2000) pageSize = 2000;
|
||||
|
||||
JSONObject listConfig = new JSONObject();
|
||||
listConfig.put("pageNo", 1);
|
||||
listConfig.put("pageSize", Math.max(pageSize, 1));
|
||||
listConfig.put("pageSize", pageSize);
|
||||
listConfig.put("reload", false);
|
||||
listConfig.put("statsField", false);
|
||||
listConfig.put("entity", entity.getName());
|
||||
listConfig.put("fields", fields);
|
||||
listConfig.put("filter", config.getJSONObject("filter"));
|
||||
if (sort != null) listConfig.put("sort", sort);
|
||||
|
||||
DataListBuilder builder = new DataListBuilderImpl(listConfig, getUser());
|
||||
|
|
|
@ -12,7 +12,6 @@ import cn.devezhao.persist4j.PersistManagerFactory;
|
|||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
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.privileges.UserService;
|
||||
|
@ -121,7 +120,7 @@ public abstract class BaseFeedsService extends ObservableService {
|
|||
|
||||
String atAllKey = "@" + Language.L("所有人");
|
||||
if (fakeContent.contains(atAllKey)
|
||||
&& Application.getPrivilegesManager().allow(UserContextHolder.getUser(), ZeroEntry.AllowAtAllUsers)) {
|
||||
&& Application.getPrivilegesManager().allow(getCurrentUser(), ZeroEntry.AllowAtAllUsers)) {
|
||||
fakeContent = fakeContent.replace(atAllKey, "@" + UserService.ALLUSERS);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import cn.devezhao.persist4j.PersistManagerFactory;
|
|||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.privileges.OperationDeniedException;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
|
@ -43,7 +42,7 @@ public class FeedsService extends BaseFeedsService {
|
|||
public Record createOrUpdate(Record record) {
|
||||
Integer type = record.getInt("type");
|
||||
if (type != null && type == FeedsType.ANNOUNCEMENT.getMask()
|
||||
&& !UserHelper.isAdmin(UserContextHolder.getUser())) {
|
||||
&& !UserHelper.isAdmin(getCurrentUser())) {
|
||||
throw new OperationDeniedException(Language.L("仅管理员可发布公告"));
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import cn.devezhao.persist4j.Record;
|
|||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.RebuildException;
|
||||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.metadata.DeleteRecord;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
|
@ -273,7 +272,7 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
|
||||
@Override
|
||||
public int delete(ID recordId, String[] cascades) {
|
||||
final ID currentUser = UserContextHolder.getUser();
|
||||
final ID currentUser = getCurrentUser();
|
||||
final RecycleStore recycleBin = useRecycleStore(recordId);
|
||||
|
||||
int affected = this.deleteInternal(recordId);
|
||||
|
@ -317,7 +316,7 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
* @throws DataSpecificationException
|
||||
*/
|
||||
protected int deleteInternal(ID recordId) throws DataSpecificationException {
|
||||
Record delete = EntityHelper.forUpdate(recordId, UserContextHolder.getUser());
|
||||
Record delete = EntityHelper.forUpdate(recordId, getCurrentUser());
|
||||
if (!checkModifications(delete, BizzPermission.DELETE)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -374,14 +373,14 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
}
|
||||
|
||||
if (countObservers() > 0 && assignBefore != null) {
|
||||
notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.ASSIGN, assignBefore, assignAfter));
|
||||
notifyObservers(OperatingContext.create(getCurrentUser(), BizzPermission.ASSIGN, assignBefore, assignAfter));
|
||||
}
|
||||
return affected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int share(ID recordId, ID toUserId, String[] cascades, int rights) {
|
||||
final ID currentUser = UserContextHolder.getUser();
|
||||
final ID currentUser = getCurrentUser();
|
||||
final ID recordOrigin = recordId;
|
||||
// v3.2.2 若为明细则转为主记录
|
||||
if (MetadataHelper.getEntity(recordId.getEntityCode()).getMainEntity() != null) {
|
||||
|
@ -459,7 +458,7 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
|
||||
@Override
|
||||
public int unshare(ID recordId, ID accessId) {
|
||||
final ID currentUser = UserContextHolder.getUser();
|
||||
final ID currentUser = getCurrentUser();
|
||||
|
||||
Record unsharedBefore = null;
|
||||
if (countObservers() > 0) {
|
||||
|
@ -543,7 +542,7 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
if (fromTriggerNoFilter) {
|
||||
array = Application.createQueryNoFilter(sql).array();
|
||||
} else {
|
||||
Filter filter = Application.getPrivilegesManager().createQueryFilter(UserContextHolder.getUser(), action);
|
||||
Filter filter = Application.getPrivilegesManager().createQueryFilter(getCurrentUser(), action);
|
||||
array = Application.getQueryFactory().createQuery(sql, filter).array();
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ public abstract class ObservableService extends SafeObservable implements Servic
|
|||
record = delegateService.create(record);
|
||||
|
||||
if (countObservers() > 0) {
|
||||
notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.CREATE, null, record));
|
||||
notifyObservers(OperatingContext.create(getCurrentUser(), BizzPermission.CREATE, null, record));
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
@ -76,15 +76,14 @@ public abstract class ObservableService extends SafeObservable implements Servic
|
|||
record = delegateService.update(record);
|
||||
|
||||
if (countObservers() > 0) {
|
||||
notifyObservers(OperatingContext.create(UserContextHolder.getUser(), BizzPermission.UPDATE, before, record));
|
||||
notifyObservers(OperatingContext.create(getCurrentUser(), BizzPermission.UPDATE, before, record));
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(ID recordId) {
|
||||
ID currentUser = UserContextHolder.getRestoreUser();
|
||||
if (currentUser == null) currentUser = UserContextHolder.getUser();
|
||||
final ID currentUser = getCurrentUser();
|
||||
|
||||
Record deleted = null;
|
||||
if (countObservers() > 0) {
|
||||
|
@ -126,7 +125,7 @@ public abstract class ObservableService extends SafeObservable implements Servic
|
|||
* @return 返回 null 表示没开启
|
||||
*/
|
||||
protected RecycleStore useRecycleStore(ID recordId) {
|
||||
final ID currentUser = UserContextHolder.getUser();
|
||||
final ID currentUser = getCurrentUser();
|
||||
|
||||
RecycleStore recycleBin = null;
|
||||
if (RecycleBinCleanerJob.isEnableRecycleBin()) {
|
||||
|
@ -141,4 +140,13 @@ public abstract class ObservableService extends SafeObservable implements Servic
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始用户
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected ID getCurrentUser() {
|
||||
return UserContextHolder.getReplacedUser();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ package com.rebuild.core.service.project;
|
|||
|
||||
import cn.devezhao.persist4j.PersistManagerFactory;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.configuration.ConfigBean;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.service.DataSpecificationException;
|
||||
|
@ -37,7 +36,7 @@ public abstract class BaseTaskService extends ObservableService {
|
|||
* @return
|
||||
*/
|
||||
protected boolean checkModifications(ID user, ID taskOrProject) {
|
||||
if (user == null) user = UserContextHolder.getUser();
|
||||
if (user == null) user = getCurrentUser();
|
||||
Assert.notNull(taskOrProject, "taskOrProject");
|
||||
|
||||
ConfigBean c = taskOrProject.getEntityCode() == EntityHelper.ProjectTask
|
||||
|
|
|
@ -11,7 +11,6 @@ import cn.devezhao.persist4j.PersistManagerFactory;
|
|||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.privileges.OperationDeniedException;
|
||||
import com.rebuild.core.service.feeds.FeedsHelper;
|
||||
|
@ -40,7 +39,7 @@ public class ProjectCommentService extends BaseTaskService {
|
|||
|
||||
@Override
|
||||
public Record create(Record record) {
|
||||
final ID user = UserContextHolder.getUser();
|
||||
final ID user = getCurrentUser();
|
||||
checkModifications(user, record.getID("taskId"));
|
||||
|
||||
record = super.create(record);
|
||||
|
@ -56,7 +55,7 @@ public class ProjectCommentService extends BaseTaskService {
|
|||
|
||||
@Override
|
||||
public int delete(ID commentId) {
|
||||
final ID user = UserContextHolder.getUser();
|
||||
final ID user = getCurrentUser();
|
||||
if (!ProjectHelper.isManageable(commentId, user)) throw new OperationDeniedException();
|
||||
|
||||
return super.delete(commentId);
|
||||
|
|
|
@ -12,7 +12,6 @@ import cn.devezhao.persist4j.PersistManagerFactory;
|
|||
import cn.devezhao.persist4j.Record;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.UserContextHolder;
|
||||
import com.rebuild.core.configuration.ConfigBean;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.privileges.OperationDeniedException;
|
||||
|
@ -49,7 +48,7 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
|
||||
@Override
|
||||
public Record create(Record record) {
|
||||
final ID user = UserContextHolder.getUser();
|
||||
final ID user = getCurrentUser();
|
||||
checkModifications(user, record.getID("projectId"));
|
||||
|
||||
ID projectId = record.getID("projectId");
|
||||
|
@ -73,7 +72,7 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
|
||||
@Override
|
||||
public Record update(Record record) {
|
||||
final ID user = UserContextHolder.getUser();
|
||||
final ID user = getCurrentUser();
|
||||
checkModifications(user, record.getPrimary());
|
||||
|
||||
// 自动完成
|
||||
|
@ -118,7 +117,7 @@ public class ProjectTaskService extends BaseTaskService {
|
|||
|
||||
@Override
|
||||
public int delete(ID taskId) {
|
||||
final ID user = UserContextHolder.getUser();
|
||||
final ID user = getCurrentUser();
|
||||
if (!ProjectHelper.isManageable(taskId, user)) throw new OperationDeniedException();
|
||||
|
||||
// 先删评论
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.apache.commons.lang.math.NumberUtils;
|
|||
import org.springframework.util.Assert;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
@ -141,8 +142,26 @@ public class AdvFilterParser extends SetUser {
|
|||
|
||||
// 自动确定查询项
|
||||
if (MODE_QUICK.equalsIgnoreCase(filterExpr.getString("type"))) {
|
||||
JSONArray quickItems = buildQuickFilterItems(filterExpr.getString("quickFields"));
|
||||
this.filterExpr.put("items", quickItems);
|
||||
String quickFields = filterExpr.getString("quickFields");
|
||||
JSONArray quickItems = buildQuickFilterItems(quickFields, 1);
|
||||
|
||||
// // v3.6-b4 值1|值2 UNTEST
|
||||
// // 转义可输入 \|
|
||||
// JSONObject values = filterExpr.getJSONObject("values");
|
||||
// String[] valuesPlus = values.values().iterator().next().toString().split("(?<!\\\\)\\|");
|
||||
// if (valuesPlus.length > 1) {
|
||||
// values.clear();
|
||||
// values.put("1", valuesPlus[0].trim());
|
||||
//
|
||||
// for (int i = 2; i <= valuesPlus.length; i++) {
|
||||
// JSONArray quickItemsPlus = buildQuickFilterItems(quickFields, i);
|
||||
// values.put(String.valueOf(i), valuesPlus[i - 1].trim());
|
||||
// quickItems.addAll(quickItemsPlus);
|
||||
// }
|
||||
// filterExpr.put("values", values);
|
||||
// }
|
||||
|
||||
filterExpr.put("items", quickItems);
|
||||
}
|
||||
|
||||
JSONArray items = filterExpr.getJSONArray("items");
|
||||
|
@ -167,7 +186,7 @@ public class AdvFilterParser extends SetUser {
|
|||
indexItemSqls.put(index, itemSql.trim());
|
||||
this.includeFields.add(item.getString("field"));
|
||||
}
|
||||
if (Application.devMode()) System.out.println("[dev] Parse item : " + item + " >> " + itemSql);
|
||||
if (CommonsUtils.DEVLOG) System.out.println("[dev] Parse item : " + item + " >> " + itemSql);
|
||||
}
|
||||
|
||||
if (indexItemSqls.isEmpty()) return null;
|
||||
|
@ -182,7 +201,7 @@ public class AdvFilterParser extends SetUser {
|
|||
} else if ("AND".equalsIgnoreCase(equation)) {
|
||||
return "( " + StringUtils.join(indexItemSqls.values(), " and ") + " )";
|
||||
} else {
|
||||
// 高级表达式 eg. (1 AND 2) or (3 AND 4)
|
||||
// 高级表达式 eg: (1 AND 2) or (3 AND 4)
|
||||
String[] tokens = equation.toLowerCase().split(" ");
|
||||
List<String> itemSqls = new ArrayList<>();
|
||||
for (String token : tokens) {
|
||||
|
@ -530,10 +549,15 @@ public class AdvFilterParser extends SetUser {
|
|||
}
|
||||
} else if (ParseHelper.SFT.equalsIgnoreCase(op)) {
|
||||
if (value == null) value = "0"; // No any
|
||||
// In Sql
|
||||
// `in`
|
||||
value = String.format(
|
||||
"( select userId from TeamMember where teamId in ('%s') )",
|
||||
StringUtils.join(value.split("\\|"), "', '"));
|
||||
} else if (ParseHelper.REP.equalsIgnoreCase(op)) {
|
||||
// `in`
|
||||
value = MessageFormat.format(
|
||||
"( select {0} from {1} group by {0} having (count({0}) > {2}) )",
|
||||
field, rootEntity.getName(), NumberUtils.toInt(value, 1));
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(value)) {
|
||||
|
@ -564,7 +588,8 @@ public class AdvFilterParser extends SetUser {
|
|||
|
||||
// IN
|
||||
if (op.equalsIgnoreCase(ParseHelper.IN) || op.equalsIgnoreCase(ParseHelper.NIN)
|
||||
|| op.equalsIgnoreCase(ParseHelper.SFD) || op.equalsIgnoreCase(ParseHelper.SFT)) {
|
||||
|| op.equalsIgnoreCase(ParseHelper.SFD) || op.equalsIgnoreCase(ParseHelper.SFT)
|
||||
|| op.equalsIgnoreCase(ParseHelper.REP)) {
|
||||
sb.append(value);
|
||||
} else {
|
||||
// LIKE
|
||||
|
@ -702,12 +727,12 @@ public class AdvFilterParser extends SetUser {
|
|||
* @param quickFields
|
||||
* @return
|
||||
*/
|
||||
private JSONArray buildQuickFilterItems(String quickFields) {
|
||||
private JSONArray buildQuickFilterItems(String quickFields, int valueIndex) {
|
||||
Set<String> usesFields = ParseHelper.buildQuickFields(rootEntity, quickFields);
|
||||
|
||||
JSONArray items = new JSONArray();
|
||||
for (String field : usesFields) {
|
||||
items.add(JSON.parseObject("{ op:'LK', value:'{1}', field:'" + field + "' }"));
|
||||
items.add(JSON.parseObject("{ op:'LK', value:'{" + valueIndex + "}', field:'" + field + "' }"));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,8 @@ public class ParseHelper {
|
|||
public static final String EVW = "EVW"; // 每周几
|
||||
public static final String EVM = "EVM"; // 每月几
|
||||
|
||||
public static final String REP = "REP"; // 重复的
|
||||
|
||||
// 日期时间
|
||||
|
||||
public static final String ZERO_TIME = " 00:00:00";
|
||||
|
@ -165,7 +167,7 @@ public class ParseHelper {
|
|||
return "=";
|
||||
} else if (SFB.equalsIgnoreCase(token)) {
|
||||
return "=";
|
||||
} else if (SFD.equalsIgnoreCase(token) || SFT.equalsIgnoreCase(token)) {
|
||||
} else if (SFD.equalsIgnoreCase(token) || SFT.equalsIgnoreCase(token) || REP.equalsIgnoreCase(token)) {
|
||||
return "in";
|
||||
} else if (YTA.equalsIgnoreCase(token)) {
|
||||
return "=";
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.rebuild.core.service.trigger.impl.FieldAggregation;
|
|||
import com.rebuild.core.support.CommonsLog;
|
||||
import com.rebuild.core.support.general.FieldValueHelper;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.utils.CommonsUtils;
|
||||
import com.rebuild.web.KnownExceptionConverter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -167,7 +168,7 @@ public class RobotTriggerObserver extends OperatingObserver {
|
|||
Object res = action.execute(context);
|
||||
|
||||
boolean hasAffected = res instanceof TriggerResult && ((TriggerResult) res).hasAffected();
|
||||
System.out.println("[dev] " + w + " > " + (res == null ? "N" : res) + (hasAffected ? " < REALLY AFFECTED" : ""));
|
||||
if (CommonsUtils.DEVLOG) System.out.println("[dev] " + w + " > " + (res == null ? "N" : res) + (hasAffected ? " < REALLY AFFECTED" : ""));
|
||||
|
||||
if (res instanceof TriggerResult) {
|
||||
if (originTriggerSource) {
|
||||
|
|
|
@ -9,6 +9,7 @@ package com.rebuild.core.service.trigger;
|
|||
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.rebuild.core.service.general.OperatingContext;
|
||||
import com.rebuild.utils.CommonsUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -38,7 +39,7 @@ public class TriggerSource {
|
|||
protected TriggerSource(OperatingContext origin, TriggerWhen originAction) {
|
||||
this.id = TSNO.incrementAndGet() + "-";
|
||||
addNext(origin, originAction);
|
||||
System.out.println("[dev] New trigger-source : " + this);
|
||||
if (CommonsUtils.DEVLOG) System.out.println("[dev] New trigger-source : " + this);
|
||||
|
||||
// Clear
|
||||
if (this.id.length() > 4) TSNO.set(0);
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.rebuild.core.metadata.easymeta.EasyField;
|
|||
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
||||
import com.rebuild.core.service.trigger.aviator.AviatorUtils;
|
||||
import com.rebuild.core.support.general.ContentWithFieldVars;
|
||||
import com.rebuild.core.support.general.FieldValueHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
@ -227,6 +228,11 @@ public class AggregationEvaluator {
|
|||
Object n = o[0];
|
||||
if (n == null) continue;
|
||||
|
||||
// *N
|
||||
if (n instanceof ID && mode == 3) {
|
||||
n = FieldValueHelper.getLabel((ID) n, StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
// 多引用
|
||||
if (n instanceof ID[]) {
|
||||
CollectionUtils.addAll(nvList, (ID[]) n);
|
||||
|
|
|
@ -119,7 +119,7 @@ public class FieldAggregation extends TriggerAction {
|
|||
List<String> tschain = TRIGGER_CHAIN.get();
|
||||
if (tschain == null) {
|
||||
tschain = new ArrayList<>();
|
||||
System.out.println("[dev] New trigger-chain : " + this);
|
||||
if (CommonsUtils.DEVLOG) System.out.println("[dev] New trigger-chain : " + this);
|
||||
} else {
|
||||
String w = String.format("Occured trigger-chain : %s > %s (current)", StringUtils.join(tschain, " > "), chainName);
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ public class FieldWriteback extends FieldAggregation {
|
|||
List<String> tschainCurrentLoop = new ArrayList<>(tschain);
|
||||
tschainCurrentLoop.add(chainName);
|
||||
TRIGGER_CHAIN.set(tschainCurrentLoop);
|
||||
System.out.println("[dev] Use current-loop tschain : " + tschainCurrentLoop);
|
||||
if (CommonsUtils.DEVLOG) System.out.println("[dev] Use current-loop tschain : " + tschainCurrentLoop);
|
||||
|
||||
try {
|
||||
if (stopPropagation) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import cn.devezhao.commons.ObjectUtils;
|
|||
import cn.devezhao.commons.ReflectUtils;
|
||||
import cn.devezhao.persist4j.engine.NullValue;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.BootApplication;
|
||||
import com.rebuild.core.RebuildException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
@ -42,6 +43,9 @@ import java.util.regex.Pattern;
|
|||
@Slf4j
|
||||
public class CommonsUtils {
|
||||
|
||||
// 打印开发级别日志
|
||||
public static final boolean DEVLOG = BootApplication.devMode();
|
||||
|
||||
// 通用分隔符
|
||||
public static final String COMM_SPLITER = "$$$$";
|
||||
// 通用分隔符 REGEX
|
||||
|
|
|
@ -44,7 +44,7 @@ public class JSONUtils {
|
|||
* @return
|
||||
*/
|
||||
public static JSONObject toJSONObject(String[] keys, Object[] values) {
|
||||
Assert.isTrue(keys.length == values.length, "K/V length mismatch");
|
||||
Assert.isTrue(values.length >= keys.length, "K/V length mismatch");
|
||||
|
||||
Map<String, Object> map = new HashMap<>(keys.length);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
|
|
|
@ -174,7 +174,7 @@ public class NotificationController extends BaseController {
|
|||
long time = (mm.getStartTime().getTime() - CalendarUtils.now().getTime()) / 1000;
|
||||
String note = mm.getNote() == null ? "" : String.format(" (%s)", mm.getNote());
|
||||
DateFormat df = CalendarUtils.getDateFormat("yyyy-MM-dd HH:mm");
|
||||
String msg = Language.L("系统将于 %s (%d 分钟后) 进行维护%s,预计 %s 完成。在此期间系统将无法使用,请及时保存数据,以免造成数据丢失![]如有重要操作正在进行,请联系系统管理员调整维护时间。",
|
||||
String msg = Language.L("系统将于 %s (%d 分钟后) 进行维护%s,预计 %s 完成。[]维护期间系统无法使用,请及时保存数据。如有重要操作正在进行,请联系系统管理员调整维护时间。",
|
||||
df.format(mm.getStartTime()), Math.max(time / 60, 1), note, df.format(mm.getEndTime()));
|
||||
|
||||
return JSONUtils.toJSONObject(new String[] { "msg", "time" }, new Object[] { msg, time });
|
||||
|
|
|
@ -2941,5 +2941,15 @@
|
|||
"选择设备":"选择设备",
|
||||
"录制":"录制",
|
||||
"拍摄":"拍摄",
|
||||
"停止":"停止"
|
||||
"停止":"停止",
|
||||
"已有数据内容长度超出限制,无法完成转换":"已有数据内容长度超出限制,无法完成转换",
|
||||
"确认打开外部网站?":"确认打开外部网站?",
|
||||
"重复":"重复",
|
||||
"审批已退回":"审批已退回",
|
||||
"确认删除 APP 安装包?":"确认删除 APP 安装包?",
|
||||
"系统将于 %s (%d 分钟后) 进行维护%s,预计 %s 完成。[]维护期间系统无法使用,请及时保存数据。如有重要操作正在进行,请联系系统管理员调整维护时间。":"系统将于 %s (%d 分钟后) 进行维护%s,预计 %s 完成。[]维护期间系统无法使用,请及时保存数据。如有重要操作正在进行,请联系系统管理员调整维护时间。",
|
||||
"无法进行合并,因为你对部分记录无操作权限":"无法进行合并,因为你对部分记录无操作权限",
|
||||
"主":"主",
|
||||
"附加内容":"附加内容",
|
||||
"禁用后子部门及其下用户将会同时禁用":"禁用后子部门及其下用户将会同时禁用"
|
||||
}
|
|
@ -104,7 +104,7 @@
|
|||
<div>
|
||||
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline">
|
||||
<input class="custom-control-input" type="checkbox" id="disabledViewEditable" />
|
||||
<span class="custom-control-label">[[${bundle.L('禁用详情页单字段编辑')}]] <i class="support-plat2 mdi mdi-monitor" th:title="${bundle.L('支持 PC')}"></i></span>
|
||||
<span class="custom-control-label">[[${bundle.L('禁用详情页单字段编辑')}]]</span>
|
||||
</label>
|
||||
</div>
|
||||
<th:block th:if="${currentEntity == mainEntity || detailEntity == null}">
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
.support-plat2 {
|
||||
margin-left: -22px;
|
||||
}
|
||||
.J_advOpt .custom-control-inline {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -215,7 +218,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div th:if="${fieldType == 'IMAGE'}" class="form-group row J_for-IMAGE">
|
||||
<label class="col-md-12 col-xl-3 col-lg-4 col-form-label text-lg-right pt-1">[[${bundle.L('仅允许拍照上传')}]] </label>
|
||||
<label class="col-md-12 col-xl-3 col-lg-4 col-form-label text-lg-right pt-1">[[${bundle.L('仅允许拍照上传')}]]</label>
|
||||
<div class="col-md-12 col-xl-6 col-lg-8">
|
||||
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline mb-0">
|
||||
<input class="custom-control-input" type="checkbox" id="imageCapture" />
|
||||
|
@ -449,28 +452,34 @@
|
|||
<div class="form-group row hide J_advOpt">
|
||||
<label class="col-md-12 col-xl-3 col-lg-4 col-form-label text-lg-right pt-1">[[${bundle.L('高级选项')}]] <sup class="rbv"></sup></label>
|
||||
<div class="col-md-12 col-xl-6 col-lg-8">
|
||||
<label class="custom-control custom-control-sm custom-checkbox bosskey-show">
|
||||
<input class="custom-control-input" type="checkbox" id="fieldQueryable" th:data-o="${fieldQueryable}" />
|
||||
<span class="custom-control-label">
|
||||
[[${bundle.L('允许使用')}]]
|
||||
<i class="zmdi zmdi-help zicon" data-toggle="tooltip" th:title="${bundle.L('不允许使用的字段对普通用户不可见')}"></i>
|
||||
</span>
|
||||
</label>
|
||||
<label class="custom-control custom-control-sm custom-checkbox">
|
||||
<input class="custom-control-input" type="checkbox" id="textScanCode" th:data-o="${textScanCode}" />
|
||||
<span class="custom-control-label">
|
||||
[[${bundle.L('启用扫码')}]]
|
||||
<i class="zmdi zmdi-help zicon" data-toggle="tooltip" th:title="${bundle.L('仅可在手机版企业微信、钉钉中使用')}"></i>
|
||||
</span>
|
||||
</label>
|
||||
<label class="custom-control custom-control-sm custom-checkbox">
|
||||
<input class="custom-control-input" type="checkbox" id="advDesensitized" />
|
||||
<span class="custom-control-label">
|
||||
[[${bundle.L('信息脱敏')}]]
|
||||
<i class="zmdi zmdi-help zicon" data-toggle="tooltip" th:title="${bundle.L('可在权限角色中启用“允许查看明文”选项')}"></i>
|
||||
</span>
|
||||
</label>
|
||||
<div>
|
||||
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline bosskey-show">
|
||||
<input class="custom-control-input" type="checkbox" id="fieldQueryable" th:data-o="${fieldQueryable}" />
|
||||
<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>
|
||||
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline">
|
||||
<input class="custom-control-input" type="checkbox" id="textScanCode" th:data-o="${textScanCode}" />
|
||||
<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>
|
||||
<label class="custom-control custom-control-sm custom-checkbox custom-control-inline">
|
||||
<input class="custom-control-input" type="checkbox" id="advDesensitized" />
|
||||
<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 style="margin-top: 0.25rem">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control form-control-sm"
|
||||
|
@ -493,6 +502,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row footer">
|
||||
<div class="col-md-12 col-xl-6 col-lg-8 offset-xl-3 offset-lg-4">
|
||||
<div th:if="${!fieldBuildin}" class="J_action">
|
||||
|
|
|
@ -276,8 +276,12 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
top: 0;
|
||||
}
|
||||
|
||||
.chart-box.ApprovalList .progress-wrap .progress {
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
.chart-box.ApprovalList .progress-wrap .progress-bar {
|
||||
min-width: 20px;
|
||||
min-width: 20%;
|
||||
}
|
||||
|
||||
.chart-box.ApprovalList .progress-wrap .progress-bar:hover {
|
||||
|
|
|
@ -185,6 +185,10 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.record-merge-table table > thead > tr > th {
|
||||
border-bottom-color: #aaa;
|
||||
}
|
||||
|
||||
.record-merge-table table th {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
@ -194,26 +198,62 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.record-merge-table table td.active {
|
||||
background-color: #f5f8fd;
|
||||
background-color: #dee2e6;
|
||||
.record-merge-table table td > div,
|
||||
.record-merge-table table th > a {
|
||||
max-width: 500px;
|
||||
word-wrap: break-word;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.record-merge-table table td.sysfield {
|
||||
cursor: not-allowed;
|
||||
.record-merge-table table td > div > a::after {
|
||||
content: ', ';
|
||||
color: #404040;
|
||||
}
|
||||
|
||||
.record-merge-table table td > div > a:last-child::after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
.record-merge-table table td > div > a:hover {
|
||||
color: #4285f4 !important;
|
||||
}
|
||||
|
||||
.record-merge-table table td.active {
|
||||
border: 1px double #34a853;
|
||||
background-color: #f5f8fd;
|
||||
}
|
||||
|
||||
.record-merge-table table td.active::after {
|
||||
font-family: 'Material Design Icons', serif;
|
||||
content: '\F012C';
|
||||
position: absolute;
|
||||
right: 7px;
|
||||
top: 5px;
|
||||
right: 6px;
|
||||
top: 6px;
|
||||
color: #34a853;
|
||||
font-size: 1.12rem;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.record-merge-table table tr.bt2 {
|
||||
border-top: 2px solid #dee2e6;
|
||||
.record-merge-table table tbody tr:first-child td.active::before {
|
||||
height: 1px;
|
||||
line-height: 1;
|
||||
font-size: 0;
|
||||
content: '';
|
||||
position: absolute;
|
||||
background-color: #34a853;
|
||||
top: -1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.record-merge-table table td.sysfield {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.record-merge-table table tr.bt2 {
|
||||
border-top: 2px solid #aaa;
|
||||
}
|
||||
|
||||
.record-merge-table table tr.bt2 label {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,14 @@ body {
|
|||
padding: 41px 0;
|
||||
}
|
||||
|
||||
.view-body.loading .main-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.view-body.loading .view-header > .header-icon::before {
|
||||
animation: flash 2s infinite;
|
||||
}
|
||||
|
||||
.tab-container {
|
||||
margin-top: -8px;
|
||||
padding-right: 4px;
|
||||
|
|
|
@ -279,13 +279,18 @@ $(document).ready(() => {
|
|||
$('button.J_MobileAppPath').on('click', () => $input[0].click())
|
||||
|
||||
const $del = $('button.J_MobileAppPath-del').on('click', () => {
|
||||
$.post(location.href, JSON.stringify({ MobileAppPath: '' }), (res) => {
|
||||
if (res.error_code === 0) {
|
||||
$('a.J_MobileAppPath').removeAttr('href').text('')
|
||||
$del.addClass('hide')
|
||||
} else {
|
||||
RbHighbar.error(res.error_msg)
|
||||
}
|
||||
RbAlert.create($L('确认删除 APP 安装包?'), {
|
||||
onConfirm: function () {
|
||||
this.hide()
|
||||
$.post(location.href, JSON.stringify({ MobileAppPath: '' }), (res) => {
|
||||
if (res.error_code === 0) {
|
||||
$('a.J_MobileAppPath').removeAttr('href').text('')
|
||||
$del.addClass('hide')
|
||||
} else {
|
||||
RbHighbar.error(res.error_msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -690,7 +690,7 @@ class ApprovalList extends BaseChart {
|
|||
const s = APPROVAL_STATES[item[0]]
|
||||
if (!s || s[1] <= 0) return null
|
||||
|
||||
const p = ((item[1] * 100) / statsTotal).toFixed(2) + '%'
|
||||
const p = ((item[1] * 100) / statsTotal).toFixed(1) + '%'
|
||||
return (
|
||||
<div
|
||||
key={s[0]}
|
||||
|
@ -800,6 +800,7 @@ class ApprovalList extends BaseChart {
|
|||
// eslint-disable-next-line react/jsx-no-undef
|
||||
renderRbcomp(<ApprovalApproveForm id={record} approval={approval} entity={entity} call={close} />, null, function () {
|
||||
that.__approvalForms[record] = this
|
||||
that._lastStats = null
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -342,6 +342,7 @@ const OP_TYPE = {
|
|||
EVW: $L('本周..'),
|
||||
EVM: $L('本月..'),
|
||||
DDD: $L('指定..天'),
|
||||
REP: $L('重复') + ' (LAB)',
|
||||
}
|
||||
const OP_NOVALUE = ['NL', 'NT', 'SFU', 'SFB', 'SFD', 'YTA', 'TDA', 'TTA', 'PUW', 'CUW', 'NUW', 'PUM', 'CUM', 'NUM', 'PUQ', 'CUQ', 'NUQ', 'PUY', 'CUY', 'NUY']
|
||||
const OP_DATE_NOPICKER = [
|
||||
|
@ -375,6 +376,7 @@ const OP_DATE_NOPICKER = [
|
|||
'EVW',
|
||||
'EVM',
|
||||
'DDD',
|
||||
'REP',
|
||||
]
|
||||
const REFENTITY_CACHE = {}
|
||||
const PICKLIST_CACHE = {}
|
||||
|
@ -493,6 +495,9 @@ class FilterItem extends React.Component {
|
|||
op = ['IN', 'NIN']
|
||||
}
|
||||
|
||||
// UNTEST
|
||||
// if (['TEXT', 'PHONE', 'EMAIL', 'URL', 'DATE', 'PICKLIST', 'CLASSIFICATION'].includes(fieldType)) op.push('REP')
|
||||
|
||||
if (this.isApprovalState()) op = ['IN', 'NIN']
|
||||
else if (this.state.field === VF_ACU) op = ['IN', 'SFU', 'SFB', 'SFT']
|
||||
else op.push('NL', 'NT')
|
||||
|
|
|
@ -609,7 +609,7 @@ class ApprovalApproveForm extends ApprovalUsersForm {
|
|||
RbHighbar.error(res.error_msg)
|
||||
} else {
|
||||
_alert && _alert.hide(true)
|
||||
_reload(this, state === 10 ? $L('审批已同意') : $L('审批已驳回'))
|
||||
_reload(this, state === 10 ? $L('审批已同意') : rejectNode ? $L('审批已退回') : $L('审批已驳回'))
|
||||
typeof this.props.call === 'function' && this.props.call()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1842,6 +1842,7 @@ CellRenders.addRender('TAG', function (v, s, k) {
|
|||
class RecordMerger extends RbModalHandler {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state.keepMain = props.ids[0]
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -1861,11 +1862,12 @@ class RecordMerger extends RbModalHandler {
|
|||
idData.map((item, idx) => {
|
||||
if (idx === 0) return null
|
||||
return (
|
||||
<th key={idx} data-id={item[0]}>
|
||||
<strong>{item[1]}</strong>
|
||||
<a href={`${rb.baseUrl}/app/redirect?id=${item[0]}&type=newtab`} target="_blank" title={$L('打开')}>
|
||||
<th key={idx} data-id={item[0]} onClick={() => this.setState({ keepMain: item[0] })}>
|
||||
<a href={`${rb.baseUrl}/app/redirect?id=${item[0]}&type=newtab`} target="_blank" title={$L('打开')} onClick={(e) => $stopEvent(e)}>
|
||||
<b className="fs-12">{item[1]}</b>
|
||||
<i className="icon zmdi zmdi zmdi-open-in-new ml-1" />
|
||||
</a>
|
||||
{this.state.keepMain === item[0] && <span className="badge badge-success badge-pill ml-1">{$L('主')}</span>}
|
||||
</th>
|
||||
)
|
||||
})}
|
||||
|
@ -1874,15 +1876,26 @@ class RecordMerger extends RbModalHandler {
|
|||
<tbody ref={(c) => (this._$tbody = c)}>
|
||||
{datas.map((item, idx) => {
|
||||
if (idx === 0) return null
|
||||
if ($isSysMask(item[0][1])) return null
|
||||
|
||||
let chk
|
||||
const data4field = []
|
||||
for (let i = 1; i < item.length; i++) {
|
||||
let s = item[i]
|
||||
let v = item[i]
|
||||
let activeClazz
|
||||
if ($empty(item[i])) {
|
||||
s = <span className="text-muted">{$L('空')}</span>
|
||||
if ($empty(v)) {
|
||||
v = <span className="text-muted">{$L('空')}</span>
|
||||
} else {
|
||||
if ($.isArray(v)) {
|
||||
v = v.map(function (item) {
|
||||
return (
|
||||
<a key={item} onClick={() => RbPreview.create(item)}>
|
||||
{$fileCutName(item)}
|
||||
</a>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
activeClazz = 'active'
|
||||
if (chk) activeClazz = null
|
||||
if (activeClazz) chk = true
|
||||
|
@ -1892,8 +1905,8 @@ class RecordMerger extends RbModalHandler {
|
|||
if (IS_COMMONS) activeClazz = 'sysfield'
|
||||
|
||||
data4field.push(
|
||||
<td key={`${idx}-${i}`} data-index={i} className={activeClazz} onClick={(e) => !IS_COMMONS && this._chkValue(e)}>
|
||||
{s}
|
||||
<td key={`${idx}-${i}`} data-index={i} className={activeClazz} onClick={(e) => !IS_COMMONS && this._selectValue(e)}>
|
||||
<div>{v}</div>
|
||||
</td>
|
||||
)
|
||||
}
|
||||
|
@ -1951,8 +1964,8 @@ class RecordMerger extends RbModalHandler {
|
|||
})
|
||||
}
|
||||
|
||||
_chkValue(e) {
|
||||
const $td = $(e.target)
|
||||
_selectValue(e) {
|
||||
const $td = $(e.currentTarget)
|
||||
$td.parent().find('td').removeClass('active')
|
||||
$td.addClass('active')
|
||||
}
|
||||
|
@ -1991,7 +2004,6 @@ class RecordMerger extends RbModalHandler {
|
|||
merged[field] = id || null
|
||||
}
|
||||
})
|
||||
console.log(merged)
|
||||
|
||||
const details = []
|
||||
$(this._$mergeDetails)
|
||||
|
@ -1999,15 +2011,26 @@ class RecordMerger extends RbModalHandler {
|
|||
.each(function () {
|
||||
details.push($(this).val())
|
||||
})
|
||||
const url = `/app/${this.props.entity}/record-merge/merge?ids=${this.props.ids.join(',')}&deleteAfter=${del || false}&mergeDetails=${details.join(',')}`
|
||||
|
||||
// 主第一、排重
|
||||
let ids = [this.state.keepMain]
|
||||
this.props.ids.forEach(function (id) {
|
||||
if (!ids.includes(id)) ids.push(id)
|
||||
})
|
||||
|
||||
const url = `/app/${this.props.entity}/record-merge/merge?ids=${ids.join(',')}&deleteAfter=${del || false}&mergeDetails=${details.join(',')}`
|
||||
const $btn = $(this._$btn).find('.btn').button('loading')
|
||||
$.post(url, JSON.stringify(merged), (res) => {
|
||||
if (res.error_code === 0) {
|
||||
this.hide()
|
||||
RbHighbar.success($L('合并成功'))
|
||||
this.props.listRef.reload()
|
||||
|
||||
setTimeout(() => {
|
||||
CellRenders.clickView({ id: res.data, entity: this.props.entity })
|
||||
window.RbViewModal.create({ id: res.data, entity: this.props.entity })
|
||||
if (window.RbListPage) {
|
||||
location.hash = `!/View/${this.props.entity}/${res.data}`
|
||||
}
|
||||
}, 500)
|
||||
} else {
|
||||
RbHighbar.error(res.error_msg)
|
||||
|
|
|
@ -736,18 +736,13 @@ class RepeatedViewer extends RbModalHandler {
|
|||
return <td key={`col-${idx}-${i}`}>{o || <span className="text-muted">{$L('无')}</span>}</td>
|
||||
})}
|
||||
<td className="actions">
|
||||
<button type="button" className="btn btn-light btn-sm w-auto" onClick={() => this.openView(item[0])} title={$L('查看详情')}>
|
||||
<a className="btn btn-light btn-sm w-auto" style={{ lineHeight: '28px' }} title={$L('打开')} href={`${rb.baseUrl}/app/redirect?id=${item[0]}&type=newtab`} target="_blank">
|
||||
<i className="zmdi zmdi-open-in-new fs-16 down-2" />
|
||||
</button>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
openView(id) {
|
||||
if (window.RbViewModal) window.RbViewModal.create({ id: id, entity: this.props.entity })
|
||||
else window.open(`${rb.baseUrl}/app/entity/view?id=${id}`)
|
||||
}
|
||||
}
|
||||
|
||||
// -- LiteForm
|
||||
|
|
|
@ -112,7 +112,7 @@ class RbViewForm extends React.Component {
|
|||
if (res.error_code === 0) {
|
||||
if (res.data.lastModified !== this.__lastModified) {
|
||||
handle && handle.showLoading()
|
||||
setTimeout(() => location.reload(), window.VIEW_LOAD_DELAY || 200)
|
||||
setTimeout(() => location.reload(), 200)
|
||||
}
|
||||
} else if (res.error_msg === 'NO_EXISTS') {
|
||||
this.renderViewError($L('记录已经不存在,可能已被其他用户删除'))
|
||||
|
@ -594,6 +594,7 @@ const RbViewPage = {
|
|||
|
||||
renderRbcomp(<RbViewForm entity={entity[0]} id={id} onViewEditable={ep && ep.U} />, 'tab-rbview', function () {
|
||||
RbViewPage._RbViewForm = this
|
||||
setTimeout(() => $('.view-body.loading').removeClass('loading'), 100)
|
||||
})
|
||||
|
||||
$('.J_close').on('click', () => this.hide())
|
||||
|
|
|
@ -44,7 +44,6 @@ $(document).ready(function () {
|
|||
// 正则
|
||||
if (SHOW_ADVPATTERN.includes(dt)) {
|
||||
$('.J_advOpt').removeClass('hide')
|
||||
|
||||
$('.J_advPattern .badge').on('click', function () {
|
||||
$('#advPattern').val($(this).data('patt'))
|
||||
})
|
||||
|
@ -337,7 +336,9 @@ const _handlePicklist = function (dt) {
|
|||
}
|
||||
$('#picklist-items').empty()
|
||||
$(res.data).each(function () {
|
||||
const $item = $(`<li class="dd-item" data-key="${this.id}"><div class="dd-handle" style="color:${this.color || 'inherit'} !important">${this.text}</div></li>`).appendTo('#picklist-items')
|
||||
const $item = $(`<li class="dd-item" data-key="${this.mask || this.id}"><div class="dd-handle" style="color:${this.color || 'inherit'} !important">${this.text}</div></li>`).appendTo(
|
||||
'#picklist-items'
|
||||
)
|
||||
if ($isTrue(this['default'])) $item.addClass('default')
|
||||
})
|
||||
if (res.data.length > 5) $('#picklist-items').parent().removeClass('autoh')
|
||||
|
@ -754,9 +755,7 @@ const __TYPE2TYPE = {
|
|||
'PHONE': ['TEXT'],
|
||||
'EMAIL': ['TEXT'],
|
||||
'URL': ['TEXT'],
|
||||
'NTEXT': ['TEXT'],
|
||||
'IMAGE': ['FILE'],
|
||||
'FILE': ['IMAGE'],
|
||||
}
|
||||
class FieldTypeCast extends RbFormHandler {
|
||||
render() {
|
||||
|
|
|
@ -477,7 +477,7 @@ var _showStateMM = function (mm) {
|
|||
RbGritter.create(WrapHtml($mm.prop('outerHTML')), {
|
||||
timeout: (mm.time + 60) * 1000,
|
||||
type: 'danger',
|
||||
icon: 'mdi-server-network',
|
||||
icon: 'mdi-server-off',
|
||||
onCancel: function () {
|
||||
var expires = moment()
|
||||
.add(Math.min(mm.time - 30, 300), 'seconds')
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/view-page.css}" />
|
||||
<title th:text="${entityLabel}"></title>
|
||||
</head>
|
||||
<body class="view-body">
|
||||
<body class="view-body loading">
|
||||
<div class="view-header">
|
||||
<i class="header-icon zmdi" th:classappend="|zmdi-${entityIcon}|"></i>
|
||||
<h3 class="title" th:text="${bundle.L('%s详情', entityLabel)}"></h3>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/view-page.css}" />
|
||||
<title th:text="${entityLabel}"></title>
|
||||
</head>
|
||||
<body class="view-body">
|
||||
<body class="view-body loading">
|
||||
<div class="view-header">
|
||||
<i class="header-icon zmdi" th:classappend="|zmdi-${entityIcon}|"></i>
|
||||
<h3 class="title" th:text="${bundle.L('%s详情', entityLabel)}"></h3>
|
||||
|
|
|
@ -103,4 +103,15 @@ public class AdvFilterParserTest extends TestSupport {
|
|||
items.add(JSON.parseObject("{ op:'FUD', field:'datetime', value:'1' }"));
|
||||
System.out.println(new AdvFilterParser(filterExp).toSqlWhere());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRep() {
|
||||
JSONObject filterExp = new JSONObject();
|
||||
filterExp.put("entity", TestAllFields);
|
||||
JSONArray items = new JSONArray();
|
||||
filterExp.put("items", items);
|
||||
|
||||
items.add(JSON.parseObject("{ op:'REP', field:'TestAllFieldsName', value:2 }"));
|
||||
System.out.println(new AdvFilterParser(filterExp).toSqlWhere());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue