二开案例.表单服务.服务端表单服务
【应用场景】
将服务端的通用功能封装成表单服务,当操作在服务端执行时,连带执行此服务。
【案例演示】
封装一个发送消息的表单服务,绑定在采购订单的保存操作上,每次保存时,就给指定用户发送一条消息。
【实现步骤】
编写表单服务自定义参数界面->编写表单服务类->注册表单服务->在单据上使用表单服务
<1>打开BOS设计器,设计表单服务自定义参数界面。
<2>编写自定义参数类,用于包装表单服务的自定义参数。
using Kingdee.BOS.Orm.DataEntity;
using System;
namespace Jac.XkDemo.BOS.Core.AppBusinessService
{
/// <summary>
/// 发送消息服务的配置参数
/// </summary>
[Serializable]
public class SendMessageParameter
{
/// <summary>
/// 接收人字段Key
/// </summary>
[SimpleProperty]
public string ReceiverKey { get; set; }
/// <summary>
/// 组织字段Key
/// </summary>
[SimpleProperty]
public string OrgKey { get; set; }
}
}
<3>编写表单服务在BOS设计器中的自定义参数界面的控制代码,实现设计时功能。
using DevExpress.XtraEditors.Controls;
using Kingdee.BOS.Core.Designer;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Core.Metadata.FieldElement;
using Kingdee.BOS.Core.Metadata.FormElement;
using Kingdee.BOS.DomainModelDesigner.PropertyEditor;
using Kingdee.BOS.DomainModelDesigner.ServiceDesigner;
using Kingdee.BOS.Resource;
using Kingdee.BOS.Util;
using Kingdee.BOS.WinForm;
using Kingdee.BOS.WinForm.Ctrl;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace Jac.XkDemo.BOS.Core.AppBusinessService
{
/// <summary>
/// 发送消息服务配置界面
/// </summary>
public class SendMessageDesigner : KDDynamicUserControl, IFormBusinessServiceDesigner
{
#region 私有变量、控件
/// <summary>
/// 接收人字段(必录)
/// </summary>
private KDComboBox cbbReceiverKey;
/// <summary>
/// 组织字段
/// </summary>
private KDComboBox cbbOrgKey;
/// <summary>
/// 界面配置成果
/// </summary>
private FormBusinessService businessService;
#endregion
#region ctor
/// <summary>
/// 构造函数,传入本界面对应的动态表单编码,基类自动完成界面的加载
/// </summary>
/// <remarks>
/// 本界面与特定下推、特定选单共用一个界面,界面改动时,要注意影响
/// </remarks>
public SendMessageDesigner()
: base("Jac_SendMessage")
{
// TODO
}
#endregion
#region IFormBusinessServiceDesigner
/// <summary>
/// 初始化控件
/// </summary>
protected override void InitializeComponent()
{
base.InitializeComponent();
this.cbbReceiverKey = (KDComboBox)(this.GetControl<KDItemContainer>("F_Jac_ReceiverKey").Control);
this.cbbReceiverKey.Properties.TextEditStyle = TextEditStyles.DisableTextEditor;
this.cbbOrgKey = (KDComboBox)(this.GetControl<KDItemContainer>("F_Jac_OrgKey").Control);
this.cbbOrgKey.Properties.TextEditStyle = TextEditStyles.DisableTextEditor;
}
/// <summary>
/// 表单服务编辑控件
/// </summary>
public System.Windows.Forms.Control ActionDesignerCtl
{
get { return this; }
}
/// <summary>
/// 表单服务实例、描述信息
/// </summary>
public FormBusinessService Service { get; set; }
/// <summary>
/// 表单服务所在的元素实例
/// </summary>
public AbstractElement SourceElement { get; set; }
/// <summary>
/// 领域模型设计Model对象,管理元数据信息
/// </summary>
public IMetaDataDesignerModel Model { get; set; }
/// <summary>
/// 表单服务确定后,返回检查结果
/// </summary>
private bool actionValidated;
/// <summary>
/// 表单服务确定后,返回检查结果
/// </summary>
public bool ActionValidated
{
get
{
this.actionValidated = true; // 默认为通过
// 校验
var errorMessage = string.Empty;
if (!ValidateOperateParameter(ref errorMessage))
{
KDMessageBox.Show(errorMessage, "金蝶提示", MessageBoxButtons.OK);
this.actionValidated = false;
return this.actionValidated;
}
return this.actionValidated;
}
set { this.actionValidated = value; }
}
/// <summary>
/// 表单服务类型
/// </summary>
public string ActionType { get; set; }
/// <summary>
/// 开始解析、展示实例数据
/// </summary>
public new void Load()
{
this.businessService = this.Service;
if (this.businessService == null)
{
this.businessService = new FormBusinessService(this.Service);
}
var businessInfo = this.Model.FormMetaData.BusinessInfo;
// 把已经配置的服务参数,展示到界面上
SendMessageParameter sendMessageParameter = null;
if (!string.IsNullOrWhiteSpace(businessService.Setting))
{
sendMessageParameter = JsonConvert.DeserializeObject<SendMessageParameter>(businessService.Setting);
}
if (sendMessageParameter == null)
{
sendMessageParameter = new SendMessageParameter();
}
BindReceiver(businessInfo, sendMessageParameter);
BindOrg(businessInfo, sendMessageParameter);
}
/// <summary>
/// 打包、提交表单服务实例
/// </summary>
public void Commit()
{
var sendMessageParameter = new SendMessageParameter();
var receiverKey = this.cbbReceiverKey.EditValue as ListItem;
if (receiverKey != null)
{
sendMessageParameter.ReceiverKey = receiverKey.Value.ToString();
}
var orgKey = this.cbbOrgKey.EditValue as ListItem;
if (orgKey != null)
{
sendMessageParameter.OrgKey = orgKey.Value.ToString();
}
businessService.Setting = JsonConvert.SerializeObject(sendMessageParameter);
this.Service = this.businessService;
}
#endregion
#region 私有函数
/// <summary>
/// 绑定接收人字段
/// </summary>
private void BindReceiver(BusinessInfo businessInfo, SendMessageParameter parameter)
{
this.cbbReceiverKey.Properties.Items.Clear();
var userFields = businessInfo.GetFieldList().Where(o => o is UserField).ToList();
var list = new List<ListItem>();
list.Add(new ListItem("", ""));
ListItem defaultItem = null;
var hasDefaultItem = !string.IsNullOrWhiteSpace(parameter.ReceiverKey);
foreach (var field in userFields)
{
var item = new ListItem(field.Key, field.Name.ToString());
list.Add(item);
if (hasDefaultItem && field.Key.EqualsIgnoreCase(parameter.ReceiverKey))
{
defaultItem = item;
}
}
this.cbbReceiverKey.Properties.Items.AddRange(list);
if (defaultItem != null)
{
this.cbbReceiverKey.EditValue = defaultItem;
}
else
{
this.cbbReceiverKey.EditValue = list[0];
}
}
/// <summary>
/// 绑定组织字段
/// </summary>
private void BindOrg(BusinessInfo businessInfo, SendMessageParameter parameter)
{
this.cbbOrgKey.Properties.Items.Clear();
var orgFields = businessInfo.GetFieldList().Where(o => o is OrgField).ToList();
var list = new List<ListItem>();
list.Add(new ListItem("", ""));
ListItem defaultItem = null;
var hasDefaultItem = !string.IsNullOrWhiteSpace(parameter.OrgKey);
foreach (var field in orgFields)
{
var item = new ListItem(field.Key, field.Name.ToString());
list.Add(item);
if (hasDefaultItem && field.Key.EqualsIgnoreCase(parameter.OrgKey))
{
defaultItem = item;
}
}
this.cbbOrgKey.Properties.Items.AddRange(list);
if (defaultItem != null)
{
this.cbbOrgKey.EditValue = defaultItem;
}
else
{
this.cbbOrgKey.EditValue = list[0];
}
}
/// <summary>
/// 校验参数对象
/// </summary>
/// <param name="errorMessage"></param>
/// <returns></returns>
private bool ValidateOperateParameter(ref string errorMessage)
{
SendMessageParameter sendMessageParameter = null;
if (!string.IsNullOrWhiteSpace(businessService.Setting))
{
sendMessageParameter = JsonConvert.DeserializeObject<SendMessageParameter>(businessService.Setting);
}
if (sendMessageParameter == null || string.IsNullOrWhiteSpace(sendMessageParameter.ReceiverKey))
{
errorMessage = "请设置接收人字段";
return false;
}
return true;
}
#endregion 配置校验
}
}
<4>编写服务端表单服务,实现运行时功能。
using Kingdee.BOS;
using Kingdee.BOS.App.Data;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.Enums;
using Kingdee.BOS.Core.Metadata.FormElement;
using Kingdee.BOS.Core.Msg;
using Kingdee.BOS.Msg;
using Kingdee.BOS.Orm;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Util;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Jac.XkDemo.BOS.Core.AppBusinessService
{
/// <summary>
/// 【服务层表单服务】发送消息
/// </summary>
public class SendMessageService : AbstractAppBusinessService
{
#region var
/// <summary>
/// 服务端表单服务执行参数
/// </summary>
private AppBusinessServiceArgs appBusinessServiceArgs;
/// <summary>
/// 服务配置
/// </summary>
private FormBusinessService serviceConfig;
#endregion
#region IAppFormBusinessService
/// <summary>
/// 重载是否允许在IDE中设定执行时机:本服务不允许在IDE设定时间点,服务要求必须在操作后执行
/// </summary>
public override bool SupportActionPoint
{
get { return false; }
}
/// <summary>
/// 重载执行时间点:设定本服务仅在操作后执行
/// </summary>
public override int ActionPoint
{
get { return (int)BOSEnums.Enu_ServiceActionPoint.AfterOperation; }
}
/// <summary>
/// 是否允许批量执行?本服务允许批量执行;
/// </summary>
public override bool RequestBatchProcess
{
get { return true; }
}
/// <summary>
/// 添加本服务必须加载的字段
/// </summary>
/// <param name="fieldKeys"></param>
public override void PreparePropertys(List<string> fieldKeys)
{
// TODO:服务中要用到的字段,需提前注册
//fieldKeys.Add("FXXX");
}
/// <summary>
/// 服务执行函数:在允许批量执行时,本函数不会被调用
/// </summary>
/// <param name="e"></param>
public override void DoAction(AppBusinessServiceArgs e)
{
// TODO: 本服务允许批量执行,本函数不会被调用,无需实现
}
/// <summary>
/// 服务执行函数:在允许批量执行时,本函数被调用
/// </summary>
/// <param name="e"></param>
public override void DoActionBatch(AppBusinessServiceArgs e)
{
this.appBusinessServiceArgs = e;
this.serviceConfig = e.FormBusinessService;
this.SendMessage();
}
#endregion
#region 辅助函数
private void SendMessage()
{
if (string.IsNullOrWhiteSpace(serviceConfig.Setting))
{
return;
}
var sendMessageParameter = JsonConvert.DeserializeObject<SendMessageParameter>(serviceConfig.Setting);
if (string.IsNullOrWhiteSpace(sendMessageParameter.ReceiverKey))
{
return;
}
var userField = appBusinessServiceArgs.FullBusinessInfo.GetField(sendMessageParameter.ReceiverKey);
if (userField == null)
{
return;
}
var value = userField.GetFieldValue(appBusinessServiceArgs.DataEntity) as DynamicObject;
if (value == null)
{
return;
}
var receiverId = Convert.ToInt64(value[0]);
var title = string.Format("【{0}】操作执行通知", appBusinessServiceArgs.FullBusinessInfo.GetForm().Name);
var billNo = appBusinessServiceArgs.FullBusinessInfo.GetBillNoField().GetFieldValue(appBusinessServiceArgs.DataEntity);
var msg = string.Format("单据编号为【{0}】的【{1}】执行了【{2}】操作", billNo, appBusinessServiceArgs.FullBusinessInfo.GetForm().Name, appBusinessServiceArgs.FormOperation.OperationName);
SendMessage(Context, appBusinessServiceArgs.FullBusinessInfo.GetForm().Id, appBusinessServiceArgs.DataEntity[0].ToString()
, title, msg, Context.UserId, receiverId);
}
/// <summary>
/// 发送消息(精简版,仅支持一个收件人,不写发件箱)
/// </summary>
/// <param name="ctx"></param>
/// <param name="formId"></param>
/// <param name="pkId"></param>
/// <param name="title"></param>
/// <param name="content"></param>
/// <param name="senderId"></param>
/// <param name="receiverId"></param>
private static void SendMessage(Context ctx, string formId, string pkId, string title, string content, long senderId, long receiverId)
{
Message msg = new DynamicObject(Message.MessageDynamicObjectType);
msg.MessageId = SequentialGuid.NewGuid().ToString();
msg.MsgType = MsgType.CommonMessage;
msg.SenderId = senderId;
msg.ReceiverId = receiverId;
msg.Title = title;
msg.Content = content;
msg.ObjectTypeId = formId;
msg.KeyValue = pkId;
msg.CreateTime = DateTime.Now;
// 保存消息
var dataManager = DataManagerUtils.GetDataManager(Message.MessageDynamicObjectType, new OLEDbDriver(ctx));
dataManager.Save(msg.DataEntity);
}
#endregion
}
}
<5>将表单服务注册到BOS平台。
-- 数据库执行以下脚本,注册表单服务
-- 注册服务层表单服务
DELETE FROM T_MDL_FORMBUSINESS WHERE FACTIONID=88801
INSERT INTO T_MDL_FORMBUSINESS
( FACTIONID ,
FNAME ,
FTYPE ,
FSETCOMPONENT ,
FRUNCOMPONENT ,
FDESIGNERVISIBLE ,
FREVERSEACTIONCLASS ,
FPUSHCOMPONENT ,
FDEFAULTRAISETYPE ,
FAPPSCENARIOTYPE
)
VALUES ( 88801 , -- FACTIONID - int
'SendMessage' , -- FNAME - varchar(50)
8 , -- FTYPE - int
'Jac.XkDemo.BOS.Core.AppBusinessService.SendMessageDesigner, Jac.XkDemo.BOS.Core' , -- FSETCOMPONENT - varchar(150)
'Jac.XkDemo.BOS.Core.AppBusinessService.SendMessageService, Jac.XkDemo.BOS.Core' , -- FRUNCOMPONENT - varchar(150)
1 , -- FDESIGNERVISIBLE - int
'' , -- FREVERSEACTIONCLASS - varchar(150)
'' , -- FPUSHCOMPONENT - varchar(150)
41 , -- FDEFAULTRAISETYPE - int
1 -- FAPPSCENARIOTYPE - int
)
DELETE FROM T_MDL_FORMBUSINESS_L WHERE FACTIONID=88801
INSERT INTO T_MDL_FORMBUSINESS_L
( FPKID ,
FACTIONID ,
FLOCALEID ,
FDESC ,
FSYNTAX ,
FPARAMETER
)
VALUES ( (SELECT ISNULL(MAX(FPKID),0)+1 FROM T_MDL_FORMBUSINESS_L) , -- FPKID - int
88801 , -- FACTIONID - int
2052 , -- FLOCALEID - int
N'发送消息' , -- FDESC - nvarchar(255)
N'SendMessage()' , -- FSYNTAX - nvarchar(255)
N'发送消息' -- FPARAMETER - nvarchar(1000)
)
---------------------------------------------------------------------------------------------------------
<6>拷贝当前组件到应用站点的WebSite\Bin目录下,重启IIS。
<7>拷贝当前组件到BOS设计器运行目录下,重新登录BOS设计器。
BOS设计器通常安装在目录:C:\Program Files (x86)\Kingdee\K3Cloud\DeskClient\K3CloudClient
<8>BOS设计器扩展采购订单,保存操作注册发送消息的表单服务,保存元数据,至此,开发完毕。
【功能验证】
<1>登录业务站点,打开采购订单列表,进入某个采购订单的编辑界面,执行保存操作,此时,对应操作人会收到一条普通消息。
执行保存操作:
收到普通消息:
---------------------------------------------------------------------------------------------------------
【知识点】
<1>表单服务对应的元数据:
<2>如果表单服务在BOS设计器中使用了自定义参数,那么对应组件需要同步更新到BOS设计器运行目录,如果是本地测试,直接拷贝一下就可以快速测试了,如果是生产环境,建议将组件统一打包到部署包中,打包方式可参考教程:https://vip.kingdee.com/school/97996311328065024
---------------------------------------------------------------------------------------------------------
【金蝶云星空BOS二次开发案例演示】https://vip.kingdee.com/article/94751030918525696
二开案例.表单服务.服务端表单服务
本文2024-09-23 03:59:49发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-162431.html