Files
DocprintService/src/YhCore.Service/Impl/WYDocPrintService.cs
T
2026-09-02 10:23:24 +08:00

1340 lines
61 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
/// <summary>
/// 文印核心业务服务(移植旧 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 去重实现,语义一致。
/// </summary>
public class WYDocPrintService : IWYDocPrintService
{
private readonly IRepository<WY_DocPrint> _doc;
private readonly IRepository<Common_Dictionary> _dic;
private readonly IRepository<Common_flowinfo> _flowinfo;
private readonly IRepository<Common_flowstep> _flowstep;
private readonly IRepository<Common_flowtranctInfo> _flowtranct;
private readonly IRepository<Common_Groupuser> _groupuser;
private readonly IRepository<Common_freeGroupuser> _freegroup;
private readonly IRepository<Common_freeflowinfo> _freeflowinfo;
private readonly IRepository<Common_UserFlowZhipai> _zhipai;
private readonly IRepository<Common_SendUserinfo> _senduser;
private readonly IRepository<Common_UpFiles> _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<WY_DocPrint> doc,
IRepository<Common_Dictionary> dic,
IRepository<Common_flowinfo> flowinfo,
IRepository<Common_flowstep> flowstep,
IRepository<Common_flowtranctInfo> flowtranct,
IRepository<Common_Groupuser> groupuser,
IRepository<Common_freeGroupuser> freegroup,
IRepository<Common_freeflowinfo> freeflowinfo,
IRepository<Common_UserFlowZhipai> zhipai,
IRepository<Common_SendUserinfo> senduser,
IRepository<Common_UpFiles> 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 抄送
/// <summary>抄送列表(旧 SendRdList:DocStatus 1/11,SendUserID 含本人;旧为教师内连接)。</summary>
public async Task<List<DocPrintListItem>> 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<DocPrintListItem>();
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;
}
/// <summary>查看抄送人员详情(旧 SendDetailsList)。</summary>
public async Task<List<SendDetailItem>> SendDetailsListAsync(int serId)
{
var result = new List<SendDetailItem>();
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;
}
/// <summary>修改抄送人(旧 EditSend:SetChaoSend + 回写 WY_DocPrint.SendUserID)。</summary>
public async Task<string> 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 附件
/// <summary>获取附件数据源(旧 filelist)。</summary>
public async Task<List<DocPrintFileItem>> FileListAsync(string ids)
{
var result = new List<DocPrintFileItem>();
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
/// <summary>
/// 添加文印(旧 Create):落库 + 首步骤定位 + 附件 TopicID 回写 + 指派 upsert + 自由流程挂链 + 抄送。
/// 旧短信/待办/已读未读推送降级为纯落库;旧 OtherData(IsNextStepMyShenhe) 新响应无槽位,不再返回。
/// </summary>
public async Task<int> 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;
}
/// <summary>
/// 修改文印(旧 Edit):字段覆盖 + 状态复位 0 + 附件/指派/自由流程/抄送处理。
/// 旧实现附件差异比对因 UpFile 已先被覆盖而成为死代码(新增附件不回写 TopicID),此处保持同样行为。
/// </summary>
public async Task<int> 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;
}
/// <summary>删除文印(旧 Delete:按 ids 批量物理删除;旧待办中心清理已降级)。</summary>
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();
}
/// <summary>撤销(旧 Revoke:写撤销流水 + 更新单据状态;旧待办/短信/已读未读已降级)。</summary>
public async Task<string> 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 列表
/// <summary>我的文印列表(旧 MyList;旧 DocTypeName 误用 YZBM 字典,此处保持旧行为)。</summary>
public async Task<List<DocPrintListItem>> 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<DocPrintListItem>();
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;
}
/// <summary>
/// 全部文印列表(旧 AllList 原生 SQL 四分类:x=待我审(0) y=我已审(1) z=抄送我(2) m=我发起(3),按优先级去重)。
/// 旧 Name 过滤的 SQL 拼接存在运算符优先级缺陷,此处按语义实现:内容/教师名/字典名任一命中。
/// </summary>
public async Task<List<DocPrintListItem>> 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<decimal>();
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<DocPrintListItem>();
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;
}
/// <summary>
/// 文印审核列表(旧 ShenheList:固定流程 + 指派 + 自由流程三路并集,HashSet 去重)。
/// 旧实现的 Name 过滤作用在未被使用的查询上(死代码),此处保持 Name 不生效的旧行为。
/// </summary>
public async Task<List<DocPrintListItem>> 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<DocPrintListItem>();
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;
}
/// <summary>
/// 审批列表(旧 SPList:待审(DS,zt=false)∪ 我已审(YS,zt=true,排除 DS),_disabled 即 zt)。
/// </summary>
public async Task<List<DocPrintListItem>> 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<DocPrintListItem>();
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;
}
/// <summary>文印已审列表(旧 YishenList:本人审核流水关联,排除撤销与已领取)。</summary>
public async Task<List<DocPrintListItem>> 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<DocPrintListItem>();
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;
}
/// <summary>全部文印列表(旧 totalList,管理员视角,按状态/时间过滤)。</summary>
public async Task<List<DocPrintListItem>> 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<DocPrintListItem>();
foreach (var item in docs)
{
TryGetTea(teaMap, item.UserID, out var tea);
result.Add(await BuildListItemAsync(item, tea, dictMap, "yyyy-MM-dd"));
}
return result;
}
/// <summary>
/// 获取当前一条文印详情(旧 MyListtoOne:单元素列表 + 附件明细;
/// 旧 OtherData.tempresultfile 并入条目 tempresultfile,userCenterUrl/teaPhoto 头像不再返回)。
/// </summary>
public async Task<List<DocPrintDetailItem>> MyListtoOneAsync(int serId, string schSerId)
{
var result = new List<DocPrintDetailItem>();
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<DocPrintFileItem>(),
};
// 附件明细: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;
}
/// <summary>绑定流程(旧 Bindflowinfo:本校启用流程下拉)。</summary>
public async Task<List<BindFlowOption>> 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 审核动作
/// <summary>
/// 审核确认(旧 shenheok):事务内写流水 + 推进固定/自由流程或终态;
/// 重复审核 / 已处理单据按旧语义抛业务异常;旧短信/待办/已读未读已降级。
/// </summary>
public async Task<string> 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;
}
}
/// <summary>
/// 领取确认(旧 AffirmApplyforOk):写 actionstatus=11 流水 + 单据置为已领取(11)。
/// 旧代码查重用 datatype=="1010" 而写入用 AppCode(1003),导致查重永远为空;
/// 此处统一为 1003 修正重复领取校验。
/// </summary>
public async Task<string> 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 指派
/// <summary>查询指派(旧 GetUserZhipai:取最近一次指派记录)。</summary>
public async Task<string> 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;
}
/// <summary>
/// 指派 upsert(旧 UserFlowZhipai:flowid&gt;0 时按六元组查重,有则更新无则新增;异常按旧实现吞掉不回滚主流程)。
/// </summary>
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 统计
/// <summary>文印数量按月统计(旧 List1:按年月分组 + MonthDiff 补零;起止时间任一为空时不补零)。</summary>
public async Task<List<MonthStatItem>> 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<MonthStatItem>();
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;
}
/// <summary>文印详情统计列表(旧 List2:非待审单据按申请时间倒序分页)。</summary>
public async Task<List<DocDetailStatItem>> 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<DocDetailStatItem>();
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();
}
/// <summary>文印数量按用户排名(旧 List3)。</summary>
public async Task<List<UserRankItem>> 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();
}
/// <summary>按月份统计明细(旧 List4:指定年月已印好单据,按申请时间倒序分页)。</summary>
public async Task<List<StatListItem>> 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);
}
/// <summary>按用户统计明细(旧 List5:指定用户已印好单据,按申请时间倒序分页)。</summary>
public async Task<List<StatListItem>> 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 内部辅助:查询集合
/// <summary>
/// 待审单据集合(旧 SPList/ShenheList/GetShnheCount 的三路 Union,HashSet 去重):
/// 固定流程组命中 / 指派包含本人 / 自由流程组命中。
/// requireFlowIdNonZero:旧 SPList 固定分支带 flowid != 0 条件,ShenheList 仅 flowid != null。
/// </summary>
private async Task<List<WY_DocPrint>> 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<WY_DocPrint, bool>(a => a.flowid != null && a.flowid != 0)
: new Func<WY_DocPrint, bool>(a => a.flowid != null);
var result = new HashSet<decimal>();
var list = new List<WY_DocPrint>();
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<Dictionary<int, (string Name, string Photo)>> 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<int, (string Name, string Photo)> 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<int, (string Name, string Photo)> teaMap, string userId)
=> TryGetTea(teaMap, userId, out var tea) ? tea.Name : "";
/// <summary>字典名缓存(旧 Get_DictionaryOnly:typeID+CodeID 定位,本校或通用,按 Enable 升序取首个)。</summary>
private async Task<Dictionary<string, string>> 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<string, string> dictMap, string type, string code)
=> code != null && dictMap.TryGetValue(type + "|" + code, out var name) ? name : "";
private static bool DictNameContains(Dictionary<string, string> dictMap, string type, string code, string name)
{
var dictName = DictName(dictMap, type, code);
return dictName != null && dictName.IndexOf(name) >= 0;
}
private static List<int> ParseIds(string commaIds)
{
if (string.IsNullOrEmpty(commaIds)) return new List<int>();
return commaIds.Split(',')
.Where(a => !string.IsNullOrEmpty(a) && int.TryParse(a, out _))
.Select(int.Parse).ToList();
}
#endregion
#region 内部辅助:状态 / 列表项
/// <summary>状态文案(旧 GetStatusByCode:0=待审人名+审核中,1=印刷中,2=审核未通过,3=已撤销,11=已印刷;teaMap 为空时走 SDK 兜底)。</summary>
private async Task<string> GetStatusByCodeAsync(string statusid, int stepid, string zhipai, int? freestepid, Dictionary<int, (string Name, string Photo)> 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 "";
}
/// <summary>按 id 顺序取教师名:校内映射优先(teaMap 可为 null),缺失的批量走 SDK 兜底。</summary>
private async Task<List<string>> GetTeaNamesAsync(List<int> ids, Dictionary<int, (string Name, string Photo)> teaMap)
{
var map = teaMap ?? new Dictionary<int, (string Name, string Photo)>();
var missing = ids.Where(i => !map.ContainsKey(i)).Distinct().ToList();
var fallback = new Dictionary<int, string>();
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();
}
/// <summary>是否禁编辑(旧 GetEditDeleteStatus:待审且无任何审核流水才可编辑)。</summary>
private Task<bool> 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<DocPrintListItem> BuildListItemAsync(WY_DocPrint item, (string Name, string Photo) tea,
Dictionary<string, string> 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,
};
}
/// <summary>统计明细条目(旧 List4/List5 投影,editstatus 对应旧 Common.GetEditDeleteStatus)。</summary>
private async Task<List<StatListItem>> BuildStatListAsync(List<WY_DocPrint> 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<StatListItem>();
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 内部辅助:流程挂链 / 抄送 / 附件
/// <summary>自由流程挂链(旧 ApproveFlow.SetPrimarySteptID:从 stepid 起沿 laststep 链回写 dataid)。</summary>
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;
}
}
/// <summary>抄送人落库(旧 ApproveFlow.SetChaoSend:按用户+flowType 全删再插)。</summary>
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();
}
/// <summary>附件 TopicID 回写(旧 Create 的 Attach + SetModifiedProperty("TopicID"))。</summary>
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();
}
/// <summary>月份间隔(旧 MonthDiff:跨年分段补零)。</summary>
private static List<string> MonthDiff(DateTime start, DateTime end)
{
var months = new List<string>();
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
}
}