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;
///
/// 测评管理服务实现
///
public class AssessmentService : IAssessmentService
{
private readonly AdminBusinessDbContext _dbContext;
private readonly ILogger _logger;
///
/// 测评类型状态名称映射
///
private static readonly Dictionary TypeStatusNames = new()
{
{ 0, "已下线" },
{ 1, "已上线" },
{ 2, "即将上线" }
};
///
/// 构造函数
///
/// 数据库上下文
/// 日志记录器
public AssessmentService(
AdminBusinessDbContext dbContext,
ILogger logger)
{
_dbContext = dbContext;
_logger = logger;
}
#region 测评类型操作
///
public async Task> 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.Create(items, total, request.Page, request.PageSize);
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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 题目操作
///
/// 题目状态名称映射
///
private static readonly Dictionary QuestionStatusNames = new()
{
{ 0, "禁用" },
{ 1, "启用" }
};
///
public async Task> 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.Create(questions, total, request.Page, request.PageSize);
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task BatchImportQuestionsAsync(BatchImportQuestionsRequest request)
{
var result = new BatchImportResult
{
TotalCount = request.Questions.Count,
SuccessCount = 0,
FailedCount = 0,
Errors = new List()
};
// 验证测评类型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();
var questionsToAdd = new List();
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;
}
///
public async Task 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 报告分类操作
///
/// 分类类型名称映射
///
private static readonly Dictionary CategoryTypeNames = new()
{
{ 1, "八大智能" },
{ 2, "个人特质" },
{ 3, "细分能力" },
{ 4, "先天学习" },
{ 5, "学习能力" },
{ 6, "大脑类型" },
{ 7, "性格类型" },
{ 8, "未来能力" }
};
///
/// 计分规则名称映射
///
private static readonly Dictionary ScoreRuleNames = new()
{
{ 1, "累加(1-10分)" },
{ 2, "二值(0/1分)" }
};
///
public async Task> 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()
})
.ToListAsync();
// 构建树形结构
return BuildCategoryTree(categories);
}
///
public async Task 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()
})
.FirstOrDefaultAsync();
if (category == null)
{
throw new BusinessException(ErrorCodes.CategoryNotFound, "分类不存在");
}
return category;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task HasChildCategoriesAsync(long categoryId)
{
return await _dbContext.ReportCategories
.AnyAsync(c => c.ParentId == categoryId && !c.IsDeleted);
}
#endregion
#region 私有方法
///
/// 获取测评类型状态名称
///
/// 状态值
/// 状态名称
private static string GetTypeStatusName(int status)
{
return TypeStatusNames.TryGetValue(status, out var name) ? name : "未知";
}
///
/// 获取题目状态名称
///
/// 状态值
/// 状态名称
private static string GetQuestionStatusName(int status)
{
return QuestionStatusNames.TryGetValue(status, out var name) ? name : "未知";
}
///
/// 获取分类类型名称
///
/// 分类类型值
/// 分类类型名称
private static string GetCategoryTypeName(int categoryType)
{
return CategoryTypeNames.TryGetValue(categoryType, out var name) ? name : "未知";
}
///
/// 获取计分规则名称
///
/// 计分规则值
/// 计分规则名称
private static string GetScoreRuleName(int scoreRule)
{
return ScoreRuleNames.TryGetValue(scoreRule, out var name) ? name : "未知";
}
///
/// 构建分类树形结构
///
/// 所有分类列表
/// 树形结构列表(顶级分类)
private static List BuildCategoryTree(List categories)
{
// 创建字典以便快速查找
var categoryDict = categories.ToDictionary(c => c.Id);
// 顶级分类列表
var rootCategories = new List();
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 题目分类映射操作
///
public async Task> 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;
}
///
public async Task> 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;
}
///
public async Task 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 报告结论操作
///
/// 结论类型名称映射
///
private static readonly Dictionary ConclusionTypeNames = new()
{
{ 1, "最强" },
{ 2, "较强" },
{ 3, "较弱" },
{ 4, "最弱" }
};
///
public async Task> 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
public async Task 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;
}
///
/// 获取结论类型名称
///
/// 结论类型值
/// 结论类型名称
private static string GetConclusionTypeName(int conclusionType)
{
return ConclusionTypeNames.TryGetValue(conclusionType, out var name) ? name : "未知";
}
#endregion
}