using NPOI.SS.UserModel;
using System.Net;
using static Tiobon.Core.Model.Consts;

namespace Tiobon.Core.Services;

/// <summary>
/// 课程 (服务)
/// </summary>
public class Ghre_CourseServices : BaseServices<Ghre_Course, Ghre_CourseDto, InsertGhre_CourseInput, EditGhre_CourseInput>, IGhre_CourseServices
{
    private readonly IBaseRepository<Ghre_Course> _dal;
    private IGhre_CourseClassServices _ghre_CourseClassServices;
    private IGhre_CourseSnapServices _ghre_CourseSnapServices;
    public Ghre_CourseServices(IBaseRepository<Ghre_Course> dal,
        ICaching caching,
        IGhre_CourseClassServices ghre_CourseClassServices,
        IGhre_CourseSnapServices ghre_CourseSnapServices)
    {
        this._dal = dal;
        base.BaseDal = dal;
        _ghre_CourseClassServices = ghre_CourseClassServices;
        _ghre_CourseSnapServices = ghre_CourseSnapServices;
        base._caching = caching;
    }

    public async Task<ServicePageResult<Ghre_CourseDto>> QueryList(QueryBody filter, string status, List<long> ids)
    {
        RefAsync<int> totalCount = 0;
        string sql = @$"SELECT *
                        FROM (SELECT A.*,
                                     E.CourseWareName + ' (' + E.CourseWareNo + ')' CourseWareName,
                                     F.StaffName + ' (' + F.StaffNo + ')' ManagerStaffName,
                                     G.UserName CreateName,
                                     H.UserName UpdateName,
                                     CASE A.InOrOut
                                        WHEN 'In' THEN F.StaffName
                                        WHEN 'Out' THEN J.TeacherName
                                     END TeacherName,
                                     ISNULL (A.UpdateTime, A.CreateTime) CreateTime1
                              FROM Ghre_Course A
                                   LEFT JOIN Ghre_CourseWare E ON A.CourseWareId = E.Id
                                   LEFT JOIN Ghra_Staff F ON A.ManagerId = F.StaffID
                                   LEFT JOIN Ghrs_User G ON A.CreateBy = G.UserId
                                   LEFT JOIN Ghrs_User H ON A.UpdateBy = H.UserId
                                   LEFT JOIN Ghra_Staff I ON A.TeacherId = I.StaffID
                                   LEFT JOIN Ghre_Teacher J ON A.SchoolTeacherId = I.StaffID
                              WHERE A.IsEnable = 1 AND dbo.FUserDataBelongPriv ({App.User.ID}, A.DataBelongID, NULL) = 1) A";

        if (string.IsNullOrWhiteSpace(filter.orderBy))
            filter.orderBy = "CourseNo ASC";

        string conditions = " WHERE 1=1";


        if (!string.IsNullOrWhiteSpace(status))
            conditions += $" AND Status ='{status}'";
        if (ids != null && ids.Any())
            conditions += $" AND Id IN({string.Join(",", ids)})";


        if (filter.jsonParam != null)
            foreach (JProperty jProperty in filter.jsonParam.Properties())
            {
                var name = jProperty.Name;
                var value = jProperty.Value.ToString();
                if (name == "page" || name == "pageSize")
                    continue;

                if (!string.IsNullOrWhiteSpace(value))
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);

                    if (name == "CourseNoOrName")
                    {
                        conditions += $" AND ( CourseNo LIKE '%{jsonParam.columnValue}%' OR CourseName LIKE '%{jsonParam.columnValue}%')";
                        continue;
                    }

                    switch (jsonParam.operationKey)
                    {
                        case "Include":
                            conditions += $" AND {name} LIKE '%{jsonParam.columnValue}%'";
                            break;
                        case "NotInclude":
                            conditions += $" AND {name} NOT LIKE '%{jsonParam.columnValue}%'";
                            break;
                        case "IsNull":
                            conditions += $" AND {name} IS NULL";
                            break;
                        case "NotNull":
                            conditions += $" AND {name} IS NOT NULL";
                            break;
                        case "Equal":
                            conditions += $" AND {name} ='{jsonParam.columnValue}'";
                            break;
                        case "NotEqual":
                            conditions += $" AND {name} !='{jsonParam.columnValue}'";
                            break;
                        case "GreaterOrEqual"://大于等于
                            conditions += $" AND {name} >='{jsonParam.columnValue}'";
                            break;
                        case "Greater"://大于
                            conditions += $" AND {name} >'{jsonParam.columnValue}'";
                            break;
                        case "LessOrEqual"://小于等于
                            conditions += $" AND {name} <='{jsonParam.columnValue}'";
                            break;
                        case "Less"://小于
                            conditions += $" AND {name} <'{jsonParam.columnValue}'";
                            break;
                        case "EqualAny":// 
                            if (jsonParam.columnValue != null)
                            {
                                var ids1 = JsonHelper.JsonToObj<List<string>>(jsonParam.columnValue.ToString());

                                conditions += $" AND {name} IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))})";
                            }
                            break;
                        case "NotEqualAny":// 
                            if (jsonParam.columnValue != null)
                            {
                                var ids1 = JsonHelper.JsonToObj<List<string>>(jsonParam.columnValue.ToString());

                                conditions += $" AND ({name} NOT IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))}) OR {name} IS NULL)";
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        if (filter.pageSize == 0)
            filter.pageSize = 10000;
        sql += conditions;
        var data = await Db.SqlQueryable<Ghre_CourseDto>(sql)
            .OrderBy(filter.orderBy)
            .ToPageListAsync(filter.pageNum, filter.pageSize, totalCount);

        var classsIds1 = data.Select(x => x.CourseClassId).Distinct().ToList();
        var classsIds = new List<long>();

        classsIds1.ForEach(x =>
        {
            if (!string.IsNullOrWhiteSpace(x))
            {
                var courseClassIds = JsonConvert.DeserializeObject<List<long>>(x);
                classsIds = classsIds.Concat(courseClassIds).ToList();
            }
        });
        classsIds = classsIds.Distinct().ToList();
        var classs = await _ghre_CourseClassServices.Query(x => classsIds.Contains(x.Id));

        var courseSceneIds1 = data.Select(x => x.CourseSceneIds).Distinct().ToList();
        var courseSceneIds = new List<long>();

        courseSceneIds1.ForEach(x =>
        {
            if (!string.IsNullOrWhiteSpace(x))
                courseSceneIds = courseSceneIds.Concat(JsonConvert.DeserializeObject<List<long>>(x)).ToList();

        });
        //data.ForEach(x =>
        //{
        //    if (x.CourseSceneId != null)
        //        courseSceneIds.Add(x.CourseSceneId.Value);
        //});
        courseSceneIds = courseSceneIds.Distinct().ToList();
        var courseScenes = await Db.Queryable<Ghre_CourseScene>().Where(x => courseSceneIds.Contains(x.Id)).ToListAsync();

        data.ForEach(async x =>
        {
            x.ChargeMethodLabel = await GetParaLabel("CourseChargeMethod", x.ChargeMethod);
            x.CourseClass2 = await GetParaLabel("TrainingCourseClass2", x.ChargeMethod);
            x.InOrOutLabel = await GetParaLabel("CourseInOrOut", x.InOrOut);
            x.IsOPenLabel = x.IsOpen == "1" ? "是" : "否";
            var courseClass = classs.Where(a => x.CourseClassId.Contains(a.Id.ToString())).ToList();
            x.CourseClassName = string.Join(",", courseClass.Select(a => a.ClassName + " (" + a.ClassNo + ")"));

            if (x.CourseSceneIds.IsNotEmptyOrNull())
            {
                x.CourseSceneIds1 = JsonConvert.DeserializeObject<List<long>>(x.CourseSceneIds);
                if (x.CourseSceneIds1.Any())
                {
                    var courseScene = courseScenes.Where(a => x.CourseSceneIds1.Contains(a.Id)).ToList();
                    x.CourseSceneName = string.Join(",", courseScene.Select(a => a.SceneName + " (" + a.SceneNo + ")"));
                }
            }

            //else if (x.CourseSceneId != null)
            //{
            //    var courseScene = courseScenes.Where(a => a.Id == x.CourseSceneId).ToList();
            //    x.CourseSceneName = string.Join(",", courseScene.Select(a => a.SceneName + " (" + a.SceneNo + ")"));
            //}
            x.BuiltInLabel = x.BuiltIn == 1 ? "是" : "否";
            x.DataBelongName = await GetDataBelongName(x.DataBelongID);
        });

        return new ServicePageResult<Ghre_CourseDto>(filter.pageNum, totalCount, filter.pageSize, data);
    }

    public async Task<ServiceResult<int>> QueryDeptID(int StaffID)
    {
        string sql = $"SELECT A.DeptID from Ghra_Staff A LEFT JOIN Ghro_Dept B ON A.DeptID = B.DeptID WHERE A.StaffID='{StaffID}'";

        int id = await Db.Ado.GetIntAsync(sql);
        return ServiceResult<int>.OprateSuccess("查询成功！", id);

    }
    public async Task<ServiceResult<CommonSelect>> QueryTeacher(long? linkId)
    {
        var result = new CommonSelect();
        JArray TableColumn = new JArray();
        JArray DT_TablePageInfoT1 = new JArray();
        JArray DT_TableDataT1 = new JArray();
        JObject searchItem = new JObject();
        JObject item;
        DataTable dt;
        string sql;

        searchItem = new JObject  {
            new JProperty("defaultHidden", true),
            new JProperty("field","value"),
            new JProperty("label","讲师ID"),
        };
        TableColumn.Add(searchItem);
        searchItem = new JObject  {
            new JProperty("field","label"),
            new JProperty("label","讲师名称"),
        };
        TableColumn.Add(searchItem);

        sql = "SELECT Id, TeacherNo , TeacherName FROM Ghre_Teacher WHERE IsEnable=1 ";

        if (linkId != null)
            sql += $"AND SchoolId ='{linkId}'";
        dt = await Db.Ado.GetDataTableAsync(sql);

        for (int i = 0; i < dt.Rows.Count; i++)
        {
            item = new JObject {
                new JProperty("value",long.Parse(dt.Rows[i]["Id"].ToString())),
                new JProperty("label",dt.Rows[i]["TeacherNo"].ToString()+"-"+dt.Rows[i]["TeacherName"].ToString())
            };
            DT_TableDataT1.Add(item);
        }

        item = new JObject {
            new JProperty("ListMax",100),
            new JProperty("ListMin",10),
            new JProperty("PageNum",1),
            new JProperty("PageSize",99999),
            new JProperty("TotalCount",dt.Rows.Count),
            new JProperty("UIType","Auto")
        };
        DT_TablePageInfoT1.Add(item);

        result.JM_TableColumnT1.TableColumn = TableColumn;
        result.DT_TableDataT1 = DT_TableDataT1;
        result.DT_TablePageInfoT1 = DT_TablePageInfoT1;
        return new ServiceResult<CommonSelect>() { Success = true, Message = "查询成功", Data = result, };

    }

    public override async Task<ServiceFormResult<Ghre_CourseDto>> QueryForm(QueryForm body)
    {
        var result = await base.QueryForm(body);
        string examPaperId = result.result.DT_TableDataT1[0].ExamPaperId;
        if (!string.IsNullOrWhiteSpace(examPaperId))
            result.result.DT_TableDataT1[0].ExamPaperIds = JsonConvert.DeserializeObject<List<long>>(examPaperId);

        string courseClassId = result.result.DT_TableDataT1[0].CourseClassId;
        if (!string.IsNullOrWhiteSpace(courseClassId))
            result.result.DT_TableDataT1[0].CourseClassIds = JsonConvert.DeserializeObject<List<long>>(courseClassId);

        string courseSceneIds = result.result.DT_TableDataT1[0].CourseSceneIds;
        if (!string.IsNullOrWhiteSpace(courseSceneIds))
            result.result.DT_TableDataT1[0].CourseSceneIds1 = JsonConvert.DeserializeObject<List<long>>(courseSceneIds);

        else result.result.DT_TableDataT1[0].ExamPaperIds = new List<long>();

        if (body.doType == "Copy")
        {
            result.result.DT_TableDataT1[0].CourseNo = null;
            result.result.DT_TableDataT1[0].CourseName = null;
        }
        result.result.DT_TableDataT1[0].IsOPenLabel = result.result.DT_TableDataT1[0].IsOpen == "1" ? "是" : "否";
        return result;

    }

    public override async Task<Ghre_CourseDto> QueryById(object objId)
    {
        var data = await base.QueryById(objId);

        if (data == null)
            throw new Exception("无效的Id");
        var DT_TableDataT1 = Mapper.Map(data).ToANew<Ghre_CourseDto>();
        string examPaperId = DT_TableDataT1.ExamPaperId;

        var classsIds = new List<long>();

        var courseClassIds = JsonConvert.DeserializeObject<List<long>>(DT_TableDataT1.CourseClassId);
        classsIds = classsIds.Concat(courseClassIds).ToList();
        classsIds = classsIds.Distinct().ToList();
        var classs = await _ghre_CourseClassServices.Query(x => classsIds.Contains(x.Id));
        var courseSceneIds = new List<long>();

        if (DT_TableDataT1.CourseSceneIds.IsNotEmptyOrNull())
            courseSceneIds = courseSceneIds.Concat(JsonConvert.DeserializeObject<List<long>>(DT_TableDataT1.CourseSceneIds)).ToList();

        courseSceneIds = courseSceneIds.Distinct().ToList();
        var courseScenes = await Db.Queryable<Ghre_CourseScene>().Where(x => courseSceneIds.Contains(x.Id)).ToListAsync();

        DT_TableDataT1.ChargeMethodLabel = await GetParaLabel("CourseChargeMethod", DT_TableDataT1.ChargeMethod);
        DT_TableDataT1.InOrOutLabel = await GetParaLabel("CourseInOrOut", DT_TableDataT1.InOrOut);
        DT_TableDataT1.IsOPenLabel = DT_TableDataT1.IsOpen == "1" ? "是" : "否";

        var courseClass = classs.Where(a => DT_TableDataT1.CourseClassId.Contains(a.Id.ToString())).ToList();
        DT_TableDataT1.CourseClassName = string.Join(",", courseClass.Select(a => a.ClassName + " (" + a.ClassNo + ")"));
        if (DT_TableDataT1.CourseSceneIds.IsNotEmptyOrNull())
        {
            var courseScene = courseScenes.Where(a => DT_TableDataT1.CourseSceneIds.Contains(a.Id.ToString())).ToList();
            DT_TableDataT1.CourseSceneName = string.Join(",", courseScene.Select(a => a.SceneName + " (" + a.SceneNo + ")"));
        }

        if (!string.IsNullOrWhiteSpace(examPaperId))
            DT_TableDataT1.ExamPaperIds = JsonConvert.DeserializeObject<List<long>>(examPaperId);

        string courseClassId = DT_TableDataT1.CourseClassId;
        if (!string.IsNullOrWhiteSpace(courseClassId))
            DT_TableDataT1.CourseClassIds = JsonConvert.DeserializeObject<List<long>>(courseClassId);

        string courseSceneIds1 = DT_TableDataT1.CourseSceneIds;
        if (!string.IsNullOrWhiteSpace(courseSceneIds1))
            DT_TableDataT1.CourseSceneIds1 = JsonConvert.DeserializeObject<List<long>>(courseSceneIds1);

        else DT_TableDataT1.ExamPaperIds = new List<long>();

        DT_TableDataT1.IsOPenLabel = DT_TableDataT1.IsOpen == "1" ? "是" : "否";
        if (DT_TableDataT1.ManagerId != null)
            DT_TableDataT1.ManagerStaffName = (await Db.Queryable<Ghra_Staff>().Where(x => x.StaffID == DT_TableDataT1.ManagerId).FirstAsync())?.StaffName;
        if (DT_TableDataT1.CourseWareId != null)
            DT_TableDataT1.CourseWareName = (await Db.Queryable<Ghre_CourseWare>().Where(x => x.Id == DT_TableDataT1.CourseWareId).FirstAsync())?.CourseWareName;
        if (DT_TableDataT1.CreditRuleId != null)
            DT_TableDataT1.CreditRuleName = (await Db.Queryable<Ghre_CreditRule>().Where(x => x.Id == DT_TableDataT1.CreditRuleId).FirstAsync())?.RuleName;
        return DT_TableDataT1;
    }

    public async Task<ServiceResult> UpdateStatus(long[] ids, string status)
    {
        if (status != DIC_COURSE_STATUS.RELEASED && status != DIC_COURSE_STATUS.DISABLED && status != DIC_COURSE_STATUS.DRAFT)
            throw new Exception("无效的状态");

        HttpRequest request = UserContext.Context.Request;
        var api = request.Path.ObjToString().TrimEnd('/').ToLower();
        var ip = GetUserIp(UserContext.Context);

        var entities = new List<Ghre_Course>();
        foreach (var id in ids)
        {
            if (id == null || !BaseDal.Any(id))
                continue;

            var entity = await BaseDal.QueryById(id);

            #region 关联数据有效性验证
            if (entity.Status == DIC_COURSE_STATUS.DRAFT && status == DIC_COURSE_STATUS.RELEASED)
            {
                if (!entity.CourseClassId.IsNull())
                {
                    var CourseClassIds = JsonConvert.DeserializeObject<List<long>>(entity.CourseClassId);
                    if (CourseClassIds != null && CourseClassIds.Any())
                    {
                        for (int i = 0; i < CourseClassIds.Count; i++)
                        {
                            if (!await Db.Queryable<Ghre_CourseClass>().AnyAsync(x => x.Id == CourseClassIds[i]))
                                throw new Exception($"课程关联的课程分类已失效，请修正数据后继续发布！");
                        }
                    }
                }

                if (!entity.CourseSceneId.IsNull())
                    if (!await Db.Queryable<Ghre_CourseScene>().AnyAsync(x => x.Id == entity.CourseSceneId))
                        return ServiceResult.OprateFailed($"课程关联的课程场景已失效，请修正数据后继续发布！");

                if (!entity.ExamPaperId.IsNull())
                {
                    var ExamPaperIds = JsonConvert.DeserializeObject<List<long>>(entity.ExamPaperId);
                    if (ExamPaperIds != null && ExamPaperIds.Any())
                    {
                        for (int i = 0; i < ExamPaperIds.Count; i++)
                        {
                            if (!await Db.Queryable<Ghre_ExamPaper>().AnyAsync(x => x.Id == ExamPaperIds[0] && x.Status == DIC_EXAM_PAPER_STATUS.RELEASED))
                                return ServiceResult.OprateFailed($"课程关联的试卷已失效，请修正数据后继续发布！");
                        }
                    }
                }

                #region 课程ID 同步至课件
                if (!entity.CourseWareId.IsNull())
                {

                    var wares = await Db.Queryable<Ghre_CourseWare>().Where(x => x.CourseIds.Contains(id.ToString()) && x.Id != id).ToListAsync();
                    for (int j = 0; j < wares.Count; j++)
                    {
                        var courseIds2 = new List<long>();
                        if (!string.IsNullOrWhiteSpace(wares[j].CourseIds))
                            courseIds2 = JsonConvert.DeserializeObject<List<long>>(wares[j].CourseIds);
                        courseIds2 = courseIds2.Where(x => x != id).ToList();
                        wares[j].CourseIds = JsonConvert.SerializeObject(courseIds2);
                    }
                    await Db.Updateable(wares).UpdateColumns(it => new { it.CourseIds }).ExecuteCommandAsync();

                    var ware = await Db.Queryable<Ghre_CourseWare>().FirstAsync(x => x.Id == entity.CourseWareId);
                    if (ware != null)
                    {
                        var courseIds2 = new List<long>();
                        if (!string.IsNullOrWhiteSpace(ware.CourseIds))
                            courseIds2 = JsonConvert.DeserializeObject<List<long>>(ware.CourseIds);

                        if (!courseIds2.Any(x => x == id))
                        {
                            courseIds2.Add(id);

                            ware.CourseIds = JsonConvert.SerializeObject(courseIds2);
                            await Db.Updateable<Ghre_CourseWare>().SetColumns(it => it.CourseIds == ware.CourseIds).Where(it => it.Id == ware.Id).ExecuteCommandAsync();
                        }
                    }
                }
                #endregion

                entity.PublishTime = DateTime.Now;
            }
            else if (status == DIC_COURSE_STATUS.DRAFT && entity.Status == DIC_COURSE_STATUS.RELEASED)
            {
                #region 课程ID 同步至课件
                if (!entity.CourseWareId.IsNull())
                {

                    var wares = await Db.Queryable<Ghre_CourseWare>().Where(x => x.CourseIds.Contains(id.ToString()) && x.Id != id).ToListAsync();
                    for (int j = 0; j < wares.Count; j++)
                    {
                        var courseIds2 = new List<long>();
                        if (!string.IsNullOrWhiteSpace(wares[j].CourseIds))
                            courseIds2 = JsonConvert.DeserializeObject<List<long>>(wares[j].CourseIds);
                        courseIds2 = courseIds2.Where(x => x != id).ToList();
                        wares[j].CourseIds = JsonConvert.SerializeObject(courseIds2);
                    }
                    await Db.Updateable(wares).UpdateColumns(it => new { it.CourseIds }).ExecuteCommandAsync();
                }
                #endregion
            }
            #endregion

            //没有任何人学习(没点过学习入口，即学习时长=0)可以取消发布;
            //已经有人开始学习:不可以取消，不可以停用;
            //所有人学完:不可以取消，只可以停用;
            if (entity.Status == DIC_COURSE_STATUS.RELEASED)
            {
                var examPaper = await Db.Queryable<Ghre_ExamPaper>().FirstAsync(x => x.LinkId == id && x.LinkType == "CourseId" && x.Status != DIC_COURSE_STATUS.DISABLED);
                if (examPaper is null && entity.CourseSceneId != null)
                    examPaper = await Db.Queryable<Ghre_ExamPaper>().FirstAsync(x => x.LinkId == entity.CourseSceneId && x.LinkType == "CourseSceneId" && x.Status != DIC_COURSE_STATUS.DISABLED);
                if (examPaper != null)
                    return ServiceResult.OprateFailed($"课程【{entity.CourseName}({entity.CourseNo})】已与试卷【{examPaper.PaperName}({examPaper.PaperName})】关联，暂不可{(status == DIC_COURSE_STATUS.DRAFT ? "取消发布" : "停用")}");

                if (entity.CourseWareId.IsNullOrEmpty())
                {

                    if (status == DIC_COURSE_STATUS.DRAFT &&
                        await Db.Queryable<Ghre_StudyRecord>().
                        AnyAsync(x => x.CourseId == id &&
                        (x.StudyStatus == DIC_STUDY_RECORD_STUDY_STATUS.NO_FINISH || x.StudyStatus == DIC_STUDY_RECORD_STUDY_STATUS.HAS_FINISH) &&
                        x.CourseEndTime != null &&
                        x.CourseEndTime.Value.Date >= DateTime.Now.Date))
                        return ServiceResult.OprateFailed($"课程【{entity.CourseName}({entity.CourseNo})】有学员正在学习中，暂不可取消发布！");

                    if (status == DIC_COURSE_STATUS.DISABLED &&
                       await Db.Queryable<Ghre_StudyRecord>().
                       AnyAsync(x => x.CourseId == id &&
                       x.StudyStatus == DIC_STUDY_RECORD_STUDY_STATUS.NO_FINISH &&
                       x.CourseEndTime != null &&
                       x.CourseEndTime.Value.Date >= DateTime.Now.Date))
                        return ServiceResult.OprateFailed($"课程【{entity.CourseName}({entity.CourseNo})】有学员正在学习中，暂不可停用！");

                }
                else
                {
                    if (status == DIC_COURSE_STATUS.DRAFT &&
                            await Db.Queryable<Ghre_StudyRecord>().
                            AnyAsync(x => x.CourseSceneId == entity.CourseWareId &&
                            (x.StudyStatus == DIC_STUDY_RECORD_STUDY_STATUS.NO_FINISH || x.StudyStatus == DIC_STUDY_RECORD_STUDY_STATUS.HAS_FINISH) &&
                            x.CourseEndTime != null &&
                            x.CourseEndTime.Value.Date >= DateTime.Now.Date))
                        return ServiceResult.OprateFailed($"课程【{entity.CourseName}({entity.CourseNo})】有学员正在学习中，暂不可取消发布！");

                    if (status == DIC_COURSE_STATUS.DISABLED &&
                       await Db.Queryable<Ghre_StudyRecord>().
                       AnyAsync(x => x.CourseSceneId == entity.CourseWareId &&
                       x.StudyStatus == DIC_STUDY_RECORD_STUDY_STATUS.NO_FINISH &&
                       x.CourseEndTime != null &&
                       x.CourseEndTime.Value.Date >= DateTime.Now.Date))
                        return ServiceResult.OprateFailed($"课程【{entity.CourseName}({entity.CourseNo})】有学员正在学习中，暂不可停用！");
                }
            }

            entity.UpdateIP = ip;
            entity.UpdateProg = api;
            if (status == DIC_COURSE_STATUS.RELEASED || status == DIC_COURSE_STATUS.DISABLED || status == DIC_COURSE_STATUS.DRAFT)
            {
                entity.Status = status;
                entities.Add(entity);
            }

            #region 生成课程快照
            if (status == DIC_COURSE_STATUS.RELEASED)
            {
                CheckCodeExist("Ghre_Course", "CourseNo", entity.CourseNo, ModifyType.Add, "【已发布】中课程编号", id, $"Status='{DIC_COURSE_STATUS.RELEASED}'");
                var sql = $"UPDATE Ghre_CourseSnap SET IsEnable = 0 WHERE CourseId = '{id}' AND IsEnable = 1";
                await Db.Ado.ExecuteCommandAsync(sql);

                var entity1 = Mapper.Map(entity).ToANew<InsertGhre_CourseSnapInput>();
                var courseClassIds = JsonConvert.DeserializeObject<List<long>>(entity1.CourseClassId);
                var classs = await _ghre_CourseClassServices.Query(x => courseClassIds.Contains(x.Id));
                entity1.CourseClass = string.Join("、", classs.Select(o => o.ClassName));
                entity1.CourseClass1 = string.Join("、", classs.Select(o => o.ClassName + "(" + o.ClassNo + ")"));
                entity1.CourseId = id;

                var examPaper = await Db.Queryable<Ghre_ExamPaper>().FirstAsync(x => x.LinkId == id && x.LinkType == "CourseId" && x.Status != DIC_COURSE_STATUS.DISABLED);
                await _ghre_CourseSnapServices.Add(entity1);
            }
            #endregion

            #region 处理对应场景标准课时、学分等
            if (entity.CourseSceneId.IsNotEmptyOrNull())
            {
                var courseScene = await Db.Queryable<Ghre_CourseScene>().Where(x => x.Id == entity.CourseSceneId).FirstAsync();
                if (courseScene != null)
                {
                    var courses = await Db.Queryable<Ghre_Course>()
                        .WhereIF(status == DIC_COURSE_STATUS.RELEASED, x => x.Id == id || (x.CourseSceneId == entity.CourseSceneId && x.Status == DIC_COURSE_STATUS.RELEASED))
                        .WhereIF(status != DIC_COURSE_STATUS.RELEASED, x => x.Id != id || (x.CourseSceneId == entity.CourseSceneId && x.Status == DIC_COURSE_STATUS.RELEASED))
                        .ToListAsync();

                    courseScene.StandardHour = courses.Sum(x => x.StandardHour);
                    courseScene.CreditPoints = courses.Sum(x => x.CreditPoints);
                    if (courses.Any())
                    {
                        courseScene.CoverUrl = courses.First()?.CoverUrl;
                        courseScene.UseDefaultCoverImage = courses.First()?.UseDefaultCoverImage;
                        courseScene.DefaultCoverImageName = courses.First()?.DefaultCoverImageName;
                    }

                    await Db.Updateable(courseScene).UpdateColumns(it => new
                    {
                        it.StandardHour,
                        it.CreditPoints,
                        it.CoverUrl,
                        it.UseDefaultCoverImage,
                        it.DefaultCoverImageName
                    }).ExecuteCommandAsync();
                }
            }

            #endregion
        }

        var result = await BaseDal.Update(entities);
        if (status == DIC_COURSE_STATUS.RELEASED)
            return ServiceResult.OprateSuccess("发布成功！");
        else if (status == DIC_COURSE_STATUS.DRAFT)
            return ServiceResult.OprateSuccess("已启用成功，请进入草稿箱查看！");
        else
            return ServiceResult.OprateSuccess("停用成功！");

    }

    public override async Task<long> Add(InsertGhre_CourseInput entity)
    {
        entity.ExamPaperId = JsonHelper.ObjToJson(entity.ExamPaperIds);
        if (entity.CourseClassIds != null)
            entity.CourseClassId = JsonHelper.ObjToJson(entity.CourseClassIds);
        entity.CourseSceneIds = JsonHelper.ObjToJson(entity.CourseSceneIds1);
        entity.Status = DIC_COURSE_STATUS.DRAFT;
        entity.DefaultCoverImageName = entity.DefaultCoverImageName ?? "defaultCourseCover1";
        entity.UseDefaultCoverImage = entity.UseDefaultCoverImage ?? true;
        //entity.IsOpen = entity.IsOPenLabel == true ? "1" : "0";
        if (entity.ClassId != null)
        {
            entity.CourseClassIds = [entity.ClassId.Value];
            entity.CourseClassId = JsonHelper.ObjToJson(entity.CourseClassIds);
        }

        if (entity.InOrOut == "In")
        {
            var teacher = await Db.Queryable<Ghre_Teacher>().FirstAsync(x => x.StaffId == entity.TeacherId);
            if (!teacher.IsNull())
            {
                entity.SchoolTeacherId = teacher.Id;
            }
            else entity.SchoolTeacherId = null;
        }

        if (await QueryCompanyCode() == "Ushio")
        {
            var courseClass = await Db.Queryable<Ghre_CourseClass>().Where(x => x.Id == entity.CourseClassIds[0]).Select(x => x.ClassNo).FirstAsync();
            var prefixTemp = courseClass + entity.CourseClass2.Substring(1, entity.CourseClass2.Length - 1);
            entity.CourseNo = await GenerateContinuousSequence("Ghre_Course", "CourseNo", prefixTemp, prefixTemp.Length + 2, 2);
        }
        var result = await base.Add(entity);

        return result;
    }

    public override async Task<bool> Update(long Id, EditGhre_CourseInput editModel)
    {

        editModel.ExamPaperId = JsonHelper.ObjToJson(editModel.ExamPaperIds);
        if (editModel.CourseClassIds != null)
            editModel.CourseClassId = JsonHelper.ObjToJson(editModel.CourseClassIds);
        editModel.CourseSceneIds = JsonHelper.ObjToJson(editModel.CourseSceneIds1);
        if (editModel.ClassId != null)
        {
            editModel.CourseClassIds = [editModel.ClassId.Value];
            editModel.CourseClassId = JsonHelper.ObjToJson(editModel.CourseClassIds);
        }
        if (!editModel.CourseClassId.IsNull())
        {
            var CourseClassIds = JsonConvert.DeserializeObject<List<long>>(editModel.CourseClassId);
            if (CourseClassIds != null && CourseClassIds.Any())
            {
                for (int i = 0; i < CourseClassIds.Count; i++)
                {
                    if (!await Db.Queryable<Ghre_CourseClass>().AnyAsync(x => x.Id == CourseClassIds[i]))
                        throw new Exception($"课程关联的课程分类已失效，请修正数据后继续发布！");
                }
            }
        }

        if (!editModel.CourseSceneId.IsNull())
            if (!await Db.Queryable<Ghre_CourseScene>().AnyAsync(x => x.Id == editModel.CourseSceneId))
                throw new Exception($"课程关联的课程场景已失效，请修正数据后继续发布！");

        if (!editModel.ExamPaperId.IsNull())
        {
            var ExamPaperIds = JsonConvert.DeserializeObject<List<long>>(editModel.ExamPaperId);
            if (ExamPaperIds != null && ExamPaperIds.Any())
            {
                for (int i = 0; i < ExamPaperIds.Count; i++)
                {
                    if (!await Db.Queryable<Ghre_ExamPaper>().AnyAsync(x => x.Id == ExamPaperIds[i] && x.Status == DIC_EXAM_PAPER_STATUS.RELEASED))
                        throw new Exception($"课程关联的试卷已失效，请修正数据后继续发布！");
                }
            }
        }

        //editModel.IsOpen = editModel.IsOPenLabel == true ? "1" : "0";

        var result = await base.Update(Id, editModel);
        return result;
    }

    #region 获取通用列表下拉
    /// <summary>
    /// 获取通用列表下拉
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public async Task<ServiceResult<CommonSelect>> GetSelectAsync(long? linkId, string keyWords)
    {
        var result = new CommonSelect();
        var TableColumn = new JArray();
        var DT_TablePageInfoT1 = new JArray();
        var DT_TableDataT1 = new JArray();
        var searchItem = new JObject();
        JObject item;
        DataTable dt;
        string sql;
        searchItem = new JObject {
            new JProperty("defaultHidden", true),
            new JProperty("field","value"),
            new JProperty("label","课程ID")
        };
        TableColumn.Add(searchItem);
        searchItem = new JObject {
            new JProperty("field","label"),
            new JProperty("label","课程名称")
        };
        TableColumn.Add(searchItem);

        sql = $"SELECT Id,  CourseNo , CourseName FROM Ghre_Course WHERE Status ='{Consts.DIC_COURSE_STATUS.RELEASED}' AND IsEnable=1";
        if (!string.IsNullOrWhiteSpace(keyWords))
            sql += $"AND ( CourseNo like '%{keyWords}%' or CourseName like '%{keyWords}%')";

        if (linkId.HasValue)
            sql += $" AND (CourseSceneId='{linkId}' or CourseSceneIds like '%{linkId}%')";
        sql += $"  ORDER BY UpdateTime DESC, CreateTime DESC";
        dt = await Db.Ado.GetDataTableAsync(sql);

        for (int i = 0; i < dt.Rows.Count; i++)
        {
            item = new JObject {
                new JProperty("value",long.Parse(dt.Rows[i]["Id"].ToString())),
                    new JProperty("label", dt.Rows[i]["CourseName"].ToString() + "("+dt.Rows[i]["CourseNo"].ToString()+")")
                };
            DT_TableDataT1.Add(item);
        }

        item = new JObject {
            new JProperty("ListMax",100),
                new JProperty("ListMin",10),
                new JProperty("PageNum",1),
                new JProperty("PageSize",99999),
                new JProperty("TotalCount",dt.Rows.Count),
                new JProperty("UIType","Auto")
             };
        DT_TablePageInfoT1.Add(item);
        result.JM_TableColumnT1.TableColumn = TableColumn;
        result.DT_TableDataT1 = DT_TableDataT1;
        result.DT_TablePageInfoT1 = DT_TablePageInfoT1;
        return new ServiceResult<CommonSelect>() { Success = true, Message = "查询成功", Data = result, };
    }
    #endregion

    public async Task<ServiceResult<ExcelData>> ExportExcel(QueryExport body, string status)
    {
        QueryBody filter = new QueryBody();
        filter.pageNum = 1;
        filter.pageSize = 1000000;
        filter.langId = body.langId;

        var condition = "1=1";
        var ids = new List<long>();
        if (body.exportSet.SelectRowKeys != null && body.exportSet.SelectRowKeys.Any())
            ids = body.exportSet.SelectRowKeys;

        var data = await QueryList(filter, status, ids);


        string sql = $@"SELECT *
                            FROM Ghrs_PageSettingQuery
                            WHERE     IsEnable = 1
                                  AND PageNo = '{body.menuName}'
                                  AND (defaultHidden = 'false' or defaultHidden is null)
                            ORDER BY SortNo ASC";

        var columns = await Db.Ado.SqlQueryAsync<QueryExportColumn>(sql);

        var fieldDescs = new Dictionary<string, string>();
        if (body.exportSet.ExFields.Any())
            body.exportSet.ExFields.ForEach(x =>
            {
                if (columns.Any(o => o.field == x))
                    fieldDescs.Add(x, columns.FirstOrDefault(o => o.field == x)?.label);
            });
        else
            fieldDescs = columns.ToDictionary(item => item.field, item => item.label);
        var dt = ToDataTable(data.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 + body.exportSet.TitleName + ".xlsx";
        NPOIHelper.ExportExcel(dt, body.exportSet.TitleName, "sheet1", physicsPath + path);
        var result = new ExcelData();
        result.filePath = "/Advanced" + path;
        result.fileName = body.exportSet.TitleName + ".xlsx";
        return ServiceResult<ExcelData>.OprateSuccess("导出成功", result);
    }

    public override async Task<ServiceResult<string>> DownloadExcel(string menuName)
    {
        var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot";
        var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}ExcelTemplate{Path.DirectorySeparatorChar}"}";
        if (!Directory.Exists(physicsPath + path))
            Directory.CreateDirectory(physicsPath + path);

        Type entityType = typeof(Ghre_Course);
        var fileName = entityType.GetEntityTableName() + ".xlsx";
        //physicsPath = physicsPath + path + fileName;

        IWorkbook hssfworkbook;
        ISheet sheet;
        using (FileStream file = new FileStream(physicsPath + path + fileName, FileMode.Open, FileAccess.Read))
        {
            //hssfworkbook = new HSSFWorkbook(file);
            //hssfworkbook = new XSSFWorkbook(file);
            hssfworkbook = WorkbookFactory.Create(file);
        }
        ISheet sheet2 = hssfworkbook.CreateSheet("下拉数据");

        var newFileName = Guid.NewGuid() + ".xlsx";
        int listColIndex = 0;
        //string sql = @"select 'Course' field, Id id, CourseNo no, CourseName name from Ghre_Course where IsEnable=1 and Status='Released'";
        //var dataSourceLists = await Db.Ado.SqlQueryAsync<DataSourceList>(sql);
        //if (dataSourceLists.Any())
        //{
        //    var types = new List<string>
        //    {
        //    "学习记录"
        //    };

        //    types.ForEach(sheetName =>
        //    {
        //        int sheetIndex = hssfworkbook.GetSheetIndex(sheetName);
        //        if (sheetIndex >= 0)
        //        {
        //            sheet = hssfworkbook.GetSheetAt(sheetIndex);

        //            SetCellDropdownList(sheet, 0, 0, dataSourceLists.Select(x => x.name).ToArray());
        //        }

        //    });
        //    MemoryStream ms;
        //    using (ms = new MemoryStream())
        //    {
        //        hssfworkbook.Write(ms);
        //        ms.Flush();
        //        hssfworkbook.Dispose();
        //        //ms.Position = 0;
        //        //return ms;
        //    }
        //    using (FileStream fs = new FileStream(physicsPath + path + newFileName, FileMode.Create, FileAccess.Write))
        //    {
        //        byte[] data = ms.ToArray();
        //        fs.Write(data, 0, data.Length);
        //        fs.Flush();
        //    }

        //}

        var physicsPath1 = physicsPath + path + fileName;
        //if (dataSourceLists.Any())
        //    physicsPath1 = physicsPath + path + newFileName;
        var result = ServiceResult<string>.OprateSuccess("课程管理_" + DateTimeHelper.ConvertToSecondString1(DateTime.Now) + ".xlsx", physicsPath1);
        return result;
    }
    public override async Task<ServiceResult<ExcelData>> ImportExcel(IFormFile file, string menuName = null, long? MasterId = null)
    {
        var data = new ExcelData();
        long id = SnowFlakeSingle.instance.getID();
        var physicsPath = $"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}wwwroot";
        var path = $"{$"{Path.DirectorySeparatorChar}files{Path.DirectorySeparatorChar}import{Path.DirectorySeparatorChar}{id}{Path.DirectorySeparatorChar}"}";
        if (!Directory.Exists(physicsPath + path))
            Directory.CreateDirectory(physicsPath + path);

        var filepath = physicsPath + path + file.FileName;
        using (var stream = File.Create(filepath))
        {
            await file.CopyToAsync(stream);
        }
        string extension = Path.GetExtension(filepath);

        bool isExistError = false;
        var id1 = SnowFlakeSingle.instance.getID();
        string errorFileName = path + SnowFlakeSingle.instance.getID() + extension;

        var dt = NPOIHelper.ImportExcel(filepath, "课程管理");
        if (dt.Columns["Comments"] == null)
            dt.Columns.Add("Comments", typeof(string));

        for (int i = 0; i < dt.Rows.Count; i++)
        {
            var comments = new List<string>();

            if (!dt.Columns.Contains("课程编号（必填）"))
            {
                comments.Add("未查询到【课程编号】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("课程名称（必填）"))
            {
                comments.Add("未查询到【课程名称】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }

            if (!dt.Columns.Contains("课程分类（必填）"))
            {
                comments.Add("未查询到【课程分类】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("课程场景"))
            {
                comments.Add("未查询到【课程场景】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }

            if (!dt.Columns.Contains("标准课时（必填）"))
            {
                comments.Add("未查询到【标准课时】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("学分（必填）"))
            {
                comments.Add("未查询到【学分】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("内/外训"))
            {
                comments.Add("未查询到【内/外训】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("是否公开课（必填）"))
            {
                comments.Add("未查询到【是否公开课】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("培训有效期（月）"))
            {
                comments.Add("未查询到【培训有效期（月）】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("课程大纲"))
            {
                comments.Add("未查询到【课程大纲】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("课前准备"))
            {
                comments.Add("未查询到【课前准备】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (!dt.Columns.Contains("备注"))
            {
                comments.Add("未查询到【备注】列！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }

            var courseNo = dt.Rows[i]["课程编号（必填）"].ToString();
            long? courseClassId = null;
            var courseClass = dt.Rows[i]["课程分类（必填）"].ToString();
            var courseName = dt.Rows[i]["课程名称（必填）"].ToString();
            long? courseSceneId = null;
            var courseScene = dt.Rows[i]["课程场景"].ToString();
            var standardHour = dt.Rows[i]["标准课时（必填）"].ToString();
            var creditPoints = dt.Rows[i]["学分（必填）"].ToString();
            var inOrOut = dt.Rows[i]["内/外训"].ToString();
            var isOPen = dt.Rows[i]["是否公开课（必填）"].ToString();
            var validityPeriod = dt.Rows[i]["培训有效期（月）"].ToString();
            var outline = dt.Rows[i]["课程大纲"].ToString();
            var beforeReady = dt.Rows[i]["课前准备"].ToString();
            var remarkSz = dt.Rows[i]["备注"].ToString();

            if (await base.AnyAsync(x => x.CourseNo == courseNo && x.CourseName == courseName))
            {
                comments.Add($"系统已存在相同编号名称课程数据！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }

            if (courseClass.IsNotEmptyOrNull())
            {
                courseClassId = (await _ghre_CourseClassServices.QuerySingle(x => x.ClassName == courseClass))?.Id;
                if (courseClassId is null)
                    courseClassId = await _ghre_CourseClassServices.Add(new InsertGhre_CourseClassInput()
                    {
                        ClassNo = courseClass,
                        ClassName = courseClass

                    });
            }
            else
            {
                comments.Add($"课程分类为空！");
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }
            if (courseScene.IsNotEmptyOrNull())
            {
                await Db.Queryable<Ghre_CourseScene>().Where(x => x.CourseName == courseScene).FirstAsync();
                courseSceneId = (await Db.Queryable<Ghre_CourseScene>().Where(x => x.CourseName == courseScene).FirstAsync())?.Id;
            }


            if (standardHour.IsNullOrEmpty())
                standardHour = "0";
            if (creditPoints.IsNullOrEmpty())
                creditPoints = "0";

            if (inOrOut.IsNotEmptyOrNull())
            {
                var items = await GetParaList("CourseInOrOut");
                inOrOut = items.Where(x => x.ParaDetailName == inOrOut).FirstOrDefault()?.ParaDetailNo ?? "In";
            }

            if (isOPen.IsNullOrEmpty())
                isOPen = "是";

            List<long?> courseClassId1 = [courseClassId];
            var dict = new Dictionary<string, object>
                {
                    { "Id", SnowFlakeSingle.Instance.NextId() },
                    { "CreateBy", App.User.ID },
                    { "CreateTime", DateTime.Now },
                    { "CourseClassId",JsonHelper.ObjToJson(courseClassId1) },
                    { "CourseNo", courseNo },
                    { "CourseName", courseName },
                    { "CourseSceneId",courseSceneId },
                    { "StandardHour", standardHour },
                    { "CreditPoints", creditPoints },
                    { "InOrOut", inOrOut },
                    { "IsOPen", isOPen=="是" ? true:false },
                    { "ValidityPeriod", validityPeriod },
                    { "Outline", outline },
                    { "BeforeReady", beforeReady },
                    { "Status", "Draft" },
                    { "UseDefaultCoverImage", true },
                    { "DefaultCoverImageName", "defaultCourseCover1" },
                    { "RemarkSz", remarkSz }
                };
            try
            {
                await Db.Insertable(dict).AS("Ghre_Course").ExecuteCommandAsync();
                data.SuccessCount++;
                //data.SuccessCount += list.Count;
            }
            catch (Exception E)
            {
                comments.Add(E.Message);
                data.ErrorCount++;
                dt.Rows[i]["Comments"] = string.Join(";", comments.Select(a => a));
                isExistError = true;
                continue;
            }

        }

        if (isExistError)
        {
            NPOIHelper.ExportExcel(dt, null, "课程管理", physicsPath + errorFileName);
            data.filePath = "/Advanced" + errorFileName;
        }
        return ServiceResult<ExcelData>.OprateSuccess("导入成功！", data);
    }

    #region 获取公开课查询条件
    public async Task<ServiceResult<CoursePublicSearch>> QueryPublicSearchFields(QueryBody body)
    {
        var entity = new CoursePublicSearch();
        string sql = @"SELECT Langkey field,
                       CASE {2}
                          WHEN 1 THEN isnull (Value01, LangValue)
                          WHEN 2 THEN isnull (Value02, LangValue)
                          WHEN 3 THEN isnull (Value03, LangValue)
                          WHEN 4 THEN isnull (Value04, LangValue)
                          WHEN 5 THEN isnull (Value05, LangValue)
                          WHEN 6 THEN isnull (Value06, LangValue)
                          WHEN 7 THEN isnull (Value07, LangValue)
                          WHEN 8 THEN isnull (Value08, LangValue)
                          WHEN 9 THEN isnull (Value09, LangValue)
                          WHEN 10 THEN isnull (Value10, LangValue)
                       END label
                FROM Ghrs_LangKey
                WHERE     IsEnable = 1
                      AND (LangKey LIKE 'GHR_Page%' OR LangKey LIKE 'GHR_Common%')";
        sql = string.Format(sql, body.menuName, App.User.ID, body.langId);
        entity.DT_PageMutiMsg = await Db.Ado.SqlQueryAsync<DT_PageMutiMsg>(sql);
        entity.SearchFields.Add(new CoursePublicSearchField()
        {
            label = "课程编号/名称",
            field = "CourseNoOrName",
            elementType = "Input",
            editable = true,
            required = false,
            multipleSelect = false,
        });
        entity.SearchFields.Add(new CoursePublicSearchField()
        {
            label = "课程分类",
            field = "CourseClassId",
            elementType = "ApiSelect",
            dataSource = "CommonList_TrainingCourseClass",
            editable = true,
            required = false,
            multipleSelect = false,
        });
        entity.SearchFields.Add(new CoursePublicSearchField()
        {
            label = "课程场景",
            field = "CourseSceneId",
            elementType = "ApiSelect",
            dataSource = "CommonList_TrainingCourseScene",
            editable = true,
            required = false,
            multipleSelect = false,
        });
        entity.SearchFields.Add(new CoursePublicSearchField()
        {
            label = "是否学过",
            field = "HasStudy",
            elementType = "ApiSelect",
            dataSource = "TBParaDetail_Train_CourseIsOpen",
            editable = true,
            required = false,
            multipleSelect = false,
        });
        return ServiceResult<CoursePublicSearch>.OprateSuccess("", entity);
    }
    #endregion

    #region 获取公开课
    public async Task<ServicePageResult<CoursePublic>> QueryPublic(QueryBody filter)
    {
        int? staffId = GetStaffId();
        RefAsync<int> totalCount = 0;
        var dt = DateTime.Now.Date;
        string sql = @$"SELECT * FROM (SELECT A.Id,
                               A.CoverUrl,
                               A.PublishTime,
                               A.CourseNo, 
                               A.UseDefaultCoverImage,
                               A.DefaultCoverImageName,
                               A.CourseSceneId,
                               A.CourseClassId,
                               A.CourseName + ' (' + A.CourseNo + ')' CourseName,
                               ISNULL (A.StandardHour, 0) StandardHour,
                               ISNULL (A.CreditPoints, 0) CreditPoints,
                               NULL ExamDate,
                               B.BeginTime ExamBeginDate,
                               B.EndTime ExamEndDate,
                               CAST ('0' AS BIT) DisableBtn,
                               B.DateType,
                               B.AfterHowLong,
                               C.Id StudyRecordId,
                               C.BeginTime StudyBeginTime
                        FROM Ghre_Course A
                             LEFT JOIN Ghre_Exam B
                                ON     A.Id = B.CourseId
                                   AND B.Status = '{DIC_EXAM_STATUS.RELEASED}'
                                   AND B.IsEnable =1
                                   AND (   (    B.DateType = '{DicExamDateType.EXAM_DATE}'
                                            AND B.BeginTime <= '{dt}'
                                            AND B.EndTime >= '{dt}')
                                        OR B.DateType = '{DicExamDateType.AFTER_HOW_LONG}')
                             LEFT JOIN Ghre_StudyRecord C
                                ON     A.Id = C.CourseId
                                   AND C.IsEnable = 1
                                   AND C.StaffId = '{staffId}'
                                   AND C.CourseBeginTime <= '{dt}'
                                   AND C.CourseEndTime >= '{dt}'
                        WHERE     A.IsOpen = 1
                              AND A.IsEnable = 1
                              AND A.Status = '{DIC_COURSE_STATUS.RELEASED}') A";
        //if (await QueryCompanyCode() == "Ushio" && string.IsNullOrWhiteSpace(filter.orderBy))
        //{
        //    filter.orderBy = "PublishTime DESC";
        //}
        //else
        if (string.IsNullOrWhiteSpace(filter.orderBy))
            filter.orderBy = "PublishTime DESC";

        string conditions = " WHERE 1=1";
        if (filter.jsonParam != null)
            foreach (JProperty jProperty in filter.jsonParam.Properties())
            {
                var name = jProperty.Name;
                var value = jProperty.Value.ToString();
                if (name == "page" || name == "pageSize")
                    continue;

                if (name == "CourseNoOrName")
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);
                    conditions += $" AND (CourseNo LIKE '%{jsonParam.columnValue}%' OR CourseName LIKE '%{jsonParam.columnValue}%')";

                    continue;
                }

                if (name == "HasStudy")
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);
                    if (jsonParam.columnValue != null)
                        if (jsonParam.columnValue.ToString() == "1")
                            conditions += $" AND (StudyRecordId IS NOT NULL AND StudyBeginTime IS NOT NULL)";
                        else
                            conditions += $" AND (StudyRecordId IS NULL OR StudyBeginTime IS NULL)";

                    continue;
                }
                if (name == "CourseClassId")
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);
                    conditions += $" AND CourseClassId LIKE '%{jsonParam.columnValue}%' ";

                    continue;
                }

                if (name == "KeyWords")
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);
                    conditions += $" AND CourseName LIKE '%{jsonParam.columnValue}%' ";

                    continue;
                }

                if (!string.IsNullOrWhiteSpace(value))
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);

                    switch (jsonParam.operationKey)
                    {
                        case "Include":
                            conditions += $" AND {name} LIKE '%{jsonParam.columnValue}%'";
                            break;
                        case "NotInclude":
                            conditions += $" AND {name} NOT LIKE '%{jsonParam.columnValue}%'";
                            break;
                        case "IsNull":
                            conditions += $" AND {name} IS NULL";
                            break;
                        case "NotNull":
                            conditions += $" AND {name} IS NOT NULL";
                            break;
                        case "Equal":
                            conditions += $" AND {name} ='{jsonParam.columnValue}'";
                            break;
                        case "NotEqual":
                            conditions += $" AND {name} !='{jsonParam.columnValue}'";
                            break;
                        default:
                            break;
                    }
                }
            }

        //if (ids != null && ids.Any())
        //    conditions += $" AND Id IN({string.Join(",", ids)})";

        sql += conditions;
        if (filter.pageSize == 0)
            filter.pageSize = 10000;
        var data = await Db.SqlQueryable<CoursePublic>(sql)
            .OrderBy(filter.orderBy)
            .ToPageListAsync(filter.pageNum, filter.pageSize, totalCount);

        data.ForEach(x =>
        {
            if (!x.ExamId.IsNull())
            {
                if (x.ExamBeginDate != null && x.ExamEndDate != null && x.DateType == DicExamDateType.EXAM_DATE)
                    x.ExamDateString = DateTimeHelper.ConvertToDayString(x.ExamBeginDate) + " ~ " + DateTimeHelper.ConvertToDayString(x.ExamEndDate);
                else if (x.DateType == DicExamDateType.AFTER_HOW_LONG)
                    x.ExamDateString = $"学完{x.AfterHowLong}天";
            }

            if (!x.StudyRecordId.IsNull())
                x.DisableBtn = true;
        });

        return new ServicePageResult<CoursePublic>(filter.pageNum, totalCount, filter.pageSize, data);
    }
    #endregion

    #region 场景ID获取课程
    public async Task<ServiceResult<List<Ghre_CourseDto>>> QueryBySceneId(long courseSceneId)
    {
        var entitys = await base.Query(x => x.CourseSceneId != null && x.CourseSceneIds.Contains(courseSceneId.ObjToString()) && x.Status == Consts.DIC_COURSE_STATUS.RELEASED);
        var courseWareIds = entitys.Select(x => x.CourseWareId).Distinct().ToList();
        var attachments = await Db.Queryable<Ghre_CourseWareAttachment>().Where(x => courseWareIds.Contains(x.CourseWareId)).ToListAsync();
        //var attachments = await _ghre_CourseWareAttachmentServices.Query(x => x.CourseWareId != null && attachmentIds.Contains(x.CourseWareId.Value));

        var entitys1 = Mapper.Map(entitys).ToANew<List<Ghre_CourseDto>>();
        entitys1.ForEach(x =>
        {
            x.CourseWareName = string.Join(",", attachments.Where(o => o.CourseWareId == x.CourseWareId).OrderBy(x => x.SortNo).Select(o => o.AttachmentName));
        });

        return ServiceResult<List<Ghre_CourseDto>>.OprateSuccess("查询成功", entitys1);
    }
    #endregion

    #region 修改场景下课程顺序
    public async Task<ServiceResult> ModifyCourseSortNo(List<Ghre_Course> courses)
    {
        await Db.Updateable(courses).UpdateColumns(it => new { it.SortNo }).ExecuteCommandAsync();
        return ServiceResult.OprateSuccess("执行成功！");
    }
    #endregion

    #region 查询课程、课程场景
    public async Task<ServicePageResult<CourseAndScene>> QueryCourseAndScene(QueryBody filter)
    {
        RefAsync<int> totalCount = 0;
        string sql = @"SELECT Id,
       CourseNo,
       CourseName, 
       Type from Ghre_CourseScene_V A";

        if (string.IsNullOrWhiteSpace(filter.orderBy))
            filter.orderBy = "CourseNo ASC";

        string conditions = " WHERE 1=1";

        conditions += $"AND dbo.FUserDataBelongPriv ({App.User.ID}, A.DataBelongID, NULL) = 1";

        if (filter.jsonParam != null)
            foreach (JProperty jProperty in filter.jsonParam.Properties())
            {
                var name = jProperty.Name;
                var value = jProperty.Value.ToString();
                if (name == "page" || name == "pageSize")
                    continue;

                if (!string.IsNullOrWhiteSpace(value))
                {
                    var jsonParam = JsonConvert.DeserializeObject<JsonParam>(value);

                    if (name == "CourseNoOrName")
                    {
                        conditions += $" AND ( CourseNo LIKE '%{jsonParam.columnValue}%' OR CourseName LIKE '%{jsonParam.columnValue}%')";
                        continue;
                    }

                    switch (jsonParam.operationKey)
                    {
                        case "Include":
                            conditions += $" AND {name} LIKE '%{jsonParam.columnValue}%'";
                            break;
                        case "NotInclude":
                            conditions += $" AND {name} NOT LIKE '%{jsonParam.columnValue}%'";
                            break;
                        case "IsNull":
                            conditions += $" AND {name} IS NULL";
                            break;
                        case "NotNull":
                            conditions += $" AND {name} IS NOT NULL";
                            break;
                        case "Equal":
                            conditions += $" AND {name} ='{jsonParam.columnValue}'";
                            break;
                        case "NotEqual":
                            conditions += $" AND {name} !='{jsonParam.columnValue}'";
                            break;
                        case "GreaterOrEqual"://大于等于
                            conditions += $" AND {name} >='{jsonParam.columnValue}'";
                            break;
                        case "Greater"://大于
                            conditions += $" AND {name} >'{jsonParam.columnValue}'";
                            break;
                        case "LessOrEqual"://小于等于
                            conditions += $" AND {name} <='{jsonParam.columnValue}'";
                            break;
                        case "Less"://小于
                            conditions += $" AND {name} <'{jsonParam.columnValue}'";
                            break;
                        case "EqualAny":// 
                            if (jsonParam.columnValue != null)
                            {
                                var ids1 = JsonHelper.JsonToObj<List<string>>(jsonParam.columnValue.ToString());

                                conditions += $" AND {name} IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))})";
                            }
                            break;
                        case "NotEqualAny":// 
                            if (jsonParam.columnValue != null)
                            {
                                var ids1 = JsonHelper.JsonToObj<List<string>>(jsonParam.columnValue.ToString());

                                conditions += $" AND ({name} NOT IN ({string.Join(",", ids1.Select(id => "'" + id + "'"))}) OR {name} IS NULL)";
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        if (filter.pageSize == 0)
            filter.pageSize = 10000;
        sql += conditions;
        totalCount = await Db.Ado.GetIntAsync($"SELECT COUNT(0) from ({sql}) A WHERE 1=1");

        var sql1 = GetQueryString(sql, filter.pageNum, filter.pageSize, filter.orderBy);

        var data = DbAccess.QueryList<CourseAndScene>(sql1);

        for (int i = 0; i < data.Count; i++)
        {
            data[i].RequiredCount = await Db.Queryable<Ghre_StudyRecord>()
                .Where(x => (x.CourseSceneId == data[i].Id || x.CourseId == data[i].Id) && x.OpenClassId == null && x.CourseType.Contains("Required"))
                .CountAsync();

            data[i].ElectiveCount = await Db.Queryable<Ghre_StudyRecord>()
                .Where(x => (x.CourseSceneId == data[i].Id || x.CourseId == data[i].Id) && x.OpenClassId == null && x.CourseType.Contains("Elective"))
                .CountAsync();


            data[i].OpenClassCount = await Db.Queryable<Ghre_StudyRecord>()
                .Where(x => (x.CourseSceneId == data[i].Id || x.CourseId == data[i].Id) && x.OpenClassId != null)
                .CountAsync();

            data[i].CompleteCount = await Db.Queryable<Ghre_StudyRecord>()
               .Where(x => (x.CourseSceneId == data[i].Id || x.CourseId == data[i].Id) && x.CompleteStatus == DIC_STUDY_RECORD_STUDY_COMPLETE_STATUS.FINISHED)
               .CountAsync();

            var studyRecordIds = await Db.Queryable<Ghre_StudyRecord>()
               .Where(x => x.CourseSceneId == data[i].Id || x.CourseId == data[i].Id)
               .Select(x => x.Id)
               .ToListAsync();

            data[i].TotalStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>()
                .Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value))
                .SumAsync(x => x.StudyDuration);
            data[i].TotalStudyDuration = data[i].TotalStudyDuration ?? 0;
            if (data[i].TotalStudyDuration > 0)
            {
                var avgStudyDuration = data[i].TotalStudyDuration / (studyRecordIds.Count);

                data[i].AvgStudyDuration = avgStudyDuration.TrimDecimalString(2);
            }

            data[i].AvgScore = await Db.Queryable<Ghre_ExamRecord>()
               .Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value))
               .AvgAsync(x => x.Score);

            data[i].AvgScore = data[i].AvgScore ?? 0;

            if (data[i].AvgScore > 0)
                data[i].AvgScore = data[i].AvgScore.TrimDecimal(2);

            var examCount = await Db.Queryable<Ghre_ExamRecord>()
               .Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value))
               .CountAsync();
            var passCount = await Db.Queryable<Ghre_ExamRecord>()
               .Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value) && x.IsPass == true)
               .CountAsync();
            if (passCount > 0 && examCount > 0)
                data[i].PassPercent = passCount / examCount;
        }



        return new ServicePageResult<CourseAndScene>(filter.pageNum, totalCount, filter.pageSize, data);
    }
    #endregion

    #region 课程统计
    /// <summary>
    /// 课程统计
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<dynamic> QueryStatistic(long id)
    {
        if (!await AnyAsync(x => x.Id == id))
            return await QuerySceneStatistic(id);

        dynamic obj = new ExpandoObject();
        dynamic data = new ExpandoObject();
        var entity = await QueryById(id);

        data.CourseClassName = entity.CourseClassName;
        data.StandardHour = entity.StandardHour;
        data.CreditPoints = entity.CreditPoints;
        data.ManagerStaffName = entity.ManagerStaffName;
        data.InOrOut = entity.InOrOutLabel;
        data.IsOpen = entity.IsOPenLabel;
        data.ValidityPeriod = entity.ValidityPeriod;
        data.CourseSceneName = entity.CourseSceneName;
        data.TeacherName = entity.TeacherName;
        data.Type = "Course";

        //必修人数
        var RequiredCount = await Db.Queryable<Ghre_StudyRecord>().Where(x => x.CourseId == id && (x.CourseType == "ManualRequired" || x.CourseType == "Required")).CountAsync();
        data.RequiredCount = RequiredCount;

        //选修人次
        var ElectiveCount = await Db.Queryable<Ghre_StudyRecord>().Where(x => x.CourseId == id && (x.CourseType == "ManualElective" || x.CourseType == "Elective")).CountAsync();
        data.ElectiveCount = ElectiveCount;

        var CompleteCount = await Db.Queryable<Ghre_StudyRecord>().Where(x => x.CourseId == id && x.CompleteStatus == DIC_STUDY_RECORD_STUDY_COMPLETE_STATUS.FINISHED && (x.CourseType == "ManualElective" || x.CourseType == "Elective" || x.CourseType == "ManualElective" || x.CourseType == "Elective")).CountAsync();
        //完成人数
        data.CompleteCount = CompleteCount;
        //开班人数
        var OpenClassCount = await Db.Queryable<Ghre_StudyRecord>()
            .Where(x => x.CourseId == id && x.OpenClassId != null)
            .CountAsync();
        data.OpenClassCount = OpenClassCount;

        var studyRecordIds = await Db.Queryable<Ghre_StudyRecord>().Where(x => x.CourseId == id).Select(x => x.Id).ToListAsync();
        //总学习时长
        data.TotalStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>().Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value)).SumAsync(x => x.StudyDuration);

        var AvgStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>().Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value)).GroupBy(x => x.StaffId)
                    .Select(m => new { m.StaffId, StudyDuration = SqlFunc.AggregateSum(m.StudyDuration) }).ToListAsync();
        //平均学习时长
        var AvgStudyDuration1 = AvgStudyDuration.Average(x => x.StudyDuration);
        if (AvgStudyDuration1 != null)
        {

            var AvgStudyDuration2 = AvgStudyDuration1.TrimDecimalString(2);
            data.AvgStudyDuration = UtilHelper.RemoveZero(Convert.ToDecimal(AvgStudyDuration2));
        }
        else data.AvgStudyDuration = 0;
        //平均分
        var AvgScore = await Db.Queryable<Ghre_ExamRecord>().Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value)).AvgAsync(x => x.FinallyScore ?? (x.Score + x.AdjustScore));
        data.AvgScore = AvgScore ?? 0;

        //通过率
        var passPercent = 0;

        if (CompleteCount > 0 && (RequiredCount + ElectiveCount + OpenClassCount) > 0)
            passPercent = CompleteCount / (RequiredCount + ElectiveCount + OpenClassCount);
        data.PassPercent = passPercent;

        //考试安排次数
        data.ExamScheduleCount = await Db.Queryable<Ghre_Exam>().Where(x => x.CourseId == id).CountAsync();

        //考试人数
        data.ExamCount = await Db.Queryable<Ghre_ExamRecord>().Where(x => x.CourseId == id).CountAsync();

        //考试人次
        data.ExamGroupCount = await Db.Queryable<Ghre_ExamRecordGroup>()
            .Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value))
            .CountAsync();

        //反馈人数
        data.FeedbackCount = 0;

        #region 课件学习时长
        var courseWareStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>()
            .Where(a => a.StudyRecordId != null && studyRecordIds.Contains(a.StudyRecordId.Value))

            .GroupBy(a => new { a.CourseWareId, a.CourseWareAttachmentId })
                    .Select(a => new
                    {
                        a.CourseWareId,
                        a.CourseWareAttachmentId,
                        StudyDuration = SqlFunc.AggregateSum(a.StudyDuration)
                    })
                    .ToListAsync();

        var courseWareStudyDurations = new JArray();

        for (int i = 0; i < courseWareStudyDuration.Count; i++)
        {
            var courseWare = await Db.Queryable<Ghre_CourseWare>().Where(x => x.Id == courseWareStudyDuration[i].CourseWareId).FirstAsync();
            var courseWareAttachment = await Db.Queryable<Ghre_CourseWareAttachment>().Where(x => x.Id == courseWareStudyDuration[i].CourseWareAttachmentId).FirstAsync();
            var item = new JObject
            {
                new JProperty("CourseWareId", courseWareStudyDuration[i].CourseWareAttachmentId),
                new JProperty("CourseWareAttachmentId", courseWareStudyDuration[i].CourseWareAttachmentId),
                new JProperty("StudyDuration", courseWareStudyDuration[i].StudyDuration),
                new JProperty("CourseWareName", courseWare?.CourseWareNo+courseWare?.CourseWareName+courseWare?.VersionNo+courseWareAttachment.AttachmentName),
            };
            courseWareStudyDurations.Add(item);
        }
        data.CourseWareStudyDurations = courseWareStudyDurations;
        #endregion

        #region 课件学习人数占比
        var courseWareStudyCount1 = await Db.Queryable<Ghre_StudyRecordDetail>()
            .Where(a => a.StudyRecordId != null && studyRecordIds.Contains(a.StudyRecordId.Value))
            .Select(a => new { a.CourseWareAttachmentId, a.StaffId })
            .Distinct().ToListAsync();
        var courseWareStudyCount = courseWareStudyCount1
            .GroupBy(a => a.CourseWareAttachmentId)
            .Select(a => new
            {
                CourseWareAttachmentId = a.Key,
                Count = a.Count()
            })
            .ToList();

        var courseWareStudyCounts = new JArray();

        for (int i = 0; i < courseWareStudyCount.Count; i++)
        {
            var courseWareAttachment = await Db.Queryable<Ghre_CourseWareAttachment>().Where(x => x.Id == courseWareStudyCount[i].CourseWareAttachmentId).FirstAsync();
            var item = new JObject
            {
                new JProperty("CourseWareAttachmentId", courseWareStudyCount[i].CourseWareAttachmentId),
                new JProperty("CourseWareName",  courseWareAttachment.AttachmentName),
                new JProperty("Count",  courseWareStudyCount[i].Count),
            };
            courseWareStudyCounts.Add(item);
        }
        data.CourseWareStudyCounts = courseWareStudyCounts;
        #endregion

        #region 关联的考试排行
        var exams = await Db.Queryable<Ghre_Exam>()
            .LeftJoin<Ghre_ExamPaper>((a, b) => a.ExamPaperId == b.Id)//多个条件用&&
            .Where(a => a.CourseId == id && a.Status != "Draft")
            .Select((a, b) => new
            {
                a.Id,
                a.ExamNo,
                a.ExamName,
                b.PaperName
            })
            .ToListAsync();
        var examRankings = new JArray();

        for (int i = 0; i < exams.Count; i++)
        {

            var groups = await Db.Queryable<Ghre_ExamRecordGroup>().Where(x => x.ExamId == exams[i].Id).CountAsync();
            var examRecordCount = await Db.Queryable<Ghre_ExamRecord>().Where(x => x.ExamId == exams[i].Id).CountAsync();
            var examRecordPassCount = await Db.Queryable<Ghre_ExamRecord>()
                .Where(x => x.ExamId == exams[i].Id && x.IsPass == true && x.IsPass != null)
                .CountAsync();
            var examRecordRetakeCount = await Db.Queryable<Ghre_ExamRecord>()
                .Where(x => x.ExamId == exams[i].Id && x.RetakeTimes > 0 && x.RetakeTimes != null)
                .CountAsync();

            passPercent = 0;
            var retakePercent = 0;

            if (examRecordCount > 0)
            {
                if (examRecordPassCount > 0) passPercent = (examRecordPassCount / examRecordCount) * 100;
                if (examRecordRetakeCount > 0) retakePercent = (examRecordRetakeCount / examRecordCount) * 100;
            }

            var item = new JObject
            {
                new JProperty("ExamName", $"{exams[i].ExamName}（{exams[i].ExamNo}）" ),
                new JProperty("PaperName",  exams[i].PaperName),
                new JProperty("Attempts", groups),
                new JProperty("PassPercent", passPercent),
                new JProperty("RetakePercent", retakePercent), 
                //new JProperty("CourseWareName",  courseWareAttachment.AttachmentName),
            };
            examRankings.Add(item);
        }
        data.ExamRankings = examRankings;
        #endregion

        #region 错误率排名 

        var questionErrorRankings = await Db.Queryable<Ghre_Question>()
            .Where(x => x.CourseId == id || x.CourseIds.Contains(id.ToString()))
            .Select(x => new QuestionErrorRanking
            {
                Id = x.Id,
                QuestionNo = x.QuestionNo,
                QuestionContent = x.QuestionContent
            })
            .ToListAsync();

        var questionIds = questionErrorRankings.Select(x => x.Id).ToList();

        var recordDetails = await Db.Queryable<Ghre_ExamRecordDetail>()
            .Where(x => x.QuestionId != null && questionIds.Contains(x.QuestionId.Value))
            .ToListAsync();

        for (int i = 0; i < questionErrorRankings.Count; i++)
        {
            questionErrorRankings[i].QuestionContent = WebUtility.HtmlDecode(questionErrorRankings[i].QuestionContent);
            questionErrorRankings[i].TotalCount = recordDetails.Where(x => x.QuestionId == questionErrorRankings[i].Id).Count();
            questionErrorRankings[i].ErrorCount = recordDetails.Where(x => x.QuestionId == questionErrorRankings[i].Id && x.IsCorrect != true).Count();

            if (questionErrorRankings[i].ErrorCount > 0 && questionErrorRankings[i].TotalCount > 0)
            {

                decimal? Percent1 = questionErrorRankings[i].ErrorCount / questionErrorRankings[i].TotalCount;
                questionErrorRankings[i].Percent1 = Percent1.TrimDecimalString(2);
                questionErrorRankings[i].Percent = Convert.ToDecimal((Percent1 * 100).TrimDecimalString(0));
            }
        }
        questionErrorRankings = questionErrorRankings.OrderByDescending(x => x.Percent).ToList();
        data.QuestionErrorRankings = questionErrorRankings;

        #endregion

        obj.Data = data;
        obj.Success = true;
        obj.Status = 200;
        obj.Message = "查询成功！";
        return obj;
    }
    #endregion

    #region 课程场景统计
    /// <summary>
    /// 课程场景统计
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public async Task<dynamic> QuerySceneStatistic(long id)
    {

        dynamic obj = new ExpandoObject();
        dynamic data = new ExpandoObject();
        var entity = await Db.Queryable<Ghre_CourseScene>().Where(x => x.Id == id).FirstAsync();

        var Courses = await Db.Queryable<Ghre_Course>()
            .Where(x => x.CourseSceneId == id || x.CourseSceneIds.Contains(id.ToString()))
            .Select(x => new { x.Id, x.CourseNo, x.CourseName })
            .ToListAsync();
        var courseIds = Courses.Select(x => x.Id).ToList();
        data.Courses = Courses;
        data.StandardHour = entity.StandardHour;
        data.CreditPoints = entity.CreditPoints;
        data.Type = "CourseScene";

        //必修人数
        var RequiredCount = await Db.Queryable<Ghre_StudyRecord>()
            .Where(x => x.CourseSceneId == id && (x.CourseType == "ManualRequired" || x.CourseType == "Required"))
            .CountAsync();
        data.RequiredCount = RequiredCount;

        //选修人次
        var ElectiveCount = await Db.Queryable<Ghre_StudyRecord>()
            .Where(x => x.CourseSceneId == id && (x.CourseType == "ManualElective" || x.CourseType == "Elective")).CountAsync();
        data.ElectiveCount = ElectiveCount;

        var CompleteCount = await Db.Queryable<Ghre_StudyRecord>().Where(x => x.CourseSceneId == id && x.CompleteStatus == DIC_STUDY_RECORD_STUDY_COMPLETE_STATUS.FINISHED && (x.CourseType == "ManualElective" || x.CourseType == "Elective" || x.CourseType == "ManualElective" || x.CourseType == "Elective")).CountAsync();
        //完成人数
        data.CompleteCount = CompleteCount;
        //开班人数
        var OpenClassCount = await Db.Queryable<Ghre_StudyRecord>()
            .Where(x => x.CourseSceneId == id && x.OpenClassId != null)
            .CountAsync();
        data.OpenClassCount = OpenClassCount;

        var studyRecordIds = await Db.Queryable<Ghre_StudyRecord>().Where(x => x.CourseSceneId == id).Select(x => x.Id).ToListAsync();
        //总学习时长
        data.TotalStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>().Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value)).SumAsync(x => x.StudyDuration);

        var AvgStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>().Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value)).GroupBy(x => x.StaffId)
                    .Select(m => new { m.StaffId, StudyDuration = SqlFunc.AggregateSum(m.StudyDuration) }).ToListAsync();
        //平均学习时长
        //平均学习时长
        var AvgStudyDuration1 = AvgStudyDuration.Average(x => x.StudyDuration);
        if (AvgStudyDuration1 != null)
        {

            var AvgStudyDuration2 = AvgStudyDuration1.TrimDecimalString(2);
            data.AvgStudyDuration = UtilHelper.RemoveZero(Convert.ToDecimal(AvgStudyDuration2));
        }
        else data.AvgStudyDuration = 0;
        //平均分
        var AvgScore = await Db.Queryable<Ghre_ExamRecord>().Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value)).AvgAsync(x => x.FinallyScore ?? (x.Score + x.AdjustScore));
        data.AvgScore = AvgScore ?? 0;

        //通过率
        var passPercent = 0;

        if (CompleteCount > 0 && (RequiredCount + ElectiveCount + OpenClassCount) > 0)
            passPercent = CompleteCount / (RequiredCount + ElectiveCount + OpenClassCount);
        data.PassPercent = passPercent;

        //考试安排次数
        data.ExamScheduleCount = await Db.Queryable<Ghre_Exam>().Where(x => x.CourseSceneId == id).CountAsync();

        //考试人数
        data.ExamCount = await Db.Queryable<Ghre_ExamRecord>().Where(x => x.CourseSceneId == id).CountAsync();

        //考试人次
        data.ExamGroupCount = await Db.Queryable<Ghre_ExamRecordGroup>()
            .Where(x => x.StudyRecordId != null && studyRecordIds.Contains(x.StudyRecordId.Value))
            .CountAsync();

        //反馈人数
        data.FeedbackCount = 0;

        #region 课件学习时长
        var courseWareStudyDuration = await Db.Queryable<Ghre_StudyRecordDetail>()
            .Where(a => a.StudyRecordId != null && studyRecordIds.Contains(a.StudyRecordId.Value))

            .GroupBy(a => new { a.CourseWareId, a.CourseWareAttachmentId })
                    .Select(a => new
                    {
                        a.CourseWareId,
                        a.CourseWareAttachmentId,
                        StudyDuration = SqlFunc.AggregateSum(a.StudyDuration)
                    })
                    .ToListAsync();

        var courseWareStudyDurations = new JArray();

        for (int i = 0; i < courseWareStudyDuration.Count; i++)
        {
            var courseWare = await Db.Queryable<Ghre_CourseWare>().Where(x => x.Id == courseWareStudyDuration[i].CourseWareId).FirstAsync();
            var courseWareAttachment = await Db.Queryable<Ghre_CourseWareAttachment>().Where(x => x.Id == courseWareStudyDuration[i].CourseWareAttachmentId).FirstAsync();
            var item = new JObject
            {
                new JProperty("CourseWareId", courseWareStudyDuration[i].CourseWareAttachmentId),
                new JProperty("CourseWareAttachmentId", courseWareStudyDuration[i].CourseWareAttachmentId),
                new JProperty("StudyDuration", courseWareStudyDuration[i].StudyDuration),
                new JProperty("CourseWareName", courseWare?.CourseWareNo+courseWare?.CourseWareName+courseWare?.VersionNo+courseWareAttachment.AttachmentName),
            };
            courseWareStudyDurations.Add(item);
        }
        data.CourseWareStudyDurations = courseWareStudyDurations;
        #endregion

        #region 课件学习人数占比
        var courseWareStudyCount1 = await Db.Queryable<Ghre_StudyRecordDetail>()
            .Where(a => a.StudyRecordId != null && studyRecordIds.Contains(a.StudyRecordId.Value))
            .Select(a => new { a.CourseWareAttachmentId, a.StaffId })
            .Distinct().ToListAsync();
        var courseWareStudyCount = courseWareStudyCount1
            .GroupBy(a => a.CourseWareAttachmentId)
            .Select(a => new
            {
                CourseWareAttachmentId = a.Key,
                Count = a.Count()
            })
            .ToList();

        var courseWareStudyCounts = new JArray();

        for (int i = 0; i < courseWareStudyCount.Count; i++)
        {
            var courseWareAttachment = await Db.Queryable<Ghre_CourseWareAttachment>().Where(x => x.Id == courseWareStudyCount[i].CourseWareAttachmentId).FirstAsync();
            var item = new JObject
            {
                new JProperty("CourseWareAttachmentId", courseWareStudyCount[i].CourseWareAttachmentId),
                new JProperty("CourseWareName",  courseWareAttachment.AttachmentName),
                new JProperty("Count",  courseWareStudyCount[i].Count),
            };
            courseWareStudyCounts.Add(item);
        }
        data.CourseWareStudyCounts = courseWareStudyCounts;
        #endregion

        #region 关联的考试排行
        var exams = await Db.Queryable<Ghre_Exam>()
            .LeftJoin<Ghre_ExamPaper>((a, b) => a.ExamPaperId == b.Id)//多个条件用&&
            .Where(a => a.CourseSceneId == id && a.Status != "Draft")
            .Select((a, b) => new
            {
                a.Id,
                a.ExamNo,
                a.ExamName,
                b.PaperName
            })
            .ToListAsync();
        var examRankings = new JArray();

        for (int i = 0; i < exams.Count; i++)
        {

            var groups = await Db.Queryable<Ghre_ExamRecordGroup>().Where(x => x.ExamId == exams[i].Id).CountAsync();
            var examRecordCount = await Db.Queryable<Ghre_ExamRecord>().Where(x => x.ExamId == exams[i].Id).CountAsync();
            var examRecordPassCount = await Db.Queryable<Ghre_ExamRecord>()
                .Where(x => x.ExamId == exams[i].Id && x.IsPass == true && x.IsPass != null)
                .CountAsync();
            var examRecordRetakeCount = await Db.Queryable<Ghre_ExamRecord>()
                .Where(x => x.ExamId == exams[i].Id && x.RetakeTimes > 0 && x.RetakeTimes != null)
                .CountAsync();

            passPercent = 0;
            var retakePercent = 0;

            if (examRecordCount > 0)
            {
                if (examRecordPassCount > 0) passPercent = (examRecordPassCount / examRecordCount) * 100;
                if (examRecordRetakeCount > 0) retakePercent = (examRecordRetakeCount / examRecordCount) * 100;
            }

            var item = new JObject
            {
                new JProperty("ExamName", $"{exams[i].ExamName}（{exams[i].ExamNo}）" ),
                new JProperty("PaperName",  exams[i].PaperName),
                new JProperty("Attempts", groups),
                new JProperty("PassPercent", passPercent),
                new JProperty("RetakePercent", retakePercent), 
                //new JProperty("CourseWareName",  courseWareAttachment.AttachmentName),
            };
            examRankings.Add(item);
        }
        data.ExamRankings = examRankings;
        #endregion

        #region 错误率排名 

        var exp = Expressionable.Create<Ghre_Question>();

        courseIds.ForEach(id1 =>
        {
            exp.Or(x => x.CourseId == id1 || x.CourseIds.Contains(id1.ToString()));
        });
        var questionErrorRankings = await Db.Queryable<Ghre_Question>()
            .Where(exp.ToExpression())
            .Select(x => new QuestionErrorRanking
            {
                Id = x.Id,
                QuestionNo = x.QuestionNo,
                QuestionContent = x.QuestionContent
            })
            .ToListAsync();

        var questionIds = questionErrorRankings.Select(x => x.Id).ToList();

        var recordDetails = await Db.Queryable<Ghre_ExamRecordDetail>()
            .Where(x => x.QuestionId != null && questionIds.Contains(x.QuestionId.Value))
            .ToListAsync();

        for (int i = 0; i < questionErrorRankings.Count; i++)
        {
            questionErrorRankings[i].QuestionContent = WebUtility.HtmlDecode(questionErrorRankings[i].QuestionContent);
            questionErrorRankings[i].TotalCount = recordDetails.Where(x => x.QuestionId == questionErrorRankings[i].Id).Count();
            questionErrorRankings[i].ErrorCount = recordDetails.Where(x => x.QuestionId == questionErrorRankings[i].Id && x.IsCorrect != true).Count();

            if (questionErrorRankings[i].ErrorCount > 0 && questionErrorRankings[i].TotalCount > 0)
            {

                decimal? Percent1 = questionErrorRankings[i].ErrorCount / questionErrorRankings[i].TotalCount;
                questionErrorRankings[i].Percent1 = Percent1.TrimDecimalString(2);
                questionErrorRankings[i].Percent = Convert.ToDecimal((Percent1 * 100).TrimDecimalString(0));
            }
        }
        questionErrorRankings = questionErrorRankings.OrderByDescending(x => x.Percent).ToList();
        data.QuestionErrorRankings = questionErrorRankings;

        #endregion

        obj.Data = data;
        obj.Success = true;
        obj.Status = 200;
        obj.Message = "查询成功！";
        return obj;
    }
    #endregion
}