@@ -31,30 +31,141 @@ func (s *Student) GetCultivatePlan() (string, error) {
3131 if err != nil {
3232 return "" , err
3333 }
34+
35+ // 获取初始页面状态
3436 viewStateMap , err := s .getState (constants .CultivatePlanURL )
3537 if err != nil {
3638 return "" , err
3739 }
40+
41+ // 尝试精确匹配学院和专业代码
42+ url , err := s .getCultivatePlanWithPreciseMatch (info , viewStateMap )
43+ if err == nil {
44+ return url , nil
45+ }
46+
47+ // 如果精确匹配失败,使用fallback逻辑
48+ return s .getCultivatePlanWithFallback (info , viewStateMap )
49+ }
50+
51+ // 精确匹配学院和专业代码获取培养方案
52+ func (s * Student ) getCultivatePlanWithPreciseMatch (info * StudentDetail , viewStateMap map [string ]string ) (string , error ) {
53+ // 获取学院选择页面
54+ initialDoc , err := s .GetWithIdentifier (constants .CultivatePlanURL )
55+ if err != nil {
56+ return "" , err
57+ }
58+
59+ // 查找学院代码
60+ collegeSelect := htmlquery .FindOne (initialDoc , `//select[@id="xymcdpl"]` )
61+ if collegeSelect == nil {
62+ return "" , fmt .Errorf ("college select not found" )
63+ }
64+
65+ collegeCode := ""
66+ collegeOptions := htmlquery .Find (collegeSelect , ".//option" )
67+ for _ , option := range collegeOptions {
68+ optionText := htmlquery .InnerText (option )
69+ optionValue := htmlquery .SelectAttr (option , "value" )
70+
71+ // 直接匹配学院名称
72+ if optionText == info .College {
73+ collegeCode = optionValue
74+ break
75+ }
76+
77+ // 处理学院改名的情况
78+ if (strings .Contains (optionText , "计算机与大数据" ) || strings .Contains (optionText , "数学与统计" )) &&
79+ strings .Contains (info .College , "数学与计算机" ) {
80+ collegeCode = optionValue
81+ break
82+ }
83+ }
84+
85+ if collegeCode == "" {
86+ return "" , fmt .Errorf ("college code not found for %s" , info .College )
87+ }
88+
89+ viewStateGenerator := htmlquery .SelectAttr (htmlquery .FindOne (initialDoc , `//*[@id="__VIEWSTATEGENERATOR"]` ), "value" )
90+
91+ // 选择年级和学院后获取专业列表
92+ majorListResp , err := s .PostWithIdentifier (constants .CultivatePlanURL , map [string ]string {
93+ "__VIEWSTATE" : viewStateMap ["VIEWSTATE" ],
94+ "__EVENTVALIDATION" : viewStateMap ["EVENTVALIDATION" ],
95+ "__EVENTTARGET" : "ctl00$njdpl" ,
96+ "__EVENTARGUMENT" : "" ,
97+ "__VIEWSTATEGENERATOR" : viewStateGenerator ,
98+ "ctl00$njdpl" : info .Grade , // 年级
99+ "ctl00$xymcdpl" : collegeCode , // 学院名称
100+ "ctl00$dldpl" : "<-全部->" , // 大类
101+ "ctl00$zymcdpl" : "<-全部->" , // 专业代码
102+ "ctl00$zylbdpl" : "本专业" , // 修读类别:本专业/辅修
103+ "ctl00$ContentPlaceHolder1$DDL_syxw" : "<-全部->" , // 授予学位
104+ "ctl00$ContentPlaceHolder1$BT_submit" : "确定" ,
105+ })
106+ if err != nil {
107+ return "" , err
108+ }
109+
110+ // 查找专业代码
111+ majorSelect := htmlquery .FindOne (majorListResp , `//select[@id="zymcdpl"]` )
112+ if majorSelect == nil {
113+ return "" , fmt .Errorf ("major select not found" )
114+ }
115+
116+ majorCode := ""
117+ majorOptions := htmlquery .Find (majorSelect , ".//option" )
118+ for _ , option := range majorOptions {
119+ optionText := htmlquery .InnerText (option )
120+ if optionText == info .Major {
121+ majorCode = htmlquery .SelectAttr (option , "value" )
122+ break
123+ }
124+ }
125+
126+ if majorCode == "" {
127+ return "" , fmt .Errorf ("major code not found for %s" , info .Major )
128+ }
129+
130+ // 构造最终URL
131+ finalURL := fmt .Sprintf ("/pyfa/pyjh/pyfa_bzy.aspx?nj=%s&xyh=%s&zyh=%s&zylb=本专业&id=%s" ,
132+ info .Grade , collegeCode , majorCode , s .Identifier )
133+
134+ return constants .JwchPrefix + finalURL , nil
135+ }
136+
137+ // fallback逻辑:当精确匹配失败时使用
138+ func (s * Student ) getCultivatePlanWithFallback (info * StudentDetail , viewStateMap map [string ]string ) (string , error ) {
139+ // 获取初始页面状态
140+ initialDoc , err := s .GetWithIdentifier (constants .CultivatePlanURL )
141+ if err != nil {
142+ return "" , err
143+ }
144+
145+ viewStateGenerator := htmlquery .SelectAttr (htmlquery .FindOne (initialDoc , `//*[@id="__VIEWSTATEGENERATOR"]` ), "value" )
146+
147+ // 只选择年级,提交查询
38148 res , err := s .PostWithIdentifier (constants .CultivatePlanURL ,
39149 map [string ]string {
40- "__VIEWSTATE" : viewStateMap ["VIEWSTATE" ],
41- "__EVENTVALIDATION" : viewStateMap ["EVENTVALIDATION" ],
42- "ctl00$njdpl" : info .Grade , // 年级
43- // "ctl00$xymcdpl": "010",// 学院名称
44- "ctl00$dldpl" : "<-全部->" , // 大类
45- "ctl00$zymcdpl" : "<-全部->" , // 专业代码(无法获取)
46- "ctl00$zylbdpl" : "本专业" , // 本专业、辅修
150+ "__VIEWSTATE" : viewStateMap ["VIEWSTATE" ],
151+ "__EVENTVALIDATION" : viewStateMap ["EVENTVALIDATION" ],
152+ "__EVENTTARGET" : "" ,
153+ "__EVENTARGUMENT" : "" ,
154+ "__VIEWSTATEGENERATOR" : viewStateGenerator ,
155+ "ctl00$njdpl" : info .Grade ,
156+ "ctl00$dldpl" : "<-全部->" ,
157+ "ctl00$zymcdpl" : "<-全部->" ,
158+ "ctl00$zylbdpl" : "本专业" ,
47159 "ctl00$ContentPlaceHolder1$DDL_syxw" : "<-全部->" ,
48160 "ctl00$ContentPlaceHolder1$BT_submit" : "确定" ,
49161 })
50162 if err != nil {
51163 return "" , err
52164 }
53165 xpathExpr := fmt .Sprintf ("//tr[td[matches(string(.), '^(.*?)%s$')]]/td/a[contains(@href, 'pyfa')]/@href" , regexp .QuoteMeta (info .Major ))
54-
55166 node := htmlquery .FindOne (res , xpathExpr )
56167 if node == nil {
57- return "" , fmt .Errorf ("%s" , " cultivate plan not found" )
168+ return "" , fmt .Errorf ("cultivate plan not found for major: %s" , info . Major )
58169 }
59170
60171 url := htmlquery .SelectAttr (node , "href" )
0 commit comments