diff --git a/src/downloadworker.cpp b/src/downloadworker.cpp
new file mode 100644
index 0000000..8ca0a13
--- /dev/null
+++ b/src/downloadworker.cpp
@@ -0,0 +1,234 @@
+#include "downloadworker.h"
+#include <QIODevice>
+#include <QEventLoop>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QDebug>
+#include <QThread>
+
+DownloadWorker::DownloadWorker(QObject *parent)
+{
+
+}
+
+void DownloadWorker::setIdentifier(int identifier)
+{
+    this->identifier = identifier;
+}
+
+void DownloadWorker::setParamter(const QString &url, QPair<qint64, qint64> range, QFile *file)
+{
+    this->url = url;
+    this->startPos = range.first;
+    this->endPos = range.second;
+    this->file = file;
+}
+
+qint64 DownloadWorker::getReceivedPos()
+{
+    return receivedPos;
+}
+
+void DownloadWorker::doWork()
+{
+        mgr = new QNetworkAccessManager(this);
+        QNetworkRequest request;
+        request.setUrl(url);
+        request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+        request.setRawHeader("Range", QString("bytes=%1-%2").arg(startPos)
+                    .arg(endPos).toLocal8Bit());
+        reply = mgr->get(request);
+        qDebug() << "开始下载数据:" << QString(" %1~%2 -> writePos Start %3")
+            .arg(startPos).arg(endPos).arg(receivedPos);
+        connect(reply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
+        [this](QNetworkReply::NetworkError error){
+            if (error != QNetworkReply::NoError) {
+                qDebug() << "出错了:" << reply->errorString();
+            }
+        });
+        connect(reply, &QNetworkReply::finished, mgr, &QNetworkAccessManager::deleteLater);
+        connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
+        connect(reply, &QNetworkReply::readyRead, this, &DownloadWorker::dataReady);
+        connect(reply, &QNetworkReply::finished, this, &DownloadWorker::slotFinish);
+        connect(reply, &QNetworkReply::downloadProgress, this, &DownloadWorker::handleProcess);
+
+}
+
+void DownloadWorker::doStop()
+{
+    reply->disconnect();
+    reply->aboutToClose();
+    reply->deleteLater();
+    reply = nullptr;
+}
+
+void DownloadWorker::dataReady()
+{
+    QByteArray data = reply->readAll();
+    file->seek(startPos + receivedPos);
+    file->write(data);
+    receivedPos += data.size();
+}
+
+void DownloadWorker::slotFinish()
+{
+    file->flush();
+    qDebug() << "数据块下载完毕:" << QString(" %1~%2 -> writePos Start %3")
+        .arg(startPos).arg(endPos).arg(receivedPos);
+    emit workFinished();
+}
+
+void DownloadWorker::handleProcess(qint64, qint64)
+{
+    emit this->downloadProcess();
+}
+
+
+DownloadController::DownloadController(QObject *parent)
+{
+    this->threadNum = QThread::idealThreadCount() > 4 ? 4 : QThread::idealThreadCount();
+}
+
+DownloadController::~DownloadController()
+{
+    for(int i = 0; i < workers.size(); i++) {
+        workers.at(i)->doStop();
+        workers.at(i)->disconnect();
+        workers.at(i)->deleteLater();
+    }
+    workers.clear();
+}
+
+void DownloadController::setFilename(QString filename)
+{
+    this->filename = filename;
+}
+
+void DownloadController::setThreadNum(int threadNum)
+{
+    this->threadNum = threadNum;
+}
+
+/**
+ * @brief 开始下载
+ */
+void DownloadController::startDownload(const QString &url)
+{
+    // 下载任务等分,计算每个线程的下载数据
+    fileSize = getFileSize(url);
+    if (fileSize == 0) {
+        emit errorOccur("文件大小获取失败");
+        return; 
+    }
+    qint64 segmentSize = fileSize / threadNum;
+    ranges.resize(threadNum);
+    QVector<qint64> receivedBytes;
+    receivedBytes.resize(threadNum);
+    for (int i = 0; i < threadNum; i++) {
+        ranges[i].first = i * segmentSize;
+        ranges[i].second = i * segmentSize + segmentSize - 1;
+        receivedBytes[i] = 0;
+    }
+    ranges[threadNum-1].second = fileSize; // 余数部分加入最后一个
+
+    // 打开文件
+    file = new QFile;
+    file->setFileName(filename);
+    if (file->exists())
+        file->remove();
+    if (!file->open(QIODevice::WriteOnly)) {
+        delete file;
+        file = nullptr;
+        emit errorOccur(file->errorString());
+        return;
+    }
+    file->resize(fileSize);
+
+    // 创建下载线程
+    workers.clear();
+    for(int i = 0; i < ranges.size(); i++) {
+        qDebug() << QString("第%1个下载请求:%2-%3").arg(i).arg(ranges.at(i).first).arg(ranges.at(i).second);
+        auto worker = new DownloadWorker(this);
+        auto range = ranges.at(i);
+        worker->setIdentifier(i);
+        worker->setParamter(url, range, file);
+        workers.append(worker);
+        connect(worker, &DownloadWorker::downloadProcess, this, &DownloadController::handleProcess);
+        connect(worker, &DownloadWorker::workFinished, this, &DownloadController::chunkDownloadFinish);
+        worker->doWork();
+    }
+}
+
+/**
+ * @brief 停止下载
+ */
+void DownloadController::stopDownload()
+{
+    for(int i = 0; i < workers.size(); i++) {
+        workers.at(i)->doStop();
+        workers.at(i)->disconnect();
+        workers.at(i)->deleteLater();
+    }
+    workers.clear();
+//    file->flush();
+    file->close();
+    delete file;
+    file = nullptr;
+}
+
+
+void DownloadController::handleProcess()
+{
+    qint64 bytesReceived = 0;
+    for(int i = 0; i < workers.size(); i++) {
+        bytesReceived += workers.at(i)->getReceivedPos();
+    }
+    qDebug() << QString("下载进度 %1-%2").arg(bytesReceived).arg(fileSize);
+    emit downloadProcess(bytesReceived, fileSize);
+}
+
+void DownloadController::chunkDownloadFinish()
+{
+    finish++;
+    if (finish == threadNum) {
+        file->flush();
+        file->close();
+        delete file;
+        file = nullptr;
+        for(int i = 0; i < workers.size(); i++) {
+            workers.at(i)->doStop();
+            workers.at(i)->disconnect();
+            workers.at(i)->deleteLater();
+        }
+        workers.clear();
+        emit downloadFinished();
+    }
+}
+
+qint64 DownloadController::getFileSize(const QString& url)
+{
+    QEventLoop event;
+    QNetworkAccessManager requestManager;
+    QNetworkRequest request;
+    request.setUrl(QUrl(url));
+    request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+    QNetworkReply *reply = requestManager.head(request);
+    connect(reply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
+    [this, reply](QNetworkReply::NetworkError error){
+        if (error != QNetworkReply::NoError) {
+            emit errorOccur(reply->errorString());
+        }
+    });
+    connect(reply, &QNetworkReply::finished, &event, &QEventLoop::quit);
+    event.exec();
+    qint64 fileSize = 0;
+    if (reply->rawHeader("Accept-Ranges") == QByteArrayLiteral("bytes")
+            && reply->hasRawHeader(QString("Content-Length").toLocal8Bit())) {
+        fileSize = reply->header(QNetworkRequest::ContentLengthHeader).toUInt();
+    }
+    qDebug() << "文件大小为:" << fileSize;
+    reply->deleteLater();
+    return fileSize;
+}
+
diff --git a/src/downloadworker.h b/src/downloadworker.h
new file mode 100644
index 0000000..8e719d6
--- /dev/null
+++ b/src/downloadworker.h
@@ -0,0 +1,73 @@
+#ifndef DOWNLOADWORKER_H
+#define DOWNLOADWORKER_H
+
+#include <QObject>
+#include <QList>
+#include <QFile>
+#include <QNetworkReply>
+
+class DownloadWorker : public QObject
+{
+    Q_OBJECT
+public:
+    explicit DownloadWorker(QObject *parent = nullptr);
+    void setIdentifier(int identifier);
+    void setParamter(const QString &url, QPair<qint64, qint64> range, QFile *flle);
+    qint64 getReceivedPos();
+
+public slots:
+    void doWork();
+    void doStop();
+    void dataReady();
+    void slotFinish();
+    void handleProcess(qint64, qint64);
+
+signals:
+    void resultReady(int identifier, QByteArray data);
+    void testSignals();
+    void workFinished();
+    void downloadProcess();
+
+private:
+    int identifier;
+    QString url;
+    qint64 startPos;
+    qint64 endPos;
+    qint64 receivedPos = 0;
+    QNetworkReply *reply;
+    QNetworkAccessManager *mgr;
+    QFile *file;
+};
+
+class DownloadController : public QObject
+{
+    Q_OBJECT
+public:
+    explicit DownloadController(QObject *parent = nullptr);
+    ~DownloadController();
+    void setFilename(QString filename);
+    void setThreadNum(int threadNum);
+    void startDownload(const QString &url);
+    void stopDownload();
+    qint64 getFileSize(const QString& url);
+
+public slots:    
+    void handleProcess();
+    void chunkDownloadFinish();
+
+signals:
+    void errorOccur(const QString& msg);
+    void downloadProcess(qint64, qint64);
+    void downloadFinished();
+
+private:
+    int threadNum;
+    QString filename;
+    qint64 fileSize;
+    QVector<QPair<qint64, qint64>> ranges;
+    QFile *file;
+    QList<DownloadWorker*> workers;
+    int finish = 0;
+};
+
+#endif // FILEDOWNLOADWORKER_H
diff --git a/src/spark-store.pro b/src/spark-store.pro
index 09c2bbe..14407ec 100644
--- a/src/spark-store.pro
+++ b/src/spark-store.pro
@@ -27,6 +27,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
 
 SOURCES += main.cpp\
     appitem.cpp \
+    downloadworker.cpp \
     widget.cpp \
     downloadlist.cpp \
     image_show.cpp \
@@ -37,6 +38,7 @@ SOURCES += main.cpp\
 
 HEADERS  += \
     appitem.h \
+    downloadworker.h \
     widget.h \
     downloadlist.h \
     image_show.h \
diff --git a/src/widget.cpp b/src/widget.cpp
index 796dacf..d7f3f89 100644
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -33,6 +33,7 @@
 #include "HttpClient.h"
 #include "appitem.h"
 #include "flowlayout.h"
+#include "downloadworker.h"
 
 DWIDGET_USE_NAMESPACE
 
@@ -48,6 +49,8 @@ Widget::Widget(DBlurEffectWidget *parent) :
     m_loadweb->show();
 
     httpClient = new AeaQt::HttpClient;
+    // 并发下载
+    downloadController = new DownloadController(this);
 
     connect(ui->menu_main,&QPushButton::clicked,[=](){Widget::chooseLeftMenu(0);});
     connect(ui->menu_network,&QPushButton::clicked,[=](){Widget::chooseLeftMenu(1);});
@@ -72,6 +75,7 @@ Widget::Widget(DBlurEffectWidget *parent) :
     connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::finishedScreenshotLoad, this, &Widget::sltAppinfoScreenshot, Qt::ConnectionType::BlockingQueuedConnection);
     connect(&appinfoLoadThread, &SpkAppInfoLoaderThread::finishAllLoading, this, &Widget::sltAppinfoFinish, Qt::ConnectionType::BlockingQueuedConnection);
 
+
     // 搜索事件
     connect(searchEdit, &DSearchEdit::returnPressed, this, [=]()
     {
@@ -705,31 +709,41 @@ void Widget::on_pushButton_download_clicked()
     system("cp icon.png icon_"+QString::number(allDownload-1).toUtf8()+".png");
     download_list[allDownload-1].seticon(icon);
     if(!isBusy){
-        file = new QFile(fileName);
-        if(!file->open(QIODevice::WriteOnly)){
-            delete file;
-            file = nullptr;
-            return ;
-        }
+//        file = new QFile(fileName);
+//        if(!file->open(QIODevice::WriteOnly)){
+//            delete file;
+//            file = nullptr;
+//            return ;
+//        }
+
         nowDownload+=1;
-        startRequest(urList.at(nowDownload-1)); // 进行链接请求
+
+        startRequest(urList.at(nowDownload-1), fileName); // 进行链接请求
     }
     if(ui->pushButton_download->text()==tr("Reinstall")){
         download_list[allDownload-1].reinstall=true;
     }
 }
 
-void Widget::startRequest(QUrl url)
+void Widget::startRequest(QUrl url, QString fileName)
 {
     ui->listWidget->show();
     ui->label->hide();
     isBusy=true;
     isdownload=true;
     download_list[allDownload-1].free=false;
-    reply = manager->get(QNetworkRequest(url));
-    connect(reply,SIGNAL(finished()),this,SLOT(httpFinished()));
-    connect(reply,SIGNAL(readyRead()),this,SLOT(httpReadyRead()));
-    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(updateDataReadProgress(qint64,qint64)));
+
+//    reply = manager->get(QNetworkRequest(url));
+//    connect(reply,SIGNAL(finished()),this,SLOT(httpFinished()));
+//    connect(reply,SIGNAL(readyRead()),this,SLOT(httpReadyRead()));
+//    connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(updateDataReadProgress(qint64,qint64)));
+    connect(downloadController, &DownloadController::downloadProcess, this, &Widget::updateDataReadProgress);
+    connect(downloadController, &DownloadController::downloadFinished, this, &Widget::httpFinished);
+    connect(downloadController, &DownloadController::errorOccur, [this](QString msg){
+        this->sendNotification(msg);
+    });
+    downloadController->setFilename(fileName);
+    downloadController->startDownload(url.toString());
 }
 
 void Widget::searchApp(QString text)
@@ -846,6 +860,8 @@ void Widget::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
     download_list[nowDownload-1].setValue((bytesRead*10000)/totalBytes);    // 当前值
     download_size=bytesRead;
     if(download_list[nowDownload-1].close){ // 随时检测下载是否被取消
+        downloadController->disconnect();
+        downloadController->stopDownload();
         download_list[nowDownload-1].closeDownload();
         httpFinished();
     }
@@ -958,12 +974,12 @@ void Widget::sltAppinfoFinish()
 
 void Widget::httpFinished() // 完成下载
 {
-    file->flush();
-    file->close();
-    reply->deleteLater();
-    reply = nullptr;
-    delete file;
-    file = nullptr;
+//    file->flush();
+//    file->close();
+//    reply->deleteLater();
+//    reply = nullptr;
+//    delete file;
+//    file = nullptr;
     isdownload=false;
     isBusy=false;
     download_list[nowDownload-1].readyInstall();
@@ -974,14 +990,14 @@ void Widget::httpFinished() // 完成下载
             nowDownload+=1;
         }
         QString fileName=download_list[nowDownload-1].getName();
-        file = new QFile(fileName);
-        if(!file->open(QIODevice::WriteOnly))
-        {
-            delete file;
-            file = nullptr;
-            return ;
-        }
-        startRequest(urList.at(nowDownload-1));
+//        file = new QFile(fileName);
+//        if(!file->open(QIODevice::WriteOnly))
+//        {
+//            delete file;
+//            file = nullptr;
+//            return ;
+//        }
+        startRequest(urList.at(nowDownload-1), fileName);
     }
 }
 
@@ -1269,6 +1285,7 @@ void Widget::on_webEngineView_urlChanged(const QUrl &arg1)
         ui->pushButton_download->setEnabled(false);
         ui->stackedWidget->setCurrentIndex(2);
         qDebug()<<"https://demo-one-vert.vercel.app/"+type_name+"/"+pname;
+        qDebug()<< "链接地址:" << arg1;
         /*
         load.cancel();//打开并发加载线程前关闭正在执行的线程
         load = QtConcurrent::run([=](){
diff --git a/src/widget.h b/src/widget.h
index a1a1bf7..80f3e23 100644
--- a/src/widget.h
+++ b/src/widget.h
@@ -39,6 +39,7 @@ class Widget;
 
 
 class FlowLayout;
+class DownloadController;
 
 namespace AeaQt {
     class HttpClient;
@@ -51,7 +52,7 @@ class Widget : public DBlurEffectWidget
 public:
     explicit Widget(DBlurEffectWidget *parent = nullptr);
     ~Widget();
-    void startRequest(QUrl url);
+    void startRequest(QUrl url, QString fileName);
     void searchApp(QString);
     int nowDownload=0;
     int allDownload=0;
@@ -163,6 +164,7 @@ private:
     AeaQt::HttpClient *httpClient;
     FlowLayout *applist_grid;
     QHBoxLayout *main;
+    DownloadController *downloadController;
 };
 
 #endif // WIDGET_H