From 6779a89c5778ec7b1c91702f39709594f1f180b8 Mon Sep 17 00:00:00 2001
From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com>
Date: Sun, 6 Jul 2025 02:23:12 +0900
Subject: [PATCH 1/2] =?UTF-8?q?=E6=9B=B4=E5=BF=AB=E5=AF=BC=E5=85=A5?=
=?UTF-8?q?=E8=85=B3=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/confirm/main.tsx | 16 +-
src/pages/import/App.tsx | 469 ++++++++++++++++++++-----------------
src/pages/import/main.tsx | 16 +-
src/pages/install/main.tsx | 16 +-
src/pages/options/main.tsx | 16 +-
src/pages/popup/main.tsx | 20 +-
src/pkg/backup/import.ts | 5 +-
src/pkg/backup/struct.ts | 14 ++
8 files changed, 320 insertions(+), 252 deletions(-)
diff --git a/src/pages/confirm/main.tsx b/src/pages/confirm/main.tsx
index c46c85b52..ccdd40f27 100644
--- a/src/pages/confirm/main.tsx
+++ b/src/pages/confirm/main.tsx
@@ -19,12 +19,14 @@ const loggerCore = new LoggerCore({
loggerCore.logger().debug("confirm page start");
+const Root = (
+
+
+
+
+
+);
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
-
-
-
-
-
-
+ process.env.NODE_ENV === "development" ? {Root} : Root
);
diff --git a/src/pages/import/App.tsx b/src/pages/import/App.tsx
index 57ea41c21..b6ce6880f 100644
--- a/src/pages/import/App.tsx
+++ b/src/pages/import/App.tsx
@@ -1,102 +1,260 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useState, useCallback } from "react";
import { Button, Card, Checkbox, Divider, List, Message, Space, Switch, Typography } from "@arco-design/web-react";
import { useTranslation } from "react-i18next"; // 导入react-i18next的useTranslation钩子
import JSZip from "jszip";
-import { ScriptBackupData, ScriptOptions, SubscribeBackupData } from "@App/pkg/backup/struct";
+import { ScriptOptions, ScriptData, SubscribeData } from "@App/pkg/backup/struct";
import { prepareScriptByCode } from "@App/pkg/utils/script";
-import { Script, SCRIPT_STATUS_DISABLE, SCRIPT_STATUS_ENABLE, ScriptDAO } from "@App/app/repo/scripts";
-import { Subscribe } from "@App/app/repo/subscribe";
+import { SCRIPT_STATUS_DISABLE, SCRIPT_STATUS_ENABLE, ScriptDAO } from "@App/app/repo/scripts";
import Cache from "@App/app/cache";
import CacheKey from "@App/app/cache_key";
import { parseBackupZipFile } from "@App/pkg/backup/utils";
-import { resourceClient, scriptClient, synchronizeClient, valueClient } from "../store/features/script";
+import { scriptClient, synchronizeClient, valueClient } from "../store/features/script";
+import { sleep } from "@App/pkg/utils/utils";
-type ScriptData = ScriptBackupData & {
- script?: { script: Script; oldScript?: Script };
- install: boolean;
- error?: string;
-};
-
-type SubscribeData = SubscribeBackupData & {
- subscribe?: Subscribe;
- install: boolean;
-};
+const ScriptListItem = React.memo(
+ ({
+ item,
+ index,
+ t,
+ onToggle,
+ onStatusToggle,
+ }: {
+ item: ScriptData;
+ index: number;
+ t: (a: string) => string,
+ onToggle: (index: number) => () => void;
+ onStatusToggle: (index: number, checked: boolean) => void;
+ }) => {
+ return (
+
+
+
+ {item.script?.script?.name || item.error || t("unknown")}
+
+ {t("author")}: {item.script?.script?.metadata.author?.[0]}
+ {t("description")}: {item.script?.script?.metadata.description?.[0]}
+ {t("source")}: {item.options?.meta.file_url || t("local_creation")}
+
+ {t("operation")}: {(item.install && (item.script?.oldScript ? t("update") : t("add_new"))) ||
+ (item.error ? `${t("error")}: ${item.options?.meta.name} - ${item.options?.meta.uuid}` : t("no_operation"))}
+
+
+
+
{t("enable_script")}
+
+ onStatusToggle(index, checked)}
+ />
+
+
+
+ );
+ }
+);
function App() {
const [scripts, setScripts] = useState([]);
- const [subscribes, setSubscribe] = useState([]);
+ const [subscribes, setSubscribes] = useState([]);
const [selectAll, setSelectAll] = useState([true, true]);
const [installNum, setInstallNum] = useState([0, 0]);
const [loading, setLoading] = useState(true);
- const url = new URL(window.location.href);
- const uuid = url.searchParams.get("uuid") || "";
const { t } = useTranslation(); // 使用useTranslation钩子获取翻译函数
- useEffect(() => {
- Cache.getInstance()
- .get(CacheKey.importFile(uuid))
- .then(async (resp: { filename: string; url: string }) => {
- // 使用缓存优化脚本加载速度
- const scriptDAO = new ScriptDAO();
- scriptDAO.enableCache();
+ const fetchData = async () => {
+ try {
+
+ const url = new URL(window.location.href);
+ const uuid = url.searchParams.get("uuid") || "";
+ const resp: { filename: string; url: string } = await Cache.getInstance().get(CacheKey.importFile(uuid));
+ const filedata = await fetch(resp.url).then((resp) => resp.blob());
+ const zip = await JSZip.loadAsync(filedata);
+ const backData = await parseBackupZipFile(zip);
+ const backDataScript = backData.script as ScriptData[];
- const filedata = await fetch(resp.url).then((resp) => resp.blob());
- const zip = await JSZip.loadAsync(filedata);
- const backData = await parseBackupZipFile(zip);
- const backDataScript = backData.script as ScriptData[];
- setScripts(backDataScript);
- // 获取各个脚本现在已经存在的信息
- const result = await Promise.all(
- backDataScript.map(async (item) => {
- try {
- const prepareScript = await prepareScriptByCode(
- item.code,
- item.options?.meta.file_url || "",
- item.options?.meta.sc_uuid || undefined,
- true,
- scriptDAO
- );
- item.script = prepareScript;
- } catch (e: any) {
- item.error = e.toString();
- return item;
- }
- if (!item.options) {
- item.options = {
- options: {} as ScriptOptions,
- meta: {
- name: item.script?.script.name,
- // 此uuid是对tm的兼容处理
- uuid: item.script?.script.uuid,
- sc_uuid: item.script?.script.uuid,
- file_url: item.script?.script.downloadUrl || "",
- modified: item.script?.script.createtime,
- subscribe_url: item.script?.script.subscribeUrl,
- },
- settings: {
- enabled:
- item.enabled === false
- ? false
- : !(item.script?.script.metadata.background || item.script?.script.metadata.crontab),
- position: item.script?.script.sort,
- },
- };
- }
- item.script.script.sort = item.options.settings.position || 0;
- item.script.script.status =
- item.enabled !== false && item.options.settings.enabled ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE;
- item.install = true;
+ // 使用缓存优化脚本加载速度
+ const scriptDAO = new ScriptDAO();
+ scriptDAO.enableCache();
+
+ // setScripts(backDataScript);
+ // 获取各个脚本现在已经存在的信息
+ await Promise.all(
+ backDataScript.map(async (item) => {
+ try {
+ const prepareScript = await prepareScriptByCode(
+ item.code,
+ item.options?.meta.file_url || "",
+ item.options?.meta.sc_uuid || undefined,
+ true,
+ scriptDAO
+ );
+ item.script = prepareScript;
+ } catch (e: any) {
+ item.error = e.toString();
return item;
- })
- );
- setScripts(result);
- setSelectAll([true, true]);
- setLoading(false);
- })
- .catch((e) => {
- Message.error(`获取导入文件失败: ${e}`);
+ }
+ if (!item.options) {
+ item.options = {
+ options: {} as ScriptOptions,
+ meta: {
+ name: item.script?.script.name,
+ // 此uuid是对tm的兼容处理
+ uuid: item.script?.script.uuid,
+ sc_uuid: item.script?.script.uuid,
+ file_url: item.script?.script.downloadUrl || "",
+ modified: item.script?.script.createtime,
+ subscribe_url: item.script?.script.subscribeUrl,
+ },
+ settings: {
+ enabled:
+ item.enabled === false
+ ? false
+ : !(item.script?.script.metadata.background || item.script?.script.metadata.crontab),
+ position: item.script?.script.sort,
+ },
+ };
+ }
+ item.script.script.sort = item.options.settings.position || 0;
+ item.script.script.status =
+ item.enabled !== false && item.options.settings.enabled ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE;
+ item.install = true;
+ return item;
+ })
+ );
+ const results = backDataScript.slice().sort((a, b) => {
+ const aName = a.script?.script?.name || '';
+ const bName = b.script?.script?.name || '';
+ if (aName && bName) return aName.localeCompare(bName);
+ return 0;
});
+ setScripts(results);
+ setSelectAll([true, true]);
+ setLoading(false);
+ } catch (e) {
+ Message.error(`获取导入文件失败: ${e}`);
+ }
+ };
+
+ useEffect(() => {
+ fetchData();
+ }, []);
+
+ const scriptImportAsync = async (item: ScriptData) => {
+ try {
+ await sleep(1);
+ await scriptClient.install(item.script?.script!, item.code);
+ await Promise.all([
+ (async () => { // 导入资源
+ if (!item.requires || !item.resources || !item.requiresCss) return;
+ if (!item.requires[0] && !item.resources[0] && !item.requiresCss[0]) return;
+ await sleep(((Math.random() * 600) | 0) + 200);
+ await synchronizeClient.importResources(
+ item.script?.script.uuid,
+ item.requires,
+ item.resources,
+ item.requiresCss
+ );
+ })(),
+ (async () => { // 导入数据
+ const { data } = item.storage;
+ const entries = Object.entries(data);
+ if (entries.length === 0) return;
+ await sleep(((Math.random() * 600) | 0) + 200);
+ for (const [key, value] of entries) {
+ await valueClient.setScriptValue(item.script?.script.uuid!, key, value);
+ }
+ })()
+ ]);
+ await sleep(1);
+ setInstallNum((prev) => [prev[0] + 1, prev[1]]);
+ } catch (e) {
+ // 跳過失敗
+ }
+ }
+
+ const importScripts = useCallback(async (scripts: ScriptData[]) => {
+ const promises: Promise[] = [];
+ for (const item of scripts) {
+ if (item.install && !item.error) {
+ promises.push(scriptImportAsync(item));
+ }
+ }
+ return Promise.all(promises);
+ }, []);
+
+ const importButtonClick = useCallback((scripts: ScriptData[]) => async () => {
+ setInstallNum((prev) => [0, prev[1]]);
+ setLoading(true);
+ await importScripts(scripts);
+ setLoading(false);
+ Message.success(t("import_success")!);
+ }, []);
+
+ const handleSelectAllScripts = useCallback(() => {
+ setSelectAll((prev) => {
+ const newValue = !prev[0];
+ setScripts((prevScripts) => prevScripts.map((script) => ({ ...script, install: newValue })));
+ return [newValue, prev[1]];
+ });
}, []);
+
+ const handleSelectAllSubscribes = useCallback(() => {
+ setSelectAll((prev) => {
+ const newValue = !prev[1];
+ setSubscribes((prevSubscribes) => prevSubscribes.map((subscribe) => ({ ...subscribe, install: newValue })));
+ return [prev[0], newValue];
+ });
+ }, []);
+
+ const handleScriptToggle = useCallback((index: number) => {
+ setScripts((prevScripts) => {
+ const newScripts = [...prevScripts];
+ newScripts[index] = { ...newScripts[index], install: !newScripts[index].install };
+ setSelectAll((prev) => [newScripts.every((script) => script.install), prev[1]]);
+ return newScripts;
+ });
+ }, []);
+
+ const handleScriptToggleClick = useCallback((index: number) => () => {
+ handleScriptToggle(index);
+ }, [handleScriptToggle]);
+
+ const handleSubscribeToggle = useCallback((index: number) => {
+ setSubscribes((prevSubscribes) => {
+ const newSubscribes = [...prevSubscribes];
+ newSubscribes[index] = { ...newSubscribes[index], install: !newSubscribes[index].install };
+ setSelectAll((prev) => [prev[0], newSubscribes.every((subscribe) => subscribe.install)]);
+ return newSubscribes;
+ });
+ }, []);
+
+ const handleScriptStatusToggle = useCallback((index: number, checked: boolean) => {
+ setScripts((prevScripts) => {
+ const newScripts = [...prevScripts];
+ newScripts[index] = {
+ ...newScripts[index],
+ script: {
+ ...newScripts[index].script!,
+ script: {
+ ...newScripts[index].script!.script,
+ status: checked ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE,
+ },
+ },
+ };
+ return newScripts;
+ });
+ }, []);
+
return (
@@ -105,35 +263,7 @@ function App() {
@@ -143,18 +273,7 @@ function App() {
{t("select_scripts_to_import")}:{" "}
- {
- setScripts((prev) => {
- setSelectAll([!selectAll[0], selectAll[1]]);
- return prev.map((item) => {
- item.install = !selectAll[0];
- return item;
- });
- });
- }}
- >
+
{t("select_all")}
@@ -162,102 +281,30 @@ function App() {
{t("select_subscribes_to_import")}:{" "}
- {
- setSubscribe((prev) => {
- setSelectAll([selectAll[0], !selectAll[1]]);
- return prev.map((item) => {
- item.install = !selectAll[1];
- return item;
- });
- });
- }}
- >
+
{t("select_all")}
{t("subscribe_import_progress")}: {installNum[1]}/{subscribes.length}
- (
- {
- const install = item.install;
- setScripts((prev) => {
- prev[index].install = !install;
- return [...prev];
- });
- }}
- >
-
-
- {item.script?.script?.name || item.error || t("unknown")}
-
-
- {t("author")}: {item.script?.script?.metadata.author && item.script?.script?.metadata.author[0]}
-
-
- {t("description")}:{" "}
- {item.script?.script?.metadata.description && item.script?.script?.metadata.description[0]}
-
-
- {t("source")}: {item.options?.meta.file_url || t("local_creation")}
-
-
- {t("operation")}:{" "}
- {(item.install && (item.script?.oldScript ? t("update") : t("add_new"))) ||
- (item.error
- ? `${t("error")}: ${item.options?.meta.name} - ${item.options?.meta.uuid}`
- : t("no_operation"))}
-
-
-
-
{t("enable_script")}
-
- {
- setScripts((prev) => {
- prev[index].script!.script.status = checked ? SCRIPT_STATUS_ENABLE : SCRIPT_STATUS_DISABLE;
- return [...prev];
- });
- }}
- />
-
-
-
- )}
- />
+ {scripts.length > 0 && (
+ (
+
+ )}
+ />
+ )}
diff --git a/src/pages/import/main.tsx b/src/pages/import/main.tsx
index b32295bf7..0b6bf0ea3 100644
--- a/src/pages/import/main.tsx
+++ b/src/pages/import/main.tsx
@@ -19,12 +19,14 @@ const loggerCore = new LoggerCore({
loggerCore.logger().debug("import page start");
+const Root = (
+
+
+
+
+
+);
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
-
-
-
-
-
-
+ process.env.NODE_ENV === "development" ? {Root} : Root
);
diff --git a/src/pages/install/main.tsx b/src/pages/install/main.tsx
index e769ad3fd..51643e1a7 100644
--- a/src/pages/install/main.tsx
+++ b/src/pages/install/main.tsx
@@ -19,12 +19,14 @@ const loggerCore = new LoggerCore({
loggerCore.logger().debug("install page start");
+const Root = (
+
+
+
+
+
+);
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
-
-
-
-
-
-
+ process.env.NODE_ENV === "development" ? {Root} : Root
);
diff --git a/src/pages/options/main.tsx b/src/pages/options/main.tsx
index 487b5eab9..ff8669784 100644
--- a/src/pages/options/main.tsx
+++ b/src/pages/options/main.tsx
@@ -29,12 +29,14 @@ loggerCore.logger().debug("options page start");
storeSubscribe();
+const Root = (
+
+
+
+
+
+);
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
-
-
-
-
-
-
+ process.env.NODE_ENV === "development" ? {Root} : Root
);
diff --git a/src/pages/popup/main.tsx b/src/pages/popup/main.tsx
index 421b275bb..923faf695 100644
--- a/src/pages/popup/main.tsx
+++ b/src/pages/popup/main.tsx
@@ -19,16 +19,14 @@ const loggerCore = new LoggerCore({
loggerCore.logger().debug("popup page start");
+const Root = (
+
+
+
+)
+
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
-
-
-
-
+ process.env.NODE_ENV === "development" ? {Root} : Root
);
diff --git a/src/pkg/backup/import.ts b/src/pkg/backup/import.ts
index ab237a436..b1609b223 100644
--- a/src/pkg/backup/import.ts
+++ b/src/pkg/backup/import.ts
@@ -12,6 +12,7 @@ import {
SubscribeBackupData,
SubscribeOptionsFile,
ValueStorage,
+ ScriptData, SubscribeData,
} from "./struct";
import FileSystem, { File } from "@Packages/filesystem/filesystem";
@@ -225,8 +226,8 @@ export default class BackupImport {
// 将map转化为数组
return ({
- script: Array.from(map.values()),
- subscribe: Array.from(subscribe.values()),
+ script: (Array.from(map.values())),
+ subscribe: (Array.from(subscribe.values())),
});
}
diff --git a/src/pkg/backup/struct.ts b/src/pkg/backup/struct.ts
index ffec859df..5e34d3056 100644
--- a/src/pkg/backup/struct.ts
+++ b/src/pkg/backup/struct.ts
@@ -1,3 +1,6 @@
+import { Script } from "@App/app/repo/scripts";
+import { Subscribe } from "@App/app/repo/subscribe";
+
/* eslint-disable camelcase */
export type ResourceMeta = {
@@ -80,6 +83,17 @@ export type ScriptBackupData = {
enabled?: boolean;
};
+export type ScriptData = ScriptBackupData & {
+ script?: { script: Script; oldScript?: Script };
+ install: boolean;
+ error?: string;
+};
+
+export type SubscribeData = SubscribeBackupData & {
+ subscribe?: Subscribe;
+ install: boolean;
+};
+
export type SubscribeScript = {
uuid: string;
url: string;
From f17a4fb18ed2ce5f5319ebc15b896d4b1f27d16b Mon Sep 17 00:00:00 2001
From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com>
Date: Sun, 6 Jul 2025 22:41:59 +0900
Subject: [PATCH 2/2] =?UTF-8?q?=E6=B3=A8=E9=87=8B=20await=20sleep(1);?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/import/App.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/pages/import/App.tsx b/src/pages/import/App.tsx
index b6ce6880f..07f6c625e 100644
--- a/src/pages/import/App.tsx
+++ b/src/pages/import/App.tsx
@@ -151,7 +151,7 @@ function App() {
const scriptImportAsync = async (item: ScriptData) => {
try {
- await sleep(1);
+ // await sleep(1);
await scriptClient.install(item.script?.script!, item.code);
await Promise.all([
(async () => { // 导入资源
@@ -175,7 +175,7 @@ function App() {
}
})()
]);
- await sleep(1);
+ // await sleep(1);
setInstallNum((prev) => [prev[0] + 1, prev[1]]);
} catch (e) {
// 跳過失敗