提交代码

This commit is contained in:
youda 2025-04-19 18:38:30 +08:00
parent 426d6dd943
commit b2ed70fe28
3 changed files with 463 additions and 1 deletions

View File

@ -17,6 +17,10 @@ use think\facade\Db;
use app\common\model\Shang;
use app\common\model\ProfitExpenses;
use app\common\model\ProfitRvenue;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
class Statistics extends Base
{
@ -914,4 +918,416 @@ class Statistics extends Base
return json(['code' => 0, 'msg' => '获取成功', 'data' => $data]);
}
/**
* 导出盒子利润统计数据
* @return void
*/
public function exportProfit()
{
// 获取查询参数
$goodId = trim(input('get.goodId'));
$title = trim(input('get.title'));
$status = trim(input('get.status'));
$type = trim(input('get.type'));
$addtime = trim(input('get.addtime'));
// 解析时间范围
$hasTimeRange = false;
$startTime = 0;
$endTime = 0;
if (!empty($addtime)) {
$hasTimeRange = true;
$times = explode(' - ', $addtime);
$startTime = strtotime($times[0]);
$endTime = strtotime($times[1]);
}
// 构建查询条件
$where = [['delete_time', '=', null]];
if ($goodId) {
$where[] = ['id', '=', $goodId];
}
if ($title) {
$where[] = ['title', 'like', '%' . $title . '%'];
}
if ($status) {
$where[] = ['status', '=', $status];
}
if ($type) {
$where[] = ['type', '=', $type];
}
// 获取测试用户ID
$testUsers = User::where('istest', '>', 0)->column('id');
$testUserIds = empty($testUsers) ? [0] : $testUsers;
// 获取盒子类型名称映射
$typesList = $this->getGoodsTypes();
$typesMap = [];
foreach ($typesList as $item) {
$typesMap[$item['value']] = $item['fl_name'];
}
// 查询所有符合条件的盒子
$goods = Db::name('goods')
->where($where)
->field(['id', 'title', 'status', 'type', 'price', 'imgurl'])
->order('id desc')
->select()
->toArray();
// 如果没有数据,返回错误提示
if (empty($goods)) {
return json(['code' => 1, 'msg' => '没有找到符合条件的数据']);
}
// 创建一个新的工作簿
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 设置工作表名称
$sheet->setTitle('盒子利润统计');
// 设置表头
$headers = [
'ID', '盒子名称', '盒子类型', '状态', '单价', '抽奖次数',
'收入(微信+钻石)', '出货价值', '已兑换达达卷', '已申请发货',
'利润', '利润率(%)'
];
foreach ($headers as $col => $header) {
$sheet->setCellValueByColumnAndRow($col + 1, 1, $header);
}
// 设置表头样式
$headerStyle = [
'font' => ['bold' => true],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['rgb' => 'E0E0E0'],
],
];
$sheet->getStyle('A1:L1')->applyFromArray($headerStyle);
// 填充数据
$row = 2;
foreach ($goods as $item) {
// 获取该盒子的统计数据
$statsData = $this->getBoxProfitStats($item['id'], $hasTimeRange, $startTime, $endTime, $testUserIds);
// 获取状态文字
$statusText = '';
switch ($item['status']) {
case 1: $statusText = '上架'; break;
case 2: $statusText = '下架'; break;
case 3: $statusText = '售罄'; break;
default: $statusText = '自动下架'; break;
}
// 填充一行数据
$sheet->setCellValue('A' . $row, $item['id']);
$sheet->setCellValue('B' . $row, $item['title']);
$sheet->setCellValue('C' . $row, isset($typesMap[$item['type']]) ? $typesMap[$item['type']] : '未知类型');
$sheet->setCellValue('D' . $row, $statusText);
$sheet->setCellValue('E' . $row, $item['price']);
$sheet->setCellValue('F' . $row, $statsData['cj_count']);
$sheet->setCellValue('G' . $row, $statsData['use_money']);
$sheet->setCellValue('H' . $row, $statsData['sc_money']);
$sheet->setCellValue('I' . $row, $statsData['re_money']);
$sheet->setCellValue('J' . $row, $statsData['fh_money']);
$sheet->setCellValue('K' . $row, $statsData['profit']);
$sheet->setCellValue('L' . $row, $statsData['profit_rate']);
// 设置负利润的行为红色背景
if ($statsData['profit'] < 0) {
$sheet->getStyle('A' . $row . ':L' . $row)->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setRGB('FFEBEE');
}
$row++;
}
// 调整列宽
foreach (range('A', 'L') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
// 添加汇总行
$summaryData = $this->getSummaryStatisticsData($goodId, $title, $status, $type, $addtime);
$row++;
$sheet->setCellValue('A' . $row, '汇总');
$sheet->mergeCells('A' . $row . ':F' . $row);
$sheet->setCellValue('G' . $row, $summaryData['totalIncome']);
$sheet->setCellValue('H' . $row, $summaryData['totalCost']);
$sheet->setCellValue('I' . $row, $summaryData['totalReMoney']);
$sheet->setCellValue('J' . $row, $summaryData['totalFhMoney']);
$sheet->setCellValue('K' . $row, $summaryData['totalProfit']);
// 计算总体利润率
$profitRate = 0;
if ($summaryData['totalIncome'] > 0) {
$profitRate = ($summaryData['totalProfit'] / $summaryData['totalIncome']) * 100;
}
$sheet->setCellValue('L' . $row, round($profitRate, 2));
// 设置汇总行样式
$summaryStyle = [
'font' => ['bold' => true],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['rgb' => ($summaryData['totalProfit'] >= 0 ? 'E8F5E9' : 'FFEBEE')],
],
];
$sheet->getStyle('A' . $row . ':L' . $row)->applyFromArray($summaryStyle);
// 设置Excel文件属性
$spreadsheet->getProperties()
->setCreator('盒子利润统计系统')
->setLastModifiedBy('盒子利润统计系统')
->setTitle('盒子利润统计数据')
->setSubject('盒子利润统计数据')
->setDescription('导出的盒子利润统计数据');
// 设置输出文件名
$filename = '盒子利润统计_' . date('YmdHis') . '.xlsx';
// 设置HTTP头表明这是一个Excel文件
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $filename . '"');
header('Cache-Control: max-age=0');
// 将工作簿写入到PHP输出流
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
exit;
}
/**
* 获取单个盒子的利润统计数据(用于导出)
* @param int $goodId 盒子ID
* @param bool $hasTimeRange 是否有时间范围限制
* @param int $startTime 开始时间
* @param int $endTime 结束时间
* @param array $testUserIds 测试用户ID列表
* @return array 统计数据
*/
private function getBoxProfitStats($goodId, $hasTimeRange, $startTime, $endTime, $testUserIds)
{
// 查询1获取充值金额和余额消费总和
$orderQuery = Db::name('order')
->where('status', '=', 1)
->where(function ($query) {
$query->where('price', '>', 0)
->whereOr('use_money', '>', 0);
})
->where('goods_id', '=', $goodId)
->where('user_id', 'not in', $testUserIds);
// 只有在有时间范围时才添加时间条件
if ($hasTimeRange) {
$orderQuery->where('pay_time', '>', $startTime)
->where('pay_time', '<', $endTime);
}
// 分别获取price和use_money的总和后相加
$priceSum = $orderQuery->sum('price');
$useMoneySum = $orderQuery->sum('use_money');
$useMoney = floatval($priceSum) + floatval($useMoneySum);
// 查询2获取出货成本
$scMoneyQuery = Db::name('order_list')
->where('goods_id', '=', $goodId)
->where('user_id', 'not in', $testUserIds);
if ($hasTimeRange) {
$scMoneyQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$scMoney = $scMoneyQuery->sum('goodslist_money');
// 查询3获取兑换成本
$reMoneyQuery = Db::name('order_list')
->where('goods_id', '=', $goodId)
->where('LENGTH(recovery_num)', '>', 0)
->where('user_id', 'not in', $testUserIds);
if ($hasTimeRange) {
$reMoneyQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$reMoney = $reMoneyQuery->sum('goodslist_money');
// 查询4获取发货成本
$fhMoneyQuery = Db::name('order_list')
->where('goods_id', '=', $goodId)
->where('LENGTH(send_num)', '>', 0)
->where('user_id', 'not in', $testUserIds);
if ($hasTimeRange) {
$fhMoneyQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$fhMoney = $fhMoneyQuery->sum('goodslist_money');
// 查询5获取抽奖次数
$cjCountQuery = Db::name('order_list')
->where('goods_id', '=', $goodId)
->where('user_id', 'not in', $testUserIds)
->where('parent_goods_list_id', '=', 0);
if ($hasTimeRange) {
$cjCountQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$cjCount = $cjCountQuery->count();
// 计算利润和利润率
$profit = floatval($useMoney) - floatval($scMoney);
$profitRate = 0;
if ($useMoney > 0) {
$profitRate = round(($profit / $useMoney) * 100, 2);
}
return [
'use_money' => floatval($useMoney),
'sc_money' => floatval($scMoney),
're_money' => floatval($reMoney),
'fh_money' => floatval($fhMoney),
'cj_count' => intval($cjCount),
'profit' => $profit,
'profit_rate' => $profitRate
];
}
/**
* 获取汇总统计数据(用于导出)
*/
private function getSummaryStatisticsData($goodId, $title, $status, $type, $addtime)
{
// 解析时间范围
$hasTimeRange = false;
$startTime = 0;
$endTime = 0;
if (!empty($addtime)) {
$hasTimeRange = true;
$times = explode(' - ', $addtime);
$startTime = strtotime($times[0]);
$endTime = strtotime($times[1]);
}
// 构建查询条件
$goodsWhere = [['delete_time', '=', null]];
if ($goodId) {
$goodsWhere[] = ['id', '=', $goodId];
}
if ($title) {
$goodsWhere[] = ['title', 'like', '%' . $title . '%'];
}
if ($status) {
$goodsWhere[] = ['status', '=', $status];
}
if ($type) {
$goodsWhere[] = ['type', '=', $type];
}
// 获取符合条件的盒子ID列表
$goodsIds = Db::name('goods')
->where($goodsWhere)
->column('id');
if (empty($goodsIds)) {
return [
'totalIncome' => 0,
'totalCost' => 0,
'totalProfit' => 0,
'totalReMoney' => 0,
'totalFhMoney' => 0
];
}
// 获取测试用户ID
$testUsers = User::where('istest', '>', 0)->column('id');
$testUserIds = empty($testUsers) ? [0] : $testUsers;
// 查询1获取充值金额和余额消费总和
$orderQuery = Db::name('order')
->where('status', '=', 1)
->where(function ($query) {
$query->where('price', '>', 0)
->whereOr('use_money', '>', 0);
})
->where('goods_id', 'in', $goodsIds)
->where('user_id', 'not in', $testUserIds);
// 只有在有时间范围时才添加时间条件
if ($hasTimeRange) {
$orderQuery->where('pay_time', '>', $startTime)
->where('pay_time', '<', $endTime);
}
// 分别获取price和use_money的总和后相加
$priceSum = $orderQuery->sum('price');
$useMoneySum = $orderQuery->sum('use_money');
$totalIncome = floatval($priceSum) + floatval($useMoneySum);
// 查询2获取出货成本
$scMoneyQuery = Db::name('order_list')
->where('goods_id', 'in', $goodsIds)
->where('user_id', 'not in', $testUserIds);
if ($hasTimeRange) {
$scMoneyQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$totalCost = floatval($scMoneyQuery->sum('goodslist_money'));
// 查询3获取兑换成本
$reMoneyQuery = Db::name('order_list')
->where('goods_id', 'in', $goodsIds)
->where('LENGTH(recovery_num)', '>', 0)
->where('user_id', 'not in', $testUserIds);
if ($hasTimeRange) {
$reMoneyQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$totalReMoney = floatval($reMoneyQuery->sum('goodslist_money'));
// 查询4获取发货成本
$fhMoneyQuery = Db::name('order_list')
->where('goods_id', 'in', $goodsIds)
->where('LENGTH(send_num)', '>', 0)
->where('user_id', 'not in', $testUserIds);
if ($hasTimeRange) {
$fhMoneyQuery->where('addtime', '>', $startTime)
->where('addtime', '<', $endTime);
}
$totalFhMoney = floatval($fhMoneyQuery->sum('goodslist_money'));
// 计算总利润
$totalProfit = $totalIncome - $totalCost;
// 返回汇总数据
return [
'totalIncome' => $totalIncome,
'totalCost' => $totalCost,
'totalProfit' => $totalProfit,
'totalReMoney' => $totalReMoney,
'totalFhMoney' => $totalFhMoney
];
}
}

View File

@ -428,4 +428,5 @@ Route::rule('statistics_exchangeList', 'Statistics/exchangeList', 'GET');
Route::rule('statistics_shipmentList', 'Statistics/shipmentList', 'GET');
Route::rule('statistics_productsOverview', 'Statistics/productsOverview', 'GET');
Route::rule('statistics_getBoxStatistics', 'Statistics/getBoxStatistics', 'GET');
Route::rule('statistics_getSummaryStatistics', 'Statistics/getSummaryStatistics', 'GET');
Route::rule('statistics_getSummaryStatistics', 'Statistics/getSummaryStatistics', 'GET');
Route::rule('statistics_exportProfit', 'Statistics/exportProfit', 'GET');

View File

@ -47,6 +47,11 @@
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
</button>
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-normal" id="exportBtn" type="button">
<i class="layui-icon layui-icon-export"></i> 导出Excel
</button>
</div>
</div>
</form>
@ -463,6 +468,46 @@
loadSummaryStatistics();
});
// 导出按钮点击事件
$('#exportBtn').on('click', function () {
// 获取当前查询参数
var params = getSearchParams();
// 弹出确认对话框
layer.confirm('确定要导出当前条件下的所有盒子利润统计数据吗?', {
btn: ['确定', '取消'],
title: '导出确认'
}, function(index) {
layer.close(index);
// 显示加载层
var loadIndex = layer.load(2, {shade: [0.3, '#fff']});
// 构建导出URL及参数
var exportUrl = '{:url("/admin/statistics_exportProfit")}';
var queryString = $.param(params);
if (queryString) {
exportUrl += '?' + queryString;
}
// 创建一个隐藏的a标签用于下载
var downloadLink = document.createElement('a');
downloadLink.style.display = 'none';
downloadLink.href = exportUrl;
downloadLink.target = '_blank';
document.body.appendChild(downloadLink);
// 模拟点击下载
downloadLink.click();
// 移除临时元素
setTimeout(function() {
document.body.removeChild(downloadLink);
layer.close(loadIndex);
}, 2000);
});
});
// 监听表格工具条事件
table.on('tool(profitTable)', function (obj) {
var data = obj.data;