model = new \app\admin\model\FcFinanceFlow; } /** * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 */ /** * 导出资金流水(Excel) * GET fc/financeflow/export?type=income|expense */ public function export() { $type = trim((string)$this->request->get('type', '')); $q = Db::name('fc_finance_flow'); if ($type !== '') { $q->where('type', $type); } $rows = $q->order('createtime desc')->limit(50000)->select(); $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('资金流水'); $sheet->fromArray(['流水号', '类型', '场景', '金额(元)', '账户余额(元)', '关联ID', '备注', '时间'], null, 'A1'); $r = 2; foreach ($rows as $row) { $sheet->fromArray([ (string)$row['flow_no'], $row['type'] === 'income' ? '收入' : '支出', (string)$row['scene'], (float)$row['amount'], (float)$row['balance'], (int)$row['related_id'], (string)$row['remark'], date('Y-m-d H:i:s', (int)$row['createtime']), ], null, 'A' . $r); $r++; } $this->downloadXlsx($spreadsheet, '资金流水_' . date('YmdHis')); } /** * 导出营收报表(Excel) * GET fc/financeflow/exportReport?period=day|month|year */ public function exportReport() { $period = trim((string)$this->request->get('period', 'month')); if (!in_array($period, ['day', 'month', 'year'], true)) { $period = 'month'; } $fmtMap = ['day' => '%Y-%m-%d', 'month' => '%Y-%m', 'year' => '%Y']; $fmt = $fmtMap[$period]; $post = $this->periodSum('post', $fmt); $member = $this->periodSum('member', $fmt); $recharge = $this->periodSum('recharge', $fmt); $withdraw = $this->periodWithdraw($fmt); $keys = array_unique(array_merge(array_keys($post), array_keys($member), array_keys($recharge), array_keys($withdraw))); sort($keys); $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('营收报表'); $sheet->fromArray(['周期', '发布收入', '会员收入', '充值收入', '提现支出', '净收入'], null, 'A1'); $r = 2; foreach ($keys as $k) { $p = isset($post[$k]) ? (float)$post[$k] : 0; $m = isset($member[$k]) ? (float)$member[$k] : 0; $rc = isset($recharge[$k]) ? (float)$recharge[$k] : 0; $w = isset($withdraw[$k]) ? (float)$withdraw[$k] : 0; $sheet->fromArray([ (string)$k, round($p, 2), round($m, 2), round($rc, 2), round($w, 2), round($p + $m + $rc - $w, 2), ], null, 'A' . $r); $r++; } $label = ['day' => '日', 'month' => '月', 'year' => '年'][$period]; $this->downloadXlsx($spreadsheet, '营收报表_按' . $label . '_' . date('YmdHis')); } /** 按周期聚合某类已支付订单 */ protected function periodSum($type, $fmt) { $rows = Db::name('fc_order') ->where('status', 'paid') ->where('type', $type) ->field("FROM_UNIXTIME(createtime, '{$fmt}') AS period, SUM(amount) AS total") ->group('period') ->select(); $map = []; foreach ($rows as $row) { $map[$row['period']] = (float)$row['total']; } return $map; } /** 按周期聚合已到账提现 */ protected function periodWithdraw($fmt) { $rows = Db::name('fc_withdraw') ->where('status', 'paid') ->whereNotNull('paytime') ->field("FROM_UNIXTIME(paytime, '{$fmt}') AS period, SUM(amount) AS total") ->group('period') ->select(); $map = []; foreach ($rows as $row) { $map[$row['period']] = (float)$row['total']; } return $map; } /** 输出 xlsx 下载 */ protected function downloadXlsx($spreadsheet, $filename) { $filename = preg_replace('/[^\w\x{4e00}-\x{9fa5}\-]/u', '', $filename) . '.xlsx'; header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment;filename="' . $filename . '"'); header('Cache-Control: max-age=0'); $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet); $writer->save('php://output'); exit; } }