提交代码
This commit is contained in:
parent
e81b954d0a
commit
3bc11c8d0e
|
|
@ -43,22 +43,39 @@ class Statistics extends Base
|
||||||
if ($type) {
|
if ($type) {
|
||||||
$where[] = ['type', '=', $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;
|
$where = [['delete_time', '=', null]];
|
||||||
$endTime = time();
|
if ($goodId) {
|
||||||
if ($addtime) {
|
$where[] = ['id', '=', $goodId];
|
||||||
$times = explode(' - ', $addtime);
|
}
|
||||||
$startTime = strtotime($times[0]);
|
if ($title) {
|
||||||
$endTime = strtotime($times[1]);
|
$where[] = ['title', 'like', '%' . $title . '%'];
|
||||||
|
}
|
||||||
|
if ($status) {
|
||||||
|
$where[] = ['status', '=', $status];
|
||||||
|
}
|
||||||
|
if ($type) {
|
||||||
|
$where[] = ['type', '=', $type];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取测试用户ID
|
// 构建SQL查询,只返回基本信息
|
||||||
$testUsers = User::where('istest', '>', 0)->column('id');
|
|
||||||
$testUserIds = empty($testUsers) ? [0] : $testUsers;
|
|
||||||
$testUserIdsStr = implode(',', $testUserIds);
|
|
||||||
|
|
||||||
// 构建SQL查询
|
|
||||||
$query = Db::name('goods')->alias('goods')
|
$query = Db::name('goods')->alias('goods')
|
||||||
->field([
|
->field([
|
||||||
'goods.id',
|
'goods.id',
|
||||||
|
|
@ -67,54 +84,70 @@ class Statistics extends Base
|
||||||
'goods.price',
|
'goods.price',
|
||||||
'goods.stock',
|
'goods.stock',
|
||||||
'goods.status',
|
'goods.status',
|
||||||
'goods.type',
|
'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'
|
|
||||||
])
|
])
|
||||||
->where($where)
|
->where($where)
|
||||||
->order(['goods.id' => 'desc']);
|
->order(['goods.id' => 'desc']);
|
||||||
|
|
||||||
// 获取列表数据
|
// 获取总数量
|
||||||
$list = $query->select()->toArray();
|
$total = $query->count();
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
$list = $query->page($page, $limit)->select()->toArray();
|
||||||
|
|
||||||
// 计算总金额
|
// 获取盒子类型名称
|
||||||
$totalIncome = 0;
|
$typesList = $this->getGoodsTypes();
|
||||||
$totalCost = 0;
|
$typesMap = [];
|
||||||
$totalProfit = 0;
|
foreach ($typesList as $item) {
|
||||||
$totalReMoney = 0;
|
$typesMap[$item['value']] = $item['fl_name'];
|
||||||
$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'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$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; // 标记是否已加载统计数据
|
||||||
|
}
|
||||||
|
|
||||||
// 传递数据给视图
|
// 返回JSON数据
|
||||||
View::assign([
|
return json([
|
||||||
'list' => $list,
|
'code' => 0,
|
||||||
'totalIncome' => $totalIncome,
|
'msg' => '获取数据成功',
|
||||||
'totalCost' => $totalCost,
|
'count' => $total,
|
||||||
'totalProfit' => $totalProfit,
|
'data' => $list,
|
||||||
'totalReMoney' => $totalReMoney,
|
'summary' => [
|
||||||
'totalFhMoney' => $totalFhMoney,
|
'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');
|
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用户排行榜
|
#UserRank.php用户排行榜
|
||||||
#============================
|
#============================
|
||||||
Route::rule('user_rank', 'UserRank/index', 'GET');
|
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-fluid">
|
||||||
<div class="layui-card">
|
<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-form-item">
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
<div class="layui-input-inline" style="width:150px;margin-left: 0px">
|
<div class="layui-input-inline" style="width:150px;margin-left: 0px">
|
||||||
<input type="text" name="goodId" value="{$Request.get.goodId}" placeholder="请输入盒子Id"
|
<input type="text" name="goodId" id="goodId" placeholder="请输入盒子Id" autocomplete="off" class="layui-input">
|
||||||
autocomplete="off" class="layui-input">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
<div class="layui-input-inline" style="width:150px;margin-left: 0px">
|
<div class="layui-input-inline" style="width:150px;margin-left: 0px">
|
||||||
<input type="text" name="title" value="{$Request.get.title}" placeholder="请输入盒子名称"
|
<input type="text" name="title" id="title" placeholder="请输入盒子名称" autocomplete="off" class="layui-input">
|
||||||
autocomplete="off" class="layui-input">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
<div class="layui-input-inline" style="width: 180px;margin-left: 0px">
|
<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="">--请选择盒子状态--</option>
|
||||||
<option value="1" {if condition="$Request.get.status eq 1" }selected{/if}>上架</option>
|
<option value="1">上架</option>
|
||||||
<option value="2" {if condition="$Request.get.status eq 2" }selected{/if}>下架</option>
|
<option value="2">下架</option>
|
||||||
<option value="3" {if condition="$Request.get.status eq 3" }selected{/if}>售罄</option>
|
<option value="3">售罄</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -37,13 +35,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-inline">
|
<div class="layui-inline">
|
||||||
<div class="layui-input-inline" style="width:300px;margin-left: 0px">
|
<div class="layui-input-inline" style="width:300px;margin-left: 0px">
|
||||||
<input type="text" id="addtime" name="addtime" value="{$Request.get.addtime}"
|
<input type="text" id="addtime" name="addtime" class="layui-input" placeholder="选择时间" autocomplete="off">
|
||||||
class="layui-input" placeholder="选择时间" autocomplete="off">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-inline">
|
<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>
|
<i class="layui-icon layui-icon-search layuiadmin-button-btn"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -52,12 +49,12 @@
|
||||||
|
|
||||||
<!-- 统计摘要区域 -->
|
<!-- 统计摘要区域 -->
|
||||||
<div class="layui-card-body">
|
<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-col-md3">
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div class="layui-card-header">总收入</div>
|
<div class="layui-card-header">总收入</div>
|
||||||
<div class="layui-card-body" style="font-size: 24px; color: #01AAED;">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -65,15 +62,15 @@
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div class="layui-card-header">总出货价值</div>
|
<div class="layui-card-header">总出货价值</div>
|
||||||
<div class="layui-card-body" style="font-size: 24px; color: #FFB800;">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-col-md3">
|
<div class="layui-col-md3">
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div class="layui-card-header">总利润</div>
|
<div class="layui-card-header">总利润</div>
|
||||||
<div class="layui-card-body" style="font-size: 24px; color: {$totalProfit >= 0 ? '#5FB878' : '#FF5722'};">
|
<div class="layui-card-body" style="font-size: 24px;">
|
||||||
¥ {$totalProfit|default="0"|round=2}
|
¥ <span id="totalProfit" class="profit-value">0.00</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -81,88 +78,33 @@
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
<div class="layui-card-header">总兑换/发货价值</div>
|
<div class="layui-card-header">总兑换/发货价值</div>
|
||||||
<div class="layui-card-body" style="font-size: 24px;">
|
<div class="layui-card-body" style="font-size: 24px;">
|
||||||
<span style="color: #FF9800;">¥ {$totalReMoney|default="0"|round=2}</span> /
|
<span style="color: #FF9800;">¥ <span id="totalReMoney">0.00</span></span> /
|
||||||
<span style="color: #673AB7;">¥ {$totalFhMoney|default="0"|round=2}</span>
|
<span style="color: #673AB7;">¥ <span id="totalFhMoney">0.00</span></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 数据表格区域 -->
|
<!-- 数据表格区域 -->
|
||||||
<table class="layui-table">
|
<table id="profitTable" lay-filter="profitTable"></table>
|
||||||
<thead>
|
|
||||||
<tr>
|
<!-- 表格操作栏模板 -->
|
||||||
<th>盒子ID</th>
|
<script type="text/html" id="operationTpl">
|
||||||
<th>盒子名称</th>
|
<button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="viewProductsOverview">出货概览</button>
|
||||||
<th>盒子类型/状态</th>
|
</script>
|
||||||
<th>盒子单价</th>
|
|
||||||
<th>抽奖次数</th>
|
<!-- 利润和利润率模板 -->
|
||||||
<th>收入</th>
|
<script type="text/html" id="profitTpl">
|
||||||
<th>出货价值</th>
|
<span class="layui-badge {{d.profit >= 0 ? 'layui-bg-green' : 'layui-bg-red'}}">
|
||||||
<th>兑换价值</th>
|
¥ {{d.profit.toFixed(2)}}
|
||||||
<th>发货价值</th>
|
</span>
|
||||||
<th>利润</th>
|
</script>
|
||||||
<th>利润率</th>
|
|
||||||
<th>操作</th>
|
<script type="text/html" id="profitRateTpl">
|
||||||
</tr>
|
<span class="layui-badge {{d.profit_rate >= 0 ? 'layui-bg-green' : 'layui-bg-red'}}">
|
||||||
</thead>
|
{{d.profit_rate.toFixed(2)}}%
|
||||||
<tbody>
|
</span>
|
||||||
{volist name="list" id="vo"}
|
</script>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -173,6 +115,7 @@
|
||||||
var layer = layui.layer;
|
var layer = layui.layer;
|
||||||
var laydate = layui.laydate;
|
var laydate = layui.laydate;
|
||||||
var form = layui.form;
|
var form = layui.form;
|
||||||
|
var table = layui.table;
|
||||||
|
|
||||||
// 日期时间范围
|
// 日期时间范围
|
||||||
laydate.render({
|
laydate.render({
|
||||||
|
|
@ -180,7 +123,7 @@
|
||||||
type: 'datetime',
|
type: 'datetime',
|
||||||
range: true
|
range: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载盒子类型数据
|
// 加载盒子类型数据
|
||||||
function loadGoodsTypes() {
|
function loadGoodsTypes() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
@ -192,102 +135,294 @@
|
||||||
var html = '<option value="">--盒子类型--</option>';
|
var html = '<option value="">--盒子类型--</option>';
|
||||||
|
|
||||||
$.each(res.data, function (index, item) {
|
$.each(res.data, function (index, item) {
|
||||||
if(item.value == '{$Request.get.type}'){
|
html += '<option value="' + item.value + '" title="' + item.remark + '">' + item.fl_name + '</option>';
|
||||||
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>';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
$('#goodsType').html(html);
|
$('#goodsType').html(html);
|
||||||
form.render('select');
|
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() {
|
$(function() {
|
||||||
loadGoodsTypes();
|
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>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -26,7 +26,7 @@ class Config extends Base
|
||||||
return $this->renderSuccess('获取成功', [
|
return $this->renderSuccess('获取成功', [
|
||||||
'good_type' => $goodsTypeList,
|
'good_type' => $goodsTypeList,
|
||||||
'app_setting' => $app_setting,
|
'app_setting' => $app_setting,
|
||||||
'version' => '100'
|
'version' => '101'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,12 +183,18 @@ class Login extends Base
|
||||||
*/
|
*/
|
||||||
public function login()
|
public function login()
|
||||||
{
|
{
|
||||||
|
// 初始化日志收集变量
|
||||||
|
$logMessages = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$code = request()->param("code", '');
|
$code = request()->param("code", '');
|
||||||
if (empty($code)) {
|
if (empty($code)) {
|
||||||
|
$logMessages[] = '用户未获取到code:' . $code;
|
||||||
|
Log::error(end($logMessages));
|
||||||
return $this->renderError('请求参数错误');
|
return $this->renderError('请求参数错误');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$logMessages[] = '用户开始登录: ' . $code;
|
||||||
$click_id = request()->header('clickid');
|
$click_id = request()->header('clickid');
|
||||||
$wxServer = new \app\common\server\Wx($this->app);
|
$wxServer = new \app\common\server\Wx($this->app);
|
||||||
$user_base = $wxServer->getOpenid($code);
|
$user_base = $wxServer->getOpenid($code);
|
||||||
|
|
@ -241,52 +247,75 @@ class Login extends Base
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
|
||||||
'account_token' => $account_token,
|
// 检查UserAccount是否存在
|
||||||
'token_num' => $token_num,
|
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
|
||||||
'token_time' => $time,
|
if ($userAccount) {
|
||||||
'last_login_time' => $time,
|
// 存在则更新
|
||||||
'last_login_ip' => ip2long($last_login_ip1),
|
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||||
'last_login_ip1' => $last_login_ip1,
|
'account_token' => $account_token,
|
||||||
'ip_adcode' => $ip_adcode,
|
'token_num' => $token_num,
|
||||||
'ip_province' => $ip_province,
|
'token_time' => $time,
|
||||||
'ip_city' => $ip_city,
|
'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(
|
UserLoginLog::recordLogin(
|
||||||
$user['id'],
|
$user['id'],
|
||||||
'wechat',
|
'wechat',
|
||||||
$last_login_ip1,
|
$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);
|
return $this->renderSuccess("登录成功", $account_token);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$nickname = request()->param('nickname', '');
|
$nickname = request()->param('nickname', '');
|
||||||
$headimg = request()->param('headimg', '');
|
$headimg = request()->param('headimg', '');
|
||||||
if (!$nickname) {
|
// if (!$nickname) {
|
||||||
return $this->renderError('请求参数错误!');
|
// return $this->renderError('请求参数错误!');
|
||||||
}
|
// }
|
||||||
|
|
||||||
$pid = 0;
|
$pid = 0;
|
||||||
$pid_pid = request()->param('pid', 0);
|
$pid_pid = request()->param('pid', 0);
|
||||||
if ($pid_pid > 0) {
|
|
||||||
log::info("获取推荐人id" . $pid_pid);
|
|
||||||
}
|
|
||||||
$randx = rand(1000, 9999);
|
$randx = rand(1000, 9999);
|
||||||
if ($nickname == "微信用户") {
|
$nickname = "微信用户" . $randx;
|
||||||
$nickname = $nickname . $randx;
|
$logMessages[] = $nickname;
|
||||||
}
|
$randx = rand(10000, 99999);
|
||||||
$identicon = new \Identicon\Identicon();
|
$identicon = new \Identicon\Identicon();
|
||||||
$imageData = $identicon->getImageData($openid . $nickname);
|
$imageData = $identicon->getImageData($openid . $nickname);
|
||||||
$uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png");
|
$uploadResult = $this->uploader->uploadFile($imageData, "storage/users/icon/default/" . $randx . ".png");
|
||||||
$headimg = $uploadResult['full_url'];
|
$headimg = $uploadResult['full_url'];
|
||||||
if ($pid_pid) {
|
if ($pid_pid) {
|
||||||
|
$logMessages[] = "尝试获取推荐人ID: " . $pid_pid;
|
||||||
$pid_info = User::where('id', '=', $pid_pid)->value("id");
|
$pid_info = User::where('id', '=', $pid_pid)->value("id");
|
||||||
if ($pid_info) {
|
if ($pid_info) {
|
||||||
log::info("获取推荐人id" . $pid_info);
|
$logMessages[] = "获取推荐人ID成功: " . $pid_info;
|
||||||
$pid = $pid_info;
|
$pid = $pid_info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -319,12 +348,10 @@ class Login extends Base
|
||||||
$redis = (new RedisHelper())->getRedis();
|
$redis = (new RedisHelper())->getRedis();
|
||||||
$lockKey = 'user:beta_reward:' . $user_id;
|
$lockKey = 'user:beta_reward:' . $user_id;
|
||||||
if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
if ($redis->set($lockKey, 1, ['nx', 'ex' => 60])) {
|
||||||
try {
|
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
||||||
$res[] = User::changeMoney($user_id, 50000, 8, '内测免费送');
|
$logMessages[] = '赠送钻石: 50000';
|
||||||
} finally {
|
// 释放锁
|
||||||
// 释放锁
|
$redis->del($lockKey);
|
||||||
$redis->del($lockKey);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -380,20 +407,32 @@ class Login extends Base
|
||||||
$user_id,
|
$user_id,
|
||||||
'wechat:v1.0.0',
|
'wechat:v1.0.0',
|
||||||
$last_login_ip1,
|
$last_login_ip1,
|
||||||
$ip_province . $ip_city
|
''//$ip_province . $ip_city
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$logMessages[] = '==》用户注册成功: ' . $code . ' 用户ID: ' . $user_id;
|
||||||
|
// 输出收集的所有日志
|
||||||
|
Log::info(implode("==>", $logMessages));
|
||||||
|
|
||||||
Db::commit();
|
Db::commit();
|
||||||
return $this->renderSuccess("登录成功", $account_token);
|
return $this->renderSuccess("登录成功", $account_token);
|
||||||
} else {
|
} else {
|
||||||
Db::rollback();
|
Db::rollback();
|
||||||
|
|
||||||
|
$logMessages[] = '==》用户注册失败: ' . $code . ' 用户ID: ' . $user_id;
|
||||||
|
// 输出收集的所有日志
|
||||||
|
Log::info(implode("==>", $logMessages));
|
||||||
|
|
||||||
return $this->renderError("登录失败");
|
return $this->renderError("登录失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error('错误信息' . $e->getMessage());
|
$logMessages[] = '登录失败->错误信息: ' . $e->getMessage();
|
||||||
Log::error('错误行数' . $e->getLine());
|
$logMessages[] = '登录失败->错误行数: ' . $e->getLine();
|
||||||
|
// 输出收集的错误日志
|
||||||
|
Log::error(implode("==>", $logMessages));
|
||||||
|
|
||||||
|
return $this->renderError("登录失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -403,13 +442,24 @@ class Login extends Base
|
||||||
*/
|
*/
|
||||||
public function h5login()
|
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 {
|
try {
|
||||||
$code = request()->param("code", '');
|
|
||||||
if (empty($code)) {
|
|
||||||
return $this->renderError('请求参数错误');
|
|
||||||
}
|
|
||||||
$click_id = request()->header('clickid');
|
|
||||||
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
|
$wxServer = new \app\common\server\WechatOfficialAccount($this->app);
|
||||||
$user_base = $wxServer->getAccessToken($code);
|
$user_base = $wxServer->getAccessToken($code);
|
||||||
// $user_base_info = $wxServer->getUserInfo($user_base);
|
// $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,
|
// 检查UserAccount是否存在
|
||||||
'token_num' => $token_num,
|
$userAccount = UserAccount::where(['user_id' => $user['id']])->find();
|
||||||
'token_time' => $time,
|
if ($userAccount) {
|
||||||
'last_login_time' => $time,
|
// 存在则更新
|
||||||
'last_login_ip' => ip2long($last_login_ip1),
|
$res[] = UserAccount::where(['user_id' => $user['id']])->update([
|
||||||
'last_login_ip1' => $last_login_ip1,
|
'account_token' => $account_token,
|
||||||
'ip_adcode' => $ip_adcode,
|
'token_num' => $token_num,
|
||||||
'ip_province' => $ip_province,
|
'token_time' => $time,
|
||||||
'ip_city' => $ip_city,
|
'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(
|
UserLoginLog::recordLogin(
|
||||||
|
|
@ -515,6 +585,13 @@ class Login extends Base
|
||||||
'click_id' => $click_id,
|
'click_id' => $click_id,
|
||||||
'uid' => '',
|
'uid' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 生成用户uid
|
||||||
|
$uid = $this->generateUid($user_id);
|
||||||
|
if ($uid) {
|
||||||
|
User::where('id', $user_id)->update(['uid' => $uid]);
|
||||||
|
}
|
||||||
|
|
||||||
$time = time();
|
$time = time();
|
||||||
#token字符串
|
#token字符串
|
||||||
$token_num = getRandStr(10);
|
$token_num = getRandStr(10);
|
||||||
|
|
@ -581,6 +658,9 @@ class Login extends Base
|
||||||
Log::error('错误信息' . $e->getMessage());
|
Log::error('错误信息' . $e->getMessage());
|
||||||
Log::error('错误行数' . $e->getLine());
|
Log::error('错误行数' . $e->getLine());
|
||||||
return $this->renderError('非法请求');
|
return $this->renderError('非法请求');
|
||||||
|
} finally {
|
||||||
|
// 确保释放锁
|
||||||
|
$redis->del($lockKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -613,62 +693,89 @@ class Login extends Base
|
||||||
public function login_bind_mobile()
|
public function login_bind_mobile()
|
||||||
{
|
{
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$user_id = $user['id'];
|
if (empty($user)) {
|
||||||
$code = request()->param("code", '');
|
return $this->renderError('用户不存在');
|
||||||
$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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$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()
|
public function login_bind_mobile_h5()
|
||||||
{
|
{
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$user_id = $user['id'];
|
if (empty($user)) {
|
||||||
$mobile = request()->param("mobile", '');
|
return $this->renderError('用户不存在');
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$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()
|
public function recordLogin()
|
||||||
{
|
{
|
||||||
try {
|
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();
|
$user = $this->getUser();
|
||||||
if (empty($user)) {
|
if (empty($user)) {
|
||||||
return $this->renderError('用户不存在');
|
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'];
|
$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 {
|
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 {
|
} 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) {
|
} catch (\Exception $e) {
|
||||||
Log::error('记录登录错误: ' . $e->getMessage());
|
Log::error('记录登录错误: ' . $e->getMessage());
|
||||||
Log::error('错误行数: ' . $e->getLine());
|
Log::error('错误行数: ' . $e->getLine());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user