فهرست منبع

updating: 基本完成挖矿服务端,继续测试

joe 4 سال پیش
والد
کامیت
6d5ccdb28e

+ 65 - 33
app/api/controller/coin/UserCoinController.php

@@ -9,6 +9,7 @@ use app\models\user\UserCoin;
 use app\Request;
 use crmeb\services\{UtilService, JsonService};
 use think\facade\Config;
+use think\facade\Cache;
 
 class UserCoinController {
     public function status(Request $request) {
@@ -22,12 +23,15 @@ class UserCoinController {
         }
         //
         $defStatus = [
+            'boot' => 0,
+            'stop' => 0,
             'progress'=> 0,
             'symbol'=>$symbol,
             'icon'=>$icon,
             'price'=> 0.00,
             'total'=> 0,
             'step' => 0,
+            'ts' => 0,
         ];
 
         if (!$symbol) {
@@ -36,11 +40,22 @@ class UserCoinController {
         }
 
         $uid = $request->uid();
-        $mymining = UserHash::mining_get($uid) ?? $defStatus;
-        if ($mymining['progress'] > 0) {
-            $mining = $this->calcMining($uid, $mymining);
-            UserHash::mining_set($uid, $mining);
+        $mymining = UserHash::mining_get($uid);
+        if (!$mymining) {
+            $mymining = $defStatus;
         }
+        if ($mymining['progress'] > 0.0) {
+            $mymining = $this->calcMining($uid, $mymining);
+            UserHash::mining_set($uid, $mymining);
+        }
+        return app('json')->successful([
+            'symbol' => $mymining['symbol'],
+            'icon' => $mymining['icon'],
+            'price' => $mymining['price'],
+            'step' => $mymining['step'],
+            'progress' => $mymining['progress'],
+            'total' => $mymining['total'],
+        ]);
     }
 
     /**
@@ -52,37 +67,41 @@ class UserCoinController {
         if ($p['progress'] <= 0) {
             return $p;
         }
-        if (!isset($p['ts'])) {
+        if (!isset($p['ts']) || !isset($p['boot']) || !isset($p['stop']) || !isset($p['step'])) {
+            Log::warning('error format.');
             return $p;
         }
         $now = time();
-        $secs_passed = $now - $p['ts'];
-        $secs_unit = Config::get('app.mining_sec_unit');
-        $reward_unit = Config::get('app.mining_num_per_unit');
-        $hours = Config::get('app.mining_time');
-        if (count($hours) != 2 || $hours[0] > $hours[1]) {
-            Log::warning('app.mining_time config error.');
-            return $p;
-        }
-        $hour = random_int($hours[0], $hours[1]);
-        $secs = $hour * 60 * 60;
+        $secs_passed = $now - $p['ts'];     // 从上次到现在
         //
-        if ($secs_passed >= $secs) { // 挖矿结束
-            $p['progress'] = 0;
-
+        if ($now >= $p['stop']) { // 挖矿结束
+            $secs_remain = $p['stop'] - $p['ts'];
+            if ($secs_remain < 0) {
+                $secs_remain = 0;
+            }
             // 本次个数
-            $count = floatval(bcmul(bcdiv($secs, $secs_unit, 8), $reward_unit, 8));
-            // save to database
-            if (!UserCoinTransfer::addMining($uid, $p['order_id'], $p['symbol'], $count)) {
-                Log::error("user<$uid> save transfer failed, amount<$count>");
+            $count = floatval(bcmul($p['step'], $secs_remain, 8));
+            $p['progress'] += floatval(bcadd($p['progress'], $count, 8));
+            // save to db
+            UserCoinTransfer::beginTrans();
+            $r1 = UserCoinTransfer::addMining($uid, $p['order_id'], $p['symbol'], $p['progress']);
+            $r2 = UserCoin::upsertCoin($uid, $p['symbol'], $p['progress']);
+            UserCoinTransfer::checkTrans($r1 && $r2);
+            if (!$r1 || !$r2) {
+                $amount = $p['progress'];
+                Log::error("user<$uid> save transfer failed, amount<$amount>");
+                return $p;
             }
-
-            $p['total'] += $count;
+            // -- save to db
+            $p['ts'] = $now;
+            $p['total'] = floatval(bcadd($p['total'], $p['progress'], 8));
+            $p['progress'] = 0;
             return $p;
         }
-
-        $count = floatval(bcmul(bcdiv($secs_passed, $secs_unit, 8), $reward_unit, 8));
-        $p['progress'] = $count;
+        // 进行中
+        $count = floatval(bcmul($p['step'], $secs_passed, 8));
+        $p['progress'] = floatval(bcadd($p['progress'], $count, 8));
+        $p['ts'] = $now;
 
         return $p;
     }
@@ -92,6 +111,7 @@ class UserCoinController {
      */
     public function boot(Request $request) {
         $uid = $request->uid();
+        $now = time();
         // 是否开启活动
         $symbol = Config::get('app.mining_symbo');
         if (!$symbol) {
@@ -100,7 +120,8 @@ class UserCoinController {
         // 是否已经开启
         $mining = UserHash::mining_get($uid);
         if ($mining) {
-            if (isset($mining['progress']) && $mining['progress'] > 0.0) {
+            if (isset($mining['progress']) && $mining['progress'] > 0.0
+                && isset($mining['boot']) && isset($mining['stop']) && isset($mining['ts'])) {
                 return app('json')->fail('已启动');
             }
         }
@@ -108,26 +129,37 @@ class UserCoinController {
         // 是否有订单
         $orderId = StoreOrderCartInfo::getMiningOrderId($uid);
         if (!$orderId) {
-            return app('json')->fail('下单后可启动');
+            return app('json')->fail('参加活动后可启动,请参看新手教程');
         }
         // 标记订单
         if (!StoreOrderCartInfo::setMining($orderId)) {
-            return app('json')->fail('执行失败');
+            return app('json')->fail('启动失败');
         }
         // 开启
         $secs_unit = Config::get('app.mining_sec_unit');
         $reward_unit = Config::get('app.mining_num_per_unit');
-        $progress = floatval(bcdiv($reward_unit, $secs_unit, 8));
+        $step = floatval(bcdiv($reward_unit, $secs_unit, 8));
+        $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]) {
+            Log::warning('app.mining_time config error.');
+            return app('json')->fail('启动失败,请联系客服');;
+        }
+        $hour = random_int($hours[0], $hours[1]);
+        $stop = $now + $hour * 60 * 60;
 
         $suc = UserHash::mining_set($uid, [
+            'boot' => $now,
+            'step' => $step,
+            'stop' => $stop,
             'symbol'=> $symbol,
             'icon' => $icon,
             'price' => 0,
             'progress' => $progress,
             'total' => $balance,
-            'ts' => time(),
+            'ts' => $now + 1,
             'order_id' => $orderId,
         ]);
 
@@ -137,7 +169,7 @@ class UserCoinController {
         }
 
         return app('json')->successful([
-            "symbol" => $symbol,
+            'symbol' => $symbol,
             'icon' => $icon,
             'price' => 0,
             'step' => $progress,

+ 1 - 0
app/models/coin/UserCoinTransfer.php

@@ -74,6 +74,7 @@ class UserCoinTransfer extends BaseModel {
             ->alias('t')->join('dict_coin c', 'c.symbol=t.symbol')
             ->field('t.symbol, c.icon, t.from, t.to, t.amount, t.out, t.ts')
             ->limit(($page-1) * $limit, $limit)->select()->toArray();
+        //echo self::getLastSql();
         return $res;
     }
 

+ 17 - 1
app/models/user/UserCoin.php

@@ -8,7 +8,8 @@ class UserCoin extends BaseModel {
 
     use ModelTrait;
 
-    public static function upsertAddr($uid, $symbol, $addr) {
+    public static function upsertAddr($uid, $symbol, $addr) 
+    {
         $cond = ['uid'=>$uid, 'symbol'=>$symbol];
         $row = self::where($cond)->find();
         if ($row) {
@@ -21,4 +22,19 @@ class UserCoin extends BaseModel {
             ]);
         }
     }
+
+    public static function upsertCoin($uid, $symbol, $amount)
+    {
+        $cond = ['uid'=>$uid, 'symbol'=>$symbol];
+        $row = self::where($cond)->find();
+        if ($row) {
+            return self::where($cond)->inc('balance', $amount)->update();
+        }else{
+            return self::create([
+                'uid'=>$uid,
+                'symbol'=>$symbol,
+                'balance'=>$amount,
+            ]);
+        }
+    }
 }

+ 1 - 1
config/activity.php

@@ -4,7 +4,7 @@ return [
     // 根分类ID
     'root_cate_id' => 10,
     // 是否开启挖矿活动
-    'mining_enabled' => false,
+    'mining_enabled' => true,
     'mining_display_name' => '黑洞星球',
     'mining_display_pic' => 'http://x.png',
     // 挖矿活动ID

+ 2 - 2
config/app.php

@@ -54,9 +54,9 @@ return [
     /// 挖矿配置, 每次更新币种后需要重新配置
     // 单次挖矿时长
     'mining_symbo' => 'DOGE',
-    'mining_time' => [12, 24],
+    'mining_time' => [1, 2],
     // 每 @mining_sec_unit 挖币 @mining_num_per_unit
-    'mining_sec_unit' => 5,
+    'mining_sec_unit' => 1,
     'mining_num_per_unit' => 0.01,
 
     // 排行榜 banner 750 x 142

+ 14 - 0
crmeb/services/async/ActivityCalc.php

@@ -10,6 +10,12 @@ use app\models\user\UserNotice;
 use crmeb\basic\BaseModel;
 use think\facade\Log;
 
+
+/**
+ * 活动基类
+ * 
+ * 活动设计为:一个活动有一个商品分类,该分类下的商品为该活动商品
+ */
 abstract class ActivityCalc {
     protected $ctx = [];
 
@@ -18,6 +24,7 @@ abstract class ActivityCalc {
     }
 
     /**
+     * 根据分类 ID 来获取该分类下已被购买的单件商品,及其订单,用户信息
      * @param $cate_id
      * @return array
      */
@@ -38,7 +45,11 @@ abstract class ActivityCalc {
         return $products;
     }
 
+    /**
+     * 用统一的架构来计算输赢
+     */
     public function calc() {
+        // 活动分类ID
         $cate_id = $this->getId();
         $products = self::getOrders($cate_id);
         if (count($products) <= 1) {
@@ -55,6 +66,7 @@ abstract class ActivityCalc {
         $left_cost = 0;
         $right_cost = 0;
 
+        // 打乱商品顺序
         shuffle($products);
         shuffle($products);
 
@@ -75,9 +87,11 @@ abstract class ActivityCalc {
             $pcost = bcmul($num, $cost, 2);
             // orderId
             $oid = $p['id'];
+            // 标记付款和成本
             $p['paid'] = $ppaid;
             $p['cost'] = $pcost;
 
+            // 处理一个订单多件商品的情况
             if (!isset($orders[$oid])) {
                 $orders[$oid] = 1;
             } else {

+ 6 - 1
crmeb/services/async/ClearanceCalc.php

@@ -30,9 +30,10 @@ class ClearanceCalc extends ActivityCalc{
     }
 
     protected function getNameCN() {
-        return '抢神';
+        return '神抢手';
     }
 
+    // 赔款比例, 为利润的比例
     protected function repRate() {
         return 0.2;
     }
@@ -41,6 +42,10 @@ class ClearanceCalc extends ActivityCalc{
         return 0;
     }
 
+    /**
+     * 分边函数,返回 true 分到左边
+     * 
+     */
     protected function leaningJudge($index, $product, $attr) {
         return $index % 2 != 0;
     }

+ 4 - 0
crmeb/services/async/LuckyCalc.php

@@ -29,6 +29,10 @@ class LuckyCalc extends ActivityCalc{
         return $leftwin ? 20 : 21;
     }
 
+    /**
+     * 20 分类到左边
+     * 这里严格要求商品必须设置 20 21 属性
+     */
     protected function leaningJudge($index, $product, $attr) {
         $suk = isset($attr['suk']) ? $attr['suk'] : 'any';
         $flag = $this->searchActiveInSuk($suk);

+ 3 - 1
docs/TODO

@@ -3,4 +3,6 @@
 
 # 优化排行榜为 5m 刷新一次 ,存入redis
 
-# 定时删除多余跑马灯
+# 定时删除多余跑马灯
+
+# admin, no multi-category. must have 2021 in lucky category while no 2021 in others.