using Learn.Archives.API.Controllers.Dto; using Learn.Archives.API.Expand; using Learn.Archives.Core.Common; using Learn.Archives.Core.Model; using Learn.Archives.Core.Model.Dto; using Learn.Archives.Core.Model.Enum; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MiniExcelLibs; using SqlSugar; using Swashbuckle.AspNetCore.SwaggerGen; using System.Diagnostics; using System.Security.Claims; using System.Text.RegularExpressions; using UserCenter.Model; using UserCenter.Model.Common; using UserCenter.Model.Enum; namespace Learn.Archives.API.Controllers { public class SchoolBusinessController : BackController { readonly Repository baseService; readonly Repository schoolService; readonly Repository adminService; readonly IHttpContextAccessor accessor; readonly LiveUserInfo userInfo; public SchoolBusinessController(Repository baseService, Repository schoolService, IHttpContextAccessor accessor, Repository adminService, LiveUserInfo userInfo) : base(baseService) { this.baseService = baseService; this.schoolService = schoolService; this.accessor = accessor; this.adminService = adminService; this.userInfo = userInfo; } public class QueryPageDto { /// /// 学校id /// public long SchoolId { get; set; } /// /// 年级 /// public string? Grade { get; set; } /// /// 赴校人员ID /// public string? UserName{ get; set; } /// /// 是否查询完结 /// public bool? SolutionEnd { get; set; } public DateTime? StartTime { get; set; } public DateTime? EndTime { get; set; } /// /// 页面索引 /// public int PageIndex { get; set; } = 0; /// /// 页面数量 /// public int PageSize { get; set; } = 20; } public override Task Edit([FromBody] SchoolBusiness model) { if (model.SolutionRecord != null && model.SolutionRecord.SolutionEnd == true) model.SolutionEnd = true; if (!string.IsNullOrEmpty(model._grade)) { var g = GradeHelper.GetStudentGradeBaseByGrade(model._grade); model.GradeLevel = g.GradeLevel; model.GradeYear = g.GradeYear; } return base.Edit(model); } public override async Task Info(long id) { return (await base.Info(id) as object).Adapt(); } /// /// 查询 赴校列表 /// /// [HttpPost] public async Task> QueryPageList(QueryPageDto dto) { var gInfo = GradeHelper.GetStudentGradeBaseByGrade(dto.Grade); RefAsync total = 0; var resData = await baseService.AsQueryable() .WhereIF(dto.SchoolId != 0, s => s.SchoolId == dto.SchoolId) .WhereIF(gInfo != null, s => s.GradeLevel == gInfo.GradeLevel && s.GradeYear == gInfo.GradeYear) .WhereIF(dto.SolutionEnd != null, s => s.SolutionEnd == dto.SolutionEnd) .WhereIF(dto.StartTime != null, s => s.StartTime >= dto.StartTime) .WhereIF(dto.EndTime != null, s => s.StartTime <= dto.EndTime) .WhereIF(!string.IsNullOrEmpty(dto.UserName), s => s.SchoolBusinessUser != null && SqlFunc.JsonLike(s.SchoolBusinessUser, dto.UserName)) .OrderByDescending(s => s.Id) .Select() .ToPageListAsync(dto.PageIndex, dto.PageSize, total); foreach (var item in resData) item.CanOperate =userInfo.IsSa || (item.SchoolBusinessUser?.Contains(userInfo.Name) ?? false); return new PageResult() { Data = resData, Total = total }; } /// /// 导入考试信息 /// /// [HttpPost, ResultIgnore] [HttpLogEnable] public async Task Import(IFormFile? file) { var fl = file != null ? file : accessor.HttpContext?.Request.Form.Files[0]; if (fl == null) Oh.ModelError("传入无效的数据"); if (!Path.GetExtension(fl.FileName).Equals(".xlsx", StringComparison.OrdinalIgnoreCase)) Oh.ModelError("请选择导入文件为.xlsx的后缀名!"); //分析excel IEnumerable dataList; using var stream = new MemoryStream(); { await fl.CopyToAsync(stream); dataList = stream.Query() .Where(s => !string.IsNullOrEmpty(s.School)); } if (dataList == null || dataList.Count() == 0) Oh.ModelError("导入失败:无有效数据"); //处理数据 var errorExcelInfo = new List(); var insertInfo = new List(); var db = schoolService.Context; foreach (var imp in dataList) { var school = await schoolService.GetFirstAsync(s => s.Name == imp.School); if (school == null) { imp.Error = $"导入失败:学校 [{imp.School}] 未找到!"; errorExcelInfo.Add(imp); continue; } var gradeInfo = GradeHelper.GetStudentGradeBaseByGrade(imp.Grade); if (gradeInfo == null) { imp.Error = $"导入失败:学校 [{imp.School}] 年级[{imp.Grade}]不符合规范!"; errorExcelInfo.Add(imp); continue; } var adminNameArr = imp.Users.Split(","); if (adminNameArr == null) { imp.Error = $"赴校人员未能识别"; errorExcelInfo.Add(imp); continue; } var adminArr = await adminService.AsQueryable() .Where(s => adminNameArr.Contains(s.Name)) .Select(s => s.Name).ToArrayAsync(); if (adminArr == null || adminArr.Length!= adminNameArr.Length) { imp.Error = $"赴校人员未能完全识别成功"; errorExcelInfo.Add(imp); continue; } var qStr = new Dictionary() { {FeedbackQuestionTypeEnum.学校领导班子,(imp.Q学校领导班子,imp.P学校领导班子) }, {FeedbackQuestionTypeEnum.双师课堂,(imp.Q双师课堂,imp.P双师课堂) }, {FeedbackQuestionTypeEnum.设备,(imp.Q设备,imp.P设备) }, {FeedbackQuestionTypeEnum.学生,(imp.Q学生,imp.P学生) }, {FeedbackQuestionTypeEnum.其他,(imp.Q其他,imp.P其他) } }; var resultQuestion = new List(); var regex = new Regex(@"(问题\d+):(.*?)(?=;|$)", RegexOptions.Singleline); foreach (var kvp in qStr) { var questionType = kvp.Key; var questions = kvp.Value.Questions; var solutions = kvp.Value.Solutions; if (string.IsNullOrEmpty(questions) || string.IsNullOrEmpty(solutions)) continue; // 解析问题 var questionMatches = regex.Matches(questions); var solutionMatches = regex.Matches(solutions); // 创建字典以便快速查找解决方案 var solutionDict = new Dictionary(); foreach (Match match in solutionMatches) if (match.Groups.Count == 3) solutionDict[match.Groups[1].Value] = match.Groups[2].Value; // 创建DTO对象 foreach (Match match in questionMatches) { if (match.Groups.Count == 3) { var sort = match.Groups[1].Value; var question = match.Groups[2].Value; solutionDict.TryGetValue(sort, out var solution); resultQuestion.Add(new FeedbackQuestionsDto { QuestionType = questionType, Sort = sort, Question = question, Solution = solution, EndTime = null // 根据需求设置解决时间 }); } } } var feedbackQuestions = resultQuestion.ToArray(); if(feedbackQuestions.Length==0) { imp.Error = $"未能识别到有效的赴校问题信息"; errorExcelInfo.Add(imp); continue; } //沟通时间/执行记录 var regex1 = new Regex(@"(.*?):(.*?)(?=;|$)", RegexOptions.Singleline); var record = new List(); if (!string.IsNullOrEmpty(imp.Record)) foreach (Match match in regex1.Matches(imp.Record)) { record.Add(new RecordDto() { ExecutionTime = match.Groups[1].Value.ExtractDateTime(), ExecutionRecords = match.Groups[2].Value, }); } var business = new SchoolBusiness() { SchoolId = school.Id, SchoolName = school.Name, GradeLevel = gradeInfo.GradeLevel, GradeYear = gradeInfo.GradeYear, ClassMeeting = imp.ClassMeeting, Discussion = imp.Discussion, SchoolBusinessUser = adminArr, Remark = imp.Remark, StartTime = imp.StartTime, FeedbackQuestions = feedbackQuestions, SolutionRecord = new SolutionRecordDto() { EndRecord = imp.EndRecord, EndRecordTime = imp.EndRecord.ExtractDateTime(), Solution = imp.Solution, Record = record, } }; business.SolutionEnd = business.SolutionRecord.EndRecordTime != null; insertInfo.Add(business); }; if (errorExcelInfo.Count != 0) return File(errorExcelInfo.ExportExcel(), "application/ms-excel" , $"错误赴校信息{DateTime.Now.ToString("MMddHHmm")}.xlsx"); //写入数据库 await baseService.InsertRangeAsync(insertInfo); return Ok(); } /// /// 下载导入模板 /// /// [HttpGet, ResultIgnore, AllowAnonymous] public IActionResult DwImportTemplate() { var resultList = new List() { new SchoolBusinessImport() { School="必填 与系统对应", Grade="必填 : 初一/高一/初2025", IsDiscussion="是/否", IsClassMeeting="是/否", Remark="选填 备注", ClassMeeting ="选填 开展班会情况", Discussion ="选填 开展会谈情况", Solution="选填 需求/方案的描述", Users="必填: 例 用户1,用户2 与系统中用户名称对应", Record="选填 格式[时间:记录内容;] \r\n 例 2025年9月11日:执行了第一次沟通;\r\n2025年9月12日:执行了第二次沟通,沟通非常顺畅;", EndRecord="选填 格式 [时间:记录内容]\r\n 例 2025年9月13日:已经顺利落地了解决方案", Q学校领导班子="例子: 问题1:问题内容;问题2:问题内容2;", P学校领导班子="例子: 问题1:问题解决方法;问题2:问题解决方法2;", } }; return File(resultList.ExportExcel(), "application/ms-excel", "导入赴校信息模板.xlsx"); } /// /// 下载导出模板 /// /// [HttpGet, ResultIgnore, AllowAnonymous] public async Task ExportTemplate() { var qData = await baseService.AsQueryable() .Where(s => true) .ToArrayAsync(); //todo完善数据转换 var resultList = new List() { new SchoolBusinessImport() { School="必填 与系统对应", Grade="必填 : 初一/高一/初2025", IsDiscussion="是/否", IsClassMeeting="是/否", Remark="选填 备注", ClassMeeting ="选填 开展班会情况", Discussion ="选填 开展会谈情况", Solution="选填 需求/方案的描述", Users="必填: 例 用户1,用户2 与系统中用户名称对应", Record="选填 格式[时间:记录内容;] \r\n 例 2025年9月11日:执行了第一次沟通;\r\n2025年9月12日:执行了第二次沟通,沟通非常顺畅;", EndRecord="选填 格式 [时间:记录内容]\r\n 例 2025年9月13日:已经顺利落地了解决方案", Q学校领导班子="例子: 问题1:问题内容;问题2:问题内容2;", P学校领导班子="例子: 问题1:问题解决方法;问题2:问题解决方法2;", } }; return File(resultList.ExportExcel(), "application/ms-excel", "导入赴校信息模板.xlsx"); } } }