UserCoinController.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. namespace app\api\controller\coin;
  3. use app\models\coin\UserCoinTransfer;
  4. use app\models\redis\UserHash;
  5. use app\models\store\StoreOrderCartInfo;
  6. use app\models\system\DictCoin;
  7. use app\models\user\UserCoin;
  8. use app\Request;
  9. use crmeb\services\{UtilService, JsonService};
  10. use think\facade\Config;
  11. class UserCoinController {
  12. public function status(Request $request) {
  13. // 是否开启挖矿
  14. $symbol = Config::get('app.mining_symbo');
  15. //
  16. $icon = Cache::get($symbol);
  17. if (!$icon) {
  18. $icon = DictCoin::where('symbol', $symbol)->value('icon');
  19. Cache::set($symbol, $icon);
  20. }
  21. //
  22. $defStatus = [
  23. 'progress'=> 0,
  24. 'symbol'=>$symbol,
  25. 'icon'=>$icon,
  26. 'price'=> 0.00,
  27. 'total'=> 0,
  28. 'step' => 0,
  29. ];
  30. if (!$symbol) {
  31. Log::warning('mining disabled: $symbol');
  32. return app('json')->successful($defStatus);
  33. }
  34. $uid = $request->uid();
  35. $mymining = UserHash::mining_get($uid) ?? $defStatus;
  36. if ($mymining['progress'] > 0) {
  37. $mining = $this->calcMining($uid, $mymining);
  38. UserHash::mining_set($uid, $mining);
  39. }
  40. }
  41. /**
  42. * 根据上次挖矿状态, 和过去的时长, 计算当前的状态
  43. * @param $p
  44. * @return mixed
  45. */
  46. protected function calcMining($uid, $p) {
  47. if ($p['progress'] <= 0) {
  48. return $p;
  49. }
  50. if (!isset($p['ts'])) {
  51. return $p;
  52. }
  53. $now = time();
  54. $secs_passed = $now - $p['ts'];
  55. $secs_unit = Config::get('app.mining_sec_unit');
  56. $reward_unit = Config::get('app.mining_num_per_unit');
  57. $hours = Config::get('app.mining_time');
  58. if (count($hours) != 2 || $hours[0] > $hours[1]) {
  59. Log::warning('app.mining_time config error.');
  60. return $p;
  61. }
  62. $hour = random_int($hours[0], $hours[1]);
  63. $secs = $hour * 60 * 60;
  64. //
  65. if ($secs_passed >= $secs) { // 挖矿结束
  66. $p['progress'] = 0;
  67. // 本次个数
  68. $count = floatval(bcmul(bcdiv($secs, $secs_unit, 8), $reward_unit, 8));
  69. // save to database
  70. if (!UserCoinTransfer::addMining($uid, $p['order_id'], $p['symbol'], $count)) {
  71. Log::error("user<$uid> save transfer failed, amount<$count>");
  72. }
  73. $p['total'] += $count;
  74. return $p;
  75. }
  76. $count = floatval(bcmul(bcdiv($secs_passed, $secs_unit, 8), $reward_unit, 8));
  77. $p['progress'] = $count;
  78. return $p;
  79. }
  80. /**
  81. * 启动
  82. */
  83. public function boot(Request $request) {
  84. $uid = $request->uid();
  85. // 是否开启活动
  86. $symbol = Config::get('app.mining_symbo');
  87. if (!$symbol) {
  88. return app('json')->fail('本活动未开启');
  89. }
  90. // 是否已经开启
  91. $mining = UserHash::mining_get($uid);
  92. if ($mining) {
  93. if (isset($mining['progress']) && $mining['progress'] > 0.0) {
  94. return app('json')->fail('已启动');
  95. }
  96. }
  97. // 是否有订单
  98. $orderId = StoreOrderCartInfo::getMiningOrderId($uid);
  99. if (!$orderId) {
  100. return app('json')->fail('下单后可启动');
  101. }
  102. // 标记订单
  103. if (!StoreOrderCartInfo::setMining($orderId)) {
  104. return app('json')->fail('执行失败');
  105. }
  106. // 开启
  107. $secs_unit = Config::get('app.mining_sec_unit');
  108. $reward_unit = Config::get('app.mining_num_per_unit');
  109. $progress = floatval(bcdiv($reward_unit, $secs_unit, 8));
  110. $icon = DictCoin::getIcon($symbol);
  111. $balance = UserCoin::where('uid', $uid)->where('symbol', $symbol)->value('balance') ?? 0.0;
  112. $suc = UserHash::mining_set($uid, [
  113. 'symbol'=> $symbol,
  114. 'icon' => $icon,
  115. 'price' => 0,
  116. 'progress' => $progress,
  117. 'total' => $balance,
  118. 'ts' => time(),
  119. 'order_id' => $orderId,
  120. ]);
  121. if ($suc != 0 && $suc != 1) {
  122. StoreOrderCartInfo::setMining($orderId, 0);
  123. return app('json')->fail('未成功执行');
  124. }
  125. return app('json')->successful([
  126. "symbol" => $symbol,
  127. 'icon' => $icon,
  128. 'price' => 0,
  129. 'step' => $progress,
  130. 'progress' => $progress,
  131. 'total' => $balance,
  132. ]);
  133. }
  134. /**
  135. * 请求转账记录
  136. */
  137. public function history(Request $request) {
  138. [$page, $limit] = UtilService::getMore([
  139. ['page', 1],
  140. ['limit', 20],
  141. ], $request, true);
  142. $uid = $request->uid();
  143. $rows = UserCoinTransfer::getUserTransferred($uid, $page, $limit);
  144. return app('json')->successful($rows);
  145. }
  146. /*
  147. * 更新钱包地址
  148. */
  149. public function updateAddr(Request $request) {
  150. list($symbol, $addr) = UtilService::postMore([
  151. ['symbol', ''],
  152. ['addr', ''],
  153. ], $request, true);
  154. if (!$symbol || !$addr) {
  155. return app('json')->fail('参数不可为空');
  156. }
  157. if (!DictCoin::where('symbol', $symbol)->select()->toArray()) {
  158. return app('json')->fail('未找到目标');
  159. }
  160. $uid = $request->uid();
  161. $suc = UserCoin::upsertAddr($uid, $symbol, $addr);
  162. if (!$suc) {
  163. return app('json')->fail('执行失败');
  164. }
  165. return app('json')->successful();
  166. }
  167. /*
  168. * 提现
  169. */
  170. public function transfer(Request $request) {
  171. list($symbol, $amount) = UtilService::postMore([
  172. ['symbol', ''],
  173. ['amount', 0.0]
  174. ], $request, true);
  175. if(!$symbol) {
  176. return app('json')->fail('参数不可为空');
  177. }
  178. $meta = DictCoin::where('symbol', $symbol)->find();
  179. if (!$meta) {
  180. return app('json')->fail('未找到目标');
  181. }
  182. $meta = $meta->toArray();
  183. if ($amount < $meta['min_withdrawal']){
  184. return app('json')->fail('未达到最低限额');
  185. }
  186. $uid = $request->uid();
  187. $userCoin = UserCoin::where(['uid'=>$uid, 'symbol'=>$symbol])->find();
  188. if (!$userCoin) {
  189. return app('json')->fail('不适用的用户');
  190. }
  191. $userCoin = $userCoin->toArray();
  192. if(!$userCoin['addr']) {
  193. return app('json')->fail('地址未设置');
  194. }
  195. if ($userCoin['balance'] < $amount) {
  196. return app('json')->fail('余额不足');
  197. }
  198. $transferred = UserCoinTransfer::hasTransferred($uid, $symbol, $userCoin['addr']);
  199. if (!$transferred) {
  200. return app('json')->fail('首次操作需联系客服进行');
  201. }
  202. // transfer
  203. UserCoin::beginTrans();
  204. $left = bcsub($userCoin['balance'], $amount, 8);
  205. $res1 = UserCoin::where(['uid'=>$uid, 'symbol'=>$symbol])->update(['balance'=>$left]);
  206. $res2 = UserCoinTransfer::withdrawal($uid, $symbol, $userCoin['addr'], $amount);
  207. $ok = $res1 && $res2;
  208. UserCoin::checkTrans($ok);
  209. if (!$ok) {
  210. return app('json')->fail('执行失败');
  211. }
  212. return app('json')->successful('成功,已开始审核');
  213. }
  214. }