💼國中成績一覽表
「社會」分為三科:「歷史」、「地理」、「公民」,分數都一樣,只算一個「社會」成績。
// 「各班成績表」
function makeClassTable(classNo){
// prepare data
let data = Student.dataForClassTable(classNo);
// set values into sheet
const sheet = app.sheetByName(classNo);
sheet.clear();
sheet.setValues(data);
// ----------------------- format tables -----------------------
const rows = data.length;
const cols = data[0].length;
const dataRange = sheet.range(1,1,rows, cols);
// ┌─────┐
// │ 畫線 │
// └─────┘
dataRange
.setBorder(true, true, true, true, true,true);
// ┌─────────┐
// │ 數字格式 │
// └─────────┘
dataRange
.inset({top: 2, left: 3, right: 2})
.setNumberFormat('0.0');
// ┌─────┐
// │ 對齊 │
// └─────┘
dataRange.firstNColumns(3).alignCenter(); // 前三欄:「班級、座號、姓名」
dataRange.firstNRows(2).alignCenter(); // 前兩列:標題、表頭
// ┌─────────┐
// │ 水平合併 │
// └─────────┘
dataRange.nthRow(1) // 標題
.mergeAcross()
.setFontSize(14)
.setFontWeight('bold');
// ┌───────┐
// │ 背景色 │
// └───────┘
[
dataRange.nthRow(2), // 表頭
dataRange.cell(rows, 3), // 「平均」格
].forEach(rng => rng.setBackground(app.color.gray))
// ┌─────────┐
// │ 欄位寬度 │
// └─────────┘
sheet.setColumnWidths(1, 2, 40); // 「座號」欄
sheet.setColumnWidths(3, cols - 4, 60); //
sheet.setColumnWidths(cols - 1, 2, 40); // 「班排 校排」欄
// ┌─────────┐
// │ 條件格式 │
// └─────────┘
const scoresRange = dataRange.inset({top: 3, left: 3, right: 4}); // 五科分數區
const averageRange = dataRange.nthColumn(10); // 「平均」欄
const classRankRange = dataRange.nthColumn(cols - 1); // 「班排」欄
const schoolRankRange = dataRange.nthColumn(cols); // 「校排」欄
// 分數 < 60
const redIfLessThan60 = SpreadsheetApp
.newConditionalFormatRule() // ⭐️ ConditionalFormatRuleBuilder
.whenNumberLessThan(60) // - 🔸 condition
.setBackground(app.color.lightRed) // - 🔸 formats
.setRanges([scoresRange, averageRange]) // - 🔸 ranges
.build(); // ⭐️ ConditionalFormatRule
// 班排前3
const blueIfLessThan4 = SpreadsheetApp
.newConditionalFormatRule() // ⭐️ ConditionalFormatRuleBuilder
.whenNumberLessThan(4) // - 🔸 condition
.setBackground(app.color.lightBlue) // - 🔸 formats
.setRanges([classRankRange]) // - 🔸 ranges
.build(); // ⭐️ ConditionalFormatRule
// 校排前30
const greenIfLessThan31 = SpreadsheetApp
.newConditionalFormatRule() // ⭐️ ConditionalFormatRuleBuilder
.whenNumberLessThan(31) // - 🔸 condition
.setBackground(app.color.lightGreen) // - 🔸 formats
.setRanges([schoolRankRange]) // - 🔸 ranges
.build(); // ⭐️ ConditionalFormatRule
[
redIfLessThan60, // score < 60
blueIfLessThan4, // top 3 each class
greenIfLessThan31, // top 30 at school
].forEach(rule => sheet.appendConditionalFormatRule(rule));
};2022.07.21:平均與老闆跑出來的不一樣(原因:原來的欄位順序跟後來的不一樣)
2022.07.24:全新改版,用 Google Apps Script 重新改寫。
improvements
function main() {
log(`學生數:${app.students.length}`);
log(`班級:${app.classes}`);
// first 20 students
// Array.from({length: 20}, (_, i) => i).forEach(i => log(app.students[i]));
// first class
log(`第一班的班平均:`)
log(Class.all[0].score);
// --------------------------- 製表 ---------------------------
makeAverageTable(); // 「各班平均」表
makeTop3Table(); // top 3
makeTop30Table(); // top 30
// 各班成績表
app.classes.forEach(classNo => makeClassTable(classNo));
}
// 班排
function setRankOfClass(){
// 🔸 student.rankOfClass
app.classes.forEach(classNo => {
app.students.filter(s => s.classNo === classNo && s.total !== '') // 排除完全沒分數的人
.rank('rankOfClass', (a, b) => +b.total - +a.total);
});
}
// 校排
function setRankOfSchool(){
// 🔸 student.rankOfSchool
app.students.filter(s => s.total !== '') // 排除完全沒分數的人
.rank('rankOfSchool', (a, b) => +b.total - +a.total);
}
// ?01 - ?06 班成績表
function makeClassTable(classNo){
app.makeTable(classNo, Student.dataForClassTable(classNo), {
// column widths
columnWidths: (r, {cols=r.cols()}={}) => [[1, cols, 60]],
// ranges
ranges: {
// border
border: (r) => [r.inset({top: 1, bottom: 1})],
// grid lines
gridlines: (r) => [r.inset({top: 1})],
// gray ranges
gray: (r, {rows=r.rows()}={}) => [
r.nthRow(2),
r.cell(rows, 3)
],
// bold
bold: (r) => [r.nthRow(1)],
// merge across
mergeAcross: (r) => [r.nthRow(1)],
// align center
alignCenter: (r) => [r],
// ----- number format -----
numberFormat: (r, {cols=r.cols()}={}) => [
{format: '0.00', ranges: [
r.inset({top: 2, left: 3, right: 2}),
]},
{format: '00', ranges: [
r.nthColumn(2).inset({top: 2, bottom: 1})
]},
{format: '0', ranges: [
r.lastNColumns(2).inset({top: 2, bottom: 1})
]},
],
// ----- conditinoal format -----
scores: (r, {cols=r.cols()}={}) => [
r.inset({top: 2, left: 3, right: 4}),
r.nthColumn(cols - 2).inset({top: 2, bottom: 1}),
],
top3: (r) => [r.lastNthColumn(2).inset({top: 2, bottom: 1})],
top30: (r) => [r.lastNthColumn(1).inset({top: 2, bottom: 1})],
},
});
}
// 「各班平均」表
function makeAverageTable(){
app.makeTable('各班平均', Class.dataForAverageTable, {
columnWidths: (r, {cols=r.cols()}={}) => [[1, cols, 60]],
ranges: {
border: (r) => [r.inset({top: 1, bottom: 1})],
gridlines : (r) => [r],
numberFormat: (r) => [{format: '0.0', ranges: [r.inset({top: 2, left: 1})]}],
mergeAcross : (r) => [r.nthRow(1)],
alignCenter : (r) => [r],
gray: (r, {rows=r.rows()}={}) => [r.nthRow(2), r.cell(rows, 1)],
scores: (r) => [
r.inset({top: 2, left: 1, right: 2}), // 五科分數區
r.lastNthColumn(1).inset({top: 2, bottom: 1}), // 平均欄
],
}
});
}
// 「班排前三」表
function makeTop3Table() {
app.makeTable('班排前三', Student.dataForTop3Table(), {
columnWidths: (r, {cols=r.cols()}={}) => [[1, cols, 60]],
ranges: {
gridlines: (r) => [r.inset({top: 1})],
border: (r) => [r.inset({top: 1})],
alignCenter: (r) => [r], // whole data range
mergeAcross: (r) => [r.nthRow(1)], // title
bold: (r) => [r.nthRow(1)], // title
gray: (r) => [r.nthRow(2)], // header
numberFormat: (r) => [{format: '00', ranges: [r.nthColumn(2).inset({top: 2})]}], // seat No.
}
});
}
// 「top 30」表
function makeTop30Table() {
app.makeTable('校排前三十', Student.dataForTop30Table(), {
columnWidths: (r, {cols=r.cols()}={}) => [[1, cols, 60]],
ranges: {
gridlines: (r) => [r.inset({top: 1})],
border: (r) => [r.inset({top: 1})],
alignCenter: (r) => [r], // whole data range
mergeAcross: (r) => [r.nthRow(1)], // title
bold: (r) => [r.nthRow(1)], // title
gray: (r) => [r.nthRow(2)], // header
numberFormat: (r) => [
{format: '00', ranges: [r.nthColumn(2).inset({top: 2})]}, // seat No.
{format: '0.0', ranges: [r.inset({top: 2, left: 3, right: 1})]}, // 總分 平均
],
}
});
}Last updated
Was this helpful?