feat: 添加书籍导入功能

1. 新增@tauri-apps/plugin-dialog依赖,实现文件选择能力
2. 配置macOS私有API权限,适配系统能力
3. 首页导入按钮绑定点击事件,支持选择txt/epub文件
4. 注册dialog插件到tauri应用生命周期
This commit is contained in:
sparksfly 2026-08-19 23:46:30 +08:00
parent d1926cde42
commit 5c1be1cdb0
8 changed files with 190 additions and 294 deletions

View File

@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2", "@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2.7.2",
"@tauri-apps/plugin-opener": "^2", "@tauri-apps/plugin-opener": "^2",
"@tauri-apps/plugin-store": "~2.4.4", "@tauri-apps/plugin-store": "~2.4.4",
"axios": "^1.19.0", "axios": "^1.19.0",

View File

@ -11,6 +11,9 @@ importers:
'@tauri-apps/api': '@tauri-apps/api':
specifier: ^2 specifier: ^2
version: 2.11.1 version: 2.11.1
'@tauri-apps/plugin-dialog':
specifier: ^2.7.2
version: 2.7.2
'@tauri-apps/plugin-opener': '@tauri-apps/plugin-opener':
specifier: ^2 specifier: ^2
version: 2.5.4 version: 2.5.4
@ -19,7 +22,7 @@ importers:
version: 2.4.4 version: 2.4.4
axios: axios:
specifier: ^1.19.0 specifier: ^1.19.0
version: 1.19.0(debug@4.4.3) version: 1.19.0
dayjs: dayjs:
specifier: ^1.11.21 specifier: ^1.11.21
version: 1.11.23 version: 1.11.23
@ -37,7 +40,7 @@ importers:
version: 3.5.41(typescript@7.0.2) version: 3.5.41(typescript@7.0.2)
vue-router: vue-router:
specifier: ^5.2.0 specifier: ^5.2.0
version: 5.2.0(@vue/compiler-sfc@3.5.41)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@7.0.2)(vue@3.5.41(typescript@7.0.2)))(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2)) version: 5.2.0(@vue/compiler-sfc@3.5.41)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@7.0.2)(vue@3.5.41(typescript@7.0.2)))(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2))
devDependencies: devDependencies:
'@tauri-apps/cli': '@tauri-apps/cli':
specifier: ^2 specifier: ^2
@ -83,10 +86,10 @@ importers:
version: 7.0.2 version: 7.0.2
unplugin-auto-import: unplugin-auto-import:
specifier: ^21.1.0 specifier: ^21.1.0
version: 21.1.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)) version: 21.1.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))
unplugin-vue-components: unplugin-vue-components:
specifier: ^32.1.0 specifier: ^32.1.0
version: 32.1.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2)) version: 32.1.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2))
vite: vite:
specifier: ^8.2.1 specifier: ^8.2.1
version: 8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0) version: 8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)
@ -174,13 +177,6 @@ packages:
'@juggle/resize-observer@3.4.0': '@juggle/resize-observer@3.4.0':
resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
'@napi-rs/lzma-linux-x64-gnu@1.5.1':
resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==}
engines: {node: ^22.20 || ^24.12 || >=25}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxc-project/types@0.144.0': '@oxc-project/types@0.144.0':
resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==} resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==}
@ -359,144 +355,6 @@ packages:
'@rolldown/pluginutils@1.0.1': '@rolldown/pluginutils@1.0.1':
resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
'@rollup/rollup-android-arm-eabi@4.62.4':
resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.62.4':
resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.62.4':
resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.62.4':
resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.62.4':
resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.62.4':
resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.62.4':
resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.62.4':
resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.62.4':
resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.62.4':
resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.62.4':
resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.62.4':
resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==}
cpu: [loong64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.62.4':
resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.62.4':
resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==}
cpu: [ppc64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.62.4':
resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.62.4':
resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.62.4':
resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.62.4':
resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.62.4':
resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-openbsd-x64@4.62.4':
resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==}
cpu: [x64]
os: [openbsd]
'@rollup/rollup-openharmony-arm64@4.62.4':
resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==}
cpu: [arm64]
os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.62.4':
resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.62.4':
resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-gnu@4.62.4':
resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==}
cpu: [x64]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.62.4':
resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==}
cpu: [x64]
os: [win32]
'@tauri-apps/api@2.11.1': '@tauri-apps/api@2.11.1':
resolution: {integrity: sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==} resolution: {integrity: sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==}
@ -576,6 +434,9 @@ packages:
engines: {node: '>= 10'} engines: {node: '>= 10'}
hasBin: true hasBin: true
'@tauri-apps/plugin-dialog@2.7.2':
resolution: {integrity: sha512-pX0IGm1I3I6wc+zeKYcq1GSqogK6okCNX5fOdaNU5ab1AjGS6l1E5wFNjEb7meg7ZFSp0JUs+0jQGQNyOvLrsg==}
'@tauri-apps/plugin-opener@2.5.4': '@tauri-apps/plugin-opener@2.5.4':
resolution: {integrity: sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==} resolution: {integrity: sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==}
@ -764,11 +625,6 @@ packages:
'@volar/typescript@2.4.28': '@volar/typescript@2.4.28':
resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
'@vue-macros/common@3.1.4': '@vue-macros/common@3.1.4':
resolution: {integrity: sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==} resolution: {integrity: sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==}
@ -1249,11 +1105,6 @@ packages:
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true hasBin: true
rollup@4.62.4:
resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
sass@1.102.0: sass@1.102.0:
resolution: {integrity: sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==} resolution: {integrity: sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==}
engines: {node: '>=20.19.0'} engines: {node: '>=20.19.0'}
@ -1538,9 +1389,6 @@ snapshots:
'@juggle/resize-observer@3.4.0': {} '@juggle/resize-observer@3.4.0': {}
'@napi-rs/lzma-linux-x64-gnu@1.5.1':
optional: true
'@oxc-project/types@0.144.0': {} '@oxc-project/types@0.144.0': {}
'@parcel/watcher-android-arm64@2.6.0': '@parcel/watcher-android-arm64@2.6.0':
@ -1644,81 +1492,6 @@ snapshots:
'@rolldown/pluginutils@1.0.1': {} '@rolldown/pluginutils@1.0.1': {}
'@rollup/rollup-android-arm-eabi@4.62.4':
optional: true
'@rollup/rollup-android-arm64@4.62.4':
optional: true
'@rollup/rollup-darwin-arm64@4.62.4':
optional: true
'@rollup/rollup-darwin-x64@4.62.4':
optional: true
'@rollup/rollup-freebsd-arm64@4.62.4':
optional: true
'@rollup/rollup-freebsd-x64@4.62.4':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.62.4':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.62.4':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.62.4':
optional: true
'@rollup/rollup-linux-arm64-musl@4.62.4':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.62.4':
optional: true
'@rollup/rollup-linux-loong64-musl@4.62.4':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.62.4':
optional: true
'@rollup/rollup-linux-ppc64-musl@4.62.4':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.62.4':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.62.4':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.62.4':
optional: true
'@rollup/rollup-linux-x64-gnu@4.62.4':
optional: true
'@rollup/rollup-linux-x64-musl@4.62.4':
optional: true
'@rollup/rollup-openbsd-x64@4.62.4':
optional: true
'@rollup/rollup-openharmony-arm64@4.62.4':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.62.4':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.62.4':
optional: true
'@rollup/rollup-win32-x64-gnu@4.62.4':
optional: true
'@rollup/rollup-win32-x64-msvc@4.62.4':
optional: true
'@tauri-apps/api@2.11.1': {} '@tauri-apps/api@2.11.1': {}
'@tauri-apps/cli-darwin-arm64@2.11.4': '@tauri-apps/cli-darwin-arm64@2.11.4':
@ -1768,6 +1541,10 @@ snapshots:
'@tauri-apps/cli-win32-ia32-msvc': 2.11.4 '@tauri-apps/cli-win32-ia32-msvc': 2.11.4
'@tauri-apps/cli-win32-x64-msvc': 2.11.4 '@tauri-apps/cli-win32-x64-msvc': 2.11.4
'@tauri-apps/plugin-dialog@2.7.2':
dependencies:
'@tauri-apps/api': 2.11.1
'@tauri-apps/plugin-opener@2.5.4': '@tauri-apps/plugin-opener@2.5.4':
dependencies: dependencies:
'@tauri-apps/api': 2.11.1 '@tauri-apps/api': 2.11.1
@ -1885,13 +1662,11 @@ snapshots:
'@volar/source-map@2.4.28': {} '@volar/source-map@2.4.28': {}
'@volar/typescript@2.4.28(typescript@7.0.2)': '@volar/typescript@2.4.28':
dependencies: dependencies:
'@volar/language-core': 2.4.28 '@volar/language-core': 2.4.28
path-browserify: 1.0.1 path-browserify: 1.0.1
vscode-uri: 3.1.0 vscode-uri: 3.1.0
optionalDependencies:
typescript: 7.0.2
'@vue-macros/common@3.1.4(vue@3.5.41(typescript@7.0.2))': '@vue-macros/common@3.1.4(vue@3.5.41(typescript@7.0.2))':
dependencies: dependencies:
@ -2014,9 +1789,9 @@ snapshots:
asynckit@0.4.0: {} asynckit@0.4.0: {}
axios@1.19.0(debug@4.4.3): axios@1.19.0:
dependencies: dependencies:
follow-redirects: 1.16.0(debug@4.4.3) follow-redirects: 1.16.0
form-data: 4.0.6 form-data: 4.0.6
https-proxy-agent: 5.0.1 https-proxy-agent: 5.0.1
proxy-from-env: 2.1.0 proxy-from-env: 2.1.0
@ -2115,9 +1890,7 @@ snapshots:
optionalDependencies: optionalDependencies:
picomatch: 4.0.5 picomatch: 4.0.5
follow-redirects@1.16.0(debug@4.4.3): follow-redirects@1.16.0: {}
optionalDependencies:
debug: 4.4.3
form-data@4.0.6: form-data@4.0.6:
dependencies: dependencies:
@ -2378,39 +2151,6 @@ snapshots:
'@rolldown/binding-win32-arm64-msvc': 1.2.4 '@rolldown/binding-win32-arm64-msvc': 1.2.4
'@rolldown/binding-win32-x64-msvc': 1.2.4 '@rolldown/binding-win32-x64-msvc': 1.2.4
rollup@4.62.4:
dependencies:
'@types/estree': 1.0.9
optionalDependencies:
'@napi-rs/lzma-linux-x64-gnu': 1.5.1
'@rollup/rollup-android-arm-eabi': 4.62.4
'@rollup/rollup-android-arm64': 4.62.4
'@rollup/rollup-darwin-arm64': 4.62.4
'@rollup/rollup-darwin-x64': 4.62.4
'@rollup/rollup-freebsd-arm64': 4.62.4
'@rollup/rollup-freebsd-x64': 4.62.4
'@rollup/rollup-linux-arm-gnueabihf': 4.62.4
'@rollup/rollup-linux-arm-musleabihf': 4.62.4
'@rollup/rollup-linux-arm64-gnu': 4.62.4
'@rollup/rollup-linux-arm64-musl': 4.62.4
'@rollup/rollup-linux-loong64-gnu': 4.62.4
'@rollup/rollup-linux-loong64-musl': 4.62.4
'@rollup/rollup-linux-ppc64-gnu': 4.62.4
'@rollup/rollup-linux-ppc64-musl': 4.62.4
'@rollup/rollup-linux-riscv64-gnu': 4.62.4
'@rollup/rollup-linux-riscv64-musl': 4.62.4
'@rollup/rollup-linux-s390x-gnu': 4.62.4
'@rollup/rollup-linux-x64-gnu': 4.62.4
'@rollup/rollup-linux-x64-musl': 4.62.4
'@rollup/rollup-openbsd-x64': 4.62.4
'@rollup/rollup-openharmony-arm64': 4.62.4
'@rollup/rollup-win32-arm64-msvc': 4.62.4
'@rollup/rollup-win32-ia32-msvc': 4.62.4
'@rollup/rollup-win32-x64-gnu': 4.62.4
'@rollup/rollup-win32-x64-msvc': 4.62.4
fsevents: 2.3.3
optional: true
sass@1.102.0: sass@1.102.0:
dependencies: dependencies:
chokidar: 5.0.0 chokidar: 5.0.0
@ -2463,7 +2203,7 @@ snapshots:
undici-types@8.3.0: {} undici-types@8.3.0: {}
unimport@6.4.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)): unimport@6.4.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)):
dependencies: dependencies:
acorn: 8.18.0 acorn: 8.18.0
escape-string-regexp: 5.0.0 escape-string-regexp: 5.0.0
@ -2477,7 +2217,7 @@ snapshots:
scule: 1.3.0 scule: 1.3.0
strip-literal: 4.0.0 strip-literal: 4.0.0
tinyglobby: 0.2.17 tinyglobby: 0.2.17
unplugin: 3.3.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)) unplugin: 3.3.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))
unplugin-utils: 0.3.2 unplugin-utils: 0.3.2
optionalDependencies: optionalDependencies:
rolldown: 1.2.4 rolldown: 1.2.4
@ -2491,13 +2231,13 @@ snapshots:
- vite - vite
- webpack - webpack
unplugin-auto-import@21.1.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)): unplugin-auto-import@21.1.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)):
dependencies: dependencies:
local-pkg: 1.2.1 local-pkg: 1.2.1
magic-string: 1.2.0 magic-string: 1.2.0
picomatch: 4.0.5 picomatch: 4.0.5
unimport: 6.4.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)) unimport: 6.4.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))
unplugin: 3.3.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)) unplugin: 3.3.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))
unplugin-utils: 0.3.2 unplugin-utils: 0.3.2
transitivePeerDependencies: transitivePeerDependencies:
- '@farmfe/core' - '@farmfe/core'
@ -2516,7 +2256,7 @@ snapshots:
pathe: 2.0.3 pathe: 2.0.3
picomatch: 4.0.5 picomatch: 4.0.5
unplugin-vue-components@32.1.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2)): unplugin-vue-components@32.1.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2)):
dependencies: dependencies:
chokidar: 5.0.0 chokidar: 5.0.0
local-pkg: 1.2.1 local-pkg: 1.2.1
@ -2525,7 +2265,7 @@ snapshots:
obug: 2.1.4 obug: 2.1.4
picomatch: 4.0.5 picomatch: 4.0.5
tinyglobby: 0.2.17 tinyglobby: 0.2.17
unplugin: 3.3.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)) unplugin: 3.3.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))
unplugin-utils: 0.3.2 unplugin-utils: 0.3.2
vue: 3.5.41(typescript@7.0.2) vue: 3.5.41(typescript@7.0.2)
transitivePeerDependencies: transitivePeerDependencies:
@ -2539,14 +2279,13 @@ snapshots:
- vite - vite
- webpack - webpack
unplugin@3.3.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)): unplugin@3.3.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)):
dependencies: dependencies:
'@jridgewell/remapping': 2.3.5 '@jridgewell/remapping': 2.3.5
picomatch: 4.0.5 picomatch: 4.0.5
webpack-virtual-modules: 0.6.2 webpack-virtual-modules: 0.6.2
optionalDependencies: optionalDependencies:
rolldown: 1.2.4 rolldown: 1.2.4
rollup: 4.62.4
vite: 8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0) vite: 8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)
vdirs@0.1.8(vue@3.5.41(typescript@7.0.2)): vdirs@0.1.8(vue@3.5.41(typescript@7.0.2)):
@ -2574,7 +2313,7 @@ snapshots:
vscode-uri@3.1.0: {} vscode-uri@3.1.0: {}
vue-router@5.2.0(@vue/compiler-sfc@3.5.41)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@7.0.2)(vue@3.5.41(typescript@7.0.2)))(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2)): vue-router@5.2.0(@vue/compiler-sfc@3.5.41)(pinia@4.0.3(@vue/devtools-api@8.2.1)(typescript@7.0.2)(vue@3.5.41(typescript@7.0.2)))(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))(vue@3.5.41(typescript@7.0.2)):
dependencies: dependencies:
'@babel/generator': 8.0.0 '@babel/generator': 8.0.0
'@vue-macros/common': 3.1.4(vue@3.5.41(typescript@7.0.2)) '@vue-macros/common': 3.1.4(vue@3.5.41(typescript@7.0.2))
@ -2591,7 +2330,7 @@ snapshots:
picomatch: 4.0.5 picomatch: 4.0.5
scule: 1.3.0 scule: 1.3.0
tinyglobby: 0.2.17 tinyglobby: 0.2.17
unplugin: 3.3.0(rolldown@1.2.4)(rollup@4.62.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0)) unplugin: 3.3.0(rolldown@1.2.4)(vite@8.2.1(@types/node@26.2.0)(sass@1.102.0)(yaml@2.9.0))
unplugin-utils: 0.3.2 unplugin-utils: 0.3.2
vue: 3.5.41(typescript@7.0.2) vue: 3.5.41(typescript@7.0.2)
yaml: 2.9.0 yaml: 2.9.0
@ -2611,7 +2350,7 @@ snapshots:
vue-tsc@3.3.10(typescript@7.0.2): vue-tsc@3.3.10(typescript@7.0.2):
dependencies: dependencies:
'@volar/typescript': 2.4.28(typescript@7.0.2) '@volar/typescript': 2.4.28
'@vue/language-core': 3.3.10 '@vue/language-core': 3.3.10
typescript: 7.0.2 typescript: 7.0.2

144
src-tauri/Cargo.lock generated
View File

@ -2544,6 +2544,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [ dependencies = [
"bitflags 2.13.1", "bitflags 2.13.1",
"block2", "block2",
"libc",
"objc2", "objc2",
"objc2-core-foundation", "objc2-core-foundation",
] ]
@ -3155,6 +3156,30 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "rfd"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672"
dependencies = [
"block2",
"dispatch2",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"log",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows-sys 0.60.2",
]
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.3" version = "2.1.3"
@ -3811,6 +3836,7 @@ dependencies = [
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-helper", "tauri-helper",
"tauri-plugin-dialog",
"tauri-plugin-opener", "tauri-plugin-opener",
"tauri-plugin-store", "tauri-plugin-store",
] ]
@ -4133,6 +4159,48 @@ dependencies = [
"walkdir", "walkdir",
] ]
[[package]]
name = "tauri-plugin-dialog"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940"
dependencies = [
"log",
"raw-window-handle",
"rfd",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"tauri-plugin-fs",
"thiserror 2.0.20",
"url",
]
[[package]]
name = "tauri-plugin-fs"
version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371"
dependencies = [
"anyhow",
"dunce",
"glob",
"log",
"objc2-foundation",
"percent-encoding",
"schemars 0.8.22",
"serde",
"serde_json",
"serde_repr",
"tauri",
"tauri-plugin",
"tauri-utils",
"thiserror 2.0.20",
"toml 1.1.4+spec-1.1.0",
"url",
]
[[package]] [[package]]
name = "tauri-plugin-opener" name = "tauri-plugin-opener"
version = "2.5.4" version = "2.5.4"
@ -5281,6 +5349,15 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.61.2" version = "0.61.2"
@ -5314,13 +5391,30 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6", "windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6", "windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6", "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm", "windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6", "windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6", "windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6", "windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6", "windows_x86_64_msvc 0.52.6",
] ]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link 0.2.1",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]] [[package]]
name = "windows-threading" name = "windows-threading"
version = "0.1.0" version = "0.1.0"
@ -5351,6 +5445,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.2" version = "0.42.2"
@ -5363,6 +5463,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.2" version = "0.42.2"
@ -5375,12 +5481,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]] [[package]]
name = "windows_i686_gnullvm" name = "windows_i686_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.2" version = "0.42.2"
@ -5393,6 +5511,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.2" version = "0.42.2"
@ -5405,6 +5529,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.2" version = "0.42.2"
@ -5417,6 +5547,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.2" version = "0.42.2"
@ -5429,6 +5565,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.40" version = "0.5.40"

View File

@ -22,7 +22,7 @@ tauri-build = { version = "2", features = [] }
tauri-helper = "0.2.1" tauri-helper = "0.2.1"
[dependencies] [dependencies]
tauri = { version = "2", features = [] } tauri = { version = "2", features = ["macos-private-api"] }
tauri-plugin-opener = "2" tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
@ -35,3 +35,4 @@ sqlx = { version = "0.9.0", features = [
"chrono", "chrono",
] } ] }
chrono = "0.4.45" chrono = "0.4.45"
tauri-plugin-dialog = "2.7.2"

View File

@ -9,6 +9,8 @@
"core:window:allow-start-dragging", "core:window:allow-start-dragging",
"core:window:allow-close", "core:window:allow-close",
"core:window:allow-minimize", "core:window:allow-minimize",
"opener:default" "opener:default",
"dialog:default",
"dialog:allow-open"
] ]
} }

View File

@ -10,6 +10,7 @@ use services::db::init_pool;
pub fn run() { pub fn run() {
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_dialog::init())
.setup(|app| { .setup(|app| {
let pool = tauri::async_runtime::block_on(async { let pool = tauri::async_runtime::block_on(async {
init_pool().await.expect("sqlite数据库连接池初始化失败!") init_pool().await.expect("sqlite数据库连接池初始化失败!")

View File

@ -10,6 +10,7 @@
"frontendDist": "../dist" "frontendDist": "../dist"
}, },
"app": { "app": {
"macOSPrivateApi": true,
"windows": [ "windows": [
{ {
"title": "幽灵阅读器", "title": "幽灵阅读器",

View File

@ -26,7 +26,7 @@
<n-scrollbar class="book-scrollbar"> <n-scrollbar class="book-scrollbar">
<n-empty v-if="bookList.length === 0" class="empty" description="还没有导入书籍哦"> <n-empty v-if="bookList.length === 0" class="empty" description="还没有导入书籍哦">
<template #extra> <template #extra>
<n-button size="small" type="primary" round>立即导入</n-button> <n-button size="small" type="primary" round @click="importBook">立即导入</n-button>
</template> </template>
</n-empty> </n-empty>
</n-scrollbar> </n-scrollbar>
@ -35,6 +35,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { open } from "@tauri-apps/plugin-dialog"
import { BookSearch24Regular } from "@vicons/fluent" import { BookSearch24Regular } from "@vicons/fluent"
import { SettingOutlined } from "@vicons/antd" import { SettingOutlined } from "@vicons/antd"
@ -46,6 +47,14 @@ const searchValue = ref("")
const goSettingView = () => { const goSettingView = () => {
router.push({ name: "Setting" }) router.push({ name: "Setting" })
} }
const importBook = async () => {
const filePath = await open({
multiple: false,
filters: [{ name: "TXT", extensions: ["txt", "epub"]}]
})
console.log(filePath)
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>