forked from liweijie/education
1 line
56 KiB
JSON
1 line
56 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\\teachBusiness\\calendar\\components\\SchoolCalendarEditor.vue?vue&type=script&lang=js","dependencies":[{"path":"C:\\Users\\Admin\\Desktop\\education\\frontend\\src\\views\\teachBusiness\\calendar\\components\\SchoolCalendarEditor.vue","mtime":1787627704322},{"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\\babel-loader\\lib\\index.js","mtime":1787309793142},{"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:Ly8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KLy8KDQppbXBvcnQgeyBnZXRTZW1lc3RlciB9IGZyb20gJ0AvYXBpL3RlYWNoQnVzaW5lc3Mvc2VtZXN0ZXInDQppbXBvcnQgeyBsaXN0WHF4bGIsIHVwZGF0ZVhxeGxiIH0gZnJvbSAnQC9hcGkvdGVhY2hCdXNpbmVzcy94cXhsYicNCg0KLy8g6IqC5qyh5a6a5LmJ77yaMTIvMzQvNTYg5bi45pi+77yMNzgv5pma5LiKL+WknOmXtOeUseW8gOWFs+aOp+WItuWPr+ingQ0KY29uc3QgU0xPVF9ERUZTID0gWw0KICB7IGtleTogJzEyJywgbGFiZWw6ICcxLTInLCBjdHJsOiBudWxsIH0sDQogIHsga2V5OiAnMzQnLCBsYWJlbDogJzMtNCcsIGN0cmw6IG51bGwgfSwNCiAgeyBrZXk6ICc1NicsIGxhYmVsOiAnNS02JywgY3RybDogbnVsbCB9LA0KICB7IGtleTogJzc4JywgbGFiZWw6ICc3LTgnLCBjdHJsOiAnc2hvdzc4JyB9LA0KICB7IGtleTogJ25pZ2h0JywgbGFiZWw6ICfmmZrkuIonLCBjdHJsOiAnc2hvd05pZ2h0JyB9LA0KICB7IGtleTogJ2xhdGUnLCBsYWJlbDogJ+WknOmXtCcsIGN0cmw6ICdzaG93TGF0ZU5pZ2h0JyB9DQpdDQoNCi8vIOWJjeerr+iKguasoSBrZXkgLT4g5ZCO56uvIHhxeGxiLmNvdXJzZUNsYXNzIOiKguasoeiMg+WbtO+8iOWmgiAxMiDoioIgLT4gIjEtMiLjgIHlpJzpl7QgLT4gIjExLTEyIu+8iQ0KY29uc3QgU0xPVF9DT1VSU0VfTUFQID0gew0KICAnMTInOiAnMS0yJywNCiAgJzM0JzogJzMtNCcsDQogICc1Nic6ICc1LTYnLA0KICAnNzgnOiAnNy04JywNCiAgbmlnaHQ6ICc5LTEwJywNCiAgbGF0ZTogJzExLTEyJw0KfQ0KDQpjb25zdCBXRUVLX0RBWVMgPSBbJ+WRqOS4gCcsICflkajkuownLCAn5ZGo5LiJJywgJ+WRqOWbmycsICflkajkupQnLCAn5ZGo5YWtJywgJ+WRqOaXpSddDQoNCmZ1bmN0aW9uIHBhZDIobikgew0KICByZXR1cm4gbiA8IDEwID8gJzAnICsgbiA6ICcnICsgbg0KfQ0KDQpmdW5jdGlvbiBmbXREYXRlKGQpIHsNCiAgcmV0dXJuIGQuZ2V0RnVsbFllYXIoKSArICctJyArIHBhZDIoZC5nZXRNb250aCgpICsgMSkgKyAnLScgKyBwYWQyKGQuZ2V0RGF0ZSgpKQ0KfQ0KDQpleHBvcnQgZGVmYXVsdCB7DQogIG5hbWU6ICdTY2hvb2xDYWxlbmRhckVkaXRvcicsDQogIHByb3BzOiB7DQogICAgbmQ6IHsgdHlwZTogW1N0cmluZywgTnVtYmVyXSwgZGVmYXVsdDogJycgfSwNCiAgICBzZW1lc3Rlck5hbWU6IHsgdHlwZTogU3RyaW5nLCBkZWZhdWx0OiAnJyB9DQogIH0sDQogIGRhdGEoKSB7DQogICAgcmV0dXJuIHsNCiAgICAgIC8vIOWtpuacn+aXpeacn+iMg+WbtA0KICAgICAgc3RhcnREYXRlOiBudWxsLA0KICAgICAgZW5kRGF0ZTogbnVsbCwNCiAgICAgIHRvdGFsV2Vla3M6IDAsDQogICAgICBkYXRlUmFuZ2VUZXh0OiAnJywNCiAgICAgIHdlZWtzOiBbXSwNCiAgICAgIC8vIOaYvuekuuW8gOWFs++8iOm7mOiupOS4jeWLvumAie+8jOavj+WkqeS7heaYvuekuiAxLTIvMy00LzUtNiDkuInkuKroioLmrKHvvIkNCiAgICAgIHNob3c3ODogZmFsc2UsDQogICAgICBzaG93TmlnaHQ6IGZhbHNlLA0KICAgICAgc2hvd0xhdGVOaWdodDogZmFsc2UsDQogICAgICAvLyDlt6XlhbfmoI/ooajljZUNCiAgICAgIHRvb2xiYXI6IHsNCiAgICAgICAgZXZlbnROYW1lOiAnJywNCiAgICAgICAgYm9sZDogZmFsc2UsDQogICAgICAgIHNjaGVkdWxhYmxlOiBmYWxzZSwNCiAgICAgICAgbWFpbkNvdXJzZTogZmFsc2UsDQogICAgICAgIHJlbWFya1Nob3c6IGZhbHNlLA0KICAgICAgICByZW1hcms6ICcnDQogICAgICB9LA0KICAgICAgLy8g5LqL5Lu25a2Y5YKo77yaa2V5ID0gY2VsbEtleSAtPiBldmVudA0KICAgICAgZXZlbnRzOiB7fSwNCiAgICAgIC8vIOaaguWtmOiiq+makOiXj+iKguasoeWIl+S4iueahOS6i+S7tu+8mmtleSA9IOWRqC3mmJ/mnJ8t6IqC5qyhIC0+IGV2ZW5077yM5YiX5YaN5qyh5pi+56S65pe25oGi5aSNDQogICAgICBoaWRkZW5FdmVudHM6IHt9LA0KICAgICAgLy8g6YCJ5oup6ZuG77yI55So5pWw57uE5Lul5L+d6K+BIFZ1ZTIg5ZON5bqU5byP77yJDQogICAgICBzZWxlY3RlZEtleXM6IFtdLA0KICAgICAgLy8g5ouW5ou954q25oCBDQogICAgICBzZWxlY3Rpbmc6IGZhbHNlLA0KICAgICAgZHJhZ1N0YXJ0OiBudWxsLA0KICAgICAgZHJhZ1N0YXJ0U2VsZWN0ZWQ6IGZhbHNlLCAvLyDmjInkuIvotbfngrnlnKjmjInkuIvliY3mmK/lkKblt7LpgInkuK0NCiAgICAgIG1vdmVkOiBmYWxzZSwgLy8g5piv5ZCm5Y+R55Sf56e75Yqo77yI5Yy65YiG54K55Ye75LiO5ouW5ou977yJDQogICAgICBkcmFnQWRkTW9kZTogZmFsc2UsIC8vIGN0cmwg5ouW5ou95Li66L+95YqgDQogICAgICAvLyDnqpflj6PmjqfliLYNCiAgICAgIGFic29yYlByZXZpZXc6ICcnDQogICAgfQ0KICB9LA0KICBjb21wdXRlZDogew0KICAgIC8vIOW9k+WJjeWPr+ingeWIl++8iOeUseW8gOWFs+i/h+a7pO+8jOm7mOiupOavj+WkqeS4ieS4quiKguasoe+8iQ0KICAgIHZpc2libGVDb2x1bW5zKCkgew0KICAgICAgY29uc3QgY29scyA9IFtdDQogICAgICBsZXQgY29sSW5kZXggPSAwDQogICAgICBXRUVLX0RBWVMuZm9yRWFjaCgoZGF5TGFiZWwsIGRheUluZGV4KSA9PiB7DQogICAgICAgIFNMT1RfREVGUy5mb3JFYWNoKHNsb3QgPT4gew0KICAgICAgICAgIGlmIChzbG90LmN0cmwgJiYgIXRoaXNbc2xvdC5jdHJsXSkgcmV0dXJuDQogICAgICAgICAgY29scy5wdXNoKHsgY29sSW5kZXg6IGNvbEluZGV4LCBkYXlJbmRleDogZGF5SW5kZXgsIHNsb3RLZXk6IHNsb3Qua2V5LCBzbG90TGFiZWw6IHNsb3QubGFiZWwsIGRheUxhYmVsOiBkYXlMYWJlbCB9KQ0KICAgICAgICAgIGNvbEluZGV4KysNCiAgICAgICAgfSkNCiAgICAgIH0pDQogICAgICByZXR1cm4gY29scw0KICAgIH0sDQogICAgLy8geHF4bGIg55qE5bm05bqm77yIbmTvvInkuLrlubTku73vvIjlpoIgMjAyNu+8ie+8jOeUsSA2IOS9jeWtpuacn+S7o+WPt++8iOWmgiAyMDI2MDHvvInmiKrlj5bliY0gNCDkvY3lvpflh7oNCiAgICB4cXhsYk5kKCkgew0KICAgICAgcmV0dXJuIE51bWJlcihTdHJpbmcodGhpcy5uZCkuc2xpY2UoMCwgNCkpDQogICAgfQ0KICB9LA0KICB3YXRjaDogew0KICAgIG5kOiB7DQogICAgICBpbW1lZGlhdGU6IHRydWUsDQogICAgICBoYW5kbGVyKHZhbCkgew0KICAgICAgICBpZiAodmFsKSB0aGlzLmxvYWRTZW1lc3RlcigpDQogICAgICB9DQogICAgfSwNCiAgICB2aXNpYmxlQ29sdW1ucyhuZXdDb2xzLCBvbGRDb2xzKSB7DQogICAgICAvLyDoioLmrKHliJfmmL7pmpDkvJrmlLnlj5jliJfntKLlvJXvvIzmjInjgIzlkajmnJ8t5pif5pyfLeiKguasoeOAjemHjeWumuS9jeS6i+S7tu+8jOmBv+WFjeS6i+S7tumaj+aXtumXtOagvOWIl+WBj+enuw0KICAgICAgaWYgKG9sZENvbHMgJiYgb2xkQ29scy5sZW5ndGgpIHsNCiAgICAgICAgY29uc3Qgb2xkUG9zT2YgPSBpbmRleCA9PiAob2xkQ29sc1tpbmRleF0gfHwgbnVsbCkNCiAgICAgICAgY29uc3QgbmV3SW5kZXggPSAoZGF5SW5kZXgsIHNsb3RLZXkpID0+IHsNCiAgICAgICAgICBjb25zdCBjID0gbmV3Q29scy5maW5kKHggPT4geC5kYXlJbmRleCA9PT0gZGF5SW5kZXggJiYgeC5zbG90S2V5ID09PSBzbG90S2V5KQ0KICAgICAgICAgIHJldHVybiBjID8gYy5jb2xJbmRleCA6IC0xDQogICAgICAgIH0NCiAgICAgICAgY29uc3QgbmV4dCA9IHt9DQogICAgICAgIE9iamVjdC5rZXlzKHRoaXMuZXZlbnRzKS5mb3JFYWNoKGtleSA9PiB7DQogICAgICAgICAgY29uc3QgbSA9IGtleS5tYXRjaCgvXncoXGQrKS1jKFxkKykkLykNCiAgICAgICAgICBpZiAoIW0pIHJldHVybg0KICAgICAgICAgIGNvbnN0IHdJZHggPSArbVsxXQ0KICAgICAgICAgIGNvbnN0IG9sZCA9IG9sZFBvc09mKCttWzJdKQ0KICAgICAgICAgIGlmICghb2xkKSByZXR1cm4NCiAgICAgICAgICBjb25zdCBuZXdDID0gbmV3SW5kZXgob2xkLmRheUluZGV4LCBvbGQuc2xvdEtleSkNCiAgICAgICAgICBpZiAobmV3QyA8IDApIHsNCiAgICAgICAgICAgIC8vIOivpeiKguasoeWIl+iiq+makOiXj++8muS6i+S7tuaaguWtmO+8jOW+heWIl+WGjeasoeaYvuekuuaXtuaBouWkjQ0KICAgICAgICAgICAgdGhpcy5oaWRkZW5FdmVudHNbdGhpcy5jZWxsU3RhYmxlS2V5KHdJZHgsIG9sZC5kYXlJbmRleCwgb2xkLnNsb3RLZXkpXSA9IHRoaXMuZXZlbnRzW2tleV0NCiAgICAgICAgICAgIHJldHVybg0KICAgICAgICAgIH0NCiAgICAgICAgICBuZXh0Wyd3JyArIHdJZHggKyAnLWMnICsgbmV3Q10gPSB0aGlzLmV2ZW50c1trZXldDQogICAgICAgIH0pDQogICAgICAgIC8vIOaBouWkjemHjeaWsOaYvuekuueahOmakOiXj+iKguasoeS6i+S7tg0KICAgICAgICBPYmplY3Qua2V5cyh0aGlzLmhpZGRlbkV2ZW50cykuZm9yRWFjaChzdGFibGUgPT4gew0KICAgICAgICAgIGNvbnN0IHAgPSBzdGFibGUuc3BsaXQoJy0nKQ0KICAgICAgICAgIGNvbnN0IHdJZHggPSArcFswXQ0KICAgICAgICAgIGNvbnN0IGRheUluZGV4ID0gK3BbMV0NCiAgICAgICAgICBjb25zdCBzbG90S2V5ID0gcFsyXQ0KICAgICAgICAgIGNvbnN0IG5ld0MgPSBuZXdJbmRleChkYXlJbmRleCwgc2xvdEtleSkNCiAgICAgICAgICBpZiAobmV3QyA+PSAwKSB7DQogICAgICAgICAgICBuZXh0Wyd3JyArIHdJZHggKyAnLWMnICsgbmV3Q10gPSB0aGlzLmhpZGRlbkV2ZW50c1tzdGFibGVdDQogICAgICAgICAgICBkZWxldGUgdGhpcy5oaWRkZW5FdmVudHNbc3RhYmxlXQ0KICAgICAgICAgIH0NCiAgICAgICAgfSkNCiAgICAgICAgdGhpcy5ldmVudHMgPSBuZXh0DQogICAgICB9DQogICAgICAvLyDliJflj5jljJblkI7muIXnqbrml6DmlYjpgInmi6nvvIjliJfntKLlvJXlkKvkuYnkvJrlj5jvvIkNCiAgICAgIHRoaXMuc2VsZWN0ZWRLZXlzID0gW10NCiAgICB9DQogIH0sDQogIGJlZm9yZURlc3Ryb3koKSB7DQogICAgdGhpcy5yZW1vdmVHbG9iYWxMaXN0ZW5lcnMoKQ0KICB9LA0KICBtZXRob2RzOiB7DQogICAgLyogLS0tLS0tLS0tLSDmlbDmja7liqDovb0gLS0tLS0tLS0tLSAqLw0KICAgIGxvYWRTZW1lc3RlcigpIHsNCiAgICAgIGlmICghdGhpcy5uZCkgcmV0dXJuDQogICAgICBnZXRTZW1lc3Rlcih0aGlzLm5kKQ0KICAgICAgICAudGhlbihyZXMgPT4gew0KICAgICAgICAgIGNvbnN0IGRhdGEgPSByZXMuZGF0YSB8fCByZXMgfHwge30NCiAgICAgICAgICBjb25zdCBreCA9IChkYXRhLmt4cnEgfHwgJycpLnRvU3RyaW5nKCkuc2xpY2UoMCwgMTApDQogICAgICAgICAgY29uc3QganggPSAoZGF0YS5qc3JxIHx8ICcnKS50b1N0cmluZygpLnNsaWNlKDAsIDEwKQ0KICAgICAgICAgIGlmIChreCAmJiBqeCkgew0KICAgICAgICAgICAgdGhpcy5zdGFydERhdGUgPSBuZXcgRGF0ZShreC5yZXBsYWNlKC8tL2csICcvJykpDQogICAgICAgICAgICB0aGlzLmVuZERhdGUgPSBuZXcgRGF0ZShqeC5yZXBsYWNlKC8tL2csICcvJykpDQogICAgICAgICAgICB0aGlzLmJ1aWxkV2Vla3MoKQ0KICAgICAgICAgIH0NCiAgICAgICAgICB0aGlzLmxvYWRYcXhsYkV2ZW50cygpDQogICAgICAgIH0pDQogICAgICAgIC5jYXRjaCgoKSA9PiB7DQogICAgICAgICAgdGhpcy4kbWVzc2FnZS53YXJuaW5nKCflrabmnJ/or6bmg4Xojrflj5blpLHotKXvvIzor7fnoa7orqTlrabmnJ/mlbDmja4nKQ0KICAgICAgICB9KQ0KICAgIH0sDQogICAgLy8g5LuO5ZCO56uv5ouJ5Y+W5pys5a2m5pyf5qCh5Y6G5LqL5Lu277yM5riy5p+T5Yiw5a+55bqU5pe26Ze05qC877yI5bm05bqm55SxIDYg5L2N5a2m5pyf5Luj5Y+35oiq5Y+W5YmNIDQg5L2N77yJDQogICAgbG9hZFhxeGxiRXZlbnRzKCkgew0KICAgICAgbGlzdFhxeGxiKHsgbmQ6IHRoaXMueHF4bGJOZCB9KS50aGVuKHJlcyA9PiB7DQogICAgICAgIGNvbnN0IGRhdGEgPSByZXMuZGF0YQ0KICAgICAgICBjb25zdCBsaXN0ID0gQXJyYXkuaXNBcnJheShkYXRhKSA/IGRhdGEgOiAoZGF0YSAmJiBkYXRhLnJlY29yZHMpIHx8IFtdDQogICAgICAgIHJldHVybiBsaXN0DQogICAgICB9KS50aGVuKGxpc3QgPT4gew0KICAgICAgICBjb25zdCBsb2FkZWQgPSB7fQ0KICAgICAgICBsaXN0LmZvckVhY2goaXRlbSA9PiB7DQogICAgICAgICAgY29uc3QgcG9zID0gdGhpcy5sb2NhdGVYcXhsYihpdGVtKQ0KICAgICAgICAgIGlmICghcG9zKSByZXR1cm4NCiAgICAgICAgICBjb25zdCBldiA9IHsNCiAgICAgICAgICAgIGJoOiBpdGVtLmJoLA0KICAgICAgICAgICAgbmFtZTogaXRlbS5qcW1jIHx8ICcnLA0KICAgICAgICAgICAgYm9sZDogISFpdGVtLmpjLA0KICAgICAgICAgICAgc2NoZWR1bGFibGU6ICEhaXRlbS5rcGssDQogICAgICAgICAgICBtYWluQ291cnNlOiAhIWl0ZW0uemRwaywNCiAgICAgICAgICAgIHJlbWFya1Nob3c6ICEhaXRlbS5ienhzLA0KICAgICAgICAgICAgcmVtYXJrOiBpdGVtLmJ6IHx8ICcnDQogICAgICAgICAgfQ0KICAgICAgICAgIGNvbnN0IGNvbEluZGV4ID0gdGhpcy5jb2xJbmRleE9mKHBvcy5kYXlJbmRleCwgcG9zLnNsb3RLZXkpDQogICAgICAgICAgaWYgKGNvbEluZGV4ID49IDApIHsNCiAgICAgICAgICAgIGxvYWRlZFt0aGlzLmNlbGxLZXkocG9zLndJZHgsIGNvbEluZGV4KV0gPSBldg0KICAgICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICAvLyDor6XoioLmrKHliJflvZPliY3pmpDol4/vvJrmmoLlrZjvvIjlkKsgYmjvvInvvIzlvoXliJfmmL7npLrml7bnlLEgdmlzaWJsZUNvbHVtbnMg55uR5ZCs5oGi5aSNDQogICAgICAgICAgICB0aGlzLmhpZGRlbkV2ZW50c1t0aGlzLmNlbGxTdGFibGVLZXkocG9zLndJZHgsIHBvcy5kYXlJbmRleCwgcG9zLnNsb3RLZXkpXSA9IGV2DQogICAgICAgICAgfQ0KICAgICAgICB9KQ0KICAgICAgICAvLyDlkIjlubbliLDnjrDmnInmoLzlrZDvvIjlkI7nq6/mlbDmja7opobnm5blt7LmnInnirbmgIHvvIkNCiAgICAgICAgdGhpcy5ldmVudHMgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzLmV2ZW50cywgbG9hZGVkKQ0KICAgICAgfSkuY2F0Y2goKCkgPT4gew0KICAgICAgICB0aGlzLiRtZXNzYWdlLndhcm5pbmcoJ+agoeWOhuS6i+S7tuWKoOi9veWksei0pScpDQogICAgICB9KQ0KICAgIH0sDQogICAgLy8g5qC55o2u5YGH5pyf6K6w5b2V5Y+N5o6o5pe26Ze05qC85L2N572u77yIanFzaiDml6XmnJ8gKyBjb3Vyc2VDbGFzcyDoioLmrKHvvInvvIzkuI7liJfmmK/lkKblj6/op4Hml6DlhbMNCiAgICBsb2NhdGVYcXhsYihpdGVtKSB7DQogICAgICBpZiAoIXRoaXMuc3RhcnREYXRlIHx8ICFpdGVtLmpxc2opIHJldHVybiBudWxsDQogICAgICBjb25zdCBkID0gbmV3IERhdGUoU3RyaW5nKGl0ZW0uanFzaikuc2xpY2UoMCwgMTApLnJlcGxhY2UoLy0vZywgJy8nKSkNCiAgICAgIGlmIChpc05hTihkLmdldFRpbWUoKSkpIHJldHVybiBudWxsDQogICAgICBjb25zdCBvZmZzZXQgPSBNYXRoLnJvdW5kKChkIC0gdGhpcy5zdGFydERhdGUpIC8gKDI0ICogMzYwMCAqIDEwMDApKQ0KICAgICAgaWYgKG9mZnNldCA8IDApIHJldHVybiBudWxsDQogICAgICBjb25zdCB3SWR4ID0gTWF0aC5mbG9vcihvZmZzZXQgLyA3KQ0KICAgICAgY29uc3QgZGF5SW5kZXggPSBvZmZzZXQgJSA3DQogICAgICBjb25zdCBzbG90S2V5ID0gdGhpcy5jb3Vyc2VDbGFzc1RvU2xvdEtleShpdGVtLmNvdXJzZUNsYXNzKQ0KICAgICAgaWYgKHNsb3RLZXkgPT09IG51bGwpIHJldHVybiBudWxsDQogICAgICByZXR1cm4geyB3SWR4LCBkYXlJbmRleCwgc2xvdEtleSB9DQogICAgfSwNCiAgICAvLyDlkI7nq68gY291cnNlQ2xhc3Mg6IqC5qyh6IyD5Zu0IC0+IOWJjeerr+iKguasoSBrZXkNCiAgICBjb3Vyc2VDbGFzc1RvU2xvdEtleShjb3Vyc2VDbGFzcykgew0KICAgICAgaWYgKCFjb3Vyc2VDbGFzcykgcmV0dXJuIG51bGwNCiAgICAgIGNvbnN0IHMgPSBTdHJpbmcoY291cnNlQ2xhc3MpLnRyaW0oKQ0KICAgICAgZm9yIChjb25zdCBrZXkgaW4gU0xPVF9DT1VSU0VfTUFQKSB7DQogICAgICAgIGlmIChzID09PSBTTE9UX0NPVVJTRV9NQVBba2V5XSkgcmV0dXJuIGtleQ0KICAgICAgfQ0KICAgICAgLy8g5YW85a65ICI5MTAiLyIxMTEyIiDnrYnntKflh5Hlhpnms5UNCiAgICAgIGlmIChzID09PSAnOTEwJykgcmV0dXJuICduaWdodCcNCiAgICAgIGlmIChzID09PSAnMTExMicpIHJldHVybiAnbGF0ZScNCiAgICAgIHJldHVybiBudWxsDQogICAgfSwNCiAgICBidWlsZFdlZWtzKCkgew0KICAgICAgaWYgKCF0aGlzLnN0YXJ0RGF0ZSB8fCAhdGhpcy5lbmREYXRlKSByZXR1cm4NCiAgICAgIGNvbnN0IHN0YXJ0ID0gbmV3IERhdGUodGhpcy5zdGFydERhdGUpDQogICAgICBjb25zdCBlbmQgPSBuZXcgRGF0ZSh0aGlzLmVuZERhdGUpDQogICAgICBjb25zdCBkYXlzID0gTWF0aC5yb3VuZCgoZW5kIC0gc3RhcnQpIC8gKDI0ICogMzYwMCAqIDEwMDApKSArIDENCiAgICAgIHRoaXMudG90YWxXZWVrcyA9IE1hdGguY2VpbChkYXlzIC8gNykNCiAgICAgIHRoaXMuZGF0ZVJhbmdlVGV4dCA9IGZtdERhdGUoc3RhcnQpICsgJyDliLAgJyArIGZtdERhdGUoZW5kKQ0KICAgICAgY29uc3Qgd2Vla3MgPSBbXQ0KICAgICAgZm9yIChsZXQgdyA9IDA7IHcgPCB0aGlzLnRvdGFsV2Vla3M7IHcrKykgew0KICAgICAgICBjb25zdCB3a1N0YXJ0ID0gbmV3IERhdGUoc3RhcnQpDQogICAgICAgIHdrU3RhcnQuc2V0RGF0ZShzdGFydC5nZXREYXRlKCkgKyB3ICogNykNCiAgICAgICAgY29uc3Qgd2tFbmQgPSBuZXcgRGF0ZSh3a1N0YXJ0KQ0KICAgICAgICB3a0VuZC5zZXREYXRlKHdrU3RhcnQuZ2V0RGF0ZSgpICsgNikNCiAgICAgICAgd2Vla3MucHVzaCh7DQogICAgICAgICAgcmFuZ2VUZXh0OiBwYWQyKHdrU3RhcnQuZ2V0TW9udGgoKSArIDEpICsgJy0nICsgcGFkMih3a1N0YXJ0LmdldERhdGUoKSkgKw0KICAgICAgICAgICAgJ+iHsycgKyBwYWQyKHdrRW5kLmdldE1vbnRoKCkgKyAxKSArICctJyArIHBhZDIod2tFbmQuZ2V0RGF0ZSgpKQ0KICAgICAgICB9KQ0KICAgICAgfQ0KICAgICAgdGhpcy53ZWVrcyA9IHdlZWtzDQogICAgfSwNCiAgICBjb2xJbmRleE9mKGRheUluZGV4LCBzbG90S2V5KSB7DQogICAgICBjb25zdCBjb2wgPSB0aGlzLnZpc2libGVDb2x1bW5zLmZpbmQoYyA9PiBjLmRheUluZGV4ID09PSBkYXlJbmRleCAmJiBjLnNsb3RLZXkgPT09IHNsb3RLZXkpDQogICAgICByZXR1cm4gY29sID8gY29sLmNvbEluZGV4IDogLTENCiAgICB9LA0KICAgIC8qIC0tLS0tLS0tLS0g5Y2V5YWD5qC85bel5YW3IC0tLS0tLS0tLS0gKi8NCiAgICBjZWxsS2V5KHdJZHgsIGNvbEluZGV4KSB7DQogICAgICByZXR1cm4gJ3cnICsgd0lkeCArICctYycgKyBjb2xJbmRleA0KICAgIH0sDQogICAgLy8g56iz5a6a55qE5Y2V5YWD5qC86Lqr5Lu977ya5LiN6ZqP5YiX5pi+6ZqQ5Y+Y5YyW55qE5ZGoLeaYn+acny3oioLmrKENCiAgICBjZWxsU3RhYmxlS2V5KHdJZHgsIGRheUluZGV4LCBzbG90S2V5KSB7DQogICAgICByZXR1cm4gd0lkeCArICctJyArIGRheUluZGV4ICsgJy0nICsgc2xvdEtleQ0KICAgIH0sDQogICAgZ2V0RXZlbnQod0lkeCwgY29sSW5kZXgpIHsNCiAgICAgIHJldHVybiB0aGlzLmV2ZW50c1t0aGlzLmNlbGxLZXkod0lkeCwgY29sSW5kZXgpXSB8fCBudWxsDQogICAgfSwNCiAgICB3ZWVrRGF5TGFiZWwoZGF5SW5kZXgpIHsNCiAgICAgIHJldHVybiBXRUVLX0RBWVNbZGF5SW5kZXhdDQogICAgfSwNCiAgICAvLyDljZXlhYPmoLzlhoXmmL7npLrnmoTml6XmnJ/mlbDlrZfvvIjlpoIgMDcwM++8iQ0KICAgIGRhdGVOdW1iZXJPZih3SWR4LCBkYXlJbmRleCkgew0KICAgICAgaWYgKCF0aGlzLnN0YXJ0RGF0ZSkgcmV0dXJuICcnDQogICAgICBjb25zdCBkID0gbmV3IERhdGUodGhpcy5zdGFydERhdGUpDQogICAgICBkLnNldERhdGUodGhpcy5zdGFydERhdGUuZ2V0RGF0ZSgpICsgd0lkeCAqIDcgKyBkYXlJbmRleCkNCiAgICAgIHJldHVybiBwYWQyKGQuZ2V0TW9udGgoKSArIDEpICsgcGFkMihkLmdldERhdGUoKSkNCiAgICB9LA0KICAgIGNlbGxDbGFzcyh3SWR4LCBjb2wpIHsNCiAgICAgIGNvbnN0IGNsYXNzZXMgPSBbXQ0KICAgICAgLy8g5pif5pyf5Lqk5pu/6IOM5pmv77yI5Y2V5Y+M5pel5LiN5ZCM5bqV6Imy77yJDQogICAgICBpZiAoY29sLmRheUluZGV4ICUgMiA9PT0gMCkgY2xhc3Nlcy5wdXNoKCdzY2UtY2VsbC1vZGQnKQ0KICAgICAgZWxzZSBjbGFzc2VzLnB1c2goJ3NjZS1jZWxsLWV2ZW4nKQ0KICAgICAgaWYgKHRoaXMuc2VsZWN0ZWRLZXlzLmluY2x1ZGVzKHRoaXMuY2VsbEtleSh3SWR4LCBjb2wuY29sSW5kZXgpKSkgY2xhc3Nlcy5wdXNoKCdpcy1zZWxlY3RlZCcpDQogICAgICBjb25zdCBldiA9IHRoaXMuZ2V0RXZlbnQod0lkeCwgY29sLmNvbEluZGV4KQ0KICAgICAgaWYgKGV2KSB7DQogICAgICAgIGNsYXNzZXMucHVzaCgnaGFzLWV2ZW50JykNCiAgICAgICAgaWYgKCFldi5zY2hlZHVsYWJsZSkgY2xhc3Nlcy5wdXNoKCduby1zY2hlZHVsZScpDQogICAgICB9DQogICAgICByZXR1cm4gY2xhc3Nlcw0KICAgIH0sDQogICAgLyogLS0tLS0tLS0tLSDngrnlh7sgLyDmi5bmi73lpJrpgIkgLS0tLS0tLS0tLSAqLw0KICAgIG9uR3JpZE1vdXNlRG93bihlKSB7DQogICAgICBjb25zdCBjZWxsID0gZS50YXJnZXQuY2xvc2VzdCgnLnNjZS1jZWxsJykNCiAgICAgIGlmICghY2VsbCkgew0KICAgICAgICAvLyDngrnlh7vnqbrnmb3ljLrvvIjpnZ7ljZXlhYPmoLzvvIzlkKvooajlpLTjgIHlkajmrKHliJfnrYnvvInlj5bmtojmiYDmnInpgInkuK0NCiAgICAgICAgaWYgKHRoaXMuc2VsZWN0ZWRLZXlzLmxlbmd0aCkgdGhpcy5zZWxlY3RlZEtleXMgPSBbXQ0KICAgICAgICByZXR1cm4NCiAgICAgIH0NCiAgICAgIGUucHJldmVudERlZmF1bHQoKQ0KICAgICAgY29uc3Qga2V5ID0gY2VsbC5nZXRBdHRyaWJ1dGUoJ2RhdGEta2V5JykNCiAgICAgIHRoaXMuZHJhZ1N0YXJ0ID0ga2V5DQogICAgICB0aGlzLmRyYWdBZGRNb2RlID0gZS5jdHJsS2V5IHx8IGUubWV0YUtleQ0KICAgICAgLy8g6K6w5b2V6LW354K55qC85Zyo5oyJ5LiL5pe255qE6YCJ5Lit54q25oCB77yM55So5LqO5p2+5omL5pe25Yik5a6aIue6r+eCueWHuyLnmoTliIfmjaLooYzkuLoNCiAgICAgIHRoaXMuZHJhZ1N0YXJ0U2VsZWN0ZWQgPSB0aGlzLnNlbGVjdGVkS2V5cy5pbmNsdWRlcyhrZXkpDQogICAgICB0aGlzLm1vdmVkID0gZmFsc2UNCiAgICAgIHRoaXMuc2VsZWN0aW5nID0gdHJ1ZQ0KICAgICAgLy8g6Z2eIGN0cmwg5qih5byP5LiL77yM6Iul6LW354K55pys6Lqr5bey6YCJ5Lit77yI5Y+v6IO95YeG5aSH5ouW5ou95omp5bGV77yJ77yM5YWI5LiN5riF6Zmk77yM6YG/5YWN6K+v5riF56m6DQogICAgICBpZiAoIXRoaXMuZHJhZ0FkZE1vZGUgJiYgIXRoaXMuZHJhZ1N0YXJ0U2VsZWN0ZWQpIHRoaXMuc2VsZWN0ZWRLZXlzID0gW10NCiAgICAgIHRoaXMuYWRkR2xvYmFsTGlzdGVuZXJzKCkNCiAgICB9LA0KICAgIGFkZEdsb2JhbExpc3RlbmVycygpIHsNCiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIHRoaXMub25HcmlkTW91c2VNb3ZlKQ0KICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMub25HcmlkTW91c2VVcCkNCiAgICB9LA0KICAgIHJlbW92ZUdsb2JhbExpc3RlbmVycygpIHsNCiAgICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIHRoaXMub25HcmlkTW91c2VNb3ZlKQ0KICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIHRoaXMub25HcmlkTW91c2VVcCkNCiAgICB9LA0KICAgIG9uR3JpZE1vdXNlTW92ZShlKSB7DQogICAgICBpZiAoIXRoaXMuc2VsZWN0aW5nIHx8ICF0aGlzLmRyYWdTdGFydCkgcmV0dXJuDQogICAgICBpZiAoIXRoaXMubW92ZWQpIHRoaXMubW92ZWQgPSB0cnVlDQogICAgICBjb25zdCBlbCA9IGRvY3VtZW50LmVsZW1lbnRGcm9tUG9pbnQoZS5jbGllbnRYLCBlLmNsaWVudFkpDQogICAgICBjb25zdCBjZWxsID0gZWwgJiYgZWwuY2xvc2VzdCA/IGVsLmNsb3Nlc3QoJy5zY2UtY2VsbCcpIDogbnVsbA0KICAgICAgaWYgKCFjZWxsKSByZXR1cm4NCiAgICAgIGNvbnN0IGN1cktleSA9IGNlbGwuZ2V0QXR0cmlidXRlKCdkYXRhLWtleScpDQogICAgICB0aGlzLnNlbGVjdFJlY3RhbmdsZSh0aGlzLmRyYWdTdGFydCwgY3VyS2V5LCB0aGlzLmRyYWdBZGRNb2RlKQ0KICAgIH0sDQogICAgb25HcmlkTW91c2VVcCgpIHsNCiAgICAgIGlmICghdGhpcy5zZWxlY3RpbmcpIHsNCiAgICAgICAgdGhpcy5yZW1vdmVHbG9iYWxMaXN0ZW5lcnMoKQ0KICAgICAgICByZXR1cm4NCiAgICAgIH0NCiAgICAgIC8vIOe6r+eCueWHu++8iOacquenu+WKqO+8ieaXtu+8jOWBmuWNlemAiSAvIOWIh+aNog0KICAgICAgaWYgKCF0aGlzLm1vdmVkKSB7DQogICAgICAgIGNvbnN0IGtleSA9IHRoaXMuZHJhZ1N0YXJ0DQogICAgICAgIGlmICh0aGlzLmRyYWdBZGRNb2RlKSB7DQogICAgICAgICAgLy8gQ3RybCArIOWNleWHu++8muWIh+aNouivpeagvOmAieS4rQ0KICAgICAgICAgIGlmICh0aGlzLnNlbGVjdGVkS2V5cy5pbmNsdWRlcyhrZXkpKSB7DQogICAgICAgICAgICB0aGlzLnNlbGVjdGVkS2V5cyA9IHRoaXMuc2VsZWN0ZWRLZXlzLmZpbHRlcihrID0+IGsgIT09IGtleSkNCiAgICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgdGhpcy5zZWxlY3RlZEtleXMucHVzaChrZXkpDQogICAgICAgICAgfQ0KICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgIC8vIOaZrumAmuWNleWHu++8muW3sumAieS4reWImeWPlua2iOivpeagvO+8jOacqumAieS4reWImeS7hemAieS4reivpeagvA0KICAgICAgICAgIGlmICh0aGlzLmRyYWdTdGFydFNlbGVjdGVkKSB7DQogICAgICAgICAgICB0aGlzLnNlbGVjdGVkS2V5cyA9IHRoaXMuc2VsZWN0ZWRLZXlzLmZpbHRlcihrID0+IGsgIT09IGtleSkNCiAgICAgICAgICB9IGVsc2Ugew0KICAgICAgICAgICAgdGhpcy5zZWxlY3RlZEtleXMgPSBba2V5XQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgfQ0KICAgICAgdGhpcy5zZWxlY3RpbmcgPSBmYWxzZQ0KICAgICAgdGhpcy5kcmFnU3RhcnQgPSBudWxsDQogICAgICB0aGlzLmRyYWdTdGFydFNlbGVjdGVkID0gZmFsc2UNCiAgICAgIHRoaXMucmVtb3ZlR2xvYmFsTGlzdGVuZXJzKCkNCiAgICB9LA0KICAgIC8vIOagueaNrui1t+eCuee7iOeCuSBrZXkg6YCJ5Lit55+p5b2i6IyD5Zu05YaF5omA5pyJ5qC8DQogICAgc2VsZWN0UmVjdGFuZ2xlKHN0YXJ0S2V5LCBlbmRLZXksIGFkZE1vZGUpIHsNCiAgICAgIGNvbnN0IHBhcnNlID0gayA9PiB7DQogICAgICAgIGNvbnN0IG0gPSBrLm1hdGNoKC9edyhcZCspLWMoXGQrKSQvKQ0KICAgICAgICByZXR1cm4gbSA/IHsgdzogK21bMV0sIGM6ICttWzJdIH0gOiBudWxsDQogICAgICB9DQogICAgICBjb25zdCBzID0gcGFyc2Uoc3RhcnRLZXkpDQogICAgICBjb25zdCB0ID0gcGFyc2UoZW5kS2V5KQ0KICAgICAgaWYgKCFzIHx8ICF0KSByZXR1cm4NCiAgICAgIGlmICghYWRkTW9kZSkgdGhpcy5zZWxlY3RlZEtleXMgPSBbXQ0KICAgICAgY29uc3QgbWluVyA9IE1hdGgubWluKHMudywgdC53KQ0KICAgICAgY29uc3QgbWF4VyA9IE1hdGgubWF4KHMudywgdC53KQ0KICAgICAgY29uc3QgbWluQyA9IE1hdGgubWluKHMuYywgdC5jKQ0KICAgICAgY29uc3QgbWF4QyA9IE1hdGgubWF4KHMuYywgdC5jKQ0KICAgICAgZm9yIChsZXQgdyA9IG1pblc7IHcgPD0gbWF4VzsgdysrKSB7DQogICAgICAgIGZvciAobGV0IGMgPSBtaW5DOyBjIDw9IG1heEM7IGMrKykgew0KICAgICAgICAgIGNvbnN0IGtleSA9IHRoaXMuY2VsbEtleSh3LCBjKQ0KICAgICAgICAgIGlmICh0aGlzLnNlbGVjdGVkS2V5cy5pbmRleE9mKGtleSkgPT09IC0xKSB0aGlzLnNlbGVjdGVkS2V5cy5wdXNoKGtleSkNCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0sDQogICAgLyogLS0tLS0tLS0tLSDkuovku7bmk43kvZwgLS0tLS0tLS0tLSAqLw0KICAgIGFwcGx5RXZlbnQoKSB7DQogICAgICBpZiAoIXRoaXMuc2VsZWN0ZWRLZXlzLmxlbmd0aCkgew0KICAgICAgICB0aGlzLiRtZXNzYWdlLndhcm5pbmcoJ+ivt+WFiOmAieaLqeaXtumXtOagvCcpDQogICAgICAgIHJldHVybg0KICAgICAgfQ0KICAgICAgY29uc3QgbmFtZSA9IHRoaXMudG9vbGJhci5ldmVudE5hbWUudHJpbSgpDQogICAgICBpZiAoIW5hbWUpIHsNCiAgICAgICAgdGhpcy4kbWVzc2FnZS53YXJuaW5nKCfor7fovpPlhaXkuovku7blkI3np7AnKQ0KICAgICAgICByZXR1cm4NCiAgICAgIH0NCiAgICAgIGNvbnN0IGtleXMgPSBbLi4udGhpcy5zZWxlY3RlZEtleXNdDQogICAgICBrZXlzLmZvckVhY2goa2V5ID0+IHsNCiAgICAgICAgY29uc3QgcHJldiA9IHRoaXMuZXZlbnRzW2tleV0NCiAgICAgICAgdGhpcy4kc2V0KHRoaXMuZXZlbnRzLCBrZXksIHsNCiAgICAgICAgICBiaDogcHJldiA/IHByZXYuYmggOiB1bmRlZmluZWQsDQogICAgICAgICAgbmFtZTogbmFtZSwNCiAgICAgICAgICBib2xkOiB0aGlzLnRvb2xiYXIuYm9sZCwNCiAgICAgICAgICBzY2hlZHVsYWJsZTogdGhpcy50b29sYmFyLnNjaGVkdWxhYmxlLA0KICAgICAgICAgIG1haW5Db3Vyc2U6IHRoaXMudG9vbGJhci5tYWluQ291cnNlLA0KICAgICAgICAgIHJlbWFya1Nob3c6IHRoaXMudG9vbGJhci5yZW1hcmtTaG93LA0KICAgICAgICAgIHJlbWFyazogdGhpcy50b29sYmFyLnJlbWFyaw0KICAgICAgICB9KQ0KICAgICAgfSkNCiAgICAgIHRoaXMucGVyc2lzdEV2ZW50cyhrZXlzKQ0KICAgIH0sDQogICAgZGVsZXRlRXZlbnQoKSB7DQogICAgICBpZiAoIXRoaXMuc2VsZWN0ZWRLZXlzLmxlbmd0aCkgew0KICAgICAgICB0aGlzLiRtZXNzYWdlLndhcm5pbmcoJ+ivt+WFiOmAieaLqeaXtumXtOagvCcpDQogICAgICAgIHJldHVybg0KICAgICAgfQ0KICAgICAgY29uc3Qga2V5cyA9IFsuLi50aGlzLnNlbGVjdGVkS2V5c10NCiAgICAgIGtleXMuZm9yRWFjaChrZXkgPT4gew0KICAgICAgICB0aGlzLiRkZWxldGUodGhpcy5ldmVudHMsIGtleSkNCiAgICAgIH0pDQogICAgICB0aGlzLiRtZXNzYWdlLnN1Y2Nlc3MoJ+W3suWIoOmZpCAnICsga2V5cy5sZW5ndGggKyAnIOS4quaXtumXtOagvOS6i+S7ticpDQogICAgfSwNCiAgICBhYnNvcmJFdmVudCgpIHsNCiAgICAgIC8vIOWQuOWPlu+8muWPlumAieaLqeS4reesrOS4gOS4quacieS6i+S7tueahOagvA0KICAgICAgbGV0IHRhcmdldCA9IG51bGwNCiAgICAgIGZvciAoY29uc3Qga2V5IG9mIHRoaXMuc2VsZWN0ZWRLZXlzKSB7DQogICAgICAgIGlmICh0aGlzLmV2ZW50c1trZXldKSB7IHRhcmdldCA9IHRoaXMuZXZlbnRzW2tleV07IGJyZWFrIH0NCiAgICAgIH0NCiAgICAgIGlmICghdGFyZ2V0KSB7DQogICAgICAgIHRoaXMuJG1lc3NhZ2Uud2FybmluZygn5omA6YCJ5pe26Ze05qC85Lit5peg5LqL5Lu25Y+v5ZC45Y+WJykNCiAgICAgICAgcmV0dXJuDQogICAgICB9DQogICAgICB0aGlzLnRvb2xiYXIuZXZlbnROYW1lID0gdGFyZ2V0Lm5hbWUNCiAgICAgIHRoaXMudG9vbGJhci5ib2xkID0gISF0YXJnZXQuYm9sZA0KICAgICAgdGhpcy50b29sYmFyLnNjaGVkdWxhYmxlID0gISF0YXJnZXQuc2NoZWR1bGFibGUNCiAgICAgIHRoaXMudG9vbGJhci5tYWluQ291cnNlID0gISF0YXJnZXQubWFpbkNvdXJzZQ0KICAgICAgdGhpcy50b29sYmFyLnJlbWFya1Nob3cgPSAhIXRhcmdldC5yZW1hcmtTaG93DQogICAgICB0aGlzLnRvb2xiYXIucmVtYXJrID0gdGFyZ2V0LnJlbWFyayB8fCAnJw0KICAgICAgdGhpcy5hYnNvcmJQcmV2aWV3ID0gdGFyZ2V0Lm5hbWUNCiAgICB9LA0KICAgIG9uQ2VsbERibENsaWNrKHdJZHgsIGNvbCkgew0KICAgICAgY29uc3QgZXYgPSB0aGlzLmdldEV2ZW50KHdJZHgsIGNvbC5jb2xJbmRleCkNCiAgICAgIGlmIChldikgew0KICAgICAgICB0aGlzLnRvb2xiYXIuZXZlbnROYW1lID0gZXYubmFtZQ0KICAgICAgICB0aGlzLnRvb2xiYXIuYm9sZCA9ICEhZXYuYm9sZA0KICAgICAgICB0aGlzLnRvb2xiYXIuc2NoZWR1bGFibGUgPSAhIWV2LnNjaGVkdWxhYmxlDQogICAgICAgIHRoaXMudG9vbGJhci5tYWluQ291cnNlID0gISFldi5tYWluQ291cnNlDQogICAgICAgIHRoaXMudG9vbGJhci5yZW1hcmtTaG93ID0gISFldi5yZW1hcmtTaG93DQogICAgICAgIHRoaXMudG9vbGJhci5yZW1hcmsgPSBldi5yZW1hcmsgfHwgJycNCiAgICAgICAgdGhpcy5hYnNvcmJQcmV2aWV3ID0gZXYubmFtZQ0KICAgICAgICB0aGlzLiRtZXNzYWdlLmluZm8oJ+W3suWQuOWPluS6i+S7tu+8micgKyBldi5uYW1lKQ0KICAgICAgfQ0KICAgIH0sDQogICAgcmVmcmVzaEdyaWQoKSB7DQogICAgICB0aGlzLnNlbGVjdGVkS2V5cyA9IFtdDQogICAgICB0aGlzLmFic29yYlByZXZpZXcgPSAnJw0KICAgICAgdGhpcy5ldmVudHMgPSB7fQ0KICAgICAgdGhpcy5oaWRkZW5FdmVudHMgPSB7fQ0KICAgICAgdGhpcy5sb2FkWHF4bGJFdmVudHMoKQ0KICAgICAgdGhpcy4kbWVzc2FnZS5pbmZvKCflt7LliLfmlrAnKQ0KICAgIH0sDQogICAgLyogLS0tLS0tLS0tLSDlkI7nq6/mjIHkuYXljJbvvIh4cXhsYiDmjqXlj6PvvIkgLS0tLS0tLS0tLSAqLw0KICAgIC8vIOaJuemHj+S/neWtmOmAieS4reagvOS6i+S7tu+8jOi/lOWbnuWQhOagvOWtkOS/neWtmOaIkOWKny/lpLHotKXnmoTkuKrmlbANCiAgICBwZXJzaXN0RXZlbnRzKGtleXMpIHsNCiAgICAgIGNvbnN0IHRhc2tzID0ga2V5cw0KICAgICAgICAuZmlsdGVyKGtleSA9PiB0aGlzLmV2ZW50c1trZXldKQ0KICAgICAgICAubWFwKGtleSA9PiB7DQogICAgICAgICAgY29uc3QgcGF5bG9hZCA9IHRoaXMuYnVpbGRYcXhsYlBheWxvYWQoa2V5LCB0aGlzLmV2ZW50c1trZXldKQ0KICAgICAgICAgIGlmICghcGF5bG9hZCkgcmV0dXJuIFByb21pc2UucmVzb2x2ZShmYWxzZSkNCiAgICAgICAgICByZXR1cm4gdXBkYXRlWHF4bGIocGF5bG9hZCkNCiAgICAgICAgICAgIC50aGVuKCgpID0+IHRydWUpDQogICAgICAgICAgICAuY2F0Y2goKCkgPT4gZmFsc2UpDQogICAgICAgIH0pDQogICAgICByZXR1cm4gUHJvbWlzZS5hbGwodGFza3MpLnRoZW4ocmVzdWx0cyA9PiB7DQogICAgICAgIGNvbnN0IG9rID0gcmVzdWx0cy5maWx0ZXIociA9PiByID09PSB0cnVlKS5sZW5ndGgNCiAgICAgICAgY29uc3QgZmFpbCA9IHJlc3VsdHMubGVuZ3RoIC0gb2sNCiAgICAgICAgaWYgKGZhaWwgPiAwKSB7DQogICAgICAgICAgdGhpcy4kbWVzc2FnZS5lcnJvcihmYWlsICsgJyDkuKrkuovku7bkv53lrZjlpLHotKXvvIzor7fmo4Dmn6XlkI7nq6/mjqXlj6MnKQ0KICAgICAgICB9IGVsc2UgaWYgKG9rID4gMCkgew0KICAgICAgICAgIHRoaXMuJG1lc3NhZ2Uuc3VjY2Vzcygn5bey6K6+5a6aICcgKyBvayArICcg5Liq5pe26Ze05qC8JykNCiAgICAgICAgfQ0KICAgICAgICAvLyDkv53lrZjmiJDlip/lkI7ph43mlrDmi4nlj5bvvIzlm57lhpnlkITorrDlvZXkuLvplK7vvIzpgb/lhY3ph43lpI3mlrDlop4NCiAgICAgICAgdGhpcy5sb2FkWHF4bGJFdmVudHMoKQ0KICAgICAgICByZXR1cm4geyBvazogb2ssIGZhaWw6IGZhaWwgfQ0KICAgICAgfSkNCiAgICB9LA0KICAgIC8vIOaehOmAoCB4cXhsYiDmj5DkuqTmlbDmja4NCiAgICBidWlsZFhxeGxiUGF5bG9hZChrZXksIGV2KSB7DQogICAgICBjb25zdCBwb3MgPSB0aGlzLnBhcnNlQ2VsbEtleShrZXkpDQogICAgICBpZiAoIXBvcykgcmV0dXJuIG51bGwNCiAgICAgIGNvbnN0IGQgPSBuZXcgRGF0ZSh0aGlzLnN0YXJ0RGF0ZSkNCiAgICAgIGQuc2V0RGF0ZSh0aGlzLnN0YXJ0RGF0ZS5nZXREYXRlKCkgKyBwb3Mud0lkeCAqIDcgKyBwb3MuZGF5SW5kZXgpDQogICAgICByZXR1cm4gew0KICAgICAgICBkZWxGbGFnOiAwLA0KICAgICAgICBiaDogZXYuYmggfHwgdW5kZWZpbmVkLA0KICAgICAgICBuZDogdGhpcy54cXhsYk5kLA0KICAgICAgICBqcXNqOiBmbXREYXRlKGQpLA0KICAgICAgICBqcW1jOiBldi5uYW1lIHx8ICcnLA0KICAgICAgICBqYzogISFldi5ib2xkLA0KICAgICAgICBiejogZXYucmVtYXJrIHx8IG51bGwsDQogICAgICAgIGtwazogISFldi5zY2hlZHVsYWJsZSwNCiAgICAgICAgYnp4czogISFldi5yZW1hcmtTaG93LA0KICAgICAgICB6ZHBrOiAhIWV2Lm1haW5Db3Vyc2UsDQogICAgICAgIGNvdXJzZUNsYXNzOiBTTE9UX0NPVVJTRV9NQVBbcG9zLnNsb3RLZXldIHx8IG51bGwNCiAgICAgIH0NCiAgICB9LA0KICAgIC8vIOaXtumXtOagvCBrZXkgLT4geyB3SWR4LCBkYXlJbmRleCwgc2xvdEtleSB9DQogICAgcGFyc2VDZWxsS2V5KGtleSkgew0KICAgICAgY29uc3QgbSA9IGtleS5tYXRjaCgvXncoXGQrKS1jKFxkKykkLykNCiAgICAgIGlmICghbSkgcmV0dXJuIG51bGwNCiAgICAgIGNvbnN0IGNvbEluZGV4ID0gK21bMl0NCiAgICAgIGNvbnN0IGNvbCA9IHRoaXMudmlzaWJsZUNvbHVtbnMuZmluZChjID0+IGMuY29sSW5kZXggPT09IGNvbEluZGV4KQ0KICAgICAgaWYgKCFjb2wpIHJldHVybiBudWxsDQogICAgICByZXR1cm4geyB3SWR4OiArbVsxXSwgZGF5SW5kZXg6IGNvbC5kYXlJbmRleCwgc2xvdEtleTogY29sLnNsb3RLZXkgfQ0KICAgIH0sDQogICAgLyogLS0tLS0tLS0tLSDov5Tlm57lrabmnJ/nrqHnkIYgLS0tLS0tLS0tLSAqLw0KICAgIGhhbmRsZUNsb3NlKCkgew0KICAgICAgdGhpcy4kZW1pdCgnY2xvc2UnKQ0KICAgICAgdGhpcy4kcm91dGVyLnJlcGxhY2UoeyBwYXRoOiAnL3RlYWNoQnVzaW5lc3Mvc2VtZXN0ZXInIH0pDQogICAgfQ0KICB9DQp9DQo="},{"version":3,"sources":["SchoolCalendarEditor.vue"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4FA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;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;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;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;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;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","file":"SchoolCalendarEditor.vue","sourceRoot":"src/views/teachBusiness/calendar/components","sourcesContent":["<template>\r\n <div class=\"school-calendar-editor\">\r\n <!-- 标题栏 -->\r\n <div class=\"sce-titlebar\">\r\n <div class=\"sce-title-left\">\r\n <span class=\"sce-semester-name\">{{ semesterName }}</span>\r\n </div>\r\n <div class=\"sce-title-center\">\r\n <span class=\"sce-date-range\">从 {{ dateRangeText }} ,共 {{ totalWeeks }} 周</span>\r\n </div>\r\n <div class=\"sce-title-right\">\r\n <i class=\"el-icon-close\" title=\"关闭\" @click=\"handleClose\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 设置面板 -->\r\n <div class=\"sce-panel\">\r\n <div class=\"sce-panel-row\">\r\n <span class=\"sce-label\">事件名称:</span>\r\n <el-input v-model=\"toolbar.eventName\" size=\"small\" class=\"sce-event-input\" placeholder=\"请输入校历事件名称\" />\r\n <el-checkbox v-model=\"toolbar.bold\" class=\"sce-cb\">加粗显示</el-checkbox>\r\n <el-checkbox v-model=\"toolbar.schedulable\" class=\"sce-cb\">可排课</el-checkbox>\r\n <el-checkbox v-model=\"toolbar.mainCourse\" class=\"sce-cb\">正课</el-checkbox>\r\n <el-checkbox v-model=\"toolbar.remarkShow\" class=\"sce-cb\">备注显示</el-checkbox>\r\n <span class=\"sce-label\">备注:</span>\r\n <el-input\r\n v-model=\"toolbar.remark\"\r\n size=\"small\"\r\n type=\"textarea\"\r\n :rows=\"1\"\r\n class=\"sce-remark-input\"\r\n resize=\"none\"\r\n placeholder=\"备注信息\"\r\n />\r\n </div>\r\n <div class=\"sce-panel-row\">\r\n <el-button type=\"primary\" size=\"small\" icon=\"el-icon-check\" @click=\"applyEvent\">设定</el-button>\r\n <el-button type=\"danger\" size=\"small\" icon=\"el-icon-delete\" @click=\"deleteEvent\">删除</el-button>\r\n <el-button size=\"small\" icon=\"el-icon-brush\" @click=\"absorbEvent\">吸取</el-button>\r\n <el-button size=\"small\" icon=\"el-icon-refresh\" @click=\"refreshGrid\">刷新</el-button>\r\n <span class=\"sce-divider\" />\r\n <el-checkbox v-model=\"show78\" class=\"sce-cb\">显示78节</el-checkbox>\r\n <el-checkbox v-model=\"showNight\" class=\"sce-cb\">显示晚上</el-checkbox>\r\n <el-checkbox v-model=\"showLateNight\" class=\"sce-cb\">显示夜间</el-checkbox>\r\n </div>\r\n </div>\r\n\r\n <!-- 时间编排区域 -->\r\n <div ref=\"gridWrap\" class=\"sce-grid-wrap\" @mousedown=\"onGridMouseDown\">\r\n <table class=\"sce-grid\" :class=\"{ 'is-selecting': selecting }\">\r\n <thead>\r\n <tr>\r\n <th class=\"sce-corner sce-th-weekno\" :rowspan=\"2\">周次</th>\r\n <th class=\"sce-corner sce-th-weekrange\" :rowspan=\"2\">日期段</th>\r\n <th v-for=\"col in visibleColumns\" :key=\"'h1-' + col.colIndex\" :colspan=\"1\" class=\"sce-th-day\">\r\n {{ weekDayLabel(col.dayIndex) }}\r\n </th>\r\n </tr>\r\n <tr>\r\n <th v-for=\"col in visibleColumns\" :key=\"'h2-' + col.colIndex\" class=\"sce-th-slot\">\r\n {{ col.slotLabel }}\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr v-for=\"(week, wIdx) in weeks\" :key=\"'w-' + wIdx\">\r\n <td class=\"sce-week-cell sce-weekno-cell\">{{ wIdx + 1 }}</td>\r\n <td class=\"sce-week-cell sce-weekrange-cell\">{{ week.rangeText }}</td>\r\n <td\r\n v-for=\"col in visibleColumns\"\r\n :key=\"'c-' + wIdx + '-' + col.colIndex\"\r\n class=\"sce-cell\"\r\n :class=\"cellClass(wIdx, col)\"\r\n :data-key=\"cellKey(wIdx, col.colIndex)\"\r\n @dblclick=\"onCellDblClick(wIdx, col)\"\r\n >\r\n <span v-if=\"getEvent(wIdx, col.colIndex)\" class=\"sce-event-name\" :class=\"{ 'is-bold': getEvent(wIdx, col.colIndex).bold }\">{{ getEvent(wIdx, col.colIndex).name }}</span>\r\n <span v-else class=\"sce-date-num\">{{ dateNumberOf(wIdx, col.dayIndex) }}</span>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n\r\n <div class=\"sce-status\">\r\n 已选 {{ selectedKeys.length }} 个时间格\r\n <span v-if=\"absorbPreview\" class=\"sce-absorb-tip\">已吸取:{{ absorbPreview }}</span>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script>\r\nimport { getSemester } from '@/api/teachBusiness/semester'\r\nimport { listXqxlb, updateXqxlb } from '@/api/teachBusiness/xqxlb'\r\n\r\n// 节次定义:12/34/56 常显,78/晚上/夜间由开关控制可见\r\nconst SLOT_DEFS = [\r\n { key: '12', label: '1-2', ctrl: null },\r\n { key: '34', label: '3-4', ctrl: null },\r\n { key: '56', label: '5-6', ctrl: null },\r\n { key: '78', label: '7-8', ctrl: 'show78' },\r\n { key: 'night', label: '晚上', ctrl: 'showNight' },\r\n { key: 'late', label: '夜间', ctrl: 'showLateNight' }\r\n]\r\n\r\n// 前端节次 key -> 后端 xqxlb.courseClass 节次范围(如 12 节 -> \"1-2\"、夜间 -> \"11-12\")\r\nconst SLOT_COURSE_MAP = {\r\n '12': '1-2',\r\n '34': '3-4',\r\n '56': '5-6',\r\n '78': '7-8',\r\n night: '9-10',\r\n late: '11-12'\r\n}\r\n\r\nconst WEEK_DAYS = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']\r\n\r\nfunction pad2(n) {\r\n return n < 10 ? '0' + n : '' + n\r\n}\r\n\r\nfunction fmtDate(d) {\r\n return d.getFullYear() + '-' + pad2(d.getMonth() + 1) + '-' + pad2(d.getDate())\r\n}\r\n\r\nexport default {\r\n name: 'SchoolCalendarEditor',\r\n props: {\r\n nd: { type: [String, Number], default: '' },\r\n semesterName: { type: String, default: '' }\r\n },\r\n data() {\r\n return {\r\n // 学期日期范围\r\n startDate: null,\r\n endDate: null,\r\n totalWeeks: 0,\r\n dateRangeText: '',\r\n weeks: [],\r\n // 显示开关(默认不勾选,每天仅显示 1-2/3-4/5-6 三个节次)\r\n show78: false,\r\n showNight: false,\r\n showLateNight: false,\r\n // 工具栏表单\r\n toolbar: {\r\n eventName: '',\r\n bold: false,\r\n schedulable: false,\r\n mainCourse: false,\r\n remarkShow: false,\r\n remark: ''\r\n },\r\n // 事件存储:key = cellKey -> event\r\n events: {},\r\n // 暂存被隐藏节次列上的事件:key = 周-星期-节次 -> event,列再次显示时恢复\r\n hiddenEvents: {},\r\n // 选择集(用数组以保证 Vue2 响应式)\r\n selectedKeys: [],\r\n // 拖拽状态\r\n selecting: false,\r\n dragStart: null,\r\n dragStartSelected: false, // 按下起点在按下前是否已选中\r\n moved: false, // 是否发生移动(区分点击与拖拽)\r\n dragAddMode: false, // ctrl 拖拽为追加\r\n // 窗口控制\r\n absorbPreview: ''\r\n }\r\n },\r\n computed: {\r\n // 当前可见列(由开关过滤,默认每天三个节次)\r\n visibleColumns() {\r\n const cols = []\r\n let colIndex = 0\r\n WEEK_DAYS.forEach((dayLabel, dayIndex) => {\r\n SLOT_DEFS.forEach(slot => {\r\n if (slot.ctrl && !this[slot.ctrl]) return\r\n cols.push({ colIndex: colIndex, dayIndex: dayIndex, slotKey: slot.key, slotLabel: slot.label, dayLabel: dayLabel })\r\n colIndex++\r\n })\r\n })\r\n return cols\r\n },\r\n // xqxlb 的年度(nd)为年份(如 2026),由 6 位学期代号(如 202601)截取前 4 位得出\r\n xqxlbNd() {\r\n return Number(String(this.nd).slice(0, 4))\r\n }\r\n },\r\n watch: {\r\n nd: {\r\n immediate: true,\r\n handler(val) {\r\n if (val) this.loadSemester()\r\n }\r\n },\r\n visibleColumns(newCols, oldCols) {\r\n // 节次列显隐会改变列索引,按「周期-星期-节次」重定位事件,避免事件随时间格列偏移\r\n if (oldCols && oldCols.length) {\r\n const oldPosOf = index => (oldCols[index] || null)\r\n const newIndex = (dayIndex, slotKey) => {\r\n const c = newCols.find(x => x.dayIndex === dayIndex && x.slotKey === slotKey)\r\n return c ? c.colIndex : -1\r\n }\r\n const next = {}\r\n Object.keys(this.events).forEach(key => {\r\n const m = key.match(/^w(\\d+)-c(\\d+)$/)\r\n if (!m) return\r\n const wIdx = +m[1]\r\n const old = oldPosOf(+m[2])\r\n if (!old) return\r\n const newC = newIndex(old.dayIndex, old.slotKey)\r\n if (newC < 0) {\r\n // 该节次列被隐藏:事件暂存,待列再次显示时恢复\r\n this.hiddenEvents[this.cellStableKey(wIdx, old.dayIndex, old.slotKey)] = this.events[key]\r\n return\r\n }\r\n next['w' + wIdx + '-c' + newC] = this.events[key]\r\n })\r\n // 恢复重新显示的隐藏节次事件\r\n Object.keys(this.hiddenEvents).forEach(stable => {\r\n const p = stable.split('-')\r\n const wIdx = +p[0]\r\n const dayIndex = +p[1]\r\n const slotKey = p[2]\r\n const newC = newIndex(dayIndex, slotKey)\r\n if (newC >= 0) {\r\n next['w' + wIdx + '-c' + newC] = this.hiddenEvents[stable]\r\n delete this.hiddenEvents[stable]\r\n }\r\n })\r\n this.events = next\r\n }\r\n // 列变化后清空无效选择(列索引含义会变)\r\n this.selectedKeys = []\r\n }\r\n },\r\n beforeDestroy() {\r\n this.removeGlobalListeners()\r\n },\r\n methods: {\r\n /* ---------- 数据加载 ---------- */\r\n loadSemester() {\r\n if (!this.nd) return\r\n getSemester(this.nd)\r\n .then(res => {\r\n const data = res.data || res || {}\r\n const kx = (data.kxrq || '').toString().slice(0, 10)\r\n const jx = (data.jsrq || '').toString().slice(0, 10)\r\n if (kx && jx) {\r\n this.startDate = new Date(kx.replace(/-/g, '/'))\r\n this.endDate = new Date(jx.replace(/-/g, '/'))\r\n this.buildWeeks()\r\n }\r\n this.loadXqxlbEvents()\r\n })\r\n .catch(() => {\r\n this.$message.warning('学期详情获取失败,请确认学期数据')\r\n })\r\n },\r\n // 从后端拉取本学期校历事件,渲染到对应时间格(年度由 6 位学期代号截取前 4 位)\r\n loadXqxlbEvents() {\r\n listXqxlb({ nd: this.xqxlbNd }).then(res => {\r\n const data = res.data\r\n const list = Array.isArray(data) ? data : (data && data.records) || []\r\n return list\r\n }).then(list => {\r\n const loaded = {}\r\n list.forEach(item => {\r\n const pos = this.locateXqxlb(item)\r\n if (!pos) return\r\n const ev = {\r\n bh: item.bh,\r\n name: item.jqmc || '',\r\n bold: !!item.jc,\r\n schedulable: !!item.kpk,\r\n mainCourse: !!item.zdpk,\r\n remarkShow: !!item.bzxs,\r\n remark: item.bz || ''\r\n }\r\n const colIndex = this.colIndexOf(pos.dayIndex, pos.slotKey)\r\n if (colIndex >= 0) {\r\n loaded[this.cellKey(pos.wIdx, colIndex)] = ev\r\n } else {\r\n // 该节次列当前隐藏:暂存(含 bh),待列显示时由 visibleColumns 监听恢复\r\n this.hiddenEvents[this.cellStableKey(pos.wIdx, pos.dayIndex, pos.slotKey)] = ev\r\n }\r\n })\r\n // 合并到现有格子(后端数据覆盖已有状态)\r\n this.events = Object.assign({}, this.events, loaded)\r\n }).catch(() => {\r\n this.$message.warning('校历事件加载失败')\r\n })\r\n },\r\n // 根据假期记录反推时间格位置(jqsj 日期 + courseClass 节次),与列是否可见无关\r\n locateXqxlb(item) {\r\n if (!this.startDate || !item.jqsj) return null\r\n const d = new Date(String(item.jqsj).slice(0, 10).replace(/-/g, '/'))\r\n if (isNaN(d.getTime())) return null\r\n const offset = Math.round((d - this.startDate) / (24 * 3600 * 1000))\r\n if (offset < 0) return null\r\n const wIdx = Math.floor(offset / 7)\r\n const dayIndex = offset % 7\r\n const slotKey = this.courseClassToSlotKey(item.courseClass)\r\n if (slotKey === null) return null\r\n return { wIdx, dayIndex, slotKey }\r\n },\r\n // 后端 courseClass 节次范围 -> 前端节次 key\r\n courseClassToSlotKey(courseClass) {\r\n if (!courseClass) return null\r\n const s = String(courseClass).trim()\r\n for (const key in SLOT_COURSE_MAP) {\r\n if (s === SLOT_COURSE_MAP[key]) return key\r\n }\r\n // 兼容 \"910\"/\"1112\" 等紧凑写法\r\n if (s === '910') return 'night'\r\n if (s === '1112') return 'late'\r\n return null\r\n },\r\n buildWeeks() {\r\n if (!this.startDate || !this.endDate) return\r\n const start = new Date(this.startDate)\r\n const end = new Date(this.endDate)\r\n const days = Math.round((end - start) / (24 * 3600 * 1000)) + 1\r\n this.totalWeeks = Math.ceil(days / 7)\r\n this.dateRangeText = fmtDate(start) + ' 到 ' + fmtDate(end)\r\n const weeks = []\r\n for (let w = 0; w < this.totalWeeks; w++) {\r\n const wkStart = new Date(start)\r\n wkStart.setDate(start.getDate() + w * 7)\r\n const wkEnd = new Date(wkStart)\r\n wkEnd.setDate(wkStart.getDate() + 6)\r\n weeks.push({\r\n rangeText: pad2(wkStart.getMonth() + 1) + '-' + pad2(wkStart.getDate()) +\r\n '至' + pad2(wkEnd.getMonth() + 1) + '-' + pad2(wkEnd.getDate())\r\n })\r\n }\r\n this.weeks = weeks\r\n },\r\n colIndexOf(dayIndex, slotKey) {\r\n const col = this.visibleColumns.find(c => c.dayIndex === dayIndex && c.slotKey === slotKey)\r\n return col ? col.colIndex : -1\r\n },\r\n /* ---------- 单元格工具 ---------- */\r\n cellKey(wIdx, colIndex) {\r\n return 'w' + wIdx + '-c' + colIndex\r\n },\r\n // 稳定的单元格身份:不随列显隐变化的周-星期-节次\r\n cellStableKey(wIdx, dayIndex, slotKey) {\r\n return wIdx + '-' + dayIndex + '-' + slotKey\r\n },\r\n getEvent(wIdx, colIndex) {\r\n return this.events[this.cellKey(wIdx, colIndex)] || null\r\n },\r\n weekDayLabel(dayIndex) {\r\n return WEEK_DAYS[dayIndex]\r\n },\r\n // 单元格内显示的日期数字(如 0703)\r\n dateNumberOf(wIdx, dayIndex) {\r\n if (!this.startDate) return ''\r\n const d = new Date(this.startDate)\r\n d.setDate(this.startDate.getDate() + wIdx * 7 + dayIndex)\r\n return pad2(d.getMonth() + 1) + pad2(d.getDate())\r\n },\r\n cellClass(wIdx, col) {\r\n const classes = []\r\n // 星期交替背景(单双日不同底色)\r\n if (col.dayIndex % 2 === 0) classes.push('sce-cell-odd')\r\n else classes.push('sce-cell-even')\r\n if (this.selectedKeys.includes(this.cellKey(wIdx, col.colIndex))) classes.push('is-selected')\r\n const ev = this.getEvent(wIdx, col.colIndex)\r\n if (ev) {\r\n classes.push('has-event')\r\n if (!ev.schedulable) classes.push('no-schedule')\r\n }\r\n return classes\r\n },\r\n /* ---------- 点击 / 拖拽多选 ---------- */\r\n onGridMouseDown(e) {\r\n const cell = e.target.closest('.sce-cell')\r\n if (!cell) {\r\n // 点击空白区(非单元格,含表头、周次列等)取消所有选中\r\n if (this.selectedKeys.length) this.selectedKeys = []\r\n return\r\n }\r\n e.preventDefault()\r\n const key = cell.getAttribute('data-key')\r\n this.dragStart = key\r\n this.dragAddMode = e.ctrlKey || e.metaKey\r\n // 记录起点格在按下时的选中状态,用于松手时判定\"纯点击\"的切换行为\r\n this.dragStartSelected = this.selectedKeys.includes(key)\r\n this.moved = false\r\n this.selecting = true\r\n // 非 ctrl 模式下,若起点本身已选中(可能准备拖拽扩展),先不清除,避免误清空\r\n if (!this.dragAddMode && !this.dragStartSelected) this.selectedKeys = []\r\n this.addGlobalListeners()\r\n },\r\n addGlobalListeners() {\r\n document.addEventListener('mousemove', this.onGridMouseMove)\r\n document.addEventListener('mouseup', this.onGridMouseUp)\r\n },\r\n removeGlobalListeners() {\r\n document.removeEventListener('mousemove', this.onGridMouseMove)\r\n document.removeEventListener('mouseup', this.onGridMouseUp)\r\n },\r\n onGridMouseMove(e) {\r\n if (!this.selecting || !this.dragStart) return\r\n if (!this.moved) this.moved = true\r\n const el = document.elementFromPoint(e.clientX, e.clientY)\r\n const cell = el && el.closest ? el.closest('.sce-cell') : null\r\n if (!cell) return\r\n const curKey = cell.getAttribute('data-key')\r\n this.selectRectangle(this.dragStart, curKey, this.dragAddMode)\r\n },\r\n onGridMouseUp() {\r\n if (!this.selecting) {\r\n this.removeGlobalListeners()\r\n return\r\n }\r\n // 纯点击(未移动)时,做单选 / 切换\r\n if (!this.moved) {\r\n const key = this.dragStart\r\n if (this.dragAddMode) {\r\n // Ctrl + 单击:切换该格选中\r\n if (this.selectedKeys.includes(key)) {\r\n this.selectedKeys = this.selectedKeys.filter(k => k !== key)\r\n } else {\r\n this.selectedKeys.push(key)\r\n }\r\n } else {\r\n // 普通单击:已选中则取消该格,未选中则仅选中该格\r\n if (this.dragStartSelected) {\r\n this.selectedKeys = this.selectedKeys.filter(k => k !== key)\r\n } else {\r\n this.selectedKeys = [key]\r\n }\r\n }\r\n }\r\n this.selecting = false\r\n this.dragStart = null\r\n this.dragStartSelected = false\r\n this.removeGlobalListeners()\r\n },\r\n // 根据起点终点 key 选中矩形范围内所有格\r\n selectRectangle(startKey, endKey, addMode) {\r\n const parse = k => {\r\n const m = k.match(/^w(\\d+)-c(\\d+)$/)\r\n return m ? { w: +m[1], c: +m[2] } : null\r\n }\r\n const s = parse(startKey)\r\n const t = parse(endKey)\r\n if (!s || !t) return\r\n if (!addMode) this.selectedKeys = []\r\n const minW = Math.min(s.w, t.w)\r\n const maxW = Math.max(s.w, t.w)\r\n const minC = Math.min(s.c, t.c)\r\n const maxC = Math.max(s.c, t.c)\r\n for (let w = minW; w <= maxW; w++) {\r\n for (let c = minC; c <= maxC; c++) {\r\n const key = this.cellKey(w, c)\r\n if (this.selectedKeys.indexOf(key) === -1) this.selectedKeys.push(key)\r\n }\r\n }\r\n },\r\n /* ---------- 事件操作 ---------- */\r\n applyEvent() {\r\n if (!this.selectedKeys.length) {\r\n this.$message.warning('请先选择时间格')\r\n return\r\n }\r\n const name = this.toolbar.eventName.trim()\r\n if (!name) {\r\n this.$message.warning('请输入事件名称')\r\n return\r\n }\r\n const keys = [...this.selectedKeys]\r\n keys.forEach(key => {\r\n const prev = this.events[key]\r\n this.$set(this.events, key, {\r\n bh: prev ? prev.bh : undefined,\r\n name: name,\r\n bold: this.toolbar.bold,\r\n schedulable: this.toolbar.schedulable,\r\n mainCourse: this.toolbar.mainCourse,\r\n remarkShow: this.toolbar.remarkShow,\r\n remark: this.toolbar.remark\r\n })\r\n })\r\n this.persistEvents(keys)\r\n },\r\n deleteEvent() {\r\n if (!this.selectedKeys.length) {\r\n this.$message.warning('请先选择时间格')\r\n return\r\n }\r\n const keys = [...this.selectedKeys]\r\n keys.forEach(key => {\r\n this.$delete(this.events, key)\r\n })\r\n this.$message.success('已删除 ' + keys.length + ' 个时间格事件')\r\n },\r\n absorbEvent() {\r\n // 吸取:取选择中第一个有事件的格\r\n let target = null\r\n for (const key of this.selectedKeys) {\r\n if (this.events[key]) { target = this.events[key]; break }\r\n }\r\n if (!target) {\r\n this.$message.warning('所选时间格中无事件可吸取')\r\n return\r\n }\r\n this.toolbar.eventName = target.name\r\n this.toolbar.bold = !!target.bold\r\n this.toolbar.schedulable = !!target.schedulable\r\n this.toolbar.mainCourse = !!target.mainCourse\r\n this.toolbar.remarkShow = !!target.remarkShow\r\n this.toolbar.remark = target.remark || ''\r\n this.absorbPreview = target.name\r\n },\r\n onCellDblClick(wIdx, col) {\r\n const ev = this.getEvent(wIdx, col.colIndex)\r\n if (ev) {\r\n this.toolbar.eventName = ev.name\r\n this.toolbar.bold = !!ev.bold\r\n this.toolbar.schedulable = !!ev.schedulable\r\n this.toolbar.mainCourse = !!ev.mainCourse\r\n this.toolbar.remarkShow = !!ev.remarkShow\r\n this.toolbar.remark = ev.remark || ''\r\n this.absorbPreview = ev.name\r\n this.$message.info('已吸取事件:' + ev.name)\r\n }\r\n },\r\n refreshGrid() {\r\n this.selectedKeys = []\r\n this.absorbPreview = ''\r\n this.events = {}\r\n this.hiddenEvents = {}\r\n this.loadXqxlbEvents()\r\n this.$message.info('已刷新')\r\n },\r\n /* ---------- 后端持久化(xqxlb 接口) ---------- */\r\n // 批量保存选中格事件,返回各格子保存成功/失败的个数\r\n persistEvents(keys) {\r\n const tasks = keys\r\n .filter(key => this.events[key])\r\n .map(key => {\r\n const payload = this.buildXqxlbPayload(key, this.events[key])\r\n if (!payload) return Promise.resolve(false)\r\n return updateXqxlb(payload)\r\n .then(() => true)\r\n .catch(() => false)\r\n })\r\n return Promise.all(tasks).then(results => {\r\n const ok = results.filter(r => r === true).length\r\n const fail = results.length - ok\r\n if (fail > 0) {\r\n this.$message.error(fail + ' 个事件保存失败,请检查后端接口')\r\n } else if (ok > 0) {\r\n this.$message.success('已设定 ' + ok + ' 个时间格')\r\n }\r\n // 保存成功后重新拉取,回写各记录主键,避免重复新增\r\n this.loadXqxlbEvents()\r\n return { ok: ok, fail: fail }\r\n })\r\n },\r\n // 构造 xqxlb 提交数据\r\n buildXqxlbPayload(key, ev) {\r\n const pos = this.parseCellKey(key)\r\n if (!pos) return null\r\n const d = new Date(this.startDate)\r\n d.setDate(this.startDate.getDate() + pos.wIdx * 7 + pos.dayIndex)\r\n return {\r\n delFlag: 0,\r\n bh: ev.bh || undefined,\r\n nd: this.xqxlbNd,\r\n jqsj: fmtDate(d),\r\n jqmc: ev.name || '',\r\n jc: !!ev.bold,\r\n bz: ev.remark || null,\r\n kpk: !!ev.schedulable,\r\n bzxs: !!ev.remarkShow,\r\n zdpk: !!ev.mainCourse,\r\n courseClass: SLOT_COURSE_MAP[pos.slotKey] || null\r\n }\r\n },\r\n // 时间格 key -> { wIdx, dayIndex, slotKey }\r\n parseCellKey(key) {\r\n const m = key.match(/^w(\\d+)-c(\\d+)$/)\r\n if (!m) return null\r\n const colIndex = +m[2]\r\n const col = this.visibleColumns.find(c => c.colIndex === colIndex)\r\n if (!col) return null\r\n return { wIdx: +m[1], dayIndex: col.dayIndex, slotKey: col.slotKey }\r\n },\r\n /* ---------- 返回学期管理 ---------- */\r\n handleClose() {\r\n this.$emit('close')\r\n this.$router.replace({ path: '/teachBusiness/semester' })\r\n }\r\n }\r\n}\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.school-calendar-editor {\r\n display: flex;\r\n flex-direction: column;\r\n height: 100%;\r\n background: #fff;\r\n border: 1px solid #e4e7ed;\r\n border-radius: 6px;\r\n overflow: hidden;\r\n\r\n /* 标题栏 */\r\n .sce-titlebar {\r\n display: flex;\r\n align-items: center;\r\n height: 44px;\r\n padding: 0 14px;\r\n background: var(--edu-green-primary, #00875a);\r\n color: #fff;\r\n\r\n .sce-title-left { flex: 1; font-size: 15px; font-weight: 600; }\r\n .sce-title-center { flex: 1; text-align: center; font-size: 13px; opacity: 0.9; }\r\n .sce-title-right { flex: 0 0 auto; text-align: right; }\r\n\r\n .sce-title-right i {\r\n margin-left: 14px;\r\n cursor: pointer;\r\n font-size: 18px;\r\n opacity: 0.85;\r\n &:hover { opacity: 1; }\r\n }\r\n }\r\n\r\n /* 设置面板 */\r\n .sce-panel {\r\n padding: 10px 14px;\r\n border-bottom: 1px solid #ebeef5;\r\n background: #fafafa;\r\n\r\n .sce-panel-row {\r\n display: flex;\r\n align-items: center;\r\n flex-wrap: wrap;\r\n margin-bottom: 8px;\r\n\r\n &:last-child { margin-bottom: 0; }\r\n }\r\n\r\n .sce-label { font-size: 13px; color: #606266; margin-right: 6px; white-space: nowrap; }\r\n .sce-event-input { width: 200px; margin-right: 12px; }\r\n .sce-remark-input { width: 240px; margin-left: 6px; }\r\n .sce-cb { margin-right: 14px; }\r\n .sce-divider { width: 1px; height: 18px; background: #dcdfe6; margin: 0 14px; }\r\n }\r\n\r\n /* 时间编排区 */\r\n .sce-grid-wrap {\r\n flex: 1;\r\n overflow: auto;\r\n padding: 8px 10px;\r\n background: #fff;\r\n }\r\n\r\n .sce-grid {\r\n border-collapse: collapse;\r\n table-layout: fixed;\r\n width: 100%;\r\n font-size: 12px;\r\n user-select: none;\r\n\r\n th, td {\r\n border: 1px solid #e4e7ed;\r\n text-align: center;\r\n padding: 0;\r\n }\r\n\r\n .sce-corner {\r\n background: #f5f7fa;\r\n font-weight: 600;\r\n color: #303133;\r\n vertical-align: middle;\r\n }\r\n\r\n .sce-th-weekno { width: 52px; }\r\n .sce-th-weekrange { width: 110px; }\r\n\r\n .sce-th-day {\r\n background: var(--edu-green-primary, #00875a);\r\n color: #fff;\r\n font-weight: 600;\r\n height: 26px;\r\n }\r\n\r\n .sce-th-slot {\r\n background: #ecf5f0;\r\n color: #00875a;\r\n height: 22px;\r\n font-weight: 500;\r\n }\r\n\r\n .sce-week-cell {\r\n background: #f5f7fa;\r\n vertical-align: middle;\r\n white-space: nowrap;\r\n }\r\n\r\n .sce-weekno-cell {\r\n font-weight: 600;\r\n color: #303133;\r\n font-size: 13px;\r\n }\r\n\r\n .sce-weekrange-cell {\r\n font-size: 11px;\r\n color: #909399;\r\n }\r\n\r\n .sce-cell {\r\n height: 30px;\r\n position: relative;\r\n cursor: pointer;\r\n background: #fff;\r\n transition: background 0.15s;\r\n\r\n .sce-date-num { color: #c0c4cc; }\r\n\r\n // 星期交替底色:周一/三/五/日为浅绿,周二/四/六为白,便于区分星期\r\n &.sce-cell-odd { background: #eef6f1; }\r\n &.sce-cell-even { background: #ffffff; }\r\n &.has-event { background: #e6f4ea; }\r\n &.has-event .sce-event-name { color: #00663e; font-weight: 500; }\r\n &.has-event .sce-event-name.is-bold { font-weight: 700; }\r\n &.no-schedule { background: #fde2e2; }\r\n\r\n &.is-selected {\r\n outline: 2px solid var(--edu-green-primary, #00875a);\r\n outline-offset: -2px;\r\n background: #d4ecdf !important;\r\n }\r\n }\r\n }\r\n\r\n .sce-status {\r\n padding: 6px 14px;\r\n font-size: 12px;\r\n color: #909399;\r\n border-top: 1px solid #ebeef5;\r\n background: #fafafa;\r\n\r\n .sce-absorb-tip { margin-left: 12px; color: #00875a; }\r\n }\r\n}\r\n</style>\r\n"]}]} |