题库定制化导入Excwl开发

master
xiaochanghai 1 year ago
parent d5631012a5
commit 92a4c85135
  1. 17
      Tiobon.Core.Api/Controllers/Base/BaseController.cs
  2. 8
      Tiobon.Core.Api/Controllers/Ghre/Ghre_QuestionController.cs
  3. 2
      Tiobon.Core.Api/Tiobon.Core.xml
  4. 36
      Tiobon.Core.Common/Helper/NPOIHelper.cs
  5. 5
      Tiobon.Core.IServices/BASE/IBaseServices.cs
  6. 20
      Tiobon.Core.IServices/Ghre/IGhre_QuestionServices.cs
  7. 2
      Tiobon.Core.Model/Base/Ghre/Ghre_CourseWareAttachment.Dto.Base.cs
  8. 15
      Tiobon.Core.Services/BASE/BaseServices.cs
  9. 4
      Tiobon.Core.Services/Ghre/Ghre_CourseServices.cs
  10. 169
      Tiobon.Core.Services/Ghre/Ghre_QuestionServices.cs
  11. 2
      Tiobon.Core/Tiobon.Core.xml

@ -210,10 +210,21 @@ public class BaseController<IServiceBase, TEntity, TEntityDto, TInsertDto, TEdit
/// </summary> /// </summary>
/// <param name="body"></param> /// <param name="body"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost, Route("Export")] [HttpPost, Route("ExportExcel")]
public async Task<ServiceResult<long>> Export([FromBody] QueryBody body) public async Task<ServiceResult<long>> ExportExcel([FromBody] QueryBody body)
{ {
var data = (await InvokeServiceAsync("Export", [body])) as ServiceResult<long>; var data = (await InvokeServiceAsync("ExportExcel", [body])) as ServiceResult<long>;
return data;
}
#endregion
#region Excel导入
[HttpPost("ImportExcel")]
public async Task<ServiceResult<string>> ImportExcel(IFormFile file)
{
var data = (await InvokeServiceAsync("ImportExcel", [file])) as ServiceResult<string>;
return data; return data;
} }
#endregion #endregion

@ -60,12 +60,4 @@ public class Ghre_QuestionController : BaseController<IGhre_QuestionServices, Gh
#endregion\ #endregion\
#region Excel导入
[HttpPost("ImportExcel")]
public async Task<ServiceResult> ImportExcelAsync(IFormFile file)
{
return await _service.ImportExcelAsync(file);
}
#endregion
} }

@ -141,7 +141,7 @@
<param name="Ids">主键IDs</param> <param name="Ids">主键IDs</param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:Tiobon.Core.Controllers.BaseController`5.Export(Tiobon.Core.Common.QueryBody)"> <member name="M:Tiobon.Core.Controllers.BaseController`5.ExportExcel(Tiobon.Core.Common.QueryBody)">
<summary> <summary>
Excel导出 Excel导出
</summary> </summary>

@ -1,4 +1,5 @@
using System.Data; using System.Data;
using System.IO;
using System.Text; using System.Text;
using NPOI.HPSF; using NPOI.HPSF;
using NPOI.HSSF.UserModel; using NPOI.HSSF.UserModel;
@ -16,11 +17,28 @@ public class NPOIHelper
/// <param name="dtSource">源 DataTable</param> /// <param name="dtSource">源 DataTable</param>
/// <param name="strHeaderText">表头文本 空值未不要表头标题</param> /// <param name="strHeaderText">表头文本 空值未不要表头标题</param>
/// <returns></returns> /// <returns></returns>
public static MemoryStream ExportExcel(DataTable dtSource, string strHeaderText) public static MemoryStream GenerateExportExcel(DataTable dtSource, string strHeaderText, string sheetName, string strFileName = null)
{ {
//HSSFWorkbook workbook = new HSSFWorkbook(); IWorkbook workbook = new XSSFWorkbook();
XSSFWorkbook workbook = new XSSFWorkbook(); ISheet sheet;
ISheet sheet = workbook.CreateSheet(); if (!File.Exists(strFileName))
{
sheet = workbook.CreateSheet(sheetName);
}
else
{
using (FileStream file = new FileStream(strFileName, FileMode.Open, FileAccess.Read))
{
//hssfworkbook = new HSSFWorkbook(file);
//hssfworkbook = new XSSFWorkbook(file);
workbook = WorkbookFactory.Create(file);
}
if (workbook == null) throw new Exception("未能加载excel");
sheet = workbook.CreateSheet(sheetName);
}
#region 文件属性 #region 文件属性
DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation(); DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
dsi.Company = "EUCloud"; dsi.Company = "EUCloud";
@ -72,7 +90,7 @@ public class NPOIHelper
intTop = 0; intTop = 0;
#region 表头及样式 #region 表头及样式
{ {
if (strHeaderText.Length > 0) if (!string.IsNullOrWhiteSpace(strHeaderText) && strHeaderText.Length > 0)
{ {
IRow headerRow = sheet.CreateRow(intTop); IRow headerRow = sheet.CreateRow(intTop);
intTop += 1; intTop += 1;
@ -190,6 +208,7 @@ public class NPOIHelper
{ {
workbook.Write(ms); workbook.Write(ms);
ms.Flush(); ms.Flush();
workbook.Dispose();
//ms.Position = 0; //ms.Position = 0;
return ms; return ms;
} }
@ -203,9 +222,9 @@ public class NPOIHelper
/// <param name="dtSource">源 DataaTable</param> /// <param name="dtSource">源 DataaTable</param>
/// <param name="strHeaderText">表头文本</param> /// <param name="strHeaderText">表头文本</param>
/// <param name="strFileName">保存位置(文件名及路径)</param> /// <param name="strFileName">保存位置(文件名及路径)</param>
public static void ExportExcel(DataTable dtSource, string strHeaderText, string strFileName) public static void ExportExcel(DataTable dtSource, string strHeaderText, string sheetName = null, string strFileName = null)
{ {
using (MemoryStream ms = ExportExcel(dtSource, strHeaderText)) using (MemoryStream ms = GenerateExportExcel(dtSource, strHeaderText, sheetName, strFileName))
{ {
using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write)) using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
{ {
@ -260,7 +279,8 @@ public class NPOIHelper
for (int j = 0; j < cellCount; j++) for (int j = 0; j < cellCount; j++)
{ {
ICell cell = headerRow.GetCell(j); ICell cell = headerRow.GetCell(j);
dt.Columns.Add(cell.ToString()); if (!string.IsNullOrWhiteSpace(cell.ToString()))
dt.Columns.Add(cell.ToString());
} }
for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++) for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
{ {

@ -1,5 +1,6 @@
using System.Data; using System.Data;
using System.Linq.Expressions; using System.Linq.Expressions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using SqlSugar; using SqlSugar;
using Tiobon.Core.Common; using Tiobon.Core.Common;
@ -150,7 +151,9 @@ namespace Tiobon.Core.IServices.BASE
Task<PageModel<TEntity>> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int pageIndex = 1, int pageSize = 20, string orderByFields = null); Task<PageModel<TEntity>> QueryPage(Expression<Func<TEntity, bool>> whereExpression, int pageIndex = 1, int pageSize = 20, string orderByFields = null);
Task<ServicePageResult<TEntityDto>> QueryFilterPage([FromBody] QueryBody body); Task<ServicePageResult<TEntityDto>> QueryFilterPage([FromBody] QueryBody body);
Task<ServicePageResult<TEntityDto>> QueryFilterPage(QueryBody filter, string condition); Task<ServicePageResult<TEntityDto>> QueryFilterPage(QueryBody filter, string condition);
Task<ServiceResult<long>> Export([FromBody] QueryBody body); Task<ServiceResult<long>> ExportExcel([FromBody] QueryBody body);
Task<ServiceResult<string>> ImportExcel(IFormFile file);
Task<List<TResult>> QueryMuch<T, T2, T3, TResult>( Task<List<TResult>> QueryMuch<T, T2, T3, TResult>(
Expression<Func<T, T2, T3, object[]>> joinExpression, Expression<Func<T, T2, T3, object[]>> joinExpression,

@ -4,17 +4,15 @@ using Tiobon.Core.Model;
using Tiobon.Core.Model.Models; using Tiobon.Core.Model.Models;
namespace Tiobon.Core.IServices namespace Tiobon.Core.IServices
{ {
/// <summary> /// <summary>
/// 题目(自定义服务接口) /// 题目(自定义服务接口)
/// </summary> /// </summary>
public interface IGhre_QuestionServices :IBaseServices<Ghre_Question, Ghre_QuestionDto, InsertGhre_QuestionInput, EditGhre_QuestionInput> public interface IGhre_QuestionServices : IBaseServices<Ghre_Question, Ghre_QuestionDto, InsertGhre_QuestionInput, EditGhre_QuestionInput>
{ {
Task<ServiceResult<FromGhre_QuestionInput>> QueryFrom(long Id); Task<ServiceResult<FromGhre_QuestionInput>> QueryFrom(long Id);
Task<ServiceResult> InsertFrom(FromGhre_QuestionPageData insertModel); Task<ServiceResult> InsertFrom(FromGhre_QuestionPageData insertModel);
Task<ServiceResult> UpdareFrom(long Id, FromGhre_QuestionPageData insertModel); Task<ServiceResult> UpdareFrom(long Id, FromGhre_QuestionPageData insertModel);
Task<ServiceResult> ImportExcelAsync(IFormFile file);
} }
} }

@ -40,7 +40,7 @@ namespace Tiobon.Core.Model.Models
/// <summary> /// <summary>
/// 扩展名 /// 扩展名
/// </summary> /// </summary>
[Display(Name = "AttachFileExtension"), Description("扩展名"), MaxLength(32, ErrorMessage = "扩展名 不能超过 32 个字符")] [Display(Name = "AttachFileExtension"), Description("扩展名"), MaxLength(256, ErrorMessage = "扩展名 不能超过 256 个字符")]
public string AttachFileExtension { get; set; } public string AttachFileExtension { get; set; }
/// <summary> /// <summary>

@ -20,6 +20,7 @@ using Tiobon.Core.Common.Helper;
using Tiobon.Core.Common.UserManager; using Tiobon.Core.Common.UserManager;
using Tiobon.Core.DataAccess; using Tiobon.Core.DataAccess;
using Tiobon.Core.IRepository.Base; using Tiobon.Core.IRepository.Base;
using Tiobon.Core.IServices;
using Tiobon.Core.IServices.BASE; using Tiobon.Core.IServices.BASE;
using Tiobon.Core.Model; using Tiobon.Core.Model;
using Tiobon.Core.Model.Models; using Tiobon.Core.Model.Models;
@ -788,7 +789,7 @@ public class BaseServices<TEntity, TEntityDto, TInsertDto, TEditDto> : IBaseServ
return new ServicePageResult<TEntityDto>(filter.pageNum, total, filter.pageSize, entitys); return new ServicePageResult<TEntityDto>(filter.pageNum, total, filter.pageSize, entitys);
} }
public async Task<ServiceResult<long>> Export(QueryBody body) public async Task<ServiceResult<long>> ExportExcel(QueryBody body)
{ {
//sql = @$"SELECT field, //sql = @$"SELECT field,
// [dbo].[FLangKeyToValue] (mkey, {body.langId}, label) // [dbo].[FLangKeyToValue] (mkey, {body.langId}, label)
@ -816,6 +817,18 @@ public class BaseServices<TEntity, TEntityDto, TInsertDto, TEditDto> : IBaseServ
} }
public async virtual Task<ServiceResult<string>> ImportExcel(IFormFile file)
{
//long id = SnowFlakeSingle.instance.getID();
//var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot";
//var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}import{Path.DirectorySeparatorChar}{id}{Path.DirectorySeparatorChar}"}";
//if (!Directory.Exists(physicsPath + path))
// Directory.CreateDirectory(physicsPath + path);
return ServiceResult<string>.OprateSuccess("导入成功!");
}
public async Task<List<TResult>> QueryMuch<T, T2, T3, TResult>(Expression<Func<T, T2, T3, object[]>> joinExpression, Expression<Func<T, T2, T3, TResult>> selectExpression, Expression<Func<T, T2, T3, bool>> whereLambda = null) where T : class, new() public async Task<List<TResult>> QueryMuch<T, T2, T3, TResult>(Expression<Func<T, T2, T3, object[]>> joinExpression, Expression<Func<T, T2, T3, TResult>> selectExpression, Expression<Func<T, T2, T3, bool>> whereLambda = null) where T : class, new()
{ {
return await BaseDal.QueryMuch(joinExpression, selectExpression, whereLambda); return await BaseDal.QueryMuch(joinExpression, selectExpression, whereLambda);

@ -139,7 +139,7 @@ public class Ghre_CourseServices : BaseServices<Ghre_Course, Ghre_CourseDto, Ins
CASE A.InOrOut CASE A.InOrOut
WHEN 'In' THEN F.StaffName WHEN 'In' THEN F.StaffName
WHEN 'Out' THEN J.TeacherName WHEN 'Out' THEN J.TeacherName
END TeacherName END TeacherName, ISNULL(A.UpdateTime, A.CreateTime) CreateTime1
FROM Ghre_Course A FROM Ghre_Course A
LEFT JOIN Ghre_CourseClass B ON A.CourseClassId = B.Id LEFT JOIN Ghre_CourseClass B ON A.CourseClassId = B.Id
LEFT JOIN Ghre_CourseClass C ON A.CourseClassId2 = C.Id LEFT JOIN Ghre_CourseClass C ON A.CourseClassId2 = C.Id
@ -153,7 +153,7 @@ public class Ghre_CourseServices : BaseServices<Ghre_Course, Ghre_CourseDto, Ins
WHERE A.IsEnable = 1) A"; WHERE A.IsEnable = 1) A";
if (string.IsNullOrWhiteSpace(filter.orderBy)) if (string.IsNullOrWhiteSpace(filter.orderBy))
filter.orderBy = "CreateTime DESC"; filter.orderBy = "CreateTime1 DESC";
string conditions = " WHERE 1=1"; string conditions = " WHERE 1=1";

@ -4,7 +4,6 @@ using AgileObjects.AgileMapper;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using SharpCompress.Common;
using SqlSugar; using SqlSugar;
using Tiobon.Core.Common; using Tiobon.Core.Common;
using Tiobon.Core.Common.Caches; using Tiobon.Core.Common.Caches;
@ -785,24 +784,25 @@ public class Ghre_QuestionServices : BaseServices<Ghre_Question, Ghre_QuestionDt
} }
#region Excel导入 #region Excel导入
public async Task<ServiceResult> ImportExcelAsync(IFormFile file) public override async Task<ServiceResult<string>> ImportExcel(IFormFile file)
{ {
long id = SnowFlakeSingle.instance.getID(); long id = SnowFlakeSingle.instance.getID();
var path = $"{$"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}import{Path.DirectorySeparatorChar}{id}{Path.DirectorySeparatorChar}"}"; var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot";
if (!Directory.Exists(path)) var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}import{Path.DirectorySeparatorChar}{id}{Path.DirectorySeparatorChar}"}";
Directory.CreateDirectory(path); if (!Directory.Exists(physicsPath + path))
Directory.CreateDirectory(physicsPath + path);
var filepath = path + file.FileName; var filepath = physicsPath + path + file.FileName;
using (var stream = File.Create(filepath)) using (var stream = File.Create(filepath))
{ {
await file.CopyToAsync(stream); await file.CopyToAsync(stream);
} }
string extension = Path.GetExtension(filepath);
var types = new List<string> var types = new List<string>
{ {
"单选题", "单选题",
//"多选题", "多选题",
//"判断题", "判断题",
//"填空题", //"填空题",
//"简答题", //"简答题",
}; };
@ -818,35 +818,68 @@ public class Ghre_QuestionServices : BaseServices<Ghre_Question, Ghre_QuestionDt
"H", "H",
}; };
bool isExistError = false;
types.ForEach(async x => var id1 = SnowFlakeSingle.instance.getID();
{ string errorFileName = path + SnowFlakeSingle.instance.getID() + extension;
//types.ForEach(async x =>
//{
// string questionType = ConvertQuestionType1(x);
// DataTable dt = NPOIHelper.ImportExcel(filepath, x);
// NPOIHelper.ExportExcel(dt, null, x, path + id1 + extension);
//});
types.ForEach(async x =>
{
string questionType = ConvertQuestionType1(x);
DataTable dt = NPOIHelper.ImportExcel(filepath, x);
if (dt.Columns["Comments"] == null)
dt.Columns.Add("Comments", typeof(string));
string questionType = ConvertQuestionType1(x); for (int i = 0; i < dt.Rows.Count; i++)
DataTable dt = NPOIHelper.ImportExcel(filepath, "单选题"); {
for (int i = 0; i < dt.Rows.Count; i++) var comments = new List<string>();
var courseName = dt.Rows[i]["课程(必填)"].ToString();
var questionContent = dt.Rows[i]["题目内容(必填)"].ToString();
var correctAnswer = dt.Rows[i]["正确答案(必填)"].ToString();
var questionAnalysis = dt.Rows[i]["解析"].ToString();
var difficultyLevel = dt.Rows[i]["难度"].ToString() ?? "普通";
if (string.IsNullOrEmpty(questionContent))
comments.Add("题目内容为必填项!");
var question = await base.Query(x => x.QuestionContent == questionContent && x.QuestionType == questionType);
if (!question.Any())
{ {
var course = await _ghre_CourseServices.Query(x => x.CourseName == dt.Rows[i]["课程(必填)"].ToString());
var questionContent = dt.Rows[i]["题干(必填)"].ToString(); if (string.IsNullOrEmpty(courseName))
var correctAnswer = dt.Rows[i]["正确答案(必填)"].ToString(); comments.Add("课程为必填项!");
var questionAnalysis = dt.Rows[i]["解析"].ToString(); if (string.IsNullOrWhiteSpace(correctAnswer))
var difficultyLevel = dt.Rows[i]["难度"].ToString(); comments.Add("正确答案未标记!");
if (string.IsNullOrWhiteSpace(difficultyLevel))
comments.Add("难易程度必填!");
if (string.IsNullOrWhiteSpace(questionAnalysis))
comments.Add("题目解析必填!");
var question = await base.Query(x => x.QuestionContent == questionContent); var course = await _ghre_CourseServices.QuerySingleDto(x => x.CourseName == courseName);
if (!question.Any()) if (course is null)
comments.Add("课程不存在,请修正!");
var insert = new InsertGhre_QuestionInput()
{ {
var insert = new InsertGhre_QuestionInput() CourseId = course.Id,
{ QuestionNo = await GenerateContinuousSequence(questionType.Substring(0, 1)),
CourseId = course.FirstOrDefault().Id, DifficultyLevel = ConvertDifficultyLevel1(difficultyLevel),
QuestionNo = await GenerateContinuousSequence(questionType.Substring(0, 1)), QuestionType = questionType,
DifficultyLevel = ConvertDifficultyLevel1(difficultyLevel), QuestionContent = questionContent,
QuestionType = questionType, QuestionAnalysis = questionAnalysis
QuestionContent = questionContent, };
QuestionAnalysis = questionAnalysis var insertAnswers = new List<InsertGhre_QuestionAnswerInput>();
};
var id = await base.Add(insert); if (questionType == "Single" || questionType == "Multiple")
var insertAnswers = new List<InsertGhre_QuestionAnswerInput>(); {
#region 单选题/多选题
int j = 100; int j = 100;
answers.ForEach(a => answers.ForEach(a =>
{ {
@ -855,14 +888,14 @@ public class Ghre_QuestionServices : BaseServices<Ghre_Question, Ghre_QuestionDt
{ {
var isCorrect = false; var isCorrect = false;
if (x == "单选题" && correctAnswer == a) if (correctAnswer.Contains(a))
isCorrect = true; isCorrect = true;
insertAnswers.Add(new InsertGhre_QuestionAnswerInput() insertAnswers.Add(new InsertGhre_QuestionAnswerInput()
{ {
TaxisNo = j, TaxisNo = j,
QuestionNo = a, QuestionNo = a,
QuestionId = id, //QuestionId = id,
AnswerContent = answer, AnswerContent = answer,
IsCorrect = isCorrect IsCorrect = isCorrect
}); });
@ -871,19 +904,73 @@ public class Ghre_QuestionServices : BaseServices<Ghre_Question, Ghre_QuestionDt
j = j + 100; j = j + 100;
}); });
await _ghre_QuestionAnswerServices.Add(insertAnswers); if (!insertAnswers.Any())
comments.Add(questionType == "ShortAnswer" ? "关键词未填写!" : "答案选项必填!");
if (insertAnswers.Count < 2 && questionType != "ShortAnswer" && questionType != "Completion")
comments.Add("答案选项不能少于两个!");
if ((questionType == "Single" || questionType == "Multiple" || questionType == "TrueOrFalse") && !insertAnswers.Any(o => o.IsCorrect == true))
comments.Add("正确答案未标记!");
if (questionType == "Multiple" && insertAnswers.Where(o => o.IsCorrect == true).Count() < 2)
comments.Add("答案至少需标记处两个正确答案!");
#endregion
} }
else else if (questionType == "TrueOrFalse")
{ {
#region 判断题
insertAnswers.Add(new InsertGhre_QuestionAnswerInput()
{
TaxisNo = 100,
QuestionNo = "A",
//QuestionId = id,
AnswerContent = "对",
IsCorrect = correctAnswer == "正确"
});
insertAnswers.Add(new InsertGhre_QuestionAnswerInput()
{
TaxisNo = 200,
QuestionNo = "B",
//QuestionId = id,
AnswerContent = "错",
IsCorrect = correctAnswer == "错误"
});
#endregion
} }
if (comments.Any())
{
dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
isExistError = true;
continue;
}
else
{
var id = await base.Add(insert);
insertAnswers.ForEach(x => x.QuestionId = id);
await _ghre_QuestionAnswerServices.Add(insertAnswers);
}
} }
}); else
{
return ServiceResult.OprateSuccess("新增成功!"); dt.Rows[i]["Comments"] = "试题在系统中已存在!";
isExistError = true;
continue;
}
}
if (isExistError)
NPOIHelper.ExportExcel(dt, null, x, physicsPath + errorFileName);
});
if (isExistError)
return ServiceResult<string>.OprateFailed("导入文件存在错误,请下载后查看!", errorFileName);
else
return ServiceResult<string>.OprateSuccess("导入成功!");
} }
#endregion #endregion
} }

@ -141,7 +141,7 @@
<param name="Ids">主键IDs</param> <param name="Ids">主键IDs</param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:Tiobon.Core.Controllers.BaseController`5.Export(Tiobon.Core.Common.QueryBody)"> <member name="M:Tiobon.Core.Controllers.BaseController`5.ExportExcel(Tiobon.Core.Common.QueryBody)">
<summary> <summary>
Excel导出 Excel导出
</summary> </summary>

Loading…
Cancel
Save