mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 07:25:54 +08:00
Diagramming for trigger RB-93 (#664)
* be:evalTriggerTimes * be: RbFormRefform * be: ObservableService order * er * be: user delete checks * be: row selected * be: .dataTables_oper.invisible * be: BatchOperator default selected * feat: mermaid * be: comp {@NOW} * be: passwd 10 --------- Co-authored-by: devezhao <zhaofang123@gmail.com>
This commit is contained in:
parent
95287da21a
commit
ed05f15bd4
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit e76e5aede15f6c8b2ec45ec6a06c690292466fe4
|
||||
Subproject commit 9073b96b92d22bf4b6d9a09bb1d8d6e635f4d655
|
|
@ -18,7 +18,6 @@ import com.rebuild.core.privileges.UserService;
|
|||
import com.rebuild.core.service.DataSpecificationException;
|
||||
import com.rebuild.core.service.InternalPersistService;
|
||||
import com.rebuild.core.service.query.QueryHelper;
|
||||
import com.rebuild.core.support.CommonsLock;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
|
@ -43,11 +42,6 @@ public abstract class BaseConfigurationService extends InternalPersistService {
|
|||
|
||||
@Override
|
||||
public Record update(Record record) {
|
||||
ID locked = hasLock() ? CommonsLock.getLockedUser(record.getPrimary()) : null;
|
||||
if (locked != null && !locked.equals(UserContextHolder.getUser())) {
|
||||
throw new DataSpecificationException(Language.L("操作失败 (已被锁定)"));
|
||||
}
|
||||
|
||||
throwIfNotSelf(record.getPrimary());
|
||||
cleanCache(record.getPrimary());
|
||||
return super.update(putCreateBy4ShareTo(record));
|
||||
|
@ -55,11 +49,6 @@ public abstract class BaseConfigurationService extends InternalPersistService {
|
|||
|
||||
@Override
|
||||
public int delete(ID recordId) {
|
||||
ID locked = hasLock() ? CommonsLock.getLockedUser(recordId) : null;
|
||||
if (locked != null && !locked.equals(UserContextHolder.getUser())) {
|
||||
throw new DataSpecificationException(Language.L("操作失败 (已被锁定)"));
|
||||
}
|
||||
|
||||
throwIfNotSelf(recordId);
|
||||
cleanCache(recordId);
|
||||
return super.delete(recordId);
|
||||
|
|
|
@ -132,9 +132,14 @@ public class UserService extends BaseService {
|
|||
String dsql = String.format("delete from `layout_config` where `CREATED_BY` = '%s'", recordId);
|
||||
Application.getSqlExecutor().execute(dsql);
|
||||
|
||||
// 2.删除并刷新缓存
|
||||
// 2.删除三方
|
||||
String dsql2 = String.format("delete from `external_user` where `BIND_USER` = '%s'", recordId);
|
||||
Application.getSqlExecutor().execute(dsql2);
|
||||
|
||||
// 3.删除并刷新缓存
|
||||
super.delete(recordId);
|
||||
Application.getUserStore().removeUser(recordId);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -214,9 +219,7 @@ public class UserService extends BaseService {
|
|||
}
|
||||
|
||||
int policy = RebuildConfiguration.getInt(ConfigurationItem.PasswordPolicy);
|
||||
if (policy <= 1) {
|
||||
return;
|
||||
}
|
||||
if (policy <= 1) return;
|
||||
|
||||
int countUpper = 0;
|
||||
int countLower = 0;
|
||||
|
@ -237,8 +240,8 @@ public class UserService extends BaseService {
|
|||
if (countUpper == 0 || countLower == 0 || countDigit == 0) {
|
||||
throw new DataSpecificationException(Language.L("密码不能小于 6 位,且必须包含数字和大小写字母"));
|
||||
}
|
||||
if (policy >= 3 && (countSpecial == 0 || password.length() < 8)) {
|
||||
throw new DataSpecificationException(Language.L("密码不能小于 8 位,且必须包含数字和大小写字母及特殊字符"));
|
||||
if (policy >= 3 && (countSpecial == 0 || password.length() < 10)) {
|
||||
throw new DataSpecificationException(Language.L("密码不能小于 10 位,且必须包含数字和大小写字母及特殊字符"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,13 +492,6 @@ public class UserService extends BaseService {
|
|||
"select user from LoginLog where user = ?")
|
||||
.setParameter(1, user)
|
||||
.unique();
|
||||
if (hasLogin != null) return true;
|
||||
|
||||
// 绑定
|
||||
Object[] hasBind = Application.createQueryNoFilter(
|
||||
"select bindUser from ExternalUser where bindUser = ?")
|
||||
.setParameter(1, user)
|
||||
.unique();
|
||||
return hasBind != null;
|
||||
return hasLogin != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import com.rebuild.utils.CommonsUtils;
|
|||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -63,6 +64,7 @@ import java.util.HashSet;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -88,11 +90,18 @@ public class GeneralEntityService extends ObservableService implements EntitySer
|
|||
|
||||
protected GeneralEntityService(PersistManagerFactory aPMFactory) {
|
||||
super(aPMFactory);
|
||||
}
|
||||
|
||||
// 通知
|
||||
addObserver(new NotificationObserver());
|
||||
// 触发器
|
||||
addObserver(new RobotTriggerObserver());
|
||||
@Override
|
||||
protected Observer[] getOrderObservers() {
|
||||
Observer[] obs = new Observer[] {
|
||||
// 触发器
|
||||
new RobotTriggerObserver(),
|
||||
// 通知
|
||||
new NotificationObserver(),
|
||||
};
|
||||
obs = ArrayUtils.addAll(obs, super.getOrderObservers());
|
||||
return obs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -45,15 +45,21 @@ public abstract class ObservableService extends Observable implements ServiceSpe
|
|||
protected ObservableService(PersistManagerFactory aPMFactory) {
|
||||
this.delegateService = new BaseService(aPMFactory);
|
||||
|
||||
// 默认监听者
|
||||
addObserver(new RevisionHistoryObserver());
|
||||
addObserver(new AttachmentAwareObserver());
|
||||
for (Observer o : getOrderObservers()) {
|
||||
log.info("Add observer : {} for [ {} ] ", o, getEntityCode());
|
||||
addObserver(o);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addObserver(Observer o) {
|
||||
super.addObserver(o);
|
||||
log.info("Add observer : {} for [ {} ] ", o, getEntityCode());
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
protected Observer[] getOrderObservers() {
|
||||
// 默认监听者
|
||||
return new Observer[] {
|
||||
new RevisionHistoryObserver(), // 2
|
||||
new AttachmentAwareObserver(), // 1
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,6 +52,13 @@ public class RecordDifference {
|
|||
return diffMerge(after, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取不同
|
||||
*
|
||||
* @param after
|
||||
* @param diffCommons
|
||||
* @return
|
||||
*/
|
||||
protected JSON diffMerge(Record after, boolean diffCommons) {
|
||||
if (record == null && after == null) {
|
||||
throw new RebuildException("Both records cannot be null");
|
||||
|
@ -107,10 +114,10 @@ public class RecordDifference {
|
|||
}
|
||||
|
||||
/**
|
||||
* 是否不同
|
||||
* 是否相同
|
||||
*
|
||||
* @param diff
|
||||
* @param diffCommons
|
||||
* @param diffCommons 是否比较系统共用字段
|
||||
* @return
|
||||
* @see #diffMerge(Record)
|
||||
*/
|
||||
|
|
|
@ -696,6 +696,7 @@ public class AdvFilterParser extends SetUser {
|
|||
private static final String PATT_FIELDVAR = "\\{@([\\w.]+)}";
|
||||
// `当前`变量(当前日期、时间、用户)
|
||||
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;
|
||||
|
@ -706,7 +707,7 @@ public class AdvFilterParser extends SetUser {
|
|||
Object useValue = null;
|
||||
|
||||
// {@CURRENT} DATE
|
||||
if (CURRENT_ANY.equals(fieldName)) {
|
||||
if (CURRENT_ANY.equals(fieldName) || CURRENT_DATE.equals(fieldName)) {
|
||||
DisplayType dt = EasyMetaFactory.getDisplayType(queryField);
|
||||
if (dt == DisplayType.DATE || dt == DisplayType.DATETIME || dt == DisplayType.TIME) {
|
||||
useValue = CalendarUtils.now();
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.springframework.util.Assert;
|
|||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -108,7 +107,7 @@ public class QueryHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取明细(完整)记录
|
||||
* 获取明细列表记录
|
||||
*
|
||||
* @param mainId
|
||||
* @return
|
||||
|
@ -129,7 +128,7 @@ public class QueryHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取明细 ID
|
||||
* 获取明细列表 ID
|
||||
*
|
||||
* @param mainId
|
||||
* @return
|
||||
|
@ -217,12 +216,9 @@ public class QueryHelper {
|
|||
final ID primaryId = base.getPrimary();
|
||||
Assert.notNull(primaryId, "Record primary cannot be null");
|
||||
|
||||
Set<String> fields = new HashSet<>();
|
||||
for (Iterator<String> iter = base.getAvailableFieldIterator(); iter.hasNext(); ) {
|
||||
fields.add(iter.next());
|
||||
}
|
||||
|
||||
Set<String> fields = new HashSet<>(base.getAvailableFields());
|
||||
fields.add(base.getEntity().getPrimaryField().getName());
|
||||
|
||||
Record snap = Application.getQueryFactory().recordNoFilter(primaryId, fields.toArray(new String[0]));
|
||||
|
||||
if (snap == null) throw new NoRecordFoundException(primaryId);
|
||||
|
|
|
@ -337,8 +337,7 @@ public class FieldAggregation extends TriggerAction {
|
|||
protected boolean isCurrentSame(Record record) {
|
||||
if (!ignoreSame) return false;
|
||||
|
||||
Record c = Application.getQueryFactory().recordNoFilter(
|
||||
record.getPrimary(), record.getAvailableFields().toArray(new String[0]));
|
||||
Record c = QueryHelper.querySnap(record);
|
||||
return new RecordDifference(record).isSame(c, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,17 +43,15 @@ public final class UpgradeDatabase {
|
|||
try {
|
||||
while (true) {
|
||||
String[] sql = scripts.get(upgradeVer + 1);
|
||||
if (sql == null) {
|
||||
break;
|
||||
} else if (sql.length == 0) {
|
||||
upgradeVer++;
|
||||
continue;
|
||||
}
|
||||
if (sql == null) break;
|
||||
|
||||
log.info("\n>> UPGRADE SQL (#" + (upgradeVer + 1) + ") >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + StringUtils.join(sql, "\n"));
|
||||
Application.getSqlExecutor().executeBatch(sql, 60 * 2);
|
||||
upgradeVer++;
|
||||
if (sql.length > 0) {
|
||||
log.info("\n>> UPGRADE SQL (#" + upgradeVer + ") >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" + StringUtils.join(sql, "\n"));
|
||||
Application.getSqlExecutor().executeBatch(sql, 60 * 2);
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (currentVer != upgradeVer) {
|
||||
RebuildConfiguration.set(ConfigurationItem.DBVer, upgradeVer);
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.rebuild.api.RespBody;
|
|||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.configuration.ConfigurationException;
|
||||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.service.datareport.DataReportManager;
|
||||
import com.rebuild.core.service.datareport.EasyExcelGenerator;
|
||||
import com.rebuild.core.service.datareport.EasyExcelListGenerator;
|
||||
|
@ -33,6 +34,7 @@ import com.rebuild.web.EntityParam;
|
|||
import com.rebuild.web.IdParam;
|
||||
import com.rebuild.web.admin.ConfigCommons;
|
||||
import com.rebuild.web.commons.FileDownloader;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
@ -42,7 +44,9 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -68,13 +72,26 @@ public class ReportTemplateController extends BaseController {
|
|||
String entity = getParameter(request, "entity");
|
||||
String q = getParameter(request, "q");
|
||||
|
||||
String sql = "select configId,belongEntity,belongEntity,name,isDisabled,modifiedOn,templateType,extraDefinition from DataReportConfig" +
|
||||
String sql = "select configId,belongEntity,belongEntity,name,isDisabled,modifiedOn,templateType,extraDefinition,configId from DataReportConfig" +
|
||||
" where (1=1) and (2=2)" +
|
||||
" order by modifiedOn desc, name";
|
||||
|
||||
Object[][] list = ConfigCommons.queryListOfConfig(sql, entity, q);
|
||||
for (Object[] o : list) {
|
||||
o[7] = o[7] == null ? JSONUtils.EMPTY_OBJECT : JSON.parseObject((String) o[7]);
|
||||
JSONObject extra = o[7] == null ? JSONUtils.EMPTY_OBJECT : JSON.parseObject((String) o[7]);
|
||||
o[7] = extra;
|
||||
o[8] = null;
|
||||
|
||||
String vu = extra.getString("visibleUsers");
|
||||
if (StringUtils.isNotBlank(vu)) {
|
||||
List<String> vuNames = new ArrayList<>();
|
||||
for (String id : vu.split(",")) {
|
||||
if (ID.isId(id)) {
|
||||
vuNames.add(UserHelper.getName(ID.valueOf(id)));
|
||||
}
|
||||
}
|
||||
o[8] = StringUtils.join(vuNames, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
return RespBody.ok(list);
|
||||
|
|
|
@ -42,7 +42,7 @@ import com.rebuild.web.EntityController;
|
|||
import com.rebuild.web.commons.FileDownloader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
@ -307,9 +307,9 @@ public class MetaEntityController extends EntityController {
|
|||
public ModelAndView pageSheet(HttpServletRequest request) {
|
||||
ModelAndView mv = createModelAndView("/admin/metadata/entities-sheet");
|
||||
|
||||
String spec = getParameter(request, "e");
|
||||
String spec = getParameter(request, "s");
|
||||
Set<String> specList = null;
|
||||
if (org.apache.commons.lang3.StringUtils.isNotBlank(spec)) {
|
||||
if (StringUtils.isNotBlank(spec)) {
|
||||
specList = new HashSet<>();
|
||||
for (String s : spec.split(",")) specList.add(s.trim().toUpperCase());
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ public class MetaEntityController extends EntityController {
|
|||
ConfigBean[] cbs = PickListManager.instance.getPickListRaw(f, Boolean.TRUE);
|
||||
List<String> texts = new ArrayList<>();
|
||||
for (ConfigBean cb : cbs) texts.add(cb.getID("id") + ":" + cb.getString("text"));
|
||||
opt = org.apache.commons.lang3.StringUtils.join(texts, "//");
|
||||
opt = StringUtils.join(texts, "//");
|
||||
}
|
||||
|
||||
fields.add(new Object[] {
|
||||
|
|
|
@ -21,10 +21,8 @@ import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
|
|||
import com.rebuild.core.service.trigger.ActionFactory;
|
||||
import com.rebuild.core.service.trigger.ActionType;
|
||||
import com.rebuild.core.service.trigger.TriggerAction;
|
||||
import com.rebuild.core.support.CommonsLock;
|
||||
import com.rebuild.core.support.License;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.rbv.trigger.TriggerByTimerJob;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
import com.rebuild.web.BaseController;
|
||||
import com.rebuild.web.admin.ConfigCommons;
|
||||
|
@ -88,7 +86,6 @@ public class TriggerAdminController extends BaseController {
|
|||
mv.getModel().put("actionContent", config[4]);
|
||||
mv.getModel().put("priority", config[5]);
|
||||
mv.getModel().put("name", config[6]);
|
||||
mv.getModel().put("lockedUser", JSON.toJSONString(CommonsLock.getLockedUserFormat(configId)));
|
||||
mv.getModel().put("isDisabled", config[8] == null ? false : config[8]);
|
||||
|
||||
return mv;
|
||||
|
@ -121,22 +118,28 @@ public class TriggerAdminController extends BaseController {
|
|||
public Object[][] triggerList(HttpServletRequest request) {
|
||||
String belongEntity = getParameter(request, "entity");
|
||||
String q = getParameter(request, "q");
|
||||
String sql = "select configId,belongEntity,belongEntity,name,isDisabled,modifiedOn,when,actionType,configId,priority,actionContent from RobotTriggerConfig" +
|
||||
String sql = "select configId,belongEntity,belongEntity,name,isDisabled,modifiedOn,when,actionType,priority,actionContent from RobotTriggerConfig" +
|
||||
" where (1=1) and (2=2)" +
|
||||
" order by modifiedOn desc, name";
|
||||
|
||||
Object[][] array = ConfigCommons.queryListOfConfig(sql, belongEntity, q);
|
||||
for (Object[] o : array) {
|
||||
o[7] = Language.L(ActionType.valueOf((String) o[7]));
|
||||
o[8] = CommonsLock.getLockedUserFormat((ID) o[8]);
|
||||
|
||||
// 目标实体
|
||||
o[10] = tryParseTargetEntity((String) o[10], (String) o[1]);
|
||||
o[9] = tryParseTargetEntity((String) o[9], (String) o[1], true);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private String tryParseTargetEntity(String config, String sourceEntity) {
|
||||
/**
|
||||
* 尝试解析目标实体
|
||||
*
|
||||
* @param config
|
||||
* @param sourceEntity
|
||||
* @param useLabel
|
||||
* @return
|
||||
*/
|
||||
public static String tryParseTargetEntity(String config, String sourceEntity, boolean useLabel) {
|
||||
if (!JSONUtils.wellFormat(config)) return null;
|
||||
|
||||
JSONObject configJson = JSON.parseObject(config);
|
||||
|
@ -147,9 +150,9 @@ public class TriggerAdminController extends BaseController {
|
|||
else if (targetEntity.contains(".")) targetEntity = targetEntity.split("\\.")[1];
|
||||
|
||||
if (MetadataHelper.containsEntity(targetEntity)) {
|
||||
return EasyMetaFactory.getLabel(targetEntity);
|
||||
return useLabel ? EasyMetaFactory.getLabel(targetEntity) : targetEntity;
|
||||
} else {
|
||||
return String.format("[%s]", targetEntity.toUpperCase());
|
||||
return useLabel ? String.format("[%s]", targetEntity.toUpperCase()) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,19 +167,12 @@ public class TriggerAdminController extends BaseController {
|
|||
|
||||
targetEntity = cb.getString("target");
|
||||
if (MetadataHelper.containsEntity(targetEntity)) {
|
||||
return EasyMetaFactory.getLabel(targetEntity);
|
||||
return useLabel ? EasyMetaFactory.getLabel(targetEntity) : targetEntity;
|
||||
} else {
|
||||
return String.format("[%s]", targetEntity.toUpperCase());
|
||||
return useLabel ? String.format("[%s]", targetEntity.toUpperCase()) : null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@GetMapping("trigger/eval-trigger-times")
|
||||
public JSON evalTriggerTimes(HttpServletRequest request) {
|
||||
String whenTimer = getParameterNotNull(request, "whenTimer");
|
||||
List<String> s = TriggerByTimerJob.getInTriggerTime(whenTimer);
|
||||
return (JSON) JSON.toJSON(s);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -711,7 +711,7 @@
|
|||
"密码":"密码",
|
||||
"密码不能小于 6 位":"密码不能小于 6 位",
|
||||
"密码不能小于 6 位,且必须包含数字和大小写字母":"密码不能小于 6 位,且必须包含数字和大小写字母",
|
||||
"密码不能小于 8 位,且必须包含数字和大小写字母及特殊字符":"密码不能小于 8 位,且必须包含数字和大小写字母及特殊字符",
|
||||
"密码不能小于 10 位,且必须包含数字和大小写字母及特殊字符":"密码不能小于 10 位,且必须包含数字和大小写字母及特殊字符",
|
||||
"密码将重置为 **%s** 是否确认?":"密码将重置为 **%s** 是否确认?",
|
||||
"密码错误":"密码错误",
|
||||
"对比图":"对比图",
|
||||
|
@ -1664,7 +1664,7 @@
|
|||
"验证码已发送至你的邮箱":"验证码已发送至你的邮箱",
|
||||
"验证码无效":"验证码无效",
|
||||
"验证码错误":"验证码错误",
|
||||
"高 (最低8位,必须同时包含数字、字母、特殊字符)":"高 (最低8位,必须同时包含数字、字母、特殊字符)",
|
||||
"高 (最低10位,必须同时包含数字、字母、特殊字符)":"高 (最低10位,必须同时包含数字、字母、特殊字符)",
|
||||
"高级功能":"高级功能",
|
||||
"高级控制":"高级控制",
|
||||
"高级查询":"高级查询",
|
||||
|
|
|
@ -59,7 +59,8 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>[[${bundle.L('名称')}]]</th>
|
||||
<th>[[${bundle.L('应用实体')}]]</th>
|
||||
<th width="20%">[[${bundle.L('应用实体')}]]</th>
|
||||
<th>[[${bundle.L('使用用户')}]]</th>
|
||||
<th width="80" class="no-sort">[[${bundle.L('启用')}]]</th>
|
||||
<th width="120" class="no-sort">[[${bundle.L('修改时间')}]]</th>
|
||||
<th width="150" class="no-sort"></th>
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
<span th:text="${e[1]}" class="badge ml-1" title="Entity Code"></span>
|
||||
<a class="float-right font-weight-normal fs-12" href="#index">top</a>
|
||||
</div>
|
||||
<table class="table table-sm table-fixed table-hover">
|
||||
<table class="table table-sm table-hover table-fixed table-btm-line">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field Name</th>
|
||||
|
@ -116,7 +116,7 @@
|
|||
const opt = $item.text() || ''
|
||||
if (opt.length < 10) return
|
||||
|
||||
const $ul = $('<ol class="pl-3 m-0"></ol>').appendTo($item.empty())
|
||||
const $ul = $('<ul class="pl-3 m-0"></ul>').appendTo($item.empty())
|
||||
$(opt.split('//')).each(function () {
|
||||
const o = this.split(':')
|
||||
$(`<li><span>${o[1]}</span> <code>${o[0]}</code></li>`).appendTo($ul)
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<div>
|
||||
<div class="float-right">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-light w-auto dropdown-toggle mr-1" type="button" data-toggle="dropdown">+ [[${bundle.L('添加')}]]</button>
|
||||
<button class="btn btn-light w-auto dropdown-toggle mr-1" 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_add-divider">[[${bundle.L('分栏')}]]</a>
|
||||
<a class="dropdown-item J_add-refform">[[${bundle.L('表单引用')}]] <sup class="rbv"></sup></a>
|
||||
|
|
|
@ -195,7 +195,6 @@
|
|||
whenTimer: '[[${whenTimer}]]',
|
||||
whenFilter: [(${whenFilter ?:'null'})],
|
||||
actionContent: [(${actionContent ?:'null'})],
|
||||
lockedUser: [(${lockedUser ?:'null'})],
|
||||
}
|
||||
</script>
|
||||
<script th:src="@{/assets/js/rb-advfilter.js}" type="text/babel"></script>
|
||||
|
|
|
@ -42,13 +42,13 @@
|
|||
<div class="row rb-datatable-body">
|
||||
<div class="col-sm-12">
|
||||
<div class="rb-loading rb-loading-active data-list">
|
||||
<table class="table table-hover table-striped table-fixed tablesort">
|
||||
<table class="table table-hover table-striped tablesort">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>[[${bundle.L('名称')}]]</th>
|
||||
<th width="15%">[[${bundle.L('源实体')}]]</th>
|
||||
<th width="15%">[[${bundle.L('触发类型')}]]</th>
|
||||
<th width="15%" class="no-sort">[[${bundle.L('触发动作')}]]</th>
|
||||
<th>[[${bundle.L('源实体')}]]</th>
|
||||
<th>[[${bundle.L('触发类型')}]]</th>
|
||||
<th class="no-sort">[[${bundle.L('触发动作')}]]</th>
|
||||
<th width="80" class="int-sort">[[${bundle.L('优先级')}]]</th>
|
||||
<th width="80" class="no-sort">[[${bundle.L('启用')}]]</th>
|
||||
<th width="120" class="no-sort">[[${bundle.L('修改时间')}]]</th>
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<div>
|
||||
<span>© REBUILD ([[${Version}]])</span>
|
||||
<b>·</b>
|
||||
<a href="https://getrebuild.com/docs/admin/install" target="_blank" class="link">[[${bundle.L('安装指南')}]]</a>
|
||||
<a href="https://getrebuild.com/docs/admin/install" target="_blank" class="link link-icon">[[${bundle.L('安装指南')}]]</a>
|
||||
</div>
|
||||
<div
|
||||
class="mt-1 license link"
|
||||
|
|
|
@ -184,7 +184,7 @@
|
|||
<td data-id="PasswordPolicy" th:data-value="${PasswordPolicy}">
|
||||
<th:block th:if="${PasswordPolicy == '1'}">[[${bundle.L('低 (最低6位,无字符类型限制)')}]]</th:block>
|
||||
<th:block th:if="${PasswordPolicy == '2'}">[[${bundle.L('中 (最低6位,必须同时包含数字、字母)')}]]</th:block>
|
||||
<th:block th:if="${PasswordPolicy == '3'}">[[${bundle.L('高 (最低8位,必须同时包含数字、字母、特殊字符)')}]]</th:block>
|
||||
<th:block th:if="${PasswordPolicy == '3'}">[[${bundle.L('高 (最低10位,必须同时包含数字、字母、特殊字符)')}]]</th:block>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -650,6 +650,8 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
bottom: 20px;
|
||||
z-index: 10;
|
||||
opacity: 0.6;
|
||||
transition: opacity 0.2s linear;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.zoom:hover {
|
||||
|
@ -674,6 +676,11 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
color: #777;
|
||||
}
|
||||
|
||||
.zoom .zoom-in:hover i,
|
||||
.zoom .zoom-out:hover i {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.fields-table .custom-control {
|
||||
padding-left: 1.9377rem !important;
|
||||
}
|
||||
|
|
|
@ -913,6 +913,20 @@ select.form-control:not([disabled]) {
|
|||
background-size: 16px;
|
||||
}
|
||||
|
||||
div.link a:hover,
|
||||
p.link a:hover,
|
||||
li.link a:hover,
|
||||
a.link:hover,
|
||||
a.column-url:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
a.link.link-icon::after {
|
||||
content: '\f1a3';
|
||||
font-family: 'Material-Design-Iconic-Font', serif;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
/* rbform */
|
||||
|
||||
.form-layout > .row {
|
||||
|
@ -1279,12 +1293,23 @@ select.form-control:not([disabled]) {
|
|||
/* v35 */
|
||||
.form-layout.refform {
|
||||
display: block;
|
||||
background-color: rgba(230, 230, 230, 0.3);
|
||||
box-shadow: inset 0px 0px 10px rgba(230, 230, 230, 0.6);
|
||||
border-radius: 2px;
|
||||
background-color: rgba(230, 230, 230, 0.2);
|
||||
box-shadow: inset 0 0 10px rgba(230, 230, 230, 0.5);
|
||||
width: 100%;
|
||||
margin: 10px 15px;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-layout.refform > .open-in-new {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 3px;
|
||||
font-size: 1.45rem;
|
||||
padding: 5px;
|
||||
display: inline-block;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.input-group.has-append {
|
||||
|
@ -1645,14 +1670,6 @@ i.dividing.ui-draggable-dragging {
|
|||
border-bottom: 0 solid;
|
||||
}
|
||||
|
||||
div.link a:hover,
|
||||
p.link a:hover,
|
||||
li.link a:hover,
|
||||
a.link:hover,
|
||||
a.column-url:hover {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.column-empty {
|
||||
padding: 8px !important;
|
||||
}
|
||||
|
@ -2085,8 +2102,9 @@ th.column-fixed {
|
|||
width: auto;
|
||||
left: 10px;
|
||||
margin: -11px 0 0;
|
||||
padding: 3px 5px 3px 5px;
|
||||
padding: 3px 5px 0;
|
||||
color: #666;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.form-line.hover fieldset legend {
|
||||
|
@ -2103,12 +2121,11 @@ th.column-fixed {
|
|||
|
||||
.form-line.hover fieldset legend::before {
|
||||
font-family: 'Material-Design-Iconic-Font', serif;
|
||||
font-size: 1.4rem;
|
||||
font-size: 1.5rem;
|
||||
content: '\f2f9';
|
||||
width: 10px;
|
||||
width: 13px;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
margin-right: 3px;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
transform: translateY(-1px);
|
||||
|
|
|
@ -32,6 +32,11 @@ class ReportList extends ConfigList {
|
|||
{outputType.includes('html') && <span className="badge badge-secondary badge-sm ml-1">HTML</span>}
|
||||
</td>
|
||||
<td>{item[2] || item[1]}</td>
|
||||
<td>
|
||||
<div className="text-break" style={{ maxWidth: 300 }}>
|
||||
{item[8] || $L('所有用户')}
|
||||
</div>
|
||||
</td>
|
||||
<td>{ShowEnable(item[4])}</td>
|
||||
<td>
|
||||
<DateShow date={item[5]} />
|
||||
|
@ -176,7 +181,9 @@ class ReportEditor extends ConfigFormDlg {
|
|||
</div>
|
||||
</div>
|
||||
<div className="form-group row">
|
||||
<label className="col-sm-3 col-form-label text-sm-right">{$L('谁能使用这个报表')}</label>
|
||||
<label className="col-sm-3 col-form-label text-sm-right">
|
||||
{$L('谁能使用这个报表')} <sup className="rbv" />
|
||||
</label>
|
||||
<div className="col-sm-7">
|
||||
<UserSelector
|
||||
ref={(c) => (this._UserSelector = c)}
|
||||
|
@ -326,7 +333,7 @@ class ReportEditor extends ConfigFormDlg {
|
|||
outputType: output.length === 0 ? 'excel' : output.join(','),
|
||||
templateVersion: (this.props.extraDefinition || {}).templateVersion || 2,
|
||||
// v3.5
|
||||
visibleUsers: this._UserSelector.val().join(','),
|
||||
visibleUsers: rb.commercial < 1 ? null : this._UserSelector.val().join(','),
|
||||
}
|
||||
|
||||
if (this.props.id) {
|
||||
|
|
|
@ -83,7 +83,7 @@ useEditComp = function (name) {
|
|||
<select className="form-control form-control-sm">
|
||||
<option value="1">{$L('低 (最低6位,无字符类型限制)')}</option>
|
||||
<option value="2">{$L('中 (最低6位,必须同时包含数字、字母)')}</option>
|
||||
<option value="3">{$L('高 (最低8位,必须同时包含数字、字母、特殊字符)')}</option>
|
||||
<option value="3">{$L('高 (最低10位,必须同时包含数字、字母、特殊字符)')}</option>
|
||||
</select>
|
||||
)
|
||||
} else if ('DefaultLanguage' === name) {
|
||||
|
|
|
@ -265,6 +265,6 @@ class DlgEnableUser extends RbModalHandler {
|
|||
}
|
||||
|
||||
const _reload = function (timeout) {
|
||||
setTimeout(() => location.reload(), timeout || 1)
|
||||
setTimeout(() => RbViewPage.reload(), timeout || 1)
|
||||
parent && parent.RbListPage && parent.RbListPage.reload()
|
||||
}
|
||||
|
|
|
@ -120,7 +120,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>
|
||||
|
|
|
@ -514,7 +514,7 @@ class DlgEditRefform extends DlgEditField {
|
|||
<option value="">{$L('无')}</option>
|
||||
{Object.keys(_ValidFields).map((k) => {
|
||||
const field = _ValidFields[k]
|
||||
if (field.displayTypeName === 'REFERENCE')
|
||||
if (field.displayTypeName === 'REFERENCE' && !(field.fieldName === 'approvalId'))
|
||||
return (
|
||||
<option key={field.fieldName} value={field.fieldName}>
|
||||
{field.fieldLabel}
|
||||
|
|
|
@ -16,15 +16,16 @@ class RbModal extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const props = this.props
|
||||
const style1 = {}
|
||||
if (this.props.zIndex) style1.zIndex = this.props.zIndex
|
||||
if (props.zIndex) style1.zIndex = props.zIndex
|
||||
|
||||
const iframe = !this.props.children // No child
|
||||
const style2 = { maxWidth: ~~(this.props.width || 680) }
|
||||
const iframe = !props.children // No child
|
||||
const style2 = { maxWidth: ~~(props.width || 680) }
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`modal rbmodal colored-header colored-header-${this.props.colored || 'primary'}`}
|
||||
className={`modal rbmodal colored-header colored-header-${props.colored || 'primary'}`}
|
||||
style={style1}
|
||||
ref={(c) => {
|
||||
this._rbmodal = c
|
||||
|
@ -33,14 +34,19 @@ class RbModal extends React.Component {
|
|||
<div className="modal-dialog" style={style2}>
|
||||
<div className="modal-content" style={style2}>
|
||||
<div className="modal-header modal-header-colored">
|
||||
{this.props.icon && <i className={`icon zmdi zmdi-${this.props.icon}`} />}
|
||||
<h3 className="modal-title">{this.props.title || 'UNTITLED'}</h3>
|
||||
{props.icon && <i className={`icon zmdi zmdi-${props.icon}`} />}
|
||||
<h3 className="modal-title">{props.title || 'UNTITLED'}</h3>
|
||||
{props.url && props.urlOpenInNew && (
|
||||
<a className="close s fs-18" href={props.url} target="_blank" title={$L('在新页面打开')}>
|
||||
<span className="zmdi zmdi-open-in-new" />
|
||||
</a>
|
||||
)}
|
||||
<button className="close" type="button" onClick={() => this.hide()} title={$L('关闭')}>
|
||||
<span className="zmdi zmdi-close" />
|
||||
</button>
|
||||
</div>
|
||||
<div className={`modal-body ${iframe ? 'iframe rb-loading' : ''} ${iframe && this.state.frameLoad !== false ? 'rb-loading-active' : ''}`} id={this._htmlid}>
|
||||
{this.props.children || <iframe src={this.props.url} frameBorder="0" scrolling="no" onLoad={() => this.resize()} />}
|
||||
{props.children || <iframe src={props.url} frameBorder="0" scrolling="no" onLoad={() => this.resize()} />}
|
||||
{iframe && <RbSpinner />}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -97,25 +103,25 @@ class RbModal extends React.Component {
|
|||
/**
|
||||
* @param {*} url
|
||||
* @param {*} title
|
||||
* @param {*} options
|
||||
* @param {*} option
|
||||
*/
|
||||
static create(url, title, options) {
|
||||
static create(url, title, option) {
|
||||
// URL prefix
|
||||
if (url.substr(0, 1) === '/' && rb.baseUrl) url = rb.baseUrl + url
|
||||
|
||||
options = options || {}
|
||||
options.disposeOnHide = options.disposeOnHide === true // default false
|
||||
option = option || {}
|
||||
option.disposeOnHide = option.disposeOnHide === true // default false
|
||||
this.__HOLDERs = this.__HOLDERs || {}
|
||||
|
||||
const that = this
|
||||
if (options.disposeOnHide === false && !!that.__HOLDERs[url]) {
|
||||
if (option.disposeOnHide === false && !!that.__HOLDERs[url]) {
|
||||
that.__HOLDER = that.__HOLDERs[url]
|
||||
that.__HOLDER.show()
|
||||
that.__HOLDER.resize()
|
||||
} else {
|
||||
renderRbcomp(<RbModal url={url} title={title} width={options.width} disposeOnHide={options.disposeOnHide} zIndex={options.zIndex} />, null, function () {
|
||||
renderRbcomp(<RbModal url={url} urlOpenInNew={option.urlOpenInNew} title={title} width={option.width} disposeOnHide={option.disposeOnHide} zIndex={option.zIndex} />, null, function () {
|
||||
that.__HOLDER = this
|
||||
if (options.disposeOnHide === false) that.__HOLDERs[url] = this
|
||||
if (option.disposeOnHide === false) that.__HOLDERs[url] = this
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ const AdvFilters = {
|
|||
class BatchOperator extends RbFormHandler {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state.dataRange = 2
|
||||
this.state.dataRange = props.listRef.getSelectedIds(true).length > 0 ? 1 : 2
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -1094,16 +1094,23 @@ class RbList extends React.Component {
|
|||
_clickRow(e) {
|
||||
const $target = $(e.target)
|
||||
if ($target.hasClass('custom-control-label')) return // ignored
|
||||
const holdSelected = $target.hasClass('custom-checkbox') || $target.parents('.custom-checkbox').hasClass('custom-checkbox')
|
||||
console.log($target)
|
||||
|
||||
const $tr = $target.parents('tr')
|
||||
let holdSelected = true
|
||||
if ($target.hasClass('column-checkbox')) {
|
||||
const $chk = $tr.find('.custom-control-input')[0]
|
||||
$chk.checked = !$chk.checked
|
||||
holdSelected = true
|
||||
} else {
|
||||
holdSelected = $target.hasClass('custom-checkbox') || $target.parents('.custom-checkbox').hasClass('custom-checkbox')
|
||||
}
|
||||
|
||||
if (holdSelected) {
|
||||
if ($tr.find('.custom-control-input')[0].checked) $tr.addClass('active')
|
||||
else $tr.removeClass('active')
|
||||
} else {
|
||||
this._toggleRows({ target: { checked: false } }, true)
|
||||
$tr.addClass('active').find('.custom-control-input').prop('checked', true)
|
||||
$tr.addClass('active').find('.custom-control-input')[0].checked = true
|
||||
}
|
||||
|
||||
this._checkSelected()
|
||||
|
@ -1165,7 +1172,7 @@ class RbList extends React.Component {
|
|||
|
||||
_tryActive($el) {
|
||||
if ($el.length === 1) {
|
||||
this._clickRow({ target: $el.find('.custom-checkbox') }, true)
|
||||
this._clickRow({ target: $el.find('td:eq(1)') })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ const RbListPage = {
|
|||
if (ep.A !== true) $('.J_assign').remove()
|
||||
if (ep.S !== true) $('.J_share, .J_unshare').remove()
|
||||
$cleanMenu('.J_action')
|
||||
$('.dataTables_oper.invisible').removeClass('invisible')
|
||||
}
|
||||
|
||||
// Filter Pane
|
||||
|
|
|
@ -2767,18 +2767,23 @@ class RbFormRefform extends React.Component {
|
|||
// 有错误
|
||||
if (res.error_code > 0 || !!res.data.error) {
|
||||
const err = res.data.error || res.error_msg
|
||||
this.setState({ formComponent: <div>{err}</div> })
|
||||
this.setState({ formComponent: <div className="text-danger">{err}</div> })
|
||||
return
|
||||
}
|
||||
|
||||
const VFORM = (
|
||||
<div className="row">
|
||||
{res.data.elements.map((item) => {
|
||||
item.$$$parent = this
|
||||
// eslint-disable-next-line no-undef
|
||||
return detectViewElement(item, props.entity)
|
||||
})}
|
||||
</div>
|
||||
<RF>
|
||||
<a title={$L('在新页面打开')} className="close open-in-new" href={`${rb.baseUrl}/app/entity/view?id=${props.id}`} target="_blank">
|
||||
<i className="icon zmdi zmdi-open-in-new" />
|
||||
</a>
|
||||
<div className="row">
|
||||
{res.data.elements.map((item) => {
|
||||
item.$$$parent = this
|
||||
// eslint-disable-next-line no-undef
|
||||
return detectViewElement(item, props.entity)
|
||||
})}
|
||||
</div>
|
||||
</RF>
|
||||
)
|
||||
this.setState({ formComponent: VFORM })
|
||||
})
|
||||
|
|
|
@ -28,24 +28,6 @@ $(document).ready(() => {
|
|||
})
|
||||
$('.J_startHour2').val('23')
|
||||
|
||||
$('.on-timers select, .on-timers input').on('change', () => {
|
||||
const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}`
|
||||
$.get(`/admin/robot/trigger/eval-trigger-times?whenTimer=${whenTimer}`, (res) => {
|
||||
renderRbcomp(
|
||||
<RbAlertBox
|
||||
icon="time"
|
||||
message={
|
||||
<div>
|
||||
<span className="mr-1">{$L('预计执行时间')}</span>
|
||||
<code>{res.data.join(', ')}</code>
|
||||
</div>
|
||||
}
|
||||
/>,
|
||||
$('.eval-exec-times')[0]
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
if (wpc.when > 0) {
|
||||
$([1, 2, 4, 16, 32, 64, 128, 256, 512, 1024, 2048]).each(function () {
|
||||
let mask = this
|
||||
|
@ -67,6 +49,29 @@ $(document).ready(() => {
|
|||
})
|
||||
}
|
||||
|
||||
// 评估具体执行时间
|
||||
function evalTriggerTimes() {
|
||||
const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}`
|
||||
$.get(`/admin/robot/trigger/eval-trigger-times?whenTimer=${whenTimer}`, (res) => {
|
||||
renderRbcomp(
|
||||
<RbAlertBox
|
||||
icon="time"
|
||||
message={
|
||||
<div>
|
||||
<span className="mr-1">{$L('预计执行时间')}</span>
|
||||
<code>{res.data.join(', ')}</code>
|
||||
</div>
|
||||
}
|
||||
/>,
|
||||
$('.eval-exec-times')[0]
|
||||
)
|
||||
})
|
||||
}
|
||||
if (rb.commercial >= 10) {
|
||||
$('.on-timers select').on('change', () => $setTimeout(evalTriggerTimes, 500, 'eval-trigger-times'))
|
||||
$('.on-timers input').on('input', () => $setTimeout(evalTriggerTimes, 500, 'eval-trigger-times'))
|
||||
}
|
||||
|
||||
let advFilter
|
||||
$('.J_whenFilter .btn').on('click', () => {
|
||||
if (advFilter) {
|
||||
|
@ -149,11 +154,6 @@ $(document).ready(() => {
|
|||
})
|
||||
})
|
||||
|
||||
if (wpc.lockedUser && wpc.lockedUser[0] !== rb.currentUser) {
|
||||
$('.footer .alert-warning').removeClass('hide').find('.message').text($L('已被 %s 锁定,其他人无法操作', wpc.lockedUser[1]))
|
||||
$('.footer .btn').attr('disabled', true)
|
||||
}
|
||||
|
||||
if (LastLogsViewer.renderLog && rb.commercial > 1) {
|
||||
$.get(`/admin/robot/trigger/last-logs?id=${wpc.configId}`, (res) => {
|
||||
const _data = res.data || []
|
||||
|
|
|
@ -65,9 +65,6 @@ class TriggerList extends ConfigList {
|
|||
return (
|
||||
<RF>
|
||||
{(this.state.data || []).map((item) => {
|
||||
const locked = item[8]
|
||||
const disabled = locked && locked[0] !== rb.currentUser
|
||||
|
||||
return (
|
||||
<tr key={item[0]}>
|
||||
<td>
|
||||
|
@ -76,34 +73,28 @@ class TriggerList extends ConfigList {
|
|||
<td>{item[2] || item[1]}</td>
|
||||
<td>
|
||||
{item[7]}
|
||||
{item[10] && (
|
||||
{item[9] && (
|
||||
<span title={$L('目标实体')} className="ml-1">
|
||||
({item[10]})
|
||||
({item[9]})
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="text-wrap">{item[6] > 0 ? $L('当 %s 时', formatWhen(item[6])) : <span className="text-warning">({$L('无触发动作')})</span>}</td>
|
||||
<td>
|
||||
<span className="badge badge-light">{item[9]}</span>
|
||||
<span className="badge badge-light">{item[8]}</span>
|
||||
</td>
|
||||
<td>{ShowEnable(item[4], item[0])}</td>
|
||||
<td>
|
||||
<DateShow date={item[5]} />
|
||||
</td>
|
||||
<td className="actions">
|
||||
{locked ? (
|
||||
<a className="icon" title={locked[0] === rb.currentUser ? $L('解锁') : $L('已被 %s 锁定', locked[1])} onClick={() => this.handleLock(item)}>
|
||||
<i className={`zmdi zmdi-lock-outline text-${disabled ? 'danger' : 'warning'}`} />
|
||||
</a>
|
||||
) : (
|
||||
<a className="icon" title={$L('锁定')} onClick={() => this.handleLock(item, true)}>
|
||||
<i className="zmdi zmdi-lock-open" />
|
||||
</a>
|
||||
)}
|
||||
<a className="icon" title={$L('修改')} onClick={() => !disabled && this.handleEdit(item)} disabled={disabled}>
|
||||
<a className="icon" title={$L('触发过程')} onClick={() => this.handleShowChain(item[0])}>
|
||||
<i className="zmdi mdi mdi-vector-polyline mdi-rotate-180" />
|
||||
</a>
|
||||
<a className="icon" title={$L('修改')} onClick={() => this.handleEdit(item)}>
|
||||
<i className="zmdi zmdi-edit" />
|
||||
</a>
|
||||
<a className="icon danger-hover" title={$L('删除')} onClick={() => !disabled && this.handleDelete(item[0])} disabled={disabled}>
|
||||
<a className="icon danger-hover" title={$L('删除')} onClick={() => this.handleDelete(item[0])}>
|
||||
<i className="zmdi zmdi-delete" />
|
||||
</a>
|
||||
</td>
|
||||
|
@ -114,27 +105,6 @@ class TriggerList extends ConfigList {
|
|||
)
|
||||
}
|
||||
|
||||
handleLock(item, lock) {
|
||||
if (lock !== true && item[8][0] !== rb.currentUser) {
|
||||
RbHighbar.create($L('请联系 %s 解锁', item[8][1]))
|
||||
return
|
||||
}
|
||||
|
||||
const tips = lock ? $L('锁定后只有你可以修改/删除,其他人无法操作,直到你解锁') : $L('确认解锁?')
|
||||
|
||||
RbAlert.create(tips, {
|
||||
type: 'warning',
|
||||
onConfirm: function () {
|
||||
this.disabled(true)
|
||||
$.post(`/admin/lock/${lock ? 'lock' : 'unlock'}?id=${item[0]}`, (res) => {
|
||||
this.hide()
|
||||
if (res.error_code === 0) dlgActionAfter()
|
||||
else RbHighbar.error(res.error_msg)
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
handleEdit(item) {
|
||||
renderRbcomp(<TriggerEdit id={item[0]} name={item[3]} isDisabled={item[4]} />)
|
||||
}
|
||||
|
@ -150,6 +120,13 @@ class TriggerList extends ConfigList {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
handleShowChain(id) {
|
||||
if (rb.commercial < 10) {
|
||||
return RbHighbar.error(WrapHtml($L('免费版不支持此功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)')))
|
||||
}
|
||||
RbModal.create(`trigger/trigger-chain?id=${id}`, $L('触发过程'), { urlOpenInNew: true })
|
||||
}
|
||||
}
|
||||
|
||||
class TriggerEdit extends ConfigFormDlg {
|
||||
|
|
1642
src/main/resources/web/assets/lib/charts/mermaid.min.js
vendored
Normal file
1642
src/main/resources/web/assets/lib/charts/mermaid.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
113
src/main/resources/web/common/mermaid-chart.html
Normal file
113
src/main/resources/web/common/mermaid-chart.html
Normal file
|
@ -0,0 +1,113 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:replace="~{/_include/header}" />
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/assets/css/approvals.css}" />
|
||||
<title>[[${title ?:'REBUILD'}]]</title>
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
.main-content,
|
||||
pre {
|
||||
background-color: #fff;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.main-content,
|
||||
pre.mermaid {
|
||||
min-height: 500px;
|
||||
}
|
||||
pre.mermaid {
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
pre.mermaid .edgeLabel,
|
||||
pre.mermaid .er.relationshipLabel {
|
||||
background-color: #fff !important;
|
||||
font-size: 14px;
|
||||
}
|
||||
pre.mermaid .relationshipLabelBox {
|
||||
fill: none !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
pre.mermaid .nodeLabel {
|
||||
font-size: 14px;
|
||||
color: #222;
|
||||
}
|
||||
pre.mermaid .node rect {
|
||||
fill: #e6eff8 !important;
|
||||
stroke: #4285f4 !important;
|
||||
}
|
||||
pre.mermaid .mermaidTooltip {
|
||||
display: none;
|
||||
font-size: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-content m-0 p-0">
|
||||
<pre class="mermaid">
|
||||
[(${mermaidData})]
|
||||
</pre>
|
||||
</div>
|
||||
<div class="zoom hide">
|
||||
<a class="zoom-in">
|
||||
<i class="zmdi zmdi-plus"></i>
|
||||
</a>
|
||||
<span>100%</span>
|
||||
<a class="zoom-out">
|
||||
<i class="zmdi zmdi-minus"></i>
|
||||
</a>
|
||||
</div>
|
||||
<th:block th:replace="~{/_include/footer}" />
|
||||
<script th:src="@{/assets/lib/charts/mermaid.min.js?v=10.4.0}"></script>
|
||||
<script type="text/babel">
|
||||
$(document).ready(() => {
|
||||
const $node = $('.mermaid')
|
||||
|
||||
mermaid.initialize({
|
||||
securityLevel: 'loose',
|
||||
startOnLoad: false,
|
||||
})
|
||||
mermaid
|
||||
.run({
|
||||
nodes: $node,
|
||||
})
|
||||
.then(() => {
|
||||
$('.zoom').removeClass('hide')
|
||||
parent.RbModal.resize()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
let zoom = 100
|
||||
function setZoom(z) {
|
||||
zoom += z
|
||||
if (zoom < 20) zoom = 20
|
||||
if (zoom > 500) zoom = 500
|
||||
|
||||
$('.zoom > span').text(zoom + '%')
|
||||
$node.css('transform', `scale(${zoom / 100})`)
|
||||
}
|
||||
$('.zoom .zoom-in').on('click', () => setZoom(10))
|
||||
$('.zoom .zoom-out').on('click', () => setZoom(-10))
|
||||
|
||||
$node.draggable({ cursor: 'move', scroll: false })
|
||||
|
||||
$(document).on('mousewheel', (e) => {
|
||||
const value = e.originalEvent.wheelDelta || -e.originalEvent.detail
|
||||
const delta = Math.max(-1, Math.min(1, value))
|
||||
setZoom(delta < 0 ? -10 : 10)
|
||||
})
|
||||
})
|
||||
|
||||
function nodeClick(a) {
|
||||
window.open(`../../entity/${a}/base`)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -90,7 +90,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="dataTables_oper">
|
||||
<div class="dataTables_oper invisible">
|
||||
<button class="btn btn-space btn-secondary J_view" type="button" disabled="disabled"><i class="icon zmdi zmdi-folder"></i> [[${bundle.L('打开')}]]</button>
|
||||
<button class="btn btn-space btn-secondary J_edit" type="button" disabled="disabled"><i class="icon zmdi zmdi-edit"></i> [[${bundle.L('编辑')}]]</button>
|
||||
<div class="btn-group btn-space J_action">
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="dataTables_oper">
|
||||
<div class="dataTables_oper invisible">
|
||||
<button class="btn btn-space btn-secondary J_view" type="button" disabled="disabled"><i class="icon zmdi zmdi-folder"></i> [[${bundle.L('打开')}]]</button>
|
||||
<button class="btn btn-space btn-secondary J_edit" type="button" disabled="disabled"><i class="icon zmdi zmdi-edit"></i> [[${bundle.L('编辑')}]]</button>
|
||||
<button class="btn btn-space btn-primary J_new" type="button" disabled="disabled"><i class="icon zmdi zmdi-plus"></i> [[${bundle.L('新建')}]]</button>
|
||||
|
|
Loading…
Reference in a new issue