| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 | 
							- {{define "modals/qrcodeModal"}}
 
- <a-modal id="qrcode-modal" v-model="qrModal.visible" :closable="true" :class="themeSwitcher.currentTheme"
 
-   width="fit-content" :dialog-style="isMobile ? { top: '18px' } : {}" :footer="null">
 
-   <template #title>
 
-     <a-space direction="horizontal">
 
-       <span>[[ qrModal.title ]]</span>
 
-       <a-popover :overlay-class-name="themeSwitcher.currentTheme" trigger="click" placement="bottom">
 
-         <template slot="content">
 
-           <a-space direction="vertical">
 
-             <template v-for="(row, index) in qrModal.qrcodes">
 
-               <b>[[ row.remark ]]</b>
 
-               <a-space direction="horizontal">
 
-                 <a-switch size="small" :checked="row.useIPv4" @click="toggleIPv4(index)"></a-switch>
 
-                 <span>{{ i18n "useIPv4ForHost" }}</span>
 
-               </a-space>
 
-             </template>
 
-           </a-space>
 
-         </template>
 
-         <a-icon type="setting"></a-icon>
 
-       </a-popover>
 
-     </a-space>
 
-   </template>
 
-   <tr-qr-modal class="qr-modal">
 
-     <template v-if="app.subSettings?.enable && qrModal.subId">
 
-       <tr-qr-box class="qr-box">
 
-         <a-tag color="purple" class="qr-tag"><span>{{ i18n "pages.settings.subSettings"}}</span></a-tag>
 
-         <tr-qr-bg class="qr-bg-sub">
 
-           <tr-qr-bg-inner class="qr-bg-sub-inner">
 
-             <canvas @click="copy(genSubLink(qrModal.client.subId))" id="qrCode-sub" class="qr-cv"></canvas>
 
-           </tr-qr-bg-inner>
 
-         </tr-qr-bg>
 
-       </tr-qr-box>
 
-       <tr-qr-box class="qr-box" v-if="app.subSettings.subJsonEnable">
 
-         <a-tag color="purple" class="qr-tag"><span>{{ i18n "pages.settings.subSettings"}} Json</span></a-tag>
 
-         <tr-qr-bg class="qr-bg-sub">
 
-           <tr-qr-bg-inner class="qr-bg-sub-inner">
 
-             <canvas @click="copy(genSubJsonLink(qrModal.client.subId))" id="qrCode-subJson" class="qr-cv"></canvas>
 
-           </tr-qr-bg-inner>
 
-         </tr-qr-bg>
 
-       </tr-qr-box>
 
-     </template>
 
-     <template v-for="(row, index) in qrModal.qrcodes">
 
-       <tr-qr-box class="qr-box">
 
-         <a-tag color="green" class="qr-tag"><span>[[ row.remark ]]</span></a-tag>
 
-         <tr-qr-bg class="qr-bg">
 
-           <canvas @click="copy(row.link)" :id="'qrCode-'+index" class="qr-cv"></canvas>
 
-         </tr-qr-bg>
 
-       </tr-qr-box>
 
-     </template>
 
-   </tr-qr-modal>
 
- </a-modal>
 
- <style>
 
-   .ant-table:not(.ant-table-expanded-row .ant-table) {
 
-     outline: 1px solid #f0f0f0;
 
-     outline-offset: -1px;
 
-     border-radius: 1rem;
 
-     overflow-x: hidden;
 
-   }
 
-   
 
-   /* QR code transition effects */
 
-   .qr-cv {
 
-     transition: all 0.3s ease-in-out;
 
-   }
 
-   
 
-   .qr-transition-enter-active, .qr-transition-leave-active {
 
-     transition: opacity 0.3s, transform 0.3s;
 
-   }
 
-   
 
-   .qr-transition-enter, .qr-transition-leave-to {
 
-     opacity: 0;
 
-     transform: scale(0.9);
 
-   }
 
-   
 
-   .qr-transition-enter-to, .qr-transition-leave {
 
-     opacity: 1;
 
-     transform: scale(1);
 
-   }
 
-   
 
-   .qr-flash {
 
-     animation: qr-flash-animation 0.6s;
 
-   }
 
-   
 
-   @keyframes qr-flash-animation {
 
-     0% {
 
-       opacity: 1;
 
-       transform: scale(1);
 
-     }
 
-     50% {
 
-       opacity: 0.5;
 
-       transform: scale(0.95);
 
-     }
 
-     100% {
 
-       opacity: 1;
 
-       transform: scale(1);
 
-     }
 
-   }
 
- </style>
 
- <script>
 
-   const qrModal = {
 
-     title: '',
 
-     dbInbound: new DBInbound(),
 
-     client: null,
 
-     qrcodes: [],
 
-     visible: false,
 
-     subId: '',
 
-     show: function (title = '', dbInbound, client) {
 
-       this.title = title;
 
-       this.dbInbound = dbInbound;
 
-       this.inbound = dbInbound.toInbound();
 
-       this.client = client;
 
-       this.subId = '';
 
-       this.qrcodes = [];
 
-       // Reset the status fetched flag when showing the modal
 
-       if (qrModalApp) qrModalApp.statusFetched = false;
 
-       if (this.inbound.protocol == Protocols.WIREGUARD) {
 
-         this.inbound.genInboundLinks(dbInbound.remark).split('\r\n').forEach((l, index) => {
 
-           this.qrcodes.push({
 
-             remark: "Peer " + (index + 1),
 
-             link: l,
 
-             useIPv4: false,
 
-             originalLink: l
 
-           });
 
-         });
 
-       } else {
 
-         this.inbound.genAllLinks(this.dbInbound.remark, app.remarkModel, client).forEach(l => {
 
-           this.qrcodes.push({
 
-             remark: l.remark,
 
-             link: l.link,
 
-             useIPv4: false,
 
-             originalLink: l.link
 
-           });
 
-         });
 
-       }
 
-       this.visible = true;
 
-     },
 
-     close: function () {
 
-       this.visible = false;
 
-     },
 
-   };
 
-   const qrModalApp = new Vue({
 
-     delimiters: ['[[', ']]'],
 
-     el: '#qrcode-modal',
 
-     mixins: [MediaQueryMixin],
 
-     data: {
 
-       qrModal: qrModal,
 
-       serverStatus: null,
 
-       statusFetched: false,
 
-     },
 
-     methods: {
 
-       async getStatus() {
 
-         try {
 
-           const msg = await HttpUtil.get('/panel/api/server/status');
 
-           if (msg.success) {
 
-             this.serverStatus = msg.obj;
 
-           }
 
-         } catch (e) {
 
-           console.error("Failed to get status:", e);
 
-         }
 
-       },
 
-       
 
-       toggleIPv4(index) {
 
-         const row = qrModal.qrcodes[index];
 
-         row.useIPv4 = !row.useIPv4;
 
-         this.updateLink(index);
 
-       },
 
-       updateLink(index) {
 
-         const row = qrModal.qrcodes[index];
 
-         if (!this.serverStatus || !this.serverStatus.publicIP) {
 
-           return;
 
-         }
 
-         
 
-         if (row.useIPv4 && this.serverStatus.publicIP.ipv4) {
 
-           // Replace the hostname or IP in the link with the IPv4 address
 
-           const originalLink = row.originalLink;
 
-           const url = new URL(originalLink);
 
-           const ipv4 = this.serverStatus.publicIP.ipv4;
 
-           
 
-           if (qrModal.inbound.protocol == Protocols.WIREGUARD) {
 
-             // Special handling for WireGuard config
 
-             const endpointRegex = /Endpoint = ([^:]+):(\d+)/;
 
-             const match = originalLink.match(endpointRegex);
 
-             if (match) {
 
-               row.link = originalLink.replace(
 
-                 `Endpoint = ${match[1]}:${match[2]}`,
 
-                 `Endpoint = ${ipv4}:${match[2]}`
 
-               );
 
-             }
 
-           } else {
 
-             // For other protocols using URL format
 
-             url.hostname = ipv4;
 
-             row.link = url.toString();
 
-           }
 
-         } else {
 
-           // Restore original link
 
-           row.link = row.originalLink;
 
-         }
 
-         
 
-         // Update QR code with transition effect
 
-         const canvasElement = document.querySelector('#qrCode-' + index);
 
-         if (canvasElement) {
 
-           // Add flash animation class
 
-           canvasElement.classList.add('qr-flash');
 
-           
 
-           // Remove the class after animation completes
 
-           setTimeout(() => {
 
-             canvasElement.classList.remove('qr-flash');
 
-           }, 600);
 
-         }
 
-         
 
-         this.setQrCode("qrCode-" + index, row.link);
 
-       },
 
-       copy(content) {
 
-         ClipboardManager
 
-           .copyText(content)
 
-           .then(() => {
 
-             app.$message.success('{{ i18n "copied" }}')
 
-           })
 
-       },
 
-       setQrCode(elementId, content) {
 
-         new QRious({
 
-           element: document.querySelector('#' + elementId),
 
-           size: 400,
 
-           value: content,
 
-           background: 'white',
 
-           backgroundAlpha: 0,
 
-           foreground: 'black',
 
-           padding: 2,
 
-           level: 'L'
 
-         });
 
-       },
 
-       genSubLink(subID) {
 
-         return app.subSettings.subURI + subID;
 
-       },
 
-       genSubJsonLink(subID) {
 
-         return app.subSettings.subJsonURI + subID;
 
-       },
 
-       revertOverflow() {
 
-         const elements = document.querySelectorAll(".qr-tag");
 
-         elements.forEach((element) => {
 
-           element.classList.remove("tr-marquee");
 
-           element.children[0].style.animation = '';
 
-           while (element.children.length > 1) {
 
-             element.removeChild(element.lastChild);
 
-           }
 
-         });
 
-       }
 
-     },
 
-     updated() {
 
-       if (this.qrModal.visible) {
 
-         fixOverflow();
 
-         if (!this.statusFetched) {
 
-           this.getStatus();
 
-           this.statusFetched = true;
 
-         }
 
-       } else {
 
-         this.revertOverflow();
 
-         // Reset the flag when modal is closed so it will fetch again next time
 
-         this.statusFetched = false;
 
-       }
 
-       if (qrModal.client && qrModal.client.subId) {
 
-         qrModal.subId = qrModal.client.subId;
 
-         this.setQrCode("qrCode-sub", this.genSubLink(qrModal.subId));
 
-         if (app.subSettings.subJsonEnable) {
 
-           this.setQrCode("qrCode-subJson", this.genSubJsonLink(qrModal.subId));
 
-         }
 
-       }
 
-       qrModal.qrcodes.forEach((element, index) => {
 
-         this.setQrCode("qrCode-" + index, element.link);
 
-         // Update links based on current toggle state
 
-         if (element.useIPv4 && this.serverStatus && this.serverStatus.publicIP) {
 
-           this.updateLink(index);
 
-         }
 
-       });
 
-     }
 
-   });
 
-   function fixOverflow() {
 
-     const elements = document.querySelectorAll(".qr-tag");
 
-     elements.forEach((element) => {
 
-       function isElementOverflowing(element) {
 
-         const overflowX = element.offsetWidth < element.scrollWidth,
 
-           overflowY = element.offsetHeight < element.scrollHeight;
 
-         return overflowX || overflowY;
 
-       }
 
-       function wrapContentsInMarquee(element) {
 
-         element.classList.add("tr-marquee");
 
-         element.children[0].style.animation = `move-ltr ${(element.children[0].clientWidth / element.clientWidth) * 5
 
-           }s ease-in-out infinite`;
 
-         const marqueeText = element.children[0];
 
-         if (element.children.length < 2) {
 
-           for (let i = 0; i < 1; i++) {
 
-             const marqueeText = element.children[0].cloneNode(true);
 
-             element.children[0].after(marqueeText);
 
-           }
 
-         }
 
-       }
 
-       if (isElementOverflowing(element)) {
 
-         wrapContentsInMarquee(element);
 
-       }
 
-     });
 
-   }
 
- </script>
 
- {{end}}
 
 
  |