From 7da88993af956c02299264e108e00e081027a931 Mon Sep 17 00:00:00 2001 From: lyndonliu Date: Tue, 19 Mar 2024 18:31:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=80=83=E8=AF=95=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=94=B6=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DolphinAppService.cs | 5 +- .../Exams/ExamAnnotateEventHandler.cs | 22 ++ .../Exams/ExamGatherEventHandler.cs | 22 ++ .../Exams/ExamManager.cs | 334 ++++++++++++++++++ .../Services/ExamAppService.cs | 17 + .../Constants/DbConsts.cs | 13 + Dolphin.ExamPictureCut.Core/DbConsts.cs | 8 - .../Dolphin.ExamPictureCut.Core.csproj | 13 +- .../DolphinExamPictureCutCoreModule.cs | 17 +- .../Domains/Basic/GroupBook.cs | 120 +++++++ .../Domains/Basic/GroupBookPaperTemplate.cs | 60 ++++ .../Domains/Basic/Tenant.cs | 26 ++ .../Domains/Biz/MarkingSettingObjective.cs | 13 + .../Domains/Biz/MarkingSettingSubjective.cs | 14 + .../Domains/Biz/MkExamResult.cs | 38 ++ .../Domains/Biz/SubjectiveMarkingResult.cs | 26 ++ .../Domains/Quest/PenOfflineData.cs | 61 ++++ .../Exams/Dto/ExamAnnotateEto.cs | 9 + .../Exams/Dto/ExamStudentGatherEto.cs | 32 ++ .../Exams/Dto/TemplateJsonModelDto.cs | 159 +++++++++ .../Exams/IExamManager.cs | 10 + .../Extensions/IdExt.cs | 64 ++++ .../Extensions/RectExt.cs | 31 ++ ...Dolphin.ExamPictureCut.HttpApi.Host.csproj | 10 +- .../DolphinExamPictureCutHttpApiHostModule.cs | 77 +++- .../Properties/launchSettings.json | 14 +- .../appsettings.Development.json | 37 ++ .../appsettings.json | 56 +-- 28 files changed, 1246 insertions(+), 62 deletions(-) create mode 100644 Dolphin.ExamPictureCut.Application/Exams/ExamAnnotateEventHandler.cs create mode 100644 Dolphin.ExamPictureCut.Application/Exams/ExamGatherEventHandler.cs create mode 100644 Dolphin.ExamPictureCut.Application/Exams/ExamManager.cs create mode 100644 Dolphin.ExamPictureCut.Application/Services/ExamAppService.cs create mode 100644 Dolphin.ExamPictureCut.Core/Constants/DbConsts.cs delete mode 100644 Dolphin.ExamPictureCut.Core/DbConsts.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBook.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBookPaperTemplate.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Basic/Tenant.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingObjective.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingSubjective.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Biz/MkExamResult.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Biz/SubjectiveMarkingResult.cs create mode 100644 Dolphin.ExamPictureCut.Core/Domains/Quest/PenOfflineData.cs create mode 100644 Dolphin.ExamPictureCut.Core/Exams/Dto/ExamAnnotateEto.cs create mode 100644 Dolphin.ExamPictureCut.Core/Exams/Dto/ExamStudentGatherEto.cs create mode 100644 Dolphin.ExamPictureCut.Core/Exams/Dto/TemplateJsonModelDto.cs create mode 100644 Dolphin.ExamPictureCut.Core/Exams/IExamManager.cs create mode 100644 Dolphin.ExamPictureCut.Core/Extensions/IdExt.cs create mode 100644 Dolphin.ExamPictureCut.Core/Extensions/RectExt.cs create mode 100644 Dolphin.ExamPictureCut.HttpApi.Host/appsettings.Development.json diff --git a/Dolphin.ExamPictureCut.Application/DolphinAppService.cs b/Dolphin.ExamPictureCut.Application/DolphinAppService.cs index a054514..3d6401a 100644 --- a/Dolphin.ExamPictureCut.Application/DolphinAppService.cs +++ b/Dolphin.ExamPictureCut.Application/DolphinAppService.cs @@ -1,10 +1,13 @@ -using Dolphin.ExamPictureCut.Localization; +using Dolphin.ExamPictureCut.Localization; +using SqlSugar; using Volo.Abp.Application.Services; namespace Dolphin.ExamPictureCut; public abstract class DolphinAppService : ApplicationService { + protected ISqlSugarClient Db => LazyServiceProvider.LazyGetRequiredService(); + protected DolphinAppService() { LocalizationResource = typeof(DolphinResource); diff --git a/Dolphin.ExamPictureCut.Application/Exams/ExamAnnotateEventHandler.cs b/Dolphin.ExamPictureCut.Application/Exams/ExamAnnotateEventHandler.cs new file mode 100644 index 0000000..08af4f7 --- /dev/null +++ b/Dolphin.ExamPictureCut.Application/Exams/ExamAnnotateEventHandler.cs @@ -0,0 +1,22 @@ +using Dolphin.ExamPictureCut.Exams.Dto; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; + +namespace Dolphin.ExamPictureCut.Exams; + +/// +/// 考试批阅后割图 +/// +public class ExamAnnotateEventHandler : IDistributedEventHandler//, ITransientDependency +{ + private readonly IExamManager _examManager; + public ExamAnnotateEventHandler(IExamManager examManager) + { + _examManager = examManager; + } + + public async Task HandleEventAsync(ExamAnnotateEto eventData) + { + await _examManager.ExamAnnotate(eventData); + } +} diff --git a/Dolphin.ExamPictureCut.Application/Exams/ExamGatherEventHandler.cs b/Dolphin.ExamPictureCut.Application/Exams/ExamGatherEventHandler.cs new file mode 100644 index 0000000..8e922ad --- /dev/null +++ b/Dolphin.ExamPictureCut.Application/Exams/ExamGatherEventHandler.cs @@ -0,0 +1,22 @@ +using Dolphin.ExamPictureCut.Exams.Dto; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; + +namespace Dolphin.ExamPictureCut.Exams; + +/// +/// 考试收集 +/// +public class ExamGatherEventHandler : IDistributedEventHandler, ITransientDependency +{ + private readonly IExamManager _examManager; + public ExamGatherEventHandler(IExamManager examManager) + { + _examManager = examManager; + } + + public async Task HandleEventAsync(ExamStudentGatherEto eventData) + { + await _examManager.ExamStudentGather(eventData); + } +} diff --git a/Dolphin.ExamPictureCut.Application/Exams/ExamManager.cs b/Dolphin.ExamPictureCut.Application/Exams/ExamManager.cs new file mode 100644 index 0000000..9c09fb1 --- /dev/null +++ b/Dolphin.ExamPictureCut.Application/Exams/ExamManager.cs @@ -0,0 +1,334 @@ +using Dolphin.ExamPictureCut.Domains.Basic; +using Dolphin.ExamPictureCut.Domains.Biz; +using Dolphin.ExamPictureCut.Domains.Quest; +using Dolphin.ExamPictureCut.Exams.Dto; +using Dolphin.ExamPictureCut.Extensions; +using Flurl.Http; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using NoFurion; +using NoFurion.SqlSugar; +using SkiaSharp; +using SqlSugar; +using Volo.Abp.BlobStoring; +using Volo.Abp.Domain.Services; +using Yitter.IdGenerator; + +namespace Dolphin.ExamPictureCut.Exams; + +public class ExamManager : DomainService, IExamManager +{ + private readonly ISqlSugarClient Db; + private readonly IBlobContainer _blobContainer; + public ExamManager(ISqlSugarClient db, IBlobContainer blobContainer) + { + Db = db; + _blobContainer = blobContainer; + } + + [AutoTran] + public async Task ExamStudentGather(ExamStudentGatherEto eto) + { + var guid = GuidGenerator.Create().ToString("N"); + var penSerial = eto.StudentExamNum; + + var templateIds = JsonConvert.DeserializeObject>(eto.TemplateId); + var templates = await Db.Queryable().Where(w => templateIds.Contains(w.Id)) + .Select(s => new { s.Id, s.PaperId, s.PartId, s.PageIndex, s.ImgUrl, s.QueData }).ToListAsync(); + var paperInfo = templates.Select(s => + { + var data = JsonConvert.DeserializeObject(s.QueData); + return new PaperQueData + { + TemplateId = s.Id, + PaperId = s.PaperId, + PartId = s.PartId, + PageIndex = s.PageIndex, + QueData = data.queData, + }; + }).OrderBy(s => s.PartId).ThenBy(s => s.PageIndex).ToList(); + + var paperIds = templates.Select(s => s.PaperId).ToList(); + + // 获取点阵数据 + var lattices = await Db.Queryable() + .Where(w => w.PenSerial == penSerial && paperIds.Contains(w.PageSerial) && w.logType == LogType.作业) + .Select(s => new PenOfflineData + { + PageSerial = s.PageSerial, + CX = s.CX, + CY = s.CY, + Time = s.Time, + strokeIndex = s.strokeIndex, + }).ToListAsync(); + if (lattices.Count == 0) + { + Logger.LogInformation("{ExamSubjectId} {penSerial} 无点阵数据", eto.ExamSubjectId, penSerial); + return; + } + + var DbBiz = await GetTenantDb(eto.SchoolId); + var kgtDtls = await DbBiz.Queryable() + .Where(w => w.ExamSubjectId == eto.ExamSubjectId) + .Select(s => new MkExamResult + { + Id = YitIdHelper.NextId(), + StudentNo = penSerial, + ExamId = eto.ExamId, + ExamSubjectId = eto.ExamSubjectId, + QuestionNumber = s.QuestionNum, + IsObjectiveQuestion = true, + GroupNo = guid, + }).ToListAsync(); + var zgtSettingDtls = await DbBiz.Queryable().Where(w => w.ExamSubjectId == eto.ExamSubjectId).ToListAsync(); + var zgtDtls = zgtSettingDtls.Select(s => new SubjectiveMarkingResult + { + Id = YitIdHelper.NextId(), + ExamSubjectId = eto.ExamSubjectId, + ExamSubjectSchoolId = eto.ExamSubjectSchoolId, + StudentExamNum = penSerial, + QuestionNum = s.QuestionNum, + TotalScore = s.Score, + SubQuestionCount = s.SubQuestionCount, + SubQuestionDetail = s.SubQuestionDetail, + GroupNo = guid, + BigQuestionNum = s.BigQuestionNum, + IsExcess = s.IsExcess, + }).ToList(); + + // 割原题 + if (!zgtSettingDtls.Any(s => s.DotPenOriginalImg.IsNotNullOrEmpty())) + { + var redisLockKey = "LockKey:" + eto.ExamSubjectId; + var redisLock = await RedisHelper.GetAsync(redisLockKey); + if (string.IsNullOrEmpty(redisLock)) + { + await RedisHelper.SetAsync(redisLockKey, "1"); + foreach (var tmp in templates) + { + var imgStream = await tmp.ImgUrl.GetStreamAsync(); + var bitmap = SKBitmap.Decode(imgStream); + + } + await RedisHelper.SetAsync(redisLockKey, "0"); + } + else + { + while (await RedisHelper.GetAsync(redisLockKey) == "1") + { + Thread.Sleep(500); + } + } + } + + var kgt = new List>(); + var zgt = new List>(); // 纸张Id, 题号, 是否跨页 + var pageSerials = new List(); // 需要计算的页 + foreach (var paper in paperInfo) + { + var paperLatts = lattices.Where(w => w.PageSerial == paper.PaperId).ToList(); + foreach (var que in paper.QueData) + { + if (que.type == "1") // 客观题 + { + if (que.options.Any() && que.options.Any(opt => paperLatts.Any(s => RectExt.IsRectContainsLattice(opt.AnswerArea, s)))) + { + pageSerials.Add(paper.PaperId); + kgt.Add(new(paper.PaperId, que.no)); + } + } + else if (que.type == "2") // 主观题 + { + if (que.options.Any() && paperLatts.Any(s => RectExt.IsRectContainsLattice(que.options[0].AnswerArea, s))) + { + pageSerials.Add(paper.PaperId); + var ky = false; + var quePaperId = paper.PaperId; + var queOthPaper = paperInfo.FirstOrDefault(w => w.PartId == paper.PartId && w.PageIndex != paper.PageIndex && w.QueData.Any(s => s.no == que.no)); + if (queOthPaper != null) + { + ky = true; + if (paper.PageIndex > queOthPaper.PageIndex) + { + pageSerials.Add(queOthPaper.PaperId); + quePaperId = queOthPaper.PaperId; + } + } + if (!zgt.Any(s => s.Item1 == quePaperId && s.Item2 == que.no)) + zgt.Add(new(quePaperId, que.no, ky)); + } + } + } + } + + var kgtPapers = kgt.GroupBy(s => s.Item1).Select(s => s.Key).ToList(); // 客观题处理 + foreach (var paperId in kgtPapers) + { + var paper = paperInfo.FirstOrDefault(w => w.PaperId == paperId); + var paperLatts = lattices.Where(w => w.PageSerial == paperId).ToList(); + + var queNos = kgt.Where(w => w.Item1 == paperId).Select(s => s.Item2).ToList(); + foreach (var queNo in queNos) + { + var queInfo = paper.QueData.FirstOrDefault(w => w.no == queNo); + var queLatts = paperLatts.Where(w => queInfo.options.Any(s => RectExt.IsRectContainsLattice(s.AnswerArea, w)) + || queInfo.resetPoint.Any(s => RectExt.IsRectContainsLattice(s, w))).ToList(); + + long? resetTime = null; + if (queInfo.resetPoint.Any()) + { + var resetLatts = queLatts.Where(w => RectExt.IsRectContainsLattice(queInfo.resetPoint[0], w)).ToList(); + resetTime = resetLatts.Any() ? resetLatts.Max(w => w.Time) : null; + } + + var stuAnswer = ""; + // 遍历每个选项 + foreach (var option in queInfo.options) + { + if (!option.point.Any()) continue; // 该选项无坐标数据 + var choose = queLatts.WhereIF(resetTime.HasValue, w => w.Time > resetTime).Where(a => RectExt.IsRectContainsLattice(option.point[0], a)); + if (!choose.Any()) continue; + stuAnswer += option.option; + } + + var dtl = kgtDtls.FirstOrDefault(w => w.QuestionNumber == queNo); + if (dtl != null) + { + dtl.QuestionValue = stuAnswer; + } + } + } + + var zgtPapers = zgt.GroupBy(s => s.Item1).Select(s => s.Key).ToList(); // 主观题处理 + foreach (var paperId in zgtPapers) + { + var paper = paperInfo.FirstOrDefault(w => w.PaperId == paperId); + var paperJobPage = templateIds.FindIndex(s => s == paper.TemplateId) + 1; + var paperLatts = lattices.Where(w => w.PageSerial == paperId).ToList(); + var paperPicture = $"questionAnswer/{eto.JobId}/{studentId}/{paperJobPage}/{paper.PartId}.png"; + var questionPaperPicture = string.Empty; + + var ques = zgt.Where(w => w.Item1 == paperId).ToList(); + foreach (var que in ques) + { + var queNo = que.Item2; + var queInfo = paper.QueData.FirstOrDefault(w => w.no == queNo); + var answerArea = queInfo.options[0].AnswerArea; + var queLatts = paperLatts.Where(w => RectExt.IsRectContainsLattice(answerArea, w)) + .Select(s => new SubjectiveLatt() + { + Stroke = s.strokeIndex, + X = s.CX.AUToPX(), + Y = s.CY.AUToPX() - answerArea.pxTop, + Time = s.Time, + }).ToList(); + + if (que.Item3) // 跨页 + { + var queOnNextPaper = paperInfo.FirstOrDefault(w => w.PartId == paper.PartId && w.PageIndex == paper.PageIndex + 1 && w.QueData.Any(s => s.no == queNo)); + var queInfoOnNextPaper = queOnNextPaper.QueData.FirstOrDefault(w => w.no == queNo); + var answerAreaOnNextPaper = queInfoOnNextPaper.options[0].AnswerArea; + var queLattsOnNextPaper = lattices.Where(w => w.PageSerial == queOnNextPaper.PaperId && RectExt.IsRectContainsLattice(answerAreaOnNextPaper, w)) + .Select(s => new SubjectiveLatt() + { + Stroke = s.strokeIndex, + X = s.CX.AUToPX(), + Y = s.CY.AUToPX() + answerArea.pxHeight - answerAreaOnNextPaper.pxTop, + Time = s.Time, + }).ToList(); + queLatts.AddRange(queLattsOnNextPaper); + } + + var jobDtl = dtls.FirstOrDefault(w => w.SectionId == paper.PartId && w.QuestionNo == queNo); + var stuAnswer = ""; + + var imgStream = await $"{App.Configuration["Aliyun:OssJob:Host"]}/{jobDtl.QuestionPicture}".GetStreamAsync(); + var queBitmap = SKBitmap.Decode(imgStream); + + using (var canvas = new SKCanvas(queBitmap)) + { + // 一笔一笔的画上去 + var strokeIndexs = queLatts.GroupBy(g => g.Stroke).Select(s => s.Key).ToList(); + foreach (var stroke in strokeIndexs) + { + var points = queLatts.Where(w => w.Stroke == stroke).OrderBy(s => s.Time).Select(s => new SKPoint(s.X, s.Y)).ToArray(); + var skPointMode = SKPointMode.Polygon; + if (points.Length == 1) + skPointMode = SKPointMode.Points; + else if (points.Length == 2) + skPointMode = SKPointMode.Lines; + + canvas.DrawPoints(skPointMode, points, skPaint); + } + stuAnswer = $"questionAnswer/{eto.JobId}/{studentId}/{paperJobPage}/{paper.PartId}-{queNo}.png"; + JobExtension.UploadFileToCloud(stuAnswer, queBitmap.Encode(SKEncodedImageFormat.Png, 100).ToArray()); + } + + questionPaperPicture = jobDtl.QuestionPaperPicture; + jobDtl.StudentAnswers = stuAnswer; + + var dtl = zgtDtls.FirstOrDefault(w => w.QuestionNum == queNo); + if (dtl != null) + { + dtl.StudentAnswer = stuAnswer; + } + } + + // 大图处理(拼接答案) + var paperZgtDtls = dtls.Where(w => w.SectionId == paper.PartId && w.QuestionType == JobQuestionTypeEnum.主观题 && w.QuestionPaperPicture == questionPaperPicture) + .OrderBy(s => SqlFunc.ToInt32(s.QuestionNo)).ToList(); + var bitmaps = new List(); + foreach (var zgtDtl in paperZgtDtls) + { + var studentAnswer = zgtDtl.StudentAnswers; + var url = studentAnswer.IsNotNullOrEmpty() ? studentAnswer : zgtDtl.QuestionPicture; + var imgStream = await $"{App.Configuration["Aliyun:OssJob:Host"]}/{url}".GetStreamAsync(); + var bitmap = SKBitmap.Decode(imgStream); + bitmaps.Add(bitmap); + } + var width = bitmaps.FirstOrDefault()?.Width ?? 0; + var height = bitmaps.Sum(s => s.Height); + using (var paperBitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul)) + { + using (var canvas = new SKCanvas(paperBitmap)) + { + var top = 0; + foreach (var bitmap in bitmaps) + { + canvas.DrawBitmap(bitmap, 0, top); + top += bitmap.Height; + } + } + JobExtension.UploadFileToCloud(paperPicture, paperBitmap.Encode(SKEncodedImageFormat.Png, 100).ToArray()); + } + } + // 删除 + await DbBiz.Deleteable().Where(w => w.ExamSubjectId == eto.ExamSubjectId && w.StudentNo == penSerial).ExecuteCommandAsync(); + await DbBiz.Updateable() + .SetColumns(s => s.IsDeleted == true) + .Where(w => w.ExamSubjectId == eto.ExamSubjectId && w.StudentExamNum == penSerial) + .ExecuteCommandAsync(); + // 新增 + await DbBiz.Insertable(kgtDtls).ExecuteCommandAsync(); + await DbBiz.Insertable(zgtDtls).ExecuteCommandAsync(); + } + + public async Task ExamAnnotate(ExamAnnotateEto eto) + { + } + + public async Task GetTenantDb(long tenantCode) + { + var tenant = await Db.Queryable().Where(w => w.TenantCode == tenantCode).FirstAsync(); + ExceptionExt.ThrowIf(tenant == null, $"{nameof(tenant)} is null with ${tenantCode}"); + + var config = new SqlSugarConfig(); + return new SqlSugarClient(new ConnectionConfig() + { + DbType = DbType.MySql, + ConnectionString = tenant.ConnectionString, + IsAutoCloseConnection = true, + ConfigureExternalServices = config.ExtService, + }); + } +} diff --git a/Dolphin.ExamPictureCut.Application/Services/ExamAppService.cs b/Dolphin.ExamPictureCut.Application/Services/ExamAppService.cs new file mode 100644 index 0000000..be30a4e --- /dev/null +++ b/Dolphin.ExamPictureCut.Application/Services/ExamAppService.cs @@ -0,0 +1,17 @@ +using Dolphin.ExamPictureCut.Exams; + +namespace Dolphin.ExamPictureCut.Services; + +public class ExamAppService : DolphinAppService +{ + private readonly IExamManager _examManager; + public ExamAppService(IExamManager examManager) + { + _examManager = examManager; + } + + public async Task Test() + { + await _examManager.ExamStudentGather(new() { SchoolId = 1 }); + } +} diff --git a/Dolphin.ExamPictureCut.Core/Constants/DbConsts.cs b/Dolphin.ExamPictureCut.Core/Constants/DbConsts.cs new file mode 100644 index 0000000..f570775 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Constants/DbConsts.cs @@ -0,0 +1,13 @@ +namespace Dolphin.ExamPictureCut.Constants; + +public class DbConsts +{ + public const string marking_basic = "marking_basic"; + public const string marking_biz = "marking_biz"; + public const string penoffline = "penoffline"; +} + +public class SysConsts +{ + public const string AppName = "ExamPictureCut"; +} diff --git a/Dolphin.ExamPictureCut.Core/DbConsts.cs b/Dolphin.ExamPictureCut.Core/DbConsts.cs deleted file mode 100644 index 82baa41..0000000 --- a/Dolphin.ExamPictureCut.Core/DbConsts.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Dolphin.ExamPictureCut; - -public class DbConsts -{ - public const string basic = "basic"; -} - - diff --git a/Dolphin.ExamPictureCut.Core/Dolphin.ExamPictureCut.Core.csproj b/Dolphin.ExamPictureCut.Core/Dolphin.ExamPictureCut.Core.csproj index ecf334d..ffba384 100644 --- a/Dolphin.ExamPictureCut.Core/Dolphin.ExamPictureCut.Core.csproj +++ b/Dolphin.ExamPictureCut.Core/Dolphin.ExamPictureCut.Core.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -14,7 +14,18 @@ + + + + + + + + + + + diff --git a/Dolphin.ExamPictureCut.Core/DolphinExamPictureCutCoreModule.cs b/Dolphin.ExamPictureCut.Core/DolphinExamPictureCutCoreModule.cs index aec08dd..f9641fe 100644 --- a/Dolphin.ExamPictureCut.Core/DolphinExamPictureCutCoreModule.cs +++ b/Dolphin.ExamPictureCut.Core/DolphinExamPictureCutCoreModule.cs @@ -1,6 +1,9 @@ -using Dolphin.ExamPictureCut.Localization; +using Dolphin.ExamPictureCut.Localization; using NoFurion.Extensions; using Volo.Abp.Application; +using Volo.Abp.BlobStoring; +using Volo.Abp.BlobStoring.Aliyun; +using Volo.Abp.EventBus.RabbitMq; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; @@ -11,12 +14,22 @@ namespace Dolphin.ExamPictureCut; [DependsOn( typeof(AbpLocalizationModule), - typeof(AbpDddApplicationContractsModule) + typeof(AbpDddApplicationContractsModule), + typeof(AbpBlobStoringAliyunModule), + typeof(AbpEventBusRabbitMqModule) )] public class DolphinExamPictureCutCoreModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { + Configure(options => + { + options.Containers.ConfigureDefault(container => + { + container.UseAliyun(aliyun => { }); + }); + }); + Configure(options => { options.FileSets.AddEmbedded(); diff --git a/Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBook.cs b/Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBook.cs new file mode 100644 index 0000000..0678aa9 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBook.cs @@ -0,0 +1,120 @@ +using Dolphin.ExamPictureCut.Constants; +using SqlSugar; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Dolphin.ExamPictureCut.Domains.Basic; + +[Table(nameof(GroupBook)), Tenant(DbConsts.marking_basic)] +public class GroupBook +{ + [SugarColumn(IsPrimaryKey = true, ColumnName = "id", Length = 32)] + public string Id { get; set; } + + [SugarColumn(ColumnName = "book_id")] + public long BookId { get; set; } + [SugarColumn(ColumnName = "book_name", IsNullable = true)] + public string BookName { get; set; } + + /// + /// 页面方向 0 竖向 1 横向 + /// + [SugarColumn(ColumnName = "orientation")] + public int Orientation { get; set; } + + /// + /// 页面大小 A3 = 8,A4 = 9,A4Small = 10,A5 = 11,B4 = 12, B5 = 13, + /// + [SugarColumn(ColumnName = "page_size")] + public int PaperSize { get; set; } + + /// + /// 所属科目 + /// + [SugarColumn(ColumnName = "course_name", IsNullable = true)] + public string CourseName { get; set; } + + [SugarColumn(ColumnName = "remark", IsNullable = true)] + public string Remark { get; set; } + + /// + /// 是否试卷 + /// + [SugarColumn(ColumnName = "is_paper")] + public bool IsPaper { get; set; } + + /// + /// 是否归档 + /// + [SugarColumn(ColumnName = "is_save")] + public bool IsSave { get; set; } + + [SugarColumn(ColumnName = "download_url", IsNullable = true)] + public string DownloadUrl { get; set; } + /// + /// 生成状态 0 未生成 1 正在生成 2 生成成功 3生成失败 + /// + [SugarColumn(ColumnName = "state")] + public int State { get; set; } + + /// + /// 学段 + /// + [SugarColumn(ColumnName = "stage", IsNullable = true)] + public string Stage { get; set; } + /// + /// 学段Id + /// + [SugarColumn(ColumnName = "stage_id")] + public long StageId { get; set; } + + /// + /// 年级 + /// + [SugarColumn(ColumnName = "grade_name", IsNullable = true)] + public string GradeName { get; set; } + /// + /// 科目 + /// + [SugarColumn(ColumnName = "subject_name", IsNullable = true)] + public string SubjectName { get; set; } + [SugarColumn(ColumnName = "subject_id")] + public int SubjectId { get; set; } + /// + /// 年份 + /// + [SugarColumn(ColumnName = "year")] + public int Year { get; set; } + + /// + /// 模板制作状态 + /// + [SugarColumn(ColumnName = "template_make_status")] + public TemplateMakeStatusEnum TemplateMakeStatus { get; set; } + + /// + /// 归类Id + /// + [SugarColumn(ColumnName = "catalog_id", IsNullable = true)] + public string CatalogId { get; set; } + /// + /// 归类名称 + /// + [SugarColumn(ColumnName = "catalog_name", IsNullable = true)] + public string CatalogName { get; set; } + + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreUpdate = true, InsertServerTime = true)] + public DateTime CreateTime { get; set; } + + [SugarColumn(ColumnName = "update_time", InsertServerTime = true, UpdateServerTime = true)] + public DateTime UpdateTime { get; set; } +} + +/// +/// 模板制作状态 +/// +public enum TemplateMakeStatusEnum +{ + 未制作 = 0, + 制作中 = 1, + 已完成 = 2, +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBookPaperTemplate.cs b/Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBookPaperTemplate.cs new file mode 100644 index 0000000..977b3eb --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Basic/GroupBookPaperTemplate.cs @@ -0,0 +1,60 @@ +using Dolphin.ExamPictureCut.Constants; +using SqlSugar; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Dolphin.ExamPictureCut.Domains.Basic; + +[Table(nameof(GroupBookPaperTemplate)), Tenant(DbConsts.marking_basic)] +public class GroupBookPaperTemplate +{ + [SugarColumn(IsPrimaryKey = true, ColumnName = "id", Length = 32)] + public string Id { get; set; } + + [SugarColumn(ColumnName = "book_id")] + public long BookId { get; set; } + [SugarColumn(ColumnName = "book_name", IsNullable = true)] + public string BookName { get; set; } + + /// + /// 章 + /// + [SugarColumn(ColumnName = "chapter_id")] + public long ChapterId { get; set; } + [SugarColumn(ColumnName = "chapter_name", IsNullable = true)] + public string ChapterName { get; set; } + + /// + /// 节 + /// + [SugarColumn(ColumnName = "part_id")] + public long PartId { get; set; } + [SugarColumn(ColumnName = "part_name", IsNullable = true)] + public string PartName { get; set; } + + [SugarColumn(ColumnName = "page_index")] + public int PageIndex { get; set; } + + [SugarColumn(ColumnName = "paper_id", IsNullable = true)] + public string PaperId { get; set; } + + [SugarColumn(ColumnName = "img_url", IsNullable = true)] + public string ImgUrl { get; set; } + + [SugarColumn(ColumnName = "que_data", IsNullable = true, ColumnDataType = "text")] + public string QueData { get; set; } + + /// + /// 模板制作状态 + /// + [SugarColumn(ColumnName = "template_make_status")] + public TemplateMakeStatusEnum TemplateMakeStatus { get; set; } + + [SugarColumn(ColumnName = "order")] + public int Order { get; set; } + + [SugarColumn(ColumnName = "create_time", IsOnlyIgnoreUpdate = true, InsertServerTime = true)] + public DateTime CreateTime { get; set; } + + [SugarColumn(ColumnName = "update_time", InsertServerTime = true, UpdateServerTime = true)] + public DateTime UpdateTime { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Basic/Tenant.cs b/Dolphin.ExamPictureCut.Core/Domains/Basic/Tenant.cs new file mode 100644 index 0000000..40c621f --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Basic/Tenant.cs @@ -0,0 +1,26 @@ +using Dolphin.ExamPictureCut.Constants; +using SqlSugar; +using System.ComponentModel.DataAnnotations.Schema; +using Volo.Abp; + +namespace Dolphin.ExamPictureCut.Domains.Basic; + +[Table(nameof(Tenant)), Tenant(DbConsts.marking_basic)] +public class Tenant : ISoftDelete +{ + [SugarColumn(IsIdentity = true, IsPrimaryKey = true)] + public long Id { get; set; } + public string IpAddr { get; set; } + public string Database { get; set; } + public string Dbuser { get; set; } + public string Password { get; set; } + public string Port { get; set; } + public long TenantCode { get; set; } + public string TenantName { get; set; } + + [NotMapped] + public string ConnectionString => $"Server={IpAddr};Port={Port};Database={Database};Uid={Dbuser};Pwd={Password};"; + + public bool IsEnable { get; set; } + public bool IsDeleted { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingObjective.cs b/Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingObjective.cs new file mode 100644 index 0000000..da577b0 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingObjective.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Dolphin.ExamPictureCut.Domains.Biz; + +[Table(nameof(MarkingSettingObjective))] +public class MarkingSettingObjective +{ + public long Id { get; set; } + public long ExamSubjectId { get; set; } + public string QuestionNum { get; set; } + public float Score { get; set; } + public string ObjectiveAnswer { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingSubjective.cs b/Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingSubjective.cs new file mode 100644 index 0000000..56290bf --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Biz/MarkingSettingSubjective.cs @@ -0,0 +1,14 @@ +namespace Dolphin.ExamPictureCut.Domains.Biz; + +public class MarkingSettingSubjective +{ + public long Id { get; set; } + public long ExamSubjectId { get; set; } + public string QuestionNum { get; set; } + public float Score { get; set; } + public int SubQuestionCount { get; set; } + public string SubQuestionDetail { get; set; } + public string BigQuestionNum { get; set; } + public bool IsExcess { get; set; } + public string DotPenOriginalImg { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Biz/MkExamResult.cs b/Dolphin.ExamPictureCut.Core/Domains/Biz/MkExamResult.cs new file mode 100644 index 0000000..013aea0 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Biz/MkExamResult.cs @@ -0,0 +1,38 @@ +using SqlSugar; + +namespace Dolphin.ExamPictureCut.Domains.Biz; + +[SugarTable("MK_ExamResult")] +public class MkExamResult +{ + [SugarColumn(IsPrimaryKey = true, ColumnName = "ID_bigint")] + public long Id { get; set; } + + [SugarColumn(ColumnName = "StudentNo_nvarchar")] + public string StudentNo { get; set; } + + [SugarColumn(ColumnName = "ExamId_bigint")] + public long ExamId { get; set; } + + public long ExamSubjectId { get; set; } + + [SugarColumn(ColumnName = "QuestionNumber_int")] + public string QuestionNumber { get; set; } + + [SugarColumn(ColumnName = "SmallQuestion_int")] + public int SmallQuestion { get; set; } + + [SugarColumn(ColumnName = "IsObjectiveQuestions_bit")] + public bool IsObjectiveQuestion { get; set; } + + [SugarColumn(ColumnName = "QuestionValue_nvarchar")] + public string QuestionValue { get; set; } + + [SugarColumn(ColumnName = "QuestionNumberSlaveIndex_int")] + public int QuestionNumberSlaveIndex { get; set; } + + [SugarColumn(ColumnName = "GroupNo_nvarchar")] + public string GroupNo { get; set; } + + public bool IsSync { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Biz/SubjectiveMarkingResult.cs b/Dolphin.ExamPictureCut.Core/Domains/Biz/SubjectiveMarkingResult.cs new file mode 100644 index 0000000..a5f4b27 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Biz/SubjectiveMarkingResult.cs @@ -0,0 +1,26 @@ +using Volo.Abp; + +namespace Dolphin.ExamPictureCut.Domains.Biz; + +public class SubjectiveMarkingResult : ISoftDelete +{ + public long Id { get; set; } + public long ExamSubjectId { get; set; } + public long ExamSubjectSchoolId { get; set; } + public string StudentExamNum { get; set; } + public string QuestionNum { get; set; } + public float Score { get; set; } + public float TotalScore { get; set; } + public int SubQuestionCount { get; set; } + public string SubQuestionDetail { get; set; } = "[]"; + public string StudentAnswer { get; set; } + public string GroupNo { get; set; } + public bool IsAssign { get; set; } + public bool IsRating { get; set; } + public string CommentImgUrl { get; set; } = "[]"; + public string BigQuestionNum { get; set; } + public bool IsExcess { get; set; } + public bool IsDeleted { get; set; } + public DateTime CreateDate { get; set; } + public DateTime UpdateDate { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Domains/Quest/PenOfflineData.cs b/Dolphin.ExamPictureCut.Core/Domains/Quest/PenOfflineData.cs new file mode 100644 index 0000000..c65396f --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Domains/Quest/PenOfflineData.cs @@ -0,0 +1,61 @@ +using Dolphin.ExamPictureCut.Constants; +using Dolphin.ExamPictureCut.Domains.Basic; +using SqlSugar; + +namespace Dolphin.ExamPictureCut.Domains.Quest; + +/// +/// 点阵笔离线数据 +/// +[Tenant(DbConsts.penoffline)] +public class PenOfflineData +{ + /// + /// 笔id + /// + [SugarColumn(ColumnDataType = "symbol")] + public string PenSerial { get; set; } + /// + /// 纸张id + /// + [SugarColumn(ColumnDataType = "symbol")] + public string PageSerial { get; set; } = "no"; + public int CX { get; set; } + public int CY { get; set; } + /// + /// 时间戳 + /// + public long Time { get; set; } + /// + /// 笔数据类型 + /// + public PenDataType DataType { get; set; } + /// + /// 笔画 + /// + public long strokeIndex { get; set; } + /// + /// 记录类型 + /// + public LogType logType { get; set; } +} + +/// +/// 点阵笔数据类型 +/// +public enum PenDataType +{ + 落笔, + 移动, + 抬笔, + 连接, + 断开连接 +} +/// +/// 记录类型 +/// +public enum LogType +{ + 作业, + 互动课堂 +} diff --git a/Dolphin.ExamPictureCut.Core/Exams/Dto/ExamAnnotateEto.cs b/Dolphin.ExamPictureCut.Core/Exams/Dto/ExamAnnotateEto.cs new file mode 100644 index 0000000..4ede874 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Exams/Dto/ExamAnnotateEto.cs @@ -0,0 +1,9 @@ +using Volo.Abp.EventBus; + +namespace Dolphin.ExamPictureCut.Exams.Dto; + +[EventName("Dolphin.ExamAnnotateEto")] +public class ExamAnnotateEto +{ + public string ExamId { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Exams/Dto/ExamStudentGatherEto.cs b/Dolphin.ExamPictureCut.Core/Exams/Dto/ExamStudentGatherEto.cs new file mode 100644 index 0000000..a9f6e9d --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Exams/Dto/ExamStudentGatherEto.cs @@ -0,0 +1,32 @@ +using Volo.Abp.EventBus; + +namespace Dolphin.ExamPictureCut.Exams.Dto; + +[EventName("Dolphin.ExamStudentGatherEto")] +public class ExamStudentGatherEto +{ + /// + /// 考试Id + /// + public long ExamId { get; set; } + /// + /// 考试科目Id + /// + public long ExamSubjectId { get; set; } + /// + /// 所属学校 + /// + public long SchoolId { get; set; } + /// + /// + /// + public long ExamSubjectSchoolId { get; set; } + /// + /// 模板id + /// + public string TemplateId { get; set; } + /// + /// 所属学生 + /// + public string StudentExamNum { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Exams/Dto/TemplateJsonModelDto.cs b/Dolphin.ExamPictureCut.Core/Exams/Dto/TemplateJsonModelDto.cs new file mode 100644 index 0000000..035f103 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Exams/Dto/TemplateJsonModelDto.cs @@ -0,0 +1,159 @@ +namespace Dolphin.ExamPictureCut.Exams.Dto; + +public class SubjectiveLatt +{ + public long Stroke { get; set; } + public float X { get; set; } + public float Y { get; set; } + public long Time { get; set; } +} +public class TemplateJsonModel_DataArr +{ + public string id { get; set; } + public string jobName { get; set; } + public string imgUrl { get; set; } + public string paperId { get; set; } + public long bookId { get; set; } + public long chapterId { get; set; } + public long partId { get; set; } + public List queData { get; set; } +} +public class PaperQueData +{ + public string TemplateId { get; set; } + public string PaperId { get; set; } + public long PartId { get; set; } + public int PageIndex { get; set; } + public List QueData { get; set; } +} +public class TemplateJsonModel_QueData +{ + /// + /// 题号 + /// + public string no { get; set; } + /// + /// 题型 + /// + public string type { get; set; } + /// + /// 选项 + /// + public List options { get; set; } + /// + /// 答案 + /// + public List answer { get; set; } + /// + /// 关联学科网知识点 + /// + public List xkKnows { get; set; } = new(); + /// + /// 重置按钮 + /// + public List resetPoint { get; set; } +} + +/// +/// 选项 +/// +public class TemplateJsonModel_Option +{ + /// + /// 选项代号 + /// + public string option { get; set; } + /// + /// ID + /// + public long index { get; set; } + /// + /// + /// + public bool active { get; set; } + /// + /// + /// + public List point { get; set; } + /// + /// 第一个答案区域 + /// + public TemplateJsonModel_Rect AnswerArea { get { return point.FirstOrDefault() ?? new(); } } +} +/// +/// 选项-坐标 +/// +public class TemplateJsonModel_Rect +{ + public float pxWidth { get; set; } + public float pxHeight { get; set; } + public float pxTop { get; set; } + public float pxLeft { get; set; } + public int angle { get; set; } + public string type { get; set; } + public long bindId { get; set; } +} +/// +/// 答案 +/// +public class TemplateJsonModel_Answer +{ + /// + /// 答案 + /// + public string name { get; set; } + /// + /// + /// + public bool active { get; set; } +} +/// +/// 知识点 +/// +public class TemplateJsonModel_Know +{ + /// + /// + /// + public long id { get; set; } + /// + /// 知识点名称 + /// + public string knowName { get; set; } + /// + /// 知识点描述 + /// + public string knowDescription { get; set; } + /// + /// 上级ID + /// + public long parentId { get; set; } + /// + /// 上级知识点名称 + /// + public string parentKnowName { get; set; } + /// + /// 科目 + /// + public int subjectId { get; set; } + /// + /// 科目名称 + /// + public string subjectName { get; set; } + /// + /// + /// + public int categoryId { get; set; } + /// + /// + /// + public string categoryName { get; set; } + /// + /// 难度 + /// + public int difficulty { get; set; } + /// + /// 是否选中 + /// + public bool Checked { get; set; } +} diff --git a/Dolphin.ExamPictureCut.Core/Exams/IExamManager.cs b/Dolphin.ExamPictureCut.Core/Exams/IExamManager.cs new file mode 100644 index 0000000..6897ba3 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Exams/IExamManager.cs @@ -0,0 +1,10 @@ +using Dolphin.ExamPictureCut.Exams.Dto; +using Volo.Abp.Domain.Services; + +namespace Dolphin.ExamPictureCut.Exams; + +public interface IExamManager : IDomainService +{ + Task ExamStudentGather(ExamStudentGatherEto eto); + Task ExamAnnotate(ExamAnnotateEto eto); +} diff --git a/Dolphin.ExamPictureCut.Core/Extensions/IdExt.cs b/Dolphin.ExamPictureCut.Core/Extensions/IdExt.cs new file mode 100644 index 0000000..05fa9fe --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Extensions/IdExt.cs @@ -0,0 +1,64 @@ +using Dolphin.ExamPictureCut.Constants; +using System.Timers; +using Yitter.IdGenerator; +using Timer = System.Timers.Timer; + +namespace Dolphin.ExamPictureCut.Extensions; + +public class IdExt +{ + public static IdGeneratorOptions GetIdGeneratorOptions(string uniqueValue) + { + byte workerIdBitLength = 8; + var maxWorkId = Math.Pow(2, workerIdBitLength) - 1; //63 + var workIdKey = $"{uniqueValue}idgen:workid"; + + var workId = GetNextWorkId(); + + while (!RedisHelper.SetNx($"{workIdKey}:{workId}", SysConsts.AppName)) + { + // workId 已被占用,获取下一个workId + workId = GetNextWorkId(); + }; + + // 设置5分钟过期 + RedisHelper.Expire($"{workIdKey}:{workId}", 60 * 5); + + // 设置定时器,每4分钟更新一次过期时间 + SetTimer(4, (s, e) => + { + RedisHelper.Expire($"{workIdKey}:{workId}", 60 * 5); + }); + + // WorkerIdBitLength + SeqBitLength 不超过 22 + return new IdGeneratorOptions + { + WorkerIdBitLength = workerIdBitLength, + //SeqBitLength = 6, // 数值越高,性能越好,但是Id也越长 + WorkerId = (ushort)workId + }; + + long GetNextWorkId() + { + var workId = RedisHelper.IncrBy(workIdKey); + if (workId > maxWorkId) + { + // 大于了最大可用WorkId,重置workId,并获取 + RedisHelper.Set(workIdKey, -1); + workId = RedisHelper.IncrBy(workIdKey); + } + + return workId; + } + } + + private static Timer _timer; + private static void SetTimer(int mins, ElapsedEventHandler eh) + { + // 创建一个 Timer 实例,并设置其相关属性 + _timer = new Timer(TimeSpan.FromMinutes(mins).TotalMilliseconds); // 4 分钟 + _timer.Elapsed += eh; + _timer.AutoReset = true; // 设置 Timer 实例能否多次触发 + _timer.Enabled = true; // 启动 Timer 实例 + } +} diff --git a/Dolphin.ExamPictureCut.Core/Extensions/RectExt.cs b/Dolphin.ExamPictureCut.Core/Extensions/RectExt.cs new file mode 100644 index 0000000..90482f3 --- /dev/null +++ b/Dolphin.ExamPictureCut.Core/Extensions/RectExt.cs @@ -0,0 +1,31 @@ +using Dolphin.ExamPictureCut.Domains.Quest; +using Dolphin.ExamPictureCut.Exams.Dto; + +namespace Dolphin.ExamPictureCut.Extensions; + +public static class RectExt +{ + public static float MMToPX(this float MM) + { + return MM * 96 / 25.4F; + } + + /// + /// AU转像素 + /// + /// + /// + public static float AUToPX(this int AU) + { + + return (AU * 0.3F / 8).MMToPX(); + } + + public static bool IsRectContainsLattice(TemplateJsonModel_Rect rect, PenOfflineData latt) + { + var x = latt.CX.AUToPX(); + var y = latt.CY.AUToPX(); + return rect.pxLeft <= x && x <= rect.pxLeft + rect.pxWidth + && rect.pxTop <= y && y <= rect.pxTop + rect.pxHeight; + } +} diff --git a/Dolphin.ExamPictureCut.HttpApi.Host/Dolphin.ExamPictureCut.HttpApi.Host.csproj b/Dolphin.ExamPictureCut.HttpApi.Host/Dolphin.ExamPictureCut.HttpApi.Host.csproj index d03b5bd..6189630 100644 --- a/Dolphin.ExamPictureCut.HttpApi.Host/Dolphin.ExamPictureCut.HttpApi.Host.csproj +++ b/Dolphin.ExamPictureCut.HttpApi.Host/Dolphin.ExamPictureCut.HttpApi.Host.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -10,13 +10,11 @@ - - - - - + + + diff --git a/Dolphin.ExamPictureCut.HttpApi.Host/DolphinExamPictureCutHttpApiHostModule.cs b/Dolphin.ExamPictureCut.HttpApi.Host/DolphinExamPictureCutHttpApiHostModule.cs index 50f5f0b..d4a7b55 100644 --- a/Dolphin.ExamPictureCut.HttpApi.Host/DolphinExamPictureCutHttpApiHostModule.cs +++ b/Dolphin.ExamPictureCut.HttpApi.Host/DolphinExamPictureCutHttpApiHostModule.cs @@ -1,19 +1,20 @@ +using Dolphin.ExamPictureCut.Constants; +using Dolphin.ExamPictureCut.Extensions; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; -using Microsoft.AspNetCore.DataProtection; using Microsoft.OpenApi.Models; using NoFurion.SqlSugar; using SqlSugar; -using StackExchange.Redis; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Reflection; using Volo.Abp; using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; -using Volo.Abp.Caching; -using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Modularity; using Volo.Abp.Swashbuckle; -using Volo.Abp.VirtualFileSystem; +using Yitter.IdGenerator; namespace Dolphin.ExamPictureCut; @@ -22,7 +23,6 @@ namespace Dolphin.ExamPictureCut; typeof(AbpAutofacModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), - typeof(AbpCachingStackExchangeRedisModule), typeof(AbpSwashbuckleModule) )] public class DolphinExamPictureCutHttpApiHostModule : AbpModule @@ -42,17 +42,63 @@ public class DolphinExamPictureCutHttpApiHostModule : AbpModule private void ConfigureSqlSugar(ServiceConfigurationContext context, IConfiguration configuration) { var config = new SqlSugarConfig(); + var ExtService = new ConfigureExternalServices + { + EntityService = delegate (PropertyInfo prop, EntityColumnInfo col) + { + if (prop.GetCustomAttribute() != null) + { + col.IsIgnore = true; + } + + if (prop.PropertyType == typeof(string)) + { + col.DataType = "text"; + } + + if (!col.IsPrimarykey) + { + if (prop.GetCustomAttribute() != null) + { + return; + } + + if (new NullabilityInfoContext().Create(prop).WriteState == NullabilityState.Nullable || prop.PropertyType == typeof(string)) + { + col.IsNullable = true; + } + } + + col.DbColumnName = UtilMethods.ToUnderLine(col.DbColumnName); + }, + EntityNameService = delegate (Type t, EntityInfo entity) + { + TableAttribute customAttribute = t.GetCustomAttribute(); + if (customAttribute != null) + { + entity.DbTableName = UtilMethods.ToUnderLine(customAttribute.Name); + } + } + }; context.Services.AddSingleton(s => { var scope = new SqlSugarScope( new List() { new ConnectionConfig() { - ConfigId = DbConsts.basic, - DbType = DbType.PostgreSQL, - ConnectionString = configuration.GetConnectionString(DbConsts.basic), + ConfigId = DbConsts.marking_basic, + DbType = DbType.MySql, + ConnectionString = configuration.GetConnectionString(DbConsts.marking_basic), IsAutoCloseConnection = true, - ConfigureExternalServices = config.ExtService, + ConfigureExternalServices = ExtService, + }, + new ConnectionConfig() + { + ConfigId = DbConsts.penoffline, + DbType = DbType.QuestDB, + ConnectionString = configuration.GetConnectionString(DbConsts.penoffline), + IsAutoCloseConnection = true, + ConfigureExternalServices = ExtService, }, }, db => @@ -74,7 +120,9 @@ public class DolphinExamPictureCutHttpApiHostModule : AbpModule private void ConfigureCache(IConfiguration configuration) { - //Configure(options => { options.KeyPrefix = "Dolphin:"; }); + RedisHelper.Initialization(new CSRedis.CSRedisClient(configuration.GetValue("Redis:Configuration"))); + + YitIdHelper.SetIdGenerator(IdExt.GetIdGeneratorOptions("mk")); } private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration) @@ -90,12 +138,7 @@ public class DolphinExamPictureCutHttpApiHostModule : AbpModule private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration) { - context.Services.AddAbpSwaggerGenWithOAuth( - configuration["AuthServer:Authority"], - new Dictionary - { - {"Dolphin", "Dolphin API"} - }, + context.Services.AddAbpSwaggerGen( options => { options.HideAbpEndpoints(); // 隐藏 Abp 相关的 endpoints diff --git a/Dolphin.ExamPictureCut.HttpApi.Host/Properties/launchSettings.json b/Dolphin.ExamPictureCut.HttpApi.Host/Properties/launchSettings.json index b9c1c2a..87931b5 100644 --- a/Dolphin.ExamPictureCut.HttpApi.Host/Properties/launchSettings.json +++ b/Dolphin.ExamPictureCut.HttpApi.Host/Properties/launchSettings.json @@ -1,12 +1,12 @@ -{ +{ "profiles": { "Dolphin.ExamPictureCut.HttpApi.Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:53350;http://localhost:53351" + "commandName": "Project", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://192.168.2.138:53350" } } } diff --git a/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.Development.json b/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.Development.json new file mode 100644 index 0000000..e85d9b0 --- /dev/null +++ b/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.Development.json @@ -0,0 +1,37 @@ +{ + "App": { + "CorsOrigins": "https://*.23544.com" + }, + "ConnectionStrings": { + "marking_basic": "Server=192.168.2.9;Port=3306;Database=marking_basic;Uid=root;Pwd=qwe123!@#;AllowLoadLocalInfile=true;", + "penoffline": "host=192.168.2.7;port=8812;username=zhjs;password=zhjsniubi;database=qdb;ServerCompatibilityMode=NoTypeLoading;" + }, + "Redis": { + "Configuration": "192.168.2.7:6379,password=qwe123!@#,defaultDatabase=14,idleTimeout=3000,poolsize=5,prefix=marking" + }, + "StringEncryption": { + "DefaultPassPhrase": "LB6Ts3T0sdE5VSNq" + }, + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "192.168.2.7", + "Port": "5672", + "UserName": "rabbit", + "Password": "qwe123!@#" + } + }, + "EventBus": { + "ClientName": "collect_queue", + "ExchangeName": "tenant_ex" + } + }, + "Aliyun": { + "AccessKeyId": "LTAI5tJ6stiMWGhVU3TtRyAf", + "AccessKeySecret": "A3pwnGx2SW1orvraCkXta6Lx4sV06e", + "Endpoint": "https://oss-cn-chengdu.aliyuncs.com", + "RegionId": "oss-cn-chengdu", + "ContainerName": "mk-xk-test", + "CustomHostUrl": "//mk-xk-test.23544.com" + } +} diff --git a/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.json b/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.json index cc5f773..c4f5077 100644 --- a/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.json +++ b/Dolphin.ExamPictureCut.HttpApi.Host/appsettings.json @@ -1,21 +1,37 @@ -{ - "App": { - "CorsOrigins": "https://*.nofurion.com" - }, - "ConnectionStrings": { - "Default": "Host=localhost;Port=5432;Database=nofurion;User ID=root;Password=myPassword;" - }, - "Redis": { - "Configuration": "127.0.0.1" - }, - "AuthServer": { - "Authority": "https://localhost:44377", - "RequireHttpsMetadata": "true", - "SwaggerClientId": "Dolphin_Swagger" - }, - "StringEncryption": { - "DefaultPassPhrase": "LB6Ts3T0sdE5VSNq" - } +{ + "App": { + "CorsOrigins": "https://*.23544.com" + }, + "ConnectionStrings": { + "marking_basic": "Server=192.168.2.9;Port=3306;Database=marking_basic;Uid=root;Pwd=qwe123!@#;AllowLoadLocalInfile=true;", + "penoffline": "host=192.168.2.7;port=8812;username=zhjs;password=zhjsniubi;database=qdb;ServerCompatibilityMode=NoTypeLoading;" + }, + "Redis": { + "Configuration": "192.168.2.7:6379,password=qwe123!@#,defaultDatabase=14,idleTimeout=3000,poolsize=5,prefix=marking" + }, + "StringEncryption": { + "DefaultPassPhrase": "LB6Ts3T0sdE5VSNq" + }, + "RabbitMQ": { + "Connections": { + "Default": { + "HostName": "192.168.2.7", + "Port": "5672", + "UserName": "rabbit", + "Password": "qwe123!@#" + } + }, + "EventBus": { + "ClientName": "collect_queue", + "ExchangeName": "tenant_ex" + } + }, + "Aliyun": { + "AccessKeyId": "LTAI5tJ6stiMWGhVU3TtRyAf", + "AccessKeySecret": "A3pwnGx2SW1orvraCkXta6Lx4sV06e", + "Endpoint": "https://oss-cn-chengdu.aliyuncs.com", + "RegionId": "oss-cn-chengdu", + "ContainerName": "mk-xk", + "CustomHostUrl": "//mk-xk.23544.com" + } } - -