香港公司秘書/公司治理專業資格考試 CGQP|《香港公司法》模擬題庫

每位學員用自己的帳號登入,錯題本與練習記錄會分開存放,不會互相混淆。 帳號資料储存在您目前使用的這台裝置瀏覽器內。
📖 考點速覽|12 章重點蒸餾(開考前 5 分鐘過一遍)(點擊展開)
第1章 · 公司設立與類型
  • 《公司條例》(第 622 章)為香港公司法的核心法例
  • 公司類型:私人/公眾/擔保有限公司;上市與否
  • 公司屬獨立法人(separate legal personality);成立證書即表面證據
第2章 · 章程細則與公司權力
  • 章程細則(articles):內部憲法,成員與公司之間有合約效力
  • 修改章程:特別決議(≥75%),不得違反法例
  • 公司超越經營範圍的行為對善意第三人的效力
第3章 · 董事的任免與職責
  • 董事資格:至少 18 歲、私人公司須有一名自然人董事
  • 罷免董事:通知+普通決議(s462 機制)
  • 董事辭任的通知與生效時間
第4章 · 股份與股本
  • 股份類別權利:股息權、資本分配權、表決權
  • 類別權利變更須類別股東會批准(或其他約定機制)
  • 優先購股權(pre-emption):新股須先向現有股東發售
第5章 · 會議與決議程序
  • 決議門檻:普通決議簡單多數;特別決議 75%
  • 會議法定人數與通知由章程訂明
  • 決議瑕疵的救濟與重開會議
第6章 · 清盤、清盤人與撤銷註冊
  • 自動清盤:成員自動清盤(有償債能力)vs 債權人自動清盤
  • 法院清盤:無力償債、公義清盤(just & equitable)
  • 撤銷註冊:活躍營業、無未清債務、全體成員同意
第7章 · 股份轉讓與登記
  • 股份轉讓:轉讓文書(instrument of transfer)+ 股票交公司登記
  • 轉讓須繳印花稅;公司可依章程拒絕登記並通知
  • 轉讓與贈予、繼承的處理差異
第8章 · 押記與擔保
  • 押記須在 1 個月內向公司註冊處登記,逾期不可對抗清盤人
  • 固定押記(fixed)vs 浮動押記(floating)及結晶化(crystallisation)
  • 負面保證條款(negative pledge)的作用
第9章 · 破產與無力償債
  • 無力償債測試:資產負債表測試 vs 現金流測試
  • 債權人自願安排(CVA)與和解
  • 清盤呈請的依據與程序;優先償還順序
第10章 · 調查與執法權力
  • 處長及證監會的調查權力:查閱簿冊、傳召人證
  • 市場失當行為審裁處(MMT)與刑事檢控的分軌
  • 公司注冊處處長的執法(假注冊、違規申報)
第11章 · 高級人員責任
  • 高級人員(officer)定義:董事、秘書及有關人士
  • 失責罪行:罰款、日罰、取消董事資格(DR 序號制度)
  • 公司犯案的歸責:高級人員同意、縱容或疏忽
第12章 · 情景應用
  • 綜合情景:股權糾紛、押記優先次序、清盤分配的推演

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

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

📊 各章節表現

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

📕 我的錯題本(0 題)

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

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

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

🗂 我的練習記錄

👤 我的帳號

🔑 修改密碼

const BANK = [[1,1,"1","香港公司的主要組成文件是:","組織章程細則(Articles of Association)及公司成立表格","股東的口頭協議","商業登記證","租賃合同","A","《公司條例》下公司憲章即組織章程細則;公司亦受法例規管。成立須提交 NNC1 表格及章程。"],[2,1,"1","香港私人有限公司的成員人數上限是:","20人","50人","100人","無上限","B","《公司條例》第11條界定私人公司成員上限為50人,並須限制股份轉讓及不向公眾邀約。"],[3,1,"1","香港公司的「獨立法人地位」確立於經典案例:","Salomon v Salomon & Co Ltd","Donoghue v Stevenson","Carlill v Carbolic Smoke Ball Co","R v R","A","Salomon v Salomon 確立公司為獨立於股東的法律實體,享有自己的權利義務,是公司法基石。"],[4,1,"1","「刺破公司面紗」(lifting the corporate veil)最常見於:","公司濫用法人地位進行欺詐或逃避法律義務時","公司盈利增長時","公司更換名稱時","公司派發股息時","A","法院在欺詐、非法目的或公司為代理人/信託等情況下,會忽略法人地位直究背後控制人。"],[5,1,"1","香港公司可在公司註冊處以哪種方式設立?","提交 NNC1 表格(法團設立表格)及章程細則","口頭宣誓","致電註冊處","發布社交媒體帖文","A","以 NNC1 表格(連同章程)向公司註冊處申請,獲發公司註冊證明書即成立為法團。"],[6,1,"1","擔保有限公司(company limited by guarantee)的特點是:","股東以其擔保額為限承擔責任,通常無股本","必須發行股票上市","成員責任無限","只能由政府設立","A","擔保有限公司成員承諾於清盤時繳付擔保額,常見於社團、慈善機構等非營利組織。"],[7,1,"1","無限公司(unlimited company)在香港的特點是:","成員責任無限,但仍是獨立法人","不是法人團體","不能持有物業","毋須申報","A","無限公司仍是法人,只是成員責任不受限制;其報表冊無須公開(除非上市公司)。"],[8,1,"1","海外公司在香港設立營業地點,須:","按《公司條例》第16部註冊為註冊非香港公司","毋須任何手續","重新在香港成立新公司","只開設銀行戶口即可","A","在港設有營業地點並在香港有實質業務往來的境外公司,須於一個月內註冊為註冊非香港公司。"],[9,1,"1","公司名稱的法定限制包括:","不得與現有公司名稱相同及不得使用禁用字詞","必須以「有限公司」以外的字眼結尾","必須包含創辦人姓名","必須是英文","A","公司名稱須可辨識(有限公司以 Limited/有限公司 結尾)、不與註冊處名冊重複、無違法或誤導字詞。"],[10,1,"1","《公司條例》下「高級人員」(officer)的定義包括:","董事、公司秘書及在授權範圍內行事的經理","只限行政總裁","只限大股東","公司清潔員","A","高級人員包括董事、公司秘書及其他(實際或聲稱)行使管理職能的人員,多數合規刑罰同時適用於公司及其高級人員。"],[11,2,"2","組織章程細則(articles)與股東協議(shareholders' agreement)的主要區別是:","章程須提交註冊並公開,且受公司法框架規管;股東協議屬私人合約,條款可不公開","股東協議比章程更具公開性","兩者完全相同","章程無法律效力","A","章程是公司憲章並對外披露;股東協議是合同性安排,保密性高,但與章程衝突時未必能修改公司法定權力。"],[12,2,"2","修改章程細則所需的決議及法定限制是:","特別決議(75%),修改不得與法例牴觸及須符合程序","普通決議即可","須法院批准","不可修改","A","修改章程須通過特別決議;修改不得使成員承擔更多責任(除非同意)及須真誠為公司整體利益(Allen v Gold Reefs 案)。"],[13,2,"2","「內部管理規則」(Turand rule,Royal British Bank v Turquand 案)是指:","與公司交易的外人可假定公司內部程序已妥為遵守","公司內部文件對外一律無效","董事可無視章程","股東無權查閱紀錄","A","內部管理規則保護真誠交易的第三人,其可假定公司已按章程履行內部程序,無須查核董事決議等內部合規。"],[14,2,"2","董事的權力來源通常是:","公司章程及股東決議的授予","個人聲望","政府任命","法院指令","A","董事行使權力須以章程授權及(特定事項)股東決議為基礎,並受法例及信義職責約束。"],[15,2,"2","保留事項(reserved matters)通常指:","須特定股東或董事會特別批准的事項,常見於合資公司股東協議","公司日常文具採購","員工餐單選擇","年會紀念品設計","A","保留事項是小股東/投資者保護機制,就重大事項(增發股份、重大投資等)設否決或特別批准要求。"],[16,2,"2","公司能力(capacity)方面,現代香港《公司條例》第115條訂明:","公司具有自然人的能力、權利、權力及特權","公司能力受營業目的限制","公司不得持有物業","公司不能起訴","A","第115條確立公司具備自然人的一切能力,越權行為(ultra vires)爭議大為減少。"],[17,2,"2","公司與董事之間的合約,以下正確的是:","公司可與董事訂立合約,但董事須遵守利益披露及批准程序","禁止公司與董事有任何合約","董事合約毋須任何批准","只在清盤時有效","A","董事與公司的重大交易須經利益申報、董事會或股東批准(視乎性質),違反可致合約可撤銷及賠償。"],[18,2,"2","公司名稱更改的法定程序是:","通過特別決議及在規定時間內提交 NM1 表格註冊","直接印製新名片","通知銀行即可","毋須任何手續","A","更改名稱須通過特別決議、以 NM1 表格向註冊處申請,獲發新的公司註冊證明書後生效。"],[19,2,"2","「保留事項」若與章程衝突,一般處理是:","章程為公司憲章,股東協議的保留事項應盡量透過章程落實,否則可能僅具合同效力","股東協議永遠優先","兩者無關","由經理決定","A","股東協議不能直接修改公司法定架構,重大治理安排應反映於章程;否則只能在合同層面追究違約。"],[20,2,"2","公司印章(common seal)在香港的現行規定是:","公司可選擇是否備有印章;備有者須按章程使用,法例亦允許以簽署方式簽立文件","所有文件必須蓋章","禁止使用印章","由法院統一保管","A","2009年改革後印章屬選擇性;文件可由授權人士簽署簽立(契據須符合特定簽署要求)。"],[21,3,"3","香港公司董事的最低人數(私人公司)是:","1名自然人董事","2名","3名","5名","A","《公司條例》第457條要求私人公司至少1名自然人董事,上市公司則須至少2名。"],[22,3,"3","以下哪類人士不可擔任香港公司董事?","未解除破產令的破產人","年滿30歲的人","持有外國護照的人","非公司股東的人","A","未獲解除破產的破產人、因欺詐相關罪行被定罪並受取消資格令約束者不得任董事;外籍人士可以(但上市公司須符合其他規定)。"],[23,3,"3","取消董事資格(disqualification)的常見理由是:","公司清盤中涉及的欺詐或無故持續虧損等不當行為","年齡偏大","離職","持有大量股份","A","法院可因欺詐、挪用、持續違反公司法等行為取消資格,最長15年不得擔任董事或參與管理。"],[24,3,"3","董事免除職務(removal)的程序是:","由公司在股東大會以普通決議罷免(並須發出28天通知)","由行政總裁直接解僱","由公司秘書簽字","無須程序","A","《公司條例》第462條:公司可於董事任期屆滿前以普通決議罷免,須於會前28天向公司及該董事發出通知。"],[25,3,"3","董事辭任時的通知方式是:","向公司發出書面辭任通知(NND4 由公司提交註冊處)","口頭告知同事","在公司群組留言","無須通知","A","董事可向公司發出辭任通知,公司須在15天內以 ND2B 表格申報註冊處,並登記於董事登記冊。"],[26,3,"3","董事的「不受約束的判斷」職責是指:","董事不得因受他人控制而行事,須為適當目的獨立判斷","董事可任意行事","董事不受法例約束","董事無須出席會議","A","若董事實際上受制於他人(如影子董事指示),即違反獨立判斷職責;該職責防止董事淪為傀儡。"],[27,3,"3","董事職責中「促進公司成功」的含義是:","以全體成員整體利益行事,並考慮僱員、供應商、社區及環境影響等長期後果","只為大股東利益","只顧短期利潤","促進董事個人財富","A","第465(1)條要求董事真誠地以全體成員整體利益促進公司成功,並考慮僱員利益、商業往來、環境影響及公司聲譽等因素。"],[28,3,"3","董事薪酬的批准權限一般屬於:","由章程或股東決議授權;上市公司的董事薪酬須於股東大會批准","董事自行決定","公司秘書決定","核數師決定","A","董事服務酬金須經股東批准(除非章程另有授權),上市公司須在年報詳細披露各董事酬金。"],[29,3,"3","董事貸款(loans to directors)的法定限制是:","公司一般不得向董事或其關聯人士提供貸款,除符合法定例外","可以無限制提供","只須口頭同意","由公司秘書決定","A","《公司條例》第500-502條原則禁止向董事及關聯實體貸款,例外包括小額開支、公司集團內貸款等須經批准的情況。"],[30,3,"3","董事與公司的合約若未經批准且存在未披露利益,可能導致:","公司可撤銷合約、董事須交還所得利潤","合約自動有效","董事獲得獎勵","無任何後果","A","違反信義職責的後果包括合約可撤銷、利益返還(account of profits)、損害賠償,並可能觸犯刑事規定。"],[31,4,"4","「面值」(par value)制度在香港的現狀是:","2014年新《公司條例》起已取消,股份無面值","仍然強制使用","只在上市公司使用","由銀行決定","A","第622章引入無面值(no-par value)制度,簡化股本會計及股份發行定價。"],[32,4,"4","資本維持原則(capital maintenance doctrine)的核心是:","公司不得未經法定程序向股東返還資本","公司不得盈利","公司必須每年增資","公司資本只可存入現金","A","公司資本須保持作為債權人的保障,回購、贖回、股息及削減股本均須依循法定程序。"],[33,4,"4","削減股本(capital reduction)的合法途徑:","由法院確認或以償付能力陳述(solvency statement)支持的特殊決議","董事會內部同意即可","口頭宣佈","毋須任何程序","A","《公司條例》第218條提供兩條路徑:法院批准或以償付能力陳述支持的特殊決議(無須法院程序)。"],[34,4,"4","償付能力測試(solvency test)要求:","董事確認公司在減資/分派後仍能償還到期債務","公司股票上漲","公司須持有現金","由核數師簽發意見","A","董事須根據償付能力陳述確認公司有能力按期償債,並由核數師或律師發表報告支持。"],[35,4,"4","股份回購(share buy-back)的合規要點是:","須符合《公司條例》及(上市公司)《上市規則》及《收購守則》的程序,經股東批准","可在私下秘密進行","無須股東批准","毋須公告","A","上市公司的股份回購須經股東一般性授權或特別批准、按規定程序進行並公告;違反可構成市場失當。"],[36,4,"4","優先股(preference shares)的特點通常是:","在股息分配及清盤時優先於普通股,但一般無投票權或有限投票權","永遠有投票權","只能由董事持有","不能派息","A","優先股權利由章程及發行條款界定,常見特徵是固定股息優先及清盤優先,投票權受限。"],[37,4,"4","股份轉讓的生效時點是:","完成成員登記冊轉讓登記時","簽署買賣合約時","支付款項時","口頭協議時","A","公司股份轉讓自登記於成員登記冊時生效,登記前受讓人尚非法定成員。"],[38,4,"4","「攤薄」(dilution)風險常見於:","公司增發新股而現有股東未按比例認購時","公司派息時","公司購買辦公用品時","公司上市前","A","增發股份若未經現有股東按比例參與,其持股百分比及投票權會被攤薄,故法定/上市規則要求優先認購權(pre-emption)。"],[39,4,"4","法定股本(authorised share capital)在香港現行制度下:","已於2014年廢除","仍然強制申報","由證監會設定","等於註冊資本","A","無面值制度下,法定股本概念已廢除,公司只需申報已發行股本總額。"],[40,4,"4","股息分派的法定前提是:","有可分派利潤(accumulated realised profits)並經董事會決議","有現金即可","股東要求即可","無任何限制","A","第291條規定只有累積已實現利潤(扣除累積虧損)方可分派,違反分派令知情的董事及股東負返還責任。"],[41,5,"5","私人公司成員大會的通知期一般為:","14天","21天","28天","7天","A","私人公司成員大會須發出不少於14天通知(除非經特定多數同意縮短)。"],[42,5,"5","決議類別中,「特別決議」適用於:","修改章程、更改名稱、削減股本、自願清盤等重大事項","日常營運決策","批准員工加薪","採購辦公用品","A","特別決議(75%多數)適用於公司法指明的重大事項;其他事項一般以普通決議處理。"],[43,5,"5","「一致同意決議」(unanimous resolution)的特點是:","須全體合資格成員書面同意,主要適用於私家公司某些特定事項","只須主席同意","由法院下令","適用於上市公司日常決策","A","某些特定事項(如重註資本細節)須全體成員一致同意,反映其對成員權利的重大影響。"],[44,5,"5","會議通知的「送達」要求是:","按章程及法例允許的方式(書面、電郵等)送達每名成員及董事","只在大會現場宣讀","只在報紙刊登","口頭通知部分股東即可","A","通知須按章程規定方式送達所有有權出席者,程序瑕疵可影響決議效力。"],[45,5,"5","投票平局(casting vote)的處理是:","按章程細則規定(通常主席有決定性一票)","一律無效","由公司秘書決定","抽籤決定","A","主席是否擁有 casting vote 須視乎章程;若章程未規定,平局即決議不通過。"],[46,5,"5","公司決議的「推翻」途徑包括:","程序違規時可由法院宣布無效或通過新的決議修正","一律不可推翻","由公司秘書撤銷","向媒體投訴","A","違反通知、多數或法例的決議可被挑戰;公司亦可在一定期限內以新決議處理程序瑕疵。"],[47,5,"5","股東查閱公司紀錄的法定權利:","成員有權查閱成員登記冊等法定紀錄,公司須提供合理協助","無任何查閱權","只能查閱年報","查閱須警方批准","A","法定登記冊(成員、董事、押記等)須供成員免費或收費查閱,保障股東知情權。"],[48,5,"5","「技術違規」(procedural irregularity)對決議的影響:","多數情況下法院可按公平原則決定是否使決議無效(視乎實質影響)","一律自動無效","一律有效","只須罰款","A","法院按實質公平及對結果的影響判斷程序違規的後果,並非所有違規都推翻決議。"],[49,5,"5","「虛假陳述」(misstatement)在會議文件中的法律後果是:","招致刑事責任及民事賠償","無任何後果","只影響公司形象","可獲稅務優惠","A","通函、公告中的虛假或誤導陳述可構成刑事罪行(如《證券及期貨條例》披露規定)及民事欺詐責任。"],[50,5,"5","公司秘書在會議程序中的角色可概括為:","確保通知、法定人數、表決、紀錄及申報全流程合規","代替主席決定議程內容","代替股東投票","自行決定會議結果","A","公司秘書是會議程序的守門人,須確保每個環節符合法例、章程及良好實務。"],[51,6,"6","香港公司「自願清盤」(voluntary winding up)分為:","成員自願清盤及債權人自願清盤","強制清盤及自動清盤","簡易清盤及複雜清盤","個人清盤及公司清盤","A","有償付能力的公司可進行成員自願清盤;無償付能力則須債權人自願清盤,程序及監督主體不同。"],[52,6,"6","強制清盤(compulsory winding up)的申請理由通常是:","公司無力償債及股東特別決議等法定理由","董事會自行決定","公司秘書個人決定","任何員工申請即可","A","《公司(清盤及雜項條文)條例》第177條列明可清盤理由,最常見是無力償債(如未能回應法定償債要求書)。"],[53,6,"6","「法定償債要求書」(statutory demand)的作用是:","證明公司無力償債的證據之一,未於21天內妥為處理可作清盤呈請依據","取代法院判決","自動清盤","僅為提醒","A","債權人可向公司發出償債要求書,公司若未在21天內償付或達成和解,債權人可據此向法院呈請清盤。"],[54,6,"6","撤銷註冊(deregistration)與清盤的主要區別是:","撤銷註冊適用於無營運、無負債的小型公司,程序簡單成本低;清盤涉及資產分配及清算人","撤銷註冊須法院批准","兩者完全相同","清盤更簡單","A","撤銷註冊要求公司從未營運或已停止營運3個月、無未清償債務等;有負債或須分配資產者須清盤。"],[55,6,"6","公司清盤後「財產分配」的優先次序一般是:","清盤費用與清算人酬金、優先債務(如僱員工資)、普通無抵押債權人,最後是股東","股東優先","客戶優先","無先後次序","A","清盤中按法定優先次序分配:清算費用→優先債項→無抵押債權人→成員(如有剩餘)。"],[56,6,"6","清盤人(liquidator)的主要職責是:","收集變現資產、償還債務並向法院/債權人匯報","經營新業務","代表公司起訴所有客戶","無須匯報","A","清盤人接管公司事務,變現資產、裁定債權、分配款項並向法院及債權人提交報告。"],[57,6,"6","「不當交易」(fraudulent trading)的法律後果是:","涉事董事或參與者須對公司債務承擔個人責任,並可能刑事檢控","無任何責任","只影響信用評級","由股東自願承擔","A","第275條規定明知欺詐債權人而繼續交易者,法院可令其個人承擔公司債務,並附帶刑事罰則。"],[58,6,"6","「取消資格令」(disqualification order)的申請主體包括:","破產管理署署長、清盤人、證監會等","只限公司股東","只限員工","只限客戶","A","破產管理署、清盤人、臨時清盤人及證監會(就上市公司失當)均可向法院申請取消資格令。"],[59,6,"6","「成員自願清盤」的前提是:","公司有能力償還全部債務,並由董事作出償付能力聲明","公司破產","法院命令","債權人同意即可","A","成員自願清盤須由全體董事作出償付能力聲明,確認12個月內可清償債務,否則轉為債權人自願清盤。"],[60,6,"6","公司解散(dissolution)後,公司法人地位:","終止,公司不再是法律實體","繼續存在","轉為無限公司","由董事代管","A","解散後法人地位終止;若日後發現仍有資產,可由法院應申請將公司復業處理。"],[121,7,"7","私人公司章程對股份轉讓的常見限制是:","董事會有權拒絕登記轉讓及優先購買權(pre-emption)","自由轉讓","政府批准","無限制","A","私人公司透過章程限制轉讓以維持股東結構穩定,法院一般尊重此類商業安排。"],[122,7,"7","股份轉讓印花稅的計算基準是:","代價或股份價值兩者較高者的0.1%(買賣雙方各付)","1%","免稅","5%","A","《印花稅條例》就香港股份轉讓徵收從價印花稅,未貼印花文件不可作為登記憑證。"],[123,7,"7","公司拒絕登記轉讓時,法定要求是:","須在規定時間內將拒絕理由通知承讓人","無須通知","口頭告知即可","由核數師通知","A","第632條要求公眾公司在限期內登記或以書面說明拒絕理由。"],[124,7,"7","「掛失股份」的正確理解是:","股份本身不會遺失,遺失的是股票憑證,可透過補發程序處理","股份消滅","自動轉讓","無法處理","A","股票是所有權憑證而非股份本身,遺失可循登報與彌償程序補發。"],[125,7,"7","股份共有(joint holding)的表決規則通常是:","登記冊排名在先者投票方為有效(章程可另有規定)","人人可投","無效","抽籤","A","共同持有人中只有首位登記人可行使投票等權利,避免重複投票。"],[126,7,"7","「代名人持有」(nominee holding)對公司登記冊的影響是:","登記冊只顯示代名人,實益擁有人不在登記冊","須列實益人","不允許","由秘書決定","A","這是 SCR 制度存在的背景:以重要控制人登記冊補足實益透明度。"],[127,7,"7","「強制轉讓」條款(如股東退職須售股)的法律風險是:","若條款過於苛刻可能被法院視為不合理限制而無法執行","一定有效","一定無效","無風險","A","法院會審查轉讓限制的合理性,尤其對離職股東的估值機制。"],[128,7,"7","「鎖定期」條款的商業功能是:","保障創業團隊與投資者的穩定期,防止過早退出損害公司","增加費用","無功能","違法","A","鎖定期在創投協議常見,屬合同安排,違反可訴。"],[129,7,"7","「股份質押」與「股份轉讓」的區別是:","質押是擔保安排,股份仍屬出質人;轉讓是所有權移轉","完全相同","質押即轉讓","無區別","A","質押權人於違約時方可處置股份,日常仍由出質人行使權利。"],[130,7,"7","死亡股東的股份處理是:","遺產代理人經死亡證明與授予書後登記為股東或轉讓予受益人","股份作廢","自動歸公司","政府接收","A","登記處須核實遺產授予書方辦理,程序嚴謹保護各方權益。"],[131,8,"8","「浮動押記」(floating charge)的特點是:","以不斷變動的資產(如存貨、應收)作擔保,違約事件時轉為固定押記","固定資產抵押","個人擔保","無擔保","A","浮動押記靈活覆蓋流動資產,經結晶(crystallisation)固定於特定資產。"],[132,8,"8","押記登記的時限與逾期後果是:","設立後一個月內登記,逾期押記對清盤人及債權人無效","三個月","一年","無時限","A","第5條《公司(押記登記)規例》:逾期可向法院申請延展但風險高。"],[133,8,"8","「押記證書」(certificate of registration)的作用是:","證明押記已註冊,是對抗第三方的重要憑證","取代合同","無用","宣傳材料","A","貸款人通常在放款前要求取得押記註冊證書。"],[134,8,"8","「負面保證」(negative pledge)條款的效力是:","承諾不再設立同等或優先押記,屬合同約束而非登記限制","法定禁令","自動登記","無效力","A","違反負面保證構成違約,但後設押記的登記效力不因此受影響。"],[135,8,"8","「個人擔保」(personal guarantee)在公司融資中的風險是:","擔保人個人以全部資產承擔公司債務,違約可致破產","無風險","只影響公司","由公司承擔","A","中小企融資常要求股東個人擔保,須清楚風險並評估償付能力。"],[136,8,"8","「交叉違約」(cross default)條款的作用是:","其他融資違約時本融資亦視為違約,保護債權人及早行動","增加利息","無作用","違法","A","交叉違約使債權人在債務人財務惡化時可提前追償。"],[137,8,"8","「債權證」(debenture)在香港法下的含義是:","涵蓋公司設定的各類擔保文件(固定/浮動押記)","只是債券","股票的一種","無意義","A","法律上 debenture 是廣義擔保文書,是浮動押記的常見載體。"],[138,8,"8","「按揭」(mortgage)與「押記」(charge)的技術區別是:","按揭轉移法定權益(附回贖權),押記只設擔保權益","無區別","完全相同","按揭無效","A","現代實務多用押記形式,避免按揭的複雜回贖規則。"],[139,8,"8","「擔保債權人」在清盤中的地位是:","就其擔保資產優先受償,不參與無抵押分配(除非不足)","最後受償","平等分配","無權利","A","有擔保債權人可行使擔保權(接管/出售),餘額才進入普通清盤分配。"],[140,8,"8","「接管人」(receiver)的委任依據通常是:","押記文件中的授權或法院命令","公司秘書決定","股東決議","自動產生","A","浮動押記持有人可委任接管人接管資產與業務,是債權人的重要救濟。"],[141,9,"9","「無力償債」的兩大測試是:","資產負債表測試(負債>資產)與現金流測試(無力償還到期債務)","利潤測試","規模測試","人數測試","A","兩項測試並用,任一成立即可證明無力償債。"],[142,9,"9","「法定償債要求書」未獲回應後,債權人可以:","向法院提出清盤呈請","直接接管公司","更換董事","出售股份","A","21天後未償付或達成和解,可作清盤呈請依據。"],[143,9,"9","「自願安排」(IVA-like scheme)在公司層面的名稱是:","公司自願償債安排(須債權人會議批准)","口頭協議","單方決定","無此制度","A","《公司條例》第622部? 實際上香港公司重組主要透過方案安排(scheme of arrangement)或臨時清盤人保護。"],[144,9,"9","「方案安排」(scheme of arrangement)的法律基礎是:","《公司(清盤及雜項條文)條例》第674條,須債權人/成員分組批准及法院認許","行政命令","董事決定","股東大會普通決議即可","A","方案安排是大規模債務重組與併購(如私有化)的法定工具。"],[145,9,"9","「臨時清盤人」(provisional liquidator)的主要功能是:","呈請後於清盤令前保護公司資產","經營新業務","出售股份","無功能","A","臨時清盤人凍結管理層權力,防止資產流失。"],[146,9,"9","「優先償還」的債項通常包括:","清盤費用、僱員工資與遣散費等法定優先債項","普通債權","股東貸款","客戶預付","A","《公司(清盤及雜項條文)條例》第265條列明優先順序。"],[147,9,"9","「隱匿資產」在清盤中的後果是:","構成刑事罪行(隱匿公司財產),可判監","無後果","罰款即可","民事賠償","A","第276條及相關罪行針對清盤前後隱匿財產,刑罰嚴厲。"],[148,9,"9","「公司董事」在清盤中的協助義務是:","向清盤人交出資產、賬冊並提供公司事務資料","無義務","只報銷費用","拒絕提供","A","不合作可被檢控或被法院強制。"],[149,9,"9","「重整」(restructuring)與「清盤」的目標差異是:","重整旨在延續企業價值,清盤旨在有序結束並分配資產","完全相同","清盤保留業務","無區別","A","重整透過方案或重融資挽救企業,清盤是最後手段。"],[150,9,"9","「董事薪金在清盤前突增」可能被清盤人視為:","不當支付或欺詐優惠而追回","正常開支","無問題","股東批准即可","A","清盤前向關聯人突增支付可被審查並追回。"],[151,10,"10","財務匯報局(AFRC)的調查權力包括:","就上市實體財匯匯報失當及核數師行為進行查察與調查","無調查權","只提建議","屬私人機構","A","AFRC 2022年轉為獨立監管,直接查察上市公司審計與財匯匯報。"],[152,10,"10","證監會(SFC)的調查工具包括:","要求提供紀錄、約見人士、搜查(經法院手令)","隨意拘捕","無工具","只發信","A","《證券及期貨條例》第179-183條賦予廣泛調查權,妨礙調查屬刑事罪行。"],[153,10,"10","「提交文件命令」不遵守的後果是:","刑事罰款及監禁","自動豁免","無後果","民事和解","A","妨礙監管調查(如銷毀文件)獨立構成嚴重罪行。"],[154,10,"10","公司秘書在監管調查中的恰當角色是:","統籌文件收集、紀錄保存與溝通協調,協助法律顧問","獨自應對","銷毀敏感文件","對外發聲","A","秘書是調查程序管理的中樞,須確保完整與合規。"],[155,10,"10","「廉政公署」對私營機構的管轄依據是:","《防止賄賂條例》第9條(代理人收受利益)","只管政府","無管轄","銀行指引","A","ICAC 可調查私營機構賄賂,第9條是其核心工具。"],[156,10,"10","「競爭事務委員會」關注的行為是:","圍標、操縱價格等反競爭行為(第一/第二行為)","降價促銷","正常合作","上市安排","A","《競爭條例》禁止反競爭協定與濫用市場支配地位。"],[157,10,"10","「個人資料私隱專員」的執法工具包括:","執行通知、調查與檢控","無工具","只提供建議","罰款上限100元","A","違反執行通知可被檢控,罰則隨修例提高。"],[158,10,"10","「跨境數據調取」的合規挑戰是:","內地與香港數據出境規則不同,須評估法律衝突","無挑戰","自由傳輸","由 IT 決定","A","數據跨境須評估《個人信息保護法》與香港私隱法例的雙重義務。"],[159,10,"10","「舉報人」向監管機構直接舉報的保護是:","《證券及期貨條例》第381條等提供有限保護","完全無保護","須公司同意","禁止舉報","A","內部舉報制度仍是最佳實踐,直接舉報受有限法定保護。"],[160,10,"10","「和解協議」(settlement)與監管機構達成的典型條款是:","罰款、補救措施、不再犯承諾及可能的公開聲明","無義務","只道歉","退款即可","A","SFC 和解常涉公開譴責與整改,影響信譽須納入考量。"],[161,11,"11","「在默許、縱容或同意下」(in default)的含義是:","高級人員知悉或應知悉違規而未阻止,與公司共同承擔罰則","無關","自動免責","由股東決定","A","多數公司法罪行含「in default」罰則,強調高級人員的主動合規義務。"],[162,11,"11","「公司秘書」被視為高級人員的原因是:","法律定義包括公司秘書,其須就自身職務行為承擔責任","無法律地位","只屬行政","由主席決定","A","第2條定義公司秘書為高級人員,須勤勉履行法定職務。"],[163,11,"11","「董事指示他人違規」的責任是:","指示者與執行者均可被檢控","只罰執行者","無責任","由公司承擔","A","教唆或授權違規者同樣承擔刑事責任。"],[164,11,"11","「免責條款」(indemnity)對董事刑事責任的效力是:","不能免除刑事責任,民事賠償的免除亦受限制","全部有效","只免刑事","完全無效","A","《公司條例》第470條禁止免除董事的疏忽、違責、失職及欺詐責任。"],[165,11,"11","「董事責任保險」與「公司補償」的關係是:","公司可在合法範圍內為董事購買保險及提供補償(刑事罰款除外)","一律禁止","替代保險","無此制度","A","第470(5)條允許公司為董事購買保險,但不能覆蓋刑事罰款。"],[166,11,"11","「高級人員培訓」的治理意義是:","讓董事與高管理解法律義務,降低「不知者犯規」的風險","浪費時間","無意義","只為形式","A","系統培訓是董事勤勉抗辯與治理文化的一部分。"],[167,11,"11","「授權人員」(authorised person)的範圍包括:","董事、秘書及獲授權代表公司行事的人士","只限董事","清潔員","訪客","A","申報義務由授權人員承擔,授權管理須嚴謹。"],[168,11,"11","「刑事紀錄」對董事資格的影響是:","涉及欺詐等罪行可致取消資格令","無影響","自動破產","由銀行決定","A","法院可因欺詐相關定罪發出取消資格令。"],[169,11,"11","「公司違規時高級人員的抗辯」通常是:","已盡合理努力防止違規(due diligence defence)","不知者無罪","上司指示即可","無抗辯","A","部分罪行設盡責抗辯,須以紀錄證明已採取合理措施。"],[170,11,"11","「累犯」對罰則的影響是:","某些罪行累犯罰則加重,並影響取消資格評估","無影響","減免罰款","自動豁免","A","重複違規顯示治理失效,監管與法院從嚴處理。"],[171,12,"12","公司擬向控股股東出售資產,公司秘書的合規清單應包括:","獨立董事委員會、IFA 意見、獨立股東批准、公告與通函","只通知大股東","直接完成","事後補批","A","關連交易程序是保護小股東的核心,秘書須逐項落實。"],[172,12,"12","董事提出在封鎖期賣股「應急」,公司秘書應:","告知 Model Code 禁止及例外程序(如重大困難下經批准的出售)","直接拒絕後不管","協助隱瞞","代其交易","A","Model Code 允許極端情況下經批准交易,但程序嚴格且須公告。"],[173,12,"12","公司收到法院傳票涉及前董事行為,應:","檢視紀錄與保險,通知 D&O 保險人並委任律師","置之不理","私下和解","刪除紀錄","A","及時通知保險與法律行動保護公司與董事權益。"],[174,12,"12","股東要求召開特別大會討論罷免主席,應:","按法定程序核實請求(5%表決權),安排會議並保障程序","拒絕","拖延","由主席否決","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_hkcl'; const K_ACCOUNTS = 'sunai_accounts_cgqp_hkcl'; const K_SESSION = 'sunai_session_cgqp_hkcl'; function wrongKey(){ return 'sunai_wrong_cgqp_hkcl::' + (ME ? ME.uid : 'guest'); } function recKey(){ return 'sunai_records_cgqp_hkcl::' + (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_hkcl', []); 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();