feat(history): 添加历史数据管理功能和数据分析图表

- 在addons.php中添加example模块路由配置
- 新增application/config.php配置文件,包含应用设置、数据库配置等
- 实现dashboard.js仪表盘功能,包含冷热号码分析、比例分析图表
- 添加history.js历史数据管理功能,支持号码查询和统计分析
- 集成echarts图表库实现数据可视化展示
- 添加号码颜色映射和生肖映射功能
- 实现号码球样式格式化显示
- 添加遗漏号码、走势图、冷热分析等数据分析功能
This commit is contained in:
2026-04-25 22:35:24 +08:00
parent 008d4b3e19
commit 78e7233bc0
42 changed files with 2981 additions and 10 deletions
+26 -5
View File
@@ -43,13 +43,34 @@ define(['jquery'], function ($) {
var html = '';
// 热号:按次数降序取前5名
var hotAll = hc.all.slice().sort(function (a, b) { return b.count - a.count; });
var hotTop5 = hotAll.slice(0, 5);
// 冷号:按次数升序取前5名,第5名有并列则全部包含
var coldAll = hc.all.slice().sort(function (a, b) { return a.count - b.count; });
var coldList = coldAll.slice(0, 5);
if (coldList.length >= 5) {
var threshold = coldList[4].count;
var rest = coldAll.slice(5);
for (var k = 0; k < rest.length; k++) {
if (rest[k].count === threshold) coldList.push(rest[k]);
else break;
}
}
html += '<div class="dash-section"><h4>🔥❄️ 冷热号码</h4><div class="row">';
html += '<div class="col-sm-6"><div class="dash-card" style="border-left:3px solid #e74c3c;"><div style="color:#e74c3c;font-weight:bold;margin-bottom:8px;">热号 Top 5</div>';
for (var i = 0; i < 5; i++) html += ball(hc.hot[i].num, hc.hot[i].color) + ' ';
html += '</div></div>';
html += '<div class="col-sm-6"><div class="dash-card" style="border-left:3px solid #3498db;"><div style="color:#3498db;font-weight:bold;margin-bottom:8px;">冷号 Top 5</div>';
for (var i = 0; i < 5; i++) html += ball(hc.cold[i].num, hc.cold[i].color) + ' ';
html += '</div></div></div></div>';
html += '<div style="display:flex;flex-wrap:wrap;">';
for (var i = 0; i < hotTop5.length; i++) {
html += '<span style="flex:0 0 20%;text-align:center;margin-bottom:4px;">' + ball(hotTop5[i].num, hotTop5[i].color) + '<br><span style="font-size:11px;color:#999;">' + hotTop5[i].count + '次</span></span>';
}
html += '</div></div></div>';
html += '<div class="col-sm-6"><div class="dash-card" style="border-left:3px solid #3498db;"><div style="color:#3498db;font-weight:bold;margin-bottom:8px;">冷号</div>';
html += '<div style="display:flex;flex-wrap:wrap;">';
for (var i = 0; i < coldList.length; i++) {
html += '<span style="flex:0 0 20%;text-align:center;margin-bottom:4px;">' + ball(coldList[i].num, coldList[i].color) + '<br><span style="font-size:11px;color:#999;">' + coldList[i].count + '次</span></span>';
}
html += '</div></div></div></div></div>';
html += '<div class="dash-section"><h4>📊 比例分析</h4><div class="row">';
html += '<div class="col-sm-4"><div class="dash-card"><div id="colorwave-chart" style="width:100%;height:200px;"></div></div></div>';
+323
View File
@@ -0,0 +1,323 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'example/bootstraptable/index',
add_url: '',
edit_url: 'example/bootstraptable/edit',
del_url: 'example/bootstraptable/del',
multi_url: '',
}
});
var table = $("#table");
//在普通搜索提交搜索前
table.on('common-search.bs.table', function (event, table, query) {
//这里可以获取到普通搜索表单中字段的查询条件
console.log(query);
});
//在普通搜索渲染后
table.on('post-common-search.bs.table', function (event, table) {
var form = $("form", table.$commonsearch);
$("input[name='title']", form).addClass("selectpage").data("source", "example/bootstraptable/selectpage").data("primaryKey", "title").data("field", "title").data("orderBy", "id desc");
$("input[name='username']", form).addClass("selectpage").data("source", "auth/admin/index").data("primaryKey", "username").data("field", "username").data("orderBy", "id desc");
Form.events.cxselect(form);
Form.events.selectpage(form);
});
//在表格内容渲染完成后回调的事件
table.on('post-body.bs.table', function (e, settings, json, xhr) {
console.log(e, settings, json, xhr);
});
//当表格数据加载完成时
table.on('load-success.bs.table', function (e, data) {
//这里可以获取从服务端获取的JSON数据
console.log(data);
//这里我们手动设置底部的值
$("#money").text(data.extend.money);
$("#price").text(data.extend.price);
});
// 初始化表格
// 这里使用的是Bootstrap-table插件渲染表格
// 相关文档:https://doc.fastadmin.net/doc/table.html
table.bootstrapTable({
//表格参数可以参考:https://doc.fastadmin.net/doc/190.html
url: $.fn.bootstrapTable.defaults.extend.index_url,
columns: [
[
//更多列参数可以参考:https://doc.fastadmin.net/doc/191.html
//该列为复选框字段,如果后台的返回state值将会默认选中
{field: 'state', checkbox: true,},
//sortable为是否排序,operate为搜索时的操作符,visible表示是否可见
{field: 'id', title: 'ID', sortable: true, operate: false},
//直接响应搜索
{field: 'username', title: __('管理员'), formatter: Table.api.formatter.search},
//模糊搜索
{field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '模糊搜索,*表示任意字符', width: '280px'},
//通过Ajax渲染searchList,也可以使用JSON数据
{
field: 'url',
title: __('Url'),
align: 'left',
searchList: $.getJSON('example/bootstraptable/searchlist?search=a&field=row[user_id]'),
formatter: Controller.api.formatter.url,
addClass: "selectpicker"
},
//点击IP时同时执行搜索此IP
{
field: 'ip',
title: __('IP'),
events: Controller.api.events.ip,
formatter: Controller.api.formatter.ip
},
//自定义栏位,custom是不存在的字段
{field: 'custom', title: __('切换'), operate: false, formatter: Controller.api.formatter.custom},
{
field: 'admin_id', title: __('联动搜索'), searchList: function (column) {
return Template('categorytpl', {});
}, formatter: function (value, row, index) {
return '无';
}, visible: false
},
//启用时间段搜索
{
field: 'createtime',
title: __('Update time'),
sortable: true,
formatter: Table.api.formatter.datetime,
operate: 'RANGE',
addclass: 'datetimerange'
},
//操作栏,默认有编辑、删除或排序按钮,可自定义配置buttons来扩展按钮
{
field: 'operate',
width: "150px",
title: __('Operate'),
table: table,
events: Table.api.events.operate,
buttons: [
{
name: 'click',
title: __('点击执行事件'),
classname: 'btn btn-xs btn-info btn-click',
icon: 'fa fa-leaf',
// dropdown: '更多',//如果包含dropdown,将会以下拉列表的形式展示
click: function (data) {
Layer.alert("点击按钮执行的事件");
}
},
{
name: 'detail',
title: __('弹出窗口打开'),
classname: 'btn btn-xs btn-primary btn-dialog',
icon: 'fa fa-list',
url: 'example/bootstraptable/detail',
callback: function (data) {
Layer.alert("接收到回传数据:" + JSON.stringify(data), {title: "回传数据"});
}
},
{
name: 'ajax',
title: __('发送Ajax'),
classname: 'btn btn-xs btn-success btn-magic btn-ajax',
icon: 'fa fa-magic',
confirm: '确认发送Ajax请求?',
url: 'example/bootstraptable/detail',
success: function (data, ret) {
Layer.alert(ret.msg + ",返回数据:" + JSON.stringify(data));
//如果需要阻止成功提示,则必须使用return false;
//return false;
},
error: function (data, ret) {
console.log(data, ret);
Layer.alert(ret.msg);
return false;
}
},
{
name: 'addtabs',
title: __('新选项卡中打开'),
classname: 'btn btn-xs btn-warning btn-addtabs',
icon: 'fa fa-folder-o',
url: 'example/bootstraptable/detail'
}
],
formatter: Table.api.formatter.operate
},
],
],
//更多配置参数可参考:https://doc.fastadmin.net/doc/190.html
//亦可以参考require-table.js中defaults的配置
//快捷搜索,这里可在控制器定义快捷搜索的字段
search: true,
//启用普通表单搜索
commonSearch: true,
//显示导出按钮
showExport: true,
//启用跨页选择
maintainSelected: true,
//启用固定列
fixedColumns: true,
//固定左侧列数
fixedNumber: 3,
//固定右侧列数
fixedRightNumber: 1,
//导出类型
exportDataType: "all", //共有basic, all, selected三种值 basic当前页 all全部 selected仅选中
//导出下拉列表选项
exportTypes: ['json', 'xml', 'csv', 'txt', 'doc', 'excel'],
//可以控制是否默认显示搜索单表,false则隐藏,默认为false
searchFormVisible: true,
queryParams: function (params) {
//这里可以追加搜索条件
var filter = JSON.parse(params.filter);
var op = JSON.parse(params.op);
//这里可以动态赋值,比如从URL中获取admin_id的值,filter.admin_id=Fast.api.query('admin_id');
filter.admin_id = 1;
op.admin_id = "=";
params.filter = JSON.stringify(filter);
params.op = JSON.stringify(op);
return params;
},
});
// 为表格绑定事件
Table.api.bindevent(table);
// 监听下拉列表改变的事件
$(document).on('change', 'select[name=admin]', function () {
$("input[name='admin_id']").val($(this).val());
});
//自定义Tab筛选条件
$('.panel-heading .nav-custom-condition a[data-toggle="tab"]', table.closest(".panel-intro")).on('shown.bs.tab', function (e) {
var value = $(this).data("value");
var options = table.bootstrapTable('getOptions');
var queryParams = options.queryParams;
options.pageNumber = 1;
options.queryParams = function (params) {
//这一行必须要存在,否则在点击下一页时会丢失搜索栏数据
params = queryParams(params);
//如果希望追加搜索条件,可使用
var filter = params.filter ? JSON.parse(params.filter) : {};
var op = params.op ? JSON.parse(params.op) : {};
if (value) {
//这里可以自定义多个筛选条件
filter.admin_id = value;
op.admin_id = '=';
} else {
//选全部时要移除相应的条件
delete filter.admin_id;
delete op.admin_id;
}
params.filter = JSON.stringify(filter);
params.op = JSON.stringify(op);
//如果希望忽略搜索栏搜索条件,可使用
//params.filter = JSON.stringify(value?{admin_id: value}:{});
//params.op = JSON.stringify(value?{admin_id: '='}:{});
return params;
};
table.trigger("uncheckbox");
table.bootstrapTable('refresh', {pageNumber: 1});
return false;
});
// 指定搜索条件
$(document).on("click", ".btn-singlesearch", function () {
var options = table.bootstrapTable('getOptions');
var queryParams = options.queryParams;
options.pageNumber = 1;
options.queryParams = function (params) {
//这一行必须要存在,否则在点击下一页时会丢失搜索栏数据
params = queryParams(params);
//如果希望追加搜索条件,可使用
var filter = params.filter ? JSON.parse(params.filter) : {};
var op = params.op ? JSON.parse(params.op) : {};
filter.url = 'login';
op.url = 'like';
params.filter = JSON.stringify(filter);
params.op = JSON.stringify(op);
//如果希望忽略搜索栏搜索条件,可使用
//params.filter = JSON.stringify({url: 'login'});
//params.op = JSON.stringify({url: 'like'});
return params;
};
table.bootstrapTable('refresh', {});
Toastr.info("当前执行的是自定义搜索,搜索URL中包含login的数据");
return false;
});
// 获取选中项
$(document).on("click", ".btn-selected", function () {
Layer.alert(JSON.stringify(Table.api.selecteddata(table)));
});
// 启动和暂停按钮
$(document).on("click", ".btn-start,.btn-pause", function () {
//在table外不可以使用添加.btn-change的方法
//只能自己调用Table.api.multi实现
//如果操作全部则ids可以置为空
var ids = Table.api.selectedids(table);
Table.api.multi("changestatus", ids.join(","), table, this);
});
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
detail: function () {
$(document).on('click', '.btn-callback', function () {
Fast.api.close($("input[name=callback]").val());
});
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
},
formatter: {//渲染的方法
url: function (value, row, index) {
return '<div class="input-group input-group-sm" style="width:250px;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
},
ip: function (value, row, index) {
return '<a class="btn btn-xs btn-ip bg-success"><i class="fa fa-map-marker"></i> ' + value + '</a>';
},
custom: function (value, row, index) {
//添加上btn-change可以自定义请求的URL进行数据处理
return '<a class="btn-change text-success" data-url="example/bootstraptable/change" data-confirm="确认切换状态?" data-id="' + row.id + '"><i class="fa ' + (row.title == '' ? 'fa-toggle-on fa-flip-horizontal text-gray' : 'fa-toggle-on') + ' fa-2x"></i></a>';
},
},
events: {//绑定事件的方法
ip: {
//格式为:方法名+空格+DOM元素
'click .btn-ip': function (e, value, row, index) {
e.stopPropagation();
var container = $("#table").data("bootstrap.table").$container;
var options = $("#table").bootstrapTable('getOptions');
//这里我们手动将数据填充到表单然后提交
$("form.form-commonsearch [name='ip']", container).val(value);
$("form.form-commonsearch", container).trigger('submit');
Toastr.info("执行了自定义搜索操作");
}
},
}
}
};
return Controller;
});
@@ -0,0 +1,52 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'example/colorbadge/index',
add_url: '',
edit_url: '',
del_url: 'example/colorbadge/del',
multi_url: '',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
columns: [
[
{field: 'state', checkbox: true, },
{field: 'id', title: 'ID'},
{field: 'title', title: __('Title')},
{field: 'ip', title: __('IP')},
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
],
onLoadSuccess: function (data) {
// 在表格第次加载成功后,刷新左侧菜单栏彩色小角标,支持一次渲染多个
// 如果需要在进入后台即显示左侧的彩色小角标,请使用服务端渲染方式,详情修改application/admin/controller/Index.php
Backend.api.sidebar({
'example/colorbadge': data.total
});
Toastr.info("左侧角标已经刷新成功");
}
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Form.api.bindevent($("form[role=form]"));
},
edit: function () {
Form.api.bindevent($("form[role=form]"));
}
};
return Controller;
});
@@ -0,0 +1,60 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'example/controllerjump/index',
add_url: '',
edit_url: '',
del_url: 'example/controllerjump/del',
multi_url: '',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
columns: [
[
{field: 'state', checkbox: true, },
{field: 'id', title: 'ID'},
{field: 'admin_id', title: __('Admin_id')},
{field: 'title', title: __('Title')},
{field: 'ip', title: __('IP'),formatter: Controller.api.formatter.ip},
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Form.api.bindevent($("form[role=form]"));
},
edit: function () {
Form.api.bindevent($("form[role=form]"));
},
api: {
formatter: {
ip: function (value, row, index) {
//这里手动构造URL
url = "example/bootstraptable?" + this.field + "=" + value;
//方式一,直接返回class带有addtabsit的链接,这可以方便自定义显示内容
//return '<a href="' + url + '" class="label label-success addtabsit" title="' + __("Search %s", value) + '">' + __('Search %s', value) + '</a>';
//方式二,直接调用Table.api.formatter.addtabs
this.url = url;
return Table.api.formatter.addtabs.call(this, value, row, index);
}
}
}
};
return Controller;
});
@@ -0,0 +1,33 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
Template.helper("Fast", Fast);
//因为日期选择框不会触发change事件,导致无法刷新textarea,所以加上判断
$(document).on("dp.change", "#second-form .datetimepicker", function () {
$(this).parent().prev().find("input").trigger("change");
});
$(document).on("fa.event.appendfieldlist", "#first-table .btn-append", function (e, obj) {
});
$(document).on("fa.event.appendfieldlist", "#second-table .btn-append", function (e, obj) {
//绑定动态下拉组件
Form.events.selectpage(obj);
//绑定日期组件
Form.events.datetimepicker(obj);
//绑定上传组件
Form.events.faupload(obj);
//上传成功回调事件,变更按钮的背景
$(".upload-image", obj).data("upload-success", function (data) {
$(this).css("background-image", "url('" + Fast.api.cdnurl(data.url) + "')");
})
});
Form.api.bindevent($("form[role=form]"), function (data, ret) {
Layer.alert(data.data);
});
},
};
return Controller;
});
@@ -0,0 +1,63 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
//
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'example/customsearch/index',
add_url: 'example/customsearch/add',
edit_url: '',
del_url: 'example/customsearch/del',
multi_url: 'example/customsearch/multi',
table: '',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'id',
searchFormVisible: true,
searchFormTemplate: 'customformtpl',
columns: [
[
{checkbox: true},
{field: 'id', title: 'ID', operate: false},
{field: 'admin_id', title: __('Admin_id'), visible: false, operate: false},
{field: 'username', title: __('Username'), formatter: Table.api.formatter.search},
{field: 'title', title: __('Title')},
{field: 'url', title: __('Url'), align: 'left'},
{field: 'ip', title: __('IP')},
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{
field: 'operate',
title: __('Operate'),
table: table,
events: Table.api.events.operate,
formatter: Table.api.formatter.operate
}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
}
}
};
return Controller;
});
@@ -0,0 +1,14 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
$("#cxselect-example .col-xs-12").each(function () {
$("textarea", this).val($(this).prev().prev().html().replace(/[ ]{2}/g, ''));
});
//这里需要手动为Form绑定上元素事件
Form.api.bindevent($("form#cxselectform"));
}
};
return Controller;
});
+206
View File
@@ -0,0 +1,206 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'echarts', 'echarts-theme'], function ($, undefined, Backend, Table, Form, Template, Echarts) {
var Controller = {
index: function () {
//这句话在多选项卡统计表时必须存在,否则会导致影响的图表宽度不正确
$(document).on("click", ".charts-custom a[data-toggle=\"tab\"]", function () {
var that = this;
setTimeout(function () {
var id = $(that).attr("href");
var chart = Echarts.getInstanceByDom($(id)[0]);
chart.resize();
}, 0);
});
// 基于准备好的dom,初始化echarts实例
var lineChart = Echarts.init(document.getElementById('line-chart'), 'walden');
// 指定图表的配置项和数据
var option = {
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [{
data: [49, 92, 61, 134, 90, 130, 120],
type: 'line'
}]
};
// 使用刚指定的配置项和数据显示图表。
lineChart.setOption(option);
// 基于准备好的dom,初始化echarts实例
var areaChart = Echarts.init(document.getElementById('area-chart'), 'walden');
// 指定图表的配置项和数据
var option = {
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
areaStyle: {}
}]
};
// 使用刚指定的配置项和数据显示图表。
areaChart.setOption(option);
var pieChart = Echarts.init(document.getElementById('pie-chart'), 'walden');
var option = {
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 10,
data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['50%', '70%'],
avoidLabelOverlap: false,
label: {
normal: {
show: false,
position: 'center'
},
emphasis: {
show: true,
textStyle: {
fontSize: '30',
fontWeight: 'bold'
}
}
},
labelLine: {
normal: {
show: false
}
},
data: [
{value: 335, name: '直接访问'},
{value: 310, name: '邮件营销'},
{value: 234, name: '联盟广告'},
{value: 135, name: '视频广告'},
{value: 1548, name: '搜索引擎'}
]
}
]
};
// 使用刚指定的配置项和数据显示图表。
pieChart.setOption(option);
var barChart = Echarts.init(document.getElementById('bar-chart'), 'walden');
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['产品销售', '2015', '2016', '2017'],
['风扇', 43.3, 85.8, 93.7],
['电视机', 83.1, 73.4, 55.1],
['空调', 86.4, 65.2, 82.5],
['冰箱', 72.4, 53.9, 39.1]
]
},
xAxis: {type: 'category'},
yAxis: {},
// Declare several bar series, each will be mapped
// to a column of dataset.source by default.
series: [
{type: 'bar'},
{type: 'bar'},
{type: 'bar'}
]
};
// 使用刚指定的配置项和数据显示图表。
barChart.setOption(option);
var barChart = Echarts.init(document.getElementById('simplebar-chart'));
option = {
xAxis: {
type: 'category',
axisLine: {
lineStyle: {
color: "#fff"
}
},
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: "#fff"
}
}
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar',
itemStyle: {
color: "#fff",
opacity: 0.6
}
}]
};
// 使用刚指定的配置项和数据显示图表。
barChart.setOption(option);
var barChart = Echarts.init(document.getElementById('smoothline-chart'));
option = {
textStyle: {
color: "#fff"
},
color: ['#fff'],
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisLine: {
lineStyle: {
color: "#fff"
}
}
},
yAxis: {
type: 'value',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: "#fff"
}
}
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: true,
areaStyle: {
opacity: 0.4
}
}]
};
// 使用刚指定的配置项和数据显示图表。
barChart.setOption(option);
}
};
return Controller;
});
@@ -0,0 +1,93 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init();
//绑定事件
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
var panel = $($(this).attr("href"));
if (panel.length > 0) {
Controller.table[panel.attr("id")].call(this);
$(this).on('click', function (e) {
$($(this).attr("href")).find(".btn-refresh").trigger("click");
});
}
//移除绑定的事件
$(this).unbind('shown.bs.tab');
});
//必须默认触发shown.bs.tab事件
$('ul.nav-tabs li.active a[data-toggle="tab"]').trigger("shown.bs.tab");
},
table: {
first: function () {
// 表格1
var table1 = $("#table1");
table1.bootstrapTable({
url: 'example/multitable/table1',
toolbar: '#toolbar1',
sortName: 'id',
search: false,
columns: [
[
{field: 'state', checkbox: true, },
{field: 'id', title: 'ID'},
{field: 'filename', title: __('Name')},
{field: 'imagewidth', title: __('Imagewidth')},
{field: 'imageheight', title: __('Imageheight')},
{field: 'mimetype', title: __('Mimetype')},
{field: 'operate', title: __('Operate'), table: table1, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格1绑定事件
Table.api.bindevent(table1);
},
second: function () {
// 表格2
var table2 = $("#table2");
table2.bootstrapTable({
url: 'example/multitable/table2',
extend: {
index_url: '',
add_url: '',
edit_url: '',
del_url: '',
multi_url: '',
table: '',
},
toolbar: '#toolbar2',
sortName: 'id',
search: false,
columns: [
[
{field: 'id', title: 'ID'},
{field: 'title', title: __('Title')},
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
{field: 'ip', title: __('ip')},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
]
]
});
// 为表格2绑定事件
Table.api.bindevent(table2);
}
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
},
}
};
return Controller;
});
@@ -0,0 +1,48 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'example/relationmodel/index',
add_url: '',
edit_url: '',
del_url: 'example/relationmodel/del',
multi_url: '',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
columns: [
[
{field: 'state', checkbox: true, },
{field: 'id', title: 'ID', operate: '='},
{field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '关键字,模糊搜索'},
{field: 'admin.avatar', title: __('Avatar'), operate: false, formatter: Table.api.formatter.image},
{field: 'admin.username', title: __('Username'), operate: 'FIND_IN_SET'},
{field: 'admin.nickname', title: __('Nickname'), operate: 'LIKE %...%', placeholder: '关键字,模糊搜索'},
{field: 'ip', title: __('IP'), operate: '='},
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'admin.createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
],
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Form.api.bindevent($("form[role=form]"));
},
edit: function () {
Form.api.bindevent($("form[role=form]"));
},
};
return Controller;
});
@@ -0,0 +1,81 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init();
this.table.first();
this.table.second();
},
table: {
first: function () {
// 表格1
var table1 = $("#table1");
table1.bootstrapTable({
url: 'example/tablelink/table1',
toolbar: '#toolbar1',
sortName: 'id',
search: false,
columns: [
[
// {field: 'state', checkbox: true,},
{field: 'id', title: 'ID'},
{field: 'username', title: __('Nickname')},
{
field: 'operate', title: __('Operate'), table: table1, events: Table.api.events.operate, buttons: [
{
name: 'log',
title: '日志列表',
text: '日志列表',
icon: 'fa fa-list',
classname: 'btn btn-primary btn-xs btn-click',
click: function (e, data) {
$("#myTabContent2 .form-commonsearch input[name='username']").val(data.username);
$("#myTabContent2 .btn-refresh").trigger("click");
}
}
], formatter: Table.api.formatter.operate
}
]
]
});
// 为表格1绑定事件
Table.api.bindevent(table1);
},
second: function () {
// 表格2
var table2 = $("#table2");
table2.bootstrapTable({
url: 'example/tablelink/table2',
extend: {
index_url: '',
add_url: '',
edit_url: '',
del_url: '',
multi_url: '',
table: '',
},
toolbar: '#toolbar2',
sortName: 'id',
search: false,
columns: [
[
{field: 'state', checkbox: true,},
{field: 'id', title: 'ID'},
{field: 'username', title: __('Nickname')},
{field: 'title', title: __('Title')},
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
{field: 'ip', title: __('ip')},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
]
]
});
// 为表格2绑定事件
Table.api.bindevent(table2);
}
},
};
return Controller;
});
@@ -0,0 +1,115 @@
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function ($, undefined, Backend, Table, Form, Template) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'example/tabletemplate/index',
add_url: '',
edit_url: '',
del_url: 'example/tabletemplate/del',
multi_url: '',
}
});
var table = $("#table");
Template.helper("Moment", Moment);
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
templateView: true,
columns: [
[
{field: 'state', checkbox: true, },
{field: 'id', title: 'ID', operate: false},
//直接响应搜索
{field: 'username', title: __('Username'), formatter: Table.api.formatter.search},
//模糊搜索
{field: 'title', title: __('Title'), operate: 'LIKE %...%', placeholder: '模糊搜索,*表示任意字符', style: 'width:200px'},
//通过Ajax渲染searchList
{field: 'url', title: __('Url'), align: 'left', formatter: Controller.api.formatter.url},
//点击IP时同时执行搜索此IP,同时普通搜索使用下拉列表的形式
{field: 'ip', title: __('IP'), searchList: ['127.0.0.1', '127.0.0.2'], events: Controller.api.events.ip, formatter: Controller.api.formatter.ip},
//browser是一个不存在的字段
//通过formatter来渲染数据,同时为它添加上事件
{field: 'browser', title: __('Browser'), operate: false, events: Controller.api.events.browser, formatter: Controller.api.formatter.browser},
//启用时间段搜索
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
],
],
//禁用默认搜索
search: false,
//启用普通表单搜索
commonSearch: false,
//可以控制是否默认显示搜索单表,false则隐藏,默认为false
searchFormVisible: false,
//分页大小
pageSize: 12
});
// 为表格绑定事件
Table.api.bindevent(table);
//指定搜索条件
$(document).on("click", ".btn-toggle-view", function () {
var options = table.bootstrapTable('getOptions');
table.bootstrapTable('refreshOptions', {templateView: !options.templateView});
});
//点击详情
$(document).on("click", ".btn-detail[data-id]", function () {
Backend.api.open('example/bootstraptable/detail/ids/' + $(this).data('id'), __('Detail'));
});
//获取选中项
$(document).on("click", ".btn-selected", function () {
//在templateView的模式下不能调用table.bootstrapTable('getSelections')来获取选中的ID,只能通过下面的Table.api.selectedids来获取
Layer.alert(JSON.stringify(Table.api.selectedids(table)));
});
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
},
formatter: {
url: function (value, row, index) {
return '<div class="input-group input-group-sm" style="width:250px;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
},
ip: function (value, row, index) {
return '<a class="btn btn-xs btn-ip bg-success"><i class="fa fa-map-marker"></i> ' + value + '</a>';
},
browser: function (value, row, index) {
//这里我们直接使用row的数据
return '<a class="btn btn-xs btn-browser">' + row.useragent.split(" ")[0] + '</a>';
}
},
events: {
ip: {
'click .btn-ip': function (e, value, row, index) {
var options = $("#table").bootstrapTable('getOptions');
//这里我们手动将数据填充到表单然后提交
$("#commonSearchContent_" + options.idTable + " form [name='ip']").val(value);
$("#commonSearchContent_" + options.idTable + " form").trigger('submit');
Toastr.info("执行了自定义搜索操作");
}
},
browser: {
'click .btn-browser': function (e, value, row, index) {
Layer.alert("该行数据为: <code>" + JSON.stringify(row) + "</code>");
}
}
}
}
};
return Controller;
});
+40 -3
View File
@@ -35,6 +35,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'num6', title: __('Num6'), formatter: Controller.api.formatter.numBall},
{field: 'num7', title: __('Num7'), formatter: Controller.api.formatter.numBall},
{field: 'openTime', title: __('OpenTime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
{field: 'search_day', title: '每月日号', visible: false, searchable: true, operate: '=', style: 'width:80px;', extend: 'min="1" max="31" placeholder="1-31"'}
]
]
});
@@ -660,12 +661,48 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
return map[status] || '';
};
if (!data || data.length === 0) {
// 新接口返回 {list: [...], current: {hot: [], cold: [], warm: []}}
var listData = data.list || data;
var current = data.current || null;
if (!listData || listData.length === 0) {
$('#shc-result', layero).html('<div class="alert alert-info">暂无数据</div>');
return;
}
var html = '<div style="padding:0 5px;">';
// 当前冷热号汇总区域
if (current && (current.hot.length > 0 || current.cold.length > 0)) {
var renderNumBall = function (item) {
var color = getColor(item.num);
return '<span style="display:inline-block;width:30px;height:30px;line-height:30px;text-align:center;border-radius:50%;color:#fff;background-color:' + color + ';font-weight:bold;font-size:14px;" title="' + item.num + ' ×' + item.count + '">' + item.num + '</span>';
};
html += '<div style="background:#fafafa;border:1px solid #e0e0e0;border-radius:6px;padding:12px;margin-bottom:12px;">';
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;color:#333;"><i class="fa fa-bullseye"></i> 当前热号</div>';
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;">';
for (var h = 0; h < current.hot.length; h++) {
html += renderNumBall(current.hot[h]);
}
if (current.hot.length === 0) {
html += '<span style="color:#999;font-size:12px;">暂无热号</span>';
}
html += '</div>';
html += '<div style="height:8px;"></div>';
html += '<div style="font-size:13px;font-weight:bold;margin-bottom:8px;color:#333;"><i class="fa fa-snowflake-o"></i> 当前冷号</div>';
html += '<div style="display:flex;flex-wrap:wrap;gap:6px;">';
for (var c = 0; c < current.cold.length; c++) {
html += renderNumBall(current.cold[c]);
}
if (current.cold.length === 0) {
html += '<span style="color:#999;font-size:12px;">暂无冷号</span>';
}
html += '</div>';
html += '</div>';
}
// 历史记录表格
html += '<table class="table table-striped table-bordered table-hover" style="font-size:13px;">' +
'<thead><tr>' +
'<th style="text-align:center;width:120px;">期号</th>' +
@@ -676,8 +713,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
'<th style="text-align:center;width:60px;">排名</th>' +
'</tr></thead><tbody>';
for (var i = 0; i < data.length; i++) {
var item = data[i];
for (var i = 0; i < listData.length; i++) {
var item = listData[i];
var rowClass = '';
if (item.status === 'hot') rowClass = 'style="background:#fff5f5;"';
else if (item.status === 'cold') rowClass = 'style="background:#f5f8ff;"';