提交代码
This commit is contained in:
parent
e81b954d0a
commit
3bc11c8d0e
|
|
@ -43,22 +43,39 @@ class Statistics extends Base
|
|||
if ($type) {
|
||||
$where[] = ['type', '=', $type];
|
||||
}
|
||||
return View::fetch("Statistics/profit");
|
||||
}
|
||||
/**
|
||||
* 盒子利润统计数据接口(用于前端分离模式)
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function profitData(Request $request)
|
||||
{
|
||||
$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'));
|
||||
$page = intval(input('page', 1));
|
||||
$limit = intval(input('limit', 20));
|
||||
|
||||
// 解析时间范围
|
||||
$startTime = 0;
|
||||
$endTime = time();
|
||||
if ($addtime) {
|
||||
$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;
|
||||
$testUserIdsStr = implode(',', $testUserIds);
|
||||
|
||||
// 构建SQL查询
|
||||
// 构建SQL查询,只返回基本信息
|
||||
$query = Db::name('goods')->alias('goods')
|
||||
->field([
|
||||
'goods.id',
|
||||
|
|
@ -67,54 +84,70 @@ class Statistics extends Base
|
|||
'goods.price',
|
||||
'goods.stock',
|
||||
'goods.status',
|
||||
'goods.type',
|
||||
'(SELECT COALESCE(sum(use_money), 0) + COALESCE(sum(price), 0) FROM `order` WHERE status=1 AND (price>0 OR use_money>0) AND pay_time > ' . $startTime . ' and pay_time < ' . $endTime . ' AND goods_id=goods.id AND status=1 AND user_id NOT IN (' . $testUserIdsStr . ')) AS use_money',
|
||||
'(SELECT COALESCE(sum(goodslist_money), 0) FROM `order_list` WHERE goods_id=goods.id AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ') AS sc_money',
|
||||
'(SELECT COALESCE(sum(goodslist_money), 0) FROM `order_list` WHERE goods_id=goods.id AND LENGTH(recovery_num)>0 AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ') AS re_money',
|
||||
'(SELECT COALESCE(sum(goodslist_money), 0) FROM `order_list` WHERE goods_id=goods.id AND LENGTH(send_num)>0 AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ') AS fh_money',
|
||||
'(SELECT count(1) FROM `order_list` WHERE goods_id=goods.id AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ' and parent_goods_list_id=0 ) AS cj_count'
|
||||
'goods.type'
|
||||
])
|
||||
->where($where)
|
||||
->order(['goods.id' => 'desc']);
|
||||
|
||||
// 获取列表数据
|
||||
$list = $query->select()->toArray();
|
||||
// 获取总数量
|
||||
$total = $query->count();
|
||||
|
||||
// 分页
|
||||
$list = $query->page($page, $limit)->select()->toArray();
|
||||
|
||||
// 计算总金额
|
||||
$totalIncome = 0;
|
||||
$totalCost = 0;
|
||||
$totalProfit = 0;
|
||||
$totalReMoney = 0;
|
||||
$totalFhMoney = 0;
|
||||
|
||||
foreach ($list as &$item) {
|
||||
// 计算单个盒子的利润和利润率
|
||||
$item['profit'] = $item['use_money'] - $item['sc_money'];
|
||||
$item['profit_rate'] = $item['use_money'] > 0 ? round(($item['profit'] / $item['use_money']) * 100, 2) : 0;
|
||||
$item['is_negative'] = $item['profit'] < 0;
|
||||
|
||||
// 计算总金额
|
||||
$totalIncome += $item['use_money'];
|
||||
$totalCost += $item['sc_money'];
|
||||
$totalReMoney += $item['re_money'];
|
||||
$totalFhMoney += $item['fh_money'];
|
||||
// 获取盒子类型名称
|
||||
$typesList = $this->getGoodsTypes();
|
||||
$typesMap = [];
|
||||
foreach ($typesList as $item) {
|
||||
$typesMap[$item['value']] = $item['fl_name'];
|
||||
}
|
||||
|
||||
$totalProfit = $totalIncome - $totalCost;
|
||||
// 初始化统计数据为0
|
||||
foreach ($list as &$item) {
|
||||
// 添加类型名称
|
||||
$item['type_name'] = isset($typesMap[$item['type']]) ? $typesMap[$item['type']] : '未知类型';
|
||||
|
||||
// 初始化统计字段为0,后续会异步加载
|
||||
$item['use_money'] = 0;
|
||||
$item['sc_money'] = 0;
|
||||
$item['re_money'] = 0;
|
||||
$item['fh_money'] = 0;
|
||||
$item['cj_count'] = 0;
|
||||
$item['profit'] = 0;
|
||||
$item['profit_rate'] = 0;
|
||||
$item['is_negative'] = false;
|
||||
$item['loaded'] = false; // 标记是否已加载统计数据
|
||||
}
|
||||
|
||||
// 传递数据给视图
|
||||
View::assign([
|
||||
'list' => $list,
|
||||
'totalIncome' => $totalIncome,
|
||||
'totalCost' => $totalCost,
|
||||
'totalProfit' => $totalProfit,
|
||||
'totalReMoney' => $totalReMoney,
|
||||
'totalFhMoney' => $totalFhMoney,
|
||||
// 返回JSON数据
|
||||
return json([
|
||||
'code' => 0,
|
||||
'msg' => '获取数据成功',
|
||||
'count' => $total,
|
||||
'data' => $list,
|
||||
'summary' => [
|
||||
'totalIncome' => 0,
|
||||
'totalCost' => 0,
|
||||
'totalProfit' => 0,
|
||||
'totalReMoney' => 0,
|
||||
'totalFhMoney' => 0,
|
||||
]
|
||||
]);
|
||||
|
||||
return View::fetch("Statistics/profit");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取盒子类型列表(用于API调用)
|
||||
*/
|
||||
private function getGoodsTypes()
|
||||
{
|
||||
$types = Db::name('goods_type')
|
||||
->field('value, fl_name, remark')
|
||||
->where('is_fenlei', 1)
|
||||
->order('sort_order asc')
|
||||
->select()
|
||||
->toArray();
|
||||
return $types;
|
||||
}
|
||||
/**
|
||||
* 解析时间范围
|
||||
*/
|
||||
|
|
@ -616,4 +649,63 @@ class Statistics extends Base
|
|||
return View::fetch('Statistics/productsOverview');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个盒子的统计数据
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function getBoxStatistics(Request $request)
|
||||
{
|
||||
$goodId = intval(input('get.goods_id', 0));
|
||||
$addtime = trim(input('get.addtime', ''));
|
||||
|
||||
if ($goodId <= 0) {
|
||||
return json(['code' => 1, 'msg' => '参数错误']);
|
||||
}
|
||||
|
||||
// 解析时间范围
|
||||
$startTime = 0;
|
||||
$endTime = time();
|
||||
if ($addtime) {
|
||||
$times = explode(' - ', $addtime);
|
||||
$startTime = strtotime($times[0]);
|
||||
$endTime = strtotime($times[1]);
|
||||
}
|
||||
|
||||
// 获取测试用户ID
|
||||
$testUsers = User::where('istest', '>', 0)->column('id');
|
||||
$testUserIds = empty($testUsers) ? [0] : $testUsers;
|
||||
$testUserIdsStr = implode(',', $testUserIds);
|
||||
|
||||
// 查询单个盒子的统计数据
|
||||
$data = Db::name('goods')->alias('goods')
|
||||
->field([
|
||||
'goods.id',
|
||||
'(SELECT COALESCE(sum(use_money), 0) + COALESCE(sum(price), 0) FROM `order` WHERE status=1 AND (price>0 OR use_money>0) AND pay_time > ' . $startTime . ' and pay_time < ' . $endTime . ' AND goods_id=goods.id AND status=1 AND user_id NOT IN (' . $testUserIdsStr . ')) AS use_money',
|
||||
'(SELECT COALESCE(sum(goodslist_money), 0) FROM `order_list` WHERE goods_id=goods.id AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ') AS sc_money',
|
||||
'(SELECT COALESCE(sum(goodslist_money), 0) FROM `order_list` WHERE goods_id=goods.id AND LENGTH(recovery_num)>0 AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ') AS re_money',
|
||||
'(SELECT COALESCE(sum(goodslist_money), 0) FROM `order_list` WHERE goods_id=goods.id AND LENGTH(send_num)>0 AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ') AS fh_money',
|
||||
'(SELECT count(1) FROM `order_list` WHERE goods_id=goods.id AND user_id NOT IN (' . $testUserIdsStr . ') AND addtime > ' . $startTime . ' and addtime < ' . $endTime . ' and parent_goods_list_id=0 ) AS cj_count'
|
||||
])
|
||||
->where('goods.id', '=', $goodId)
|
||||
->find();
|
||||
|
||||
if (!$data) {
|
||||
return json(['code' => 1, 'msg' => '盒子不存在']);
|
||||
}
|
||||
|
||||
// 处理数值,确保为浮点型
|
||||
$data['use_money'] = floatval($data['use_money']);
|
||||
$data['sc_money'] = floatval($data['sc_money']);
|
||||
$data['re_money'] = floatval($data['re_money']);
|
||||
$data['fh_money'] = floatval($data['fh_money']);
|
||||
|
||||
// 计算利润和利润率
|
||||
$data['profit'] = $data['use_money'] - $data['sc_money'];
|
||||
$data['profit_rate'] = $data['use_money'] > 0 ? round(($data['profit'] / $data['use_money']) * 100, 2) : 0;
|
||||
$data['is_negative'] = $data['profit'] < 0;
|
||||
|
||||
return json(['code' => 0, 'msg' => '获取成功', 'data' => $data]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,4 +415,15 @@ Route::get('sign_config_coupons', 'SignConfig/getCoupons');
|
|||
#UserRank.php用户排行榜
|
||||
#============================
|
||||
Route::rule('user_rank', 'UserRank/index', 'GET');
|
||||
Route::rule('user_rank_data', 'UserRank/getRankData', 'GET');
|
||||
Route::rule('user_rank_data', 'UserRank/getRankData', 'GET');
|
||||
|
||||
#============================
|
||||
#Statistics.php统计管理
|
||||
#============================
|
||||
Route::rule('statistics_profit', 'Statistics/profit', 'GET');
|
||||
Route::rule('statistics/profitData', 'Statistics/profitData', 'GET');
|
||||
Route::rule('statistics_order', 'Statistics/orderList', 'GET');
|
||||
Route::rule('statistics_orderList', 'Statistics/goodsList', 'GET');
|
||||
Route::rule('statistics_exchangeList', 'Statistics/exchangeList', 'GET');
|
||||
Route::rule('statistics_shipmentList', 'Statistics/shipmentList', 'GET');
|
||||
Route::rule('statistics_productsOverview', 'Statistics/productsOverview', 'GET');
|
||||
|
|
@ -4,27 +4,25 @@
|
|||
<div class="layui-fluid">
|
||||
<div class="layui-card">
|
||||
<!-- 搜索条件区域 -->
|
||||
<form method="get" class="layui-form layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form layui-card-header layuiadmin-card-header-auto">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<div class="layui-input-inline" style="width:150px;margin-left: 0px">
|
||||
<input type="text" name="goodId" value="{$Request.get.goodId}" placeholder="请输入盒子Id"
|
||||
autocomplete="off" class="layui-input">
|
||||
<input type="text" name="goodId" id="goodId" placeholder="请输入盒子Id" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<div class="layui-input-inline" style="width:150px;margin-left: 0px">
|
||||
<input type="text" name="title" value="{$Request.get.title}" placeholder="请输入盒子名称"
|
||||
autocomplete="off" class="layui-input">
|
||||
<input type="text" name="title" id="title" placeholder="请输入盒子名称" autocomplete="off" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<div class="layui-input-inline" style="width: 180px;margin-left: 0px">
|
||||
<select name="status" style="width:100%">
|
||||
<select name="status" id="status" style="width:100%">
|
||||
<option value="">--请选择盒子状态--</option>
|
||||
<option value="1" {if condition="$Request.get.status eq 1" }selected{/if}>上架</option>
|
||||
<option value="2" {if condition="$Request.get.status eq 2" }selected{/if}>下架</option>
|
||||
<option value="3" {if condition="$Request.get.status eq 3" }selected{/if}>售罄</option>
|
||||
<option value="1">上架</option>
|
||||
<option value="2">下架</option>
|
||||
<option value="3">售罄</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -37,13 +35,12 @@
|
|||
</div>
|
||||
<div class="layui-inline">
|
||||
<div class="layui-input-inline" style="width:300px;margin-left: 0px">
|
||||
<input type="text" id="addtime" name="addtime" value="{$Request.get.addtime}"
|
||||
class="layui-input" placeholder="选择时间" autocomplete="off">
|
||||
<input type="text" id="addtime" name="addtime" class="layui-input" placeholder="选择时间" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layuiadmin-btn-useradmin mmm" lay-submit lay-filter="LAY-user-front-search">
|
||||
<button class="layui-btn layuiadmin-btn-useradmin" id="searchBtn" type="button">
|
||||
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -52,12 +49,12 @@
|
|||
|
||||
<!-- 统计摘要区域 -->
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-row layui-col-space15" id="statisticsSummary">
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总收入</div>
|
||||
<div class="layui-card-body" style="font-size: 24px; color: #01AAED;">
|
||||
¥ {$totalIncome|default="0"|round=2}
|
||||
¥ <span id="totalIncome">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -65,15 +62,15 @@
|
|||
<div class="layui-card">
|
||||
<div class="layui-card-header">总出货价值</div>
|
||||
<div class="layui-card-body" style="font-size: 24px; color: #FFB800;">
|
||||
¥ {$totalCost|default="0"|round=2}
|
||||
¥ <span id="totalCost">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">总利润</div>
|
||||
<div class="layui-card-body" style="font-size: 24px; color: {$totalProfit >= 0 ? '#5FB878' : '#FF5722'};">
|
||||
¥ {$totalProfit|default="0"|round=2}
|
||||
<div class="layui-card-body" style="font-size: 24px;">
|
||||
¥ <span id="totalProfit" class="profit-value">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -81,88 +78,33 @@
|
|||
<div class="layui-card">
|
||||
<div class="layui-card-header">总兑换/发货价值</div>
|
||||
<div class="layui-card-body" style="font-size: 24px;">
|
||||
<span style="color: #FF9800;">¥ {$totalReMoney|default="0"|round=2}</span> /
|
||||
<span style="color: #673AB7;">¥ {$totalFhMoney|default="0"|round=2}</span>
|
||||
<span style="color: #FF9800;">¥ <span id="totalReMoney">0.00</span></span> /
|
||||
<span style="color: #673AB7;">¥ <span id="totalFhMoney">0.00</span></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<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>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{volist name="list" id="vo"}
|
||||
<tr {if condition="$vo.is_negative"}style="background-color: #ffebee;"{/if}>
|
||||
<td>{$vo.id}</td>
|
||||
<td>{$vo.title}</td>
|
||||
<td>
|
||||
<button class="layui-btn layui-btn-normal layui-btn-radius layui-btn-xs" data-type="{$vo.type}">加载中...</button>
|
||||
/
|
||||
{if condition="$vo.status eq 1"}
|
||||
<span class="layui-badge layui-bg-green">上架</span>
|
||||
{elseif condition="$vo.status eq 2"}
|
||||
<span class="layui-badge layui-bg-gray">下架</span>
|
||||
{elseif condition="$vo.status eq 3"}
|
||||
<span class="layui-badge layui-bg-orange">售罄</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td>¥ {$vo.price}</td>
|
||||
<td>{$vo.cj_count}</td>
|
||||
<td>
|
||||
<span class="layui-badge layui-bg-blue">¥ {$vo.use_money|default="0"|round=2}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="layui-badge layui-bg-orange">¥ {$vo.sc_money|default="0"|round=2}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="layui-badge" style="background-color: #FF9800;">¥ {$vo.re_money|default="0"|round=2}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="layui-badge" style="background-color: #673AB7;">¥ {$vo.fh_money|default="0"|round=2}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="layui-badge {if condition="$vo.profit >= 0"}layui-bg-green{else}layui-bg-red{/if}">
|
||||
¥ {$vo.profit|default="0"|round=2}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="layui-badge {if condition="$vo.profit_rate >= 0"}layui-bg-green{else}layui-bg-red{/if}">
|
||||
{$vo.profit_rate|default="0"|round=2}%
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="layui-btn layui-btn-danger layui-btn-xs" onclick="viewProductsOverview({$vo.id})">出货概览</button>
|
||||
<!-- <button class="layui-btn layui-btn-xs" onclick="viewOrders({$vo.id})">支付订单</button>
|
||||
<button class="layui-btn layui-btn-normal layui-btn-xs" onclick="viewOrderLists({$vo.id})">出货明细</button>
|
||||
|
||||
<button class="layui-btn layui-btn-warm layui-btn-xs" onclick="viewExchangeList({$vo.id})">兑换明细</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-xs" onclick="viewShipmentList({$vo.id})">发货明细</button> -->
|
||||
</td>
|
||||
</tr>
|
||||
{/volist}
|
||||
{if condition="empty($list)"}
|
||||
<tr>
|
||||
<td colspan="11" style="text-align:center;">暂时没有数据!</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</tbody>
|
||||
</table>
|
||||
<table id="profitTable" lay-filter="profitTable"></table>
|
||||
|
||||
<!-- 表格操作栏模板 -->
|
||||
<script type="text/html" id="operationTpl">
|
||||
<button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="viewProductsOverview">出货概览</button>
|
||||
</script>
|
||||
|
||||
<!-- 利润和利润率模板 -->
|
||||
<script type="text/html" id="profitTpl">
|
||||
<span class="layui-badge {{d.profit >= 0 ? 'layui-bg-green' : 'layui-bg-red'}}">
|
||||
¥ {{d.profit.toFixed(2)}}
|
||||
</span>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="profitRateTpl">
|
||||
<span class="layui-badge {{d.profit_rate >= 0 ? 'layui-bg-green' : 'layui-bg-red'}}">
|
||||
{{d.profit_rate.toFixed(2)}}%
|
||||
</span>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -173,6 +115,7 @@
|
|||
var layer = layui.layer;
|
||||
var laydate = layui.laydate;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
|
||||
// 日期时间范围
|
||||
laydate.render({
|
||||
|
|
@ -180,7 +123,7 @@
|
|||
type: 'datetime',
|
||||
range: true
|
||||
});
|
||||
|
||||
|
||||
// 加载盒子类型数据
|
||||
function loadGoodsTypes() {
|
||||
$.ajax({
|
||||
|
|
@ -192,102 +135,294 @@
|
|||
var html = '<option value="">--盒子类型--</option>';
|
||||
|
||||
$.each(res.data, function (index, item) {
|
||||
if(item.value == '{$Request.get.type}'){
|
||||
html += '<option value="' + item.value + '" title="' + item.remark + '" selected>' + item.fl_name + '</option>';
|
||||
} else {
|
||||
html += '<option value="' + item.value + '" title="' + item.remark + '">' + item.fl_name + '</option>';
|
||||
}
|
||||
html += '<option value="' + item.value + '" title="' + item.remark + '">' + item.fl_name + '</option>';
|
||||
});
|
||||
$('#goodsType').html(html);
|
||||
form.render('select');
|
||||
|
||||
// 更新表格中的类型显示
|
||||
$('button[data-type]').each(function() {
|
||||
var type = $(this).data('type');
|
||||
var typeInfo = res.data.find(function(item) {
|
||||
return item.value == type;
|
||||
});
|
||||
if (typeInfo) {
|
||||
$(this).text(typeInfo.fl_name);
|
||||
} else {
|
||||
$(this).text('未知类型');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 全局变量,存储汇总数据
|
||||
var summaryData = {
|
||||
totalIncome: 0,
|
||||
totalCost: 0,
|
||||
totalProfit: 0,
|
||||
totalReMoney: 0,
|
||||
totalFhMoney: 0
|
||||
};
|
||||
|
||||
// 全局变量,用于控制异步加载
|
||||
var loadingQueue = [];
|
||||
var isLoading = false;
|
||||
var maxConcurrentRequests = 3; // 最大并发请求数
|
||||
|
||||
// 初始化表格
|
||||
var profitTable = table.render({
|
||||
elem: '#profitTable',
|
||||
url: '{:url("/admin/statistics/profitData")}',
|
||||
method: 'get',
|
||||
page: true,
|
||||
limit: 20,
|
||||
where: getSearchParams(),
|
||||
parseData: function(res) {
|
||||
if (res.code === 0) {
|
||||
// 清空汇总数据
|
||||
summaryData = {
|
||||
totalIncome: 0,
|
||||
totalCost: 0,
|
||||
totalProfit: 0,
|
||||
totalReMoney: 0,
|
||||
totalFhMoney: 0
|
||||
};
|
||||
|
||||
// 更新统计摘要数据为0
|
||||
updateStatisticsSummary(summaryData);
|
||||
|
||||
return {
|
||||
"code": 0,
|
||||
"msg": res.msg,
|
||||
"count": res.count,
|
||||
"data": res.data
|
||||
};
|
||||
}
|
||||
return {
|
||||
"code": res.code,
|
||||
"msg": res.msg,
|
||||
"count": 0,
|
||||
"data": []
|
||||
};
|
||||
},
|
||||
cols: [[
|
||||
{field: 'id', title: '盒子ID', width: 80, sort: true, fixed: 'left'},
|
||||
{field: 'title', title: '盒子名称', width: 180},
|
||||
{templet: function(d) {
|
||||
var statusHtml = '';
|
||||
if(d.status == 1) {
|
||||
statusHtml = '<span class="layui-badge layui-bg-green">上架</span>';
|
||||
} else if(d.status == 2) {
|
||||
statusHtml = '<span class="layui-badge layui-bg-gray">下架</span>';
|
||||
} else if(d.status == 3) {
|
||||
statusHtml = '<span class="layui-badge layui-bg-orange">售罄</span>';
|
||||
}
|
||||
return '<div><button class="layui-btn layui-btn-normal layui-btn-radius layui-btn-xs type-btn" data-type="'+d.type+'">'+d.type_name+'</button> / ' + statusHtml + '</div>';
|
||||
}, title: '盒子类型/状态', width: 160},
|
||||
{field: 'price', title: '盒子单价', width: 100, templet: '<div>¥ {{d.price}}</div>'},
|
||||
{field: 'cj_count', title: '抽奖次数', width: 100, 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>';
|
||||
}
|
||||
return '<div>' + d.cj_count + '</div>';
|
||||
}},
|
||||
{field: 'use_money', title: '收入', width: 110, 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>';
|
||||
}
|
||||
return '<div><span class="layui-badge layui-bg-blue">¥ ' + d.use_money.toFixed(2) + '</span></div>';
|
||||
}},
|
||||
{field: 'sc_money', title: '出货价值', width: 110, 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>';
|
||||
}
|
||||
return '<div><span class="layui-badge layui-bg-orange">¥ ' + d.sc_money.toFixed(2) + '</span></div>';
|
||||
}},
|
||||
{field: 're_money', title: '兑换价值', width: 110, 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>';
|
||||
}
|
||||
return '<div><span class="layui-badge" style="background-color: #FF9800;">¥ ' + d.re_money.toFixed(2) + '</span></div>';
|
||||
}},
|
||||
{field: 'fh_money', title: '发货价值', width: 110, 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>';
|
||||
}
|
||||
return '<div><span class="layui-badge" style="background-color: #673AB7;">¥ ' + d.fh_money.toFixed(2) + '</span></div>';
|
||||
}},
|
||||
{field: 'profit', title: '利润', width: 110, 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>';
|
||||
}
|
||||
var colorClass = d.profit >= 0 ? 'layui-bg-green' : 'layui-bg-red';
|
||||
return '<div><span class="layui-badge ' + colorClass + '">¥ ' + d.profit.toFixed(2) + '</span></div>';
|
||||
}},
|
||||
{field: 'profit_rate', title: '利润率', width: 100, 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>';
|
||||
}
|
||||
var colorClass = d.profit_rate >= 0 ? 'layui-bg-green' : 'layui-bg-red';
|
||||
return '<div><span class="layui-badge ' + colorClass + '">' + d.profit_rate.toFixed(2) + '%</span></div>';
|
||||
}},
|
||||
{title: '操作', width: 110, toolbar: '#operationTpl', fixed: 'right'}
|
||||
]],
|
||||
done: function(res) {
|
||||
// 清空加载队列
|
||||
loadingQueue = [];
|
||||
isLoading = false;
|
||||
|
||||
// 将所有数据项添加到加载队列中
|
||||
var tableData = table.cache.profitTable || [];
|
||||
for (var i = 0; i < tableData.length; i++) {
|
||||
if (!tableData[i].loaded) {
|
||||
loadingQueue.push(tableData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 开始加载统计数据
|
||||
processLoadingQueue();
|
||||
}
|
||||
});
|
||||
|
||||
// 处理加载队列
|
||||
function processLoadingQueue() {
|
||||
if (isLoading || loadingQueue.length === 0) return;
|
||||
|
||||
isLoading = true;
|
||||
var requests = 0;
|
||||
var activeRequests = 0;
|
||||
|
||||
// 获取当前需要处理的项目
|
||||
while (requests < maxConcurrentRequests && loadingQueue.length > 0) {
|
||||
var item = loadingQueue.shift();
|
||||
requests++;
|
||||
activeRequests++;
|
||||
|
||||
loadBoxStatistics(item, function() {
|
||||
activeRequests--;
|
||||
if (activeRequests === 0) {
|
||||
isLoading = false;
|
||||
processLoadingQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 加载单个盒子的统计数据
|
||||
function loadBoxStatistics(item, callback) {
|
||||
var params = getSearchParams();
|
||||
|
||||
$.ajax({
|
||||
url: '{:url("/admin/statistics/getBoxStatistics")}',
|
||||
type: 'GET',
|
||||
data: {
|
||||
goods_id: item.id,
|
||||
addtime: params.addtime
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 0) {
|
||||
var data = res.data;
|
||||
|
||||
// 更新表格中的数据
|
||||
var tableData = table.cache.profitTable;
|
||||
for (var i = 0; i < tableData.length; i++) {
|
||||
if (tableData[i].id === item.id) {
|
||||
tableData[i].use_money = data.use_money;
|
||||
tableData[i].sc_money = data.sc_money;
|
||||
tableData[i].re_money = data.re_money;
|
||||
tableData[i].fh_money = data.fh_money;
|
||||
tableData[i].cj_count = data.cj_count;
|
||||
tableData[i].profit = data.profit;
|
||||
tableData[i].profit_rate = data.profit_rate;
|
||||
tableData[i].is_negative = data.is_negative;
|
||||
tableData[i].loaded = true;
|
||||
|
||||
// 更新汇总数据
|
||||
summaryData.totalIncome += data.use_money;
|
||||
summaryData.totalCost += data.sc_money;
|
||||
summaryData.totalReMoney += data.re_money;
|
||||
summaryData.totalFhMoney += data.fh_money;
|
||||
summaryData.totalProfit = summaryData.totalIncome - summaryData.totalCost;
|
||||
|
||||
// 更新统计摘要
|
||||
updateStatisticsSummary(summaryData);
|
||||
|
||||
// 设置背景色
|
||||
if (data.is_negative) {
|
||||
$('tr[data-index="' + i + '"]').css('background-color', '#ffebee');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 重新渲染表格
|
||||
table.render({
|
||||
elem: '#profitTable',
|
||||
data: tableData,
|
||||
page: false,
|
||||
cols: profitTable.config.cols
|
||||
});
|
||||
}
|
||||
|
||||
if (callback) callback();
|
||||
},
|
||||
error: function() {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 更新统计摘要
|
||||
function updateStatisticsSummary(summary) {
|
||||
if (!summary) return;
|
||||
|
||||
$('#totalIncome').text(summary.totalIncome.toFixed(2));
|
||||
$('#totalCost').text(summary.totalCost.toFixed(2));
|
||||
$('#totalProfit').text(summary.totalProfit.toFixed(2));
|
||||
$('#totalReMoney').text(summary.totalReMoney.toFixed(2));
|
||||
$('#totalFhMoney').text(summary.totalFhMoney.toFixed(2));
|
||||
|
||||
// 设置利润颜色
|
||||
var profitElem = $('#totalProfit');
|
||||
if (summary.totalProfit >= 0) {
|
||||
profitElem.parent().css('color', '#5FB878');
|
||||
} else {
|
||||
profitElem.parent().css('color', '#FF5722');
|
||||
}
|
||||
}
|
||||
|
||||
// 获取搜索参数
|
||||
function getSearchParams() {
|
||||
return {
|
||||
goodId: $('#goodId').val(),
|
||||
title: $('#title').val(),
|
||||
status: $('#status').val(),
|
||||
type: $('#goodsType').val(),
|
||||
addtime: $('#addtime').val()
|
||||
};
|
||||
}
|
||||
|
||||
// 搜索按钮点击事件
|
||||
$('#searchBtn').on('click', function() {
|
||||
profitTable.reload({
|
||||
where: getSearchParams(),
|
||||
page: {
|
||||
curr: 1
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 监听表格工具条事件
|
||||
table.on('tool(profitTable)', function(obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'viewProductsOverview') {
|
||||
// 查看出货概览
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '出货概览',
|
||||
shadeClose: false,
|
||||
shade: 0.3,
|
||||
area: ['90%', '90%'],
|
||||
content: '{:url("/admin/statistics_productsOverview")}?goods_id=' + data.id
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 页面加载完成后执行
|
||||
$(function() {
|
||||
loadGoodsTypes();
|
||||
});
|
||||
});
|
||||
|
||||
// 查看支付订单列表
|
||||
function viewOrders(goodsId) {
|
||||
var url = "{:url('/admin/statistics_order')}?goods_id=" + goodsId;
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '支付订单列表',
|
||||
shadeClose: false,
|
||||
shade: 0.3,
|
||||
area: ['90%', '90%'],
|
||||
content: url
|
||||
});
|
||||
}
|
||||
|
||||
// 查看出货列表
|
||||
function viewOrderLists(goodsId) {
|
||||
var url = "{:url('/admin/statistics_orderList')}?goods_id=" + goodsId;
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '出货列表',
|
||||
shadeClose: false,
|
||||
shade: 0.3,
|
||||
area: ['90%', '90%'],
|
||||
content: url
|
||||
});
|
||||
}
|
||||
|
||||
// 查看兑换列表
|
||||
function viewExchangeList(goodsId) {
|
||||
var url = "{:url('/admin/statistics_exchangeList')}?goods_id=" + goodsId;
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '兑换列表',
|
||||
shadeClose: false,
|
||||
shade: 0.3,
|
||||
area: ['90%', '90%'],
|
||||
content: url
|
||||
});
|
||||
}
|
||||
|
||||
// 查看发货列表
|
||||
function viewShipmentList(goodsId) {
|
||||
var url = "{:url('/admin/statistics_shipmentList')}?goods_id=" + goodsId;
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '发货列表',
|
||||
shadeClose: false,
|
||||
shade: 0.3,
|
||||
area: ['90%', '90%'],
|
||||
content: url
|
||||
});
|
||||
}
|
||||
|
||||
// 查看出货概览
|
||||
function viewProductsOverview(goodsId) {
|
||||
var url = "{:url('/admin/statistics_productsOverview')}?goods_id=" + goodsId;
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '出货概览',
|
||||
shadeClose: false,
|
||||
shade: 0.3,
|
||||
area: ['90%', '90%'],
|
||||
content: url
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -26,7 +26,7 @@ class Config extends Base
|
|||
return $this->renderSuccess('获取成功', [
|
||||
'good_type' => $goodsTypeList,
|
||||
'app_setting' => $app_setting,
|
||||
'version' => '100'
|
||||
'version' => '101'
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,12 +183,18 @@ class Login extends Base
|
|||
*/
|
||||
public function login()
|
||||
{
|
||||
// 初始化日志收集变量
|
||||
$logMessages = [];
|
||||
|
||||
try {
|
||||
$code = request()->param("code", '');
|
||||
if (empty($code)) {
|
||||
$logMessages[] = '用户未获取到code:' . $code;
|
||||
Log::error(end($logMessages));
|
||||
return $this->renderError('请求参数错误');
|
||||
}
|
||||
|
||||
$logMessages[] = '用户开始登录: ' . $code;
|
||||
$click_id = request()->header('clickid');
|
||||
$wxServer = new \app\common\server\Wx($this->app);
|
||||
$user_base = $wxServer->getOpenid($code);
|
||||
|
|
@ -241,52 +247,75 @@ class Login extends Base
|
|||
} else {
|
||||
|
||||
}
|
||||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $time,
|
||||
'last_login_ip' => ip2long($last_login_ip1),
|
||||
'last_login_ip1' => $last_login_ip1,
|
||||
'ip_adcode' => $ip_adcode,
|
||||
'ip_province' => $ip_province,
|
||||
'ip_city' => $ip_city,
|
||||
]);
|
||||
|
||||
// 检查UserAccount是否存在
|
||||
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
|
||||
if ($userAccount) {
|
||||
// 存在则更新
|
||||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $time,
|
||||
'last_login_ip' => ip2long($last_login_ip1),
|
||||
'last_login_ip1' => $last_login_ip1,
|
||||
'ip_adcode' => $ip_adcode,
|
||||
'ip_province' => $ip_province,
|
||||
'ip_city' => $ip_city,
|
||||
]);
|
||||
} else {
|
||||
// 不存在则新增
|
||||
$res[] = UserAccount::insert([
|
||||
'user_id' => $user['id'],
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $time,
|
||||
'last_login_ip' => ip2long($last_login_ip1),
|
||||
'last_login_ip1' => $last_login_ip1,
|
||||
'ip_adcode' => $ip_adcode,
|
||||
'ip_province' => $ip_province,
|
||||
'ip_city' => $ip_city,
|
||||
]);
|
||||
}
|
||||
|
||||
// 记录用户登录日志(每天只记录一次)
|
||||
UserLoginLog::recordLogin(
|
||||
$user['id'],
|
||||
'wechat',
|
||||
$last_login_ip1,
|
||||
$ip_province . $ip_city
|
||||
''//$ip_province . $ip_city
|
||||
);
|
||||
|
||||
$logMessages[] = '用户登录成功: ' . $code . ' 用户ID: ' . $user['id'] . '用户手机号' . $user['mobile'];
|
||||
// 输出收集的所有日志
|
||||
Log::info(implode("==》", $logMessages));
|
||||
|
||||
return $this->renderSuccess("登录成功", $account_token);
|
||||
|
||||
} else {
|
||||
$nickname = request()->param('nickname', '');
|
||||
$headimg = request()->param('headimg', '');
|
||||
if (!$nickname) {
|
||||
return $this->renderError('请求参数错误!');
|
||||
}
|
||||
// if (!$nickname) {
|
||||
// return $this->renderError('请求参数错误!');
|
||||
// }
|
||||
|
||||
$pid = 0;
|
||||
$pid_pid = request()->param('pid', 0);
|
||||
if ($pid_pid > 0) {
|
||||
log::info("获取推荐人id" . $pid_pid);
|
||||
}
|
||||
|
||||
$randx = rand(1000, 9999);
|
||||
if ($nickname == "微信用户") {
|
||||
$nickname = $nickname . $randx;
|
||||
}
|
||||
$nickname = "微信用户" . $randx;
|
||||
$logMessages[] = $nickname;
|
||||
$randx = rand(10000, 99999);
|
||||
$identicon = new \Identicon\Identicon();
|
||||
$imageData = $identicon->getImageData($openid . $nickname);
|
||||
$uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png");
|
||||
$headimg = $uploadResult['full_url'];
|
||||
if ($pid_pid) {
|
||||
$logMessages[] = "尝试获取推荐人ID: " . $pid_pid;
|
||||
$pid_info = User::where('id', '=', $pid_pid)->value("id");
|
||||
if ($pid_info) {
|
||||
log::info("获取推荐人id" . $pid_info);
|
||||
$logMessages[] = "获取推荐人ID成功: " . $pid_info;
|
||||
$pid = $pid_info;
|
||||
}
|
||||
}
|
||||
|
|
@ -319,12 +348,10 @@ class Login extends Base
|
|||
$redis = (new RedisHelper())->getRedis();
|
||||
$lockKey = 'user:beta_reward:' . $user_id;
|
||||
if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
||||
try {
|
||||
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||||
} finally {
|
||||
// 释放锁
|
||||
$redis->del($lockKey);
|
||||
}
|
||||
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||||
$logMessages[] = '赠送钻石: 50000';
|
||||
// 释放锁
|
||||
$redis->del($lockKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -380,20 +407,32 @@ class Login extends Base
|
|||
$user_id,
|
||||
'wechat:v1.0.0',
|
||||
$last_login_ip1,
|
||||
$ip_province . $ip_city
|
||||
''//$ip_province . $ip_city
|
||||
);
|
||||
|
||||
$logMessages[] = '==》用户注册成功: ' . $code . ' 用户ID: ' . $user_id;
|
||||
// 输出收集的所有日志
|
||||
Log::info(implode("==>", $logMessages));
|
||||
|
||||
Db::commit();
|
||||
return $this->renderSuccess("登录成功", $account_token);
|
||||
} else {
|
||||
Db::rollback();
|
||||
|
||||
$logMessages[] = '==》用户注册失败: ' . $code . ' 用户ID: ' . $user_id;
|
||||
// 输出收集的所有日志
|
||||
Log::info(implode("==>", $logMessages));
|
||||
|
||||
return $this->renderError("登录失败");
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('错误信息' . $e->getMessage());
|
||||
Log::error('错误行数' . $e->getLine());
|
||||
$logMessages[] = '登录失败->错误信息: ' . $e->getMessage();
|
||||
$logMessages[] = '登录失败->错误行数: ' . $e->getLine();
|
||||
// 输出收集的错误日志
|
||||
Log::error(implode("==>", $logMessages));
|
||||
|
||||
return $this->renderError("登录失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -403,13 +442,24 @@ class Login extends Base
|
|||
*/
|
||||
public function h5login()
|
||||
{
|
||||
// 获取请求参数
|
||||
$code = request()->param("code", '');
|
||||
if (empty($code)) {
|
||||
return $this->renderError('请求参数错误');
|
||||
}
|
||||
$click_id = request()->header('clickid');
|
||||
|
||||
// 使用Redis全局锁防止并发请求
|
||||
$redis = (new RedisHelper())->getRedis();
|
||||
$lockKey = 'global:h5login:lock:' . md5($code . $click_id);
|
||||
|
||||
// 尝试获取锁,设置过期时间为30秒
|
||||
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 30])) {
|
||||
// 如果获取锁失败,表示有并发请求正在处理
|
||||
return $this->renderError('登录请求处理中,请稍后再试');
|
||||
}
|
||||
|
||||
try {
|
||||
$code = request()->param("code", '');
|
||||
if (empty($code)) {
|
||||
return $this->renderError('请求参数错误');
|
||||
}
|
||||
$click_id = request()->header('clickid');
|
||||
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
|
||||
$user_base = $wxServer->getAccessToken($code);
|
||||
// $user_base_info = $wxServer->getUserInfo($user_base);
|
||||
|
|
@ -460,17 +510,37 @@ class Login extends Base
|
|||
|
||||
|
||||
}
|
||||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $time,
|
||||
'last_login_ip' => ip2long($last_login_ip1),
|
||||
'last_login_ip1' => $last_login_ip1,
|
||||
'ip_adcode' => $ip_adcode,
|
||||
'ip_province' => $ip_province,
|
||||
'ip_city' => $ip_city,
|
||||
]);
|
||||
|
||||
// 检查UserAccount是否存在
|
||||
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
|
||||
if ($userAccount) {
|
||||
// 存在则更新
|
||||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $time,
|
||||
'last_login_ip' => ip2long($last_login_ip1),
|
||||
'last_login_ip1' => $last_login_ip1,
|
||||
'ip_adcode' => $ip_adcode,
|
||||
'ip_province' => $ip_province,
|
||||
'ip_city' => $ip_city,
|
||||
]);
|
||||
} else {
|
||||
// 不存在则新增
|
||||
$res[] = UserAccount::insert([
|
||||
'user_id' => $user['id'],
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $time,
|
||||
'last_login_ip' => ip2long($last_login_ip1),
|
||||
'last_login_ip1' => $last_login_ip1,
|
||||
'ip_adcode' => $ip_adcode,
|
||||
'ip_province' => $ip_province,
|
||||
'ip_city' => $ip_city,
|
||||
]);
|
||||
}
|
||||
|
||||
// 记录用户登录日志(每天只记录一次)
|
||||
UserLoginLog::recordLogin(
|
||||
|
|
@ -515,6 +585,13 @@ class Login extends Base
|
|||
'click_id' => $click_id,
|
||||
'uid' => '',
|
||||
]);
|
||||
|
||||
// 生成用户uid
|
||||
$uid = $this->generateUid($user_id);
|
||||
if ($uid) {
|
||||
User::where('id', $user_id)->update(['uid' => $uid]);
|
||||
}
|
||||
|
||||
$time = time();
|
||||
#token字符串
|
||||
$token_num = getRandStr(10);
|
||||
|
|
@ -581,6 +658,9 @@ class Login extends Base
|
|||
Log::error('错误信息' . $e->getMessage());
|
||||
Log::error('错误行数' . $e->getLine());
|
||||
return $this->renderError('非法请求');
|
||||
} finally {
|
||||
// 确保释放锁
|
||||
$redis->del($lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -613,62 +693,89 @@ class Login extends Base
|
|||
public function login_bind_mobile()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$user_id = $user['id'];
|
||||
$code = request()->param("code", '');
|
||||
$wxServer = new \app\common\server\Wx($this->app);
|
||||
$mobile = $wxServer->getMobile($code);
|
||||
// return $this->renderError($mobile,[$mobile,$code]);
|
||||
Db::startTrans();
|
||||
$res = [];
|
||||
// $res[] = User::where(['id' => $user['id']])->update([
|
||||
// 'mobile' => $mobile,
|
||||
// 'update_time' => time(),
|
||||
// ]);
|
||||
$data = [];
|
||||
$user_mobile = User::where(['mobile' => $mobile])->find();
|
||||
if ($user_mobile) {
|
||||
$old_user_account = UserAccount::where(['user_id' => $user_id])->find();
|
||||
#修改openid
|
||||
$res[] = User::where(['id' => $user_mobile['id']])
|
||||
->update([
|
||||
'openid' => $user['openid'],
|
||||
// 'nickname' => $user['nickname'],
|
||||
// 'headimg' => $user['headimg'],
|
||||
]);
|
||||
$time = time();
|
||||
#token字符串
|
||||
$token_num = getRandStr(10);
|
||||
#加密token
|
||||
$account_token = user_md5($user_mobile['id'] . $token_num . $time);
|
||||
#修改token
|
||||
$res[] = UserAccount::where(['user_id' => $user_mobile['id']])->update([
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $old_user_account['last_login_time'],
|
||||
'last_login_ip' => $old_user_account['last_login_ip'],
|
||||
]);
|
||||
#修改
|
||||
$res[] = User::where(['id' => $user['id']])->delete();
|
||||
$res[] = UserAccount::where(['user_id' => $user_id])->delete();
|
||||
$data['token'] = $account_token;
|
||||
// $res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||
// 'token_time' => time(),
|
||||
// ]);
|
||||
} else {
|
||||
$res[] = User::where(['id' => $user['id']])->update([
|
||||
'mobile' => $mobile,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
}
|
||||
if (resCheck($res)) {
|
||||
Db::commit();
|
||||
return $this->renderSuccess("绑定成功2", $data);
|
||||
} else {
|
||||
Db::rollback();
|
||||
return $this->renderSuccess("绑定成功3");
|
||||
if (empty($user)) {
|
||||
return $this->renderError('用户不存在');
|
||||
}
|
||||
|
||||
$user_id = $user['id'];
|
||||
$code = request()->param("code", '');
|
||||
if (empty($code)) {
|
||||
return $this->renderError('参数错误,缺少code');
|
||||
}
|
||||
|
||||
// 使用Redis全局锁防止并发绑定请求
|
||||
$redis = (new RedisHelper())->getRedis();
|
||||
$lockKey = 'global:bind_mobile:lock:' . $user_id;
|
||||
|
||||
// 尝试获取锁,设置过期时间为20秒
|
||||
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 20])) {
|
||||
// 如果获取锁失败,表示有并发请求正在处理
|
||||
return $this->renderError('绑定请求处理中,请稍后再试');
|
||||
}
|
||||
|
||||
try {
|
||||
$wxServer = new \app\common\server\Wx($this->app);
|
||||
$mobile = $wxServer->getMobile($code);
|
||||
// return $this->renderError($mobile,[$mobile,$code]);
|
||||
Db::startTrans();
|
||||
$res = [];
|
||||
// $res[] = User::where(['id' => $user['id']])->update([
|
||||
// 'mobile' => $mobile,
|
||||
// 'update_time' => time(),
|
||||
// ]);
|
||||
$data = [];
|
||||
$user_mobile = User::where(['mobile' => $mobile])->find();
|
||||
if ($user_mobile) {
|
||||
$old_user_account = UserAccount::where(['user_id' => $user_id])->find();
|
||||
#修改openid
|
||||
$res[] = User::where(['id' => $user_mobile['id']])
|
||||
->update([
|
||||
'openid' => $user['openid'],
|
||||
// 'nickname' => $user['nickname'],
|
||||
// 'headimg' => $user['headimg'],
|
||||
]);
|
||||
$time = time();
|
||||
#token字符串
|
||||
$token_num = getRandStr(10);
|
||||
#加密token
|
||||
$account_token = user_md5($user_mobile['id'] . $token_num . $time);
|
||||
#修改token
|
||||
$res[] = UserAccount::where(['user_id' => $user_mobile['id']])->update([
|
||||
'account_token' => $account_token,
|
||||
'token_num' => $token_num,
|
||||
'token_time' => $time,
|
||||
'last_login_time' => $old_user_account['last_login_time'],
|
||||
'last_login_ip' => $old_user_account['last_login_ip'],
|
||||
]);
|
||||
#修改
|
||||
$res[] = User::where(['id' => $user['id']])->delete();
|
||||
$res[] = UserAccount::where(['user_id' => $user_id])->delete();
|
||||
$data['token'] = $account_token;
|
||||
// $res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||
// 'token_time' => time(),
|
||||
// ]);
|
||||
} else {
|
||||
$res[] = User::where(['id' => $user['id']])->update([
|
||||
'mobile' => $mobile,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
}
|
||||
if (resCheck($res)) {
|
||||
Db::commit();
|
||||
return $this->renderSuccess("绑定成功", $data);
|
||||
} else {
|
||||
Db::rollback();
|
||||
return $this->renderError("绑定失败");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
Log::error('绑定手机号错误: ' . $e->getMessage());
|
||||
Log::error('错误行数: ' . $e->getLine());
|
||||
return $this->renderError('绑定失败: ' . $e->getMessage());
|
||||
} finally {
|
||||
// 确保释放锁
|
||||
$redis->del($lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -678,22 +785,49 @@ class Login extends Base
|
|||
public function login_bind_mobile_h5()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$user_id = $user['id'];
|
||||
$mobile = request()->param("mobile", '');
|
||||
Db::startTrans();
|
||||
$res = [];
|
||||
$res[] = User::where(['id' => $user_id])->update([
|
||||
'mobile' => $mobile,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
if (resCheck($res)) {
|
||||
Db::commit();
|
||||
return $this->renderSuccess("绑定成功2");
|
||||
} else {
|
||||
Db::rollback();
|
||||
return $this->renderSuccess("绑定成功3");
|
||||
if (empty($user)) {
|
||||
return $this->renderError('用户不存在');
|
||||
}
|
||||
|
||||
$user_id = $user['id'];
|
||||
$mobile = request()->param("mobile", '');
|
||||
if (empty($mobile)) {
|
||||
return $this->renderError('请输入手机号');
|
||||
}
|
||||
|
||||
// 使用Redis全局锁防止并发绑定请求
|
||||
$redis = (new RedisHelper())->getRedis();
|
||||
$lockKey = 'global:bind_mobile_h5:lock:' . $user_id;
|
||||
|
||||
// 尝试获取锁,设置过期时间为10秒
|
||||
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 10])) {
|
||||
// 如果获取锁失败,表示有并发请求正在处理
|
||||
return $this->renderError('绑定请求处理中,请稍后再试');
|
||||
}
|
||||
|
||||
try {
|
||||
Db::startTrans();
|
||||
$res = [];
|
||||
$res[] = User::where(['id' => $user_id])->update([
|
||||
'mobile' => $mobile,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
if (resCheck($res)) {
|
||||
Db::commit();
|
||||
return $this->renderSuccess("绑定成功");
|
||||
} else {
|
||||
Db::rollback();
|
||||
return $this->renderError("绑定失败");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
Log::error('绑定手机号H5错误: ' . $e->getMessage());
|
||||
Log::error('错误行数: ' . $e->getLine());
|
||||
return $this->renderError('绑定失败: ' . $e->getMessage());
|
||||
} finally {
|
||||
// 确保释放锁
|
||||
$redis->del($lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -718,77 +852,86 @@ class Login extends Base
|
|||
public function recordLogin()
|
||||
{
|
||||
try {
|
||||
// $user_id = $this->getUserid1();
|
||||
// //去redis中查询一下,如果存在今日的数据,则不在往下执行
|
||||
// $redis = (new RedisHelper())->getRedis();
|
||||
// $today = date('Y-m-d');
|
||||
// $redis_key = "login_record:" . $today . ":" . $user_id;
|
||||
// $redis_data = $redis->get($redis_key);
|
||||
// if ($redis_data) {
|
||||
// return $this->renderSuccess('登录记录成功');
|
||||
// }
|
||||
// 获取用户信息
|
||||
$user = $this->getUser();
|
||||
if (empty($user)) {
|
||||
return $this->renderError('用户不存在');
|
||||
}
|
||||
|
||||
// 获取设备信息
|
||||
$device = request()->param('device', ''); // 设备类型
|
||||
$device_info = request()->param('device_info', ''); // 设备详细信息
|
||||
|
||||
// 获取IP和地理位置信息
|
||||
$ip = $this->getRealIp();
|
||||
$location = '';
|
||||
$ip_province = '';
|
||||
$ip_city = '';
|
||||
$ip_adcode = '';
|
||||
|
||||
$result = $this->ip_location($ip);
|
||||
if ($result) {
|
||||
$ip_province = $result['province'];
|
||||
$ip_city = $result['city'];
|
||||
$ip_adcode = $result['adcode'];
|
||||
$location = $ip_province . $ip_city;
|
||||
}
|
||||
$user_id = $user['id'];
|
||||
$isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
|
||||
if ($isTest == "1") {
|
||||
// 使用Redis锁防止重复获取
|
||||
$redis = (new RedisHelper())->getRedis();
|
||||
$lockKey = 'user:beta_reward:' . $user_id;
|
||||
if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
||||
$userCount = ProfitMoney::where('user_id', $user_id)
|
||||
->where('type', 8)
|
||||
->where('content', '=', '内测免费送')
|
||||
->count();
|
||||
if ($userCount == 0) {
|
||||
|
||||
// 使用Redis全局锁防止并发请求
|
||||
$redis = (new RedisHelper())->getRedis();
|
||||
$lockKey = 'global:record_login:lock:' . $user_id;
|
||||
|
||||
// 尝试获取锁,设置过期时间为10秒
|
||||
if (!$redis->set($lockKey, 1, ['nx', 'ex' => 10])) {
|
||||
// 如果获取锁失败,直接返回成功,避免用户等待
|
||||
return $this->renderSuccess('登录成功', [
|
||||
'uid' => $user['uid'] ?: $user['id'],
|
||||
'nickname' => $user['nickname'],
|
||||
'headimg' => imageUrl($user['headimg'])
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取设备信息
|
||||
$device = request()->param('device', ''); // 设备类型
|
||||
$device_info = request()->param('device_info', ''); // 设备详细信息
|
||||
|
||||
// 获取IP和地理位置信息
|
||||
$ip = $this->getRealIp();
|
||||
$location = '';
|
||||
$ip_province = '';
|
||||
$ip_city = '';
|
||||
$ip_adcode = '';
|
||||
|
||||
$result = $this->ip_location($ip);
|
||||
if ($result) {
|
||||
$ip_province = $result['province'];
|
||||
$ip_city = $result['city'];
|
||||
$ip_adcode = $result['adcode'];
|
||||
$location = $ip_province . $ip_city;
|
||||
}
|
||||
|
||||
$isTest = \app\common\helper\ConfigHelper::getSystemTestKey("enable_test");
|
||||
if ($isTest == "1") {
|
||||
// 使用全局 Redis 锁防止重复获取内测奖励
|
||||
$bonusLockKey = 'global:bonus:lock:' . $user_id;
|
||||
if ($redis->set($bonusLockKey, 1, ['nx', 'ex' => 60])) {
|
||||
try {
|
||||
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||||
$userCount = ProfitMoney::where('user_id', $user_id)
|
||||
->where('type', 8)
|
||||
->where('content', '=', '内测免费送')
|
||||
->count();
|
||||
if ($userCount == 0) {
|
||||
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||||
}
|
||||
} finally {
|
||||
// 释放锁
|
||||
$redis->del($lockKey);
|
||||
// 释放内测奖励锁
|
||||
$redis->del($bonusLockKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录登录日志
|
||||
UserLoginLog::recordLogin(
|
||||
$user['id'],
|
||||
$device,
|
||||
$ip,
|
||||
$location
|
||||
);
|
||||
|
||||
return $this->renderSuccess('登录成功', [
|
||||
'uid' => $user['uid'] ?: $user['id'],
|
||||
'nickname' => $user['nickname'],
|
||||
'headimg' => imageUrl($user['headimg'])
|
||||
]);
|
||||
} finally {
|
||||
// 确保释放锁
|
||||
$redis->del($lockKey);
|
||||
}
|
||||
|
||||
// 记录登录日志
|
||||
UserLoginLog::recordLogin(
|
||||
$user['id'],
|
||||
$device,
|
||||
$ip,
|
||||
$location
|
||||
);
|
||||
// //将数据写入redis,过期时间为当天剩余的时间
|
||||
// $redis->set($redis_key, json_encode($user), 86400 - time() % 86400);
|
||||
return $this->renderSuccess('登录成功', [
|
||||
'uid' => $user['uid'] ?: $user['id'],
|
||||
'nickname' => $user['nickname'],
|
||||
'headimg' => imageUrl($user['headimg'])
|
||||
]);
|
||||
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('记录登录错误: ' . $e->getMessage());
|
||||
Log::error('错误行数: ' . $e->getLine());
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user