diff --git a/constants/constants.go b/constants/constants.go index d328422..5c5004d 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -8,6 +8,8 @@ const ( UserInfoURL = "https://jwcjwxt2.fzu.edu.cn:81/jcxx/xsxx/StudentInformation.aspx" SSOLoginURL = "https://jwcjwxt2.fzu.edu.cn/Sfrz/SSOLogin" SchoolCalendarURL = "https://jwcjwxt2.fzu.edu.cn:82/xl.asp" + CreditQueryURL = "https://jwcjwxt2.fzu.edu.cn:81/student/xyzk/xftj/CreditStatistics.aspx" + GPAQueryURL = "https://jwcjwxt2.fzu.edu.cn:81/student/xyzk/jdpm/GPA_sheet.aspx" ) var BuildingArray = []string{"公共教学楼东1", "公共教学楼东2", "公共教学楼东3", "公共教学楼文科楼", "公共教学楼西1", "公共教学楼西2", "公共教学楼西3", "公共教学楼中楼"} diff --git a/credit.go b/credit.go new file mode 100644 index 0000000..cfefe1b --- /dev/null +++ b/credit.go @@ -0,0 +1,116 @@ +package jwch + +import ( + "fmt" + "strings" + + "github.com/antchfx/htmlquery" + "github.com/west2-online/jwch/constants" +) + +func (s *Student) GetCredit() (creditStatistics []CreditStatistics, err error) { + + resp, err := s.GetWithIdentifier(constants.CreditQueryURL) + if err != nil { + return nil, err + } + + spanNode := htmlquery.FindOne(resp, `//*[@id="ContentPlaceHolder1_LB_kb"]`) + if spanNode == nil { + return nil, fmt.Errorf("failed to find the statistics span element") + } + + tables := htmlquery.Find(spanNode, "//table") + if len(tables) == 0 { + return nil, fmt.Errorf("failed to find tables within the span element") + } + tables = tables[:len(tables)-1] // 去掉最后一个表格 + + creditStatistics = []CreditStatistics{} + + for _, table := range tables { + rows := htmlquery.Find(table, "//tr") + + // 临时存储三列数据 + temp := [3][]string{ + make([]string, 0), + make([]string, 0), + make([]string, 0), + } + // 遍历每行,提取单元格数据 + for index, row := range rows { + cells := htmlquery.Find(row, "./td") + // 提取单元格数据 + for _, cell := range cells { + text := htmlquery.InnerText(cell) + if text != "查" { // 因为表格的第三行多了一个单元格,去掉一个无用的格子它使得表格规整 + temp[index] = append(temp[index], text) + } + } + } + // 构建 CreditStatistics + for i := 0; i < len(temp[0]); i++ { + // 去掉个人信息的列(这列第一个单元格式空的)和“修习情况”这个无效的列 + if strings.TrimSpace(temp[0][i]) != "" && !strings.Contains(temp[0][i], "情况") { + bean := CreditStatistics{ + Type: temp[0][i], + Gain: temp[2][i], + Total: temp[1][i], + } + creditStatistics = append(creditStatistics, bean) + } + } + } + + return creditStatistics, nil +} +func (s *Student) GetGPA() (gpa GPABean, err error) { + resp, err := s.GetWithIdentifier(constants.GPAQueryURL) + if err != nil { + return gpa, err + } + + document := htmlquery.FindOne(resp, `//*[@id="ContentPlaceHolder1_Label1"]`) + if document == nil { + return gpa, fmt.Errorf("failed to find the time element") + } + + timeText := htmlquery.InnerText(document) + gpa.Time = strings.TrimSpace(timeText) + + table := htmlquery.FindOne(resp, `//*[@id="ContentPlaceHolder1_DataList_xxk"]`) + if table == nil { + return gpa, fmt.Errorf("failed to find the GPA table") + } + + // 获取表头标题 + titleRow := htmlquery.FindOne(table, `//tr[@style="height:30px; background:#efefef; border-bottom:1px solid gray; border-left:1px solid gray; vertical-align:middle;"]`) + if titleRow == nil { + return gpa, fmt.Errorf("failed to find the title row in GPA table") + } + + // 获取每个表头标题的单元格 + tdsTitle := htmlquery.Find(titleRow, `./td[@align="center"]`) + width := len(tdsTitle) + + // 获取表格中的所有数据 + tdsFull := htmlquery.Find(table, `.//td[@align="center"]`) + if len(tdsFull) == 0 { + return gpa, fmt.Errorf("failed to find GPA data cells") + } + + height := len(tdsFull)/width - 1 + + var data []GPAData + for h := 1; h <= height; h++ { + for w := 0; w < width; w++ { + data = append(data, GPAData{ + Type: htmlquery.InnerText(tdsTitle[w]), + Value: htmlquery.InnerText(tdsFull[width*h+w]), + }) + } + } + gpa.Data = data + + return gpa, nil +} diff --git a/jwch_test.go b/jwch_test.go index c2bce09..b92b8e8 100644 --- a/jwch_test.go +++ b/jwch_test.go @@ -277,3 +277,34 @@ func Test_GetTermEvents(t *testing.T) { fmt.Println(utils.PrintStruct(events)) } + +func Test_GetCredit(t *testing.T) { + if !islogin { + err := login() + if err != nil { + t.Error(err) + } + } + + credit, err := stu.GetCredit() + if err != nil { + t.Error(err) + } + + fmt.Println(utils.PrintStruct(credit)) +} + +func Test_GetGPA(t *testing.T) { + if !islogin { + err := login() + if err != nil { + t.Error(err) + } + } + gpa, err := stu.GetGPA() + if err != nil { + t.Error(err) + } + + fmt.Println(utils.PrintStruct(gpa)) +} diff --git a/model.go b/model.go index cf04a59..497805b 100644 --- a/model.go +++ b/model.go @@ -1,8 +1,9 @@ package jwch import ( - "github.com/go-resty/resty/v2" "net/http" + + "github.com/go-resty/resty/v2" ) // 学生对象 @@ -129,3 +130,19 @@ type CalTermEvent struct { StartDate string `json:"startDate"` // 开始日期 格式:2024-08-26 EndDate string `json:"endDate"` // 结束日期 格式:2025-01-17 } + +type CreditStatistics struct { + Type string // 学分类型 + Gain string // 已获得 + Total string // 应获学分 +} + +type GPAData struct { + Type string + Value string +} + +type GPABean struct { + Time string // 绩点计算时间 + Data []GPAData +}