mirror of
https://github.com/getrebuild/rebuild.git
synced 2024-09-20 07:25:54 +08:00
parent
eb319ba113
commit
55ce1fbc39
2
pom.xml
2
pom.xml
|
@ -232,12 +232,14 @@
|
|||
</dependency>
|
||||
-->
|
||||
<!-- Use Live Reload: https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools.livereload -->
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- Use SPEC -->
|
||||
<dependency>
|
||||
|
|
|
@ -190,9 +190,11 @@ public class ApprovalProcessor extends SetUser {
|
|||
ccs4share = nextNodes.getCcUsers4Share(this.getUser(), this.record, selectNextUsers);
|
||||
}
|
||||
|
||||
Set<String> ccAccounts = nextNodes.getCcAccounts(this.record);
|
||||
|
||||
FlowNode currentNode = getFlowParser().getNode((String) stepApprover[2]);
|
||||
Application.getBean(ApprovalStepService.class)
|
||||
.txApprove(approvedStep, currentNode.getSignMode(), ccs, nextApprovers, nextNode, addedData, checkUseGroup);
|
||||
.txApprove(approvedStep, currentNode.getSignMode(), ccs, ccAccounts, nextApprovers, nextNode, addedData, checkUseGroup);
|
||||
|
||||
// 非主事物
|
||||
if (ccs4share != null) share2CcIfNeed(this.record, ccs4share);
|
||||
|
@ -435,7 +437,7 @@ public class ApprovalProcessor extends SetUser {
|
|||
this.approval = status.getApprovalId();
|
||||
|
||||
Object[][] array = Application.createQueryNoFilter(
|
||||
"select approver,state,remark,approvedTime,createdOn,createdBy,node,prevNode,nodeBatch,ccUsers from RobotApprovalStep" +
|
||||
"select approver,state,remark,approvedTime,createdOn,createdBy,node,prevNode,nodeBatch,ccUsers,ccAccounts from RobotApprovalStep" +
|
||||
" where recordId = ? and isWaiting = 'F' and isCanceled = 'F' order by createdOn")
|
||||
.setParameter(1, this.record)
|
||||
.array();
|
||||
|
@ -537,6 +539,11 @@ public class ApprovalProcessor extends SetUser {
|
|||
for (ID u : (ID[]) step[9]) names.add(UserHelper.getName(u));
|
||||
s.put("ccUsers", names);
|
||||
}
|
||||
if (step.length > 10 && step[10] != null) {
|
||||
List<String> mobileOrEmails = new ArrayList<>();
|
||||
Collections.addAll(mobileOrEmails, step[10].toString().split(","));
|
||||
s.put("ccAccounts", mobileOrEmails);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ package com.rebuild.core.service.approval;
|
|||
import cn.devezhao.bizz.privileges.impl.BizzPermission;
|
||||
import cn.devezhao.commons.CalendarUtils;
|
||||
import cn.devezhao.commons.ObjectUtils;
|
||||
import cn.devezhao.commons.RegexUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.PersistManagerFactory;
|
||||
import cn.devezhao.persist4j.Record;
|
||||
|
@ -35,6 +36,7 @@ import com.rebuild.core.service.trigger.RobotTriggerManual;
|
|||
import com.rebuild.core.service.trigger.TriggerAction;
|
||||
import com.rebuild.core.service.trigger.TriggerWhen;
|
||||
import com.rebuild.core.support.i18n.Language;
|
||||
import com.rebuild.core.support.integration.SMSender;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -123,12 +125,13 @@ public class ApprovalStepService extends InternalPersistService {
|
|||
* @param stepRecord
|
||||
* @param signMode
|
||||
* @param cc
|
||||
* @param ccAccounts
|
||||
* @param nextApprovers [驳回时无需]
|
||||
* @param nextNode 下一节点或回退节点
|
||||
* @param addedData [驳回时无需]
|
||||
* @param checkUseGroup [驳回时无需]
|
||||
*/
|
||||
public void txApprove(Record stepRecord, String signMode, Set<ID> cc, Set<ID> nextApprovers, String nextNode, Record addedData, String checkUseGroup) {
|
||||
public void txApprove(Record stepRecord, String signMode, Set<ID> cc, Set<String> ccAccounts, Set<ID> nextApprovers, String nextNode, Record addedData, String checkUseGroup) {
|
||||
// 审批时更新主记录(驳回时不会传这个值)
|
||||
if (addedData != null) {
|
||||
GeneralEntityServiceContextHolder.setAllowForceUpdate(addedData.getPrimary());
|
||||
|
@ -158,6 +161,9 @@ public class ApprovalStepService extends InternalPersistService {
|
|||
if (cc != null && !cc.isEmpty()) {
|
||||
stepRecord.setIDArray("ccUsers", cc.toArray(new ID[0]));
|
||||
}
|
||||
if (ccAccounts != null && !ccAccounts.isEmpty()) {
|
||||
stepRecord.setString("ccAccounts", StringUtils.join(ccAccounts, ","));
|
||||
}
|
||||
|
||||
super.update(stepRecord);
|
||||
final ID stepRecordId = stepRecord.getPrimary();
|
||||
|
@ -175,14 +181,30 @@ public class ApprovalStepService extends InternalPersistService {
|
|||
final String entityLabel = EasyMetaFactory.getLabel(MetadataHelper.getEntity(recordId.getEntityCode()));
|
||||
final String remark = stepRecord.getString("remark");
|
||||
|
||||
// 抄送人
|
||||
// 抄送
|
||||
final String ccMsg = Language.L("用户 @%s 提交的 %s 审批已由 @%s %s,请知悉",
|
||||
submitter, entityLabel, approver, Language.L(state));
|
||||
|
||||
if (cc != null && !cc.isEmpty()) {
|
||||
String ccMsg = Language.L("用户 @%s 提交的 %s 审批已由 @%s %s,请知悉",
|
||||
submitter, entityLabel, approver, Language.L(state));
|
||||
if (StringUtils.isNotBlank(remark)) ccMsg += "\n > " + remark;
|
||||
String innerMsg = ccMsg;
|
||||
if (StringUtils.isNotBlank(remark)) innerMsg += "\n > " + remark;
|
||||
|
||||
for (ID c : cc) {
|
||||
Application.getNotifications().send(MessageBuilder.createApproval(c, ccMsg, recordId));
|
||||
Application.getNotifications().send(MessageBuilder.createApproval(c, innerMsg, recordId));
|
||||
}
|
||||
}
|
||||
// v3.2 外部人员
|
||||
if (ccAccounts != null && !ccAccounts.isEmpty()) {
|
||||
String mobileMsg = MessageBuilder.formatMessage(ccMsg, Boolean.FALSE);
|
||||
|
||||
String emailSubject = Language.L("审批通知");
|
||||
String emailMsg = ccMsg;
|
||||
if (StringUtils.isNotBlank(remark)) emailMsg += "\n > " + remark;
|
||||
emailMsg = MessageBuilder.formatMessage(emailMsg, Boolean.TRUE);
|
||||
|
||||
for (String me : ccAccounts) {
|
||||
if (SMSender.availableSMS() && RegexUtils.isCNMobile(me)) SMSender.sendSMSAsync(me, mobileMsg);
|
||||
else if (SMSender.availableMail()) SMSender.sendMailAsync(me, emailSubject, emailMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,15 @@ See LICENSE and COMMERCIAL in the project root for license information.
|
|||
|
||||
package com.rebuild.core.service.approval;
|
||||
|
||||
import cn.devezhao.commons.RegexUtils;
|
||||
import cn.devezhao.persist4j.Entity;
|
||||
import cn.devezhao.persist4j.Field;
|
||||
import cn.devezhao.persist4j.engine.ID;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.rebuild.core.Application;
|
||||
import com.rebuild.core.metadata.EntityHelper;
|
||||
import com.rebuild.core.metadata.MetadataHelper;
|
||||
import com.rebuild.core.privileges.UserHelper;
|
||||
import com.rebuild.core.privileges.bizz.Department;
|
||||
import com.rebuild.utils.JSONUtils;
|
||||
|
@ -146,9 +149,7 @@ public class FlowNode {
|
|||
*/
|
||||
public Set<ID> getSpecUsers(ID operator, ID record) {
|
||||
JSONArray userDefs = getDataMap().getJSONArray("users");
|
||||
if (userDefs == null || userDefs.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
if (userDefs == null || userDefs.isEmpty()) return Collections.emptySet();
|
||||
|
||||
String userType = userDefs.getString(0);
|
||||
if (USER_SELF.equalsIgnoreCase(userType)) {
|
||||
|
@ -216,6 +217,38 @@ public class FlowNode {
|
|||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取外部抄送人(手机或邮箱)
|
||||
*
|
||||
* @param record
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getCcAccounts(ID record) {
|
||||
JSONArray accountFields = getDataMap().getJSONArray("accounts");
|
||||
if (accountFields == null || accountFields.isEmpty()) return Collections.emptySet();
|
||||
|
||||
Entity useEntity = MetadataHelper.getEntity(record.getEntityCode());
|
||||
List<String> useFields = new ArrayList<>();
|
||||
|
||||
for (Object o : accountFields) {
|
||||
if (MetadataHelper.getLastJoinField(useEntity, (String) o) != null) {
|
||||
useFields.add((String) o);
|
||||
}
|
||||
}
|
||||
if (useFields.isEmpty()) return Collections.emptySet();
|
||||
|
||||
Object[] o = Application.getQueryFactory().uniqueNoFilter(record, useFields.toArray(new String[0]));
|
||||
if (o == null) return Collections.emptySet();
|
||||
|
||||
Set<String> mobileOrEmail = new HashSet<>();
|
||||
for (Object me : o) {
|
||||
if (RegexUtils.isCNMobile((String) me) || RegexUtils.isEMail((String) me)) {
|
||||
mobileOrEmail.add((String) me);
|
||||
}
|
||||
}
|
||||
return mobileOrEmail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String string = String.format("Id:%s, Type:%s", nodeId, type);
|
||||
|
|
|
@ -105,6 +105,21 @@ public class FlowNodeGroup {
|
|||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param recordId
|
||||
* @return
|
||||
*/
|
||||
public Set<String> getCcAccounts(ID recordId) {
|
||||
Set<String> mobileOrEmails = new HashSet<>();
|
||||
// 一般就一个,但不排除多个 CC 节点
|
||||
for (FlowNode node : nodes) {
|
||||
if (FlowNode.TYPE_CC.equals(node.getType())) {
|
||||
mobileOrEmails.addAll(node.getCcAccounts(recordId));
|
||||
}
|
||||
}
|
||||
return mobileOrEmails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param operator
|
||||
* @param recordId
|
||||
|
|
|
@ -60,7 +60,7 @@ public class SMSender {
|
|||
try {
|
||||
sendMail(to, subject, content);
|
||||
} catch (Exception ex) {
|
||||
log.error("Mail failed to send : {} < {}", to, subject, ex);
|
||||
log.error("Email failed to send!", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ public class SMSender {
|
|||
return emailId;
|
||||
|
||||
} catch (EmailException ex) {
|
||||
log.error("SMTP failed to send : {} > {}", to, subject, ex);
|
||||
log.error("SMTP failed to send : {} | {} | {}", to, subject, content, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ public class SMSender {
|
|||
String r = OkHttpUtils.post("https://api-v4.mysubmail.com/mail/send.json", params);
|
||||
rJson = JSON.parseObject(r);
|
||||
} catch (Exception ex) {
|
||||
log.error("Submail failed to send : {} > {}", to, subject, ex);
|
||||
log.error("Submail failed to send : {} | {} | {}", to, subject, content, ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -166,12 +166,11 @@ public class SMSender {
|
|||
String sendId = ((JSONObject) returns.get(0)).getString("send_id");
|
||||
createLog(to, logContent, TYPE_EMAIL, sendId, null);
|
||||
return sendId;
|
||||
|
||||
} else {
|
||||
log.error("Mail failed to send : {} > {}\nError : {}", to, subject, rJson);
|
||||
createLog(to, logContent, TYPE_EMAIL, null, rJson.getString("msg"));
|
||||
return null;
|
||||
}
|
||||
|
||||
log.error("Submail failed to send : {} | {} | {}\nError : {}", to, subject, content, rJson);
|
||||
createLog(to, logContent, TYPE_EMAIL, null, rJson.getString("msg"));
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,7 +228,7 @@ public class SMSender {
|
|||
try {
|
||||
sendSMS(to, content);
|
||||
} catch (Exception ex) {
|
||||
log.error("SMS failed to send : {}", to, ex);
|
||||
log.error("SMS failed to send!", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -274,7 +273,7 @@ public class SMSender {
|
|||
String r = OkHttpUtils.post("https://api-v4.mysubmail.com/sms/send.json", params);
|
||||
rJson = JSON.parseObject(r);
|
||||
} catch (Exception ex) {
|
||||
log.error("Subsms failed to send : {} > {}", to, content, ex);
|
||||
log.error("Subsms failed to send : {} | {}", to, content, ex);
|
||||
return null;
|
||||
} finally {
|
||||
HeavyStopWatcher.clean();
|
||||
|
@ -284,12 +283,11 @@ public class SMSender {
|
|||
String sendId = rJson.getString("send_id");
|
||||
createLog(to, content, TYPE_SMS, sendId, null);
|
||||
return sendId;
|
||||
|
||||
} else {
|
||||
log.error("SMS failed to send : {} > {}\nError : {}", to, content, rJson);
|
||||
createLog(to, content, TYPE_SMS, null, rJson.getString("msg"));
|
||||
return null;
|
||||
}
|
||||
|
||||
log.error("Subsms failed to send : {} | {}\nError : {}", to, content, rJson);
|
||||
createLog(to, content, TYPE_SMS, null, rJson.getString("msg"));
|
||||
return null;
|
||||
}
|
||||
|
||||
// @see com.rebuild.core.support.CommonsLog
|
||||
|
|
|
@ -126,6 +126,7 @@ public class ApprovalController extends BaseController {
|
|||
JSONObject data = new JSONObject();
|
||||
data.put("nextApprovers", formatUsers(approverList));
|
||||
data.put("nextCcs", formatUsers(ccList));
|
||||
data.put("nextCcAccounts", nextNodes.getCcAccounts(recordId));
|
||||
data.put("approverSelfSelecting", nextNodes.allowSelfSelectingApprover());
|
||||
data.put("ccSelfSelecting", nextNodes.allowSelfSelectingCc());
|
||||
data.put("isLastStep", nextNodes.isLastStep());
|
||||
|
|
|
@ -298,6 +298,7 @@
|
|||
<field name="isBacked" type="bool" default-value="F" description="是否退回"/>
|
||||
<field name="nodeBatch" type="string" max-length="100" updatable="false" description="审批节点批次"/>
|
||||
<field name="ccUsers" type="reference-list" ref-entity="User" updatable="false" description="抄送人"/>
|
||||
<field name="ccAccounts" type="string" max-length="500" updatable="false" description="抄送外部人员"/>
|
||||
<index field-list="recordId,approvalId,node,isCanceled,isWaiting,isBacked,nodeBatch"/>
|
||||
</entity>
|
||||
|
||||
|
|
|
@ -439,6 +439,7 @@ create table if not exists `robot_approval_step` (
|
|||
`IS_BACKED` char(1) default 'F' comment '是否退回',
|
||||
`NODE_BATCH` varchar(100) comment '审批节点批次',
|
||||
`CC_USERS` varchar(420) comment '抄送人',
|
||||
`CC_ACCOUNTS` varchar(500) comment '抄送外部人员',
|
||||
`MODIFIED_ON` timestamp not null default current_timestamp comment '修改时间',
|
||||
`MODIFIED_BY` char(20) not null comment '修改人',
|
||||
`CREATED_BY` char(20) not null comment '创建人',
|
||||
|
@ -853,4 +854,4 @@ insert into `project_plan_config` (`CONFIG_ID`, `PROJECT_ID`, `PLAN_NAME`, `SEQ`
|
|||
|
||||
-- DB Version (see `db-upgrade.sql`)
|
||||
insert into `system_config` (`CONFIG_ID`, `ITEM`, `VALUE`)
|
||||
values ('021-9000000000000001', 'DBVer', 47);
|
||||
values ('021-9000000000000001', 'DBVer', 49);
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
-- Database upgrade scripts for rebuild 1.x and 2.x
|
||||
-- Each upgraded starts with `-- #VERSION`
|
||||
|
||||
-- #49 (v3.2)
|
||||
alter table `robot_approval_step`
|
||||
add column `CC_ACCOUNTS` varchar(500) comment '抄送外部人员';
|
||||
|
||||
-- #47 (v3.1)
|
||||
alter table `robot_approval_step`
|
||||
add column `CC_USERS` varchar(420) comment '抄送人';
|
||||
|
|
|
@ -3030,6 +3030,21 @@ form {
|
|||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.form.approval-form .cc-accounts {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.form.approval-form .cc-accounts a {
|
||||
color: #404040;
|
||||
}
|
||||
|
||||
.form.approval-form .cc-accounts a + a::before {
|
||||
content: ',';
|
||||
margin-left: 1px;
|
||||
margin-right: 4px;
|
||||
color: #8a8a8a;
|
||||
}
|
||||
|
||||
.select2-sm .select2-container--default .select2-selection--single,
|
||||
.select2-sm .select2-container--default .select2-selection--multiple {
|
||||
min-height: 36px;
|
||||
|
@ -4407,7 +4422,7 @@ html.external-auth .auth-body.must-center .login {
|
|||
|
||||
.user-popup .infos p.phone::after,
|
||||
.user-popup .infos p.email::after {
|
||||
font-family: 'Material-Design-Iconic-Font', serif;
|
||||
font-family: 'Material Design Icons', serif;
|
||||
}
|
||||
|
||||
.user-popup .infos p.phone::after,
|
||||
|
@ -4418,12 +4433,11 @@ html.external-auth .auth-body.must-center .login {
|
|||
}
|
||||
|
||||
.user-popup .infos p.phone::after {
|
||||
content: '\f2d4';
|
||||
content: '\F011C';
|
||||
}
|
||||
|
||||
.user-popup .infos p.email::after {
|
||||
content: '\f15a';
|
||||
transform: translateY(1px);
|
||||
content: '\F01F0';
|
||||
}
|
||||
|
||||
.copied-check > .zmdi-copy::before {
|
||||
|
|
|
@ -203,6 +203,7 @@ class SimpleNode extends NodeSpec {
|
|||
|
||||
if (data.selfSelecting && data.users.length > 0) descs.push($L('允许自选'))
|
||||
if (data.ccAutoShare) descs.push($L('自动共享'))
|
||||
if ((data.accounts || []).length > 0) descs.push(`${$L('外部人员')}(${data.accounts.length})`)
|
||||
if (this.nodeType === 'approver') descs.push(data.signMode === 'AND' ? $L('会签') : data.signMode === 'ALL' ? $L('依次审批') : $L('或签'))
|
||||
|
||||
return (
|
||||
|
@ -764,10 +765,6 @@ class ApproverNodeConfig extends StartNodeConfig {
|
|||
|
||||
// 抄送人
|
||||
class CCNodeConfig extends StartNodeConfig {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
|
@ -790,18 +787,45 @@ class CCNodeConfig extends StartNodeConfig {
|
|||
<span className="custom-control-label">{$L('抄送人无读取权限时自动共享')}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="form-group mt-3">
|
||||
<label className="text-bold">
|
||||
{$L('抄送给外部人员 (可选)')} <sup className="rbv" title={$L('增值功能')} />
|
||||
</label>
|
||||
<UserSelectorWithField ref={(c) => (this._UserSelector2 = c)} userType={2} hideUser hideDepartment hideRole hideTeam />
|
||||
<p className="form-text">{$L('选择外部人员的电话(手机)或邮箱字段')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.renderButton()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
super.componentDidMount()
|
||||
|
||||
if ((this.props.accounts || []).length > 0) {
|
||||
$.post(`/commons/search/user-selector?entity=${this.props.entity || wpc.applyEntity}`, JSON.stringify(this.props.accounts), (res) => {
|
||||
if (res.error_code === 0 && res.data.length > 0) {
|
||||
this._UserSelector2.setState({ selected: res.data })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
save = () => {
|
||||
const d = {
|
||||
nodeName: this.state.nodeName,
|
||||
users: this._UserSelector.getSelected(),
|
||||
selfSelecting: this.state.selfSelecting,
|
||||
ccAutoShare: this.state.ccAutoShare,
|
||||
accounts: this._UserSelector2.getSelected(),
|
||||
}
|
||||
|
||||
if (d.accounts.length > 1 && rb.commercial < 1) {
|
||||
RbHighbar.error(WrapHtml($L('免费版不支持抄送给外部人员功能 [(查看详情)](https://getrebuild.com/docs/rbv-features)')))
|
||||
return
|
||||
}
|
||||
|
||||
if (d.users.length === 0 && !d.selfSelecting) {
|
||||
|
@ -1040,12 +1064,31 @@ class UserSelectorWithField extends UserSelector {
|
|||
super.componentDidMount()
|
||||
|
||||
this._fields = []
|
||||
$.get(`/admin/robot/approval/user-fields?entity=${this.props.entity || wpc.applyEntity}`, (res) => {
|
||||
this._fields = res.data || []
|
||||
})
|
||||
|
||||
// 外部人员
|
||||
if (this.props.userType === 2) {
|
||||
$.get(`/commons/metadata/fields?deep=2&entity=${this.props.entity || wpc.applyEntity}`, (res) => {
|
||||
res.data &&
|
||||
res.data.forEach((item) => {
|
||||
if (item.type === 'PHONE' || item.type === 'EMAIL') {
|
||||
this._fields.push({ id: item.name, text: item.label })
|
||||
}
|
||||
})
|
||||
this.switchTab()
|
||||
})
|
||||
} else {
|
||||
$.get(`/admin/robot/approval/user-fields?entity=${this.props.entity || wpc.applyEntity}`, (res) => {
|
||||
this._fields = res.data || []
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
switchTab(type) {
|
||||
if (this.props.userType === 2) {
|
||||
this.setState({ tabType: 'FIELDS', items: this._fields || [] })
|
||||
return
|
||||
}
|
||||
|
||||
type = type || this.state.tabType
|
||||
if (type === 'FIELDS') {
|
||||
const q = this.state.query
|
||||
|
|
|
@ -323,6 +323,17 @@ class ApprovalUsersForm extends RbFormHandler {
|
|||
<UserSelector ref={(c) => (this._ccSelector = c)} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(this.state.nextCcAccounts || []).length > 0 && (
|
||||
<div className="mt-2 cc-accounts">
|
||||
<span>{$L('及以下外部人员')}</span>
|
||||
<div className="mt-1">
|
||||
{this.state.nextCcAccounts.map((me) => {
|
||||
return <a key={me}>{me}</a>
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
@ -734,16 +745,23 @@ class ApprovalStepViewer extends React.Component {
|
|||
<p className="text-wrap">{item.remark}</p>
|
||||
</blockquote>
|
||||
)}
|
||||
{item.ccUsers && item.state >= 10 && (
|
||||
{item.state >= 10 && (item.ccUsers || []).length + (item.ccAccounts || []).length > 0 && (
|
||||
<blockquote className="blockquote timeline-blockquote mb-0 cc">
|
||||
<p className="text-wrap">
|
||||
<span className="mr-1">
|
||||
<i className="zmdi zmdi-mail-send mr-1" />
|
||||
{$L('已抄送')}
|
||||
</span>
|
||||
{item.ccUsers.map((item) => {
|
||||
{(item.ccUsers || []).map((item) => {
|
||||
return <a key={item}>{item}</a>
|
||||
})}
|
||||
{(item.ccAccounts || []).map((item) => {
|
||||
return (
|
||||
<a key={item} title={$L('外部人员')}>
|
||||
{item}
|
||||
</a>
|
||||
)
|
||||
})}
|
||||
</p>
|
||||
</blockquote>
|
||||
)}
|
||||
|
|
|
@ -60,6 +60,7 @@ class ContentSendNotification extends ActionContentSpec {
|
|||
</div>
|
||||
<div className={this.state.userType === 2 ? '' : 'hide'}>
|
||||
<AccountSelectorWithField ref={(c) => (this._sendTo2 = c)} hideUser hideDepartment hideRole hideTeam />
|
||||
<p className="form-text">{$L('选择外部人员的电话(手机)或邮箱字段')}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -180,12 +181,12 @@ class AccountSelectorWithField extends UserSelector {
|
|||
|
||||
this._fields = []
|
||||
$.get(`/commons/metadata/fields?deep=2&entity=${this.props.entity || wpc.sourceEntity}`, (res) => {
|
||||
$(res.data).each((idx, item) => {
|
||||
if (item.type === 'PHONE' || item.type === 'EMAIL') {
|
||||
this._fields.push({ id: item.name, text: item.label })
|
||||
}
|
||||
})
|
||||
|
||||
res.data &&
|
||||
res.data.forEach((item) => {
|
||||
if (item.type === 'PHONE' || item.type === 'EMAIL') {
|
||||
this._fields.push({ id: item.name, text: item.label })
|
||||
}
|
||||
})
|
||||
this.switchTab()
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue