新版本哪吒面板0.18.14+已支持后台的自定义脚本,以及由于新版本serverstatus主题代码更新导致原前台脚本bug,所以新开一个前后台脚本的整合帖。
更新日志
2024年09月03日
更新后台脚本修复可能无法获取到所需数据的bug
2024年08月30日
更新后台脚本支持商家信息管理
更新后台脚本商家支持下拉选择
2024年08月28日
修复shop为空时按钮链接的小bug
优化默认主题进度条过短时到期日期显示问题
增加默认启用半透明效果代码
2024年08月20日
更新前台脚本过期时间进度条样式,尽量贴合原框架风格
后台脚本特性
支持商家信息管理、VPS额外信息管理,将尽可能保证支持界面可视化操作,减少编辑脚本操作
前台脚本
<script> // 默认分组模式 if(!localStorage.getItem("showGroup")){ localStorage.setItem("showGroup", true); } // 默认暗黑模式 if(!localStorage.getItem("theme")){ localStorage.setItem("theme", 'dark'); } // 默认半透明效果 if(!localStorage.getItem("semiTransparent")){ localStorage.setItem("semiTransparent", 'true'); } window.onload = function(){ const affLinks = { crunchbits: 'https://get.crunchbits.com/order/lblk-yearly-kvm-ssd-vps/84', rainyun: 'https://www.rainyun.com/MjYzMTk=_', colocrossing: 'https://cloud.colocrossing.com/aff.php?aff=316', racknerd: 'https://my.racknerd.com/aff.php?aff=9727', } const contacts = { main: 'telegram', animatedType: 'vertical', telegram: { label: 'TG', icon: 'telegram plane', url: 'https://t.me/bmqyChatBot' }, qq: { label: 'QQ', icon: 'qq', url: 'https://wpa.qq.com/msgrd?V=3&Uin=88268459&Site=nezha.887776.xyz&menu=yes' }, email: { label: 'Email', icon: 'mail', url: 'mailto:notice@bmqy.net' }, } const extraData = { 2: { pid: 0, shop: 'crunchbits', price: '$27.38', cycle: 'Year', start: '08/13/2023', expire: '08/13/2024', autoPay: '否' }, 15: { pid: 0, shop: 'crunchbits', price: '$22.69', cycle: 'Year', start: '04/08/2024', expire: '04/08/2025', autoPay: '否' }, 10: { pid: 358, shop: 'racknerd', price: '$10.98', cycle: 'Year', start: '11/14/2023', expire: '11/14/2024', autoPay: '否' }, 12: { pid: 23, shop: 'colocrossing', price: '$10.00', cycle: 'Year', start: '02/13/2024', expire: '02/13/2025', autoPay: '否' }, 13: { pid: 0, shop: 'rainyun', price: '¥245', cycle: 'Year', start: '07/03/2023', expire: '08/09/2024', autoPay: '否' }, 14: { pid: 0, shop: 'rainyun', price: 'P5500', cycle: 'Month', start: '12/27/2023', expire: '∞', autoPay: '是' }, } const cycleNames = { '年付': 'year', '半年付': 'half', '季付': 'quarterly', '月付': 'month', '年': 'year', '半': 'half', '季': 'quarterly', '月': 'month', 'Year': 'year', 'Half': 'half', 'Quarterly': 'quarterly', 'Month': 'month', 'Y': 'year', 'H': 'half', 'Q': 'quarterly', 'M': 'month', 'year': 'year', 'half': 'half', 'quarterly': 'quarterly', 'month': 'month', } const cycleValues = { year: 365, half: 180, quarterly: 90, month: 30, } // 判断当前主题 const cookie = document.cookie; let preferredTheme = document.body.innerHTML.match(/(?<=defaultTemplate: ")(default|server-status)(?=")/g) ? document.body.innerHTML.match(/(?<=defaultTemplate: ")(default|server-status)(?=")/g)[0] : 'default'; preferredTheme = document.cookie.match(/(server-status|default)/g) ? document.cookie.match(/(server-status|default)/g)[0] : preferredTheme; // 默认主题 if(preferredTheme === 'default'){ const cats = document.querySelectorAll('.ui.accordion'); cats.forEach((e, i)=>{ let $catsTitle = e.querySelector('.title'); let ct = $catsTitle.innerText; ct = ct.trim(); let $itemCard = e.querySelectorAll('.ui.card'); let uiCardCount = $itemCard.length; $catsTitle.innerHTML = $catsTitle.innerHTML.replace(ct, ct+ ' ('+ uiCardCount +')'); $itemCard.forEach((ee, ii)=>{ let $content = ee.querySelector('.content'); let $descriptionGrid = ee.querySelector('.description .ui.grid'); let $itemTitle = $content.querySelector('.header'); let id = ee.getAttribute('id'); if(extraData[id]){ let pid = extraData[id].pid; pid = parseInt(pid); let shop = extraData[id].shop; let price = extraData[id].price; let start = extraData[id].start; let expire = extraData[id].expire; let cycle = extraData[id].cycle; let autoPay = extraData[id].autoPay; let cycleName = cycleNames[cycle]; let cycleValue = cycleValues[cycleName]; let nowTime = parseInt(new Date().getTime() / 1000); let beginTime = parseInt(new Date(start).getTime() / 1000); if(autoPay && autoPay=='是'){ let beginDate = new Date(start); let nowDate = new Date(); let mSteps = { year: 12, half: 6, quarterly: 3, month: 1, } expire = beginDate.setMonth(beginDate.getMonth() + mSteps[cycleName]); expire = new Date(expire); while(expire.getTime() < nowDate.getTime()){ expire = expire.setMonth(expire.getMonth() + mSteps[cycleName]); expire = new Date(expire); } expire = expire.toLocaleDateString(); } let endTime = parseInt(new Date(expire).getTime() / 1000); // 购买同款按钮 let $aButtonsBox = document.createElement('div'); $aButtonsBox.setAttribute('style', 'margin-bottom: .5em;text-align:right;'); let $aLinkButtons = document.createElement('div'); $aLinkButtons.setAttribute('class', 'btn-buy-box ui buttons mini'); let $aLinkBuy = document.createElement('a'); $aLinkBuy.setAttribute('class', 'ui btn-buy button positive'); $aLinkBuy.setAttribute('target', shop ? '_blank' : ''); $aLinkBuy.innerHTML = '购买同款'; $aLinkBuy.href = shop ? affLinks[shop] : 'javascript:void(0);'; if(pid){ $aLinkBuy.href += '&pid='+ pid; } if(price){ // 购买价格行 let $priceL = document.createElement('div'); $priceL.setAttribute('class', 'three wide column'); $priceL.innerHTML = '价格'; $descriptionGrid.insertBefore($priceL, $descriptionGrid.childNodes[$descriptionGrid.childNodes.length-3]); let $priceR = document.createElement('div'); $priceR.setAttribute('class', 'price-box thirteen wide column'); $priceR.innerHTML = '<div class="ui red label"><i class="money bill alternate yellow icon"></i>'+ price +'<a class="detail">'+ cycle +'</a></div>'; $descriptionGrid.insertBefore($priceR, $descriptionGrid.childNodes[$descriptionGrid.childNodes.length-3]) } if(expire){ // 到期日期行 let $expireL = document.createElement('div'); $expireL.setAttribute('class', 'three wide column'); $expireL.innerHTML = '到期'; $descriptionGrid.insertBefore($expireL, $descriptionGrid.childNodes[$descriptionGrid.childNodes.length-3]) // 到期日期行右侧进度条 let $expireR = document.createElement('div'); let aTime = (nowTime-beginTime); let bTime = (endTime-beginTime); let cTime = parseInt(aTime / bTime * 100); let progressType = 'red'; let textStyle = 'text-shadow: 0px 0px 5px #db2828;left:.5em;text-align: right;'; if(expire === '∞'){ progressType = 'success'; textStyle = ''; } $expireR.setAttribute('class', 'expire-box thirteen wide column'); $expireR.innerHTML = '<div class="ui indicating progress '+ progressType +' active"><div class="bar" style="line-height: 1em !important;transition-duration: 300ms; min-width: unset; width: '+ cTime +'% !important;padding-left: 0.4em;"><div class="progress" style="'+ textStyle +'">'+ expire +'</div></div></div>'; $descriptionGrid.insertBefore($expireR, $descriptionGrid.childNodes[$descriptionGrid.childNodes.length-3]) } $aLinkButtons.append($aLinkBuy); let $aLinkOr = document.createElement('div'); $aLinkOr.innerHTML = '<div class="or" data-text="or"></div>'; $aLinkButtons.append($aLinkOr); // 购买同款按钮右侧联系方式 let remainingAnimatedType = contacts['animatedType']; let priceValue = price.replace(/[$¥P€]/g, ''); let priceUnit = price.match(/[$¥P€]/g)[0]; let remainingDays = Math.floor((endTime - nowTime) / (24 * 60 * 60)); let remainingPrice = parseFloat(priceValue) / cycleValue * remainingDays; if(!remainingPrice){ remainingPrice = 0; } remainingPrice = remainingPrice.toFixed(2); let mainContact = contacts['main']; // 购买同款按钮右侧主要联系方式显示剩余价值 let $aLinkContactMain = document.createElement('a'); $aLinkContactMain.setAttribute('class', 'contact-main ui button '+ remainingAnimatedType +' animated blue'); $aLinkContactMain.setAttribute('target', '_blank'); $aLinkContactMain.innerHTML = '<div class="hidden content" style="padding:0;" title="剩余价值">'+ contacts[mainContact].label +'议价</div><div class="visible content" style="padding:0;" title="剩余价值"><i class="'+ contacts[mainContact].icon +' icon" style="color:white;"></i>'+ priceUnit + remainingPrice +'</div>'; $aLinkContactMain.href = contacts[mainContact].url; $aLinkButtons.append($aLinkContactMain); $aButtonsBox.append($aLinkButtons); // 购买同款按钮右侧其它联系方式 for(let key in contacts){ if(key!='main' && key!='animatedType' && key!=contacts['main']){ let icon = contacts[key].icon; let $aLinkContact = document.createElement('a'); $aLinkContact.setAttribute('class', 'contact-btn ui circular '+ icon +' mini icon button'); $aLinkContact.setAttribute('target', '_blank'); $aLinkContact.setAttribute('style', 'margin-left:.5em;'); $aLinkContact.innerHTML = '<i class="'+ icon +' icon"></i>'; $aLinkContact.href = contacts[key].url; $aButtonsBox.append($aLinkContact); } } $content.append($aButtonsBox); } }); }); } // ServerStatus主题 function bindToggleViewClick(){ let $toggleView = document.querySelector('aside.toolbox .toggleView') $toggleView && $toggleView.addEventListener('click', ()=>{ setTimeout(function(){ location.reload(); }, 0); }); } if(preferredTheme === 'server-status'){ bindToggleViewClick(); let $biThreeDots = document.querySelector('aside.toolbox .bi-three-dots'); $biThreeDots && $biThreeDots.addEventListener('click', ()=>{ bindToggleViewClick(); }); let $tables = document.querySelectorAll('.table.table-condensed'); $tables.forEach(e=>{ $tableTh = e.querySelector('.node-group-tag th'); $list = e.querySelectorAll('tr.accordion-toggle'); $tableTh && ($tableTh.innerText += '('+ $list.length +')'); let $head = e.querySelector('table.table-condensed thead').lastChild; let $servers = e.querySelector('#servers'); // 隐藏三列:系统、在线天数、负载 $head.querySelector('th.os').style.display = 'none'; $head.querySelector('th.uptime').style.display = 'none'; $head.querySelector('th.load').style.display = 'none'; // 添加三列 let $expireTh = document.createElement('th'); $expireTh.innerText = '到期 / 剩余价值'; $expireTh.setAttribute('class', 'node-cell expire center'); $head.insertBefore($expireTh, $head.childNodes[3]); let $buyTh = document.createElement('th'); $buyTh.innerText = '购买同款'; $buyTh.setAttribute('class', 'node-cell expire center'); $head.append($buyTh); let $contactTh = document.createElement('th'); $contactTh.innerText = '议价'; $contactTh.setAttribute('class', 'node-cell expire center'); $head.append($contactTh); $servers.querySelectorAll('tr.accordion-toggle').forEach(ee=>{ ee.querySelector('td.os').style.display = 'none'; ee.querySelector('td.uptime').style.display = 'none'; ee.querySelector('td.load').style.display = 'none'; let id = ee.getAttribute('id'); id = id.replace('r', ''); if(extraData[id]){ let pid = extraData[id].pid; pid = parseInt(pid); let shop = extraData[id].shop; let price = extraData[id].price; let start = extraData[id].start; let expire = extraData[id].expire; let cycle = extraData[id].cycle; let autoPay = extraData[id].autoPay; let cycleName = cycleNames[cycle]; let cycleValue = cycleValues[cycleName]; let nowTime = parseInt(new Date().getTime() / 1000); let beginTime = parseInt(new Date(start).getTime() / 1000); if(autoPay && autoPay=='是'){ let beginDate = new Date(start); let nowDate = new Date(); let mSteps = { year: 12, half: 6, quarterly: 3, month: 1, } expire = beginDate.setMonth(beginDate.getMonth() + mSteps[cycleName]); expire = new Date(expire); while(expire.getTime() < nowDate.getTime()){ expire = expire.setMonth(expire.getMonth() + mSteps[cycleName]); expire = new Date(expire); } expire = expire.toLocaleDateString(); } let endTime = parseInt(new Date(expire).getTime() / 1000); if(expire || price){ // 到期时间、剩余价值列 let $expireTd = document.createElement('td'); $expireTd.setAttribute('class', 'node-cell expire'); let aTime = (nowTime-beginTime); let bTime = (endTime-beginTime); let cTime = parseInt(aTime / bTime * 100); let progressType = 'danger'; if(expire === '∞'){ progressType = 'warning'; } let priceValue = price.replace(/[$¥P€]/g, ''); let priceUnit = price.match(/[$¥P€]/g)[0]; let remainingDays = Math.floor((endTime - nowTime) / (24 * 60 * 60)); let remainingPrice = parseFloat(priceValue) / cycleValue * remainingDays; if(!remainingPrice){ remainingPrice = 0; } remainingPrice = remainingPrice.toFixed(2); $expireTd.innerHTML = '<div class="progress progress-expire"><div class="progress-bar progress-bar-'+ progressType +' progress-bar-striped active" style="width: '+ cTime +'%;padding-right:5px;background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);"><small class="progress" style="white-space: nowrap;background-color: transparent !important;background-image: unset;">'+ expire +' / '+ priceUnit + remainingPrice +'</small></div></div>'; ee.insertBefore($expireTd, ee.childNodes[3]); } // 购买同款列 let $buyTd = document.createElement('td'); $buyTd.setAttribute('class', 'node-cell buy'); $buyTd.setAttribute('style', 'text-align:center;'); let $buyTdBtn = document.createElement('div'); $buyTdBtn.setAttribute('class', 'ui left labeled button'); let $buyTdBtnLabel = document.createElement('div'); $buyTdBtnLabel.setAttribute('class', 'ui basic label mini'); $buyTdBtnLabel.setAttribute('style', 'min-height: 20px;padding:0 .5em;height: 20px;font-weight:normal;line-height: 20px;font-size:.78571429rem;'); $buyTdBtnLabel.innerHTML = price +' / '+ cycle; $buyTdBtn.append($buyTdBtnLabel); let $buyTdBtnLabelIcon = document.createElement('a'); $buyTdBtnLabelIcon.setAttribute('class', 'ui icon button mini green'); $buyTdBtnLabelIcon.setAttribute('style', 'min-height: 20px;padding:0 .5em;height: 20px;line-height: 20px;'); $buyTdBtnLabelIcon.setAttribute('target', shop ? '_blank' : ''); $buyTdBtnLabelIcon.addEventListener('click', (e)=>{e.stopPropagation()}); $buyTdBtnLabelIcon.innerHTML = '<i class="shopping cart icon"></i>'; $buyTdBtnLabelIcon.href = shop ? affLinks[shop] : 'javascript:void(0);'; if(pid){ $buyTdBtnLabelIcon.href += '&pid='+ pid; } $buyTdBtn.append($buyTdBtnLabelIcon); $buyTd.append($buyTdBtn); ee.append($buyTd); // 联系方式列 let $contactTd = document.createElement('td'); $contactTd.setAttribute('class', 'node-cell contact'); $contactTd.setAttribute('style', 'text-align:center;white-space:nowrap;'); for(let key in contacts){ if(key!='main' && key!='animatedType'){ let $contactTdContactBtn = document.createElement('a'); let contactIcon = contacts[key].icon; $contactTdContactBtn.setAttribute('class', 'ui circular '+ contactIcon +' icon button mini blue'); $contactTdContactBtn.setAttribute('style', 'min-height: 20px;padding:0 .5em;height: 20px;line-height: 20px;'); $contactTdContactBtn.setAttribute('target', '_blank'); $contactTdContactBtn.addEventListener('click', (e)=>{e.stopPropagation()}); $contactTdContactBtn.innerHTML = '<i class="'+ contactIcon +' icon"></i>'; $contactTdContactBtn.href = contacts[key].url; $contactTd.append($contactTdContactBtn); } } ee.append($contactTd); } else { // 无附加信息时显示占位符 let $expireTd = document.createElement('td'); $expireTd.setAttribute('class', 'node-cell expire'); $expireTd.setAttribute('style', 'text-align:center;'); $expireTd.innerHTML = '-'; ee.insertBefore($expireTd, ee.childNodes[3]); let $buyTd = document.createElement('td'); $buyTd.setAttribute('class', 'node-cell buy'); $buyTd.setAttribute('style', 'text-align:center;'); $buyTd.innerHTML = '-'; ee.append($buyTd); let $contactTd = document.createElement('td'); $contactTd.setAttribute('class', 'node-cell contact'); $contactTd.setAttribute('style', 'text-align:center;'); $contactTd.innerHTML = '-'; ee.append($contactTd); } }); }); } } </script>
后台脚本
<script> window.onload = function(){ const storagePreKey = 'nzVpsChuChuangData.'; const storageSet = function(key, value){ key = `${storagePreKey}${key}`; localStorage.setItem(key, JSON.stringify(value)); } const storageGet = function(key, defaultValue){ key = `${storagePreKey}${key}`; return JSON.parse(localStorage.getItem(key)) || defaultValue; } const extraDataKeyName = { shop:"商家名称", pid: '产品ID', price:"购买价格", cycle: "付款周期", start: "购买日期", expire: "过期时间", autoPay: '自动续费', } const cycleOptions = [ '年付', '半年付', '季付', '月付', '年', '半', '季', '月', 'Year', 'Half', 'Quarterly', 'Month', 'Y', 'H', 'Q', 'M', 'year', 'half', 'quarterly', 'month', ]; const autoPayOptions = [ '否', '是' ]; let timmer = null; let changer = false; const pathname = location.pathname; const $footer = document.querySelector('.footer'); if(!$footer || $footer.innerText.indexOf('Powered by 哪吒监控')==-1) return false; let raw = storageGet('raw', ''); let affLinks = storageGet('affLinks', null); let extra = storageGet('extra', null); let isFirst = false; if(affLinks == null && extra== null){ isFirst = true; } if(pathname === '/setting'){ const $settingForm = document.forms.settingForm; let settingData = new FormData($settingForm); settingData = new URLSearchParams(settingData).toString(); storageSet('raw', settingData); const CustomCode = document.querySelector('textarea[name=CustomCode]').value; let CustomCodeValueAffLinks =CustomCode.match(/(?<=affLinks = )[\s\S]+(?=\n([\s\t]+)?const contacts)/g); let CustomCodeValueExtra =CustomCode.match(/(?<=extraData = )[\s\S]+(?=\n([\s\t]+)?const cycleNames)/g); if(!CustomCodeValueAffLinks || !CustomCodeValueExtra){ $.suiAlert({ title: '', description: '请检查是否已经添加《哪吒面板VPS橱窗脚本》,脚本可去:https://www.bmqy.net/2665.html,获取', type: 'error', time: '3', position: 'top-center', }); return false; } CustomCodeValueAffLinks = CustomCodeValueAffLinks ? CustomCodeValueAffLinks[0] : '{}'; CustomCodeValueAffLinks = CustomCodeValueAffLinks.replace(/([0-9a-zA-Z]+):\s?'/g, '"$1":"').replace(/'/g, '"').replace(/[\r\n]+/g, '').replace(/,}/g, '}'); affLinks = JSON.parse(CustomCodeValueAffLinks); storageSet('affLinks', affLinks); CustomCodeValueExtra = CustomCodeValueExtra ? CustomCodeValueExtra[0] : '{}'; CustomCodeValueExtra = CustomCodeValueExtra.replace(/([0-9a-zA-Z]+):/g, '"$1":').replace(/},\n}/g, '}\n}').replace(/'/g, '"').replace(/[\r\n]+/g, '').replace(/,}/g, '}'); extra = JSON.parse(CustomCodeValueExtra); storageSet('extra', extra); if(isFirst){ $.suiAlert({ title: '', description: 'VPS橱窗后台脚本数据获取成功,可以正常使用了。', type: 'success', time: '3', position: 'top-center', }); } else { $.suiAlert({ title: '', description: 'VPS橱窗后台脚本已重新获取数据。', type: 'success', time: '3', position: 'top-center', }); } } else { if(pathname !='/' && pathname !='/login' && (affLinks == null || extra == null)){ $.suiAlert({ title: '', description: '请先进入【设置】页面获取脚本所需数据!!!', type: 'warning', time: '3', position: 'top-center', }); return false; } if(pathname === '/server'){ createShopFormModal(affLinks); const $table = document.querySelector('table.table'); const $tableTr = $table.querySelectorAll('tbody tr'); $tableTr.forEach(e=>{ let $tds = e.querySelectorAll('td'); let id = $tds[1].innerText; id = id.replace(/\(\d+\)/g, ''); let $nameTd = $tds[2]; let $extraDataBox = document.createElement('div'); $extraDataBox.id = id; $extraDataBox.setAttribute('class', 'extra-box'); $extraDataBox.setAttribute('style', 'margin-top:10px;'); for(let key in extraDataKeyName){ let extraData = extra[id]; let $inputLabel = document.createElement('div'); $inputLabel.setAttribute('style', 'white-space: nowrap;padding-bottom:3px;'); let requiredTag = ''; if(['price', 'cycle', 'start'].indexOf(key) > -1){ requiredTag = '*'; } $inputLabel.innerHTML = '<span style="display:inline-block;width:70px;">'+ requiredTag + extraDataKeyName[key] +':</span>'; let $input = document.createElement('input'); if(key === 'pid'){ $input.placeholder = '商家所售产品ID'; } else if(['start', 'expire'].indexOf(key) > -1){ $input.placeholder = '月/日/年'; } else if(key === 'price'){ $input.placeholder = '支持:$、¥、€、P'; } if(['shop', 'cycle', 'autoPay'].indexOf(key) > -1){ $input = document.createElement('select'); if(key === 'shop'){ $input.options.add(new Option('请选择', '')); for(let key in affLinks){ $input.options.add(new Option(key, key)); } } if(key === 'cycle'){ for(let key in cycleOptions){ $input.options.add(new Option(cycleOptions[key], cycleOptions[key])); } } if(key === 'autoPay'){ for(let key in autoPayOptions){ $input.options.add(new Option(autoPayOptions[key], autoPayOptions[key])); } } } $input.name = key; if(extraData){ $input.value = extraData[key] ? extraData[key] : ''; } $input.addEventListener('change', ()=>{ changer = true; if(timmer) return false; console.log('1s 后提交'); timmer = setTimeout(function(){ updateExtraData(); }, 1500); }); $input.addEventListener('focus', ()=>{ if(timmer){ console.log('终断提交'); clearTimeout(timmer); timmer = null; } }); $input.addEventListener('blur', ()=>{ if(timmer) return false; if(changer){ console.log('1s 后提交'); timmer = setTimeout(function(){ updateExtraData(); }, 1500); } }); $inputLabel.append($input); if(key === 'shop'){ let $addShopBtn = document.createElement('button'); $addShopBtn.title = '管理商家信息'; $addShopBtn.setAttribute('class', 'ui icon button mini'); $addShopBtn.setAttribute('style', 'margin-left:5px;'); $addShopBtn.innerHTML = '<i class="icon setting"></i>'; $addShopBtn.addEventListener('click', managerShoopFormModal); $inputLabel.append($addShopBtn); } $extraDataBox.append($inputLabel); } $nameTd.append($extraDataBox); }) } } function updateExtraData(){ let paramsRaw = new URLSearchParams(raw); let customCodeOld = paramsRaw.get('CustomCode'); let $extraBox = document.querySelectorAll('table.table .extra-box'); let extraNew = {}; $extraBox.forEach(e=>{ let shop = e.querySelector('select[name=shop]').value, pid = e.querySelector('input[name=pid]').value, price = e.querySelector('input[name=price]').value, cycle = e.querySelector('select[name=cycle]').value, start = e.querySelector('input[name=start]').value, expire = e.querySelector('input[name=expire]').value, autoPay = e.querySelector('select[name=autoPay]').value; if(price && cycle && start){ extraNew[e.id] = { shop: shop, pid: pid, price: price, cycle: cycle, start: start, expire: expire, autoPay: autoPay, } } }); storageSet('extra', extraNew); let customCodeNew = customCodeOld.replace(/(?<=extraData = )[\s\S]+(?=\n[\s\t]*const cycleNames)/g, JSON.stringify(extraNew)); paramsRaw.set('CustomCode', customCodeNew); $.post('/api/setting', paramsRaw.toString()).then(res=>{ if(res.code == 200){ $.suiAlert({ title: '', description: 'VPS橱窗前台脚本更新成功。', type: 'success', time: '3', position: 'top-center', }); } else { $.suiAlert({ title: '', description: responses.responseText, type: 'error', time: '3', position: 'top-center', }); } }).catch(err=>{ $.suiAlert({ title: '', description: JSON.stringify(err), type: 'error', time: '3', position: 'top-center', }); }).always(()=>{ clearTimeout(timmer); timmer = null; changer = false; }) } function managerShoopFormModal(){ showOnSubmitFormModal(".shopForm.modal", "#shopForm", "/api/setting", getShopData); } function getShopData(){ let paramsRaw = new URLSearchParams(raw); let customCodeOld = paramsRaw.get('CustomCode'); let affLinks = storageGet('affLinks', null); let customCodeNew = customCodeOld.replace(/(?<=affLinks = )[\s\S]+(?=\n[\s\t]*const contacts)/g, JSON.stringify(affLinks)); paramsRaw.set('CustomCode', customCodeNew); return paramsRaw.toString(); } function updateShopData(){ let $shopForm = document.querySelector('#shopForm'); let data = {}; let emptyCount = 0; for(let i=0; i<$shopForm.elements.length; i+=2){ let $name = $shopForm.elements[i]; let $url = $shopForm.elements[i+1]; if($name.value && $url.value){ data[$name.value] = $url.value; storageSet('affLinks', data); if(i == $shopForm.elements.length-2){ createShopFormModal(data); } } else { emptyCount += 1; } } if(emptyCount > 1){ createShopFormModal(data); } } function createInput(name, value){ let $input = document.createElement('input'); $input.type = 'text'; $input.name = name; $input.setAttribute('value', value || ''); $input.placeholder = name==='name' ? '名称' : '邀请链接'; $input.addEventListener('blur', updateShopData); return $input; } function createShopFormModal(affLinks){ let $shopFormModal = document.querySelector('#shopFormModal'); let isFirst = true; if(!$shopFormModal){ $shopFormModal = document.createElement('div'); $shopFormModal.id = 'shopFormModal'; $shopFormModal.setAttribute('class', 'ui tiny shopForm modal transition hidden'); } else { isFirst = false; $shopFormModal.innerHTML = ''; } let $shopForm = document.createElement('form'); $shopForm.id = 'shopForm'; $shopForm.setAttribute('class', 'ui form'); for(let key in affLinks){ let $shopFormField = document.createElement('div'); let $shopFormGrid = document.createElement('div'); $shopFormGrid.setAttribute('class', 'ui grid'); let $shopFormGridItem = document.createElement('div'); $shopFormGridItem.setAttribute('class', 'four wide column'); $shopFormGridItem.append(createInput('name', key)); $shopFormGrid.append($shopFormGridItem); $shopFormGridItem = document.createElement('div'); $shopFormGridItem.setAttribute('class', 'twelve wide column'); $shopFormGridItem.append(createInput('url', affLinks[key])); $shopFormGrid.append($shopFormGridItem); $shopFormField.append($shopFormGrid); $shopForm.append($shopFormField); } let $shopFormField = document.createElement('div'); let $shopFormGrid = document.createElement('div'); $shopFormGrid.setAttribute('class', 'ui grid'); let $shopFormGridItem = document.createElement('div'); $shopFormGridItem = document.createElement('div'); $shopFormGridItem.setAttribute('class', 'four wide column'); $shopFormGridItem.append(createInput('name', '')); $shopFormGrid.append($shopFormGridItem); $shopFormGridItem = document.createElement('div'); $shopFormGridItem.setAttribute('class', 'twelve wide column'); $shopFormGridItem.append(createInput('url', '')); $shopFormGrid.append($shopFormGridItem); $shopFormField.append($shopFormGrid); $shopForm.append($shopFormField); let $shopFormModalHead = document.createElement('div'); $shopFormModalHead.setAttribute('class', 'header'); $shopFormModalHead.innerHTML = 'VPS橱窗商家信息管理'; $shopFormModal.append($shopFormModalHead); let $shopFormModalContent = document.createElement('div'); $shopFormModalContent.setAttribute('class', 'content'); $shopFormModalContent.append($shopForm); $shopFormModal.append($shopFormModalContent); let $shopFormModalActions = document.createElement('div'); $shopFormModalActions.setAttribute('class', 'actions'); let $shopFormModalActionsCancelBtn = document.createElement('div'); $shopFormModalActionsCancelBtn.setAttribute('class', 'ui negative button'); $shopFormModalActionsCancelBtn.innerHTML = '取消'; $shopFormModalActions.append($shopFormModalActionsCancelBtn); let $shopFormModalActionsConfirmBtn = document.createElement('div'); $shopFormModalActionsConfirmBtn.setAttribute('class', 'ui positive nezha-primary-btn right labeled icon button vps-window-btn'); $shopFormModalActionsConfirmBtn.innerHTML = '确认<i class="checkmark icon"></i>'; $shopFormModalActions.append($shopFormModalActionsConfirmBtn); $shopFormModal.append($shopFormModalActions); isFirst && document.body.append($shopFormModal); } function showOnSubmitFormModal(modelSelector, formID, URL, getData) { $(modelSelector) .modal({ closable: true, onApprove: function () { let success = false; const btn = $(modelSelector + " .vps-window-btn.button"); const form = $(modelSelector + " form"); if (btn.hasClass("loading")) { return success; } form.children(".message").remove(); btn.toggleClass("loading"); const data = getData ? getData() : $(formID) .serializeArray() .reduce(function (obj, item) { // ID 类的数据 if (item.name === "pid") { obj[item.name] = parseInt(item.value); } else { obj[item.name] = item.value; } return obj; }, {}); $.post(URL, data) .done(function (resp) { if (resp.code == 200) { window.location.reload() } else { form.append( `<div class="ui negative message"><div class="header">操作失败</div><p>` + resp.message + `</p></div>` ); } }) .fail(function (err) { form.append( `<div class="ui negative message"><div class="header">网络错误</div><p>` + err.responseText + `</p></div>` ); }) .always(function () { btn.toggleClass("loading"); }); return success; }, }) .modal("show"); } } </script>
效果图