Selaa lähdekoodia

🎨 更换图标

快乐的梦鱼 1 kuukausi sitten
vanhempi
commit
2fe021f9bf

+ 7 - 8
nuxt.config.ts

@@ -53,15 +53,14 @@ export default defineNuxtConfig({
     '/news/': { swr: 1800 },
     '/research/': { swr: 1800 },
 
-    '/introduction/**': { swr: true },
-    '/communicate/**': { swr: true },
-    '/fusion/**': { swr: true },
-    '/inheritor/**': { swr: true },
-    '/news/**': { swr: true },
-    '/research/**': { swr: true },
-    '/village/**': { swr: true },
+    '/introduction/**': { swr: false },
+    '/communicate/**': { swr: false },
+    '/fusion/**': { swr: false },
+    '/inheritor/**': { swr: false },
+    '/news/**': { swr: false },
+    '/research/**': { swr: false },
+    '/village/**': { swr: false },
     
-
     '/inheritor/submit': { ssr: false },
   }
 })

BIN
public/android-chrome-192x192.png


BIN
public/android-chrome-512x512.png


BIN
public/apple-touch-icon.png


BIN
public/favicon-16x16.png


BIN
public/favicon-32x32.png


BIN
public/favicon.ico


+ 1 - 0
public/site.webmanifest

@@ -0,0 +1 @@
+{"background_color":"#ffffff","display":"standalone","icons":[{"sizes":"192x192","src":"/android-chrome-192x192.png","type":"image/png"},{"sizes":"512x512","src":"/android-chrome-512x512.png","type":"image/png"}],"name":"","short_name":"","theme_color":"#ffffff"}

BIN
src/assets/images/Logo2.png


+ 2 - 2
src/components/Footer.vue

@@ -4,7 +4,7 @@
       <div class="row">
         <div class="col-sm-12 col-md-6">
           <div class="logo">
-            <img src="@/assets/images/LogoIcon.png" />
+            <img src="https://mn.wenlvti.net/app_static/minnan/logo-large-light.png" />
             <h2>闽南文化生态保护区 (厦门市)</h2>
           </div>
         </div>
@@ -62,7 +62,7 @@
       margin: 0;
     }
     img {
-      width: 30px;
+      width: 60px;
       height: 30px;
       margin-right: 10px;
     }

+ 3 - 3
src/components/NavBar.vue

@@ -47,7 +47,7 @@
     </div>
     <div class="group center">
       <div class="headerlogos">
-        <img class="main-clickable" src="@/assets/images/LogoIcon.png" @click="goIndex" />
+        <img class="main-clickable" src="https://mn.wenlvti.net/app_static/minnan/logo-large-light.png" @click="goIndex" />
         <div>
           <p class="large">世界闽南文化交流中心</p>
           <p>闽南文化生态保护区<span>(厦门市)</span></p>
@@ -159,7 +159,7 @@ nav.main {
     align-items: center;
 
     img {
-      width: 55px;
+      width: 95px;
       height: 55px; 
       margin-right: 10px;
     }
@@ -275,7 +275,7 @@ nav.main {
   nav.main {
     .headerlogos {
       img {
-        width: 35px;
+        width: 55px;
         height: 35px; 
         margin-right: 7px;
       }

+ 17 - 11
src/scripts/UpdateScript/index.mjs

@@ -14,6 +14,7 @@ import axios from 'axios';
 import path from 'path';
 import { dirname } from 'node:path';
 import { fileURLToPath } from 'node:url';
+import { config } from './postConfig.mjs';
 
 //基础配置
 //========================================
@@ -21,7 +22,7 @@ import { fileURLToPath } from 'node:url';
 const __filename = fileURLToPath(import.meta.url);
 const __dirname = dirname(__filename);
 const constant = {
-  ServerUrl: 'http://update-server1.imengyu.top/',
+  ServerUrl: config.server,
   TokenSave: path.resolve(__dirname, './_token.json'),
 };
 let currentData = {
@@ -29,12 +30,17 @@ let currentData = {
   identifier: '',
 };
 
-readFile(constant.TokenSave).then((res) => {
-  currentData = JSON.parse(res);
+function initIdentifier() {
   if (!currentData.identifier) 
     currentData.identifier = `commandClient${Math.floor(Math.random() * 1000)}`;
+}
+
+readFile(constant.TokenSave).then((res) => {
+  currentData = JSON.parse(res);
+  initIdentifier();
   start();
 }).catch(() => {
+  initIdentifier();
   start();
 })
 
@@ -261,13 +267,15 @@ async function getVersion(action, type) {
 //选择方法
 //========================================
 
-export async function selectVersion(requireString = false, defaultVersionId = null) {
-  const data = (await axiosInstance.get('/version/list')).data;
+export async function selectVersion(defaultVersionId = null) {
+  const data = (await axiosInstance.get('/version/list?full=true&search=' + JSON.stringify({ 
+    appId: config.appId 
+  }))).data;
   if (data.length === 0) {
     console.error('没有版本');
     return;
   }
-  const resultId = (await select({
+  const versionId = (await select({
     choices: data.map(p => ({
       value: p.id,
       name: p.version,
@@ -275,13 +283,11 @@ export async function selectVersion(requireString = false, defaultVersionId = nu
     default: defaultVersionId,
     message: '选择一个版本',
   }));
-  if (requireString) {
-    return data.find(p => p.id === resultId).version
-  }
-  return resultId;
+  const versionName = data.find(p => p.id === versionId).version;
+  return { versionId, versionName };
 }
 export async function selectUpdate() {
-  const versionId = await selectVersion();
+  const { versionId } = await selectVersion();
   const data = (await axiosInstance.get('/version/update?search=' + JSON.stringify({ versionId }))).data;
   if (data.length === 0) {
     console.error('没有更新');

+ 15 - 6
src/scripts/UpdateScript/postConfig.mjs

@@ -1,8 +1,9 @@
-import { readFileSync } from 'node:fs';
-import { pad } from './postUpdate.mjs';;
+import { readFileSync, existsSync } from 'node:fs';
 import { dirname } from 'node:path';
 import { fileURLToPath } from 'node:url';
+import { pad } from './utils.mjs';
 import path from 'node:path';
+import JSON5 from 'json5';
 
 //基础配置
 //========================================
@@ -10,11 +11,16 @@ import path from 'node:path';
 const __filename = fileURLToPath(import.meta.url);
 const __dirname = dirname(__filename);
 
+const localConfigPath = path.resolve(__dirname, './_localConfig.json');
+const localConfig = existsSync(localConfigPath) ? JSON.parse(readFileSync(localConfigPath, 'utf8')) : {};
+
 //提交更新配置
 //========================================
 
 export const config = {
+  server: localConfig.updateServer || 'https://update-server1.imengyu.top/',
   submitKey: '',
+  appId: 2,
   uploadWebConfig: {
     storageAction: 'override',
     storageProps: {
@@ -35,6 +41,9 @@ export const config = {
     ],
   },
   buildWebOutVersionPath: '', //版本号输出目录,输出版本号至文件以供项目使用。相对于当前文件目录
+  getCustomConfig: async (param, isApp, versionName) => {
+    return {}//额外的自定义配置
+  },
   /**
    * 自定义生成Web版本号的方法。
    * @param {Date} now 当前日期
@@ -46,20 +55,20 @@ export const config = {
     const version = `${now.getFullYear().toString().substring(2)}${pad(now.getMonth() + 1, 2)}${pad(now.getDate(), 2)}.${pad(lastTodaySubVersion, 2)}`;
     return version;
   },
-  buildAppCallback: async (param, versionCode, lastTodaySubVersion) => {
+  buildAppCallback: async (param, versionCode, versionName, lastTodaySubVersion) => {
     //构建App
     throw new Error('未实现buildAppCallback方法');
   }, 
-  buildAppGetUploadFile: async (param) => {
+  buildAppGetUploadFile: async (param, versionCode, versionName) => {
     //获取上传文件路径
     throw new Error('未实现buildAppGetUploadFile方法');
   }, 
-  buildAppGetOSSFileName: async (param) => {
+  buildAppGetOSSFileName: async (param, versionCode, versionName) => {
     //生成OSS保存路径
     throw new Error('buildAppGetOSSFileName');
   },//构建命令
   buildAppOutDir: './dist', //构建输出目录。相对于当前文件目录
-  buildAppGetVersion: async () => {
+  buildAppGetVersion: async (versionName) => {
     //获取版本号
     throw new Error('未实现buildAppGetVersion方法');
   },

+ 186 - 195
src/scripts/UpdateScript/postUpdate.mjs

@@ -4,16 +4,14 @@
  * Copyright © 2025 imengyu.top imengyu-update-server
  */
 
-import { confirm , input } from '@inquirer/prompts';
-import { writeFile, readFile, access, unlink, readdir, stat, constants } from 'node:fs/promises';
-import { exec } from 'node:child_process';
-import fs from 'fs';
-import archiver from 'archiver';
-import path, { resolve } from 'node:path';
+import { confirm, select, input } from '@inquirer/prompts';
+import { writeFile, readFile, access, unlink, stat, constants } from 'node:fs/promises';
+import path from 'node:path';
 import OSS from 'ali-oss';
 import cliProgress from 'cli-progress';
 import { selectVersion } from './index.mjs';
 import { config } from './postConfig.mjs';
+import { readFileRange, compressZip, execAsync } from './utils.mjs';
 import { dirname } from 'node:path';
 import { fileURLToPath } from 'node:url';
 
@@ -23,40 +21,9 @@ import { fileURLToPath } from 'node:url';
 const __filename = fileURLToPath(import.meta.url);
 const __dirname = dirname(__filename);
 
-function readFileRange(file, start, length) {
-  return new Promise((resolve, reject) => {
-    fs.open(file, 'r', (err, fd) => {
-      if (err) {
-        reject('Error opening file:', er);
-        return;
-      }
-      const buffer = Buffer.alloc(length);
-      fs.read(fd, buffer, 0, length, start, (err, bytesRead, buffer) => {
-        if (err) {
-          reject('Error reading file:', err)
-          return;
-        }
-        fs.close(fd, (err) => {
-          if (err) {
-            reject('Error closing file:', err)
-            return ;
-          }
-          resolve(buffer);
-        });
-      });
-    });
-  })
-  
-}
-export function pad(num, n) {
-  var strNum = num.toString();
-  var len = strNum.length;
-  while (len < n) {
-    strNum = "0" + strNum;
-    len++;
-  }
-  return strNum;
-}
+const UPLOAD_APP_TYPE_LOCAL = 1;
+const UPLOAD_APP_TYPE_ALI_OSS = 2;
+
 async function getConfig() {
   let postConfig = {
     lastVersion: '',
@@ -82,29 +49,114 @@ async function getUpdateInfo(postConfig) {
   let updateInfo = await input({ message: '输入更新信息', default: postConfig.lastUpdateInfo });
   if (updateInfo === 'git') {
     console.log('开始获取git提交信息');
-    updateInfo = await new Promise((resolve, reject) => {
-      exec('git log -1 --pretty=format:"%h %s"', (error, stdout, stderr) => {
-        if (error) {
-          reject(error);
-          return;
-        }
-        resolve(stdout);
-      });
-    });
-    console.log('使用git提交信息作为更新信息');
+    updateInfo = await execAsync('git log -1 --pretty=format:"%h %s"');
+    console.log('使用git提交信息 "' + updateInfo + '" 作为更新信息');
   }
   return updateInfo;
 }
+async function uploadMulitPartLarge(axiosInstance, fileInfo, filePath) {
+
+  console.log('开始分片上传');
+
+  const multuploadInfo = (await axiosInstance.post('/update-large-token', {
+    fileSize: fileInfo.size,
+    fileName: path.basename(filePath)
+  })).data;
+  const chunkSize = multuploadInfo.splitPartSize;
+
+  const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
+  bar1.start(100, 0);
+
+  for (let i = 0; i < multuploadInfo.allChunks; i++) {
+    const start = i * chunkSize;
+    const len = Math.min(start + chunkSize, fileInfo.size) - start;
+    const uploadZipContent = await readFileRange(filePath, start, len);
+    const subFormData = new FormData();
+    subFormData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
+    subFormData.append("key", multuploadInfo.key);
+    subFormData.append("info", JSON.stringify({}));
+    
+    (await axiosInstance.post('/update-large', subFormData, {
+      headers: { 'Content-Type': 'multipart/form-data' }
+    })).data;
+    
+    bar1.update(Math.floor(i / multuploadInfo.allChunks * 100));
+  }
+
+  bar1.update(100);
+  bar1.stop();
+
+  return multuploadInfo.key;
+}
+async function aliOSSMultipartUpload(client, fileName, uploadFile, progressCallback) {
+  
+  const fileInfo = await stat(uploadFile); // 获取文件信息
+  const partSize = 10 * 1024 * 1024; // 分片大小,这里使用10MB
+  const partCount = Math.ceil(fileInfo.size / partSize); // 计算总分片数
+  
+  console.log(`开始分片上传到阿里OSS,文件大小: ${(fileInfo.size / 1024 / 1024).toFixed(2)}MB,分片数: ${partCount}`);
+  
+  try {
+    // 初始化分片上传
+    const multipartUpload = await client.initMultipartUpload(fileName);
+    const uploadId = multipartUpload.uploadId;
+    
+    // 上传分片
+    const parts = [];
+    for (let i = 0; i < partCount; i++) {
+      const start = i * partSize;
+      const len = Math.min(partSize, fileInfo.size - start);
+      
+      // 读取文件分片
+      const fileData = await readFileRange(uploadFile, start, len);
+      
+      // 上传分片
+      const partResult = await client.uploadPart(fileName, fileData, uploadId, i + 1);
+      parts.push({
+        ETag: partResult.res.headers.etag,
+        PartNumber: i + 1
+      });
+      
+      // 计算并回调进度
+      const progress = (i + 1) / partCount;
+      if (progressCallback) {
+        progressCallback(progress);
+      }
+      
+      console.log(`已上传分片 ${i + 1}/${partCount} (${(progress * 100).toFixed(2)}%)`);
+    }
+    
+    // 完成分片上传
+    await client.completeMultipartUpload(fileName, uploadId, parts);
+    
+    console.log('阿里OSS分片上传完成');
+    
+    // 获取上传后的文件URL
+    const url = await client.generateObjectUrl(fileName);
+    return url;
+  } catch (error) {
+    console.error('阿里OSS分片上传失败:', error);
+    throw error;
+  }
+}
 
 //App更新与提交
 //========================================
 
 export async function postAppUpdate(axiosInstance, param) {
   const postConfig = await getConfig();
-  const versionId = await selectVersion(false, postConfig.lastVersion);
+  const { versionId, versionName } = await selectVersion(postConfig.lastVersion);
   const updateInfo = await getUpdateInfo(postConfig);
 
-  await axiosInstance.post('/update-post', { config: { type: 2, test: true, versionId, uploadWebConfig: config.uploadWebConfig, submitKey: config.submitKey } });
+  const serverConfig = await axiosInstance.post('/update-post', { 
+    config: { 
+      type: 2, 
+      test: true, 
+      versionId, 
+      uploadAppConfig: {}, 
+      submitKey: config.submitKey 
+    } 
+  });
 
   postConfig.lastVersion = versionId;
   postConfig.lastUpdateInfo = updateInfo;
@@ -126,13 +178,13 @@ export async function postAppUpdate(axiosInstance, param) {
   }));
 
   const force = await confirm({ message: '强制更新?', default: false });
-  const updateNext = hotfix ? false : await confirm({ message: '作为下个版本?', default: false });
-  const versionCode = config.buildAppGetVersion();
+  const updateNext = await confirm({ message: '作为下个版本?', default: false });
+  const versionCode = await config.buildAppGetVersion(versionName);
 
   await saveConfig(postConfig);
 
   if (updateSource === 'rebuild') 
-    await config.buildAppCallback(param, versionCode, postConfig.lastTodaySubVersion);
+    await config.buildAppCallback(param, versionCode, versionName, postConfig.lastTodaySubVersion);
   else if (updateSource === 'uploaded-alioss') {
     const fileName = await input({ message: '输入已上传的阿里OSS文件路径' });
     try {
@@ -161,7 +213,8 @@ export async function postAppUpdate(axiosInstance, param) {
     return;
   }
 
-  const uploadFile = await config.buildAppGetUploadFile(param);
+  const uploadFile = await config.buildAppGetUploadFile(param, versionCode, versionName);
+  const fileName = `${await config.buildAppGetOSSFileName(param, versionCode, path.basename(uploadFile), uploadFile)}`;
   try {
     await access(uploadFile, constants.R_OK)
   } catch {
@@ -178,12 +231,16 @@ export async function postAppUpdate(axiosInstance, param) {
 
     const formData = new FormData();
     formData.append("file", new Blob([ appData ], { type : 'application/zip' }));
-    formData.append("type", 2);
-    formData.append("versionId", versionId);
-    formData.append("updateInfo", updateInfo);
-    formData.append("uploadAppConfig", { updateAsNext: updateNext });
-    formData.append("force", force);
-    formData.append("versionCode", versionCode);
+    formData.append("config", JSON.stringify({
+      type: 2,
+      versionId,
+      versionCode,
+      updateInfo,
+      updateCustomConfig: await config.getCustomConfig(param, true, versionName),
+      uploadAppConfig: { updateAsNext: updateNext },
+      force,
+      fileName,
+    }));
 
     try {
       const result = (await axiosInstance.post('/update-post', formData, {
@@ -191,67 +248,80 @@ export async function postAppUpdate(axiosInstance, param) {
       })).data;
       console.log('上传成功');
       console.log('新更新ID: ' + result.updateId);
-      console.log('删除构建文件');
-
-      await unlink(uploadFile);
     } catch (e) {
       console.error('上传失败', e);
     }
-
   } else {
-    //阿里OSS上传
-    //请求STS进行临时授权
-    const stsToken = (await axiosInstance.post('/update-ali-oss-sts')).data;
-    const client = new OSS({
-      region: stsToken.Region,
-      accessKeyId: stsToken.AccessKeyId,
-      accessKeySecret: stsToken.AccessKeySecret,
-      stsToken: stsToken.SecurityToken,
-      bucket: stsToken.Bucket,
-      refreshSTSToken: async () => {
-        const refreshToken = (await axiosInstance.get("/update-ali-oss-sts")).data;
-        return {
-          accessKeyId: refreshToken.AccessKeyId,
-          accessKeySecret: refreshToken.AccessKeySecret,
-          stsToken: refreshToken.SecurityToken,
-        };
-      },
-    });
-    
-    //小于96mb则直接上传,否则分片上传
-    const fileName = `/${await config.buildAppGetOSSFileName(param)}`;
 
-    console.log('Start upload to ali oss');
+    let ossConfig;
+    let multuploadedKey;
+
+    if (serverConfig.uploadAppType === UPLOAD_APP_TYPE_LOCAL) {
+      //本地大文件上传
+      multuploadedKey = await uploadMulitPartLarge(axiosInstance, fileInfo, uploadFile);
+    } else if (serverConfig.uploadAppType === UPLOAD_APP_TYPE_ALI_OSS) {
+      //阿里OSS上传
+      //请求STS进行临时授权
+      const stsToken = (await axiosInstance.post('/update-ali-oss-sts')).data;
+      const client = new OSS({
+        region: stsToken.Region,
+        accessKeyId: stsToken.AccessKeyId,
+        accessKeySecret: stsToken.AccessKeySecret,
+        stsToken: stsToken.SecurityToken,
+        bucket: stsToken.Bucket,
+        refreshSTSToken: async () => {
+          const refreshToken = (await axiosInstance.get("/update-ali-oss-sts")).data;
+          return {
+            accessKeyId: refreshToken.AccessKeyId,
+            accessKeySecret: refreshToken.AccessKeySecret,
+            stsToken: refreshToken.SecurityToken,
+          };
+        },
+      });
+      
+      //小于96mb则直接上传,否则分片上传
+
+      console.log('Start upload to ali oss');
+
+      let returnUrl = '';
+      if (fileInfo.size < 96 * 1024 * 1024) {
+        const result = await client.put(fileName, uploadFile);
+        returnUrl = result.url;
+      } else {
+        const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
+        bar1.start(100, 0);
+        returnUrl = await aliOSSMultipartUpload(client, fileName, uploadFile, (p) => {
+          bar1.update(p * 100);
+        });
+        bar1.update(100);
+        bar1.stop();
+      }
 
-    let returnUrl = '';
-    if (fileInfo.size < 96 * 1024 * 1024) {
-      const result = await client.put(fileName, uploadFile);
-      returnUrl = result.url;
+      ossConfig = {
+        ossPath: fileName,
+        ossPublic: returnUrl,
+      };
+
+      console.log('Upload to ali oss done');
     } else {
-      const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
-      bar1.start(100, 0);
-      await aliOSSMultipartUpload(client, fileName, uploadFile, (p) => {
-        bar1.update(p * 100);
-      });
-      bar1.update(100);
-      bar1.stop();
+      console.error('错误的 uploadAppType 配置 ' + serverConfig.uploadAppType);
     }
-
-    console.log('Upload to ali oss done');
   
     try {
       const result = (await axiosInstance.post('/update-post', {
-        type: 2,
-        ossConfig: {
-          ossPath: fileName,
-          ossPublic: returnUrl,
+        config: {
+          type: 2,
+          ossConfig,
+          multuploadedKey,
+          uploadAppConfig: {
+            updateAsNext: updateNext,
+          },
+          updateCustomConfig: await config.getCustomConfig(param, true, versionName),
+          versionId,
+          updateInfo,
+          versionCode: versionCode,
+          fileName
         },
-        uploadAppConfig: {
-          updateAsNext: updateNext,
-        },
-        versionId,
-        updateInfo,
-        versionCode: versionCode
       })).data;
       console.log('上传成功');
       console.log('新更新ID: ' + result.updateId);
@@ -269,7 +339,7 @@ export async function postWebUpdate(axiosInstance, param) {
   const noDelete = param.ndelete;
   
   const postConfig = await getConfig();
-  const versionId = await selectVersion(false, postConfig.lastVersion);
+  const { versionId, versionName } = await selectVersion(postConfig.lastVersion);
   const updateInfo = await getUpdateInfo(postConfig);
 
   postConfig.lastVersion = versionId;
@@ -288,16 +358,7 @@ export async function postWebUpdate(axiosInstance, param) {
   
   if (!skipBuild && config.buildWebCommand) {
     console.log('正在执行构建...');
-
-    await new Promise((resolve, reject) => {
-      exec(config.buildWebCommand, function(err, stdout) {
-        if (err)
-          reject(err);
-        else 
-          resolve();
-      });
-    });
-
+    await execAsync(config.buildWebCommand);
     console.log('构建完成');
   }
 
@@ -313,52 +374,9 @@ export async function postWebUpdate(axiosInstance, param) {
   const outputPath = __dirname + '/upload.zip';
   const skipFiles = config?.buildWebOptions?.skipFiles ?? [];
 
-  function checkPathSkip(path) {
-    if (!skipFiles || skipFiles.length === 0)
-      return;
-    return skipFiles.find((item) => path.startsWith(item));
-  }
-
   if (!skipBuild) {
     console.log('开始压缩zip...');
-
-    const output = fs.createWriteStream(outputPath);
-    const archive = archiver('zip', {
-      zlib: { level: 9 } // Sets the compression level.
-    });
-    archive.pipe(output);
-
-    async function loopDir(path, subPrefix) {
-      const files = await readdir(path);
-      for (const file of files) {
-        const subPath = subPrefix + '/' + file;
-        if (checkPathSkip(subPath))
-          continue;
-        const filestat = await stat(distDir + subPath);
-        if (filestat.isDirectory()) {
-          await loopDir(distDir + subPath, subPath);
-        } else {
-          archive.file(distDir + subPath, { name: subPath });
-        }
-      }
-    }
-    await loopDir(distDir, '')
-
-    console.log('等待压缩zip...');
-
-    const waitArchive = new Promise((resolve, reject) => {
-      output.on('close', function() {
-        console.log(archive.pointer() + ' total bytes');
-        console.log('archiver has been finalized and the output file descriptor has closed.');
-        resolve();
-      });
-      archive.on('error', function(err) {
-        reject(err);
-      });
-    })
-
-    await archive.finalize();
-    await waitArchive;
+    await compressZip(distDir, outputPath, skipFiles);
   }
 
   console.log('开始上传zip');
@@ -374,41 +392,14 @@ export async function postWebUpdate(axiosInstance, param) {
     updateInfo,
     versionCode,
     uploadWebConfig: config.uploadWebConfig,
+    updateCustomConfig: await config.getCustomConfig(param, true, versionName),
   }
 
   if (fileInfo.size < 8 * 1024 * 1024) {
     const uploadZipContent = await readFile(outputPath);
     formData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
   } else {
-    const multuploadInfo = (await axiosInstance.post('/update-large-token', {
-      fileSize: fileInfo.size,
-      fileName: path.basename(outputPath)
-    })).data;
-    const chunkSize = multuploadInfo.splitPartSize;
-
-    const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
-    bar1.start(100, 0);
-
-    for (let i = 0; i < multuploadInfo.allChunks; i++) {
-      const start = i * chunkSize;
-      const len = Math.min(start + chunkSize, fileInfo.size) - start;
-      const uploadZipContent = await readFileRange(outputPath, start, len);
-      const subFormData = new FormData();
-      subFormData.append("file", new Blob([ uploadZipContent ], { type : 'application/zip' }), 'upload.zip');
-      subFormData.append("key", multuploadInfo.key);
-      subFormData.append("info", JSON.stringify({}));
-      
-      (await axiosInstance.post('/update-large', subFormData, {
-        headers: { 'Content-Type': 'multipart/form-data' }
-      })).data;
-      
-      bar1.update(Math.floor(i / multuploadInfo.allChunks * 100));
-    }
-
-    bar1.update(100);
-    bar1.stop();
-
-    submitConfig.multuploadedKey = multuploadInfo.key;
+    submitConfig.multuploadedKey = await uploadMulitPartLarge(axiosInstance, fileInfo, outputPath);
   }
 
   try {