mirror of
https://github.com/imsyy/SPlayer.git
synced 2025-11-25 03:14:57 +08:00
feat: 完善 i18n 支持 & fix: ios 端图标显示 #38
This commit is contained in:
@@ -33,11 +33,11 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14",
|
||||
"@rollup/plugin-terser": "^0.4.0",
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vitejs/plugin-vue": "^3.2.0",
|
||||
"naive-ui": "^2.34.2",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"naive-ui": "^2.34.4",
|
||||
"unplugin-auto-import": "^0.12.0",
|
||||
"unplugin-vue-components": "^0.22.11",
|
||||
"vite": "^3.2.4",
|
||||
"vite-plugin-pwa": "^0.14.1"
|
||||
"vite": "^4.3.8",
|
||||
"vite-plugin-pwa": "^0.15.0"
|
||||
}
|
||||
}
|
||||
496
pnpm-lock.yaml
generated
496
pnpm-lock.yaml
generated
@@ -42,7 +42,7 @@ dependencies:
|
||||
version: 5.0.0
|
||||
vite-plugin-html:
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0(vite@3.2.4)
|
||||
version: 3.2.0(vite@4.3.8)
|
||||
vue:
|
||||
specifier: ^3.2.45
|
||||
version: 3.2.45
|
||||
@@ -67,11 +67,11 @@ devDependencies:
|
||||
specifier: ^0.12.0
|
||||
version: 0.12.0
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^3.2.0
|
||||
version: 3.2.0(vite@3.2.4)(vue@3.2.45)
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3(vite@4.3.8)(vue@3.2.45)
|
||||
naive-ui:
|
||||
specifier: ^2.34.2
|
||||
version: 2.34.2(vue@3.2.45)
|
||||
specifier: ^2.34.4
|
||||
version: 2.34.4(vue@3.2.45)
|
||||
unplugin-auto-import:
|
||||
specifier: ^0.12.0
|
||||
version: 0.12.0(rollup@2.79.1)
|
||||
@@ -79,11 +79,11 @@ devDependencies:
|
||||
specifier: ^0.22.11
|
||||
version: 0.22.11(rollup@2.79.1)(vue@3.2.45)
|
||||
vite:
|
||||
specifier: ^3.2.4
|
||||
version: 3.2.4(sass@1.56.1)
|
||||
specifier: ^4.3.8
|
||||
version: 4.3.8(sass@1.56.1)
|
||||
vite-plugin-pwa:
|
||||
specifier: ^0.14.1
|
||||
version: 0.14.1(vite@3.2.4)(workbox-build@6.5.4)(workbox-window@6.5.4)
|
||||
specifier: ^0.15.0
|
||||
version: 0.15.0(vite@4.3.8)(workbox-build@6.5.4)(workbox-window@6.5.4)
|
||||
|
||||
packages:
|
||||
|
||||
@@ -1268,22 +1268,182 @@ packages:
|
||||
resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
|
||||
dev: true
|
||||
|
||||
/@esbuild/android-arm@0.15.16:
|
||||
resolution: {integrity: sha512-nyB6CH++2mSgx3GbnrJsZSxzne5K0HMyNIWafDHqYy7IwxFc4fd/CgHVZXr8Eh+Q3KbIAcAe3vGyqIPhGblvMQ==}
|
||||
/@esbuild/android-arm64@0.17.19:
|
||||
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-arm@0.17.19:
|
||||
resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64@0.15.16:
|
||||
resolution: {integrity: sha512-SDLfP1uoB0HZ14CdVYgagllgrG7Mdxhkt4jDJOKl/MldKrkQ6vDJMZKl2+5XsEY/Lzz37fjgLQoJBGuAw/x8kQ==}
|
||||
/@esbuild/android-x64@0.17.19:
|
||||
resolution: {integrity: sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-arm64@0.17.19:
|
||||
resolution: {integrity: sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-x64@0.17.19:
|
||||
resolution: {integrity: sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-arm64@0.17.19:
|
||||
resolution: {integrity: sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-x64@0.17.19:
|
||||
resolution: {integrity: sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm64@0.17.19:
|
||||
resolution: {integrity: sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm@0.17.19:
|
||||
resolution: {integrity: sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ia32@0.17.19:
|
||||
resolution: {integrity: sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64@0.17.19:
|
||||
resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-mips64el@0.17.19:
|
||||
resolution: {integrity: sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ppc64@0.17.19:
|
||||
resolution: {integrity: sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-riscv64@0.17.19:
|
||||
resolution: {integrity: sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-s390x@0.17.19:
|
||||
resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-x64@0.17.19:
|
||||
resolution: {integrity: sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/netbsd-x64@0.17.19:
|
||||
resolution: {integrity: sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/openbsd-x64@0.17.19:
|
||||
resolution: {integrity: sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/sunos-x64@0.17.19:
|
||||
resolution: {integrity: sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-arm64@0.17.19:
|
||||
resolution: {integrity: sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-ia32@0.17.19:
|
||||
resolution: {integrity: sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-x64@0.17.19:
|
||||
resolution: {integrity: sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@icon-park/vue-next@1.4.2(vue@3.2.45):
|
||||
resolution: {integrity: sha512-+QklF255wkfBOabY+xw6FAI0Bwln/RhdwCunNy/9sKdKuChtaU67QZqU67KGAvZUTeeBgsL+yaHHxqfQeGZXEQ==}
|
||||
engines: {node: '>= 8.0.0', npm: '>= 5.0.0'}
|
||||
@@ -1442,20 +1602,6 @@ packages:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-replace@5.0.2(rollup@3.10.0):
|
||||
resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.0.2(rollup@3.10.0)
|
||||
magic-string: 0.27.0
|
||||
rollup: 3.10.0
|
||||
dev: true
|
||||
|
||||
/@rollup/plugin-terser@0.4.0(rollup@2.79.1):
|
||||
resolution: {integrity: sha512-Ipcf3LPNerey1q9ZMjiaWHlNPEHNU/B5/uh9zXLltfEQ1lVSLLeZSgAtTPWGyw8Ip1guOeq+mDtdOlEj/wNxQw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -1506,21 +1652,6 @@ packages:
|
||||
rollup: 2.79.1
|
||||
dev: true
|
||||
|
||||
/@rollup/pluginutils@5.0.2(rollup@3.10.0):
|
||||
resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^1.20.0||^2.0.0||^3.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/estree': 1.0.0
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 2.3.1
|
||||
rollup: 3.10.0
|
||||
dev: true
|
||||
|
||||
/@surma/rollup-plugin-off-main-thread@2.2.3:
|
||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||
dependencies:
|
||||
@@ -1570,14 +1701,14 @@ packages:
|
||||
resolution: {integrity: sha512-chv1CYAl8P32P3Ycwgd5+vw/OFNc2mtkKdb1Rw4T5IJmKy6GVDsoUKV3N2l208HATn7CCQphZtuPDdsm7K2kmA==}
|
||||
dev: true
|
||||
|
||||
/@vitejs/plugin-vue@3.2.0(vite@3.2.4)(vue@3.2.45):
|
||||
resolution: {integrity: sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==}
|
||||
/@vitejs/plugin-vue@4.2.3(vite@4.3.8)(vue@3.2.45):
|
||||
resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
vite: ^3.0.0
|
||||
vite: ^4.0.0
|
||||
vue: ^3.2.25
|
||||
dependencies:
|
||||
vite: 3.2.4(sass@1.56.1)
|
||||
vite: 4.3.8(sass@1.56.1)
|
||||
vue: 3.2.45
|
||||
dev: true
|
||||
|
||||
@@ -2209,194 +2340,34 @@ packages:
|
||||
is-symbol: 1.0.4
|
||||
dev: true
|
||||
|
||||
/esbuild-android-64@0.15.16:
|
||||
resolution: {integrity: sha512-Vwkv/sT0zMSgPSVO3Jlt1pUbnZuOgtOQJkJkyyJFAlLe7BiT8e9ESzo0zQSx4c3wW4T6kGChmKDPMbWTgtliQA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-android-arm64@0.15.16:
|
||||
resolution: {integrity: sha512-lqfKuofMExL5niNV3gnhMUYacSXfsvzTa/58sDlBET/hCOG99Zmeh+lz6kvdgvGOsImeo6J9SW21rFCogNPLxg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-darwin-64@0.15.16:
|
||||
resolution: {integrity: sha512-wo2VWk/n/9V2TmqUZ/KpzRjCEcr00n7yahEdmtzlrfQ3lfMCf3Wa+0sqHAbjk3C6CKkR3WKK/whkMq5Gj4Da9g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-darwin-arm64@0.15.16:
|
||||
resolution: {integrity: sha512-fMXaUr5ou0M4WnewBKsspMtX++C1yIa3nJ5R2LSbLCfJT3uFdcRoU/NZjoM4kOMKyOD9Sa/2vlgN8G07K3SJnw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-freebsd-64@0.15.16:
|
||||
resolution: {integrity: sha512-UzIc0xlRx5x9kRuMr+E3+hlSOxa/aRqfuMfiYBXu2jJ8Mzej4lGL7+o6F5hzhLqWfWm1GWHNakIdlqg1ayaTNQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-freebsd-arm64@0.15.16:
|
||||
resolution: {integrity: sha512-8xyiYuGc0DLZphFQIiYaLHlfoP+hAN9RHbE+Ibh8EUcDNHAqbQgUrQg7pE7Bo00rXmQ5Ap6KFgcR0b4ALZls1g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-32@0.15.16:
|
||||
resolution: {integrity: sha512-iGijUTV+0kIMyUVoynK0v+32Oi8yyp0xwMzX69GX+5+AniNy/C/AL1MjFTsozRp/3xQPl7jVux/PLe2ds10/2w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-64@0.15.16:
|
||||
resolution: {integrity: sha512-tuSOjXdLw7VzaUj89fIdAaQT7zFGbKBcz4YxbWrOiXkwscYgE7HtTxUavreBbnRkGxKwr9iT/gmeJWNm4djy/g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-arm64@0.15.16:
|
||||
resolution: {integrity: sha512-mPYksnfHnemNrvjrDhZyixL/AfbJN0Xn9S34ZOHYdh6/jJcNd8iTsv3JwJoEvTJqjMggjMhGUPJAdjnFBHoH8A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-arm@0.15.16:
|
||||
resolution: {integrity: sha512-XKcrxCEXDTOuoRj5l12tJnkvuxXBMKwEC5j0JISw3ziLf0j4zIwXbKbTmUrKFWbo6ZgvNpa7Y5dnbsjVvH39bQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-mips64le@0.15.16:
|
||||
resolution: {integrity: sha512-kSJO2PXaxfm0pWY39+YX+QtpFqyyrcp0ZeI8QPTrcFVQoWEPiPVtOfTZeS3ZKedfH+Ga38c4DSzmKMQJocQv6A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-ppc64le@0.15.16:
|
||||
resolution: {integrity: sha512-NimPikwkBY0yGABw6SlhKrtT35sU4O23xkhlrTT/O6lSxv3Pm5iSc6OYaqVAHWkLdVf31bF4UDVFO+D990WpAA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-riscv64@0.15.16:
|
||||
resolution: {integrity: sha512-ty2YUHZlwFOwp7pR+J87M4CVrXJIf5ZZtU/umpxgVJBXvWjhziSLEQxvl30SYfUPq0nzeWKBGw5i/DieiHeKfw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-linux-s390x@0.15.16:
|
||||
resolution: {integrity: sha512-VkZaGssvPDQtx4fvVdZ9czezmyWyzpQhEbSNsHZZN0BHvxRLOYAQ7sjay8nMQwYswP6O2KlZluRMNPYefFRs+w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-netbsd-64@0.15.16:
|
||||
resolution: {integrity: sha512-ElQ9rhdY51et6MJTWrCPbqOd/YuPowD7Cxx3ee8wlmXQQVW7UvQI6nSprJ9uVFQISqSF5e5EWpwWqXZsECLvXg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-openbsd-64@0.15.16:
|
||||
resolution: {integrity: sha512-KgxMHyxMCT+NdLQE1zVJEsLSt2QQBAvJfmUGDmgEq8Fvjrf6vSKB00dVHUEDKcJwMID6CdgCpvYNt999tIYhqA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-sunos-64@0.15.16:
|
||||
resolution: {integrity: sha512-exSAx8Phj7QylXHlMfIyEfNrmqnLxFqLxdQF6MBHPdHAjT7fsKaX6XIJn+aQEFiOcE4X8e7VvdMCJ+WDZxjSRQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-windows-32@0.15.16:
|
||||
resolution: {integrity: sha512-zQgWpY5pUCSTOwqKQ6/vOCJfRssTvxFuEkpB4f2VUGPBpdddZfdj8hbZuFRdZRPIVHvN7juGcpgCA/XCF37mAQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-windows-64@0.15.16:
|
||||
resolution: {integrity: sha512-HjW1hHRLSncnM3MBCP7iquatHVJq9l0S2xxsHHj4yzf4nm9TU4Z7k4NkeMlD/dHQ4jPlQQhwcMvwbJiOefSuZw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild-windows-arm64@0.15.16:
|
||||
resolution: {integrity: sha512-oCcUKrJaMn04Vxy9Ekd8x23O8LoU01+4NOkQ2iBToKgnGj5eo1vU9i27NQZ9qC8NFZgnQQZg5oZWAejmbsppNA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/esbuild@0.15.16:
|
||||
resolution: {integrity: sha512-o6iS9zxdHrrojjlj6pNGC2NAg86ECZqIETswTM5KmJitq+R1YmahhWtMumeQp9lHqJaROGnsBi2RLawGnfo5ZQ==}
|
||||
/esbuild@0.17.19:
|
||||
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@esbuild/android-arm': 0.15.16
|
||||
'@esbuild/linux-loong64': 0.15.16
|
||||
esbuild-android-64: 0.15.16
|
||||
esbuild-android-arm64: 0.15.16
|
||||
esbuild-darwin-64: 0.15.16
|
||||
esbuild-darwin-arm64: 0.15.16
|
||||
esbuild-freebsd-64: 0.15.16
|
||||
esbuild-freebsd-arm64: 0.15.16
|
||||
esbuild-linux-32: 0.15.16
|
||||
esbuild-linux-64: 0.15.16
|
||||
esbuild-linux-arm: 0.15.16
|
||||
esbuild-linux-arm64: 0.15.16
|
||||
esbuild-linux-mips64le: 0.15.16
|
||||
esbuild-linux-ppc64le: 0.15.16
|
||||
esbuild-linux-riscv64: 0.15.16
|
||||
esbuild-linux-s390x: 0.15.16
|
||||
esbuild-netbsd-64: 0.15.16
|
||||
esbuild-openbsd-64: 0.15.16
|
||||
esbuild-sunos-64: 0.15.16
|
||||
esbuild-windows-32: 0.15.16
|
||||
esbuild-windows-64: 0.15.16
|
||||
esbuild-windows-arm64: 0.15.16
|
||||
'@esbuild/android-arm': 0.17.19
|
||||
'@esbuild/android-arm64': 0.17.19
|
||||
'@esbuild/android-x64': 0.17.19
|
||||
'@esbuild/darwin-arm64': 0.17.19
|
||||
'@esbuild/darwin-x64': 0.17.19
|
||||
'@esbuild/freebsd-arm64': 0.17.19
|
||||
'@esbuild/freebsd-x64': 0.17.19
|
||||
'@esbuild/linux-arm': 0.17.19
|
||||
'@esbuild/linux-arm64': 0.17.19
|
||||
'@esbuild/linux-ia32': 0.17.19
|
||||
'@esbuild/linux-loong64': 0.17.19
|
||||
'@esbuild/linux-mips64el': 0.17.19
|
||||
'@esbuild/linux-ppc64': 0.17.19
|
||||
'@esbuild/linux-riscv64': 0.17.19
|
||||
'@esbuild/linux-s390x': 0.17.19
|
||||
'@esbuild/linux-x64': 0.17.19
|
||||
'@esbuild/netbsd-x64': 0.17.19
|
||||
'@esbuild/openbsd-x64': 0.17.19
|
||||
'@esbuild/sunos-x64': 0.17.19
|
||||
'@esbuild/win32-arm64': 0.17.19
|
||||
'@esbuild/win32-ia32': 0.17.19
|
||||
'@esbuild/win32-x64': 0.17.19
|
||||
|
||||
/escalade@3.1.1:
|
||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||
@@ -2540,6 +2511,7 @@ packages:
|
||||
|
||||
/function-bind@1.1.1:
|
||||
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
|
||||
dev: true
|
||||
|
||||
/function.prototype.name@1.1.5:
|
||||
resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
|
||||
@@ -2695,6 +2667,7 @@ packages:
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
dev: true
|
||||
|
||||
/he@1.2.0:
|
||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||
@@ -2805,6 +2778,7 @@ packages:
|
||||
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
||||
dependencies:
|
||||
has: 1.0.3
|
||||
dev: true
|
||||
|
||||
/is-date-object@1.0.5:
|
||||
resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
|
||||
@@ -3059,13 +3033,6 @@ packages:
|
||||
sourcemap-codec: 1.4.8
|
||||
dev: true
|
||||
|
||||
/magic-string@0.27.0:
|
||||
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/merge-stream@2.0.0:
|
||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||
dev: true
|
||||
@@ -3117,8 +3084,8 @@ packages:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
dev: true
|
||||
|
||||
/naive-ui@2.34.2(vue@3.2.45):
|
||||
resolution: {integrity: sha512-JyvtVqHzS0O0DyPFFg95cJW0fp2WCEPsjXbeplkxFIfJHCgp5KC75PjnBycryegjPiZNLn9WlRDxXU5emEqRfg==}
|
||||
/naive-ui@2.34.4(vue@3.2.45):
|
||||
resolution: {integrity: sha512-aPG8PDfhSzIzn/jSC9y3Jb3Pe2wHJ7F0cFV1EWlbImSrZECeUmoc+fIcOSWbizoztkKfaUAeKwYdMl09MKkj1g==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
@@ -3140,7 +3107,7 @@ packages:
|
||||
vdirs: 0.1.8(vue@3.2.45)
|
||||
vooks: 0.2.12(vue@3.2.45)
|
||||
vue: 3.2.45
|
||||
vueuc: 0.4.49(vue@3.2.45)
|
||||
vueuc: 0.4.51(vue@3.2.45)
|
||||
dev: true
|
||||
|
||||
/nanoid@3.3.4:
|
||||
@@ -3148,6 +3115,11 @@ packages:
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
/nanoid@3.3.6:
|
||||
resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
|
||||
/ndarray-pack@1.2.1:
|
||||
resolution: {integrity: sha512-51cECUJMT0rUZNQa09EoKsnFeDL4x2dHRT0VR5U2H5ZgEcm95ZDWcMA5JShroXjHOejmAD/fg8+H+OvUnVXz2g==}
|
||||
dependencies:
|
||||
@@ -3261,6 +3233,7 @@ packages:
|
||||
|
||||
/path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
dev: true
|
||||
|
||||
/pathe@0.2.0:
|
||||
resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
|
||||
@@ -3337,6 +3310,14 @@ packages:
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
|
||||
/postcss@8.4.23:
|
||||
resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
dependencies:
|
||||
nanoid: 3.3.6
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
|
||||
/pretty-bytes@5.6.0:
|
||||
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -3488,6 +3469,7 @@ packages:
|
||||
is-core-module: 2.11.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
|
||||
/reusify@1.0.4:
|
||||
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
|
||||
@@ -3512,14 +3494,14 @@ packages:
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/rollup@3.10.0:
|
||||
resolution: {integrity: sha512-JmRYz44NjC1MjVF2VKxc0M1a97vn+cDxeqWmnwyAF4FvpjK8YFdHpaqvQB+3IxCvX05vJxKZkoMDU8TShhmJVA==}
|
||||
/rollup@3.23.0:
|
||||
resolution: {integrity: sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==}
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
@@ -3698,6 +3680,7 @@ packages:
|
||||
/supports-preserve-symlinks-flag@1.0.0:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/temp-dir@2.0.0:
|
||||
resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==}
|
||||
@@ -3960,7 +3943,7 @@ packages:
|
||||
extsprintf: 1.3.0
|
||||
dev: false
|
||||
|
||||
/vite-plugin-html@3.2.0(vite@3.2.4):
|
||||
/vite-plugin-html@3.2.0(vite@4.3.8):
|
||||
resolution: {integrity: sha512-2VLCeDiHmV/BqqNn5h2V+4280KRgQzCFN47cst3WiNK848klESPQnzuC3okH5XHtgwHH/6s1Ho/YV6yIO0pgoQ==}
|
||||
peerDependencies:
|
||||
vite: '>=2.0.0'
|
||||
@@ -3977,30 +3960,28 @@ packages:
|
||||
html-minifier-terser: 6.1.0
|
||||
node-html-parser: 5.4.2
|
||||
pathe: 0.2.0
|
||||
vite: 3.2.4(sass@1.56.1)
|
||||
vite: 4.3.8(sass@1.56.1)
|
||||
dev: false
|
||||
|
||||
/vite-plugin-pwa@0.14.1(vite@3.2.4)(workbox-build@6.5.4)(workbox-window@6.5.4):
|
||||
resolution: {integrity: sha512-5zx7yhQ8RTLwV71+GA9YsQQ63ALKG8XXIMqRJDdZkR8ZYftFcRgnzM7wOWmQZ/DATspyhPih5wCdcZnAIsM+mA==}
|
||||
/vite-plugin-pwa@0.15.0(vite@4.3.8)(workbox-build@6.5.4)(workbox-window@6.5.4):
|
||||
resolution: {integrity: sha512-gpmx3BeubsRIXRBkjPToOTJbo8fknNmZFQs24i0TPZyaNVa0n27YHDo0Y72amnO70WvHKGE3e1fn8SYUP7e8SA==}
|
||||
peerDependencies:
|
||||
vite: ^3.1.0 || ^4.0.0
|
||||
workbox-build: ^6.5.4
|
||||
workbox-window: ^6.5.4
|
||||
dependencies:
|
||||
'@rollup/plugin-replace': 5.0.2(rollup@3.10.0)
|
||||
debug: 4.3.4
|
||||
fast-glob: 3.2.12
|
||||
pretty-bytes: 6.0.0
|
||||
rollup: 3.10.0
|
||||
vite: 3.2.4(sass@1.56.1)
|
||||
vite: 4.3.8(sass@1.56.1)
|
||||
workbox-build: 6.5.4
|
||||
workbox-window: 6.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vite@3.2.4(sass@1.56.1):
|
||||
resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==}
|
||||
/vite@4.3.8(sass@1.56.1):
|
||||
resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -4024,10 +4005,9 @@ packages:
|
||||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
esbuild: 0.15.16
|
||||
postcss: 8.4.19
|
||||
resolve: 1.22.1
|
||||
rollup: 2.79.1
|
||||
esbuild: 0.17.19
|
||||
postcss: 8.4.23
|
||||
rollup: 3.23.0
|
||||
sass: 1.56.1
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
@@ -4091,8 +4071,8 @@ packages:
|
||||
'@vue/server-renderer': 3.2.45(vue@3.2.45)
|
||||
'@vue/shared': 3.2.45
|
||||
|
||||
/vueuc@0.4.49(vue@3.2.45):
|
||||
resolution: {integrity: sha512-WarAC44a/Yx78CxkAgROYLq+LkAeCGA/6wHidVoFmHLbzyF3SiP2nzRNGD/8zJeJInXv18EnWK6A//eGgMMq8w==}
|
||||
/vueuc@0.4.51(vue@3.2.45):
|
||||
resolution: {integrity: sha512-pLiMChM4f+W8czlIClGvGBYo656lc2Y0/mXFSCydcSmnCR1izlKPGMgiYBGjbY9FDkFG8a2HEVz7t0DNzBWbDw==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.11
|
||||
dependencies:
|
||||
|
||||
28
src/App.vue
28
src/App.vue
@@ -42,11 +42,13 @@ import { musicStore, userStore, settingStore, siteStore } from "@/store";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getLoginState, refreshLogin } from "@/api/login";
|
||||
import { userDailySignin, userYunbeiSign } from "@/api/user";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Provider from "@/components/Provider/index.vue";
|
||||
import Nav from "@/components/Nav/index.vue";
|
||||
import Player from "@/components/Player/index.vue";
|
||||
import packageJson from "@/../package.json";
|
||||
|
||||
const { t } = useI18n();
|
||||
const music = musicStore();
|
||||
const user = userStore();
|
||||
const setting = settingStore();
|
||||
@@ -122,27 +124,23 @@ const signIn = () => {
|
||||
Promise.all(signInPromises)
|
||||
.then((results) => {
|
||||
localStorage.setItem("lastSignInDate", today);
|
||||
console.log("签到成功!");
|
||||
console.log("userDailySignin:", results[0]);
|
||||
console.log("userYunbeiSign:", results[1]);
|
||||
console.log(t("general.message.signInSuccess"), results[0], results[1]);
|
||||
$notification["success"]({
|
||||
content: "签到成功",
|
||||
meta: "每日签到及云贝签到成功",
|
||||
content: t("general.message.signInSuccess"),
|
||||
meta: t("general.message.signInSuccessDesc"),
|
||||
duration: 3000,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("签到失败:", error);
|
||||
$message.error("每日签到失败");
|
||||
console.error(t("general.message.signInFailed"), error);
|
||||
$message.error(t("general.message.signInFailed"));
|
||||
});
|
||||
} else {
|
||||
console.log("今天已经签到过了!");
|
||||
}
|
||||
};
|
||||
|
||||
// 系统重置
|
||||
const cleanAll = () => {
|
||||
$message ? $message.success("重置成功") : alert("重置成功");
|
||||
$message ? $message.success(t("other.cleanAll")) : alert(t("other.cleanAll"));
|
||||
localStorage.clear();
|
||||
document.location.reload();
|
||||
};
|
||||
@@ -166,6 +164,10 @@ onMounted(() => {
|
||||
window.$signIn = signIn;
|
||||
window.$setSiteTitle = setSiteTitle;
|
||||
|
||||
// 更改页面语言
|
||||
const html = document.documentElement;
|
||||
if (html) html.setAttribute("lang", setting.language);
|
||||
|
||||
// 公告
|
||||
if (annShow) {
|
||||
$notification["info"]({
|
||||
@@ -204,15 +206,15 @@ onMounted(() => {
|
||||
} else {
|
||||
user.userLogOut();
|
||||
if (music.getPlayListMode === "cloud") {
|
||||
$message.info("登录已失效,请重新登录");
|
||||
$message.info(t("other.loginExpired"));
|
||||
music.setPlaylists([]);
|
||||
music.setPlayListMode("list");
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
$message.error("请求发生错误");
|
||||
console.error("请求发生错误" + err);
|
||||
console.error(t("general.message.acquisitionFailed"), err);
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
router.push("/500");
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -100,6 +100,7 @@ export const getMusicDetail = (ids) => {
|
||||
url: "/song/detail",
|
||||
params: {
|
||||
ids,
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
>
|
||||
<n-text
|
||||
class="name"
|
||||
depth="3"
|
||||
:depth="isDark ? 3 : 0"
|
||||
v-html="item.name"
|
||||
@click.stop="jumpArtist(item.id)"
|
||||
/>
|
||||
@@ -34,6 +34,11 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
// 是否变灰
|
||||
isDark: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
// 跳转歌手页面
|
||||
@@ -67,4 +72,4 @@ const jumpArtist = (id) => {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -173,6 +173,7 @@ const renderIcon = (icon) => {
|
||||
|
||||
// 封面图像地址
|
||||
const getCoverUrl = (url) => {
|
||||
if (!url) return "/images/pic/default.png";
|
||||
const imageUrl = url.replace(/^http:/, "https:");
|
||||
if (imageUrl.endsWith(".jpg")) {
|
||||
return imageUrl + "?param=300y300";
|
||||
|
||||
@@ -273,4 +273,4 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@@ -215,7 +215,7 @@ const changeUserOptions = (val) => {
|
||||
userOptions.value = val
|
||||
? [
|
||||
{
|
||||
label: t("nav.userChildren.playlists"),
|
||||
label: t("nav.userChildren.playlist"),
|
||||
key: "/user/playlists",
|
||||
},
|
||||
{
|
||||
@@ -227,7 +227,7 @@ const changeUserOptions = (val) => {
|
||||
key: "/user/album",
|
||||
},
|
||||
{
|
||||
label: t("nav.userChildren.artists"),
|
||||
label: t("nav.userChildren.artist"),
|
||||
key: "/user/artists",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -10,12 +10,17 @@
|
||||
:show-size-picker="showSizePicker"
|
||||
:show-quick-jumper="showQuickJumper"
|
||||
>
|
||||
<template #prefix="{ itemCount }"> 共 {{ itemCount }} 项 </template>
|
||||
<template #goto> 前往 </template>
|
||||
<template #prefix="{ itemCount }">
|
||||
{{ $t("general.name.itemCount", { size: itemCount }) }}
|
||||
</template>
|
||||
<template #goto> {{ $t("general.name.goto") }} </template>
|
||||
</n-pagination>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
// 数据总量
|
||||
totalCount: {
|
||||
@@ -47,23 +52,23 @@ const currentPageNumber = ref(1);
|
||||
// 自定义每页数量
|
||||
const pageSizes = ref([
|
||||
{
|
||||
label: "10条/页",
|
||||
label: t("general.name.pageSizes", { num: 10 }),
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
label: "20条/页",
|
||||
label: t("general.name.pageSizes", { num: 20 }),
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
label: "30条/页",
|
||||
label: t("general.name.pageSizes", { num: 30 }),
|
||||
value: 30,
|
||||
},
|
||||
{
|
||||
label: "50条/页",
|
||||
label: t("general.name.pageSizes", { num: 50 }),
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
label: "100条/页",
|
||||
label: t("general.name.pageSizes", { num: 100 }),
|
||||
value: 100,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<!-- 提示文本 -->
|
||||
<Transition name="lrc">
|
||||
<div class="tip" v-show="lrcMouseStatus">
|
||||
<n-text>点击选中的歌词以调整播放进度</n-text>
|
||||
<n-text>{{ $t("other.lrcClicks") }}</n-text>
|
||||
</div>
|
||||
</Transition>
|
||||
<div class="left">
|
||||
@@ -78,7 +78,7 @@
|
||||
<span>{{
|
||||
music.getPlaySongData
|
||||
? music.getPlaySongData.name
|
||||
: "暂无歌曲"
|
||||
: $t("other.noSong")
|
||||
}}</span>
|
||||
<span
|
||||
v-if="music.getPlaySongData && music.getPlaySongData.alia"
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
<div class="desc">
|
||||
<span class="name text-hidden">
|
||||
{{
|
||||
music.getPlaySongData ? music.getPlaySongData.name : "暂无歌曲"
|
||||
music.getPlaySongData
|
||||
? music.getPlaySongData.name
|
||||
: $t("other.noSong")
|
||||
}}
|
||||
</span>
|
||||
<div v-if="music.getPlaySongData" class="message">
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
@click.stop="router.push(`/song?id=${music.getPlaySongData.id}`)"
|
||||
>
|
||||
{{
|
||||
music.getPlaySongData ? music.getPlaySongData.name : "暂无歌曲"
|
||||
music.getPlaySongData
|
||||
? music.getPlaySongData.name
|
||||
: $t("other.noSong")
|
||||
}}
|
||||
</div>
|
||||
<div class="artisrOrLrc" v-if="music.getPlaySongData">
|
||||
@@ -112,7 +114,6 @@
|
||||
<div class="control">
|
||||
<n-icon
|
||||
v-if="!music.getPersonalFmMode"
|
||||
title="上一曲"
|
||||
class="prev"
|
||||
size="30"
|
||||
:component="SkipPreviousRound"
|
||||
@@ -128,7 +129,6 @@
|
||||
<div class="play-state">
|
||||
<n-icon
|
||||
size="46"
|
||||
:title="music.getPlayState ? '暂停' : '播放'"
|
||||
:component="
|
||||
music.getPlayState ? PauseCircleFilled : PlayCircleFilled
|
||||
"
|
||||
@@ -260,6 +260,7 @@ import {
|
||||
import { getSongPlayingTime } from "@/utils/timeTools";
|
||||
import { useRouter } from "vue-router";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import VueSlider from "vue-slider-component";
|
||||
import AddPlaylist from "@/components/DataModal/AddPlaylist.vue";
|
||||
import PlayListDrawer from "@/components/DataModal/PlayListDrawer.vue";
|
||||
@@ -268,6 +269,7 @@ import ColorThief from "colorthief";
|
||||
import BigPlayer from "./BigPlayer.vue";
|
||||
import "vue-slider-component/theme/default.css";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const setting = settingStore();
|
||||
const music = musicStore();
|
||||
@@ -302,7 +304,7 @@ const getPlaySongData = (data, level = setting.songLevel) => {
|
||||
if (res.success) {
|
||||
console.log("当前歌曲可用");
|
||||
if (!pc && (fee === 1 || fee === 4))
|
||||
$message.info("当前歌曲为 VIP 专享,仅可试听");
|
||||
$message.info(t("general.message.vipTip"));
|
||||
// 获取音乐地址
|
||||
getMusicUrl(id, level).then((res) => {
|
||||
player.value = createSound(
|
||||
@@ -313,7 +315,7 @@ const getPlaySongData = (data, level = setting.songLevel) => {
|
||||
if (useUnmServerHas && setting.useUnmServer) {
|
||||
getMusicNumUrlData(id);
|
||||
} else {
|
||||
$message.warning("当前歌曲播放失败,跳至下一首");
|
||||
$message.warning(t("general.message.playError"));
|
||||
music.setPlaySongIndex("next");
|
||||
}
|
||||
}
|
||||
@@ -326,7 +328,7 @@ const getPlaySongData = (data, level = setting.songLevel) => {
|
||||
} catch (err) {
|
||||
if (music.getPlaylists[0] && music.getPlayState) {
|
||||
console.log("当前歌曲所有音源匹配失败:" + err);
|
||||
$message.warning("当前歌曲所有音源匹配失败,跳至下一首");
|
||||
$message.warning(t("general.message.playError"));
|
||||
music.setPlaySongIndex("next");
|
||||
}
|
||||
}
|
||||
@@ -343,7 +345,7 @@ const getMusicNumUrlData = (id) => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("解灰失败:" + err);
|
||||
$message.warning("当前歌曲解灰失败,跳至下一首");
|
||||
$message.warning(t("general.message.playError"));
|
||||
music.setPlaySongIndex("next");
|
||||
});
|
||||
};
|
||||
|
||||
@@ -8,14 +8,15 @@ export default {
|
||||
toplists: "Toplists",
|
||||
artists: "Artists",
|
||||
},
|
||||
user: "My",
|
||||
user: "Library",
|
||||
userChildren: {
|
||||
playlists: "My Playlists",
|
||||
playlist: "My Playlists",
|
||||
like: "Liked Playlists",
|
||||
album: "Liked Albums",
|
||||
artists: "Liked Artists",
|
||||
artist: "Liked Artists",
|
||||
cloud: "Music Cloud",
|
||||
login: "Login",
|
||||
results: "Music Library",
|
||||
},
|
||||
avatar: {
|
||||
dark: "Dark Mode",
|
||||
@@ -43,7 +44,10 @@ export default {
|
||||
albums: "Albums",
|
||||
playlists: "Playlists",
|
||||
tip: "Confirm to delete all search history ?",
|
||||
results: "search results",
|
||||
},
|
||||
officialList: "Official List",
|
||||
globalList: "Global List",
|
||||
},
|
||||
// Home
|
||||
home: {
|
||||
@@ -51,7 +55,7 @@ export default {
|
||||
exclusive: "Exclusive Recommend",
|
||||
playlists: "Recommended Playlists",
|
||||
artists: "Artist Recommend",
|
||||
newAlbum: "New Release",
|
||||
newAlbum: "New Albums",
|
||||
more: "More",
|
||||
},
|
||||
modules: {
|
||||
@@ -73,6 +77,21 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
// Login
|
||||
login: {
|
||||
login: "Login {name}",
|
||||
qr: "QR",
|
||||
phone: "Captcha",
|
||||
email: "Email",
|
||||
canNotUse: "This login method is temporarily unavailable",
|
||||
loggedIn: "Already logged in, please don't log in again",
|
||||
qrText1: "Please open APP and scan the code to login",
|
||||
qrText2: "The current QR code is invalid, please scan it again",
|
||||
qrText3: "Scan successfully, please confirm login in the client",
|
||||
qrText4: "Login successfully",
|
||||
qrText5: "Login error, please try again",
|
||||
qrText6: "Login QR code generation failed",
|
||||
},
|
||||
// Menu
|
||||
menu: {
|
||||
play: "Play now",
|
||||
@@ -127,15 +146,44 @@ export default {
|
||||
},
|
||||
name: {
|
||||
song: "Song",
|
||||
hotSong: "Top Songs",
|
||||
playlist: "Playlist",
|
||||
playlists: "Playlists",
|
||||
videos: "Videos",
|
||||
toplists: "Toplists",
|
||||
artists: "Artists",
|
||||
album: "Album",
|
||||
link: "Link",
|
||||
cloud: "Cloud",
|
||||
songSize: "{size} songs",
|
||||
albumSize: "{size} albums",
|
||||
mvSize: "{size} MVs",
|
||||
unknownSong: "Unknown Songs",
|
||||
unknownArtist: "Unknown Artist",
|
||||
itemCount: "Total {size} items",
|
||||
goto: "Goto",
|
||||
pageSizes: "{num} items/page",
|
||||
desc: "{name} Introduction",
|
||||
allDesc: "All Introduction",
|
||||
allSong: "All Songs",
|
||||
allPLaylist: "All Playlists",
|
||||
artistDesc: "Singer Introduction",
|
||||
play: "Play",
|
||||
add: "Add",
|
||||
comment: "Comment",
|
||||
noKeywords: "Incomplete parameters",
|
||||
goBack: "Back to previous page",
|
||||
reload: "Reload",
|
||||
allComments: "All Comments",
|
||||
hotComments: "Hot Comments",
|
||||
toCurrentlySong: "Go to currently playing song",
|
||||
loadMore: "Load More",
|
||||
playlistType: "Playlist Category",
|
||||
bestPlaylist: "Best Playlist",
|
||||
upCloud: "Cloud Upload",
|
||||
cloudUsed: "Used {used}%, Remaining {remaining} G",
|
||||
simiVideo: "Similar Videos",
|
||||
restore: "Restore",
|
||||
},
|
||||
dialog: {
|
||||
check: "Check",
|
||||
@@ -148,6 +196,7 @@ export default {
|
||||
download: "Downloading",
|
||||
downloadingNow: "Downloading now",
|
||||
editor: "Editor",
|
||||
resetUp: "Re-Upload",
|
||||
},
|
||||
message: {
|
||||
copySuccess: "Copied successfully",
|
||||
@@ -161,6 +210,10 @@ export default {
|
||||
downloadSuccess: "{name} Download completed",
|
||||
downloadFailure: "Download failed, please try another sound quality",
|
||||
downloadError: "There was an error downloading, please try again",
|
||||
upCloudSuccess: "{name} Upload successful",
|
||||
upCloudFailure: "There was an error uploading the song",
|
||||
upCloudError: "There was an error uploading the song, please try again",
|
||||
upCloudNotHas: "Upload song details failed to get, try song match",
|
||||
editorSuccess: "Edit successful",
|
||||
editorFailed: "Edit failed, Please try again",
|
||||
operationFailed: "Operation failed, please try again",
|
||||
@@ -171,8 +224,23 @@ export default {
|
||||
needVip: "This operation requires a member account",
|
||||
needCheck: "Please check your input",
|
||||
isLoading: "Data loading",
|
||||
vipTip:
|
||||
"The current song is exclusive for VIP and can be listened to only",
|
||||
playError: "Current song failed to play, skip to next song",
|
||||
signInSuccess: "Sign In Success",
|
||||
signInSuccessDesc: "Daily sign-in and Yunbei sign-in success",
|
||||
signInFailed: "Failed to sign in",
|
||||
},
|
||||
},
|
||||
// State
|
||||
state: {
|
||||
prohibition: "Prohibit access",
|
||||
prohibitionDesc: "There are always doors that are closed to you",
|
||||
notFound: "Resources do not exist",
|
||||
notFoundDesc: "Why did you come here?",
|
||||
error: "Server error",
|
||||
errorDesc: "The server is broken, try again later",
|
||||
},
|
||||
// Other
|
||||
other: {
|
||||
sData: "Original song information",
|
||||
@@ -194,5 +262,100 @@ export default {
|
||||
plDesTip: "Please enter the playlist description",
|
||||
plTag: "Playlist Tags",
|
||||
plTagTip: "Please enter the playlist tags",
|
||||
lrcClicks: "Click on the selected lyrics to adjust the playback progress",
|
||||
noSong: "No Song",
|
||||
noHistory: "No play history",
|
||||
justShow: "Show only the last {num} songs",
|
||||
noDesc: "Too lazy, do not even write the introduction",
|
||||
containing: "Song list containing this song",
|
||||
loginExpired: "Login is disabled, please login again",
|
||||
cleanAll: "Reset successful",
|
||||
},
|
||||
// Setting
|
||||
setting: {
|
||||
main: "Basic",
|
||||
player: "Player",
|
||||
themeChange: "Theme color changed to {name}",
|
||||
themeType: "Theme Color Selection",
|
||||
themeTypeTip: "Change the site theme color, taking effect immediately",
|
||||
themeTypeDialog: "Confirm to restore the full site theme color as default?",
|
||||
language: "Language",
|
||||
changeLanguage: "Language has been switched to {name}",
|
||||
theme: "Light/Dark Mode",
|
||||
themeAuto: "Follow System Light/Dark Mode",
|
||||
autoSignIn: "Daily Check-in",
|
||||
autoSignInTip: "Automatically perform daily check-in",
|
||||
bannerShow: "Show Banner Image",
|
||||
listClickMode: "List Click Mode",
|
||||
listClickModeTip:
|
||||
"This setting is ineffective on mobile, both click modes will be in effect",
|
||||
dblclick: "Double-click to play",
|
||||
click: "Single-click to play",
|
||||
searchHistory: "Display Search History",
|
||||
bottomLyricShow: "Display Bottom Lyrics",
|
||||
bottomLyricShowTip:
|
||||
"Whether to display lyrics at the bottom of the screen while playing",
|
||||
songVolumeFade: "Song Volume Fade",
|
||||
songVolumeFadeTip:
|
||||
"Gradually fade in/out volume when stopping/starting playback",
|
||||
memoryLastPlaybackPosition: "Remember Playback Position",
|
||||
memoryLastPlaybackPositionTip:
|
||||
"Resume last playback progress after refreshing the page",
|
||||
songLevel: "Song Quality",
|
||||
songLevelTip:
|
||||
"Lossless quality and above require a Black Vinyl Club membership",
|
||||
standard: "Standard",
|
||||
higher: "Higher",
|
||||
exhigh: "Extreme",
|
||||
lossless: "Lossless",
|
||||
hires: "Hi-Res",
|
||||
jyeffect: "Whale Cloud Hi-Fi",
|
||||
jymaster: "Whale Cloud Master",
|
||||
useUnmServerShow: "Use UNM to play blocked songs",
|
||||
useUnmServerShowTip1: "Whether to use UNM to replace blocked song links",
|
||||
useUnmServerShowTip2:
|
||||
"Please configure UNM-Server before using unblocking feature",
|
||||
showLyricSetting: "Play Page Shortcut Settings",
|
||||
showLyricSettingTip: "Show shortcut settings on the play page",
|
||||
resetApp: "Reset the program",
|
||||
resetAppTip:
|
||||
"Try this if the program displays abnormally or if there is a problem",
|
||||
resetAppWarning:
|
||||
"Confirming reset to default? Your login status and custom settings will be lost!",
|
||||
playerStyle: "Player Style",
|
||||
playerStyleTip: "Style of the player's left-hand function area",
|
||||
cover: "Cover Mode",
|
||||
record: "Record Mode",
|
||||
backgroundImageShow: "Play Background Style",
|
||||
solid: "Solid Cover",
|
||||
blur: "Blurry Cover",
|
||||
backgroundImageShowTip1: "Display album cover in blurred mode",
|
||||
backgroundImageShowTip2: "Extract album's main color as background color",
|
||||
showTransl: "Show Lyric Translation",
|
||||
showTranslTip: "Whether to display lyric translation when available",
|
||||
showRoma: "Show Lyric Transliteration",
|
||||
showRomaTip: "Whether to display lyric transliteration when available",
|
||||
countDownShow: "Show Countdown Before Playing",
|
||||
countDownShowTip: "Some songs may have incorrect countdown display",
|
||||
showYrc: "Show Word-by-Word Lyrics",
|
||||
showYrcTip:
|
||||
"Whether to display word-by-word lyrics when available, experimental feature",
|
||||
lrcMousePause: "Intelligent Scroll Pause",
|
||||
lrcMousePauseTip:
|
||||
"Whether to pause scrolling when the mouse is over the lyrics area",
|
||||
lyricsBlock: "Lyric Scrolling Position",
|
||||
lyricsBlockTip: "The position where the lyrics are highlighted",
|
||||
blockStart: "Near the Top",
|
||||
blockCenter: "Horizontally Centered",
|
||||
lyricsFontSize: "Lyric Text Size",
|
||||
lyrics1: "Smallest",
|
||||
lyrics2: "Default",
|
||||
lyrics3: "Largest",
|
||||
lyricsPosition: "Default Lyric Position",
|
||||
positionLeft: "Left",
|
||||
positionCenter: "Centered",
|
||||
lyricsBlur: "Lyric Blur",
|
||||
lyricsBlurTip:
|
||||
"Blur lyrics other than the currently playing ones, experimental feature",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -8,14 +8,15 @@ export default {
|
||||
toplists: "排行榜",
|
||||
artists: "歌手",
|
||||
},
|
||||
user: "我的",
|
||||
user: "音乐库",
|
||||
userChildren: {
|
||||
login: "登录账号",
|
||||
playlists: "我的歌单",
|
||||
playlist: "我的歌单",
|
||||
like: "收藏的歌单",
|
||||
album: "收藏的专辑",
|
||||
artists: "收藏的歌手",
|
||||
artist: "收藏的歌手",
|
||||
cloud: "音乐云盘",
|
||||
results: "的音乐库",
|
||||
},
|
||||
avatar: {
|
||||
dark: "深色模式",
|
||||
@@ -43,7 +44,10 @@ export default {
|
||||
albums: "专辑",
|
||||
playlists: "歌单",
|
||||
tip: "确认删除全部的搜索历史记录?",
|
||||
results: "的搜索结果",
|
||||
},
|
||||
officialList: "官方榜",
|
||||
globalList: "全球榜",
|
||||
},
|
||||
// 首页
|
||||
home: {
|
||||
@@ -73,6 +77,21 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
// Login
|
||||
login: {
|
||||
login: "登录 {name}",
|
||||
qr: "扫码登录",
|
||||
phone: "验证码登录",
|
||||
email: "邮箱登录",
|
||||
canNotUse: "该登录方式暂时无法使用",
|
||||
loggedIn: "已登录,请勿重复登录",
|
||||
qrText1: "请打开云音乐 APP 扫码登录",
|
||||
qrText2: "当前二维码已失效,请重新扫码",
|
||||
qrText3: "扫描成功,请在客户端确认登录",
|
||||
qrText4: "登录成功",
|
||||
qrText5: "登录出错,请重试",
|
||||
qrText6: "登录二维码生成失败",
|
||||
},
|
||||
// 菜单
|
||||
menu: {
|
||||
play: "立即播放",
|
||||
@@ -125,7 +144,9 @@ export default {
|
||||
},
|
||||
name: {
|
||||
song: "歌曲",
|
||||
hotSong: "热门歌曲",
|
||||
playlist: "歌单",
|
||||
videos: "视频",
|
||||
playlists: "播放列表",
|
||||
toplists: "排行榜",
|
||||
artists: "歌手",
|
||||
@@ -133,7 +154,34 @@ export default {
|
||||
link: "链接",
|
||||
cloud: "云盘",
|
||||
songSize: "{size} 首",
|
||||
albumSize: "{size} 张专辑",
|
||||
mvSize: "{size} 个 MV",
|
||||
unknownSong: "未知歌曲",
|
||||
unknownArtist: "未知歌手",
|
||||
itemCount: "共{size}项",
|
||||
goto: "前往",
|
||||
pageSizes: "{num}条/页",
|
||||
desc: "{name}简介",
|
||||
allDesc: "全部简介",
|
||||
allSong: "全部歌曲",
|
||||
allPLaylist: "全部歌单",
|
||||
artistDesc: "歌手介绍",
|
||||
play: "播放",
|
||||
add: "添加",
|
||||
comment: "评论",
|
||||
noKeywords: "参数不完整",
|
||||
goBack: "返回上一级",
|
||||
reload: "重新载入",
|
||||
allComments: "全部评论",
|
||||
hotComments: "热门评论",
|
||||
toCurrentlySong: "前往当前播放歌曲",
|
||||
loadMore: "加载更多",
|
||||
playlistType: "歌单分类",
|
||||
bestPlaylist: "精品歌单",
|
||||
upCloud: "云盘上传",
|
||||
cloudUsed: "已用 {used}%,剩余 {remaining} G",
|
||||
simiVideo: "相似视频",
|
||||
restore: "恢复默认",
|
||||
},
|
||||
dialog: {
|
||||
check: "检查",
|
||||
@@ -146,6 +194,7 @@ export default {
|
||||
download: "下载",
|
||||
downloadingNow: "正在下载",
|
||||
editor: "编辑",
|
||||
resetUp: "重新上传",
|
||||
},
|
||||
message: {
|
||||
copySuccess: "复制成功",
|
||||
@@ -159,6 +208,10 @@ export default {
|
||||
downloadSuccess: "{name}下载完成",
|
||||
downloadFailure: "下载失败,请尝试其他音质",
|
||||
downloadError: "下载出现错误,请重试",
|
||||
upCloudSuccess: "{name} 上传成功",
|
||||
upCloudFailure: "歌曲上传出现错误",
|
||||
upCloudError: "歌曲上传出错,请重试",
|
||||
upCloudNotHas: "上传歌曲详细信息获取失败,可尝试歌曲匹配",
|
||||
editorSuccess: "编辑成功",
|
||||
editorFailed: "编辑失败,请重试",
|
||||
operationFailed: "操作失败,请重试",
|
||||
@@ -169,8 +222,22 @@ export default {
|
||||
needVip: "该操作需要账号为黑胶会员",
|
||||
needCheck: "请检查您的输入",
|
||||
isLoading: "数据加载中",
|
||||
vipTip: "当前歌曲为 VIP 专享,仅可试听",
|
||||
playError: "当前歌曲播放失败,跳至下一首",
|
||||
signInSuccess: "签到成功",
|
||||
signInSuccessDesc: "每日签到及云贝签到成功",
|
||||
signInFailed: "签到失败",
|
||||
},
|
||||
},
|
||||
// State
|
||||
state: {
|
||||
prohibition: "禁止访问",
|
||||
prohibitionDesc: "总有些门是对你关闭的",
|
||||
notFound: "资源不存在",
|
||||
notFoundDesc: "怎么跑到这来了?",
|
||||
error: "服务器错误",
|
||||
errorDesc: "服务器寄了,等会再试吧",
|
||||
},
|
||||
// Other
|
||||
other: {
|
||||
sData: "原歌曲信息",
|
||||
@@ -191,5 +258,88 @@ export default {
|
||||
plDesTip: "请输入歌单描述",
|
||||
plTag: "歌单标签",
|
||||
plTagTip: "请输入歌单标签",
|
||||
lrcClicks: "点击选中的歌词以调整播放进度",
|
||||
noSong: "暂无歌曲",
|
||||
noHistory: "暂无播放历史",
|
||||
justShow: "仅显示最近 {num} 首",
|
||||
noDesc: "太懒了吧,连简介都不写",
|
||||
containing: "包含这首歌的歌单",
|
||||
loginExpired: "登录已失效,请重新登录",
|
||||
cleanAll: "重置成功",
|
||||
},
|
||||
setting: {
|
||||
main: "基础",
|
||||
player: "播放器",
|
||||
themeChange: "主题色更换为 {name}",
|
||||
themeType: "主题色选择",
|
||||
themeTypeTip: "更换全站主题色,即时生效",
|
||||
themeTypeDialog: "确认恢复全站主题色为默认?",
|
||||
language: "语言",
|
||||
changeLanguage: "语言已切换为 {name}",
|
||||
theme: "明暗模式",
|
||||
themeAuto: "明暗模式跟随系统",
|
||||
autoSignIn: "每日签到",
|
||||
autoSignInTip: "是否自动进行每日签到",
|
||||
bannerShow: "显示轮播图",
|
||||
listClickMode: "列表点击方式",
|
||||
listClickModeTip: "移动端该设置项无效,单击同时生效",
|
||||
dblclick: "双击播放",
|
||||
click: "单击播放",
|
||||
searchHistory: "显示搜索历史",
|
||||
bottomLyricShow: "显示底栏歌词",
|
||||
bottomLyricShowTip: "是否在播放时显示歌词",
|
||||
songVolumeFade: "歌曲渐入渐出",
|
||||
songVolumeFadeTip: "是否在歌曲暂停 / 播放时渐入渐出",
|
||||
memoryLastPlaybackPosition: "记忆播放位置",
|
||||
memoryLastPlaybackPositionTip: "是否在刷新后恢复上次播放进度",
|
||||
songLevel: "歌曲音质",
|
||||
songLevelTip: "无损音质及以上需要您为黑胶会员",
|
||||
standard: "标准",
|
||||
higher: "较高",
|
||||
exhigh: "极高",
|
||||
lossless: "无损",
|
||||
hires: "Hi-Res",
|
||||
jyeffect: "鲸云臻音",
|
||||
jymaster: "鲸云母带",
|
||||
useUnmServerShow: "尝试替换无法播放的歌曲",
|
||||
useUnmServerShowTip1: "是否使用 UNM 替换无法播放的歌曲链接",
|
||||
useUnmServerShowTip2: "请配置 UNM-Server 后使用解灰功能",
|
||||
showLyricSetting: "播放页快捷设置",
|
||||
showLyricSettingTip: "是否在播放页面显示快捷设置",
|
||||
resetApp: "程序重置",
|
||||
resetAppTip: "若程序显示异常或出现问题时可尝试此操作",
|
||||
resetAppWarning: "确认重置为默认状态?你的登录状态以及自定义设置都将丢失!",
|
||||
playerStyle: "播放器样式",
|
||||
playerStyleTip: "播放器左侧功能区样式",
|
||||
cover: "封面模式",
|
||||
record: "唱片模式",
|
||||
backgroundImageShow: "播放背景样式",
|
||||
solid: "封面主色",
|
||||
blur: "封面模糊",
|
||||
backgroundImageShowTip1: "将专辑封面模糊显示",
|
||||
backgroundImageShowTip2: "提取专辑主色作为背景颜色",
|
||||
showTransl: "显示歌词翻译",
|
||||
showTranslTip: "是否在具有翻译歌词时显示",
|
||||
showRoma: "显示歌词音译",
|
||||
showRomaTip: "是否在具有音译歌词时显示",
|
||||
countDownShow: "显示前奏等待",
|
||||
countDownShowTip: "部分歌曲前奏可能存在显示错误",
|
||||
showYrc: "显示逐字歌词",
|
||||
showYrcTip: "是否在歌曲具有逐字歌词时显示,实验性功能",
|
||||
lrcMousePause: "智能暂停滚动",
|
||||
lrcMousePauseTip: "鼠标移入歌词区域是否暂停滚动",
|
||||
lyricsBlock: "歌词滚动位置",
|
||||
lyricsBlockTip: "歌词高亮时所处的位置",
|
||||
blockStart: "靠近顶部",
|
||||
blockCenter: "水平居中",
|
||||
lyricsFontSize: "歌词文本大小",
|
||||
lyrics1: "最小",
|
||||
lyrics2: "默认",
|
||||
lyrics3: "最大",
|
||||
lyricsPosition: "默认歌词位置",
|
||||
positionLeft: "居左",
|
||||
positionCenter: "居中",
|
||||
lyricsBlur: "歌词模糊",
|
||||
lyricsBlurTip: "除当前播放歌词外模糊显示,实验性功能",
|
||||
},
|
||||
};
|
||||
|
||||
38
src/main.js
38
src/main.js
@@ -18,25 +18,29 @@ app.use(pinia);
|
||||
app.use(router);
|
||||
|
||||
// 国际化
|
||||
useI18n(app)
|
||||
useI18n(app);
|
||||
|
||||
app.mount("#app");
|
||||
|
||||
// 检测到更新提醒
|
||||
let pwaMessage = null;
|
||||
navigator.serviceWorker.addEventListener("onupdatefound", () => {
|
||||
console.info("发现站点更新,正在下载新版本");
|
||||
pwaMessage = $message.loading("发现站点更新,正在下载新版本", {
|
||||
closable: true,
|
||||
duration: 0,
|
||||
if ("serviceWorker" in navigator) {
|
||||
let pwaMessage = null;
|
||||
|
||||
// 检测到更新提醒
|
||||
navigator.serviceWorker.addEventListener("onupdatefound", () => {
|
||||
console.info("发现站点更新,正在下载新版本");
|
||||
pwaMessage = $message.loading("发现站点更新,正在下载新版本", {
|
||||
closable: true,
|
||||
duration: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
// 更新完成提醒
|
||||
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||
console.info("站点已更新,刷新后生效");
|
||||
if (pwaMessage) pwaMessage?.destroy();
|
||||
$message.info("站点已更新,刷新后生效", {
|
||||
closable: true,
|
||||
duration: 0,
|
||||
|
||||
// 更新完成提醒
|
||||
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||
console.info("站点已更新,刷新后生效");
|
||||
if (pwaMessage) pwaMessage?.destroy();
|
||||
$message.info("站点已更新,刷新后生效", {
|
||||
closable: true,
|
||||
duration: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { NIcon } from "naive-ui";
|
||||
import { PlayCycle, PlayOnce, ShuffleOne } from "@icon-park/vue-next";
|
||||
import { soundStop, fadePlayOrPause } from "@/utils/Player";
|
||||
import parseLyric from "@/utils/parseLyric";
|
||||
import getLanguageData from "@/utils/getLanguageData";
|
||||
|
||||
const useMusicDataStore = defineStore("musicData", {
|
||||
state: () => {
|
||||
@@ -190,29 +191,28 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$message.error("获取私人 FM 失败");
|
||||
$message.error(getLanguageData("personalFmError"));
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("获取私人 FM 失败:" + err);
|
||||
$message.error("获取私人 FM 失败");
|
||||
console.error(getLanguageData("personalFmError"), err);
|
||||
$message.error(getLanguageData("personalFmError"));
|
||||
}
|
||||
},
|
||||
// 私人fm垃圾桶
|
||||
setFmDislike(id, tip = true) {
|
||||
setFmDislike(id) {
|
||||
const user = userStore();
|
||||
if (user.userLogin) {
|
||||
setFmTrash(id).then((res) => {
|
||||
if (res.code == 200) {
|
||||
if (tip) $message.success("已将该歌曲移除至垃圾桶");
|
||||
this.persistData.personalFmMode = true;
|
||||
this.setPlaySongIndex("next");
|
||||
} else {
|
||||
$message.error("歌曲移除至垃圾桶失败");
|
||||
$message.error(getLanguageData("fmTrashError"));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$message.error("请登录账号后使用");
|
||||
$message.error(getLanguageData("needLogin"));
|
||||
}
|
||||
},
|
||||
// 更改喜欢列表
|
||||
@@ -239,30 +239,30 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
setLikeSong(id, like).then((res) => {
|
||||
if (res.code == 200) {
|
||||
list.push(id);
|
||||
$message.info("已添加到我喜欢的音乐");
|
||||
$message.info(getLanguageData("loveSong"));
|
||||
} else {
|
||||
$message.error("喜欢音乐时发生错误");
|
||||
$message.error(getLanguageData("loveSongError"));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$message.info("我喜欢的音乐中已存在该歌曲");
|
||||
$message.info(getLanguageData("loveSongRepeat"));
|
||||
}
|
||||
} else {
|
||||
if (exists) {
|
||||
setLikeSong(id, like).then((res) => {
|
||||
if (res.code == 200) {
|
||||
list.splice(list.indexOf(id), 1);
|
||||
$message.info("已从我喜欢的音乐中移除");
|
||||
$message.info(getLanguageData("loveSongRemove"));
|
||||
} else {
|
||||
$message.error("取消喜欢音乐时发生错误");
|
||||
$message.error(getLanguageData("loveSongRemoveError"));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$message.error("我喜欢的列表中未找到该歌曲");
|
||||
$message.error(getLanguageData("loveSongNoFound"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$message.error("请登录账号后使用");
|
||||
$message.error(getLanguageData("needLogin"));
|
||||
}
|
||||
},
|
||||
// 更改音乐播放状态
|
||||
@@ -284,7 +284,6 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
// 添加歌单至播放列表
|
||||
setPlaylists(value) {
|
||||
this.persistData.playlists = value.slice();
|
||||
console.log(`已添加${value.length}首歌曲至播放列表`);
|
||||
},
|
||||
// 更改每日推荐数据
|
||||
setDailySongs(value) {
|
||||
@@ -303,8 +302,6 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
mv: v.mv ? v.mv : null,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("处理每日推荐发生错误");
|
||||
}
|
||||
},
|
||||
// 歌词处理
|
||||
@@ -313,8 +310,8 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
try {
|
||||
this.playSongLyric = parseLyric(value);
|
||||
} catch (err) {
|
||||
$message.error("歌词处理出错");
|
||||
console.error("歌词处理出错:" + err);
|
||||
$message.error(getLanguageData("getLrcError"));
|
||||
console.error(getLanguageData("getLrcError"), err);
|
||||
}
|
||||
} else {
|
||||
console.log("该歌曲暂无歌词");
|
||||
@@ -353,17 +350,17 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
setPlaySongMode() {
|
||||
if (this.persistData.playSongMode === "normal") {
|
||||
this.persistData.playSongMode = "random";
|
||||
$message.info("随机播放", {
|
||||
$message.info(getLanguageData("random"), {
|
||||
icon: () => h(NIcon, null, { default: () => h(ShuffleOne) }),
|
||||
});
|
||||
} else if (this.persistData.playSongMode === "random") {
|
||||
this.persistData.playSongMode = "single";
|
||||
$message.info("单曲循环", {
|
||||
$message.info(getLanguageData("single"), {
|
||||
icon: () => h(NIcon, null, { default: () => h(PlayOnce) }),
|
||||
});
|
||||
} else {
|
||||
this.persistData.playSongMode = "normal";
|
||||
$message.info("列表循环", {
|
||||
$message.info(getLanguageData("normal"), {
|
||||
icon: () => h(NIcon, null, { default: () => h(PlayCycle) }),
|
||||
});
|
||||
}
|
||||
@@ -389,7 +386,7 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
soundStop($player);
|
||||
fadePlayOrPause($player, "play", this.persistData.playVolume);
|
||||
} else {
|
||||
$message.error("播放出错,请刷新后重试");
|
||||
$message.error(getLanguageData("playError"));
|
||||
}
|
||||
// 判断是否处于最后/第一首
|
||||
if (this.persistData.playSongIndex < 0) {
|
||||
@@ -418,12 +415,12 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
value.id !==
|
||||
this.persistData.playlists[this.persistData.playSongIndex]?.id
|
||||
) {
|
||||
console.log("播放歌曲与上一次不一致");
|
||||
console.log("Play a song that is not the same as the last one");
|
||||
if (typeof $player !== "undefined") soundStop($player);
|
||||
this.isLoadingSong = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("出现错误:" + error);
|
||||
console.error("Error:" + error);
|
||||
}
|
||||
if (index !== -1) {
|
||||
this.persistData.playSongIndex = index;
|
||||
@@ -435,6 +432,9 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
},
|
||||
// 在当前播放歌曲后添加
|
||||
addSongToNext(value) {
|
||||
// 更改播放模式为列表循环
|
||||
this.persistData.playSongMode = "normal";
|
||||
// 查找是否存在于播放列表
|
||||
const index = this.persistData.playlists.findIndex(
|
||||
(o) => o.id === value.id
|
||||
);
|
||||
@@ -456,7 +456,7 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
value
|
||||
);
|
||||
}
|
||||
$message.success(value.name + " 已添加至下一曲播放");
|
||||
$message.success(value.name + " " + getLanguageData("addSongToNext"));
|
||||
},
|
||||
// 播放列表移除歌曲
|
||||
removeSong(index) {
|
||||
@@ -468,7 +468,7 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
// 如果删除的是当前播放歌曲,则重置播放器
|
||||
soundStop($player);
|
||||
}
|
||||
$message.success(name + " 已从播放列表中移除");
|
||||
$message.success(name + " " + getLanguageData("removeSong"));
|
||||
this.persistData.playlists.splice(index, 1);
|
||||
// 检查当前播放歌曲的索引是否超出了列表范围
|
||||
if (this.persistData.playSongIndex >= this.persistData.playlists.length) {
|
||||
@@ -482,7 +482,7 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
if (res.code == 200) {
|
||||
this.catList = res;
|
||||
} else {
|
||||
$message.error("歌单分类获取失败");
|
||||
$message.error(getLanguageData("getDataError"));
|
||||
}
|
||||
});
|
||||
if (highquality) {
|
||||
@@ -490,7 +490,7 @@ const useMusicDataStore = defineStore("musicData", {
|
||||
if (res.code == 200) {
|
||||
this.highqualityCatList = res.tags;
|
||||
} else {
|
||||
$message.error("精品歌单分类获取失败");
|
||||
$message.error(getLanguageData("getDataError"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { NIcon } from "naive-ui";
|
||||
import { WbSunnyFilled, DarkModeFilled } from "@vicons/material";
|
||||
import getLanguageData from "@/utils/getLanguageData";
|
||||
|
||||
const useSettingDataStore = defineStore("settingData", {
|
||||
state: () => {
|
||||
@@ -70,7 +71,9 @@ const useSettingDataStore = defineStore("settingData", {
|
||||
// 切换明暗模式
|
||||
setSiteTheme(value) {
|
||||
const isLightMode = value === "light";
|
||||
const message = isLightMode ? "已切换至浅色模式" : "已切换至深色模式";
|
||||
const message = isLightMode
|
||||
? getLanguageData("lightMode")
|
||||
: getLanguageData("darkMode");
|
||||
const icon = isLightMode ? WbSunnyFilled : DarkModeFilled;
|
||||
this.theme = value;
|
||||
$message.info(message, {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
getUserAlbum,
|
||||
} from "@/api/user";
|
||||
import { formatNumber, getLongTime } from "@/utils/timeTools";
|
||||
import getLanguageData from "@/utils/getLanguageData";
|
||||
|
||||
const useUserDataStore = defineStore("userData", {
|
||||
state: () => {
|
||||
@@ -89,8 +90,8 @@ const useUserDataStore = defineStore("userData", {
|
||||
// this.setUserPlayLists();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("获取用户详情失败:" + err);
|
||||
$message.error("获取用户详情失败,请刷新后重试");
|
||||
console.error(getLanguageData("getDataError"), err);
|
||||
$message.error(getLanguageData("getDataError"));
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -149,17 +150,17 @@ const useUserDataStore = defineStore("userData", {
|
||||
this.userPlayLists.isLoading = false;
|
||||
} else {
|
||||
this.userPlayLists.isLoading = false;
|
||||
$message.error("用户歌单为空");
|
||||
$message.info(getLanguageData("getDaraEmpty"));
|
||||
}
|
||||
} catch (err) {
|
||||
this.userPlayLists.isLoading = false;
|
||||
if (this.userLogin) {
|
||||
console.error("获取用户歌单时出现错误:" + err);
|
||||
$message.error("获取用户歌单时出现错误,请刷新后重试");
|
||||
console.error(getLanguageData("getDataError"), err);
|
||||
$message.error(getLanguageData("getDataError"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$message.error("请登录账号后使用");
|
||||
$message.error(getLanguageData("needLogin"));
|
||||
}
|
||||
},
|
||||
// 更改用户收藏歌手
|
||||
@@ -185,17 +186,17 @@ const useUserDataStore = defineStore("userData", {
|
||||
this.userArtistLists.isLoading = false;
|
||||
} else {
|
||||
this.userArtistLists.isLoading = false;
|
||||
$message.error("用户收藏歌手为空");
|
||||
$message.info(getLanguageData("getDaraEmpty"));
|
||||
}
|
||||
} catch (err) {
|
||||
this.userArtistLists.isLoading = false;
|
||||
if (this.userLogin) {
|
||||
console.error("用户收藏歌手获取失败:" + err);
|
||||
$message.error("用户收藏歌手获取失败,请刷新后重试");
|
||||
console.error(getLanguageData("getDataError"), err);
|
||||
$message.error(getLanguageData("getDataError"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$message.error("请登录账号后使用");
|
||||
$message.error(getLanguageData("needLogin"));
|
||||
}
|
||||
},
|
||||
// 更改用户收藏专辑
|
||||
@@ -229,12 +230,12 @@ const useUserDataStore = defineStore("userData", {
|
||||
} catch (err) {
|
||||
this.userAlbum.isLoading = false;
|
||||
if (this.userLogin) {
|
||||
console.error("用户收藏专辑获取失败:" + err);
|
||||
$message.error("用户收藏专辑获取失败,请刷新后重试");
|
||||
console.error(getLanguageData("getDataError"), err);
|
||||
$message.error(getLanguageData("getDataError"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$message.error("请登录账号后使用");
|
||||
$message.error(getLanguageData("needLogin"));
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ import { songScrobble } from "@/api/song";
|
||||
import { musicStore } from "@/store";
|
||||
import { NIcon } from "naive-ui";
|
||||
import { MusicNoteFilled } from "@vicons/material";
|
||||
import getLanguageData from "./getLanguageData";
|
||||
|
||||
// 歌曲信息更新定时器
|
||||
let timeupdateInterval = null;
|
||||
@@ -73,7 +74,7 @@ export const createSound = (src, autoPlay = true) => {
|
||||
// 播放事件
|
||||
sound?.on("play", () => {
|
||||
if (!Object.keys(music.getPlaySongData).length) {
|
||||
$message.error("音乐数据获取失败");
|
||||
$message.error(getLanguageData("songLoadError"));
|
||||
return false;
|
||||
}
|
||||
testNumber = 0;
|
||||
@@ -116,23 +117,23 @@ export const createSound = (src, autoPlay = true) => {
|
||||
// 错误事件
|
||||
sound?.on("loaderror", () => {
|
||||
if (testNumber > 2) {
|
||||
$message.error("歌曲播放失败");
|
||||
console.error("歌曲播放失败");
|
||||
$message.error(getLanguageData("songPlayError"));
|
||||
console.error(getLanguageData("songPlayError"));
|
||||
music.setPlayState(false);
|
||||
}
|
||||
if (testNumber < 4) {
|
||||
if (music.getPlaylists[0]) $getPlaySongData(music.getPlaySongData);
|
||||
testNumber++;
|
||||
} else {
|
||||
$message.error("歌曲重试次数过多,请刷新后重试", {
|
||||
$message.error(getLanguageData("songLoadTest"), {
|
||||
closable: true,
|
||||
duration: 0,
|
||||
});
|
||||
}
|
||||
});
|
||||
sound?.on("playerror", () => {
|
||||
$message.error("歌曲播放出错");
|
||||
console.error("歌曲播放出错");
|
||||
$message.error(getLanguageData("songPlayError"));
|
||||
console.error(getLanguageData("songPlayError"));
|
||||
music.setPlayState(false);
|
||||
});
|
||||
// 生成频谱
|
||||
@@ -140,8 +141,8 @@ export const createSound = (src, autoPlay = true) => {
|
||||
// 返回音频对象
|
||||
return (window.$player = sound);
|
||||
} catch (err) {
|
||||
$message.error("音乐播放器初始化失败");
|
||||
console.error("音乐播放器初始化失败:" + err);
|
||||
$message.error(getLanguageData("songLoadError"));
|
||||
console.error(getLanguageData("songLoadError"), err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
88
src/utils/getLanguageData.js
Normal file
88
src/utils/getLanguageData.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { settingStore } from "@/store";
|
||||
|
||||
/**
|
||||
* 翻译文本数据
|
||||
*/
|
||||
const languageData = {
|
||||
"zh-CN": {
|
||||
million: "万",
|
||||
billion: "亿",
|
||||
year: "年",
|
||||
month: "月",
|
||||
day: "日",
|
||||
just: "刚刚发布",
|
||||
minutesAgo: "分钟前",
|
||||
yesterday: "昨天",
|
||||
lightMode: "已切换至浅色模式",
|
||||
darkMode: "已切换至深色模式",
|
||||
personalFmError: "获取私人 FM 失败",
|
||||
fmTrashError: "歌曲移除至垃圾桶失败",
|
||||
needLogin: "请登录账号后使用",
|
||||
loveSong: "已添加到我喜欢的音乐",
|
||||
loveSongError: "喜欢音乐时发生错误",
|
||||
loveSongRepeat: "我喜欢的音乐中已存在该歌曲",
|
||||
loveSongRemove: "已从我喜欢的音乐中移除",
|
||||
loveSongRemoveError: "取消喜欢音乐时发生错误",
|
||||
loveSongNoFound: "我喜欢的列表中未找到该歌曲",
|
||||
getDataError: "数据获取失败,请刷新后重试",
|
||||
getDaraEmpty: "数据为空",
|
||||
getLrcError: "歌词处理出错",
|
||||
random: "随机播放",
|
||||
single: "单曲循环",
|
||||
normal: "列表循环",
|
||||
playError: "播放出错,请刷新后重试",
|
||||
addSongToNext: "已添加至下一曲播放",
|
||||
removeSong: "已从播放列表中移除",
|
||||
songLoadError: "音乐数据获取失败",
|
||||
songPlayError: "歌曲播放失败",
|
||||
songLoadTest: "歌曲重试次数过多,请刷新后重试",
|
||||
},
|
||||
en: {
|
||||
million: "M",
|
||||
billion: "B",
|
||||
year: "-",
|
||||
month: "-",
|
||||
day: "",
|
||||
just: "Just released",
|
||||
minutesAgo: "Minutes ago",
|
||||
yesterday: "Yesterday",
|
||||
lightMode: "Switched to light mode",
|
||||
darkMode: "Switched to dark mode",
|
||||
personalFmError: "Get Private FM Failed",
|
||||
fmTrashError: "Song removal to trash failed",
|
||||
needLogin: "Please login to your account to use",
|
||||
loveSong: "Added to my favorite music",
|
||||
loveSongError: "An error occurred while liking music",
|
||||
loveSongRepeat: "The song already exists in my favorite music",
|
||||
loveSongRemove: "Removed from my favorite music",
|
||||
loveSongError: "An error occurred while unliking music",
|
||||
loveSongNoFound: "The song was not found in my favorite list",
|
||||
getDataError: "Data acquisition failed, please refresh and try again",
|
||||
getDaraEmpty: "Data is empty",
|
||||
getLrcError: "Lyrics processing error",
|
||||
random: "Random play",
|
||||
single: "Single loop",
|
||||
normal: "list loop",
|
||||
playError: "Playback error, please refresh and try again",
|
||||
addSongToNext: "has been added to the next song to play",
|
||||
removeSong: "has been removed from the playlist",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 返回翻译文本
|
||||
* @param {String} type 文本类别
|
||||
* @returns {Object} 对应语种文本
|
||||
*/
|
||||
const getLanguageData = (type) => {
|
||||
try {
|
||||
const setting = settingStore();
|
||||
const language = setting.language;
|
||||
return languageData[language][type];
|
||||
} catch (err) {
|
||||
console.log("Failed to get translated:" + err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default getLanguageData;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { settingStore } from "@/store";
|
||||
import getLanguageData from "./getLanguageData";
|
||||
|
||||
/**
|
||||
* 歌曲时长时间戳转换
|
||||
@@ -103,35 +103,3 @@ export const getSongPlayingTime = (num) => {
|
||||
const seconds = String(Math.floor(num % 60)).padStart(2, "0");
|
||||
return `${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 返回翻译文本
|
||||
* @returns {Object} 对应语种文本
|
||||
*/
|
||||
const getLanguageData = (type) => {
|
||||
const setting = settingStore();
|
||||
const language = setting.language;
|
||||
const languageData = {
|
||||
"zh-CN": {
|
||||
million: "万",
|
||||
billion: "亿",
|
||||
year: "年",
|
||||
month: "月",
|
||||
day: "日",
|
||||
just: "刚刚发布",
|
||||
minutesAgo: "分钟前",
|
||||
yesterday: "昨天",
|
||||
},
|
||||
en: {
|
||||
million: "M",
|
||||
billion: "B",
|
||||
year: "-",
|
||||
month: "-",
|
||||
day: "",
|
||||
just: "Just released",
|
||||
minutesAgo: "Minutes ago",
|
||||
yesterday: "Yesterday",
|
||||
},
|
||||
};
|
||||
return languageData[language][type];
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="playlist" v-if="albumDetail">
|
||||
<div class="album" v-if="albumDetail">
|
||||
<div class="left">
|
||||
<div class="cover">
|
||||
<n-avatar
|
||||
@@ -20,7 +20,9 @@
|
||||
</n-text>
|
||||
</div>
|
||||
<div class="intr">
|
||||
<span class="name">专辑简介</span>
|
||||
<span class="name">{{
|
||||
$t("general.name.desc", { name: $t("general.name.album") })
|
||||
}}</span>
|
||||
<span class="desc text-hidden">
|
||||
{{ albumDetail.description }}
|
||||
</span>
|
||||
@@ -32,19 +34,8 @@
|
||||
v-if="albumDetail?.description.length > 70"
|
||||
@click="albumDescShow = true"
|
||||
>
|
||||
全部简介
|
||||
{{ $t("general.name.allDesc") }}
|
||||
</n-button>
|
||||
<n-modal
|
||||
class="s-modal"
|
||||
v-model:show="albumDescShow"
|
||||
preset="card"
|
||||
title="歌单简介"
|
||||
:bordered="false"
|
||||
>
|
||||
<n-scrollbar>
|
||||
<n-text v-html="albumDetail.description.replace(/\n/g, '<br>')" />
|
||||
</n-scrollbar>
|
||||
</n-modal>
|
||||
</div>
|
||||
<n-space class="tag" v-if="albumDetail.tags">
|
||||
<n-tag
|
||||
@@ -62,7 +53,7 @@
|
||||
<template #icon>
|
||||
<n-icon :component="MusicList" />
|
||||
</template>
|
||||
播放
|
||||
{{ $t("general.name.play") }}
|
||||
</n-button>
|
||||
<n-dropdown
|
||||
placement="right-start"
|
||||
@@ -86,27 +77,40 @@
|
||||
class="creator"
|
||||
@click="router.push(`/artist/songs?id=${albumDetail.artist.id}`)"
|
||||
>
|
||||
<n-icon :depth="3" :component="People" />
|
||||
{{ albumDetail.artist.name }}
|
||||
</n-text>
|
||||
<div class="time">
|
||||
<div class="createTime">
|
||||
<span class="num">发行时间:</span>
|
||||
{{ getLongTime(albumDetail.publishTime) }}
|
||||
<n-space class="time">
|
||||
<div class="num">
|
||||
<n-icon :depth="3" :component="Time" />
|
||||
<n-text v-html="getLongTime(albumDetail.publishTime)" />
|
||||
</div>
|
||||
<div class="company" v-if="albumDetail.company">
|
||||
<span class="num">发行公司:</span>
|
||||
{{ albumDetail.company }}
|
||||
<div class="num" v-if="albumDetail.company">
|
||||
<n-icon :depth="3" :component="City" />
|
||||
<n-text v-html="albumDetail.company" />
|
||||
</div>
|
||||
</div>
|
||||
</n-space>
|
||||
</div>
|
||||
<DataLists :listData="albumData" hideAlbum />
|
||||
<!-- 专辑简介 -->
|
||||
<n-modal
|
||||
class="s-modal"
|
||||
v-model:show="albumDescShow"
|
||||
preset="card"
|
||||
:title="$t('general.name.desc', { name: $t('general.name.album') })"
|
||||
:bordered="false"
|
||||
>
|
||||
<n-scrollbar>
|
||||
<n-text v-html="albumDetail.description.replace(/\n/g, '<br>')" />
|
||||
</n-scrollbar>
|
||||
</n-modal>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title" v-else-if="!albumId">
|
||||
<span class="key">参数不完整</span>
|
||||
<span class="key">{{ $t("general.name.noKeywords") }}</span>
|
||||
<br />
|
||||
<n-button strong secondary @click="router.go(-1)" style="margin-top: 20px">
|
||||
返回上一级
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="loading" v-else>
|
||||
@@ -127,10 +131,21 @@ import { NIcon, NAvatar, NText } from "naive-ui";
|
||||
import { getAlbum, likeAlbum } from "@/api/album";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getSongTime, getLongTime } from "@/utils/timeTools";
|
||||
import { MusicList, LinkTwo, More, Like, Unlike } from "@icon-park/vue-next";
|
||||
import {
|
||||
MusicList,
|
||||
LinkTwo,
|
||||
More,
|
||||
Like,
|
||||
Unlike,
|
||||
People,
|
||||
Time,
|
||||
City,
|
||||
} from "@icon-park/vue-next";
|
||||
import { userStore, musicStore, settingStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const user = userStore();
|
||||
const music = musicStore();
|
||||
@@ -181,7 +196,10 @@ const setDropdownOptions = () => {
|
||||
dropdownOptions.value = [
|
||||
{
|
||||
key: "copy",
|
||||
label: "复制专辑链接",
|
||||
label: t("menu.copy", {
|
||||
name: t("general.name.album"),
|
||||
other: t("general.name.link"),
|
||||
}),
|
||||
props: {
|
||||
onClick: () => {
|
||||
if (navigator.clipboard) {
|
||||
@@ -189,12 +207,13 @@ const setDropdownOptions = () => {
|
||||
navigator.clipboard.writeText(
|
||||
`https://music.163.com/#/playlist?id=${albumId.value}`
|
||||
);
|
||||
$message.success("专辑链接复制成功");
|
||||
$message.success(t("general.message.copySuccess"));
|
||||
} catch (err) {
|
||||
$message.error("复制失败:", err);
|
||||
console.error(t("general.message.copyFailure"), err);
|
||||
$message.error(t("general.message.copyFailure"));
|
||||
}
|
||||
} else {
|
||||
$message.error("您的浏览器暂不支持该操作");
|
||||
$message.error(t("general.message.notSupported"));
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -202,7 +221,9 @@ const setDropdownOptions = () => {
|
||||
},
|
||||
{
|
||||
key: "like",
|
||||
label: isLikeOrDislike(albumId.value) ? "收藏专辑" : "取消收藏专辑",
|
||||
label: isLikeOrDislike(albumId.value)
|
||||
? t("menu.collection", { name: t("general.name.album") })
|
||||
: t("menu.cancelCollection", { name: t("general.name.album") }),
|
||||
show: user.userLogin,
|
||||
props: {
|
||||
onClick: () => {
|
||||
@@ -220,7 +241,7 @@ const getAlbumData = (id) => {
|
||||
console.log(res);
|
||||
// 专辑信息
|
||||
albumDetail.value = res.album;
|
||||
$setSiteTitle(res.album.name + " - 专辑");
|
||||
$setSiteTitle(res.album.name + " - " + t("general.name.album"));
|
||||
// 专辑歌曲
|
||||
if (res.songs) {
|
||||
albumData.value = [];
|
||||
@@ -240,7 +261,7 @@ const getAlbumData = (id) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("获取专辑歌曲失败");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -276,27 +297,54 @@ const playAllSong = () => {
|
||||
music.setPlayState(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("播放全部歌曲失败:" + err);
|
||||
$message.error("播放全部歌曲失败,请重试");
|
||||
console.error($message.error(t("general.message.operationFailed")), err);
|
||||
$message.error($message.error(t("general.message.operationFailed")));
|
||||
}
|
||||
};
|
||||
|
||||
// 收藏/取消收藏
|
||||
const toChangeLike = async (id) => {
|
||||
const type = isLikeOrDislike(id) ? 1 : 2;
|
||||
const likeMsg = t("general.name.album");
|
||||
const isThereASpace = setting.language === "zh-CN" ? "" : " ";
|
||||
try {
|
||||
const res = await likeAlbum(type, id);
|
||||
if (res.code === 200) {
|
||||
$message.success(`专辑${type == 1 ? "收藏成功" : "取消收藏成功"}`);
|
||||
$message.success(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.success") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.success") })
|
||||
}`
|
||||
);
|
||||
user.setUserAlbumLists(() => {
|
||||
setDropdownOptions();
|
||||
});
|
||||
} else {
|
||||
$message.error(`专辑${type == 1 ? "收藏失败" : "取消收藏失败"}`);
|
||||
$message.error(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
$message.error(`专辑${type == 1 ? "收藏失败" : "取消收藏失败"}`);
|
||||
console.error(`专辑${type == 1 ? "收藏失败:" : "取消收藏失败:"}` + err);
|
||||
$message.error(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`
|
||||
);
|
||||
console.error(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`,
|
||||
err
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -330,7 +378,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.playlist,
|
||||
.album,
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -438,6 +486,8 @@ watch(
|
||||
font-weight: bold;
|
||||
}
|
||||
.creator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 6px;
|
||||
font-size: 16px;
|
||||
opacity: 0.8;
|
||||
@@ -447,6 +497,9 @@ watch(
|
||||
opacity: 1;
|
||||
color: var(--main-color);
|
||||
}
|
||||
.n-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.time {
|
||||
margin-top: 8px;
|
||||
@@ -458,10 +511,13 @@ watch(
|
||||
align-items: flex-start;
|
||||
}
|
||||
.num {
|
||||
color: #999;
|
||||
}
|
||||
div {
|
||||
margin-right: 12px;
|
||||
// color: #999;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.n-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<div class="all-songs">
|
||||
<div class="title" v-if="artistId">
|
||||
<span class="key">{{ artistName ? artistName : "未知歌手" }}</span>
|
||||
<span>全部歌曲</span>
|
||||
<template v-if="artistData[0]">
|
||||
<span class="key">{{
|
||||
artistName ? artistName : $t("general.name.unknownArtist")
|
||||
}}</span>
|
||||
<span>{{ $t("general.name.allSong") }} </span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="title" v-else>
|
||||
<span class="key">未提供所需信息</span>
|
||||
<span class="key">{{ $t("general.name.noKeywords") }}</span>
|
||||
<br />
|
||||
<n-button
|
||||
strong
|
||||
@@ -13,7 +17,7 @@
|
||||
@click="router.go(-1)"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
返回上一级
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="songs" v-if="artistId">
|
||||
@@ -34,9 +38,11 @@ import { getArtistDetail, getArtistAllSongs } from "@/api/artist";
|
||||
import { getMusicDetail } from "@/api/song";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getSongTime } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 歌手信息
|
||||
@@ -91,15 +97,15 @@ const getArtistAllSongsData = (id, limit = 30, offset = 0, order = "hot") => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("歌手全部歌曲为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
})
|
||||
.catch((err) => {
|
||||
router.go(-1);
|
||||
console.error("歌手全部歌曲获取失败:" + err);
|
||||
$message.error("歌手全部歌曲获取失败");
|
||||
console.error(t("general.message.acquisitionFailed"), err);
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -17,15 +17,15 @@
|
||||
<div class="num">
|
||||
<n-text class="musicSize" @click="tabChange('songs')">
|
||||
<n-icon :component="MusicNoteFilled" />
|
||||
{{ artistData.musicSize }} 首歌
|
||||
{{ $t("general.name.songSize", { size: artistData.musicSize }) }}
|
||||
</n-text>
|
||||
<n-text class="albumSize" @click="tabChange('albums')">
|
||||
<n-icon :component="AlbumFilled" />
|
||||
{{ artistData.albumSize }} 张专辑
|
||||
{{ $t("general.name.albumSize", { size: artistData.albumSize }) }}
|
||||
</n-text>
|
||||
<n-text class="mvSize" @click="tabChange('videos')">
|
||||
<n-icon :component="VideocamRound" />
|
||||
{{ artistData.mvSize }} 个 MV
|
||||
{{ $t("general.name.mvSize", { size: artistData.mvSize }) }}
|
||||
</n-text>
|
||||
</div>
|
||||
<n-text class="desc text-hidden" @click="artistDescShow = true">
|
||||
@@ -51,7 +51,13 @@
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
{{ artistLikeBtn ? "收藏歌手" : "取消收藏歌手" }}
|
||||
{{
|
||||
artistLikeBtn
|
||||
? $t("menu.collection", { name: $t("general.name.artists") })
|
||||
: $t("menu.cancelCollection", {
|
||||
name: $t("general.name.artists"),
|
||||
})
|
||||
}}
|
||||
</n-button>
|
||||
</n-space>
|
||||
<!-- 歌手介绍 -->
|
||||
@@ -59,7 +65,7 @@
|
||||
class="s-modal"
|
||||
v-model:show="artistDescShow"
|
||||
preset="card"
|
||||
title="歌手介绍"
|
||||
:title="$t('general.name.artistDesc')"
|
||||
:bordered="false"
|
||||
>
|
||||
<n-scrollbar>
|
||||
@@ -69,7 +75,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="error" v-else-if="!artistId">
|
||||
<n-text>参数不完整</n-text>
|
||||
<n-text>{{ $t("general.name.noKeywords") }}</n-text>
|
||||
<br />
|
||||
<n-button
|
||||
strong
|
||||
@@ -77,7 +83,7 @@
|
||||
@click="router.go(-1)"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
返回上一级
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<n-tabs
|
||||
@@ -87,8 +93,8 @@
|
||||
v-model:value="tabValue"
|
||||
v-if="artistData"
|
||||
>
|
||||
<n-tab name="songs"> 热门单曲 </n-tab>
|
||||
<n-tab name="albums"> 专辑 </n-tab>
|
||||
<n-tab name="songs"> {{ $t("general.name.hotSong") }} </n-tab>
|
||||
<n-tab name="albums"> {{ $t("general.name.album") }} </n-tab>
|
||||
<n-tab name="videos"> MV </n-tab>
|
||||
</n-tabs>
|
||||
<main class="content" v-if="artistData">
|
||||
@@ -117,7 +123,9 @@ import {
|
||||
PersonAddAlt1Round,
|
||||
PersonRemoveAlt1Round,
|
||||
} from "@vicons/material";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const user = userStore();
|
||||
|
||||
@@ -146,17 +154,15 @@ const getArtistDetailData = (id) => {
|
||||
musicSize: res.data.artist.musicSize,
|
||||
mvSize: res.data.artist.mvSize,
|
||||
};
|
||||
$setSiteTitle(res.data.artist.name + " - 歌手");
|
||||
$setSiteTitle(res.data.artist.name + " - " + t("general.name.artists"));
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
})
|
||||
.catch((err) => {
|
||||
router.go(-1);
|
||||
console.error("歌手信息获取失败:" + err);
|
||||
$message.error("歌手信息获取失败");
|
||||
console.error(t("general.message.acquisitionFailed"), err);
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
});
|
||||
} else {
|
||||
$message.error("参数不完整");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -193,13 +199,23 @@ const toLikeArtist = (data) => {
|
||||
likeArtist(type, data.id).then((res) => {
|
||||
if (res.code === 200) {
|
||||
$message.success(
|
||||
`${data.name}${type == 1 ? "收藏成功" : "取消收藏成功"}`
|
||||
`${data.name} ${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.success") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.success") })
|
||||
}`
|
||||
);
|
||||
user.setUserArtistLists(() => {
|
||||
artistLikeBtn.value = isLikeOrDislike(artistId.value);
|
||||
});
|
||||
} else {
|
||||
$message.error(`${data.name}${type == 1 ? "收藏失败" : "取消收藏失败"}`);
|
||||
$message.error(
|
||||
`${data.name} ${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
round
|
||||
@click="router.push(`/all-songs?id=${artistId}&page=1`)"
|
||||
>
|
||||
全部歌曲
|
||||
{{ $t("general.name.allSong") }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
|
||||
@@ -6,17 +6,18 @@
|
||||
class="goback"
|
||||
@click="router.push(`/comment?id=${music.getPlaySongData.id}&page=1`)"
|
||||
content-style="padding: 6px"
|
||||
>前往当前播放歌曲
|
||||
>
|
||||
{{ $t("general.name.toCurrentlySong") }}
|
||||
</n-card>
|
||||
</Transition>
|
||||
<div class="title" v-if="songId">
|
||||
<span class="key">全部评论</span>
|
||||
<span class="key">{{ $t("general.name.allComments") }}</span>
|
||||
<n-card class="song">
|
||||
<SmallSongData :getDataByID="songId" />
|
||||
</n-card>
|
||||
</div>
|
||||
<div class="title" v-else>
|
||||
<span class="key">缺少必要参数</span>
|
||||
<span class="key">{{ $t("general.name.noKeywords") }}</span>
|
||||
<br />
|
||||
<n-button
|
||||
strong
|
||||
@@ -24,12 +25,12 @@
|
||||
@click="router.go(-1)"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
返回上一页
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="commentData" v-if="songId && commentData.allComments[0]">
|
||||
<div class="hotComments" v-if="commentData.hotComments[0]">
|
||||
<n-h6 prefix="bar"> 热门评论 </n-h6>
|
||||
<n-h6 prefix="bar"> {{ $t("general.name.hotComments") }} </n-h6>
|
||||
<div class="loading" v-if="!commentData.hotComments[0]">
|
||||
<n-skeleton text :repeat="3" />
|
||||
<n-skeleton text style="width: 60%" />
|
||||
@@ -44,8 +45,8 @@
|
||||
</div>
|
||||
<div class="allComments" ref="allCommentsRef">
|
||||
<n-h6 prefix="bar">
|
||||
全部评论
|
||||
<span class="count">{{ commentsCount }} 条</span>
|
||||
{{ $t("general.name.allComments") }}
|
||||
<span class="count">{{ commentsCount }} +</span>
|
||||
</n-h6>
|
||||
<div class="loading" v-if="!commentData.allComments[0]">
|
||||
<n-skeleton text :repeat="3" />
|
||||
@@ -73,9 +74,12 @@
|
||||
import { musicStore } from "@/store";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getComment } from "@/api/comment";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import SmallSongData from "@/components/DataList/SmallSongData.vue";
|
||||
import Comment from "@/components/Comment/index.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const music = musicStore();
|
||||
|
||||
@@ -114,7 +118,7 @@ const getCommentData = (id, offset = 0) => {
|
||||
commentData.allComments = res.comments;
|
||||
commentsCount.value = res.total;
|
||||
} else {
|
||||
$message.info("暂无评论");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
router.go(-1);
|
||||
}
|
||||
// 请求后回顶
|
||||
@@ -134,7 +138,7 @@ const pageNumberChange = (val) => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("全部评论");
|
||||
$setSiteTitle(t("general.name.allComments"));
|
||||
// 获取评论数据
|
||||
if (songId.value) getCommentData(songId.value, (pageNumber.value - 1) * 20);
|
||||
});
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
<n-text class="num" v-html="new Date().getDate()" />
|
||||
</div>
|
||||
<div class="right">
|
||||
<n-gradient-text class="big" type="danger"> 每日推荐 </n-gradient-text>
|
||||
<n-gradient-text class="big" type="danger">
|
||||
{{ $t("home.modules.dailySongs.title") }}
|
||||
</n-gradient-text>
|
||||
<n-text class="tip" :depth="3">
|
||||
根据你的音乐口味生成 · 每天 6:00 更新
|
||||
{{ $t("home.modules.dailySongs.subtitle") }}
|
||||
</n-text>
|
||||
</div>
|
||||
</div>
|
||||
@@ -20,8 +22,10 @@
|
||||
import { getDailySongs } from "@/api/home";
|
||||
import { musicStore } from "@/store";
|
||||
import { CalendarTodayFilled } from "@vicons/material";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const music = musicStore();
|
||||
|
||||
// 获取每日推荐数据
|
||||
@@ -31,14 +35,14 @@ const getDailySongsData = () => {
|
||||
if (res.data.dailySongs) {
|
||||
music.setDailySongs(res.data.dailySongs);
|
||||
} else {
|
||||
$message.error("每日推荐获取失败");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("每日推荐");
|
||||
$setSiteTitle(t("home.modules.dailySongs.title"));
|
||||
getDailySongsData();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
:loading="loading"
|
||||
@click="loadingMore"
|
||||
>
|
||||
加载更多
|
||||
{{ $t("general.name.loadMore") }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
@@ -134,7 +134,7 @@ const getArtistListData = (
|
||||
});
|
||||
} else {
|
||||
hasMore.value = false;
|
||||
$message.error("歌手内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -169,7 +169,6 @@ const artistTypeChange = (index) => {
|
||||
const loadingMore = () => {
|
||||
loading.value = true;
|
||||
artistsOffset.value += 30;
|
||||
if (artistsOffset.value >= 300) $message.info("太多了吧 😲");
|
||||
getArtistListData(
|
||||
artistType[artistTypeNamesChoose.value],
|
||||
artistArea[artistTypeNamesChoose.value],
|
||||
@@ -202,7 +201,7 @@ watch(
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("发现 - 歌手");
|
||||
$setSiteTitle(t("nav.discover") + " - " + t("nav.discoverChildren.artists"));
|
||||
// 获取歌手数据
|
||||
getArtistListData(
|
||||
artistType[artistTypeNamesChoose.value],
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
class="s-modal"
|
||||
v-model:show="catModalShow"
|
||||
preset="card"
|
||||
title="歌单分类"
|
||||
:title="$t('general.name.playlistType')"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #header>
|
||||
歌单分类
|
||||
{{ $t("general.name.playlistType") }}
|
||||
<n-tag
|
||||
round
|
||||
class="tag"
|
||||
@@ -37,7 +37,7 @@
|
||||
:bordered="false"
|
||||
@click="changeTagName('全部歌单')"
|
||||
>
|
||||
全部歌单
|
||||
{{ $t("general.name.allPLaylist") }}
|
||||
</n-tag>
|
||||
</template>
|
||||
<n-scrollbar>
|
||||
@@ -76,7 +76,9 @@
|
||||
</n-list-item>
|
||||
</n-list>
|
||||
</div>
|
||||
<div class="error" v-else>分类数据获取失败</div>
|
||||
<div class="error" v-else>
|
||||
{{ $t("general.message.acquisitionFailed") }}
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
</n-modal>
|
||||
<!-- 精品歌单开关 -->
|
||||
@@ -84,7 +86,7 @@
|
||||
v-if="getHaveHqPlaylists(music.highqualityCatList, catName)"
|
||||
align="center"
|
||||
>
|
||||
<n-text>精品歌单</n-text>
|
||||
<n-text>{{ $t("general.name.bestPlaylist") }}</n-text>
|
||||
<n-switch
|
||||
v-model:value="hqPLayListOpen"
|
||||
@update:value="hqPLayListChange"
|
||||
@@ -116,7 +118,7 @@
|
||||
}
|
||||
"
|
||||
>
|
||||
加载更多
|
||||
{{ $t("general.name.loadMore") }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
@@ -128,9 +130,11 @@ import { useRouter } from "vue-router";
|
||||
import { musicStore } from "@/store";
|
||||
import { getHighqualityPlaylist, getTopPlaylist } from "@/api/playlist";
|
||||
import { formatNumber } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const music = musicStore();
|
||||
|
||||
@@ -206,7 +210,7 @@ const getPlaylistData = (cat = "全部歌单", limit = 30, offset = 0) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("歌单列表为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -240,7 +244,7 @@ const getHqPlaylistData = (cat = "全部歌单", limit = 30) => {
|
||||
});
|
||||
} else {
|
||||
hasMore.value = false;
|
||||
$message.error("精品歌单列表为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -315,7 +319,7 @@ watch(
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("发现 - 歌单");
|
||||
$setSiteTitle(t("nav.discover") + " - " + t("general.name.playlist"));
|
||||
// 获取歌单分类
|
||||
if (!music.catList.sub || !music.highqualityCatList[0])
|
||||
music.setCatList(true);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="toplists">
|
||||
<n-divider v-if="toplistData.officialList[0]">官方榜</n-divider>
|
||||
<n-divider v-if="toplistData.officialList[0]">
|
||||
{{ $t("nav.officialList") }}
|
||||
</n-divider>
|
||||
<Transition mode="out-in">
|
||||
<n-grid
|
||||
class="official"
|
||||
@@ -49,7 +51,7 @@
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</Transition>
|
||||
<n-divider>全球榜</n-divider>
|
||||
<n-divider>{{ $t("nav.globalList") }}</n-divider>
|
||||
<CoverLists :listData="toplistData.globalList" listType="topList" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -58,8 +60,10 @@
|
||||
import { getToplist } from "@/api/album";
|
||||
import { useRouter } from "vue-router";
|
||||
import { formatNumber } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 排行榜数据
|
||||
@@ -91,13 +95,13 @@ const getToplistData = () => {
|
||||
});
|
||||
console.log(toplistData);
|
||||
} else {
|
||||
$message.error("排行榜获取失败");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("发现 - 排行榜");
|
||||
$setSiteTitle(t("nav.discover") + " - " + t("nav.discoverChildren.toplists"));
|
||||
getToplistData();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="history">
|
||||
<div class="title" v-if="music.getPlayHistory[0]">
|
||||
<span class="key">播放历史</span>
|
||||
<span class="key">{{ $t("nav.avatar.history") }}</span>
|
||||
</div>
|
||||
<div class="title" v-else>
|
||||
<span class="key">暂无播放历史</span>
|
||||
<span class="key">{{ $t("other.noHistory") }}</span>
|
||||
<br />
|
||||
<n-button
|
||||
strong
|
||||
@@ -12,7 +12,7 @@
|
||||
@click="router.go(-1)"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
返回上一页
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<DataLists
|
||||
@@ -20,7 +20,9 @@
|
||||
:listData="music.getPlayHistory"
|
||||
/>
|
||||
<n-divider v-if="music.getPlayHistory[0]" class="tip" dashed>
|
||||
<n-text :depth="3" style="font-size: 12px">仅显示最近 100 首</n-text>
|
||||
<n-text :depth="3" style="font-size: 12px">
|
||||
{{ $t("other.justShow", { num: 100 }) }}
|
||||
</n-text>
|
||||
</n-divider>
|
||||
</div>
|
||||
</template>
|
||||
@@ -28,13 +30,15 @@
|
||||
<script setup>
|
||||
import { musicStore } from "@/store";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const music = musicStore();
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("播放历史");
|
||||
$setSiteTitle(t("nav.avatar.history"));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
<script setup>
|
||||
import { settingStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Banner from "@/components/Banner/index.vue";
|
||||
import PaPlayLists from "@/components/Personalized/PaPlayLists.vue";
|
||||
import PaArtists from "@/components/Personalized/PaArtists.vue";
|
||||
@@ -40,7 +39,6 @@ import PaPersonalFm from "@/components/Personalized/PaPersonalFm.vue";
|
||||
import PaRadar from "@/components/Personalized/PaRadar.vue";
|
||||
import PaLikeSongs from "@/components/Personalized/PaLikeSongs.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const setting = settingStore();
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="login">
|
||||
<div class="title">
|
||||
<img src="/images/logo/favicon.png" alt="logo" />
|
||||
<span>登录云音乐</span>
|
||||
<n-text>{{ $t("login.login", { name: siteTitle }) }}</n-text>
|
||||
</div>
|
||||
<n-tabs
|
||||
animated
|
||||
@@ -17,7 +17,7 @@
|
||||
}"
|
||||
@update:value="tabChange"
|
||||
>
|
||||
<n-tab-pane name="qr" tab="二维码登录">
|
||||
<n-tab-pane name="qr" :tab="$t('login.qr')">
|
||||
<n-card class="qr-img">
|
||||
<n-skeleton
|
||||
v-if="!qrImg"
|
||||
@@ -37,14 +37,14 @@
|
||||
</n-card>
|
||||
<span class="tip">{{ qrText }}</span>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="phone" tab="手机号登录">
|
||||
<n-tab-pane name="phone" :tab="$t('login.phone')">
|
||||
<n-alert
|
||||
style="width: 100%; margin-top: -20px; margin-bottom: 12px"
|
||||
type="warning"
|
||||
>
|
||||
该登录方式暂时无法使用
|
||||
{{ $t("login.canNotUse") }}
|
||||
</n-alert>
|
||||
<n-form
|
||||
<!-- <n-form
|
||||
class="phone"
|
||||
ref="phoneFormRef"
|
||||
:model="phoneFormData"
|
||||
@@ -83,12 +83,19 @@
|
||||
</n-form-item>
|
||||
<n-form-item>
|
||||
<n-button style="width: 100%" type="primary" @click="phoneLogin">
|
||||
登录
|
||||
{{$t("login.login")}}
|
||||
</n-button>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-form> -->
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="email" :tab="$t('login.email')">
|
||||
<n-alert
|
||||
style="width: 100%; margin-top: -20px; margin-bottom: 12px"
|
||||
type="warning"
|
||||
>
|
||||
{{ $t("login.canNotUse") }}
|
||||
</n-alert>
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="email" tab="邮箱登录"> 还没搞 </n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
</template>
|
||||
@@ -106,17 +113,20 @@ import {
|
||||
import { useRouter } from "vue-router";
|
||||
import { PhoneAndroidRound, PasswordRound } from "@vicons/material";
|
||||
import { formRules } from "@/utils/formRules";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import QrcodeVue from "qrcode.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const user = userStore();
|
||||
const music = musicStore();
|
||||
const setting = settingStore();
|
||||
const siteTitle = import.meta.env.VITE_SITE_TITLE;
|
||||
const { numberRule, mobileRule } = formRules();
|
||||
|
||||
// 二维码数据
|
||||
const qrImg = ref(null);
|
||||
const qrText = ref("请打开云音乐 APP 扫码登录");
|
||||
const qrText = ref(t("login.qrText1"));
|
||||
|
||||
// 手机号登录数据
|
||||
const phoneFormRef = ref(null);
|
||||
@@ -147,15 +157,15 @@ const saveLoginData = (data) => {
|
||||
if (res.data.profile) {
|
||||
user.setUserData(res.data.profile);
|
||||
user.userLogin = true;
|
||||
qrText.value = "登录成功";
|
||||
$message.success("登录成功");
|
||||
qrText.value = t("login.qrText4");
|
||||
$message.success(t("login.qrText4"));
|
||||
// 自动签到
|
||||
if ($signIn) $signIn();
|
||||
clearInterval(qrCheckInterval.value);
|
||||
router.push("/user");
|
||||
} else {
|
||||
user.userLogOut();
|
||||
$message.error("登录出错,请重试");
|
||||
$message.error(t("login.qrText5"));
|
||||
getQrKeyData();
|
||||
}
|
||||
});
|
||||
@@ -166,7 +176,7 @@ const getQrKeyData = () => {
|
||||
// 检测是否登录
|
||||
getLoginState().then((res) => {
|
||||
if (res.data.profile && window.localStorage.getItem("cookie")) {
|
||||
$message.info("已登录,请勿重复登录");
|
||||
$message.info(t("login.loggedIn"));
|
||||
user.userLogin = true;
|
||||
router.push("/user");
|
||||
} else {
|
||||
@@ -178,7 +188,7 @@ const getQrKeyData = () => {
|
||||
qrImg.value = `https://music.163.com/login?codekey=${res.data.unikey}`;
|
||||
checkQrState(res.data.unikey);
|
||||
} else {
|
||||
$message.error("登录二维码生成失败");
|
||||
$message.error(t("login.qrText6"));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -194,19 +204,16 @@ const checkQrState = (key) => {
|
||||
if (res.code == 800) {
|
||||
getQrKeyData();
|
||||
loginStateMessage.value = null;
|
||||
qrText.value = "当前二维码已失效,请重新扫码";
|
||||
qrText.value = t("login.qrText2");
|
||||
} else if (res.code == 801) {
|
||||
loginStateMessage.value = null;
|
||||
qrText.value = "请打开云音乐 APP 扫码登录";
|
||||
qrText.value = t("login.qrText1");
|
||||
} else if (res.code == 802) {
|
||||
qrText.value = "扫描成功,请在客户端确认登录";
|
||||
qrText.value = t("login.qrText3");
|
||||
if (!loginStateMessage.value) {
|
||||
loginStateMessage.value = $message.loading(
|
||||
"扫描成功,请在客户端确认登录",
|
||||
{
|
||||
duration: 0,
|
||||
}
|
||||
);
|
||||
loginStateMessage.value = $message.loading(t("login.qrText3"), {
|
||||
duration: 0,
|
||||
});
|
||||
}
|
||||
} else if (res.code == 803) {
|
||||
loginStateMessage.value.destroy();
|
||||
@@ -291,7 +298,7 @@ const tabChange = (val) => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("登录");
|
||||
$setSiteTitle(t("login.login"));
|
||||
// 隐藏控制条
|
||||
music.setPlayBarState(false);
|
||||
// 获取二维码登录 key
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="new-album">
|
||||
<div class="title">
|
||||
<span class="key">全部新碟</span>
|
||||
<span class="key">{{ $t("home.title.newAlbum") }}</span>
|
||||
</div>
|
||||
<n-space class="category">
|
||||
<n-tag
|
||||
@@ -31,9 +31,11 @@
|
||||
import { getAlbumNew } from "@/api/album";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getLongTime } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 新碟数据
|
||||
@@ -52,24 +54,24 @@ const albumAreaChoose = ref(
|
||||
);
|
||||
const albumArea = [
|
||||
{
|
||||
label: "全部",
|
||||
label: t("general.type.all"),
|
||||
value: "ALL",
|
||||
},
|
||||
{
|
||||
label: "华语",
|
||||
label: t("general.type.china"),
|
||||
value: "ZH",
|
||||
},
|
||||
{
|
||||
label: "欧美",
|
||||
label: t("general.type.western"),
|
||||
value: "EA",
|
||||
},
|
||||
{
|
||||
label: "韩国",
|
||||
value: "KR",
|
||||
label: t("general.type.japan"),
|
||||
value: "JP",
|
||||
},
|
||||
{
|
||||
label: "日本",
|
||||
value: "JP",
|
||||
label: t("general.type.korea"),
|
||||
value: "KR",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -92,7 +94,7 @@ const getAlbumNewData = (area, limit = 30, offset = 0) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("全部新碟为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -149,7 +151,7 @@ const changeArea = (area) => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("全部新碟");
|
||||
$setSiteTitle(t("home.title.newAlbum"));
|
||||
getAlbumNewData(
|
||||
albumAreaChoose.value,
|
||||
pagelimit.value,
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
<n-text class="creator">{{ playListDetail.creator.nickname }}</n-text>
|
||||
</div>
|
||||
<div class="intr">
|
||||
<span class="name">歌单简介</span>
|
||||
<span class="name">{{
|
||||
$t("general.name.desc", { name: $t("general.name.playlist") })
|
||||
}}</span>
|
||||
<span class="desc text-hidden">
|
||||
{{
|
||||
playListDetail.description
|
||||
? playListDetail.description
|
||||
: "太懒了吧,连简介都不写"
|
||||
: $t("oyher.noDesc")
|
||||
}}
|
||||
</span>
|
||||
<n-button
|
||||
@@ -35,7 +37,7 @@
|
||||
v-if="playListDetail?.description?.length > 70"
|
||||
@click="playListDescShow = true"
|
||||
>
|
||||
全部简介
|
||||
{{ $t("general.name.allDesc") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<n-space class="tag" v-if="playListDetail.tags">
|
||||
@@ -55,7 +57,7 @@
|
||||
<template #icon>
|
||||
<n-icon :component="MusicList" />
|
||||
</template>
|
||||
播放
|
||||
{{ $t("general.name.play") }}
|
||||
</n-button>
|
||||
<n-dropdown
|
||||
placement="right-start"
|
||||
@@ -75,17 +77,20 @@
|
||||
<div class="right">
|
||||
<div class="meta">
|
||||
<n-text class="name">{{ playListDetail.name }}</n-text>
|
||||
<n-text class="creator">{{ playListDetail.creator.nickname }}</n-text>
|
||||
<div class="time">
|
||||
<div class="createTime">
|
||||
<span class="num">创建时间:</span>
|
||||
{{ getLongTime(playListDetail.createTime) }}
|
||||
<n-text class="creator">
|
||||
<n-icon :depth="3" :component="People" />
|
||||
{{ playListDetail.creator.nickname }}
|
||||
</n-text>
|
||||
<n-space class="time">
|
||||
<div class="num">
|
||||
<n-icon :depth="3" :component="Newlybuild" />
|
||||
<n-text v-html="getLongTime(playListDetail.createTime)" />
|
||||
</div>
|
||||
<div class="updateTime">
|
||||
<span class="num">更新时间:</span>
|
||||
{{ getLongTime(playListDetail.updateTime) }}
|
||||
<div class="num">
|
||||
<n-icon :depth="3" :component="Write" />
|
||||
<n-text v-html="getLongTime(playListDetail.updateTime)" />
|
||||
</div>
|
||||
</div>
|
||||
</n-space>
|
||||
</div>
|
||||
<DataLists :listData="playListData" />
|
||||
<Pagination
|
||||
@@ -101,7 +106,7 @@
|
||||
class="s-modal"
|
||||
v-model:show="playListDescShow"
|
||||
preset="card"
|
||||
title="歌单简介"
|
||||
:title="$t('general.name.desc', { name: $t('general.name.playlist') })"
|
||||
:bordered="false"
|
||||
>
|
||||
<n-scrollbar>
|
||||
@@ -112,11 +117,13 @@
|
||||
</div>
|
||||
<div class="title" v-else-if="!playListId || !loadingState">
|
||||
<span class="key">{{
|
||||
loadingState ? "参数不完整" : "歌单信息加载失败"
|
||||
loadingState
|
||||
? $t("general.name.noKeywords")
|
||||
: $t("general.message.acquisitionFailed")
|
||||
}}</span>
|
||||
<br />
|
||||
<n-button strong secondary @click="router.go(-1)" style="margin-top: 20px">
|
||||
返回上一页
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<div class="loading" v-else>
|
||||
@@ -150,11 +157,16 @@ import {
|
||||
DeleteFour,
|
||||
Like,
|
||||
Unlike,
|
||||
Newlybuild,
|
||||
Write,
|
||||
People,
|
||||
} from "@icon-park/vue-next";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
// import SpecialPlayLists from "./SpecialPlayLists.json";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const user = userStore();
|
||||
const music = musicStore();
|
||||
@@ -222,7 +234,10 @@ const setDropdownOptions = () => {
|
||||
dropdownOptions.value = [
|
||||
{
|
||||
key: "copy",
|
||||
label: "复制歌单链接",
|
||||
label: t("menu.copy", {
|
||||
name: t("general.name.playlist"),
|
||||
other: t("general.name.link"),
|
||||
}),
|
||||
props: {
|
||||
onClick: () => {
|
||||
if (navigator.clipboard) {
|
||||
@@ -230,12 +245,13 @@ const setDropdownOptions = () => {
|
||||
navigator.clipboard.writeText(
|
||||
`https://music.163.com/#/playlist?id=${playListId.value}`
|
||||
);
|
||||
$message.success("歌单链接复制成功");
|
||||
$message.success(t("general.message.copySuccess"));
|
||||
} catch (err) {
|
||||
$message.error("复制失败:", err);
|
||||
console.error(t("general.message.copyFailure"), err);
|
||||
$message.error(t("general.message.copyFailure"));
|
||||
}
|
||||
} else {
|
||||
$message.error("您的浏览器暂不支持该操作");
|
||||
$message.error(t("general.message.notSupported"));
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -243,7 +259,7 @@ const setDropdownOptions = () => {
|
||||
},
|
||||
{
|
||||
key: "del",
|
||||
label: "删除歌单",
|
||||
label: t("menu.del"),
|
||||
show: user.userLogin && isCanDelete(playListId.value),
|
||||
props: {
|
||||
onClick: () => {
|
||||
@@ -254,7 +270,9 @@ const setDropdownOptions = () => {
|
||||
},
|
||||
{
|
||||
key: "like",
|
||||
label: isLikeOrDislike(playListId.value) ? "收藏歌单" : "取消收藏歌单",
|
||||
label: isLikeOrDislike(playListId.value)
|
||||
? t("menu.collection", { name: t("general.name.playlist") })
|
||||
: t("menu.cancelCollection", { name: t("general.name.playlist") }),
|
||||
show: user.userLogin && !isCanDelete(playListId.value),
|
||||
props: {
|
||||
onClick: () => {
|
||||
@@ -275,12 +293,16 @@ const getPlayListDetailData = (id) => {
|
||||
totalCount.value = res.playlist.trackCount;
|
||||
// 歌单信息
|
||||
playListDetail.value = res.playlist;
|
||||
$setSiteTitle(res.playlist.name + " - 歌单");
|
||||
$setSiteTitle(res.playlist.name + " - " + t("general.name.playlist"));
|
||||
})
|
||||
.catch((err) => {
|
||||
$setSiteTitle("歌单详情");
|
||||
$setSiteTitle(t("general.name.playlist"));
|
||||
loadingState.value = false;
|
||||
console.error("获取歌单信息失败:" + err);
|
||||
console.error(
|
||||
$message.error(t("general.message.acquisitionFailed")),
|
||||
err
|
||||
);
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -306,7 +328,7 @@ const getAllPlayListData = (id, limit = 30, offset = 0) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("获取歌单内歌曲失败");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -344,27 +366,29 @@ const playAllSong = () => {
|
||||
music.setPlayState(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("播放全部歌曲失败:" + err);
|
||||
$message.error("播放全部歌曲失败,请重试");
|
||||
console.error($message.error(t("general.message.operationFailed")), err);
|
||||
$message.error($message.error(t("general.message.operationFailed")));
|
||||
}
|
||||
};
|
||||
|
||||
// 删除歌单
|
||||
const toDelPlayList = (data) => {
|
||||
if (data.id === user.getUserPlayLists?.own[0].id) {
|
||||
$message.warning("默认歌单无法删除");
|
||||
$message.warning(t("menu.unableToDelete"));
|
||||
return false;
|
||||
}
|
||||
$dialog.warning({
|
||||
class: "s-dialog",
|
||||
title: "删除歌单",
|
||||
content: "确认删除歌单 " + data.name + "?删除后将不可恢复!",
|
||||
positiveText: "删除",
|
||||
negativeText: "取消",
|
||||
title: t("general.dialog.delete"),
|
||||
content: t("menu.delQuestion", {
|
||||
name: data.name,
|
||||
}),
|
||||
positiveText: t("general.dialog.delete"),
|
||||
negativeText: t("general.dialog.cancel"),
|
||||
onPositiveClick: () => {
|
||||
delPlayList(data.id).then((res) => {
|
||||
if (res.code === 200) {
|
||||
$message.success("删除成功");
|
||||
$message.success(t("general.message.deleteSuccess"));
|
||||
user.setUserPlayLists();
|
||||
router.push("/user/playlists");
|
||||
}
|
||||
@@ -376,19 +400,46 @@ const toDelPlayList = (data) => {
|
||||
// 收藏/取消收藏
|
||||
const toChangeLike = async (id) => {
|
||||
const type = isLikeOrDislike(id) ? 1 : 2;
|
||||
const likeMsg = t("general.name.playlist");
|
||||
const isThereASpace = setting.language === "zh-CN" ? "" : " ";
|
||||
try {
|
||||
const res = await likePlaylist(type, id);
|
||||
if (res.code === 200) {
|
||||
$message.success(`歌单${type == 1 ? "收藏成功" : "取消收藏成功"}`);
|
||||
$message.success(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.success") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.success") })
|
||||
}`
|
||||
);
|
||||
user.setUserPlayLists(() => {
|
||||
setDropdownOptions();
|
||||
});
|
||||
} else {
|
||||
$message.error(`歌单${type == 1 ? "收藏失败" : "取消收藏失败"}`);
|
||||
$message.error(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
$message.error(`歌单${type == 1 ? "收藏失败" : "取消收藏失败"}`);
|
||||
console.error(`歌单${type == 1 ? "收藏失败:" : "取消收藏失败:"}` + err);
|
||||
$message.error(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`
|
||||
);
|
||||
console.error(
|
||||
`${likeMsg + isThereASpace}${
|
||||
type == 1
|
||||
? t("menu.collection", { name: t("general.dialog.failed") })
|
||||
: t("menu.cancelCollection", { name: t("general.dialog.failed") })
|
||||
}`,
|
||||
err
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -580,6 +631,8 @@ watch(
|
||||
font-weight: bold;
|
||||
}
|
||||
.creator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 6px;
|
||||
font-size: 16px;
|
||||
opacity: 0.8;
|
||||
@@ -589,6 +642,9 @@ watch(
|
||||
opacity: 1;
|
||||
color: var(--main-color);
|
||||
}
|
||||
.n-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.time {
|
||||
margin-top: 8px;
|
||||
@@ -600,10 +656,13 @@ watch(
|
||||
align-items: flex-start;
|
||||
}
|
||||
.num {
|
||||
color: #999;
|
||||
}
|
||||
div {
|
||||
margin-right: 12px;
|
||||
// color: #999;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.n-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,16 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { getSearchData } from "@/api/search";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getLongTime } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索数据
|
||||
@@ -49,7 +52,7 @@ const getSearchDataList = (keywords, limit = 30, offset = 0, type = 10) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("搜索内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -101,4 +104,4 @@ onMounted(() => {
|
||||
(pageNumber.value - 1) * pagelimit.value
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
<script setup>
|
||||
import { getSearchData } from "@/api/search";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import ArtistLists from "@/components/DataList/ArtistLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索数据
|
||||
@@ -35,7 +37,7 @@ const getSearchDataList = (keywords, limit = 30, offset = 0, type = 100) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("搜索内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -60,4 +62,4 @@ watch(
|
||||
onMounted(() => {
|
||||
getSearchDataList(searchKeywords.value);
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<div class="title" v-if="searchKeywords">
|
||||
<span class="key">{{ searchKeywords }}</span>
|
||||
<span>的搜索结果</span>
|
||||
<n-text class="key" v-html="searchKeywords" />
|
||||
<n-text v-html="$t('nav.search.results')" />
|
||||
</div>
|
||||
<div class="title" v-else>
|
||||
<span class="key">未提供搜索关键字</span>
|
||||
<span class="key">{{ $t("general.name.noKeywords") }}</span>
|
||||
<br />
|
||||
<n-button
|
||||
strong
|
||||
@@ -13,7 +13,7 @@
|
||||
@click="router.go(-1)"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
返回上一级
|
||||
{{ $t("general.name.goBack") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<n-tabs
|
||||
@@ -23,11 +23,11 @@
|
||||
v-model:value="tabValue"
|
||||
v-if="searchKeywords"
|
||||
>
|
||||
<n-tab name="songs"> 单曲 </n-tab>
|
||||
<n-tab name="artists"> 歌手 </n-tab>
|
||||
<n-tab name="albums"> 专辑 </n-tab>
|
||||
<n-tab name="videos"> 视频 </n-tab>
|
||||
<n-tab name="playlists"> 歌单 </n-tab>
|
||||
<n-tab name="songs">{{ $t("general.name.song") }}</n-tab>
|
||||
<n-tab name="artists">{{ $t("general.name.artists") }}</n-tab>
|
||||
<n-tab name="albums">{{ $t("general.name.album") }}</n-tab>
|
||||
<n-tab name="videos">{{ $t("general.name.videos") }}</n-tab>
|
||||
<n-tab name="playlists">{{ $t("general.name.playlist") }}</n-tab>
|
||||
</n-tabs>
|
||||
<main class="content" v-if="searchKeywords">
|
||||
<router-view v-slot="{ Component }">
|
||||
@@ -43,6 +43,9 @@
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索关键词
|
||||
@@ -74,7 +77,8 @@ const tabChange = (value) => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (searchKeywords.value) $setSiteTitle(searchKeywords.value + "的搜索结果");
|
||||
if (searchKeywords.value)
|
||||
$setSiteTitle(searchKeywords.value + " " + t("nav.search.results"));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
import { getSearchData } from "@/api/search";
|
||||
import { useRouter } from "vue-router";
|
||||
import { formatNumber } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索数据
|
||||
@@ -49,7 +52,7 @@ const getSearchDataList = (keywords, limit = 30, offset = 0, type = 1000) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("搜索内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -101,4 +104,4 @@ onMounted(() => {
|
||||
(pageNumber.value - 1) * pagelimit.value
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -16,8 +16,11 @@ import { getSearchData } from "@/api/search";
|
||||
// import { getMusicDetail } from "@/api/song";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getSongTime } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索数据
|
||||
@@ -58,7 +61,7 @@ const getSearchDataList = (keywords, limit = 30, offset = 0, type = 1) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("搜索内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
|
||||
@@ -10,13 +10,16 @@
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { getSearchData } from "@/api/search";
|
||||
import { useRouter } from "vue-router";
|
||||
import { formatNumber, getSongTime } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import VideoLists from "@/components/DataList/VideoLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// 搜索数据
|
||||
@@ -50,7 +53,7 @@ const getSearchDataList = (keywords, limit = 30, offset = 0, type = 1004) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("搜索内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -102,4 +105,4 @@ onMounted(() => {
|
||||
(pageNumber.value - 1) * pagelimit.value
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="setting">
|
||||
<div class="title">全局设置</div>
|
||||
<div class="title">{{ $t("nav.avatar.setting") }}</div>
|
||||
<n-tabs
|
||||
class="main-tab"
|
||||
type="segment"
|
||||
@update:value="tabChange"
|
||||
v-model:value="tabValue"
|
||||
>
|
||||
<n-tab name="main"> 基础 </n-tab>
|
||||
<n-tab name="player"> 播放器 </n-tab>
|
||||
<n-tab name="other"> 其他 </n-tab>
|
||||
<n-tab name="main">{{ $t("setting.main") }}</n-tab>
|
||||
<n-tab name="player">{{ $t("setting.player") }}</n-tab>
|
||||
<n-tab name="other">{{ $t("general.type.other") }}</n-tab>
|
||||
</n-tabs>
|
||||
<main class="content">
|
||||
<router-view v-slot="{ Component }">
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
||||
// Tab 默认选中
|
||||
@@ -48,7 +50,7 @@ watch(
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("全局设置");
|
||||
$setSiteTitle(t("nav.avatar.setting"));
|
||||
// 回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
});
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
>
|
||||
<div class="top">
|
||||
<div class="name">
|
||||
主题色选择
|
||||
<span class="tip">更换全站主题色,即时生效</span>
|
||||
{{ $t("setting.themeType") }}
|
||||
<span class="tip">{{ $t("setting.themeTypeTip") }}</span>
|
||||
</div>
|
||||
<n-button
|
||||
v-if="themeType !== 'red'"
|
||||
@@ -18,7 +18,7 @@
|
||||
secondary
|
||||
@click="changeThemeColor(null, true)"
|
||||
>
|
||||
恢复默认
|
||||
{{ $t("general.name.restore") }}
|
||||
</n-button>
|
||||
</div>
|
||||
<n-grid
|
||||
@@ -35,12 +35,12 @@
|
||||
:class="item.label === themeType ? 'item check' : 'item'"
|
||||
@click="changeThemeColor(item)"
|
||||
>
|
||||
<n-text v-html="item.name" />
|
||||
<n-text v-html="language === 'zh-CN' ? item.name : item.label" />
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">语言</div>
|
||||
<div class="name">{{ $t("setting.language") }}</div>
|
||||
<n-select
|
||||
class="set"
|
||||
v-model:value="language"
|
||||
@@ -49,28 +49,28 @@
|
||||
/>
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">明暗模式</div>
|
||||
<n-select class="set" v-model:value="theme" :options="darkOptions" />
|
||||
<div class="name">{{ $t("setting.theme") }}</div>
|
||||
<n-select class="set" v-model:value="theme" :options="themeOptions" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">明暗模式跟随系统</div>
|
||||
<div class="name">{{ $t("setting.themeAuto") }}</div>
|
||||
<n-switch v-model:value="themeAuto" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
每日签到
|
||||
<span class="tip">是否自动进行每日签到</span>
|
||||
{{ $t("setting.autoSignIn") }}
|
||||
<span class="tip">{{ $t("setting.autoSignInTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="autoSignIn" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">显示轮播图</div>
|
||||
<div class="name">{{ $t("setting.bannerShow") }}</div>
|
||||
<n-switch v-model:value="bannerShow" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
列表点击方式
|
||||
<span class="tip">移动端该设置项无效,单击同时生效</span>
|
||||
{{ $t("setting.listClickMode") }}
|
||||
<span class="tip">{{ $t("setting.listClickModeTip") }}</span>
|
||||
</div>
|
||||
<n-select
|
||||
class="set"
|
||||
@@ -79,34 +79,36 @@
|
||||
/>
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">显示搜索历史</div>
|
||||
<div class="name">{{ $t("setting.searchHistory") }}</div>
|
||||
<n-switch v-model:value="searchHistory" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
显示底栏歌词
|
||||
<span class="tip">是否在播放时显示歌词</span>
|
||||
{{ $t("setting.bottomLyricShow") }}
|
||||
<span class="tip">{{ $t("setting.bottomLyricShowTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="bottomLyricShow" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
歌曲渐入渐出
|
||||
<span class="tip">是否在歌曲暂停 / 播放时渐入渐出</span>
|
||||
{{ $t("setting.songVolumeFade") }}
|
||||
<span class="tip">{{ $t("setting.songVolumeFadeTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="songVolumeFade" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
记忆播放位置
|
||||
<span class="tip">是否在刷新后恢复上次播放进度</span>
|
||||
{{ $t("setting.memoryLastPlaybackPosition") }}
|
||||
<span class="tip">{{
|
||||
$t("setting.memoryLastPlaybackPositionTip")
|
||||
}}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="memoryLastPlaybackPosition" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
歌曲音质
|
||||
<span class="tip">无损音质及以上需要您为黑胶会员</span>
|
||||
{{ $t("setting.songLevel") }}
|
||||
<span class="tip">{{ $t("setting.songLevelTip") }}</span>
|
||||
</div>
|
||||
<n-select
|
||||
class="set"
|
||||
@@ -116,12 +118,12 @@
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
尝试替换无法播放的歌曲
|
||||
{{ $t("setting.useUnmServerShow") }}
|
||||
<span class="tip">
|
||||
{{
|
||||
useUnmServerShow
|
||||
? "是否使用 UNM 替换无法播放的歌曲链接"
|
||||
: "请配置 UNM-Server 后使用解灰功能"
|
||||
? $t("setting.useUnmServerShowTip1")
|
||||
: $t("setting.useUnmServerShowTip2")
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
@@ -133,8 +135,8 @@
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
播放页快捷设置
|
||||
<span class="tip">是否在播放页面显示快捷设置</span>
|
||||
{{ $t("setting.showLyricSetting") }}
|
||||
<span class="tip">{{ $t("setting.showLyricSettingTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="showLyricSetting" :round="false" />
|
||||
</n-card>
|
||||
@@ -173,28 +175,34 @@ const { locale, t } = useI18n();
|
||||
const useUnmServerShow = import.meta.env.VITE_UNM_API ? true : false;
|
||||
|
||||
// 深浅模式
|
||||
const darkOptions = [
|
||||
{
|
||||
label: "浅色模式",
|
||||
value: "light",
|
||||
},
|
||||
{
|
||||
label: "深色模式",
|
||||
value: "dark",
|
||||
},
|
||||
];
|
||||
const themeOptions = ref([]);
|
||||
const themeChange = () => {
|
||||
themeOptions.value = [
|
||||
{
|
||||
label: t("nav.avatar.light"),
|
||||
value: "light",
|
||||
},
|
||||
{
|
||||
label: t("nav.avatar.dark"),
|
||||
value: "dark",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// 列表模式
|
||||
const listClickModeOptions = [
|
||||
{
|
||||
label: "双击播放",
|
||||
value: "dblclick",
|
||||
},
|
||||
{
|
||||
label: "单击播放",
|
||||
value: "click",
|
||||
},
|
||||
];
|
||||
const listClickModeOptions = ref([]);
|
||||
const listClickModeChange = () => {
|
||||
listClickModeOptions.value = [
|
||||
{
|
||||
label: t("setting.dblclick"),
|
||||
value: "dblclick",
|
||||
},
|
||||
{
|
||||
label: t("setting.click"),
|
||||
value: "click",
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// 语言
|
||||
const languageOptions = [
|
||||
@@ -210,67 +218,84 @@ const languageOptions = [
|
||||
|
||||
// 语言切换
|
||||
const changeLanguage = (value, option) => {
|
||||
console.log("语言切换:" + value);
|
||||
const html = document.documentElement;
|
||||
locale.value = value;
|
||||
$message.success("语言切换:" + option.label);
|
||||
if (html) html.setAttribute("lang", value);
|
||||
changeAllOptions();
|
||||
console.log(t("setting.changeLanguage", { name: value }));
|
||||
$message.success(t("setting.changeLanguage", { name: option.label }));
|
||||
};
|
||||
|
||||
// 歌曲音质
|
||||
const songLevelOptions = [
|
||||
{
|
||||
label: "标准",
|
||||
value: "standard",
|
||||
},
|
||||
{
|
||||
label: "较高",
|
||||
value: "higher",
|
||||
},
|
||||
,
|
||||
{
|
||||
label: "极高",
|
||||
value: "exhigh",
|
||||
},
|
||||
{
|
||||
label: "无损",
|
||||
value: "lossless",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
{
|
||||
label: "Hi-Res",
|
||||
value: "hires",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
{
|
||||
label: "鲸云臻音",
|
||||
value: "jyeffect",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
{
|
||||
label: "鲸云母带",
|
||||
value: "jymaster",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
];
|
||||
const songLevelOptions = ref([]);
|
||||
const songLevelChange = () => {
|
||||
songLevelOptions.value = [
|
||||
{
|
||||
label: t("setting.standard"),
|
||||
value: "standard",
|
||||
},
|
||||
{
|
||||
label: t("setting.higher"),
|
||||
value: "higher",
|
||||
},
|
||||
,
|
||||
{
|
||||
label: t("setting.exhigh"),
|
||||
value: "exhigh",
|
||||
},
|
||||
{
|
||||
label: t("setting.lossless"),
|
||||
value: "lossless",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
{
|
||||
label: t("setting.hires"),
|
||||
value: "hires",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
{
|
||||
label: t("setting.jyeffect"),
|
||||
value: "jyeffect",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
{
|
||||
label: t("setting.jymaster"),
|
||||
value: "jymaster",
|
||||
disabled: user.userData?.vipType ? false : true,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// 更改所有配置
|
||||
const changeAllOptions = () => {
|
||||
themeChange();
|
||||
listClickModeChange();
|
||||
songLevelChange();
|
||||
};
|
||||
|
||||
// 更换主题色
|
||||
const changeThemeColor = (data, reset = false) => {
|
||||
if (reset) {
|
||||
$dialog.warning({
|
||||
class: "s-dialog",
|
||||
title: "恢复默认",
|
||||
content: "确认恢复全站主题色为默认?",
|
||||
positiveText: "确认",
|
||||
negativeText: "取消",
|
||||
title: t("general.name.restore"),
|
||||
content: t("setting.themeTypeDialog"),
|
||||
positiveText: t("general.name.restore"),
|
||||
negativeText: t("general.dialog.cancel"),
|
||||
onPositiveClick: () => {
|
||||
$message.success("主题色已重置");
|
||||
$message.success(t("other.cleanAll"));
|
||||
themeType.value = "red";
|
||||
},
|
||||
});
|
||||
} else {
|
||||
$message.success("主题色更换为" + data.name);
|
||||
$message.success(t("setting.themeChange", { name: data.name }));
|
||||
themeType.value = data.label;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
changeAllOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -2,30 +2,36 @@
|
||||
<div class="set-other">
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
程序重置
|
||||
<span class="tip">若程序显示异常或出现问题时可尝试此操作</span>
|
||||
{{ $t("setting.resetApp") }}
|
||||
<span class="tip">{{ $t("setting.resetAppTip") }}</span>
|
||||
</div>
|
||||
<n-button strong secondary type="error" @click="resetApp">
|
||||
重置
|
||||
{{ $t("general.name.restore") }}
|
||||
</n-button>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// 程序重置
|
||||
const resetApp = () => {
|
||||
const cleanAll = () => {
|
||||
$message ? $message.success("重置成功") : alert("重置成功");
|
||||
$message
|
||||
? $message.success(t("other.cleanAll"))
|
||||
: alert(t("other.cleanAll"));
|
||||
localStorage.clear();
|
||||
window.location.href = "/";
|
||||
};
|
||||
$dialog.warning({
|
||||
class: "s-dialog",
|
||||
title: "程序重置",
|
||||
content: "确认重置为默认状态?你的登录状态以及自定义设置都将丢失!",
|
||||
positiveText: "确认重置",
|
||||
negativeText: "取消",
|
||||
title: t("setting.resetApp"),
|
||||
content: t("setting.resetAppWarning"),
|
||||
positiveText: t("setting.resetApp"),
|
||||
negativeText: t("general.dialog.cancel"),
|
||||
onPositiveClick: () => {
|
||||
$cleanAll ? $cleanAll() : cleanAll();
|
||||
},
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div class="set-player">
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
播放器样式
|
||||
<span class="tip">播放器左侧功能区样式</span>
|
||||
{{ $t("setting.playerStyle") }}
|
||||
<span class="tip">{{ $t("setting.playerStyleTip") }}</span>
|
||||
</div>
|
||||
<n-select
|
||||
class="set"
|
||||
@@ -13,11 +13,11 @@
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
播放背景样式
|
||||
{{ $t("setting.backgroundImageShow") }}
|
||||
<span class="tip">{{
|
||||
backgroundImageShow === "blur"
|
||||
? "将专辑封面模糊显示"
|
||||
: "提取专辑主色作为背景颜色"
|
||||
? $t("setting.backgroundImageShowTip1")
|
||||
: $t("setting.backgroundImageShowTip2")
|
||||
}}</span>
|
||||
</div>
|
||||
<n-select
|
||||
@@ -28,43 +28,43 @@
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
显示歌词翻译
|
||||
<span class="tip">是否在具有翻译歌词时显示</span>
|
||||
{{ $t("setting.showTransl") }}
|
||||
<span class="tip">{{ $t("setting.showTranslTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="showTransl" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
显示歌词音译
|
||||
<span class="tip">是否在具有音译歌词时显示</span>
|
||||
{{ $t("setting.showRoma") }}
|
||||
<span class="tip">{{ $t("setting.showRomaTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="showRoma" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
显示前奏等待
|
||||
<span class="tip">部分歌曲前奏可能存在显示错误</span>
|
||||
</div>
|
||||
<n-switch v-model:value="countDownShow" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
显示逐字歌词
|
||||
<span class="tip">是否在歌曲具有逐字歌词时显示,实验性功能</span>
|
||||
{{ $t("setting.showYrc") }}
|
||||
<span class="tip">{{ $t("setting.showYrcTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="showYrc" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
智能暂停滚动
|
||||
<span class="tip">鼠标移入歌词区域是否暂停滚动</span>
|
||||
{{ $t("setting.countDownShow") }}
|
||||
<span class="tip">{{ $t("setting.countDownShowTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="countDownShow" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
{{ $t("setting.lrcMousePause") }}
|
||||
<span class="tip">{{ $t("setting.lrcMousePauseTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="lrcMousePause" :round="false" />
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
歌词滚动位置
|
||||
<span class="tip">歌词高亮时所处的位置</span>
|
||||
{{ $t("setting.lyricsBlock") }}
|
||||
<span class="tip">{{ $t("setting.lyricsBlockTip") }}</span>
|
||||
</div>
|
||||
<n-select
|
||||
class="set"
|
||||
@@ -79,7 +79,7 @@
|
||||
alignItems: 'flex-start',
|
||||
}"
|
||||
>
|
||||
<div class="name">歌词文本大小</div>
|
||||
<div class="name">{{ $t("setting.lyricsFontSize") }}</div>
|
||||
<n-slider
|
||||
v-model:value="lyricsFontSize"
|
||||
:tooltip="false"
|
||||
@@ -87,9 +87,9 @@
|
||||
:min="3"
|
||||
:step="0.01"
|
||||
:marks="{
|
||||
3: '最小',
|
||||
3.6: '默认',
|
||||
4: '最大',
|
||||
3: t('setting.lyrics1'),
|
||||
3.6: t('setting.lyrics2'),
|
||||
4: t('setting.lyrics3'),
|
||||
}"
|
||||
/>
|
||||
<div :class="lyricsBlur ? 'more blur' : 'more'">
|
||||
@@ -114,7 +114,7 @@
|
||||
</div>
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">默认歌词位置</div>
|
||||
<div class="name">{{ $t("setting.lyricsPosition") }}</div>
|
||||
<n-select
|
||||
class="set"
|
||||
v-model:value="lyricsPosition"
|
||||
@@ -123,8 +123,8 @@
|
||||
</n-card>
|
||||
<n-card class="set-item">
|
||||
<div class="name">
|
||||
歌词模糊
|
||||
<span class="tip">未播放或已播放歌词模糊显示,实验性功能</span>
|
||||
{{ $t("setting.lyricsBlur") }}
|
||||
<span class="tip">{{ $t("setting.lyricsBlurTip") }}</span>
|
||||
</div>
|
||||
<n-switch v-model:value="lyricsBlur" :round="false" />
|
||||
</n-card>
|
||||
@@ -145,6 +145,9 @@
|
||||
<script setup>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { settingStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const setting = settingStore();
|
||||
const {
|
||||
@@ -165,11 +168,11 @@ const {
|
||||
// 歌词位置
|
||||
const lyricsPositionOptions = [
|
||||
{
|
||||
label: "居左",
|
||||
label: t("setting.positionLeft"),
|
||||
value: "left",
|
||||
},
|
||||
{
|
||||
label: "居中",
|
||||
label: t("setting.positionCenter"),
|
||||
value: "center",
|
||||
},
|
||||
];
|
||||
@@ -177,11 +180,11 @@ const lyricsPositionOptions = [
|
||||
// 歌词滚动位置
|
||||
const lyricsBlockOptions = [
|
||||
{
|
||||
label: "靠近顶部",
|
||||
label: t("setting.blockStart"),
|
||||
value: "start",
|
||||
},
|
||||
{
|
||||
label: "水平居中",
|
||||
label: t("setting.blockCenter"),
|
||||
value: "center",
|
||||
},
|
||||
];
|
||||
@@ -189,11 +192,11 @@ const lyricsBlockOptions = [
|
||||
// 播放器样式
|
||||
const playerStyleOptions = [
|
||||
{
|
||||
label: "封面模式",
|
||||
label: t("setting.cover"),
|
||||
value: "cover",
|
||||
},
|
||||
{
|
||||
label: "唱片模式",
|
||||
label: t("setting.record"),
|
||||
value: "record",
|
||||
},
|
||||
];
|
||||
@@ -201,11 +204,11 @@ const playerStyleOptions = [
|
||||
// 播放背景类型
|
||||
const backgroundImageShowOptions = [
|
||||
{
|
||||
label: "封面主色",
|
||||
label: t("setting.solid"),
|
||||
value: "solid",
|
||||
},
|
||||
{
|
||||
label: "封面模糊",
|
||||
label: t("setting.blur"),
|
||||
value: "blur",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -2,14 +2,24 @@
|
||||
<div class="song" v-if="musicDetail">
|
||||
<div class="detail">
|
||||
<div class="pic">
|
||||
<n-avatar
|
||||
<n-image
|
||||
show-toolbar-tooltip
|
||||
class="coverImg"
|
||||
:src="
|
||||
musicDetail.al.picUrl
|
||||
? musicDetail.al.picUrl.replace(/^http:/, 'https:') +
|
||||
'?param=1024y1024'
|
||||
: '/images/pic/default.png'
|
||||
"
|
||||
:previewed-img-props="{ style: { borderRadius: '8px' } }"
|
||||
:preview-src="getCoverUrl(musicDetail?.al.picUrl)"
|
||||
:src="getCoverUrl(musicDetail?.al.picUrl, 1024)"
|
||||
fallback-src="/images/pic/default.png"
|
||||
>
|
||||
<template #placeholder>
|
||||
<div class="cover-loading">
|
||||
<n-spin />
|
||||
</div>
|
||||
</template>
|
||||
</n-image>
|
||||
<n-image
|
||||
class="shadow"
|
||||
preview-disabled
|
||||
:src="getCoverUrl(musicDetail?.al.picUrl, 1024)"
|
||||
fallback-src="/images/pic/default.png"
|
||||
/>
|
||||
</div>
|
||||
@@ -22,20 +32,43 @@
|
||||
v-if="musicDetail.alia[0]"
|
||||
v-html="musicDetail.alia[0]"
|
||||
/>
|
||||
<div class="all-artist">
|
||||
<n-text class="tip" depth="3">歌手:</n-text>
|
||||
<AllArtists v-if="musicDetail.ar" :artistsData="musicDetail.ar" />
|
||||
<n-space class="tag">
|
||||
<n-tag
|
||||
v-if="musicDetail.fee == 1 || musicDetail.fee == 4"
|
||||
class="vip"
|
||||
round
|
||||
:bordered="false"
|
||||
>
|
||||
{{ musicDetail.fee == 1 ? "VIP" : "EP" }}
|
||||
</n-tag>
|
||||
<n-tag
|
||||
v-if="musicDetail.pc"
|
||||
class="cloud"
|
||||
round
|
||||
type="info"
|
||||
:bordered="false"
|
||||
>
|
||||
{{ $t("general.name.cloud") }}
|
||||
</n-tag>
|
||||
</n-space>
|
||||
<div class="item">
|
||||
<n-icon :depth="3" :component="People" />
|
||||
<AllArtists
|
||||
v-if="musicDetail.ar"
|
||||
:artistsData="musicDetail.ar"
|
||||
:isDark="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="album">
|
||||
<n-text class="tip" depth="3">专辑:</n-text>
|
||||
<div class="item">
|
||||
<n-icon :depth="3" :component="RecordDisc" />
|
||||
<n-text
|
||||
class="text"
|
||||
v-html="musicDetail.al.name"
|
||||
@click="router.push(`/album?id=${musicDetail.al.id}`)"
|
||||
/>
|
||||
</div>
|
||||
<div class="time" v-if="musicDetail.publishTime">
|
||||
<n-text class="tip" depth="3">发行日期:</n-text>
|
||||
<div class="item" v-if="musicDetail.publishTime">
|
||||
<n-icon :depth="3" :component="Time" />
|
||||
<n-text
|
||||
class="text"
|
||||
v-html="getLongTime(musicDetail.publishTime)"
|
||||
@@ -50,9 +83,9 @@
|
||||
@click="addSong(musicDetail)"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="PlayArrowRound" />
|
||||
<n-icon :component="PlayOne" />
|
||||
</template>
|
||||
播放
|
||||
{{ $t("general.name.play") }}
|
||||
</n-button>
|
||||
<n-button
|
||||
strong
|
||||
@@ -60,9 +93,9 @@
|
||||
@click="addPlayListRef.openAddToPlaylist(musicId)"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="PlaylistAddRound" />
|
||||
<n-icon :component="ListAdd" />
|
||||
</template>
|
||||
添加
|
||||
{{ $t("general.name.add") }}
|
||||
</n-button>
|
||||
<n-button
|
||||
strong
|
||||
@@ -70,9 +103,9 @@
|
||||
@click="router.push(`/comment?id=${musicDetail.id}&page=1`)"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="MessageFilled" />
|
||||
<n-icon :component="Comments" />
|
||||
</template>
|
||||
评论
|
||||
{{ $t("general.name.comment") }}
|
||||
</n-button>
|
||||
<n-button
|
||||
strong
|
||||
@@ -81,16 +114,22 @@
|
||||
@click="router.push(`/video?id=${musicDetail.mv}`)"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon :component="VideocamRound" />
|
||||
<n-icon :component="Youtube" />
|
||||
</template>
|
||||
MV
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</div>
|
||||
<n-divider />
|
||||
<div class="comments" v-if="commentData[0]">
|
||||
<n-h6 prefix="bar"> {{ $t("general.name.hotComments") }} </n-h6>
|
||||
<div class="content">
|
||||
<Comment v-for="item in commentData" :key="item" :commentData="item" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="simiPlayList" v-if="simiPlayList[0]">
|
||||
<n-h6 prefix="bar"> 包含这首歌的歌单 </n-h6>
|
||||
<n-divider />
|
||||
<n-h6 prefix="bar"> {{ $t("other.containing") }} </n-h6>
|
||||
<CoverLists :listData="simiPlayList" />
|
||||
</div>
|
||||
<!-- 添加到歌单 -->
|
||||
@@ -100,20 +139,27 @@
|
||||
|
||||
<script setup>
|
||||
import { getSimiPlayList, getMusicDetail } from "@/api/song";
|
||||
import { getComment } from "@/api/comment";
|
||||
import { useRouter } from "vue-router";
|
||||
import { musicStore } from "@/store";
|
||||
import { getLongTime } from "@/utils/timeTools";
|
||||
import {
|
||||
PlayArrowRound,
|
||||
MessageFilled,
|
||||
VideocamRound,
|
||||
PlaylistAddRound,
|
||||
} from "@vicons/material";
|
||||
PlayOne,
|
||||
Comments,
|
||||
ListAdd,
|
||||
Youtube,
|
||||
People,
|
||||
RecordDisc,
|
||||
Time,
|
||||
} from "@icon-park/vue-next";
|
||||
import { formatNumber } from "@/utils/timeTools";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import AllArtists from "@/components/DataList/AllArtists.vue";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
import AddPlaylist from "@/components/DataModal/AddPlaylist.vue";
|
||||
import Comment from "@/components/Comment/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const music = musicStore();
|
||||
const addPlayListRef = ref(null);
|
||||
@@ -122,9 +168,23 @@ const addPlayListRef = ref(null);
|
||||
const musicId = ref(router.currentRoute.value.query.id);
|
||||
const musicDetail = ref(null);
|
||||
|
||||
// 评论数据
|
||||
const commentData = ref([]);
|
||||
|
||||
// 相似数据
|
||||
const simiPlayList = ref([]);
|
||||
|
||||
// 封面图像地址
|
||||
const getCoverUrl = (url, size = null) => {
|
||||
if (!url) return "/images/pic/default.png";
|
||||
const sizeUrl = size ? `?param=${size}y${size}` : "";
|
||||
const imageUrl = url.replace(/^http:/, "https:");
|
||||
if (imageUrl.endsWith(".jpg")) {
|
||||
return imageUrl + sizeUrl;
|
||||
}
|
||||
return imageUrl;
|
||||
};
|
||||
|
||||
// 获取歌曲数据
|
||||
const getMusicDetailData = (id) => {
|
||||
getMusicDetail(id).then((res) => {
|
||||
@@ -132,16 +192,39 @@ const getMusicDetailData = (id) => {
|
||||
if (res.songs[0]) {
|
||||
musicDetail.value = res.songs[0];
|
||||
$setSiteTitle(
|
||||
res.songs[0].name + " - " + res.songs[0].ar[0].name + " - 单曲"
|
||||
res.songs[0].name +
|
||||
" - " +
|
||||
res.songs[0].ar[0].name +
|
||||
" - " +
|
||||
t("general.name.song")
|
||||
);
|
||||
// 获取热门评论
|
||||
getCommentData(id);
|
||||
// 获取相似数据
|
||||
getSimiData(id);
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
} else {
|
||||
$message.error("歌曲信息获取失败");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取评论数据
|
||||
const getCommentData = (id) => {
|
||||
getComment(id)
|
||||
.then((res) => {
|
||||
// 写入数据
|
||||
if (res.total > 0) {
|
||||
commentData.value = res.hotComments;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(t("general.message.acquisitionFailed"), err);
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
});
|
||||
};
|
||||
|
||||
// 获取相似数据
|
||||
const getSimiData = (id) => {
|
||||
getSimiPlayList(id).then((res) => {
|
||||
@@ -205,11 +288,54 @@ watch(
|
||||
justify-content: center;
|
||||
max-width: 280px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
margin-right: 40px;
|
||||
.n-avatar {
|
||||
position: relative;
|
||||
transition: transform 0.3s;
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.coverImg {
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: inherit;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
:deep(img) {
|
||||
width: 100%;
|
||||
}
|
||||
.cover-loading {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 100%;
|
||||
background-color: #0001;
|
||||
.n-spin-body {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.shadow {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
filter: blur(16px) opacity(0.6);
|
||||
transform: scale(0.92, 0.96);
|
||||
z-index: 0;
|
||||
background-size: cover;
|
||||
aspect-ratio: 1/1;
|
||||
:deep(img) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
@@ -228,14 +354,17 @@ watch(
|
||||
.alia {
|
||||
font-size: 20px;
|
||||
}
|
||||
.all-artist {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.tag {
|
||||
margin: 12px 0;
|
||||
}
|
||||
.album {
|
||||
margin: 4px 0;
|
||||
.item {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
.n-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
.text {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
@@ -252,6 +381,7 @@ watch(
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.pic {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -267,5 +397,8 @@ watch(
|
||||
}
|
||||
}
|
||||
}
|
||||
.comments {
|
||||
margin-top: 40px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
<n-result
|
||||
class="error"
|
||||
status="403"
|
||||
title="禁止访问"
|
||||
description="总有些门是对你关闭的"
|
||||
:title="$t('state.prohibition')"
|
||||
:description="$t('state.prohibitionDesc')"
|
||||
>
|
||||
<template #footer>
|
||||
<n-button type="primary" @click="router.go(-1)">回到上一页</n-button>
|
||||
<n-button type="primary" @click="router.go(-1)">{{
|
||||
$t("general.name.goBack")
|
||||
}}</n-button>
|
||||
</template>
|
||||
</n-result>
|
||||
</template>
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
<n-result
|
||||
class="error"
|
||||
status="404"
|
||||
title="资源不存在"
|
||||
description="怎么跑到这来了"
|
||||
:title="$t('state.notFound')"
|
||||
:description="$t('state.notFoundDesc')"
|
||||
>
|
||||
<template #footer>
|
||||
<n-button type="primary" @click="router.go(-1)">回到上一页</n-button>
|
||||
<n-button type="primary" @click="router.go(-1)">{{
|
||||
$t("general.name.goBack")
|
||||
}}</n-button>
|
||||
</template>
|
||||
</n-result>
|
||||
</template>
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
<n-result
|
||||
class="error"
|
||||
status="500"
|
||||
title="服务器错误"
|
||||
description="服务器寄了,等会再试吧"
|
||||
:title="$t('state.error')"
|
||||
:description="$t('state.errorDesc')"
|
||||
>
|
||||
<template #footer>
|
||||
<n-button type="primary" @click="router.push('/')">重新载入</n-button>
|
||||
<n-button type="primary" @click="router.push('/')">{{
|
||||
$t("general.name.reload")
|
||||
}}</n-button>
|
||||
</template>
|
||||
</n-result>
|
||||
</template>
|
||||
@@ -28,4 +30,4 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
<script setup>
|
||||
import { userStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const user = userStore();
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("音乐库 - 收藏的专辑");
|
||||
$setSiteTitle(t("nav.user") + " - " + t("nav.userChildren.album"));
|
||||
if (!user.getUserAlbumLists.has && !user.getUserAlbumLists.isLoading)
|
||||
user.setUserAlbumLists();
|
||||
});
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
<script setup>
|
||||
import { userStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import ArtistLists from "@/components/DataList/ArtistLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const user = userStore();
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("音乐库 - 收藏的歌手");
|
||||
$setSiteTitle(t("nav.user") + " - " + t("nav.userChildren.artist"));
|
||||
if (!user.getUserArtistLists.has && !user.getUserArtistLists.isLoading)
|
||||
user.setUserArtistLists();
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<template #icon>
|
||||
<n-icon :component="BackupRound" />
|
||||
</template>
|
||||
上传歌曲
|
||||
{{ $t("general.name.upCloud") }}
|
||||
</n-button>
|
||||
<input
|
||||
ref="upSongRef"
|
||||
@@ -34,11 +34,14 @@
|
||||
/>
|
||||
</template>
|
||||
<n-text>
|
||||
已用 {{ (100 / (cloudSpace[1] / cloudSpace[0])).toFixed() }}%,剩余
|
||||
{{ cloudSpace[1] - cloudSpace[0] }} G
|
||||
{{
|
||||
$t("general.name.cloudUsed", {
|
||||
used: (100 / (cloudSpace[1] / cloudSpace[0])).toFixed(),
|
||||
remaining: cloudSpace[1] - cloudSpace[0],
|
||||
})
|
||||
}}
|
||||
</n-text>
|
||||
</n-popover>
|
||||
|
||||
<span>{{ cloudSpace[1] }} G</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,7 +57,7 @@
|
||||
class="s-modal close"
|
||||
v-model:show="upSongModal"
|
||||
preset="card"
|
||||
title="云盘上传"
|
||||
:title="$t('general.name.upCloud')"
|
||||
:auto-focus="false"
|
||||
:bordered="false"
|
||||
:close-on-esc="false"
|
||||
@@ -70,9 +73,11 @@
|
||||
/>
|
||||
<template #footer>
|
||||
<n-space justify="end" v-if="upSongType === 'error'">
|
||||
<n-button @click="closeUpSongModal"> 取消 </n-button>
|
||||
<n-button @click="closeUpSongModal">
|
||||
{{ $t("general.dialog.cancel") }}
|
||||
</n-button>
|
||||
<n-button type="primary" @click="resetUpSongModal">
|
||||
重新上传
|
||||
{{ $t("general.dialog.resetUp") }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
@@ -86,9 +91,11 @@ import { useRouter } from "vue-router";
|
||||
import { settingStore } from "@/store";
|
||||
import { getSongTime } from "@/utils/timeTools";
|
||||
import { BackupRound } from "@vicons/material";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DataLists from "@/components/DataList/DataLists.vue";
|
||||
import Pagination from "@/components/Pagination/index.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const setting = settingStore();
|
||||
|
||||
@@ -135,7 +142,7 @@ const getCloudData = (limit = 30, offset = 0, scroll = true) => {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
$message.error("搜索内容为空");
|
||||
$message.error(t("general.message.acquisitionFailed"));
|
||||
}
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -147,7 +154,6 @@ const onUploadProgress = (progressEvent) => {
|
||||
const { loaded, total } = progressEvent;
|
||||
const percentCompleted = Math.round((loaded * 100) / total);
|
||||
upSongCompleted.value = Number(percentCompleted);
|
||||
console.log(`上传 ${percentCompleted}% 完成`);
|
||||
};
|
||||
|
||||
// 歌曲上传
|
||||
@@ -163,21 +169,25 @@ const upCloudSongData = (e) => {
|
||||
if (res.code === 200) {
|
||||
closeUpSongModal();
|
||||
if (!res.privateCloud.simpleSong.al?.name) {
|
||||
$message.warning("上传歌曲详细信息获取失败,可尝试歌曲纠正");
|
||||
$message.warning(t("general.message.upCloudNotHas"));
|
||||
}
|
||||
$message.success(res.privateCloud.simpleSong?.name + " 上传成功");
|
||||
$message.success(
|
||||
t("general.message.upCloudSuccess", {
|
||||
name: res.privateCloud.simpleSong?.name,
|
||||
})
|
||||
);
|
||||
getCloudData(pagelimit.value, (pageNumber.value - 1) * pagelimit.value);
|
||||
} else {
|
||||
upSongType.value = "error";
|
||||
$message.error("歌曲上传出错,请重试");
|
||||
console.error("歌曲上传出错,请重试");
|
||||
$message.error(t("general.message.upCloudError"));
|
||||
console.error(t("general.message.upCloudError"));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
upSongType.value = "error";
|
||||
closeUpSongModal();
|
||||
$message.error("歌曲上传出现错误");
|
||||
console.error("歌曲上传出现错误:" + err);
|
||||
$message.error(t("general.message.upCloudFailure"));
|
||||
console.error(t("general.message.upCloudFailure"), err);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -233,7 +243,7 @@ watch(
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("音乐库 - 音乐云盘");
|
||||
$setSiteTitle(t("nav.user") + " - " + t("nav.userChildren.cloud"));
|
||||
getCloudData(pagelimit.value, (pageNumber.value - 1) * pagelimit.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
/>
|
||||
<div class="text">
|
||||
<n-text class="key">{{ user.getUserData.nickname }}</n-text>
|
||||
<n-text class="tip">的音乐库</n-text>
|
||||
<n-text class="tip" v-html="$t('nav.userChildren.results')" />
|
||||
</div>
|
||||
</div>
|
||||
<n-tabs
|
||||
@@ -22,10 +22,10 @@
|
||||
@update:value="tabChange"
|
||||
v-model:value="tabValue"
|
||||
>
|
||||
<n-tab name="playlists">{{ $t("nav.userChildren.playlists") }}</n-tab>
|
||||
<n-tab name="playlists">{{ $t("nav.userChildren.playlist") }}</n-tab>
|
||||
<n-tab name="like">{{ $t("nav.userChildren.like") }}</n-tab>
|
||||
<n-tab name="album">{{ $t("nav.userChildren.album") }}</n-tab>
|
||||
<n-tab name="artists">{{ $t("nav.userChildren.artists") }}</n-tab>
|
||||
<n-tab name="artists">{{ $t("nav.userChildren.artist") }}</n-tab>
|
||||
<n-tab name="cloud">{{ $t("nav.userChildren.cloud") }}</n-tab>
|
||||
</n-tabs>
|
||||
<main class="content">
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
|
||||
<script setup>
|
||||
import { userStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const user = userStore();
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("音乐库 - 收藏的歌单");
|
||||
$setSiteTitle(t("nav.user") + " - " + t("nav.userChildren.like"));
|
||||
if (!user.getUserPlayLists.has && !user.getUserPlayLists.isLoading)
|
||||
user.setUserPlayLists();
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<template #icon>
|
||||
<n-icon :component="AddCircleRound" />
|
||||
</template>
|
||||
新建歌单
|
||||
{{ $t("menu.create") }}
|
||||
</n-button>
|
||||
<!-- 新建歌单 -->
|
||||
<CreatePlaylist ref="createPlaylistRef" />
|
||||
@@ -24,14 +24,16 @@
|
||||
<script setup>
|
||||
import { AddCircleRound } from "@vicons/material";
|
||||
import { userStore } from "@/store";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import CoverLists from "@/components/DataList/CoverLists.vue";
|
||||
import CreatePlaylist from "@/components/DataModal/CreatePlaylist.vue";
|
||||
|
||||
const { t } = useI18n();
|
||||
const user = userStore();
|
||||
const createPlaylistRef = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
$setSiteTitle("音乐库 - 我的歌单");
|
||||
$setSiteTitle(t("nav.user") + " - " + t("nav.userChildren.playlist"));
|
||||
if (!user.getUserPlayLists.has && !user.getUserPlayLists.isLoading)
|
||||
user.setUserPlayLists();
|
||||
});
|
||||
|
||||
@@ -16,21 +16,21 @@
|
||||
<div class="num">
|
||||
<span class="playCount">
|
||||
<n-icon :component="OndemandVideoFilled" />
|
||||
{{ formatNumber(videoData.playCount) }} 次播放
|
||||
{{ formatNumber(videoData.playCount) }}
|
||||
</span>
|
||||
<span class="shareCount">
|
||||
<n-icon :component="ShareFilled" />
|
||||
{{ formatNumber(videoData.shareCount) }} 次分享
|
||||
{{ formatNumber(videoData.shareCount) }}
|
||||
</span>
|
||||
<span class="commentCount">
|
||||
<n-icon :component="MessageOutlined" />
|
||||
{{ formatNumber(videoData.commentCount) }} 条评论
|
||||
{{ formatNumber(videoData.commentCount) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment" v-if="commentData.allComments[0]">
|
||||
<div class="hotComments" v-if="commentData.hotComments[0]">
|
||||
<n-h6 prefix="bar"> 热门评论 </n-h6>
|
||||
<n-h6 prefix="bar"> {{ $t("general.name.hotComments") }} </n-h6>
|
||||
<div class="loading" v-if="!commentData.hotComments[0]">
|
||||
<n-skeleton text :repeat="3" />
|
||||
<n-skeleton text style="width: 60%" />
|
||||
@@ -45,8 +45,8 @@
|
||||
</div>
|
||||
<div class="allComments" ref="allCommentsRef">
|
||||
<n-h6 prefix="bar">
|
||||
全部评论
|
||||
<span class="count">{{ commentsCount }} 条</span>
|
||||
{{ $t("general.name.allComments") }}
|
||||
<span class="count">{{ commentsCount }} +</span>
|
||||
</n-h6>
|
||||
<div class="loading" v-if="!commentData.allComments[0]">
|
||||
<n-skeleton text :repeat="3" />
|
||||
@@ -68,7 +68,7 @@
|
||||
</div>
|
||||
</section>
|
||||
<section class="simiVideo">
|
||||
<n-h6 prefix="bar"> 相似视频 </n-h6>
|
||||
<n-h6 prefix="bar"> {{ $t("general.name.simiVideo") }} </n-h6>
|
||||
<VideoLists v-if="simiVideo[0]" :listData="simiVideo" />
|
||||
</section>
|
||||
</div>
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from "vue-router";
|
||||
import { musicStore } from "@/store";
|
||||
import { musicStore, settingStore } from "@/store";
|
||||
import { getVideoDetail, getVideoUrl, getSimiVideo } from "@/api/video";
|
||||
import { getComment } from "@/api/comment";
|
||||
import { formatNumber, getSongTime } from "@/utils/timeTools";
|
||||
@@ -85,6 +85,7 @@ import {
|
||||
ShareFilled,
|
||||
MessageOutlined,
|
||||
} from "@vicons/material";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import VideoLists from "@/components/DataList/VideoLists.vue";
|
||||
import AllArtists from "@/components/DataList/AllArtists.vue";
|
||||
import Comment from "@/components/Comment/index.vue";
|
||||
@@ -92,8 +93,10 @@ import Pagination from "@/components/Pagination/index.vue";
|
||||
import Plyr from "plyr";
|
||||
import "plyr/dist/plyr.css";
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const music = musicStore();
|
||||
const setting = settingStore();
|
||||
|
||||
// 视频 id
|
||||
const videoId = ref(router.currentRoute.value.query.id);
|
||||
@@ -113,19 +116,22 @@ const playerOptions = {
|
||||
default: 1080,
|
||||
options: [1080, 720, 480, 240],
|
||||
},
|
||||
i18n: {
|
||||
play: "播放",
|
||||
pause: "暂停",
|
||||
speed: "速度",
|
||||
settings: "设置",
|
||||
normal: "正常",
|
||||
quality: "画质",
|
||||
pip: "画中画",
|
||||
enterFullscreen: "开启全屏",
|
||||
exitFullscreen: "退出全屏",
|
||||
mute: "音量",
|
||||
unmute: "静音",
|
||||
},
|
||||
i18n:
|
||||
setting.language === "zh-CN"
|
||||
? {
|
||||
play: "播放",
|
||||
pause: "暂停",
|
||||
speed: "速度",
|
||||
settings: "设置",
|
||||
normal: "正常",
|
||||
quality: "画质",
|
||||
pip: "画中画",
|
||||
enterFullscreen: "开启全屏",
|
||||
exitFullscreen: "退出全屏",
|
||||
mute: "音量",
|
||||
unmute: "静音",
|
||||
}
|
||||
: {},
|
||||
tooltips: {
|
||||
controls: true,
|
||||
},
|
||||
@@ -142,7 +148,13 @@ const commentsCount = ref(0);
|
||||
const getVideoData = (id) => {
|
||||
getVideoDetail(id).then((res) => {
|
||||
videoData.value = res.data;
|
||||
$setSiteTitle(res.data.name + " - " + res.data.artists[0].name + " - 视频");
|
||||
$setSiteTitle(
|
||||
res.data.name +
|
||||
" - " +
|
||||
res.data.artists[0].name +
|
||||
" - " +
|
||||
t("general.name.videos")
|
||||
);
|
||||
const requests = res.data.brs.map((v) => {
|
||||
return getVideoUrl(id, v.br);
|
||||
});
|
||||
@@ -163,8 +175,8 @@ const getVideoData = (id) => {
|
||||
};
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
$message.error("视频加载失败,请重试");
|
||||
console.error(t("general.message.userChildren.playlist"), err);
|
||||
$message.error(t("general.message.userChildren.playlist"));
|
||||
});
|
||||
// 请求后回顶
|
||||
if (typeof $scrollToTop !== "undefined") $scrollToTop();
|
||||
@@ -221,7 +233,6 @@ onMounted(() => {
|
||||
getCommentData(videoId.value);
|
||||
// 播放器事件
|
||||
player.value.on("playing", () => {
|
||||
console.log("视频开始播放");
|
||||
// 隐藏控制条及暂停音乐
|
||||
music.setPlayBarState(false);
|
||||
music.setPlayState(false);
|
||||
|
||||
Reference in New Issue
Block a user