起步软件技术论坛-X3

 找回密码
 立即注册
搜索
楼主: noahark

如何在流程功能外,通过代码控制流程(不仅是启动,还可能是流转,回退)**

[复制链接]
 楼主| 发表于 2008-9-24 17:59:42 | 显示全部楼层
谢谢你的回答!如果客户现在有这样的需求,即,"在一个完全与流程A无关的功能里,根据我的业务数据,控制流程A(不仅是启动,还可能是流转,回退).”,或用你说的说法,也就是"不把功能运行起来,从而实现流程的控制"。

这个需求能否实现?如何实现?烦请确认。

不胜感激!若有冒犯,实因事情急,道个歉先,别介意!
回复 支持 反对

使用道具 举报

发表于 2008-9-24 18:41:08 | 显示全部楼层
我觉得需要模拟一个完整环境,从人员开始(防止违反权限定义)

我在系统流程监控里看到一些代码,楼主可以参考一下。
系统空间\系统功能\业务流程\流程监控\系统流程监控\系统流程监视
TMainForm.ShowBizData(ADeptID, APositionID, APersonID: String; ATask: TTask);
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-9-25 09:44:35 | 显示全部楼层
你说的非常对,我也认为可能需要模拟一个完整的,与在流程功能内驱动流程相似的环境。关键是这个环境如何模拟?我看了你的代码,实在看不出与我要解决的问题有何关系?

此技术问题涉及到公司一个很大项目的招标,烦请贵公司集思广益,讨论一下我的问题,帮我实现这个功能。

谢谢!
回复 支持 反对

使用道具 举报

发表于 2008-9-25 10:28:30 | 显示全部楼层
稍等,正在尝试!
回复 支持 反对

使用道具 举报

发表于 2008-9-25 15:25:52 | 显示全部楼层
做了个例子,楼主试试:
unit FlowManagerForm;

interface

uses
  Business.System, Business.Model, Business.Forms, Business.Data,
  Business.Model.Flow, Business.Model.Org;

type
  TFlowManagerForm = class(TForm)
    FuncBroker: TFuncBroker;
    InfoBrokerFLOWMANAGERINFO: TInfoBroker;
    ControlBar: TControlBar;
    DataNavigator: TDataNavigator;
    DocViewBar: TDocViewBar;
    Panel: TPanel;
    DocViewFLOWMANAGERINFO_FLOWVIEW: TDocView;
    ToolBar1: TToolBar;
    tbFlowBack: TToolButton;
    ToolButton2: TToolButton;
    tbFlowOut: TToolButton;
    ToolButton4: TToolButton;
    dsbFlow: TDataSetBroker;
    dsbTask: TDataSetBroker;
    dsbTaskMessage: TDataSetBroker;
    FlowBroker1: TFlowBroker;
    tbRunTaskFunc: TToolButton;
    procedure BizFormDestroy(Sender: TObject);
    procedure tbRunTaskFuncClick(Sender: TObject);
    procedure tbFlowOutClick(Sender: TObject);
    procedure tbFlowBackClick(Sender: TObject);
  private
    FOperator: TOperator;
    FFlowControl: TFlowControl;
    FFlow: TFlow;
    FTask: TTask;

    function CanProcess: Boolean;
    function CurrentFlowGuid: String;
    function CurrentTaskGuid: String;
    function CurrentTaskMessageGuid: String;
    function GetExecutorDept: String;
    function GetExecutorPosition: String;
    function GetExecutorPerson: String;

    function CurrentFlow: TFlow;
    function CurrentTask: TTask;
    function CurrentTaskMessage(ATask: TTask): TTaskMessage;

    function GetTaskFuncURL(const ATask: TTask): string;
    function GetTaskFunc(AContext: TContext; const AFuncURL: string): TFunc;
    function GetPositionContext: TContext;
    function GetFlowContext(AContext: TContext): TContext;
    function RunTaskFunc(CreateMainForm: Boolean): Boolean;
  public
    {public declarations}
  end;

implementation

procedure TFlowManagerForm.BizFormDestroy(Sender: TObject);
begin
  if Assigned(FFlow) then
    FFlow.Free;
  if Assigned(FTask) then
    FTask.Free;
  if Assigned(FFlowControl) then
    FFlowControl.Free;
  if Assigned(FOperator) then
    Opr.Logoff(FOperator);
end;

function TFlowManagerForm.CanProcess: Boolean;
begin
  Result := (dsbTask.DataSet.FieldByName('FSTATE').AsString = 'tsStarted') and
    (dsbTaskMessage.DataSet.FieldByName('FSTATE').AsString = 'tmsSend');
end;

function TFlowManagerForm.CurrentFlowGuid: String;
begin
  Result := dsbFlow.DataSet.FieldByName('FGuid').AsString;
end;

function TFlowManagerForm.CurrentTaskGuid: String;
begin
  Result := dsbTask.DataSet.FieldByName('FGuid').AsString;
end;

function TFlowManagerForm.CurrentTaskMessageGuid: String;
begin
  Result := dsbTaskMessage.DataSet.FieldByName('FGuid').AsString;
end;

function TFlowManagerForm.GetExecutorDept: String;
begin
  Result := dsbTaskMessage.DataSet.FieldByName('FRDEPT').AsString;
end;

function TFlowManagerForm.GetExecutorPosition: String;
begin
  Result := dsbTaskMessage.DataSet.FieldByName('FRPOSITION').AsString;
end;

function TFlowManagerForm.GetExecutorPerson: String;
begin
  Result := dsbTaskMessage.DataSet.FieldByName('FRPERSON').AsString;
end;

function TFlowManagerForm.CurrentFlow: TFlow;
begin
  if not Assigned(FFlow) then
    FFlow := TFlow.Create;
  if not SysUtils.SameText(FFlow.GUID, CurrentFlowGuid) then
    Business.Model.Flow.Flow.FlowEngine.LoadFlow(CurrentFlowGuid, FFlow);
  Result := FFlow;
end;

function TFlowManagerForm.CurrentTask: TTask;
begin
  if not Assigned(FTask) then
    FTask := TTask.Create;
  if not SysUtils.SameText(FTask.GUID, CurrentTaskGuid) then
    Business.Model.Flow.Flow.FlowEngine.LoadTask(CurrentTaskGuid, FTask);
  Result := FTask;
end;

function TFlowManagerForm.CurrentTaskMessage(ATask: TTask): TTaskMessage;
var
  I: Integer;
begin
  Result := nil;
  for I := 0 to ATask.TaskMessages.Count - 1 do
    if SysUtils.SameText(CurrentTaskMessageGuid, ATask.TaskMessages[I].GUID) then
    begin
      Result := ATask.TaskMessages[I];
      break;
    end;
end;

function TFlowManagerForm.GetTaskFuncURL(const ATask: TTask): string;
var
  lProcURL: TBizURL;
  lProc: TProc;
begin
  lProcURL := TBizURL.Create;
  try
    lProcURL.URL := ATask.ProcURL;
    lProc := TProc(Business.Model.BizSys.BizSystem.GetBizObject(lProcURL));
    Result := TProcActivity(lProc.GetUnit(ATask.ProcUnitID)).FuncURL.URL;
  finally
    lProcURL.Free;
  end;
end;

function TFlowManagerForm.GetTaskFunc(AContext: TContext; const AFuncURL: string): TFunc;
var
  lBizClassURL: TBizClassURL;
begin
  lBizClassURL := TBizClassURL.Create;
  Try
    lBizClassURL.BizURL.URL := AFuncURL;
    Result := TFunc(AContext.GetBizObject(lBizClassURL));
  finally
    lBizClassURl.Free;
  end;
end;

function TFlowManagerForm.GetPositionContext: TContext;
CONST
  msg_NotFoundPosition = '组织节点[部门:%s, 岗位:%s, 人员:%s]的岗位环境不存在,'+
    #13 + #10 + '可能是已经被删除或代理!';
var
  lPerson: TPerson;
  lPosition: TOperatorPosition;
  lDeptID, lPositionID, lPersonID: string;
  lPositions: TOperatorPositionArray;
begin
  Result := nil;
  //if CanProcess then
  //begin
    lDeptID := GetExecutorDept;
    lPositionID := GetExecutorPosition;
    lPersonID := GetExecutorPerson;

    if Assigned(FOperator) and (FOperator.ID <> lPersonID) then
      Opr.Logoff(FOperator);
    lPerson := Org.OrgSys.OrgSystem.GetPerson(lPersonID);
    FOperator := Opr.Logon(lPerson.ID, lPerson.Password);
    try
      lPositions := [];
      if FOperator.FindPosition(lDeptID, lPositionID, lPersonID, lPositions) then
        lPosition := lPositions[0]
      else
        lPosition := nil;

      if lPosition <> nil then
        Result := lPosition.Context
      else
        JSDialogs.ShowMsg(SysUtils.Format(msg_NotFoundPosition,
              [lDeptID, lPositionID, lPersonID]), '');
    finally
     //
    end;
  //end;
end;

function TFlowManagerForm.GetFlowContext(AContext: TContext): TContext;
var
  lContext: TContext;
begin
  Result := nil;
  if AContext <> nil then
    lContext := AContext
  else
    Exit;

  if (FFlowControl <> nil) then
    FFlowControl.Free;
  FFlowControl := TFlowControl.Create(lContext);
  Result := FFlowControl.Context;
end;

function TFlowManagerForm.RunTaskFunc(CreateMainForm: Boolean): Boolean;
var
  lFuncURL: string;
  lFunc: TFunc;
  lFlowContext: TContext;
  lTask: TTask;
  lTaskMessage: TTaskMessage;
  lOrgURL: TOrgURL;
begin
  Result := CanProcess;
  if not Result then exit;
  lTask := CurrentTask;
  lTaskMessage := CurrentTaskMessage(lTask);
  lFlowContext := GetFlowContext(GetPositionContext);
  if lFlowContext = nil then
    Exit;
  lOrgUrl := TOrgUrl.Create(lTaskMessage.ReceiverDeptID,
    lTaskMessage.ReceiverPositionID, lTaskMessage.ReceiverID);
  try
    FFlowControl.ExecuteTask(lTask, lOrgUrl);
    lFuncURL := GetTaskFuncURL(lTask);
    lFunc := GetTaskFunc(lFlowContext, lFuncURL);
    FFlowControl.Func := lFunc;
    lFunc.Run('');
    if CreateMainForm and (lFunc.MainForm <> nil) then
    begin

      lFunc.MainForm.Show;
    end;
    Result := true;
  finally
    lOrgUrl.Free;
  end;
end;

procedure TFlowManagerForm.tbRunTaskFuncClick(Sender: TObject);
begin
  RunTaskFunc(true);
end;

procedure TFlowManagerForm.tbFlowOutClick(Sender: TObject);
var
  lTasks: TList;
begin
  lTasks := TList.Create;
  try
    if RunTaskFunc(false) then
      begin
        lTasks.Add(CurrentTask);
        FFlowControl.FlowOut(lTasks);
      end;
  finally
    lTasks.Free;
  end;
end;

procedure TFlowManagerForm.tbFlowBackClick(Sender: TObject);
var
  lTasks: TList;
begin
  lTasks := TList.Create;
  try
    if RunTaskFunc(false) then
      begin
        lTasks.Add(CurrentTask);
        FFlowControl.FlowBack(lTasks);
      end;
  finally
    lTasks.Free;
  end;
end;

end.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-9-25 16:19:25 | 显示全部楼层
Thank you very much, let me try!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-9-25 17:06:30 | 显示全部楼层
我看了一下你的代码,确实能实现我说的需要,ExecuteTask,Run但不显示出界面,通过Execute,Run来创建工作流所需要的环境。

但实际上,如果我知道Execute,Run内部的实现机制,我们则不需要绕这么大个圈(说绕圈可能也不准确,因为虽说在流程功能外控制这些任务,ExecuteTask,Run很多时候是应该做的)。

我们实际上是要为客户实现邮件驱动流程,或者是短消息驱动流程的功能,在移动办公日趋盛行的现在,这类功能很有价值.建议你们能在保证保护你们技术秘密前提下,为Partner开放更多的类库层次的内部实现,以方便Partner扩展相关功能.贵公司在Delphi上的技术应用已高高在上,在开放性上也还能像Delphi一样做的更好(贵公司已经做的很好了!)!这绝对是双赢!

在一次感谢你的辛苦回复,相信以后还有麻烦的地方!thank you!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-10-15 15:41:41 | 显示全部楼层
你好!再次打扰!注意到在你例子代码的“GetPositionContext”方法里,调用了“Opr.Logon”,能不能不通过Logon的方式获取需要的“Context”?
回复 支持 反对

使用道具 举报

发表于 2008-10-15 17:52:04 | 显示全部楼层
logon执行后,系统会创建相应的人员环境,楼主可以用代码直接去取了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-10-16 09:34:56 | 显示全部楼层
问题是反复logon,logout效率太低了!我们希望有直接的获取该context方法。我做了测试,直接传入当前登录用户某窗体的Context,也正常执行。当然,这可能与当前登录用户的相关设置,如权限有关。

我还是希望知道不通过Logon的方式获取需要的,正确的,肯定的“Context”的方法!谢谢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Justep Inc.

GMT+8, 2025-7-28 06:05 , Processed in 0.048400 second(s), 13 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表