lizhen 15 ساعت پیش
والد
کامیت
5df26ee46a

+ 114 - 4
addons/exam/controller/Paper.php

@@ -193,19 +193,19 @@ class Paper extends Base
     {
         $request       = Request::instance();
         $user_id       = $this->auth->id;
-
         $grade_id      = $request->post('grade_id');
         $paper_id      = $request->post('paper_id/d', 0);
         $questions     = $request->post('questions/a', []);
         $start_time    = $request->post('start_time/d', time());
         $room_id       = 0;
         $room_grade_id = $request->post('room_grade_id/d', 0);
-
+      
         if (!$user_id || !$paper_id || !$questions) {
             $this->error('提交数据有误');
         }
 
         $check = Db::name('exam_grade')->where('status',1)->where('id',$grade_id)->where('user_id',$user_id)->where('paper_id',$paper_id)->find();
+
         if(!$check){
             $this->error('交卷有误,或者您已交卷');
         }
@@ -270,10 +270,10 @@ class Paper extends Base
                 $this->error('交卷失败');
             }
             
-            // 如果提交成功,推送积分到工行
+            // 异步推送积分到工行(写入队列)
             $cephone = '15388010006';
             //$cephone = $this->auth->mobile;
-            $this->update_villager_integral($cephone, $result['score'], '10938', [$this->auth->nickname]);
+            $this->addIcbcQueue($cephone, $result['score'], '10938', $this->auth->nickname);
             
         }
 
@@ -434,6 +434,116 @@ class Paper extends Base
     }
 
     /**
+     * 添加工行积分任务到队列
+     * @param string $mobile_phone 手机号
+     * @param int $integral_value 积分值
+     * @param string $integral_type 积分类型
+     * @param string $nickname 用户昵称
+     */
+    private function addIcbcQueue($mobile_phone, $integral_value, $integral_type, $nickname)
+    {
+        try {
+            $data = [
+                'mobile_phone' => $mobile_phone,
+                'integral_value' => $integral_value,
+                'integral_type' => $integral_type,
+                'nickname' => $nickname,
+                'status' => 0, // 0-待处理, 1-处理中, 2-成功, 3-失败
+                'retry_count' => 0,
+                'createtime' => time(),
+                'updatetime' => time(),
+            ];
+            
+            Db::name('icbc_queue')->insert($data);
+            
+            // 立即尝试异步处理(不阻塞当前请求)
+            $this->processIcbcQueueAsync();
+            
+        } catch (\Exception $e) {
+            // 队列写入失败,记录日志但不影响主流程
+            \think\Log::record('工行队列写入失败: ' . $e->getMessage(), 'error');
+        }
+    }
+
+    /**
+     * 异步处理工行队列(不阻塞当前请求)
+     */
+    private function processIcbcQueueAsync()
+    {
+        // 使用fastcgi_finish_request()立即返回响应给用户
+        if (function_exists('fastcgi_finish_request')) {
+            fastcgi_finish_request();
+        }
+        
+        // 后台处理队列
+        $this->processIcbcQueue();
+    }
+
+    /**
+     * 处理工行队列任务
+     */
+    public function processIcbcQueue()
+    {
+        // 获取待处理的任务(限制每次处理10条)
+        $tasks = Db::name('icbc_queue')
+            ->where('status', 0)
+            ->where('retry_count', '<', 3) // 最多重试3次
+            ->limit(10)
+            ->select();
+        
+        foreach ($tasks as $task) {
+            try {
+                // 更新状态为处理中
+                Db::name('icbc_queue')->where('id', $task['id'])->update([
+                    'status' => 1,
+                    'updatetime' => time()
+                ]);
+                
+                // 调用工行接口
+                $result = $this->update_villager_integral(
+                    $task['mobile_phone'],
+                    $task['integral_value'],
+                    $task['integral_type'],
+                    [$task['nickname']]
+                );
+                
+                // 根据结果更新状态
+                if (isset($result['return_code']) && $result['return_code'] == 0) {
+                    // 成功
+                    Db::name('icbc_queue')->where('id', $task['id'])->update([
+                        'status' => 2,
+                        'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
+                        'updatetime' => time()
+                    ]);
+                } else {
+                    // 失败,增加重试次数
+                    $retry_count = $task['retry_count'] + 1;
+                    $status = $retry_count >= 3 ? 3 : 0; // 重试3次后标记为失败
+                    
+                    Db::name('icbc_queue')->where('id', $task['id'])->update([
+                        'status' => $status,
+                        'retry_count' => $retry_count,
+                        'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
+                        'error_msg' => isset($result['return_msg']) ? $result['return_msg'] : '未知错误',
+                        'updatetime' => time()
+                    ]);
+                }
+                
+            } catch (\Exception $e) {
+                // 异常处理
+                Db::name('icbc_queue')->where('id', $task['id'])->update([
+                    'status' => 0,
+                    'retry_count' => $task['retry_count'] + 1,
+                    'error_msg' => $e->getMessage(),
+                    'updatetime' => time()
+                ]);
+                
+                \think\Log::record('工行队列处理异常[ID:'.$task['id'].']: ' . $e->getMessage(), 'error');
+            }
+        }
+    }
+
+    /**
      * 写入工行接口日志
      * @param bool $is_success 是否成功
      * @param array $result 返回结果

+ 1 - 0
application/command.php

@@ -17,4 +17,5 @@ return [
     'app\admin\command\Min',
     'app\admin\command\Addon',
     'app\admin\command\Api',
+    'app\command\IcbcQueue',
 ];

+ 200 - 0
application/command/IcbcQueue.php

@@ -0,0 +1,200 @@
+<?php
+
+namespace app\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\Output;
+use think\Db;
+
+/**
+ * 工行积分队列处理命令
+ * 命令行运行: php think icbc_queue
+ */
+class IcbcQueue extends Command
+{
+    protected function configure()
+    {
+        $this->setName('icbc_queue')
+            ->setDescription('处理工行积分推送队列');
+    }
+
+    protected function execute(Input $input, Output $output)
+    {
+        $output->writeln("开始处理工行积分队列...");
+        
+        // 获取待处理的任务
+        $tasks = Db::name('icbc_queue')
+            ->where('status', 0)
+            ->where('retry_count', '<', 3)
+            ->limit(50)
+            ->select();
+        
+        if (empty($tasks)) {
+            $output->writeln("没有待处理的任务");
+            return;
+        }
+        
+        $output->writeln("找到 " . count($tasks) . " 个待处理任务");
+        
+        foreach ($tasks as $task) {
+            try {
+                // 更新状态为处理中
+                Db::name('icbc_queue')->where('id', $task['id'])->update([
+                    'status' => 1,
+                    'updatetime' => time()
+                ]);
+                
+                $output->writeln("处理任务 ID: {$task['id']}, 手机号: {$task['mobile_phone']}, 积分: {$task['integral_value']}");
+                
+                // 调用工行接口
+                $result = $this->callIcbcApi($task);
+                
+                // 根据结果更新状态
+                if (isset($result['return_code']) && $result['return_code'] == 0) {
+                    // 成功
+                    Db::name('icbc_queue')->where('id', $task['id'])->update([
+                        'status' => 2,
+                        'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
+                        'updatetime' => time()
+                    ]);
+                    $output->writeln("✓ 任务 {$task['id']} 处理成功");
+                } else {
+                    // 失败,增加重试次数
+                    $retry_count = $task['retry_count'] + 1;
+                    $status = $retry_count >= 3 ? 3 : 0;
+                    
+                    Db::name('icbc_queue')->where('id', $task['id'])->update([
+                        'status' => $status,
+                        'retry_count' => $retry_count,
+                        'result' => json_encode($result, JSON_UNESCAPED_UNICODE),
+                        'error_msg' => isset($result['return_msg']) ? $result['return_msg'] : '未知错误',
+                        'updatetime' => time()
+                    ]);
+                    
+                    $output->writeln("✗ 任务 {$task['id']} 处理失败: " . (isset($result['return_msg']) ? $result['return_msg'] : '未知错误'));
+                }
+                
+            } catch (\Exception $e) {
+                // 异常处理
+                Db::name('icbc_queue')->where('id', $task['id'])->update([
+                    'status' => 0,
+                    'retry_count' => $task['retry_count'] + 1,
+                    'error_msg' => $e->getMessage(),
+                    'updatetime' => time()
+                ]);
+                
+                $output->writeln("✗ 任务 {$task['id']} 异常: " . $e->getMessage());
+            }
+            
+            // 避免请求过快
+            usleep(100000); // 0.1秒
+        }
+        
+        $output->writeln("队列处理完成");
+    }
+
+    /**
+     * 调用工行接口
+     */
+    private function callIcbcApi($task)
+    {
+        include_once EXTEND_PATH . 'icbc/DefaultIcbcClient.php';
+        
+        // 生成16位唯一序列号
+        $fSeqNo = time() . str_pad(mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
+        
+        // 构建业务参数
+        $biz_content = [
+            'fSeqNo' => $fSeqNo,
+            'corpCode' => 'xingfulishequ',
+            'mobilePhone' => $task['mobile_phone'],
+            'integralValue' => (string)$task['integral_value'],
+            'integralType' => $task['integral_type'],
+            'remark1' => $task['nickname'],
+        ];
+        
+        // 工行RSA密钥
+        $public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwFgHD4kzEVPdOj03ctKM7KV+16bWZ5BMNgvEeuEQwfQYkRVwI9HFOGkwNTMn5hiJXHnlXYCX+zp5r6R52MY0O7BsTCLT7aHaxsANsvI9ABGx3OaTVlPB59M6GPbJh0uXvio0m1r/lTW3Z60RU6Q3oid/rNhP3CiNgg0W6O3AGqwIDAQAB';
+        $private_key = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCR8/ZvKPAdZzsyvapySvztQm56s1N59ynKMOWpUbK4c5MNWMl+q3dvsp+UiSAx2TAeGkYfW3W6nO/3Y0hAZki99fmuzpPujEeHhs79HNwGZYQjN71Vck2JeflTq8jpL+9/up0Kz2nbwtZDMKTTEgbfNeO24gV1bmvD2kQ9j66RIyuXSDwQbVbQfl6LiqKoJm3rbtsbwX1Ytc0/Szslyor1VdPZWnHDMm3m78Hqu7X3vL6K7fAW/4FVbeKV7vWjvyiTQfETmuADqMdsqV5YeqUZWE/Dnzg+6JV/3L9nJ8f+/mPlh8k1h1oW035GrADKFKf1M2ujKKeHICnj7qKCdBeNAgMBAAECggEAHkh+U2YtHAy1Tbvox7ojbJ8iCTd4FJBiDV/D5zPaX0crtdM8S5oMOBLZ5ZnmIjGsODK/ZfY2ITg62huxfBs88J0+5zRZoV9d4BLqk74PMQyTNDN2h2omCGZUgzXbg/a8PMZdm0aZ8k0k4+AN8vWEk3+89c9Dzq/QkFyTWCqdz+Mp9NkcOjA255kj5/D1q9Zj0x9VcmKg3oTtrKL/dkspUxVaMKXcpo6J4AszC05tT3N0SNLhcq51I6B9QdbYsYCkP9whPNYIl/y4dN4QnNEivQzA5/ltr5DDQZc7Xke1+SpJN+ylBOBJ8yvNoDnuxx0xEWuNJ5bUzyri/DNjZRKNQQKBgQDKkxn5R4Q3rChI/KVIXHMecTs9fXN5pbnA8UKU6ZeTl+wHffxwRieHZJJp1nDcQ5i8YXCtqEJcJGFn3T0rEjVCJ/RVHclFO+TjYaK9HtyNJLPrvKmAzjCzV1yPfe4qmpgJddzZI7Vii2uFgklixvhkoY74hwSJtvLPTO0p0xrYdQKBgQC4cgfpCMLYlaHQGz+dAEf4IewQpwBGn7XShCpiXGFciGZZEIzvJMzXP7yo8pDMHQbB4kQsTRRG2fcdHGWI5VQGHPqG5O0tUueKGUlSg7j8Y/Pp8ZrBGSrlilAf17I/u9MC7Xe2ZRVGNgPDYAyjMEGmClI0n2+aN6b4CFVBjYmfuQKBgEKO9KDIE7QrF41rnW7aGWTuNVWty2wzvIWdf4/n9EqlRwLrLS9CjahZrhWiRLDKcPusVFZqi2s09OAoe/mT4PXcpNX2lHPwCvN+1/allje10HvrIBJXLP8v/BSVftR2uO+azzZ1GhrHzksulKgk0eZWguA7lI0fFEZycxYj65UlAoGAD9p1RZlkLfuGgf2llRgOF4zK3o+MHYXiuep0PioUkECFE4ixpGh0Vtf6nkbjHTgteYK6O1iQsppPfCgRrheQBkp9WhTZMfkbP6p2u+nof4ET2PrUQ16naj1eL655erLpKypADORZVMSVxDhAPdKLAfuHH1DI5ed8qXsF4PGKb7kCgYEAm/d+daT6YsbHDZlJ/J9Q8rRkKmiqj43NGQSHKg6Z6BEDibm8wRmj3Itu1N6XVChuaH+ekJzvUnZ/q1nyYzGvy6bOHYn3ziF9aH7wuhcRZ4qARmKDnzTBLg2QXBK1+400O3LJ+sAH/yuH/Y4hzRE6YMxBQpdYfnlJcIFVimAsT1w=';
+        
+        // 构建通用请求参数
+        $data = [
+            'app_id' => '10000000000004096993',
+            'msg_id' => createUniqueNo('msg', time()),
+            'format' => 'json',
+            'charset' => 'UTF-8',
+            'encrypt_type' => 'AES',
+            'sign_type' => 'RSA2',
+        ];
+        
+        try {
+            // 创建工行客户端
+            $client = new \DefaultIcbcClient(
+                $data['app_id'],
+                $private_key,
+                $data['sign_type'],
+                $data['charset'],
+                $data['format'],
+                $public_key,
+                '', '', '', ''
+            );
+            
+            // 构建请求参数
+            $request = [
+                'serviceUrl' => 'https://gw.dccnet.com.cn:8084/api/mybank/farm/farmplatf/updateVillagerIntegral/V1',
+                'method' => 'POST',
+                'isNeedEncrypt' => false,
+                'extraParams' => null,
+                'biz_content' => $biz_content,
+            ];
+            
+            // 发送请求
+            $response = $client->execute($request, $data['msg_id'], '');
+            
+            // 解析响应
+            if (empty($response)) {
+                return ['return_code' => '-1', 'return_msg' => '接口无响应'];
+            }
+            
+            $result = json_decode($response, true);
+            
+            if (json_last_error() !== JSON_ERROR_NONE) {
+                return ['return_code' => '-2', 'return_msg' => 'JSON解析失败'];
+            }
+            
+            // 写入日志
+            $this->writeLog($result['return_code'] == 0, $result, $biz_content);
+            
+            return $result;
+            
+        } catch (\Exception $e) {
+            return ['return_code' => '-99', 'return_msg' => '异常: ' . $e->getMessage()];
+        }
+    }
+
+    /**
+     * 写入日志
+     */
+    private function writeLog($is_success, $result, $request_data)
+    {
+        $log_dir = RUNTIME_PATH . 'icbc_log/';
+        if (!is_dir($log_dir)) {
+            mkdir($log_dir, 0755, true);
+        }
+        
+        $filename = $is_success ? 'suc.txt' : 'failicbc.txt';
+        $filepath = $log_dir . $filename;
+        
+        $log_content = [
+            '时间' => date('Y-m-d H:i:s'),
+            '请求数据' => $request_data,
+            '返回数据' => $result,
+            '分隔线' => str_repeat('-', 80)
+        ];
+        
+        $log_text = "\n" . json_encode($log_content, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
+        file_put_contents($filepath, $log_text, FILE_APPEND);
+    }
+}
+

+ 26 - 0
icbc_queue.sql

@@ -0,0 +1,26 @@
+-- 工行积分推送队列表
+
+-- 临时修改sql_mode,避免只能使用严格模式的问题
+SET SESSION sql_mode = '';
+
+-- 创建表
+CREATE TABLE IF NOT EXISTS `fa_icbc_queue` (
+  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `mobile_phone` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
+  `integral_value` int(11) NOT NULL DEFAULT '0' COMMENT '积分值',
+  `integral_type` varchar(50) NOT NULL DEFAULT '' COMMENT '积分类型',
+  `nickname` varchar(100) NOT NULL DEFAULT '' COMMENT '用户昵称',
+  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态:0=待处理,1=处理中,2=成功,3=失败',
+  `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数',
+  `result` text COMMENT '返回结果',
+  `error_msg` varchar(500) DEFAULT '' COMMENT '错误信息',
+  `createtime` int(11) DEFAULT NULL COMMENT '创建时间',
+  `updatetime` int(11) DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  KEY `status` (`status`),
+  KEY `createtime` (`createtime`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工行积分推送队列';
+
+-- 恢复原来的sql_mode(可选)
+-- SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
+

+ 26 - 0
icbc_queue_no_prefix.sql

@@ -0,0 +1,26 @@
+-- 工行积分推送队列表(无前缀版本)
+-- 如果报错找不到表,使用此文件
+
+SET SESSION sql_mode = '';
+
+-- 删除可能存在的旧表
+DROP TABLE IF EXISTS `icbc_queue`;
+
+-- 创建表(不带前缀)
+CREATE TABLE `icbc_queue` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `mobile_phone` varchar(20) NOT NULL DEFAULT '',
+  `integral_value` int(11) NOT NULL DEFAULT '0',
+  `integral_type` varchar(50) NOT NULL DEFAULT '',
+  `nickname` varchar(100) NOT NULL DEFAULT '',
+  `status` tinyint(1) NOT NULL DEFAULT '0',
+  `retry_count` int(11) NOT NULL DEFAULT '0',
+  `result` text,
+  `error_msg` varchar(500) DEFAULT '',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `status` (`status`),
+  KEY `createtime` (`createtime`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工行积分推送队列';
+

+ 22 - 0
icbc_queue_simple.sql

@@ -0,0 +1,22 @@
+-- 工行积分推送队列表(简化版)
+-- 如果icbc_queue.sql执行有问题,请使用此文件
+
+DROP TABLE IF EXISTS `fa_icbc_queue`;
+
+CREATE TABLE `fa_icbc_queue` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `mobile_phone` varchar(20) NOT NULL DEFAULT '',
+  `integral_value` int(11) NOT NULL DEFAULT '0',
+  `integral_type` varchar(50) NOT NULL DEFAULT '',
+  `nickname` varchar(100) NOT NULL DEFAULT '',
+  `status` tinyint(1) NOT NULL DEFAULT '0',
+  `retry_count` int(11) NOT NULL DEFAULT '0',
+  `result` text,
+  `error_msg` varchar(500) DEFAULT '',
+  `createtime` int(11) DEFAULT NULL,
+  `updatetime` int(11) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `status` (`status`),
+  KEY `createtime` (`createtime`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+

+ 226 - 0
工行积分异步队列使用说明.md

@@ -0,0 +1,226 @@
+# 工行积分异步队列使用说明
+
+## 一、功能说明
+
+将工行积分推送接口改为异步队列处理,用户交卷后立即返回结果,不需要等待工行接口响应。
+
+### 主要特点:
+- ✅ 用户交卷后立即响应,不阻塞主流程
+- ✅ 自动重试机制(失败自动重试3次)
+- ✅ 完整的日志记录(成功/失败分别记录)
+- ✅ 任务状态追踪
+- ✅ 支持定时任务批量处理
+
+## 二、安装步骤
+
+### 1. 创建数据库表
+
+执行项目根目录下的 `icbc_queue.sql` 文件:
+
+```sql
+-- 在数据库中执行
+source icbc_queue.sql;
+```
+
+或者直接复制SQL语句到数据库执行工具中运行。
+
+### 2. 验证命令是否注册成功
+
+在项目根目录执行:
+
+```bash
+php think
+```
+
+如果看到 `icbc_queue` 命令,说明注册成功。
+
+## 三、工作原理
+
+### 流程图:
+
+```
+用户交卷
+  ↓
+保存成绩到数据库
+  ↓
+将积分任务写入队列表 (fa_icbc_queue)
+  ↓
+立即返回成功给用户 ← [fastcgi_finish_request()]
+  ↓
+后台异步调用工行接口
+  ↓
+更新队列状态 (成功/失败)
+  ↓
+记录日志 (suc.txt / failicbc.txt)
+```
+
+## 四、队列处理方式
+
+### 方式一:自动处理(推荐)
+
+用户交卷后会自动触发一次队列处理(不阻塞响应)。
+
+**优点**:无需配置,自动执行  
+**缺点**:如果失败需要重试,需要依赖定时任务
+
+### 方式二:定时任务处理(生产环境推荐)
+
+配置Linux crontab定时任务,每分钟执行一次:
+
+```bash
+# 编辑crontab
+crontab -e
+
+# 添加以下内容(每分钟执行一次)
+* * * * * cd /path/to/your/project && php think icbc_queue >> /dev/null 2>&1
+```
+
+**示例**:
+```bash
+* * * * * cd /www/shequ && php think icbc_queue >> /dev/null 2>&1
+```
+
+### 方式三:手动处理
+
+在项目根目录执行命令:
+
+```bash
+php think icbc_queue
+```
+
+## 五、队列状态说明
+
+| 状态值 | 说明 | 描述 |
+|-------|------|------|
+| 0 | 待处理 | 任务已创建,等待处理 |
+| 1 | 处理中 | 任务正在处理 |
+| 2 | 成功 | 任务处理成功 |
+| 3 | 失败 | 任务处理失败(重试3次后) |
+
+## 六、日志文件说明
+
+### 日志位置:
+- 成功日志:`runtime/icbc_log/suc.txt`
+- 失败日志:`runtime/icbc_log/failicbc.txt`
+
+### 日志格式:
+```json
+{
+    "时间": "2024-01-01 12:00:00",
+    "请求数据": {
+        "fSeqNo": "1234567890123456",
+        "corpCode": "xingfulishequ",
+        "mobilePhone": "15388010006",
+        "integralValue": "100",
+        "integralType": "10938",
+        "remark1": "张三"
+    },
+    "返回数据": {
+        "return_code": "0",
+        "return_msg": "成功",
+        "fSeqNo": "1234567890123456"
+    },
+    "原始响应": "...",
+    "分隔线": "--------------------------------------------------------------------------------"
+}
+```
+
+## 七、队列管理
+
+### 查看队列状态
+
+```sql
+-- 查看待处理任务
+SELECT * FROM fa_icbc_queue WHERE status = 0;
+
+-- 查看失败任务
+SELECT * FROM fa_icbc_queue WHERE status = 3;
+
+-- 查看成功任务(最近10条)
+SELECT * FROM fa_icbc_queue WHERE status = 2 ORDER BY updatetime DESC LIMIT 10;
+
+-- 统计各状态任务数量
+SELECT status, COUNT(*) as count FROM fa_icbc_queue GROUP BY status;
+```
+
+### 重置失败任务
+
+```sql
+-- 将失败的任务重置为待处理(会重新尝试)
+UPDATE fa_icbc_queue SET status = 0, retry_count = 0 WHERE status = 3;
+```
+
+### 清理历史数据
+
+```sql
+-- 删除30天前的成功记录
+DELETE FROM fa_icbc_queue WHERE status = 2 AND updatetime < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY));
+```
+
+## 八、监控建议
+
+### 1. 监控待处理任务数量
+
+如果待处理任务数量持续增长,说明处理速度跟不上,需要:
+- 增加定时任务执行频率
+- 检查工行接口是否正常
+
+### 2. 监控失败任务
+
+定期检查失败任务,分析失败原因:
+```sql
+SELECT error_msg, COUNT(*) as count 
+FROM fa_icbc_queue 
+WHERE status = 3 
+GROUP BY error_msg;
+```
+
+### 3. 监控日志文件大小
+
+定期清理或归档日志文件,避免占用过多磁盘空间。
+
+## 九、常见问题
+
+### Q1:队列任务不执行怎么办?
+
+**答**:检查以下几点:
+1. 数据库表是否创建成功
+2. 命令是否注册成功(`php think` 查看)
+3. 定时任务是否配置正确
+4. 查看 `runtime/log` 目录下的错误日志
+
+### Q2:任务一直处于"处理中"状态
+
+**答**:可能是上次处理异常导致。手动重置:
+```sql
+UPDATE fa_icbc_queue SET status = 0 WHERE status = 1 AND updatetime < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 10 MINUTE));
+```
+
+### Q3:如何修改重试次数?
+
+**答**:修改 `Paper.php` 中的重试判断条件:
+```php
+->where('retry_count', '<', 3) // 改为你想要的次数
+```
+
+### Q4:如何修改单次处理的任务数量?
+
+**答**:修改 `Paper.php` 中的 limit 值:
+```php
+->limit(10) // 改为你想要的数量
+```
+
+## 十、性能优化建议
+
+1. **合理设置处理频率**:根据业务量调整定时任务频率
+2. **定期清理历史数据**:避免表数据过大影响查询性能
+3. **添加索引**:已包含 status 和 createtime 索引
+4. **监控队列积压**:及时发现和处理异常
+
+## 十一、技术支持
+
+如有问题,请查看:
+- ThinkPHP日志:`runtime/log/`
+- 工行接口日志:`runtime/icbc_log/`
+- 队列任务表:`fa_icbc_queue`
+