wesmiler 6 mēneši atpakaļ
vecāks
revīzija
c0eeee68a3
100 mainītis faili ar 395 papildinājumiem un 1401 dzēšanām
  1. 0 1
      app/Helpers/common.php
  2. 22 25
      app/Http/Controllers/Api/v1/ExamController.php
  3. 10 8
      app/Http/Controllers/Api/v1/TestController.php
  4. 0 291
      app/Services/Api/BalanceLogService.php
  5. 3 1
      app/Services/Api/CourseService.php
  6. 0 464
      app/Services/Api/DepositService.php
  7. 248 19
      app/Services/Api/ExamService.php
  8. 0 198
      app/Services/Api/GoodsService.php
  9. 2 187
      app/Services/Api/OrderService.php
  10. 69 31
      app/Services/Api/PaperService.php
  11. 35 33
      app/Services/DeepSeekService.php
  12. 6 6
      config/platform.php
  13. BIN
      public/app/jdapp_v1.2.30.apk
  14. BIN
      public/favicon.ico
  15. BIN
      public/h5/assets/uvicons.f0fbf8a0.ttf
  16. 0 2
      public/h5/index.html
  17. 0 21
      public/h5/static/customicons.css
  18. BIN
      public/h5/static/customicons.ttf
  19. 0 32
      public/h5/static/iconfont.css
  20. BIN
      public/h5/static/iconfont.ttf
  21. BIN
      public/h5/static/icons/home-active.png
  22. BIN
      public/h5/static/icons/home.png
  23. BIN
      public/h5/static/icons/mine-active.png
  24. BIN
      public/h5/static/icons/mine.png
  25. BIN
      public/h5/static/icons/order-active.png
  26. BIN
      public/h5/static/icons/order-delivery-active.png
  27. BIN
      public/h5/static/icons/order-delivery.png
  28. BIN
      public/h5/static/icons/order.png
  29. BIN
      public/h5/static/images/bg.png
  30. BIN
      public/h5/static/images/card-bg.png
  31. BIN
      public/h5/static/images/icon-account-log.png
  32. BIN
      public/h5/static/images/icon-alipay.png
  33. BIN
      public/h5/static/images/icon-avatar.png
  34. BIN
      public/h5/static/images/icon-code.png
  35. BIN
      public/h5/static/images/icon-coin.png
  36. BIN
      public/h5/static/images/icon-copy.png
  37. BIN
      public/h5/static/images/icon-cricle.png
  38. BIN
      public/h5/static/images/icon-custom-avatar.png
  39. BIN
      public/h5/static/images/icon-custom-menu.png
  40. BIN
      public/h5/static/images/icon-despoit-refund.png
  41. BIN
      public/h5/static/images/icon-empty.png
  42. BIN
      public/h5/static/images/icon-header-card.png
  43. BIN
      public/h5/static/images/icon-loading.png
  44. BIN
      public/h5/static/images/icon-log.png
  45. BIN
      public/h5/static/images/icon-modify-pwd.png
  46. BIN
      public/h5/static/images/icon-password.png
  47. BIN
      public/h5/static/images/icon-phone.png
  48. BIN
      public/h5/static/images/icon-phone1.png
  49. BIN
      public/h5/static/images/icon-phone2.png
  50. BIN
      public/h5/static/images/icon-privacy.png
  51. BIN
      public/h5/static/images/icon-pwd-right.png
  52. BIN
      public/h5/static/images/icon-radio-check.png
  53. BIN
      public/h5/static/images/icon-radio-checked.png
  54. BIN
      public/h5/static/images/icon-recharge-menu.png
  55. BIN
      public/h5/static/images/icon-recharge.png
  56. BIN
      public/h5/static/images/icon-register.png
  57. BIN
      public/h5/static/images/icon-upload.png
  58. BIN
      public/h5/static/images/icon-voice-menu.png
  59. BIN
      public/h5/static/images/icon-voice.png
  60. BIN
      public/h5/static/images/icon-withdraw-menu.png
  61. BIN
      public/h5/static/images/icon-wxpay.png
  62. BIN
      public/h5/static/images/loading.gif
  63. BIN
      public/h5/static/images/no-data.png
  64. 0 1
      public/h5/static/index.883130ca.css
  65. 0 29
      public/h5/static/js/chunk-vendors.08ad7f7b.js
  66. 0 1
      public/h5/static/js/index.c2f2b229.js
  67. 0 1
      public/h5/static/js/pages-account-log.cd0c6bd7.js
  68. 0 1
      public/h5/static/js/pages-account-log~pages-account-withdraw~pages-account-withdrawLog~pages-agree-recharge~pages-agree-~04f4b299.1c97a3dc.js
  69. 0 1
      public/h5/static/js/pages-account-log~pages-account-withdraw~pages-account-withdrawLog~pages-chat-index~pages-deposit-lo~0061d6ff.e6502d94.js
  70. 0 1
      public/h5/static/js/pages-account-log~pages-account-withdraw~pages-account-withdrawLog~pages-chat-index~pages-deposit-lo~6fea2be9.c88fe845.js
  71. 0 1
      public/h5/static/js/pages-account-withdraw.ab4473e2.js
  72. 0 1
      public/h5/static/js/pages-account-withdrawLog.e04f6953.js
  73. 0 1
      public/h5/static/js/pages-account-withdraw~pages-chat-index~pages-deposit-pay~pages-deposit-refund~pages-deposit-refuse~~8c2da746.39796529.js
  74. 0 1
      public/h5/static/js/pages-agree-recharge.932f28bd.js
  75. 0 1
      public/h5/static/js/pages-agree-recharge~pages-agree-register~pages-article-privacy.52f1a4dc.js
  76. 0 1
      public/h5/static/js/pages-agree-register.6d87283e.js
  77. 0 1
      public/h5/static/js/pages-article-privacy.2478202d.js
  78. 0 1
      public/h5/static/js/pages-chat-index.6f113bea.js
  79. 0 1
      public/h5/static/js/pages-deposit-log.d5d76fc9.js
  80. 0 1
      public/h5/static/js/pages-deposit-pay.e3f38737.js
  81. 0 1
      public/h5/static/js/pages-deposit-refund.73e99416.js
  82. 0 1
      public/h5/static/js/pages-deposit-refuse.13811af3.js
  83. 0 1
      public/h5/static/js/pages-index-index.a4464313.js
  84. 0 1
      public/h5/static/js/pages-index-index~pages-order-delivery~pages-order-index.baf0e525.js
  85. 0 1
      public/h5/static/js/pages-login-forget.6a8ff486.js
  86. 0 1
      public/h5/static/js/pages-login-forget~pages-login-login~pages-register-index.adfce370.js
  87. 0 1
      public/h5/static/js/pages-login-login.26302269.js
  88. 0 1
      public/h5/static/js/pages-mine-index.410be7bb.js
  89. 0 1
      public/h5/static/js/pages-mine-modify.696445df.js
  90. 0 1
      public/h5/static/js/pages-mine-profile.a563048f.js
  91. 0 1
      public/h5/static/js/pages-order-delivery.ba1fe2ed.js
  92. 0 1
      public/h5/static/js/pages-order-detail.4c8a36d0.js
  93. 0 1
      public/h5/static/js/pages-order-index.0298dfb5.js
  94. 0 1
      public/h5/static/js/pages-order-picker.042362ba.js
  95. 0 1
      public/h5/static/js/pages-register-index.95af7d49.js
  96. BIN
      public/h5/static/logo.png
  97. BIN
      public/h5/static/mp3/msg.mp3
  98. 0 22
      public/h5/static/theme.css
  99. BIN
      public/h5/static/uni.ttf
  100. 0 0
      routes/api.php

+ 0 - 1
app/Helpers/common.php

@@ -2167,7 +2167,6 @@ if (!function_exists('httpRequest')) {
             curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
             $ret = curl_exec($ch);
             $ret = trim($ret);
-            var_dump($ret);
             curl_close($ch);
             if (!preg_match("/^{/", $ret)) {
                 return ['code' => 'err', 'msg' => $ret];

+ 22 - 25
app/Http/Controllers/Api/v1/ExamController.php

@@ -74,27 +74,8 @@ class ExamController extends webApp
     {
         try {
             $params = request()->all();
-            if(ExamService::make()->answer($this->userId, $params)){
-                return showJson(1002, true);
-            }else{
-                return showJson(ExamService::make()->getError(), false);
-            }
-        } catch (\Exception $exception) {
-            $error = ['error' => $exception->getMessage(), 'trace' => $exception->getTrace()];
-            return message(1009, false, $error);
-        }
-    }
-
-    /**
-     * 交卷
-     * @return array
-     */
-    public function submit()
-    {
-        try {
-            $params = request()->all();
-            if(ExamService::make()->submit($this->userId, $params)){
-                return showJson(1002, true);
+            if($result = ExamService::make()->answer($this->userId, $params)){
+                return showJson(ExamService::make()->getError(), true, $result);
             }else{
                 return showJson(ExamService::make()->getError(), false);
             }
@@ -112,7 +93,7 @@ class ExamController extends webApp
     {
         try {
             $id = request()->post('id');
-            if(ExamService::make()->reset($id)){
+            if(ExamService::make()->reset($id, $this->userId)){
                 return showJson(1002, true);
             }else{
                 return showJson(ExamService::make()->getError(), false);
@@ -131,12 +112,12 @@ class ExamController extends webApp
     public function info()
     {
         $params = request()->all();
-        $id = isset($params['id']) ? intval($params['id']) : 0;
-        if (empty($id)) {
+        $rid = isset($params['rid']) ? intval($params['rid']) : 0;
+        if (empty($rid)) {
             return message(1036, false);
         }
 
-        if ($info = ArticleService::make()->getInfo($id)) {
+        if ($info = ExamService::make()->getInfo($rid)) {
             return message(1010, true, $info);
         } else {
             return message(1009, false);
@@ -158,4 +139,20 @@ class ExamController extends webApp
         $datas = ExamService::make()->getRankByType($type);
         return message(1010, true, $datas);
     }
+
+    /**
+     * 排行榜
+     */
+    public function cards()
+    {
+        $params = request()->all();
+        $rid = isset($params['rid']) ? intval($params['rid']) : 0;
+        $paperId = isset($params['id']) ? intval($params['id']) : 0;
+        if (empty($paperId)) {
+            return message(1031, false);
+        }
+
+        $datas = ExamService::make()->getCardList($this->userId, $paperId,  $rid);
+        return message(1010, true, $datas);
+    }
 }

+ 10 - 8
app/Http/Controllers/Api/v1/TestController.php

@@ -17,23 +17,25 @@ class TestController extends webApp
 
     public function check()
     {
-        $result = (new TesseractOCR(ATTACHMENT_PATH.'/temp/20250922/answer1.jpeg'))->lang('chi_sim')->run();
+        $ocr = new TesseractOCR();
+        $result = $ocr->recognize(ATTACHMENT_PATH.'/temp/20250922/answer1.jpeg');
+//        $result = (new TesseractOCR(ATTACHMENT_PATH.'/temp/20250922/answer1.jpeg'))->lang('chi_sim')->run();
         dump($result);
-        return 66;
+//        return 66;
 
 
         $data = [
-//            'answer'=> '表达了诗人孤独、愁苦的心境和对时光流逝的感慨。',
-            'answer'=> 'https://shuati.derkj.com/uploads/temp/20250922/answer1.jpeg',
+            'answer'=> '表达了诗人孤独、愁苦的心境和对时光流逝的感慨。',
+//            'answer'=> 'https://shuati.derkj.com/uploads/temp/20250922/answer1.jpeg',
             'score'=>10,
-            'topic'=> 'https://shuati.derkj.com/uploads/temp/20250922/topic2.png',
-//            'topic'=> '2.请简述一下杜甫的诗《登高》中“无边落木萧萧下,不尽长江滚滚来”这两句诗描绘了怎样的景象?表达了诗人怎样的情感?',
+//            'topic'=> 'https://shuati.derkj.com/uploads/temp/20250922/topic2.png',
+            'topic'=> '2.请简述一下杜甫的诗《登高》中“无边落木萧萧下,不尽长江滚滚来”这两句诗描绘了怎样的景象?表达了诗人怎样的情感?',
             'type'=> 2
         ];
 
 
-        $result = DeepSeekService::make()->upload('/temp/20250922/topic2.jpeg');
-//        $result = DeepSeekService::make()->apiRequest($data,'deepseek-chat');
+//        $result = DeepSeekService::make()->upload('/temp/20250922/topic2.jpeg');
+        $result = DeepSeekService::make()->apiRequest($data,'deepseek-chat');
         dump($result);
 //        $papers = [28,29];
 //        $datas = [];

+ 0 - 291
app/Services/Api/BalanceLogService.php

@@ -1,291 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
-// +----------------------------------------------------------------------
-// | 版权所有 2017~2021 LARAVEL研发中心
-// +----------------------------------------------------------------------
-// | 官方网站: http://www.laravel.cn
-// +----------------------------------------------------------------------
-// | Author: laravel开发员 <laravel.qq.com>
-// +----------------------------------------------------------------------
-
-namespace App\Services\Api;
-
-use App\Models\AccountLogModel;
-use App\Models\ActionLogModel;
-use App\Models\BalanceLogModel;
-use App\Models\MemberModel;
-use App\Services\BaseService;
-use App\Services\ConfigService;
-use App\Services\RedisService;
-use Illuminate\Support\Facades\DB;
-
-/**
- * 余额管理-服务类
- * @author laravel开发员
- * @since 2020/11/11
- */
-class BalanceLogService extends BaseService
-{
-    public static $instance = null;
-
-    /**
-     * 构造函数
-     * @author laravel开发员
-     * @since 2020/11/11
-     * AccountService constructor.
-     */
-    public function __construct()
-    {
-        $this->model = new BalanceLogModel();
-    }
-
-    /**
-     * 静态入口
-     * @return static|null
-     */
-    public static function make()
-    {
-        if (!self::$instance) {
-            self::$instance = (new static());
-        }
-        return self::$instance;
-    }
-
-    /**
-     * @param $params
-     * @param int $pageSize
-     * @return array
-     */
-    public function getDataList($params, $pageSize = 15)
-    {
-        $query = $this->getQuery($params);
-        $list = $query->select(['a.*'])
-            ->orderBy('a.status','asc')
-            ->orderBy('a.create_time','desc')
-            ->orderBy('a.id','desc')
-            ->paginate($pageSize > 0 ? $pageSize : 9999999);
-        $list = $list? $list->toArray() :[];
-        if($list){
-            foreach($list['data'] as &$item){
-                $item['create_time'] = $item['create_time']? datetime($item['create_time'],'Y-m-d H:i:s') : '';
-                $item['time_text'] = $item['create_time']? datetime($item['create_time'],'Y年m月d日') : '';
-            }
-        }
-
-        return [
-            'pageSize'=> $pageSize,
-            'total'=>isset($list['total'])? $list['total'] : 0,
-            'list'=> isset($list['data'])? $list['data'] : []
-        ];
-    }
-
-    public function getQuery($params)
-    {
-        $where = ['a.mark' => 1];
-        $status = isset($params['status'])? $params['status'] : 0;
-        $type = isset($params['type'])? $params['type'] : 0;
-        if($status>0){
-            $where['a.status'] = $status;
-        }
-        if($type>0){
-            $where['a.type'] = $type;
-        }
-
-        return $this->model->with(['member'])->from("balance_logs as a")
-            ->leftJoin('member as b','b.id','=','a.user_id')
-            ->where($where)
-            ->where(function ($query) use($params) {
-                $keyword = isset($params['keyword']) ? $params['keyword'] : '';
-                $userId = isset($params['user_id'])? $params['user_id'] : 0;
-                if($userId){
-                    $query->where('a.user_id',$userId);
-                }
-
-                if ($keyword) {
-                    $query->where(function($query) use($keyword){
-                        $query->where('b.nickname','like',"%{$keyword}%")
-                            ->orWhere('b.mobile','like',"%{$keyword}%")
-                            ->orWhere('b.realname','like',"%{$keyword}%");
-                    });
-                }
-
-                $orderNo = isset($params['order_no'])? trim($params['order_no']) : '';
-                if($orderNo){
-                    $query->where(function($query) use($orderNo){
-                        $query->where('a.order_no','like',"%{$orderNo}%");
-                    });
-                }
-
-
-                $account = isset($params['account'])? trim($params['account']) : '';
-                if($account){
-                    $query->where(function($query) use($account){
-                        $query->where('a.account','like',"%{$account}%");
-                    });
-                }
-            })
-            ->where(function ($query) use($params){
-
-                // 日期
-                $date = isset($params['date']) ? $params['date'] : [];
-                $start = isset($date[0])? $date[0] : '';
-                $end = isset($date[1])? $date[1] : '';
-                $end = $start>=$end? '' : $end;
-                if ($start) {
-                    $query->where('a.create_time','>=', strtotime($start));
-                }
-                if($end){
-                    $query->where('a.create_time','<=', strtotime($end));
-                }
-            });
-    }
-
-    /**
-     * 收入提现
-     * @param $userId
-     * @param $params
-     * @return array|false
-     */
-    public function withdraw($userId, $params)
-    {
-        // 参数验证
-        $money = isset($params['money'])? floatval($params['money']) : 0;
-        $remark = isset($params['remark'])? trim($params['remark']) : '';
-        $account = isset($params['account'])? trim($params['account']) : '';
-        $realname = isset($params['realname'])? trim($params['realname']) : '';
-        if($money<=0){
-            $this->error = 2301;
-            return false;
-        }
-        if(empty($realname) || empty($account)){
-            $this->error = 2302;
-            return false;
-        }
-
-        $openWithdraw = ConfigService::make()->getConfigByCode('withdraw_open',1);
-        if(!$openWithdraw){
-            $this->error = 2304;
-            return false;
-        }
-
-        $withdrawMin = ConfigService::make()->getConfigByCode('withdraw_min',0.1);
-        if($withdrawMin>0 && $money < $withdrawMin){
-            $this->error = lang(2305,['money'=>$withdrawMin]);
-            return false;
-        }
-
-
-        // 锁
-        $cacheLockKey = "caches:members:withdraw:{$userId}";
-        if(RedisService::get($cacheLockKey)){
-            $this->error = 1034;
-            return false;
-        }
-
-        // 判断用户账号状态
-        RedisService::set($cacheLockKey, ['user_id'=>$userId,'params'=>$params], rand(10,20));
-        $userInfo = MemberService::make()->getInfo($userId,[], true);
-        $confirmStatus = isset($userInfo['confirm_status'])? $userInfo['confirm_status'] : 0;
-        $status = isset($userInfo['status'])? $userInfo['status'] : 0;
-        $balance = isset($userInfo['balance'])? $userInfo['balance'] : 0;
-        $nickname = isset($userInfo['nickname'])? $userInfo['nickname'] : '';
-        if(empty($userInfo) || $status != 1){
-            $this->error = 2016;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 账号审核情况
-        if($confirmStatus != 1){
-            $this->error = 2042;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        if($money> $balance){
-            $this->error = 2303;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 提现处理
-        DB::beginTransaction();
-        $updateData = ['balance'=>DB::raw("balance - {$money}"),'update_time'=>time()];
-        if(!MemberModel::where(['id'=> $userId])->update($updateData)){
-            DB::rollBack();
-            $this->error = 2306;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        $orderNo = get_order_num('JW');
-        $order = [
-            'user_id'=> $userId,
-            'order_no'=> $orderNo,
-            'money'=> $money,
-            'before_money'=> $balance,
-            'type'=>2,
-            'pay_type'=>0,
-            'remark'=> $remark,
-            'realname'=> $realname,
-            'account'=> $account,
-            'create_time'=> time(),
-            'status'=>1,
-            'mark'=>1
-        ];
-        if(!$orderId = $this->model::insertGetId($order)){
-            DB::rollBack();
-            $this->error = 2307;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        $log = [
-            'user_id' => $userId,
-            'source_order_no' => $orderNo,
-            'type' => 4,
-            'money' => $money,
-            'before_money' => $balance,
-            'date'=> date('Y-m-d'),
-            'create_time' => time(),
-            'remark' => '收入提现',
-            'status' => 1,
-            'mark' => 1,
-        ];
-        if(!AccountLogModel::insertGetId($log)){
-            DB::rollBack();
-            $this->error = 2307;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        DB::commit();
-
-        $title = "用户[{$nickname}]申请了提现";
-        $message = [
-            'from_uid'=> $userId,
-            'to_uid'=> 1,
-            'op'=> 'notice',
-            'scene'=> 'withdraw',
-            'message'=> '提现消息',
-            'type'=> 6,
-            'order'=>[
-                'title'=> $title.'<span class="ele-text-primary">查看订单</span>',
-                'order_no'=> $orderNo,
-                'money'=> $money,
-                'date'=> date('Y-m-d H:i:s'),
-                'user_id'=> $userId,
-                'type'=> 'withdraw',
-                'remark'=> '提现消息',
-            ]
-        ];
-
-        // 操作日志
-        ActionLogModel::setRecord($userId,['type'=>2,'title'=>'收入提现','content'=>"姓名:{$realname},账号:{$account},提现{$money}元,单号:{$orderNo}",'module'=>'balanceLog']);
-        ActionLogModel::record();
-
-        $this->error = 2308;
-        return ['id'=>$orderId,'message'=>$message,'money'=>$money];
-    }
-}

+ 3 - 1
app/Services/Api/CourseService.php

@@ -14,6 +14,7 @@ namespace App\Services\Api;
 use App\Models\ExamAccessLogModel;
 use App\Models\VideoCategoryModel;
 use App\Models\VideoCoursesModel;
+use App\Models\VideoLearnLogModel;
 use App\Models\VideoModel;
 use App\Services\BaseService;
 use App\Services\ConfigService;
@@ -217,7 +218,6 @@ class CourseService extends BaseService
                     ->where(['c.user_id'=>$userId,'c.status'=>1,'c.mark'=>1]);
             })*/
             ->with(['vip'])
-            ->withCount(['courses','learns'])
             ->where(['videos_courses.id'=>$id,'videos_courses.status'=>1,'videos_courses.mark'=>1])
             ->select(['videos_courses.id','videos_courses.video_id','videos_courses.course_name','videos_courses.course_url','videos_courses.fee','videos_courses.poster','videos_courses.description','videos_courses.sort','b.type'])
             ->first();
@@ -229,6 +229,8 @@ class CourseService extends BaseService
             $data['buy_vip'] = $buyVipData? 1 : 0;
             $data['can_play'] = $buyVipData || $fee<=0? 1 : 0;
             $data['preview_time'] = ConfigService::make()->getConfigByCode('course_play_preview_time', 3);
+            $data['courses_count'] = $this->model->where(['video_id'=> $data['video_id'],'status'=>1,'mark'=>1])->count('id');
+            $data['learns_count'] = VideoLearnLogModel::where(['video_id'=> $data['video_id'],'status'=>1,'mark'=>1])->count('id');
 
             // 播放
             RedisService::set($cacheKey, $data, rand(5, 10));

+ 0 - 464
app/Services/Api/DepositService.php

@@ -1,464 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
-// +----------------------------------------------------------------------
-// | 版权所有 2017~2021 LARAVEL研发中心
-// +----------------------------------------------------------------------
-// | 官方网站: http://www.laravel.cn
-// +----------------------------------------------------------------------
-// | Author: laravel开发员 <laravel.qq.com>
-// +----------------------------------------------------------------------
-
-namespace App\Services\Api;
-
-use App\Models\AccountLogModel;
-use App\Models\ActionLogModel;
-use App\Models\DepositModel;
-use App\Models\MemberModel;
-use App\Models\OrderModel;
-use App\Services\BaseService;
-use App\Services\ConfigService;
-use App\Services\PaymentService;
-use App\Services\RedisService;
-use App\Services\SmsService;
-use Illuminate\Support\Facades\DB;
-
-/**
- * 保证金订单管理-服务类
- * @author laravel开发员
- * @since 2020/11/11
- * @package App\Services\Api
- */
-class DepositService extends BaseService
-{
-    // 静态对象
-    protected static $instance = null;
-
-    /**
-     * 构造函数
-     * @author laravel开发员
-     * @since 2020/11/11
-     */
-    public function __construct()
-    {
-        $this->model = new DepositModel();
-    }
-
-    /**
-     * 静态入口
-     */
-    public static function make()
-    {
-        if (!self::$instance) {
-            self::$instance = new static();
-        }
-        return self::$instance;
-    }
-
-    /**
-     * 列表数据
-     * @param $params
-     * @param int $pageSize
-     * @return array
-     */
-    public function getDataList($params, $pageSize = 15)
-    {
-        $cacheKey = "caches:deposit:{$pageSize}_" . ($params ? md5(json_encode($params)) : 0);
-        $datas = RedisService::get($cacheKey);
-        if (empty($datas)) {
-            $query = $this->getQuery($params)
-                ->orderBy('a.refund_status', 'asc')
-                ->orderBy('a.id', 'desc');
-
-            $field = ["a.*"];
-            $list = $query->select($field)
-                ->paginate($pageSize > 0 ? $pageSize : 9999999);
-            $list = $list ? $list->toArray() : [];
-            if ($list) {
-                foreach ($list['data'] as &$item){
-                    $item['create_time'] = $item['create_time']? datetime($item['create_time'],'Y-m-d H:i:s') : '';
-                    $item['time_text'] = $item['create_time']? datetime($item['create_time'],'Y年m月d日') : '';
-                }
-                $datas = [
-                    'pageSize' => $pageSize,
-                    'total' => isset($list['total']) ? $list['total'] : 0,
-                    'list' => isset($list['data']) ? $list['data'] : []
-                ];
-
-                RedisService::set($cacheKey, $datas, rand(3, 5));
-            }
-        }
-
-        return $datas;
-    }
-
-
-    /**
-     * 查询条件
-     * @param $params
-     * @return mixed
-     */
-    public function getQuery($params)
-    {
-        $where = ['a.status' => 0, 'a.mark' => 1];
-        $status = isset($params['status']) ? $params['status'] : 0;
-        if ($status > 0) {
-            $where['a.status'] = $status;
-        } else {
-            unset($where['a.status']);
-        }
-
-        $model = $this->model->with(['user'])->from('deposit_orders as a')
-            ->leftJoin('member as b','b.id','=','a.user_id')
-            ->where($where)
-            ->where(function ($query) use ($params) {
-                $keyword = isset($params['keyword']) ? trim($params['keyword']) : '';
-                $refund = isset($params['refund']) ? intval($params['refund']) : 0;
-                if($refund == 1){
-                    if ($keyword) {
-                        $query->where('a.refund_no', 'like', "%{$keyword}%");
-                    }
-
-                    $query->where(['a.status'=>3])->where('a.refund_status','>',0);
-                }else{
-                    if ($keyword) {
-                        $query->where('a.order_no', 'like', "%{$keyword}%");
-                    }
-                }
-
-                // 用户
-                $account = isset($params['account']) ? trim($params['account']) : '';
-                if ($account) {
-                    $query->where(function ($query) use ($account) {
-                        $query->where('b.mobile', 'like', "%{$account}%")
-                            ->orWhere('b.nickname', 'like', "%{$account}%")
-                            ->orWhere('b.id', intval($account));
-                    });
-
-                }
-
-                $userId = isset($params['user_id']) ? intval($params['user_id']) : 0;
-                if ($userId>0) {
-                    $query->where('a.user_id', $userId);
-                }
-            });
-
-        return $model;
-    }
-
-    /**
-     * 详情信息
-     * @param $id
-     * @return mixed
-     */
-    public function getInfo($id)
-    {
-        $cacheKey = "caches:deposit:info_{$id}";
-        $info = RedisService::get($cacheKey);
-        if($info){
-            return $info;
-        }
-
-        $info = $this->model->with(['user'])->where(['id' => $id])->first();
-        $info = $info? $info->toArray() :[];
-        if($info){
-            RedisService::set($cacheKey, $info, rand(5,10));
-        }
-        return $info;
-    }
-
-    /**
-     * 充值保证金
-     * @param $userId
-     * @param $params
-     * @return array|false
-     */
-    public function pay($userId, $params)
-    {
-        // 参数验证
-        $deposit = isset($params['money'])? floatval($params['money']) : 0;
-        $payType = isset($params['pay_type'])? intval($params['pay_type']) : 0;
-        $depositMoney = ConfigService::make()->getConfigByCode('deposit_money',0);
-        if($deposit<=0 || $deposit != $depositMoney){
-            RedisService::clear("caches:config:app_ios");
-            RedisService::clear("caches:config:app_android");
-            $this->error = 2054;
-            return false;
-        }
-
-        if(!in_array($payType,[10,20])){
-            $this->error = 2055;
-            return false;
-        }
-
-        $cacheLockKey = "caches:members:deposit_pay:{$userId}";
-        if(RedisService::get($cacheLockKey)){
-            $this->error = 1034;
-            return false;
-        }
-
-        // 判断用户账号状态
-        RedisService::set($cacheLockKey, ['user_id'=>$userId,'params'=>$params], rand(10,20));
-        $userInfo = MemberService::make()->getInfo($userId,[], true);
-        $confirmStatus = isset($userInfo['confirm_status'])? $userInfo['confirm_status'] : 0;
-        $status = isset($userInfo['status'])? $userInfo['status'] : 0;
-        if(empty($userInfo) || $status != 1){
-            $this->error = 2016;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 账号审核情况
-        if($confirmStatus != 1){
-            $this->error = 2042;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 判断用户保证金缴纳情况
-        $userDeposit = isset($userInfo['deposit'])? floatval($userInfo['deposit']) : 0;
-        $depositTotal = $this->getPayDeposit($userId);
-        if($depositTotal>0 && $userDeposit && ($userDeposit >= $depositMoney && $depositTotal >= $depositMoney)){
-            $this->error = 2053;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 是否有退保申请
-        if($this->model->where(['user_id'=>$userId,'refund_status'=>1,'pay_status'=>2,'status'=>3,'mark'=>1])->value('id')){
-            $this->error = 2644;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-
-        // 创建订单
-        $order = [
-            'order_no'=> get_order_num('DE'),
-            'user_id'=> $userId,
-            'money'=> $deposit,
-            'type'=> 1,
-            'pay_type'=> $payType,
-            'pay_status'=> 1,
-            'create_time'=> time(),
-            'status'=> 1,
-            'mark'=>1
-        ];
-
-        DB::beginTransaction();
-        if(!$orderId = $this->model->insertGetId($order)){
-            $this->error = 2056;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        /* TODO 支付处理 */
-        $payOrder = [
-            'type'=> 1,
-            'order_no'=> $order['order_no'],
-            'pay_money'=> $deposit,
-            'body'=> '充值保证金',
-        ];
-
-        // 调起支付
-        switch($payType){
-            case 20: // 支付宝
-                $payment = PaymentService::make()->aliPay($userInfo, $payOrder,'deposit');
-                if(empty($payment)){
-                    DB::rollBack();
-                    RedisService::clear($cacheLockKey);
-                    $this->error = PaymentService::make()->getError();
-                    return false;
-                }
-                break;
-            case 10: // 微信支付
-                $payment = PaymentService::make()->wechatPay($userInfo, $payOrder,'deposit');
-                if(empty($payment)){
-                    DB::rollBack();
-                    RedisService::clear($cacheLockKey);
-                    $this->error = PaymentService::make()->getError();
-                    return false;
-                }
-                break;
-            default:
-                RedisService::clear($cacheLockKey);
-                $this->error = 2035;
-                return false;
-        }
-
-        // 用户操作记录
-        DB::commit();
-        $this->error = 2122;
-        RedisService::clear($cacheLockKey);
-        return [
-            'order_id'=> $orderId,
-            'payment'=> $payment,
-            'total'=> $payOrder['pay_money'],
-            'pay_type'=> $payType,
-        ];
-    }
-
-    /**
-     * 实际有效保证金金额
-     * @param $userId 用户ID
-     * @return array|mixed
-     */
-    public function getPayDeposit($userId)
-    {
-        $cacheKey = "caches:members:deposit_check:{$userId}";
-        $data = RedisService::get($cacheKey);
-        if($data){
-            return $data;
-        }
-
-        $depositTotal = $this->model->where(['type'=>1,'user_id'=> $userId, 'pay_status'=>2,'status'=>3,'mark'=>1])
-            ->whereIn('refund_status',[0,3])
-            ->sum('money');
-        RedisService::set($cacheKey, $depositTotal, rand(5,10));
-        return $depositTotal;
-    }
-
-
-    /**
-     * 退保申请
-     * @param $userId
-     * @param $params
-     * @return false|int[]
-     */
-    public function refund($userId, $params)
-    {
-        // 参数验证
-        $depositId = isset($params['id'])? intval($params['id']) : 0;
-        $deposit = isset($params['money'])? floatval($params['money']) : 0;
-        $remark = isset($params['remark'])? trim($params['remark']) : '';
-        $cacheLockKey = "caches:members:deposit_refund:{$userId}";
-        if(RedisService::get($cacheLockKey)){
-            $this->error = 1034;
-            return false;
-        }
-
-        // 判断用户账号状态
-        RedisService::set($cacheLockKey, ['user_id'=>$userId,'params'=>$params], rand(10,20));
-        $userInfo = MemberService::make()->getInfo($userId,[], true);
-        $confirmStatus = isset($userInfo['confirm_status'])? $userInfo['confirm_status'] : 0;
-        $status = isset($userInfo['status'])? $userInfo['status'] : 0;
-        if(empty($userInfo) || $status != 1){
-            $this->error = 2016;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 账号审核情况
-        if($confirmStatus != 1){
-            $this->error = 2042;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 验证码验证(不传不验证)
-        $mobile = isset($params['mobile'])? trim($params['mobile']) : '';
-        $smsCode = isset($params['sms_code'])? trim($params['sms_code']) : '';
-        if (!$depositId && isset($params['sms_code']) && !SmsService::make()->check($mobile, $smsCode, 'refund')) {
-            $this->error = SmsService::make()->getError();
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 判断用户保证金缴纳情况
-        $userDeposit = isset($userInfo['deposit'])? floatval($userInfo['deposit']) : 0;
-        if($depositId){
-            $depositInfo = $this->model->where(['id'=> $depositId,'type'=>1,'user_id'=> $userId, 'pay_status'=>2,'status'=>3,'mark'=>1])
-                ->whereIn('refund_status',[0,3])->first();
-        }else{
-            $depositInfo = $this->model->where(['type'=>1,'user_id'=> $userId, 'pay_status'=>2,'status'=>3,'mark'=>1])
-                ->whereIn('refund_status',[0,3])->first();
-            $depositId = isset($depositInfo['id'])? $depositInfo['id'] : 0;
-        }
-
-        $depositInfo = $depositInfo? $depositInfo->toArray() : [];
-        $depositTotal = isset($depositInfo['money'])? floatval($depositInfo['money']) : 0;
-        if(empty($depositInfo) || $depositId<=0 || $depositTotal<=0 || $userDeposit<=0){
-            $this->error = 2057;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        if($userDeposit > $depositTotal || $deposit != $userDeposit){
-            $this->error = 2058;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 是否有进行中订单
-        if(OrderModel::whereIn('status',[1,2])->where(['user_id'=>$userId,'mark'=>1])->value('id')){
-            $this->error = 2062;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // TODO 退保处理
-        DB::beginTransaction();
-
-        // 扣除
-        $updateData = [
-            'deposit'=> 0,
-            'update_time'=>time()
-        ];
-        if(!MemberModel::where(['id'=> $userId])->update($updateData)){
-            $this->error = 2059;
-            RedisService::clear($cacheLockKey);
-            DB::rollBack();
-            return false;
-        }
-
-        // 退款单数据更新
-        $depositOrderNo = get_order_num('DR');
-        $order = [
-            'refund_at'=> date('Y-m-d H:i:s'),
-            'remark'=> $remark,
-            'refund_confirm_remark'=>'',
-            'refund_no'=> $depositOrderNo,
-            'refund_money'=> $deposit,
-            'refund_mobile'=> $mobile,
-            'refund_status'=> 1,
-            'update_time'=>time(),
-        ];
-
-        if(!$this->model->where(['id'=>$depositId])->update($order)){
-            $this->error = 2061;
-            RedisService::clear($cacheLockKey);
-            DB::rollBack();
-            return false;
-        }
-
-        $log = [
-            'user_id' => $userId,
-            'source_order_no' => $depositOrderNo,
-            'type' => 3,
-            'money' => $deposit,
-            'before_money' => $userDeposit,
-            'date'=> date('Y-m-d'),
-            'create_time' => time(),
-            'remark' => '退保申请',
-            'status' => 1,
-            'mark' => 1,
-        ];
-        if(!AccountLogModel::insertGetId($log)){
-            $this->error = 2061;
-            RedisService::clear($cacheLockKey);
-            DB::rollBack();
-            return false;
-        }
-
-        $this->error = 2060;
-        DB::commit();
-
-        // 操作日志
-        ActionLogModel::setRecord($userId,['type'=>2,'title'=>'申请退保','content'=>"手机号:{$mobile},退保金额:{$deposit}元,单号:{$depositOrderNo}",'module'=>'deposit']);
-        ActionLogModel::record();
-
-        RedisService::clear($cacheLockKey);
-        RedisService::clear("caches:deposit:info_{$depositId}");
-        return ['id'=> $depositId,'order_no'=>$depositOrderNo,'money'=>$userDeposit];
-    }
-}

+ 248 - 19
app/Services/Api/ExamService.php

@@ -13,11 +13,13 @@ namespace App\Services\Api;
 
 use App\Models\ExamAccessLogModel;
 use App\Models\ExamAnswerModel;
+use App\Models\ExamAnswerTopicModel;
 use App\Models\ExamPaperModel;
 use App\Models\ExamTopicModel;
 use App\Models\MemberAnswerRankModel;
 use App\Services\BaseService;
 use App\Services\ConfigService;
+use App\Services\DeepSeekService;
 use App\Services\RedisService;
 use Illuminate\Support\Facades\DB;
 
@@ -68,7 +70,7 @@ class ExamService extends BaseService
         }
 
         $query = $this->getQuery($params);
-        $list = $query->select(['a.id', 'a.user_id', 'a.paper_id', 'a.score', 'a.accurate_count', 'b.name', 'b.type', 'b.topic_count', 'b.score_total', 'b.is_charge', 'a.create_time', 'a.answer_times', 'a.status'])
+        $list = $query->select(['a.id', 'a.user_ids', 'a.paper_id', 'a.score', 'a.accurate_count', 'b.name', 'b.type', 'b.topic_count', 'b.score_total', 'b.is_charge', 'a.create_time', 'a.answer_times', 'a.status'])
             ->orderBy('a.create_time', 'desc')
             ->paginate($pageSize > 0 ? $pageSize : 9999999);
         $list = $list ? $list->toArray() : [];
@@ -85,7 +87,7 @@ class ExamService extends BaseService
             'list' => $rows
         ];
         if ($rows) {
-            RedisService::set($cacheKey, $datas, rand(300, 600));
+            RedisService::set($cacheKey, $datas, rand(30, 60));
         }
 
         return $datas;
@@ -142,14 +144,15 @@ class ExamService extends BaseService
     public function getHistoryList($params, $pageSize = 10)
     {
         $page = isset($params['page']) ? $params['page'] : 1;
-        $cacheKey = "caches:exams:history_{$page}_{$pageSize}:" . md5(json_encode($params));
+        $userId = isset($params['user_id']) ? $params['user_id'] : 0;
+        $cacheKey = "caches:exams:{$userId}_history_{$page}:" . md5(json_encode($params));
         $datas = RedisService::get($cacheKey);
         if ($datas) {
             return $datas;
         }
 
         $query = $this->getQuery($params);
-        $list = $query->select(['a.id', 'a.user_id', 'a.paper_id', 'a.score', 'a.accurate_count', 'b.name', 'b.type', 'b.topic_count', 'b.score_total', 'b.is_charge', 'a.create_time', 'a.answer_times', 'a.status'])
+        $list = $query->select(['a.id', 'a.user_id', 'a.paper_id', 'a.score', 'a.accurate_count', 'b.name', 'b.type','b.scene_type', 'b.topic_count', 'b.score_total', 'b.is_charge', 'a.create_time', 'a.answer_times', 'a.status'])
             ->orderBy('a.create_time', 'desc')
             ->paginate($pageSize > 0 ? $pageSize : 9999999);
         $list = $list ? $list->toArray() : [];
@@ -183,7 +186,7 @@ class ExamService extends BaseService
     {
         $page = isset($params['page']) ? $params['page'] : 1;
         $type = isset($params['type']) ? $params['type'] : 1;
-        $cacheKey = "caches:exams:practice_{$userId}:{$page}_" . md5(json_encode($params));
+        $cacheKey = "caches:exams:{$userId}_practice:{$page}_" . md5(json_encode($params));
         $datas = RedisService::get($cacheKey);
         // 每日一练访问次数统计
         if(empty($sc)){
@@ -196,7 +199,7 @@ class ExamService extends BaseService
 
         $list = $this->model->from('exam_answers as a')
             ->leftJoin('exam_papers as b', 'b.id', '=', 'a.paper_id')
-            ->where(['b.scene_type' => 1, 'b.status' => 1, 'b.mark' => 1, 'a.mark' => 1])
+            ->where(['b.scene_type' => 1, 'b.status' => 1,'a.status'=>1, 'b.mark' => 1, 'a.mark' => 1])
             ->where(function ($query) use ($params) {
                 $type = isset($params['type']) && $params['type'] ? intval($params['type']) : 1;
                 if ($type > 0) {
@@ -284,12 +287,30 @@ class ExamService extends BaseService
         return $datas;
     }
 
+    public function getCardList($userId, $paperId, $rid=0)
+    {
+        $cacheKey = "caches:exams:{$userId}_cardList:{$paperId}_{$rid}";
+        $datas = RedisService::get($cacheKey);
+        if($datas){
+            return $datas;
+        }
+
+        $datas = ExamTopicModel::from('exam_topics as a')
+            ->leftJoin('exam_answers_topics as b',function($join) use($rid){
+                if($rid){
+                    $join->
+                }
+            })
+            ->where(['a.paper_id'=> $paperId, 'a.status'=>1,'a.mark'=>1])
+            ->select(['a.*','b.id'])
+    }
+
     /**
      * 重新答题,清除答题记录数据
      * @param $id
      * @return bool
      */
-    public function reset($id)
+    public function reset($id, $userId=0)
     {
         $log = $this->model->where(['id'=> $id,'mark'=>1])->first();
         if(empty($log)){
@@ -298,19 +319,27 @@ class ExamService extends BaseService
 
         $updateData = ['score'=>0,'accurate_count'=>0,'answer_count'=>0,'answer_times'=>0,'answer_last_id'=>0,'is_submit'=>0,'status'=>1];
         $this->model->where(['id'=> $id,'mark'=>1])->update($updateData);
+        ExamAnswerTopicModel::where(['answer_log_id'=> $id,'mark'=>1])->update(['status'=>2,'update_time'=>time()]);
+        RedisService::keyDel("caches:exams:{$userId}*");
         return true;
     }
 
+    /**
+     * 答题
+     * @param $userId
+     * @param $params
+     * @return array|false
+     */
     public function answer($userId, $params)
     {
         $paperId = isset($params['id'])? $params['id'] : 0;
         $rid = isset($params['rid'])? $params['rid'] : 0;
         $tid = isset($params['tid'])? $params['tid'] : 0;
-        $type = isset($params['type'])? $params['type'] : 1;
         $isSubmit = isset($params['is_submit'])? $params['is_submit'] : 1;
         $answer = isset($params['answer'])? $params['answer'] : '';
         $answerImage = isset($params['answer_image'])? $params['answer_image'] : '';
         $answerType = isset($params['answer_type']) && $params['answer_type']? $params['answer_type'] : 2;
+        $remainTime = isset($params['remain_time']) && $params['remain_time']? $params['remain_time'] : 0;
         if($isSubmit<=0 && empty($answer)){
             $this->error = '请先提交答案';
             return false;
@@ -321,12 +350,22 @@ class ExamService extends BaseService
             return false;
         }
 
+        $cacheKey = "caches:answers:{$userId}_{$paperId}:{$tid}_{$rid}";
+        if(RedisService::get($cacheKey.'_lock')){
+            $this->error = '请不要频繁提交';
+            return false;
+        }
+
+        RedisService::set($cacheKey.'_lock', $params, rand(2,3));
+
         // 试卷数据
-        $paperInfo = ExamPaperModel::where(['id'=> $paperId,'type'=>$type,'status'=>1,'mark'=>1])
+        $paperInfo = ExamPaperModel::where(['id'=> $paperId,'status'=>1,'mark'=>1])
             ->first();
-        $correctAnswer = isset($paperInfo['correct_answer'])? $paperInfo['correct_answer'] : '';
+        $type = isset($paperInfo['type']) && $paperInfo['type']? $paperInfo['type'] : 1;
         $sceneType = isset($paperInfo['scene_type']) && $paperInfo['scene_type']? $paperInfo['scene_type'] : 1;
+        $topicCount = isset($paperInfo['topic_count'])? $paperInfo['topic_count'] : 0;
         if(empty($paperInfo)){
+            RedisService::clear($cacheKey.'_lock');
             $this->error = '试题数据错误,请返回刷新重试';
             return false;
         }
@@ -334,19 +373,31 @@ class ExamService extends BaseService
         // 题目数据
         $topicInfo = ExamTopicModel::where(['id'=> $tid,'paper_id'=>$paperId,'status'=>1,'mark'=>1])->first();
         $topicType = isset($topicInfo['topic_type'])? trim($topicInfo['topic_type']) : '';
-        if(empty($topicInfo) || empty($topicType)){
+        $topicScore = isset($topicInfo['score'])? intval($topicInfo['score']) : 0;
+        $topicName = isset($topicInfo['topic_name'])? $topicInfo['topic_name'] : '';
+        $topicShowType = isset($topicInfo['show_type'])? $topicInfo['show_type'] : 1;
+        $correctAnswer = isset($topicInfo['correct_answer'])? $topicInfo['correct_answer'] : '';
+        if(empty($topicInfo) || empty($topicType) || empty($topicName)){
+            RedisService::clear($cacheKey.'_lock');
             $this->error = '题库已更新,请返回刷新重试';
             return false;
         }
 
         // 答题记录
         $submit = 0;
+        $answerCount = 0;
         if($rid){
             $answerInfo = ExamAnswerModel::where(['id'=>$rid,'status'=>1,'mark'=>1])->first();
             $submit = isset($answerInfo['is_submit'])? $answerInfo['is_submit'] : 0;
+            $answerCount = isset($answerInfo['answer_count'])? $answerInfo['answer_count'] : 0;
             if(empty($answerInfo)){
                 $rid = 0;
             }
+
+            if($submit){
+                $this->error = '您已交卷';
+                return false;
+            }
         }
 
         // 验证答案内容类型和数据
@@ -356,38 +407,216 @@ class ExamService extends BaseService
             $answerInfo = ExamAnswerModel::where(['paper_id'=>$paperId,'status'=>1,'mark'=>1])->where('create_time','>=', strtotime(date('Y-m-d')))->first();
             $rid = isset($answerInfo['id'])? $answerInfo['id'] : 0;
             $submit = isset($answerInfo['is_submit'])? $answerInfo['is_submit'] : 0;
+            $answerCount = isset($answerInfo['answer_count'])? $answerInfo['answer_count'] : 0;
         }
 
         // 是否已交卷
         if($submit == 1){
+            RedisService::clear($cacheKey.'_lock');
             $this->error = '您已交卷';
             return false;
         }
 
-        /* TODO 验证答案 */
-        if(in_array($topicType,['选择题','单选题'])){
+        // 直接交卷
+        if($isSubmit==1 && empty($answer)){
+            // 是否提交过
+            if($answerCount<=0){
+                $this->error = '您未提交过答案,请先答题再交卷';
+                return false;
+            }
+
+            $this->model->where(['id'=> $rid])->update(['is_submit'=>1,'update_time'=>time()]);
+            $this->error = '交卷成功';
+            RedisService::keyDel("caches:exams:{$userId}*");
+            return ['rid'=> $rid,'paper_id'=>$paperId];
+        }
+
+        // 该题是否已提交答案
+        $logId = 0;
+        if($rid>0){
+            $answerTopic = ExamAnswerTopicModel::where(['answer_log_id'=>$rid,'topic_id'=> $tid,'mark'=>1])->first();
+            $accurate = isset($answerTopic['accurate'])? $answerTopic['accurate'] : -1;
+            $logId = isset($answerTopic['id'])? $answerTopic['id'] : 0;
+            $status = isset($answerTopic['status'])? $answerTopic['status'] : 0;
+            if($answerTopic && $accurate>=0 && $status == 1){
+                RedisService::clear($cacheKey.'_lock');
+                $this->error = '该题答案已提交';
+                return false;
+            }
+        }
 
-        } else if (in_array($topicType, ['简答题','计算题','阅读理解'])){
+        /* TODO 验证答案 */
+        $submitType = 1;
+        $topicData = [
+            'user_id'=> $userId,
+            'topic_id'=> $tid,
+            'answer'=> $answerType==1? get_image_path($answer) : $answer,
+            'score'=>0,
+            'accurate'=>0,
+            'create_time'=> time(),
+            'status'=> 1,
+            'mark'=> 1,
+        ];
+        if(in_array($topicType,['选择题','单选题','多选题','填空题'])){
+            $topicData['answer_analysis'] = isset($topicInfo['answer_analysis'])? $topicInfo['answer_analysis'] : '';
+            if($answer == $correctAnswer){
+                $topicData['accurate'] = 1;
+                $topicData['score'] = $topicScore;
+            }else{
+                $topicData['accurate'] = 0;
+            }
+//      }else if (in_array($topicType, ['简答题','计算题','阅读理解'])){
+        }else {
             // 图片答案AI验证
             if($answerType == 1){
+                $submitType = 3;
+                $apiData = [
+                    'answer'=> $answer,
+                    'score'=> $topicScore,
+                    'topic'=> $topicShowType == 2 && $topicName? DeepSeekService::make()->getImageTopicData($topicName) : $topicName,
+                ];
+
+                $result = DeepSeekService::make()->apiRequest($apiData);
+                RedisService::clear($cacheKey.'_lock');
+                $this->error = '功能开放中~';
+                return false;
+            }else {
+                $submitType = 2;
+                $apiData = [
+                    'answer'=> $answer,
+                    'score'=> $topicScore,
+                    'topic'=> $topicShowType == 2 && $topicName? DeepSeekService::make()->getImageTopicData($topicName) : $topicName,
+                ];
+
+                $result = DeepSeekService::make()->apiRequest($apiData);
+                $score = isset($result['score'])?$result['score'] : 0;
+                $analysis = isset($result['analysis'])?$result['analysis'] :  '';
+                if($score>0){
+                    $topicData['accurate'] = 1;
+                    $topicData['score'] = $score;
+                    $topicData['answer_analysis'] = $analysis;
+                }else{
+                    $topicData['accurate'] = 0;
+                }
+            }
+        }
 
+        $totalTime = ConfigService::make()->getConfigByCode('answer_total_time', 1800);
+        $answerTime = $totalTime >$remainTime? $totalTime-$remainTime : $totalTime;
+        DB::beginTransaction();
+        if($rid){
+            $log = [
+                'answer_times'=> $answerTime,
+                'answer_last_at'=> date('Y-m-d H:i:s'),
+                'answer_count'=> DB::raw("answer_count + 1"),
+                'answer_last_id'=> $tid,
+                'is_submit'=> $isSubmit==1?1:0,
+                'update_time'=> time()
+            ];
 
-            }else {
+            // 对题数
+            if($topicData['accurate']==1){
+                $log['accurate_count'] = DB::raw("accurate_count + 1");
+                $log['score'] = DB::raw("score + {$topicData['score']}");
+            }
 
+            if(!$this->model->where(['id'=> $rid])->update($log)){
+                DB::rollBack();
+                RedisService::clear($cacheKey.'_lock');
+                $this->error = '答题失败,请刷新后重新提交';
+                return false;
+            }
+        }else{
+            $log = [
+                'user_id'=> $userId,
+                'paper_id'=> $paperId,
+                'score'=> $topicData['score'],
+                'answer_count'=> 1,
+                'answer_times'=> $answerTime,
+                'answer_last_at'=> date('Y-m-d H:i:s'),
+                'answer_last_id'=> $tid,
+                'is_submit'=> $isSubmit,
+                'create_time'=> time()
+            ];
+
+            if(!$rid = $this->model->insertGetId($log)){
+                DB::rollBack();
+                RedisService::clear($cacheKey.'_lock');
+                $this->error = '答题失败,请刷新后重新提交';
+                return false;
 
             }
         }
+        // 答题题目数据
+        $topicData['answer_type'] = $submitType;
+        $topicData['answer_log_id'] = $rid;
+
+        if($logId){
+            $topicData['update_time'] = $submitType;
+            ExamAnswerTopicModel::where(['id'=> $logId])->update([$topicData]);
+        }else if (!ExamAnswerTopicModel::insert($topicData)){
+            DB::rollBack();
+            RedisService::clear($cacheKey.'_lock');
+            $this->error = '答题失败,请刷新后重新提交';
+            return false;
+        }
 
+        DB::commit();
+        $this->error = '答题成功';
+        RedisService::clear($cacheKey.'_lock');
+        RedisService::keyDel("caches:exams:{$userId}*");
+        RedisService::clear("caches:exams:info_{$rid}");
+        RedisService::keyDel("caches:paper:info_{$userId}:p{$paperId}*");
+        return ['paper_id'=> $paperId,'rid'=>$rid,'tid'=>$tid, 'accurate'=> $topicData['accurate'],'answer'=>$topicData['answer']];
+    }
 
+    /**
+     * 是否有答题记录数据
+     * @param $rid
+     * @param $tid
+     * @return array|mixed
+     */
+    public function getAnswerCacheTopic($rid, $tid)
+    {
+        $cacheKey = "caches:answers:topic_{$rid}_{$tid}";
+        $data = RedisService::get($cacheKey);
+        if($data){
+            return $data;
+        }
+        $data = ExamAnswerTopicModel::where(['rid'=> $rid,'topic_id'=>$tid,'mark'=>1])->value('id');
+        if($data){
+            RedisService::set($cacheKey, $data, rand(5, 10));
+        }
 
+        return $data;
+    }
 
-        if($rid){
-            $data = [
-                ''
-            ];
+    /**
+     * 答题分数结果详情
+     * @param $rid
+     * @return array|mixed
+     */
+    public function getInfo($rid)
+    {
+        $cacheKey = "caches:exams:info_{$rid}";
+        $data = RedisService::get($cacheKey);
+        if($data){
+            return $data;
         }
 
+        $data = $this->model->from('exam_answers as a')
+            ->leftJoin('exam_papers as b','b.id','=','a.paper_id')
+            ->where(['a.id'=> $rid,'a.status'=>1,'a.mark'=>1])
+            ->select(['a.*','b.topic_count'])
+            ->first();
+        $data = $data? $data->toArray() : [];
+        if($data){
+            $data['accurate_rate'] = round($data['accurate_count']/$data['topic_count'] * 100,2);
+            $data['answer_times_text'] = $data['answer_times']? format_times($data['answer_times']) : '00:00';
+            RedisService::set($cacheKey, $data, rand(5, 10));
+        }
 
+        return $data;
     }
 
 }

+ 0 - 198
app/Services/Api/GoodsService.php

@@ -1,198 +0,0 @@
-<?php
-// +----------------------------------------------------------------------
-// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
-// +----------------------------------------------------------------------
-// | 版权所有 2017~2021 LARAVEL研发中心
-// +----------------------------------------------------------------------
-// | 官方网站: http://www.laravel.cn
-// +----------------------------------------------------------------------
-// | Author: laravel开发员 <laravel.qq.com>
-// +----------------------------------------------------------------------
-
-namespace App\Services\Api;
-
-use App\Models\GoodsModel;
-use App\Models\OrderModel;
-use App\Services\BaseService;
-use App\Services\RedisService;
-use wxkxklmyt\Scws;
-
-/**
- * 货物商品管理-服务类
- * @author laravel开发员
- * @since 2020/11/11
- * @package App\Services\Api
- */
-class GoodsService extends BaseService
-{
-// 静态对象
-    protected static $instance = null;
-
-    /**
-     * 构造函数
-     * @author laravel开发员
-     * @since 2020/11/11
-     */
-    public function __construct()
-    {
-        $this->model = new GoodsModel();
-    }
-
-    /**
-     * 静态入口
-     */
-    public static function make()
-    {
-        if (!self::$instance) {
-            self::$instance = new static();
-        }
-        return self::$instance;
-    }
-
-    /**
-     * 列表数据
-     * @param $params
-     * @param int $pageSize
-     * @return array
-     */
-    public function getDataList($params, $pageSize = 15)
-    {
-        $cacheKey = "caches:goods:picker:{$pageSize}_" . ($params ? md5(json_encode($params)) : 0);
-        $datas = RedisService::get($cacheKey);
-        if (empty($datas)) {
-            $query = $this->getQuery($params)
-                ->orderBy('a.create_time', 'desc')
-                ->orderBy('a.id', 'desc');
-
-            $field = ["a.*"];
-            $list = $query->select($field)
-                ->paginate($pageSize > 0 ? $pageSize : 9999999);
-            $list = $list ? $list->toArray() : [];
-            if ($list) {
-                foreach ($list['data'] as &$item) {
-                    $item['shipper_phone_text'] = $item['shipper_phone'] ? format_mobile($item['shipper_phone']) : '';
-                    $item['receiver_phone_text'] = $item['receiver_phone'] ? format_mobile($item['receiver_phone']) : '';
-                }
-                $datas = [
-                    'pageSize' => $pageSize,
-                    'total' => isset($list['total']) ? $list['total'] : 0,
-                    'list' => isset($list['data']) ? $list['data'] : []
-                ];
-
-                RedisService::set($cacheKey, $datas, rand(3, 5));
-            }
-        }
-
-        return $datas;
-    }
-
-
-    /**
-     * 查询条件
-     * @param $params
-     * @return mixed
-     */
-    public function getQuery($params)
-    {
-        $where = ['a.status' => 1, 'a.mark' => 1];
-        $status = isset($params['status']) ? $params['status'] : 1;
-        if ($status > 0) {
-            $where['a.status'] = $status;
-        } else {
-            unset($where['a.status']);
-        }
-        $model = $this->model->from('goods as a')
-            ->where($where)
-            ->where(function ($query) use ($params) {
-                $pickerStatus = isset($params['picker_status']) ? $params['picker_status'] : 1;
-                $userId = isset($params['user_id']) ? $params['user_id'] : 0;
-                if ($pickerStatus) {
-                    $query->where(function ($query) use ($pickerStatus, $userId) {
-                        $goodsIds = OrderModel::where(function ($query) use ($userId) {
-                                $query->whereIn('status', [2, 3]);
-                                if($userId){
-                                    $query->orWhere(function($query) use($userId){
-                                        $query->where(['user_id' => $userId, 'status' => 1]);
-                                    });
-                                }
-                            })
-                            ->where('mark', 1)
-                            ->where('create_time', '>=', time() - 30 * 86400)
-                            ->pluck('goods_id');
-                        $goodsIds = $goodsIds ? array_unique($goodsIds->toArray()) : [];
-                        $query->where('a.picker_status', $pickerStatus);
-                        if ($goodsIds) {
-                            $query->whereNotIn('a.id', $goodsIds);
-                        }
-
-                    });
-                }
-
-                $keyword = isset($params['keyword']) ? trim($params['keyword']) : '';
-                if ($keyword) {
-                    $scws = new Scws();
-                    $kws = $scws->scws($keyword, 3, false);
-                    if (count($kws) > 1) {
-                        $query->where(function ($query) use ($kws) {
-                            foreach ($kws as $kw) {
-                                $kw = trim($kw);
-                                $query->where('a.goods_name', 'like', "%{$kw}%")
-                                    ->orWhere('a.car_type', 'like', "%{$kw}%");
-                            }
-                        });
-                    } else {
-                        $query->where(function ($query) use ($keyword) {
-                            $query->where('a.goods_name', 'like', "%{$keyword}%")
-                                ->orWhere('a.car_type', 'like', "%{$keyword}%");
-                        });
-                    }
-                }
-
-                // 取货人
-                $shipper = isset($params['shipper']) ? trim($params['shipper']) : '';
-                if ($shipper) {
-                    $query->where(function ($query) use ($shipper) {
-                        $query->where('a.shipper_name', 'like', "%{$shipper}%")
-                            ->orWhere('a.shipper_phone', 'like', "%{$shipper}%");
-                    });
-
-                }
-
-                // 收货人
-                $receiver = isset($params['receiver']) ? trim($params['receiver']) : '';
-                if ($receiver) {
-                    $query->where(function ($query) use ($receiver) {
-                        $query->where('a.receiver_name', 'like', "%{$receiver}%")
-                            ->orWhere('a.receiver_phone', 'like', "%{$receiver}%");
-                    });
-                }
-            });
-
-        return $model;
-    }
-
-    /**
-     * 详情信息
-     * @param $id
-     * @return mixed
-     */
-    public function getInfo($id)
-    {
-        $cacheKey = "caches:goods:info_{$id}";
-        $info = RedisService::get($cacheKey);
-        if ($info) {
-            return $info;
-        }
-
-        $info = $this->model->where(['id' => $id])->first();
-        $info = $info ? $info->toArray() : [];
-        if ($info) {
-            $info['bonus'] = isset($info['price']) ? $info['price'] : 0;
-            $info['shipper_phone_text'] = isset($info['shipper_phone']) ? format_mobile($info['shipper_phone']) : '';
-            $info['receiver_phone_text'] = isset($info['receiver_phone']) ? format_mobile($info['receiver_phone']) : '';
-            RedisService::set($cacheKey, $info, rand(10, 20));
-        }
-        return $info;
-    }
-
-}

+ 2 - 187
app/Services/Api/OrderService.php

@@ -11,12 +11,8 @@
 
 namespace App\Services\Api;
 
-use App\Models\MemberModel;
 use App\Models\OrderModel;
 use App\Services\BaseService;
-use App\Services\ConfigService;
-use App\Services\RedisService;
-use Illuminate\Support\Facades\DB;
 
 /**
  * 订单-服务类
@@ -84,10 +80,6 @@ class OrderService extends BaseService
                 if ($status) {
                     $item['status_text'] = isset($statusArr[$status]) ? $statusArr[$status] : '';
                 }
-
-                $item['goods'] = isset($item['goods']) && $item['goods'] ? $item['goods'] : [];
-                $item['goods']['shipper_phone_text'] = $item['goods']['shipper_phone']?format_mobile($item['goods']['shipper_phone']) : '';
-                $item['goods']['receiver_phone_text'] = $item['goods']['receiver_phone']?format_mobile($item['goods']['receiver_phone']) : '';
             }
             unset($item);
         }
@@ -107,7 +99,7 @@ class OrderService extends BaseService
     public function getQuery($params)
     {
         $where = ['a.mark' => 1];
-        return $this->model->from('orders as a')->with(['goods'])
+        return $this->model->from('orders as a')
             ->leftJoin('member as b', 'b.id', '=', 'a.user_id')
             ->where($where)
             ->where(function($query) use($params){
@@ -133,7 +125,7 @@ class OrderService extends BaseService
     public function getOrderInfo($id)
     {
         $statusArr = [1 => '待审核', 2 => '进行中', 3 => '已完成'];
-        $info = $this->model->from('orders as a')->with(['goods'])
+        $info = $this->model->from('orders as a')
             ->leftJoin('member as b', 'b.id', '=', 'a.user_id')
             ->where(['a.id' => $id, 'a.mark' => 1])
             ->select(['a.*'])
@@ -147,185 +139,8 @@ class OrderService extends BaseService
             if ($status) {
                 $info['status_text'] = isset($statusArr[$status]) ? $statusArr[$status] : '';
             }
-
-            $info['goods'] = isset($info['goods']) && $info['goods'] ? $info['goods'] : [];
-            $info['goods']['shipper_phone_text'] = $info['goods']['shipper_phone']?format_mobile($info['goods']['shipper_phone']) : '';
-            $info['goods']['receiver_phone_text'] = $info['goods']['receiver_phone']?format_mobile($info['goods']['receiver_phone']) : '';
         }
 
         return $info;
     }
-
-    /**
-     * 创建订单
-     * @param $userId 用户
-     * @param $params 参数
-     * @return array|false
-     */
-    public function createOrder($userId, $params)
-    {
-        $goodsId = isset($params['goods_id']) && $params['goods_id'] ? intval($params['goods_id']) : 0;
-        // 参数验证
-        if (empty($goodsId)) {
-            $this->error = 2103;
-            return false;
-        }
-
-        // 缓存锁
-        $cacheLockKey = "caches:orders:submit_lock:{$userId}_{$goodsId}";
-        if (RedisService::get($cacheLockKey)) {
-            $this->error = 2107;
-            return false;
-        }
-
-        // 货物信息
-        RedisService::set($cacheLockKey, ['params' => $params, 'user_id' => $userId], rand(2, 3));
-        $goodsInfo = GoodsModel::where(['id' => $goodsId,'status'=>1, 'mark' => 1])
-            ->select(['id','num', 'price','picker_status', 'status'])
-            ->first();
-        $pickerStatus = isset($goodsInfo['picker_status']) ? $goodsInfo['picker_status'] : 0;
-        $price = isset($goodsInfo['price']) ? floatval($goodsInfo['price']) : 0;
-        $num = isset($goodsInfo['num']) ? intval($goodsInfo['num']) : 0;
-        if(empty($goodsInfo)){
-            $this->error = 2201;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        if(in_array($pickerStatus,[2,3])){
-            $this->error = "220{$pickerStatus}";
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        if($price<=0){
-            $this->error = 2204;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 用户信息
-        $userInfo = MemberModel::where(['id' => $userId, 'mark' => 1])
-            ->select(['id', 'mobile', 'nickname','deposit','picker_status','confirm_status', 'status'])
-            ->first();
-        $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
-        $nickname = isset($userInfo['nickname']) ? $userInfo['nickname'] : '';
-        $confirmStatus = isset($userInfo['confirm_status']) ? $userInfo['confirm_status'] : 0;
-        $userPickerStatus = isset($userInfo['picker_status']) ? $userInfo['picker_status'] : 0;
-        $userDeposit = isset($userInfo['deposit']) ? floatval($userInfo['deposit']) : 0;
-        if(empty($userInfo) || $status != 1){
-            $this->error = 2016;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 账号审核情况
-        if($confirmStatus != 1){
-            $this->error = 2042;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        if($userPickerStatus != 1){
-            $this->error = 2205;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 缴纳保证金验证
-        $depositMoney = ConfigService::make()->getConfigByCode('deposit_money',0);
-        $depositTotal = DepositService::make()->getPayDeposit($userId);
-        if($depositMoney>0 && ($userDeposit < $depositMoney || $depositTotal < $depositMoney)){
-            $this->error = 2206;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        // 订单数据
-        $pickerCount = $this->model->where(['goods_id'=> $goodsId,'mark'=>1])->whereIn('status',[1,2])->count('id');
-        if($this->model->where(['user_id'=>$userId,'goods_id'=>$goodsId,'mark'=>1])->whereIn('status',[1,2,3])->value('id')){
-            $this->error = 2209;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-        if($this->model->where(['user_id'=>$userId,'mark'=>1])->whereIn('status',[1,2])->value('id')){
-            $this->error = 2209;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-        $bonusRate = ConfigService::make()->getConfigByCode('picker_bonus_rate',100);
-        $bonusRate = $bonusRate>0 && $bonusRate<=100? intval($bonusRate) : 100;
-        $bonus = moneyFormat($price * $bonusRate/100,2);
-        $orderNo = get_order_num('PD');
-        $order = [
-            'order_no' => $orderNo,
-            'user_id' => $userId,
-            'goods_id' => $goodsId,
-            'total' => $price,
-            'bonus' => $bonus,
-            'create_time' => time(),
-            'update_time' => time(),
-            'status' => 1,
-            'mark' => 1,
-        ];
-
-        // 订单处理
-        DB::beginTransaction();
-        if (!$orderId = $this->model->insertGetId($order)) {
-            DB::rollBack();
-            $this->error = 2207;
-            RedisService::clear($cacheLockKey);
-            return false;
-        }
-
-        $title = "用户[{$nickname}]有新的抢单";
-        $message = [
-            'from_uid'=> $userId,
-            'to_uid'=> 1,
-            'op'=> 'notice',
-            'scene'=> 'picker',
-            'message'=> '接单消息',
-            'type'=> 5,
-            'order'=>[
-                'title'=> $title.'<span class="ele-text-primary">查看订单</span>',
-                'order_no'=> $orderNo,
-                'money'=> $bonus,
-                'date'=> date('Y-m-d H:i:s'),
-                'user_id'=> $userId,
-                'type'=> 'deposit',
-                'remark'=> '接单消息',
-            ]
-        ];
-
-        DB::commit();
-        $pickerCount = $pickerCount+1;
-        $this->error = lang('2208',['num'=>$pickerCount]);
-        RedisService::clear($cacheLockKey);
-        RedisService::keyDel("caches:goods:picker*");
-        return ['order_id' => $orderId,'message'=>$message, 'total' => $price, 'num' => $pickerCount, 'goods' => $goodsId];
-    }
-
-    /**
-     * 今日数量统计数据
-     * @param $userId
-     * @param int $type
-     * @return array|mixed
-     */
-    public function getCountByDay($userId, $status=3)
-    {
-        $cacheKey = "caches:accounts:count_{$userId}_{$status}";
-        $data = RedisService::get($cacheKey);
-        if($data){
-            return $data;
-        }
-
-        $data = $this->model->where(['user_id'=> $userId,'status'=>$status,'mark'=>1])
-            ->where('create_time','>=', strtotime(date('Y-m-d')))
-            ->count('id');
-        if($data){
-            RedisService::set($cacheKey, $data, rand(5,10));
-        }
-
-        return $data;
-    }
 }

+ 69 - 31
app/Services/Api/PaperService.php

@@ -66,13 +66,17 @@ class PaperService extends BaseService
         }
 
         $query = $this->getQuery($params);
-        $list = $query->select(['a.id','a.user_id','a.paper_id','a.score','a.accurate_count','b.name','b.type','b.topic_count','b.score_total','b.is_charge','a.create_time','a.answer_times','a.status'])
+        $list = $query->select(['a.*','b.id as rid','b.score','b.accurate_count','b.answer_times','b.answer_count','b.is_submit'])
             ->orderBy('a.create_time','desc')
             ->paginate($pageSize > 0 ? $pageSize : 9999999);
         $list = $list? $list->toArray() :[];
         if($list){
             foreach($list['data'] as &$item){
-                $item['create_time'] = $item['create_time']? datetime($item['create_time'],'Y-m-d H.i.s') : '';
+                $item['score'] = !empty($item['score'])? $item['score'] : 0;
+                $item['is_submit'] = !empty($item['is_submit'])? $item['is_submit'] : 0;
+                $item['answer_count'] = !empty($item['answer_count'])? $item['answer_count'] : 0;
+                $item['accurate_count'] = !empty($item['accurate_count'])? $item['accurate_count'] : 0;
+                $item['date'] = $item['create_time'] ? datetime($item['create_time'], 'Y-m-d') : '';
             }
         }
 
@@ -96,7 +100,7 @@ class PaperService extends BaseService
      */
     public function getQuery($params)
     {
-        $where = ['b.status'=>1,'b.mark'=>1,'a.mark' => 1];
+        $where = ['a.status'=>1,'a.mark'=>1];
         $status = isset($params['status'])? $params['status'] : 0;
         $type = isset($params['type'])? $params['type'] : 0;
         $sceneType = isset($params['scene_type'])? $params['scene_type'] : 0;
@@ -105,24 +109,27 @@ class PaperService extends BaseService
             $where['a.status'] = $status;
         }
         if($type>0){
-            $where['b.type'] = $type;
+            $where['a.type'] = $type;
         }
 
         if($sceneType>0){
-            $where['b.scene_type'] = $sceneType;
+            $where['a.scene_type'] = $sceneType;
         }
 
         if($subjectId>0){
-            $where['b.subject_id'] = $subjectId;
+            $where['a.subject_id'] = $subjectId;
         }
 
-        return $this->model->from('exam_answers as a')
-            ->leftJoin('exam_papers as b','b.id','=','a.paper_id')
+        return $this->model->from('exam_papers as a')
+            ->leftJoin('exam_answers as b', function($join){
+                // 未完成交卷的答题数据
+                $join->on('b.paper_id','=','a.id')->where(['b.is_submit'=>0]);
+            })
             ->where($where)
             ->where(function ($query) use($params){
                 $keyword = isset($params['keyword'])? $params['keyword'] : '';
                 if($keyword){
-                    $query->where('b.name','like',"%{$keyword}%");
+                    $query->where('a.name','like',"%{$keyword}%");
                 }
             });
     }
@@ -163,6 +170,30 @@ class PaperService extends BaseService
     }
 
     /**
+     * 用户最近答题记录
+     * @param $userId
+     * @param $paperId
+     * @return array|mixed
+     */
+    public function getLastAnswerLogId($userId,$paperId)
+    {
+        $cacheKey = "caches:paper:log_{$userId}_{$paperId}";
+        $id = RedisService::get($cacheKey);
+        if($id){
+            return $id;
+        }
+
+        $id = ExamAnswerModel::where(['user_id'=> $userId,'paper_id'=> $paperId,'status'=>1,'mark'=>1])
+            ->where('create_time','>=', strtotime(date('Y-m-d')))
+            ->value('id');
+        if($id){
+            RedisService::set($cacheKey, $id, rand(5, 10));
+        }
+
+        return $id;
+    }
+
+    /**
      * 获取详情
      * @param $id
      * @return array|mixed
@@ -180,15 +211,19 @@ class PaperService extends BaseService
         }
 
         // 若进行答题
-        if($rid<=0 && $type != 1) {
-            // 判断N分钟内是否有未交卷的答题
-            $lastAnswerInfo = $this->getLastAnswer($userId, $paperId, 0);
-            $rid = isset($lastAnswerInfo['id']) ? $lastAnswerInfo['id'] : 0;
+        if($rid<=0) {
+            if($type != 1){
+                // 判断N分钟内是否有未交卷的答题
+                $lastAnswerInfo = $this->getLastAnswer($userId, $paperId, 0);
+                $rid = isset($lastAnswerInfo['id']) ? $lastAnswerInfo['id'] : 0;
+            }else {
+                $rid = $this->getLastAnswerLogId($userId, $paperId);
+            }
         }
         $where = ['a.id'=> $paperId,'a.status'=>1,'a.mark'=>1];
         $info = $this->model->from('exam_papers as a')
             ->leftJoin('exam_answers as b',function($join) use($rid){
-                $join->on('b.paper_id','=','a.id')->where(['b.id'=>$rid]);
+                $join->on('b.paper_id','=','a.id')->where(['b.id'=>$rid,'b.status'=>1]);
             })
             ->where($where)
             ->select(['a.id as paper_id','b.id as rid','b.score','b.accurate_count','b.answer_count','b.answer_last_id','b.answer_times','a.name','a.type','a.scene_type','a.subject_id','a.score_total','a.topic_count','a.total_time','a.is_charge','a.create_time','a.status'])
@@ -209,26 +244,29 @@ class PaperService extends BaseService
             $info['answer_times'] = isset($info['answer_times'])? intval($info['answer_times']) : 0;
             $info['remain_time'] = $totalTime>$info['answer_times']? $totalTime-$info['answer_times'] : 0;
             $info['remain_time_text'] = $info['remain_time']? format_times($info['remain_time']) : '00:00';
-
+            $info['progress'] = intval($info['answer_count']/$info['topic_count'] * 100);
             // 当前题目
             //$prefix = env('DB_PREFIX','_lev');
             $model = ExamTopicModel::from('exam_topics as a')
                 ->leftJoin('exam_answers_topics as b', function($join) use($rid){
                     // 是否有最近答题记录
-                    $join->on('b.topic_id','=',"a.id")->where("b.answer_log_id",'=', $rid)->where("b.mark",'=', 1);
+                    $join->on('b.topic_id','=',"a.id")->where("b.answer_log_id",'=', $rid)->where(['b.status'=>1,"b.mark"=> 1]);
                 })
-                ->where(['a.paper_id'=> $paperId,'a.status'=>1,'a.mark'=>1])
-                ->where(function($query) use($tid, $lastId){
-                    // 答题卡选择的题目,否则默认按题目排序返回第一题
-                    if($tid>0){
-                      $query->where('a.id', $tid);
-                    }else if($lastId){
-                        $query->where('a.id', '>', $lastId);
-                    }
-                });
+                ->where(['a.paper_id'=> $paperId,'a.status'=>1,'a.mark'=>1]);
             $model1 = clone  $model;
-            if($model->value('a.id')<=0 && $lastId){
-                $model = $model1->where('a.id', $lastId);
+            // 验证最近一题是否为最后一题
+            $model1 = $model1->where(function($query) use($tid,$lastId){
+                // 答题卡选择的题目,否则默认按题目排序返回第一题
+                if($tid>0){
+                    $query->where('a.id', $tid);
+                }else if($lastId){
+                    $query->where('a.id', '>', $lastId);
+                }
+            });
+            if($model1->value('a.id')<=0 && $lastId){
+                $model = $model->where('a.id', $lastId);
+            }else{
+                $model = $model1;
             }
             $info['topic'] = $model->select(['a.*','b.id as answer_topic_id','b.answer_log_id','b.answer as submit_answer','b.answer_type as submit_answer_type','b.score as submit_score','b.accurate'])
                 ->orderBy('a.sort','desc')
@@ -287,10 +325,10 @@ class PaperService extends BaseService
                 }
 
                 // 未答题隐藏答案
-                if(empty($info['topic']['submit_answer'])){
-                    $info['topic']['correct_answer'] = '未答题';
-                    $info['topic']['topic_analysis'] = '';
-                }
+//                if(empty($info['topic']['submit_answer'])){
+//                    $info['topic']['correct_answer'] = '未答题';
+//                    $info['topic']['topic_analysis'] = '';
+//                }
 
                 // 多选题
                 $topicType = isset($info['topic']['topic_type'])? $info['topic']['topic_type'] : '';

+ 35 - 33
app/Services/DeepSeekService.php

@@ -2,6 +2,8 @@
 
 namespace App\Services;
 
+use thiagoalessio\TesseractOCR\TesseractOCR;
+
 /**
  * DeepSeek服务管理-服务类
  * @author laravel开发员
@@ -70,28 +72,8 @@ class DeepSeekService extends BaseService
         $answer = isset($params['answer'])? $params['answer'] : '';
         $topic = isset($params['topic'])? $params['topic'] : '';
         $score = isset($params['score'])? $params['score'] : 0;
-        $type = isset($params['type'])? $params['type'] : 1; // 1-文字答案图片题目,2-文字答案文字题目,3-图片答案图片题目,4-图片答案文字题目
         $content = "你是一个答题高手";
-        if($type==1){
-            $message = "请判断答案【{$answer}】内容并针对图片[image]{$topic}[/image]中题目共{$score}分给出评分,请返回针对该题目的包含score字段评分、topic字段题目内容以及analyze题目解析字段的结果";
-        }else if ($type == 2){
-            $message = "题目为【{$topic}】的答案【{$answer}】总分共{$score}分能得多少分?请返回针对该题目的包含score字段评分、topic字段题目内容以及analyze题目解析字段的结果";
-        }else if ($type == 3){
-            $file = file_get_contents(ATTACHMENT_PATH.get_image_path($answer));
-            $file = "data:image/jpeg;base64".base64_encode($file);
-            $file1 = file_get_contents(ATTACHMENT_PATH.get_image_path($topic));
-            $file1 = "data:image/jpeg;base64".base64_encode($file1);
-            $message = "请判断图片内容{$file}中答案内容并针对图片{$file1}中题目内容总分共{$score}分给出评分,请返回针对该题目的包含score字段评分、topic字段题目内容以及analyze题目解析字段的结果";
-        }else{
-            $message = "请判断图片[image]{$answer}[/image]中答文字案内容并针对【{$topic}】题目内容总分共{$score}分给出评分,请返回针对该题目的包含score字段评分、topic字段题目内容以及analyze题目解析字段的结果";
-        }
-
-        $file = file_get_contents(ATTACHMENT_PATH.get_image_path($answer));
-//        var_dump($file);
-        $file = "data:image/jpeg;base64,".base64_encode($file);
-        $message = "请上传图片[image]{$answer}[/image],返回分子分析数据";
-        //$message = "请分析图片[image]{$image}[/image]中答案与".($type==1?'题目'.$topic:"图片[image]{$topic}[/image]中题目内容")."的正确度,共{$score}分,请返回包含score字段评分、topic字段题目内容、analyze题目解析字段的结果";
-        dump($message);
+        $message = "题目为【{$topic}】的答案【{$answer}】总分共{$score}分能得多少分?请返回针对该题目的包含score字段评分、topic字段题目内容以及analyze题目解析字段的结果";
         $data = [
             'model'=> $model,
             'messages'=> [
@@ -104,17 +86,16 @@ class DeepSeekService extends BaseService
                     'content' => $message
                 ],
             ],
-            //'stream' => false, //false 非流  true//流返回,需要前端追加和保持长连接
-//            'response_format'=>[
-//                'type'=>'text' //返回格式(text,json_object)
-//            ],
-//            "max_tokens"=>2048, //最大返回token数
+            'stream' => false, //false 非流  true//流返回,需要前端追加和保持长连接
+            'response_format'=>[
+                'type'=>'text' //返回格式(text,json_object)
+            ],
+            "max_tokens"=>2048, //最大返回token数
         ];
 
 
         $url = $this->apiUrl.$this->apiUrls[$model];
         $result = aiRequest($url, json_encode($data), 20, $headers);
-        dump($result);
         $choices = isset($result['choices'])? $result['choices'] : [];
         $choiceData = isset($choices[0]['message'])? $choices[0]['message'] : [];
         $choiceContent = isset($choiceData['content'])? $choiceData['content'] : '';
@@ -123,6 +104,12 @@ class DeepSeekService extends BaseService
         return $content;
     }
 
+
+    /**
+     * 上传图片
+     * @param $image
+     * @return false
+     */
     public function upload($image)
     {
         if(empty($this->apiUrl) || empty($this->apiKey) || empty($this->apiName)){
@@ -138,17 +125,32 @@ class DeepSeekService extends BaseService
 
 
         $filePath = ATTACHMENT_PATH.get_image_path($image);
-        var_dump($filePath);
         $obj = new \CURLFile($filePath);
         $data = [
             'image'=> $obj,
         ];
         $url = $this->apiUrl.$this->apiUrls['upload'];
-        var_dump($url);
-//        $url = 'http://127.0.5.12/api/v1/upload/image';
-//        var_dump($options);
-//        $result = file_get_contents($url, false, $context);
         $result = aiRequest($url, $data, 10, $headers);
-        dump($result);
+
+    }
+
+    /**
+     * 获取题目内容
+     * @param $imageUrl
+     * @return false
+     */
+    public function getImageTopicData($imageUrl)
+    {
+        if(empty($imageUrl)){
+            return false;
+        }
+        // 图片获取数据
+        if(preg_match("/(images|temp)/", $imageUrl)){
+            $path = get_image_path($imageUrl);
+            $ocr = new TesseractOCR();
+            return $ocr->recognize(ATTACHMENT_PATH.$path);
+        }
+
+        return $imageUrl;
     }
 }

+ 6 - 6
config/platform.php

@@ -5,19 +5,19 @@ return [
             "id" => 1,
             "name" => '每日一练',
             "code" => 'day-practice',
-            'page' => '/pages/exam/practice'
+            'page' => '/pages/exam/practice?st=1'
         ],
         [
             "id" => 2,
             "name" => '历年真题',
             "code" => 'past-paper',
-            'page' => '/pages/exam/past_paper'
+            'page' => '/pages/exam/index?st=2'
         ],
         [
             "id" => 3,
             "name" => '模拟试题',
             "code" => 'mock-paper',
-            'page' => '/pages/exam/mock_paper'
+            'page' => '/pages/exam/index?st=3'
         ],
         [
             "id" => 98,
@@ -29,19 +29,19 @@ return [
             "id" => 5,
             "name" => '复习资料',
             "code" => 'review-materials',
-            'page' => '/pages/exam/review'
+            'page' => '/pages/exam/index?st=5'
         ],
         [
             "id" => 4,
             "name" => '模拟考试',
             "code" => 'mock-exam',
-            'page' => '/pages/exam/past_paper'
+            'page' => '/pages/exam/index?st=4'
         ],
         [
             "id" => 2,
             "name" => '考前冲刺',
             "code" => 'exam-sprint',
-            'page' => '/pages/exam/sprint'
+            'page' => '/pages/exam/index?st=6'
         ],
         [
             "id" => 99,

BIN
public/app/jdapp_v1.2.30.apk


BIN
public/favicon.ico


BIN
public/h5/assets/uvicons.f0fbf8a0.ttf


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 2
public/h5/index.html


+ 0 - 21
public/h5/static/customicons.css

@@ -1,21 +0,0 @@
-@font-face {
-	font-family: "customicons";
-	/* Project id 2878519 */
-	src: url('/static/customicons.ttf') format('truetype');
-}
-
-.customicons {
-	font-family: "customicons" !important;
-}
-
-.youxi:before {
-	content: "\e60e";
-}
-
-.wenjian:before {
-	content: "\e60f";
-}
-
-.zhuanfa:before {
-	content: "\e610";
-}

BIN
public/h5/static/customicons.ttf


+ 0 - 32
public/h5/static/iconfont.css

@@ -1,32 +0,0 @@
-@font-face {
-  font-family: "iconfont"; /* Project id  */
-  src: url('@/static/iconfont.ttf') format('truetype');
-}
-
-.iconfont {
-  font-family: "iconfont" !important;
-  font-size: 16px;
-  font-style: normal;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-.icon-link:before {
-  content: "\e772";
-}
-
-.icon-poweroff:before {
-  content: "\e774";
-}
-
-.icon-safety-certificate:before {
-  content: "\e776";
-}
-
-.icon-chart-pie-alt:before {
-  content: "\e78c";
-}
-
-.icon-kongxincai:before {
-  content: "\e642";
-}

BIN
public/h5/static/iconfont.ttf


BIN
public/h5/static/icons/home-active.png


BIN
public/h5/static/icons/home.png


BIN
public/h5/static/icons/mine-active.png


BIN
public/h5/static/icons/mine.png


BIN
public/h5/static/icons/order-active.png


BIN
public/h5/static/icons/order-delivery-active.png


BIN
public/h5/static/icons/order-delivery.png


BIN
public/h5/static/icons/order.png


BIN
public/h5/static/images/bg.png


BIN
public/h5/static/images/card-bg.png


BIN
public/h5/static/images/icon-account-log.png


BIN
public/h5/static/images/icon-alipay.png


BIN
public/h5/static/images/icon-avatar.png


BIN
public/h5/static/images/icon-code.png


BIN
public/h5/static/images/icon-coin.png


BIN
public/h5/static/images/icon-copy.png


BIN
public/h5/static/images/icon-cricle.png


BIN
public/h5/static/images/icon-custom-avatar.png


BIN
public/h5/static/images/icon-custom-menu.png


BIN
public/h5/static/images/icon-despoit-refund.png


BIN
public/h5/static/images/icon-empty.png


BIN
public/h5/static/images/icon-header-card.png


BIN
public/h5/static/images/icon-loading.png


BIN
public/h5/static/images/icon-log.png


BIN
public/h5/static/images/icon-modify-pwd.png


BIN
public/h5/static/images/icon-password.png


BIN
public/h5/static/images/icon-phone.png


BIN
public/h5/static/images/icon-phone1.png


BIN
public/h5/static/images/icon-phone2.png


BIN
public/h5/static/images/icon-privacy.png


BIN
public/h5/static/images/icon-pwd-right.png


BIN
public/h5/static/images/icon-radio-check.png


BIN
public/h5/static/images/icon-radio-checked.png


BIN
public/h5/static/images/icon-recharge-menu.png


BIN
public/h5/static/images/icon-recharge.png


BIN
public/h5/static/images/icon-register.png


BIN
public/h5/static/images/icon-upload.png


BIN
public/h5/static/images/icon-voice-menu.png


BIN
public/h5/static/images/icon-voice.png


BIN
public/h5/static/images/icon-withdraw-menu.png


BIN
public/h5/static/images/icon-wxpay.png


BIN
public/h5/static/images/loading.gif


BIN
public/h5/static/images/no-data.png


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/index.883130ca.css


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 29
public/h5/static/js/chunk-vendors.08ad7f7b.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/index.c2f2b229.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-log.cd0c6bd7.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-log~pages-account-withdraw~pages-account-withdrawLog~pages-agree-recharge~pages-agree-~04f4b299.1c97a3dc.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-log~pages-account-withdraw~pages-account-withdrawLog~pages-chat-index~pages-deposit-lo~0061d6ff.e6502d94.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-log~pages-account-withdraw~pages-account-withdrawLog~pages-chat-index~pages-deposit-lo~6fea2be9.c88fe845.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-withdraw.ab4473e2.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-withdrawLog.e04f6953.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-account-withdraw~pages-chat-index~pages-deposit-pay~pages-deposit-refund~pages-deposit-refuse~~8c2da746.39796529.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-agree-recharge.932f28bd.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-agree-recharge~pages-agree-register~pages-article-privacy.52f1a4dc.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-agree-register.6d87283e.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-article-privacy.2478202d.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-chat-index.6f113bea.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-deposit-log.d5d76fc9.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-deposit-pay.e3f38737.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-deposit-refund.73e99416.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-deposit-refuse.13811af3.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-index-index.a4464313.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-index-index~pages-order-delivery~pages-order-index.baf0e525.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-login-forget.6a8ff486.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-login-forget~pages-login-login~pages-register-index.adfce370.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-login-login.26302269.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-mine-index.410be7bb.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-mine-modify.696445df.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-mine-profile.a563048f.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-order-delivery.ba1fe2ed.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-order-detail.4c8a36d0.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-order-index.0298dfb5.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-order-picker.042362ba.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
public/h5/static/js/pages-register-index.95af7d49.js


BIN
public/h5/static/logo.png


BIN
public/h5/static/mp3/msg.mp3


+ 0 - 22
public/h5/static/theme.css

@@ -1,22 +0,0 @@
-:root {
-	--color: #248dd3;
-	/* --color: #7bd8ff; */
-	/* --color: #72aef7; */
-	/* --color: #ff6900; */
-
-	--color1: #9cdaff;
-	--color2: #ff7006;
-	--color3: #a4ddf1;
-	--color4: #f7c10b;
-	/* --color1: #ff7006; */
-	--color-red: #ff7878;
-	/* --color1: #e6739c; */
-	/* --color2: #8ea0f6; */
-	/* --color2: #e0a5c2; */
-	--bg-color: #f2f2f2;
-	--padding-rl: 10rpx;
-	--padding-tb: 10rpx;
-	--text-color: #777;
-	--padding-bottom: 8rpx;
-	--card-bg: #29adff;
-}

BIN
public/h5/static/uni.ttf


+ 0 - 0
routes/api.php


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels