request->param('page', 1); $limit = $this->request->param('limit', 10); $type = $this->request->param('type', ''); $form = $this->request->param('form', ''); $userId = $this->getUserInfo('id'); $companyId = $this->getUserInfo('companyId'); $where = [ ['companyId','=',$companyId], ['userId' ,'=', $userId] ]; if ($type != '') { $where[] = ['type','=',$type]; } if ($form != '') { $where[] = ['form','=',$form]; } $query = TokensRecord::where($where); $total = $query->count(); $list = $query->where($where)->page($page,$limit)->order('id desc')->select(); foreach ($list as &$item) { if (in_array($item['type'],[1])){ $nickname = Db::table('s2_wechat_friend')->where(['id' => $item['friendIdOrGroupId']])->value('nickname'); $item['nickname'] = !empty($nickname) ? $nickname : '-'; } if (in_array($item['type'],[2,3])){ $nickname = Db::table('s2_wechat_chatroom')->where(['id' => $item['friendIdOrGroupId']])->value('nickname'); $item['nickname'] = !empty($nickname) ? $nickname : '-'; } } unset($item); return ResponseHelper::success(['list'=>$list,'total'=>$total]); } public function consumeTokens($data = []) { if (empty($data)){ return ResponseHelper::error('数据缺失'); } $tokens = isset($data['tokens']) ? intval($data['tokens']) : 0; $type = isset($data['type']) ? intval($data['type']) : 0; $form = isset($data['form']) ? intval($data['form']) : 0; $wechatAccountId = isset($data['wechatAccountId']) ? intval($data['wechatAccountId']) : 0; $friendIdOrGroupId = isset($data['friendIdOrGroupId']) ? intval($data['friendIdOrGroupId']) : 0; $remarks = isset($data['remarks']) ? $data['remarks'] : ''; $companyId = isset($data['companyId']) ? intval($data['companyId']) : $this->getUserInfo('companyId'); $userId = isset($data['userId']) ? intval($data['userId']) : $this->getUserInfo('id'); // 验证必要参数 if ($tokens <= 0) { return ResponseHelper::error('tokens数量必须大于0'); } if (!in_array($type, [0, 1])) { return ResponseHelper::error('类型参数错误,0为减少,1为增加'); } if (!in_array($form, [0, 1, 2, 3, 4, 5])) { return ResponseHelper::error('来源参数错误'); } // 重试机制,最多重试3次 $maxRetries = 3; $retryCount = 0; while ($retryCount < $maxRetries) { try { return $this->doConsumeTokens($userId, $companyId, $tokens, $type, $form, $wechatAccountId, $friendIdOrGroupId, $remarks); } catch (\Exception $e) { $retryCount++; if ($retryCount >= $maxRetries) { return ResponseHelper::error('操作失败,请稍后重试:' . $e->getMessage()); } // 短暂延迟后重试 usleep(100000); // 100ms } } } /** * 执行tokens消费的核心方法 */ private function doConsumeTokens($userId, $companyId, $tokens, $type, $form, $wechatAccountId, $friendIdOrGroupId, $remarks) { // 开启数据库事务 Db::startTrans(); try { // 使用悲观锁获取用户当前tokens余额,确保并发安全 $userInfo = TokensCompany::where('companyId', $companyId)->lock(true)->find(); if (!$userInfo) { throw new \Exception('用户不存在'); } $currentTokens = intval($userInfo['tokens']); // 计算新的余额 $newBalance = $type == 1 ? ($currentTokens + $tokens) : ($currentTokens - $tokens); // 使用原子更新操作,基于当前值进行更新,防止并发覆盖 $updateResult = TokensCompany::where('companyId', $companyId) ->where('companyId', $companyId) ->update([ 'tokens' => $newBalance, 'updateTime' => time() ]); if (!$updateResult) { // 如果更新失败,说明tokens值已被其他事务修改,需要重新获取 throw new \Exception('tokens余额已被其他操作修改,请重试'); } // 记录tokens变动 $recordData = [ 'companyId' => $companyId, 'userId' => $userId, 'wechatAccountId' => $wechatAccountId, 'friendIdOrGroupId' => $friendIdOrGroupId, 'form' => $form, 'type' => $type, 'tokens' => $tokens, 'balanceTokens' => $newBalance, 'remarks' => $remarks, 'createTime' => time() ]; $recordId = Db::name('tokens_record')->insertGetId($recordData); if (!$recordId) { throw new \Exception('记录tokens变动失败'); } // 提交事务 Db::commit(); return ResponseHelper::success([ 'recordId' => $recordId, 'oldBalance' => $currentTokens, 'newBalance' => $newBalance, 'changeAmount' => $type == 1 ? $tokens : -$tokens ], 'tokens变动记录成功'); } catch (\Exception $e) { // 回滚事务 Db::rollback(); throw $e; // 重新抛出异常,让重试机制处理 } } }