Reletaed update (#456)

* Edit on related list

* fix: Approval state for details

* better styles
This commit is contained in:
RB 2022-04-18 18:13:54 +08:00 committed by GitHub
parent 24813ba35f
commit c9d07809ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 158 additions and 63 deletions

2
@rbv

@ -1 +1 @@
Subproject commit 403b1fd962ccffe8fed8fc0ee7360650bc2f89d9
Subproject commit 46f0d2198f1df816ac6ced50701a12a5bbed9184

View file

@ -100,8 +100,8 @@ public class FormsBuilder extends FormsManager {
Assert.isTrue(entityMeta.getEntityCode().equals(record.getEntityCode()), "[entity] and [record] do not match");
}
// 明细实体
final Entity mainEntity = entityMeta.getMainEntity();
// 如果明细实体
final Entity hasMainEntity = entityMeta.getMainEntity();
// 审批流程状态
ApprovalState approvalState;
@ -109,11 +109,11 @@ public class FormsBuilder extends FormsManager {
// 新建
if (record == null) {
if (mainEntity != null) {
ID mainId = FormBuilderContextHolder.getMainIdOfDetail();
Assert.notNull(mainId, "Call `FormBuilderContextHolder#setMainIdOfDetail` first!");
if (hasMainEntity != null) {
ID mainid = FormBuilderContextHolder.getMainIdOfDetail();
Assert.notNull(mainid, "Call `FormBuilderContextHolder#setMainIdOfDetail` first!");
approvalState = EntityHelper.isUnsavedId(mainId) ? null : getHadApproval(mainEntity, mainId);
approvalState = EntityHelper.isUnsavedId(mainid) ? null : getHadApproval(hasMainEntity, mainid);
if ((approvalState == ApprovalState.PROCESSING || approvalState == ApprovalState.APPROVED)) {
return formatModelError(approvalState == ApprovalState.APPROVED
? Language.L("主记录已完成审批,不能添加明细")
@ -123,8 +123,8 @@ public class FormsBuilder extends FormsManager {
// 明细无需审批
approvalState = null;
if (!EntityHelper.isUnsavedId(mainId)
&& !Application.getPrivilegesManager().allowUpdate(user, mainId)) {
if (!EntityHelper.isUnsavedId(mainid)
&& !Application.getPrivilegesManager().allowUpdate(user, mainid)) {
return formatModelError(Language.L("你没有添加明细权限"));
}
@ -151,11 +151,11 @@ public class FormsBuilder extends FormsManager {
approvalState = getHadApproval(entityMeta, record);
if (approvalState != null) {
String recordType = mainEntity == null ? Language.L("记录") : Language.L("主记录");
String recordType = hasMainEntity == null ? Language.L("记录") : Language.L("主记录");
if (approvalState == ApprovalState.APPROVED) {
return formatModelError(Language.L("%s已完成审批禁止操作", recordType));
return formatModelError(Language.L("%s已完成审批禁止编辑", recordType));
} else if (approvalState == ApprovalState.PROCESSING) {
return formatModelError(Language.L("%s正在审批中禁止操作", recordType));
return formatModelError(Language.L("%s正在审批中禁止编辑", recordType));
}
}
}
@ -190,8 +190,8 @@ public class FormsBuilder extends FormsManager {
}
// /明细实体处理
if (entityMeta.getMainEntity() != null) {
model.set("mainMeta", EasyMetaFactory.toJSON(entityMeta.getMainEntity()));
if (hasMainEntity != null) {
model.set("mainMeta", EasyMetaFactory.toJSON(hasMainEntity));
} else if (entityMeta.getDetailEntity() != null) {
model.set("detailMeta", EasyMetaFactory.toJSON(entityMeta.getDetailEntity()));
}
@ -230,13 +230,15 @@ public class FormsBuilder extends FormsManager {
return RobotApprovalManager.instance.hadApproval(entity, null);
}
// 无明细实体
// 普通实体
if (entity.getMainEntity() == null) {
return RobotApprovalManager.instance.hadApproval(entity, recordId);
}
ID mainId = FormBuilderContextHolder.getMainIdOfDetail();
if (mainId == null) {
// 明细实体
ID mainid = FormBuilderContextHolder.getMainIdOfDetail();
if (mainid == null) {
Field dtmField = MetadataHelper.getDetailToMainField(entity);
Object[] o = Application.getQueryFactory().uniqueNoFilter(recordId, dtmField.getName());
if (o == null) {
@ -244,9 +246,10 @@ public class FormsBuilder extends FormsManager {
return null;
}
mainId = (ID) o[0];
mainid = (ID) o[0];
}
return RobotApprovalManager.instance.hadApproval(entity, mainId);
return RobotApprovalManager.instance.hadApproval(entity.getMainEntity(), mainid);
}
/**

View file

@ -17,6 +17,7 @@ import com.alibaba.fastjson.JSON;
import com.rebuild.core.Application;
import com.rebuild.core.metadata.EntityHelper;
import com.rebuild.core.metadata.MetadataHelper;
import com.rebuild.core.service.approval.ApprovalState;
import com.rebuild.core.service.feeds.FeedsType;
import com.rebuild.core.service.query.ParseHelper;
import com.rebuild.core.service.query.QueryHelper;
@ -64,6 +65,8 @@ public class RelatedListController extends BaseController {
Entity relatedEntity = MetadataHelper.getEntity(related.split("\\.")[0]);
Object[][] array = QueryHelper.createQuery(sql, relatedEntity).setLimit(ps, pn * ps - ps).array();
List<Object> res = new ArrayList<>();
for (Object[] o : array) {
Object nameValue = o[1];
nameValue = FieldValueHelper.wrapFieldValue(nameValue, relatedEntity.getNameField(), true);
@ -71,13 +74,19 @@ public class RelatedListController extends BaseController {
nameValue = FieldValueHelper.NO_LABEL_PREFIX + o[0].toString().toUpperCase();
}
o[1] = nameValue;
o[2] = I18nUtils.formatDate((Date) o[2]);
int approvalState = o.length > 3 ? ObjectUtils.toInt(o[3]) : 0;
boolean canUpdate = approvalState != ApprovalState.APPROVED.getState()
&& approvalState != ApprovalState.PROCESSING.getState()
&& Application.getPrivilegesManager().allowUpdate(user, (ID) o[0]);
res.add(new Object[] {
o[0], nameValue, I18nUtils.formatDate((Date) o[2]),
approvalState, canUpdate });
}
return JSONUtils.toJSONObject(
new String[] { "total", "data" },
new Object[] { 0, array });
new Object[] { 0, res });
}
@GetMapping("related-counts")
@ -158,6 +167,10 @@ public class RelatedListController extends BaseController {
sql.append(primaryField.getName()).append(",")
.append(namedField.getName()).append(",")
.append(EntityHelper.ModifiedOn);
if (MetadataHelper.hasApprovalField(relatedEntity)) {
sql.append(",").append(EntityHelper.ApprovalState);
}
}
sql.append(" from ").append(relatedEntity.getName()).append(" where ").append(mainWhere);

View file

@ -338,6 +338,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
content: '·';
color: #aaa;
margin-right: 6px;
font-weight: bolder;
}
.chart-list > div .btn {

View file

@ -146,7 +146,8 @@ See LICENSE and COMMERCIAL in the project root for license information.
.file-list-item > div.detail .extras > span + span::before {
content: '·';
margin: 0 8px 0 10px;
margin: 0 10px;
font-weight: bolder;
}
.file-list-item > div.detail a:hover {

View file

@ -201,6 +201,18 @@ button[disabled] {
line-height: 1.2 !important;
}
.badge-sm {
border-radius: 99px;
font-weight: normal;
font-size: 12px;
padding: 1px 6px 0;
line-height: 17px;
}
.badge-sm.badge-light {
line-height: 15px;
}
a.badge.text-id {
color: #4285f4;
cursor: pointer;
@ -1719,7 +1731,7 @@ th.column-fixed {
.dataTables_info .stat-item::before {
content: '·';
color: #999;
font-weight: bold;
font-weight: bolder;
margin: 0 5px;
}

View file

@ -172,8 +172,32 @@ body {
font-size: 1.2rem;
}
.related-list .card .header-title .col-2.text-right {
.related-list .card .header-title .record-meta {
padding-right: 30px;
text-align: right;
}
.related-list .card .header-title .record-meta .badge {
margin-right: 13px;
}
.related-list .card .header-title .record-meta a.edit {
color: #999;
font-size: 1.231rem;
margin-left: -38px;
margin-top: -2px;
position: absolute;
display: none;
padding: 0 10px;
}
.related-list .card .header-title .record-meta a.edit:hover {
color: #4285f4;
}
.related-list .card:hover .header-title .record-meta a.edit,
.related-list .card.active .header-title .record-meta a.edit {
display: inline-block;
}
.related-list .related-toolbar {
@ -189,7 +213,7 @@ body {
padding-top: 3px;
}
.view-operating > div{
.view-operating > div {
margin-top: 15px;
}
@ -346,7 +370,7 @@ body {
}
.rbview-form .form-group.editable a.edit::before {
font-family: 'Material-Design-Iconic-Font';
font-family: 'Material-Design-Iconic-Font', serif;
content: '\f158';
font-size: 16px;
display: inline-block;
@ -482,8 +506,6 @@ body {
.view-history .view-history-items > li b:first-child {
font-weight: normal;
min-width: 60px;
display: inline-block;
}
.CodeMirror-fullscreen {
@ -549,16 +571,28 @@ body {
.tasks-list.inview .header-title .task-meta {
text-align: right;
color: #878787;
font-size: 12px;
}
.tasks-list.inview .header-title .task-meta .avatar {
.tasks-list.inview .header-title .task-meta > span {
margin-left: 10px;
position: relative;
}
.tasks-list.inview .header-title .task-meta > span + span::before {
content: '·';
margin-right: 10px;
font-weight: bolder;
}
.tasks-list.inview .header-title .task-meta > span .avatar {
position: absolute;
top: -4px;
right: 15px;
margin-left: 15px;
margin-top: -4px;
margin-left: -24px;
cursor: default;
}
.tasks-list.inview .header-title .task-meta .avatar img {
.tasks-list.inview .header-title .task-meta > span img {
width: 26px;
height: 26px;
}

View file

@ -132,7 +132,7 @@ class LightTaskList extends RelatedList {
return (
<div className={`card priority-${item.priority} status-${item.status}`} key={item.id}>
<div className="row header-title">
<div className="col-7 title">
<div className="col-8 title">
<label className="custom-control custom-control-sm custom-checkbox custom-control-inline ptask">
<input className="custom-control-input" type="checkbox" defaultChecked={item.status > 0} disabled={readonly} onClick={() => this._toggleStatus(item)} />
<span className="custom-control-label" />
@ -141,30 +141,35 @@ class LightTaskList extends RelatedList {
[{item.taskNumber}] {item.taskName}
</a>
</div>
<div className="col-5 task-meta">
<div className="row">
<div className="col-7 pr-0 text-ellipsis">{item.planName}</div>
<div className="col-5 text-ellipsis">
{!item.deadline && !item.endTime && (
<React.Fragment>
<span className="mr-1">{$L('创建时间')}</span>
<DateShow date={item.createdOn} />
</React.Fragment>
)}
{item.endTime && (
<React.Fragment>
<span className="mr-1">{$L('完成时间')}</span>
<DateShow date={item.endTime} />
</React.Fragment>
)}
{!item.endTime && item.deadline && (
<React.Fragment>
<span className="mr-1">{$L('到期时间')}</span>
<DateShow date={item.deadline} />
</React.Fragment>
)}
</div>
</div>
<div className="col-4 task-meta">
{item.executor && (
<span>
<a className="avatar" title={`${$L('执行人')} ${item.executor[1]}`}>
<img src={`${rb.baseUrl}/account/user-avatar/${item.executor[0]}`} alt="Avatar" />
</a>
</span>
)}
<span title={$L('项目')}>{item.planName}</span>
{!item.deadline && !item.endTime && (
<span>
<span className="mr-1">{$L('创建时间')}</span>
<DateShow date={item.createdOn} />
</span>
)}
{item.endTime && (
<span>
<span className="mr-1">{$L('完成时间')}</span>
<DateShow date={item.endTime} />
</span>
)}
{!item.endTime && item.deadline && (
<span>
<span className="mr-1">{$L('到期时间')}</span>
<DateShow date={item.deadline} />
</span>
)}
</div>
</div>
</div>

View file

@ -43,7 +43,7 @@ class RbViewForm extends React.Component {
if (window.RbViewPage) window.RbViewPage.setReadonly()
else $('.J_edit, .J_delete').remove()
hadAlert = <RbAlertBox message={hadApproval === 2 ? $L('主记录正在审批中明细记录禁止修改') : $L('主记录已审批完成明细记录禁止修改')} />
hadAlert = <RbAlertBox message={hadApproval === 2 ? $L('主记录正在审批中明细记录禁止操作') : $L('主记录已审批完成明细记录禁止操作')} />
}
hadApproval = null
}
@ -305,6 +305,11 @@ class RelatedList extends React.Component {
}
}
const APPROVAL_STATE_CLAZZs = {
2: [$L('审批中'), 'warning'],
10: [$L('通过'), 'success'],
11: [$L('驳回'), 'danger'],
}
// ~ 业务实体相关项列表
class EntityRelatedList extends RelatedList {
constructor(props) {
@ -322,15 +327,24 @@ class EntityRelatedList extends RelatedList {
}
renderItem(item) {
const astate = APPROVAL_STATE_CLAZZs[item[3]]
return (
<div key={item[0]} className={`card ${this.state.viewOpens[item[0]] ? 'active' : ''}`} ref={`item-${item[0]}`}>
<div className="row header-title" onClick={() => this._toggleInsideView(item[0])}>
<div className="col-10">
<div className="col-9">
<a href={`#!/View/${this.__entity}/${item[0]}`} onClick={(e) => this._handleView(e)} title={$L('打开')}>
{item[1]}
</a>
</div>
<div className="col-2 text-right">
<div className="col-3 record-meta">
{item[4] && (
<a className="edit" onClick={(e) => this._handleEdit(e, item[0])} title={$L('编辑')}>
<i className="icon zmdi zmdi-edit" />
</a>
)}
{astate && <span className={`badge badge-sm badge-${astate[1]}`}>{astate[0]}</span>}
<span className="fs-12 text-muted" title={`${$L('修改时间')} ${item[2]}`}>
{$fromNow(item[2])}
</span>
@ -372,6 +386,16 @@ class EntityRelatedList extends RelatedList {
})
}
_handleEdit(e, id) {
$stopEvent(e, true)
RbFormModal.create({
id: id,
entity: this.__entity,
title: $L('编辑%s', this.props.entity2[0]),
icon: this.props.entity2[1],
})
}
_handleView(e) {
$stopEvent(e, true)
RbViewPage.clickView(e.currentTarget)
@ -692,8 +716,10 @@ const RbViewPage = {
).appendTo('.nav-tabs')
const $tabPane = $(`<div class="tab-pane" id="${tabId}"></div>`).appendTo('.tab-content')
const configThat = this
$tabNav.find('a').on('click', function () {
$tabPane.find('.related-list').length === 0 && renderRbcomp(<MixRelatedList entity={entity} mainid={that.__id} autoExpand={$isTrue(wpc.viewTabsAutoExpand)} />, $tabPane)
$tabPane.find('.related-list').length === 0 &&
renderRbcomp(<MixRelatedList entity={entity} entity2={[configThat.entityLabel, configThat.icon]} mainid={that.__id} autoExpand={$isTrue(wpc.viewTabsAutoExpand)} />, $tabPane)
})
})
this.updateVTabs()