feat(ClientBlack): 新增客户黑名单审批流程

- 黑名单新增、删除、批量导入、批量移出在配置审批节点后,审批通过才生效
- 新增黑名单待提交后可提交审批;仅首节点未审批时可撤回,进入后续节点禁止撤回
- 增加黑名单审批列表、审批弹窗、审批操作日志及状态筛选
- 支持审批配置中的“黑名单审批”流程及对应菜单、模块权限、操作权限
- 黑名单审批中禁止同名记录覆盖备注;已在黑名单中的同名导入会明确提示本次将修改备注
- 未配置审批节点时保持原有直接生效行为
- 增加黑名单审批状态机单测,39/39 通过
- 修正撤回全部失败时仍提示“撤回审批成功”的问题
This commit is contained in:
tengyufan
2026-08-13 17:21:04 +08:00
parent 9df39491da
commit 8afd449c40
26 changed files with 1090 additions and 106 deletions
@@ -0,0 +1,32 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace YLErp.DBModels
{
/// <summary>
/// 客户黑名单审批及操作日志。
/// </summary>
[Table("client_blacklog")]
public class ClientBlackLog
{
public long id { get; set; }
public int ClientBlackId { get; set; }
public string Changes { get; set; }
public string OptType { get; set; }
public string DataType { get; set; }
public int OptId { get; set; }
public string OptName { get; set; }
public DateTime OptDate { get; set; }
}
[NotMapped]
public class ClientBlackLogDto : ClientBlackLog
{
}
}
@@ -10,6 +10,13 @@ namespace YLErp.Model
[Table("client_black")]
public class client_black : DBModelWithOperator, IDataEntity, IDataTraceV2, IClonable<client_black>
{
public const string = "未提交";
public const string = "新增审批中";
public const string = "新增已拒绝";
public const string = "已加入";
public const string = "删除审批中";
public const string = "删除已拒绝";
/// <summary>
/// 客户名称
/// </summary>
@@ -25,6 +32,26 @@ namespace YLErp.Model
[DataChange]
public string Remarks { get; set; }
[DisplayName("提交审批时间")]
public DateTime? ApprovalOptDate { get; set; }
[DisplayName("提交审批人")]
public string ApprovalOptName { get; set; }
public int ApprovalProcess { get; set; }
[DisplayName("状态")]
public string State { get; set; } = "";
[DisplayName("创建人")]
public int? creator_id { get; set; }
[DisplayName("创建人")]
public string creator_name { get; set; }
[DisplayName("创建时间")]
public DateTime? creator_time { get; set; }
public client_black Clone()
{
return (client_black)MemberwiseClone();
@@ -0,0 +1,121 @@
using YLErp.Model;
namespace YLErp.Modules.ClientModule.Tests
{
[TestClass]
public class ClientBlackApprovalPolicyTests
{
[DataTestMethod]
[DataRow(client_black.未提交, false)]
[DataRow(client_black.新增审批中, false)]
[DataRow(client_black.新增已拒绝, false)]
[DataRow(client_black.已加入, true)]
[DataRow(client_black.删除审批中, true)]
[DataRow(client_black.删除已拒绝, true)]
public void IsEffective_OnlyAppliedOrPendingRemovalStatesAreEffective(string state, bool expected)
{
Assert.AreEqual(expected, ClientBlackApprovalPolicy.IsEffective(state));
}
[DataTestMethod]
[DataRow(client_black.未提交, true)]
[DataRow(client_black.新增已拒绝, true)]
[DataRow(client_black.新增审批中, false)]
[DataRow(client_black.已加入, false)]
[DataRow(client_black.删除审批中, false)]
[DataRow(client_black.删除已拒绝, false)]
public void CanSubmitAddition_OnlyDraftOrRejectedAdditionCanSubmit(string state, bool expected)
{
Assert.AreEqual(expected, ClientBlackApprovalPolicy.CanSubmitAddition(state));
}
[DataTestMethod]
[DataRow(client_black.已加入, true)]
[DataRow(client_black.删除已拒绝, true)]
[DataRow(client_black.未提交, false)]
[DataRow(client_black.新增审批中, false)]
[DataRow(client_black.新增已拒绝, false)]
[DataRow(client_black.删除审批中, false)]
public void CanRequestRemoval_OnlyEffectiveNonPendingRemovalStatesCanRequest(string state, bool expected)
{
Assert.AreEqual(expected, ClientBlackApprovalPolicy.CanRequestRemoval(state));
}
[DataTestMethod]
[DataRow(client_black.新增审批中, 1, true)]
[DataRow(client_black.删除审批中, 1, true)]
[DataRow(client_black.新增审批中, 2, false)]
[DataRow(client_black.删除审批中, 2, false)]
[DataRow(client_black.未提交, 0, false)]
public void CanWithdraw_OnlyFirstApprovalNodeCanWithdraw(string state, int approvalProcess, bool expected)
{
Assert.AreEqual(expected, ClientBlackApprovalPolicy.CanWithdraw(state, approvalProcess));
}
[DataTestMethod]
[DataRow(client_black.新增审批中, client_black.新增已拒绝)]
[DataRow(client_black.删除审批中, client_black.删除已拒绝)]
public void RejectedState_DistinguishesAdditionAndRemoval(string state, string expected)
{
Assert.AreEqual(expected, ClientBlackApprovalPolicy.GetRejectedState(state));
}
[DataTestMethod]
[DataRow(client_black.新增审批中, client_black.未提交, 0)]
[DataRow(client_black.删除审批中, client_black.已加入, -2)]
public void WithdrawState_RestoresStateBeforeSubmission(string state, string expectedState, int expectedProcess)
{
var result = ClientBlackApprovalPolicy.GetWithdrawResult(state);
Assert.AreEqual(expectedState, result.State);
Assert.AreEqual(expectedProcess, result.ApprovalProcess);
}
[DataTestMethod]
[DataRow(client_black.新增审批中, client_black.已加入, false)]
[DataRow(client_black.删除审批中, null, true)]
public void GetFinalResult_AdditionAppliesAndRemovalDeletes(string state, string expectedState, bool expectedDelete)
{
var result = ClientBlackApprovalPolicy.GetFinalResult(state);
Assert.AreEqual(expectedState, result.State);
Assert.AreEqual(expectedDelete, result.ShouldDelete);
}
[DataTestMethod]
[DataRow(false, client_black.已加入, -2, true)]
[DataRow(true, client_black.未提交, 0, false)]
public void GetAdditionResult_OnlyEffectiveWithoutApprovalProcess(bool hasApprovalProcess, string expectedState, int expectedProcess, bool expectedEffective)
{
var result = ClientBlackApprovalPolicy.GetAdditionResult(hasApprovalProcess);
Assert.AreEqual(expectedState, result.State);
Assert.AreEqual(expectedProcess, result.ApprovalProcess);
Assert.AreEqual(expectedEffective, result.IsEffective);
}
[DataTestMethod]
[DataRow(false, client_black.已加入, -2, true)]
[DataRow(true, client_black.删除审批中, 1, false)]
public void GetRemovalResult_OnlyDeletesImmediatelyWithoutApprovalProcess(bool hasApprovalProcess, string expectedState, int expectedProcess, bool expectedDelete)
{
var result = ClientBlackApprovalPolicy.GetRemovalResult(hasApprovalProcess);
Assert.AreEqual(expectedState, result.State);
Assert.AreEqual(expectedProcess, result.ApprovalProcess);
Assert.AreEqual(expectedDelete, result.ShouldDelete);
}
[DataTestMethod]
[DataRow(client_black.未提交, true)]
[DataRow(client_black.新增已拒绝, true)]
[DataRow(client_black.新增审批中, false)]
[DataRow(client_black.删除审批中, false)]
[DataRow(client_black.已加入, true)]
[DataRow(client_black.删除已拒绝, true)]
public void CanReplaceRemarks_ApprovalPendingRowsCannotBeOverwritten(string state, bool expected)
{
Assert.AreEqual(expected, ClientBlackApprovalPolicy.CanReplaceRemarks(state));
}
}
}
+3 -1
View File
@@ -19,6 +19,8 @@ namespace BaseOUDAL
public DbSet<client_black> client_black { get; set; }
public DbSet<ClientBlackLog> client_blacklog { get; set; }
public DbSet<client_file> client_file { get; set; }
public DbSet<client_file_audit> client_file_audit { get; set; }
@@ -57,4 +59,4 @@ namespace BaseOUDAL
public DbSet<ClientCustomerManage> client_customer_manage { get; set; }
}
}
}
@@ -0,0 +1,20 @@
namespace YLErp.Model
{
public class ClientBlackApprovalQueryRes
{
public int id { get; set; }
public string EncryptId { get; set; }
public string ProcessStatus { get; set; }
public int ProcessOrderId { get; set; }
public string ProcessRoleName { get; set; }
public string ClientName { get; set; }
public int ProcessRoleId { get; set; }
public string Comments { get; set; }
public string ApprovalOptName { get; set; }
public DateTime? ApprovalOptDate { get; set; }
public string State { get; set; }
public int? creator_id { get; set; }
public string creator_name { get; set; }
public DateTime? creator_time { get; set; }
}
}
+18
View File
@@ -0,0 +1,18 @@
using YLErp.Helpers;
namespace YLErp.Model
{
/// <summary>
/// 黑名单审批请求。
/// </summary>
public class ClientBlackAuditReq
{
public string enid { get; set; }
public int id => DataProtectHelper.DecryptInt(enid);
public string status { get; set; }
public string auditComment { get; set; }
}
}
+6
View File
@@ -14,6 +14,12 @@ namespace YLErp.Model
/// </summary>
public string Name { get; set; }
public DateTime? DateFromOptDate { get; set; }
public DateTime? DateToOptDate { get; set; }
public string ClientBlackStates { get; set; }
}
}
@@ -0,0 +1,89 @@
using YLErp.Model;
namespace YLErp.Modules.ClientModule
{
public static class ClientBlackApprovalPolicy
{
public static readonly string[] EffectiveStates =
{
client_black.,
client_black.,
client_black.
};
public static bool IsEffective(string state)
{
return EffectiveStates.Contains(state);
}
public static bool CanSubmitAddition(string state)
{
return state == client_black. || state == client_black.;
}
public static ClientBlackAdditionResult GetAdditionResult(bool hasApprovalProcess)
{
return hasApprovalProcess
? new ClientBlackAdditionResult(client_black., 0, false)
: new ClientBlackAdditionResult(client_black., -2, true);
}
public static bool CanRequestRemoval(string state)
{
return state == client_black. || state == client_black.;
}
public static ClientBlackRemovalResult GetRemovalResult(bool hasApprovalProcess)
{
return hasApprovalProcess
? new ClientBlackRemovalResult(client_black., 1, false)
: new ClientBlackRemovalResult(client_black., -2, true);
}
public static bool CanReplaceRemarks(string state)
{
return state != client_black. && state != client_black.;
}
public static bool CanWithdraw(string state, int approvalProcess)
{
return approvalProcess == 1 &&
(state == client_black. || state == client_black.);
}
public static string GetRejectedState(string state)
{
return state switch
{
client_black. => client_black.,
client_black. => client_black.,
_ => throw new ArgumentException("当前状态不允许拒绝审批", nameof(state))
};
}
public static ClientBlackWithdrawResult GetWithdrawResult(string state)
{
return state switch
{
client_black. => new ClientBlackWithdrawResult(client_black., 0),
client_black. => new ClientBlackWithdrawResult(client_black., -2),
_ => throw new ArgumentException("当前状态不允许撤回审批", nameof(state))
};
}
public static ClientBlackFinalResult GetFinalResult(string state)
{
return state switch
{
client_black. => new ClientBlackFinalResult(client_black., false),
client_black. => new ClientBlackFinalResult(null, true),
_ => throw new ArgumentException("当前状态不允许完成审批", nameof(state))
};
}
}
public readonly record struct ClientBlackWithdrawResult(string State, int ApprovalProcess);
public readonly record struct ClientBlackFinalResult(string State, bool ShouldDelete);
public readonly record struct ClientBlackAdditionResult(string State, int ApprovalProcess, bool IsEffective);
public readonly record struct ClientBlackRemovalResult(string State, int ApprovalProcess, bool ShouldDelete);
}
@@ -41,6 +41,19 @@ namespace YLErp.Modules.ClientModule
{
predicate = predicate.And(d => d.Name.Contains(req.Name));
}
if (!string.IsNullOrEmpty(req.ClientBlackStates))
{
var states = req.ClientBlackStates.Split(',', StringSplitOptions.RemoveEmptyEntries);
predicate = predicate.And(d => states.Contains(d.State));
}
if (req.DateFromOptDate.HasValue)
{
predicate = predicate.And(d => d.OptDate >= req.DateFromOptDate.Value);
}
if (req.DateToOptDate.HasValue)
{
predicate = predicate.And(d => d.OptDate < req.DateToOptDate.Value.AddDays(1));
}
}
var query = DbContext.client_black.AsNoTracking().Where(predicate);
@@ -93,6 +106,314 @@ namespace YLErp.Modules.ClientModule
return retListResult;
}
public List<approvalprocess> ProcessList()
{
return DbContextFactory.GetYLDbContext().approvalprocess
.Where(s => s.processType == "ClientBlackProcess")
.OrderBy(s => s.order)
.ToList();
}
public void DeleteClientBlack(IEnumerable<int> ids)
{
var idList = ids?.Distinct().ToList() ?? new List<int>();
if (idList.Count == 0)
{
throw new ServiceException("请选择要移出的黑名单客户");
}
var rows = DbContext.client_black.Where(x => idList.Contains(x.id)).ToList();
if (rows.Count != idList.Count)
{
throw new ServiceException("未找到要删除的数据");
}
var hasProcess = ProcessList().Any();
foreach (var row in rows)
{
if (!ClientBlackApprovalPolicy.CanRequestRemoval(row.State))
{
throw new ServiceException($"黑名单客户{row.Name}当前状态不允许移出");
}
if (hasProcess)
{
var result = ClientBlackApprovalPolicy.GetRemovalResult(true);
row.State = result.State;
row.ApprovalProcess = result.ApprovalProcess;
row.ApprovalOptName = UserName;
row.ApprovalOptDate = DateTime.Now;
ClientBlackCategoryLog(row.id, client_black.);
}
else
{
RemoveEffectiveBlack(row);
}
}
DbContext.SaveChanges();
}
public void WithdrawApprovalClientBlack(List<int> ids, out int withdrawCount, out string msg)
{
withdrawCount = 0;
msg = "";
var rows = DbContext.client_black.Where(x => ids.Contains(x.id)).ToList();
foreach (var row in rows)
{
if (!ClientBlackApprovalPolicy.CanWithdraw(row.State, row.ApprovalProcess))
{
if (row.ApprovalProcess > 1)
{
msg += row.Name + ",";
}
continue;
}
var result = ClientBlackApprovalPolicy.GetWithdrawResult(row.State);
row.State = result.State;
row.ApprovalProcess = result.ApprovalProcess;
row.ApprovalOptName = null;
row.ApprovalOptDate = null;
ClientBlackCategoryLog(row.id, row.State);
withdrawCount++;
}
DbContext.SaveChanges();
}
public void SubmitApprovalClientBlack(List<int> ids)
{
var rows = DbContext.client_black.Where(x => ids.Contains(x.id)).ToList();
var process = ProcessList();
foreach (var row in rows)
{
if (!ClientBlackApprovalPolicy.CanSubmitAddition(row.State))
{
continue;
}
if (process.Count == 0)
{
row.State = client_black.;
row.ApprovalProcess = -2;
row.ApprovalOptName = UserName;
row.ApprovalOptDate = DateTime.Now;
var notifications = new List<(Client oldClient, Client newClient)>();
ApplyEffectiveAddition(row.Name, notifications);
ClientBlackCategoryLog(row.id, client_black., "未设置审批流程,直接通过");
DbContext.SaveChanges();
SendClientNotifications(notifications);
continue;
}
row.State = client_black.;
row.ApprovalProcess = 1;
row.ApprovalOptName = UserName;
row.ApprovalOptDate = DateTime.Now;
ClientBlackCategoryLog(row.id, client_black.);
}
DbContext.SaveChanges();
}
public string AuditClientBlack(ClientBlackAuditReq req, bool isBatch = false, string optType = "")
{
var row = DbContext.client_black.Find(req.id);
if (row == null)
{
throw new ServiceException("审批失败,系统中没有该黑名单记录");
}
if (row.State != client_black. && row.State != client_black.)
{
throw new ServiceException("当前黑名单不在审批中");
}
var process = ProcessList();
var currentNode = process.FirstOrDefault(x => x.order == row.ApprovalProcess);
if (currentNode == null || !UserBLL.GetRolesByUserId(UserId).Any(x => x.Id == currentNode.roleId))
{
throw new ServiceException("当前用户无权审批该节点");
}
if (req.status == "reject")
{
row.State = ClientBlackApprovalPolicy.GetRejectedState(row.State);
row.ApprovalProcess = -1;
row.ApprovalOptDate = DateTime.Now;
row.OptId = UserId;
row.OptName = UserName;
row.OptDate = DateTime.Now;
ClientBlackCategoryLog(row.id, row.State, req.auditComment);
DbContext.SaveChanges();
return "提交成功";
}
if (req.status != "pass")
{
throw new ServiceException("status参数不支持:" + req.status);
}
var nextNode = process.FirstOrDefault(x => x.order > row.ApprovalProcess);
if (nextNode != null)
{
row.ApprovalProcess = nextNode.order;
row.ApprovalOptDate = DateTime.Now;
row.OptId = UserId;
row.OptName = UserName;
row.OptDate = DateTime.Now;
ClientBlackCategoryLog(row.id, row.State, req.auditComment);
DbContext.SaveChanges();
return "提交成功";
}
var final = ClientBlackApprovalPolicy.GetFinalResult(row.State);
if (final.ShouldDelete)
{
RemoveEffectiveBlack(row, req.auditComment, isBatch ? optType : null);
DbContext.SaveChanges();
}
else
{
row.State = final.State;
row.ApprovalProcess = -2;
row.ApprovalOptDate = DateTime.Now;
var notifications = new List<(Client oldClient, Client newClient)>();
ApplyEffectiveAddition(row.Name, notifications);
ClientBlackCategoryLog(row.id, isBatch ? optType : row.State, req.auditComment);
DbContext.SaveChanges();
SendClientNotifications(notifications);
}
return "提交成功";
}
public SearchListResult<ClientBlackApprovalQueryRes> ClientBlackApprovalQuery(ClientBlackReq req)
{
var process = ProcessList();
var predicate = PredicateBuilder.Create<client_black>(x => x.ApprovalProcess > 0);
if (!string.IsNullOrWhiteSpace(req.Name))
{
predicate = predicate.And(x => x.Name.Contains(req.Name));
}
var query = from row in DbContext.client_black.AsNoTracking().Where(predicate)
select new ClientBlackApprovalQueryRes
{
id = row.id,
EncryptId = row.EncryptId,
ProcessOrderId = row.ApprovalProcess,
ProcessRoleId = 0,
ProcessStatus = "审批中 流程" + (row.ApprovalProcess - 1) + "/" + process.Count,
State = row.State,
ClientName = row.Name,
Comments = row.Remarks,
ApprovalOptName = row.ApprovalOptName,
ApprovalOptDate = row.ApprovalOptDate,
creator_id = row.creator_id,
creator_name = row.creator_name,
creator_time = row.creator_time
};
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "ApprovalOptDate";
req.sord = "desc";
}
var result = query.OrderByDescending(x => x.ApprovalOptDate).ToSearchList(req);
var roles = new ErpBaseContext().Roles
.Select(x => new { x.Id, x.Name })
.ToDictionary(x => x.Id, x => x.Name);
foreach (var item in result.rows)
{
var node = process.FirstOrDefault(x => x.order == item.ProcessOrderId);
if (node == null)
{
continue;
}
item.ProcessRoleId = node.roleId;
item.ProcessRoleName = roles.TryGetValue(node.roleId, out var roleName) ? roleName : string.Empty;
}
return result;
}
private void ApplyEffectiveAddition(string name, List<(Client oldClient, Client newClient)> notifications)
{
var client = DbContext.client.FirstOrDefault(c => c.Name == name);
if (client == null)
{
return;
}
var dt = DateTime.Now;
var oldClient = client.Clone();
if (client.ProcessStatus == "已开户")
{
client.ProcessOrderId = -4;
client.ProcessStatus = "已休眠";
client.OptId = UserId;
client.OptName = UserName;
client.OptDate = dt;
DbContext.ClientAuditLog.Add(new ClientAuditLog
{
ClientId = client.id,
OptType = "休眠",
Changes = string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = dt
});
notifications.Add((oldClient, client));
}
DbContext.ClientAuditLog.Add(new ClientAuditLog
{
ClientId = client.id,
OptType = "加入黑名单",
Changes = string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = dt
});
}
private void RemoveEffectiveBlack(client_black row, string changes = null, string optType = null)
{
var client = DbContext.client.FirstOrDefault(c => c.Name == row.Name);
if (client != null)
{
DbContext.ClientAuditLog.Add(new ClientAuditLog
{
ClientId = client.id,
OptType = "移除黑名单",
Changes = string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
});
}
DbContext.client_black.Remove(row);
ClientBlackCategoryLog(row.id, optType ?? "已删除", changes);
}
private void SendClientNotifications(List<(Client oldClient, Client newClient)> notifications)
{
foreach (var (oldClient, newClient) in notifications)
{
new ClientKafkaService(_kafkaProduce).Send(newClient, oldClient);
}
}
public void ClientBlackCategoryLog(int clientblackId, string optType, string changes = null)
{
DbContext.client_blacklog.Add(new ClientBlackLog
{
ClientBlackId = clientblackId,
OptType = optType,
Changes = changes,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
});
}
/// <summary>
/// 客户黑名单导入
/// </summary>
@@ -165,37 +486,47 @@ namespace YLErp.Modules.ClientModule
public void AddClientBlack(IEnumerable<client_black> list, bool checkStatus)
{
var inputList = list?.ToList() ?? new List<client_black>();
var errMsgList = new List<string>();
var nameList = list.Select(O => O.Name);
var dbList = DbContext.client_black.Where(O => nameList.Contains(O.Name));
var nameList = inputList.Select(O => O.Name).ToList();
var dbList = DbContext.client_black.Where(O => nameList.Contains(O.Name)).ToList();
foreach (var item in dbList)
{
var obj = inputList.FirstOrDefault(O => O.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase));
if (obj == null)
{
continue;
}
if (!ClientBlackApprovalPolicy.CanReplaceRemarks(item.State))
{
throw new ServiceException("黑名单客户在审批中无法修改!");
}
if (checkStatus && !string.IsNullOrWhiteSpace(item.Remarks) && item.Remarks != obj.Remarks)
{
errMsgList.Add($"{item.Name}");
}
}
if (checkStatus)
{
foreach (var item in dbList)
{
var obj = list.First(O => O.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrWhiteSpace(item.Remarks) && item.Remarks != obj.Remarks)
{
errMsgList.Add($"{item.Name}");
continue;
}
}
if (errMsgList.Count > 0)
{
var msg = "";
if (errMsgList.Count <= 5)
{
msg = $"客户:{string.Join(",", errMsgList)},备注已存在,是否替换?";
msg = $"客户:{string.Join(",", errMsgList)}当前已在黑名单中,本次将修改备注,备注已存在是否确认?";
}
else
{
msg = $"{string.Join(",", errMsgList.Take(5))} 等{errMsgList.Count}个客户,备注已存在,是否替换?";
msg = $"{string.Join(",", errMsgList.Take(5))} 等{errMsgList.Count}个客户当前已在黑名单中,本次将修改备注,备注已存在是否确认?";
}
throw new ServiceException(msg);
}
}
// 在外部定义列表来保存需要通知的客户对
var clientsToNotify = new List<(Client oldClient, Client newClient)>();
foreach (var item in list)
var newItems = new List<client_black>();
var processList = ProcessList();
foreach (var item in inputList)
{
if (string.IsNullOrWhiteSpace(item.Name))
{
@@ -206,61 +537,45 @@ namespace YLErp.Modules.ClientModule
item.OptId = UserId;
item.OptName = UserName;
item.OptDate = DateTime.Now;
var clientexistence = DbContext.client.FirstOrDefault(c => c.Name == item.Name);
if (clientexistence != null)
var existing = dbList.FirstOrDefault(x => x.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase));
if (existing != null)
{
var dt = DateTime.Now;
if (clientexistence.ProcessStatus == "已开户")
var oldRemarks = existing.Remarks;
existing.Remarks = item.Remarks;
existing.OptId = UserId;
existing.OptName = UserName;
existing.OptDate = DateTime.Now;
if (oldRemarks != existing.Remarks)
{
var oldClient= clientexistence.Clone();
clientexistence.ProcessOrderId = -4;
clientexistence.ProcessStatus = "已休眠";
clientexistence.OptId = UserId;
clientexistence.OptName = UserName;
clientexistence.OptDate = dt;
DbContext.ClientAuditLog.Add(new ClientAuditLog
{
ClientId = clientexistence.id,
OptType = "休眠",
Changes = string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = dt
});
// 如果原有状态是已开户,添加到通知列表
if (oldClient != null)
{
clientsToNotify.Add((oldClient, clientexistence));
}
ClientBlackCategoryLog(existing.id, "修改备注", $"备注:{oldRemarks ?? string.Empty} -> {existing.Remarks ?? string.Empty}");
}
///日志记录
DbContext.ClientAuditLog.Add(new ClientAuditLog
{
ClientId = clientexistence.id,
OptType = "加入黑名单",
Changes = string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = dt
});
continue;
}
var additionResult = ClientBlackApprovalPolicy.GetAdditionResult(processList.Any());
item.State = additionResult.State;
item.ApprovalProcess = additionResult.ApprovalProcess;
item.creator_id = UserId;
item.creator_name = UserName;
item.creator_time = DateTime.Now;
if (additionResult.IsEffective)
{
ApplyEffectiveAddition(item.Name, clientsToNotify);
}
newItems.Add(item);
}
if (dbList.Any())
DbContext.client_black.AddRange(newItems);
DbContext.SaveChanges();
foreach (var item in newItems)
{
DbContext.client_black.RemoveRange(dbList);
DbContext.SaveChanges();
ClientBlackCategoryLog(item.id, item.State);
}
DbContext.client_black.AddRange(list);
DbContext.SaveChanges();
// 发送Kafka消息
foreach (var (oldClient, newClient) in clientsToNotify)
{
new ClientKafkaService(_kafkaProduce).Send(newClient, oldClient);
}
var importHasTagClientNames = list.Where(p => p.Tags != null && p.Tags.Count > 0).Select(p => p.Name).Distinct().ToList();
var importHasTagClientNames = inputList.Where(p => p.Tags != null && p.Tags.Count > 0).Select(p => p.Name).Distinct().ToList();
if (importHasTagClientNames != null && importHasTagClientNames.Count > 0)
{
var dbClients = DbContext.client.AsNoTracking().Where(p => importHasTagClientNames.Contains(p.Name)).Select(p => new ClientSimpleDto
@@ -273,7 +588,7 @@ namespace YLErp.Modules.ClientModule
var tagService = new TagService(OptUser);
dbClients.ForEach(p =>
{
var importInfo = list.FirstOrDefault(d => d.Name.Equals(p.Name));
var importInfo = inputList.FirstOrDefault(d => d.Name.Equals(p.Name));
if (importInfo != null)
{
tagService.SetClientTagForClientImport(new TagModule.Dto.SetClientTagForClientEditRequest { ClientId = p.id, Tags = importInfo.Tags });
@@ -317,7 +317,7 @@ namespace YLErp.Modules.ClientModule
{
return "第" + rowNum + "行客户类别,机构属性,客户性质关联性质有误,导入失败";
}
if (DbContext.client_black.Any(c => c.Name == Name))
if (DbContext.client_black.Any(c => c.Name == Name && ClientBlackApprovalPolicy.EffectiveStates.Contains(c.State)))
{
return $"客户'{Name}'已经存在于黑名单中”";
}
@@ -1070,7 +1070,7 @@ namespace YLErp.Modules.ClientModule
}
}
}
if (DbContext.client_black.Any(c => c.Name == Name))
if (DbContext.client_black.Any(c => c.Name == Name && ClientBlackApprovalPolicy.EffectiveStates.Contains(c.State)))
{
return "" + Name + "客户已经存在于黑名单中”";
}
@@ -1733,7 +1733,7 @@ namespace YLErp.Modules.ClientModule
//默认为1
IsReceiveEmail = 1;
if (DbContext.client_black.Any(c => c.Name == Name))
if (DbContext.client_black.Any(c => c.Name == Name && ClientBlackApprovalPolicy.EffectiveStates.Contains(c.State)))
{
return "" + Name + "客户已经存在于黑名单中";
}
@@ -130,7 +130,7 @@ namespace YLErp.Modules.ClientModule
try
{
if (DbContext.client_black.Any(c => c.Name == client.Name))
if (DbContext.client_black.Any(c => c.Name == client.Name && ClientBlackApprovalPolicy.EffectiveStates.Contains(c.State)))
{
client.RejectOrderId = client.ApprovalOrderId;
client.ApprovalOrderId = -1;
@@ -158,7 +158,7 @@ namespace YLErp.Modules.ClientModule
throw new ServiceException("客户名称 必须填写");
}
if (DbContext.client_black.Any(c => c.Name == req.Name))
if (DbContext.client_black.Any(c => c.Name == req.Name && ClientBlackApprovalPolicy.EffectiveStates.Contains(c.State)))
{
throw new ServiceException("该客户为黑名单客户,无法进行下一步操作");
}
@@ -703,7 +703,7 @@ namespace YLErp.Modules.ClientModule
//新增时,新的客户名如果在黑名单里,不允许新增
//修改时,旧的客户名如果在黑名单里,不允许修改
if (!isAddNew && !req.Name.Equals(blackNameForCheck) && DbContext.client_black.Any(x => x.Name == blackNameForCheck))
if (!isAddNew && !req.Name.Equals(blackNameForCheck) && DbContext.client_black.Any(x => x.Name == blackNameForCheck && ClientBlackApprovalPolicy.EffectiveStates.Contains(x.State)))
{
throw new ServiceException("该客户为黑名单客户," + (req.id > 0 ? "不允许修改客户名称" : "不允许新增"));
}
@@ -7,6 +7,7 @@ using System.Linq.Expressions;
using YLErp.BLL.Eod;
using YLErp.DBModels;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Model.Enum;
using YLErp.Modules.TradeModule;
@@ -28,6 +29,17 @@ namespace YLErp.Modules.SystemModule
{
var clientQuery = DataCacheProvider.GetClientDataSource().AsQueryable();
if (type == "ClientBlackProcess")
{
var clientdb = DbContextFactory.GetClientDbContext(OptUser);
if (clientdb.client_black.Any(x => x.State == client_black. || x.State == client_black.))
{
throw new ServiceException(data == null || data.Count == 0
? "有黑名单在审批中,不能删除审批流程!"
: "有黑名单在审批中,不能修改审批流程!");
}
}
var delList = DbContext.approvalprocess.Where(s => s.processType == type).ToArray();
DbContext.approvalprocess.RemoveRange(delList);
+3
View File
@@ -129,8 +129,11 @@
<FunctionSub Name="客户修改" Type="Operate" Note="是否有权限修改客户信息"></FunctionSub>
<FunctionSub Name="客户审批" Title="客户审批"></FunctionSub>
<FunctionSub Name="黑名单客户" Title="黑名单客户"></FunctionSub>
<FunctionSub Name="黑名单审批" Title="黑名单审批"></FunctionSub>
<FunctionSub Name="审批中客户信息编辑" Title="审批中客户信息编辑" Type="Operate" Note="是否可以修改审批中的客户信息"></FunctionSub>
<FunctionSub Name="黑名单客户管理" Type="Operate" Note="是否有权限进行客户黑名单操作" ></FunctionSub>
<FunctionSub Name="黑名单客户提交审批" Type="Operate" Note="是否有权限提交黑名单新增审批" ></FunctionSub>
<FunctionSub Name="黑名单客户撤回提交审批" Type="Operate" Note="是否有权限撤回黑名单审批" ></FunctionSub>
<FunctionSub Name="客户销户" Type="Operate" Note="是否有权限进行客户销户操作" ></FunctionSub>
<FunctionSub Name="客户休眠" Type="Operate" Note="是否有权限进行客户休眠操作" ></FunctionSub>
<FunctionSub Name="客户等级管理" Type="Operate" Note="是否有权限进行客户等级操作" ></FunctionSub>
+2 -1
View File
@@ -63,6 +63,7 @@
{Name:"客户列表",Rights:["客户管理-客户查看"],Url:"client/ClientList"},
{Name:"客户审批",Rights:["客户管理-客户审批"],Url:"clientApproval/openingclientList"},
{Name:"黑名单客户",Rights:["客户管理-黑名单客户"],Url:"clientblack/clientblacklist"},
{Name:"黑名单审批",Rights:["客户管理-黑名单审批"],Url:"clientblack/clientblackApproval"},
{Name:"授信管理",Rights:["客户管理-授信管理"],Url:"credit/creditList"},
{Name:"资信评级",Rights:["客户管理-资信评级"],Url:"client_rating/List"},
{Name:"机构账号设置",Rights:["客户管理-机构账号设置"],Url:"v3/client/account"}
@@ -107,4 +108,4 @@
{Name:"做市账户",Rights:["系统管理-做市账户"],Url:"TrsAccountManage/Index"}
]
}
]
]
+6
View File
@@ -251,6 +251,12 @@ namespace YLErp.Web
/// </summary>
public bool => _user.HasRight("客户管理-黑名单客户管理");
public bool => _user.HasRight("客户管理-黑名单审批");
public bool => _user.HasRight("客户管理-黑名单客户提交审批");
public bool => _user.HasRight("客户管理-黑名单客户撤回提交审批");
/// <summary>
/// 客户管理-黑名单客户
/// </summary>
@@ -93,7 +93,8 @@ namespace YLErp.Web.Controllers
var creditProcess = list.Where(s => s.processType == "CreditProcess").OrderBy(s => s.order).ToList();
var outCashProcess = list.Where(s => s.processType == "OutCashProcess").OrderBy(s => s.order).ToList();
var clientProcess = list.Where(s => s.processType == "ClientProcess").OrderBy(s => s.order).ThenBy(s => s.parentNode).ThenBy(s => s.node).ToList();
return Json(new { OpenProcess = openProcess, TradeProcess = tradeProcess, CloseProcess = closeProcess, CreditProcess = creditProcess, OutCashProcess= outCashProcess,ClientProcess = clientProcess });
var clientBlackProcess = list.Where(s => s.processType == "ClientBlackProcess").OrderBy(s => s.order).ThenBy(s => s.parentNode).ThenBy(s => s.node).ToList();
return Json(new { OpenProcess = openProcess, TradeProcess = tradeProcess, CloseProcess = closeProcess, CreditProcess = creditProcess, OutCashProcess= outCashProcess,ClientProcess = clientProcess, ClientBlackProcess = clientBlackProcess });
}
@@ -232,4 +233,4 @@ namespace YLErp.Web.Controllers
return Json(sList);
}
}
}
}
+2 -2
View File
@@ -2529,7 +2529,7 @@ namespace YLErp.Web.Controllers
return JsonError(error);
}
var clientblack = clientDB.client_black.FirstOrDefault(c => c.Name == client.Name);
if (clientblack != null)
if (clientblack != null && YLErp.Modules.ClientModule.ClientBlackApprovalPolicy.IsEffective(clientblack.State))
{
return JsonError("该客户为黑名单客户,禁止取消休眠");
}
@@ -3402,4 +3402,4 @@ namespace YLErp.Web.Controllers
return JsonSuccess();
}
}
}
}
+81 -31
View File
@@ -5,6 +5,19 @@ namespace YLErp.Web.Controllers
{
public class clientblackController : BaseController
{
public static List<SelectListItem> GetClientBlackStates()
{
return new List<SelectListItem>
{
new() { Text = client_black., Value = client_black. },
new() { Text = client_black., Value = client_black. },
new() { Text = client_black., Value = client_black. },
new() { Text = client_black., Value = client_black. },
new() { Text = client_black., Value = client_black. },
new() { Text = client_black., Value = client_black. }
};
}
[MyAuthorize("客户管理-黑名单客户")]
public ActionResult clientblacklist()
{
@@ -55,38 +68,75 @@ namespace YLErp.Web.Controllers
}
public ActionResult DeleteClientBlack(string ids)
{
var datalist = ids.Split(',');
var list = new List<int>();
foreach (var item in datalist)
try
{
var data = clientDB.client_black.Find(int.Parse(item));
if (data == null)
{
return JsonError("未找到要删除的数据");
}
else
{
var clitid = clientDB.client.Where(c => c.Name == data.Name).FirstOrDefault();
if (clitid != null)
{
clientDB.ClientAuditLog.Add(new ClientAuditLog
{
ClientId = clitid.id,
OptType = "移除黑名单",
Changes = string.Empty,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
});
}
clientDB.client_black.Remove(data);
}
var datalist = ids.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList();
var service = new ClientBlackService(CurUser);
service.DeleteClientBlack(datalist);
return JsonSuccess(service.ProcessList().Any() ? "已经提交删除审批!" : "删除成功");
}
clientDB.SaveChanges();
return JsonSuccess("删除成功");
catch (Exception ex)
{
return JsonError(ex.GetBaseException().Message);
}
}
[MyAuthorize("客户管理-黑名单审批")]
public ActionResult clientblackApproval()
{
return View();
}
[HttpPost, MyAuthorize("客户管理-黑名单审批")]
public JsonResult clientblackApprovalQuery(ClientBlackReq req)
{
return Json(new ClientBlackService(CurUser).ClientBlackApprovalQuery(req));
}
[HttpPost, MyAuthorize("客户管理-黑名单客户提交审批")]
public JsonResult clientblackSubmit(string ids)
{
var idList = ids.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList();
new ClientBlackService(CurUser).SubmitApprovalClientBlack(idList);
return JsonSuccess("提交审批成功");
}
[HttpPost, MyAuthorize("客户管理-黑名单客户撤回提交审批")]
public JsonResult clientblackWithdraw(string ids)
{
var idList = ids.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList();
new ClientBlackService(CurUser).WithdrawApprovalClientBlack(idList, out var withdrawCount, out var msg);
if (withdrawCount == 0)
{
return JsonError(string.IsNullOrWhiteSpace(msg)
? "所选记录当前状态无法撤回审批"
: $"以下记录已进入后续节点无法撤回:{msg}");
}
return JsonSuccess("撤回审批成功" + (string.IsNullOrWhiteSpace(msg) ? "" : $",以下记录已进入后续节点无法撤回:{msg}"));
}
[HttpPost, MyAuthorize("客户管理-黑名单审批")]
public JsonResult Auditclientblack(ClientBlackAuditReq req)
{
new ClientBlackService(CurUser).AuditClientBlack(req);
return JsonSuccess("审批成功");
}
[MyAuthorize("客户管理-黑名单审批")]
public ActionResult clientblackView(string enid)
{
var id = DataProtectHelper.DecryptInt(enid);
var item = clientDB.client_black.FirstOrDefault(x => x.id == id);
return View(item);
}
[MyAuthorize("客户管理-黑名单客户")]
public ActionResult clientblackLogList(int id)
{
var logs = clientDB.client_blacklog.Where(x => x.ClientBlackId == id)
.OrderByDescending(x => x.id)
.ToList();
return View(logs);
}
@@ -101,4 +151,4 @@ namespace YLErp.Web.Controllers
return File(bytes, xlsxMimeType, $"黑名单导出-{DateTime.Now:yyyy-MM-dd}.xlsx");
}
}
}
}
@@ -786,6 +786,46 @@
</div>
</div>
</div>
<div v-show="isClientBlack">
<div style="margin: 10px auto">黑名单审批流程</div>
<div>
<div class="node-wrap">
<div class="end-node">
<div class="end-node-text">申请人</div>
</div>
<div class="node-add-btn-box">
<div class="add-node-btn">
<button class="addNodeClick" v-on:click="addProcess(0,false,0)">+</button>
</div>
</div>
</div>
<template v-for="(item,index) in clientBlackItems">
<div class="node-wrap">
<div class="node-wrap-box start-node">
<div class="title" style="background: rgb(255, 148, 62);">
<span class="userEdit">审核节点</span>
<i class="glyphicon glyphicon-remove btnRemove" v-on:click="delProcess(item)"></i>
</div>
<div>
<span>审核角色</span>
<select v-model="item.SelectValue" style="width:143px;height:20px;">
<option v-for="option in roleOptions" v-bind:value="option.Value">{{option.Text}}</option>
</select>
</div>
</div>
<div class="node-add-btn-box">
<div class="add-node-btn">
<button class="addNodeClick" v-on:click="addProcess(item.Index,false,0)">+</button>
</div>
</div>
</div>
</template>
<div class="end-node">
<div class="end-node-circle"></div>
<div class="end-node-text">结束流程</div>
</div>
</div>
</div>
<div id="addtooltip-warpper">
<div id="addtooltip-box">
<div v-on:click="tradeAddProcess(1)">
@@ -0,0 +1,74 @@
@{
ViewBag.Title = "黑名单客户审批";
Layout = "~/Views/Shared/_MainLayout.cshtml";
var pageObj = new
{
roles = UserBLL.GetRolesByUserId(CurUser.UserId).Select(x => x.Id)
};
}
@section CSS{
<link href="~/Style/Css/tradeConfirmList.css" rel="stylesheet" />
<style>
.ui-jqgrid tr.jqgrow td { white-space: pre-wrap; }
</style>
}
@section JS{
<script type="text/javascript">
const page = @Json.Serialize(pageObj);
var g_grid = {};
$(function () {
var PostData = {};
@Html.Raw(JqGridSimple.OutGrid("/clientblack/clientblackApprovalQuery", true));
g_grid = $('#listGrid');
document.onkeydown = function (event) {
if ((event || window.event).keyCode == 13) SearchClick(true);
};
});
var colModelGrid = [
{ name: 'id', hidden: true },
{ name: 'ProcessRoleId', hidden: true },
{ name: '', label: '操作', width: 90, align: 'center', sortable: false, formatter: approvalButton },
{ name: 'ProcessStatus', label: '黑名单审批', width: 135, align: 'center' },
{ name: 'State', label: '审批状态', width: 135, align: 'center' },
{ name: 'ProcessRoleName', label: '审批角色', width: 140, align: 'center', sortable: false },
{ name: 'ClientName', label: '客户名称', width: 220, align: 'center', sortable: false },
{ name: 'Comments', label: '黑名单备注', width: 260, align: 'center' },
{ name: 'ApprovalOptName', label: '提交审批人', width: 120, align: 'center' },
{ name: 'ApprovalOptDate', label: '提交审批时间', width: 160, align: 'center' }
];
function approvalButton(cellValue, options, rowObject) {
if (!isAuthorize(rowObject.ProcessRoleId)) {
return '<input type="button" class="wentiEdit" value="审批" disabled="disabled" />';
}
return '<input type="button" class="wentiEdit" title="审批" value="审批" onclick="openApproval(\'' + rowObject.EncryptId + '\');return false;" />';
}
function isAuthorize(roleId) {
if (roleId === undefined || roleId === null || roleId === '') return false;
return page.roles.some(function (id) { return id.toString() === roleId.toString(); });
}
function openApproval(enid) {
main.open('审批', '/clientblack/clientblackView?enid=' + enid + '&approval=true', {
area: ['1000px', '75%'],
end: function () { SearchClick(); }
});
}
function SearchClick(isSearchclick) {
var listGrid = $('#listGrid');
listGrid.appendPostData({ Name: $('#Name').val() });
if (isSearchclick) listGrid.jqGrid('setGridParam', { page: 1 });
listGrid.trigger('reloadGrid');
}
</script>
}
<div class="searchdiv">
<label>客户名称</label>
<input type="text" name="Name" id="Name" maxlength="50" />
@MyControls.SearchBtn()
</div>
@Html.Raw(JqGridSimple.OutTable())
@@ -0,0 +1,14 @@
@model IEnumerable<YLErp.DBModels.ClientBlackLog>
@{
ViewBag.Title = "黑名单操作历史";
Layout = "~/Views/Shared/_InfoLayout.cshtml";
}
<table class="table table-bordered">
<thead><tr><th>时间</th><th>操作人</th><th>操作内容</th><th>说明</th></tr></thead>
<tbody>
@foreach (var item in Model ?? Enumerable.Empty<YLErp.DBModels.ClientBlackLog>())
{
<tr><td>@item.OptDate.ToString("yyyy-MM-dd HH:mm:ss")</td><td>@item.OptName</td><td>@item.OptType</td><td>@item.Changes</td></tr>
}
</tbody>
</table>
@@ -0,0 +1,45 @@
@using YLErp.Modules.ClientModule
@model YLErp.Model.client_black
@{
ViewBag.Title = "黑名单客户审批";
Layout = "~/Views/Shared/_InfoLayout.cshtml";
var process = new ClientBlackService(CurUser).ProcessList();
var currentNode = process.FirstOrDefault(x => x.order == Model?.ApprovalProcess);
var canAudit = currentNode != null && UserBLL.GetRolesByUserId(CurUser.UserId).Any(x => x.Id == currentNode.roleId);
}
@section JS {
<script>
function audit(status) {
main.confirmPost(status === 'pass' ? '确认审批通过?' : '确认拒绝?', '/clientblack/Auditclientblack', {
enid: '@(Model?.EncryptId)', status: status, auditComment: $('#AuditComment').val()
}).done(function (data) {
if (!data.success) return;
window.parent.location.reload();
window.close();
});
}
</script>
}
<div class="toolbarDiv" style="height:70px">
<div style="display:inline-block;float:left;">
@if (canAudit)
{
@MyControls.Btn("审批通过", "audit('pass');")
@MyControls.Btn("拒绝", "audit('reject');")
}
</div>
</div>
<div class="yc-panel">
<table class="table table-bordered">
<colgroup><col span="1" width="200" /></colgroup>
<tr><th class="tdRight">客户名称</th><td>@Model?.Name</td></tr>
<tr><th class="tdRight">黑名单备注</th><td>@Model?.Remarks</td></tr>
<tr><th class="tdRight">审批状态</th><td>@Model?.State</td></tr>
<tr><th class="tdRight">提交审批人</th><td>@Model?.ApprovalOptName</td></tr>
<tr><th class="tdRight">提交审批时间</th><td>@Model?.ApprovalOptDate?.ToString("yyyy-MM-dd HH:mm:ss")</td></tr>
<tr>
<th class="tdRight">审批说明</th>
<td><textarea class="text-box text-left" rows="3" id="AuditComment" style="width:700px;height:70px;"></textarea></td>
</tr>
</table>
</div>
@@ -51,10 +51,10 @@
var colModelGrid = [{
name: 'id', label: 'id', index: 'id', width: 0, hidden: true, optionHide: true
}, {
name: 'opt', label: '操作', index: 'opt', width: 150, align: 'left', hidden: !page.canEdit, optionHide: !page.canEdit, sortable: false,
name: 'opt', label: '操作', index: 'opt', width: 200, align: 'left', hidden: !page.canEdit, optionHide: !page.canEdit, sortable: false,
formatter: function (cellValue, options, rowObject) {
if (page.canEdit) {
var html = ("<input type=\"button\" class=\"wentiEdit\" onclick=\"startAddclientblack('{0}');return false;\" value=\"设置\" /><input type=\"button\" class=\"wentiEdit\" onclick=\"ClientBlackDeleteRow('{0}');return false;\" value=\"删除\" />")
var html = ("<input type=\"button\" class=\"wentiEdit\" onclick=\"clientblackLogView('{0}');return false;\" value=\"查看\" /><input type=\"button\" class=\"wentiEdit\" onclick=\"startAddclientblack('{0}');return false;\" value=\"设置\" /><input type=\"button\" class=\"wentiEdit\" onclick=\"ClientBlackDeleteRow('{0}');return false;\" value=\"删除\" />")
.template(rowObject.id);
return html;
}
@@ -65,7 +65,9 @@
}, {
name: 'Name', label: '客户名称', index: 'Name', width: 260
}, {
name: 'Remarks', label: '备注', index: 'Remarks', width: 500
name: 'Remarks', label: '备注', index: 'Remarks', width: 500
}, {
name: 'State', label: '状态', index: 'State', width: 120
}, {
name: 'OptName', label: '操作人', index: 'OptName', width: 150
}, {
@@ -146,7 +148,7 @@
function SearchClick(isSearchclick) {
var listGrid = $('#listGrid');
listGrid.appendPostData({ Name: $("#Name").val() });
listGrid.appendPostData({ OptName: $("#OptName").val() });
listGrid.appendPostData({ ClientBlackStates: $("#ClientBlackStates").val()?.join(',') || '' });
if (typeof (isSearchclick) != "undefined" && isSearchclick) {
//点击搜索时默认第一页
listGrid.jqGrid('setGridParam', {page: 1});
@@ -241,6 +243,19 @@
});
})
}
function ClientBlackSubmit() {
var ids = main.GetGridIds($('#listGrid'));
if (!ids.length) { main.message('请选择要提交的数据!'); return; }
main.post('/clientblack/clientblackSubmit', { ids: ids.toString() }).done(function () { SearchClick(); });
}
function ClientBlackWithdraw() {
var ids = main.GetGridIds($('#listGrid'));
if (!ids.length) { main.message('请选择要撤回的数据!'); return; }
main.post('/clientblack/clientblackWithdraw', { ids: ids.toString() }).done(function () { SearchClick(); });
}
function clientblackLogView(id) {
main.open('操作历史', '/clientblack/clientblackLogList?id=' + id, { area: ['1000px', '75%'] });
}
</script>
}
@@ -267,6 +282,7 @@
<form class="form-inline search-form" onsubmit="return false;" autocomplete="off">
<label>客户名称</label>
<input type="text" name="Name" id="Name" maxlength="50" />
@Html.MyAceDropdownInput("ClientBlackStates", "状态", clientblackController.GetClientBlackStates())
<button type="button" class="btn btn-primary" onclick="return(SearchClick(true));"><span class="glyphicon glyphicon-search"></span> 查询</button>
@if (CurUser.客户管理.黑名单客户管理)
{
@@ -275,6 +291,14 @@
<button type="button" class="btn btn-primary" onclick="ExportClientBlack();">批量导出</button>
<button type="button" class="btn btn-primary" onclick="ClientBlackDelete();">批量移除</button>
}
@if (CurUser.客户管理.黑名单客户提交审批)
{
<button type="button" class="btn btn-primary" onclick="ClientBlackSubmit();">提交审批</button>
}
@if (CurUser.客户管理.黑名单客户撤回提交审批)
{
<button type="button" class="btn btn-primary" onclick="ClientBlackWithdraw();">撤回审批</button>
}
</form>
</div>
@Html.Raw(JqGridSimple.OutTable())
@Html.Raw(JqGridSimple.OutTable())
@@ -53,7 +53,8 @@ var app = new Vue({
{ text: '交易新增与修改', value: '2' },
{ text: '交易了结', value: '6' },
/* { text: '资信与授信', value: '3' },*/
{ text: '出金', value: '4' }
{ text: '出金', value: '4' },
{ text: '黑名单', value: '7' }
],
isOpen: false,
@@ -62,12 +63,14 @@ var app = new Vue({
isCredit: false,
isOutCash: false,
isClient: false,
isClientBlack: false,
openItems: [],
clientItems: [],
tradeItems: [],
closeItems: [],
creditItems: [],
outCashItems: [],
clientBlackItems: [],
openCounter: 0,
tradeCounter: 0,
creditCounter: 0,
@@ -140,6 +143,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
} else if (thisObj.selected === '2') {
thisObj.isOpen = false;
thisObj.isTrade = true;
@@ -147,6 +151,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
} else if (thisObj.selected === '6') { // 需求②:交易了结流程
thisObj.isOpen = false;
thisObj.isTrade = false;
@@ -154,6 +159,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
} else if (thisObj.selected === '3') {
thisObj.isOpen = false;
thisObj.isTrade = false;
@@ -161,6 +167,7 @@ var app = new Vue({
thisObj.isCredit = true;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
}
else if (thisObj.selected === '4') {
thisObj.isOpen = false;
@@ -169,6 +176,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = true;
thisObj.isClient = false;
thisObj.isClientBlack = false;
}
else if (thisObj.selected === '5') {
thisObj.isOpen = false;
@@ -177,6 +185,16 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = true;
thisObj.isClientBlack = false;
}
else if (thisObj.selected === '7') {
thisObj.isOpen = false;
thisObj.isTrade = false;
thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = true;
}
else {
thisObj.isOpen = false;
@@ -185,6 +203,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
}
thisObj.getProcess();
},
@@ -385,6 +404,18 @@ var app = new Vue({
thisObj.addCloseNode(index, child, node);
return;
}
else if (selectType === "7") { //黑名单
var item = {
Type: 'ClientBlackProcess',
Index: index + 1,
SelectValue: 0
};
thisObj.clientBlackItems.splice(index, 0, item);
thisObj.clientBlackItems.forEach(function (x, itemIndex) {
x.Index = itemIndex + 1;
});
return;
}
},
delProcess: function (openItem) {
@@ -417,6 +448,14 @@ var app = new Vue({
});
return;
}
else if (selectType === "7") {//黑名单
var index = thisObj.clientBlackItems.indexOf(openItem);
thisObj.clientBlackItems.splice(index, 1);
thisObj.clientBlackItems.forEach(function (x, itemIndex) {
x.Index = itemIndex + 1;
});
return;
}
},
addOpenProcess(index, child, node) {
var thisObj = this;
@@ -528,6 +567,10 @@ var app = new Vue({
thisObj.saveCloseProcess();
return;
}
else if (selectType === "7") { //黑名单
thisObj.clientBlackOk();
return;
}
},
openOk() {
var thisObj = this;
@@ -857,6 +900,38 @@ var app = new Vue({
});
}
},
clientBlackOk() {
var thisObj = this;
var items = thisObj.clientBlackItems;
for (var i = 0; i < items.length; i++) {
if (items[i].SelectValue === "" || items[i].SelectValue === 0) {
main.message('流程中断,请重新选择');
return;
}
for (var j = i + 1; j < items.length; j++) {
if (parseInt(items[i].SelectValue) === parseInt(items[j].SelectValue)) {
main.message('流程包含重复项,请重新选择');
return;
}
}
}
if (items.length > 0) {
main.confirm("确认修改黑名单审批流程?", function () {
main.post("/AccountOpeningProcess/AddProcess",
{ type: "ClientBlackProcess", data: items },
{ async: false }).done(function () {
thisObj.getProcess();
});
});
} else {
main.confirm("删除审批流程后,黑名单变更会直接生效,确认删除?", function () {
main.post("/AccountOpeningProcess/AddProcess",
{ type: "ClientBlackProcess" },
{ async: false });
});
}
},
getProcess() {
var thisObj = this;
thisObj.openItems = [];
@@ -865,6 +940,7 @@ var app = new Vue({
thisObj.creditItems = [];
thisObj.outCashItems = [];
thisObj.clientItems = [];
thisObj.clientBlackItems = [];
main.post("/AccountOpeningProcess/GetProcess",
{},
{ async: false }).done(
@@ -945,6 +1021,14 @@ var app = new Vue({
triggerCondition: value.triggerCondition
});
});
(res.ClientBlackProcess || []).forEach(function (value) {
thisObj.clientBlackItems.push({
id: value.id,
Type: value.processType,
Index: value.order,
SelectValue: value.roleId
});
});
// 需求①:加载后把 triggerCondition(JSON)解析为结构化对象供 UI 编辑
['openItems', 'tradeItems', 'closeItems', 'clientItems'].forEach(function (arr) {
thisObj[arr].forEach(function (item) {