增加流程状态转换列表

This commit is contained in:
yubaolee 2016-09-07 11:11:34 +08:00
parent 96e8eec1e7
commit 0c82f7b8c3
20 changed files with 499 additions and 38 deletions

View File

@ -0,0 +1,38 @@
using System;
using OpenAuth.Domain;
using OpenAuth.Domain.Interface;
namespace OpenAuth.App
{
public class ApplyTransitionHistoryApp
{
private IRepository<ApplyTransitionHistory> _repository;
public ApplyTransitionHistoryApp(IRepository<ApplyTransitionHistory> repository)
{
_repository = repository;
}
public ApplyTransitionHistory Get(Guid processId, string currentstate, string nextState)
{
return _repository.FindSingle(h => h.ApplyId == processId && !h.TransitionTime.HasValue &&
h.InitialState == currentstate && h.DestinationState == nextState);
}
public void Add(ApplyTransitionHistory historyItem)
{
_repository.Add(historyItem);
}
public void Update(ApplyTransitionHistory historyItem)
{
_repository.Update(historyItem);
}
public void DeleteByProcess(Guid processId)
{
_repository.Delete(dth =>
dth.ApplyId == processId && !dth.TransitionTime.HasValue);
}
}
}

View File

@ -80,8 +80,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ApplyTransitionHistoryApp.cs" />
<Compile Include="CategoryManagerApp.cs" />
<Compile Include="AuthorizeApp.cs" />
<Compile Include="WorkflowInboxApp.cs" />
<Compile Include="ModuleElementManagerApp.cs" />
<Compile Include="ModuleManagerApp.cs" />
<Compile Include="ResourceManagerApp.cs" />

View File

@ -147,5 +147,14 @@ namespace OpenAuth.App
{
_relevanceRepository.DeleteBy("UserRole", roleids.ToLookup(roleId => userId));
}
public List<Guid> GetUsersInRole(string ruleName)
{
var role = _repository.FindSingle(u => u.Name == ruleName);
if (role == null) return null;
return _relevanceRepository.Find(u => u.Key == "UserRole"
&& u.SecondId == role.Id).Select(u => u.FirstId).ToList();
}
}
}

View File

@ -143,5 +143,9 @@ namespace OpenAuth.App
_relevanceRepository.AddRelevance("UserOrg", orgIds.ToLookup(u => user.Id));
}
public IEnumerable<User> GetUsers(IEnumerable<Guid> userids)
{
return _repository.Find(u => userids.Contains(u.Id));
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using OpenAuth.App.ViewModel;
using OpenAuth.Domain;
using OpenAuth.Domain.Interface;
namespace OpenAuth.App
{
public class WorkflowInboxApp
{
private IRepository<WorkflowInbox> _repository;
public WorkflowInboxApp(IRepository<WorkflowInbox> repository)
{
_repository = repository;
}
public void DeleteAllByProcess(Guid processId)
{
_repository.Delete(u =>u.ProcessId == processId);
}
public void Add(WorkflowInbox newInboxItem)
{
_repository.Add(newInboxItem);
}
}
}

View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a CodeSmith Template.
//
// DO NOT MODIFY contents of this file. Changes to this
// file will be lost if the code is regenerated.
// Author:Yubao Li
// </autogenerated>
//------------------------------------------------------------------------------
using System;
namespace OpenAuth.Domain
{
/// <summary>
///
/// </summary>
public partial class ApplyTransitionHistory :Entity
{
public ApplyTransitionHistory()
{
this.AllowedToUserNames= string.Empty;
this.TransitionTime= DateTime.Now;
this.InitialState= string.Empty;
this.DestinationState= string.Empty;
this.Command= string.Empty;
}
/// <summary>
///
/// </summary>
public System.Guid ApplyId { get; set; }
/// <summary>
///
/// </summary>
public System.Guid? UserId { get; set; }
/// <summary>
///
/// </summary>
public string AllowedToUserNames { get; set; }
/// <summary>
///
/// </summary>
public System.DateTime? TransitionTime { get; set; }
/// <summary>
///
/// </summary>
public long Order { get; set; }
/// <summary>
///
/// </summary>
public string InitialState { get; set; }
/// <summary>
///
/// </summary>
public string DestinationState { get; set; }
/// <summary>
///
/// </summary>
public string Command { get; set; }
}
}

View File

@ -42,6 +42,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ApplyTransitionHistory.cs" />
<Compile Include="Category.cs" />
<Compile Include="Core\User.cs" />
<Compile Include="DicDetail.cs" />
@ -72,6 +73,7 @@
<Compile Include="Service\StockManagerService.cs" />
<Compile Include="Stock.cs" />
<Compile Include="User.cs" />
<Compile Include="WorkflowInbox.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a CodeSmith Template.
//
// DO NOT MODIFY contents of this file. Changes to this
// file will be lost if the code is regenerated.
// Author:Yubao Li
// </autogenerated>
//------------------------------------------------------------------------------
namespace OpenAuth.Domain
{
/// <summary>
///
/// </summary>
public partial class WorkflowInbox :Entity
{
/// <summary>
/// 工作流实体ID
/// </summary>
public System.Guid ProcessId { get; set; }
/// <summary>
/// 用户ID
/// </summary>
public System.Guid IdentityId { get; set; }
}
}

View File

@ -165,18 +165,13 @@ function detail() {
id: 'detailDlg',
url: '/GoodsApplies/Detail?id=' + selected.Id,
title: '进度详情',
width: 800,
height: 600,
width: 900,
height: 700,
mask:true
});
$(document)
.on('bjui.beforeCloseDialog',
function(e) {
var $dialog = $(e.target);
if ($dialog.id == "detailDlg") {
$(document).on('bjui.beforeCloseDialog',function(e) {
list.reload();
}
});
});
}
function add() {

View File

@ -1,6 +1,5 @@
var schemecode = 'SimpleWF';
var wfdesigner = undefined;
console.log("detail");
function wfdesignerRedraw() {
var data;
@ -9,7 +8,6 @@ function wfdesignerRedraw() {
data = wfdesigner.data;
wfdesigner.destroy();
}
console.log(QueryString.id); //取不到值??
var processid = $("#processId").val();
wfdesigner = new WorkflowDesigner({
@ -18,7 +16,7 @@ function wfdesignerRedraw() {
renderTo: 'wfdesigner',
imagefolder: '/images/',
graphwidth: 800,
graphheight: 600
graphheight: 500
});
if (data == undefined) {

View File

@ -39,6 +39,8 @@ namespace OpenAuth.Mvc.Controllers
{
apply.UserId = AuthUtil.GetCurrentUser().User.Id;
_app.AddOrUpdate(apply);
CreateWorkflowIfNotExists(apply.Id);
}
catch (Exception ex)
{
@ -53,7 +55,6 @@ namespace OpenAuth.Mvc.Controllers
try
{
GoodsApplyVM apply = _app.Get(id);
CreateWorkflowIfNotExists(id);
apply.Commands = GetCommands(id);
return View(apply);
}
@ -160,5 +161,6 @@ namespace OpenAuth.Mvc.Controllers
WorkflowInit.Runtime.ExecuteCommand(id, currentUser, currentUser, command);
}
}
}

View File

@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.Linq;
using System.Text;
using OpenAuth.App;
using OpenAuth.Domain;
using OptimaJet.Workflow.Core.Model;
using OptimaJet.Workflow.Core.Runtime;
@ -16,7 +20,11 @@ namespace OpenAuth.Mvc.Models
}
public void ExecuteAction(string name, ProcessInstance processInstance, WorkflowRuntime runtime, string actionParameter)
{
throw new NotImplementedException();
if (_actions.ContainsKey(name))
{
_actions[name].Invoke(processInstance, actionParameter);
return;
}
}
public bool ExecuteCondition(string name, ProcessInstance processInstance, WorkflowRuntime runtime, string actionParameter)
@ -26,7 +34,113 @@ namespace OpenAuth.Mvc.Models
public List<string> GetActions()
{
return new List<string>{"ok"};
return _actions.Keys.ToList();
}
private static Dictionary<string, Action<ProcessInstance, string>> _actions = new Dictionary
<string, Action<ProcessInstance, string>>
{
{"创建流程记录", WriteTransitionHistory}, //仅用于PreExecution创建流程初始转换列表
{"更新流程记录", UpdateTransitionHistory}
};
private static ApplyTransitionHistoryApp _applyTransitionHistoryApp = AutofacExt.GetFromFac<ApplyTransitionHistoryApp>();
public static void WriteTransitionHistory(ProcessInstance processInstance, string parameter)
{
if (processInstance.IdentityIds == null)
return;
var currentstate = WorkflowInit.Runtime.GetLocalizedStateName(processInstance.ProcessId, processInstance.CurrentState);
var nextState = WorkflowInit.Runtime.GetLocalizedStateName(processInstance.ProcessId, processInstance.ExecutedActivityState);
var command = WorkflowInit.Runtime.GetLocalizedCommandName(processInstance.ProcessId, processInstance.CurrentCommand);
var historyItem = new ApplyTransitionHistory
{
Id = Guid.NewGuid(),
AllowedToUserNames = GetEmployeesString(processInstance.IdentityIds),
DestinationState = nextState,
ApplyId = processInstance.ProcessId,
InitialState = currentstate,
Command = command
};
_applyTransitionHistoryApp.Add(historyItem);
}
private static string GetEmployeesString(IEnumerable<string> identities)
{
var identitiesGuid = identities.Select(c => new Guid(c));
var app = AutofacExt.GetFromFac<UserManagerApp>();
var employees = app.GetUsers(identitiesGuid);
var sb = new StringBuilder();
bool isFirst = true;
foreach (var employee in employees)
{
if (!isFirst)
sb.Append(",");
isFirst = false;
sb.Append(employee.Name);
}
return sb.ToString();
}
public static void UpdateTransitionHistory(ProcessInstance processInstance, string parameter)
{
var currentstate = WorkflowInit.Runtime.GetLocalizedStateName(processInstance.ProcessId, processInstance.CurrentState);
var nextState = WorkflowInit.Runtime.GetLocalizedStateName(processInstance.ProcessId, processInstance.ExecutedActivityState);
var command = WorkflowInit.Runtime.GetLocalizedCommandName(processInstance.ProcessId, processInstance.CurrentCommand);
var isTimer = !string.IsNullOrEmpty(processInstance.ExecutedTimer);
var historyItem = _applyTransitionHistoryApp.Get(processInstance.ProcessId, currentstate, nextState);
if (historyItem == null)
{
historyItem = new ApplyTransitionHistory()
{
Id = Guid.NewGuid(),
AllowedToUserNames = string.Empty,
DestinationState = nextState,
ApplyId = processInstance.ProcessId,
InitialState = currentstate
};
_applyTransitionHistoryApp.Add(historyItem);
}
historyItem.Command = !isTimer ? command : string.Format("Timer: {0}", processInstance.ExecutedTimer);
historyItem.TransitionTime = DateTime.Now;
if (string.IsNullOrWhiteSpace(processInstance.IdentityId))
historyItem.UserId = null;
else
historyItem.UserId = new Guid(processInstance.IdentityId);
try
{
_applyTransitionHistoryApp.Update(historyItem);
}
catch (DbEntityValidationException e)
{
Console.WriteLine(e);
}
}
internal static void DeleteEmptyPreHistory(Guid processId)
{
_applyTransitionHistoryApp.DeleteByProcess(processId);
}
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Configuration;
using System.Xml.Linq;
using OpenAuth.App;
using OpenAuth.Domain;
using OptimaJet.Workflow.Core.Builder;
using OptimaJet.Workflow.Core.Bus;
using OptimaJet.Workflow.Core.Persistence;
@ -27,7 +28,7 @@ namespace OpenAuth.Mvc.Models
{
var connectionString = ConfigurationManager.ConnectionStrings["WorkFlow"].ConnectionString;
var builder = new WorkflowBuilder<XElement>(
new MSSQLProvider(connectionString),
new MSSQLProvider(connectionString),
new OptimaJet.Workflow.Core.Parser.XmlWorkflowParser(),
new MSSQLProvider(connectionString)
).WithDefaultCache();
@ -35,7 +36,7 @@ namespace OpenAuth.Mvc.Models
_runtime = new WorkflowRuntime(new Guid("{8D38DB8F-F3D5-4F26-A989-4FDD40F32D9D}"))
.WithBuilder(builder)
.WithRuleProvider(new WorkflowRuleProvider())
// .WithActionProvider(new WorkflowActionProvider())
.WithActionProvider(new WorkflowActionProvider())
.WithPersistenceProvider(new MSSQLProvider(connectionString))
.WithTimerManager(new TimerManager())
.WithBus(new NullBus())
@ -58,12 +59,51 @@ namespace OpenAuth.Mvc.Models
if (string.IsNullOrEmpty(e.SchemeCode))
return;
//创建流程状态转换记录
WorkflowActionProvider.DeleteEmptyPreHistory(e.ProcessId);
_runtime.PreExecuteFromCurrentActivity(e.ProcessId);
//更新通知列表
UpdateInbox(e);
//¸ü¸ÄÉêÇëµÄ״̬
UpdateApplyState(e);
}
/// <summary>
/// 更新申请状态
/// </summary>
private static void UpdateApplyState(ProcessStatusChangedEventArgs e)
{
var nextState = WorkflowInit.Runtime.GetLocalizedStateName(e.ProcessId, e.ProcessInstance.CurrentState);
var _app = AutofacExt.GetFromFac<GoodsApplyApp>();
_app.ChangeState(e.ProcessId, e.ProcessInstance.CurrentState, nextState);
}
/// <summary>
/// 更新通知列表
/// </summary>
private static void UpdateInbox(ProcessStatusChangedEventArgs e)
{
var inboxApp = AutofacExt.GetFromFac<WorkflowInboxApp>();
inboxApp.DeleteAllByProcess(e.ProcessId);
if (e.NewStatus != ProcessStatus.Finalized)
{
var newActors = Runtime.GetAllActorsForDirectCommandTransitions(e.ProcessId);
foreach (var newActor in newActors)
{
var newInboxItem = new WorkflowInbox()
{
Id = Guid.NewGuid(),
IdentityId = new Guid(newActor),
ProcessId = e.ProcessId
};
inboxApp.Add(newInboxItem);
}
}
}
}
}

View File

@ -57,7 +57,15 @@ namespace OpenAuth.Mvc.Models
public IEnumerable<string> GetIdentities(ProcessInstance processInstance, WorkflowRuntime runtime, string ruleName, string parameter)
{
throw new NotImplementedException();
var userids = _app.GetUsersInRole(ruleName);
if (userids == null) return null;
var userstrs = new List<string>();
foreach (var userid in userids)
{
userstrs.Add(userid.ToString());
}
return userstrs;
}
}
}

View File

@ -18,7 +18,7 @@
<tr>
<td></td>
<td>
<a href='javascript:DownloadScheme()'>Download scheme workflow</a>
<a href='javascript:DownloadScheme()'>下载流程模板</a>
</td>
</tr>
<tr>
@ -26,21 +26,21 @@
<input type="file" name="uploadFile" id="uploadFile" style="width:350px">
</td>
<td>
<a href='javascript:UploadScheme()'>Upload scheme workflow</a>
<a href='javascript:UploadScheme()'>上传流程模板</a>
</td>
</tr>
</table>
</form>
<table>
<tr>
<td>Size:</td>
<td>大小:</td>
<td><input id="graphwidth" value="1200" /> x <input id="graphheight" value="600" /></td>
<td><button onclick="wfdesignerRedraw()">Resize</button></td>
<td><button onclick="wfdesignerRedraw()">缩放</button></td>
<td>
|
</td>
<td><button onclick="OnNew()">New</button></td>
<td><button onclick="OnSave()">Save</button></td>
<td><button onclick="OnNew()">新建</button></td>
<td><button onclick="OnSave()">保存</button></td>
</tr>
</table>

View File

@ -1,6 +1,7 @@
@{
Layout = null;
}
@using OptimaJet.Workflow.Core.Model
@model OpenAuth.App.ViewModel.GoodsApplyVM
<script src="/Scripts/jquery-ui.js"></script>
@ -11,18 +12,39 @@
<script src="/Scripts/ace.js"></script>
<script src="/Scripts/json5.js"></script>
<div class="bjui-pageContent">
<input value="@Model.Id" id="processId" class="hidden"/>
<span class="h1">@Model.Name</span>
<span class="alert-info">数量:@Model.Number</span>
<span class="label label-default">你可以:</span>
@foreach (var cmd in Model.Commands)
{
<button type="button" class="btn btn-default btn-cmd" value="@cmd.Key">@cmd.Value</button>
}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<input value="@Model.Id" id="processId" class="hidden" />
<h3 class="panel-title">
@Model.Name
</h3>
</div>
@if (Model.Commands.Length > 0)
{
<div class="panel-body">
<span class="label label-default">你可以执行:</span>
@foreach (var cmd in Model.Commands)
{
if (cmd.Classifier == TransitionClassifier.Reverse)
{
<button type="button" class="btn btn-danger btn-cmd" value="@cmd.Key">@cmd.Value</button>
}
else
{
<button type="button" class="btn btn-primary btn-cmd" value="@cmd.Key">@cmd.Value</button>
}
}
</div>
}
<div class="panel-body">
<div id="wfdesigner"></div>
</div>
</div>
</div>
</div>
<br/>
<div id="wfdesigner"></div>
</div>
<script src="/BllScripts/queryString.js"></script>
<script src="/BllScripts/processDetail.js"></script>

View File

@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a CodeSmith Template.
//
// DO NOT MODIFY contents of this file. Changes to this
// file will be lost if the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
using System.ComponentModel.DataAnnotations.Schema;
using OpenAuth.Domain;
namespace OpenAuth.Repository.Models.Mapping
{
public partial class ApplyTransitionHistoryMap
: System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<ApplyTransitionHistory>
{
public ApplyTransitionHistoryMap()
{
// table
ToTable("ApplyTransitionHistory", "dbo");
// keys
HasKey(t => t.Id);
// Properties
Property(t => t.Id)
.HasColumnName("Id")
.IsRequired();
Property(t => t.ApplyId)
.HasColumnName("ApplyId")
.IsRequired();
Property(t => t.UserId)
.HasColumnName("UserId")
.IsOptional();
Property(t => t.AllowedToUserNames)
.HasColumnName("AllowedToUserNames")
.IsRequired();
Property(t => t.TransitionTime)
.HasColumnName("TransitionTime")
.IsOptional();
Property(t => t.Order)
.HasColumnName("Order")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(t => t.InitialState)
.HasColumnName("InitialState")
.HasMaxLength(1024)
.IsRequired();
Property(t => t.DestinationState)
.HasColumnName("DestinationState")
.HasMaxLength(1024)
.IsRequired();
Property(t => t.Command)
.HasColumnName("Command")
.HasMaxLength(1024)
.IsRequired();
// Relationships
}
}
}

View File

@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a CodeSmith Template.
//
// DO NOT MODIFY contents of this file. Changes to this
// file will be lost if the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
using OpenAuth.Domain;
namespace OpenAuth.Repository.Models.Mapping
{
public partial class WorkflowInboxMap
: System.Data.Entity.ModelConfiguration.EntityTypeConfiguration<WorkflowInbox>
{
public WorkflowInboxMap()
{
// table
ToTable("WorkflowInbox", "dbo");
// keys
HasKey(t => t.Id);
// Properties
Property(t => t.Id)
.HasColumnName("Id")
.IsRequired();
Property(t => t.ProcessId)
.HasColumnName("ProcessId")
.IsRequired();
Property(t => t.IdentityId)
.HasColumnName("IdentityId")
.IsRequired();
// Relationships
}
}
}

View File

@ -11,7 +11,6 @@ using System.Data.Entity;
using OpenAuth.Domain;
using OpenAuth.Repository.Models.Mapping;
namespace OpenAuth.Repository.Models
{
public partial class OpenAuthDBContext: DbContext
@ -40,6 +39,9 @@ namespace OpenAuth.Repository.Models
public System.Data.Entity.DbSet<Role> Roles { get; set; }
public System.Data.Entity.DbSet<Stock> Stocks { get; set; }
public System.Data.Entity.DbSet<User> Users { get; set; }
public System.Data.Entity.DbSet<WorkflowInbox> WorkflowInboxes { get; set; }
public DbSet<ApplyTransitionHistory> ApplyTransitionHistories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
@ -55,6 +57,9 @@ namespace OpenAuth.Repository.Models
modelBuilder.Configurations.Add(new RoleMap());
modelBuilder.Configurations.Add(new StockMap());
modelBuilder.Configurations.Add(new UserMap());
modelBuilder.Configurations.Add(new WorkflowInboxMap());
modelBuilder.Configurations.Add(new ApplyTransitionHistoryMap());
}
}
}

View File

@ -55,7 +55,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Models\Mapping\ApplyTransitionHistoryMap.cs" />
<Compile Include="Models\Mapping\GoodsApplyMap.cs" />
<Compile Include="Models\Mapping\WorkflowInboxMap.cs" />
<Compile Include="UnitWork.cs" />
<Compile Include="BaseRepository.cs" />
<Compile Include="Models\Mapping\CategoryMap.cs" />