Parcourir la source

bugfix: 黑洞星球

joe il y a 3 ans
Parent
commit
8401df4f97
4 fichiers modifiés avec 150 ajouts et 61 suppressions
  1. 4 0
      CHANGELOG
  2. 140 56
      app/api/controller/coin/UserCoinController.php
  3. 2 1
      config/activity.php
  4. 4 4
      config/app.php

+ 4 - 0
CHANGELOG

@@ -0,0 +1,4 @@
+
+2022-02-14:
+ALTER TABLE twong.eb_dict_coin ADD mine_per_sec DECIMAL(8,8) DEFAULT 0.0 NOT NULL COMMENT '每秒可挖个数';
+ALTER TABLE twong.eb_dict_coin ADD status SMALLINT DEFAULT 0 NOT NULL COMMENT '0 上架但不可挖 -1 已下架 1 可挖';

+ 140 - 56
app/api/controller/coin/UserCoinController.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace app\api\controller\coin;
 
 use app\models\coin\UserCoinTransfer;
@@ -11,50 +12,103 @@ use crmeb\services\{UtilService, JsonService};
 use think\facade\Config;
 use think\facade\Cache;
 
-class UserCoinController {
+// 精度相关的函数
+// 转换为 string, 不同于 strval(),这个对于极小 float 不会使用科学计数法表示
+function twstr($val, $scale = 2): string
+{
+    return number_format($val, $scale, '.', '');
+}
+
+function twadd($l, $r, $scale = 2): string
+{
+    return bcadd(twstr($l, $scale + 2), twstr($r, $scale + 2), $scale);
+}
+
+function twsub($l, $r, $scale = 2): string
+{
+    return bcsub(twstr($l, $scale + 2), twstr($r, $scale + 2), $scale);
+}
+
+function twmul($l, $r, $scale = 2): string
+{
+    return bcmul(twstr($l, $scale + 2), twstr($r, $scale + 2), $scale);
+}
+
+function twdiv($l, $r, $scale = 2): string
+{
+    return bcdiv(twstr($l, $scale + 2), twstr($r, $scale + 2), $scale);
+}
+
+function twmod($l, $r, $scale = 2): string
+{
+    return bcmod(twstr($l, $scale + 2), twstr($r, $scale + 2), $scale);
+}
+
+function twcomp($l, $r, $scale = 2): string
+{
+    return bccomp(twstr($l, $scale + 2), twstr($r, $scale + 2), $scale);
+}
+
+class UserCoinController
+{
     /**
      * @api {get} /coin/status 挖矿当前状态
      * @apiName GetCoinStatus
      * @apiGroup User.Coin
      * 
      */
-    public function status(Request $request) {
+    public function status(Request $request)
+    {
         // 是否开启挖矿
         $symbol = Config::get('app.mining_symbo');
         //
-        $icon = Cache::get($symbol);
-        if (!$icon) {
-            $icon = DictCoin::where('symbol', $symbol)->value('icon');
-            Cache::set($symbol, $icon);
+        $coinInfo = Cache::get($symbol);
+        if (!$coinInfo) {
+            $coinInfo = DictCoin::where('symbol', $symbol)->find();
+            if (!$coinInfo) {
+                return app('json')->failed('活动临时关闭,请联系客服');
+            }
+            $coinInfo = $coinInfo->toArray();
+            Cache::set($symbol, $coinInfo);
         }
+        // print_r($coinInfo);
         //
         $defStatus = [
             'boot' => 0,
             'stop' => 0,
-            'progress'=> 0,
-            'symbol'=>$symbol,
-            'icon'=>$icon,
-            'price'=> 0.00,
-            'total'=> 0,
+            'progress' => 0,
+            'symbol' => $symbol,
+            'icon' => $coinInfo['icon'],
+            'price' => $coinInfo['price'],
+            'total' => 0,
             'step' => 0,
             'ts' => 0,
         ];
 
+        // 沒配置挖什麼
         if (!$symbol) {
             warnlog('mining disabled: $symbol');
             return app('json')->successful($defStatus);
         }
 
+        // 獲取用戶進度
         $uid = $request->uid();
-        $mymining = json_decode((new UserRds)->get($uid, UserRds::FIELD_MINING), true);
+        $rds = new UserRds();
+        $mymining = json_decode($rds->get($uid, UserRds::FIELD_MINING), true);
         if (!$mymining) {
             $mymining = $defStatus;
+            return app('json')->successful($defStatus);
         }
+        //
         if ($mymining['progress'] > 0.0) {
-            $mymining = $this->calcMining($uid, $mymining);
-            (new UserRds)->sets($uid, $mymining);
-        } else {
+            $mymining = $this->calcMining($uid, $coinInfo, $mymining);
+            $rds->set($uid, UserRds::FIELD_MINING, json_encode($mymining));
+        } else {    // 本次挖矿已经结束
             $mymining['total'] = UserCoin::where('uid', $uid)->where('symbol', $symbol)->value('balance') ?? 0.0;
+            $mymining['symbol'] = $symbol;
+            $mymining['icon'] = $coinInfo['icon'];
+            $mymining['price'] = $coinInfo['price'];
+            $mymining['step'] = self::get_step();
         }
         return app('json')->successful([
             'symbol' => $mymining['symbol'],
@@ -72,12 +126,12 @@ class UserCoinController {
      */
     protected function floatStep($step)
     {
-        $amp = bcdiv($step, 10, 8);
-		$min = bcsub($step, $amp, 8);
-		$max = bcadd($step, $amp, 8);
-		$distance = bcsub($max, $min, 8);
-		$section = bcdiv($distance, 10, 8);
-		return bcmul($section, mt_rand(0, 10), 8) + $min;
+        $amp = twdiv($step, 10, 8);
+        $min = twsub($step, $amp, 8);
+        $max = twadd($step, $amp, 8);
+        $distance = twsub($max, $min, 8);
+        $section = twdiv($distance, 10, 8);
+        return twmul($section, mt_rand(0, 10), 8) + $min;
     }
 
     /**
@@ -85,13 +139,16 @@ class UserCoinController {
      * @param $p
      * @return mixed
      */
-    protected function calcMining($uid, $p) {
-        if (!isset($p['ts']) || 
-            !isset($p['boot']) || 
-            !isset($p['stop']) || 
-            !isset($p['step']) || 
-            !isset($p['progress'])) {
-                warnlog('error format.');
+    protected function calcMining($uid, $coinInfo, $p)
+    {
+        if (
+            !isset($p['ts']) ||
+            !isset($p['boot']) ||
+            !isset($p['stop']) ||
+            !isset($p['step']) ||
+            !isset($p['progress'])
+        ) {
+            warnlog('error format.');
             return $p;
         }
 
@@ -108,8 +165,8 @@ class UserCoinController {
                 $secs_remain = 0;
             }
             // 本次个数
-            $count = floatval(bcmul($step, $secs_remain, 8));
-            $p['progress'] += floatval(bcadd($p['progress'], $count, 8));
+            $count = floatval(twmul($step, $secs_remain, 8));
+            $p['progress'] += floatval(twadd($p['progress'], $count, 8));
             // save to db
             UserCoinTransfer::beginTrans();
             $r1 = UserCoinTransfer::addMining($uid, $p['order_id'], $p['symbol'], $p['progress']);
@@ -122,37 +179,61 @@ class UserCoinController {
             }
             // -- save to db
             $p['ts'] = $now;
-            $p['total'] = floatval(bcadd($p['total'], $p['progress'], 8));
+            $p['total'] = floatval(twadd($p['total'], $p['progress'], 8));
             $p['progress'] = 0;
+            // 更换为可能的新的币种
+            $p['symbol'] = $coinInfo['symbol'];
+            $p['icon'] = $coinInfo['icon'];
+            $p['price'] = $coinInfo['price'];
+            $p['step'] = self::get_step();
             return $p;
         }
         // 进行中
-        $count = floatval(bcmul($step, $secs_passed, 8));
-        $p['progress'] = floatval(bcadd($p['progress'], $count, 8));
+        $count = floatval(twmul($step, $secs_passed, 8));
+        $p['progress'] = floatval(twadd($p['progress'], $count, 8));
         $p['ts'] = $now;
 
         return $p;
     }
 
+    public static function get_step(): float
+    {
+        $secs_unit = Config::get('app.mining_sec_unit');
+        $reward_unit = Config::get('app.mining_num_per_unit');
+        return twdiv($reward_unit, $secs_unit, 8);
+    }
+
     /**
      * @api {post} /coin/boot 启动挖矿
      * @apiName PostCoinBoot
      * @apiGroup User.Coin
      * 
      */
-    public function boot(Request $request) {
+    public function boot(Request $request)
+    {
         $uid = $request->uid();
         $now = time();
+        // 是否停止
+        if (Config::get('activity.mining_stopped')) {
+            return app('json')->fail('活动已暂停,稍后开启');
+        }
+
         // 是否开启活动
         $symbol = Config::get('app.mining_symbo');
         if (!$symbol) {
             return app('json')->fail('本活动未开启');
         }
         // 是否已经开启
-        $mining = json_decode((new UserRds)->get($uid, UserRds::FIELD_MINING), true);
+        $rds = new UserRds();
+        $mining = json_decode($rds->get($uid, UserRds::FIELD_MINING), true);
         if ($mining) {
-            if (isset($mining['progress']) && $mining['progress'] > 0.0
-                && isset($mining['boot']) && isset($mining['stop']) && isset($mining['ts'])) {
+            if (
+                isset($mining['progress']) &&
+                $mining['progress'] > 0.0 &&
+                isset($mining['boot']) &&
+                isset($mining['stop']) &&
+                isset($mining['ts'])
+            ) {
                 return app('json')->fail('已启动');
             }
         }
@@ -160,19 +241,19 @@ class UserCoinController {
         // 是否有订单
         $orderId = StoreOrderCartInfo::getMiningOrderId($uid);
         if (!$orderId) {
-            return app('json')->fail('参加活动后可启动,请参看新手教程');
+            return app('json')->fail('参加活动下单后可启动,请参看 首页->官方资讯->新手教程');
         }
         // 标记订单
         if (!StoreOrderCartInfo::setMining($orderId)) {
             return app('json')->fail('启动失败');
         }
         // 开启
-        $secs_unit = Config::get('app.mining_sec_unit');
-        $reward_unit = Config::get('app.mining_num_per_unit');
-        $step = floatval(bcdiv($reward_unit, $secs_unit, 8));
+        $step = self::get_step(); 
         $progress = $step;
         $icon = DictCoin::getIcon($symbol);
+        // 已挖总额
         $balance = UserCoin::where('uid', $uid)->where('symbol', $symbol)->value('balance') ?? 0.0;
+        // 单次活动时长
         $hours = Config::get('app.mining_time');
         if (count($hours) != 2 || $hours[0] > $hours[1]) {
             warnlog('app.mining_time config error.');
@@ -181,22 +262,22 @@ class UserCoinController {
         $hour = random_int($hours[0], $hours[1]);
         $stop = $now + $hour * 60 * 60;
 
-        $suc = (new UserRds)->sets($uid, [
+        $suc = $rds->set($uid, UserRds::FIELD_MINING, json_encode([
             'boot' => $now,
             'step' => $step,
             'stop' => $stop,
-            'symbol'=> $symbol,
+            'symbol' => $symbol,
             'icon' => $icon,
             'price' => 0,
             'progress' => $progress,
             'total' => $balance,
             'ts' => $now + 1,
             'order_id' => $orderId,
-        ]);
-        
+        ]));
+
         if ($suc != 0 && $suc != 1) {
             StoreOrderCartInfo::setMining($orderId, 0);
-            return app('json')->fail('未成功执行');
+            return app('json')->fail('未成功启动');
         }
 
         return app('json')->successful([
@@ -215,7 +296,8 @@ class UserCoinController {
      * @apiGroup User.Coin
      * 
      */
-    public function history(Request $request) {
+    public function history(Request $request)
+    {
         [$page, $limit] = UtilService::getMore([
             ['page', 1],
             ['limit', 20],
@@ -231,7 +313,8 @@ class UserCoinController {
      * @apiGroup User.Coin
      * 
      */
-    public function updateAddr(Request $request) {
+    public function updateAddr(Request $request)
+    {
         list($symbol, $addr) = UtilService::postMore([
             ['symbol', ''],
             ['addr', ''],
@@ -257,13 +340,14 @@ class UserCoinController {
      * @apiGroup User.Coin
      * 
      */
-    public function transfer(Request $request) {
+    public function transfer(Request $request)
+    {
         list($symbol, $amount) = UtilService::postMore([
             ['symbol', ''],
             ['amount', 0.0]
         ], $request, true);
 
-        if(!$symbol) {
+        if (!$symbol) {
             return app('json')->fail('参数不可为空');
         }
         $meta = DictCoin::where('symbol', $symbol)->find();
@@ -271,16 +355,16 @@ class UserCoinController {
             return app('json')->fail('未找到目标');
         }
         $meta = $meta->toArray();
-        if ($amount < $meta['min_withdrawal']){
+        if ($amount < $meta['min_withdrawal']) {
             return app('json')->fail('未达到最低限额');
         }
         $uid = $request->uid();
-        $userCoin = UserCoin::where(['uid'=>$uid, 'symbol'=>$symbol])->find();
+        $userCoin = UserCoin::where(['uid' => $uid, 'symbol' => $symbol])->find();
         if (!$userCoin) {
             return app('json')->fail('不适用的用户');
         }
         $userCoin = $userCoin->toArray();
-        if(!$userCoin['addr']) {
+        if (!$userCoin['addr']) {
             return app('json')->fail('地址未设置');
         }
         if ($userCoin['balance'] < $amount) {
@@ -292,8 +376,8 @@ class UserCoinController {
         }
         // transfer
         UserCoin::beginTrans();
-        $left = bcsub($userCoin['balance'], $amount, 8);
-        $res1 = UserCoin::where(['uid'=>$uid, 'symbol'=>$symbol])->update(['balance'=>$left]);
+        $left = twsub($userCoin['balance'], $amount, 8);
+        $res1 = UserCoin::where(['uid' => $uid, 'symbol' => $symbol])->update(['balance' => $left]);
         $res2 = UserCoinTransfer::withdrawal($uid, $symbol, $userCoin['addr'], $amount);
 
         $ok = $res1 && $res2;
@@ -303,4 +387,4 @@ class UserCoinController {
         }
         return app('json')->successful('成功,已开始审核');
     }
-}
+}

+ 2 - 1
config/activity.php

@@ -4,7 +4,8 @@ return [
     // 根分类ID
     'root_cate_id' => 10,
     // 是否开启挖矿活动
-    'mining_enabled' => true,
+    'mining_enabled' => true,   // 决定客户端是否显示黑洞星球活动
+    'mining_stopped' => false,   // 停止挖矿,启用但停止,可以让当前挖矿未结束的用户结束挖矿,进而关闭活动或更换矿种
     'mining_display_name' => '黑洞星球',
     'mining_display_pic' => 'http://x.png',
     // 挖矿活动ID

+ 4 - 4
config/app.php

@@ -44,7 +44,7 @@ return [
     'show_error_msg'   => false,
 
     // 前端是否顯示商品賠付盈利
-    'show_benefit' => false,
+    'show_benefit' => true,
     'off_days_before'  => 30,   // 超過(n)天數下架
     // 部署的云服务器或 VPS IP 地址
     'server_ip'        => '81.70.81.74',
@@ -66,11 +66,11 @@ return [
 
     /// 挖矿配置, 每次更新币种后需要重新配置
     // 单次挖矿时长
-    'mining_symbo' => 'DOGE',
-    'mining_time' => [1, 2],
+    'mining_symbo' => 'RMB',
+    'mining_time' => [20, 24],    // 两个值 [min, max] 之间随机, 单位 h
     // 每 @mining_sec_unit 挖币 @mining_num_per_unit
     'mining_sec_unit' => 1,
-    'mining_num_per_unit' => 0.01,
+    'mining_num_per_unit' => 0.000024,
 
     // 排行榜 banner 750 x 142 首页 banner 750x375 精品推荐滚动图 750x282
     'leader_board_banner' => 'http://twongstatic.shotshock.shop/banner_rank_750x142.jpg',