forked from liweijie/education
1 line
59 KiB
JSON
1 line
59 KiB
JSON
{"remainingRequest":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\vue-loader\\lib\\index.js??vue-loader-options!C:\\Users\\Admin\\Desktop\\education\\frontend\\src\\views\\teachOffice\\shiftSemester\\ClassCalendarDialog.vue?vue&type=script&setup=true&lang=ts","dependencies":[{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\src\\views\\teachOffice\\shiftSemester\\ClassCalendarDialog.vue","mtime":1787321078645},{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\cache-loader\\dist\\cjs.js","mtime":1787309791955},{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\node_modules\\vue-loader\\lib\\index.js","mtime":1787309793790}],"contextDependencies":[],"result":[{"type":"Buffer","data":"base64:DQppbXBvcnQgeyBjb21wdXRlZCwgb25CZWZvcmVVbm1vdW50LCBvbk1vdW50ZWQsIHJlYWN0aXZlLCByZWYsIHdhdGNoIH0gZnJvbSAndnVlJw0KaW1wb3J0IHsgRWxNZXNzYWdlIH0gZnJvbSAnZWxlbWVudC1wbHVzJw0KaW1wb3J0IGRheWpzIGZyb20gJ2RheWpzJw0KaW1wb3J0IENsYXNzVGVhbVNlbGVjdERpYWxvZyBmcm9tICcuL0NsYXNzVGVhbVNlbGVjdERpYWxvZy52dWUnDQoNCi8vID09PT09PT09PT09PT09PT09PT09IFByb3BzICYgRW1pdHMgPT09PT09PT09PT09PT09PT09PT0NCmNvbnN0IHByb3BzID0gd2l0aERlZmF1bHRzKA0KICBkZWZpbmVQcm9wczx7DQogICAgbW9kZWxWYWx1ZTogYm9vbGVhbg0KICAgIC8qKiDnj63mrKHlj7fvvIjlpoIgMDIwM++8iSAqLw0KICAgIGJjPzogc3RyaW5nDQogICAgLyoqIOWtpuacn+WQjeensCAqLw0KICAgIHNlbWVzdGVyTmFtZT86IHN0cmluZw0KICB9PigpLA0KICB7DQogICAgYmM6ICcwMzk5JywNCiAgICBzZW1lc3Rlck5hbWU6ICcyMDE35bm056eL5a2j5a2m5pyfJw0KICB9DQopDQoNCmNvbnN0IGVtaXQgPSBkZWZpbmVFbWl0czx7DQogIChlOiAndXBkYXRlOm1vZGVsVmFsdWUnLCB2YWx1ZTogYm9vbGVhbik6IHZvaWQNCn0+KCkNCg0KY29uc3QgdmlzaWJsZSA9IGNvbXB1dGVkKHsNCiAgZ2V0OiAoKSA9PiBwcm9wcy5tb2RlbFZhbHVlLA0KICBzZXQ6ICh2YWwpID0+IGVtaXQoJ3VwZGF0ZTptb2RlbFZhbHVlJywgdmFsKQ0KfSkNCg0KLy8gPT09PT09PT09PT09PT09PT09PT0gV2luZG93cyDmoIfpopjmoI8gPT09PT09PT09PT09PT09PT09PT0NCi8vIOavj+asoeaJk+W8gOWvueivneahhuaXtumHjee9rumAieaLqeeKtuaAgQ0Kd2F0Y2goDQogICgpID0+IHByb3BzLm1vZGVsVmFsdWUsDQogICh2YWwpID0+IHsNCiAgICBpZiAodmFsKSB7DQogICAgICBzZWxlY3RlZElkcy52YWx1ZSA9IG5ldyBTZXQoKQ0KICAgIH0NCiAgfQ0KKQ0KDQovLyA9PT09PT09PT09PT09PT09PT09PSDlrabmnJ/kuI7nj63mrKHkv6Hmga8gPT09PT09PT09PT09PT09PT09PT0NCi8qKiDmoKHljobojIPlm7QgKi8NCmNvbnN0IGNhbFN0YXJ0ID0gJzIwMTctMDctMDgnDQpjb25zdCBjYWxFbmQgPSAnMjAxOC0wMi0xMScNCmNvbnN0IGNhbFdlZWtzID0gMzINCi8qKiDnj63ljobojIPlm7TvvIjmoKHljobln7rnoYDkuIrkuLrnj63mrKHlronmjpLvvIkgKi8NCmNvbnN0IGNsYXNzU3RhcnQgPSAnMjAxNy0wOC0yNCcNCmNvbnN0IGNsYXNzRW5kID0gJzIwMTgtMDItMDUnDQpjb25zdCBjbGFzc1dlZWtzID0gMjUNCg0KLy8gPT09PT09PT09PT09PT09PT09PT0g5LqL5Lu26K6+572u5Yy65Z+fID09PT09PT09PT09PT09PT09PT09DQpjb25zdCBldmVudE5hbWUgPSByZWYoJycpDQpjb25zdCBpc0JvbGQgPSByZWYoZmFsc2UpICAgICAgICAgLy8g5Yqg57KX5pi+56S6DQpjb25zdCBpc1NjaGVkdWxhYmxlID0gcmVmKGZhbHNlKSAgLy8g5Y+v5o6S6K++DQpjb25zdCBpc1JlZ3VsYXJDbGFzcyA9IHJlZihmYWxzZSkgLy8g5q2j6K++DQpjb25zdCBzaG93UmVtYXJrID0gcmVmKGZhbHNlKSAgICAgLy8g6K++6KGo5aSH5rOo5Lit5pi+56S6DQpjb25zdCByZW1hcmsgPSByZWYoJycpDQpjb25zdCBzaG93NzggPSByZWYoZmFsc2UpICAgICAgICAgLy8g5pi+56S6Ny846IqCDQpjb25zdCBzaG93RXZlbmluZyA9IHJlZih0cnVlKSAgICAgLy8g5pi+56S65pma5LiK77yI5bey5Yu+6YCJ77yJDQpjb25zdCBzaG93TmlnaHQgPSByZWYoZmFsc2UpICAgICAgLy8g5pi+56S65aSc6Ze0DQoNCi8vID09PT09PT09PT09PT09PT09PT09IOaXtuauteWumuS5iSA9PT09PT09PT09PT09PT09PT09PQ0KaW50ZXJmYWNlIFBlcmlvZERlZiB7DQogIGtleTogc3RyaW5nDQogIGxhYmVsOiBzdHJpbmcNCn0NCg0KLyoqIOWFqOmDqOaXtuaute+8mjEtMuOAgTMtNOOAgTUtNiDmgZLmmL7npLrvvJs3LTggLyA5LTEwKOaZmuS4iikgLyDlpJzpl7Qg55Sx5aSN6YCJ5qGG5o6n5Yi2ICovDQpjb25zdCBBTExfUEVSSU9EUzogUGVyaW9kRGVmW10gPSBbDQogIHsga2V5OiAnMS0yJywgbGFiZWw6ICcxLTInIH0sDQogIHsga2V5OiAnMy00JywgbGFiZWw6ICczLTQnIH0sDQogIHsga2V5OiAnNS02JywgbGFiZWw6ICc1LTYnIH0sDQogIHsga2V5OiAnNy04JywgbGFiZWw6ICc3LTgnIH0sDQogIHsga2V5OiAnOS0xMCcsIGxhYmVsOiAnOS0xMCcgfSwNCiAgeyBrZXk6ICduaWdodCcsIGxhYmVsOiAn5aSc6Ze0JyB9DQpdDQoNCi8qKiDkuovku7bmqKHlvI/kuIvmoIcg4oaSIEFMTF9QRVJJT0RTIOS4i+agh++8iDEtMuOAgTMtNOOAgTUtNuOAgTktMTDvvIkgKi8NCmNvbnN0IFBBVFRFUk5fUEVSSU9EX0lEWCA9IFswLCAxLCAyLCA0XQ0KDQovKiog5pe26Ze057yW5o6S5Yy65Z+f5a6e6ZmF5pi+56S655qE5pe25q6177yI55Sx5LiJ5Liq5aSN6YCJ5qGG5o6n5Yi277yJICovDQpjb25zdCB2aXNpYmxlUGVyaW9kcyA9IGNvbXB1dGVkPFBlcmlvZERlZltdPigoKSA9Pg0KICBBTExfUEVSSU9EUy5maWx0ZXIoKHApID0+IHsNCiAgICBpZiAocC5rZXkgPT09ICc3LTgnKSByZXR1cm4gc2hvdzc4LnZhbHVlDQogICAgaWYgKHAua2V5ID09PSAnOS0xMCcpIHJldHVybiBzaG93RXZlbmluZy52YWx1ZQ0KICAgIGlmIChwLmtleSA9PT0gJ25pZ2h0JykgcmV0dXJuIHNob3dOaWdodC52YWx1ZQ0KICAgIHJldHVybiB0cnVlDQogIH0pDQopDQoNCi8vID09PT09PT09PT09PT09PT09PT09IOePreWOhuihqOagvOaVsOaNriA9PT09PT09PT09PT09PT09PT09PQ0KY29uc3QgZGF5TmFtZXMgPSBbJ+S4gCcsICfkuownLCAn5LiJJywgJ+WbmycsICfkupQnXQ0KDQovKiog5LqL5Lu257G75Z6LIOKGkiDpopzoibIgKi8NCnR5cGUgU2xvdFR5cGUgPSAncmVkJyB8ICdkYXJrJyB8ICdncmVlbicgfCAnY3lhbicNCg0KY29uc3QgVFlQRV9TVFlMRTogUmVjb3JkPFNsb3RUeXBlLCB7IGJnOiBzdHJpbmc7IGZnOiBzdHJpbmcgfT4gPSB7DQogIHJlZDogeyBiZzogJyNkOTQzNDMnLCBmZzogJyNmZmZmZmYnIH0sICAgIC8vIOato+W4uOivvueoiy/mtLvliqjvvIjpqazln7rjgIHkv53lr4bjgIHluIPpm7fjgIHnu7Tkv67jgIHluIPkv67jgIHmiJjmnK/jgIHlm73luoboioLjgIHmlL/lt6XvvIkNCiAgZGFyazogeyBiZzogJyMyYThhN2YnLCBmZzogJyNmZmZmZmYnIH0sICAgLy8g5rex6Z2SL+WiqOe7v++8mua4uOazs+OAgemBk+W+t+OAgeaXpeacn+agh+iusA0KICBncmVlbjogeyBiZzogJyM0ZjlkNTcnLCBmZzogJyNmZmZmZmYnIH0sICAvLyDnibnmroror77nqIsv5rS75Yqo77yI5qC45b+D44CB57uE6K6t77yJDQogIGN5YW46IHsgYmc6ICcjOGZkNGUwJywgZmc6ICcjMTQ1MDVhJyB9ICAgIC8vIOmdki/mtYXok53vvJrlrabliY3jgIHlhYPml6YNCn0NCg0KaW50ZXJmYWNlIFNsb3REZWYgew0KICB0ZXh0OiBzdHJpbmcNCiAgdHlwZTogU2xvdFR5cGUNCn0NCnR5cGUgU2xvdERlZk9yTnVsbCA9IFNsb3REZWYgfCBudWxsDQoNCmludGVyZmFjZSBXZWVrRGVmIHsNCiAgbnVtOiBudW1iZXINCiAgc3RhcnQ6IHN0cmluZw0KICBlbmQ6IHN0cmluZw0KICAvKiog5ZGo5LiA5LqL5Lu25qih5byP77yIMS0y44CBMy0044CBNS0244CBOS0xMO+8ie+8jG51bGwg6KGo56S65pel5pyf5qC8ICovDQogIG1vbmRheTogU2xvdERlZk9yTnVsbFtdDQogIC8qKiDlkajkuox+5ZGo5LqU5LqL5Lu25qih5byP77yI6YCa5bi45LiO5ZGo5LiA55u45ZCM77yJICovDQogIG90aGVyczogU2xvdERlZk9yTnVsbFtdDQp9DQoNCmNvbnN0IEUgPSAodGV4dDogc3RyaW5nLCB0eXBlOiBTbG90VHlwZSk6IFNsb3REZWYgPT4gKHsgdGV4dCwgdHlwZSB9KQ0KY29uc3QgRDogU2xvdERlZk9yTnVsbCA9IG51bGwgLy8g5pel5pyf5qC877ya5pi+56S65b2T5aSp5pel5pyfDQoNCi8qKiDnj63ljobkuovku7bvvIjnrKw45ZGofuesrDI55ZGo77yM5Lil5qC85oyJ5oiq5Zu+6L+Y5Y6f77ybbnVsbCDkuLrml6XmnJ/moLzvvIkgKi8NCmNvbnN0IHdlZWtEZWZzOiBXZWVrRGVmW10gPSBbDQogIC8vIOWtpuWJjemAguW6lO+8iOmdku+8iQ0KICB7DQogICAgbnVtOiA4LCBzdGFydDogJzA4LTIxJywgZW5kOiAnMDgtMjcnLA0KICAgIG1vbmRheTogW0UoJ+WtpuWJjScsICdjeWFuJyksIEUoJ+WtpuWJjScsICdjeWFuJyksIEUoJ+WtpuWJjScsICdjeWFuJyksIEUoJ+WtpuWJjScsICdjeWFuJyldLA0KICAgIG90aGVyczogW0UoJ+WtpuWJjScsICdjeWFuJyksIEUoJ+WtpuWJjScsICdjeWFuJyksIEUoJ+WtpuWJjScsICdjeWFuJyksIEUoJ+WtpuWJjScsICdjeWFuJyldDQogIH0sDQogIC8vIOmprOWfuu+8iOe6ou+8iSsg5ri45rOz77yI5aKo57u/77yJDQogIHsNCiAgICBudW06IDksIHN0YXJ0OiAnMDgtMjgnLCBlbmQ6ICcwOS0wMycsDQogICAgbW9uZGF5OiBbRSgn6ams5Z+6JywgJ3JlZCcpLCBFKCfmuLjms7MnLCAnZGFyaycpLCBELCBEXSwNCiAgICBvdGhlcnM6IFtFKCfpqazln7onLCAncmVkJyksIEUoJ+a4uOazsycsICdkYXJrJyksIEQsIERdDQogIH0sDQogIHsNCiAgICBudW06IDEwLCBzdGFydDogJzA5LTA0JywgZW5kOiAnMDktMTAnLA0KICAgIG1vbmRheTogW0UoJ+mprOWfuicsICdyZWQnKSwgRSgn5ri45rOzJywgJ2RhcmsnKSwgRCwgRF0sDQogICAgb3RoZXJzOiBbRSgn6ams5Z+6JywgJ3JlZCcpLCBFKCfmuLjms7MnLCAnZGFyaycpLCBELCBEXQ0KICB9LA0KICAvLyDpqazln7rvvIjnuqLvvIkrIOS/neWvhu+8iOe6ou+8iQ0KICB7DQogICAgbnVtOiAxMSwgc3RhcnQ6ICcwOS0xMScsIGVuZDogJzA5LTE3JywNCiAgICBtb25kYXk6IFtFKCfpqazln7onLCAncmVkJyksIEUoJ+S/neWvhicsICdyZWQnKSwgRCwgRF0sDQogICAgb3RoZXJzOiBbRSgn6ams5Z+6JywgJ3JlZCcpLCBFKCfkv53lr4YnLCAncmVkJyksIEQsIERdDQogIH0sDQogIHsNCiAgICBudW06IDEyLCBzdGFydDogJzA5LTE4JywgZW5kOiAnMDktMjQnLA0KICAgIG1vbmRheTogW0UoJ+mprOWfuicsICdyZWQnKSwgRSgn5L+d5a+GJywgJ3JlZCcpLCBELCBEXSwNCiAgICBvdGhlcnM6IFtFKCfpqazln7onLCAncmVkJyksIEUoJ+S/neWvhicsICdyZWQnKSwgRCwgRF0NCiAgfSwNCiAgLy8g5biD6Zu377yI57qi77yJDQogIHsNCiAgICBudW06IDEzLCBzdGFydDogJzA5LTI1JywgZW5kOiAnMTAtMDEnLA0KICAgIG1vbmRheTogW0UoJ+W4g+mbtycsICdyZWQnKSwgRSgn5biD6Zu3JywgJ3JlZCcpLCBELCBEXSwNCiAgICBvdGhlcnM6IFtFKCfluIPpm7cnLCAncmVkJyksIEUoJ+W4g+mbtycsICdyZWQnKSwgRCwgRF0NCiAgfSwNCiAgLy8g5Zu95bqG6IqC77yI57qi77yJDQogIHsNCiAgICBudW06IDE0LCBzdGFydDogJzEwLTAyJywgZW5kOiAnMTAtMDgnLA0KICAgIG1vbmRheTogW0UoJ+WbveW6huiKgicsICdyZWQnKSwgRSgn5Zu95bqG6IqCJywgJ3JlZCcpLCBFKCflm73luoboioInLCAncmVkJyksIEUoJ+WbveW6huiKgicsICdyZWQnKV0sDQogICAgb3RoZXJzOiBbRSgn5Zu95bqG6IqCJywgJ3JlZCcpLCBFKCflm73luoboioInLCAncmVkJyksIEUoJ+WbveW6huiKgicsICdyZWQnKSwgRSgn5Zu95bqG6IqCJywgJ3JlZCcpXQ0KICB9LA0KICB7DQogICAgbnVtOiAxNSwgc3RhcnQ6ICcxMC0wOScsIGVuZDogJzEwLTE1JywNCiAgICBtb25kYXk6IFtFKCfluIPpm7cnLCAncmVkJyksIEUoJ+W4g+mbtycsICdyZWQnKSwgRCwgRF0sDQogICAgb3RoZXJzOiBbRSgn5biD6Zu3JywgJ3JlZCcpLCBFKCfluIPpm7cnLCAncmVkJyksIEQsIERdDQogIH0sDQogIHsNCiAgICBudW06IDE2LCBzdGFydDogJzEwLTE2JywgZW5kOiAnMTAtMjInLA0KICAgIG1vbmRheTogW0UoJ+W4g+mbtycsICdyZWQnKSwgRSgn5biD6Zu3JywgJ3JlZCcpLCBELCBEXSwNCiAgICBvdGhlcnM6IFtFKCfluIPpm7cnLCAncmVkJyksIEUoJ+W4g+mbtycsICdyZWQnKSwgRCwgRF0NCiAgfSwNCiAgew0KICAgIG51bTogMTcsIHN0YXJ0OiAnMTAtMjMnLCBlbmQ6ICcxMC0yOScsDQogICAgbW9uZGF5OiBbRSgn5biD6Zu3JywgJ3JlZCcpLCBFKCfluIPpm7cnLCAncmVkJyksIEQsIERdLA0KICAgIG90aGVyczogW0UoJ+W4g+mbtycsICdyZWQnKSwgRSgn5biD6Zu3JywgJ3JlZCcpLCBELCBEXQ0KICB9LA0KICAvLyDnu7Tkv67vvIjnuqLvvIkNCiAgew0KICAgIG51bTogMTgsIHN0YXJ0OiAnMTAtMzAnLCBlbmQ6ICcxMS0wNScsDQogICAgbW9uZGF5OiBbRSgn57u05L+uJywgJ3JlZCcpLCBFKCfnu7Tkv64nLCAncmVkJyksIEQsIERdLA0KICAgIG90aGVyczogW0UoJ+e7tOS/ricsICdyZWQnKSwgRSgn57u05L+uJywgJ3JlZCcpLCBELCBEXQ0KICB9LA0KICAvLyDnu7Tkv67vvIjnuqLvvIkrIOaguOW/g++8iOe7v++8iQ0KICB7DQogICAgbnVtOiAxOSwgc3RhcnQ6ICcxMS0wNicsIGVuZDogJzExLTEyJywNCiAgICBtb25kYXk6IFtFKCfnu7Tkv64nLCAncmVkJyksIEUoJ+e7tOS/ricsICdyZWQnKSwgRSgn5qC45b+DJywgJ2dyZWVuJyksIERdLA0KICAgIG90aGVyczogW0UoJ+e7tOS/ricsICdyZWQnKSwgRSgn57u05L+uJywgJ3JlZCcpLCBFKCfmoLjlv4MnLCAnZ3JlZW4nKSwgRF0NCiAgfSwNCiAgLy8g5biD5L+u77yI57qi77yJDQogIHsNCiAgICBudW06IDIwLCBzdGFydDogJzExLTEzJywgZW5kOiAnMTEtMTknLA0KICAgIG1vbmRheTogW0UoJ+W4g+S/ricsICdyZWQnKSwgRSgn5biD5L+uJywgJ3JlZCcpLCBELCBEXSwNCiAgICBvdGhlcnM6IFtFKCfluIPkv64nLCAncmVkJyksIEUoJ+W4g+S/ricsICdyZWQnKSwgRCwgRF0NCiAgfSwNCiAgew0KICAgIG51bTogMjEsIHN0YXJ0OiAnMTEtMjAnLCBlbmQ6ICcxMS0yNicsDQogICAgbW9uZGF5OiBbRSgn5biD5L+uJywgJ3JlZCcpLCBFKCfluIPkv64nLCAncmVkJyksIEQsIERdLA0KICAgIG90aGVyczogW0UoJ+W4g+S/ricsICdyZWQnKSwgRSgn5biD5L+uJywgJ3JlZCcpLCBELCBEXQ0KICB9LA0KICB7DQogICAgbnVtOiAyMiwgc3RhcnQ6ICcxMS0yNycsIGVuZDogJzEyLTAzJywNCiAgICBtb25kYXk6IFtFKCfluIPkv64nLCAncmVkJyksIEUoJ+W4g+S/ricsICdyZWQnKSwgRCwgRF0sDQogICAgb3RoZXJzOiBbRSgn5biD5L+uJywgJ3JlZCcpLCBFKCfluIPkv64nLCAncmVkJyksIEQsIERdDQogIH0sDQogIC8vIOe7tOS/ru+8iOe6ou+8iQ0KICB7DQogICAgbnVtOiAyMywgc3RhcnQ6ICcxMi0wNCcsIGVuZDogJzEyLTEwJywNCiAgICBtb25kYXk6IFtFKCfnu7Tkv64nLCAncmVkJyksIEUoJ+e7tOS/ricsICdyZWQnKSwgRCwgRF0sDQogICAgb3RoZXJzOiBbRSgn57u05L+uJywgJ3JlZCcpLCBFKCfnu7Tkv64nLCAncmVkJyksIEQsIERdDQogIH0sDQogIHsNCiAgICBudW06IDI0LCBzdGFydDogJzEyLTExJywgZW5kOiAnMTItMTcnLA0KICAgIG1vbmRheTogW0UoJ+e7tOS/ricsICdyZWQnKSwgRSgn57u05L+uJywgJ3JlZCcpLCBELCBEXSwNCiAgICBvdGhlcnM6IFtFKCfnu7Tkv64nLCAncmVkJyksIEUoJ+e7tOS/ricsICdyZWQnKSwgRCwgRF0NCiAgfSwNCiAgew0KICAgIG51bTogMjUsIHN0YXJ0OiAnMTItMTgnLCBlbmQ6ICcxMi0yNCcsDQogICAgbW9uZGF5OiBbRSgn57u05L+uJywgJ3JlZCcpLCBFKCfnu7Tkv64nLCAncmVkJyksIEQsIERdLA0KICAgIG90aGVyczogW0UoJ+e7tOS/ricsICdyZWQnKSwgRSgn57u05L+uJywgJ3JlZCcpLCBELCBEXQ0KICB9LA0KICAvLyDmiJjmnK/vvIjnuqLvvIkNCiAgew0KICAgIG51bTogMjYsIHN0YXJ0OiAnMTItMjUnLCBlbmQ6ICcxMi0zMScsDQogICAgbW9uZGF5OiBbRSgn5oiY5pyvJywgJ3JlZCcpLCBFKCfmiJjmnK8nLCAncmVkJyksIEUoJ+aImOacrycsICdyZWQnKSwgRSgn5oiY5pyvJywgJ3JlZCcpXSwNCiAgICBvdGhlcnM6IFtFKCfmiJjmnK8nLCAncmVkJyksIEUoJ+aImOacrycsICdyZWQnKSwgRSgn5oiY5pyvJywgJ3JlZCcpLCBFKCfmiJjmnK8nLCAncmVkJyldDQogIH0sDQogIC8vIOWFg+aXpu+8iOmdku+8jOWRqOS4gO+8iSsg57uE6K6t77yI57u/77yM5ZGo5LqMfuWRqOS6lO+8iQ0KICB7DQogICAgbnVtOiAyNywgc3RhcnQ6ICcwMS0wMScsIGVuZDogJzAxLTA3JywNCiAgICBtb25kYXk6IFtFKCflhYPml6YnLCAnY3lhbicpLCBFKCflhYPml6YnLCAnY3lhbicpLCBFKCflhYPml6YnLCAnY3lhbicpLCBFKCflhYPml6YnLCAnY3lhbicpXSwNCiAgICBvdGhlcnM6IFtFKCfnu4Torq0nLCAnZ3JlZW4nKSwgRSgn57uE6K6tJywgJ2dyZWVuJyksIEUoJ+e7hOiurScsICdncmVlbicpLCBFKCfnu4Torq0nLCAnZ3JlZW4nKV0NCiAgfSwNCiAgLy8g5pS/5bel77yI57qi77yJKyDpgZPlvrfvvIjloqjnu7/vvIkNCiAgew0KICAgIG51bTogMjgsIHN0YXJ0OiAnMDEtMDgnLCBlbmQ6ICcwMS0xNCcsDQogICAgbW9uZGF5OiBbRSgn5pS/5belJywgJ3JlZCcpLCBFKCfpgZPlvrcnLCAnZGFyaycpLCBFKCfpgZPlvrcnLCAnZGFyaycpLCBFKCcwMTA2JywgJ2RhcmsnKV0sDQogICAgb3RoZXJzOiBbRSgn5pS/5belJywgJ3JlZCcpLCBFKCfpgZPlvrcnLCAnZGFyaycpLCBFKCfpgZPlvrcnLCAnZGFyaycpLCBEXQ0KICB9LA0KICB7DQogICAgbnVtOiAyOSwgc3RhcnQ6ICcwMS0xNScsIGVuZDogJzAxLTIxJywNCiAgICBtb25kYXk6IFtFKCfmlL/lt6UnLCAncmVkJyksIEUoJ+mBk+W+tycsICdkYXJrJyksIEUoJ+mBk+W+tycsICdkYXJrJyksIEUoJzAxMTUnLCAnZGFyaycpXSwNCiAgICBvdGhlcnM6IFtFKCfmlL/lt6UnLCAncmVkJyksIEUoJ+mBk+W+tycsICdkYXJrJyksIEUoJ+mBk+W+tycsICdkYXJrJyksIERdDQogIH0NCl0NCg0KLy8gPT09PT09PT09PT09PT09PT09PT0g5pe26Ze05qC85pWw5o2uID09PT09PT09PT09PT09PT09PT09DQppbnRlcmZhY2UgQ2VsbERhdGEgew0KICBpZDogc3RyaW5nDQogIHdlZWtJZHg6IG51bWJlcg0KICBkYXk6IG51bWJlciAgICAgICAgLy8gMD3lkajkuIAgLi4uIDQ95ZGo5LqUDQogIHBlcmlvZEtleTogc3RyaW5nICAvLyDml7bmrrUga2V5DQogIGRhdGVUZXh0OiBzdHJpbmcgICAvLyDlvZPlpKnml6XmnJ8gTU1ERA0KICB0ZXh0OiBzdHJpbmcgICAgICAgLy8g5pi+56S65paH5pys77yI5LqL5Lu25ZCNIOaIliDml6XmnJ/vvIkNCiAgaXNEYXRlOiBib29sZWFuICAgIC8vIOaYr+WQpuS4uuaXpeacn+agvO+8iOaXoOS6i+S7tu+8iQ0KICB0eXBlOiBTbG90VHlwZQ0KICBib2xkOiBib29sZWFuICAgICAgICAgIC8vIOWKoOeyl+aYvuekug0KICBzY2hlZHVsYWJsZTogYm9vbGVhbiAgIC8vIOWPr+aOkuivvu+8iGZhbHNlIOKGkiDlt6bkuIrop5LngbDlnZfvvIkNCiAgcmVndWxhcjogYm9vbGVhbiAgICAgICAvLyDmraPor77vvIh0cnVlIOKGkiDlj7PkuIrop5Lok53lnZfvvIkNCiAgcmVtYXJrOiBib29sZWFuICAgICAgICAvLyDor77ooajlpIfms6jkuK3mmL7npLoNCn0NCg0KLyoqIOesrDjlkajlkajkuIDvvIjotbflp4vml6XmnJ/vvIkgKi8NCmNvbnN0IFNUQVJUX0RBVEUgPSAnMjAxNy0wOC0yMScNCg0KLyoqIOagueaNruWRqOWumuS5ieeUn+aIkOaXtumXtOagvOaVsOaNru+8iOWRqOS4gH7lkajkupQgw5cg5YWo6YOo5pe25q6177yJICovDQpjb25zdCBidWlsZENlbGxzID0gKCk6IENlbGxEYXRhW10gPT4gew0KICBjb25zdCBjZWxsczogQ2VsbERhdGFbXSA9IFtdDQogIGNvbnN0IHN0YXJ0RGF0ZSA9IGRheWpzKFNUQVJUX0RBVEUpDQogIHdlZWtEZWZzLmZvckVhY2goKHcsIHdpKSA9PiB7DQogICAgZm9yIChsZXQgZCA9IDA7IGQgPCA1OyBkKyspIHsNCiAgICAgIGNvbnN0IGRhdGVUZXh0ID0gc3RhcnREYXRlLmFkZCh3aSwgJ3dlZWsnKS5hZGQoZCwgJ2RheScpLmZvcm1hdCgnTU1ERCcpDQogICAgICBjb25zdCBwYXR0ZXJuID0gZCA9PT0gMCA/IHcubW9uZGF5IDogdy5vdGhlcnMNCiAgICAgIGZvciAobGV0IHBpID0gMDsgcGkgPCBBTExfUEVSSU9EUy5sZW5ndGg7IHBpKyspIHsNCiAgICAgICAgY29uc3QgcGVyaW9kID0gQUxMX1BFUklPRFNbcGldDQogICAgICAgIGNvbnN0IGlzU3BlY2lhbFBlcmlvZCA9IHBlcmlvZC5rZXkgPT09ICc3LTgnIHx8IHBlcmlvZC5rZXkgPT09ICduaWdodCcNCiAgICAgICAgY29uc3QgZGogPSBQQVRURVJOX1BFUklPRF9JRFguaW5kZXhPZihwaSkNCiAgICAgICAgY29uc3QgZGVmOiBTbG90RGVmT3JOdWxsID0gaXNTcGVjaWFsUGVyaW9kID8gbnVsbCA6IChwYXR0ZXJuW2RqXSA/PyBudWxsKQ0KICAgICAgICBjb25zdCBpc0V2ZW50ID0gISFkZWY/LnRleHQNCiAgICAgICAgY2VsbHMucHVzaCh7DQogICAgICAgICAgaWQ6IGAke3dpfS0ke2R9LSR7cGVyaW9kLmtleX1gLA0KICAgICAgICAgIHdlZWtJZHg6IHdpLA0KICAgICAgICAgIGRheTogZCwNCiAgICAgICAgICBwZXJpb2RLZXk6IHBlcmlvZC5rZXksDQogICAgICAgICAgZGF0ZVRleHQsDQogICAgICAgICAgdGV4dDogaXNFdmVudCA/IGRlZiEudGV4dCA6IGRhdGVUZXh0LA0KICAgICAgICAgIGlzRGF0ZTogIWlzRXZlbnQsDQogICAgICAgICAgdHlwZTogaXNFdmVudCA/IGRlZiEudHlwZSA6ICdkYXJrJywNCiAgICAgICAgICBib2xkOiBmYWxzZSwNCiAgICAgICAgICBzY2hlZHVsYWJsZTogdHJ1ZSwNCiAgICAgICAgICByZWd1bGFyOiBmYWxzZSwNCiAgICAgICAgICByZW1hcms6IGZhbHNlDQogICAgICAgIH0pDQogICAgICB9DQogICAgfQ0KICB9KQ0KICByZXR1cm4gY2VsbHMNCn0NCg0KY29uc3QgYWxsQ2VsbHMgPSByZWFjdGl2ZTxDZWxsRGF0YVtdPihidWlsZENlbGxzKCkpDQpjb25zdCBjZWxsTWFwID0gbmV3IE1hcDxzdHJpbmcsIENlbGxEYXRhPigpDQphbGxDZWxscy5mb3JFYWNoKChjKSA9PiBjZWxsTWFwLnNldChjLmlkLCBjKSkNCmNvbnN0IGdldENlbGwgPSAod2Vla0lkeDogbnVtYmVyLCBkYXk6IG51bWJlciwgcGVyaW9kS2V5OiBzdHJpbmcpOiBDZWxsRGF0YSA9Pg0KICBjZWxsTWFwLmdldChgJHt3ZWVrSWR4fS0ke2RheX0tJHtwZXJpb2RLZXl9YCkhDQoNCi8qKiDljZXlhYPmoLzmoLflvI/vvJrkuovku7bmoLznlKjkuovku7boibLvvJvml6XmnJ/moLzmjInmmJ/mnJ/kuqTmm7/og4zmma/oibLvvIjkuIDjgIHkuInjgIHkupTmt7Hnu78gLyDkuozjgIHlm5vmtYXnu7/vvIkgKi8NCmNvbnN0IGNlbGxTdHlsZSA9IChjZWxsOiBDZWxsRGF0YSkgPT4gew0KICBpZiAoY2VsbC5pc0RhdGUpIHsNCiAgICByZXR1cm4gY2VsbC5kYXkgJSAyID09PSAwDQogICAgICA/IHsgYmFja2dyb3VuZENvbG9yOiAnIzJhOGE3ZicsIGNvbG9yOiAnI2ZmZmZmZicgfQ0KICAgICAgOiB7IGJhY2tncm91bmRDb2xvcjogJyNkNmU5ZTInLCBjb2xvcjogJyMyMDYwNGYnIH0NCiAgfQ0KICBjb25zdCBzdCA9IFRZUEVfU1RZTEVbY2VsbC50eXBlXQ0KICByZXR1cm4geyBiYWNrZ3JvdW5kQ29sb3I6IHN0LmJnLCBjb2xvcjogc3QuZmcgfQ0KfQ0KDQovKiog5Y2V5YWD5qC857G777ya6YCJ5Lit5oCBIC8g6YCJ6aG56K+t5LmJICovDQpjb25zdCBjZWxsQ2xhc3MgPSAoY2VsbDogQ2VsbERhdGEpID0+ICh7DQogICdpcy1ldmVudCc6ICFjZWxsLmlzRGF0ZSwNCiAgJ2lzLWRhdGUnOiBjZWxsLmlzRGF0ZSwNCiAgJ2lzLWJvbGQnOiAhY2VsbC5pc0RhdGUgJiYgY2VsbC5ib2xkLA0KICBzZWxlY3RlZDogc2VsZWN0ZWRJZHMudmFsdWUuaGFzKGNlbGwuaWQpLA0KICAnbm90LXNjaGVkdWxhYmxlJzogIWNlbGwuaXNEYXRlICYmICFjZWxsLnNjaGVkdWxhYmxlLA0KICAnaXMtcmVndWxhcic6ICFjZWxsLmlzRGF0ZSAmJiBjZWxsLnJlZ3VsYXINCn0pDQoNCi8vID09PT09PT09PT09PT09PT09PT09IOWkmumAieS6pOS6ku+8iOaLluWKqOi/nueJhyArIEN0cmwg5aSa5Yy65Z+f77yJID09PT09PT09PT09PT09PT09PT09DQpjb25zdCBzZWxlY3RlZElkcyA9IHJlZjxTZXQ8c3RyaW5nPj4obmV3IFNldCgpKQ0KDQppbnRlcmZhY2UgRHJhZ1BvcyB7IHI6IG51bWJlcjsgYzogbnVtYmVyIH0NCg0KbGV0IGRyYWdBY3RpdmUgPSBmYWxzZQ0KbGV0IGRyYWdNb3ZlZCA9IGZhbHNlDQpsZXQgZHJhZ0N0cmwgPSBmYWxzZQ0KbGV0IGFuY2hvckNlbGw6IENlbGxEYXRhIHwgbnVsbCA9IG51bGwNCmxldCBhbmNob3JQb3M6IERyYWdQb3MgPSB7IHI6IDAsIGM6IDAgfQ0KbGV0IGxhc3RQb3M6IERyYWdQb3MgPSB7IHI6IDAsIGM6IDAgfQ0KbGV0IGRyYWdTbmFwc2hvdCA9IG5ldyBTZXQ8c3RyaW5nPigpDQoNCi8qKiDorqHnrpfmoLzlrZDlnKjlvZPliY3mmL7npLrliJfluIPlsYDkuIvnmoTooYzliJflnZDmoIcgKi8NCmNvbnN0IGdldFBvcyA9IChjZWxsOiBDZWxsRGF0YSk6IERyYWdQb3MgPT4gew0KICBjb25zdCBwZXJpb2RJZHggPSB2aXNpYmxlUGVyaW9kcy52YWx1ZS5maW5kSW5kZXgoKHApID0+IHAua2V5ID09PSBjZWxsLnBlcmlvZEtleSkNCiAgcmV0dXJuIHsgcjogY2VsbC53ZWVrSWR4LCBjOiBjZWxsLmRheSAqIHZpc2libGVQZXJpb2RzLnZhbHVlLmxlbmd0aCArIHBlcmlvZElkeCB9DQp9DQoNCi8qKiDorqHnrpcgYW5jaG9yIOS4jiBsYXN0IOS5i+mXtOefqeW9ouWGheeahOaJgOacieagvOWtkCBpZCAqLw0KY29uc3QgcmVjdElkcyA9IChhOiBEcmFnUG9zLCBiOiBEcmFnUG9zKTogc3RyaW5nW10gPT4gew0KICBjb25zdCByMSA9IE1hdGgubWluKGEuciwgYi5yKSwgcjIgPSBNYXRoLm1heChhLnIsIGIucikNCiAgY29uc3QgYzEgPSBNYXRoLm1pbihhLmMsIGIuYyksIGMyID0gTWF0aC5tYXgoYS5jLCBiLmMpDQogIGNvbnN0IGlkczogc3RyaW5nW10gPSBbXQ0KICBmb3IgKGNvbnN0IGNlbGwgb2YgYWxsQ2VsbHMpIHsNCiAgICBjb25zdCBwID0gZ2V0UG9zKGNlbGwpDQogICAgaWYgKHAuciA+PSByMSAmJiBwLnIgPD0gcjIgJiYgcC5jID49IGMxICYmIHAuYyA8PSBjMikgaWRzLnB1c2goY2VsbC5pZCkNCiAgfQ0KICByZXR1cm4gaWRzDQp9DQoNCmNvbnN0IHVwZGF0ZVNlbGVjdGlvbiA9ICgpID0+IHsNCiAgY29uc3QgaWRzID0gcmVjdElkcyhhbmNob3JQb3MsIGxhc3RQb3MpDQogIHNlbGVjdGVkSWRzLnZhbHVlID0gZHJhZ0N0cmwNCiAgICA/IG5ldyBTZXQoWy4uLmRyYWdTbmFwc2hvdCwgLi4uaWRzXSkNCiAgICA6IG5ldyBTZXQoaWRzKQ0KfQ0KDQpjb25zdCBvbkNlbGxNb3VzZURvd24gPSAoY2VsbDogQ2VsbERhdGEsIGU6IE1vdXNlRXZlbnQpID0+IHsNCiAgaWYgKGUuYnV0dG9uICE9PSAwKSByZXR1cm4NCiAgZHJhZ0FjdGl2ZSA9IHRydWUNCiAgZHJhZ01vdmVkID0gZmFsc2UNCiAgZHJhZ0N0cmwgPSBlLmN0cmxLZXkgfHwgZS5tZXRhS2V5DQogIGRyYWdTbmFwc2hvdCA9IG5ldyBTZXQoc2VsZWN0ZWRJZHMudmFsdWUpDQogIGFuY2hvckNlbGwgPSBjZWxsDQogIGFuY2hvclBvcyA9IGdldFBvcyhjZWxsKQ0KICBsYXN0UG9zID0geyAuLi5hbmNob3JQb3MgfQ0KICAvLyDpnZ4gQ3RybCDmjInkuIvml7bnq4vljbPmuIXnqbrml6fpgInmi6nvvIhDdHJsIOaLluWKqOWImeS/neeVmeW5tui/veWKoO+8iQ0KICBpZiAoIWRyYWdDdHJsKSBzZWxlY3RlZElkcy52YWx1ZSA9IG5ldyBTZXQoKQ0KfQ0KDQpjb25zdCBvbkNlbGxNb3VzZU1vdmUgPSAoY2VsbDogQ2VsbERhdGEpID0+IHsNCiAgaWYgKCFkcmFnQWN0aXZlKSByZXR1cm4NCiAgY29uc3QgcG9zID0gZ2V0UG9zKGNlbGwpDQogIGlmIChwb3MuciA9PT0gbGFzdFBvcy5yICYmIHBvcy5jID09PSBsYXN0UG9zLmMpIHJldHVybg0KICBsYXN0UG9zID0gcG9zDQogIGRyYWdNb3ZlZCA9IHRydWUNCiAgdXBkYXRlU2VsZWN0aW9uKCkNCn0NCg0KY29uc3QgZW5kU2VsZWN0ID0gKCkgPT4gew0KICBpZiAoIWRyYWdBY3RpdmUpIHJldHVybg0KICBkcmFnQWN0aXZlID0gZmFsc2UNCiAgaWYgKCFkcmFnTW92ZWQgJiYgYW5jaG9yQ2VsbCkgew0KICAgIGlmIChkcmFnQ3RybCkgew0KICAgICAgLy8gQ3RybCArIOWNleWHu++8muWIh+aNouWNleS4quagvOWtkA0KICAgICAgY29uc3Qgc2V0ID0gbmV3IFNldChzZWxlY3RlZElkcy52YWx1ZSkNCiAgICAgIGlmIChzZXQuaGFzKGFuY2hvckNlbGwuaWQpKSBzZXQuZGVsZXRlKGFuY2hvckNlbGwuaWQpDQogICAgICBlbHNlIHNldC5hZGQoYW5jaG9yQ2VsbC5pZCkNCiAgICAgIHNlbGVjdGVkSWRzLnZhbHVlID0gc2V0DQogICAgfSBlbHNlIHsNCiAgICAgIC8vIOaZrumAmuWNleWHu++8muWNlemAieivpeagvA0KICAgICAgc2VsZWN0ZWRJZHMudmFsdWUgPSBuZXcgU2V0KFthbmNob3JDZWxsLmlkXSkNCiAgICB9DQogIH0NCn0NCg0KLyoqIOeCueWHu+aXtumXtOe8luaOkuWMuuWfn+S7peWklueahOepuueZveWMuuWfn+aXtuWPlua2iOmAieaLqe+8iOaMiemSri/ovpPlhaXmoYbnrYnkuqTkupLlhYPntKDkuI3op6blj5HvvIkgKi8NCmNvbnN0IG9uRG9jQ2xpY2sgPSAoZTogTW91c2VFdmVudCkgPT4gew0KICBjb25zdCB0ID0gZS50YXJnZXQgYXMgSFRNTEVsZW1lbnQNCiAgaWYgKHQuY2xvc2VzdCgnLmNhbGVuZGFyLXRhYmxlJykpIHJldHVybg0KICBpZiAodC5jbG9zZXN0KCdidXR0b24sIGlucHV0LCAuZWwtYnV0dG9uLCAuZWwtY2hlY2tib3gsIC5lbC1zZWxlY3QsIC5lbC1pbnB1dCwgLmVsLWRhdGUtZWRpdG9yJykpIHJldHVybg0KICBzZWxlY3RlZElkcy52YWx1ZSA9IG5ldyBTZXQoKQ0KfQ0KDQpvbk1vdW50ZWQoKCkgPT4gew0KICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgZW5kU2VsZWN0KQ0KICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIG9uRG9jQ2xpY2spDQp9KQ0Kb25CZWZvcmVVbm1vdW50KCgpID0+IHsNCiAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIGVuZFNlbGVjdCkNCiAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignY2xpY2snLCBvbkRvY0NsaWNrKQ0KfSkNCg0KLy8gPT09PT09PT09PT09PT09PT09PT0g5LqL5Lu25pON5L2cID09PT09PT09PT09PT09PT09PT09DQovKiog5bCG5LqL5Lu25qC86K6+572u5aSN5Yi25Yiw5bel5YW35qCP77yI5ZC45Y+W77yJICovDQpjb25zdCBhcHBseVRvVG9vbGJhciA9IChjZWxsOiBDZWxsRGF0YSkgPT4gew0KICBldmVudE5hbWUudmFsdWUgPSBjZWxsLnRleHQNCiAgaXNCb2xkLnZhbHVlID0gY2VsbC5ib2xkDQogIGlzU2NoZWR1bGFibGUudmFsdWUgPSBjZWxsLnNjaGVkdWxhYmxlDQogIGlzUmVndWxhckNsYXNzLnZhbHVlID0gY2VsbC5yZWd1bGFyDQogIHNob3dSZW1hcmsudmFsdWUgPSBjZWxsLnJlbWFyaw0KfQ0KDQovKiog5ZC45Y+WKEkp77ya5bCG6YCJ5Lit5LqL5Lu25qC855qE5ZCN56ew5ZKM6YCJ6aG56K6+572u5aSN5Yi25Yiw5bel5YW35qCPICovDQpjb25zdCBoYW5kbGVBYnNvcmIgPSAoKSA9PiB7DQogIGNvbnN0IGNlbGwgPSBbLi4uc2VsZWN0ZWRJZHMudmFsdWVdLm1hcCgoaWQpID0+IGNlbGxNYXAuZ2V0KGlkKSEpLmZpbmQoKGMpID0+ICFjLmlzRGF0ZSkNCiAgaWYgKCFjZWxsKSB7DQogICAgRWxNZXNzYWdlLndhcm5pbmcoJ+ivt+WFiOmAieaLqeimgeWQuOWPlueahOS6i+S7tuagvCcpDQogICAgcmV0dXJuDQogIH0NCiAgYXBwbHlUb1Rvb2xiYXIoY2VsbCkNCiAgRWxNZXNzYWdlLnN1Y2Nlc3MoJ+W3suWQuOWPluS6i+S7tuiuvue9ruWIsOW3peWFt+agj++8jOWPr+WDj+WIt+WtkOS4gOagt+W/q+mAn+iuvuWumicpDQp9DQoNCi8qKiDlj4zlh7vkuovku7bmoLzvvJrnm7TmjqXlkLjlj5YgKi8NCmNvbnN0IGhhbmRsZUNlbGxEYmxDbGljayA9IChjZWxsOiBDZWxsRGF0YSkgPT4gew0KICBpZiAoY2VsbC5pc0RhdGUpIHsNCiAgICBFbE1lc3NhZ2UuaW5mbygn6K+l5pe26Ze05qC85rKh5pyJ5LqL5Lu277yM5peg5rOV5ZC45Y+WJykNCiAgICByZXR1cm4NCiAgfQ0KICBhcHBseVRvVG9vbGJhcihjZWxsKQ0KICBFbE1lc3NhZ2Uuc3VjY2Vzcyhg5bey5ZC45Y+W44CMJHtjZWxsLnRleHR944CN55qE6K6+572u5Yiw5bel5YW35qCPYCkNCn0NCg0KLyoqIOiuvuWumihTKe+8muWwhuS6i+S7tuWQjeensOWSjOmAiemhueW6lOeUqOWIsOaJgOmAieaXtumXtOagvCAqLw0KY29uc3QgaGFuZGxlU2V0ID0gKCkgPT4gew0KICBjb25zdCBpZHMgPSBbLi4uc2VsZWN0ZWRJZHMudmFsdWVdDQogIGlmICghaWRzLmxlbmd0aCkgew0KICAgIEVsTWVzc2FnZS53YXJuaW5nKCfor7flhYjlnKjml7bpl7TnvJbmjpLljLrln5/pgInmi6nml7bpl7TmoLwnKQ0KICAgIHJldHVybg0KICB9DQogIGNvbnN0IG5hbWUgPSBldmVudE5hbWUudmFsdWUudHJpbSgpDQogIGlmICghbmFtZSkgew0KICAgIEVsTWVzc2FnZS53YXJuaW5nKCfor7flhYjovpPlhaXkuovku7blkI3np7AnKQ0KICAgIHJldHVybg0KICB9DQogIGlkcy5mb3JFYWNoKChpZCkgPT4gew0KICAgIGNvbnN0IGMgPSBjZWxsTWFwLmdldChpZCkhDQogICAgYy50ZXh0ID0gbmFtZQ0KICAgIGMuaXNEYXRlID0gZmFsc2UNCiAgICBjLnR5cGUgPSAncmVkJw0KICAgIGMuYm9sZCA9IGlzQm9sZC52YWx1ZQ0KICAgIGMuc2NoZWR1bGFibGUgPSBpc1NjaGVkdWxhYmxlLnZhbHVlDQogICAgYy5yZWd1bGFyID0gaXNSZWd1bGFyQ2xhc3MudmFsdWUNCiAgICBjLnJlbWFyayA9IHNob3dSZW1hcmsudmFsdWUNCiAgfSkNCiAgRWxNZXNzYWdlLnN1Y2Nlc3MoYOW3suS4uiAke2lkcy5sZW5ndGh9IOS4quaXtumXtOagvOiuvuWumuS6i+S7tuOAjCR7bmFtZX3jgI1gKQ0KfQ0KDQovKiog5Yig6ZmkKEQp77ya5riF6Zmk5omA6YCJ5pe26Ze05qC855qE5LqL5Lu277yM5oGi5aSN5pel5pyf5pi+56S644CB5L2O5pqX6IOM5pmvICovDQpjb25zdCBoYW5kbGVEZWxldGUgPSAoKSA9PiB7DQogIGNvbnN0IGlkcyA9IFsuLi5zZWxlY3RlZElkcy52YWx1ZV0NCiAgaWYgKCFpZHMubGVuZ3RoKSB7DQogICAgRWxNZXNzYWdlLndhcm5pbmcoJ+ivt+WFiOmAieaLqeimgeWIoOmZpOS6i+S7tueahOaXtumXtOagvCcpDQogICAgcmV0dXJuDQogIH0NCiAgaWRzLmZvckVhY2goKGlkKSA9PiB7DQogICAgY29uc3QgYyA9IGNlbGxNYXAuZ2V0KGlkKSENCiAgICBjLmlzRGF0ZSA9IHRydWUNCiAgICBjLnRleHQgPSBjLmRhdGVUZXh0DQogICAgYy5ib2xkID0gZmFsc2UNCiAgICBjLnNjaGVkdWxhYmxlID0gdHJ1ZQ0KICAgIGMucmVndWxhciA9IGZhbHNlDQogICAgYy5yZW1hcmsgPSBmYWxzZQ0KICB9KQ0KICBFbE1lc3NhZ2Uuc3VjY2Vzcyhg5bey5Yig6ZmkICR7aWRzLmxlbmd0aH0g5Liq5pe26Ze05qC855qE5LqL5Lu2YCkNCn0NCg0KLyoqIOWtpuWRmOmYn+mAieWPluW8ueeql++8iOW6lOeUqOS6juWFtuWug+ePreasoe+8iSAqLw0KY29uc3QgdGVhbVNlbGVjdFZpc2libGUgPSByZWYoZmFsc2UpDQovKiog5b2T5YmN5bqU55So5qih5byP77yacmVnaW9uPemAieWumuWMuuWfnyAvIHdob2xlPeaVtOS4quePreWOhiAqLw0KY29uc3QgYXBwbHlNb2RlID0gcmVmPCdyZWdpb24nIHwgJ3dob2xlJz4oJ3JlZ2lvbicpDQoNCi8qKiDpgInlrprljLrln5/orr7nva7lupTnlKjkuo7lhbblroPnj63mrKEoTSnvvJrlhYjpgInmi6nml7bpl7TmoLzvvIzlho3lvLnlh7rlrablkZjpmJ/pgInlj5bnqpflj6MgKi8NCmNvbnN0IGhhbmRsZUFwcGx5T3RoZXIgPSAoKSA9PiB7DQogIGlmICghc2VsZWN0ZWRJZHMudmFsdWUuc2l6ZSkgew0KICAgIEVsTWVzc2FnZS53YXJuaW5nKCfor7flhYjlnKjml7bpl7TnvJbmjpLljLrln5/pgInmi6nml7bpl7TmoLwnKQ0KICAgIHJldHVybg0KICB9DQogIGFwcGx5TW9kZS52YWx1ZSA9ICdyZWdpb24nDQogIHRlYW1TZWxlY3RWaXNpYmxlLnZhbHVlID0gdHJ1ZQ0KfQ0KDQovKiog5pW05Liq54+t5Y6G5bqU55So5LqO5YW25a6D54+t5qyhKFcp77ya5by55Ye65a2m5ZGY6Zif6YCJ5Y+W56qX5Y+jICovDQpjb25zdCBoYW5kbGVBcHBseVdob2xlID0gKCkgPT4gew0KICBhcHBseU1vZGUudmFsdWUgPSAnd2hvbGUnDQogIHRlYW1TZWxlY3RWaXNpYmxlLnZhbHVlID0gdHJ1ZQ0KfQ0KDQovKiog5a2m5ZGY6Zif6YCJ5Y+W56Gu6K6k5ZCO5bqU55SoICovDQpjb25zdCBoYW5kbGVUZWFtQ29uZmlybSA9ICgpID0+IHsNCiAgaWYgKGFwcGx5TW9kZS52YWx1ZSA9PT0gJ3dob2xlJykgew0KICAgIC8vIOWQjuerr+aOpeWPo+acquaPkOS+m++8jOS7heWJjeerr+a8lOekuu+8muWwhuW9k+WJjeePreWOhuWujOaVtOWkjeWItuWIsOaJgOmAieePreasoQ0KICAgIEVsTWVzc2FnZS5zdWNjZXNzKCfmlbTkuKrnj63ljoblt7LlrozmlbTlpI3liLbliLDmiYDpgInnj63mrKHvvIjlkI7nq6/mjqXlj6PmnKrmj5DkvpvvvIzliY3nq6/mvJTnpLrvvIknKQ0KICB9IGVsc2Ugew0KICAgIEVsTWVzc2FnZS5zdWNjZXNzKCflt7LlupTnlKjpgInlrprljLrln5/orr7nva7liLDmiYDpgInnj63mrKHvvIjliY3nq6/mvJTnpLrvvIknKQ0KICB9DQp9DQoNCi8qKiDliLfmlrAoRSnvvJrmgaLlpI3liJ3lp4vnj63ljobmlbDmja4gKi8NCmNvbnN0IGhhbmRsZVJlZnJlc2ggPSAoKSA9PiB7DQogIGFsbENlbGxzLnNwbGljZSgwLCBhbGxDZWxscy5sZW5ndGgsIC4uLmJ1aWxkQ2VsbHMoKSkNCiAgY2VsbE1hcC5jbGVhcigpDQogIGFsbENlbGxzLmZvckVhY2goKGMpID0+IGNlbGxNYXAuc2V0KGMuaWQsIGMpKQ0KICBzZWxlY3RlZElkcy52YWx1ZSA9IG5ldyBTZXQoKQ0KICBldmVudE5hbWUudmFsdWUgPSAnJw0KICBFbE1lc3NhZ2Uuc3VjY2Vzcygn5bey5Yi35paw54+t5Y6GJykNCn0NCg=="},{"version":3,"sources":["ClassCalendarDialog.vue"],"names":[],"mappings":";AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"ClassCalendarDialog.vue","sourceRoot":"src/views/teachOffice/shiftSemester","sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'\r\nimport { ElMessage } from 'element-plus'\r\nimport dayjs from 'dayjs'\r\nimport ClassTeamSelectDialog from './ClassTeamSelectDialog.vue'\r\n\r\n// ==================== Props & Emits ====================\r\nconst props = withDefaults(\r\n defineProps<{\r\n modelValue: boolean\r\n /** 班次号(如 0203) */\r\n bc?: string\r\n /** 学期名称 */\r\n semesterName?: string\r\n }>(),\r\n {\r\n bc: '0399',\r\n semesterName: '2017年秋季学期'\r\n }\r\n)\r\n\r\nconst emit = defineEmits<{\r\n (e: 'update:modelValue', value: boolean): void\r\n}>()\r\n\r\nconst visible = computed({\r\n get: () => props.modelValue,\r\n set: (val) => emit('update:modelValue', val)\r\n})\r\n\r\n// ==================== Windows 标题栏 ====================\r\n// 每次打开对话框时重置选择状态\r\nwatch(\r\n () => props.modelValue,\r\n (val) => {\r\n if (val) {\r\n selectedIds.value = new Set()\r\n }\r\n }\r\n)\r\n\r\n// ==================== 学期与班次信息 ====================\r\n/** 校历范围 */\r\nconst calStart = '2017-07-08'\r\nconst calEnd = '2018-02-11'\r\nconst calWeeks = 32\r\n/** 班历范围(校历基础上为班次安排) */\r\nconst classStart = '2017-08-24'\r\nconst classEnd = '2018-02-05'\r\nconst classWeeks = 25\r\n\r\n// ==================== 事件设置区域 ====================\r\nconst eventName = ref('')\r\nconst isBold = ref(false) // 加粗显示\r\nconst isSchedulable = ref(false) // 可排课\r\nconst isRegularClass = ref(false) // 正课\r\nconst showRemark = ref(false) // 课表备注中显示\r\nconst remark = ref('')\r\nconst show78 = ref(false) // 显示7/8节\r\nconst showEvening = ref(true) // 显示晚上(已勾选)\r\nconst showNight = ref(false) // 显示夜间\r\n\r\n// ==================== 时段定义 ====================\r\ninterface PeriodDef {\r\n key: string\r\n label: string\r\n}\r\n\r\n/** 全部时段:1-2、3-4、5-6 恒显示;7-8 / 9-10(晚上) / 夜间 由复选框控制 */\r\nconst ALL_PERIODS: PeriodDef[] = [\r\n { key: '1-2', label: '1-2' },\r\n { key: '3-4', label: '3-4' },\r\n { key: '5-6', label: '5-6' },\r\n { key: '7-8', label: '7-8' },\r\n { key: '9-10', label: '9-10' },\r\n { key: 'night', label: '夜间' }\r\n]\r\n\r\n/** 事件模式下标 → ALL_PERIODS 下标(1-2、3-4、5-6、9-10) */\r\nconst PATTERN_PERIOD_IDX = [0, 1, 2, 4]\r\n\r\n/** 时间编排区域实际显示的时段(由三个复选框控制) */\r\nconst visiblePeriods = computed<PeriodDef[]>(() =>\r\n ALL_PERIODS.filter((p) => {\r\n if (p.key === '7-8') return show78.value\r\n if (p.key === '9-10') return showEvening.value\r\n if (p.key === 'night') return showNight.value\r\n return true\r\n })\r\n)\r\n\r\n// ==================== 班历表格数据 ====================\r\nconst dayNames = ['一', '二', '三', '四', '五']\r\n\r\n/** 事件类型 → 颜色 */\r\ntype SlotType = 'red' | 'dark' | 'green' | 'cyan'\r\n\r\nconst TYPE_STYLE: Record<SlotType, { bg: string; fg: string }> = {\r\n red: { bg: '#d94343', fg: '#ffffff' }, // 正常课程/活动(马基、保密、布雷、维修、布修、战术、国庆节、政工)\r\n dark: { bg: '#2a8a7f', fg: '#ffffff' }, // 深青/墨绿:游泳、道德、日期标记\r\n green: { bg: '#4f9d57', fg: '#ffffff' }, // 特殊课程/活动(核心、组训)\r\n cyan: { bg: '#8fd4e0', fg: '#14505a' } // 青/浅蓝:学前、元旦\r\n}\r\n\r\ninterface SlotDef {\r\n text: string\r\n type: SlotType\r\n}\r\ntype SlotDefOrNull = SlotDef | null\r\n\r\ninterface WeekDef {\r\n num: number\r\n start: string\r\n end: string\r\n /** 周一事件模式(1-2、3-4、5-6、9-10),null 表示日期格 */\r\n monday: SlotDefOrNull[]\r\n /** 周二~周五事件模式(通常与周一相同) */\r\n others: SlotDefOrNull[]\r\n}\r\n\r\nconst E = (text: string, type: SlotType): SlotDef => ({ text, type })\r\nconst D: SlotDefOrNull = null // 日期格:显示当天日期\r\n\r\n/** 班历事件(第8周~第29周,严格按截图还原;null 为日期格) */\r\nconst weekDefs: WeekDef[] = [\r\n // 学前适应(青)\r\n {\r\n num: 8, start: '08-21', end: '08-27',\r\n monday: [E('学前', 'cyan'), E('学前', 'cyan'), E('学前', 'cyan'), E('学前', 'cyan')],\r\n others: [E('学前', 'cyan'), E('学前', 'cyan'), E('学前', 'cyan'), E('学前', 'cyan')]\r\n },\r\n // 马基(红)+ 游泳(墨绿)\r\n {\r\n num: 9, start: '08-28', end: '09-03',\r\n monday: [E('马基', 'red'), E('游泳', 'dark'), D, D],\r\n others: [E('马基', 'red'), E('游泳', 'dark'), D, D]\r\n },\r\n {\r\n num: 10, start: '09-04', end: '09-10',\r\n monday: [E('马基', 'red'), E('游泳', 'dark'), D, D],\r\n others: [E('马基', 'red'), E('游泳', 'dark'), D, D]\r\n },\r\n // 马基(红)+ 保密(红)\r\n {\r\n num: 11, start: '09-11', end: '09-17',\r\n monday: [E('马基', 'red'), E('保密', 'red'), D, D],\r\n others: [E('马基', 'red'), E('保密', 'red'), D, D]\r\n },\r\n {\r\n num: 12, start: '09-18', end: '09-24',\r\n monday: [E('马基', 'red'), E('保密', 'red'), D, D],\r\n others: [E('马基', 'red'), E('保密', 'red'), D, D]\r\n },\r\n // 布雷(红)\r\n {\r\n num: 13, start: '09-25', end: '10-01',\r\n monday: [E('布雷', 'red'), E('布雷', 'red'), D, D],\r\n others: [E('布雷', 'red'), E('布雷', 'red'), D, D]\r\n },\r\n // 国庆节(红)\r\n {\r\n num: 14, start: '10-02', end: '10-08',\r\n monday: [E('国庆节', 'red'), E('国庆节', 'red'), E('国庆节', 'red'), E('国庆节', 'red')],\r\n others: [E('国庆节', 'red'), E('国庆节', 'red'), E('国庆节', 'red'), E('国庆节', 'red')]\r\n },\r\n {\r\n num: 15, start: '10-09', end: '10-15',\r\n monday: [E('布雷', 'red'), E('布雷', 'red'), D, D],\r\n others: [E('布雷', 'red'), E('布雷', 'red'), D, D]\r\n },\r\n {\r\n num: 16, start: '10-16', end: '10-22',\r\n monday: [E('布雷', 'red'), E('布雷', 'red'), D, D],\r\n others: [E('布雷', 'red'), E('布雷', 'red'), D, D]\r\n },\r\n {\r\n num: 17, start: '10-23', end: '10-29',\r\n monday: [E('布雷', 'red'), E('布雷', 'red'), D, D],\r\n others: [E('布雷', 'red'), E('布雷', 'red'), D, D]\r\n },\r\n // 维修(红)\r\n {\r\n num: 18, start: '10-30', end: '11-05',\r\n monday: [E('维修', 'red'), E('维修', 'red'), D, D],\r\n others: [E('维修', 'red'), E('维修', 'red'), D, D]\r\n },\r\n // 维修(红)+ 核心(绿)\r\n {\r\n num: 19, start: '11-06', end: '11-12',\r\n monday: [E('维修', 'red'), E('维修', 'red'), E('核心', 'green'), D],\r\n others: [E('维修', 'red'), E('维修', 'red'), E('核心', 'green'), D]\r\n },\r\n // 布修(红)\r\n {\r\n num: 20, start: '11-13', end: '11-19',\r\n monday: [E('布修', 'red'), E('布修', 'red'), D, D],\r\n others: [E('布修', 'red'), E('布修', 'red'), D, D]\r\n },\r\n {\r\n num: 21, start: '11-20', end: '11-26',\r\n monday: [E('布修', 'red'), E('布修', 'red'), D, D],\r\n others: [E('布修', 'red'), E('布修', 'red'), D, D]\r\n },\r\n {\r\n num: 22, start: '11-27', end: '12-03',\r\n monday: [E('布修', 'red'), E('布修', 'red'), D, D],\r\n others: [E('布修', 'red'), E('布修', 'red'), D, D]\r\n },\r\n // 维修(红)\r\n {\r\n num: 23, start: '12-04', end: '12-10',\r\n monday: [E('维修', 'red'), E('维修', 'red'), D, D],\r\n others: [E('维修', 'red'), E('维修', 'red'), D, D]\r\n },\r\n {\r\n num: 24, start: '12-11', end: '12-17',\r\n monday: [E('维修', 'red'), E('维修', 'red'), D, D],\r\n others: [E('维修', 'red'), E('维修', 'red'), D, D]\r\n },\r\n {\r\n num: 25, start: '12-18', end: '12-24',\r\n monday: [E('维修', 'red'), E('维修', 'red'), D, D],\r\n others: [E('维修', 'red'), E('维修', 'red'), D, D]\r\n },\r\n // 战术(红)\r\n {\r\n num: 26, start: '12-25', end: '12-31',\r\n monday: [E('战术', 'red'), E('战术', 'red'), E('战术', 'red'), E('战术', 'red')],\r\n others: [E('战术', 'red'), E('战术', 'red'), E('战术', 'red'), E('战术', 'red')]\r\n },\r\n // 元旦(青,周一)+ 组训(绿,周二~周五)\r\n {\r\n num: 27, start: '01-01', end: '01-07',\r\n monday: [E('元旦', 'cyan'), E('元旦', 'cyan'), E('元旦', 'cyan'), E('元旦', 'cyan')],\r\n others: [E('组训', 'green'), E('组训', 'green'), E('组训', 'green'), E('组训', 'green')]\r\n },\r\n // 政工(红)+ 道德(墨绿)\r\n {\r\n num: 28, start: '01-08', end: '01-14',\r\n monday: [E('政工', 'red'), E('道德', 'dark'), E('道德', 'dark'), E('0106', 'dark')],\r\n others: [E('政工', 'red'), E('道德', 'dark'), E('道德', 'dark'), D]\r\n },\r\n {\r\n num: 29, start: '01-15', end: '01-21',\r\n monday: [E('政工', 'red'), E('道德', 'dark'), E('道德', 'dark'), E('0115', 'dark')],\r\n others: [E('政工', 'red'), E('道德', 'dark'), E('道德', 'dark'), D]\r\n }\r\n]\r\n\r\n// ==================== 时间格数据 ====================\r\ninterface CellData {\r\n id: string\r\n weekIdx: number\r\n day: number // 0=周一 ... 4=周五\r\n periodKey: string // 时段 key\r\n dateText: string // 当天日期 MMDD\r\n text: string // 显示文本(事件名 或 日期)\r\n isDate: boolean // 是否为日期格(无事件)\r\n type: SlotType\r\n bold: boolean // 加粗显示\r\n schedulable: boolean // 可排课(false → 左上角灰块)\r\n regular: boolean // 正课(true → 右上角蓝块)\r\n remark: boolean // 课表备注中显示\r\n}\r\n\r\n/** 第8周周一(起始日期) */\r\nconst START_DATE = '2017-08-21'\r\n\r\n/** 根据周定义生成时间格数据(周一~周五 × 全部时段) */\r\nconst buildCells = (): CellData[] => {\r\n const cells: CellData[] = []\r\n const startDate = dayjs(START_DATE)\r\n weekDefs.forEach((w, wi) => {\r\n for (let d = 0; d < 5; d++) {\r\n const dateText = startDate.add(wi, 'week').add(d, 'day').format('MMDD')\r\n const pattern = d === 0 ? w.monday : w.others\r\n for (let pi = 0; pi < ALL_PERIODS.length; pi++) {\r\n const period = ALL_PERIODS[pi]\r\n const isSpecialPeriod = period.key === '7-8' || period.key === 'night'\r\n const dj = PATTERN_PERIOD_IDX.indexOf(pi)\r\n const def: SlotDefOrNull = isSpecialPeriod ? null : (pattern[dj] ?? null)\r\n const isEvent = !!def?.text\r\n cells.push({\r\n id: `${wi}-${d}-${period.key}`,\r\n weekIdx: wi,\r\n day: d,\r\n periodKey: period.key,\r\n dateText,\r\n text: isEvent ? def!.text : dateText,\r\n isDate: !isEvent,\r\n type: isEvent ? def!.type : 'dark',\r\n bold: false,\r\n schedulable: true,\r\n regular: false,\r\n remark: false\r\n })\r\n }\r\n }\r\n })\r\n return cells\r\n}\r\n\r\nconst allCells = reactive<CellData[]>(buildCells())\r\nconst cellMap = new Map<string, CellData>()\r\nallCells.forEach((c) => cellMap.set(c.id, c))\r\nconst getCell = (weekIdx: number, day: number, periodKey: string): CellData =>\r\n cellMap.get(`${weekIdx}-${day}-${periodKey}`)!\r\n\r\n/** 单元格样式:事件格用事件色;日期格按星期交替背景色(一、三、五深绿 / 二、四浅绿) */\r\nconst cellStyle = (cell: CellData) => {\r\n if (cell.isDate) {\r\n return cell.day % 2 === 0\r\n ? { backgroundColor: '#2a8a7f', color: '#ffffff' }\r\n : { backgroundColor: '#d6e9e2', color: '#20604f' }\r\n }\r\n const st = TYPE_STYLE[cell.type]\r\n return { backgroundColor: st.bg, color: st.fg }\r\n}\r\n\r\n/** 单元格类:选中态 / 选项语义 */\r\nconst cellClass = (cell: CellData) => ({\r\n 'is-event': !cell.isDate,\r\n 'is-date': cell.isDate,\r\n 'is-bold': !cell.isDate && cell.bold,\r\n selected: selectedIds.value.has(cell.id),\r\n 'not-schedulable': !cell.isDate && !cell.schedulable,\r\n 'is-regular': !cell.isDate && cell.regular\r\n})\r\n\r\n// ==================== 多选交互(拖动连片 + Ctrl 多区域) ====================\r\nconst selectedIds = ref<Set<string>>(new Set())\r\n\r\ninterface DragPos { r: number; c: number }\r\n\r\nlet dragActive = false\r\nlet dragMoved = false\r\nlet dragCtrl = false\r\nlet anchorCell: CellData | null = null\r\nlet anchorPos: DragPos = { r: 0, c: 0 }\r\nlet lastPos: DragPos = { r: 0, c: 0 }\r\nlet dragSnapshot = new Set<string>()\r\n\r\n/** 计算格子在当前显示列布局下的行列坐标 */\r\nconst getPos = (cell: CellData): DragPos => {\r\n const periodIdx = visiblePeriods.value.findIndex((p) => p.key === cell.periodKey)\r\n return { r: cell.weekIdx, c: cell.day * visiblePeriods.value.length + periodIdx }\r\n}\r\n\r\n/** 计算 anchor 与 last 之间矩形内的所有格子 id */\r\nconst rectIds = (a: DragPos, b: DragPos): string[] => {\r\n const r1 = Math.min(a.r, b.r), r2 = Math.max(a.r, b.r)\r\n const c1 = Math.min(a.c, b.c), c2 = Math.max(a.c, b.c)\r\n const ids: string[] = []\r\n for (const cell of allCells) {\r\n const p = getPos(cell)\r\n if (p.r >= r1 && p.r <= r2 && p.c >= c1 && p.c <= c2) ids.push(cell.id)\r\n }\r\n return ids\r\n}\r\n\r\nconst updateSelection = () => {\r\n const ids = rectIds(anchorPos, lastPos)\r\n selectedIds.value = dragCtrl\r\n ? new Set([...dragSnapshot, ...ids])\r\n : new Set(ids)\r\n}\r\n\r\nconst onCellMouseDown = (cell: CellData, e: MouseEvent) => {\r\n if (e.button !== 0) return\r\n dragActive = true\r\n dragMoved = false\r\n dragCtrl = e.ctrlKey || e.metaKey\r\n dragSnapshot = new Set(selectedIds.value)\r\n anchorCell = cell\r\n anchorPos = getPos(cell)\r\n lastPos = { ...anchorPos }\r\n // 非 Ctrl 按下时立即清空旧选择(Ctrl 拖动则保留并追加)\r\n if (!dragCtrl) selectedIds.value = new Set()\r\n}\r\n\r\nconst onCellMouseMove = (cell: CellData) => {\r\n if (!dragActive) return\r\n const pos = getPos(cell)\r\n if (pos.r === lastPos.r && pos.c === lastPos.c) return\r\n lastPos = pos\r\n dragMoved = true\r\n updateSelection()\r\n}\r\n\r\nconst endSelect = () => {\r\n if (!dragActive) return\r\n dragActive = false\r\n if (!dragMoved && anchorCell) {\r\n if (dragCtrl) {\r\n // Ctrl + 单击:切换单个格子\r\n const set = new Set(selectedIds.value)\r\n if (set.has(anchorCell.id)) set.delete(anchorCell.id)\r\n else set.add(anchorCell.id)\r\n selectedIds.value = set\r\n } else {\r\n // 普通单击:单选该格\r\n selectedIds.value = new Set([anchorCell.id])\r\n }\r\n }\r\n}\r\n\r\n/** 点击时间编排区域以外的空白区域时取消选择(按钮/输入框等交互元素不触发) */\r\nconst onDocClick = (e: MouseEvent) => {\r\n const t = e.target as HTMLElement\r\n if (t.closest('.calendar-table')) return\r\n if (t.closest('button, input, .el-button, .el-checkbox, .el-select, .el-input, .el-date-editor')) return\r\n selectedIds.value = new Set()\r\n}\r\n\r\nonMounted(() => {\r\n document.addEventListener('mouseup', endSelect)\r\n document.addEventListener('click', onDocClick)\r\n})\r\nonBeforeUnmount(() => {\r\n document.removeEventListener('mouseup', endSelect)\r\n document.removeEventListener('click', onDocClick)\r\n})\r\n\r\n// ==================== 事件操作 ====================\r\n/** 将事件格设置复制到工具栏(吸取) */\r\nconst applyToToolbar = (cell: CellData) => {\r\n eventName.value = cell.text\r\n isBold.value = cell.bold\r\n isSchedulable.value = cell.schedulable\r\n isRegularClass.value = cell.regular\r\n showRemark.value = cell.remark\r\n}\r\n\r\n/** 吸取(I):将选中事件格的名称和选项设置复制到工具栏 */\r\nconst handleAbsorb = () => {\r\n const cell = [...selectedIds.value].map((id) => cellMap.get(id)!).find((c) => !c.isDate)\r\n if (!cell) {\r\n ElMessage.warning('请先选择要吸取的事件格')\r\n return\r\n }\r\n applyToToolbar(cell)\r\n ElMessage.success('已吸取事件设置到工具栏,可像刷子一样快速设定')\r\n}\r\n\r\n/** 双击事件格:直接吸取 */\r\nconst handleCellDblClick = (cell: CellData) => {\r\n if (cell.isDate) {\r\n ElMessage.info('该时间格没有事件,无法吸取')\r\n return\r\n }\r\n applyToToolbar(cell)\r\n ElMessage.success(`已吸取「${cell.text}」的设置到工具栏`)\r\n}\r\n\r\n/** 设定(S):将事件名称和选项应用到所选时间格 */\r\nconst handleSet = () => {\r\n const ids = [...selectedIds.value]\r\n if (!ids.length) {\r\n ElMessage.warning('请先在时间编排区域选择时间格')\r\n return\r\n }\r\n const name = eventName.value.trim()\r\n if (!name) {\r\n ElMessage.warning('请先输入事件名称')\r\n return\r\n }\r\n ids.forEach((id) => {\r\n const c = cellMap.get(id)!\r\n c.text = name\r\n c.isDate = false\r\n c.type = 'red'\r\n c.bold = isBold.value\r\n c.schedulable = isSchedulable.value\r\n c.regular = isRegularClass.value\r\n c.remark = showRemark.value\r\n })\r\n ElMessage.success(`已为 ${ids.length} 个时间格设定事件「${name}」`)\r\n}\r\n\r\n/** 删除(D):清除所选时间格的事件,恢复日期显示、低暗背景 */\r\nconst handleDelete = () => {\r\n const ids = [...selectedIds.value]\r\n if (!ids.length) {\r\n ElMessage.warning('请先选择要删除事件的时间格')\r\n return\r\n }\r\n ids.forEach((id) => {\r\n const c = cellMap.get(id)!\r\n c.isDate = true\r\n c.text = c.dateText\r\n c.bold = false\r\n c.schedulable = true\r\n c.regular = false\r\n c.remark = false\r\n })\r\n ElMessage.success(`已删除 ${ids.length} 个时间格的事件`)\r\n}\r\n\r\n/** 学员队选取弹窗(应用于其它班次) */\r\nconst teamSelectVisible = ref(false)\r\n/** 当前应用模式:region=选定区域 / whole=整个班历 */\r\nconst applyMode = ref<'region' | 'whole'>('region')\r\n\r\n/** 选定区域设置应用于其它班次(M):先选择时间格,再弹出学员队选取窗口 */\r\nconst handleApplyOther = () => {\r\n if (!selectedIds.value.size) {\r\n ElMessage.warning('请先在时间编排区域选择时间格')\r\n return\r\n }\r\n applyMode.value = 'region'\r\n teamSelectVisible.value = true\r\n}\r\n\r\n/** 整个班历应用于其它班次(W):弹出学员队选取窗口 */\r\nconst handleApplyWhole = () => {\r\n applyMode.value = 'whole'\r\n teamSelectVisible.value = true\r\n}\r\n\r\n/** 学员队选取确认后应用 */\r\nconst handleTeamConfirm = () => {\r\n if (applyMode.value === 'whole') {\r\n // 后端接口未提供,仅前端演示:将当前班历完整复制到所选班次\r\n ElMessage.success('整个班历已完整复制到所选班次(后端接口未提供,前端演示)')\r\n } else {\r\n ElMessage.success('已应用选定区域设置到所选班次(前端演示)')\r\n }\r\n}\r\n\r\n/** 刷新(E):恢复初始班历数据 */\r\nconst handleRefresh = () => {\r\n allCells.splice(0, allCells.length, ...buildCells())\r\n cellMap.clear()\r\n allCells.forEach((c) => cellMap.set(c.id, c))\r\n selectedIds.value = new Set()\r\n eventName.value = ''\r\n ElMessage.success('已刷新班历')\r\n}\r\n</script>\r\n\r\n<template>\r\n <el-dialog\r\n v-model=\"visible\"\r\n title=\"班历设置\"\r\n width=\"94%\"\r\n top=\"4vh\"\r\n :close-on-click-modal=\"false\"\r\n destroy-on-close\r\n class=\"class-calendar-dialog\"\r\n >\r\n <div class=\"class-calendar\">\r\n <!-- ==================== 1. 学期与班次信息 ==================== -->\r\n <div class=\"info-panel\">\r\n <div class=\"info-title-row\">\r\n <span class=\"semester-name\">{{ semesterName }}</span>\r\n <span class=\"class-name\">班次{{ bc }}</span>\r\n </div>\r\n <div class=\"date-range-row\">\r\n <div class=\"range-item\">从{{ calStart }}到{{ calEnd }},共{{ calWeeks }}周</div>\r\n <div class=\"range-item\">从{{ classStart }}到{{ classEnd }},共{{ classWeeks }}周</div>\r\n </div>\r\n </div>\r\n\r\n <!-- ==================== 2. 设置面板(事件设置 + 操作按钮) ==================== -->\r\n <div class=\"settings-panel\">\r\n <div class=\"event-settings-row\">\r\n <div class=\"setting-item\">\r\n <span class=\"setting-label\">事件名称</span>\r\n <el-input v-model=\"eventName\" size=\"small\" style=\"width: 140px\" placeholder=\"\" />\r\n </div>\r\n <el-checkbox v-model=\"isBold\" size=\"small\">加粗显示</el-checkbox>\r\n <el-checkbox v-model=\"isSchedulable\" size=\"small\">可排课</el-checkbox>\r\n <el-checkbox v-model=\"isRegularClass\" size=\"small\">正课</el-checkbox>\r\n <el-checkbox v-model=\"showRemark\" size=\"small\">课表备注中显示</el-checkbox>\r\n <div class=\"setting-item\">\r\n <span class=\"setting-label\">备注</span>\r\n <el-input v-model=\"remark\" size=\"small\" style=\"width: 150px\" placeholder=\"\" />\r\n </div>\r\n <el-checkbox v-model=\"show78\" size=\"small\">显示7/8节</el-checkbox>\r\n <el-checkbox v-model=\"showEvening\" size=\"small\">显示晚上</el-checkbox>\r\n <el-checkbox v-model=\"showNight\" size=\"small\">显示夜间</el-checkbox>\r\n </div>\r\n\r\n <!-- ==================== 3. 操作按钮区域 ==================== -->\r\n <div class=\"action-buttons-row\">\r\n <button type=\"button\" class=\"gray-btn\" @click=\"handleAbsorb\">吸取(I)</button>\r\n <button type=\"button\" class=\"gray-btn\" @click=\"handleSet\">设定(S)</button>\r\n <button type=\"button\" class=\"gray-btn\" @click=\"handleDelete\">删除(D)</button>\r\n <button type=\"button\" class=\"blue-btn\" @click=\"handleApplyOther\">选定区域设置应用于其它班次(M)</button>\r\n <button type=\"button\" class=\"gray-btn\" @click=\"handleApplyWhole\">整个班历应用于其它班次(W)</button>\r\n <button type=\"button\" class=\"gray-btn\" @click=\"handleRefresh\">刷新(E)</button>\r\n </div>\r\n </div>\r\n\r\n <!-- ==================== 4. 时间编排区域 ==================== -->\r\n <div class=\"table-area\">\r\n <div class=\"calendar-table-wrapper\">\r\n <table class=\"calendar-table\">\r\n <thead>\r\n <tr class=\"head-row-1\">\r\n <th rowspan=\"2\" class=\"cell-week-head\">周次</th>\r\n <th rowspan=\"2\" class=\"cell-range-head\">日期段</th>\r\n <th v-for=\"name in dayNames\" :key=\"name\" :colspan=\"visiblePeriods.length\">{{ name }}</th>\r\n </tr>\r\n <tr class=\"head-row-2\">\r\n <template v-for=\"(_, di) in dayNames\" :key=\"`p-${di}`\">\r\n <th v-for=\"p in visiblePeriods\" :key=\"`${di}-${p.key}`\">{{ p.label }}</th>\r\n </template>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr v-for=\"(w, wi) in weekDefs\" :key=\"w.num\">\r\n <td class=\"week-num\">{{ w.num }}</td>\r\n <td class=\"date-range\">{{ w.start }}至{{ w.end }}</td>\r\n <template v-for=\"d in 5\" :key=\"d\">\r\n <td\r\n v-for=\"p in visiblePeriods\"\r\n :key=\"`${wi}-${d - 1}-${p.key}`\"\r\n class=\"cell\"\r\n :class=\"cellClass(getCell(wi, d - 1, p.key))\"\r\n :style=\"cellStyle(getCell(wi, d - 1, p.key))\"\r\n :title=\"getCell(wi, d - 1, p.key).isDate ? '该时间格无事件,可选中后设定事件' : '双击可吸取该事件设置'\"\r\n @mousedown.prevent=\"onCellMouseDown(getCell(wi, d - 1, p.key), $event)\"\r\n @mousemove=\"onCellMouseMove(getCell(wi, d - 1, p.key))\"\r\n @dblclick=\"handleCellDblClick(getCell(wi, d - 1, p.key))\"\r\n >{{ getCell(wi, d - 1, p.key).text }}</td>\r\n </template>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"select-tip\">\r\n 提示:在时间编排区域按住鼠标拖动可连片多选,按住 Ctrl 键可用鼠标选择多个区域;双击事件格可吸取其设置。\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ==================== 学员队选取弹窗 ==================== -->\r\n <ClassTeamSelectDialog\r\n v-model=\"teamSelectVisible\"\r\n @confirm=\"handleTeamConfirm\"\r\n />\r\n </el-dialog>\r\n</template>\r\n\r\n<style scoped lang=\"scss\">\r\n// `class` 会直接加在 .el-dialog 元素自身,因此高度直接写在这里(不用 :deep)\r\n.class-calendar-dialog {\r\n display: flex;\r\n flex-direction: column;\r\n height: 92vh;\r\n margin: 4vh auto;\r\n overflow: hidden;\r\n\r\n :deep(.el-dialog__header) {\r\n flex-shrink: 0;\r\n margin-right: 0;\r\n }\r\n\r\n :deep(.el-dialog__body) {\r\n display: flex;\r\n flex-direction: column;\r\n padding: 14px 18px 18px;\r\n overflow: hidden;\r\n flex: 1;\r\n min-height: 0;\r\n }\r\n}\r\n\r\n.class-calendar {\r\n display: flex;\r\n flex-direction: column;\r\n flex: 1;\r\n min-height: 0;\r\n\r\n // ========== 1. 学期与班次信息 ==========\r\n .info-panel {\r\n flex-shrink: 0;\r\n background: #fff;\r\n border: 1px solid #ebeef5;\r\n border-radius: 4px;\r\n padding: 12px 20px;\r\n margin-bottom: 12px;\r\n\r\n .info-title-row {\r\n display: flex;\r\n align-items: baseline;\r\n gap: 20px;\r\n margin-bottom: 8px;\r\n\r\n .semester-name,\r\n .class-name {\r\n font-size: 22px;\r\n font-weight: 700;\r\n color: #1e6fff;\r\n }\r\n }\r\n\r\n .date-range-row {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n\r\n .range-item {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: #1e6fff;\r\n }\r\n }\r\n }\r\n\r\n // ========== 2. 设置面板 ==========\r\n .settings-panel {\r\n flex-shrink: 0;\r\n background: #fff;\r\n border: 1px solid #ebeef5;\r\n border-radius: 4px;\r\n padding: 12px 20px;\r\n margin-bottom: 12px;\r\n\r\n .event-settings-row {\r\n display: flex;\r\n align-items: center;\r\n flex-wrap: wrap;\r\n gap: 14px;\r\n margin-bottom: 12px;\r\n\r\n .setting-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n\r\n .setting-label {\r\n font-size: 13px;\r\n color: #606266;\r\n white-space: nowrap;\r\n }\r\n }\r\n }\r\n\r\n .action-buttons-row {\r\n display: flex;\r\n align-items: center;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n padding-top: 10px;\r\n border-top: 1px solid #ebeef5;\r\n }\r\n }\r\n\r\n // ========== 3. 银灰色 / 蓝色边框按钮 ==========\r\n .gray-btn {\r\n min-width: 80px;\r\n height: 28px;\r\n padding: 0 14px;\r\n font-size: 12px;\r\n color: #000;\r\n background: linear-gradient(180deg, #fdfdfd 0%, #ececec 50%, #dcdcdc 100%);\r\n border: 1px solid #7a7a7a;\r\n border-radius: 2px;\r\n cursor: pointer;\r\n\r\n &:hover {\r\n background: linear-gradient(180deg, #ffffff 0%, #f4f4f4 50%, #e6e6e6 100%);\r\n }\r\n\r\n &:active {\r\n background: #c8c8c8;\r\n }\r\n }\r\n\r\n .blue-btn {\r\n min-width: 190px;\r\n height: 28px;\r\n padding: 0 14px;\r\n font-size: 12px;\r\n color: #1e6fff;\r\n background: #ecf5ff;\r\n border: 1px solid #1e6fff;\r\n border-radius: 2px;\r\n cursor: pointer;\r\n\r\n &:hover {\r\n background: #d9ecff;\r\n }\r\n\r\n &:active {\r\n background: #c6e2ff;\r\n }\r\n }\r\n\r\n // ========== 4. 时间编排区域 ==========\r\n .table-area {\r\n flex: 1;\r\n min-height: 0;\r\n display: flex;\r\n flex-direction: column;\r\n background: #fff;\r\n border: 1px solid #ebeef5;\r\n border-radius: 4px;\r\n overflow: hidden;\r\n\r\n .calendar-table-wrapper {\r\n flex: 1;\r\n min-height: 0;\r\n overflow: auto;\r\n\r\n &::-webkit-scrollbar {\r\n width: 8px;\r\n height: 8px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: #dcdfe6;\r\n border-radius: 4px;\r\n &:hover { background: #c0c4cc; }\r\n }\r\n &::-webkit-scrollbar-track {\r\n background: #f5f7fa;\r\n }\r\n }\r\n\r\n .select-tip {\r\n flex-shrink: 0;\r\n padding: 6px 12px;\r\n font-size: 12px;\r\n color: #909399;\r\n border-top: 1px solid #ebeef5;\r\n background: #fafafa;\r\n }\r\n\r\n .calendar-table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n table-layout: fixed;\r\n font-size: 12px;\r\n user-select: none;\r\n\r\n thead {\r\n position: sticky;\r\n top: 0;\r\n z-index: 2;\r\n\r\n th {\r\n background: #f5f7fa;\r\n border: 1px solid #ebeef5;\r\n color: #303133;\r\n font-weight: 600;\r\n height: 28px;\r\n padding: 0 4px;\r\n text-align: center;\r\n min-width: 52px;\r\n white-space: nowrap;\r\n }\r\n }\r\n\r\n tbody {\r\n td {\r\n &.week-num,\r\n &.date-range {\r\n background: #fafafa;\r\n color: #303133;\r\n font-weight: 600;\r\n }\r\n\r\n &.week-num {\r\n width: 48px;\r\n }\r\n\r\n &.date-range {\r\n width: 130px;\r\n }\r\n }\r\n\r\n .cell {\r\n position: relative;\r\n height: 30px;\r\n padding: 0 2px;\r\n text-align: center;\r\n vertical-align: middle;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n border: 1px solid #ebeef5;\r\n cursor: default;\r\n transition: filter 0.1s;\r\n\r\n &:hover {\r\n filter: brightness(0.92);\r\n }\r\n\r\n &.is-event {\r\n cursor: pointer;\r\n font-weight: 500;\r\n }\r\n\r\n // 选中高亮:蓝色描边\r\n &.selected {\r\n outline: 2px solid #1e6fff;\r\n outline-offset: -2px;\r\n z-index: 1;\r\n }\r\n\r\n // 加粗显示\r\n &.is-bold {\r\n font-weight: 700;\r\n }\r\n\r\n // 可排课未勾选 → 左上角灰色小方块(该时段全校不允许排课)\r\n &.not-schedulable::before {\r\n content: '';\r\n position: absolute;\r\n top: 1px;\r\n left: 1px;\r\n width: 7px;\r\n height: 7px;\r\n background: #c8c8c8;\r\n border: 1px solid #909399;\r\n }\r\n\r\n // 正课 → 右上角蓝色小方块\r\n &.is-regular::after {\r\n content: '';\r\n position: absolute;\r\n top: 1px;\r\n right: 1px;\r\n width: 7px;\r\n height: 7px;\r\n background: #1e6fff;\r\n border: 1px solid #0b4bc0;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n"]}]} |