简介
新版本哪吒面板0.18.14+
已支持后台的自定义脚本,以及由于新版本serverstatus
主题代码更新导致原前台脚本bug
,所以新开一个前后台脚本的整合帖。
更新日志
- 2024年09月03日
- 更新
后台脚本
修复可能无法获取到所需数据的bug
- 更新
- 2024年08月30日
- 更新
后台脚本
支持商家信息管理
- 更新
后台脚本
商家支持下拉选择
- 更新
- 2024年08月28日
- 修复
shop
为空时按钮链接的小bug - 优化
默认主题
进度条过短时到期日期
显示问题 - 增加默认启用
半透明效果
代码
- 修复
- 2024年08月20日
- 更新前台脚本过期时间进度条样式,尽量贴合原框架风格
其它说明
- 原贴《哪吒面板终极进化之VPS橱窗》不再更新
- 前台脚本特性及说明,暂请参考原贴,此帖不再赘述
- 原贴《油猴脚本:哪吒VPS橱窗后台脚本》及其中的油猴脚本不再更新,推荐使用新版本的后台自定义脚本。
- 后台脚本特性及说明,暂请参考原贴,此帖不再赘述
后台脚本特性
支持商家信息管理
、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>
效果图