1. BOS中找到【流程中心】-【工作流】-【流程管理中心】-【流程管理_流程实例】,若未扩展的话先点击右键选
择扩展,然后再二开:
![image.webp](/download/0100b3bfa6065ca74f0bb504a556e2ffe12a.webp)
2. 在打开的扩展中添加文本字段:
当前处理人:字段名: FCURRENTRECEIVER 标识: FCurrentReceiver
当前时长间隔:字段名:FLATETIMES 标识:FLateTimes
![image.webp](/download/01002877dfe3229d4a4cad0c2ac71e8b4e70.webp)
3. 将插件挂在到列表插件中:
![image.webp](/download/0100d46acdef37c7411f91cb0ea2f648f25e.webp)
具体的插件打包和挂载的方式请参考文章:[二开案例.开发环境.从零开发第一个插件](https://wenku.my7c.com/article/83500607104976896?productLineId=1&isKnowledge=2)
若使用python插件,则直接注册即可:
![image.webp](/download/010071e8532aeacb4ab492db86929d46b01d.webp)
4. 插件挂载或注册完成后修改已完成流程视图【v_wf_PMProcInstEnd】,将刚加的两个字段添加到视图中,不然点击已完成流程时会报错:
```sqlserver
CREATE VIEW [dbo].[v_wf_PMProcInstEnd] AS SELECT
FPROCINSTID,
FNUMBER,
FSUMMARY,
FCREATETIME,
FCOMPLETETIME,
FMODIFYTIME,
FSTATUS,
FORIGINATORID,
FMODIFIERID,
FPROCDEFID,
FVERSIONID,
FTMPID,
FFAILUREOUTINFO,
FFAILUREMESSAGE,
FCURRENTRECEIVER,
FLATETIMES
FROM
T_WF_PROCINST
WHERE
( FSTATUS = '1' OR FSTATUS = '4' )
```
5. C#代码示例
```C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Kingdee.BOS;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.List;
using Kingdee.BOS.Core.List.PlugIn;
using Kingdee.BOS.Core.List.PlugIn.Args;
using Kingdee.BOS.ServiceHelper;
using Kingdee.BOS.Util;
namespace Test.BOS.Workflow.Plugins.ProManageProcInst
{
[Description("流程管理中心显示当前处理人和当前时间间隔")]
public class ProcInstCurrentReceiver: AbstractListPlugIn
{
bool Reload = true;
public Dictionary<string, List<string>> receivers = new Dictionary<string, List<string>>();
public Dictionary<string, List<string>> times = new Dictionary<string, List<string>>();
public override void OnInitialize(InitializeEventArgs e)
{
base.OnInitialize(e);
Reload = true;
receivers.Clear();
times.Clear();
}
public override void FormatCellValue(FormatCellValueArgs args)
{
string formId = this.View.BillBusinessInfo.GetForm().Id;
if (formId.EqualsIgnoreCase("WF_ProcInstBillEndHis"))
{
return;
}
if (Reload)
{
ListSelectedRowCollection pageInfo = (this.View as IListView).CurrentPageRowsInfo;
string[] procInstIds = pageInfo.Select(p => p.PrimaryKeyValue).ToArray();
GetReceiverAndCreateTime(procInstIds);
Reload = false;
}
if (!(args.DataRow is ListRow row))
{
return;
}
string procInstId = ObjectUtils.Object2String(row.DynamicObject["FPROCINSTID"]);
if (args.Header.Key.EqualsIgnoreCase("FCurrentReceiver"))
{
args.FormateValue = receivers.ContainsKey(procInstId) ? string.Join(",", receivers[procInstId]) : "";
}
if (args.Header.Key.EqualsIgnoreCase("FLateTimes"))
{
int status = ObjectUtils.Object2Int(row.DynamicObject["FSTATUS"]);
if (status == 2 || status == 1)
{
DateTimeFormatInfo formatInfo = new DateTimeFormatInfo
{
ShortDatePattern = "yyyy-MM-dd HH:mm:ss"
};
string createTimeString = times.ContainsKey(procInstId) ? string.Join(",", times[procInstId]) : "";
if (createTimeString != null || createTimeString != "")
{
DateTime createTime = Convert.ToDateTime(createTimeString, formatInfo);
DateTime nowTime = Convert.ToDateTime(DateTime.Now.ToString(), formatInfo);
TimeSpan timeSpan = nowTime - createTime;
string diff = "";
string days = "";
string hours = "";
string mins = "";
string secs = "";
if (timeSpan.Days > 0)
{
days = timeSpan.Days.ToString() + "天";
}
if (timeSpan.Hours > 0)
{
if (timeSpan.Hours >= 10)
{
hours = timeSpan.Hours.ToString() + "小时";
}
else
{
hours = "0" + timeSpan.Hours.ToString() + "小时";
}
}
if (timeSpan.Minutes > 0)
{
if (timeSpan.Minutes >= 10)
{
mins = timeSpan.Minutes.ToString() + "分钟";
}
else
{
mins = "0" + timeSpan.Minutes.ToString() + "分钟";
}
}
if (timeSpan.Seconds > 0)
{
if (timeSpan.Seconds >= 10)
{
secs = timeSpan.Seconds.ToString() + "秒";
}
else
{
secs = "0" + timeSpan.Seconds.ToString() + "秒";
}
}
else
{
secs = timeSpan.Milliseconds + "毫秒";
}
diff = string.Format("{0}{1}{2}{3}", days, hours, mins, secs);
args.FormateValue = diff;
}
else
{
args.FormateValue = "00秒";
}
}
else
{
args.FormateValue = "00秒";
}
}
base.FormatCellValue(args);
}
[Description("获取当前处理人和创建时间")]
private void GetReceiverAndCreateTime(string[] procInstIds)
{
string idsSql = StringUtils.GetSqlWithCardinality(procInstIds.Length, "@FID", 2);
SqlParam param = new SqlParam("@FID", KDDbType.udt_varchartable, procInstIds);
string sql = string.Format("select t0.FPROCINSTID, t0.FRECEIVERNAMES, t0.FCREATETIME from V_WF_PROCINSTASSIGN t0 inner join {0} t1 on t0.FPROCINSTID = t1.FID", idsSql);
List<SqlParam> paramsList = new List<SqlParam>
{
param
};
var res = DBServiceHelper.ExecuteDynamicObject(this.View.Context, sql, null, null, System.Data.CommandType.Text, paramsList.ToArray());
if (!res.IsEmpty())
{
foreach (var data in res)
{
string procInstId = ObjectUtils.Object2String(data["FPROCINSTID"]);
if (!receivers.ContainsKey(procInstId))
{
receivers[procInstId] = new List<string> { ObjectUtils.Object2String(data["FRECEIVERNAMES"]) };
times[procInstId] = new List<string> { ObjectUtils.Object2String(data["FCREATETIME"]) };
} else
{
receivers[procInstId].Add(ObjectUtils.Object2String(data["FRECEIVERNAMES"]));
times[procInstId].Add(ObjectUtils.Object2String(data["FCREATETIME"]));
}
}
}
}
}
}
```
6. python代码示例:
```python
import clr
clr.AddReference('System')
clr.AddReference('System.Data')
clr.AddReference('Kingdee.BOS')
clr.AddReference('Kingdee.BOS.Core')
clr.AddReference("Kingdee.BOS.App")
clr.AddReference("Newtonsoft.Json")
clr.AddReference("mscorlib")
from System import *
from System.Data import *
from System.ComponentModel import *
from System.Globalization import *
from System.Collections.Generic import *
from Kingdee.BOS import *
from Kingdee.BOS.ServiceHelper import *
from Kingdee.BOS.Util import *
from Kingdee.BOS.Log import *
from Newtonsoft.Json import *
from Kingdee.BOS.Core.DynamicForm.PlugIn.Args import *
from Kingdee.BOS.App.Data import *
Reload = True
receivers = Dictionary[str, List[str]]()
times = Dictionary[str, List[str]]()
def OnInitialize(e):
global Reload
global dicts
global times
Reload = True
receivers.Clear()
times.Clear()
def FormatCellValue(args):
global Reload
global receivers
global times
formId = this.ListView.BillBusinessInfo.GetForm().Id
if formId == "WF_ProcInstBillEndHis":
return
if Reload:
pageInfo = this.ListView.CurrentPageRowsInfo
procInstIds = pageInfo.GetPrimaryKeyValues()
GetReceiverAndCreateTime(procInstIds)
Reload = False
row = args.DataRow
if row :
procInstId = ObjectUtils.Object2String(row.DynamicObject["FPROCINSTID"])
if args.Header.Key == "FCurrentReceiver":
args.FormateValue = "," . join(receivers[procInstId]) if receivers.ContainsKey(procInstId) else ""
if args.Header.Key == "FLateTimes" :
status = ObjectUtils.Object2Int(row.DynamicObject["FSTATUS"])
if status == 2 or status == 1 :
formatInfo = DateTimeFormatInfo()
formatInfo.ShortDatePattern = "yyyy-MM-dd HH:mm:ss.ff"
createTimeString = "" . join(times[procInstId]) if times.ContainsKey(procInstId) else ""
if len(createTimeString.replace(" ", "")) > 0 :
createTime = Convert.ToDateTime(createTimeString, formatInfo)
nowTime = Convert.ToDateTime(DateTime.Now.ToString(), formatInfo)
timeSpan = nowTime - createTime
days = (str.format("{0}天", timeSpan.Days.ToString())) if timeSpan.Days > 0 else ""
hours = (str.format("{0}小时", timeSpan.Hours.ToString()) if timeSpan.Hours >= 10 else str.format("0{0}小时", timeSpan.Hours.ToString())) if timeSpan.Hours > 0 else ""
mins = (str.format("{0}分钟", timeSpan.Minutes.ToString()) if timeSpan.Minutes >= 10 else str.format("0{0}分钟", timeSpan.Minutes.ToString())) if timeSpan.Minutes > 0 else ""
secs = (str.format("{0}秒", timeSpan.Seconds.ToString()) if timeSpan.Seconds >= 10 else str.format("0{0}秒", timeSpan.Seconds.ToString())) if timeSpan.Seconds > 0 else str.format("{0}毫秒", timeSpan.Milliseconds)
diff = str.format("{0}{1}{2}{3}", days, hours, mins, secs)
args.FormateValue = diff
else :
args.FormateValue = ""
else :
args.FormateValue = ""
return
else :
return
def GetReceiverAndCreateTime(procInstIds):
idsSql = StringUtils.GetSqlWithCardinality(len(procInstIds), "@FID", 2)
sql = "select t0.FPROCINSTID, t0.FRECEIVERNAMES, t0.FCREATETIME from V_WF_PROCINSTASSIGN t0 inner join " + idsSql + " t1 on t0.FPROCINSTID = t1.FID"
param = SqlParam("@FID", KDDbType.udt_varchartable, procInstIds)
paramsList = List[SqlParam]()
paramsList.Add(param)
res = DBServiceHelper.ExecuteDynamicObject(this.View.Context, sql, None, None, CommandType.Text, paramsList.ToArray())
if len(res) > 0:
for data in res:
procInstId = ObjectUtils.Object2String(data["FPROCINSTID"])
if procInstId not in receivers:
receivers[procInstId] = List[str]()
receivers[procInstId].Add(ObjectUtils.Object2String(data["FRECEIVERNAMES"]))
else :
receivers[procInstId].Add(ObjectUtils.Object2String(data["FRECEIVERNAMES"]))
if procInstId not in times:
times[procInstId] = List[str]()
times[procInstId].Add(ObjectUtils.Object2String(data["FCREATETIME"]))
else :
times[procInstId].Add(ObjectUtils.Object2String(data["FCREATETIME"]))
```
你好!参考你的代码已经可以实现在界面显示了。
但可惜没法用“当前处理人”字段进行过滤。目前变通方法是去列表的列名那过滤。
请问,这点还可以优化吗?
从网页先 copy 到 text,再粘贴进去。
结果报错如下
Could not add reference to assembly Kingdee.BOS.App
在 IronPython.Runtime.ClrModule.AddReference(CodeContext context, String name)
在 IronPython.Runtime.ClrModule.AddReference(CodeContext context, Object[] references)
在 Microsoft.Scripting.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
在 Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
在 Microsoft.Scripting.Interpreter.LightLambda.Run4[T0,T1,T2,T3,TRet](T0 arg0, T1 arg1, T2 arg2, T3 arg3)
在 System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
在 Microsoft.Scripting.Interpreter.DynamicInstruction`4.Run(InterpretedFrame frame)
在 Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
在 Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
在 IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
在 Kingdee.BOS.DomainModelDesigner.PropertyEditor.frmPythonScriptEdit.InitializeScope()
在 Kingdee.BOS.DomainModelDesigner.PropertyEditor.frmPythonScriptEdit.ButtonItem_Click(Object sender, EventArgs e)
打开流程管理中心也报错如下,请问是哪里有问题呢?谢谢