1340 lines
61 KiB
C#
1340 lines
61 KiB
C#
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>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
|
||
}
|
||
}
|