import { CourseScoreInfo , CurrentSemesterStudentAcademicInfo , CourseScheduleInfoDTO , CourseScheduleInfo } from '../types' ; import { pipe , map } from 'ramda' ; import { APIAllPassingScoresDTO , APIAllPassingScoresDTOLnCj , APISubitemScoreFxcjDTO , APISubitemScoreLookDTO , APITeachingAssessmentEvaluationQueryAllResult , SubitemScoreRecord , TeachingAssessmentEvaluationRecord , TermScoresData } from './result.interface' ; import { getLevelCodeByScore , getLevelNameByScore , getPointByScore } from '@/plugins/score/utils' ; import { Num , sleep } from '@/helper/util' ; import { getChineseNumber } from '@/helper/getter' ; import { Logger } from '@/helper/logger' ; import { getExamTypeNameByCode , getPageHTML , getThisTermScoresDataURL , LoadHTMLToDealWithError } from './utils' ; const requestTeachingAssessmentEvaluationQueryAll = async ( { pageNum , pageSize , flag } ) : Promise < APITeachingAssessmentEvaluationQueryAllResult > => await $ . post ( '/student/teachingAssessment/evaluation/queryAll' , { pageNum , pageSize , flag } ) ; const requestTeachingAssessmentEvaluationRecords = async ( type ) : Promise < TeachingAssessmentEvaluationRecord [ ] > => { const flag = type === '期末评教' ? 'kt' : type === '课堂及时评教' ? 'ktjs' : null ; if ( ! flag ) { throw new Error ( `[教学评估查询] 错误的查询类型: ${ type }` ) ; } const probeRes = await requestTeachingAssessmentEvaluationQueryAll ( { pageNum : 1 , pageSize : 1 , flag } ) ; if ( probeRes . status !== 200 || probeRes . msg !== 'OK' || ! probeRes ?. data ?. records ) { throw new Error ( `[教学评估查询] teachingAssessment/evaluation/queryAll 探针返回值错误: ${ JSON . stringify ( probeRes ) }` ) ; } const { data : { pageContext : { totalCount : pageSize } } } = probeRes ; const res = await requestTeachingAssessmentEvaluationQueryAll ( { pageNum : 1 , pageSize , flag } ) ; if ( res . status !== 200 || res . msg !== 'OK' || ! res ?. data ?. records ) { throw new Error ( `[教学评估查询] teachingAssessment/evaluation/queryAll 返回值错误: ${ JSON . stringify ( res ) }` ) ; } const { data : { records } } = res ; const convert = ( list ) : TeachingAssessmentEvaluationRecord [ ] => list . map ( ( { KTID , LSRXM , WJBM , ZXJXJHH , KCH , KXH , SFPG , JKRQ , WJMC , YXDCPG , PGLXDM , JKKG , JKPGTS , KCM , PGID , RN } ) => ( { courseId : KTID , teacherName : LSRXM , questionnaireId : WJBM , executiveEducationPlanNumber : ZXJXJHH , courseNumber : KCH , courseSequenceNumber : KXH , isEvaluated : Boolean ( Num ( SFPG ) ) , courseEndDate : JKRQ , questionnaireName : WJMC , allowMultipleEvaluations : Boolean ( Num ( YXDCPG ) ) , evaluationTypeCode : PGLXDM , JKKG , JKPGTS : JKPGTS , courseName : KCM , evaluationId : PGID , recordNumber : RN } ) ) ; return convert ( records ) ; } ; const requestTeachingEvaluationPageHTML = async ( courseId ) : Promise < string > => { const url = `/student/teachingEvaluation/newEvaluation/evaluation/${ courseId }` ; const html = await getPageHTML ( url ) ; return html ; } ; async function requestStudentSemesterNumberList ( ) { const url = '/student/courseSelect/calendarSemesterCurriculum/index' ; const rawHTML = await getPageHTML ( url ) ; const codeList = Array . from ( $ ( '#planCode' , rawHTML ) . find ( 'option' ) ) . map ( v => $ ( v ) . val ( ) as string ) ; return codeList ; } async function requestStudentInfo ( ) { const url = '/student/rollManagement/rollInfo/index' ; const rawHTML = await getPageHTML ( url ) ; const programPlanNumber = $ ( '#zx' , rawHTML ) . val ( ) as string ; const programPlanName = $ ( '#zx' , rawHTML ) . parent ( ) . text ( ) . trim ( ) ; const infos = Array . from ( $ ( '.profile-info-row' , rawHTML ) ) . map ( ( v ) : HTMLElement [ ] [ ] => { const num = $ ( v ) . children ( '.profile-info-name' ) . length ; if ( num === 1 ) { return [ [ $ ( v ) . children ( '.profile-info-name' ) [ 0 ] as HTMLElement , $ ( v ) . children ( '.profile-info-value' ) [ 0 ] as HTMLElement ] ] ; } else if ( num === 2 ) { return [ [ $ ( v ) . children ( '.profile-info-name' ) [ 0 ] as HTMLElement , $ ( v ) . children ( '.profile-info-value' ) [ 0 ] as HTMLElement ] , [ $ ( v ) . children ( '.profile-info-name' ) [ 1 ] as HTMLElement , $ ( v ) . children ( '.profile-info-value' ) [ 1 ] as HTMLElement ] ] ; } return [ [ ] ] ; } ) . flat ( 1 ) . filter ( v => v . length ) . map ( v => v . map ( element => $ ( element ) . text ( ) . trim ( ) ) ) . filter ( v => v [ 0 ] ) . concat ( [ [ '培养方案名称' , programPlanName ] , [ '培养方案代码' , programPlanNumber ] ] ) ; return new Map ( infos as [ string , string ] [ ] ) ; } const QUERY_TIME_INTERVAL = 5000 ; let robustnessAdditionalInterval = 1000 ; let lastTimeScheduleQuery = new Date ( ) . getTime ( ) ; let currentcourseNameScheduleQuery = '' ; let currentcourseNumberScheduleQuery = '' ; async function requestCourseSchedule ( semester , courseName , courseNumber ) { currentcourseNameScheduleQuery = courseName ; currentcourseNumberScheduleQuery = courseNumber ; const delta = new Date ( ) . getTime ( ) - lastTimeScheduleQuery ; if ( delta < QUERY_TIME_INTERVAL ) { await sleep ( QUERY_TIME_INTERVAL - delta + robustnessAdditionalInterval ) ; } if ( currentcourseNameScheduleQuery === courseName && currentcourseNumberScheduleQuery === courseNumber ) { lastTimeScheduleQuery = new Date ( ) . getTime ( ) ; const res = await $ . post ( '/student/integratedQuery/course/courseSchdule/courseInfo' , { zxjxjhh : semester , kch : courseNumber , kcm : courseName , pageNum : 1 , pageSize : 1000 } ) ; if ( ! res . list ) { robustnessAdditionalInterval *= 2 ; return { response : 'network_error' } ; } return { response : '' , sequence : res . list . records . map ( ( { kcm , kch , kxh , kkxsh , kkxsjc , xf , kclbdm , kclbmc , kslxdm , kslxmc , skjs , zcsm , skxq , skjc , xqm , jxlm , jasm , bkskrl , bkskyl , xkxzsm } ) => ( { courseName : kcm || '' , courseNumber : kch || '' , courseSequenceNumber : kxh || '' , courseDeptNumber : kkxsh || '' , courseDeptName : kkxsjc || '' , credit : xf || 0 , courseCategoryCode : kclbdm || '' , courseCategoryName : kclbmc || '' , examTypeCode : kslxdm || '' , examTypeName : kslxmc || '' , courseTeacher : skjs || '' , courseTime : `${ zcsm }星期${ getChineseNumber ( skxq ) }${ skjc }节` , campusName : `${ xqm }校区${ jxlm }${ jasm }` , classCapacityRemaining : `${ bkskyl } / ${ bkskrl }` , courseRegNote : xkxzsm && xkxzsm !== ';' ? xkxzsm : '' } ) ) . reduce ( ( acc , cur ) => { let index = - 1 ; for ( let i = 0 ; i < acc . length ; i ++ ) { if ( acc [ i ] . courseSequenceNumber === cur . courseSequenceNumber ) { index = i ; break ; } } const merge = ( obj1 , obj2 ) : CourseScheduleInfo => { const result = { } as CourseScheduleInfo ; for ( const key in obj1 ) { result [ key ] = obj1 [ key ] === obj2 [ key ] ? obj1 [ key ] : `${ obj1 [ key ] }，${ obj2 [ key ] }` ; } return result ; } ; if ( index === - 1 ) { return acc . concat ( cur ) ; } acc [ index ] = merge ( acc [ index ] , cur ) ; return acc ; } , [ ] as CourseScheduleInfo [ ] ) . sort ( ( a , b ) => Num ( a . courseSequenceNumber ) - Num ( b . courseSequenceNumber ) ) } ; } return { response : 'no_render' } ; } async function requestCurrentSemesterStudentAcademicInfo ( ) { const [ { zxjxjhh : currentSemester , gpa , courseNum : courseNumber , courseNum_bxqyxd : currentSemesterCourseNumber , coursePas : failedCourseNumber } ] = JSON . parse ( await $ . post ( '/main/academicInfo' ) ) ; return { courseNumber , currentSemester , gpa , currentSemesterCourseNumber , failedCourseNumber } ; } function convertSemesterNumberToText ( number ) { const r = number . match ( /(\d+)-(\d+)-(.+)/ ) ; if ( r ) { const begin = r [ 1 ] ; const end = r [ 2 ] ; const season = r [ 3 ] === '1-1' ? '秋' : '春' ; return `${ begin }-${ end }学年 ${ season }季学期` ; } return number ; } function filterCourseScoreInfoList ( list ) { return ( list . filter ( v => v . inputStatusCode === '05' ) . filter ( v => v . courseScore ) ) ; } export async function requestAllPassingScores ( ) { const url = '/student/integratedQuery/scoreQuery/allPassingScores/callback' ; try { const { lnList } = ( await $ . get ( url ) ) as APIAllPassingScoresDTO ; const records = lnList . reduce ( ( acc , cur ) => acc . concat ( cur . cjList ) , [ ] as APIAllPassingScoresDTOLnCj [ ] ) ; const formatRecord = ( { id : { executiveEducationPlanNumber , courseNumber , coureSequenceNumber : courseSequenceNumber } , examTime , entryStatusCode : inputStatusCode , courseAttributeCode : coursePropertyCode , examTypeCode , scoreEntryModeCode : inputMethodCode , courseScore , gradeScore : levelCode , notByReasonCode : unpassedReasonCode , notByReasonName : unpassedReasonExplain , courseName , englishCourseName , credit , cycle : studyHour , gradeName : levelName , courseAttributeName : coursePropertyName , gradePointScore } ) : CourseScoreInfo => ( { executiveEducationPlanNumber , executiveEducationPlanName : convertSemesterNumberToText ( executiveEducationPlanNumber ) , courseNumber , courseSequenceNumber , examTime , inputStatusCode , coursePropertyCode , examTypeCode , inputMethodCode , courseScore , levelCode : levelCode ?. toString ( ) || getLevelCodeByScore ( courseScore , executiveEducationPlanNumber ) , unpassedReasonCode , courseName , englishCourseName , credit : Num ( credit ) , studyHour : Num ( studyHour ) , coursePropertyName , examTypeName : getExamTypeNameByCode ( examTypeCode ) , levelName : levelName || getLevelNameByScore ( courseScore , executiveEducationPlanNumber ) , unpassedReasonExplain , gradePoint : gradePointScore || getPointByScore ( courseScore , executiveEducationPlanNumber ) } ) ; return pipe ( map ( formatRecord ) , filterCourseScoreInfoList ) ( records ) ; } catch ( error ) { console . log ( error ) ; throw new Error ( String ( error ) ) ; } } async function requestThisTermCourseScoreInfoList ( ) { const url = await getThisTermScoresDataURL ( ) ; try { const data = await $ . get ( url ) ; const [ { list } ] = data ; const res = filterCourseScoreInfoList ( list . map ( v => ( { courseName : v . courseName || '' , englishCourseName : v . englishCourseName || '' , courseNumber : v . id . courseNumber || '' , courseSequenceNumber : v . coureSequenceNumber || '' , credit : Num ( v . credit ) || 0 , coursePropertyCode : v . coursePropertyCode || '' , coursePropertyName : v . coursePropertyName || '' , maxScore : Num ( v . maxcj ) || 0 , avgScore : Num ( v . avgcj ) || 0 , minScore : Num ( v . mincj ) || 0 , courseScore : Num ( v . courseScore ) || 0 , levelCode : v . levlePoint || getLevelCodeByScore ( Num ( v . courseScore ) || 0 , v . id . executiveEducationPlanNumber || '' ) || '' , levelName : v . levelName || getLevelNameByScore ( Num ( v . courseScore ) || 0 , v . id . executiveEducationPlanNumber || '' ) || '' , gradePoint : Num ( v . gradePoint ) || 0 , rank : Num ( v . rank ) || 0 , examTime : v . id . examtime || '' , unpassedReasonCode : v . unpassedReasonCode || '' , unpassedReasonExplain : v . unpassedReasonExplain || '' , executiveEducationPlanNumber : v . id . executiveEducationPlanNumber || '' , executiveEducationPlanName : convertSemesterNumberToText ( v . id . executiveEducationPlanNumber ) || '' , inputStatusCode : v . inputStatusCode || '' , inputMethodCode : v . inputMethodCode || '' , studyHour : Num ( v . studyHour ) || 0 , examTypeName : v . examTypeName || '' } as CourseScoreInfo ) ) ) ; return res ; } catch ( error ) { const { title , message , html } = await LoadHTMLToDealWithError ( url ) ; Logger . error ( { title , message , html } ) ; throw new Error ( `${ title }: ${ message }` ) ; } } /**
 * 2021-12-13 01:40:29
 * NOTE: 发现调用接口时会返回 { msg: '当前不允许查看分项成绩！' }
 * 不知道是暂时的还是永久的，有待进一步观察。
 */ export async function requestSubitemScoreLook ( executiveEducationPlanNumber , courseNumber , courseSequenceNumber , examTime ) { const url = '/student/integratedQuery/scoreQuery/subitemScore/look' ; try { const result = await $ . post ( url , { zxjxjhh : executiveEducationPlanNumber , kch : courseNumber , kxh : courseSequenceNumber , kssj : examTime , param : 1 } ) ; return result ; } catch ( error ) { const { title , message , html } = await LoadHTMLToDealWithError ( url ) ; Logger . error ( { title , message , html } ) ; throw new Error ( `${ title }: ${ message }` ) ; } } /**
 * 2021-7-12
 * NOTE: 这个接口目前已经没有修复的必要了
 * 即使在 /student/integratedQuery/scoreQuery/subitemScore/fxcjIndex 页面中加上随机字符串正确调用了接口，返回的数据仍然为空。
 */ export async function requestSubitemScoreFxcj ( fxcjId ) { const url = '/student/integratedQuery/scoreQuery/subitemScore/searchFxcj' ; try { const { records } = await $ . post ( url , { fxcjId , pageNum : 1 , pageSize : 30 } ) ; return records ; } catch ( error ) { const { title , message , html } = await LoadHTMLToDealWithError ( url ) ; Logger . error ( { title , message , html } ) ; throw new Error ( `${ title }: ${ message }` ) ; } } export { requestTeachingAssessmentEvaluationRecords , requestTeachingEvaluationPageHTML , requestThisTermCourseScoreInfoList , requestCurrentSemesterStudentAcademicInfo , requestCourseSchedule , requestStudentSemesterNumberList , requestStudentInfo } ;