From 01f0f45007eea99f93abb043fb3297428a298803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Mon, 24 Aug 2026 02:13:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96:=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E6=AD=BB=E4=BB=A3=E7=A0=81(backend/useStore)=E4=B8=8E=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E7=B1=BB=E5=9E=8B=E4=BE=9D=E8=B5=96,=E5=BC=95?= =?UTF-8?q?=E5=85=A5=20marked/dompurify/vitest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 406 +++++++++++++++++++++++++++++++++++- package.json | 5 +- src/composables/useStore.ts | 73 ------- src/core/backend.ts | 173 --------------- 4 files changed, 401 insertions(+), 256 deletions(-) delete mode 100644 src/composables/useStore.ts delete mode 100644 src/core/backend.ts diff --git a/package-lock.json b/package-lock.json index 367bfc4..bde9ebf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,18 @@ "version": "1.0.0", "dependencies": { "@tauri-apps/api": "^2.11.1", + "dompurify": "^3.4.14", "mammoth": "^1.12.0", + "marked": "^18.0.10", "pdfjs-dist": "^5.6.205", "vue": "^3.5.13" }, "devDependencies": { "@tauri-apps/cli": "^2.11.4", - "@types/pdfjs-dist": "^2.10.377", "@vitejs/plugin-vue": "^5.2.1", "typescript": "~5.6.3", "vite": "^6.0.5", + "vitest": "^4.1.11", "vue-tsc": "^2.2.0" } }, @@ -1116,6 +1118,13 @@ "win32" ] }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@tauri-apps/api": { "version": "2.11.1", "resolved": "https://registry.npmmirror.com/@tauri-apps/api/-/api-2.11.1.tgz", @@ -1343,6 +1352,24 @@ "node": ">= 10" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz", @@ -1350,15 +1377,12 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/pdfjs-dist": { - "version": "2.10.377", - "resolved": "https://registry.npmmirror.com/@types/pdfjs-dist/-/pdfjs-dist-2.10.377.tgz", - "integrity": "sha512-RNBWpazVTkC5aiUIIo6d7ojlL0hJSoeQP1QCvTsVLW6qkNEpTALiI0DNGCYAGDfhbL0r17c/zNPQ15lk948UXg==", - "dev": true, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "license": "MIT", - "dependencies": { - "pdfjs-dist": "*" - } + "optional": true }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", @@ -1374,6 +1398,129 @@ "vue": "^3.2.25" } }, + "node_modules/@vitest/expect": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/expect/-/expect-4.1.11.tgz", + "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/mocker/-/mocker-4.1.11.tgz", + "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.11", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-4.1.11.tgz", + "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/runner/-/runner-4.1.11.tgz", + "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.11", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-4.1.11.tgz", + "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "@vitest/utils": "4.1.11", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/spy/-/spy-4.1.11.tgz", + "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/@vitest/utils/-/utils-4.1.11.tgz", + "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.11", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@volar/language-core": { "version": "2.4.15", "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.15.tgz", @@ -1564,6 +1711,16 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1607,6 +1764,23 @@ "balanced-match": "^1.0.0" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmmirror.com/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", @@ -1632,6 +1806,15 @@ "integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==", "license": "BSD-2-Clause" }, + "node_modules/dompurify": { + "version": "3.4.14", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.14.tgz", + "integrity": "sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/duck": { "version": "0.1.12", "resolved": "https://registry.npmmirror.com/duck/-/duck-0.1.12.tgz", @@ -1653,6 +1836,13 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.25.12.tgz", @@ -1701,6 +1891,16 @@ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "license": "MIT" }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", @@ -1827,6 +2027,18 @@ "node": ">=12.0.0" } }, + "node_modules/marked": { + "version": "18.0.10", + "resolved": "https://registry.npmmirror.com/marked/-/marked-18.0.10.tgz", + "integrity": "sha512-FJeH4bRpYoXiggcgriCGItKCSv3xkngJc4QCZ/rkQCogU3VYaLxYJoZl8Nw/b4+x7iij/pd+09mZ6A1dXzpL0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/minimatch": { "version": "9.0.9", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz", @@ -1875,6 +2087,20 @@ "license": "MIT", "optional": true }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmmirror.com/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/option": { "version": "0.2.4", "resolved": "https://registry.npmmirror.com/option/-/option-0.2.4.tgz", @@ -1903,6 +2129,13 @@ "node": ">=0.10.0" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pdfjs-dist": { "version": "5.6.205", "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-5.6.205.tgz", @@ -2041,6 +2274,13 @@ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "license": "MIT" }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2056,6 +2296,20 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2065,6 +2319,23 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -2082,6 +2353,16 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.6.3.tgz", @@ -2183,6 +2464,96 @@ } } }, + "node_modules/vitest": { + "version": "4.1.11", + "resolved": "https://registry.npmmirror.com/vitest/-/vitest-4.1.11.tgz", + "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.11", + "@vitest/mocker": "4.1.11", + "@vitest/pretty-format": "4.1.11", + "@vitest/runner": "4.1.11", + "@vitest/snapshot": "4.1.11", + "@vitest/spy": "4.1.11", + "@vitest/utils": "4.1.11", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.11", + "@vitest/browser-preview": "4.1.11", + "@vitest/browser-webdriverio": "4.1.11", + "@vitest/coverage-istanbul": "4.1.11", + "@vitest/coverage-v8": "4.1.11", + "@vitest/ui": "4.1.11", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, "node_modules/vscode-uri": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz", @@ -2228,6 +2599,23 @@ "typescript": ">=5.0.0" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/xmlbuilder": { "version": "10.1.1", "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-10.1.1.tgz", diff --git a/package.json b/package.json index 6285b5d..8b63491 100644 --- a/package.json +++ b/package.json @@ -9,22 +9,25 @@ "dev:web": "vite --mode web", "build": "vue-tsc -b && vite build", "preview": "vite preview", + "test": "vitest run", "tauri": "tauri", "tauri:dev": "tauri dev", "tauri:build": "tauri build" }, "dependencies": { "@tauri-apps/api": "^2.11.1", + "dompurify": "^3.4.14", "mammoth": "^1.12.0", + "marked": "^18.0.10", "pdfjs-dist": "^5.6.205", "vue": "^3.5.13" }, "devDependencies": { "@tauri-apps/cli": "^2.11.4", - "@types/pdfjs-dist": "^2.10.377", "@vitejs/plugin-vue": "^5.2.1", "typescript": "~5.6.3", "vite": "^6.0.5", + "vitest": "^4.1.11", "vue-tsc": "^2.2.0" } } diff --git a/src/composables/useStore.ts b/src/composables/useStore.ts deleted file mode 100644 index 1dcab19..0000000 --- a/src/composables/useStore.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* ===================================================================== - * useStore.ts — 统一 Store 接口(兼容 Tauri 和 Web 双模式) - * - * 设计: - * - 检测 __TAURI__ 环境,决定走 invoke 还是直接调 TS store - * - 暴露与现有 store 相同的方法签名(88 处组件调用零改动) - * - 返回 reactive ref(与 Vue 响应式兼容) - * - * Web 模式:直接 return store(现有行为,零改动) - * Tauri 模式:返回封装对象,内部 invoke Rust 命令 - * ===================================================================== */ -import type { Deck, Slide, SlideElement, LibItem, PageTemplate, ChatMessage, AiCfg } from '../core/types' -import { store as tsStore } from '../core/store' -import { invoke } from '../core/bridge' - -/** 是否运行在 Tauri 桌面环境中 */ -export const isTauri = typeof window !== 'undefined' && '__TAURI__' in window - -/** 根据环境创建 store 接口 */ -function createStore() { - // Web 模式:直接返回现有 TS store - if (!isTauri) return tsStore - - // Tauri 模式:封装 invoke 调用 - // 注意:所有写操作通过 exec_op 统一走 Op Log - const CLIENT_ID = 'client-' + Math.random().toString(36).slice(2, 10) - - /** 生成一个 Op 并发送到 Rust 后端 */ - async function execOp(type: string, payload: Record) { - try { - const result = await invoke<{ success: boolean; deck: Deck; error?: string }>('exec_op', { - opJson: { type, clientId: CLIENT_ID, timestamp: Date.now(), ...payload } - }) - if (result?.deck) { - // 更新本地 ref 状态(由 TauriBridge watcher 处理) - } - } catch (e) { - console.error('exec_op 失败:', e) - } - } - - // 返回与 TS store 类型兼容的对象 - // 关键属性通过 computed ref 暴露 - return { - ...tsStore, - // 读操作暂时委托给 TS store(未来Rust端会emit状态同步) - // 写操作改为 invoke - setTheme: async (name: string) => { - await execOp('set_theme', { theme: name }) - }, - addSlide: async (atIndex?: number) => { - const slide: Slide = { id: 's-' + Date.now(), background: 'bg', elements: [] } - const idx = atIndex != null ? atIndex + 1 : tsStore.getCount() - await execOp('add_slide', { atIndex: idx, slide }) - tsStore.addSlide(atIndex) - }, - updateElement: async (id: string, patch: Record) => { - await execOp('update_element', { slideIdx: tsStore.getCurrentIndex(), elementId: id, patch }) - }, - delElement: async (id: string) => { - const el = tsStore.findElement(id) - await execOp('del_element', { slideIdx: tsStore.getCurrentIndex(), elementId: id, deletedElement: el ? { ...el } : undefined }) - }, - undo: async () => { - await invoke('undo') - }, - redo: async () => { - await invoke('redo') - }, - } -} - -export const store = createStore() diff --git a/src/core/backend.ts b/src/core/backend.ts deleted file mode 100644 index da39cfe..0000000 --- a/src/core/backend.ts +++ /dev/null @@ -1,173 +0,0 @@ -/* ===================================================================== - * backend.ts — 持久化后端抽象层 - * - * store 只管内存状态 + Op Log,持久化通过 Backend 接口抽象。 - * 三个实现: - * - LocalBackend (localStorage,Web 版当前模式) - * - TauriBackend (Rust 文件系统,桌面版,B4 实现) - * - CloudBackend (HTTP API,云端版,C0 实现) - * - * 设计原则: - * - 接口只管读写数据,不管状态逻辑(状态逻辑在 store) - * - 所有方法返回 Promise(TauriBackend/CloudBackend 天然异步) - * - LocalBackend 内部用 localStorage 但包装为 Promise(统一接口) - * ===================================================================== */ -import type { Deck, LibItem, PageTemplate, Theme, ChatMessage, AiCfg } from './types' - -export interface Backend { - // ---- 当前 deck ---- - loadDeck(): Promise - saveDeck(deck: Deck): Promise - loadBackup(): Promise - saveBackup(deck: Deck): Promise - clearBackup(): Promise - - // ---- 文库 ---- - loadLibrary(): Promise - saveLibrary(lib: LibItem[]): Promise - getActiveLibId(): Promise - setActiveLibId(id: string | null): Promise - - // ---- 会话(按 chatId 隔离) ---- - loadChat(chatId: string): Promise - saveChat(chatId: string, msgs: ChatMessage[]): Promise - clearChat(chatId: string): Promise - - // ---- 用户模板 ---- - loadTemplates(): Promise - saveTemplates(tpls: PageTemplate[]): Promise - - // ---- 自定义主题 ---- - loadThemes(): Promise> - saveThemes(themes: Record): Promise - - // ---- AI 配置 ---- - loadCfg(): Promise | null> - saveCfg(cfg: AiCfg): Promise -} - -/* ============================================================ - * LocalBackend — localStorage 实现(Web 版当前模式) - * ============================================================ */ - -const KEYS = { - deck: 'u-ppt.deck.v1', - deckBak: 'u-ppt.deck.v1.bak', - lib: 'u-ppt.library.v1', - activeLib: 'u-ppt.activeLib.v1', - chatPrefix: 'u-ppt.chat.', - templates: 'u-ppt.templates.v1', - themes: 'u-ppt.themes.v1', - cfg: 'u-ppt.ai-cfg.v1', -} - -function lsGet(key: string): string | null { - try { return localStorage.getItem(key) } catch (e) { return null } -} -function lsSet(key: string, val: string): void { - try { localStorage.setItem(key, val) } catch (e) { /* 配额满等忽略 */ } -} -function lsDel(key: string): void { - try { localStorage.removeItem(key) } catch (e) {} -} - -export class LocalBackend implements Backend { - async loadDeck(): Promise { - const raw = lsGet(KEYS.deck) - if (!raw) return null - try { return JSON.parse(raw) } catch (e) { return null } - } - - async saveDeck(deck: Deck): Promise { - lsSet(KEYS.deck, JSON.stringify(deck)) - } - - async loadBackup(): Promise { - const raw = lsGet(KEYS.deckBak) - if (!raw) return null - try { return JSON.parse(raw) } catch (e) { return null } - } - - async saveBackup(deck: Deck): Promise { - lsSet(KEYS.deckBak, JSON.stringify(deck)) - } - - async clearBackup(): Promise { - lsDel(KEYS.deckBak) - } - - async loadLibrary(): Promise { - const raw = lsGet(KEYS.lib) - if (!raw) return [] - try { return JSON.parse(raw) || [] } catch (e) { return [] } - } - - async saveLibrary(lib: LibItem[]): Promise { - lsSet(KEYS.lib, JSON.stringify(lib)) - } - - async getActiveLibId(): Promise { - return lsGet(KEYS.activeLib) - } - - async setActiveLibId(id: string | null): Promise { - if (id) lsSet(KEYS.activeLib, id) - else lsDel(KEYS.activeLib) - } - - async loadChat(chatId: string): Promise { - const raw = lsGet(KEYS.chatPrefix + chatId) - if (!raw) return [] - try { return JSON.parse(raw) || [] } catch (e) { return [] } - } - - async saveChat(chatId: string, msgs: ChatMessage[]): Promise { - lsSet(KEYS.chatPrefix + chatId, JSON.stringify(msgs)) - } - - async clearChat(chatId: string): Promise { - lsDel(KEYS.chatPrefix + chatId) - } - - async loadTemplates(): Promise { - const raw = lsGet(KEYS.templates) - if (!raw) return [] - try { return JSON.parse(raw) || [] } catch (e) { return [] } - } - - async saveTemplates(tpls: PageTemplate[]): Promise { - // 只存用户模板(category === 'user') - lsSet(KEYS.templates, JSON.stringify(tpls.filter(t => t.category === 'user'))) - } - - async loadThemes(): Promise> { - const raw = lsGet(KEYS.themes) - if (!raw) return {} - try { return JSON.parse(raw) || {} } catch (e) { return {} } - } - - async saveThemes(themes: Record): Promise { - lsSet(KEYS.themes, JSON.stringify(themes)) - } - - async loadCfg(): Promise | null> { - const raw = lsGet(KEYS.cfg) - if (!raw) return null - try { return JSON.parse(raw) } catch (e) { return null } - } - - async saveCfg(cfg: AiCfg): Promise { - lsSet(KEYS.cfg, JSON.stringify(cfg)) - } -} - -/* ---------- 当前活动的 Backend 实例 ---------- */ -let activeBackend: Backend = new LocalBackend() - -export function getBackend(): Backend { - return activeBackend -} - -export function setBackend(b: Backend): void { - activeBackend = b -}