效果图:
数据库表:记账表
CREATE TABLE `fa_pigs_journal_account` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `admin_id` int(10) NOT NULL DEFAULT '0' COMMENT '管理员ID', `typedata` enum('pay','income') NOT NULL DEFAULT 'pay' COMMENT '收入/支出(单选):pay=支出,income=收入', `type_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '费用类别ID(单选)', `donetime` int(10) DEFAULT NULL COMMENT '收入/支出时间', `money` float(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '金额', `description` varchar(255) DEFAULT '' COMMENT '描述', `createtime` int(10) DEFAULT NULL COMMENT '创建时间', `updatetime` int(10) DEFAULT NULL COMMENT '更新时间', `deletetime` int(10) DEFAULT NULL COMMENT '删除时间', `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='记账表';
HTML源码
文件application/admin/view/journalmanager/income_trend/index.html
<div class="row" style="margin-top:15px;"> <div class="col-xs-12"> <div class="panel panel-default panel-intro panel-statistics"> <div class="panel-body"> <h4>收支趋势图</h4><br> <div id="datefilter"> <form id="form1" action="" role="form" novalidate class="form-inline"> <a href="javascript:;" class="btn btn-primary btn-refresh"><i class="fa fa-refresh"></i></a> <a href="javascript:;" class="btn btn-success btn-filter">{:__('Last 30 Days')}</a> <a href="javascript:;" class="btn btn-success btn-filter">{:__('Last month')}</a> <a href="javascript:;" class="btn btn-success btn-filter">{:__('This month')}</a> <a href="javascript:;" class="btn btn-success btn-filter">{:__('Last year')}</a> <a href="javascript:;" class="btn btn-success btn-filter">{:__('This year')}</a> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-calendar"></i></span> <input type="text" class="form-control input-inline datetimerange" data-type="order" placeholder="指定日期" style="width:270px;"/> </div> <a href="javascript:;" class="btn btn-default" style="font-size:14px;color:dodgerblue;"> <i class="fa fa-rmb"></i> <span class="extend"> 总收入:<span id="all_income">{$extend.allIncome}</span> 总支出:<span id="all_pay">{$extend.allPay}</span> 结余:<span id="all_balance">{$extend.allBalance}</span> </span> </a> </form> </div> <div id="echarts1" style="height:400px;width:100%;margin-top:15px;"></div> </div> </div> </div></div>
控制器源码
文件application/admin/controller/journalmanager/IncomeTrend.php
<?phpnamespace appadmincontrollerjournalmanager;use appadminmodelUser;use appcommoncontrollerBackend;use thinkDb;/** * 收支趋势图 * * @icon fa fa-bar-chart */class IncomeTrend extends Backend{ /** * */ protected $model = null; protected $noNeedRight = []; protected $isSuperAdmin = false; /** * 查看 */ public function index() { if ($this->request->isPost()) { $date = $this->request->post('date', ''); list($category, $incomeData, $payData, $balanceData, $extend) = $this->getIncomeStatisticsData($date); $statistics = ['category' => $category, 'incomeData' => $incomeData, 'payData' => $payData, 'balanceData' => $balanceData, 'extend' => $extend]; $this->success('', '', $statistics); } list($category, $incomeData, $payData, $balanceData, $extend) = $this->getIncomeStatisticsData(); $this->assignconfig('category', $category); $this->assignconfig('incomeData', $incomeData); $this->assignconfig('payData', $payData); $this->assignconfig('balanceData', $balanceData); $this->view->assign('extend', $extend); return $this->view->fetch(); } /** * 获取收支统计数据 * @param string $date * @return array */ protected function getIncomeStatisticsData($date = '') { if ($date) { list($start, $end) = explode(' - ', $date); $starttime = strtotime($start); $endtime = strtotime($end); } else { // 默认是当月 $starttime = fastDate::unixtime('month', 0, 'begin'); $endtime = fastDate::unixtime('month', 0, 'end'); } $totalseconds = $endtime - $starttime; $format = '%Y-%m-%d'; if ($totalseconds > 86400 * 30 * 2) { // 大于两个月,则横坐标为以月为粒度 形式'Y-m' $format = '%Y-%m'; } else { if ($totalseconds > 86400) { // 小于两个月 且大于一天,则横坐标以天为粒度 形式'Y-m-d' $format = '%Y-%m-%d'; } else { // 小于一天,则横坐标为以小时为粒度 形式'H:00' $format = '%H:00'; } } // 收入 $orderList = appadminmodeljournalmanagerJournalAccount::where('donetime', 'between time', [$starttime, $endtime])->where('typedata','income') ->field('donetime, typedata, SUM(money) AS amount, DATE_FORMAT(FROM_UNIXTIME(donetime), "' . $format . '") AS pay_date') ->group('pay_date') ->select(); // 支出 $payOrderList = appadminmodeljournalmanagerJournalAccount::where('donetime', 'between time', [$starttime, $endtime])->where('typedata','pay') ->field('donetime, typedata, SUM(money) AS amount, DATE_FORMAT(FROM_UNIXTIME(donetime), "' . $format . '") AS pay_date') ->group('pay_date') ->select(); if ($totalseconds > 84600 * 30 * 2) { // 大于两个月,则横坐标为以月为粒度 形式'Y-m' $starttime = strtotime('last month', $starttime); while (($starttime = strtotime('next month', $starttime)) <= $endtime) { $column[] = date('Y-m', $starttime); } } else { if ($totalseconds > 86400) { // 小于两个月 且大于一天,则横坐标以天为粒度 形式'Y-m-d' for ($time = $starttime; $time <= $endtime;) { $column[] = date("Y-m-d", $time); $time += 86400; } } else { // 小于一天,则横坐标为以小时为粒度 形式'H:00' for ($time = $starttime; $time <= $endtime;) { $column[] = date("H:00", $time); $time += 3600; } } } // 收入 $list = array_fill_keys($column, 0); $allIncome = 0; foreach ($orderList as $k => $v) { $list[$v['pay_date']] = round($v['amount'], 2); $allIncome += round($v['amount'], 2); } $payList = array_fill_keys($column, 0); // 支出 $allPay = 0; foreach ($payOrderList as $k => $v) { $payList[$v['pay_date']] = round($v['amount'], 2); $allPay += round($v['amount'], 2); } $balanceList = array_fill_keys($column, 0); // 结余 $allBalance = $allIncome - $allPay; foreach ($balanceList as $k => $v) { $balanceList[$k] = round($list[$k] - $payList[$k], 2); } $category = array_keys($list); $incomeData = array_values($list); $payData = array_values($payList); $balanceData = array_values($balanceList); $extend = array('allIncome'=>$allIncome,'allPay'=>$allPay,'allBalance'=>$allBalance); return [$category, $incomeData, $payData, $balanceData, $extend]; }}
js源码
文件public/assets/js/backend/journalmanager/income_trend.js
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-theme'], function ($, undefined, Backend, Table, Form, Echarts) { var Controller = { index: function () { // 基于准备好的dom,初始化echarts实例 var myChart1 = Echarts.init($('#echarts1')[0], 'walden'); // 指定图表的配置项和数据 var option1 = { title: { text: '', subtext: '' }, tooltip: { trigger: 'axis' }, legend: { data: ['收入', '支出', '结余'] }, toolbox: { show: true, feature: { dataView: {show: true, readOnly: false}, magicType: {show: true, type: ['line', 'bar']}, restore: {show: true}, saveAsImage: {show: true} } }, calculable: true, xAxis: { type: 'category', boundaryGap: false, data: Config.category }, yAxis: {}, grid: [{ left: 'left', top: 'top', right: '10', bottom: 30 }], series: [ { name: "收入", type: 'line', smooth: true, areaStyle: { normal: {} }, lineStyle: { normal: { width: 1.5 } }, data: Config.incomeData }, { name: "支出", type: 'line', smooth: true, areaStyle: { normal: {} }, lineStyle: { normal: { width: 1.5 } }, data: Config.payData }, { name: "结余", type: 'line', smooth: true, areaStyle: { normal: {} }, lineStyle: { normal: { width: 1.5 } }, data: Config.balanceData } ] }; // 使用刚指定的配置项和数据显示图表。 myChart1.setOption(option1); $(window).resize(function () { myChart1.resize(); }); $(".datetimerange").data("callback", function (start, end) { var date = start.format(this.locale.format) + " - " + end.format(this.locale.format); $(this.element).val(date); refresh_echart($(this.element).data("type"), date); }); Form.api.bindevent($("#form1")); var si = {}; var refresh_echart = function (type, date) { si[type] && clearTimeout(si[type]); si[type] = setTimeout(function () { Fast.api.ajax({ url: 'journalmanager/income_trend/index', data: {date: date, type: type}, loading: false }, function (data) { if (type == 'order') { option1.xAxis.data = data.category; option1.series[0].data = data.data; option1.series[1].data = data.payData; option1.series[2].data = data.balanceData; myChart1.clear(); myChart1.setOption(option1, true); $("#all_income").text(data.extend.allIncome); $("#all_pay").text(data.extend.allPay); $("#all_balance").text(data.extend.allBalance); } return false; }); }, 50); }; //点击按钮 $(document).on("click", ".btn-filter", function () { var label = $(this).text(); var obj = $(this).closest("form").find(".datetimerange").data("daterangepicker"); var dates = obj.ranges[label]; obj.startDate = dates[0]; obj.endDate = dates[1]; obj.clickApply(); }); //点击刷新 $(document).on("click", ".btn-refresh", function () { if ($(this).data("type")) { refresh_echart($(this).data("type"), ""); } else { var input = $(this).closest("form").find(".datetimerange"); var type = $(input).data("type"); var date = $(input).data("date"); refresh_echart(type, date); } }); //每隔一分钟定时刷新图表 setInterval(function () { $(".btn-refresh").trigger("click"); }, 60000); }, add: function () { Controller.api.bindevent(); }, edit: function () { Controller.api.bindevent(); }, api: { bindevent: function () { Form.api.bindevent($("form[role=form]")); } } }; return Controller;});
多语言设置
文件application/admin/lang/zh-cn.php
'Last 30 days' => '最近30天', 'Last month' => '上月', 'This month' => '本月', 'Last year' => '去年', 'This year' => '今年',
设置了日期控件的参数
在public/assets/js/require-form.js文件的daterangepicker函数里追加了两行代码
ranges[__('Last Year')] = [Moment().subtract(1, 'year').startOf('year'), Moment().subtract(1, 'year').endOf('year')]; ranges[__('This Year')] = [Moment().startOf('year'), Moment().endOf('year')];
最后一步,添加上菜单规则
规则:journalmanager/income_trend访问URL:http://yoursite/YFmcqx.php/journalmanager/income_trend?ref=addtabs
----------对你有帮助,就给个赞呗!----------
希望以上内容对你有所帮助!如果还有其他问题,请随时提问。 各类知识收集 拥有多年CMS企业建站经验,对 iCMS, Fastadmin, ClassCMS, LeCMS, PbootCMS, PHPCMS, 易优CMS, YzmCMS, 讯睿CMS, 极致CMS, Wordpress, HkCMS, YznCMS, WellCMS, ThinkCMF, 等各类cms的相互转化,程序开发,网站制作,bug修复,程序杀毒,插件定制都可以提供最佳解决方案。