1470 lines
48 KiB
C#
1470 lines
48 KiB
C#
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
using MiAssessment.Admin.Business.Data;
|
||
using MiAssessment.Admin.Business.Entities;
|
||
using MiAssessment.Admin.Business.Models;
|
||
using MiAssessment.Admin.Business.Models.Assessment;
|
||
using MiAssessment.Admin.Business.Models.Common;
|
||
using MiAssessment.Admin.Business.Services.Interfaces;
|
||
|
||
namespace MiAssessment.Admin.Business.Services;
|
||
|
||
/// <summary>
|
||
/// 测评管理服务实现
|
||
/// </summary>
|
||
public class AssessmentService : IAssessmentService
|
||
{
|
||
private readonly AdminBusinessDbContext _dbContext;
|
||
private readonly ILogger<AssessmentService> _logger;
|
||
|
||
/// <summary>
|
||
/// 测评类型状态名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> TypeStatusNames = new()
|
||
{
|
||
{ 0, "已下线" },
|
||
{ 1, "已上线" },
|
||
{ 2, "即将上线" }
|
||
};
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="dbContext">数据库上下文</param>
|
||
/// <param name="logger">日志记录器</param>
|
||
public AssessmentService(
|
||
AdminBusinessDbContext dbContext,
|
||
ILogger<AssessmentService> logger)
|
||
{
|
||
_dbContext = dbContext;
|
||
_logger = logger;
|
||
}
|
||
|
||
#region 测评类型操作
|
||
|
||
/// <inheritdoc />
|
||
public async Task<PagedResult<AssessmentTypeDto>> GetTypeListAsync(AssessmentTypeQueryRequest request)
|
||
{
|
||
// 构建查询,过滤软删除记录
|
||
var query = _dbContext.AssessmentTypes
|
||
.AsNoTracking()
|
||
.Where(t => !t.IsDeleted);
|
||
|
||
// 名称筛选
|
||
if (!string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
query = query.Where(t => t.Name.Contains(request.Name));
|
||
}
|
||
|
||
// 编码筛选
|
||
if (!string.IsNullOrWhiteSpace(request.Code))
|
||
{
|
||
query = query.Where(t => t.Code.Contains(request.Code));
|
||
}
|
||
|
||
// 状态筛选
|
||
if (request.Status.HasValue)
|
||
{
|
||
query = query.Where(t => t.Status == request.Status.Value);
|
||
}
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页查询,按 Sort 降序排列
|
||
var items = await query
|
||
.OrderByDescending(t => t.Sort)
|
||
.ThenByDescending(t => t.CreateTime)
|
||
.Skip(request.Skip)
|
||
.Take(request.PageSize)
|
||
.Select(t => new AssessmentTypeDto
|
||
{
|
||
Id = t.Id,
|
||
Name = t.Name,
|
||
Code = t.Code,
|
||
ImageUrl = t.ImageUrl,
|
||
DetailImageUrl = t.DetailImageUrl,
|
||
IntroContent = t.IntroContent,
|
||
Price = t.Price,
|
||
QuestionCount = t.QuestionCount,
|
||
Sort = t.Sort,
|
||
Status = t.Status,
|
||
StatusName = GetTypeStatusName(t.Status),
|
||
CreateTime = t.CreateTime
|
||
})
|
||
.ToListAsync();
|
||
|
||
return PagedResult<AssessmentTypeDto>.Create(items, total, request.Page, request.PageSize);
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<AssessmentTypeDto> GetTypeByIdAsync(long id)
|
||
{
|
||
var assessmentType = await _dbContext.AssessmentTypes
|
||
.AsNoTracking()
|
||
.Where(t => t.Id == id && !t.IsDeleted)
|
||
.Select(t => new AssessmentTypeDto
|
||
{
|
||
Id = t.Id,
|
||
Name = t.Name,
|
||
Code = t.Code,
|
||
ImageUrl = t.ImageUrl,
|
||
DetailImageUrl = t.DetailImageUrl,
|
||
IntroContent = t.IntroContent,
|
||
Price = t.Price,
|
||
QuestionCount = t.QuestionCount,
|
||
Sort = t.Sort,
|
||
Status = t.Status,
|
||
StatusName = GetTypeStatusName(t.Status),
|
||
CreateTime = t.CreateTime
|
||
})
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (assessmentType == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
return assessmentType;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<long> CreateTypeAsync(CreateAssessmentTypeRequest request)
|
||
{
|
||
// 验证名称必填
|
||
if (string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评名称不能为空");
|
||
}
|
||
|
||
// 验证编码必填
|
||
if (string.IsNullOrWhiteSpace(request.Code))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评编码不能为空");
|
||
}
|
||
|
||
// 验证价格必须为正数
|
||
if (request.Price <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "价格必须大于0");
|
||
}
|
||
|
||
// 验证编码唯一性
|
||
if (await IsCodeExistsAsync(request.Code))
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeCodeExists, "测评类型编码已存在");
|
||
}
|
||
|
||
// 创建实体
|
||
var assessmentType = new AssessmentType
|
||
{
|
||
Name = request.Name,
|
||
Code = request.Code,
|
||
ImageUrl = request.ImageUrl,
|
||
DetailImageUrl = request.DetailImageUrl,
|
||
IntroContent = request.IntroContent,
|
||
Price = request.Price,
|
||
QuestionCount = request.QuestionCount,
|
||
Sort = request.Sort,
|
||
Status = request.Status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
|
||
_dbContext.AssessmentTypes.Add(assessmentType);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("创建测评类型成功,ID: {TypeId}, 名称: {Name}, 编码: {Code}",
|
||
assessmentType.Id, assessmentType.Name, assessmentType.Code);
|
||
|
||
return assessmentType.Id;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateTypeAsync(UpdateAssessmentTypeRequest request)
|
||
{
|
||
// 查找测评类型
|
||
var assessmentType = await _dbContext.AssessmentTypes
|
||
.Where(t => t.Id == request.Id && !t.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (assessmentType == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 验证名称必填
|
||
if (string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评名称不能为空");
|
||
}
|
||
|
||
// 验证编码必填
|
||
if (string.IsNullOrWhiteSpace(request.Code))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评编码不能为空");
|
||
}
|
||
|
||
// 验证价格必须为正数
|
||
if (request.Price <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "价格必须大于0");
|
||
}
|
||
|
||
// 验证编码唯一性(排除自身)
|
||
if (await IsCodeExistsAsync(request.Code, request.Id))
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeCodeExists, "测评类型编码已存在");
|
||
}
|
||
|
||
// 更新字段
|
||
assessmentType.Name = request.Name;
|
||
assessmentType.Code = request.Code;
|
||
assessmentType.ImageUrl = request.ImageUrl;
|
||
assessmentType.DetailImageUrl = request.DetailImageUrl;
|
||
assessmentType.IntroContent = request.IntroContent;
|
||
assessmentType.Price = request.Price;
|
||
assessmentType.QuestionCount = request.QuestionCount;
|
||
assessmentType.Sort = request.Sort;
|
||
assessmentType.Status = request.Status;
|
||
assessmentType.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新测评类型成功,ID: {TypeId}", assessmentType.Id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> DeleteTypeAsync(long id)
|
||
{
|
||
// 查找测评类型
|
||
var assessmentType = await _dbContext.AssessmentTypes
|
||
.Where(t => t.Id == id && !t.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (assessmentType == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 软删除
|
||
assessmentType.IsDeleted = true;
|
||
assessmentType.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("删除测评类型成功,ID: {TypeId}", id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateTypeStatusAsync(long id, int status)
|
||
{
|
||
// 查找测评类型
|
||
var assessmentType = await _dbContext.AssessmentTypes
|
||
.Where(t => t.Id == id && !t.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (assessmentType == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 更新状态
|
||
assessmentType.Status = status;
|
||
assessmentType.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新测评类型状态成功,ID: {TypeId}, 状态: {Status}", id, status);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> IsCodeExistsAsync(string code, long? excludeId = null)
|
||
{
|
||
var query = _dbContext.AssessmentTypes
|
||
.Where(t => t.Code == code && !t.IsDeleted);
|
||
|
||
if (excludeId.HasValue)
|
||
{
|
||
query = query.Where(t => t.Id != excludeId.Value);
|
||
}
|
||
|
||
return await query.AnyAsync();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 题目操作
|
||
|
||
/// <summary>
|
||
/// 题目状态名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> QuestionStatusNames = new()
|
||
{
|
||
{ 0, "禁用" },
|
||
{ 1, "启用" }
|
||
};
|
||
|
||
/// <inheritdoc />
|
||
public async Task<PagedResult<QuestionDto>> GetQuestionListAsync(QuestionQueryRequest request)
|
||
{
|
||
// 构建查询,过滤软删除记录
|
||
var query = _dbContext.Questions
|
||
.AsNoTracking()
|
||
.Where(q => !q.IsDeleted);
|
||
|
||
// 测评类型筛选
|
||
if (request.AssessmentTypeId.HasValue)
|
||
{
|
||
query = query.Where(q => q.AssessmentTypeId == request.AssessmentTypeId.Value);
|
||
}
|
||
|
||
// 题号筛选
|
||
if (request.QuestionNo.HasValue)
|
||
{
|
||
query = query.Where(q => q.QuestionNo == request.QuestionNo.Value);
|
||
}
|
||
|
||
// 内容筛选
|
||
if (!string.IsNullOrWhiteSpace(request.Content))
|
||
{
|
||
query = query.Where(q => q.Content.Contains(request.Content));
|
||
}
|
||
|
||
// 状态筛选
|
||
if (request.Status.HasValue)
|
||
{
|
||
query = query.Where(q => q.Status == request.Status.Value);
|
||
}
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页查询,按 QuestionNo 升序排列
|
||
var questions = await query
|
||
.OrderBy(q => q.QuestionNo)
|
||
.ThenByDescending(q => q.CreateTime)
|
||
.Skip(request.Skip)
|
||
.Take(request.PageSize)
|
||
.Select(q => new QuestionDto
|
||
{
|
||
Id = q.Id,
|
||
AssessmentTypeId = q.AssessmentTypeId,
|
||
AssessmentTypeName = q.AssessmentType != null ? q.AssessmentType.Name : "",
|
||
QuestionNo = q.QuestionNo,
|
||
Content = q.Content,
|
||
Sort = q.Sort,
|
||
Status = q.Status,
|
||
StatusName = GetQuestionStatusName(q.Status),
|
||
CreateTime = q.CreateTime
|
||
})
|
||
.ToListAsync();
|
||
|
||
// 获取这些题目的分类数量
|
||
if (questions.Count > 0)
|
||
{
|
||
var questionIds = questions.Select(q => q.Id).ToList();
|
||
var categoryCounts = await _dbContext.QuestionCategoryMappings
|
||
.Where(m => questionIds.Contains(m.QuestionId))
|
||
.GroupBy(m => m.QuestionId)
|
||
.Select(g => new { QuestionId = g.Key, Count = g.Count() })
|
||
.ToDictionaryAsync(x => x.QuestionId, x => x.Count);
|
||
|
||
foreach (var question in questions)
|
||
{
|
||
question.CategoryCount = categoryCounts.TryGetValue(question.Id, out var count) ? count : 0;
|
||
}
|
||
}
|
||
|
||
return PagedResult<QuestionDto>.Create(questions, total, request.Page, request.PageSize);
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<QuestionDto> GetQuestionByIdAsync(long id)
|
||
{
|
||
var question = await _dbContext.Questions
|
||
.AsNoTracking()
|
||
.Where(q => q.Id == id && !q.IsDeleted)
|
||
.Select(q => new QuestionDto
|
||
{
|
||
Id = q.Id,
|
||
AssessmentTypeId = q.AssessmentTypeId,
|
||
AssessmentTypeName = q.AssessmentType != null ? q.AssessmentType.Name : "",
|
||
QuestionNo = q.QuestionNo,
|
||
Content = q.Content,
|
||
Sort = q.Sort,
|
||
Status = q.Status,
|
||
StatusName = GetQuestionStatusName(q.Status),
|
||
CreateTime = q.CreateTime
|
||
})
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (question == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNotFound, "题目不存在");
|
||
}
|
||
|
||
return question;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<long> CreateQuestionAsync(CreateQuestionRequest request)
|
||
{
|
||
// 验证测评类型ID必填
|
||
if (request.AssessmentTypeId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评类型ID无效");
|
||
}
|
||
|
||
// 验证题号必填且大于0
|
||
if (request.QuestionNo <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "题号必须大于0");
|
||
}
|
||
|
||
// 验证内容必填
|
||
if (string.IsNullOrWhiteSpace(request.Content))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "题目内容不能为空");
|
||
}
|
||
|
||
// 验证测评类型是否存在
|
||
var assessmentTypeExists = await _dbContext.AssessmentTypes
|
||
.AnyAsync(t => t.Id == request.AssessmentTypeId && !t.IsDeleted);
|
||
if (!assessmentTypeExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 验证题号唯一性(同一测评类型内)
|
||
if (await IsQuestionNoExistsAsync(request.AssessmentTypeId, request.QuestionNo))
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNoExists, "该测评类型下题号已存在");
|
||
}
|
||
|
||
// 创建实体
|
||
var question = new Question
|
||
{
|
||
AssessmentTypeId = request.AssessmentTypeId,
|
||
QuestionNo = request.QuestionNo,
|
||
Content = request.Content,
|
||
Sort = request.Sort,
|
||
Status = request.Status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
|
||
_dbContext.Questions.Add(question);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("创建题目成功,ID: {QuestionId}, 测评类型ID: {TypeId}, 题号: {QuestionNo}",
|
||
question.Id, question.AssessmentTypeId, question.QuestionNo);
|
||
|
||
return question.Id;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateQuestionAsync(UpdateQuestionRequest request)
|
||
{
|
||
// 查找题目
|
||
var question = await _dbContext.Questions
|
||
.Where(q => q.Id == request.Id && !q.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (question == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNotFound, "题目不存在");
|
||
}
|
||
|
||
// 验证测评类型ID必填
|
||
if (request.AssessmentTypeId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评类型ID无效");
|
||
}
|
||
|
||
// 验证题号必填且大于0
|
||
if (request.QuestionNo <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "题号必须大于0");
|
||
}
|
||
|
||
// 验证内容必填
|
||
if (string.IsNullOrWhiteSpace(request.Content))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "题目内容不能为空");
|
||
}
|
||
|
||
// 验证测评类型是否存在
|
||
var assessmentTypeExists = await _dbContext.AssessmentTypes
|
||
.AnyAsync(t => t.Id == request.AssessmentTypeId && !t.IsDeleted);
|
||
if (!assessmentTypeExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 验证题号唯一性(同一测评类型内,排除自身)
|
||
if (await IsQuestionNoExistsAsync(request.AssessmentTypeId, request.QuestionNo, request.Id))
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNoExists, "该测评类型下题号已存在");
|
||
}
|
||
|
||
// 更新字段
|
||
question.AssessmentTypeId = request.AssessmentTypeId;
|
||
question.QuestionNo = request.QuestionNo;
|
||
question.Content = request.Content;
|
||
question.Sort = request.Sort;
|
||
question.Status = request.Status;
|
||
question.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新题目成功,ID: {QuestionId}", question.Id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> DeleteQuestionAsync(long id)
|
||
{
|
||
// 查找题目
|
||
var question = await _dbContext.Questions
|
||
.Where(q => q.Id == id && !q.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (question == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNotFound, "题目不存在");
|
||
}
|
||
|
||
// 软删除
|
||
question.IsDeleted = true;
|
||
question.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("删除题目成功,ID: {QuestionId}", id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateQuestionStatusAsync(long id, int status)
|
||
{
|
||
// 查找题目
|
||
var question = await _dbContext.Questions
|
||
.Where(q => q.Id == id && !q.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (question == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNotFound, "题目不存在");
|
||
}
|
||
|
||
// 更新状态
|
||
question.Status = status;
|
||
question.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新题目状态成功,ID: {QuestionId}, 状态: {Status}", id, status);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<BatchImportResult> BatchImportQuestionsAsync(BatchImportQuestionsRequest request)
|
||
{
|
||
var result = new BatchImportResult
|
||
{
|
||
TotalCount = request.Questions.Count,
|
||
SuccessCount = 0,
|
||
FailedCount = 0,
|
||
Errors = new List<BatchImportError>()
|
||
};
|
||
|
||
// 验证测评类型ID
|
||
if (request.AssessmentTypeId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评类型ID无效");
|
||
}
|
||
|
||
// 验证测评类型是否存在
|
||
var assessmentTypeExists = await _dbContext.AssessmentTypes
|
||
.AnyAsync(t => t.Id == request.AssessmentTypeId && !t.IsDeleted);
|
||
if (!assessmentTypeExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 获取该测评类型下已存在的题号
|
||
var existingQuestionNos = await _dbContext.Questions
|
||
.Where(q => q.AssessmentTypeId == request.AssessmentTypeId && !q.IsDeleted)
|
||
.Select(q => q.QuestionNo)
|
||
.ToListAsync();
|
||
|
||
// 检查导入数据中的重复题号
|
||
var importQuestionNos = new HashSet<int>();
|
||
var questionsToAdd = new List<Question>();
|
||
|
||
for (int i = 0; i < request.Questions.Count; i++)
|
||
{
|
||
var item = request.Questions[i];
|
||
var rowIndex = i + 1;
|
||
|
||
// 验证题号
|
||
if (item.QuestionNo <= 0)
|
||
{
|
||
result.Errors.Add(new BatchImportError
|
||
{
|
||
RowIndex = rowIndex,
|
||
QuestionNo = item.QuestionNo,
|
||
ErrorMessage = "题号必须大于0"
|
||
});
|
||
result.FailedCount++;
|
||
continue;
|
||
}
|
||
|
||
// 验证内容
|
||
if (string.IsNullOrWhiteSpace(item.Content))
|
||
{
|
||
result.Errors.Add(new BatchImportError
|
||
{
|
||
RowIndex = rowIndex,
|
||
QuestionNo = item.QuestionNo,
|
||
ErrorMessage = "题目内容不能为空"
|
||
});
|
||
result.FailedCount++;
|
||
continue;
|
||
}
|
||
|
||
// 检查是否与数据库中已存在的题号重复
|
||
if (existingQuestionNos.Contains(item.QuestionNo))
|
||
{
|
||
result.Errors.Add(new BatchImportError
|
||
{
|
||
RowIndex = rowIndex,
|
||
QuestionNo = item.QuestionNo,
|
||
ErrorMessage = "题号已存在"
|
||
});
|
||
result.FailedCount++;
|
||
continue;
|
||
}
|
||
|
||
// 检查是否与本次导入中的其他题号重复
|
||
if (importQuestionNos.Contains(item.QuestionNo))
|
||
{
|
||
result.Errors.Add(new BatchImportError
|
||
{
|
||
RowIndex = rowIndex,
|
||
QuestionNo = item.QuestionNo,
|
||
ErrorMessage = "导入数据中存在重复题号"
|
||
});
|
||
result.FailedCount++;
|
||
continue;
|
||
}
|
||
|
||
importQuestionNos.Add(item.QuestionNo);
|
||
|
||
// 创建题目实体
|
||
var question = new Question
|
||
{
|
||
AssessmentTypeId = request.AssessmentTypeId,
|
||
QuestionNo = item.QuestionNo,
|
||
Content = item.Content,
|
||
Sort = item.Sort,
|
||
Status = item.Status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
|
||
questionsToAdd.Add(question);
|
||
result.SuccessCount++;
|
||
}
|
||
|
||
// 批量添加题目
|
||
if (questionsToAdd.Count > 0)
|
||
{
|
||
_dbContext.Questions.AddRange(questionsToAdd);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("批量导入题目成功,测评类型ID: {TypeId}, 成功: {SuccessCount}, 失败: {FailedCount}",
|
||
request.AssessmentTypeId, result.SuccessCount, result.FailedCount);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> IsQuestionNoExistsAsync(long assessmentTypeId, int questionNo, long? excludeId = null)
|
||
{
|
||
var query = _dbContext.Questions
|
||
.Where(q => q.AssessmentTypeId == assessmentTypeId && q.QuestionNo == questionNo && !q.IsDeleted);
|
||
|
||
if (excludeId.HasValue)
|
||
{
|
||
query = query.Where(q => q.Id != excludeId.Value);
|
||
}
|
||
|
||
return await query.AnyAsync();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 报告分类操作
|
||
|
||
/// <summary>
|
||
/// 分类类型名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> CategoryTypeNames = new()
|
||
{
|
||
{ 1, "八大智能" },
|
||
{ 2, "个人特质" },
|
||
{ 3, "细分能力" },
|
||
{ 4, "先天学习" },
|
||
{ 5, "学习能力" },
|
||
{ 6, "大脑类型" },
|
||
{ 7, "性格类型" },
|
||
{ 8, "未来能力" }
|
||
};
|
||
|
||
/// <summary>
|
||
/// 计分规则名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> ScoreRuleNames = new()
|
||
{
|
||
{ 1, "累加(1-10分)" },
|
||
{ 2, "二值(0/1分)" }
|
||
};
|
||
|
||
/// <inheritdoc />
|
||
public async Task<List<CategoryTreeNode>> GetCategoryTreeAsync(long assessmentTypeId)
|
||
{
|
||
// 获取该测评类型下所有未删除的分类
|
||
var categories = await _dbContext.ReportCategories
|
||
.AsNoTracking()
|
||
.Where(c => c.AssessmentTypeId == assessmentTypeId && !c.IsDeleted)
|
||
.OrderBy(c => c.Sort)
|
||
.ThenBy(c => c.CreateTime)
|
||
.Select(c => new CategoryTreeNode
|
||
{
|
||
Id = c.Id,
|
||
ParentId = c.ParentId,
|
||
AssessmentTypeId = c.AssessmentTypeId,
|
||
Name = c.Name,
|
||
Code = c.Code,
|
||
CategoryType = c.CategoryType,
|
||
CategoryTypeName = GetCategoryTypeName(c.CategoryType),
|
||
ScoreRule = c.ScoreRule,
|
||
ScoreRuleName = GetScoreRuleName(c.ScoreRule),
|
||
Sort = c.Sort,
|
||
CreateTime = c.CreateTime,
|
||
Children = new List<CategoryTreeNode>()
|
||
})
|
||
.ToListAsync();
|
||
|
||
// 构建树形结构
|
||
return BuildCategoryTree(categories);
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<CategoryTreeNode> GetCategoryByIdAsync(long id)
|
||
{
|
||
var category = await _dbContext.ReportCategories
|
||
.AsNoTracking()
|
||
.Where(c => c.Id == id && !c.IsDeleted)
|
||
.Select(c => new CategoryTreeNode
|
||
{
|
||
Id = c.Id,
|
||
ParentId = c.ParentId,
|
||
AssessmentTypeId = c.AssessmentTypeId,
|
||
Name = c.Name,
|
||
Code = c.Code,
|
||
CategoryType = c.CategoryType,
|
||
CategoryTypeName = GetCategoryTypeName(c.CategoryType),
|
||
ScoreRule = c.ScoreRule,
|
||
ScoreRuleName = GetScoreRuleName(c.ScoreRule),
|
||
Sort = c.Sort,
|
||
CreateTime = c.CreateTime,
|
||
Children = new List<CategoryTreeNode>()
|
||
})
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (category == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
return category;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<long> CreateCategoryAsync(CreateCategoryRequest request)
|
||
{
|
||
// 验证名称必填
|
||
if (string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类名称不能为空");
|
||
}
|
||
|
||
// 验证编码必填
|
||
if (string.IsNullOrWhiteSpace(request.Code))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类编码不能为空");
|
||
}
|
||
|
||
// 验证分类类型有效性
|
||
if (request.CategoryType < 1 || request.CategoryType > 8)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类类型无效,只能为1-8");
|
||
}
|
||
|
||
// 验证计分规则有效性
|
||
if (request.ScoreRule < 1 || request.ScoreRule > 2)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "计分规则无效,只能为1或2");
|
||
}
|
||
|
||
// 验证测评类型ID
|
||
if (request.AssessmentTypeId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评类型ID无效");
|
||
}
|
||
|
||
// 验证测评类型是否存在
|
||
var assessmentTypeExists = await _dbContext.AssessmentTypes
|
||
.AnyAsync(t => t.Id == request.AssessmentTypeId && !t.IsDeleted);
|
||
if (!assessmentTypeExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 如果有父分类,验证父分类是否存在
|
||
if (request.ParentId > 0)
|
||
{
|
||
var parentExists = await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.Id == request.ParentId && !c.IsDeleted);
|
||
if (!parentExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "父分类不存在");
|
||
}
|
||
}
|
||
|
||
// 创建实体
|
||
var category = new ReportCategory
|
||
{
|
||
AssessmentTypeId = request.AssessmentTypeId,
|
||
ParentId = request.ParentId,
|
||
Name = request.Name,
|
||
Code = request.Code,
|
||
CategoryType = request.CategoryType,
|
||
ScoreRule = request.ScoreRule,
|
||
Sort = request.Sort,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
|
||
_dbContext.ReportCategories.Add(category);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("创建分类成功,ID: {CategoryId}, 名称: {Name}, 编码: {Code}",
|
||
category.Id, category.Name, category.Code);
|
||
|
||
return category.Id;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateCategoryAsync(UpdateCategoryRequest request)
|
||
{
|
||
// 查找分类
|
||
var category = await _dbContext.ReportCategories
|
||
.Where(c => c.Id == request.Id && !c.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (category == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
// 验证名称必填
|
||
if (string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类名称不能为空");
|
||
}
|
||
|
||
// 验证编码必填
|
||
if (string.IsNullOrWhiteSpace(request.Code))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类编码不能为空");
|
||
}
|
||
|
||
// 验证分类类型有效性
|
||
if (request.CategoryType < 1 || request.CategoryType > 8)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类类型无效,只能为1-8");
|
||
}
|
||
|
||
// 验证计分规则有效性
|
||
if (request.ScoreRule < 1 || request.ScoreRule > 2)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "计分规则无效,只能为1或2");
|
||
}
|
||
|
||
// 验证测评类型ID
|
||
if (request.AssessmentTypeId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "测评类型ID无效");
|
||
}
|
||
|
||
// 验证测评类型是否存在
|
||
var assessmentTypeExists = await _dbContext.AssessmentTypes
|
||
.AnyAsync(t => t.Id == request.AssessmentTypeId && !t.IsDeleted);
|
||
if (!assessmentTypeExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.AssessmentTypeNotFound, "测评类型不存在");
|
||
}
|
||
|
||
// 如果有父分类,验证父分类是否存在
|
||
if (request.ParentId > 0)
|
||
{
|
||
// 不能将自己设为父分类
|
||
if (request.ParentId == request.Id)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "不能将自己设为父分类");
|
||
}
|
||
|
||
var parentExists = await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.Id == request.ParentId && !c.IsDeleted);
|
||
if (!parentExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "父分类不存在");
|
||
}
|
||
}
|
||
|
||
// 更新字段
|
||
category.AssessmentTypeId = request.AssessmentTypeId;
|
||
category.ParentId = request.ParentId;
|
||
category.Name = request.Name;
|
||
category.Code = request.Code;
|
||
category.CategoryType = request.CategoryType;
|
||
category.ScoreRule = request.ScoreRule;
|
||
category.Sort = request.Sort;
|
||
category.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新分类成功,ID: {CategoryId}", category.Id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> DeleteCategoryAsync(long id)
|
||
{
|
||
// 查找分类
|
||
var category = await _dbContext.ReportCategories
|
||
.Where(c => c.Id == id && !c.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (category == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
// 检查是否存在子分类
|
||
if (await HasChildCategoriesAsync(id))
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryHasChildren, "该分类存在子分类,无法删除");
|
||
}
|
||
|
||
// 软删除
|
||
category.IsDeleted = true;
|
||
category.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("删除分类成功,ID: {CategoryId}", id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> HasChildCategoriesAsync(long categoryId)
|
||
{
|
||
return await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.ParentId == categoryId && !c.IsDeleted);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有方法
|
||
|
||
/// <summary>
|
||
/// 获取测评类型状态名称
|
||
/// </summary>
|
||
/// <param name="status">状态值</param>
|
||
/// <returns>状态名称</returns>
|
||
private static string GetTypeStatusName(int status)
|
||
{
|
||
return TypeStatusNames.TryGetValue(status, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取题目状态名称
|
||
/// </summary>
|
||
/// <param name="status">状态值</param>
|
||
/// <returns>状态名称</returns>
|
||
private static string GetQuestionStatusName(int status)
|
||
{
|
||
return QuestionStatusNames.TryGetValue(status, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取分类类型名称
|
||
/// </summary>
|
||
/// <param name="categoryType">分类类型值</param>
|
||
/// <returns>分类类型名称</returns>
|
||
private static string GetCategoryTypeName(int categoryType)
|
||
{
|
||
return CategoryTypeNames.TryGetValue(categoryType, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取计分规则名称
|
||
/// </summary>
|
||
/// <param name="scoreRule">计分规则值</param>
|
||
/// <returns>计分规则名称</returns>
|
||
private static string GetScoreRuleName(int scoreRule)
|
||
{
|
||
return ScoreRuleNames.TryGetValue(scoreRule, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建分类树形结构
|
||
/// </summary>
|
||
/// <param name="categories">所有分类列表</param>
|
||
/// <returns>树形结构列表(顶级分类)</returns>
|
||
private static List<CategoryTreeNode> BuildCategoryTree(List<CategoryTreeNode> categories)
|
||
{
|
||
// 创建字典以便快速查找
|
||
var categoryDict = categories.ToDictionary(c => c.Id);
|
||
|
||
// 顶级分类列表
|
||
var rootCategories = new List<CategoryTreeNode>();
|
||
|
||
foreach (var category in categories)
|
||
{
|
||
if (category.ParentId == 0)
|
||
{
|
||
// 顶级分类
|
||
rootCategories.Add(category);
|
||
}
|
||
else
|
||
{
|
||
// 子分类,添加到父分类的 Children 列表
|
||
if (categoryDict.TryGetValue(category.ParentId, out var parent))
|
||
{
|
||
parent.Children.Add(category);
|
||
}
|
||
}
|
||
}
|
||
|
||
return rootCategories;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 题目分类映射操作
|
||
|
||
/// <inheritdoc />
|
||
public async Task<List<MappingCategoryDto>> GetMappingsByQuestionAsync(long questionId)
|
||
{
|
||
// 验证题目是否存在
|
||
var questionExists = await _dbContext.Questions
|
||
.AnyAsync(q => q.Id == questionId && !q.IsDeleted);
|
||
if (!questionExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNotFound, "题目不存在");
|
||
}
|
||
|
||
// 获取该题目关联的所有分类
|
||
var mappings = await _dbContext.QuestionCategoryMappings
|
||
.AsNoTracking()
|
||
.Where(m => m.QuestionId == questionId)
|
||
.Join(
|
||
_dbContext.ReportCategories.Where(c => !c.IsDeleted),
|
||
m => m.CategoryId,
|
||
c => c.Id,
|
||
(m, c) => new MappingCategoryDto
|
||
{
|
||
Id = c.Id,
|
||
Name = c.Name,
|
||
Code = c.Code,
|
||
CategoryType = c.CategoryType,
|
||
CategoryTypeName = GetCategoryTypeName(c.CategoryType),
|
||
MappingCreateTime = m.CreateTime
|
||
})
|
||
.OrderBy(c => c.CategoryType)
|
||
.ThenBy(c => c.Name)
|
||
.ToListAsync();
|
||
|
||
return mappings;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<List<MappingQuestionDto>> GetMappingsByCategoryAsync(long categoryId)
|
||
{
|
||
// 验证分类是否存在
|
||
var categoryExists = await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.Id == categoryId && !c.IsDeleted);
|
||
if (!categoryExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
// 获取该分类关联的所有题目
|
||
var mappings = await _dbContext.QuestionCategoryMappings
|
||
.AsNoTracking()
|
||
.Where(m => m.CategoryId == categoryId)
|
||
.Join(
|
||
_dbContext.Questions.Where(q => !q.IsDeleted),
|
||
m => m.QuestionId,
|
||
q => q.Id,
|
||
(m, q) => new { Mapping = m, Question = q })
|
||
.Join(
|
||
_dbContext.AssessmentTypes.Where(t => !t.IsDeleted),
|
||
mq => mq.Question.AssessmentTypeId,
|
||
t => t.Id,
|
||
(mq, t) => new MappingQuestionDto
|
||
{
|
||
Id = mq.Question.Id,
|
||
QuestionNo = mq.Question.QuestionNo,
|
||
Content = mq.Question.Content,
|
||
AssessmentTypeId = mq.Question.AssessmentTypeId,
|
||
AssessmentTypeName = t.Name,
|
||
MappingCreateTime = mq.Mapping.CreateTime
|
||
})
|
||
.OrderBy(q => q.AssessmentTypeId)
|
||
.ThenBy(q => q.QuestionNo)
|
||
.ToListAsync();
|
||
|
||
return mappings;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> BatchUpdateMappingsAsync(BatchUpdateMappingsRequest request)
|
||
{
|
||
// 验证题目ID
|
||
if (request.QuestionId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "题目ID无效");
|
||
}
|
||
|
||
// 验证题目是否存在
|
||
var questionExists = await _dbContext.Questions
|
||
.AnyAsync(q => q.Id == request.QuestionId && !q.IsDeleted);
|
||
if (!questionExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.QuestionNotFound, "题目不存在");
|
||
}
|
||
|
||
// 验证所有分类ID是否存在
|
||
if (request.CategoryIds != null && request.CategoryIds.Count > 0)
|
||
{
|
||
// 去重
|
||
var uniqueCategoryIds = request.CategoryIds.Distinct().ToList();
|
||
|
||
var existingCategoryIds = await _dbContext.ReportCategories
|
||
.Where(c => uniqueCategoryIds.Contains(c.Id) && !c.IsDeleted)
|
||
.Select(c => c.Id)
|
||
.ToListAsync();
|
||
|
||
var invalidCategoryIds = uniqueCategoryIds.Except(existingCategoryIds).ToList();
|
||
if (invalidCategoryIds.Count > 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound,
|
||
$"以下分类ID不存在: {string.Join(", ", invalidCategoryIds)}");
|
||
}
|
||
}
|
||
|
||
// 使用事务确保原子性
|
||
using var transaction = await _dbContext.Database.BeginTransactionAsync();
|
||
try
|
||
{
|
||
// 删除该题目的所有现有映射
|
||
var existingMappings = await _dbContext.QuestionCategoryMappings
|
||
.Where(m => m.QuestionId == request.QuestionId)
|
||
.ToListAsync();
|
||
|
||
if (existingMappings.Count > 0)
|
||
{
|
||
_dbContext.QuestionCategoryMappings.RemoveRange(existingMappings);
|
||
}
|
||
|
||
// 创建新的映射
|
||
if (request.CategoryIds != null && request.CategoryIds.Count > 0)
|
||
{
|
||
var uniqueCategoryIds = request.CategoryIds.Distinct().ToList();
|
||
var newMappings = uniqueCategoryIds.Select(categoryId => new QuestionCategoryMapping
|
||
{
|
||
QuestionId = request.QuestionId,
|
||
CategoryId = categoryId,
|
||
CreateTime = DateTime.Now
|
||
}).ToList();
|
||
|
||
_dbContext.QuestionCategoryMappings.AddRange(newMappings);
|
||
}
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
await transaction.CommitAsync();
|
||
|
||
_logger.LogInformation("批量更新题目分类映射成功,题目ID: {QuestionId}, 分类数量: {CategoryCount}",
|
||
request.QuestionId, request.CategoryIds?.Count ?? 0);
|
||
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await transaction.RollbackAsync();
|
||
_logger.LogError(ex, "批量更新题目分类映射失败,题目ID: {QuestionId}", request.QuestionId);
|
||
throw new BusinessException(ErrorCodes.SystemError, "批量更新映射失败,请稍后重试");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 报告结论操作
|
||
|
||
/// <summary>
|
||
/// 结论类型名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> ConclusionTypeNames = new()
|
||
{
|
||
{ 1, "最强" },
|
||
{ 2, "较强" },
|
||
{ 3, "较弱" },
|
||
{ 4, "最弱" }
|
||
};
|
||
|
||
/// <inheritdoc />
|
||
public async Task<List<ConclusionDto>> GetConclusionListAsync(long categoryId)
|
||
{
|
||
// 验证分类ID
|
||
if (categoryId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类ID无效");
|
||
}
|
||
|
||
// 验证分类是否存在
|
||
var categoryExists = await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.Id == categoryId && !c.IsDeleted);
|
||
if (!categoryExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
// 获取该分类下的所有结论,按结论类型排序
|
||
var conclusions = await _dbContext.ReportConclusions
|
||
.AsNoTracking()
|
||
.Where(c => c.CategoryId == categoryId && !c.IsDeleted)
|
||
.Join(
|
||
_dbContext.ReportCategories.Where(cat => !cat.IsDeleted),
|
||
c => c.CategoryId,
|
||
cat => cat.Id,
|
||
(c, cat) => new ConclusionDto
|
||
{
|
||
Id = c.Id,
|
||
CategoryId = c.CategoryId,
|
||
CategoryName = cat.Name,
|
||
ConclusionType = c.ConclusionType,
|
||
ConclusionTypeName = GetConclusionTypeName(c.ConclusionType),
|
||
Title = c.Title,
|
||
Content = c.Content,
|
||
CreateTime = c.CreateTime
|
||
})
|
||
.OrderBy(c => c.ConclusionType)
|
||
.ToListAsync();
|
||
|
||
return conclusions;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<ConclusionDto> GetConclusionByIdAsync(long id)
|
||
{
|
||
var conclusion = await _dbContext.ReportConclusions
|
||
.AsNoTracking()
|
||
.Where(c => c.Id == id && !c.IsDeleted)
|
||
.Join(
|
||
_dbContext.ReportCategories.Where(cat => !cat.IsDeleted),
|
||
c => c.CategoryId,
|
||
cat => cat.Id,
|
||
(c, cat) => new ConclusionDto
|
||
{
|
||
Id = c.Id,
|
||
CategoryId = c.CategoryId,
|
||
CategoryName = cat.Name,
|
||
ConclusionType = c.ConclusionType,
|
||
ConclusionTypeName = GetConclusionTypeName(c.ConclusionType),
|
||
Title = c.Title,
|
||
Content = c.Content,
|
||
CreateTime = c.CreateTime
|
||
})
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (conclusion == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ConclusionNotFound, "结论不存在");
|
||
}
|
||
|
||
return conclusion;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<long> CreateConclusionAsync(CreateConclusionRequest request)
|
||
{
|
||
// 验证分类ID
|
||
if (request.CategoryId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类ID无效");
|
||
}
|
||
|
||
// 验证结论类型有效性
|
||
if (request.ConclusionType < 1 || request.ConclusionType > 4)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "结论类型无效,只能为1(最强)、2(较强)、3(较弱)或4(最弱)");
|
||
}
|
||
|
||
// 验证内容必填
|
||
if (string.IsNullOrWhiteSpace(request.Content))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "结论内容不能为空");
|
||
}
|
||
|
||
// 验证分类是否存在
|
||
var categoryExists = await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.Id == request.CategoryId && !c.IsDeleted);
|
||
if (!categoryExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
// 创建实体
|
||
var conclusion = new ReportConclusion
|
||
{
|
||
CategoryId = request.CategoryId,
|
||
ConclusionType = request.ConclusionType,
|
||
Title = request.Title,
|
||
Content = request.Content,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
|
||
_dbContext.ReportConclusions.Add(conclusion);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("创建结论成功,ID: {ConclusionId}, 分类ID: {CategoryId}, 结论类型: {ConclusionType}",
|
||
conclusion.Id, conclusion.CategoryId, conclusion.ConclusionType);
|
||
|
||
return conclusion.Id;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateConclusionAsync(UpdateConclusionRequest request)
|
||
{
|
||
// 查找结论
|
||
var conclusion = await _dbContext.ReportConclusions
|
||
.Where(c => c.Id == request.Id && !c.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (conclusion == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ConclusionNotFound, "结论不存在");
|
||
}
|
||
|
||
// 验证分类ID
|
||
if (request.CategoryId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "分类ID无效");
|
||
}
|
||
|
||
// 验证结论类型有效性
|
||
if (request.ConclusionType < 1 || request.ConclusionType > 4)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "结论类型无效,只能为1(最强)、2(较强)、3(较弱)或4(最弱)");
|
||
}
|
||
|
||
// 验证内容必填
|
||
if (string.IsNullOrWhiteSpace(request.Content))
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "结论内容不能为空");
|
||
}
|
||
|
||
// 验证分类是否存在
|
||
var categoryExists = await _dbContext.ReportCategories
|
||
.AnyAsync(c => c.Id == request.CategoryId && !c.IsDeleted);
|
||
if (!categoryExists)
|
||
{
|
||
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
|
||
}
|
||
|
||
// 更新字段
|
||
conclusion.CategoryId = request.CategoryId;
|
||
conclusion.ConclusionType = request.ConclusionType;
|
||
conclusion.Title = request.Title;
|
||
conclusion.Content = request.Content;
|
||
conclusion.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新结论成功,ID: {ConclusionId}", conclusion.Id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> DeleteConclusionAsync(long id)
|
||
{
|
||
// 查找结论
|
||
var conclusion = await _dbContext.ReportConclusions
|
||
.Where(c => c.Id == id && !c.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (conclusion == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ConclusionNotFound, "结论不存在");
|
||
}
|
||
|
||
// 软删除
|
||
conclusion.IsDeleted = true;
|
||
conclusion.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("删除结论成功,ID: {ConclusionId}", id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取结论类型名称
|
||
/// </summary>
|
||
/// <param name="conclusionType">结论类型值</param>
|
||
/// <returns>结论类型名称</returns>
|
||
private static string GetConclusionTypeName(int conclusionType)
|
||
{
|
||
return ConclusionTypeNames.TryGetValue(conclusionType, out var name) ? name : "未知";
|
||
}
|
||
|
||
#endregion
|
||
}
|