ProjectImport.php 7.4 KB
<?php

namespace App\Console\Commands\Import;

use App\Http\Logic\Bside\Blog\BlogLogic;
use App\Http\Logic\Bside\News\NewsLogic;
use App\Http\Logic\Bside\Product\ProductLogic;
use App\Models\Import\ImportTask;
use App\Models\Mail\Mail;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

/**
 * 导入任务异步执行
 * Class ProjectImport
 * @package App\Console\Commands
 * @author Akun
 * @date 2023/9/20 15:18
 */
class ProjectImport extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'project_import';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '执行项目导入任务';


    public function handle()
    {
        while (true) {
            $this->start_import();
        }
    }

    protected function start_import()
    {
        $task_id = $this->get_task();
        if (!$task_id) {
            sleep(2);
            return true;
        }

        $task = ImportTask::where('id', $task_id)->where('status', ImportTask::STATUS_UN)->first();
        if (!$task) {
            sleep(2);
            return true;
        }

        echo 'date:' . date('Y-m-d H:i:s') . ', task_id: ' . $task->id . ', import start' . PHP_EOL;

        $task->status = ImportTask::STATUS_ING;//导入中
        $task->save();

        $is_gbk = 0;
        $file_code_type = $this->get_code_type($task->file_url);
        if ($file_code_type === false) {
            echo 'date:' . date('Y-m-d H:i:s') . ', task_id: ' . $task->id . ', import fail, error: 文件编码格式错误' . PHP_EOL;
            $task->status = ImportTask::STATUS_COM;//导入完成
            $task->save();

            $this->send_mail($task->user_id, $task->created_at, $task->type, 0, 0, 0, '文件编码格式错误,仅支持UTF-8和GBK编码格式');
            return true;
        } elseif ($file_code_type === 'GBK') {
            $is_gbk = 1;
            setlocale(LC_ALL, 'zh_CN');
        }

        //读取csv文件
        $line_of_text = [];
        try {
            $file_handle = fopen($task->file_url, 'r');
            while (!feof($file_handle)) {
                $line_of_text[] = fgetcsv($file_handle, 0, ',');
            }
            fclose($file_handle);
        } catch (\Exception $e) {
            echo 'date:' . date('Y-m-d H:i:s') . ', task_id: ' . $task->id . ', import fail, error: ' . $e->getMessage() . PHP_EOL;
            $task->status = ImportTask::STATUS_COM;//导入完成
            $task->save();

            $this->send_mail($task->user_id, $task->created_at, $task->type, 0, 0, 0, '读取文件数据失败');
            return true;
        }

        $total_count = 0; //总条数
        $success_count = 0; //成功导入条数
        $repeat_count = 0; //过滤已存在条数
        $fail_count = 0;
        if (count($line_of_text) > 1) {

            //设置数据库
            $project = ProjectServer::useProject($task->project_id);
            if ($project) {
                foreach ($line_of_text as $k => $v) {
                    if ($k > 0 && isset($v[0]) && $v[0]) {

                        if ($is_gbk) {
                            foreach ($v as $kk => $vv) {
                                $v[$kk] = mb_convert_encoding($vv, 'utf-8', 'gbk');
                            }
                        }

                        $total_count += 1;
                        try {
                            if ($task->type == ImportTask::TYPE_NEWS) {
                                if ((new NewsLogic())->importNews($task->project_id, $task->user_id, $v)) {
                                    $success_count += 1;
                                } else {
                                    $repeat_count += 1;
                                }
                            } elseif ($task->type == ImportTask::TYPE_BLOG) {
                                if ((new BlogLogic())->importBlog($task->project_id, $task->user_id, $v)) {
                                    $success_count += 1;
                                } else {
                                    $repeat_count += 1;
                                }
                            } else {
                                if ((new ProductLogic())->importProduct($task->project_id, $task->user_id, $v)) {
                                    $success_count += 1;
                                } else {
                                    $repeat_count += 1;
                                }
                            }
                        } catch (\Exception $e) {
                            $fail_count += 1;
                            echo 'date:' . date('Y-m-d H:i:s') . ', task_id: ' . $task->id . ', title: ' . $v[0] . ', import fail, error: ' . $e->getMessage() . PHP_EOL;
                        }
                    }
                }
            }
            //关闭数据库
            DB::disconnect('custom_mysql');
        }

        $task->status = ImportTask::STATUS_COM;//导入完成
        $task->total_count = $total_count;
        $task->success_count += $success_count;
        $task->save();

        $this->send_mail($task->user_id, $task->created_at, $task->type, $success_count, $fail_count, $repeat_count, '');

        echo 'date:' . date('Y-m-d H:i:s') . ', task_id: ' . $task->id . ', import end, total count: ' . $total_count . ', success count: ' . $success_count . PHP_EOL;

        sleep(2);
    }

    //获取任务
    protected function get_task()
    {
        $key = 'console_import_task';
        $task_id = Redis::rpop($key);
        if ($task_id) {
            return $task_id;
        }

        $task_list = ImportTask::where('status', ImportTask::STATUS_UN)->limit(20)->get();
        if ($task_list->count() == 0) {
            return false;
        }

        foreach ($task_list as $value) {
            Redis::lpush($key, $value->id);
        }

        $task_id = Redis::rpop($key);
        return $task_id;
    }

    //判断编码格式
    protected function get_code_type($file)
    {
        $list = array('GBK', 'UTF-8');
        $str = file_get_contents($file);
        foreach ($list as $item) {
            $tmp = mb_convert_encoding($str, $item, $item);
            if (md5($tmp) == md5($str)) {
                return $item;
            }
        }
        return false;
    }

    //发送站内通知
    protected function send_mail($user_list, $time, $type, $success_count, $repeat_count, $fail_count, $reason)
    {
        if ($type == ImportTask::TYPE_NEWS) {
            $type_content = '新闻';
        } elseif ($type == ImportTask::TYPE_BLOG) {
            $type_content = '博客';
        } else {
            $type_content = '产品';
        }
        $title = '导入结果通知';
        $content = '您于 ' . $time . ' 添加的 ' . $type_content . ' 导入任务已执行完成, 成功导入数据:' . $success_count . ' 条';
        $repeat_count && $content .= ',过滤已存在数据:' . $repeat_count . ' 条';
        $fail_count && $content .= ',导入失败:' . $fail_count . ' 条';
        $reason && $content .= ',原因:' . $reason;

        $mail_model = new Mail();
        $mail_model->add([
            'user_list' => $mail_model->setUserList($user_list),
            'title' => $title,
            'content' => $content
        ]);
    }
}