Browse Source

自贡12345 - 预案库管理

libin 4 months ago
parent
commit
98d94590dc

+ 212 - 17
src/Hotline.Api/Controllers/PlanController.cs

@@ -7,8 +7,11 @@ using Hotline.Share.Dtos.Planlibrary;
 using SqlSugar;
 using Hotline.Planlibrary;
 using XF.Domain.Exceptions;
-using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Dtos;
+using Hotline.Share.Tools;
+using Hotline.Share.Enums.Planlibrary;
+using Hotline.Application.ExportWord;
+using Hotline.Application.Tools;
 
 namespace Hotline.Api.Controllers
 {
@@ -17,24 +20,34 @@ namespace Hotline.Api.Controllers
     /// </summary>
     public class PlanController : BaseController
     {
+
         #region 注入
 
         private readonly IMapper _mapper;
         private readonly ISessionContext _sessionContext;
         private readonly IPlanApplication _planApplication;
         private readonly IRepository<PlanType> _planTypeRepository;
+        private readonly IRepository<PlanList> _planListRepository;
+        private readonly IRepository<PlanCollect> _planCollectRepository;
+        private readonly IWordHelperService _wordHelperService;
 
 
         public PlanController(
            IMapper mapper,
            ISessionContext sessionContext,
            IPlanApplication planApplication,
-           IRepository<PlanType> planTypeRepository)
+           IRepository<PlanType> planTypeRepository,
+           IRepository<PlanList> planListRepository,
+           IRepository<PlanCollect> planCollectRepository,
+           IWordHelperService wordHelperService)
         {
             _mapper = mapper;
             _sessionContext = sessionContext;
             _planApplication = planApplication;
             _planTypeRepository = planTypeRepository;
+            _planListRepository = planListRepository;
+            _planCollectRepository = planCollectRepository;
+            _wordHelperService = wordHelperService;
         }
 
         #endregion
@@ -47,7 +60,7 @@ namespace Hotline.Api.Controllers
         /// <param name="IsEnable">是否启用</param>
         /// <returns></returns>
         [HttpGet("type/treelist")]
-        public async Task<List<PlanTypeDto>> GetTreeList(bool? IsEnable)
+        public async Task<List<PlanTypeDto>> QueryAllTreeList(bool? IsEnable)
         {
             return await _planTypeRepository.Queryable()
                 .WhereIF(IsEnable.HasValue, x => x.IsEnable == IsEnable)
@@ -70,7 +83,7 @@ namespace Hotline.Api.Controllers
         [HttpPost("type/add")]
         public async Task<string> AddType([FromBody] AddPlanTypeDto dto)
         {
-            return await _planApplication.AddType(dto, HttpContext.RequestAborted);
+            return await _planApplication.AddTypeAsync(dto, HttpContext.RequestAborted);
         }
 
         /// <summary>
@@ -81,7 +94,7 @@ namespace Hotline.Api.Controllers
         [HttpPut("type/update")]
         public async Task UpdateType([FromBody] UpdatePlanTypeDto dto)
         {
-            await _planApplication.UpdateType(dto, HttpContext.RequestAborted);
+            await _planApplication.UpdateTypeAsync(dto, HttpContext.RequestAborted);
         }
 
         /// <summary>
@@ -109,25 +122,207 @@ namespace Hotline.Api.Controllers
         [HttpDelete("type/remove/{Id}")]
         public async Task RemoveType(string Id)
         {
-            await _planApplication.RemoveType(Id, HttpContext.RequestAborted);
+            await _planApplication.RemoveTypeAsync(Id, HttpContext.RequestAborted);
         }
 
         #endregion
 
         #region 预案库管理
 
-        ///// <summary>
-        ///// 预案库列表
-        ///// </summary>
-        ///// <param name="pagedDto"></param>
-        ///// <returns></returns>
-        //[HttpGet("list")]
-        //public async Task<PagedDto<KnowledgeDataDto>> GetKnowList([FromQuery] KnowPagedListDto pagedDto)
-        //{
-        //    return (await _planApplication.GetKnowList(pagedDto, HttpContext.RequestAborted))
-        //        .ToPaged();
-        //}
+        /// <summary>
+        /// 预案库列表
+        /// </summary>
+        /// <param name="pagedDto"></param>
+        /// <returns></returns>
+        [HttpGet("list")]
+        public async Task<PagedDto<PlanDataDto>> QueryAllPlanList([FromQuery] PlanListDto pagedDto)
+        {
+            return (await _planApplication.QueryAllPlanListAsync(pagedDto, HttpContext.RequestAborted)).ToPaged();
+        }
+
+        /// <summary>
+        /// 预案库草稿
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("list/draft")]
+        public async Task<string> AddPlanDraft([FromBody] AddPlanListDto dto)
+        {
+            dto.Status = EPlanStatus.Drafts;
+            return await _planApplication.AddPlanAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 预案库新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("list/add")]
+        public async Task<string> AddPlan([FromBody] AddPlanListDto dto)
+        {
+            dto.ApplyStatus = EPlanApplyStatus.Add;
+            dto.Status = EPlanStatus.Auditing;
+            return await _planApplication.AddPlanAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 预案库编辑
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("list/update")]
+        public async Task UpdatePlan([FromBody] UpdatePlanListDto dto)
+        {
+            dto.ApplyStatus = EPlanApplyStatus.Update;
+            dto.Status = EPlanStatus.Auditing;
+            await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 预案库下架
+        /// </summary>
+        /// <param name="Id">预案库ID</param>
+        /// <returns></returns>
+        [HttpPut("list/offshelf")]
+        public async Task OffshelfPlan(string Id)
+        {
+            UpdatePlanListDto dto = new UpdatePlanListDto();
+            dto.Id = Id;
+            dto.ApplyStatus = EPlanApplyStatus.Offshelf;
+            dto.Status = EPlanStatus.Auditing;
+
+            await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 预案库审核(新增、修改、下架)
+        /// </summary>
+        /// <param name="Id">预案库ID</param>
+        /// <param name="state">0不通过 1通过</param>
+        /// <returns></returns>
+        [HttpPut("list/examin")]
+        public async Task ExaminPlan(string Id, int state)
+        {
+            var plan = await _planListRepository.GetAsync(Id);
+            if (plan == null)
+                throw UserFriendlyException.SameMessage("预案库查询失败");
+
+            var planDto = _mapper.Map<UpdatePlanListDto>(plan);
+
+            if (state == 0)
+            {//不同意
+                planDto.Status = EPlanStatus.Drafts;
+            }
+            else if (state == 1)
+            {//同意 
+                if (planDto.ApplyStatus == EPlanApplyStatus.Add)
+                {
+                    planDto.Status = EPlanStatus.OnShelf;
+                }
+                if (planDto.ApplyStatus == EPlanApplyStatus.Update)
+                {
+                    planDto.Status = EPlanStatus.OnShelf;
+                }
+                if (planDto.ApplyStatus == EPlanApplyStatus.Offshelf)
+                {
+                    planDto.Status = EPlanStatus.OffShelf;
+                }
+            }
+            planDto.Id = Id;
+            planDto.ExaminTime = DateTime.Now;
+            planDto.ExaminManId = _sessionContext.UserId;
+            planDto.ExaminOrganizeId = _sessionContext.OrgId;
+
+            await _planApplication.UpdatePlanAsync(planDto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 预案库详情
+        /// </summary>
+        /// <param name="Id">预案库ID</param>
+        /// <param name="IsAddPv">默认不增加,false不增加,true增加浏览量</param>
+        /// <returns></returns>
+        [HttpGet("list/info/{Id}")]
+        public async Task<PlanInfoDto> GetPlan(string Id, bool? IsAddPv)
+        {
+            return await _planApplication.GetPlanAsync(Id, IsAddPv, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 预案库评分
+        /// </summary>
+        /// <param name="Id">预案库ID</param>
+        /// <param name="Score">评分</param>
+        /// <returns></returns>
+        [HttpPut("list/score")]
+        public async Task ScorePlan(string Id, decimal Score)
+        {
+            var collect = await _planCollectRepository.GetAsync(x => x.PlanId == Id && x.CreatorId == _sessionContext.UserId);
+            if (collect != null)
+            {
+                if (collect.Score > 0)
+                    throw UserFriendlyException.SameMessage("当前知识已经评分");
+
+                collect.Score = Score;
+                await _planCollectRepository.UpdateAsync(collect, HttpContext.RequestAborted);
+            }
+            else
+            {
+                collect.PlanId = Id;
+                collect.Score = Score;
+                await _planCollectRepository.AddAsync(collect, HttpContext.RequestAborted);
+            }
+
+            //计算总分
+            var sugar = _planCollectRepository.Queryable().Where(x => x.PlanId == Id);
+            var count = await sugar.CountAsync();
+            var collects = await sugar.SumAsync(x => x.Score);
+            var scoreTemp = collects / count;
+            var plan = await _planListRepository.GetAsync(x => x.Id == Id);
+            if (plan != null)
+            {
+                plan.Score = decimal.Round(scoreTemp.Value, 1);
+                await _planListRepository.UpdateAsync(plan, HttpContext.RequestAborted);
+            }
+        }
+
+        /// <summary>
+        /// 预案库查重
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("list/exist")]
+        public async Task<bool> ExistPlan([FromBody] PlanExistDto dto)
+        {
+            var any = await _planListRepository.Queryable()
+                .Where(x => x.Status == EPlanStatus.Auditing || x.Status >= EPlanStatus.OnShelf)
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Equals(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.Content), x => x.Content.Equals(dto.Content))
+                .WhereIF(!string.IsNullOrEmpty(dto.Id), x => x.Id != dto.Id)
+                .AnyAsync();
+            return any;
+        }
+
+        /// <summary>
+        /// 预案库导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("list/info/export")]
+        public async Task<IActionResult> PlanInfoExport([FromBody] PlanInfoExportDto dto)
+        {
+            if (dto.Ids.Length > 1)
+            {
+                var streams = await _planApplication.PlanInfoListExportAsync(dto, HttpContext.RequestAborted);
+                byte[] fileBytes = _wordHelperService.ConvertZipStream(streams);
+                var name = DateTime.Now.ToString("yyyyMMddHHmmss");
+                return File(fileBytes, "application/octet-stream", $"{name}.zip");
+            }
+            var info = await _planListRepository.GetAsync(dto.Ids[0]) ?? throw UserFriendlyException.SameMessage("预案不存在");
+            return info.Content.HtmlToStream(dto.FileType).GetFileStreamResult(dto.FileType, info.Title, false);
+        }
 
         #endregion
+
     }
 }

+ 33 - 17
src/Hotline.Application/Planlibrary/IPlanApplication.cs

@@ -1,5 +1,4 @@
 using Hotline.Share.Dtos.Planlibrary;
-using Hotline.Share.Dtos.Knowledge;
 
 namespace Hotline.Application.Planlibrary
 {
@@ -13,46 +12,63 @@ namespace Hotline.Application.Planlibrary
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        Task<string> AddType(AddPlanTypeDto dto, CancellationToken cancellationToken);
+        Task<string> AddTypeAsync(AddPlanTypeDto dto, CancellationToken cancellationToken);
 
         /// <summary>
         ///预案库类型 - 编辑
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        Task UpdateType(UpdatePlanTypeDto dto, CancellationToken cancellationToken);
+        Task UpdateTypeAsync(UpdatePlanTypeDto dto, CancellationToken cancellationToken);
 
         /// <summary>
         /// 预案库类型 - 删除
         /// </summary>
         /// <param name="Id"></param>
         /// <returns></returns>
-        Task RemoveType(string Id, CancellationToken cancellationToken);
+        Task RemoveTypeAsync(string Id, CancellationToken cancellationToken);
 
         #endregion
 
         #region 预案库管理
 
-        // 预案库分类列表
-
         /// <summary>
         /// 预案库 - 列表
         /// </summary>
         /// <param name="pagedDto"></param>
         /// <returns></returns>
-        //Task<(int, IList<KnowledgeDataDto>)> GetKnowList(KnowPagedListDto pagedDto, CancellationToken cancellationToken);
+        Task<(int, IList<PlanDataDto>)> QueryAllPlanListAsync(PlanListDto pagedDto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 预案库 - 新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task<string> AddPlanAsync(AddPlanListDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        ///预案库类型 - 编辑
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task UpdatePlanAsync(UpdatePlanListDto dto, CancellationToken cancellationToken);
 
-        // 新增(没有关键字、根据内容生成关键词,保存为草稿)
-        // 编辑
-        // 详情(增加阅读量)
-        // 审核(新增、修改、删除、下架)
-        // 下架
-        // 删除
-        // 评分
-        // 导出
+        /// <summary>
+        ///预案库类型 - 详情
+        /// </summary>
+        /// <param name="Id"></param>
+        /// <param name="IsAddPv">默认不增加,false不增加,true增加浏览量</param>
+        /// <returns></returns>
+        Task<PlanInfoDto> GetPlanAsync(string Id, bool? IsAddPv, CancellationToken cancellationToken);
 
-        // 生成关键词
-        // 关键词列表
+        /// <summary>
+        /// 预案库类型 - 批量导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task<Dictionary<string, Stream>> PlanInfoListExportAsync(PlanInfoExportDto dto, CancellationToken cancellationToken);
 
         #endregion
 

+ 245 - 71
src/Hotline.Application/Planlibrary/PlanApplication.cs

@@ -1,19 +1,19 @@
-using DocumentFormat.OpenXml.Office2010.Excel;
-using Hotline.Application.Knowledge;
-using Hotline.KnowledgeBase;
-using Hotline.Planlibrary;
-using Hotline.Repository.SqlSugar.Knowledge;
+using Hotline.Planlibrary;
 using Hotline.Settings.Hotspots;
-using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Dtos.Planlibrary;
-using Hotline.Share.Enums.KnowledgeBase;
 using Hotline.Share.Enums.Planlibrary;
 using MapsterMapper;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.SeedData;
+using Hotline.File;
+using Hotline.Application.Bulletin;
+using Hotline.Share.Tools;
+using Hotline.Application.Tools;
 
 namespace Hotline.Application.Planlibrary
 {
@@ -22,6 +22,7 @@ namespace Hotline.Application.Planlibrary
     /// </summary>
     public class PlanApplication : IPlanApplication, IScopeDependency
     {
+
         #region 注册
 
         private readonly IRepository<PlanList> _planListRepository;                      //预案库列表
@@ -31,15 +32,19 @@ namespace Hotline.Application.Planlibrary
         private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
         private readonly IRepository<Hotspot> _hotspotTypeRepository;
+        private readonly IFileRepository _fileRepository;
+        private readonly IBulletinApplication _bulletinApplication;
 
         public PlanApplication(
             IRepository<PlanList> planListRepository,
             IRepository<PlanRelationType> planRelationTypeRepository,
             IRepository<PlanType> planTypeRepository,
-            IRepository<PlanTypeOrg> planTypeOrgRepository, 
+            IRepository<PlanTypeOrg> planTypeOrgRepository,
             ISessionContext sessionContext,
             IMapper mapper,
-            IRepository<Hotspot> hotspotTypeRepository)
+            IRepository<Hotspot> hotspotTypeRepository,
+            IFileRepository fileRepository,
+            IBulletinApplication bulletinApplication)
         {
             _planListRepository = planListRepository;
             _planRelationTypeRepository = planRelationTypeRepository;
@@ -48,6 +53,8 @@ namespace Hotline.Application.Planlibrary
             _sessionContext = sessionContext;
             _mapper = mapper;
             _hotspotTypeRepository = hotspotTypeRepository;
+            _fileRepository = fileRepository;
+            _bulletinApplication = bulletinApplication;
         }
 
         #endregion
@@ -62,7 +69,7 @@ namespace Hotline.Application.Planlibrary
         /// <param name="dto"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task<string> AddType(AddPlanTypeDto dto, CancellationToken cancellationToken)
+        public async Task<string> AddTypeAsync(AddPlanTypeDto dto, CancellationToken cancellationToken)
         {
             var sandard = await _planTypeRepository.GetAsync(p => p.ParentId == dto.ParentId && p.Name == dto.Name && p.IsDeleted == false, cancellationToken);
             if (sandard is not null)
@@ -89,7 +96,7 @@ namespace Hotline.Application.Planlibrary
         /// <param name="dto"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task UpdateType(UpdatePlanTypeDto dto, CancellationToken cancellationToken)
+        public async Task UpdateTypeAsync(UpdatePlanTypeDto dto, CancellationToken cancellationToken)
         {
             //查询原有数据
             var type = await _planTypeRepository.GetAsync(dto.Id, cancellationToken);
@@ -134,7 +141,7 @@ namespace Hotline.Application.Planlibrary
         /// <param name="Id"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task RemoveType(string Id, CancellationToken cancellationToken)
+        public async Task RemoveTypeAsync(string Id, CancellationToken cancellationToken)
         {
             //查询数据是否存在
             var sandard = await _planTypeRepository.GetAsync(p => p.Id == Id && p.IsDeleted == false, cancellationToken);
@@ -161,75 +168,241 @@ namespace Hotline.Application.Planlibrary
 
         #region 预案库管理
 
+        #region 预案库 - 列表
+
         /// <summary>
         /// 预案库 - 列表
         /// </summary>
         /// <param name="pagedDto"></param>
         /// <returns></returns>
-        //public async Task<(int, IList<KnowledgeDataDto>)> GetKnowList(KnowPagedListDto pagedDto, CancellationToken cancellationToken)
-        //{
-        //    if (!_sessionContext.OrgIsCenter)
-        //    {
-        //        pagedDto.Attribution = "部门知识库";
-        //    }
-        //    var typeSpliceName = string.Empty;
-        //    var hotspotHotSpotFullName = string.Empty;
-        //    if (!string.IsNullOrEmpty(pagedDto.KnowledgeTypeId))
-        //    {
-        //        var type = await _planTypeRepository.GetAsync(x => x.Id == pagedDto.KnowledgeTypeId);
-        //        typeSpliceName = type?.SpliceName;
-        //    }
-        //    if (!string.IsNullOrEmpty(pagedDto.HotspotId))
-        //    {
-        //        var hotspot = await _hotspotTypeRepository.GetAsync(x => x.Id == pagedDto.HotspotId);
-        //        hotspotHotSpotFullName = hotspot?.HotSpotFullName;
-        //    }
-        //    var (total, temp) = await _knowledgeRepository.Queryable(false, false, false)
-        //        .Includes(x => x.User)
-        //        .Includes(x => x.SystemOrganize)
-        //        .Includes(x => x.SourceOrganize)
-        //        .Includes(x => x.HotspotType)
-        //        .Includes(x => x.Workflow)
-        //        .Includes(x => x.KnowledgeType)
-        //        .Where(x => x.IsDeleted == false)
-        //        .Where(x => x.KnowledgeType.Any(t => t.KnowledgeType.KnowledgeTypeOrgs.Any(to => to.OrgId == _sessionContext.RequiredOrgId) || t.KnowledgeType.KnowledgeTypeOrgs.Any() == false))
-        //        .Where(x => (x.Status == EKnowledgeStatus.Drafts && x.CreatorId == _sessionContext.UserId) || (x.Status != EKnowledgeStatus.Drafts))
-        //        .WhereIF(!string.IsNullOrEmpty(pagedDto.Title), x => x.Title.Contains(pagedDto.Title!))
-        //        .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), x => x.Title.Contains(pagedDto.Keyword!) || x.CreatorName.Contains(pagedDto.Keyword!) || x.CreatorOrgName.Contains(pagedDto.Keyword!) || x.SourceOrganize.Name.Contains(pagedDto.Keyword!))
-        //        .WhereIF(pagedDto.Status.HasValue && pagedDto.Status != EKnowledgeStatus.OffShelf && pagedDto.Status != EKnowledgeStatus.NewDrafts && pagedDto.Status != EKnowledgeStatus.All, x => x.Status == pagedDto.Status && ((x.ExpiredTime != null && x.ExpiredTime > DateTime.Now) || x.ExpiredTime == null))
-        //        .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == EKnowledgeStatus.OffShelf, x => x.Status == pagedDto.Status || (x.ExpiredTime != null && x.ExpiredTime < DateTime.Now && x.Status != EKnowledgeStatus.Drafts))
-        //        .WhereIF(pagedDto.IsPublic.HasValue, x => x.IsPublic == pagedDto.IsPublic)
-        //        .WhereIF(!string.IsNullOrEmpty(pagedDto.Summary), x => x.Summary != null && x.Summary.Contains(pagedDto.Summary!))
-        //        .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.KnowledgeType.Any(t => t.KnowledgeTypeSpliceName.StartsWith(typeSpliceName)))
-        //        .WhereIF(!string.IsNullOrEmpty(hotspotHotSpotFullName), x => x.HotspotType.HotSpotFullName.EndsWith(hotspotHotSpotFullName!))
-        //        .WhereIF(!string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.CreatorOrgId != null && x.CreatorOrgId.StartsWith(pagedDto.CreateOrgId!))
-        //        .WhereIF(!string.IsNullOrEmpty(pagedDto.ModuleCode), x => x.Workflow.ModuleCode == pagedDto.ModuleCode)
-        //        .WhereIF(pagedDto.Status == EKnowledgeStatus.NewDrafts, x => x.Status == EKnowledgeStatus.Drafts || x.Status == EKnowledgeStatus.Revert)
-        //        .WhereIF(pagedDto.NewDraftsStatus is EKnowledgeStatus.Drafts, x => x.Status == EKnowledgeStatus.Drafts)
-        //        .WhereIF(pagedDto.NewDraftsStatus is EKnowledgeStatus.Revert, x => x.Status == EKnowledgeStatus.Revert)
-
-        //        .WhereIF(pagedDto.CreationStartTime.HasValue, x => x.CreationTime >= pagedDto.CreationStartTime)
-        //        .WhereIF(pagedDto.CreationEndTime.HasValue, x => x.CreationTime <= pagedDto.CreationEndTime)
-
-        //          .WhereIF(pagedDto.StartOnShelfTime.HasValue, x => x.OnShelfTime >= pagedDto.StartOnShelfTime)
-        //          .WhereIF(pagedDto.EndOnShelfTime.HasValue, x => x.OnShelfTime <= pagedDto.EndOnShelfTime)
-
-        //           .WhereIF(pagedDto.StartOffShelfTime.HasValue, x => x.OffShelfTime >= pagedDto.StartOffShelfTime)
-        //          .WhereIF(pagedDto.EndOffShelfTime.HasValue, x => x.OffShelfTime <= pagedDto.EndOffShelfTime)
-
-        //          .WhereIF(pagedDto.StartUpdateTime.HasValue, x => x.LastModificationTime >= pagedDto.StartUpdateTime)
-        //          .WhereIF(pagedDto.EndUpdateTime.HasValue, x => x.LastModificationTime <= pagedDto.EndUpdateTime)
-        //        .WhereIF(!string.IsNullOrEmpty(pagedDto.Attribution), x => x.Attribution == pagedDto.Attribution)
-        //        .OrderByDescending(d => d.CreationTime)
-        //        .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, cancellationToken);
-        //    //返回数据
-        //    return (total, _mapper.Map<IList<KnowledgeDataDto>>(temp));
-        //}
+        public async Task<(int, IList<PlanDataDto>)> QueryAllPlanListAsync(PlanListDto pagedDto, CancellationToken cancellationToken)
+        {
+            if (!_sessionContext.OrgIsCenter)
+            {// 部门只能查询【部门预案库】
+                pagedDto.Attribution = "部门预案库";
+            }
+
+            var typeSpliceName = string.Empty;
+            var hotspotHotSpotFullName = string.Empty;
+
+            if (!string.IsNullOrEmpty(pagedDto.PlanTypeID))
+            {
+                var type = await _planTypeRepository.GetAsync(x => x.Id == pagedDto.PlanTypeID);
+                typeSpliceName = type?.SpliceName;
+            }
+
+            if (!string.IsNullOrEmpty(pagedDto.HotspotId))
+            {
+                var hotspot = await _hotspotTypeRepository.GetAsync(x => x.Id == pagedDto.HotspotId);
+                hotspotHotSpotFullName = hotspot?.HotSpotFullName;
+            }
+
+            //单表分页
+            var (total, temp) = await _planListRepository.Queryable()
+                //.Includes(x => x.PlanTypes)
+
+                .Where(x => x.IsDeleted == false)
+                .Where(x => (x.Status == EPlanStatus.Drafts && x.CreatorId == _sessionContext.UserId) || (x.Status != EPlanStatus.Drafts))
+                .WhereIF(OrgSeedData.CenterId != pagedDto.CreateOrgId && !string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.CreatorOrgId != null && x.CreatorOrgId.StartsWith(pagedDto.CreateOrgId!))
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.Attribution), x => x.Attribution == pagedDto.Attribution)
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.Title), x => x.Title.Contains(pagedDto.Title))
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.Keyword), x => x.Title.Contains(pagedDto.Keyword!) ||
+                                                                  x.CreatorName!.Contains(pagedDto.Keyword!) ||
+                                                                  x.CreatorOrgName!.Contains(pagedDto.Keyword!))
+                .WhereIF(pagedDto.Status.HasValue && pagedDto.Status != EPlanStatus.OffShelf &&
+                                                     pagedDto.Status != EPlanStatus.NewDrafts &&
+                                                     pagedDto.Status != EPlanStatus.All,
+                                                        x => x.Status == pagedDto.Status && ((x.ExpiredTime != null && x.ExpiredTime > DateTime.Now) || x.ExpiredTime == null))
+                .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == EPlanStatus.OffShelf, x => x.Status == pagedDto.Status || (x.ExpiredTime != null && x.ExpiredTime < DateTime.Now && x.Status != EPlanStatus.Drafts))
+                .WhereIF(pagedDto.Status.HasValue && pagedDto.Status == EPlanStatus.NewDrafts, x => x.Status == EPlanStatus.Drafts || x.Status == EPlanStatus.Revert)
+                .WhereIF(pagedDto.IsPublic.HasValue, x => x.IsPublic == pagedDto.IsPublic)
+                .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.PlanTypes.Any(t => t.PlanTypeSpliceName.StartsWith(typeSpliceName)))
+                .WhereIF(!string.IsNullOrEmpty(hotspotHotSpotFullName), x => x.HotspotType.HotSpotFullName.EndsWith(hotspotHotSpotFullName!))
+
+                .WhereIF(pagedDto.CreationTimeStart.HasValue, x => x.CreationTime >= pagedDto.CreationTimeStart)
+                .WhereIF(pagedDto.CreationTimeEnd.HasValue, x => x.CreationTime <= pagedDto.CreationTimeEnd)
+
+                .WhereIF(pagedDto.OnShelfTimeStart.HasValue, x => x.OnShelfTime >= pagedDto.OnShelfTimeStart)
+                .WhereIF(pagedDto.OnShelfTimeEnd.HasValue, x => x.OnShelfTime <= pagedDto.OnShelfTimeEnd)
+
+                .WhereIF(pagedDto.OffShelfTimeStart.HasValue, x => x.OffShelfTime >= pagedDto.OffShelfTimeStart)
+                .WhereIF(pagedDto.OffShelfTimeEnd.HasValue, x => x.OffShelfTime <= pagedDto.OffShelfTimeEnd)
+
+                .WhereIF(pagedDto.UpdateTimeStart.HasValue, x => x.UpdateTime >= pagedDto.UpdateTimeStart)
+                .WhereIF(pagedDto.UpdateTimeEnd.HasValue, x => x.UpdateTime <= pagedDto.UpdateTimeEnd)
+
+                .WhereIF(pagedDto.ExaminTimeStart.HasValue, x => x.ExaminTime >= pagedDto.ExaminTimeStart)
+                .WhereIF(pagedDto.ExaminTimeEnd.HasValue, x => x.ExaminTime <= pagedDto.ExaminTimeEnd)
+
+                .OrderByDescending(d => d.CreationTime)
+                .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, cancellationToken);
+
+            return (total, _mapper.Map<IList<PlanDataDto>>(temp));
+        }
+
+        #endregion
+
+        #region 预案库 - 新增
+
+        /// <summary>
+        /// 新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task<string> AddPlanAsync(AddPlanListDto dto, CancellationToken cancellationToken)
+        {
+            var pList = _mapper.Map<PlanList>(dto);
+
+            var any = await _planListRepository.Queryable().Where(x => x.Status == EPlanStatus.OnShelf && x.Title == dto.Title).AnyAsync();
+            if (any)
+                throw UserFriendlyException.SameMessage("当前知识标题存在重复标题!");
+
+            if (dto.Files != null)
+                pList.FileJson = await _fileRepository.AddFileAsync(dto.Files, pList.Id, "", cancellationToken);
+            await _planListRepository.AddAsync(pList, cancellationToken);
+
+            if (dto.PlanType.Any())
+            {
+                List<PlanRelationType> types = _mapper.Map<List<PlanRelationType>>(dto.PlanType);
+                types.ForEach(x => x.PlanId = pList.Id);
+                await _planRelationTypeRepository.AddRangeAsync(types, cancellationToken);
+            }
+
+            return pList.Id;
+        }
+
+        #endregion
+
+        #region 预案库 - 修改
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task UpdatePlanAsync(UpdatePlanListDto dto, CancellationToken cancellationToken)
+        {
+            var plan = await _planListRepository.GetAsync(dto.Id);
+            if (plan == null)
+                throw UserFriendlyException.SameMessage("预案库查询失败");
+
+            if ((plan.Status == EPlanStatus.OnShelf || plan.Status == EPlanStatus.Auditing) && (plan.ExpiredTime.HasValue && plan.ExpiredTime.Value > DateTime.Now))
+                throw UserFriendlyException.SameMessage("预案库数据不可修改");
+
+            var any = await _planListRepository.Queryable().Where(x => x.Status == EPlanStatus.OnShelf && x.Title == dto.Title && x.Id != dto.Id).AnyAsync();
+            if (any)
+                throw UserFriendlyException.SameMessage("当前知识标题存在重复标题!");
+
+            _mapper.Map(dto, plan);
+
+            plan.HotspotId = dto.HotspotId;
+
+            if (dto.Files.Any())
+                plan.FileJson = await _fileRepository.AddFileAsync(dto.Files, plan.Id, "", cancellationToken);
+            else
+                plan.FileJson = new List<Share.Dtos.File.FileJson>();
+
+            await _planListRepository.UpdateNullAsync(plan, cancellationToken);
+            if (dto.PlanType.Any())
+            {
+                var anyRelationTypes = await _planRelationTypeRepository.Queryable().Where(x => x.PlanId == plan.Id).ToListAsync();
+                if (anyRelationTypes.Any())
+                    await _planRelationTypeRepository.RemoveRangeAsync(anyRelationTypes);
+                List<PlanRelationType> types = _mapper.Map<List<PlanRelationType>>(dto.PlanType);
+                types.ForEach(x => x.PlanId = dto.Id);
+                await _planRelationTypeRepository.AddRangeAsync(types, cancellationToken);
+            }
+        }
+
+        #endregion
+
+        #region 预案库 - 详情
+
+        /// <summary>
+        /// 详情
+        /// </summary>
+        /// <param name="Id"></param>
+        /// <param name="IsAddPv">默认不增加,false不增加,true增加浏览量</param>
+        /// <returns></returns>
+        public async Task<PlanInfoDto> GetPlanAsync(string Id, bool? IsAddPv, CancellationToken cancellationToken)
+        {
+            var plan = await _planListRepository.GetAsync(Id);
+            if (plan == null)
+                throw UserFriendlyException.SameMessage("预案库查询失败");
+            ;
+            //转化
+            var planInfoDto = _mapper.Map<PlanInfoDto>(plan);
+
+            if (plan != null && !string.IsNullOrEmpty(plan.Content))
+                planInfoDto.Content = _bulletinApplication.GetSiteUrls(plan.Content);
+
+            // 热点
+            //var hot = await _hotspotTypeRepository.GetAsync(plan.HotspotId, cancellationToken);
+            //if (hot != null)
+            //    planDto.HotspotId = hot.HotSpotFullName;
+            
+            // 收藏
+            //var collect = await _knowledgeCollectRepository.GetAsync(x => x.KnowledgeId == Id && x.CreatorId == _sessionContext.UserId);
+            //if (collect != null)
+            //    knowledgeShowInfoDto.Collect = _mapper.Map<KnowledgeCollectDto>(collect);
+
+            if (planInfoDto.FileJson != null && planInfoDto.FileJson.Any())
+            {
+                var ids = planInfoDto.FileJson.Select(x => x.Id).ToList();
+                planInfoDto.Files = await _fileRepository.GetFilesAsync(ids, cancellationToken);
+            }
+
+            // 更新浏览量
+            //if (IsAddPv == true)
+            //    _mediator.Publish(new GetKnowledgeInfoNotify(knowledge));
+            return planInfoDto;
+        }
 
         #endregion
 
+        #region 预案库 - 批量导出
 
+        /// <summary>
+        /// 预案库 - 批量导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task<Dictionary<string, Stream>> PlanInfoListExportAsync(PlanInfoExportDto dto, CancellationToken cancellationToken)
+        {
+            var streamList = new Dictionary<string, Stream>();
+            var knowList = await _planListRepository.Queryable()
+                .Where(m => dto.Ids.Contains(m.Id))
+                .Select(m => new { m.Title, m.Content })
+                .ToListAsync(cancellationToken);
+
+            var tasks = knowList.Select(async item =>
+            {
+                var stream = await Task.Run(() => item.Content.HtmlToStream(dto.FileType), cancellationToken);
+                return new KeyValuePair<string, Stream>(
+                    item.Title + dto.FileType.GetFileExtension(),
+                    stream
+                );
+            });
+
+            var results = await Task.WhenAll(tasks);
+
+            foreach (var kvp in results)
+            {
+                if (!streamList.ContainsKey(kvp.Key))
+                {
+                    streamList.Add(kvp.Key, kvp.Value);
+                }
+            }
+
+            return streamList;
+        }
 
+        #endregion
+
+        #endregion
 
         #region 私有方法
 
@@ -357,5 +530,6 @@ namespace Hotline.Application.Planlibrary
         #endregion
 
         #endregion
+
     }
 }

+ 181 - 0
src/Hotline.Share/Dtos/Planlibrary/PlanDataDto.cs

@@ -0,0 +1,181 @@
+using Hotline.Share.Dtos.FlowEngine.Workflow;
+using Hotline.Share.Dtos.Hotspots;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Org;
+using Hotline.Share.Enums.Article;
+using Hotline.Share.Enums.KnowledgeBase;
+using Hotline.Share.Enums.Planlibrary;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Share.Dtos.Planlibrary
+{
+    public record PlanDataDto
+    {
+        /// <summary>
+        /// 知识ID
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 创建人
+        /// </summary>
+        public string CreatorName { get; set; }
+
+        /// <summary>
+        /// 浏览量
+        /// </summary>
+        public int PageView { get; set; }
+
+        /// <summary>
+        /// 是否公开
+        /// </summary>
+        public bool IsPublic { get; set; }
+
+        /// <summary>
+        /// 申请部门ID
+        /// </summary>
+        public string CreatorOrgId { get; set; }
+
+        /// <summary>
+        /// 申请部门
+        /// </summary>
+        public string CreatorOrgName { get; set; }
+
+        /// <summary>
+        /// 申请时间
+        /// </summary>
+        public DateTime CreationTime { get; set; }
+
+        /// <summary>
+        /// 上架时间
+        /// </summary>
+        public DateTime? OnShelfTime { get; set; }
+
+        /// <summary>
+        /// 更新时间
+        /// </summary>
+        public DateTime? UpdateTime { get; set; }
+
+        /// <summary>
+        /// 审核时间
+        /// </summary>
+        public DateTime? ExaminTime { get; set; }
+
+        /// <summary>
+        /// 下架时间
+        /// </summary>
+        public DateTime? OffShelfTime { get; set; }
+
+        /// <summary>
+        /// 过期时间
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
+
+        /// <summary>
+        /// 预案归属
+        /// </summary>
+        public string? Attribution { get; set; }
+
+        /// <summary>
+        /// 文档状态
+        /// </summary>
+        public EPlanStatus Status { get; set; }
+
+        public EPlanStatus NewStatus => Status != EPlanStatus.Drafts && DateTime.Now > ExpiredTime ? EPlanStatus.Overdue : Status;
+
+        /// <summary>
+        /// 文档状态名称
+        /// </summary>
+        public string StatusName => NewStatus.GetDescription();
+
+        public HotspotDto HotspotType { get; set; }
+
+        /// <summary>
+        /// 热点
+        /// </summary>
+        public string HotspotName => HotspotType != null ? HotspotType.HotSpotFullName : string.Empty;
+
+        /// <summary>
+        /// 知识分类名称
+        /// </summary>
+        public string KnowledgeTypeText => GetKnowledgeTypeText(KnowledgeType);
+
+        /// <summary>
+        /// 知识分类
+        /// </summary>
+        public List<PlanRelationTypeDto> KnowledgeType { get; set; }
+
+        /// <summary>
+        /// 获取知识分类名称
+        /// </summary>
+        /// <returns></returns>
+        public string GetKnowledgeTypeText(List<PlanRelationTypeDto> items)
+        {
+
+            if (KnowledgeType != null && KnowledgeType.Any())
+            {
+                var names = KnowledgeType.Select(x => x.PlanTypeName).ToList();
+                return string.Join(",", names);
+            }
+            return "";
+        }
+
+    }
+
+    public record PlanRelationTypeDto
+    {
+        /// <summary>
+        /// 知识库类型ID
+        /// </summary>
+        public string PlanTypeId { get; set; }
+
+        /// <summary>
+        /// 知识库类型名称
+        /// </summary>
+        public string PlanTypeName { get; set; }
+
+
+        /// <summary>
+        /// 知识库类型名称
+        /// </summary>
+        public string PlanTypeSpliceName { get; set; }
+    }
+}
+
+
+public class PlanExistDto
+{
+    /// <summary>
+    /// 标题
+    /// </summary>
+    public string Title { get; set; }
+
+    /// <summary>
+    /// 内容
+    /// </summary>
+    public string Content { get; set; }
+
+    /// <summary>
+    /// ID
+    /// </summary>
+    public string? Id { get; set; }
+}
+
+
+public class PlanInfoExportDto
+{
+    /// <summary>
+    /// 导入的知识Id集合
+    /// </summary>
+    public string[] Ids { get; set; }
+
+    /// <summary>
+    /// 导出格式
+    /// </summary>
+    public EFileType FileType { get; set; }
+}

+ 308 - 0
src/Hotline.Share/Dtos/Planlibrary/PlanListDto.cs

@@ -0,0 +1,308 @@
+using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.Knowledge;
+using Hotline.Share.Enums.KnowledgeBase;
+using Hotline.Share.Enums.Planlibrary;
+using Hotline.Share.Requests;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Planlibrary
+{
+    /// <summary>
+    /// 知识库列表
+    /// </summary>
+    public record PlanListDto : PagedRequest
+    {
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 关键词
+        /// </summary>
+        public string? Keyword { get; set; }
+
+        /// <summary>
+        /// 内容
+        /// </summary>
+        public string Content { get; set; }
+
+
+        /// <summary>
+        /// 预案状态
+        /// </summary>
+        public EPlanStatus? Status { get; set; }
+
+        /// <summary>
+        /// 预案归属
+        /// </summary>
+        public string? Attribution { get; set; }
+
+        /// <summary>
+        /// 分类ID
+        /// </summary>
+        public string? PlanTypeID { get; set; }
+
+        /// <summary>
+        /// 热点
+        /// </summary>
+        public string? HotspotId { get; set; }
+
+        /// <summary>
+        /// 是否公开
+        /// </summary>
+        public bool? IsPublic { get; set; }
+
+        /// <summary>
+        /// 是否删除
+        /// </summary>
+        public bool? IsDeleted { get; set; } = false;
+
+        /// <summary>
+        /// 阅读次数
+        /// </summary>
+        public int PageView { get; set; } = 0;
+
+        /// <summary>
+        /// 创建开始时间
+        /// </summary>
+        public DateTime? CreationTimeStart { get; set; }
+
+        /// <summary>
+        /// 创建结束时间
+        /// </summary>
+        public DateTime? CreationTimeEnd { get; set; }
+
+        /// <summary>
+        /// 上架开始时间
+        /// </summary>
+        public DateTime? OnShelfTimeStart { get; set; }
+        /// <summary>
+        /// 上架结束时间
+        /// </summary>
+        public DateTime? OnShelfTimeEnd { get; set; }
+
+        /// <summary>
+        /// 下架开始时间
+        /// </summary>
+        public DateTime? OffShelfTimeStart { get; set; }
+
+        /// <summary>
+        /// 下架结束时间
+        /// </summary>
+        public DateTime? OffShelfTimeEnd { get; set; }
+
+        /// <summary>
+        /// 更新开始时间
+        /// </summary>
+        public DateTime? UpdateTimeStart { get; set; }
+
+        /// <summary>
+        /// 更新结束时间
+        /// </summary>
+        public DateTime? UpdateTimeEnd { get; set; }
+
+        /// <summary>
+        /// 审核人ID
+        /// </summary>
+        public string? ExaminManId { get; set; }
+
+        /// <summary>
+        /// 审核部门ID
+        /// </summary>
+        public string? ExaminOrganizeId { get; set; }
+
+        /// <summary>
+        /// 当前部门ID
+        /// </summary>
+        public string CreateOrgId { get; set; }
+
+        /// <summary>
+        /// 审核开始时间
+        /// </summary>
+        public DateTime? ExaminTimeStart { get; set; }
+
+        /// <summary>
+        /// 审核结束时间
+        /// </summary>
+        public DateTime? ExaminTimeEnd { get; set; }
+
+        /// <summary>
+        /// 失效时间
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
+
+        /// <summary>
+        /// 评分
+        /// </summary>
+        public decimal? Score { get; set; } = decimal.Zero;
+    }
+
+
+    public record AddPlanListDto
+    {
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 关键词
+        /// </summary>
+        public string? Keyword { get; set; }
+
+        /// <summary>
+        /// 内容
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// 预案归属
+        /// </summary>
+        public string? Attribution { get; set; }
+
+        /// <summary>
+        /// 分类ID
+        /// </summary>
+        public string? PlanTypeID { get; set; }
+
+        /// <summary>
+        /// 分类
+        /// </summary>
+        public List<PlanRelationTypeDto> PlanType { get; set; }
+
+        /// <summary>
+        /// 热点
+        /// </summary>
+        public string? HotspotId { get; set; }
+
+        /// <summary>
+        /// 是否公开
+        /// </summary>
+        public bool? IsPublic { get; set; }
+
+        /// <summary>
+        /// 失效时间
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
+
+        /// <summary>
+        /// 预案状态
+        /// </summary>
+        public EPlanApplyStatus? ApplyStatus { get; set; }
+
+        /// <summary>
+        /// 预案状态
+        /// </summary>
+        public EPlanStatus? Status { get; set; }
+
+        /// <summary>
+        /// 上传附件
+        /// </summary>
+        public List<FileDto>? Files { get; set; }
+    }
+
+    public record UpdatePlanListDto : AddPlanListDto
+    {
+        /// <summary>
+        /// 预案库ID
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 审核人ID
+        /// </summary>
+        public string? ExaminManId { get; set; }
+
+        /// <summary>
+        /// 审核部门ID
+        /// </summary>
+        public string? ExaminOrganizeId { get; set; }
+
+        /// <summary>
+        /// 审核时间
+        /// </summary>
+        public DateTime? ExaminTime { get; set; }
+    }
+
+    public record DelPlanListDto
+    {
+        /// <summary>
+        /// 预案库ID
+        /// </summary>
+        public string Id { get; set; }
+    }
+
+
+    /// <summary>
+    /// 知识库列表
+    /// </summary>
+    public record PlanInfoDto
+    {
+        /// <summary>
+        /// 标识
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 关键词
+        /// </summary>
+        public string? Keyword { get; set; }
+
+        /// <summary>
+        /// 内容
+        /// </summary>
+        public string Content { get; set; }
+
+        /// <summary>
+        /// 是否公开
+        /// </summary>
+        public bool? IsPublic { get; set; }
+
+        /// <summary>
+        /// 阅读次数
+        /// </summary>
+        public int PageView { get; set; } = 0;
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime? CreationTime { get; set; }
+
+        /// <summary>
+        /// 失效时间
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
+
+        /// <summary>
+        /// 评分
+        /// </summary>
+        public decimal? Score { get; set; } = decimal.Zero;
+
+        /// <summary>
+        /// 创建人
+        /// </summary>
+        public string? CreatorName { get; set; }
+
+        /// <summary>
+        /// 创建部门
+        /// </summary>
+        public string? CreatorOrgName { get; set; }
+
+        public List<FileDto> Files { get; set; }
+
+        /// <summary>
+        /// 附件
+        /// </summary>
+        public List<FileJson>? FileJson { get; set; }
+    }
+}

+ 1 - 1
src/Hotline.Share/Enums/Planlibrary/EPlanApplyType.cs → src/Hotline.Share/Enums/Planlibrary/EPlanApplyStatus.cs

@@ -5,7 +5,7 @@ namespace Hotline.Share.Enums.Planlibrary;
 /// <summary>
 /// 知识审批-申请类型
 /// </summary>
-public enum EPlanApplyType
+public enum EPlanApplyStatus
 {
     /// <summary>
     /// 新增

+ 1 - 7
src/Hotline.Share/Enums/Planlibrary/EPlanStatus.cs

@@ -60,16 +60,10 @@ namespace Hotline.Share.Enums.Planlibrary
         [Description("已过期")]
         Overdue = 6,
 
-        /// <summary>
-        /// 下架审批中
-        /// </summary>
-        [Description("下架审批中")]
-        OffShelfAudit = 7,
-
         /// <summary>
         /// 草稿
         /// </summary>
         [Description("草稿")]
-        NewDrafts = 8,
+        NewDrafts = 7
     }
 }

+ 40 - 0
src/Hotline/Planlibrary/PlanCollect.cs

@@ -0,0 +1,40 @@
+using Hotline.KnowledgeBase;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Planlibrary
+{
+    [Description("预案库收藏")]
+    public class PlanCollect : FullStateEntity
+    {
+        /// <summary>
+        /// 预案库ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "预案库ID")]
+        public string PlanId { get; set; }
+
+        /// <summary>
+        /// 预案库
+        /// </summary>
+        [Navigate(NavigateType.OneToOne, nameof(PlanId))]
+        public PlanList Plan { get; set; }
+
+        /// <summary>
+        /// 评分
+        /// </summary>
+        [SugarColumn(ColumnDescription = "评分")]
+        public decimal? Score { get; set; } = decimal.Zero;
+
+        /// <summary>
+        /// 是否收藏
+        /// </summary>
+        [SugarColumn(ColumnDescription = "是否收藏")]
+        public bool? Collect { get; set; }
+    }
+}

+ 7 - 1
src/Hotline/Planlibrary/PlanList.cs

@@ -6,6 +6,7 @@ using System.ComponentModel;
 using XF.Domain.Repository;
 using Hotline.Share.Enums.Planlibrary;
 using Hotline.KnowledgeBase;
+using Hotline.Share.Dtos.File;
 
 namespace Hotline.Planlibrary;
 
@@ -36,6 +37,11 @@ public class PlanList : CreationEntity
     [SugarColumn(ColumnDataType = "text", ColumnDescription = "内容")]
     public string Content { get; set; }
 
+    /// <summary>
+    /// 预案申请状态
+    /// </summary>
+    [SugarColumn(ColumnDescription = "预案申请状态")]
+    public EPlanApplyStatus ApplyStatus { get; set; }
 
     /// <summary>
     /// 预案状态
@@ -159,5 +165,5 @@ public class PlanList : CreationEntity
     /// 附件
     /// </summary>
     [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
-    public List<string>? FileJson { get; set; }
+    public List<FileJson>? FileJson { get; set; }
 }