Ischool plugin範例-學生成績證明單
From ischool developer's network
Contents |
如何使用
- 若您為開發者,下載程式碼,可參考設定ischool plugin。
- 若您為使用者,下載執行檔,可參考安裝ischool plugin。
基本資訊
- 作者:張騉翔
- 服務單位:忠信高中
- 學生成績證明單程式碼
- 學生成績證明單執行檔
在本文中分享學生成績證明單範例,本文會分兩個主軸來說明學生成績證明單的方式,一個是以範例為主軸的方式來介紹,另一個方式是以技術的角度來整理我們在此範例中會學到哪些。
學生成績證明單需求
同學們在報考四技二專推甄時需要附上成績證明單,而成績證明單主要分兩種,一種是國英數成績證明單,另一種是學業和德行成績證明單,底下小節再詳細說明這兩種報表的需求。
國英數成績證明單
國英數成績證明單分為普通類科以及綜合與職業類科,主要的差別在於職業類科的成績計算到小數點兩位。
- 普通類科
- 綜合與職業類科
學業和德行成績證明單
學業和德行成績證明單除了分數外,另外增加級分分數,一樣的也分為普通類科以及綜合與職業類科,主要的差別在於職業類科的成績計算到小數點兩位。
- 普通類科
- 綜合與職業科
SubjectReportCard
SubjectReportCard的物件設計主要是希望對於使用者而言,能有簡易的方式只需傳入儲存檔案名稱、樣板名稱以及小數點參數即可儲存成績單;會需要傳入小數點主要是綜合科和職業類科成績需取至小數點第二位,而普通科只需取至整數,我們希望這個程式能共用綜合科及職業類科的報表。
此物件及函式設計還有許多需改良之處,例如目前將科目名稱國英數寫在程式當中,以及學年度也是;這部份我們會視使用者的需求加以更加彈性改寫,目前先以使用者的角度能易於理解設計,並能對於Smart School Pluin開發能有實務性的參考。
在SubjectReportCard當中只有一個public方法,也就是Save方法將成績單路徑、樣板路徑及小數點傳入即可;其它函式皆是幫助Save方法完成工作。
Save(儲存多筆學生成績證明單)
Save方法主要呼叫GetSubjectReportCard方法來取得實際每位學生的成績單,而Save方法主要進行排版的工作,並且將最後的結果儲存成Excel,以下為幾項程式碼小細節需注意之處:
- AccessHelper物件為存取Smart School Plugin資料的進入點,對於稍複雜的資料如學生成績需要呼叫AccessHelper的Fill系列方法來取得資料。
- Aspose的活頁簿物件(Worksheet)可呼叫HPageBreaks方法來進行換頁。
- 有個小細節需注意,根據筆者實驗,在GetSubjectReportCard函式及本函式中皆需開啟樣版(ScoreWorkBook.Open(templatename))才能正確的將結果顯示。
public void Save(string filename, string templatename, int decimalpoint) { //Step1:取得Smart School Plugin的主要物件AccessHelper,可用此物件來取得Plugin相關資訊,例如目前所選取的學生。 AccessHelper Helper = new AccessHelper(); //Step2:運用AccessHelper來取得目前所選取的學生,為StudentRecord物件的集合 List<StudentRecord> StudRecs = Helper.StudentHelper.GetSelectedStudent(); //Step3:運用AccessHelper的FillSemesterSubjectScore來填入學生學期科目成績。 Helper.StudentHelper.FillSemesterSubjectScore(true, StudRecs); //Step4:運用Aspose函式庫建立Excel的Workbook物件 Aspose.Cells.Workbook ScoreWorkBook = new Aspose.Cells.Workbook(); //Step4.1:將Workbook物件開啟樣版 ScoreWorkBook.Open(templatename); //Step5:依序循訪每位學生,將學生物件及小數點參數傳入GetSubjectReportCard函式,此函式會回傳填入值的學生樣版 for (int i = 0; i < StudRecs.Count; i++) { //Step5.1:傳入學生物件、樣版路徑及小數點,傳回Aspose的Range物件,裡面含實際學生值的樣版 Aspose.Cells.Range StudentRecordRange = GetSubjectReportCard(StudRecs[i], templatename, decimalpoint); //Step5.2:將學生樣版存到實際的活頁簿當中,並運用intSubjectReportCardRangeRow來控制學生樣版的位置 ScoreWorkBook.Worksheets[0].Cells.CreateRange(i * intSubjectReportCardRangeRow, intSubjectReportCardRangeRow, false).Copy(StudentRecordRange); //Step5.3:加入分頁符號,運用HPageBreaks方法 ScoreWorkBook.Worksheets[0].HPageBreaks.Add((i + 1) * intSubjectReportCardRangeRow, 0); } //Step6:將活頁簿儲存 ScoreWorkBook.Save(filename); }
GetStudentRange(取得單筆學生成績證明單)
GetStudentRange為產生學生成績單主要的程式,底下為幾項程式需注意事項:
- 可運用ScoreWorkBook.Worksheets[0].Cells[3, 4].PutValue()方法來放值,其中第一個值為列,第二個值為欄。
- Student物件裡有相當多學生的屬性可供存取,例如學生姓名、座號,所屬班級…等。
- SemesterSubjectScoreInfo類別為學生學期科目成績資訊,可藉由Student.SemesterSubjectScoreList方法來取得學生所有成績資訊。
- SemesterSubjectScoreInfo幾個重要的屬性,Subject為科目名稱、SchoolYear為學年度、Semester為學期(1為上學期、2為下學期)、Score為科目成績。
private Aspose.Cells.Range GetStudentRange(SmartSchool.Customization.Data.StudentRecord Student, string templatefilename, int decimalpoint) { //Step1:運用Aspose函式庫建立Excel的Workbook物件 Aspose.Cells.Workbook ScoreWorkBook = new Aspose.Cells.Workbook(); //Step1.1:將Workbook物件開啟樣版 ScoreWorkBook.Open(templatefilename); //Step2:填入學生基本資料 //Step2.1:填入學生的科系 ScoreWorkBook.Worksheets[0].Cells[3, 4].PutValue(Student.Department); //Step2.2:填入學生班級 ScoreWorkBook.Worksheets[0].Cells[3, 7].PutValue(Student.RefClass.ClassName); //Step2.3:填入學生班級座號 ScoreWorkBook.Worksheets[0].Cells[3, 9].PutValue(Student.SeatNo); //Step2.4:填入學生證號碼 ScoreWorkBook.Worksheets[0].Cells[5, 2].PutValue(Student.StudentNumber); //Step2.5:填入學生姓名 ScoreWorkBook.Worksheets[0].Cells[5, 4].PutValue(Student.StudentName); //Step3:SemesterSubjectScoreInfo為學生學期科目成績資訊,每位學生會有多筆,一一取出並判斷是否符合成績單需求的 foreach (SemesterSubjectScoreInfo SSI in Student.SemesterSubjectScoreList) { //判斷成績科目是否為國文、英文及數學並且為94至96學年,運用簡單的公式將值放置到Excel位置當中。 if ((SSI.Subject == "國文") && (SSI.SchoolYear >= intStartSchoolYear) && (SSI.SchoolYear <= intEndSchoolYear)) ScoreWorkBook.Worksheets[0].Cells[10, (SSI.SchoolYear - intStartSchoolYear) * 2 + (SSI.Semester - 1) + 2].PutValue(SSI.Score.ToString(ScoreHelper.GetDecimalFormatString(decimalpoint))); if ((SSI.Subject == "英文") && (SSI.SchoolYear >= intStartSchoolYear) && (SSI.SchoolYear <= intEndSchoolYear)) ScoreWorkBook.Worksheets[0].Cells[12, (SSI.SchoolYear - intStartSchoolYear) * 2 + (SSI.Semester - 1) + 2].PutValue(SSI.Score.ToString(ScoreHelper.GetDecimalFormatString(decimalpoint))); if ((SSI.Subject == "數學") && (SSI.SchoolYear >= intStartSchoolYear) && (SSI.SchoolYear <= intEndSchoolYear)) ScoreWorkBook.Worksheets[0].Cells[14, (SSI.SchoolYear - intStartSchoolYear ) * 2 + (SSI.Semester - 1) + 2].PutValue(SSI.Score.ToString(ScoreHelper.GetDecimalFormatString(decimalpoint))); } //Step4:計算學生平均成績,用傳參考的方式傳入,平均成績會直接寫到學生欄位裡。 CalculateSubjectAverage(ref Student); //Step4.1:將國文、英文及數學成績填至成績單相關位置,並呼叫ScoreHelper.GetDecimalFormatString函式傳回格式化字串 ScoreWorkBook.Worksheets[0].Cells[10, 8].PutValue(decimal.Parse(Student.Fields["國文平均"].ToString()).ToString(ScoreHelper.GetDecimalFormatString(decimalpoint)).ToString()); ScoreWorkBook.Worksheets[0].Cells[12, 8].PutValue(decimal.Parse(Student.Fields["英文平均"].ToString()).ToString(ScoreHelper.GetDecimalFormatString(decimalpoint)).ToString()); ScoreWorkBook.Worksheets[0].Cells[14, 8].PutValue(decimal.Parse(Student.Fields["數學平均"].ToString()).ToString(ScoreHelper.GetDecimalFormatString(decimalpoint)).ToString()); //Step5:計算學生成績排名 CalculateSubjectRank(ref Student); string strChineseRank = Student.Fields["國文排名"].ToString(); string strEnglishRank = Student.Fields["英文排名"].ToString(); string strMathRank = Student.Fields["數學排名"].ToString(); string strClassTotal = Student.RefClass.Students.Count.ToString(); //Step5.1:將班級排名加上班級總人數,並填入成績單相關位置 ScoreWorkBook.Worksheets[0].Cells[10, 9].PutValue(strChineseRank + "/" + strClassTotal); ScoreWorkBook.Worksheets[0].Cells[12, 9].PutValue(strEnglishRank + "/" + strClassTotal); ScoreWorkBook.Worksheets[0].Cells[14, 9].PutValue(strMathRank + "/" + strClassTotal); //Step6:運用ScoreHelper.GetRankPercen函式傳入排名及班級人數,算出排名百分比 ScoreWorkBook.Worksheets[0].Cells[10, 10].PutValue(ScoreHelper.GetRankPercent(strChineseRank,strClassTotal )); ScoreWorkBook.Worksheets[0].Cells[12, 10].PutValue(ScoreHelper.GetRankPercent(strEnglishRank, strClassTotal)); ScoreWorkBook.Worksheets[0].Cells[14, 10].PutValue(ScoreHelper.GetRankPercent(strMathRank, strClassTotal)); //Step7:傳回學生個人成績單在活頁簿裡的Range物件 return ScoreWorkBook.Worksheets[0].Cells.CreateRange(0, intSubjectReportCardRangeRow, false); }
CalculateSubjectAverage(計算科目平均成績)
此函式由GetStudentRange所呼叫,用來計算一位學生的科目平均成績,舉例而言某位學生的94至96學年共有6個學期的國文平均成績;目前成績證明單的需求只有國文、英文及數學,未來可視需求改為較為彈性的設計。
下面程式碼應相當簡單,將各個學期的科目成績進行加總後平均,比較需要注意的是最後面可運用Student物件的彈性設計,將計算的平均值直接加入到擴充欄位當中。
Student.Fields.Add("欄位名稱", 欄位值);
private void CalculateSubjectAverage(ref StudentRecord Student) { //Step1:本函式用來計算國文、英文及數學的學期平均成績,若是已計算過則不再計算;目前函式只固定計算國英數,未來 //依需求可改寫更彈性些。 if (!Student.Fields.ContainsKey("國文平均") && !Student.Fields.ContainsKey("英文平均") && !Student.Fields.ContainsKey("數學平均")) { //Step2.1:宣告學期各科目加總成績 decimal decChinese = 0, decEnglish = 0, decMath = 0; //Step2.2:宣告計數器計算每個科目有幾學期有成績 int ChineseCount = 0, EnglishCount = 0, MathCount = 0; //Step3:加總各學期科目成績 foreach (SemesterSubjectScoreInfo SSI in Student.SemesterSubjectScoreList) { if ((SSI.Subject == "國文") && (SSI.SchoolYear >= intStartSchoolYear) && (SSI.SchoolYear <= intEndSchoolYear)) { douChinese += SSI.Score; ChineseCount++; } if ((SSI.Subject == "英文") && (SSI.SchoolYear >= intStartSchoolYear) && (SSI.SchoolYear <= intEndSchoolYear)) { douEnglish += SSI.Score; EnglishCount++; } if ((SSI.Subject == "數學") && (SSI.SchoolYear >= intStartSchoolYear) && (SSI.SchoolYear <= intEndSchoolYear)) { douMath += SSI.Score; MathCount++; } } //Step4:將加總成績除以學期數求得學期科目平均 if (douChinese > 0) douChinese /= ChineseCount; if (douEnglish > 0) douEnglish /= EnglishCount; if (douMath > 0) douMath /= MathCount; //Step5:將學期科目平均新增欄位至學生物件中 Student.Fields.Add("國文平均", douChinese); Student.Fields.Add("英文平均", douEnglish); Student.Fields.Add("數學平均", douMath); } }
CalculateSubjectRank(計算科目排名)
計算科目排名算是在這個程式中比較費工的部份,若是在Smart School Plugin中有內建至StudentRecord物件中就會較容易多;目前筆者採用計算排名的方法是每位學生都會與班級其他學生來比較。
private void CalculateSubjectRank(ref StudentRecord Student) { //Step1:取得Smart School Plugin的主要物件AccessHelper,可用此物件來取得Plugin相關資訊,例如目前所選取的學生。 AccessHelper Helper = new AccessHelper(); //Step2:取得學生所在班級的所有學生,計算每位學生的科目平均並用來排名 List<StudentRecord> StudRecs = Student.RefClass.Students; // Step3:填入班級學生的學期科目成績 Helper.StudentHelper.FillSemesterSubjectScore(true, StudRecs); //Step4:宣告變數用來儲存排名,一開始用來儲存科目平均贏過幾個人,最後再用班級排名減去得到排名 int ChineseRank = 0, EnglishRank = 0, MathRank = 0; //Step5:與班級同學做比較,若是成績大於同學,則將排名加一 foreach (StudentRecord Classmate in StudRecs) { if (Classmate.StudentID != Student.StudentID) { StudentRecord NewClassmate = Classmate; CalculateSubjectAverage(ref NewClassmate); if (decimal.Parse(Student.Fields["國文平均"].ToString()) > decimal.Parse(NewClassmate.Fields["國文平均"].ToString())) ChineseRank++; if (decimal.Parse(Student.Fields["英文平均"].ToString()) > decimal.Parse(NewClassmate.Fields["英文平均"].ToString())) EnglishRank++; if (decimal.Parse(Student.Fields["數學平均"].ToString()) > decimal.Parse(NewClassmate.Fields["數學平均"].ToString())) MathRank++; } } //Step6:將班級人數減去排名變數值,得到實際的排名,並加入至學生自訂欄位當中 Student.Fields.Add("國文排名", Student.RefClass.Students.Count - ChineseRank); Student.Fields.Add("英文排名", Student.RefClass.Students.Count - EnglishRank); Student.Fields.Add("數學排名", Student.RefClass.Students.Count - MathRank); }
小結
在本文中分享了學生成績證明單的範例,讀者在有了對於Smart School Plugin的基礎後可以以此範例來熟悉設計您需求的範例;對於較熟悉的讀者可以直接看註解瞭解相關物件及方法用法。
