香港公司秘書/公司治理專業資格考試 CGQP|《董事會動態治理(選考)》模擬題庫

每位學員用自己的帳號登入,錯題本與練習記錄會分開存放,不會互相混淆。 帳號資料储存在您目前使用的這台裝置瀏覽器內。
📖 考點速覽|12 章重點蒸餾(開考前 5 分鐘過一遍)(點擊展開)
第1章 · 董事會動態與團隊效能
  • Belbin 團隊角色:思考型、行動型、社交型三大類
  • Tuckman 階段:組建→風暴→規范→執行
  • 董事會效能 = 成員構成 × 互動質量 × 信息質量
第2章 · 董事會與 CEO 關係
  • 主席與 CEO 分職;主席主導董事會、CEO 主導執行
  • 董事會與管理層的信息流:議程設置、簡報質量
  • 董事對管理層的支持與挑戰平衡
第3章 · 董事行為與衝突管理
  • 建設性衝突提升決策質量;群體思維(groupthink)的風險與征兆
  • Thomas-Kilmann 模型:競爭、回避、遷就、妥協、協作
  • 異議的表達與少數意見的紀錄
第4章 · 董事會評估與發展
  • 董事會評估:整體、委員會、個別董事三個層面
  • 新董事入職(induction)與持續專業培訓
  • 評估結果反饋到提名與繼任規劃
第5章 · 董事會與企業文化
  • 高層定調(tone at the top):董事會為文化問責
  • 文化的評估:員工調查、舉報數據、離職率
  • 文化與風險胃口、合規的連動
第6章 · 效能工具與實務
  • 董事會工具包:年度議程日曆、董事會章程、信息報告制度
  • 會議材料的及時性與精煉度
  • 會議時間分配:戰略議題佔比
第7章 · 董事會會議實務
  • 議程設計:重大事項前置、避免議而不決
  • 討論引導:主席的中立性與收束技巧
  • 決議紀錄:決定、理由、反對意見
第8章 · 委員會動態
  • 委員會主席須向全體董事會匯報並提交報告
  • 跨委員會協調:議題重疊時的分工
  • 委員會評估與成員輪換
第9章 · 危機中的董事會
  • 危機中的董事會:快速召集、授權機制、對外口徑一致
  • 緊急決策的授權邊界與事後追認
  • 危機後的復盤與問責
第10章 · 董事招聘與多元
  • 董事繼任規劃:技能矩陣、人才儲備
  • 董事會多元化:性別、專業背景、年齡、國際經驗
  • 提名委員會在招聘中的角色
第11章 · 治理文件與流程
  • 董事會章程(board charter):職權、運作、評估
  • 委員會職權範圍書(ToR)的要素
  • 治理文件的定期檢討更新
第12章 · 情景應用
  • 綜合情景:新董事融入、衝突化解、危機決策的推演

※ 以上為按課程大綱整理的自編備考重點,並非官方考試內容;系統學習請參閱 HKCGI 官方課程資料。

120題庫總題數
50%合格線
75%優秀線
第 1 / 100 題 模擬練習
0%
合格

📊 各章節表現

❌ 錯題回顧(已加入錯題庫)

📕 我的錯題本(0 題)

每次答錯的題目會自動記錄到這裡;在「錯題重做」中答對後會自動移出。

⚠️ 我的異議清單(0 條)

做題時點「⚠️ 質疑此題」即可記錄。確認後請一次過傳送給我們跟進核實。

🗂 我的練習記錄

👤 我的帳號

🔑 修改密碼

const BANK = [[1,1,"1","董事會作為「團隊」的效能取決於:","成員構成、互動規範、資訊流與決策過程的質量","人數最多","資歷最老","會議最長","A","董事會效能研究強調行為動態(流程)與結構特徵同樣重要。"],[2,1,"1","「心理安全」(psychological safety)在董事會的意義是:","成員敢於提出異議、質疑與壞消息而不懼報復","氣氛永遠輕鬆","不設任何規則","迴避衝突","A","心理安全是坦率討論與有效質詢的前提,缺乏它會導致群體思維。"],[3,1,"1","群體思維(groupthink)的典型徵兆是:","追求一致而壓抑異議、對外部風險信號視而不見","討論激烈","決策緩慢","紀錄詳盡","A","防範群體思維的方法包括魔鬼代言人、外部意見與主席刻意邀請異議。"],[4,1,"1","新董事融入(onboarding)的關鍵目標是:","盡快建立對公司、行業與治理框架的理解,縮短有效貢獻時間","只辦迎新晚宴","讓其自行摸索","跳過簡介","A","系統性的就任培訓與初期「夥伴制」能顯著提升新董事貢獻速度。"],[5,1,"1","董事會規模的权衡在於:","過小限制技能與多元性,過大削弱參與度與決策效率","越大越好","越小越好","固定9人","A","規模須與業務複雜度、委員會工作量及多元目標匹配。"],[6,1,"1","「資訊不對稱」在董事會中最典型的風險是:","董事依賴管理層過濾後的資訊,難以獨立判斷","資訊太多","紀錄太長","會議太頻密","A","對策包括直接接觸一線、委任獨立顧問、要求多源匯報與非執行董事閉門會議。"],[7,1,"1","執行董事會議(executive session / NED 閉門會)的價值是:","非執行董事在無管理層在場時坦率討論敏感議題","代替正式決議","排除執行董事權利","增加會議負擔","A","定期閉門討論(如審計師會面後)提升監督獨立性,是治理良好實踐。"],[8,1,"1","董事會會議節奏與資訊的匹配原則是:","重要議題預留充分時間與前置材料,避免議程過載","每會議題越多越好","文件會後補","時間越短越好","A","會議效能的常見殺手是議題過多與材料倉促,須做議題分級。"],[9,1,"1","「多元觀點」對董事會決策的實證意義是:","減少盲點、改善風險識別與創新,提升決策質量","只為公關","降低效率","純屬形象","A","性別、專業、經驗與背景多元被廣泛認為改善討論廣度與問責。"],[10,1,"1","主席在董事會動態中的關鍵職能是:","營造坦率氛圍、管理發言平衡、聚焦決策而非主導結論","代替行政總裁","壓制異議","控制資訊","A","主席的會議領導力(agenda discipline + 發言管理)直接決定討論質量。"],[11,2,"2","董事會與 CEO 的健康關係模式是:","基於信任的建設性質詢——支援執行同時保持獨立監督","完全服從","對抗為主","互不往來","A","「 engaged but independent 」是治理文獻公認的理想狀態。"],[12,2,"2","主席與 CEO 職責分工的清晰化手段是:","書面職責分工文件並向董事會披露","口頭默契","由人事部決定","無須界定","A","守則要求兩職分離時須有書面分工並披露,避免權責模糊。"],[13,2,"2","高級獨立董事(SID)的作用主要體現在:","在主席利益衝突或需獨立溝通時充當股東與董事會的橋樑","取代審計委員會","管理日常營運","批准預算","A","SID 提供制衡與溝通渠道,是主席/CEO 合一或主席非獨立時的關鍵安排。"],[14,2,"2","CEO 績效評估應由誰主導?","由主席(或提名委員會)統籌、全體非執行董事參與的正式評估","CEO 自評即可","只由財務部評分","無須評估","A","目標設定、中期反饋與年度評估構成 CEO 問責的核心機制。"],[15,2,"2","CEO 繼任規劃的治理責任屬於:","董事會(通常透過提名委員會),須長期持續進行","只在離職時考慮","CEO 自行指定","獵頭公司","A","突發離任與內部培養梯隊要求繼任規劃成為年度常設議題。"],[16,2,"2","「創辦人 CEO」治理的特殊風險是:","個人權威過大導致董事會制衡弱化與繼任困難","無特殊風險","創辦人必然理性","不需要董事","A","須以獨立董事結構、明確授權與繼任安排對沖創辦人集中風險。"],[17,2,"2","CEO 薪酬與治理的爭議點主要是:","薪酬與長期表現掛鈎不足、絕對水平失控及透明度","薪酬越低越好","無爭議","只涉及稅務","A","薪酬委員會須平衡激勵與公眾問責,設計長期業績條件與追回機制。"],[18,2,"2","「資訊流」管理上,CEO 的恰當角色是:","確保董事會獲得完整、及時、不加修飾的資訊","只報喜訊","控制董事會文件","延遲壞消息","A","隱瞞或過濾資訊侵蝕信任並放大風險,是治理崩壞的常見起點。"],[19,2,"2","主席與 CEO 意見分歧的處理原則是:","回到公司最佳利益,透過董事會程序解決,必要時尋求調解","由主席一人裁定","由 CEO 決定","媒體公開","A","分歧是正常的治理現象,關鍵是有程序處理而非個人化。"],[20,2,"2","「管理層連任悖論」是指:","管理層傾向支持現任管理層連任,可能延誤更換時機","股東反對連任","薪酬過低","無此現象","A","董事須警惕忠誠偏向,以客觀績效證據與繼任梯隊支撐人事決策。"],[21,3,"3","董事之間衝突的建設性轉化方法是:","聚焦議題與證據、明確決策標準,避免人身化","迴避所有分歧","投票快刀斬亂麻","私下拉幫結派","A","任務型衝突(task conflict)有益於決策,關係型衝突有害,須管理轉化。"],[22,3,"3","「魔鬼代言人」(devil's advocate)機制的目的是:","指定角色對主流方案提出系統性質疑,檢驗決策穩健性","拖延決策","打擊同事","滿足形式","A","結構化異議降低群體思維與確認偏誤的風險。"],[23,3,"3","董事行為準則通常涵蓋:","保密、利益衝突申報、獨立判斷、出席承諾與內幕交易限制","着裝要求","午膳偏好","社交媒體點讚","A","行為準則將信義職責轉化為可操作的行為規範並便於問責。"],[24,3,"3","董事違反保密義務的後果是:","違反信義職責,可能招致解任、訴訟及內幕交易法律責任","無後果","僅口頭警告","自動離任","A","機密資訊外洩同時可能觸發內幕消息披露與市場失當責任。"],[25,3,"3","主席處理「弱參與董事」的恰當方式是:","私下溝通期望、調整其角色,必要時透過提名委員會處理連任","公開批評","視而不見","替其投票","A","董事會效能須由主席與提名委員會以誠懇反饋與連任機制維護。"],[26,3,"3","利益衝突發生時,個別董事的標準動作是:","及早申報、暫停參與討論表決、由其餘董事處理","繼續投票","事後補報即可","要求其他人迴避","A","程序正義保護公司與董事本人,隱瞞利益是最危險的行為。"],[27,3,"3","「決策日誌」(decision log)的治理價值是:","記錄關鍵決策的依據、考量與異議,供日後問責與學習","增加工作量","替代紀錄","供宣傳用","A","面對事後檢視(尤其訴訟),完整的決策依據是董事自證勤勉的基礎。"],[28,3,"3","董事會與管理層「界限管理」指的是:","董事不越權處理日常營運,管理層不侵犯治理職能","董事做具體執行","管理層定戰略不受監督","界限無須界定","A","清晰的授權矩陣與職權範圍是界限管理的工具。"],[29,3,"3","主席的「會議氛圍」責任包括:","確保少數意見被聽見、時間管理公平、結論與行動清晰落實","讓最資深者主導","跳過結論","壓縮討論","A","會議產出=決策質量+行動清晰度,兩者都靠主席的流程掌控。"],[30,3,"3","處理董事間「聯盟政治」的預防措施是:","透明的決策程序、獨立的資訊渠道與定期全體評估","鼓勵派系","由主席指定觀點","取消討論","A","透明程序削弱私下結盟的利益基礎,維護集體決策的公正性。"],[31,4,"4","董事會年度評估的典型範圍是:","董事會整體、委員會及個別董事的構成與運作","只評估主席","只評估公司秘書","無須評估","A","守則要求定期評估,範圍覆蓋整體、委員會與個別董事(具方法自選)。"],[32,4,"4","外部評估人相對內部問卷的優勢是:","更客觀、可引入市場最佳實踐、便於處理敏感議題","成本更低","無優勢","速度更快","A","每三年引入外部評估是加強客觀性的常見節奏。"],[33,4,"4","個別董事評估的敏感點在於:","須以發展為導向、保密處理,並與連任決策謹慎銜接","全部公開","以懲罰為主","由 CEO 評分","A","評估的目的是提升貢獻與組合補位,而非公開排名。"],[34,4,"4","董事培訓需求分析應基於:","評估結果、公司戰略與風險變化、法規更新","董事個人愛好","年會次數","無須分析","A","培訓須與治理缺口和業務演變掛鈎,形成年度培訓計劃。"],[35,4,"4","「技能矩陣」(skills matrix)的用途是:","對照戰略需要盤點董事會技能,指導提名與培訓","作為薪酬表","替代履歷","裝飾年報","A","技能矩陣連接戰略需求與董事組合,是提名委員會的核心工具。"],[36,4,"4","董事繼任規劃的合理做法是:","建立候選梯隊、設定多元與技能目標、定期檢視任期與更新節奏","等到有空缺才找","永遠連任","由主席內定","A","主動的組合管理避免集體超期服役與技能斷層。"],[37,4,"4","評估結果的跟進要求是:","形成行動計劃(如調整委員會、培訓、議程改進)並定期回顧","僅存檔","向媒體公布","無須跟進","A","評估的價值在於閉環改進,否則淪為形式。"],[38,4,"4","公司秘書在董事會評估中的角色是:","統籌流程(問卷、訪談安排、結果整理)並協助落實改進","替董事作答","決定評分","無角色","A","公司秘書是評估流程的项目經理,保證程序嚴謹與資料保密。"],[39,4,"4","委員會評估應檢視的內容包括:","職權範圍的適切性、成員技能、議題覆蓋與向董事會匯報質量","只看成員出勤","只查費用","無須檢視","A","委員會是董事會效能的槓桿,評估其運作等於檢查治理執行層。"],[40,4,"4","「反思會議」(board reflection session)的設計要點是:","脫離日常議程、聚焦董事會自身運作,必要時由第三方引導","與業務匯報合併","由 CEO 主持","每年一次閒談","A","專門的自省時間讓董事會跳出議題處理模式,審視自身流程。"],[41,5,"5","董事會塑造企業文化的首要途徑是:","自身行為示範(tone at the top)並將文化納入治理議程","發布口號","委託公關","懲罰員工","A","董事會對文化的監督包括文化指標、員工調研與舉報數據的定期審視。"],[42,5,"5","文化指標(culture metrics)的示例是:","員工敬業度、流失率、舉報趨勢、合規違規與客戶投訴","只看利潤","只看股價","只看出勤","A","量化文化訊號使董事會能及早識別文化漂移與風險。"],[43,5,"5","薪酬與文化的連結點是:","激勵設計傳遞「何種行為受獎勵」的訊號,塑造行為文化","薪酬與文化無關","只發現金","越複雜越好","A","過度短期化激勵會催生冒進與掩蓋文化,須平衡長期與合規行為。"],[44,5,"5","「敢於發言」(speak up)文化的治理保障是:","有效的舉報機制、非報復政策與管理層對壞消息的正面回應","只靠個人勇氣","懲罰舉報者","匿名失效","A","董事會須透過審計委員會監察舉報制度的實效與文化響應。"],[45,5,"5","董事會在併購或重組中對文化的角色是:","將文化盡職調查納入交易評估,規劃整合中的文化融合","只看財務","文化與交易無關","事後再說","A","文化衝突是併購整合失敗的主因之一,須前置管理。"],[46,5,"5","「心理契約」被打破(如突變式裁員)的治理風險是:","信任崩塌、敬業度下滑與人才流失,損害長期執行力","無風險","立即恢復","只影響當季","A","重大人事變動須以公平程序與溝通維護組織信任。"],[47,5,"5","董事會監察「亞文化」(如銷售部門激進文化)的方法是:","跨部門數據比較、直達一線的溝通渠道與針對性審計","相信匯報就好","只看總部","無須理會","A","組織亞文化可能偏離整體準則,須以數據與直接接觸識別。"],[48,5,"5","文化與合規的關係是:","文化決定合規規則是否被真正執行,是「紙面合規」與「實質合規」的分界","無關","合規可替代文化","文化只是口號","A","監管機構(如 SFC/HKMA)日益將文化與治理列為檢查重點。"],[49,5,"5","新任董事理解企業文化的最佳途徑是:","走訪一線、與不同層級員工交流、審閱調研與舉報數據","只讀年報","只聽高層簡報","無須了解","A","直接的組織接觸有助董事校準對文化現實的判斷。"],[50,5,"5","董事會年度議程納入文化議題的方式是:","定期審視文化指標、重大人事/操守事件及員工調研結果","永不討論","只在危機後討論","交由公關","A","文化須作為常設治理議題,而非事件驅動的臨時話題。"],[51,6,"6","董事會資訊入口(board portal)的主要價值是:","安全集中地分發會議文件、便利註釋與決策追蹤","取代董事","增加費用","用於宣傳","A","門戶系統同時提升安全(權限、加密)與效率(版本控制、行動端閱讀)。"],[52,6,"6","「會議效能回顧」(meeting effectiveness review)的簡便做法是:","每次會議後快速收集成員對議程、材料與討論質量的反饋","不做回顧","一年後回想","由外人打分","A","高頻小回顧能持續微調會議設計,是低成本高回報的工具。"],[53,6,"6","董事會行事曆(board calendar)的作用是:","將法定與治理議題(年報、委員會、風險、培訓)按年度排布","只列假期","無須規劃","由行政自定","A","公司秘書以此確保法定時點與治理節奏不被遺漏。"],[54,6,"6","決策品質檢查清單(decision checklist)常包含:","資訊是否完整、替代方案、風險、利益衝突與後續監察安排","只看成敗","跳過風險","由秘書決定","A","結構化清單降低遺漏與偏誤,提升決策紀律。"],[55,6,"6","董事與管理層之外的資訊接觸(如直達內審、外部顧問)的治理意義是:","減少資訊過濾,增強董事會獨立判斷能力","增加內耗","違反規定","無意義","A","守則與良好實踐允許董事在合理程序下直接獲取獨立意見。"],[56,6,"6","遠程/混合會議模式下維持效能的關鍵是:","議程更聚焦、材料更早發放、刻意安排互動與保密管控","關閉攝影頭","議題越多越好","無須調整","A","遠程會議弱化非語言訊號,須以流程設計補償互動與坦率。"],[57,6,"6","董事會知識管理(如決策檔案庫)的長期價值是:","保留治理記憶,縮短新董事學習曲線,支援連續性","增加儲存","無用","供媒體查閱","A","人員更替中知識流失是治理斷層的主因,須制度化保存。"],[58,6,"6","主席年度工作計劃通常包括:","議程藍圖、策略 retreat、個別董事溝通安排與評估跟進","只開例會","無計劃","由秘書代勞","A","主席的角色是治理領導者,須有年度治理工作計劃。"],[59,6,"6","「策略 retreat」(董事會外訓營)的價值是:","提供充裕時間深度討論戰略與董事會自身課題,促進凝聚","旅遊團建","純聚餐","無須安排","A","每年至少一次的深度戰略討論是董事會跳出例行事務的重要機制。"],[60,6,"6","衡量董事會動態改善的證據可以是:","評估行動計劃完成率、會議效能反饋趨勢與決策重做率","無法衡量","只看出席率","只看會議數","A","效能改善須以行動落地與行為變化的證據衡量,避免自評自滿。"],[121,7,"7","「預讀材料包」的最佳實踐是:","提前3-7天連同議程發放,附摘要與決策請求","會前5分鐘","會後補發","只發摘要","A","充分的預讀時間是有效質詢與決策的前提。"],[122,7,"7","「決策請求單」(decision paper)的標準結構是:","背景、選項分析、風險、建議與所需決議","純敘述","無結構","只列數據","A","標準化文件提升董事會決策效率與質量。"],[123,7,"7","會議時間分配的原則是:","策略議題佔主,常規報告以書面先行","全部等時","報告為主","無分配","A","時間預算反映治理優先級。"],[124,7,"7","「遠程表決」的法律有效性取決於:","章程與會議規則允許及程序完整","一律無效","一律有效","主席決定","A","電子參與須符合章程與法例(如《公司條例》電子通訊規定)。"],[125,7,"7","「會前簡報」(pre-brief)由主席與誰進行最常見?","CEO 與公司秘書,對齊議程與敏感事項","全部董事","股東","無對象","A","主席-CEO-秘書三方會前協調是議程質量的關鍵。"],[126,7,"7","「執行環節」(executive session)後的產出應是:","向 CEO 傳達的具體反饋或行動","無產出","純聊天","秘密決議","A","閉門討論的價值在於形成建設性反饋。"],[127,7,"7","「會議紀錄的行動欄」(action log)的用途是:","追蹤決議與行動的責任人與期限","裝飾紀錄","無用途","代替決議","A","行動欄是會議落地的執行追蹤工具。"],[128,7,"7","「敏感議題」的會議安排要點是:","預留時間、控制文件流傳(如現場發放)","照常群發","取消討論","口頭討論不留痕","A","敏感事項的文件管控平衡知情與保密。"],[129,7,"7","「新議題插入」的治理規則是:","重大新事項未經預讀宜列為知悉或下次決策","直接表決","由主席個人決定","禁止插入","A","程序紀律保護決策質量。"],[130,7,"7","「會議效能指標」可以是:","文件準時率、決策重做率、行動完成率","會議時長","出席禮品","無指標","A","流程指標客觀反映會議治理質量。"],[131,8,"8","委員會「資訊優勢」的管理要點是:","委員會紀錄與要點及時傳閱全體董事","資訊保密不傳","只主席知道","無管理","A","委員會是董事會的延伸,資訊須回流全體。"],[132,8,"8","委員會「專業深化」的訓練安排是:","定期專題簡報(新準則、新法規)與外聘專家","無培訓","只開會","個人自學","A","委員會成員須維持專業時效。"],[133,8,"8","委員會之間「議題重疊」的協調機制是:","聯席會議或共享議題地圖明確主責委員會","各自為政","取消委員會","主席裁決一切","A","議題地圖避免監察重複與缺口。"],[134,8,"8","「委員會主席」的選任考量是:","專業能力、時間投入與領導討論的技巧","資歷最老","關係最好","隨機","A","委員會主席的勝任度直接影響監察深度。"],[135,8,"8","「審計委員會與內審主席的定期單獨會議」的目的是:","在無管理層在場時討論敏感事項","形式安排","無目的","代替審計","A","私下溝通保護獨立訊息通道。"],[136,8,"8","「委員會出席率」低的原因排查包括:","會期衝突、材料負擔與議題設計","無原因","只怪個人","忽略","A","低出席常是結構問題,須從設計解決。"],[137,8,"8","「提名委員會」納入多元目標的方式是:","候選名單要求、技能矩陣缺口導向","無方式","口頭承諾","固定名單","A","將多元與技能目標制度化於提名流程。"],[138,8,"8","「風險委員會」與業務部門的關係是:","監督與挑戰,同時了解業務現實","完全脫離","代替業務","無關係","A","風險治理須貼近業務而不被業務俘獲。"],[139,8,"8","「委員會效率」的提升工具是:","標準議程模板、年度議題日曆與會前預讀","更多會議","無工具","口頭匯報","A","流程工具降低協調成本。"],[140,8,"8","「委員會年度匯報」的內容應包括:","全年工作、重大發現與建議、跟進狀態","只列會議次數","無匯報","口頭一句","A","年度匯報是委員會向董事會與股東問責的載體。"],[141,9,"9","危機初期董事會的第一要務是:","啟動危機治理架構(指揮線、資訊流、決策授權)","開發布會","追究責任","更換管理層","A","先建立治理秩序再處理事件本身。"],[142,9,"9","危機中的「資訊頻率」應是:","高頻定時更新+重大事項即時通報","每天一次","每周一次","無節奏","A","節奏化通報穩定董事會判斷與對外口徑。"],[143,9,"9","「危機中 CEO 繼任」的預備條件是:","繼任計劃已在平時維持更新","臨時招聘","無需準備","由主席兼任即可","A","危機繼任的可行性取決於平時的梯隊建設。"],[144,9,"9","「外部顧問」在危機中的作用是:","法律、公關與技術專項支援,須統一協調","各說各話","無作用","取代董事會","A","顧問團隊須在治理架構內協調運作。"],[145,9,"9","「危機後復盤」的產出應是:","根源分析、治理與控制修正及問責處理","表揚大會","無復盤","內部消化","A","復盤將危機轉化為組織學習與韌性。"],[146,9,"9","「危機溝通」的內部優先順序通常是:","員工→客戶→市場/監管(按影響與義務排序)","媒體優先","無順序","股東唯一","A","內部先安,對外才有一致口徑。"],[147,9,"9","「停牌決策」的考量因素包括:","消息洩漏風險、市場公平性與復牌條件","股價高低","無因素","情緒","A","停牌是保護市場公平的工具,須評估利弊與時限。"],[148,9,"9","「監管溝通」在危機中的原則是:","主動、及時、一致,指定單一聯絡窗口","被動拖延","多頭回應","隱瞞","A","監管信任靠一致與透明維護。"],[149,9,"9","「危機授權」的事前設定是:","明確管理層可先行動作與須上會事項","無授權","全部上會","全部下放","A","授權清晰避免危機中決策癱瘓或越權。"],[150,9,"9","「董事會聲譽管理」的長期基礎是:","平時的治理質量與誠實記錄","公關預算","股價管理","無基礎","A","危機中的公信力源於日常治理積累。"],[151,10,"10","「董事候選人評估」的維度包括:","技能、經驗、時間可用性、獨立性與行為風格","只看履歷","只看人脈","只看學歷","A","結構化評估降低提名失誤。"],[152,10,"10","「搜尋顧問」的選用要點是:","明確成功標準、多元候選名單與利益衝突管理","只看費用","無標準","內定人選","A","專業搜尋須有透明的評選程序。"],[153,10,"10","「首次任董事」的支援設計是:","就任培訓、夥伴制與首年較淺的委員會職責","直接任主席","無支援","只給文件","A","分階段投入降低新手風險。"],[154,10,"10","「性別多元」目標的落實機制是:","提名長名單含多元候選、考核進度披露","口頭支持","無機制","設硬性無限額","A","制度化於提名流程+透明披露是國際趨勢。"],[155,10,"10","「董事離任」的治理處理包括:","評估其貢獻與原因、更新技能矩陣與繼任","無處理","立刻抹除","只辦歡送","A","離任分析回饋提名與組合管理。"],[156,10,"10","「董事會規模調整」的觸發因素是:","戰略複雜度、委員會負荷與治理效率","固定不變","越多越好","越少越好","A","規模隨治理需要動態調整。"],[157,10,"10","「海外董事」的治理考量是:","時區安排、法規差異培訓與會議模式","一律不聘","無考量","只看國籍","A","國際化董事帶來視野,須解決參與障礙。"],[158,10,"10","「連任評估」的標準應包括:","出席、貢獻、獨立性再確認與技能持續性","自動連任","只看年資","無標準","A","連任是組合管理的節點,須有客觀標準。"],[159,10,"10","「利益衝突」在新董事加入時的處理是:","納入衝突登記並定期更新聲明","無需處理","口頭提醒","事後再說","A","衝突申報是董事就任的標準程序。"],[160,10,"10","「董事會人才管道」的長期建設是:","建立觀察員/替補機制與外部人才庫","需要時再找","無管道","內部指定","A","管道建設縮短未來空缺的填補時間。"],[161,11,"11","「董事會手冊」(board manual)的內容應包括:","治理架構、委員會職權、流程、政策與紀錄模板","產品目錄","客戶資料","無內容","A","手冊是新董事與治理流程的單一事實來源。"],[162,11,"11","「年度治理日曆」的編製人是:","公司秘書與主席/委員會主席協商確定","管理層單方","外部顧問","無人編製","A","日曆確保法定與治理議題按時覆蓋。"],[163,11,"11","「利益衝突聲明」的頻率通常是:","就任時及每年更新","十年一次","無需聲明","口頭即可","A","年度聲明使衝突管理有紀錄可依。"],[164,11,"11","「文件保留政策」對治理文件的要求是:","法定期限(如紀錄不少於10年)與安全存取","永久保留","即時銷毀","無政策","A","保留與銷毀須平衡法律與安全。"],[165,11,"11","「決策授權表」的更新觸發是:","組織變動、法規變化或評估發現","永不更新","隨意更新","由員工決定","A","授權須與組織現實同步。"],[166,11,"11","「董事會資訊政策」應規範:","資訊分發範圍、保密與移動設備管理","無政策","自由轉發","無保密","A","資訊政策防範洩露與內幕交易風險。"],[167,11,"11","「治理流程數字化」的優先領域是:","文件分發、審批流、衝突登記與行動追蹤","全部紙質","只娛樂化","無數字化","A","核心流程數字化提升效率與可審計性。"],[168,11,"11","「公司秘書的獨立性」體現在:","直接向主席/董事會報告治理事宜","隸屬銷售部","由 CEO 評分決定去留","無獨立性要求","A","治理職能的報告線保障其客觀性。"],[169,11,"11","「董事會決議的執行追蹤」由誰負責?","公司秘書追蹤行動狀態並定期向董事會匯報","無人負責","只由 CEO","外部顧問","A","秘書是決議落地的程序守門人。"],[170,11,"11","「治理文件的版本控制」要點是:","統一命名、生效日期與舊版歸檔","隨意覆蓋","無版本","只存郵箱","A","版本混亂會導致執行依據錯誤。"],[171,12,"12","兩位董事在會上激烈爭執致會議失控,主席應:","暫停會議、重申議題焦點,必要時休會調解","任其發展","驅逐董事","取消會議","A","主席須維護程序與相互尊重。"],[172,12,"12","董事長期以「太忙」缺席委員會會議,應:","由主席與提名委員會檢視其承諾與連任安排","無可奈何","替其表決","公開批評","A","時間承諾是董事職責的一部分。"],[173,12,"12","CEO 提出併購決策「刻不容緩」要求跳過盡調,董事會應:","堅持程序底線,必要時以風險知悉方式決策並紀錄","照辦","秘密進行","無紀錄通過","A","程序讓步須留痕並承擔說明責任。"],[174,12,"12","董事利用會議材料透露的資訊購買股票,公司秘書應:","立即啟動 Model Code 調查並按規定處理/上報","口頭警告了事","幫忙隱瞞","無作為","A","內幕交易嫌疑須正式調查與披露。"],[175,12,"12","新主席上任想「重設」議程,公司秘書應:","協助制定年度議程藍圖並保留法定與治理必選項","全部推翻","無所作為","拒絕配合","A","議程改革須在治理完整性內進行。"],[176,12,"12","股東問詢董事會評估結果,恰當的回應是:","概述流程與改進方向,不披露個別評分","全部公開","拒絕一切","虛構結果","A","透明與個別保密的平衡是評估披露的邊界。"],[177,12,"12","管理層長期遲交董事會文件,應:","由主席提出改善要求並納入管理層考核","接受現狀","秘書代寫","降低標準","A","文件紀律是治理質量的前置條件。"],[178,12,"12","董事對公司秘書的紀錄提出異議,應:","核對紀錄與會議錄音/筆記,必要時在下次會議確認修訂","直接修改","拒絕處理","銷毀原稿","A","紀錄修訂須有依據與程序。"],[179,12,"12","委員會建議與管理層意見相左,董事會應:","聽取雙方論據後由全體董事決策","直接採納管理層","直接採納委員會","擱置","A","委員會建議是輸入而非終局,決策屬董事會。"],[180,12,"12","年度評估顯示董事會「資訊過載」,改進方向是:","議題分級(決策/知悉)、摘要化與預讀管理","增加材料","增加會議","維持不變","A","資訊治理以決策相關性為標準。"]]; const IDS = BANK.map(q => q[0]); const QMAP = {}; BANK.forEach(q => { QMAP[q[0]] = q; }); const PASS = 50, EXC = 75; let quiz = [], idx = 0, score = 0, answers = [], mode = 'normal'; let ME = null, quizStart = 0; /* ==================== 本地账号系统 ==================== */ const PAPER = 'cgqp_bd'; const K_ACCOUNTS = 'sunai_accounts_cgqp_bd'; const K_SESSION = 'sunai_session_cgqp_bd'; function wrongKey(){ return 'sunai_wrong_cgqp_bd::' + (ME ? ME.uid : 'guest'); } function recKey(){ return 'sunai_records_cgqp_bd::' + (ME ? ME.uid : 'guest'); } function lsGet(k, d){ try { const v = localStorage.getItem(k); return v == null ? d : JSON.parse(v); } catch(e){ return d; } } function lsSet(k, v){ try { localStorage.setItem(k, JSON.stringify(v)); } catch(e){} } function val(id){ const el = document.getElementById(id); return el ? el.value : ''; } function esc(s){ const d = document.createElement('div'); d.textContent = s == null ? '' : s; return d.innerHTML; } /* SHA-256:在 file:// 打开时 crypto.subtle 不可用,用它做兜底 */ function sha256hex(msg){ function rotr(x, n){ return (x >>> n) | (x << (32 - n)); } const K = [ 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 ]; let H = [0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]; const bytes = []; const u = unescape(encodeURIComponent(msg)); for (let i = 0; i < u.length; i++) bytes.push(u.charCodeAt(i)); const l = bytes.length; bytes.push(0x80); while (bytes.length % 64 !== 56) bytes.push(0); const bitLen = l * 8; bytes.push(0, 0, 0, 0, (bitLen >>> 24) & 255, (bitLen >>> 16) & 255, (bitLen >>> 8) & 255, bitLen & 255); const w = new Array(64); for (let i = 0; i < bytes.length; i += 64){ for (let j = 0; j < 16; j++){ w[j] = (bytes[i+j*4] << 24) | (bytes[i+j*4+1] << 16) | (bytes[i+j*4+2] << 8) | bytes[i+j*4+3]; } for (let j = 16; j < 64; j++){ const s0 = rotr(w[j-15],7) ^ rotr(w[j-15],18) ^ (w[j-15] >>> 3); const s1 = rotr(w[j-2],17) ^ rotr(w[j-2],19) ^ (w[j-2] >>> 10); w[j] = (w[j-16] + s0 + w[j-7] + s1) | 0; } let a=H[0],b=H[1],c=H[2],d=H[3],e=H[4],f=H[5],g=H[6],h=H[7]; for (let j = 0; j < 64; j++){ const S1 = rotr(e,6) ^ rotr(e,11) ^ rotr(e,25); const ch = (e & f) ^ (~e & g); const t1 = (h + S1 + ch + K[j] + w[j]) | 0; const S0 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22); const maj = (a & b) ^ (a & c) ^ (b & c); const t2 = (S0 + maj) | 0; h=g; g=f; f=e; e=(d+t1)|0; d=c; c=b; b=a; a=(t1+t2)|0; } H = [(H[0]+a)|0,(H[1]+b)|0,(H[2]+c)|0,(H[3]+d)|0,(H[4]+e)|0,(H[5]+f)|0,(H[6]+g)|0,(H[7]+h)|0]; } let out = ''; for (let i = 0; i < 8; i++) out += ('00000000' + (H[i] >>> 0).toString(16)).slice(-8); return out; } function bytesToHex(b){ let s = ''; for (let i = 0; i < b.length; i++) s += ('0' + b[i].toString(16)).slice(-2); return s; } function hexToBytes(h){ const o = new Uint8Array(h.length / 2); for (let i = 0; i < o.length; i++) o[i] = parseInt(h.substr(i*2, 2), 16); return o; } function randSalt(){ const b = new Uint8Array(16); if (window.crypto && crypto.getRandomValues) crypto.getRandomValues(b); else for (let i = 0; i < 16; i++) b[i] = Math.floor(Math.random() * 256); return bytesToHex(b); } /* 有 WebCrypto 时用 PBKDF2(10万次),否则用迭代 SHA-256 */ async function makeHash(pwd, salt, algo){ if (algo !== 'sha256x3000' && window.crypto && crypto.subtle && window.TextEncoder){ try { const enc = new TextEncoder(); const key = await crypto.subtle.importKey('raw', enc.encode(pwd), 'PBKDF2', false, ['deriveBits']); const bits = await crypto.subtle.deriveBits( { name: 'PBKDF2', salt: hexToBytes(salt), iterations: 100000, hash: 'SHA-256' }, key, 256); return { algo: 'pbkdf2', hash: bytesToHex(new Uint8Array(bits)) }; } catch(e) { /* 落到下面 */ } } let h = salt + '|' + pwd; for (let i = 0; i < 3000; i++) h = sha256hex(h); return { algo: 'sha256x3000', hash: h }; } function getAccounts(){ return lsGet(K_ACCOUNTS, []); } function saveAccounts(a){ lsSet(K_ACCOUNTS, a); } function showMsg(id, text, kind){ const el = document.getElementById(id); if (!el) return; el.className = 'auth-msg show ' + (kind || ''); el.textContent = text; } function hideMsg(id){ const el = document.getElementById(id); if (el) el.className = 'auth-msg'; } function authMsg(text, kind){ const onReg = document.getElementById('rg-box').style.display !== 'none'; showMsg(onReg ? 'rg-msg' : 'lg-msg', text, kind); } async function doRegister(){ const login = val('rg-login').trim(); const p1 = val('rg-pwd'), p2 = val('rg-pwd2'); if (!login) return authMsg('請填寫登入帳號', 'bad'); if (login.length < 3) return authMsg('帳號至少 3 個字元', 'bad'); if (!p1) return authMsg('請設定密碼', 'bad'); if (p1.length < 4) return authMsg('密碼至少 4 位', 'bad'); if (p1 !== p2) return authMsg('兩次輸入的密碼不一致', 'bad'); const accs = getAccounts(); if (accs.some(a => a.login.toLowerCase() === login.toLowerCase())) return authMsg('此帳號已被使用,請換一個或直接登入', 'bad'); const salt = randSalt(); const h = await makeHash(p1, salt); const acc = { uid: 'u_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7), login: login, salt: salt, algo: h.algo, hash: h.hash, name: login, cls: '', createdAt: Date.now() }; accs.push(acc); saveAccounts(accs); loginAs(acc); } async function doLogin(){ const login = val('lg-login').trim(); const pwd = val('lg-pwd'); if (!login || !pwd) return showMsg('lg-msg', '請輸入帳號與密碼', 'bad'); const acc = getAccounts().find(a => a.login.toLowerCase() === login.toLowerCase()); if (!acc) return showMsg('lg-msg', '帳號或密碼不正確', 'bad'); const h = await makeHash(pwd, acc.salt, acc.algo); if (h.hash !== acc.hash) return showMsg('lg-msg', '帳號或密碼不正確', 'bad'); loginAs(acc); } function loginAs(acc){ ME = acc; lsSet(K_SESSION, acc.uid); // 首次登入时,继承旧版(未分账号)的错题本 const legacy = lsGet('sunai_wrong_cgqp_bd', []); if (legacy && legacy.length){ const mine = loadWrong(); if (!mine.length) saveWrong(legacy.slice()); } hideMsg('lg-msg'); hideMsg('rg-msg'); document.getElementById('lg-pwd').value = ''; document.getElementById('rg-pwd').value = ''; document.getElementById('rg-pwd2').value = ''; renderUserBar(); goHome(); } function doLogout(){ if (!confirm('確定登出?登出後可用其他帳號登入。')) return; ME = null; try { localStorage.removeItem(K_SESSION); } catch(e){} renderUserBar(); document.getElementById('lg-login').value = ''; document.getElementById('lg-pwd').value = ''; show('sc-auth'); } function renderUserBar(){ const bar = document.getElementById('userbar'); if (!bar) return; if (ME){ bar.style.display = 'flex'; document.getElementById('ub-name').textContent = ME.name || ME.login; document.getElementById('ub-cls').textContent = ME.cls ? '(' + ME.cls + ')' : ''; } else { bar.style.display = 'none'; } } function updateMe(){ if (!ME) return; document.getElementById('me-name').value = ME.name || ''; document.getElementById('me-class').value = ME.cls || ''; document.getElementById('me-login').value = ME.login || ''; hideMsg('me-msg'); hideMsg('pw-msg'); document.getElementById('pw-old').value = ''; document.getElementById('pw-new').value = ''; } function saveProfile(){ const accs = getAccounts(); const acc = accs.find(a => a.uid === ME.uid); if (!acc) return showMsg('me-msg', '找不到帳號,請重新登入', 'bad'); acc.name = val('me-name').trim() || acc.login; acc.cls = val('me-class').trim(); saveAccounts(accs); ME = acc; renderUserBar(); showMsg('me-msg', '已儲存', 'good'); } async function changePwd(){ const o = val('pw-old'), n = val('pw-new'); if (!o || !n) return showMsg('pw-msg', '請填寫目前密碼與新密碼', 'bad'); if (n.length < 4) return showMsg('pw-msg', '新密碼至少 4 位', 'bad'); const accs = getAccounts(); const acc = accs.find(a => a.uid === ME.uid); if (!acc) return showMsg('pw-msg', '找不到帳號,請重新登入', 'bad'); const ho = await makeHash(o, acc.salt, acc.algo); if (ho.hash !== acc.hash) return showMsg('pw-msg', '目前密碼不正確', 'bad'); const salt = randSalt(); const hn = await makeHash(n, salt); acc.salt = salt; acc.algo = hn.algo; acc.hash = hn.hash; saveAccounts(accs); ME = acc; document.getElementById('pw-old').value = ''; document.getElementById('pw-new').value = ''; showMsg('pw-msg', '密碼已修改', 'good'); } /* ==================== 错题本 / 记录(按账号) ==================== */ function loadWrong(){ return lsGet(wrongKey(), []); } function wcKey(){ return 'sunai_wrongcnt_' + PAPER + '::' + (ME ? ME.uid : 'guest'); } function loadWC(){ return lsGet(wcKey(), {}); } function saveWC(c){ lsSet(wcKey(), c); } function bumpWrong(id){ const c = loadWC(); c[id] = (c[id] || 0) + 1; saveWC(c); } function clearWrongCnt(id){ const c = loadWC(); if (c[id]) { delete c[id]; saveWC(c); } } function loadFreq(min){ const c = loadWC(); return Object.keys(c) .filter(id => QMAP[id] && c[id] >= min) .sort((a, b) => c[b] - c[a]).map(id => +id); } function saveWrong(w){ lsSet(wrongKey(), w); } function loadRecords(){ return lsGet(recKey(), []); } function addRecord(rec){ const r = loadRecords(); r.unshift(rec); if (r.length > 300) r.length = 300; lsSet(recKey(), r); } /* ==================== 異議回報 ==================== */ function rpKey(){ return 'sunai_reports_' + PAPER + '::' + (ME ? ME.uid : 'guest'); } function loadReports(){ return lsGet(rpKey(), []); } function toggleReport(){ const box = document.getElementById('rp-box'); const show = box.style.display === 'none'; box.style.display = show ? 'block' : 'none'; document.getElementById('rp-msg').style.display = 'none'; document.getElementById('rp-text').value = ''; } function submitReport(){ const q = quiz[idx]; const reason = document.getElementById('rp-text').value.trim(); if (!reason) { alert('請先填寫你的疑問。'); return; } const a = answers[answers.length - 1]; const r = loadReports(); r.push({ paper: PAPER, qid: q.id, ch: q.ch, ref: q.ref, q: q.q.slice(0, 120), myAns: a ? a.pick : '-', correctAns: q.ans, reason: reason.slice(0, 500), at: Date.now() }); lsSet(rpKey(), r); document.getElementById('rp-msg').style.display = 'block'; document.getElementById('rp-msg').textContent = '✅ 已記錄你的回報,感謝!你可以在「異議清單」中一次過傳送給我們。'; setTimeout(()=>{ document.getElementById('rp-box').style.display = 'none'; }, 1800); } function reportTextAll(){ const r = loadReports(); if (!r.length) return ''; return '【IIQE 題目異議回報 - ' + PAPER + '】\n' + r.map((x, i) => (i + 1) + '. 題號#' + x.qid + '(第' + x.ch + '章 ' + (x.ref || '') + ')\n' + '題目:' + x.q + '…\n' + '我的答案:' + x.myAns + '|現有答案:' + x.correctAns + '\n' + '疑問:' + x.reason ).join('\n\n'); } function copyReports(){ const txt = reportTextAll(); if (!txt) { alert('目前沒有異議回報。'); return; } (navigator.clipboard ? navigator.clipboard.writeText(txt) : Promise.reject()) .then(()=>alert('已複製,可貼上給我們。')) .catch(()=>{ const ta = document.createElement('textarea'); ta.value = txt; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); alert('已複製,可貼上給我們。'); }); } function waReports(){ const txt = reportTextAll(); if (!txt) { alert('目前沒有異議回報。'); return; } window.open('https://wa.me/85268751658?text=' + encodeURIComponent(txt), '_blank'); } function openReports(){ const r = loadReports(); const box = document.getElementById('rp-list'); document.getElementById('rp-n').textContent = r.length; document.getElementById('rp-copy').disabled = r.length === 0; document.getElementById('rp-wa').disabled = r.length === 0; box.innerHTML = r.length ? r.slice().reverse().map(x => { const d = new Date(x.at); const pad = n => (n < 10 ? '0' + n : '' + n); return '
' + '
題號#' + x.qid + '(第' + x.ch + '章 ' + (x.ref || '') + ')
' + '
' + esc(x.q) + '…
' + '
我的答案 ' + x.myAns + '|現有答案 ' + x.correctAns + '
' + '
💬 ' + esc(x.reason) + '
' + '
' + d.getFullYear() + '-' + pad(d.getMonth()+1) + '-' + pad(d.getDate()) + '
' + '
'; }).join('') : '
目前沒有異議回報。
'; show('sc-reports'); } function clearWrongBank(){ if (!confirm('確定清空錯題本?此動作無法復原。')) return; saveWrong([]); openWrong(); } function openWrong(){ const w = loadWrong(); document.getElementById('wb-n').textContent = w.length; document.getElementById('wb-redo').disabled = w.length === 0; const fq = loadFreq(2); const wf = document.getElementById('wb-freq'); if (wf) wf.disabled = fq.length === 0; const box = document.getElementById('wb-list'); if (!w.length){ box.innerHTML = '
目前沒有錯題,繼續保持!
'; } else { box.innerHTML = w.map(id => { const q = QMAP[id]; if (!q) return ''; const ai = ['A','B','C','D'].indexOf(q[8]); const at = ai >= 0 ? q[4 + ai] : ''; const wc = loadWC()[id] || 1; const hot = wc >= 2 ? '❌ 錯 ' + wc + ' 次 ' : ''; return '
' + '
' + hot + esc(q[3].slice(0, 90)) + (q[3].length > 90 ? '…' : '') + '
' + '
正確答案:' + q[8] + '. ' + esc(at) + '
' + (q[9] ? '
💡 ' + esc(q[9]) + '
' : '') + '
參考章節 ' + esc(q[2] || '—') + '
' + '
'; }).join(''); } show('sc-wrong'); } function openRecords(){ const r = loadRecords(); const box = document.getElementById('rc-list'); if (!r.length){ box.innerHTML = '
還沒有練習記錄,先做一份模擬練習吧!
'; } else { box.innerHTML = r.map(x => { const d = new Date(x.at); const pad = n => (n < 10 ? '0' + n : '' + n); const when = d.getFullYear() + '-' + pad(d.getMonth()+1) + '-' + pad(d.getDate()) + ' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()); const tone = x.pct >= EXC ? 'var(--ok)' : (x.pct >= PASS ? 'var(--navy2)' : 'var(--bad)'); return '
' + '
' + x.mode + '' + '' + x.pct + '% ' + x.grade + '
' + '
答對 ' + x.correct + ' / ' + x.total + ' 題 · ' + when + '
' + '
'; }).join(''); } show('sc-records'); } function openMe(){ updateMe(); show('sc-me'); } /* ==================== 首页 / 抽题 / 答题 ==================== */ function refreshHome(){ document.getElementById('st-bank').textContent = BANK.length; const w = loadWrong(); document.getElementById('wrong-n').textContent = w.length; document.getElementById('btn-wrong').disabled = w.length === 0; const fn = loadFreq(2); const fe = document.getElementById('freq-n'); if (fe) fe.textContent = fn.length; const bf = document.getElementById('btn-freq'); if (bf) bf.disabled = fn.length === 0; const rn = loadReports().length; const rh = document.getElementById('rp-home-n'); if (rh) rh.textContent = rn; renderUserBar(); } let COUNT = 100; document.querySelectorAll('#seg-count button').forEach(b=>{ b.onclick = ()=>{ document.querySelectorAll('#seg-count button').forEach(x=>x.classList.remove('on')); b.classList.add('on'); COUNT = b.dataset.n === 'all' ? BANK.length : +b.dataset.n; }; }); (function(){ const ab = document.querySelector('#seg-count button[data-n="all"]'); if(ab) ab.textContent = '全部題庫 ' + BANK.length + ' 題'; })(); document.querySelectorAll('#seg-auth button').forEach(b=>{ b.onclick = ()=>{ document.querySelectorAll('#seg-auth button').forEach(x=>x.classList.remove('on')); b.classList.add('on'); const isLogin = b.dataset.tab === 'login'; document.getElementById('lg-box').style.display = isLogin ? 'block' : 'none'; document.getElementById('rg-box').style.display = isLogin ? 'none' : 'block'; hideMsg('lg-msg'); hideMsg('rg-msg'); }; }); document.addEventListener('keydown', function(e){ if (e.key !== 'Enter') return; if (document.getElementById('sc-auth').classList.contains('on')){ if (document.getElementById('rg-box').style.display === 'none') doLogin(); else doRegister(); } }); function show(id){ document.querySelectorAll('.screen').forEach(s=>s.classList.remove('on')); document.getElementById('sc-'+id.replace('sc-','')).classList.add('on'); window.scrollTo(0,0); } function goHome(){ refreshHome(); document.querySelectorAll('.screen').forEach(s=>s.classList.remove('on')); document.getElementById('sc-home').classList.add('on'); window.scrollTo(0,0); } function pickQuestions(){ const w = loadWrong(); if(mode === 'freq'){ const set = new Set(loadFreq(2)); return BANK.filter(q=>set.has(q[0])).sort((a,b)=>{ const c = loadWC(); return (c[b.id]||0)-(c[a.id]||0); }).map(q=>{ const letters = ['A','B','C','D']; const opts = [q[4],q[5],q[6],q[7]]; const ansIdx = letters.indexOf(q[8]); const idxs = [0,1,2,3].sort(()=>Math.random()-.5); const newOpts = idxs.map(j=>opts[j]); const newAns = letters[idxs.indexOf(ansIdx)]; return {id:q[0], ch:q[1], ref:q[2], q:q[3], opts:newOpts, ans:newAns, expl:q[9]}; }); } if(mode === 'wrong'){ const set = new Set(w); return BANK.filter(q=>set.has(q[0])).sort(()=>Math.random()-.5).map(q=>{ const letters = ['A','B','C','D']; const opts = [q[4],q[5],q[6],q[7]]; const ansIdx = letters.indexOf(q[8]); const idxs = [0,1,2,3].sort(()=>Math.random()-.5); const newOpts = idxs.map(j=>opts[j]); const newAns = letters[idxs.indexOf(ansIdx)]; return {id:q[0], ch:q[1], ref:q[2], q:q[3], opts:newOpts, ans:newAns, expl:q[9]}; }); } const byCh = {}; BANK.forEach(q=>{ (byCh[q[1]] = byCh[q[1]]||[]).push(q); }); Object.values(byCh).forEach(a=>a.sort(()=>Math.random()-.5)); const total = BANK.length; const picks = []; const counts = {}; let assigned = 0; for(const ch in byCh){ counts[ch] = Math.floor(byCh[ch].length/total*COUNT); assigned += counts[ch]; } let rem = COUNT - assigned; const order = Object.keys(byCh).sort((a,b)=>byCh[b].length-byCh[a].length); let i = 0; while(rem > 0){ counts[order[i%order.length]]++; rem--; i++; } for(const ch in counts){ counts[ch] = Math.min(counts[ch], byCh[ch].length); picks.push(...byCh[ch].slice(0, counts[ch])); } if(picks.length < COUNT){ const used = new Set(picks.map(q=>q[0])); for(const q of BANK){ if(picks.length>=COUNT) break; if(!used.has(q[0])) picks.push(q); } } return picks.sort(()=>Math.random()-.5).map(q=>{ const letters = ['A','B','C','D']; const opts = [q[4],q[5],q[6],q[7]]; const ansIdx = letters.indexOf(q[8]); const idxs = [0,1,2,3].sort(()=>Math.random()-.5); const newOpts = idxs.map(j=>opts[j]); const newAns = letters[idxs.indexOf(ansIdx)]; return {id:q[0], ch:q[1], ref:q[2], q:q[3], opts:newOpts, ans:newAns, expl:q[9]}; }); } function startQuiz(isWrong, isFreq){ if(!ME){ show('sc-auth'); return; } mode = isWrong ? 'wrong' : (isFreq ? 'freq' : 'normal'); quiz = pickQuestions(); if(!quiz.length){ alert(mode==='wrong' ? '錯題庫是空的,先去練習吧!' : (mode==='freq' ? '暫時沒有常錯題(答錯 2 次以上才會收錄)。' : '沒有可用題目')); return; } idx = 0; score = 0; answers = []; quizStart = Date.now(); document.getElementById('q-mode').textContent = mode==='wrong' ? '錯題重做' : (mode==='freq' ? '🔥 常錯題重做' : '模擬練習'); document.querySelectorAll('.screen').forEach(s=>s.classList.remove('on')); document.getElementById('sc-quiz').classList.add('on'); window.scrollTo(0,0); renderQ(); } let curLocked = false; function renderQ(){ const q = quiz[idx]; curLocked = false; document.getElementById('q-idx').textContent = '第 ' + (idx+1) + ' / ' + quiz.length + ' 題'; document.getElementById('pbar').style.width = (idx/quiz.length*100)+'%'; document.getElementById('q-text').textContent = q.q; const box = document.getElementById('q-opts'); box.innerHTML = ''; ['A','B','C','D'].forEach(L=>{ const b = document.createElement('button'); b.className = 'opt'; b.innerHTML = '' + L + '.' + esc(q.opts[['A','B','C','D'].indexOf(L)]) + ''; b.onclick = ()=>answer(L, b); box.appendChild(b); }); const ex = document.getElementById('q-expl'); ex.className = 'expl'; ex.innerHTML = ''; document.getElementById('btn-next').disabled = true; document.getElementById('btn-next').textContent = (idx === quiz.length-1) ? '查看成績 🏁' : '下一題 →'; } function answer(L, btn){ if(curLocked) return; curLocked = true; const q = quiz[idx]; const correct = (L === q.ans); const btns = document.querySelectorAll('#q-opts .opt'); btns.forEach(b=>{ b.disabled = true; }); const ansIdx = ['A','B','C','D'].indexOf(q.ans); btns[ansIdx].classList.add('correct'); if(!correct){ btn.classList.add('wrong'); } btns.forEach(b=>{ if(b!==btns[ansIdx] && b!==btn) b.classList.add('dim'); }); if(correct){ score++; clearWrongCnt(q.id); } else { const w = loadWrong(); if(!w.includes(q.id)){ w.push(q.id); saveWrong(w); } bumpWrong(q.id); } answers.push({q, pick:L, correct}); const ex = document.getElementById('q-expl'); ex.className = 'expl show ' + (correct ? 'good' : 'bad'); const expl = q.expl && q.expl.length > 3 ? q.expl : '建議重溫本章節課程內容,加深理解。'; ex.innerHTML = (correct ? '\u2705 答對了!' : '\u274C 答錯了。正確答案:' + q.ans + '
') + '
💡 ' + esc(expl) + '
' + '參考章節 ' + esc(q.ref||'—') + ''; document.getElementById('btn-next').disabled = false; } function nextQ(){ if(idx < quiz.length-1){ idx++; renderQ(); } else showResult(); } function quitQuiz(){ if(confirm('確定離開本次練習?作答紀錄將不會保存。')) goHome(); } function showResult(){ const pct = Math.round(score/quiz.length*100); document.getElementById('score-num').textContent = pct; const ring = document.getElementById('ring'); ring.style.background = 'conic-gradient(' + (pct>=PASS?'var(--navy2)':'var(--bad)') + ' ' + (pct*3.6) + 'deg, #ece7db 0deg)'; const g = document.getElementById('grade-badge'); if(pct >= EXC){ g.className='grade exc'; g.textContent='🏆 優秀'; } else if(pct >= PASS){ g.className='grade pass'; g.textContent='\u2705 合格'; } else { g.className='grade fail'; g.textContent='\u274C 不合格'; } document.getElementById('score-detail').textContent = '答對 ' + score + ' / ' + quiz.length + ' 題(合格線 ' + PASS + '%,優秀線 ' + EXC + '%)'; const byCh = {}; answers.forEach(a=>{ const ch = a.q.ch; byCh[ch] = byCh[ch]||[0,0]; byCh[ch][1]++; if(a.correct) byCh[ch][0]++; }); document.getElementById('ch-stats').innerHTML = Object.keys(byCh).sort((a,b)=>a-b).map(ch=>{ const c = byCh[ch][0], t = byCh[ch][1]; return '
第 ' + ch + ' 章:答對 ' + c + ' / ' + t + ' 題(' + Math.round(c/t*100) + '%)
'; }).join(''); const wrongs = answers.filter(a=>!a.correct); document.getElementById('wrong-review').innerHTML = wrongs.length ? wrongs.map(a=> '
答錯' + esc(a.q.q.slice(0,60)) + '…
' + '正確答案:' + a.q.ans + '. ' + esc(a.q.opts[['A','B','C','D'].indexOf(a.q.ans)].slice(0,50)) + '
' ).join('') : '
🎉 全部答對,沒有錯題!
'; if(mode === 'wrong'){ let w = loadWrong(); const corrected = answers.filter(a=>a.correct).map(a=>a.q.id); w = w.filter(id=>!corrected.includes(id)); saveWrong(w); } if(ME){ const gradeTxt = pct >= EXC ? '優秀' : (pct >= PASS ? '合格' : '不合格'); addRecord({ at: Date.now(), mode: mode === 'wrong' ? '錯題重做' : ('模擬練習 ' + quiz.length + ' 題'), total: quiz.length, correct: score, pct: pct, grade: gradeTxt, sec: Math.round((Date.now() - quizStart)/1000) }); } document.querySelectorAll('.screen').forEach(s=>s.classList.remove('on')); document.getElementById('sc-result').classList.add('on'); window.scrollTo(0,0); } /* ==================== 启动 ==================== */ (function init(){ const sid = lsGet(K_SESSION, null); if (sid){ const acc = getAccounts().find(a => a.uid === sid); if (acc) ME = acc; } renderUserBar(); if (ME){ document.querySelectorAll('.screen').forEach(s=>s.classList.remove('on')); document.getElementById('sc-home').classList.add('on'); refreshHome(); } else { document.querySelectorAll('.screen').forEach(s=>s.classList.remove('on')); document.getElementById('sc-auth').classList.add('on'); } })(); refreshHome();