be: AUTOSHARE,AUTOASSIGN

This commit is contained in:
RB 2025-08-30 18:37:15 +08:00
parent 823ceca348
commit dbd12edf1a
10 changed files with 147 additions and 126 deletions

2
@rbv

@ -1 +1 @@
Subproject commit 2ca2b34c97f72d4667d5423828c5d1b89c4ddece
Subproject commit 9c9477c9fedb9a2416bbd8c91ab9516720b126e3

View file

@ -15,6 +15,7 @@ import com.rebuild.core.Application;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyEntity;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.service.trigger.TriggerAction;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.Assert;
@ -226,4 +227,20 @@ public class MetadataSorter {
return comparator.compare(fooLetter, barLetter);
});
}
/**
* 排序
*
* @param entities
* @param selfEntity 添加自己
*/
public static void sortEntities(List<Object[]> entities, Entity selfEntity) {
Comparator<Object> comparator = Collator.getInstance(Locale.CHINESE);
entities.sort((o1, o2) -> comparator.compare(o1[1], o2[1]));
if (selfEntity != null) {
entities.add(new String[]{
selfEntity.getName(), EasyMetaFactory.getLabel(selfEntity), TriggerAction.SOURCE_SELF});
}
}
}

View file

@ -18,11 +18,11 @@ import com.rebuild.core.service.general.GeneralEntityServiceContextHolder;
import com.rebuild.core.service.general.OperatingContext;
import com.rebuild.core.service.trigger.ActionContext;
import com.rebuild.core.service.trigger.ActionType;
import com.rebuild.core.service.trigger.TriggerAction;
import com.rebuild.core.service.trigger.TriggerException;
import com.rebuild.core.service.trigger.TriggerResult;
import com.rebuild.core.support.KVStorage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
@ -35,7 +35,7 @@ import java.util.Set;
* @since 2019/8/23
*/
@Slf4j
public class AutoAssign extends TriggerAction {
public class AutoAssign extends AutoHoldTriggerAction {
public AutoAssign(ActionContext context) {
super(context);
@ -96,27 +96,23 @@ public class AutoAssign extends TriggerAction {
toUser = toUsers.toArray(new ID[0])[r];
}
Set<ID> relateds42 = null;
String hasCascades = ((JSONObject) actionContext.getActionContent()).getString("cascades");
String[] cascades = null;
if (StringUtils.isNotBlank(hasCascades)) {
cascades = hasCascades.split(",");
} else {
relateds42 = getWillRecords(operatingContext);
}
GeneralEntityServiceContextHolder.setSkipGuard(recordId);
GeneralEntityServiceContextHolder.setFromTrigger(recordId);
assign(recordId, toUser, cascades);
// 当前分配人
if (orderedAssign) {
KVStorage.setCustomValue(orderedAssignKey, toUser);
}
try {
Application.getEntityService(actionContext.getSourceEntity().getEntityCode())
.assign(recordId, toUser, cascades);
// 当前分配人
if (orderedAssign) {
KVStorage.setCustomValue(orderedAssignKey, toUser);
}
} finally {
GeneralEntityServiceContextHolder.isSkipGuardOnce();
GeneralEntityServiceContextHolder.isFromTrigger(true);
if (!CollectionUtils.isEmpty(relateds42)) {
for (ID id : relateds42) assign(id, toUser, null);
}
Collection<ID> affected = new ArrayList<>(2);
@ -124,4 +120,16 @@ public class AutoAssign extends TriggerAction {
affected.add(recordId);
return TriggerResult.success(affected);
}
private void assign(ID recordId, ID toUser, String[] cascades) {
GeneralEntityServiceContextHolder.setSkipGuard(recordId);
GeneralEntityServiceContextHolder.setFromTrigger(recordId);
try {
Application.getEntityService(recordId.getEntityCode()).assign(recordId, toUser, cascades);
} finally {
GeneralEntityServiceContextHolder.isSkipGuardOnce();
GeneralEntityServiceContextHolder.isFromTrigger(true);
}
}
}

View file

@ -87,6 +87,7 @@ public abstract class AutoHoldTriggerAction extends TriggerAction {
Entity sourceEntity = actionContext.getSourceEntity();
JSONArray fields = actionContent.getJSONArray("fields");
if (fields == null) fields = actionContent.getJSONArray("fields42");
if (fields == null) fields = actionContent.getJSONArray("revokeFields");
List<String> fieldsRefs = new ArrayList<>();

View file

@ -20,10 +20,10 @@ import com.rebuild.core.service.general.GeneralEntityServiceContextHolder;
import com.rebuild.core.service.general.OperatingContext;
import com.rebuild.core.service.trigger.ActionContext;
import com.rebuild.core.service.trigger.ActionType;
import com.rebuild.core.service.trigger.TriggerAction;
import com.rebuild.core.service.trigger.TriggerException;
import com.rebuild.core.service.trigger.TriggerResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
@ -35,7 +35,7 @@ import java.util.Set;
* @since 2019/8/23
*/
@Slf4j
public class AutoShare extends TriggerAction {
public class AutoShare extends AutoHoldTriggerAction {
public AutoShare(ActionContext context) {
super(context);
@ -64,18 +64,34 @@ public class AutoShare extends TriggerAction {
return TriggerResult.noMatching();
}
Set<ID> relateds42 = null;
String hasCascades = ((JSONObject) actionContext.getActionContent()).getString("cascades");
String[] cascades = null;
if (StringUtils.isNotBlank(hasCascades)) {
cascades = hasCascades.split(",");
} else {
relateds42 = getWillRecords(operatingContext);
}
int shareRights = BizzPermission.READ.getMask();
if (content.getBooleanValue("withUpdate")) {
shareRights += BizzPermission.UPDATE.getMask();
}
final EntityService es = Application.getEntityService(actionContext.getSourceEntity().getEntityCode());
ID[] toUsers2 = toUsers.toArray(new ID[0]);
share(recordId, toUsers2, cascades, shareRights);
if (!CollectionUtils.isEmpty(relateds42)) {
for (ID id : relateds42) share(id, toUsers2, null, shareRights);
}
Collection<ID> affected = new ArrayList<>(toUsers);
affected.add(recordId);
return TriggerResult.success(affected);
}
private void share(ID recordId, ID[] toUsers, String[] cascades, int shareRights) {
EntityService es = Application.getEntityService(recordId.getEntityCode());
for (ID toUser : toUsers) {
GeneralEntityServiceContextHolder.setSkipGuard(recordId);
GeneralEntityServiceContextHolder.setFromTrigger(recordId);
@ -87,9 +103,5 @@ public class AutoShare extends TriggerAction {
GeneralEntityServiceContextHolder.isAllowForceUpdateOnce();
}
}
Collection<ID> affected = new ArrayList<>(toUsers);
affected.add(recordId);
return TriggerResult.success(affected);
}
}

View file

@ -24,22 +24,19 @@ import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyField;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.privileges.PrivilegesManager;
import com.rebuild.core.service.trigger.TriggerAction;
import com.rebuild.web.BaseController;
import com.rebuild.web.EntityParam;
import com.rebuild.web.general.MetaFormatter;
import com.rebuild.web.robot.trigger.FieldAggregationController;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
/**
@ -174,42 +171,43 @@ public class MetadataGetting extends BaseController {
// 关联项包括相关项和引用项
@GetMapping("relateds")
public RespBody getEntityRelateds(@EntityParam Entity entity) {
// 1.我引用了谁
List<String[]> refs = new ArrayList<>();
// 相关项
List<Object[]> relateds = new ArrayList<>();
for (Field to : entity.getReferenceToFields(Boolean.FALSE, Boolean.TRUE)) {
Entity oe = to.getOwnEntity();
// 排除系统实体
if (!MetadataHelper.isBusinessEntity(oe)) continue;
// 排除明细
if (oe.getMainEntity() != null && oe.getMainEntity().equals(entity)) continue;
String entityLabel = String.format("%s (%s)",
EasyMetaFactory.getLabel(oe), EasyMetaFactory.getLabel(to));
relateds.add(new Object[]{to.getName() + "." + oe.getName(), entityLabel, oe.getMainEntity() != null});
}
// 引用项
List<Object[]> refs = new ArrayList<>();
for (Field from : MetadataSorter.sortFields(entity,
DisplayType.REFERENCE, DisplayType.N2NREFERENCE, DisplayType.ANYREFERENCE)) {
Entity re = from.getReferenceEntity();
boolean isAny = from.getType() == FieldType.ANY_REFERENCE;
// 排除系统实体和任意引用
if (!(MetadataHelper.isBusinessEntity(re) || isAny)) continue;
String entityLabel = String.format("%s (%s)",
isAny ? "" : EasyMetaFactory.getLabel(re), EasyMetaFactory.getLabel(from));
refs.add(new String[]{from.getName(), entityLabel});
refs.add(new Object[]{from.getName(), entityLabel, re.getMainEntity() != null});
}
// 2.谁引用了我
List<String[]> relateds = new ArrayList<>();
for (Field to : entity.getReferenceToFields(Boolean.FALSE, Boolean.TRUE)) {
Entity oe = to.getOwnEntity();
if (!MetadataHelper.isBusinessEntity(oe)) continue;
String entityLabel = String.format("%s (%s)",
EasyMetaFactory.getLabel(oe), EasyMetaFactory.getLabel(to));
relateds.add(new String[]{to.getName() + "." + oe.getName(), entityLabel});
}
FieldAggregationController.sortEntities(refs, null);
FieldAggregationController.sortEntities(relateds, null);
MetadataSorter.sortEntities(refs, null);
MetadataSorter.sortEntities(relateds, null);
JSONObject res = new JSONObject();
res.put("refs", refs);
res.put("relateds", relateds);
res.put("refs", refs);
res.put("self", new Object[]{
TriggerAction.SOURCE_SELF, EasyMetaFactory.getLabel(entity), entity.getMainEntity() != null});
return RespBody.ok(res);
}
private void sortEntities(List<String[]> entities) {
Comparator<Object> comparator = Collator.getInstance(Locale.CHINESE);
entities.sort((o1, o2) -> comparator.compare(o1[1], o2[1]));
}
}

View file

@ -12,13 +12,13 @@ import cn.devezhao.persist4j.Field;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rebuild.api.RespBody;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.metadata.MetadataSorter;
import com.rebuild.core.metadata.easymeta.DisplayType;
import com.rebuild.core.metadata.easymeta.EasyField;
import com.rebuild.core.metadata.easymeta.EasyMetaFactory;
import com.rebuild.core.service.approval.RobotApprovalManager;
import com.rebuild.core.service.trigger.TriggerAction;
import com.rebuild.utils.JSONUtils;
import com.rebuild.web.BaseController;
import com.rebuild.web.EntityParam;
@ -29,11 +29,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
/**
* @author devezhao
@ -44,9 +41,9 @@ import java.util.Locale;
public class FieldAggregationController extends BaseController {
@RequestMapping("field-aggregation-entities")
public List<String[]> getTargetEntities(
public RespBody getTargetEntities(
@EntityParam(name = "source") Entity sourceEntity, HttpServletRequest request) {
List<String[]> entities = new ArrayList<>();
List<Object[]> entities = new ArrayList<>();
// 1. 我引用了谁
@ -61,18 +58,19 @@ public class FieldAggregationController extends BaseController {
// v35 字段匹配
if (getBoolParameter(request, "matchfields")) {
List<String[]> temp = new ArrayList<>();
List<Object[]> temp = new ArrayList<>();
for (Entity entity : MetadataSorter.sortEntities(null, false, true)) {
temp.add(new String[]{entity.getName(), EasyMetaFactory.getLabel(entity), "$"});
}
sortEntities(temp, null);
MetadataSorter.sortEntities(temp, null);
entities.addAll(temp);
}
// v3.0 字段聚合无需自己
sortEntities(entities, null);
return entities;
MetadataSorter.sortEntities(entities, null);
return RespBody.ok(entities);
}
@RequestMapping("field-aggregation-fields")
@ -137,21 +135,4 @@ public class FieldAggregationController extends BaseController {
new String[] { "source", "target", "hadApproval", "target4Group" },
new Object[] { sourceFields, targetFields, hadApproval, targetFields2 });
}
/**
* 排序
*
* @param entities
* @param selfEntity 添加自己
*/
public static void sortEntities(List<String[]> entities, Entity selfEntity) {
Comparator<Object> comparator = Collator.getInstance(Locale.CHINESE);
entities.sort((o1, o2) -> comparator.compare(o1[1], o2[1]));
// 可更新自己通过主键字段
if (selfEntity != null) {
entities.add(new String[] {
selfEntity.getName(), EasyMetaFactory.getLabel(selfEntity), TriggerAction.SOURCE_SELF });
}
}
}

View file

@ -51,9 +51,9 @@ import java.util.Set;
public class FieldWritebackController extends BaseController {
@RequestMapping("field-writeback-entities")
public List<String[]> getTargetEntities(
public RespBody getTargetEntities(
@EntityParam(name = "source") Entity sourceEntity, HttpServletRequest request) {
List<String[]> temp = new ArrayList<>();
List<Object[]> temp = new ArrayList<>();
Set<String> unique = new HashSet<>();
// 1.我引用了谁 v2.7.1
@ -69,8 +69,8 @@ public class FieldWritebackController extends BaseController {
unique.add(refEntity.getName() + "." + refFrom.getName());
}
FieldAggregationController.sortEntities(temp, null);
List<String[]> entities = new ArrayList<>(temp);
MetadataSorter.sortEntities(temp, null);
List<Object[]> entities = new ArrayList<>(temp);
temp.clear();
// 2.谁引用了我 (N)
@ -87,12 +87,12 @@ public class FieldWritebackController extends BaseController {
}
}
FieldAggregationController.sortEntities(temp, null);
MetadataSorter.sortEntities(temp, null);
entities.addAll(temp);
temp.clear();
// 3. 自己
FieldAggregationController.sortEntities(temp, sourceEntity);
MetadataSorter.sortEntities(temp, sourceEntity);
entities.addAll(temp);
temp.clear();
@ -102,12 +102,12 @@ public class FieldWritebackController extends BaseController {
temp.add(new String[]{entity.getName(), EasyMetaFactory.getLabel(entity), "$"});
}
FieldAggregationController.sortEntities(temp, null);
MetadataSorter.sortEntities(temp, null);
entities.addAll(temp);
temp.clear();
}
return entities;
return RespBody.ok(entities);
}
@RequestMapping("field-writeback-fields")

View file

@ -14,7 +14,7 @@ class ContentAutoAssign extends ActionContentSpec {
static = { ...this.props, assignRule: 1 }
render() {
const relatedsFields = this.state.relatedsFields
const fields42 = this.state.relatedsFields
return (
<div className="auto-assign">
<form className="simple">
@ -53,7 +53,7 @@ class ContentAutoAssign extends ActionContentSpec {
<select className="form-control form-control-sm" ref={(c) => (this._cascades = c)}>
{this.state.cascadesEntity.map((item) => {
return (
<option key={'option-' + item[0]} value={item[0]}>
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
@ -61,28 +61,30 @@ class ContentAutoAssign extends ActionContentSpec {
</select>
)}
{relatedsFields && (
{fields42 && (
<select className="form-control form-control-sm" ref={(c) => (this._$relatedsFields = c)} multiple>
<optgroup label={$L('相关项')}>
{relatedsFields &&
relatedsFields.relateds.map((item) => {
{fields42 && fields42.relateds.length > 0 && (
<optgroup label={$L('相关项')}>
{fields42.relateds.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]} (N)
</option>
)
})}
</optgroup>
)}
{fields42 && fields42.refs.length > 0 && (
<optgroup label={$L('引用项')}>
{fields42.refs.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
})}
</optgroup>
<optgroup label={$L('引用项')}>
{relatedsFields &&
relatedsFields.refs.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
})}
</optgroup>
</optgroup>
)}
</select>
)}
</div>
@ -137,8 +139,8 @@ class ContentAutoAssign extends ActionContentSpec {
},
})
if (content.relatedsFields42) {
this.__select42.val(content.relatedsFields42).trigger('change')
if (content.fields42) {
this.__select42.val(content.fields42).trigger('change')
}
})
})
@ -156,7 +158,7 @@ class ContentAutoAssign extends ActionContentSpec {
assignTo: this._assignTo.getSelected(),
assignRule: ~~this.state.assignRule,
cascades: this.__select2 ? this.__select2.val().join(',') : null,
relatedsFields42: this.__select42 ? this.__select42.val() : null,
fields42: this.__select42 ? this.__select42.val() : null,
}
if (!_data.assignTo || _data.assignTo.length === 0) {
RbHighbar.create($L('请选择分配给谁'))

View file

@ -14,7 +14,7 @@ class ContentAutoShare extends ActionContentSpec {
state = { ...this.props }
render() {
const relatedsFields = this.state.relatedsFields
const fields42 = this.state.relatedsFields
return (
<div className="auto-share">
<form className="simple">
@ -39,7 +39,7 @@ class ContentAutoShare extends ActionContentSpec {
<select className="form-control form-control-sm" ref={(c) => (this._cascades = c)}>
{this.state.cascadesEntity.map((item) => {
return (
<option key={'option-' + item[0]} value={item[0]}>
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
@ -47,28 +47,30 @@ class ContentAutoShare extends ActionContentSpec {
</select>
)}
{relatedsFields && (
{fields42 && (
<select className="form-control form-control-sm" ref={(c) => (this._$relatedsFields = c)} multiple>
<optgroup label={$L('相关项')}>
{relatedsFields &&
relatedsFields.relateds.map((item) => {
{fields42 && fields42.relateds.length > 0 && (
<optgroup label={$L('相关项')}>
{fields42.relateds.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]} (N)
</option>
)
})}
</optgroup>
)}
{fields42 && fields42.refs.length > 0 && (
<optgroup label={$L('引用项')}>
{fields42.refs.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
})}
</optgroup>
<optgroup label={$L('引用项')}>
{relatedsFields &&
relatedsFields.refs.map((item) => {
return (
<option key={item[0]} value={item[0]}>
{item[1]}
</option>
)
})}
</optgroup>
</optgroup>
)}
</select>
)}
</div>
@ -129,8 +131,8 @@ class ContentAutoShare extends ActionContentSpec {
},
})
if (content.relatedsFields42) {
this.__select42.val(content.relatedsFields42).trigger('change')
if (content.fields42) {
this.__select42.val(content.fields42).trigger('change')
}
})
})
@ -145,7 +147,7 @@ class ContentAutoShare extends ActionContentSpec {
const _data = {
shareTo: this._shareTo.getSelected(),
cascades: this.__select2 ? this.__select2.val().join(',') : null,
relatedsFields42: this.__select42 ? this.__select42.val() : null,
fields42: this.__select42 ? this.__select42.val() : null,
withUpdate: $(this._withUpdate).prop('checked'),
}
if (!_data.shareTo || _data.shareTo.length === 0) {