Files
ClassHelper/scripts/ui-smoke/main.cjs
T

279 lines
23 KiB
JavaScript
Raw Normal View History

2026-10-24 15:43:32 +08:00
YªçŠx-®éÜj×�¢ëiºÚ+Чj[h‘éÜ¢éíÛŸ6å:-jZ.¶›­–)Þ³Rò¢ ¢¢vV"zêynzºòT’Xi.x9þkX¾Šù^ûÈ„VÆV7G&öâš›XªŽyÉþZéîkXþŠxŽYšŽXh^j ŽûÈž8 ¢ ¢¢Šhny¹nûÉ ¢¢âšinš^Xª‹ÛÞûÈŽyIþKª~ièN[»®Kª~xšžûÈ�¢¢"ây›¾[Ù^š^k‹.iù>KˆîyÉþZéXÙ^y›¾[ÙP¢¢2â‹ù¾XZ^K‹¾[ˆ>[¢¢B⢮Kê~‹ëžjòrKŠ®ˆùÎXÙ^˜ Kˆx+žX{²¢®ûÉ®ijÞŠˆ‹zþyK‹zþ[èNXùŽXÉb²š^™Ú.j~š)Žk‹.iù0¢¢( N( B‹ùžiŠò.x+žX{¾[znKê~‹ëžjþk*XøÞ[©B.y¨NY¹î[Ù.kX¾ŠùP¢¢R⢮Kˆ®Šûîi{një^Xù[ˆ>{J~h
^˜ ®yúR¢®ûÉ®XZŽ[þŠÚnY¢²2zy.X .Šêi{b²zîŠêNYîh˜ÞyÉþjÚ>Xù[ˆ0¢¢( N( BKˆ®Šûîi{një^yK'VâæÖ§2y¨Nhê.™(ŽûÈŽK¸®ZJ’£Ó#3£S’y¨NŠûûÈžyÉþZéîX‹n˜
¢¢bâX˜Þzºþ‹zþyKk{™;îy»Nhê^Šëþ™zࢢrâtÖæ–fW7B²6W'f–6Rv÷&W.ûÈŽkXþŠxŽYšŽXúþZ螊8^K‹®[©NyJŽûÈ�¢ ¢¢yJŽk9^ûÈŽ™ÈŠhYîzºþ[{.Y
þXªŽûÈÎK‰BvV"zêynzºþyKX[nh™ŽzêûÈžûÉ ¢¢T•õ4Ôô´UõU$ÃÖ‡GG¢òó#rããã£CòæöFR67&—G2÷V’×6Öö¶R÷'VâæÖ§0¢¢ð¦6öç7Bg2Ò&WV—&R‚væöFS¦g2r“°¦6öç7BF‚Ò&WV—&R‚væöFS§F‚r“°¦6öç7B²Â'&÷w6W%v–æF÷rÒÒ&WV—&R‚vVÆV7G&öâr“° ¢òòKÛþyJŽxºÎz¸¾ûÈŽjøþjÊkˆ^z›®ûÈžy¨BW6W$FFûÈΘþXXÒ6W'f–6Rv÷&¶W"{É>ZÙŽ[ÛY8Þš¨ÎŠø{¹>iéÀ¦–b‡&ö6W72æVçbåT•õ4Ôô´Uõ$ôd”ÄR’°¢ç6WEF‚‚wW6W$FFrÂ&ö6W72æVçbåT•õ4Ôô´Uõ$ôd”ÄR“°§Ð ¦6öç7BD$tUEõU$ÂÒ&ö6W72æVçbåT•õ4Ôô´UõU$Âóòv‡GG¢òó#rããã£Còs°¦6öç7BU4U$äÔRÒ&ö6W72æVçbåT•õ4Ôô´UõU4U"óòwFV6†W#s°¦6öç7B55tõ$BÒ&ö6W72æVçbåT•õ4Ôô´Uõ52óòwFV6†W##2s°¦6öç7B$U5TÅEôd”ÄRÒ&ö6W72æVçbåT•õ4Ôô´Uõ$U5TÅBóòrs° ¢ò¢ ¢¢Kê~‹ëžjþˆùÎXÙ^ûÈŽiYž[ˆŽ‹JnXûrFV6†W#XúþŠxy¨N˜:ŽXˆnûÈž8 ¢¢hÈžŠy.ˆ›.iØ>™™jŠYè¾ûÉ®xúÞ{ª~zêybòZÚnyIþzêybòiYž[ˆŽzêybK¸^zêynYŽXúþŠxûÈÀ¢¢iYž[ˆŽzºþKˆÞ[©NX{®xë‹ùžK©¾XZ^Xú>ûÈŽYîzºþYÎi{n[Ë®j
š¨ÎûÈžûÈÎYºjÚN‹ùž˜xÎy¨NiÉþiɾX Î[ iŠþiYž[ˆŽXúþŠxy¨NXZŽ˜:ŽˆùÎXÙ^8 ¢¢ð¦6öç7BÔTåUô•DTÕ2Ò°¢²Æ&Vâ~Kº®ŠŽy¹‚rÂFƒ¢röF6†&ö&BrÒÀ¢²Æ&Vâ~xúÞ{ª~zêybrÂFƒ¢rö6Æ76W2rÒÀ¢²Æ&Vâ~ZÚnyIþzêybrÂFƒ¢r÷7GVFVçG2rÒÀ¢²Æ&Vâ~ZÚniÉþYŽjÊrÂFƒ¢r÷FW&Ò×vVV·2rÒÀ¢²Æ&Vâ~Šûj>j‚rÂFƒ¢r÷ÆâÖVF—F÷"rÒÀ¢²Æ&Vâ~KÙÎK‰®Xù[ˆ2rÂFƒ¢rö†öÖWv÷&·2rÒÀ¢²Æ&Vâ~˜ ®yú^Xù[ˆ2rÂFƒ¢röæ÷F–f–6F–öç2rÒÀ¢²Æ&Vâ~ŠûîK»brÂFƒ¢rö6÷W'6Wv&RrÒÀ¢²Æ&Vâ~h‰{ºž[Ù^XZRrÂFƒ¢röw&FW2rÒÀ¢òòhÈ’6Æ–VçC§&VB[^zK®ŠëîZH~x«nhXZ^Xú>8 ¢²Æ&Vâ~Zê.h‹~zºòrÂFƒ¢rö6Æ–VçG2rÒÀ¥Ó° ¢ò¢¢iYž[ˆŽzºþ[ø^𾙩‰xþy¨NXZ^Xú>ûÈŽX˜Þzºþ™©‰xò²YîzºòC>ûÈÎXøÎ˜xÞKùÞ™©ÎûÈ’¢ð¦6öç7B„”DDTåôÔTåUôÄ$TÅ2Ò²~iYž[ˆŽzêybrÂ~i[hÚî[©>zêybuÓ° ¢ò¢¢zêynYŽ‹JnXû~ûÈŽiYž[ˆŽ[Ù^XZ^yJŽKè¾ûÈžûÉ®KˆîzxÞZÙþZ螊8^X‰ÞZx¾XÉn‹JnXû~Kˆˆ{B¢ð¦6öç7BDÔ”åõU4U$äÔRÒ&ö6W72æVçbåT•õ4Ôô´UôDÔ”âóòvFÖ–âs°¦6öç7BDÔ”åõ55tõ$BÒ&ö6W72æVçbåT•õ4Ôô´UôDÔ”åõ52óòvFÖ–ã#2s° ¦6öç7B&W7VÇG2ÒµÓ°¦gVæ7F–öâ&V6÷&B†æÖRÂö²ÂFWF–ÂÒrr’°¢&W7VÇG2çW6‚‡²æÖRÂö²ÂFWF–ÂÒ“°¢6öç6öÆRæÆör†G¶ö²òuµ55Òr¢u´d”ÅÒwÒG¶æÖWÒG¶FWF–ÂòÒG¶FWF–ÇÖ¢rwÖ“°§Ð ¦gVæ7F–öâ6ÆVW†×2’°¢&WGW&âæWr&öÖ—6R‚‡&W6öÇfR’Óâ6WEF–ÖV÷WB‡&W6öÇfRÂ×2’“°§Ð ¢ò¢¢YÊŽk‹.iù>‹ù¾zˆ¾˜x΋ÚîŠú.zØž[è^iÚK»nh‰z¸²¢ð¦7–æ2gVæ7F–öâv—Df÷"‡v–âÂW‡&W76–öâÂF–ÖV÷WD×2ÒS’°¢6öç7BFVFÆ–æRÒFFRææ÷r‚’²F–ÖV÷WD×3°¢v†–ÆR„FFRææ÷r‚’ÂFVFÆ–æR’°¢6öç7Bö²Òv—Bv–âçvV$6öçFVçG2æW†V7WFT¦f67&—B€¢‚‚’Óâ²G'’²&WGW&â&ööÆVâ‚GW‡&W76–öçÒ“²Ò6F6‚²&WGW&âfÇ6S²ÒÒ’‚–À¢“°¢–b†ö²’&WGW&âG'VS°¢v—B6ÆVWƒS“°¢Т&WGW&âfÇ6S°§Ð ¢ò¢ ¢¢zêynYŽK‰>[îyJŽKè¾ûÉ®y›¾[ÙR(i"iYž[ˆŽzêyb(i"[Ù^XZ^iYž[ˆ‚(i"ijÞŠˆX{®xëYÊŽX‰~Š‚(i"XŠ™šNkˆ^yn8 ¢ ¢¢yJŽh‹~Šhk".iJþhÈ[Ù^XZ^ZÚnyIþK™þŠhiJþhÈ[Ù^XZ^ˆ[ˆŽûÈÎK‰N[Ù^XZ^ˆ[ˆŽy¨NiØ>™™Xú®iÈ’FÖ–â.ûÉ ¢¢YºjÚN‹ùž˜xÎyJ‚¢®zêynYŽ‹JnXû~yÉþZéîx+žKˆ˜Ò¢®ûÈŽŠŽXÙR(i"hê^Xú2(i"X‰~ŠŽX‹~ikûÈžûÈÎ[›nYÊŽiKn[ îXŠhèžkX¾Šù^‹JnXû~ûÈÀ¢¢KùÞŠø.i»NiJþhÈ[Ù^XZ^iYž[ˆ‚.‹ùžiÚKˆÞiŠþXú®iÈžhê^Xú>ˆ;Þ‹y8yXΙÚ.x+žKˆÞXªŽ8 ¢¢ð¦7–æ2gVæ7F–öâ'VäFÖ–åFV6†W$6†V6·2‡v–â’°¢6öç7BW6W&æÖRÒ6ÖöU÷FV6†W%òG´FFRææ÷r‚—Ö°¢òòZy>YÞY»®Zé®yJŽ‹ùžKŠ®X ÎûÉ®yXΙÚ.Kˆ®Šhˆ;ÞyȾX{¢.‹ùžiŠþXi.x9þ[»®y¨N‹JnXûr.ûÈÎikžKëþK«®[z^hé.iú^jè¾yY�¢6öç7BFV6†W$æÖRÒ~Xi.x9þkX¾Šù^ˆ[ˆ‚s° ¢6öç7Bf–ÆÄÆöv–äæE7V&Ö—BÒ7–æ2‡W6W"Â77v÷&B’Óâ°¢v—Bv–âçvV$6öçFVçG2æW†V7WFT¦f67&—B†‚‚’Óâ°¢6öç7B6WEfÇVRÒ†VÆVÖVçBÂfÇVR’Óâ°¢6öç7B6WGFW"Òö&¦V7BævWD÷vå&÷W'G”FW67&—F÷"„…DÔÄ–çWDVÆVÖVçBç&÷F÷G—RÂwfÇVRr’ç6WC°¢6WGFW"æ6ÆÂ†VÆVÖVçBÂfÇVR“°¢VÆVÖVçBæF—7F6„WfVçB†æWrWfVçB‚v–çWBr²'V&&ÆW3¢G'VRÒ’“°¢VÆVÖVçBæF—7F6„WfVçB†æWrWfVçB‚v6†ævRr²'V&&ÆW3¢G'VRÒ’“°¢Ó°¢6öç7B–çWG2Ò'&’æg&öÒ†Fö7VÖVçBçVW'•6VÆV7F÷$ÆÂ‚v–çWBr’“°¢6WEfÇVR†–çWG5³ÒÂG´¥4ôâç7G&–æv–g’‡W6W"—Ò“°¢6öç7B77v÷&D–çWBÒ–çWG2æf–æB‚†—FVÒ’Óâ—FVÒçG—RÓÓÒw77v÷&Br’óò–çWG5³Ó°¢6WEfÇVR‡77v÷&D–çWBÂG´¥4ôâç7G&–æv–g’‡77v÷&B—Ò“°¢6öç7B'WGFöâÒ'&’æg&öÒ†Fö7VÖVçBçVW'•6VÆV7F÷$ÆÂ‚v'WGFöâr’’æf–æB‚†—FVÒ’Óࢆ—FVÒçFW‡D6öçFVçBóòrr’æ–æ6ÇVFW2‚~y›¾[ÙRr’À¢“°¢–b†'WGFöâ’'WGFöâæ6Æ–6²‚“°¢&WGW&âG'VS°¢Ò’‚–“°¢&WGW&âv—Df÷"‡v–âÂFö7VÖVçBçVW'•6VÆV7F÷$ÆÂ‚ræVÂÖÖVçRÖ—FVÒr’æÆVæwF‚ãÒfÂ#“°¢Ó° ¢òò’hÚ.zêynYŽ‹JnXû~ûÈŽkˆ^hèžiYž[ˆŽy›¾[Ù^h(i"i[Nš^˜xÞ‹ÛÞi»Nhê^‹ùyÉþK«®i8ÞKÙÎûÈ�¢v—Bv–âçvV$6öçFVçG2æW†V7WFT¦f67&—B†‚‚’Óâ²Æö6Å7F÷&vRæ6ÆV"‚“²&WGW&âG'VS²Ò’‚–“°¢v—Bv–âæÆöEU$Â…D$tUEõU$“°¢6öç7BÆöv–å&VG’Òv—Bv—Df÷"‡v–âÂFö7VÖVçBçVW'•6VÆV7F÷$ÆÂ‚v–çWBr’æÆVæwF‚ãÒ&ÂS“°¢–b‚Æöv–å&VG’’°¢&V6÷&B‚~zêynYŽy›¾[Ù^ûÈŽiYž[ˆŽ[Ù^XZ^X˜Þ{ÚîûÈ’rÂfÇ6RÂ~y›¾[Ù^š^iÊ®k‹.iù2r“°¢&WGW&ã°¢Т6öç7BFÖ–å&VG’Òv—Bf–ÆÄÆöv–äæE7V&Ö—B„DÔ”åõU4U$äÔRÂDÔ”åõ55tõ$B“°¢&V6÷&B‚~zêynYŽy›¾[Ù^ûÈŽiYž[ˆŽ[Ù^XZ^X˜Þ{ÚîûÈ’rÂFÖ–å&VG’‹JnXûsÒG´DÔ”åõU4U$äÔWÖ“°¢–b‚FÖ–å&VG’’&WGW&ã° ¢òòã’Æö6Å7F÷&vRæ6ÆV"‚’h¨®8Î[{.yȾ‹ø~[É^ZûÎ8Þy¨Nj~ŠëK™þKˆ[›nkˆ^hè
¾8Î[Ù>X˜Þi[hÚî[©>8Þj~š)ŽûÈÎZH~K»ÞŠŽYÊ‚VÂ×F&ÆR˜xÎûÈ�¢ÆWB†57FGW46&BÒfÇ6S°¢ÆWB†4&6·WF&ÆRÒfÇ6S°¢6öç7BF&ÆTFVFÆ–æRÒFFRææ÷r‚’²ƒ°¢v†–ÆR„FFRææ÷r‚’ÂF&ÆTFVFÆ–æRbb††57FGW46&Bbb†4&6·WF&ÆR’’°¢†57FGW46&BÒ&ööÆVâ†Fö7VÖVçBçVW'•6VÆV7F÷"‚rçvR×F—FÆRr’“°¢†4&6·WF&ÆRÒ&ööÆVâ†Fö7VÖVçBçVW'•6VÆV7F÷"‚ræVÂ×F&ÆRr’“°¢v—B6ÆVWƒ“°¢Т6öç7BF—FÆRÒ†Fö7VÖVçBçVW'•6VÆV7F÷"‚rçvR×F—FÆRr“òçFW‡D6öçFVçBóòrr’çG&–Ò‚“°¢&WGW&â°¢ö³¢Æö6F–öâçF†æÖRÓÓÒröFF&6RrbbF—FÆRÓÓÒ~i[hÚî[©>zêybrbb†57FGW46&Bbb†4&6·WF&ÆRÀ¢&V6öã¢rrÀ¢Fƒ¢Æö6F–öâçF†æÖRÀ¢F—FÆRÀ¢†57FGW46&BÀ¢†4&6·WF&ÆRÀ¢Ó°¢Ò’‚–“°¢&V6÷&B€¢~i[hÚî[©>zêynš^ûÈŽK¸^zêynYŽûÉ®x«nhXÚKˆîZH~K»ÞŠŽk‹.iù>ûÈ’rÀ¢FF&6UvSòæö²ÓÓÒG'VRÀ¢FƒÒGFF&6UvSòçF‚óòrÒwÒj~š)ƒÒGFF&6UvSòçF—FÆRóòrÒwÒx«nhXÚÒGFF&6UvSòæ†57FGW46&GÒŠƒÒGFF&6UvSòæ†4&6·WF&ÆWÒGFF&6UvSòç&V6öâóòrwÖÀ¢“° ¢òò"’h™>[È8ÎiYž[ˆŽzêyn8Þ(i"ik[»®iYž[ˆŽûÈŽŠŽXÙR(i"KùÞZÙ‚(i"X‰~ŠŽX{®xëûÈ�¢6öç7B7&VFVBÒv—Bv–âçvV$6öçFVçG2æW†V7WFT¦f67&—B††7–æ2‚’Óâ°¢6öç7BÖVçRÒ'&’æg&öÒ†Fö7VÖVçBçVW'•6VÆV7F÷$ÆÂ‚ræVÂÖÖVçRÖ—FVÒr’’æf–æB‚†æöFR’ÓࢆæöFRçFW‡D6öçFVçBóòrr’çG&–Ò‚’ç7F'G5v—F‚‚~iYž[ˆŽzêybr’À¢“°¢–b‚ÖVçR’&WGW&â²ö³¢fÇ6RÂ&V6öã¢~zêynYŽˆùÎXÙ^˜xÎk*iÈž8ÎiYž[ˆŽzêyn8ÒrÓ°¢ÖVçRæ6Æ–6²‚“°¢6öç7BFVFÆ–æRÒFFRææ÷r‚’²c°¢v†–ÆR„FFRææ÷r‚’ÂFVFÆ–æRbbÆö6F–öâçF†æÖRÓÒr÷FV6†W'2r’°¢v—BæWr&öÖ—6R‚‡&W6öÇfR’Óâ6WEF–ÖV÷WB‡&W6öÇfRƒ’“°¢Тv—BæWr&öÖ—6R‚‡&W6öÇfR’Óâ6WEF–ÖV÷WB‡&W6öÇfRÂc’“°¢6öç7BF—FÆRÒFö7VÖVçBçVW'•6VÆV7F÷"‚rçvR×F—FÆRr“òçFW‡D6öçFVçCòçG&–Ò‚’óòrs°¢6öç7B÷Vä'WGFöâÒ'&’æg&öÒ†Fö7VÖVçBçVW'•6VÆV7F÷$ÆÂ‚v'WGFöâr’’æf–æB‚†æöFR’ÓࢆæöFRçFW‡D6öçFVçBóòrr’çG&–Ò‚’ÓÓÒ~ik[»®iYž[ˆ‚rÀ¢“°¢–b‚÷Vä'WGFöâ’&WGW&â²ö³¢fÇ6RÂ&V6öã¢~iYž[ˆŽzêynš^k*iÈž8Îik[»®iYž[ˆŽ8ÞhÈž™*ârÂF—FÆRÓ°¢÷Vä'WGFöâæ6Æ–6²‚“°¢6öç7BF–Í{ónm¢G§²Úî�Æ­y׿— '}`,
);
const tableScroll = await win.webContents.executeJavaScript(`(() => {
const body = document.querySelector('.table-card .el-card__body');
const table = document.querySelector('.table-card .el-table');
return {
hasCard: Boolean(body),
cardClientWidth: body ? body.clientWidth : 0,
cardScrollWidth: body ? body.scrollWidth : 0,
tableWidth: table ? Math.round(table.getBoundingClientRect().width) : 0,
};
})()`);
record(
'手机端表格在�片内横�滚动(页��横�滚动)',
Boolean(tableScroll?.hasCard) && tableScroll.cardScrollWidth > tableScroll.cardClientWidth,
`�片�视=${tableScroll?.cardClientWidth} 内容宽=${tableScroll?.cardScrollWidth} 表格宽=${tableScroll?.tableWidth}`,
);
const toolbar = await win.webContents.executeJavaScript(
`(() => {
const control = document.querySelector('.toolbar .el-select') ?? document.querySelector('.toolbar .el-input');
return {
innerWidth: window.innerWidth,
width: control ? Math.round(control.getBoundingClientRect().width) : 0,
};
})()`,
);
record(
'手机端工具�控件铺满整行',
toolbar?.width >= toolbar?.innerWidth - 48,
`控件宽=${toolbar?.width} 视�宽=${toolbar?.innerWidth}`,
);
const dialog = await win.webContents.executeJavaScript(`(async () => {
const open = Array.from(document.querySelectorAll('button')).find((node) =>
(node.textContent ?? '').trim().includes('�布通知'),
);
if (!open) return { ok: false, reason: '未找到"�布通知"按钮' };
open.click();
const deadline = Date.now() + 5000;
while (Date.now() < deadline && !document.querySelector('.el-dialog')) {
await new Promise((resolve) => setTimeout(resolve, 60));
}
await new Promise((resolve) => setTimeout(resolve, 300));
const node = document.querySelector('.el-dialog');
if (!node) return { ok: false, reason: '弹窗未打开' };
const rect = node.getBoundingClientRect();
return {
ok: true,
width: Math.round(rect.width),
innerWidth: window.innerWidth,
left: Math.round(rect.left),
formItemWidth: Math.round(
document.querySelector('.el-dialog .el-form-item')?.getBoundingClientRect().width ?? 0,
),
};
})()`);
await captureMobileShot(win, 'mobile-3-dialog');
record(
'手机端弹窗宽度自适应(�超出视�且接近整�)',
Boolean(dialog?.ok) &&
dialog.width <= dialog.innerWidth &&
dialog.width >= dialog.innerWidth - 32 &&
dialog.left >= 0,
`弹窗宽=${dialog?.width} 视�宽=${dialog?.innerWidth} left=${dialog?.left}`,
);
await win.webContents.executeJavaScript(`(() => {
const cancel = Array.from(document.querySelectorAll('.el-dialog__footer button')).find((node) =>
(node.textContent ?? '').trim() === '�消',
);
if (cancel) cancel.click();
return true;
})()`);
await sleep(300);
// ��桌�尺寸并��窗�,��影��续(结果已全部记录)
win.setBounds({ ...win.getBounds(), width: 1440, height: 900 });
await sleep(300);
win.hide();
}
/** 新页�用真实点击进入,仅�存临时验收�级的�逆字段。 */
async function runPlanEditorChecks(win) {
await win.loadURL(new URL('/plan-editor', TARGET_URL).href);
const ready = await waitFor(
win,
`Boolean(document.querySelector('.schedule-grid thead')) && document.querySelectorAll('.schedule-grid thead th').length === 8`,
);
record(
2026-10-24 15:43:32 +08:00
'课表档案在管�端页�内展示周课表和选科侧�',
ready &&
(await win.webContents.executeJavaScript(
2026-10-24 15:43:32 +08:00
`Boolean(document.querySelector('.subject-palette')) && document.querySelectorAll('.archive-tabs button').length === 4 && getComputedStyle(document.querySelector('.archive-editor')).position !== 'fixed' && Boolean(document.querySelector('.archive-page .page-title'))`,
)),
);
const assignment = await win.webContents.executeJavaScript(`(() => {
const cell = document.querySelector('.lesson-cell');
if (!cell) return null;
const original = cell.querySelector('strong')?.textContent.trim();
cell.click();
const button = [...document.querySelectorAll('.subject-palette button')].find(b => !b.disabled && b.title !== original);
button?.click();
return { original, editable: Boolean(button) };
})()`);
const dirty =
assignment?.editable && (await waitFor(win, `document.body.innerText.includes('有未�存的修改')`));
record('点击周课表并从�侧选科生���存的课程�稿', dirty);
await win.webContents.executeJavaScript(
2026-10-24 15:43:32 +08:00
`(() => {[...document.querySelectorAll('.archive-commands .el-button')].find(b => b.textContent.trim() === '�存')?.click();})()`,
);
record(
'课表�稿�通过现有接��存',
dirty &&
(await waitFor(
win,
`document.body.innerText.includes('档案已�存') && !document.querySelector('.draft-label')`,
)),
);
// ��隔离验收�级的原科目。
if (assignment?.original) {
await win.webContents.executeJavaScript(`(() => {
document.querySelector('.lesson-cell')?.click();
const original = ${JSON.stringify(assignment.original)};
[...document.querySelectorAll('.subject-palette button')].find(b => b.title === original)?.click();
})()`);
await sleep(150);
await win.webContents.executeJavaScript(
2026-10-24 15:43:32 +08:00
`(() => {[...document.querySelectorAll('.archive-commands .el-button')].find(b => b.textContent.trim() === '�存')?.click();})()`,
);
await waitFor(win, `!document.querySelector('.draft-label')`);
}
await win.webContents.executeJavaScript(`document.querySelector('[aria-label="列表视图"]').click()`);
record(
'列表视图�留课时编辑和批��作',
await waitFor(
win,
`Boolean(document.querySelector('.course-row')) && document.body.innerText.includes('批�排课')`,
),
);
await win.webContents.executeJavaScript(
`document.querySelector('.archive-tabs button:nth-child(2)').click()`,
);
record(
'时间表页四�时间点与�存入���',
await waitFor(
win,
`document.body.innerText.includes('新建课时') && document.body.innerText.includes('�存时间表') && document.body.innerText.includes('分割线') && document.body.innerText.includes('行动')`,
),
);
const quickAdd = await win.webContents.executeJavaScript(`(async () => {
const before = document.querySelectorAll('.time-row').length;
[...document.querySelectorAll('button')].find(b => b.textContent.trim() === '+ 新建课时')?.click();
await new Promise(resolve => setTimeout(resolve, 180));
const rows = document.querySelectorAll('.time-row');
const values = [...(rows[rows.length - 1]?.querySelectorAll('.el-date-editor input') || [])].map(input => input.value);
const minutes = (value) => { const [h, m] = (value || '').split(':').map(Number); return h * 60 + m; };
return { before, after: rows.length, diff: minutes(values[1]) - minutes(values[0]) };
})()`);
record(
'时间表新建课时按快速时长生�起止时间',
quickAdd.after === quickAdd.before + 1 && quickAdd.diff === 45,
);
await win.webContents.executeJavaScript(
`(() => {[...document.querySelectorAll('.archive-toolbar button')].find(b => b.textContent.trim() === '刷新')?.click();})()`,
);
await waitFor(win, `Boolean(document.querySelector('.el-message-box'))`);
await win.webContents.executeJavaScript(
`(() => {[...document.querySelectorAll('.el-message-box button')].find(b => b.textContent.trim() === '放弃修改')?.click();})()`,
);
await waitFor(win, `!document.querySelector('.draft-label')`);
await win.webContents.executeJavaScript(
`document.querySelector('.archive-tabs button:first-child').click()`,
);
await win.webContents.executeJavaScript(`document.querySelector('[aria-label="月视图"]').click()`);
record(
'月视图�供日期导航',
await waitFor(win, `document.querySelectorAll('.calendar-grid button').length === 42`),
);
await win.webContents.executeJavaScript(`document.querySelector('[aria-label="周视图"]').click()`);
record('底部视图切��返回周课表', await waitFor(win, `Boolean(document.querySelector('.schedule-grid'))`));
fs.mkdirSync(path.join(__dirname, '../../docs/screenshots'), { recursive: true });
fs.writeFileSync(
path.join(__dirname, '../../docs/screenshots/plan-editor-live-api.png'),
(await win.webContents.capturePage()).toPNG(),
);
2026-10-24 15:43:32 +08:00
await win.webContents.executeJavaScript(
`document.querySelector('.management-menu [data-path="/dashboard"]').click()`,
);
await waitFor(win, `location.pathname === '/dashboard'`);
const collapsedBefore = await win.webContents.executeJavaScript(
`Boolean(document.querySelector('.layout-aside.is-collapsed'))`,
);
if (!collapsedBefore)
await win.webContents.executeJavaScript(`document.querySelector('.nav-toggle').click()`);
await sleep(700);
const rail = await win.webContents.executeJavaScript(`(() => {
const aside=document.querySelector('.layout-aside').getBoundingClientRect();
const icons=[...document.querySelectorAll('.management-group-title .el-icon')].filter(e=>e.getBoundingClientRect().width>0);
return icons.length>0 && icons.every(e=>{ const r=e.getBoundingClientRect(); return r.width>=18&&r.left>=aside.left&&r.right<=aside.right; });
})()`);
record('折�侧�分组图标完整显示且未被侧��切', rail);
if (!collapsedBefore)
await win.webContents.executeJavaScript(`document.querySelector('.nav-toggle').click()`);
await sleep(700);
fs.mkdirSync(path.join(__dirname, '../../docs/screenshots'), { recursive: true });
fs.writeFileSync(
path.join(__dirname, '../../docs/screenshots/plan-editor-shell.png'),
(await win.webContents.capturePage()).toPNG(),
);
await win.loadURL(new URL('/system-settings', TARGET_URL).href);
record(
'开�环境自�动明确显示��用原因',
await waitFor(
win,
`document.body.innerText.includes('开�环境') && Boolean(document.querySelector('.el-switch.is-disabled'))`,
),
);
await win.loadURL(new URL('/term-weeks', TARGET_URL).href);
record(
'学年�级设置与待补跑�示��且�执行�级',
await waitFor(
win,
`document.body.innerText.includes('学年�级计划') && document.body.innerText.includes('总周数')`,
),
);
await win.loadURL(new URL('/archives', TARGET_URL).href);
record(
'归档页有转出分区且无手动归档入�',
await waitFor(
win,
`document.body.innerText.includes('已转出') && ![...document.querySelectorAll('button')].some(e=>e.textContent.trim()==='新建归档')`,
),
);
}
async function finish(win) {
record('全程��结�(窗���且未�焦)', !win.isVisible() && !win.isFocused());
const failed = results.filter((item) => !item.ok);
const passed = results.length - failed.length;
console.log(`\n[ui-smoke] ${passed}/${results.length} 项通过`);
if (RESULT_FILE) {
try {
fs.mkdirSync(path.dirname(RESULT_FILE), { recursive: true });
fs.writeFileSync(
RESULT_FILE,
JSON.stringify(
{ passed, total: results.length, ok: failed.length === 0, results, target: TARGET_URL },
null,
2,
),
'utf8',
);
console.log(`[ui-smoke] 结果已写入 ${RESULT_FILE}`);
} catch (error) {
console.error('[ui-smoke] 写入结果失败', error);
}
}
win.destroy();
app.exit(failed.length === 0 ? 0 : 1);
}
app.whenReady().then(() =>
main().catch(async (error) => {
record('UI 冒烟执行异常', false, String(error));
console.error(error);
app.exit(1);
}),
);
app.on('window-all-closed', () => app.quit());