UserCoinController.php 8.8 KB

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