feat: 后端全量更新 - 含所有本次需求

- Contract.php: 返回合约账户余额(balance_contract)
- My.php: 地址管理增加BTC/ETH
- AppContract.php: 一键平仓(closeall)
- AppProxy.php: 代理专属注册链接 + 分级权限(L1/L2)
- site.php: 手续费减半(0.018→0.009)
- agent_permission_setup.sql: 代理权限SQL
- crypto_news_crawler.py: 新闻自动采集脚本
This commit is contained in:
li
2026-03-30 20:16:32 +08:00
commit 1b24994e74
6721 changed files with 1308571 additions and 0 deletions
+320
View File
@@ -0,0 +1,320 @@
define(['jquery', 'bootstrap', 'backend', 'form', 'template', 'loading'], function($, undefined, Backend, Form, Template, Loading) {
var Controller = {
index: function() {
Controller.api.events.toolbar();
Controller.init.table();
},
add: function() {
Controller.init.selectpicker();
Controller.api.form();
},
edit: function() {
Controller.init.selectpicker(true);
Controller.api.form();
},
init: {
selectpicker: function(disabled = false) {
$('#sType').on('loaded.bs.select , changed.bs.select', function(e, clickedIndex, isSelected, previousValue) {
var id = $('#id').val();
var sType = $(this).selectpicker('val');
$('#sTypeDom').hide();
$('.rememory').hide();
$('.urladdress').hide();
$('.sbody').hide();
switch (sType) {
case 'toShell':
$('.sbody').show().find('textarea').attr('placeholder', '');
$('#sBodyTitle').html('脚本内容:');
break;
case 'site':
Controller.init.toBackup(sType);
$('.sbody').show().find('textarea').attr('placeholder', '每行一条规则,目录不能以/结尾,示例:\ndata/config.php\nstatic/upload\n *.log\n').text();
$('#sBodyTitle').html('排除规则:');
break;
case 'database':
Controller.init.toBackup(sType);
break;
case 'logs':
Controller.init.toBackup(sType);
break;
case 'path':
Controller.init.toBackup(sType);
$('.sbody').show().find('textarea').attr('placeholder', '每行一条规则,目录不能以/结尾,示例:\ndata/config.php\nstatic/upload\n *.log\n').text();
$('#sBodyTitle').html('排除规则:');
break;
case 'rememory':
$('.rememory').show();
break;
case 'toUrl':
$('.urladdress').show();
break;
case 'syncTime':
$(this).selectpicker('val', 'toShell');
$(this).selectpicker('refresh');
$('.sbody').show().find('textarea').text('echo "|-正在尝试从0.pool.bt.cn同步时间..";\n\
ntpdate -u 0.pool.bt.cn\n\
if [ $? = 1 ];then\n\
echo "|-正在尝试从1.pool.bt.cn同步时间..";\n\
ntpdate -u 1.pool.bt.cn\n\
fi\n\
if [ $? = 1 ];then\n\
echo "|-正在尝试从0.asia.pool.ntp.org同步时间..";\n\
ntpdate -u 0.asia.pool.ntp.org\n\
fi\n\
if [ $? = 1 ];then\n\
echo "|-正在尝试从www.bt.cn同步时间..";\n\
getBtTime=$(curl -sS --connect-timeout 3 -m 60 http://www.bt.cn/api/index/get_time)\n\
if [ "${getBtTime}" ];then \n\
date -s "$(date -d @$getBtTime +"%Y-%m-%d %H:%M:%S")"\n\
fi\n\
fi\n\
echo "|-正在尝试将当前系统时间写入硬件..";\n\
hwclock -w\n\
date\n\
echo "|-时间同步完成!";');
break;
default:
break;
}
if (disabled) {
$(this).prop('disabled', true);
$(this).selectpicker('refresh');
}
});
$('#type').on('loaded.bs.select , changed.bs.select', function(e, clickedIndex, isSelected, previousValue) {
var type = $(this).selectpicker('val');
$('#whereDom').html(Template(type + "-tpl", {}));
if (type == 'week') $('#whereDom').find('.selectpicker').selectpicker('refresh');
});
},
toBackup: function(sType = '') {
$.ajax({
type: "POST",
url: "btpanel/ajax/getDataList",
data: { type: sType == 'database' ? 'databases' : 'sites' },
dataType: "JSON",
success: function(res) {
res.data.unshift({ name: '所有', ps: 'ALL' });
res.orderOpt.unshift({ name: '服务器磁盘', value: 'localhost' });
res.title = Config.crontab['sTypeArray'][sType];
var html;
if (sType == 'path') {
html = Template("sTypePathTpl", res);
} else {
html = Template("sTypeSiteTpl", res);
}
$('#sTypeDom').html(html);
$('#sTypeDom').show();
$('#sTypeDom').find('.selectpicker').selectpicker('refresh');
}
});
},
table: function() {
$('table').loading();
$.ajax({
type: "POST",
url: "btpanel/ajax/getCrontab",
dataType: "JSON",
success: function(rdata) {
if (rdata == []) {
$('table').loading('hide');
var html = Template("<tr><td colspan='6'>暂无数据</td></tr>", {});
$('#table-crontab').html(html);
} else {
$.post('btpanel/ajax/getDataList', {}, function(res) {
for (var i = 0; i < rdata.length; i++) {
for (var j = 0; j < res.orderOpt.length; j++) {
if (rdata[i].backupTo == 'localhost') {
rdata[i].backupTo = '本地磁盘';
} else if (rdata[i].backupTo == res.orderOpt[j].value) {
rdata[i].backupTo = res.orderOpt[j].name;
} else if (rdata[i].backupTo == '') {
rdata[i].backupTo = ''
}
}
var arrs = ['site', 'database', 'path'];
if ($.inArray(rdata[i].sType, arrs) == -1) rdata[i].backupTo = "--";
}
$('table').loading('hide');
var html = Template('crontabtpl', { data: rdata });
$('#table-crontab').html(html);
//绑定各种事件
Controller.api.events.startTask();
Controller.api.events.getLogs();
Controller.api.events.delCrontab();
Controller.api.events.getCrontabFind();
Controller.api.events.setTaskStatus();
});
}
}
});
},
},
api: {
events: {
delCrontab: function() {
$('.btn-del').click(function() {
var id = $(this).parent().data('id');
var title = $(this).parent().siblings('td[data-field="name"]').html();
var confirm = Layer.confirm('是否要删除【' + title + '】?', { title: '提示', icon: 3 }, function(index) {
if (index > 0) {
var loadT = Layer.msg('正在删除,请稍后...', { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('btpanel/ajax/delCrontab', { id: id }, function(rdata) {
Layer.closeAll();
Layer.close(confirm);
Layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
if (rdata.status) Controller.init.table();
});
}
});
})
},
toolbar: function() {
$('.btn-refresh').click(function() {
Controller.init.table();
})
$('.btn-add').click(function() {
Fast.api.open('btpanel/crontab/add?', '新增定时任务', {
callback: function(data) {
Controller.init.table();
}
})
})
},
// 编辑计划任务
getCrontabFind: function() {
$('.btn-edit').click(function() {
var id = $(this).parent().data('id');
var title = $(this).parent().siblings('td[data-field="name"]').html();
Fast.api.open('btpanel/crontab/edit?id=' + id, '【' + title + '】编辑', {
callback: function(data) {
Controller.init.table();
}
})
})
},
//执行任务脚本
startTask: function() {
$('.btn-StartTask').click(function() {
var id = $(this).parent().data('id');
var title = $(this).parent().siblings('td[data-field="name"]').html();
var confirm = Layer.confirm('是否要立即执行【' + title + '】?', { title: '提示', icon: 3 }, function(index) {
if (index > 0) {
var loadT = Layer.msg('正在执行,请稍后...', { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('btpanel/ajax/startTask', { id: id }, function(rdata) {
Layer.closeAll();
Layer.close(confirm);
Layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
});
})
},
getLogs: function() {
$('.btn-GetLogs').click(function() {
$('table').loading();
var id = $(this).parent().data('id');
var title = $(this).parent().siblings('td[data-field="name"]').html();
$.post('btpanel/ajax/GetLogs', { id: id, type: 'crontab' }, function(rdata) {
$('table').loading('hide');
if (!rdata.status) {
Layer.msg(rdata.msg, { icon: 2 });
return;
};
Layer.open({
id: 'logs',
type: 1,
title: '【' + title + '】日志',
shadeClose: false,
btn: ['清空', '关闭'],
yes: function(index, layero) {
var confirm = Layer.confirm('是否要清空【' + title + '】的日志?', { title: '提示', icon: 3 }, function(index) {
if (index > 0) {
var loadT = Layer.msg('正在执行,请稍后...', { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('btpanel/ajax/delLogs', { id: id }, function(rdata) {
Layer.closeAll();
Layer.close(confirm);
Layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
});
},
area: ['800px', '600px'], //宽高
content: '<pre id="editor" style="overflow: auto; border: 0px none; line-height:23px;padding: 15px; margin: 0px; white-space: pre-wrap; height: 558px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0px;font-family: \"微软雅黑\"">' + (rdata.msg == '' ? '当前日志为空' : rdata.msg) + '</pre>',
success: function() {
var scrollHeight = $('#editor').prop("scrollHeight");
$('#editor').animate({ scrollTop: scrollHeight }, 200);
}
});
});
})
},
setTaskStatus: function() {
$('.set_task_status').off('click').on('click', function() {
var id = $(this).data('id');
var status = $(this).children('span').data('status');
var title = $(this).parent().siblings('td[data-field="name"]').html();
var confirm = Layer.confirm(status == '0' ? '计划任务暂停后将无法继续运行,您真的要停用【' + title + '】吗?' : '该计划任务已停用,是否要启用【' + title + '】', { title: '提示', icon: 3 }, function(index) {
if (index > 0) {
var loadT = Layer.msg('正在设置状态,请稍后...', { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('btpanel/ajax/setCronStatus', { id: id }, function(rdata) {
Layer.closeAll();
Layer.close(confirm);
Layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
if (rdata.status) Controller.init.table();
});
}
});
})
}
},
form: function() {
Form.api.bindevent($("form[role=form]"), null, null, function(success, error) {
var form = {
id: '',
name: '',
type: '',
where1: '',
hour: '',
minute: '',
week: '',
sType: '',
sBody: '',
sName: '',
backupTo: '',
save: '',
urladdress: '',
}
$('input[class="form-control"],textarea[class="form-control"],select[class="form-control selectpicker"]').each(function(i, element) {
element == this
var name = $(element).attr('name');
var value = $(element).val();
if (form.hasOwnProperty(name)) {
form[name] = value;
}
});
$.ajax({
type: "POST",
url: $(this).attr('action'),
data: form,
dataType: "JSON",
success: function(ret) {
var index = parent.Layer.getFrameIndex(window.name);
parent.Layer.close(index);
parent.Layer.msg(ret.msg, { icon: ret.status ? 1 : 2 });
Fast.api.close(ret)
}
});
return false;
});
}
}
};
return Controller;
});
+412
View File
@@ -0,0 +1,412 @@
define(['jquery', 'bootstrap', 'backend', 'form', 'table', 'echarts', 'template', 'knob','loading'], function($, undefined, Backend, Form, Table, Echarts, Template,Loading) {
var network, isInit = true;
var rate = 2000;
var lineChart = [];
var Controller = {
index: function() {
Controller.init.knob();
Controller.init.table();
$(document).loading();
var height = $('.panel-ServerInfo .panel-body').height()-65;
$('.panel-liveLine .tab-pane').height(height + 'px');
/* shown.bs.tab为tab选项卡高亮 */
$('#liveLine a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
lineChart[$(this).data('chart')].resize();
});
Controller.module.net.chart.init(height - $('#net-info').height()-10);
Controller.module.cpu.chart.init(height);
setInterval(function() {
$.ajax({
type: "Post",
url: "btpanel/ajax/getNetWork",
dataType: "json",
success: function(res) {
network = res;
Controller.module.cpu.value(res.cpu);
Controller.module.load.value(res.load);
Controller.module.memory.value(res.mem);
Controller.module.disk.value(res.disk);
Controller.module.net.value(res.up, res.down, res.upTotal, res.downTotal);
if (isInit) {
isInit = false;
$(document).loading('hide');
Controller.init.event();
}
}
});
}, rate);
},
init: {
table: function() {
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: 'btpanel/ajax/getSiteData',
pk: 'id',
sort:'id',
pagination: false,
columns: [
[
{ field: 'id', title: 'ID'},
{ field: 'name', title: '网站名',formatter: Controller.api.table.formatter.name},
{ field: 'path', title: '根目录' },
{ field: 'backup_count', title: '备份' },
{ field: 'addtime', title: '创建时间' },
{ field: 'edate', title: '到期时间' },
{ field: 'status', title: '状态', formatter: Controller.api.table.formatter.status },
{ field: 'ps', title: '备注' }
]
]
});
$('#siteType').change(function (e) {
e.preventDefault();
table.bootstrapTable('refresh',{
url: 'btpanel/index/getSiteData?type='+$('#siteType option:selected').val()
});
});
// 为表格绑定事件
Table.api.bindevent(table);
},
knob: function() {
$(".knob").knob({
'fgColor': "#3c8dbc",
'readOnly': true,
'step': 0.1,
'height': '100px',
format: function(v) {
return v + '%';
},
release: function(v) {
$('.knob').attr('type', 'text');
}
});
},
event: function() {
Controller.module.cpu.hover();
Controller.module.load.hover();
Controller.module.memory.hover();
Controller.module.disk.hover();
}
},
module: {
cpu: {
value: function(data) {
$('.knob-cpu').val(data[0]).trigger('change');
Controller.api.echarts.addData(lineChart['cpu'], [data[0]]);
},
hover: function(data) {
$('#panel-cpu').hover(function() {
var d = network.cpu;
if (d) {
var _this = $(this);
var crs = '';
var n1 = 0;
for (var i = 0; i < d[2].length; i++) {
n1++;
crs += 'CPU-' + i + ": " + d[2][i] + '%' + (n1 % 2 == 0 ? '</br>' : ' | ');
}
layer.tips(d[3] + "</br>" + d[5] + "个物理CPU," + (d[5] * d[4]) + "个物理核心," + d[1] + "线程</br>" + crs, _this.find('.knob-cpu'), { time: 0, tips: [3, '#999'] });
}
}, function() {
layer.closeAll('tips');
});
},
chart: {
init: function(height) {
// 基于准备好的dom,初始化echarts实例
$('#chart-cpu').height(height)
var Chart = Echarts.init(document.getElementById('chart-cpu'), 'walden');
var obj = {};
obj.dataZoom = [];
obj.unit = '百分比';
obj.dataset = {
dimensions: ['时间', 'CPU'],
source: []
};
obj.series = [{
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: '#52a9ff' } },
areaStyle: { opacity: 0.5 }
}];
var option = Controller.api.echarts.getOptions(obj);
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
lineChart['cpu'] = Chart;
return Chart;
},
}
},
load: {
value: function(data) {
var _lval = Math.round((data.one / data.max) * 100);
if (_lval > 100) _lval = 100;
$('.knob-load').val(_lval).trigger('change');
},
hover: function() {
$('#panel-load').hover(function() {
var _this = $(this);
var d = network.load;
layer.tips('最近1分钟平均负载:' + d.one + '</br>最近5分钟平均负载:' + d.five + '</br>最近15分钟平均负载:' + d.fifteen + '', _this.find('.knob-load'), { time: 0, tips: [3, '#999'] });
}, function() {
layer.closeAll('tips');
})
}
},
memory: {
value: function(data) {
var _memory = (data.memRealUsed * 100 / data.memTotal).toFixed(1)
$('.knob-memory').val(_memory).trigger('change');
},
hover: function() {
$('#panel-memory').hover(function() {
var _this = $(this);
var d = network.mem;
var tips = '总大小:' + d.memTotal + '<br>' +
'可用的物理内存: ' + d.memFree + ' MB<br>' +
'已使用的物理内存: ' + d.memRealUsed + ' MB<br>' +
'缓存化内存: ' + d.memCached + ' MB<br>' +
'系统缓冲: ' + d.memBuffers + ' MB';
layer.tips(tips, _this.find('.knob-memory'), { time: 0, tips: [3, '#999'] });
}, function() {
layer.closeAll('tips');
})
}
},
disk: {
value: function(data) {
if (data.length > 0) {
var size = data[0].size[3];
$('.knob-disk').val(size.replace('%', '')).trigger('change');
}
},
hover: function() {
$('#panel-disk').hover(function() {
var _this = $(this);
var d = network.disk;
var tips = '';
$.each(d, function(index, item) {
tips += '<b>基础信息</b><br>' +
'文件系统:' + item.filesystem + '<br>' +
'类型:' + item.type + '<br>' +
'挂载点:' + item.path + '<br>' +
'<b>Inode信息</b><br>' +
'总数:' + item.inodes[0] + '<br>' +
'已用:' + item.inodes[1] + '<br>' +
'可用:' + item.inodes[2] + '<br>' +
'Inode使用率:' + item.inodes[3] + '<br>' +
'<b>容量信息</b><br>' +
'容量:' + item.size[0] + '<br>' +
'已用:' + item.size[1] + '<br>' +
'可用:' + item.size[2] + '<br>' +
'使用率:' + item.size[3];
});
layer.tips(tips, _this.find('.knob-disk'), { time: 0, tips: [3, '#999'] });
}, function() {
layer.closeAll('tips');
})
}
},
net: {
value: function(up, down, upTotal, downTotal) {
$('#upSpeed').html(up + ' KB');
$('#downSpeed').html(down + ' KB');
$('#upAll').html(Controller.api.formatBytes(upTotal, 2));
$('#downAll').html(Controller.api.formatBytes(downTotal, 2));
Controller.api.echarts.addData(lineChart['net'], [up, down]);
},
chart: {
init: function(height) {
// 基于准备好的dom,初始化echarts实例
$('#chart-net').height(height)
var Chart = Echarts.init(document.getElementById('chart-net'), 'walden');
var obj = {};
obj.dataZoom = [];
obj.unit = '单位:KB/s';
obj.dataset = {
dimensions: ['时间', '上行', '下行'],
source: []
};
obj.series = [{
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: '#f7b851' } },
areaStyle: { opacity: 0.5 }
}, {
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: '#52a9ff' } },
areaStyle: { opacity: 0.5 }
}];
var option = Controller.api.echarts.getOptions(obj);
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
lineChart['net'] = Chart;
return Chart;
},
}
}
},
api: {
echarts: {
getOptions(obj) {
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: obj.formatter
},
dataset: obj.dataset,
xAxis: {
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: "#666"
}
}
},
grid: {
left: '5%',
right: '5%',
bottom: '10%',
top: '10%'
},
yAxis: {
type: 'value',
name: obj.unit,
boundaryGap: [0, '100%'],
min: 0,
splitLine: {
lineStyle: {
color: "#ddd"
}
},
axisLine: {
lineStyle: {
color: "#666"
}
}
},
dataZoom: [{
type: 'inside',
start: 0,
zoomLock: true
}, {
start: 0,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: []
};
if (obj.legend) option.legend = obj.legend;
if (obj.dataZoom) option.dataZoom = obj.dataZoom;
for (var i = 0; i < obj.series.length; i++) {
var item = obj.series[i];
var series = {
type: item.type ? item.type : 'line',
smooth: item.smooth ? item.smooth : true,
symbol: item.symbol ? item.symbol : 'none',
showSymbol: item.showSymbol ? item.showSymbol : false,
sampling: item.sampling ? item.sampling : 'average',
areaStyle: item.areaStyle ? item.areaStyle : {},
lineStyle: item.lineStyle ? item.lineStyle : {},
itemStyle: item.itemStyle ? item.itemStyle : { normal: { color: 'rgb(0, 153, 238)' } },
symbolSize: 6,
symbol: 'none'
}
option.series.push(series);
}
return option;
},
addData: function(chart, arr, limit = 300) {
var option = chart.getOption();
var data = option.dataset[0].source;
var now = new Date();
var time = [now.getHours(), now.getMinutes() + 1, now.getSeconds()].join(':');
var newData = [time];
newData = newData.concat(arr)
data.push(newData);
if (limit && data.length > limit / (rate / 1000)) {
data.shift();
}
chart.setOption({
dataset: {
source: data
}
});
}
},
table: {
formatter: {
name: function(value, row, index) {
$.ajax({
type: "POST",
url: "btpanel/ajax/getWebSiteDomain",
data: {
id:row.id
},
async: false,
dataType: "json",
success: function (res) {
$.each(res, function (i, domain) {
if(document.domain == domain.name){
value = domain.name+' <span class="label label-success">当前站点</span>';
}
});
}
});
return value
},
status: function(value, row, index) {
var color = value == '1' ? 'text-green' : 'text-red';
var icon = value == '1' ? 'fa-play' : 'fa-pause';
var text = value == '1' ? '运行中' : '已停止';
return "<span class="+color+">"+text+"<i class='fa fa-fw " + icon + "'></i></span>"
}
}
},
formatBytes: function(a, b) {
if (0 == a) return "0 Bytes";
var c = 1024,
d = b || 2,
e = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
f = Math.floor(Math.log(a) / Math.log(c));
return parseFloat((a / Math.pow(c, f)).toFixed(d)) + " " + e[f]
},
bindevent: function() {
Form.api.bindevent($("form[role=form]"));
},
}
};
return Controller;
});
+53
View File
@@ -0,0 +1,53 @@
define(['jquery', 'bootstrap', 'backend', 'template'], function($, undefined, Backend, Template) {
var Controller = {
index: function() {
window.navPages = function(page){
Controller.init.table(page);
};
Controller.init.table(1);
Controller.api.events.panelErrorLogs();
},
init:{
table: function(page) {
$.ajax({
type: "POST",
url: "btpanel/ajax/getLogs",
data: {
limit:20,
p:page,
tojs:$('#table-page').data('events')
},
dataType: "JSON",
success: function (res) {
var html = Template('logstpl', res);
$('#table-logs').html(html);
$('#table-page').html(res.page);
}
});
},
},
api: {
events:{
panelErrorLogs:function(){
$('.label-run-logs').click(function(){
$.ajax({
type: "POST",
url: "btpanel/ajax/getPanelErrorLogs",
dataType: "JSON",
success: function (res) {
Layer.open({
type: 1,
title:false,
area: ['800px', '600px'], //宽高
content: '<pre id="editor" style="overflow: auto; border: 0px none; line-height:23px;padding: 15px; margin: 0px; white-space: pre-wrap; height: 600px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0px;font-family: \"微软雅黑\"">' + (res.msg == '' ? '当前日志为空' : res.msg) + '</pre>'
});
}
});
});
}
}
}
};
return Controller;
});
+647
View File
@@ -0,0 +1,647 @@
define(['jquery', 'bootstrap', 'backend', 'echarts', 'template'], function($, undefined, Backend, Echarts, Template) {
var chart = [];
var Controller = {
index: function() {
if (!Config.SetControl.status) {
Layer.confirm('检测到宝塔面板没有开启监控,是否立即开启?', {
icon: 3,
title: '提示',
btn: ['立即开启', '暂不开启'] //可以无限个按钮
}, function(index, layero) {
Layer.close(index);
Layer.prompt({
value: Config.SetControl.day,
title: '保存天数'
}, function(value, index, elem){
$.ajax({
type: "POST",
url: "btpanel/ajax/setControl",
data: {
type:1,
day:value
},
dataType: "JSON",
success: function(res) {
Layer.msg(res.msg)
Layer.close(index);
}
});
});
});
}
//默认查询时间为今天
$('.chart-line').data('start', Moment().startOf('day').unix());
$('.chart-line').data('end', Moment().endOf('day').unix());
Controller.api.echarts.init();
Controller.api.daterangepicker();
},
module: {
cpu: {
init: function(data) {
var Chart = Echarts.init(document.getElementById('chart-cpu'), 'walden');
var obj = {};
obj.unit = '百分比';
obj.dataset = {
dimensions: ['addtime', 'pro'],
source: data
};
obj.formatter = function(params) {
return params[0].value.addtime + '<br>CPU:' + params[0].value.pro + '%';
}
obj.series = [{
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: '#52a9ff' } },
areaStyle: { opacity: 0.5 }
}];
var option = Controller.api.echarts.getOptions(obj);
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
chart['chart-cpu'] = Chart;
return Chart;
}
},
load: {
init: function(data) {
var Chart = Echarts.init(document.getElementById('chart-load'), 'walden');
var option = {
animation: false,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: function(params) {
return params[0].value.addtime + '<br>1分钟:' + params[0].value.one + '<br>5分钟:' + params[0].value.five + '<br>15分钟:' + params[0].value.fifteen + '<br>资源使用率:' + params[0].value.pro + '%';
}
},
legend: {
data: ['one', 'five', 'fifteen'],
right: '16%',
top: '10px',
formatter: function(name) {
switch (name) {
case 'one':
name = '1分钟'
break;
case 'five':
name = '5分钟'
break;
case 'fifteen':
name = '15分钟'
break;
}
return name;
}
},
axisPointer: {
link: { xAxisIndex: 'all' },
lineStyle: {
color: '#aaaa',
width: 1
}
},
dataset: [{
dimensions: ['addtime', 'pro', 'one', 'five', 'fifteen'],
source: data
}],
grid: [{ // 直角坐标系内绘图网格
top: '10%',
left: '2%',
right: '55%',
width: '45%',
height: 'auto'
},
{
top: '10%',
left: '54%',
width: '44%',
height: 'auto'
}
],
xAxis: [{ // 直角坐标系grid的x轴
type: 'category',
axisLine: {
lineStyle: {
color: '#666'
}
},
},
{ // 直角坐标系grid的x轴
type: 'category',
gridIndex: 1,
axisLine: {
lineStyle: {
color: '#666'
}
},
},
],
yAxis: [{
scale: true,
name: '资源使用率%',
splitLine: { // y轴网格显示
show: true,
lineStyle: {
color: "#ddd"
}
},
nameTextStyle: { // 坐标轴名样式
color: '#666',
fontSize: 12,
align: 'left'
},
axisLine: {
lineStyle: {
color: '#666',
}
}
},
{
scale: true,
name: '负载详情',
gridIndex: 1,
splitLine: { // y轴网格显示
show: true,
lineStyle: {
color: "#ddd"
}
},
nameTextStyle: { // 坐标轴名样式
color: '#666',
fontSize: 12,
align: 'left'
},
axisLine: {
lineStyle: {
color: '#666',
}
}
},
],
dataZoom: [{
type: 'inside',
start: 0,
end: 100,
xAxisIndex: [0, 1],
zoomLock: true
}, {
xAxisIndex: [0, 1],
type: 'slider',
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '100%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
},
left: '2%',
right: '2%'
}],
series: [{
name: 'pro',
type: 'line',
lineStyle: {
normal: {
width: 2,
color: 'rgb(255, 140, 0)'
}
},
itemStyle: {
normal: {
color: 'rgb(255, 140, 0)'
}
},
},
{
xAxisIndex: 1,
yAxisIndex: 1,
name: 'one',
type: 'line',
lineStyle: {
normal: {
width: 2,
color: 'rgb(30, 144, 255)'
}
},
itemStyle: {
normal: {
color: 'rgb(30, 144, 255)'
}
},
},
{
xAxisIndex: 1,
yAxisIndex: 1,
name: 'five',
type: 'line',
lineStyle: {
normal: {
width: 2,
color: 'rgb(0, 178, 45)'
}
},
itemStyle: {
normal: {
color: 'rgb(0, 178, 45)'
}
},
},
{
xAxisIndex: 1,
yAxisIndex: 1,
name: 'fifteen',
type: 'line',
lineStyle: {
normal: {
width: 2,
color: 'rgb(147, 38, 255)'
}
},
itemStyle: {
normal: {
color: 'rgb(147, 38, 255)'
}
},
}
],
textStyle: {
color: '#666',
fontSize: 12
}
}
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
chart['chart-load'] = Chart;
return Chart;
}
},
memory: {
init: function(data) {
var Chart = Echarts.init(document.getElementById('chart-memory'), 'walden');
var obj = {};
obj.unit = '百分比';
obj.dataset = {
dimensions: ['addtime', 'mem'],
source: data
};
obj.formatter = function(params) {
return params[0].value.addtime + '<br>内存:' + params[0].value.mem + '%';
}
obj.series = [{
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: '#52a9ff' } },
areaStyle: { opacity: 0.5 }
}];
var option = Controller.api.echarts.getOptions(obj);
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
chart['chart-memory'] = Chart;
return Chart;
}
},
disk: {
init: function(data) {
for (var i = 0; i < data.length; i++) {
data[i].read_bytes = (data[i].read_bytes / 1024 / 60).toFixed(3);
data[i].write_bytes = (data[i].write_bytes / 1024 / 60).toFixed(3);
}
var Chart = Echarts.init(document.getElementById('chart-disk'), 'walden');
var obj = {};
obj.unit = '单位:KB/s';
obj.dataset = {
dimensions: ['addtime', 'write_bytes', 'read_bytes'],
source: data
};
obj.legend = {
data: ['write_bytes', 'read_bytes'],
formatter: function(name) {
switch (name) {
case 'write_bytes':
name = '写入字节数'
break;
case 'read_bytes':
name = '读取字节数'
break;
}
return name;
}
};
obj.formatter = function(params) {
return params[0].value.addtime + '<br>读取字节数:' + params[0].value.read_bytes + 'kb/s<br>写入字节数:' + params[0].value.write_bytes + 'kb/s';
}
obj.series = [{
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: 'rgb(255, 70, 131)' } },
areaStyle: { opacity: 0.5 }
}, {
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: 'rgb(46, 165, 186)' } },
areaStyle: { opacity: 0.5 }
}];
var option = Controller.api.echarts.getOptions(obj);
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
chart['chart-disk'] = Chart;
return Chart;
}
},
net: {
init: function(data) {
var Chart = Echarts.init(document.getElementById('chart-net'), 'walden');
var obj = {};
obj.unit = '单位:KB/s';
obj.dataset = {
dimensions: ['addtime', 'up', 'down'],
source: data
};
obj.legend = {
data: ['up', 'down'],
formatter: function(name) {
switch (name) {
case 'up':
name = '上行'
break;
case 'down':
name = '下行'
break;
}
return name;
}
};
obj.formatter = function(params) {
return params[0].value.addtime + '<br>上行:' + params[0].value.up + 'kb/s<br>下行:' + params[0].value.down + 'kb/s';
}
obj.series = [{
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: 'rgb(255, 70, 131)' } },
areaStyle: { opacity: 0.5 }
}, {
type: 'line',
smooth: true,
symbol: 'none',
lineStyle: { normal: { width: 1, color: '#aaa' } },
itemStyle: { normal: { color: 'rgb(46, 165, 186)' } },
areaStyle: { opacity: 0.5 }
}];
var option = Controller.api.echarts.getOptions(obj);
// 使用刚指定的配置项和数据显示图表。
Chart.setOption(option);
$(window).resize(function() {
Chart.resize();
});
chart['chart-net'] = Chart;
return Chart;
}
}
},
api: {
echarts: {
init() {
$('.chart-line').each(function(index, element) {
element == this;
$.ajax({
type: "POST",
url: "btpanel/ajax/getMonitorData",
data: $(element).data(),
dataType: "JSON",
success: function(res) {
switch ($(element).attr('id')) {
case 'chart-load':
Controller.module.load.init(res);
break;
case 'chart-cpu':
Controller.module.cpu.init(res);
break;
case 'chart-memory':
Controller.module.memory.init(res);
break;
case 'chart-disk':
Controller.module.disk.init(res);
break;
case 'chart-net':
Controller.module.net.init(res);
break;
default:
break;
}
}
});
});
},
getData(id) {
$.ajax({
type: "POST",
url: "btpanel/ajax/getMonitorData",
data: $('#' + id).data(),
dataType: "JSON",
success: function(res) {
chart[id].setOption({
dataset: {
source: res
}
});
}
});
},
getOptions(obj) {
var option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
},
formatter: obj.formatter
},
dataset: obj.dataset,
xAxis: {
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: "#666"
}
}
},
grid: {
left: '5%',
right: '5%',
top: '10%',
bottom: 60
},
yAxis: {
type: 'value',
name: obj.unit,
boundaryGap: [0, '100%'],
min: 0,
splitLine: {
lineStyle: {
color: "#ddd"
}
},
axisLine: {
lineStyle: {
color: "#666"
}
}
},
dataZoom: [{
type: 'slider',
start: 0,
end: 100,
zoomLock: true
}, {
start: 0,
end: 100,
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
handleSize: '80%',
handleStyle: {
color: '#fff',
shadowBlur: 3,
shadowColor: 'rgba(0, 0, 0, 0.6)',
shadowOffsetX: 2,
shadowOffsetY: 2
}
}],
series: []
};
if (obj.legend) option.legend = obj.legend;
if (obj.dataZoom) option.dataZoom = obj.dataZoom;
for (var i = 0; i < obj.series.length; i++) {
var item = obj.series[i];
var series = {
type: item.type ? item.type : 'line',
smooth: item.smooth ? item.smooth : true,
symbol: item.symbol ? item.symbol : 'none',
showSymbol: item.showSymbol ? item.showSymbol : false,
sampling: item.sampling ? item.sampling : 'average',
areaStyle: item.areaStyle ? item.areaStyle : {},
lineStyle: item.lineStyle ? item.lineStyle : {},
itemStyle: item.itemStyle ? item.itemStyle : { normal: { color: 'rgb(0, 153, 238)' } },
symbolSize: 6,
symbol: 'none'
}
option.series.push(series);
}
return option;
}
},
daterangepicker: function() {
require(['bootstrap-daterangepicker'], function() {
var options = {
timePicker: false,
autoUpdateInput: false,
timePickerSeconds: true,
timePicker24Hour: true,
autoApply: true,
locale: {
format: 'YYYY-MM-DD HH:mm:ss',
customRangeLabel: __("Custom Range"),
applyLabel: __("Apply"),
cancelLabel: __("Clear"),
},
};
var origincallback = function(start, end) {
var $chart = $(this.element).parents('.panel').find('.chart-line');
$chart.data('start', start.unix());
$chart.data('end', end.unix());
Controller.api.echarts.getData($chart.attr('id'));
};
$(".datetimerange").each(function() {
var callback = typeof $(this).data('callback') == 'function' ? $(this).data('callback') : origincallback;
$(this).on('apply.daterangepicker', function(ev, picker) {
callback.call(picker, picker.startDate, picker.endDate);
});
$(this).on('cancel.daterangepicker', function(ev, picker) {
$(this).val('').trigger('blur');
});
$(this).daterangepicker($.extend(true, options, $(this).data()), callback);
});
});
$('.label-date').hover(function() {
var active = $(this).hasClass("label-active");
if (!active) {
$(this).removeClass('label-default').addClass('label-success');
}
}, function() {
var active = $(this).hasClass("label-active");
if (!active) {
$(this).removeClass('label-success').addClass('label-default');
}
});
$('.label-date').click(function() {
var active = $(this).hasClass("label-active");
if (!active) {
$(this).siblings('.label-date').removeClass('label-success label-active').addClass('label-default');
$(this).removeClass('label-default').addClass('label-success label-active')
var date = $(this).data('date');
var $chart = $(this).parents('.panel').find('.chart-line');
switch (date) {
case 'yesterday':
$chart.data('start', Moment().subtract(1, 'days').startOf('day').unix());
$chart.data('end', Moment().subtract(1, 'days').endOf('day').unix());
Controller.api.echarts.getData($chart.attr('id'));
break;
case 'today':
$chart.data('start', Moment().startOf('day').unix());
$chart.data('end', Moment().endOf('day').unix());
Controller.api.echarts.getData($chart.attr('id'));
break;
case 'last7':
$chart.data('start', Moment().subtract(6, 'days').startOf('day').unix());
$chart.data('end', Moment().subtract(6, 'days').endOf('day').unix());
Controller.api.echarts.getData($chart.attr('id'));
break;
case 'last30':
$chart.data('start', Moment().subtract(29, 'days').startOf('day').unix());
$chart.data('end', Moment().subtract(29, 'days').endOf('day').unix());
Controller.api.echarts.getData($chart.attr('id'));
break;
default:
break;
}
}
});
}
}
};
return Controller;
});