Merge branch 'dev'

This commit is contained in:
zpc 2025-04-19 19:53:42 +08:00
commit da7db72158
3 changed files with 164 additions and 93 deletions

View File

@ -620,7 +620,7 @@ class Statistics extends Base
$productInfos = [];
if (!empty($goodslistIds)) {
$productInfos = GoodsList::where('id', 'in', $goodslistIds)
->field('id, title, imgurl, price, money, sc_money, real_pro')
->field('id, title, imgurl, price, money, sc_money, real_pro, shang_id')
->select()
->toArray();
}
@ -992,7 +992,7 @@ class Statistics extends Base
$headers = [
'ID', '盒子名称', '盒子类型', '状态', '单价', '抽奖次数',
'收入(微信+钻石)', '出货价值', '已兑换达达卷', '已申请发货',
'利润', '利润率(%)'
'单盒子利润', '单盒子利润比(%)', '利润', '利润率(%)'
];
foreach ($headers as $col => $header) {
@ -1010,7 +1010,7 @@ class Statistics extends Base
'startColor' => ['rgb' => 'E0E0E0'],
],
];
$sheet->getStyle('A1:L1')->applyFromArray($headerStyle);
$sheet->getStyle('A1:N1')->applyFromArray($headerStyle);
// 填充数据
$row = 2;
@ -1027,6 +1027,14 @@ class Statistics extends Base
default: $statusText = '自动下架'; break;
}
// 计算单盒子利润和单盒子利润比
$boxIncome = $item['price'] * $statsData['cj_count'];
$singleBoxProfit = $boxIncome - $statsData['sc_money'];
$singleBoxProfitRate = 0;
if ($boxIncome > 0) {
$singleBoxProfitRate = ($singleBoxProfit / $boxIncome) * 100;
}
// 填充一行数据
$sheet->setCellValue('A' . $row, $item['id']);
$sheet->setCellValue('B' . $row, $item['title']);
@ -1038,12 +1046,14 @@ class Statistics extends Base
$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']);
$sheet->setCellValue('K' . $row, $singleBoxProfit);
$sheet->setCellValue('L' . $row, round($singleBoxProfitRate, 2));
$sheet->setCellValue('M' . $row, $statsData['profit']);
$sheet->setCellValue('N' . $row, $statsData['profit_rate']);
// 设置负利润的行为红色背景
if ($statsData['profit'] < 0) {
$sheet->getStyle('A' . $row . ':L' . $row)->getFill()
$sheet->getStyle('A' . $row . ':N' . $row)->getFill()
->setFillType(Fill::FILL_SOLID)
->getStartColor()->setRGB('FFEBEE');
}
@ -1052,7 +1062,7 @@ class Statistics extends Base
}
// 调整列宽
foreach (range('A', 'L') as $col) {
foreach (range('A', 'N') as $col) {
$sheet->getColumnDimension($col)->setAutoSize(true);
}
@ -1066,14 +1076,25 @@ class Statistics extends Base
$sheet->setCellValue('H' . $row, $summaryData['totalCost']);
$sheet->setCellValue('I' . $row, $summaryData['totalReMoney']);
$sheet->setCellValue('J' . $row, $summaryData['totalFhMoney']);
$sheet->setCellValue('K' . $row, $summaryData['totalProfit']);
// 计算汇总单盒子利润和利润比
$totalSingleBoxProfit = $summaryData['totalIncome'] - $summaryData['totalCost'];
$sheet->setCellValue('K' . $row, $totalSingleBoxProfit);
$totalSingleBoxProfitRate = 0;
if ($summaryData['totalIncome'] > 0) {
$totalSingleBoxProfitRate = ($totalSingleBoxProfit / $summaryData['totalIncome']) * 100;
}
$sheet->setCellValue('L' . $row, round($totalSingleBoxProfitRate, 2));
$sheet->setCellValue('M' . $row, $summaryData['totalProfit']);
// 计算总体利润率
$profitRate = 0;
if ($summaryData['totalIncome'] > 0) {
$profitRate = ($summaryData['totalProfit'] / $summaryData['totalIncome']) * 100;
}
$sheet->setCellValue('L' . $row, round($profitRate, 2));
$sheet->setCellValue('N' . $row, round($profitRate, 2));
// 设置汇总行样式
$summaryStyle = [
@ -1083,7 +1104,7 @@ class Statistics extends Base
'startColor' => ['rgb' => ($summaryData['totalProfit'] >= 0 ? 'E8F5E9' : 'FFEBEE')],
],
];
$sheet->getStyle('A' . $row . ':L' . $row)->applyFromArray($summaryStyle);
$sheet->getStyle('A' . $row . ':N' . $row)->applyFromArray($summaryStyle);
// 设置Excel文件属性
$spreadsheet->getProperties()

View File

@ -15,21 +15,108 @@
$totalValue = 0;
foreach($list as $item) {
$totalCount += isset($item['goods_count']) ? $item['goods_count'] : 0;
$sc_money = isset($item['sc_money']) ? $item['sc_money'] : 0;
$money = isset($item['money']) ? $item['money'] : 0;
$goods_count = isset($item['goods_count']) ? $item['goods_count'] : 0;
$totalValue += $sc_money * $goods_count;
$totalValue += $money * $goods_count;
}
?>
<!-- 统计摘要 -->
{if condition="!empty($list)"}
<div class="layui-card" style="margin-bottom: 20px;">
<div class="layui-card-header">统计摘要</div>
<div class="layui-card-body">
<div class="layui-row layui-col-space15">
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">总出货数量</div>
<div class="layui-card-body" style="font-size: 24px; color: #01AAED;">
{$totalCount}
</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">总出货价值</div>
<div class="layui-card-body" style="font-size: 24px; color: #FF5722;">
¥ {$totalValue|round=2}
</div>
</div>
</div>
</div>
<?php if($totalCount > 0): ?>
<div class="layui-row layui-col-space15" style="margin-top: 15px;">
<div class="layui-col-md4">
<div class="layui-card">
<div class="layui-card-header">平均每次出货价值/盒子单价</div>
<div class="layui-card-body" style="font-size: 24px; color: #01AAED;">
¥ <?php echo round($totalValue / $totalCount, 2); ?>/
<?php echo round($boxInfo['price']); ?>
</div>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-card">
<div class="layui-card-header">平均出货价值/盒子单价</div>
<div class="layui-card-body" style="font-size: 24px; color: #FF5722;">
<?php
$avgValue = $totalValue / $totalCount;
$boxPrice = isset($boxInfo['price']) ? $boxInfo['price'] : 0;
$ratio = $boxPrice > 0 ? round(($avgValue / $boxPrice), 2) : 0;
echo $ratio . ' 倍';
?>
</div>
</div>
</div>
<div class="layui-col-md4">
<div class="layui-card">
<div class="layui-card-header">数据分析</div>
<div class="layui-card-body">
<?php
// 寻找出货金额最多的奖品
$maxValue = 0;
$maxItem = null;
foreach($list as $item) {
$goods_count = isset($item['goods_count']) ? $item['goods_count'] : 0;
$money = isset($item['money']) ? $item['money'] : 0;
$itemValue = $money * $goods_count;
if($itemValue > $maxValue) {
$maxValue = $itemValue;
$maxItem = $item;
}
}
if($maxItem) {
$goods_count = isset($maxItem['goods_count']) ? $maxItem['goods_count'] : 0;
$money = isset($maxItem['money']) ? $maxItem['money'] : 0;
$itemValue = $money * $goods_count;
echo "<p>出货金额最多的奖品: <strong>".$maxItem['title']."</strong> (¥".round($itemValue, 2).")</p>";
// 计算占总金额的百分比
$valuePercent = $totalValue > 0 ? round(($itemValue / $totalValue) * 100, 2) : 0;
echo "<p>占总出货金额的: <span style=\"color: #01AAED; font-weight: bold;\">".$valuePercent."%</span></p>";
}
?>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
{/if}
<table class="layui-table">
<thead>
<tr>
<th>奖品ID</th>
<th>奖品类型</th>
<th>奖品名称</th>
<th>奖品图片</th>
<th>出货数量</th>
<th>奖品单价</th>
<th>兑换金额</th>
<th>出货金额</th>
<th>理论概率</th>
<th>实际概率</th>
<th>概率偏差</th>
@ -40,6 +127,7 @@
{volist name="list" id="vo"}
<tr>
<td>{$vo.goodslist_id}</td>
<td>{$vo.shang_id|default="0"}</td>
<td>{$vo.title}</td>
<td>
<img src="{$vo.imgurl}" style="height:50px;" onerror="this.src='/static/admin/images/nopic.jpg'">
@ -49,7 +137,6 @@
</td>
<td>¥ {$vo.price|default="0"}</td>
<td>¥ {$vo.money|default="0"}</td>
<td>¥ {$vo.sc_money|default="0"}</td>
<td>
<span class="layui-badge layui-bg-green">{$vo.real_pro|default="0"}%</span>
</td>
@ -74,9 +161,9 @@
</td>
<td>
<?php
$sc_money = isset($vo['sc_money']) ? $vo['sc_money'] : 0;
$money = isset($vo['money']) ? $vo['money'] : 0;
$goods_count = isset($vo['goods_count']) ? $vo['goods_count'] : 0;
$total_value = $sc_money * $goods_count;
$total_value = $money * $goods_count;
?>
¥ <?php echo round($total_value, 2); ?>
</td>
@ -89,78 +176,6 @@
{/if}
</tbody>
</table>
<!-- 统计摘要 -->
{if condition="!empty($list)"}
<div class="layui-card">
<div class="layui-card-header">统计摘要</div>
<div class="layui-card-body">
<div class="layui-row layui-col-space15">
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">总出货数量</div>
<div class="layui-card-body" style="font-size: 24px; color: #01AAED;">
{$totalCount}
</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">总出货价值</div>
<div class="layui-card-body" style="font-size: 24px; color: #FF5722;">
¥ {$totalValue|round=2}
</div>
</div>
</div>
</div>
<?php if($totalCount > 0): ?>
<div class="layui-row layui-col-space15" style="margin-top: 15px;">
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">平均每次出货价值</div>
<div class="layui-card-body" style="font-size: 24px; color: #01AAED;">
¥ <?php echo round($totalValue / $totalCount, 2); ?>
</div>
</div>
</div>
<div class="layui-col-md6">
<div class="layui-card">
<div class="layui-card-header">数据分析</div>
<div class="layui-card-body">
<?php
// 寻找实际概率最高的奖品
$maxPercent = 0;
$maxItem = null;
foreach($list as $item) {
$goods_count = isset($item['goods_count']) ? $item['goods_count'] : 0;
$percent = round(($goods_count / $totalCount) * 100, 2);
if($percent > $maxPercent) {
$maxPercent = $percent;
$maxItem = $item;
}
}
if($maxItem) {
echo "<p>出货概率最高的奖品: <strong>".$maxItem['title']."</strong> (".$maxPercent."%)</p>";
$real_pro = isset($maxItem['real_pro']) ? $maxItem['real_pro'] : 0;
$diff = round($maxPercent - $real_pro, 2);
$diffText = $diff >= 0 ? "高于" : "低于";
$absDiff = abs($diff);
$diffColor = $diff >= 0 ? "#5FB878" : "#FF5722";
?>
<p>与理论概率相比: <span style="color: <?php echo $diffColor; ?>"><?php echo $diffText; ?>理论值 <?php echo $absDiff; ?>%</span></p>
<?php
}
?>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
{/if}
</div>
</div>
</div>

View File

@ -217,7 +217,7 @@
},
cols: [[
{ field: 'id', title: '盒子ID', width: 80, sort: true, fixed: 'left' },
{ field: 'title', title: '盒子名称', width: 200 },
{ field: 'title', title: '盒子名称', width: 180 },
{
templet: function (d) {
var statusHtml = '';
@ -235,7 +235,7 @@
},
{ field: 'price', title: '盒子单价', width: 100, templet: '<div>¥ {{d.price}}</div>' },
{
field: 'cj_count', title: '抽奖次数', width: 100, templet: function (d) {
field: 'cj_count', title: '抽奖次数', width: 90, templet: function (d) {
if (!d.loaded) {
return '<div><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
}
@ -243,7 +243,7 @@
}
},
{
field: 'use_money', title: '收入 <i class="layui-icon layui-icon-about" title="微信支付+钻石支付"></i>', width: 150, templet: function (d) {
field: 'use_money', title: '收入 <i class="layui-icon layui-icon-about" title="微信支付+钻石支付"></i>', width: 140, templet: function (d) {
if (!d.loaded) {
return '<div><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
}
@ -251,7 +251,7 @@
}
},
{
field: 'sc_money', title: '出货价值 <i class="layui-icon layui-icon-about" title="奖品的兑换价格"></i>', width: 150, templet: function (d) {
field: 'sc_money', title: '出货价值 <i class="layui-icon layui-icon-about" title="奖品的兑换价格"></i>', width: 140, templet: function (d) {
if (!d.loaded) {
return '<div><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
}
@ -259,7 +259,7 @@
}
},
{
field: 're_money', title: '已兑换达达卷', width: 150, templet: function (d) {
field: 're_money', title: '已兑换达达卷', width: 120, templet: function (d) {
if (!d.loaded) {
return '<div><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
}
@ -274,6 +274,30 @@
return '<div><span class="layui-badge" style="background-color: #673AB7;">¥ ' + d.fh_money.toFixed(2) + '</span></div>';
}
},
{
field: 'single_box_profit', title: '单盒子利润 <i class="layui-icon layui-icon-about" title="盒子单价 × 抽数 - 盒子出货总额"></i>', width: 120, templet: function (d) {
if (!d.loaded) {
return '<div><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
}
// 计算公式盒子单价x抽数-盒子出货总额
var totalIncome = d.price * d.cj_count;
var singleBoxProfit = totalIncome - d.sc_money;
var colorClass = singleBoxProfit >= 0 ? 'layui-bg-green' : 'layui-bg-red';
return '<div><span class="layui-badge ' + colorClass + '">¥ ' + singleBoxProfit.toFixed(2) + '</span></div>';
}
},
{
field: 'single_box_profit_rate', title: '单盒子利润比 <i class="layui-icon layui-icon-about" title="(盒子单价 × 抽数 - 盒子出货总额) / (盒子单价 × 抽数) × 100%"></i>', width: 140, templet: function (d) {
if (!d.loaded) {
return '<div><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>';
}
// 计算公式:(盒子单价x抽数-盒子出货总额)/(盒子单价x抽数)
var totalIncome = d.price * d.cj_count;
var singleBoxProfitRate = totalIncome > 0 ? ((totalIncome - d.sc_money) / totalIncome * 100) : 0;
var colorClass = singleBoxProfitRate >= 0 ? 'layui-bg-green' : 'layui-bg-red';
return '<div><span class="layui-badge ' + colorClass + '">' + singleBoxProfitRate.toFixed(2) + '%</span></div>';
}
},
{
field: 'profit', title: '利润 <i class="layui-icon layui-icon-about" title="收入-出货价值"></i>', width: 110, templet: function (d) {
if (!d.loaded) {
@ -404,6 +428,17 @@
tr.find('td[data-field="fh_money"] div').html('<span class="layui-badge" style="background-color: #673AB7;">¥ ' + data.fh_money.toFixed(2) + '</span>');
tr.find('td[data-field="cj_count"] div').html(data.cj_count);
// 计算并更新单盒子利润
var totalIncome = tableData[i].price * data.cj_count;
var singleBoxProfit = totalIncome - data.sc_money;
var singleBoxProfitClass = singleBoxProfit >= 0 ? 'layui-bg-green' : 'layui-bg-red';
tr.find('td[data-field="single_box_profit"] div').html('<span class="layui-badge ' + singleBoxProfitClass + '">¥ ' + singleBoxProfit.toFixed(2) + '</span>');
// 计算并更新单盒子利润比
var singleBoxProfitRate = totalIncome > 0 ? ((totalIncome - data.sc_money) / totalIncome * 100) : 0;
var singleBoxColorClass = singleBoxProfitRate >= 0 ? 'layui-bg-green' : 'layui-bg-red';
tr.find('td[data-field="single_box_profit_rate"] div').html('<span class="layui-badge ' + singleBoxColorClass + '">' + singleBoxProfitRate.toFixed(2) + '%</span>');
var profitColorClass = data.profit >= 0 ? 'layui-bg-green' : 'layui-bg-red';
tr.find('td[data-field="profit"] div').html('<span class="layui-badge ' + profitColorClass + '">¥ ' + data.profit.toFixed(2) + '</span>');