mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 15:35:55 +08:00
Merge 1f94fd3d13
into 3165a5ec48
This commit is contained in:
commit
666e4cbedc
2
@rbv
2
@rbv
|
@ -1 +1 @@
|
|||
Subproject commit 734c2297f22409c82bd1f70228362c245c4db246
|
||||
Subproject commit a9ad9283ed576644ff18581919437314bd238672
|
16
README.md
16
README.md
|
@ -15,18 +15,18 @@
|
|||
|
||||
> **福利:加入 REBUILD VIP 用户 QQ 交流群 819865721 1013051587 GET 使用技能**
|
||||
|
||||
## V3.7 新特性
|
||||
## V3.8 新特性
|
||||
|
||||
本次更新为你带来众多功能增强与优化。
|
||||
|
||||
1. [新增] 限时审批
|
||||
2. [新增] 新建任务(触发器)
|
||||
3. [新增] 地图等多个图表
|
||||
4. [新增] 自动明细记录导入(记录转换)
|
||||
5. [新增] 数据列表之卡片模式
|
||||
1. [新增] HTML 报表模版
|
||||
2. [新增] 多表单布局
|
||||
3. [新增] 明细支持 Excel 粘贴录入
|
||||
4. [新增] 图片/附件支持摄像头上传模式
|
||||
5. [新增] 手机版数据列表可导出报表
|
||||
6. [新增] 多个 FrontJS 函数
|
||||
7. [优化] 图表支持多轴显示、横向显示、显示背景
|
||||
8. [优化] 手机版全新列表搜索组件
|
||||
7. [新增] 用户支持批量操作
|
||||
8. [优化] 20+ 细节/BUG/安全性更新
|
||||
9. ...
|
||||
|
||||
更多更新详情请参见 [更新日志](https://getrebuild.com/docs/dev/changelog)
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
|||
</parent>
|
||||
<groupId>com.rebuild</groupId>
|
||||
<artifactId>rebuild</artifactId>
|
||||
<version>3.8.0-dev</version>
|
||||
<version>3.8.0-beta1</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.8.0-dev";
|
||||
public static final String VER = "3.8.0-beta1";
|
||||
/**
|
||||
* Rebuild Build [MAJOR]{1}[MINOR]{2}[PATCH]{2}[BUILD]{2}
|
||||
*/
|
||||
public static final int BUILD = 3080000;
|
||||
public static final int BUILD = 3080001;
|
||||
|
||||
static {
|
||||
// Driver for DB
|
||||
|
|
|
@ -59,6 +59,7 @@ public enum ZeroEntry {
|
|||
|
||||
/**
|
||||
* 允许撤销审批
|
||||
* v3.8 起添加撤回权限
|
||||
*/
|
||||
AllowRevokeApproval(false),
|
||||
|
||||
|
|
|
@ -583,10 +583,10 @@ public class ApprovalProcessor extends SetUser {
|
|||
if (FlowNode.NODE_AUTOAPPROVAL.equals(nodeNo)) {
|
||||
// No name
|
||||
} else if (FlowNode.NODE_REVOKED.equals(nodeNo)) {
|
||||
String nodeName = Language.L("管理员撤销");
|
||||
String nodeName = Language.L("撤销");
|
||||
s.put("nodeName", nodeName);
|
||||
} else if (FlowNode.NODE_CANCELED.equals(nodeNo)) {
|
||||
String nodeName = Language.L("提交人撤回");
|
||||
String nodeName = Language.L("撤回");
|
||||
s.put("nodeName", nodeName);
|
||||
} else {
|
||||
String nodeName = flowNode == null ? null : flowNode.getNodeName();
|
||||
|
|
|
@ -27,7 +27,6 @@ import com.rebuild.core.privileges.OperationDeniedException;
|
|||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.privileges.UserService;
|
||||
import com.rebuild.core.privileges.bizz.InternalPermission;
|
||||
import com.rebuild.core.privileges.bizz.ZeroEntry;
|
||||
import com.rebuild.core.service.BaseService;
|
||||
import com.rebuild.core.service.DataSpecificationNoRollbackException;
|
||||
import com.rebuild.core.service.general.GeneralEntityServiceContextHolder;
|
||||
|
@ -54,6 +53,8 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.rebuild.core.privileges.bizz.ZeroEntry.AllowRevokeApproval;
|
||||
|
||||
/**
|
||||
* 审批流程。此类所有方法不应直接调用,而是通过 ApprovalProcessor 封装类
|
||||
* <p>
|
||||
|
@ -324,13 +325,14 @@ public class ApprovalStepService extends BaseService {
|
|||
final boolean isAdmin = UserHelper.isAdmin(opUser);
|
||||
|
||||
if (isRevoke) {
|
||||
boolean canRevoke = Application.getPrivilegesManager().allow(opUser, ZeroEntry.AllowRevokeApproval);
|
||||
boolean canRevoke = Application.getPrivilegesManager().allow(opUser, AllowRevokeApproval);
|
||||
if (!(isAdmin || canRevoke)) {
|
||||
throw new OperationDeniedException(Language.L("你无权撤销审批"));
|
||||
}
|
||||
} else {
|
||||
boolean canRevoke = Application.getPrivilegesManager().allow(opUser, AllowRevokeApproval);
|
||||
ID s = ApprovalHelper.getSubmitter(recordId, approvalId);
|
||||
if (!(isAdmin || opUser.equals(s))) {
|
||||
if (!(canRevoke || opUser.equals(s))) {
|
||||
throw new OperationDeniedException(Language.L("你无权撤回审批"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,8 +105,10 @@ public class DataExporter extends SetUser {
|
|||
final List<String> head = this.buildHead(builder);
|
||||
|
||||
// Excel
|
||||
if ("xls".equalsIgnoreCase(csvOrExcel)) {
|
||||
File file = RebuildConfiguration.getFileOfTemp(String.format("RBEXPORT-%d.xls", System.currentTimeMillis()));
|
||||
// xlsx: 无 65535 行数限制
|
||||
if ("xls".equalsIgnoreCase(csvOrExcel) || "xlsx".equalsIgnoreCase(csvOrExcel)) {
|
||||
File file = RebuildConfiguration.getFileOfTemp(
|
||||
String.format("RBEXPORT-%d.%s", System.currentTimeMillis(), csvOrExcel.toLowerCase()));
|
||||
|
||||
List<List<String>> head4Excel = new ArrayList<>();
|
||||
for (String h : head) {
|
||||
|
|
|
@ -147,26 +147,7 @@ public class AdvFilterParser extends SetUser {
|
|||
|
||||
// 自动确定查询项
|
||||
if (MODE_QUICK.equalsIgnoreCase(filterExpr.getString("type"))) {
|
||||
String quickFields = filterExpr.getString("quickFields");
|
||||
JSONArray quickItems = buildQuickFilterItems(quickFields, 1);
|
||||
|
||||
// TODO v3.6-b4,3.7 值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);
|
||||
rebuildQuickFilter38();
|
||||
}
|
||||
|
||||
JSONArray items = filterExpr.getJSONArray("items");
|
||||
|
@ -653,6 +634,10 @@ public class AdvFilterParser extends SetUser {
|
|||
// LIKE
|
||||
if (op.equalsIgnoreCase(ParseHelper.LK) || op.equalsIgnoreCase(ParseHelper.NLK)) {
|
||||
value = '%' + value + '%';
|
||||
} else if (op.equalsIgnoreCase(ParseHelper.LK1)) {
|
||||
value = '%' + value;
|
||||
} else if (op.equalsIgnoreCase(ParseHelper.LK2)) {
|
||||
value = value + '%';
|
||||
}
|
||||
sb.append(quoteValue(value, lastFieldMeta.getType()));
|
||||
}
|
||||
|
@ -781,13 +766,57 @@ public class AdvFilterParser extends SetUser {
|
|||
|
||||
/**
|
||||
* 快速查询
|
||||
*
|
||||
*/
|
||||
private void rebuildQuickFilter38() {
|
||||
String quickFields = filterExpr.getString("quickFields");
|
||||
JSONArray quickItems = buildQuickFilterItems(quickFields, 1);
|
||||
|
||||
JSONObject values = filterExpr.getJSONObject("values");
|
||||
final String quickValue = values.values().iterator().next().toString();
|
||||
|
||||
// eg: =完全相等, *后匹配, 前匹配*
|
||||
if (quickValue.length() > 2
|
||||
&& (quickValue.startsWith("=") || quickValue.startsWith("*") || quickValue.endsWith("*"))) {
|
||||
String op2 = ParseHelper.EQ;
|
||||
String value2;
|
||||
if (quickValue.startsWith("*")) op2 = ParseHelper.LK1;
|
||||
else if (quickValue.endsWith("*")) op2 = ParseHelper.LK2;
|
||||
if (quickValue.endsWith("*")) value2 = quickValue.substring(0, quickValue.length() - 1);
|
||||
else value2 = quickValue.substring(1);
|
||||
|
||||
for (Object o : quickItems) {
|
||||
JSONObject item = (JSONObject) o;
|
||||
item.put("op", op2);
|
||||
item.put("value", value2);
|
||||
}
|
||||
|
||||
} else {
|
||||
// v3.6-b4,3.7: 多值查询(转义可输入 \|)。eg: 值1|值2
|
||||
String[] m = quickValue.split("(?<!\\\\)\\|");
|
||||
if (m.length > 1) {
|
||||
values.clear();
|
||||
values.put("1", m[0].trim());
|
||||
|
||||
for (int i = 2; i <= m.length; i++) {
|
||||
JSONArray quickItemsPlus = buildQuickFilterItems(quickFields, i);
|
||||
values.put(String.valueOf(i), m[i - 1].trim());
|
||||
quickItems.addAll(quickItemsPlus);
|
||||
}
|
||||
filterExpr.put("values", values);
|
||||
}
|
||||
}
|
||||
|
||||
// 覆盖
|
||||
filterExpr.put("items", quickItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param quickFields
|
||||
* @param valueIndex
|
||||
* @return
|
||||
*/
|
||||
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:'{" + valueIndex + "}', field:'" + field + "' }"));
|
||||
|
|
|
@ -43,6 +43,8 @@ public class ParseHelper {
|
|||
public static final String NL = "NL";
|
||||
public static final String NT = "NT";
|
||||
public static final String LK = "LK";
|
||||
public static final String LK1 = "LK1"; // *后匹配
|
||||
public static final String LK2 = "LK2"; // 前匹配*
|
||||
public static final String NLK = "NLK";
|
||||
public static final String IN = "IN";
|
||||
public static final String NIN = "NIN";
|
||||
|
@ -132,7 +134,7 @@ public class ParseHelper {
|
|||
return "is null";
|
||||
} else if (NT.equalsIgnoreCase(token)) {
|
||||
return "is not null";
|
||||
} else if (LK.equalsIgnoreCase(token)) {
|
||||
} else if (LK.equalsIgnoreCase(token) || LK1.equalsIgnoreCase(token) || LK2.equalsIgnoreCase(token)) {
|
||||
return "like";
|
||||
} else if (NLK.equalsIgnoreCase(token)) {
|
||||
return "not like";
|
||||
|
@ -214,7 +216,7 @@ public class ParseHelper {
|
|||
if (dt == DisplayType.REFERENCE) {
|
||||
Field nameField = field.getReferenceEntity().getNameField();
|
||||
if (nameField.getType() == FieldType.REFERENCE) {
|
||||
log.warn("Quick field cannot be circular-reference : " + nameField);
|
||||
log.warn("Quick field cannot be circular-reference : {}", nameField);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -269,7 +271,7 @@ public class ParseHelper {
|
|||
if (can != null) usesFields.add(can);
|
||||
|
||||
} else {
|
||||
log.warn("No field found in `quickFields` : " + field + " in " + entity.getName());
|
||||
log.warn("No field found in `quickFields` : {} in {}", field, entity.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -302,7 +304,7 @@ public class ParseHelper {
|
|||
}
|
||||
|
||||
if (usesFields.isEmpty()) {
|
||||
log.warn("No fields of search found : " + usesFields);
|
||||
log.warn("No fields of search found : {}", usesFields);
|
||||
}
|
||||
return usesFields;
|
||||
}
|
||||
|
|
|
@ -97,7 +97,8 @@ public class CommonOperatingController extends BaseController {
|
|||
Entity entityMate = MetadataHelper.getEntity(entity);
|
||||
if (StringUtils.isBlank(fields)) fields = getAllFields(entityMate);
|
||||
|
||||
String sql = String.format("select %s from %s", fields, entityMate.getName());
|
||||
String sql = String.format("select %s from %s",
|
||||
StringUtils.join(fields.split("[,;]"), ","), entityMate.getName());
|
||||
if (ParseHelper.validAdvFilter(filter)) {
|
||||
String filterWhere = new AdvFilterParser(filter, entityMate).toSqlWhere();
|
||||
if (filterWhere != null) sql += " where " + filterWhere;
|
||||
|
@ -112,14 +113,16 @@ public class CommonOperatingController extends BaseController {
|
|||
|
||||
// 获取全部字段
|
||||
private String getAllFields(Entity entity) {
|
||||
List<String> ss = new ArrayList<>();
|
||||
List<String> fs = new ArrayList<>();
|
||||
for (Field field : entity.getFields()) {
|
||||
if (!MetadataHelper.isSystemField(field.getName())) ss.add(field.getName());
|
||||
if (!MetadataHelper.isSystemField(field.getName())) fs.add(field.getName());
|
||||
}
|
||||
return StringUtils.join(ss, ",");
|
||||
return StringUtils.join(fs, ",");
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存记录
|
||||
*
|
||||
* @param record
|
||||
* @return
|
||||
*/
|
||||
|
@ -134,6 +137,8 @@ public class CommonOperatingController extends BaseController {
|
|||
}
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*
|
||||
* @param recordId
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -50,6 +50,8 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.rebuild.core.privileges.bizz.ZeroEntry.AllowRevokeApproval;
|
||||
|
||||
/**
|
||||
* @author devezhao zhaofang123@gmail.com
|
||||
* @since 2019/07/05
|
||||
|
@ -117,8 +119,9 @@ public class ApprovalController extends BaseController {
|
|||
if (user.equals(ApprovalHelper.getSubmitter(recordId, useApproval))) {
|
||||
data.put("canUrge", true);
|
||||
data.put("canCancel", true);
|
||||
} else if (UserHelper.isAdmin(user)) {
|
||||
// v3.1 管理员也可撤回
|
||||
} else if (Application.getPrivilegesManager().allow(user, AllowRevokeApproval)) {
|
||||
// v3.1 管理员可撤回
|
||||
// v3.8 有权限的可撤回
|
||||
data.put("canCancel", true);
|
||||
}
|
||||
|
||||
|
@ -128,8 +131,8 @@ public class ApprovalController extends BaseController {
|
|||
}
|
||||
|
||||
if (stateVal == ApprovalState.APPROVED.getState()) {
|
||||
// v3.4
|
||||
data.put("canRevoke", Application.getPrivilegesManager().allow(user, ZeroEntry.AllowRevokeApproval));
|
||||
// v3.4 有权限的可撤销
|
||||
data.put("canRevoke", Application.getPrivilegesManager().allow(user, AllowRevokeApproval));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,8 @@ public class LoginAction extends BaseController {
|
|||
uaSimple = "UNKNOW";
|
||||
}
|
||||
|
||||
String ipAddr = StringUtils.defaultString(ServletUtils.getRemoteAddr(request), "127.0.0.1");
|
||||
final String ipAddr = StringUtils.defaultString(ServletUtils.getRemoteAddr(request), "127.0.0.1");
|
||||
final String reqUrl = request.getRequestURL() == null ? "" : request.getRequestURL().toString();
|
||||
|
||||
final Record llog = EntityHelper.forNew(EntityHelper.LoginLog, UserService.SYSTEM_USER);
|
||||
llog.setID("user", user);
|
||||
|
@ -194,7 +195,7 @@ public class LoginAction extends BaseController {
|
|||
|
||||
String uaUrl = String.format("api/authority/user/echo?user=%s&ip=%s&ua=%s&source=%s",
|
||||
CodecUtils.base64UrlEncode(uid), ipAddr, CodecUtils.urlEncode(userAgent),
|
||||
CodecUtils.base64UrlEncode(request.getRequestURL().toString()));
|
||||
CodecUtils.base64UrlEncode(reqUrl));
|
||||
License.siteApiNoCache(uaUrl);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -267,7 +267,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="name">
|
||||
<a data-name="AllowRevokeApproval">[[${bundle.L('允许撤销审批')}]]</a>
|
||||
<a data-name="AllowRevokeApproval">[[${bundle.L('允许撤回、撤销审批')}]]</a>
|
||||
<sup class="rbv"></sup>
|
||||
</td>
|
||||
<td><i data-action="Z" class="priv R0"></i></td>
|
||||
|
|
|
@ -104,11 +104,14 @@
|
|||
<span>[[${bundle.L('执行')}]]</span>
|
||||
<input type="text" class="J_whenTimer2" placeholder="1" />
|
||||
<span>[[${bundle.L('次')}]]</span>
|
||||
|
||||
<span class="ml-2">[[${bundle.L('执行时段')}]]</span>
|
||||
<select class="J_startHour1"></select>
|
||||
<span>~</span>
|
||||
<select class="J_startHour2"></select>
|
||||
<span class="bosskey-show">
|
||||
<span class="ml-2">[[${bundle.L('执行日期')}]] (LAB)</span>
|
||||
<input type="text" class="J_whenTimer4 w-auto" placeholder="eg. 1,2,15,30" />
|
||||
</span>
|
||||
</div>
|
||||
<p class="form-text">[[${bundle.L('具体执行时间将在你设定的周期内平均分布。例如每天执行 2 次,其执行时间为 00:00 和 12:00')}]]</p>
|
||||
<div class="eval-exec-times"></div>
|
||||
|
|
|
@ -190,6 +190,7 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
.dataTables_oper.invisible2 > .btn.J_view {
|
||||
display: inline-block;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.record-merge-table {
|
||||
|
|
|
@ -1833,7 +1833,7 @@ th.column-fixed {
|
|||
}
|
||||
|
||||
.column-fixed.col-action .btn.btn-sm {
|
||||
line-height: 28px;
|
||||
line-height: 26px;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
|
|
|
@ -807,6 +807,7 @@ body {
|
|||
.timeline.approved-steps .timeline-item.state0::before {
|
||||
border-color: #fff;
|
||||
background-color: #4285f4;
|
||||
background-color: #33a451;
|
||||
}
|
||||
|
||||
.timeline.approved-steps .timeline-item.state10::before {
|
||||
|
@ -1149,6 +1150,7 @@ body {
|
|||
font-size: 0;
|
||||
background-color: #f7b904;
|
||||
border: 4px solid #fff;
|
||||
border: 6px double #fff;
|
||||
}
|
||||
|
||||
.sop-steps li.state-2 > div > span {
|
||||
|
|
|
@ -5,9 +5,10 @@ rebuild is dual-licensed under commercial and open source licenses (GPLv3).
|
|||
See LICENSE and COMMERCIAL in the project root for license information.
|
||||
*/
|
||||
|
||||
const userId = window.__PageConfig.recordId
|
||||
const wpc = window.__PageConfig || {}
|
||||
const userId = wpc.recordId
|
||||
|
||||
$(document).ready(function () {
|
||||
$(document).ready(() => {
|
||||
$('.J_delete')
|
||||
.off('click')
|
||||
.on('click', () => {
|
||||
|
@ -154,6 +155,22 @@ $(document).ready(function () {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
// v3.8
|
||||
if (userId === '001-0000000000000001') {
|
||||
const RbForm_renderAfter = RbForm.renderAfter
|
||||
RbForm.renderAfter = function (formObject) {
|
||||
typeof RbForm_renderAfter === 'function' && RbForm_renderAfter()
|
||||
|
||||
formObject.onFieldValueChange((nv) => {
|
||||
if (nv.name === 'isDisabled') {
|
||||
let c = formObject.getFieldComp('isDisabled') || {}
|
||||
if (nv.value === 'T') c.setTip(<span className="text-warning">{$L('禁用将导致超级管理员无法登录')}</span>)
|
||||
else c.setTip(null)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 启用/禁用
|
||||
|
|
|
@ -47,9 +47,12 @@ class ApprovalProcessor extends React.Component {
|
|||
window.RbViewPage && window.RbViewPage.setReadonly(true)
|
||||
|
||||
let aMsg = $L('当前记录正在审批中')
|
||||
let imApproverCurrent = false
|
||||
if (this.state.imApprover) {
|
||||
if (this.state.imApproveSatate === 1) aMsg = $L('当前记录正在等待你审批')
|
||||
else if (this.state.imApproveSatate === 10) aMsg = $L('你已审批同意,正在等待其他人审批')
|
||||
if (this.state.imApproveSatate === 1) {
|
||||
aMsg = $L('当前记录正在等待你审批')
|
||||
imApproverCurrent = true
|
||||
} else if (this.state.imApproveSatate === 10) aMsg = $L('你已审批同意,正在等待其他人审批')
|
||||
else if (this.state.imApproveSatate === 11) aMsg = $L('你已驳回审批')
|
||||
}
|
||||
|
||||
|
@ -61,19 +64,15 @@ class ApprovalProcessor extends React.Component {
|
|||
{$L('审批')}
|
||||
</button>
|
||||
)}
|
||||
{(this.state.canCancel || this.state.canUrge) && (
|
||||
<RF>
|
||||
{this.state.canUrge && (
|
||||
<button className="btn btn-secondary" onClick={this.urge}>
|
||||
{$L('催审')}
|
||||
</button>
|
||||
)}
|
||||
{this.state.canCancel && (
|
||||
<button className="btn btn-secondary" onClick={this.cancel}>
|
||||
{$L('撤回')}
|
||||
</button>
|
||||
)}
|
||||
</RF>
|
||||
{this.state.canUrge && imApproverCurrent === false && (
|
||||
<button className="btn btn-secondary" onClick={this.urge}>
|
||||
{$L('催审')}
|
||||
</button>
|
||||
)}
|
||||
{this.state.canCancel && (
|
||||
<button className="btn btn-secondary" onClick={this.cancel}>
|
||||
{$L('撤回')}
|
||||
</button>
|
||||
)}
|
||||
{this.state.canCancel38 && (
|
||||
<button className="btn btn-secondary bosskey-show" onClick={this.cancel38}>
|
||||
|
|
|
@ -912,7 +912,8 @@ class RbList extends React.Component {
|
|||
|
||||
render() {
|
||||
const lastIndex = this.state.fields.length
|
||||
const rowActions = window.FrontJS ? window.FrontJS.DataList.__rowActions : []
|
||||
let rowActions = window.FrontJS ? window.FrontJS.DataList.__rowActions : []
|
||||
if (wpc.type !== 'RecordList') rowActions = []
|
||||
|
||||
return (
|
||||
<RF>
|
||||
|
|
|
@ -76,7 +76,7 @@ const RbListPage = {
|
|||
|
||||
// Privileges
|
||||
if (ep) {
|
||||
if (ep.C === false) $('.J_new').remove()
|
||||
if (ep.C === false) $('.J_new, .J_new_group').remove()
|
||||
if (ep.D === false) $('.J_delete').remove()
|
||||
if (ep.U === false) $('.J_edit, .J_batch-update').remove()
|
||||
if (ep.A !== true) $('.J_assign').remove()
|
||||
|
|
|
@ -1148,7 +1148,10 @@ class RbFormElement extends React.Component {
|
|||
}
|
||||
// 可空/非空
|
||||
setNullable(nullable) {
|
||||
this.setState({ nullable: nullable === true })
|
||||
this.setState({ nullable: nullable === true }, () => {
|
||||
// fix:v3.8 通过此方法强制检查非空属性
|
||||
this.setValue(this.state.value || null)
|
||||
})
|
||||
}
|
||||
// 只读/非只读
|
||||
// 部分字段有效,且如字段属性为只读,即使填写值也无效
|
||||
|
|
|
@ -19,6 +19,7 @@ class RbViewForm extends React.Component {
|
|||
|
||||
this.onViewEditable = this.props.onViewEditable
|
||||
if (this.onViewEditable) this.onViewEditable = wpc.onViewEditable !== false
|
||||
if (window.__LAB_VIEWEDITABLE === false) this.onViewEditable = false
|
||||
// temp for `saveSingleFieldValue`
|
||||
this.__FormData = {}
|
||||
}
|
||||
|
|
|
@ -219,6 +219,7 @@ class MediaCapturer extends RbModal {
|
|||
ctx2d.fillStyle = 'white'
|
||||
ctx2d.fillText(moment().format('YYYY-MM-DD HH:mm:ss'), 20, 40)
|
||||
ctx2d.fillText('Device : ' + this.__currentDeviceId || '', 20, 40 + 30)
|
||||
ctx2d.fillText('User : ***' + rb.currentUser.substr(7), 20, 40 + 30 + 30)
|
||||
}
|
||||
this._capturedData = this._$resImage.toDataURL('image/jpeg', 1.0)
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ $(document).ready(() => {
|
|||
// v2.9
|
||||
if (wt[2]) $('.J_startHour1').val(wt[2])
|
||||
if (wt[3]) $('.J_startHour2').val(wt[3])
|
||||
// v3.8
|
||||
if (wt[4]) $('.J_whenTimer4').val(wt[4]).parents('.bosskey-show').removeClass('bosskey-show')
|
||||
|
||||
$('.J_whenTimer1').trigger('change')
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ $(document).ready(() => {
|
|||
|
||||
// 评估具体执行时间
|
||||
function evalTriggerTimes() {
|
||||
const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}`
|
||||
const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}:${$('.J_whenTimer4').val() || ''}`
|
||||
$.get(`/admin/robot/trigger/eval-trigger-times?whenTimer=${whenTimer}`, (res) => {
|
||||
renderRbcomp(
|
||||
<RbAlertBox
|
||||
|
@ -141,7 +143,7 @@ $(document).ready(() => {
|
|||
return
|
||||
}
|
||||
|
||||
const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}`
|
||||
const whenTimer = `${$('.J_whenTimer1').val() || 'D'}:${$('.J_whenTimer2').val() || 1}:${$('.J_startHour1').val() || 0}:${$('.J_startHour2').val() || 23}:${$('.J_whenTimer4').val() || ''}`
|
||||
|
||||
const content = contentComp.buildContent()
|
||||
if (content === false) return
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
<div class="dataTables_oper invisible2">
|
||||
<button class="btn btn-space btn-secondary J_view" type="button" disabled="disabled"><i class="icon mdi mdi-folder-open"></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">
|
||||
<div class="btn-group btn-space J_new_group">
|
||||
<button class="btn btn-primary J_new" type="button"><i class="icon zmdi zmdi-plus"></i> [[${bundle.L('新建')}]]</button>
|
||||
<button class="btn btn-primary dropdown-toggle w-auto hide" type="button" data-toggle="dropdown"><span class="icon zmdi zmdi-chevron-down"></span></button>
|
||||
<div class="dropdown-menu dropdown-menu-primary dropdown-menu-right"></div>
|
||||
|
|
Loading…
Reference in a new issue