using MongoDB.Driver.Linq;

namespace Tiobon.Core.Services;

/// <summary>
/// 开班管理 (服务)
/// </summary>
public class Ghre_OpenClassServices : BaseServices<Ghre_OpenClass, Ghre_OpenClassDto, InsertGhre_OpenClassInput, EditGhre_OpenClassInput>, IGhre_OpenClassServices
{
    private readonly IGhre_OpenClassStaffServices _ghre_OpenClassStaffServices;
    private readonly IGhre_OpenClassFeeServices _ghre_OpenClassFeeServices;
    private readonly IGhre_StaffGroupServices _ghre_StaffGroupServices;
    private readonly IGhre_OpenClassScheduleServices _ghre_OpenClassScheduleServices;
    private readonly IGhre_OpenClassFeedbackServices _ghre_OpenClassFeedbackServices;
    private readonly IGhre_SurveyServices _ghre_SurveyServices;
    private readonly IBaseRepository<Ghre_OpenClass> _dal;
    public Ghre_OpenClassServices(ICaching caching,
        IBaseRepository<Ghre_OpenClass> dal,
        IGhre_OpenClassStaffServices ghre_OpenClassStaffServices,
        IGhre_OpenClassFeeServices ghre_OpenClassFeeServices,
        IGhre_StaffGroupServices ghre_StaffGroupServices,
        IGhre_OpenClassFeedbackServices ghre_OpenClassFeedbackServices,
        IGhre_SurveyServices ghre_SurveyServices,
        IGhre_OpenClassScheduleServices ghre_OpenClassScheduleServices)
    {
        this._dal = dal;
        base.BaseDal = dal;
        base._caching = caching;
        _ghre_OpenClassStaffServices = ghre_OpenClassStaffServices;
        _ghre_OpenClassFeeServices = ghre_OpenClassFeeServices;
        _ghre_OpenClassScheduleServices = ghre_OpenClassScheduleServices;
        _ghre_StaffGroupServices = ghre_StaffGroupServices;
        _ghre_OpenClassFeedbackServices = ghre_OpenClassFeedbackServices;
        _ghre_SurveyServices = ghre_SurveyServices;
    }

    public override async Task<ServicePageResult<Ghre_OpenClassDto>> QueryFilterPage(QueryBody filter, string condition, bool? IsEnable = true)
    {

        if (filter.jsonParam != null)
            foreach (JProperty jProperty in filter.jsonParam.Properties())
            {
                var name = jProperty.Name;
                var value = jProperty.Value.ToString();
                if (name == "StartEndTime")
                {
                    var jsonParam = JsonHelper.JsonToObj<JsonParam>(value);

                    if (jsonParam.columnValue != null)
                    {
                        var ids1 = JsonHelper.JsonToObj<List<string>>(jsonParam.columnValue.ToString());

                        condition += $" AND ((StartTime>='{ids1[0]} 00:00:00' AND StartTime<='{ids1[1]} 23:59:59')";
                        condition += $" OR (EndTime>='{ids1[0]} 00:00:00' AND EndTime<='{ids1[1]} 23:59:59'))";
                    }
                }

            }

        var result = await base.QueryFilterPage(filter, condition, IsEnable);

        for (int i = 0; i < result.result.DT_TableDataT1.Count; i++)
        {
            var DT_TableDataT1 = result.result.DT_TableDataT1[i];

            DT_TableDataT1.OpenClassType = await GetParaLabel("TrainingOpenClassType", result.result.DT_TableDataT1[i].OpenClassType);
            DT_TableDataT1.OpenClassWay = await GetParaLabel("TrainingOpenClassWay", result.result.DT_TableDataT1[i].OpenClassWay);
            DT_TableDataT1.ScoringMethod = await GetParaLabel("ScoreMethod", result.result.DT_TableDataT1[i].ScoringMethod);

            if (DT_TableDataT1.LinkType == "Course")
                DT_TableDataT1.CourseOrSceneName = (await Db.Queryable<Ghre_Course>().FirstAsync(x => x.Id == DT_TableDataT1.LinkId))?.CourseName;
            else
                DT_TableDataT1.CourseOrSceneName = (await Db.Queryable<Ghre_CourseScene>().FirstAsync(x => x.Id == DT_TableDataT1.LinkId))?.SceneName;

            if (DT_TableDataT1.StartTime != null && DT_TableDataT1.EndTime != null)
                DT_TableDataT1.StartEndTime1 = $"{DateTimeHelper.ConvertToMiniuteString(DT_TableDataT1.StartTime)}~{DateTimeHelper.ConvertToMiniuteString(DT_TableDataT1.EndTime)}";

            if (DT_TableDataT1.RegisterStartTime != null && DT_TableDataT1.RegisterEndTime != null)
                DT_TableDataT1.RegisterStartEndTime1 = $"{DateTimeHelper.ConvertToMiniuteString(DT_TableDataT1.RegisterStartTime)}~{DateTimeHelper.ConvertToMiniuteString(DT_TableDataT1.RegisterEndTime)}";

            if (DT_TableDataT1.ExamStartTime != null && DT_TableDataT1.ExamEndTime != null)
                DT_TableDataT1.ExamStartEndTime1 = $"{DateTimeHelper.ConvertToMiniuteString(DT_TableDataT1.ExamStartTime)}~{DateTimeHelper.ConvertToMiniuteString(DT_TableDataT1.ExamEndTime)}";

            if (DT_TableDataT1.ExamPaperId != null)
                DT_TableDataT1.ExamPaperName = (await Db.Queryable<Ghre_ExamPaper>().FirstAsync(x => x.Id == DT_TableDataT1.ExamPaperId))?.PaperName;


            if (DT_TableDataT1.ManagerId != null)
                DT_TableDataT1.ManagerName = (await Db.Queryable<Ghra_Staff>().FirstAsync(x => x.StaffID == DT_TableDataT1.ManagerId))?.StaffName;

            if (DT_TableDataT1.TeacherId != null)
                DT_TableDataT1.TeacherName = (await Db.Queryable<Ghre_Teacher>().FirstAsync(x => x.Id == DT_TableDataT1.TeacherId))?.TeacherName;
            if (DT_TableDataT1.PlanId != null)
                DT_TableDataT1.PlanName = await Db.Ado.GetStringAsync(@$"SELECT 
               CAST (A.Year AS VARCHAR)
             + '-'
             + B.ParaDetailName
             + isnull ('-' + C.DeptName, '')
             + isnull ('-' + D.ParaDetailName, '')
             + isnull ('-' + E.CourseName, '') label
      FROM Ghre_Plan A
           LEFT JOIN Ghrs_ParaDetail B
              ON     A.TrainCategory = B.ParaDetailNo
                 AND B.ParaMasterNo = 'TrainingCategory'
           LEFT JOIN Ghro_Dept C ON A.DeptId = C.DeptID
           LEFT JOIN Ghrs_ParaDetail D
              ON     A.InOrOut = D.ParaDetailNo
                 AND D.ParaMasterNo = 'CourseInOrOut'
           LEFT JOIN Ghre_Course E ON A.CourseId = E.ID
      WHERE A.IsEnable = 1 and A.ID={DT_TableDataT1.PlanId}");
            result.result.DT_TableDataT1[i] = DT_TableDataT1;
        }
        return result;
    }

    public override async Task<long> Add(InsertGhre_OpenClassInput entity)
    {
        entity.LinkId = entity.LinkType == "Course" ? entity.CourseId : entity.CourseSceneId;
        entity.Status = "Temporary";

        var prefixTemp = string.Empty;
        if (entity.LinkType == "Course")
            prefixTemp = (await Db.Queryable<Ghre_Course>().FirstAsync(x => x.Id == entity.CourseId))?.CourseNo;
        else
            prefixTemp = (await Db.Queryable<Ghre_CourseScene>().FirstAsync(x => x.Id == entity.CourseSceneId))?.SceneNo;

        if (entity.StartEndTime != null && entity.StartEndTime.Count == 2)
        {
            entity.StartTime = entity.StartEndTime[0];
            entity.EndTime = entity.StartEndTime[1];
        }
        if (entity.RegisterStartEndTime != null && entity.RegisterStartEndTime.Count == 2)
        {
            entity.RegisterStartTime = entity.RegisterStartEndTime[0];
            entity.RegisterEndTime = entity.RegisterStartEndTime[1];
        }
        if (entity.ExamStartEndTime != null && entity.ExamStartEndTime.Count == 2)
        {
            entity.ExamStartTime = entity.ExamStartEndTime[0];
            entity.ExamEndTime = entity.ExamStartEndTime[1];
        }


        prefixTemp = prefixTemp + "K";
        entity.OpenClassNo = await GenerateContinuousSequence("Ghre_OpenClass", "OpenClassNo", prefixTemp, prefixTemp.Length + 4, 4);

        var result = await base.Add(entity);

        if (entity.Schedules != null && entity.Schedules.Any())
        {
            entity.Schedules.ForEach(x =>
            {
                x.OpenClassId = result;
                if (x.StartEndTime != null && x.StartEndTime.Count == 2)
                {
                    x.StartTime = x.StartEndTime[0];
                    x.EndTime = x.StartEndTime[1];
                }
            });
            await _ghre_OpenClassScheduleServices.Add(entity.Schedules);
        }

        if (entity.Attachments != null && entity.Attachments.Any())
        {
            var paths = entity.Attachments.Select(x => x.RelativePath.Replace("/Advanced", null)).ToList();
            await Db.Updateable<Ghre_Attachment>()
                .SetColumns(it => new Ghre_Attachment() { TableName = result.ObjToString(), AttachmentGroupID = 1 })
                .Where(it => paths.Contains(it.RelativePath))
                .ExecuteCommandAsync();
        }
        return result;
    }

    public override async Task<bool> Update(long Id, EditGhre_OpenClassInput entity)
    {

        entity.LinkId = entity.LinkType == "Course" ? entity.CourseId : entity.CourseSceneId;

        if (entity.StartEndTime != null && entity.StartEndTime.Count == 2)
        {
            entity.StartTime = entity.StartEndTime[0];
            entity.EndTime = entity.StartEndTime[1];
        }
        if (entity.RegisterStartEndTime != null && entity.RegisterStartEndTime.Count == 2)
        {
            entity.RegisterStartTime = entity.RegisterStartEndTime[0];
            entity.RegisterEndTime = entity.RegisterStartEndTime[1];
        }
        if (entity.ExamStartEndTime != null && entity.ExamStartEndTime.Count == 2)
        {
            entity.ExamStartTime = entity.ExamStartEndTime[0];
            entity.ExamEndTime = entity.ExamStartEndTime[1];
        }
        await _ghre_OpenClassScheduleServices.Delete(x => x.OpenClassId == Id);
        if (entity.Schedules != null && entity.Schedules.Any())
        {
            entity.Schedules.ForEach(x =>
            {
                if (x.StartEndTime != null && x.StartEndTime.Count == 2)
                {
                    x.StartTime = x.StartEndTime[0];
                    x.EndTime = x.StartEndTime[1];
                }
                else
                {
                    x.StartTime = null;
                    x.EndTime = null;
                }
                x.OpenClassId = Id;
            });

            await _ghre_OpenClassScheduleServices.Add(entity.Schedules);
        }
        await Db.Updateable<Ghre_Attachment>()
                .SetColumns(it => new Ghre_Attachment() { TableName = null, AttachmentGroupID = null })
                .Where(it => it.TableName == Id.ObjToString() && it.AttachmentGroupID == 1)
                .ExecuteCommandAsync();

        if (entity.Attachments != null && entity.Attachments.Any())
        {
            var paths = entity.Attachments.Select(x => x.RelativePath.Replace("/Advanced", null)).ToList();
            await Db.Updateable<Ghre_Attachment>()
                .SetColumns(it => new Ghre_Attachment() { TableName = Id.ObjToString(), AttachmentGroupID = 1 })
                .Where(it => paths.Contains(it.RelativePath))
                .ExecuteCommandAsync();
        }
        var result = await base.Update(Id, entity, null, ["Status"]);

        return result;
    }


    public override async Task<ServiceFormResult<Ghre_OpenClassDto>> QueryForm(QueryForm body)
    {
        var result = await base.QueryForm(body);
        if (result.result.DT_TableDataT1.Any())
        {
            if (result.result.DT_TableDataT1[0].LinkType == "Course")
                result.result.DT_TableDataT1[0].CourseId = result.result.DT_TableDataT1[0].LinkId;
            else
                result.result.DT_TableDataT1[0].CourseSceneId = result.result.DT_TableDataT1[0].LinkId;

            if (result.result.DT_TableDataT1[0].StartTime != null && result.result.DT_TableDataT1[0].EndTime != null)
            {
                result.result.DT_TableDataT1[0].StartEndTime.Add(result.result.DT_TableDataT1[0].StartTime);
                result.result.DT_TableDataT1[0].StartEndTime.Add(result.result.DT_TableDataT1[0].EndTime);
            }

            if (result.result.DT_TableDataT1[0].RegisterStartTime != null && result.result.DT_TableDataT1[0].RegisterEndTime != null)
            {
                result.result.DT_TableDataT1[0].RegisterStartEndTime.Add(result.result.DT_TableDataT1[0].RegisterStartTime);
                result.result.DT_TableDataT1[0].RegisterStartEndTime.Add(result.result.DT_TableDataT1[0].RegisterEndTime);
            }

            if (result.result.DT_TableDataT1[0].ExamStartTime != null && result.result.DT_TableDataT1[0].ExamEndTime != null)
            {
                result.result.DT_TableDataT1[0].ExamStartEndTime.Add(result.result.DT_TableDataT1[0].ExamStartTime);
                result.result.DT_TableDataT1[0].ExamStartEndTime.Add(result.result.DT_TableDataT1[0].ExamEndTime);
            }
            result.result.DT_TableDataT1[0].Schedules = await _ghre_OpenClassScheduleServices.QueryDto(x => x.OpenClassId == body.id);

            result.result.DT_TableDataT1[0].Attachments = await Db.Queryable<Ghre_Attachment>().Where(x => x.TableName == body.id.ObjToString() && x.AttachmentGroupID == 1).ToListAsync();

            result.result.DT_TableDataT1[0].Attachments?.ForEach(x =>
            {
                x.FileURL = "Advanced/" + x.FileURL;
                x.PhysicsPath = "Advanced/" + x.PhysicsPath;
                x.RelativePath = "Advanced/" + x.RelativePath;
                x.ThumbnailPath = "Advanced/" + x.ThumbnailPath;
            });
        }
        return result;
    }

    #region 学员
    public async Task<ServiceResult<List<Ghre_OpenClassStaffDto>>> QueryStaff(long Id)
    {
        var result = await _ghre_OpenClassStaffServices.QueryFilterPage(new QueryBody(), $"OpenClassId='{Id}'");
        return ServiceResult<List<Ghre_OpenClassStaffDto>>.OprateSuccess("查询成功！", result.result.DT_TableDataT1);
    }

    public async Task<ServiceResult> InsertStaff(long Id, List<int> staffIds)
    {
        var entity = await base.QueryById(Id);

        var stafffIds = new List<int>();
        if (entity.StaffGroupId.IsNotEmptyOrNull())
        {

            var staffGroups = await _ghre_StaffGroupServices.QueryStaff(entity.StaffGroupId.Value, new QueryBody(), "", true);

            stafffIds = staffGroups.result.DT_TableDataT1.Select(x => x.StaffID).ToList();
        }

        var staffIds1 = await Db.Queryable<Ghre_OpenClassStaff>().Where(x => x.OpenClassId == Id && x.StaffId != null).Select(s => s.StaffId.Value).ToListAsync();

        stafffIds.AddRange(staffIds1);
        stafffIds.AddRange(staffIds);
        stafffIds = stafffIds.Distinct().ToList();

        if (stafffIds.Count > entity.StudentCount)
            throw new Exception($"学员人数上限是：{entity.StudentCount}！");

        var inserts = staffIds.Where(x => !staffIds1.Contains(x))
            .Select(x => new InsertGhre_OpenClassStaffInput()
            {
                StaffId = x,
                OpenClassId = Id
            }).Distinct().ToList();
        await _ghre_OpenClassStaffServices.Add(inserts);
        return ServiceResult.OprateSuccess();
    }

    public async Task<ServiceResult> DeleteStaff(long Id, List<int> staffIds)
    {
        await Db.Updateable<Ghre_OpenClassStaff>()
                   .SetColumns(it => new Ghre_OpenClassStaff() { IsEnable = 0 })
                   .Where(it => it.StaffId != null && it.OpenClassId == Id && staffIds.Contains(it.StaffId.Value))
                   .ExecuteCommandAsync();
        return ServiceResult.OprateSuccess();
    }
    public async Task<ServiceResult<ExcelData>> ExportStaff(long Id)
    {
        var result1 = await _ghre_OpenClassStaffServices.QueryFilterPage(new QueryBody(), $"OpenClassId='{Id}'");
        var result = new ExcelData();
        result.fileName = $"开班学员{DateTimeHelper.ConvertToSecondString1(DateTime.Now)}.xlsx";
        var fieldDescs = new Dictionary<string, string>
        {
            { "StaffNo", "工号" },
            { "StaffName", "姓名" },
            { "DeptName", "部门" },
            { "TitleName", "岗位" },
            { "Indate", "入职日期" },
            { "Email", "邮箱" },
            { "Source", "数据来源" }
        };
        var dt = _ghre_OpenClassStaffServices.ToDataTable1(result1.result.DT_TableDataT1, fieldDescs, null);
        // 获取所有列名
        var dtColumns = dt.Columns;

        var id = SnowFlakeSingle.instance.getID();
        var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot";
        var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}export{Path.DirectorySeparatorChar}{id}{Path.DirectorySeparatorChar}"}";
        if (!Directory.Exists(physicsPath + path))
            Directory.CreateDirectory(physicsPath + path);

        path = path + result.fileName;
        NPOIHelper.ExportExcel(dt, "开班学员", "sheet1", physicsPath + path);

        result.filePath = "/Advanced" + path;
        return ServiceResult<ExcelData>.OprateSuccess("导出成功", result);
    }
    #endregion

    #region 费用
    public async Task<ServiceResult<List<Ghre_OpenClassFeeDto>>> QueryGroupFee(long Id)
    {
        var result = await _ghre_OpenClassFeeServices.QueryFilterPage(new QueryBody(), $"OpenClassId='{Id}' AND StaffId IS NULL");
        return ServiceResult<List<Ghre_OpenClassFeeDto>>.OprateSuccess("查询成功！", result.result.DT_TableDataT1);
    }
    public async Task<ServiceResult<List<Ghre_OpenClassFeeDto>>> QueryPersonalFee(long Id)
    {
        var result = await _ghre_OpenClassFeeServices.QueryFilterPage(new QueryBody(), $"OpenClassId='{Id}' AND StaffId IS NOT NULL");
        return ServiceResult<List<Ghre_OpenClassFeeDto>>.OprateSuccess("查询成功！", result.result.DT_TableDataT1);
    }


    public async Task<ServiceResult> InsertFee(long Id, InsertGhre_OpenClassFeeInput fee)
    {
        fee.OpenClassId = Id;
        await _ghre_OpenClassFeeServices.Add(fee);
        return ServiceResult.OprateSuccess();
    }

    public async Task<ServiceResult> DeleteFee(List<long> feeIds)
    {
        await Db.Updateable<Ghre_OpenClassFee>()
                   .SetColumns(it => new Ghre_OpenClassFee() { IsEnable = 0 })
                   .Where(it => feeIds.Contains(it.Id))
                   .ExecuteCommandAsync();
        return ServiceResult.OprateSuccess();
    }
    #endregion

    #region 总结

    public async Task<ServiceResult<Ghre_OpenClassDto>> QuerySummary(long Id)
    {
        var result = await base.QueryById(Id);

        var result1 = new Ghre_OpenClassDto();
        result1.Summary = result.Summary;
        result1.Attachments = await Db.Queryable<Ghre_Attachment>().Where(x => x.TableName == Id.ObjToString() && x.AttachmentGroupID == 2).ToListAsync();
        return ServiceResult<Ghre_OpenClassDto>.OprateSuccess("查询成功！", result1);
    }
    public async Task<ServiceResult> InsertSummary(long Id, InsertGhre_OpenClassInput entity)
    {

        await Db.Updateable<Ghre_OpenClass>()
               .SetColumns(it => new Ghre_OpenClass() { Summary = entity.Summary })
               .Where(it => it.Id == Id)
               .ExecuteCommandAsync();
        await Db.Updateable<Ghre_Attachment>()
                .SetColumns(it => new Ghre_Attachment() { TableName = null, AttachmentGroupID = null })
                .Where(it => it.TableName == Id.ObjToString() && it.AttachmentGroupID == 2)
                .ExecuteCommandAsync();

        if (entity.Attachments != null && entity.Attachments.Any())
        {
            var paths = entity.Attachments.Select(x => x.RelativePath.Replace("/Advanced", null)).ToList();
            await Db.Updateable<Ghre_Attachment>()
                .SetColumns(it => new Ghre_Attachment() { TableName = Id.ObjToString(), AttachmentGroupID = 2 })
                .Where(it => paths.Contains(it.RelativePath))
                .ExecuteCommandAsync();
        }
        return ServiceResult.OprateSuccess();
    }
    #endregion

    #region 修改状态
    [UseTran]
    public async Task<ServiceResult> UpdateStatus(List<long> ids, string status, string source = null)
    {

        switch (source)
        {
            case "TransferPublished":

                #region 转入开课，开班自动产生考试数据
                var list = await Query(x => ids.Contains(x.Id));
                for (int i = 0; i < list.Count; i++)
                {
                    var entity = list[i];

                    if (entity.ExamId.IsNullOrEmpty())
                    {
                        var exam = new Ghre_Exam()
                        {
                            ExamNo = entity.OpenClassNo,
                            ExamName = entity.OpenClassName,
                            UseDefaultCoverImage = true,
                            DateType = "ExamDate",
                            BeginTime = entity.ExamStartTime,
                            EndTime = entity.ExamEndTime,
                            ExamMode = "Online",
                            IsLinkOpenClass = true,
                            Status = "Released",
                            LinkType = entity.LinkType == "Course" ? "CourseId" : "CourseSceneId",
                            CourseId = entity.LinkType == "Course" ? entity.LinkId : null,
                            CourseSceneId = entity.LinkType == "CourseScene" ? entity.LinkId : null,
                            ExamPaperId = entity.ExamPaperId,
                            OpenClassId = entity.Id,
                            Source = "OpenClass",
                            IsRequireStudy = entity.IsRequireStudy,
                            PlanId = entity.PlanId,
                            OnlineScorePercentage = entity.OnlineScorePercentage,
                            OfflineScorePercentage = entity.OfflineScorePercentage,
                            ScoreRule = entity.ScoreRule,
                            StudyFinishedRule = entity.StudyFinishedRule,
                            IsViewResult = entity.IsViewResult,
                            IsAfterViewResultRetake = entity.IsAfterViewResultRetake,
                            DataBelongID = entity.DataBelongID,
                        };
                        var examId = await Db.Insertable(exam).ExecuteReturnSnowflakeIdAsync();

                        await Db.Updateable<Ghre_OpenClass>()
                            .SetColumns(it => new Ghre_OpenClass() { ExamId = examId })
                            .Where(it => it.Id == entity.Id)
                            .ExecuteCommandAsync();
                    }
                    else
                    {
                        await Db.Updateable<Ghre_Exam>()
                            .SetColumns(it => new Ghre_Exam()
                            {
                                ExamNo = entity.OpenClassNo,
                                ExamName = entity.OpenClassName,
                                UseDefaultCoverImage = true,
                                BeginTime = entity.ExamStartTime,
                                EndTime = entity.ExamEndTime,
                                Status = "Released",
                                LinkType = entity.LinkType == "Course" ? "CourseId" : "CourseSceneId",
                                CourseId = entity.LinkType == "Course" ? entity.LinkId : null,
                                CourseSceneId = entity.LinkType == "CourseScene" ? entity.LinkId : null,
                                ExamPaperId = entity.ExamPaperId,
                                OpenClassId = entity.Id,
                               IsRequireStudy = entity.IsRequireStudy,
                                PlanId = entity.PlanId,
                                OnlineScorePercentage = entity.OnlineScorePercentage,
                                OfflineScorePercentage = entity.OfflineScorePercentage,
                                ScoreRule = entity.ScoreRule,
                                StudyFinishedRule = entity.StudyFinishedRule,
                                IsViewResult = entity.IsViewResult,
                                IsAfterViewResultRetake = entity.IsAfterViewResultRetake,
                                DataBelongID = entity.DataBelongID,
                            })
                            .Where(it => it.Id == entity.ExamId)
                            .ExecuteCommandAsync();

                        await Db.Updateable<Ghre_ExamRecord>()
                            .SetColumns(it => new Ghre_ExamRecord()
                            {
                                BeginTime = entity.ExamStartTime,
                                EndTime = entity.ExamEndTime,
                            })
                            .Where(it => it.ExamId == entity.ExamId)
                            .ExecuteCommandAsync();
                    }

                    #region 生成反馈数据
                    if (entity.LinkType == "CourseScene")
                    {
                        var schedules = await _ghre_OpenClassScheduleServices.QueryDto(x => x.OpenClassId == entity.Id);

                        for (int j = 0; j < schedules.Count; j++)
                        {
                            await _ghre_OpenClassFeedbackServices.Add(new InsertGhre_OpenClassFeedbackInput()
                            {
                                OpenClassId = entity.Id,
                                SurveyId = entity.ParentFeedbackId,
                                StaffId = entity.ParentTeacherId,
                                Source = "ParentTeacher",
                                EffectiveTime = schedules[j].EndTime,
                                ExpiryTime = DateTime.MaxValue,
                                TeacherId = schedules[j].TeacherId,
                                CourseBeginTime = schedules[j].StartTime,
                                CourseEndTime = schedules[j].EndTime,
                                CourseId = schedules[j].CourseId,
                                Status = "N",
                                Score = 0
                            });
                        }
                    }
                    else
                    {
                        await _ghre_OpenClassFeedbackServices.Add(new InsertGhre_OpenClassFeedbackInput()
                        {
                            OpenClassId = entity.Id,
                            SurveyId = entity.ParentFeedbackId,
                            StaffId = entity.ParentTeacherId,
                            Source = "ParentTeacher",
                            EffectiveTime = entity.ExamEndTime,
                            ExpiryTime = DateTime.MaxValue,
                            TeacherId = entity.TeacherId,
                            CourseBeginTime = entity.StartTime,
                            CourseEndTime = entity.EndTime,
                            CourseId = entity.LinkId,
                            Status = "N",
                            Score = 0
                        });
                    }
                    #endregion
                }
                #endregion

                break;



            case "CancelOpening":
                var message = "";
                var list2 = await Query(x => ids.Contains(x.Id));
                for (int i = 0; i < list2.Count; i++)
                {
                    var entity = list2[i];
                    if (await Db.Queryable<Ghre_StudyRecord>()
                        .Where(it => it.OpenClassId != null && it.OpenClassId == entity.Id && it.BeginTime != null)
                        .AnyAsync())
                        return ServiceResult.OprateFailed($"开班【{entity.OpenClassName}】,已有人考试，暂不可取消开课！");

                    if (message.IsNullOrEmpty() && await Db.Queryable<Ghre_ExamRecord>()
                        .Where(it => it.OpenClassId != null && it.OpenClassId == entity.Id && it.ActualBeginTime != null)
                        .AnyAsync())
                        return ServiceResult.OprateFailed($"开班【{entity.OpenClassName}】,已有人考试，暂不可取消开课！");
                }

                if (message.IsNotEmptyOrNull())
                    throw new Exception();

                break;
            case "CancelPublished":

                var list1 = await Query(x => ids.Contains(x.Id));
                for (int i = 0; i < list1.Count; i++)
                {
                    var entity = list1[i];
                    if (await Db.Queryable<Ghre_StudyRecord>()
                        .Where(it => it.OpenClassId != null && it.OpenClassId == entity.Id && it.BeginTime != null)
                        .AnyAsync())
                        return ServiceResult.OprateFailed($"开班【{entity.OpenClassName}】,已有人学习，暂不可取消发布！");


                    if (await Db.Queryable<Ghre_ExamRecord>()
                        .Where(it => it.OpenClassId != null && it.OpenClassId == entity.Id && it.ActualBeginTime != null)
                        .AnyAsync())
                        return ServiceResult.OprateFailed($"开班【{entity.OpenClassName}】,已有人学习，暂不可取消发布！");

                }
                await Db.Deleteable<Ghre_StudyRecord>()
                  .Where(it => it.OpenClassId != null && ids.Contains(it.OpenClassId.Value))
                  .ExecuteCommandAsync();

                await Db.Deleteable<Ghre_ExamRecord>()
                  .Where(it => it.OpenClassId != null && ids.Contains(it.OpenClassId.Value))
                  .ExecuteCommandAsync();

                await Db.Deleteable<Ghre_OpenClassFeedback>()
                  .Where(it => it.OpenClassId != null && ids.Contains(it.OpenClassId.Value))
                  .ExecuteCommandAsync();
                break;

            case "Close":
                await Db.Updateable<Ghre_OpenClassFeedback>()
                        .SetColumns(it => new Ghre_OpenClassFeedback() { ExpiryTime = DateTime.Now })
                        .Where(it => it.OpenClassId != null && ids.Contains(it.OpenClassId.Value))
                        .ExecuteCommandAsync();
                break;

            default:
                break;
        }


        await Db.Updateable<Ghre_OpenClass>()
            .SetColumns(it => new Ghre_OpenClass() { Status = status })
           .Where(it => ids.Contains(it.Id))
           .ExecuteCommandAsync();


        return ServiceResult.OprateSuccess();
    }
    #endregion

    #region 成绩

    public async Task<ServiceResult<List<Ghre_OpenClassScore>>> QueryScore(long Id)
    {
        var sql = @$"SELECT A.Id,
       C.StaffNo,
       C.StaffName,
       D.DeptName,
       A.Score,
       A.AdjustScore,
       A.IsPass,
       A.FinallyIsPass,
       A.RetakeTimes,
       A.Comment
FROM Ghre_ExamRecord A
     JOIN Ghre_Exam B ON A.ExamId = B.Id
     LEFT JOIN Ghra_Staff C ON A.StaffId = C.StaffID
     LEFT JOIN Ghro_Dept D ON C.DeptID = D.DeptID
WHERE B.OpenClassId = '{Id}'";
        var entitys = await Db.Ado.SqlQueryAsync<Ghre_OpenClassScore>(sql);

        entitys.ForEach(it =>
        {
            it.IsPassLabel = it.IsPass == true ? "合格" : "不合格";
            it.FinallyIsPassLabel = it.FinallyIsPass == true ? "合格" : "不合格";
        });

        return ServiceResult<List<Ghre_OpenClassScore>>.OprateSuccess("查询成功！", entitys);
    }
    #endregion

    #region 报名
    /// <summary>
    /// 报名
    /// </summary>
    /// <param name="Id">开班ID</param>
    /// <returns></returns>
    public async Task<ServiceResult> CheckIn(long Id)
    {
        if (!await base.AnyAsync(x => x.Id == Id))
            return ServiceResult.OprateSuccess("无效的开班ID！");
        if (await Db.Queryable<Ghre_OpenClassStaff>().Where(x => x.StaffId == App.User.StaffId && x.OpenClassId == Id).AnyAsync())
            return ServiceResult.OprateSuccess("已报名，请勿重复提交！");

        var staff = new Ghre_OpenClassStaff()
        {
            StaffId = App.User.StaffId,
            OpenClassId = Id,
            Source = "CheckIn"
        };
        await Db.Insertable(staff).ExecuteReturnSnowflakeIdAsync();
        return ServiceResult.OprateSuccess("报名成功！");
    }
    #endregion

    #region 课表

    public async Task<ServiceResult<Ghre_OpenClassSchedule1>> QuerySchedule(long Id)
    {
        var data = new Ghre_OpenClassSchedule1();
        data.AttendType = await Db.Queryable<Ghre_Config>().Where(x => x.ConfigCode == "Open_Class_Schedule_Attend_Type").Select(x => x.ConfigValue).FirstAsync() ?? "CheckIn";
        var min = await Db.Queryable<Ghre_Config>().Where(x => x.ConfigCode == "Open_Class_Schedule_Valid_Attend_Min").Select(x => x.ConfigValue).FirstAsync() ?? "15";

        var entity = await base.QueryById(Id);

        var attends = await Db.Queryable<Ghre_OpenClassAttend>().Where(x => x.OpenClassId == Id && x.StaffId == App.User.StaffId).ToListAsync();

        if (entity.LinkType == "CourseScene")
        {

            data.SceneName = await Db.Queryable<Ghre_CourseScene>().Where(x => x.Id == entity.LinkId).Select(x => x.SceneName).FirstAsync();

            var sql = @$"SELECT A.Id,
       A.Address,
       A.StartTime,
       A.EndTime,
       A.TeacherId,
       A.CourseId,
       B.CourseName
FROM Ghre_OpenClassSchedule A LEFT JOIN Ghre_Course B ON A.CourseId = B.Id
WHERE A.OpenClassId = '{Id}' AND A.IsEnable = 1";
            data.Details = await Db.Ado.SqlQueryAsync<Ghre_OpenClassScheduleDeatil>(sql);
            data.Details.ForEach(x =>
            {
                x.StartTime = x.StartTime;
                x.EndTime = x.EndTime;
                x.StartTime1 = x.StartTime.Value.AddMinutes(-min.ObjToInt());
                x.EndTime1 = x.EndTime.Value.AddMinutes(min.ObjToInt());
            });
        }
        else
        {
            var detail = new Ghre_OpenClassScheduleDeatil()
            {
                Address = entity.Address,
                StartTime = entity.StartTime,
                EndTime = entity.EndTime,
                StartTime1 = entity.StartTime.Value.AddMinutes(-min.ObjToInt()),
                EndTime1 = entity.EndTime.Value.AddMinutes(min.ObjToInt()),
                CourseId = entity.LinkId,
            };
            detail.CourseName = await Db.Queryable<Ghre_Course>().Where(x => x.Id == entity.LinkId).Select(x => x.CourseName).FirstAsync();

            data.Details.Add(detail);
        }
        var dt = DateTime.Now;
        data.Details.ForEach(d =>
        {
            d.Time = DateTimeHelper.ConvertToMiniuteString(d.StartTime) + " ~ " + DateTimeHelper.ConvertToMiniuteString(d.EndTime);

            if (d.StartTime1 <= dt && dt <= d.EndTime1)
                d.Status = "Current";
            if (d.StartTime1 > dt)
                d.Status = "WaitStart";

            #region 处理签到签退时间

            if (data.SceneName.IsNotEmptyOrNull())
            {
                d.CheckInTime = attends.Where(x => x.ScheduleId == d.Id && x.Reverse1 == "CheckIn").Select(x => x.AttendTime).FirstOrDefault();
                d.CheckOutTime = attends.Where(x => x.ScheduleId == d.Id && x.Reverse1 == "CheckOut").Select(x => x.AttendTime).FirstOrDefault();

            }
            else
            {
                d.CheckInTime = attends.Where(x => x.Reverse1 == "CheckIn").Select(x => x.AttendTime).FirstOrDefault();
                d.CheckOutTime = attends.Where(x => x.Reverse1 == "CheckOut").Select(x => x.AttendTime).FirstOrDefault();
            }
            #endregion

            if (d.Status != "Current")
            {
                if (d.CheckInTime != null)
                    d.Status = "Attend";
            }
        });
        //entitys.ForEach(it =>
        //{
        //    it.IsPassLabel = it.IsPass == true ? "合格" : "不合格";
        //    it.FinallyIsPassLabel = it.FinallyIsPass == true ? "合格" : "不合格";
        //});
        var current = data.Details.Where(x => x.Status == "Current").FirstOrDefault();
        if (current != null)
        {

            data.IsCheckIn = true;
            data.IsCheckOut = false;

            if (current.CheckInTime != null)
            {
                data.IsCheckIn = false;
                data.Status = "HasCheckIn";
                var start = current.EndTime.Value.AddMinutes(-min.ObjToInt() * 2);
                if (dt >= start && dt <= current.EndTime)
                    data.IsCheckOut = true;
            }
            if (current.CheckOutTime != null)
            {
                data.IsCheckOut = false;
                data.Status = "HasCheckOut";

            }

        }

        return ServiceResult<Ghre_OpenClassSchedule1>.OprateSuccess("查询成功！", data);
    }
    #endregion

    #region 签到
    /// <summary>
    /// 签到
    /// </summary>
    /// <param name="Id">开班ID</param>
    /// <returns></returns>
    public async Task<ServiceResult> Attend(long Id, string type)
    {
        var entity = await base.QueryById(Id);

        if (entity is null)
            return ServiceResult.OprateSuccess("无效的开班ID！");

        long? scheduleId = null;
        var dt = DateTime.Now;
        var min = await Db.Queryable<Ghre_Config>().Where(x => x.ConfigCode == "Open_Class_Schedule_Valid_Attend_Min").Select(x => x.ConfigValue).FirstAsync() ?? "15";

        if (entity.LinkType == "CourseScene")
        {
            var schedules = await Db.Queryable<Ghre_OpenClassSchedule>().Where(x => x.OpenClassId == entity.Id).ToListAsync();
            schedules.ForEach(x =>
            {
                x.StartTime = x.StartTime.Value.AddMinutes(-min.ObjToInt());
                x.EndTime = x.EndTime.Value.AddMinutes(min.ObjToInt());
            });

            scheduleId = schedules.Where(x => x.StartTime <= dt && x.EndTime >= dt).FirstOrDefault()?.Id;
        }

        if (!await Db.Queryable<Ghre_OpenClassAttend>()
            .Where(x => x.OpenClassId == Id && x.StaffId == App.User.StaffId && x.ScheduleId == scheduleId && x.Reverse1 == type)
            .AnyAsync())
        {
            var staff = new Ghre_OpenClassAttend()
            {
                StaffId = App.User.StaffId,
                OpenClassId = Id,
                AttendTime = DateTime.Now,
                ScheduleId = scheduleId,
                Reverse1 = type
            };
            await Db.Insertable(staff).ExecuteReturnSnowflakeIdAsync();
        }

        return ServiceResult.OprateSuccess("签到成功！");
    }
    #endregion

    #region 邮件
    /// <summary>
    /// 邮件
    /// </summary>
    /// <param name="Id">开班ID</param>
    /// <returns></returns>
    public async Task<ServiceResult> Email(long Id)
    {
        var entity = await base.QueryById(Id);
        var stafffIds = new List<int>();
        if (entity.StaffGroupId.IsNotEmptyOrNull())
        {

            var staffGroups = await _ghre_StaffGroupServices.QueryStaff(entity.StaffGroupId.Value, new QueryBody(), "", true);

            stafffIds = staffGroups.result.DT_TableDataT1.Select(x => x.StaffID).ToList();
        }

        var staffIds1 = await Db.Queryable<Ghre_OpenClassStaff>().Where(x => x.OpenClassId == Id && x.StaffId != null).Select(s => s.StaffId.Value).ToListAsync();

        stafffIds.AddRange(staffIds1);
        stafffIds = stafffIds.Distinct().ToList();

        var staffs = await Db.Queryable<Ghra_Staff>().Where(x => stafffIds.Contains(x.StaffID) && !string.IsNullOrEmpty(x.Email)).Select(x => new { x.StaffID, x.Email }).ToListAsync();


        var courseName = await Db.Ado.GetStringAsync($"select CourseName from Ghre_CourseScene_V where id='{entity.LinkId}'");

        var content = entity.NoticeContent + " </br>"
            + $"开班编号： {entity.OpenClassNo}</br>"
            + $"开班名称： {entity.OpenClassName}</br>"
            + $"课程名称： {courseName}</br>"
            + $"开班起止日期： {DateTimeHelper.ConvertToMiniuteString(entity.StartTime)}~{DateTimeHelper.ConvertToMiniuteString(entity.EndTime)}</br>"
            + $"报名起止日期： {DateTimeHelper.ConvertToMiniuteString(entity.RegisterStartTime)}~{DateTimeHelper.ConvertToMiniuteString(entity.RegisterStartTime)}</br>"
            + $"考试起止日期： {DateTimeHelper.ConvertToMiniuteString(entity.ExamStartTime)}~{DateTimeHelper.ConvertToMiniuteString(entity.ExamStartTime)}</br>";
        for (int i = 0; i < staffs.Count; i++)
        {
            #region 发送邮件
            var mailOutbox = new Ghrs_MailOutbox();
            mailOutbox.TOMail = staffs[i].Email;
            mailOutbox.MailTitle = "开班通知";
            mailOutbox.MailBody = content;
            mailOutbox.MailPriority = 1;
            mailOutbox.ScheduleTime = DateTime.Now;
            mailOutbox.IsEnable = 1;
            mailOutbox.SortNo = 1;
            mailOutbox.CompanyID = 0;
            mailOutbox.IsDefault = 0;
            mailOutbox.CreateProg = "OpenClass";
            var id1 = await Db.Insertable(mailOutbox).ExecuteReturnIdentityAsync();
            #endregion
        }

        var teacher = await Db.Queryable<Ghre_Teacher>().Where(x => x.Id == entity.TeacherId).FirstAsync();
        if (teacher != null && teacher.Email.IsNotEmptyOrNull())
        {
            content = entity.TeacherNoticeContent + " </br>"
         + $"开班编号： {entity.OpenClassNo}</br>"
         + $"开班名称： {entity.OpenClassName}</br>"
         + $"课程名称： {courseName}</br>"
         + $"开班起止日期： {DateTimeHelper.ConvertToMiniuteString(entity.StartTime)}~{DateTimeHelper.ConvertToMiniuteString(entity.EndTime)}</br>"
         + $"报名起止日期： {DateTimeHelper.ConvertToMiniuteString(entity.RegisterStartTime)}~{DateTimeHelper.ConvertToMiniuteString(entity.RegisterStartTime)}</br>"
         + $"考试起止日期： {DateTimeHelper.ConvertToMiniuteString(entity.ExamStartTime)}~{DateTimeHelper.ConvertToMiniuteString(entity.ExamStartTime)}</br>";

            #region 发送邮件
            var mailOutbox = new Ghrs_MailOutbox();
            mailOutbox.TOMail = teacher.Email;
            mailOutbox.MailTitle = "开班通知";
            mailOutbox.MailBody = content;
            mailOutbox.MailPriority = 1;
            mailOutbox.ScheduleTime = DateTime.Now;
            mailOutbox.IsEnable = 1;
            mailOutbox.SortNo = 1;
            mailOutbox.CompanyID = 0;
            mailOutbox.IsDefault = 0;
            mailOutbox.CreateProg = "OpenClass";
            await Db.Insertable(mailOutbox).ExecuteReturnIdentityAsync();
            #endregion
        }
        return ServiceResult.OprateSuccess("发送成功！");
    }
    #endregion

    #region 评估汇总
    /// <summary>
    /// 评估汇总
    /// </summary>
    /// <param name="Id">开班ID</param>
    /// <returns></returns>
    public async Task<ServiceResult<Ghre_OpenClassStatistic>> QueryStatistic(long id)
    {
        var data = new Ghre_OpenClassStatistic();

        var entity = await base.QueryById(id);

        var surveyRecords = await Db.Queryable<Ghre_SurveyRecord>().Where(x => x.OpenClassId == id).ToListAsync();

        var surveyIds = surveyRecords.Select(x => x.SurveyId).Distinct().ToList();
        var recordOptions = await Db.Queryable<Ghre_SurveyRecordOption>()
            .Where(x => surveyIds.Contains(x.SurveyId))
            .ToListAsync();

        data.CourseScore = surveyRecords.Sum(x => x.Score);
        data.TeacherScore = surveyRecords.Sum(x => x.Score);

        var questions = await Db.Queryable<Ghre_SurveyQuestion>()
            .OrderBy(x => x.SortNo)
            .Where(x => x.SurveyId == entity.FeedbackId)
            .Select(x => new Ghre_OpenClassQuestion()
            {
                Id = x.Id,
                QuestionContent = x.QuestionContent,
                QuestionType = x.QuestionType,
                Score = 0
            }).ToListAsync();

        var parentQuestions = await Db.Queryable<Ghre_SurveyQuestion>()
            .OrderBy(x => x.SortNo)
            .Where(x => x.SurveyId == entity.ParentFeedbackId)
            .Select(x => new Ghre_OpenClassQuestion()
            {
                Id = x.Id,
                QuestionContent = x.QuestionContent,
                QuestionType = x.QuestionType,
                Score = 0
            }).ToListAsync();

        questions.ForEach(async x =>
        {
            x.QuestionType = await GetParaLabel("SurveyQuestionType", x.QuestionType);
            x.Score = recordOptions.Where(o => o.SurveyQuestionId == x.Id).Sum(x => x.Score);
        });

        parentQuestions.ForEach(async x =>
        {
            x.QuestionType = await GetParaLabel("SurveyQuestionType", x.QuestionType);
            x.Score = recordOptions.Where(o => o.SurveyQuestionId == x.Id).Sum(x => x.Score);
        });

        data.CourseGroup.Trainee = questions;
        data.CourseGroup.ParentTeacher = parentQuestions;

        data.TeacherGroup.Trainee = questions;
        data.TeacherGroup.ParentTeacher = parentQuestions;

        data.TotalGroup.Trainee = (await _ghre_SurveyServices.QueryStatistic(entity.FeedbackId.Value)).Data;
        data.TotalGroup.ParentTeacher = (await _ghre_SurveyServices.QueryStatistic(entity.ParentFeedbackId.Value)).Data;

        string sql = @$"SELECT A.Id,
       B.StaffNo,
       B.StaffName,
       C.DeptName,
       D.CourseName,
        CASE A.Status
          WHEN 'Y' THEN '已评'
          WHEN 'N' THEN '未评'
       END AS ScoreStatus,
       A.Score,
       CASE A.Source
          WHEN 'ParentTeacher' THEN '讲师上级'
          WHEN 'Trainee' THEN '学员'
       END AS Source
FROM Ghre_OpenClassFeedback A
     LEFT JOIN Ghra_Staff B ON A.StaffId = B.StaffID
     LEFT JOIN Ghro_Dept C ON C.DeptID = B.DeptID
     LEFT JOIN Ghre_Course D ON A.CourseId = D.Id
WHERE A.SurveyId = {entity.FeedbackId} OR A.SurveyId = {entity.ParentFeedbackId}";
        data.Records = DbAccess.QueryList<Ghre_OpenClassStatisticRecord>(sql);

        return ServiceResult<Ghre_OpenClassStatistic>.OprateSuccess("查询成功！", data);
    }
    #endregion
}