using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Yh.Platform.Abstractions;
using Yh.SchClass.OpenApi;
using YhCore.Entity;
using YhCore.Model.Dto;
using YhCore.Repository;
using YhCore.Service.Interfaces;
namespace YhCore.Service.Impl
{
///
/// 文印核心业务服务(移植旧 BestSchool.DocPrint.WY_list 的 CRUD/列表/审核/统计/指派部分)。
/// 与旧实现差异(迁移降级说明):
/// 1. 旧 SendMessage/SendUnread/Backlog(短信、已读未读、待办中心)在新项目缺失,全部降级为纯落库;
/// 2. 教师/头像改走教务 SDK(Yh.SchClass.OpenApi),教师标识用 teaId(TeaSerId);
/// 3. 旧返回体的 OtherData(userCenterUrl 等)无新槽位,仅 MyListtoOne 的 tempresultfile 并入 data;
/// 4. 旧 SPList/ShenheList/AllList 的多段 Union 查询改为内存 HashSet 去重实现,语义一致。
///
public class WYDocPrintService : IWYDocPrintService
{
private readonly IRepository _doc;
private readonly IRepository _dic;
private readonly IRepository _flowinfo;
private readonly IRepository _flowstep;
private readonly IRepository _flowtranct;
private readonly IRepository _groupuser;
private readonly IRepository _freegroup;
private readonly IRepository _freeflowinfo;
private readonly IRepository _zhipai;
private readonly IRepository _senduser;
private readonly IRepository _files;
private readonly YHDbContext _db;
private readonly SchClassOpenApi _sch;
private static readonly string[] DictTypes = { "WYFL", "YZBM", "YZFL" };
private static readonly string[] OfficeExts = { ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx" };
public WYDocPrintService(
IRepository doc,
IRepository dic,
IRepository flowinfo,
IRepository flowstep,
IRepository flowtranct,
IRepository groupuser,
IRepository freegroup,
IRepository freeflowinfo,
IRepository zhipai,
IRepository senduser,
IRepository files,
YHDbContext db,
SchClassOpenApi sch)
{
_doc = doc;
_dic = dic;
_flowinfo = flowinfo;
_flowstep = flowstep;
_flowtranct = flowtranct;
_groupuser = groupuser;
_freegroup = freegroup;
_freeflowinfo = freeflowinfo;
_zhipai = zhipai;
_senduser = senduser;
_files = files;
_db = db;
_sch = sch;
}
#region 抄送
/// 抄送列表(旧 SendRdList:DocStatus 1/11,SendUserID 含本人;旧为教师内连接)。
public async Task> SendRdListAsync(string name, string startDate, string endDate, string userId, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId)).ToList();
if (!string.IsNullOrEmpty(name))
docs = docs.Where(m => m.DocContent != null && m.DocContent.Contains(name)).ToList();
if (!string.IsNullOrEmpty(userId))
docs = docs.Where(m => m.SendUserID != null && m.SendUserID.IndexOf(userId) > -1).ToList();
if (DateTime.TryParse(startDate, out var date1))
docs = docs.Where(m => m.TakeDate >= date1).ToList();
if (DateTime.TryParse(endDate, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1); // 防止跨天
docs = docs.Where(m => m.TakeDate <= date2).ToList();
}
docs = docs.Where(m => m.DocStatus == "1" || m.DocStatus == "11")
.OrderByDescending(m => m.SerID)
.Skip(pageSize * pageIndex).Take(pageSize).ToList();
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var result = new List();
foreach (var item in docs)
{
// 旧实现为教师内连接:UserID 不在校内教师列表的记录被丢弃
if (!TryGetTea(teaMap, item.UserID, out var tea)) continue;
result.Add(await BuildListItemAsync(item, tea, dictMap, "yyyy-MM-dd"));
}
return result;
}
/// 查看抄送人员详情(旧 SendDetailsList)。
public async Task> SendDetailsListAsync(int serId)
{
var result = new List();
var model = await _doc.FirstOrDefaultAsync(m => m.SerID == serId);
if (model?.SendUserID == null) return result;
var ids = model.SendUserID.Split(',')
.Where(a => !string.IsNullOrEmpty(a) && int.TryParse(a, out _))
.Select(int.Parse).ToArray();
if (ids.Length == 0) return result;
var teas = await _sch.TeaInfo.GetArrTeaInfoAsync(string.Join(",", ids));
var teaMap = teas.Where(t => int.TryParse(t.TeaSerId, out _))
.GroupBy(t => int.Parse(t.TeaSerId))
.ToDictionary(g => g.Key, g => g.First());
foreach (var id in ids)
{
teaMap.TryGetValue(id, out var tea);
result.Add(new SendDetailItem
{
TeaName = tea?.Name ?? "",
TeaPhoto = tea?.Photo ?? "",
});
}
return result;
}
/// 修改抄送人(旧 EditSend:SetChaoSend + 回写 WY_DocPrint.SendUserID)。
public async Task EditSendAsync(int serId, string senduserid, string mysenduserid, string schSerId, string uid)
{
await SetChaoSendAsync(int.Parse(uid), schSerId, mysenduserid);
var model = await _doc.FirstOrDefaultAsync(m => m.SerID == serId);
if (model != null)
{
model.SendUserID = senduserid;
await _doc.SaveChangesAsync();
}
return "修改成功!";
}
#endregion
#region 附件
/// 获取附件数据源(旧 filelist)。
public async Task> FileListAsync(string ids)
{
var result = new List();
if (string.IsNullOrEmpty(ids)) return result;
var idArr = ids.Split(',')
.Where(a => !string.IsNullOrEmpty(a) && int.TryParse(a, out _))
.Select(int.Parse).ToArray();
if (idArr.Length == 0) return result;
var files = await _files.FindAsync(a => idArr.Contains(a.SerID));
return files.Select(a => new DocPrintFileItem
{
SerID = a.SerID,
FileTrueName = a.FileTrueName,
FileName = a.FileName,
FileSize = a.FileSize,
FileType = a.FileType,
DownTimes = a.DownTimes ?? 0,
}).ToList();
}
#endregion
#region 文印 CRUD
///
/// 添加文印(旧 Create):落库 + 首步骤定位 + 附件 TopicID 回写 + 指派 upsert + 自由流程挂链 + 抄送。
/// 旧短信/待办/已读未读推送降级为纯落库;旧 OtherData(IsNextStepMyShenhe) 新响应无槽位,不再返回。
///
public async Task CreateAsync(WYDocPrintSaveDto model)
{
var info = new WY_DocPrint
{
DocType = model.DocType,
DocStyle = model.DocStyle,
DPType = model.DPType,
DocShare = model.DocShare,
DocFix = model.DocFix,
DocNum = model.DocNum,
DocContent = model.DocContent,
UserID = model.UserID,
DocTitle = model.DocTitle,
EditDate = DateTime.Now,
TakeDate = model.TakeDate,
DocStatus = "0",
UpFile = model.UpFile,
explain = model.explain,
SchSerID = model.SchSerID,
flowid = model.flowid,
freestepid = model.freestepid,
SendUserID = model.SendUserID,
FreeUserID = model.FreeUserID,
zhipai = model.zhipai,
};
await _doc.AddAsync(info);
await _doc.SaveChangesAsync();
if ((model.flowid ?? 0) > 0)
{
// 固定流程:定位首步骤(prestep == 0);旧短信/已读未读推送已降级
info.DocStep = (await _flowstep.FindAsync(a => a.flowid == model.flowid && a.prestep == 0))
.Select(a => a.SerID).FirstOrDefault();
await _doc.SaveChangesAsync();
}
else if ((model.freestepid ?? 0) > 0)
{
// 自由流程:无附加落库(旧短信/已读未读推送已降级)
}
else
{
// 无流程直接完成
info.DocStatus = "1";
await _doc.SaveChangesAsync();
}
// 附件:UpFile 逗号分隔 SerID 回写 TopicID
await BindFilesTopicAsync(model.UpFile, (int)info.SerID);
// 指派 upsert
await UserFlowZhipaiAsync(int.Parse(model.UserID), model.flowid ?? 0, info.DocStep,
(int)info.SerID, model.zhipai, model.SchSerID, "Add");
// 自定义流程挂链 + 抄送
if ((info.freestepid ?? 0) > 0)
await SetPrimarySteptIDAsync((int)info.SerID, info.freestepid ?? 0);
await SetChaoSendAsync(int.Parse(info.UserID), info.SchSerID, info.SendUserID);
return (int)info.SerID;
}
///
/// 修改文印(旧 Edit):字段覆盖 + 状态复位 0 + 附件/指派/自由流程/抄送处理。
/// 旧实现附件差异比对因 UpFile 已先被覆盖而成为死代码(新增附件不回写 TopicID),此处保持同样行为。
///
public async Task EditAsync(WYDocPrintSaveDto model)
{
var info = await _doc.FirstOrDefaultAsync(x => x.SerID == model.SerID);
if (info == null) throw new DException("未找到该文印记录!");
info.DocType = model.DocType;
info.DocStyle = model.DocStyle;
info.DPType = model.DPType;
info.DocShare = model.DocShare;
info.DocFix = model.DocFix;
info.DocNum = model.DocNum;
info.DocContent = model.DocContent;
info.UserID = model.UserID;
info.DocTitle = model.DocTitle;
info.EditDate = DateTime.Now;
info.TakeDate = model.TakeDate;
info.DocStatus = "0";
// 旧实现最终回写 join(oldFids),即过滤空串后的新附件 id 串
info.UpFile = string.Join(",", ParseIds(model.UpFile));
info.explain = model.explain;
info.SchSerID = model.SchSerID;
info.flowid = model.flowid;
info.freestepid = model.freestepid;
info.SendUserID = model.SendUserID;
info.FreeUserID = model.FreeUserID;
info.zhipai = model.zhipai;
if ((model.flowid ?? 0) > 0)
{
info.DocStep = (await _flowstep.FindAsync(a => a.flowid == model.flowid && a.prestep == 0))
.Select(a => a.SerID).FirstOrDefault();
info.freestepid = null;
}
await _doc.SaveChangesAsync();
// 指派 upsert
await UserFlowZhipaiAsync(int.Parse(info.UserID), info.flowid ?? 0, info.DocStep,
(int)info.SerID, info.zhipai, info.SchSerID, "Add");
// 自定义流程挂链 + 抄送
if ((model.freestepid ?? 0) > 0)
await SetPrimarySteptIDAsync((int)info.SerID, model.freestepid ?? 0);
await SetChaoSendAsync(int.Parse(info.UserID), info.SchSerID, info.SendUserID);
return (int)info.SerID;
}
/// 删除文印(旧 Delete:按 ids 批量物理删除;旧待办中心清理已降级)。
public async Task DeleteAsync(string ids)
{
if (string.IsNullOrWhiteSpace(ids)) throw new DException("ids is not null");
var idArr = ids.Split(',')
.Where(a => !string.IsNullOrEmpty(a) && decimal.TryParse(a, out _))
.Select(decimal.Parse).ToArray();
var objlist = await _doc.FindAsync(m => idArr.Contains(m.SerID));
foreach (var item in objlist)
{
await _doc.RemoveAsync(item);
}
await _doc.SaveChangesAsync();
}
/// 撤销(旧 Revoke:写撤销流水 + 更新单据状态;旧待办/短信/已读未读已降级)。
public async Task RevokeAsync(FlowTranctDto model)
{
if (string.IsNullOrEmpty(model.remark) && model.actionstatus == 3)
model.remark = "撤销";
var tranct = new Common_flowtranctInfo
{
dataid = model.dataid,
stepid = model.stepid,
actionuserid = model.actionuserid,
actionstatus = model.actionstatus,
actiondate = DateTime.Now,
remark = model.remark,
undertaker = model.undertaker,
Pid = model.Pid,
DoneUserID = model.DoneUserID,
filespath = model.filespath,
datatype = DocPrintConstants.AppCode.ToString(),
};
await _flowtranct.AddAsync(tranct);
await _flowtranct.SaveChangesAsync();
var docModel = await _doc.FirstOrDefaultAsync(m => m.SerID == model.dataid);
if (docModel != null)
{
docModel.DocStatus = model.actionstatus.ToString();
await _doc.SaveChangesAsync();
}
return "撤销成功!";
}
#endregion
#region 列表
/// 我的文印列表(旧 MyList;旧 DocTypeName 误用 YZBM 字典,此处保持旧行为)。
public async Task> MyListAsync(string name, string status, string startDate, string endDate, string userId, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.UserID == userId && m.SchSerID == schSerId)).ToList();
if (!string.IsNullOrEmpty(name))
docs = docs.Where(m => m.DocContent != null && m.DocContent.Contains(name)).ToList();
if (!string.IsNullOrEmpty(status))
docs = docs.Where(m => m.DocStatus == status).ToList();
if (DateTime.TryParse(startDate, out var date1))
docs = docs.Where(m => m.TakeDate >= date1).ToList();
if (DateTime.TryParse(endDate, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
docs = docs.Where(m => m.TakeDate <= date2).ToList();
}
docs = docs.OrderBy(m => m.DocStatus).ThenByDescending(m => m.TakeDate).ThenByDescending(m => m.EditDate)
.Skip(pageSize * pageIndex).Take(pageSize).ToList();
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var result = new List();
foreach (var item in docs)
{
TryGetTea(teaMap, item.UserID, out var tea); // 旧为左连接,缺失补空
result.Add(await BuildListItemAsync(item, tea, dictMap, "yyyy-MM-dd HH:mm", "YZBM"));
}
return result;
}
///
/// 全部文印列表(旧 AllList 原生 SQL 四分类:x=待我审(0) y=我已审(1) z=抄送我(2) m=我发起(3),按优先级去重)。
/// 旧 Name 过滤的 SQL 拼接存在运算符优先级缺陷,此处按语义实现:内容/教师名/字典名任一命中。
///
public async Task> AllListAsync(string name, string userId, string schSerId, int pageSize, int pageIndex)
{
int uid = int.Parse(userId);
var docs = await _doc.FindAsync(m => m.SchSerID == schSerId);
var fixedGroupIds = (await _groupuser.FindAsync(b => b.userid == uid))
.Select(b => b.usergroup).Where(g => g.HasValue).Select(g => g.Value).ToList();
var freeGroupIds = (await _freegroup.FindAsync(b => b.userid == uid))
.Select(b => b.usergroup).Where(g => g.HasValue).Select(g => g.Value).ToList();
var tranctDataIds = (await _flowtranct.FindAsync(a => a.actionuserid == uid && a.datatype == DocPrintConstants.AppCode.ToString()))
.Select(a => a.dataid).ToHashSet();
bool IsPending(WY_DocPrint a) =>
a.DocStatus == "0"
&& ((a.flowid != null && a.zhipai == null && a.DocStep.HasValue && fixedGroupIds.Contains(a.DocStep.Value))
|| (a.flowid != null && a.zhipai != null && a.zhipai.Contains(userId))
|| (a.freestepid > 0 && freeGroupIds.Contains(a.freestepid ?? 0)));
var taken = new HashSet();
var combined = new List<(WY_DocPrint doc, int ctype)>();
foreach (var a in docs.Where(a => IsPending(a))) { combined.Add((a, 0)); taken.Add(a.SerID); }
foreach (var a in docs.Where(a => a.DocStatus != "3" && tranctDataIds.Contains((int)a.SerID) && !taken.Contains(a.SerID))) { combined.Add((a, 1)); taken.Add(a.SerID); }
foreach (var a in docs.Where(a => a.DocStatus == "1" && a.SendUserID != null && a.SendUserID.Contains(userId) && !taken.Contains(a.SerID))) { combined.Add((a, 2)); taken.Add(a.SerID); }
foreach (var a in docs.Where(a => a.UserID == userId && !taken.Contains(a.SerID))) { combined.Add((a, 3)); taken.Add(a.SerID); }
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
IEnumerable<(WY_DocPrint doc, int ctype)> query = combined;
if (!string.IsNullOrEmpty(name))
{
query = query.Where(t =>
(t.doc.DocContent != null && t.doc.DocContent.IndexOf(name) >= 0)
|| (t.doc.UserID != null && int.TryParse(t.doc.UserID, out var touid) && teaMap.TryGetValue(touid, out var tt) && tt.Name != null && tt.Name.IndexOf(name) >= 0)
|| DictNameContains(dictMap, "WYFL", t.doc.DocType, name)
|| DictNameContains(dictMap, "YZBM", t.doc.DocStyle, name)
|| DictNameContains(dictMap, "YZFL", t.doc.DPType, name));
}
var pageItems = query.OrderByDescending(t => t.doc.SerID).ThenByDescending(t => t.doc.TakeDate)
.Skip(pageSize * pageIndex).Take(pageSize).ToList();
var result = new List();
foreach (var (doc, ctype) in pageItems)
{
TryGetTea(teaMap, doc.UserID, out var tea);
var item = await BuildListItemAsync(doc, tea, dictMap, "yyyy-MM-dd HH:mm");
item.ctype = ctype;
result.Add(item);
}
return result;
}
///
/// 文印审核列表(旧 ShenheList:固定流程 + 指派 + 自由流程三路并集,HashSet 去重)。
/// 旧实现的 Name 过滤作用在未被使用的查询上(死代码),此处保持 Name 不生效的旧行为。
///
public async Task> ShenheListAsync(string userId, string schSerId, int pageSize, int pageIndex)
{
var docs = await GetPendingShenheDocsAsync(userId, schSerId, requireFlowIdNonZero: false);
docs = docs.OrderBy(m => m.DocStatus).ThenByDescending(m => m.TakeDate)
.Skip(pageSize * pageIndex).Take(pageSize).ToList();
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var result = new List();
foreach (var item in docs)
{
TryGetTea(teaMap, item.UserID, out var tea);
result.Add(await BuildListItemAsync(item, tea, dictMap, "yyyy-MM-dd HH:mm"));
}
return result;
}
///
/// 审批列表(旧 SPList:待审(DS,zt=false)∪ 我已审(YS,zt=true,排除 DS),_disabled 即 zt)。
///
public async Task> SPListAsync(string name, string status, string startDate, string endDate, string userId, string schSerId, int pageSize, int pageIndex)
{
var userid = int.Parse(userId);
// DS:待审集合(固定流程 flowid!=0 + 指派 + 自由流程)
var dsDocs = await GetPendingShenheDocsAsync(userId, schSerId, requireFlowIdNonZero: true);
var dsIds = dsDocs.Select(a => a.SerID).ToHashSet();
// YS:本人已审(actionstatus != 0),排除 DS
var ysDataIds = (await _flowtranct.FindAsync(b => b.actionuserid == userid
&& b.datatype == DocPrintConstants.AppCode.ToString() && b.actionstatus != 0))
.Select(b => b.dataid).ToHashSet();
var ysDocs = (await _doc.FindAsync(s => s.SchSerID == schSerId && s.DocStatus != null))
.Where(s => !dsIds.Contains(s.SerID) && ysDataIds.Contains((int)s.SerID))
.ToList();
IEnumerable<(WY_DocPrint doc, bool zt)> query = dsDocs.Select(a => (a, false))
.Concat(ysDocs.Select(a => (a, true)));
if (DateTime.TryParse(startDate, out var date1))
query = query.Where(m => m.doc.TakeDate >= date1);
if (DateTime.TryParse(endDate, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
query = query.Where(m => m.doc.TakeDate <= date2);
}
if (!string.IsNullOrEmpty(status))
query = query.Where(m => m.doc.DocStatus == status);
if (!string.IsNullOrEmpty(name))
query = query.Where(m => m.doc.DocContent != null && m.doc.DocContent.IndexOf(name) >= 0);
var ordered = query.OrderBy(m => m.doc.DocStatus).ThenByDescending(m => m.doc.EditDate).ToList();
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var result = new List();
foreach (var (doc, zt) in ordered.Skip(pageSize * pageIndex).Take(pageSize))
{
TryGetTea(teaMap, doc.UserID, out var tea);
var item = await BuildListItemAsync(doc, tea, dictMap, "yyyy-MM-dd HH:mm");
item._disabled = zt; // 我已审的记录不可再编辑(覆盖通用 _disabled 语义,与旧一致)
result.Add(item);
}
return result;
}
/// 文印已审列表(旧 YishenList:本人审核流水关联,排除撤销与已领取)。
public async Task> YishenListAsync(string name, string userId, string schSerId, int pageSize, int pageIndex)
{
int uid = int.Parse(userId);
var tranctDataIds = (await _flowtranct.FindAsync(b => b.actionuserid == uid && b.datatype == DocPrintConstants.AppCode.ToString() && b.actionstatus != 11))
.Select(b => b.dataid).ToHashSet();
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId && m.DocStatus != "3"))
.Where(m => tranctDataIds.Contains((int)m.SerID))
.ToList();
if (!string.IsNullOrEmpty(name))
docs = docs.Where(m => m.DocContent != null && m.DocContent.Contains(name)).ToList();
docs = docs.OrderByDescending(m => m.SerID).ThenByDescending(m => m.TakeDate)
.Skip(pageSize * pageIndex).Take(pageSize).ToList();
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var result = new List();
foreach (var item in docs)
{
TryGetTea(teaMap, item.UserID, out var tea);
result.Add(await BuildListItemAsync(item, tea, dictMap, "yyyy-MM-dd HH:mm"));
}
return result;
}
/// 全部文印列表(旧 totalList,管理员视角,按状态/时间过滤)。
public async Task> TotalListAsync(string name, string stateid, string starttime, string endtime, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId)).ToList();
if (DateTime.TryParse(starttime, out var date1))
docs = docs.Where(m => m.TakeDate >= date1).ToList();
if (DateTime.TryParse(endtime, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
docs = docs.Where(m => m.TakeDate <= date2).ToList();
}
if (!string.IsNullOrEmpty(stateid))
docs = docs.Where(m => m.DocStatus == stateid).ToList();
if (!string.IsNullOrEmpty(name))
docs = docs.Where(m => m.DocContent != null && m.DocContent.IndexOf(name) >= 0).ToList();
docs = docs.OrderBy(m => m.DocStatus).ThenByDescending(m => m.TakeDate)
.Skip(pageSize * pageIndex).Take(pageSize).ToList();
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var result = new List();
foreach (var item in docs)
{
TryGetTea(teaMap, item.UserID, out var tea);
result.Add(await BuildListItemAsync(item, tea, dictMap, "yyyy-MM-dd"));
}
return result;
}
///
/// 获取当前一条文印详情(旧 MyListtoOne:单元素列表 + 附件明细;
/// 旧 OtherData.tempresultfile 并入条目 tempresultfile,userCenterUrl/teaPhoto 头像不再返回)。
///
public async Task> MyListtoOneAsync(int serId, string schSerId)
{
var result = new List();
var doc = await _doc.FirstOrDefaultAsync(m => m.SerID == serId);
if (doc == null) return result;
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
if (!TryGetTea(teaMap, doc.UserID, out var tea)) return result; // 旧为教师内连接
var tranctAny = await _flowtranct.AnyAsync(a => a.dataid == serId && a.datatype == DocPrintConstants.AppCode.ToString());
var item = new DocPrintDetailItem
{
SerID = (int)doc.SerID,
DocContent = doc.DocContent,
DocType = doc.DocType,
DocTypeName = DictName(dictMap, "WYFL", doc.DocType),
DocStyle = doc.DocStyle,
DocStyleName = DictName(dictMap, "YZBM", doc.DocStyle),
DPType = doc.DPType,
DPTypeName = DictName(dictMap, "YZFL", doc.DPType),
EditDate = doc.EditDate.ToString("yyyy-MM-dd HH:mm"),
TakeDate = doc.TakeDate?.ToString("yyyy-MM-dd"),
UserID = doc.UserID,
teaname = tea.Name,
TeaPhoto = tea.Photo,
UpFile = doc.UpFile,
DocTitle = doc.DocTitle,
DocStatus = doc.DocStatus,
DocStatusName = await GetStatusByCodeAsync(doc.DocStatus, doc.DocStep ?? 0, doc.zhipai, doc.freestepid, teaMap),
DocStep = doc.DocStep?.ToString() ?? "",
explain = doc.explain,
flowid = doc.flowid?.ToString() ?? "",
DocShare = doc.DocShare,
DocFix = doc.DocFix,
DocNum = doc.DocNum,
_disabled = !(doc.DocStatus == "0" && !tranctAny), // 旧 GetEditDeleteStatus
FreeUserID = doc.FreeUserID,
SendUserID = doc.SendUserID,
freestepid = doc.freestepid,
zhipai = doc.zhipai,
rid = doc.rid,
reid = doc.reid,
grade = doc.grade,
Examtype = doc.Examtype,
tempresultfile = new List(),
};
// 附件明细:office 文件替换为 .pdf 预览名并拼接文件 Web 前缀
var fids = ParseIds(doc.UpFile);
if (fids.Count > 0)
{
var fileUrl = YhCore.Common.Config.Config.FileWebPath ?? "";
var files = await _files.FindAsync(a => fids.Contains(a.SerID));
item.tempresultfile = files.Select(a => new DocPrintFileItem
{
SerID = a.SerID,
FileTrueName = a.FileTrueName,
FileName = fileUrl + (OfficeExts.Contains(a.FileType) ? a.FileName?.Replace(a.FileType, ".pdf") : a.FileName),
FileSize = a.FileSize,
FileType = a.FileType,
DownTimes = a.DownTimes ?? 0,
}).ToList();
}
result.Add(item);
return result;
}
/// 绑定流程(旧 Bindflowinfo:本校启用流程下拉)。
public async Task> BindflowinfoAsync(string schSerId, int flowType)
{
var list = await _flowinfo.FindAsync(a => a.flowType == flowType && a.schSerID == schSerId && a.enable == 1);
return list.OrderBy(m => m.SerID)
.Select(item => new BindFlowOption
{
SerID = item.SerID.ToString(),
flowname = item.flowname,
}).ToList();
}
#endregion
#region 审核动作
///
/// 审核确认(旧 shenheok):事务内写流水 + 推进固定/自由流程或终态;
/// 重复审核 / 已处理单据按旧语义抛业务异常;旧短信/待办/已读未读已降级。
///
public async Task ShenheOkAsync(FlowTranctDto model)
{
using var tx = await _db.Database.BeginTransactionAsync();
try
{
var rdmodel = await _doc.FirstOrDefaultAsync(m => m.SerID == model.dataid);
if (rdmodel == null) throw new DException("未找到该文印记录!");
if (rdmodel.DocStatus != "0")
{
var statusName = rdmodel.DocStatus switch
{
"1" => "已印好",
"2" => "已拒绝",
"3" => "已撤销",
"11" => "已领取",
_ => "",
};
throw new DException(statusName);
}
var audited = await _flowtranct.AnyAsync(a => a.dataid == model.dataid
&& a.datatype == DocPrintConstants.AppCode.ToString() && a.stepid == model.stepid);
if (audited) throw new DException("已审核");
if (string.IsNullOrEmpty(model.remark))
model.remark = model.actionstatus == 1 ? "同意" : "不同意";
rdmodel.zhipai = model.undertaker;
var tranct = new Common_flowtranctInfo
{
dataid = model.dataid,
stepid = model.stepid,
actionuserid = model.actionuserid,
actionstatus = model.actionstatus,
actiondate = DateTime.Now,
remark = model.remark,
undertaker = model.undertaker,
Pid = model.Pid,
datatype = DocPrintConstants.AppCode.ToString(),
};
await _flowtranct.AddAsync(tranct);
await _flowtranct.SaveChangesAsync();
if (model.actionstatus == 1)
{
if (rdmodel.DocStep == null || rdmodel.DocStep == 0)
{
// 自由流程:按 laststep 推进下一步
var stepid = (await _freeflowinfo.FindAsync(a => a.laststep == model.stepid))
.Select(a => a.SerID).FirstOrDefault();
if (stepid > 0)
{
rdmodel.freestepid = stepid;
await _doc.SaveChangesAsync();
}
else
{
// 无下一步:流程结束(旧抄送短信推送已降级)
rdmodel.DocStatus = model.actionstatus.ToString();
await _doc.SaveChangesAsync();
}
}
else
{
// 固有流程:按 prestep 推进下一步
if (!int.TryParse(model.Pid, out var flowid))
throw new DException("审核失败:Pid 参数错误");
var steps = await _flowstep.FindAsync(a => a.flowid == flowid && a.prestep == model.stepid);
if (steps.Count > 0)
{
rdmodel.DocStep = steps.Select(a => a.SerID).First();
await _doc.SaveChangesAsync();
}
else
{
rdmodel.DocStatus = model.actionstatus.ToString();
await _doc.SaveChangesAsync();
}
}
}
else
{
// 拒绝:直接终态
rdmodel.DocStatus = model.actionstatus.ToString();
await _doc.SaveChangesAsync();
}
await tx.CommitAsync();
return "已审核";
}
catch
{
await tx.RollbackAsync();
throw;
}
}
///
/// 领取确认(旧 AffirmApplyforOk):写 actionstatus=11 流水 + 单据置为已领取(11)。
/// 旧代码查重用 datatype=="1010" 而写入用 AppCode(1003),导致查重永远为空;
/// 此处统一为 1003 修正重复领取校验。
///
public async Task AffirmApplyforOkAsync(FlowTranctDto model)
{
var itt = await _doc.FirstOrDefaultAsync(m => m.SerID == model.dataid);
if (itt == null) throw new DException("未找到该文印记录!");
var claimed = await _flowtranct.AnyAsync(a => a.dataid == model.dataid
&& a.datatype == DocPrintConstants.AppCode.ToString() && a.actionstatus == 11);
if (claimed) throw new DException("已领取,不能重复提交!");
var info = new Common_flowtranctInfo
{
remark = string.IsNullOrEmpty(model.remark) ? "已领取" : model.remark,
stepid = model.stepid,
dataid = model.dataid,
actionuserid = model.actionuserid,
actionstatus = 11,
datatype = DocPrintConstants.AppCode.ToString(),
actiondate = DateTime.Now,
};
await _flowtranct.AddAsync(info);
itt.DocStatus = "11";
await _flowtranct.SaveChangesAsync();
await _doc.SaveChangesAsync();
return "已通知!";
}
#endregion
#region 指派
/// 查询指派(旧 GetUserZhipai:取最近一次指派记录)。
public async Task GetUserZhipaiAsync(int userid, string schSerId, int? flowid, int? flowstepid, string type)
{
if ((flowid ?? 0) <= 0) return null;
var zhipai = (await _zhipai.FindAsync(a => a.UserID == userid && a.SchSerID == schSerId
&& a.FlowID == flowid && a.FlowStepID == flowstepid && a.type == type))
.OrderByDescending(a => a.MSerID)
.FirstOrDefault()?.zhipai;
return zhipai;
}
///
/// 指派 upsert(旧 UserFlowZhipai:flowid>0 时按六元组查重,有则更新无则新增;异常按旧实现吞掉不回滚主流程)。
///
private async Task UserFlowZhipaiAsync(int uid, int flowid, int? flowstepid, int dataid, string zhipai, string schSerId, string type)
{
try
{
if (flowid <= 0) return;
var list = await _zhipai.FirstOrDefaultAsync(a => a.UserID == uid && a.MSerID == dataid
&& a.SchSerID == schSerId && a.FlowID == flowid && a.FlowStepID == flowstepid && a.type == type);
if (list == null)
{
await _zhipai.AddAsync(new Common_UserFlowZhipai
{
UserID = uid,
MSerID = dataid,
FlowID = flowid,
FlowStepID = flowstepid,
type = type,
zhipai = zhipai,
SchSerID = schSerId,
});
}
else
{
list.FlowID = flowid;
list.FlowStepID = flowstepid;
list.type = type;
list.zhipai = zhipai;
list.SchSerID = schSerId;
}
await _zhipai.SaveChangesAsync();
}
catch
{
// 旧实现仅记日志不抛出,保持一致
}
}
#endregion
#region 统计
/// 文印数量按月统计(旧 List1:按年月分组 + MonthDiff 补零;起止时间任一为空时不补零)。
public async Task> List1Async(string starttime, string endtime, string schSerId)
{
var docs = await _doc.FindAsync(m => m.SchSerID == schSerId);
if (DateTime.TryParse(starttime, out var date1))
docs = docs.Where(m => m.EditDate >= date1).ToList();
if (DateTime.TryParse(endtime, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
docs = docs.Where(m => m.EditDate <= date2).ToList();
}
var grouped = docs.OrderBy(m => m.SerID)
.GroupBy(m => new { m.EditDate.Year, m.EditDate.Month })
.Select(g => new MonthStatItem
{
dateyear = g.Key.Year,
datemonth = g.Key.Month,
num = g.Count(),
DocNum = g.Sum(a => a.DocNum),
})
.OrderBy(a => a.dateyear)
.ToList();
// 月份区间补零(旧 MonthDiff 跨年补零;参数缺失时跳过,避免旧实现 MinValue 起点的异常输出)
if (DateTime.TryParse(starttime, out var s) && DateTime.TryParse(endtime, out var e))
{
var months = MonthDiff(s, e.AddDays(1).AddMilliseconds(-1));
var result = new List();
foreach (var m in months)
{
var year = int.Parse(m.Split(',')[0]);
var month = int.Parse(m.Split(',')[1]);
var hit = grouped.FirstOrDefault(r => r.dateyear == year && r.datemonth == month);
result.Add(new MonthStatItem { dateyear = year, datemonth = month, num = hit?.num ?? 0, DocNum = hit?.DocNum ?? 0 });
}
return result;
}
return grouped;
}
/// 文印详情统计列表(旧 List2:非待审单据按申请时间倒序分页)。
public async Task> List2Async(string starttime, string endtime, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId && m.DocStatus != "0")).ToList();
if (DateTime.TryParse(starttime, out var date1))
docs = docs.Where(m => m.EditDate >= date1).ToList();
if (DateTime.TryParse(endtime, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
docs = docs.Where(m => m.EditDate <= date2).ToList();
}
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var full = new List();
foreach (var m in docs.Where(m => TryGetTea(teaMap, m.UserID, out _)).OrderBy(m => m.SerID))
{
TryGetTea(teaMap, m.UserID, out var tea);
full.Add(new DocDetailStatItem
{
UserID = m.UserID,
teaname = tea.Name,
DocContent = m.DocContent,
DocType = m.DocType,
DocTypeName = DictName(dictMap, "WYFL", m.DocType),
DocStyle = m.DocStyle,
DocStyleName = DictName(dictMap, "YZBM", m.DocStyle),
DPType = m.DPType,
DPTypeName = DictName(dictMap, "YZFL", m.DPType),
EditDate = m.EditDate.ToString("yyyy-MM-dd"),
UpFile = m.UpFile,
DocTitle = m.DocTitle,
DocNum = m.DocNum,
DocStatus = m.DocStatus,
DocStatusName = await GetStatusByCodeAsync(m.DocStatus, m.DocStep ?? 0, m.zhipai, m.freestepid, teaMap),
});
}
return full.OrderByDescending(a => a.EditDate)
.Skip(pageSize * pageIndex).Take(pageSize)
.ToList();
}
/// 文印数量按用户排名(旧 List3)。
public async Task> List3Async(string starttime, string endtime, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId && m.DocStatus == "1")).ToList();
if (DateTime.TryParse(starttime, out var date1))
docs = docs.Where(m => m.EditDate >= date1).ToList();
if (DateTime.TryParse(endtime, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
docs = docs.Where(m => m.EditDate <= date2).ToList();
}
var teaMap = await GetTeaMapAsync(schSerId);
var grouped = docs.OrderBy(m => m.SerID)
.Where(m => TryGetTea(teaMap, m.UserID, out _)) // 旧为教师内连接
.GroupBy(m => new { m.UserID, Name = GetTeaName(teaMap, m.UserID) })
.Select(g => new UserRankItem
{
UserID = g.Key.UserID,
teaname = g.Key.Name,
num = g.Count(),
DocNum = g.Sum(a => a.DocNum),
})
.OrderByDescending(a => a.num)
.ToList();
return grouped.Skip(pageSize * pageIndex).Take(pageSize).ToList();
}
/// 按月份统计明细(旧 List4:指定年月已印好单据,按申请时间倒序分页)。
public async Task> List4Async(int year, int month, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId
&& m.DocStatus == "1" && m.EditDate.Year == year && m.EditDate.Month == month))
.OrderByDescending(a => a.EditDate)
.Skip(pageSize * pageIndex).Take(pageSize)
.ToList();
return await BuildStatListAsync(docs, schSerId);
}
/// 按用户统计明细(旧 List5:指定用户已印好单据,按申请时间倒序分页)。
public async Task> List5Async(string userid, string starttime, string endtime, string schSerId, int pageSize, int pageIndex)
{
var docs = (await _doc.FindAsync(m => m.SchSerID == schSerId && m.UserID == userid && m.DocStatus == "1")).ToList();
if (DateTime.TryParse(starttime, out var date1))
docs = docs.Where(m => m.EditDate >= date1).ToList();
if (DateTime.TryParse(endtime, out var endDateValue))
{
var date2 = endDateValue.AddDays(1).AddMilliseconds(-1);
docs = docs.Where(m => m.EditDate <= date2).ToList();
}
docs = docs.OrderByDescending(a => a.EditDate)
.Skip(pageSize * pageIndex).Take(pageSize)
.ToList();
return await BuildStatListAsync(docs, schSerId);
}
#endregion
#region 内部辅助:查询集合
///
/// 待审单据集合(旧 SPList/ShenheList/GetShnheCount 的三路 Union,HashSet 去重):
/// 固定流程组命中 / 指派包含本人 / 自由流程组命中。
/// requireFlowIdNonZero:旧 SPList 固定分支带 flowid != 0 条件,ShenheList 仅 flowid != null。
///
private async Task> GetPendingShenheDocsAsync(string userId, string schSerId, bool requireFlowIdNonZero)
{
var userid = int.Parse(userId);
var docs = await _doc.FindAsync(a => a.SchSerID == schSerId && a.DocStatus == "0");
var fixedGroupIds = (await _groupuser.FindAsync(b => b.userid == userid))
.Select(b => b.usergroup).Where(g => g.HasValue).Select(g => g.Value).ToList();
var freeGroupIds = (await _freegroup.FindAsync(b => b.userid == userid))
.Select(b => b.usergroup).Where(g => g.HasValue).Select(g => g.Value).ToList();
var fixedFlowOk = requireFlowIdNonZero
? new Func(a => a.flowid != null && a.flowid != 0)
: new Func(a => a.flowid != null);
var result = new HashSet();
var list = new List();
foreach (var a in docs)
{
bool match = false;
// 固定流程:DocStep 命中本人组(旧 zhipai == null 分支)
if (fixedFlowOk(a) && a.zhipai == null && a.DocStep.HasValue && fixedGroupIds.Contains(a.DocStep.Value))
match = true;
// 指派:zhipai 含本人
if (!match && a.DocStatus == "0" && a.zhipai != null && a.flowid != null
&& a.zhipai.Contains(userId) && a.SchSerID == schSerId)
match = true;
// 自由流程:freestepid 命中本人自由组
if (!match && a.SchSerID == schSerId && a.freestepid > 0 && freeGroupIds.Contains(a.freestepid ?? 0))
match = true;
if (match && result.Add(a.SerID))
{
list.Add(a);
}
}
return list;
}
#endregion
#region 内部辅助:教师 / 字典
private async Task> GetTeaMapAsync(string schSerId)
{
var teas = await _sch.TeaInfo.GetSchTeaInfoAsync(schSerId, null);
return teas
.Where(t => int.TryParse(t.TeaSerId, out _))
.GroupBy(t => int.Parse(t.TeaSerId))
.ToDictionary(g => g.Key, g => (g.First().Name, g.First().Photo));
}
private static bool TryGetTea(Dictionary teaMap, string userId, out (string Name, string Photo) tea)
{
tea = default;
return int.TryParse(userId, out var uid) && teaMap.TryGetValue(uid, out tea);
}
private static string GetTeaName(Dictionary teaMap, string userId)
=> TryGetTea(teaMap, userId, out var tea) ? tea.Name : "";
/// 字典名缓存(旧 Get_DictionaryOnly:typeID+CodeID 定位,本校或通用,按 Enable 升序取首个)。
private async Task> GetDictMapAsync(string schSerId)
{
var list = await _dic.FindAsync(a => a.typeID == "WYFL" || a.typeID == "YZBM" || a.typeID == "YZFL");
return list
.Where(a => a.Schserid == schSerId || string.IsNullOrEmpty(a.Schserid))
.GroupBy(a => a.typeID + "|" + a.CodeID)
.ToDictionary(g => g.Key, g => g.OrderBy(x => x.Enable).Select(x => x.Name).FirstOrDefault() ?? "");
}
private static string DictName(Dictionary dictMap, string type, string code)
=> code != null && dictMap.TryGetValue(type + "|" + code, out var name) ? name : "";
private static bool DictNameContains(Dictionary dictMap, string type, string code, string name)
{
var dictName = DictName(dictMap, type, code);
return dictName != null && dictName.IndexOf(name) >= 0;
}
private static List ParseIds(string commaIds)
{
if (string.IsNullOrEmpty(commaIds)) return new List();
return commaIds.Split(',')
.Where(a => !string.IsNullOrEmpty(a) && int.TryParse(a, out _))
.Select(int.Parse).ToList();
}
#endregion
#region 内部辅助:状态 / 列表项
/// 状态文案(旧 GetStatusByCode:0=待审人名+审核中,1=印刷中,2=审核未通过,3=已撤销,11=已印刷;teaMap 为空时走 SDK 兜底)。
private async Task GetStatusByCodeAsync(string statusid, int stepid, string zhipai, int? freestepid, Dictionary teaMap)
{
if (statusid == "0")
{
if (stepid > 0)
{
// 固有流程
var userids = (await _groupuser.FindAsync(a => a.usergroup == stepid))
.Select(a => a.userid ?? 0).Where(u => u > 0).Distinct().ToList();
if (!string.IsNullOrEmpty(zhipai))
{
var ids = zhipai.Split(',').Where(s => int.TryParse(s, out _)).Select(int.Parse).ToList();
userids = userids.Where(u => ids.Contains(u)).ToList();
}
var names = await GetTeaNamesAsync(userids, teaMap);
return string.Join(",", names) + " 审核中";
}
if ((freestepid ?? 0) > 0)
{
// 自由流程
var userids = (await _freegroup.FindAsync(a => a.usergroup == freestepid))
.Select(a => a.userid ?? 0).Where(u => u > 0).Distinct().ToList();
var names = await GetTeaNamesAsync(userids, teaMap);
return string.Join(",", names) + " 审核中";
}
return "";
}
if (statusid == "1") return "印刷中";
if (statusid == "2") return "审核未通过";
if (statusid == "3") return "已撤销";
if (statusid == "11") return "已印刷";
return "";
}
/// 按 id 顺序取教师名:校内映射优先(teaMap 可为 null),缺失的批量走 SDK 兜底。
private async Task> GetTeaNamesAsync(List ids, Dictionary teaMap)
{
var map = teaMap ?? new Dictionary();
var missing = ids.Where(i => !map.ContainsKey(i)).Distinct().ToList();
var fallback = new Dictionary();
if (missing.Count > 0)
{
var teas = await _sch.TeaInfo.GetArrTeaInfoAsync(string.Join(",", missing));
fallback = teas.Where(t => int.TryParse(t.TeaSerId, out _))
.GroupBy(t => int.Parse(t.TeaSerId))
.ToDictionary(g => g.Key, g => g.First().Name ?? "");
}
return ids.Select(i => map.TryGetValue(i, out var t) ? t.Name : fallback.TryGetValue(i, out var n) ? n : "").ToList();
}
/// 是否禁编辑(旧 GetEditDeleteStatus:待审且无任何审核流水才可编辑)。
private Task GetEditDeleteStatusAsync(int dateid, string status)
{
if (status == "0")
return _flowtranct.AnyAsync(a => a.dataid == dateid && a.datatype == DocPrintConstants.AppCode.ToString());
return Task.FromResult(true);
}
private async Task BuildListItemAsync(WY_DocPrint item, (string Name, string Photo) tea,
Dictionary dictMap, string editDateFormat, string docTypeDictType = "WYFL")
{
return new DocPrintListItem
{
SerID = (int)item.SerID,
DocContent = item.DocContent,
DocType = item.DocType,
DocTypeName = DictName(dictMap, docTypeDictType, item.DocType),
DocStyle = item.DocStyle,
DocStyleName = DictName(dictMap, "YZBM", item.DocStyle),
DPType = item.DPType,
DPTypeName = DictName(dictMap, "YZFL", item.DPType),
EditDate = item.EditDate.ToString(editDateFormat),
TakeDate = item.TakeDate?.ToString("yyyy-MM-dd"),
UserID = item.UserID,
teaname = tea.Name,
TeaPhoto = tea.Photo,
DocShare = item.DocShare,
UpFile = item.UpFile,
DocTitle = item.DocTitle,
DocStatus = item.DocStatus,
DocStatusName = await GetStatusByCodeAsync(item.DocStatus, item.DocStep ?? 0, item.zhipai, item.freestepid, null),
DocStep = item.DocStep,
flowid = item.flowid,
_disabled = await GetEditDeleteStatusAsync((int)item.SerID, item.DocStatus),
FreeUserID = item.FreeUserID,
SendUserID = item.SendUserID,
freestepid = item.freestepid,
explain = item.explain,
};
}
/// 统计明细条目(旧 List4/List5 投影,editstatus 对应旧 Common.GetEditDeleteStatus)。
private async Task> BuildStatListAsync(List docs, string schSerId)
{
var teaMap = await GetTeaMapAsync(schSerId);
var dictMap = await GetDictMapAsync(schSerId);
var firstStepIds = (await _flowstep.FindAsync(m => m.prestep == 0))
.Select(m => m.SerID).ToHashSet();
var result = new List();
foreach (var item in docs)
{
TryGetTea(teaMap, item.UserID, out var tea);
bool editstatus = true;
if (item.DocStatus != "1" && item.DocStatus != "2" && item.DocStep.HasValue)
editstatus = !firstStepIds.Contains(item.DocStep.Value); // 一审可编辑 → false
result.Add(new StatListItem
{
SerID = (int)item.SerID,
DocContent = item.DocContent,
DocType = item.DocType,
DocTypeName = DictName(dictMap, "WYFL", item.DocType),
DocStyle = item.DocStyle,
DocStyleName = DictName(dictMap, "YZBM", item.DocStyle),
DPType = item.DPType,
DPTypeName = DictName(dictMap, "YZFL", item.DPType),
EditDate = item.EditDate.ToString("yyyy-MM-dd"),
UserID = item.UserID,
teaname = tea.Name,
UpFile = item.UpFile,
DocTitle = item.DocTitle,
DocStatus = item.DocStatus,
DocStatusName = await GetStatusByCodeAsync(item.DocStatus, item.DocStep ?? 0, item.zhipai, item.freestepid, null),
editstatus = editstatus,
DocStep = item.DocStep,
flowid = item.flowid,
});
}
return result;
}
#endregion
#region 内部辅助:流程挂链 / 抄送 / 附件
/// 自由流程挂链(旧 ApproveFlow.SetPrimarySteptID:从 stepid 起沿 laststep 链回写 dataid)。
private async Task SetPrimarySteptIDAsync(int dataid, int stepid)
{
var node = await _freeflowinfo.FirstOrDefaultAsync(a => a.SerID == stepid);
if (node != null)
{
node.dataid = dataid;
await _freeflowinfo.SaveChangesAsync();
}
var nextSer = stepid;
while (true)
{
var next = await _freeflowinfo.FirstOrDefaultAsync(a => a.laststep == nextSer);
if (next == null) break;
next.dataid = dataid;
await _freeflowinfo.SaveChangesAsync();
nextSer = next.SerID;
}
}
/// 抄送人落库(旧 ApproveFlow.SetChaoSend:按用户+flowType 全删再插)。
private async Task SetChaoSendAsync(int uid, string schSerId, string senduserid)
{
var olds = await _senduser.FindAsync(a => a.flowType == DocPrintConstants.AppCode && a.userid == uid);
foreach (var old in olds)
{
await _senduser.RemoveAsync(old);
}
await _senduser.SaveChangesAsync();
await _senduser.AddAsync(new Common_SendUserinfo
{
userid = uid,
flowType = DocPrintConstants.AppCode,
Senduserid = senduserid,
schserid = schSerId,
createTime = DateTime.Now,
});
await _senduser.SaveChangesAsync();
}
/// 附件 TopicID 回写(旧 Create 的 Attach + SetModifiedProperty("TopicID"))。
private async Task BindFilesTopicAsync(string upFile, int topicId)
{
if (string.IsNullOrEmpty(upFile)) return;
var fids = ParseIds(upFile);
foreach (var fid in fids)
{
var file = await _files.FirstOrDefaultAsync(x => x.SerID == fid);
if (file != null)
{
file.TopicID = topicId;
await _files.UpdateAsync(file);
}
}
await _files.SaveChangesAsync();
}
/// 月份间隔(旧 MonthDiff:跨年分段补零)。
private static List MonthDiff(DateTime start, DateTime end)
{
var months = new List();
int sMonth = start.Month;
int sYear = start.Year;
int eMonth = end.Month;
int eYear = end.Year;
if (end.Year > start.Year)
{
var tempStart = sMonth;
while (tempStart <= 12)
{
months.Add(sYear + "," + tempStart);
tempStart++;
}
var tempEnd = 1;
while (tempEnd <= eMonth)
{
months.Add(eYear + "," + tempEnd);
tempEnd++;
}
}
else
{
var tempStart = sMonth;
var tempEnd = eMonth;
while (tempStart <= tempEnd)
{
months.Add(eYear + "," + tempStart);
tempStart++;
}
}
return months;
}
#endregion
}
}