初始化
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + Vue</title>
|
<title>相册</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "spa-view",
|
"name": "album-view",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
61
pnpm-lock.yaml
generated
61
pnpm-lock.yaml
generated
@@ -14,6 +14,9 @@ importers:
|
|||||||
'@ant-design/icons-vue':
|
'@ant-design/icons-vue':
|
||||||
specifier: ^7.0.1
|
specifier: ^7.0.1
|
||||||
version: 7.0.1(vue@3.5.13)
|
version: 7.0.1(vue@3.5.13)
|
||||||
|
'@fortawesome/fontawesome-free':
|
||||||
|
specifier: ^6.7.2
|
||||||
|
version: 6.7.2
|
||||||
'@tailwindcss/vite':
|
'@tailwindcss/vite':
|
||||||
specifier: ^4.1.4
|
specifier: ^4.1.4
|
||||||
version: 4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.88.0))
|
version: 4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.88.0))
|
||||||
@@ -23,9 +26,6 @@ importers:
|
|||||||
ant-design-vue:
|
ant-design-vue:
|
||||||
specifier: ^4.1.1
|
specifier: ^4.1.1
|
||||||
version: 4.2.6(vue@3.5.13)
|
version: 4.2.6(vue@3.5.13)
|
||||||
aos:
|
|
||||||
specifier: ^2.3.4
|
|
||||||
version: 2.3.4
|
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.6.2
|
specifier: ^1.6.2
|
||||||
version: 1.9.0
|
version: 1.9.0
|
||||||
@@ -263,6 +263,10 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@fortawesome/fontawesome-free@6.7.2':
|
||||||
|
resolution: {integrity: sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.0':
|
'@jridgewell/sourcemap-codec@1.5.0':
|
||||||
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
|
||||||
|
|
||||||
@@ -295,42 +299,36 @@ packages:
|
|||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm-musl@2.5.1':
|
'@parcel/watcher-linux-arm-musl@2.5.1':
|
||||||
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
|
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
'@parcel/watcher-linux-arm64-glibc@2.5.1':
|
||||||
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
|
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
'@parcel/watcher-linux-arm64-musl@2.5.1':
|
||||||
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
|
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
'@parcel/watcher-linux-x64-glibc@2.5.1':
|
||||||
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
|
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-musl@2.5.1':
|
'@parcel/watcher-linux-x64-musl@2.5.1':
|
||||||
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
|
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-win32-arm64@2.5.1':
|
'@parcel/watcher-win32-arm64@2.5.1':
|
||||||
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
|
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
|
||||||
@@ -388,67 +386,56 @@ packages:
|
|||||||
resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==}
|
resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.40.0':
|
'@rollup/rollup-linux-arm-musleabihf@4.40.0':
|
||||||
resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==}
|
resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.40.0':
|
'@rollup/rollup-linux-arm64-gnu@4.40.0':
|
||||||
resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==}
|
resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.40.0':
|
'@rollup/rollup-linux-arm64-musl@4.40.0':
|
||||||
resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==}
|
resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.40.0':
|
'@rollup/rollup-linux-loongarch64-gnu@4.40.0':
|
||||||
resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==}
|
resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-powerpc64le-gnu@4.40.0':
|
'@rollup/rollup-linux-powerpc64le-gnu@4.40.0':
|
||||||
resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==}
|
resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.40.0':
|
'@rollup/rollup-linux-riscv64-gnu@4.40.0':
|
||||||
resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==}
|
resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.40.0':
|
'@rollup/rollup-linux-riscv64-musl@4.40.0':
|
||||||
resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==}
|
resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.40.0':
|
'@rollup/rollup-linux-s390x-gnu@4.40.0':
|
||||||
resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==}
|
resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.40.0':
|
'@rollup/rollup-linux-x64-gnu@4.40.0':
|
||||||
resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==}
|
resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.40.0':
|
'@rollup/rollup-linux-x64-musl@4.40.0':
|
||||||
resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==}
|
resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-win32-arm64-msvc@4.40.0':
|
'@rollup/rollup-win32-arm64-msvc@4.40.0':
|
||||||
resolution: {integrity: sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==}
|
resolution: {integrity: sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==}
|
||||||
@@ -506,28 +493,24 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.4':
|
'@tailwindcss/oxide-linux-arm64-musl@4.1.4':
|
||||||
resolution: {integrity: sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==}
|
resolution: {integrity: sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.4':
|
'@tailwindcss/oxide-linux-x64-gnu@4.1.4':
|
||||||
resolution: {integrity: sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==}
|
resolution: {integrity: sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-x64-musl@4.1.4':
|
'@tailwindcss/oxide-linux-x64-musl@4.1.4':
|
||||||
resolution: {integrity: sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==}
|
resolution: {integrity: sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@tailwindcss/oxide-wasm32-wasi@4.1.4':
|
'@tailwindcss/oxide-wasm32-wasi@4.1.4':
|
||||||
resolution: {integrity: sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==}
|
resolution: {integrity: sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==}
|
||||||
@@ -632,9 +615,6 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: '>=3.2.0'
|
vue: '>=3.2.0'
|
||||||
|
|
||||||
aos@2.3.4:
|
|
||||||
resolution: {integrity: sha512-zh/ahtR2yME4I51z8IttIt4lC1Nw0ktsFtmeDzID1m9naJnWXhCoARaCgNOGXb5CLy3zm+wqmRAEgMYB5E2HUw==}
|
|
||||||
|
|
||||||
array-tree-filter@2.1.0:
|
array-tree-filter@2.1.0:
|
||||||
resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==}
|
resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==}
|
||||||
|
|
||||||
@@ -659,9 +639,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
|
||||||
engines: {node: '>= 14.16.0'}
|
engines: {node: '>= 14.16.0'}
|
||||||
|
|
||||||
classlist-polyfill@1.2.0:
|
|
||||||
resolution: {integrity: sha512-GzIjNdcEtH4ieA2S8NmrSxv7DfEV5fmixQeyTmqmRmRJPGpRBaSnA2a0VrCjyT8iW8JjEdMbKzDotAJf+ajgaQ==}
|
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@@ -851,28 +828,24 @@ packages:
|
|||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
lightningcss-linux-arm64-musl@1.29.2:
|
lightningcss-linux-arm64-musl@1.29.2:
|
||||||
resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==}
|
resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
lightningcss-linux-x64-gnu@1.29.2:
|
lightningcss-linux-x64-gnu@1.29.2:
|
||||||
resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==}
|
resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
lightningcss-linux-x64-musl@1.29.2:
|
lightningcss-linux-x64-musl@1.29.2:
|
||||||
resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==}
|
resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
lightningcss-win32-arm64-msvc@1.29.2:
|
lightningcss-win32-arm64-msvc@1.29.2:
|
||||||
resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==}
|
resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==}
|
||||||
@@ -893,12 +866,6 @@ packages:
|
|||||||
lodash-es@4.17.21:
|
lodash-es@4.17.21:
|
||||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||||
|
|
||||||
lodash.debounce@4.0.8:
|
|
||||||
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
|
|
||||||
|
|
||||||
lodash.throttle@4.1.1:
|
|
||||||
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
|
|
||||||
|
|
||||||
lodash@4.17.21:
|
lodash@4.17.21:
|
||||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||||
|
|
||||||
@@ -1229,6 +1196,8 @@ snapshots:
|
|||||||
'@esbuild/win32-x64@0.25.3':
|
'@esbuild/win32-x64@0.25.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@fortawesome/fontawesome-free@6.7.2': {}
|
||||||
|
|
||||||
'@jridgewell/sourcemap-codec@1.5.0': {}
|
'@jridgewell/sourcemap-codec@1.5.0': {}
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.1':
|
'@parcel/watcher-android-arm64@2.5.1':
|
||||||
@@ -1547,12 +1516,6 @@ snapshots:
|
|||||||
vue-types: 3.0.2(vue@3.5.13)
|
vue-types: 3.0.2(vue@3.5.13)
|
||||||
warning: 4.0.3
|
warning: 4.0.3
|
||||||
|
|
||||||
aos@2.3.4:
|
|
||||||
dependencies:
|
|
||||||
classlist-polyfill: 1.2.0
|
|
||||||
lodash.debounce: 4.0.8
|
|
||||||
lodash.throttle: 4.1.1
|
|
||||||
|
|
||||||
array-tree-filter@2.1.0: {}
|
array-tree-filter@2.1.0: {}
|
||||||
|
|
||||||
async-validator@4.2.5: {}
|
async-validator@4.2.5: {}
|
||||||
@@ -1581,8 +1544,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
readdirp: 4.1.2
|
readdirp: 4.1.2
|
||||||
|
|
||||||
classlist-polyfill@1.2.0: {}
|
|
||||||
|
|
||||||
combined-stream@1.0.8:
|
combined-stream@1.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
@@ -1787,10 +1748,6 @@ snapshots:
|
|||||||
|
|
||||||
lodash-es@4.17.21: {}
|
lodash-es@4.17.21: {}
|
||||||
|
|
||||||
lodash.debounce@4.0.8: {}
|
|
||||||
|
|
||||||
lodash.throttle@4.1.1: {}
|
|
||||||
|
|
||||||
lodash@4.17.21: {}
|
lodash@4.17.21: {}
|
||||||
|
|
||||||
loose-envify@1.4.0:
|
loose-envify@1.4.0:
|
||||||
|
|||||||
153
src/App.vue
153
src/App.vue
@@ -1,10 +1,153 @@
|
|||||||
<script setup>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<router-view />
|
<div id="app">
|
||||||
|
<!-- Snowflake effect as global background -->
|
||||||
|
<div class="snowflakes" aria-hidden="true">
|
||||||
|
<div class="snowflake" v-for="i in 50" :key="i">❅</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Router view for page content -->
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<script setup>
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// Create snowflake animation
|
||||||
|
const snowflakes = document.querySelectorAll('.snowflake')
|
||||||
|
|
||||||
|
snowflakes.forEach((snowflake, index) => {
|
||||||
|
const delay = Math.random() * 5
|
||||||
|
const duration = 3 + Math.random() * 2
|
||||||
|
const size = 0.5 + Math.random() * 0.8
|
||||||
|
const opacity = 0.3 + Math.random() * 0.7
|
||||||
|
const leftPosition = Math.random() * 100
|
||||||
|
|
||||||
|
snowflake.style.left = leftPosition + '%'
|
||||||
|
snowflake.style.animationDelay = delay + 's'
|
||||||
|
snowflake.style.animationDuration = duration + 's'
|
||||||
|
snowflake.style.fontSize = size + 'rem'
|
||||||
|
snowflake.style.opacity = opacity
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;600;700&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--primary-color: #e63946;
|
||||||
|
--secondary-color: #a8dadc;
|
||||||
|
--dark-color: #1d3557;
|
||||||
|
--light-color: #f1faee;
|
||||||
|
--accent-color: #457b9d;
|
||||||
|
--transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||||
|
--card-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
|
||||||
|
--card-hover-shadow: 0 20px 40px rgba(231, 57, 70, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Montserrat', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: var(--light-color);
|
||||||
|
position: relative;
|
||||||
|
background: #0b0000; /* Deep black background */
|
||||||
|
}
|
||||||
|
|
||||||
|
body::before {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 30% 20%, rgba(230, 57, 70, 0.25), transparent 40%),
|
||||||
|
radial-gradient(circle at 70% 80%, rgba(230, 57, 70, 0.1), transparent 40%),
|
||||||
|
radial-gradient(circle at 50% 50%, rgba(230, 57, 70, 0.15), transparent 50%),
|
||||||
|
linear-gradient(135deg, rgba(20, 0, 0, 0.9), rgba(11, 0, 0, 0.95));
|
||||||
|
backdrop-filter: blur(25px);
|
||||||
|
-webkit-backdrop-filter: blur(25px);
|
||||||
|
z-index: -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::after {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 10% 20%, rgba(255, 100, 100, 0.1), transparent 20%),
|
||||||
|
radial-gradient(circle at 90% 60%, rgba(255, 80, 80, 0.08), transparent 25%),
|
||||||
|
radial-gradient(circle at 50% 50%, rgba(255, 120, 120, 0.05), transparent 30%);
|
||||||
|
animation: glowEffect 15s infinite alternate;
|
||||||
|
z-index: -1;
|
||||||
|
mix-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes glowEffect {
|
||||||
|
0% {
|
||||||
|
opacity: 0.6;
|
||||||
|
background-position: 0% 0%;
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
opacity: 0.7;
|
||||||
|
background-position: 30% 30%;
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
opacity: 0.8;
|
||||||
|
background-position: 70% 70%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.9;
|
||||||
|
background-position: 100% 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
position: relative;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Snowflake animation styles */
|
||||||
|
.snowflakes {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snowflake {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
color: rgba(255, 200, 200, 0.8);
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
text-shadow: 0 0 10px rgba(230, 57, 70, 0.5);
|
||||||
|
animation: fall linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fall {
|
||||||
|
0% {
|
||||||
|
transform: translateY(-100vh) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(100vh) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ service.interceptors.response.use(
|
|||||||
|
|
||||||
// 封装 get 请求
|
// 封装 get 请求
|
||||||
const get = (url, params = {}) => {
|
const get = (url, params = {}) => {
|
||||||
return service.get(url, { params });
|
return service.get(url, { params: params });
|
||||||
};
|
};
|
||||||
|
|
||||||
// 封装 post 请求
|
// 封装 post 请求
|
||||||
|
|||||||
17
src/api/request/api.js
Normal file
17
src/api/request/api.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import {get, post} from '../request.js'
|
||||||
|
|
||||||
|
const prefix = ''
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取相册列表
|
||||||
|
*/
|
||||||
|
export function albumListApi() {
|
||||||
|
return get(`${prefix}/list`)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取相册详情
|
||||||
|
*/
|
||||||
|
export function albumDetailApi(data) {
|
||||||
|
// return get(`${prefix}/detail?id=${data.id}`, data)
|
||||||
|
return get(`${prefix}/detail`, data)
|
||||||
|
}
|
||||||
@@ -2,29 +2,29 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header class="bg-gradient-to-r from-blue-500 to-indigo-600 text-white py-4 px-6 flex items-center justify-between">
|
<!-- <header class="bg-gradient-to-r from-blue-500 to-indigo-600 text-white py-4 px-6 flex items-center justify-between">-->
|
||||||
<div class="flex items-center space-x-4">
|
<!-- <div class="flex items-center space-x-4">-->
|
||||||
<!-- Logo -->
|
<!-- <!– Logo –>-->
|
||||||
<img src="https://via.placeholder.com/40" alt="Logo" class="h-8 w-8 rounded-full">
|
<!-- <img src="https://via.placeholder.com/40" alt="Logo" class="h-8 w-8 rounded-full">-->
|
||||||
<span class="font-bold">My App</span>
|
<!-- <span class="font-bold">My App</span>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
|
|
||||||
<!-- Menu -->
|
<!-- <!– Menu –>-->
|
||||||
<nav class="hidden md:flex space-x-4">
|
<!-- <nav class="hidden md:flex space-x-4">-->
|
||||||
<a href="#" class="hover:text-gray-300">首页</a>
|
<!-- <a href="#" class="hover:text-gray-300">首页</a>-->
|
||||||
<a href="#" class="hover:text-gray-300">About</a>
|
<!-- <a href="#" class="hover:text-gray-300">About</a>-->
|
||||||
<a href="#" class="hover:text-gray-300">Services</a>
|
<!-- <a href="#" class="hover:text-gray-300">Services</a>-->
|
||||||
<a href="#" class="hover:text-gray-300">Contact</a>
|
<!-- <a href="#" class="hover:text-gray-300">Contact</a>-->
|
||||||
</nav>
|
<!-- </nav>-->
|
||||||
|
|
||||||
<!-- User Profile -->
|
<!-- <!– User Profile –>-->
|
||||||
<div class="flex items-center space-x-4">
|
<!-- <div class="flex items-center space-x-4">-->
|
||||||
<button class="text-sm bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
|
<!-- <button class="text-sm bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">-->
|
||||||
Personal Center
|
<!-- Personal Center-->
|
||||||
</button>
|
<!-- </button>-->
|
||||||
<img src="https://via.placeholder.com/40" alt="User Avatar" class="h-8 w-8 rounded-full cursor-pointer">
|
<!-- <img src="https://via.placeholder.com/40" alt="User Avatar" class="h-8 w-8 rounded-full cursor-pointer">-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</header>
|
<!-- </header>-->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ import MainLayout from '@/layouts/Header.vue'
|
|||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: MainLayout,
|
// component: MainLayout,
|
||||||
children: [
|
children: [
|
||||||
{ path: '', name: 'Home', component: () => import('@/views/index/index.vue') },
|
{ path: '', name: 'Home', component: () => import('@/views/index/index.vue') },
|
||||||
|
{ path: '/detail/:id', name: 'Detail', component: () => import('@/views/index/detail.vue') },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
607
src/views/index/detail.vue
Normal file
607
src/views/index/detail.vue
Normal file
@@ -0,0 +1,607 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<!-- Updated main title styling to match original -->
|
||||||
|
<h1 class="main-title">我们的相册</h1>
|
||||||
|
|
||||||
|
<!-- Loading state -->
|
||||||
|
<div v-if="loading" class="loading-container">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<p>加载照片中...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 相册详情模块 -->
|
||||||
|
<div v-else class="album-detail" id="albumDetail">
|
||||||
|
<button class="back-button" @click="goBack">
|
||||||
|
<i class="fas fa-arrow-left"></i> 返回相册列表
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="detail-header">
|
||||||
|
<h2 class="detail-title">{{ albumData.title }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="photo-grid" id="photoGrid">
|
||||||
|
<div
|
||||||
|
v-for="(photo, index) in albumData.photos"
|
||||||
|
:key="index"
|
||||||
|
class="photo-item"
|
||||||
|
@click="showPhotoPreview(photo.compressed, index)"
|
||||||
|
>
|
||||||
|
<!-- Added loading spinner for individual photos -->
|
||||||
|
<div v-if="!photo.loaded" class="photo-loading-spinner"></div>
|
||||||
|
<img
|
||||||
|
:src="`http://i.nailaoyun.cn${photo.compressed}`"
|
||||||
|
:alt="`照片 ${index + 1}`"
|
||||||
|
class="photo-img"
|
||||||
|
:class="{ loaded: photo.loaded }"
|
||||||
|
@load="onPhotoLoad(photo)"
|
||||||
|
@error="onPhotoError(photo)"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 图片预览模态框 -->
|
||||||
|
<div
|
||||||
|
v-if="previewModal.active"
|
||||||
|
class="preview-modal active"
|
||||||
|
:style="{ opacity: previewModal.opacity }"
|
||||||
|
>
|
||||||
|
<button class="close-modal" @click="closePhotoPreview">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="nav-btn prev-btn"
|
||||||
|
@click="showPrevPhoto"
|
||||||
|
:disabled="currentPhotoIndex <= 0"
|
||||||
|
>
|
||||||
|
<i class="fas fa-chevron-left"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="modal-content">
|
||||||
|
<img
|
||||||
|
class="modal-img"
|
||||||
|
:class="{ active: previewModal.imgActive }"
|
||||||
|
:src="`http://i.nailaoyun.cn${previewModal.currentImg}`"
|
||||||
|
alt="预览图片"
|
||||||
|
:style="{ transform: `rotate(${currentRotation}deg)` }"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="modal-tools">
|
||||||
|
<button class="tool-btn" @click="rotatePhoto('left')" title="向左旋转">
|
||||||
|
<i class="fas fa-undo"></i>
|
||||||
|
</button>
|
||||||
|
<button class="tool-btn" @click="rotatePhoto('right')" title="向右旋转">
|
||||||
|
<i class="fas fa-redo"></i>
|
||||||
|
</button>
|
||||||
|
<button class="tool-btn" @click="downloadPhoto" title="下载图片">
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="nav-btn next-btn"
|
||||||
|
@click="showNextPhoto"
|
||||||
|
:disabled="currentPhotoIndex >= albumData.photos.length - 1"
|
||||||
|
>
|
||||||
|
<i class="fas fa-chevron-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { albumDetailApi } from "@/api/request/api.js"
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const albumData = reactive({
|
||||||
|
title: '',
|
||||||
|
photos: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const previewModal = reactive({
|
||||||
|
active: false,
|
||||||
|
opacity: '0',
|
||||||
|
imgActive: false,
|
||||||
|
currentImg: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentPhotoIndex = ref(0)
|
||||||
|
const currentRotation = ref(0)
|
||||||
|
|
||||||
|
const fetchAlbumDetail = async (albumId) => {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const res = await albumDetailApi({ id: albumId })
|
||||||
|
console.log(res)
|
||||||
|
|
||||||
|
albumData.photos = res.photos.map(photo => ({
|
||||||
|
...photo,
|
||||||
|
loaded: false
|
||||||
|
}))
|
||||||
|
albumData.title = res.title
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取相册详情失败:', error)
|
||||||
|
// Fallback to empty state on error
|
||||||
|
albumData.photos = []
|
||||||
|
albumData.title = '相册加载失败'
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPhotoLoad = (photo) => {
|
||||||
|
photo.loaded = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPhotoError = (photo) => {
|
||||||
|
photo.loaded = true
|
||||||
|
// Could add error state handling here
|
||||||
|
console.warn('Photo failed to load:', photo.compressed)
|
||||||
|
}
|
||||||
|
|
||||||
|
const goBack = () => {
|
||||||
|
router.push('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPhotoPreview = (photo, index) => {
|
||||||
|
previewModal.currentImg = photo
|
||||||
|
currentPhotoIndex.value = index
|
||||||
|
currentRotation.value = 0
|
||||||
|
previewModal.active = true
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.opacity = '1'
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.imgActive = true
|
||||||
|
}, 50)
|
||||||
|
}, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
const closePhotoPreview = () => {
|
||||||
|
previewModal.imgActive = false
|
||||||
|
previewModal.opacity = '0'
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.active = false
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPrevPhoto = () => {
|
||||||
|
if (currentPhotoIndex.value > 0) {
|
||||||
|
currentPhotoIndex.value--
|
||||||
|
previewModal.imgActive = false
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.currentImg = albumData.photos[currentPhotoIndex.value].compressed
|
||||||
|
currentRotation.value = 0
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.imgActive = true
|
||||||
|
}, 50)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const showNextPhoto = () => {
|
||||||
|
if (currentPhotoIndex.value < albumData.photos.length - 1) {
|
||||||
|
currentPhotoIndex.value++
|
||||||
|
previewModal.imgActive = false
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.currentImg = albumData.photos[currentPhotoIndex.value].compressed
|
||||||
|
currentRotation.value = 0
|
||||||
|
setTimeout(() => {
|
||||||
|
previewModal.imgActive = true
|
||||||
|
}, 50)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotatePhoto = (direction) => {
|
||||||
|
if (direction === 'left') {
|
||||||
|
currentRotation.value -= 90
|
||||||
|
} else {
|
||||||
|
currentRotation.value += 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadPhoto = () => {
|
||||||
|
if (!albumData.photos.length) return
|
||||||
|
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = `http://i.nailaoyun.cn${albumData.photos[currentPhotoIndex.value].original || albumData.photos[currentPhotoIndex.value].compressed}`
|
||||||
|
link.download = `photo_${albumData.title}_${Date.now()}.jpg`
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 键盘导航
|
||||||
|
const handleKeydown = (e) => {
|
||||||
|
if (previewModal.active) {
|
||||||
|
if (e.key === 'ArrowLeft') {
|
||||||
|
showPrevPhoto()
|
||||||
|
} else if (e.key === 'ArrowRight') {
|
||||||
|
showNextPhoto()
|
||||||
|
} else if (e.key === 'Escape') {
|
||||||
|
closePhotoPreview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const albumId = route.params.id
|
||||||
|
fetchAlbumDetail(albumId)
|
||||||
|
document.addEventListener('keydown', handleKeydown)
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('keydown', handleKeydown)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* Updated all styling to match original dark red theme with frosted glass effects */
|
||||||
|
.container {
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 3rem;
|
||||||
|
position: relative;
|
||||||
|
font-family: 'Montserrat', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
color: var(--light-color);
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
text-shadow: 0 0 10px rgba(230, 57, 70, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 100px;
|
||||||
|
height: 3px;
|
||||||
|
background: var(--primary-color);
|
||||||
|
box-shadow: 0 0 10px rgba(230, 57, 70, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 300px;
|
||||||
|
color: var(--light-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 3px solid rgba(168, 218, 220, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: var(--secondary-color);
|
||||||
|
animation: spin 1s ease-in-out infinite;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-detail {
|
||||||
|
animation: fadeIn 0.5s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button {
|
||||||
|
background: rgba(230, 57, 70, 0.3);
|
||||||
|
border: none;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--light-color);
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
transition: var(--transition);
|
||||||
|
padding: 0.8rem 1.5rem;
|
||||||
|
border-radius: 30px;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-button:hover {
|
||||||
|
background: rgba(230, 57, 70, 0.5);
|
||||||
|
transform: translateX(-5px);
|
||||||
|
box-shadow: 0 0 10px rgba(230, 57, 70, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-title {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 300;
|
||||||
|
color: var(--light-color);
|
||||||
|
margin: 0;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-shadow: 0 0 10px rgba(230, 57, 70, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-item {
|
||||||
|
position: relative;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: var(--card-shadow);
|
||||||
|
transition: var(--transition);
|
||||||
|
aspect-ratio: 4/3;
|
||||||
|
background: rgba(29, 0, 0, 0.5);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
transform: scale(1);
|
||||||
|
border: 1px solid rgba(230, 57, 70, 0.1);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-item:hover {
|
||||||
|
transform: scale(1.03);
|
||||||
|
box-shadow: var(--card-hover-shadow);
|
||||||
|
z-index: 2;
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: var(--transition);
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-img.loaded {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Added optimized loading spinner for individual photos */
|
||||||
|
.photo-loading-spinner {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border: 3px solid rgba(168, 218, 220, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: var(--secondary-color);
|
||||||
|
animation: spin 1s ease-in-out infinite;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.95);
|
||||||
|
z-index: 1000;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
backdrop-filter: blur(15px);
|
||||||
|
-webkit-backdrop-filter: blur(15px);
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-modal.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
position: relative;
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 80vh;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 8px;
|
||||||
|
transform: scale(0.5);
|
||||||
|
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
|
||||||
|
opacity: 0;
|
||||||
|
box-shadow: 0 20px 40px rgba(230, 57, 70, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-img.active {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-tools {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn {
|
||||||
|
background: rgba(230, 57, 70, 0.3);
|
||||||
|
border: none;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--transition);
|
||||||
|
color: white;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn:hover {
|
||||||
|
background: rgba(230, 57, 70, 0.5);
|
||||||
|
transform: scale(1.1);
|
||||||
|
box-shadow: 0 0 10px rgba(230, 57, 70, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background: rgba(230, 57, 70, 0.3);
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--transition);
|
||||||
|
z-index: 10;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn:hover:not(:disabled) {
|
||||||
|
background: rgba(230, 57, 70, 0.5);
|
||||||
|
transform: translateY(-50%) scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn:disabled {
|
||||||
|
opacity: 0.3;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prev-btn {
|
||||||
|
left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.next-btn {
|
||||||
|
right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-modal {
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
right: 40px;
|
||||||
|
background: rgba(230, 57, 70, 0.3);
|
||||||
|
border: none;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: var(--transition);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-modal:hover {
|
||||||
|
background: rgba(230, 57, 70, 0.5);
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.container {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn, .close-modal {
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.container {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-title {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,11 +1,305 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
你好
|
<div class="album-index">
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="main-title">我们的相册</h1>
|
||||||
|
|
||||||
|
<div v-if="loading" class="loading-container">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
<p>加载中...</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="album-selection">
|
||||||
|
<div
|
||||||
|
v-for="album in albums"
|
||||||
|
:key="album.id"
|
||||||
|
class="album-card"
|
||||||
|
@click="goToAlbum(album.id)"
|
||||||
|
>
|
||||||
|
<div class="album-cover">
|
||||||
|
<!-- Added optimized image loading with lazy loading and error handling -->
|
||||||
|
<img
|
||||||
|
:src="`http://i.nailaoyun.cn${album.url}`"
|
||||||
|
:alt="album.title"
|
||||||
|
loading="lazy"
|
||||||
|
@load="onImageLoad"
|
||||||
|
@error="onImageError"
|
||||||
|
class="cover-image"
|
||||||
|
/>
|
||||||
|
<div class="album-overlay">
|
||||||
|
<div class="album-info">
|
||||||
|
<h3 class="album-title">{{ album.title }}</h3>
|
||||||
|
<p class="album-date">{{ formatDate(album.created_at) }}</p>
|
||||||
|
<!-- Added photo count display -->
|
||||||
|
<p class="album-count">{{ album.photo_count }} 张照片</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { albumListApi } from "@/api/request/api.js"
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const albums = ref([])
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await albumListApi()
|
||||||
|
albums.value = res
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取相册列表失败:', error)
|
||||||
|
// Fallback to empty array on error
|
||||||
|
albums.value = []
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onImageLoad = (event) => {
|
||||||
|
event.target.classList.add('loaded')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onImageError = (event) => {
|
||||||
|
// Fallback to placeholder on error
|
||||||
|
event.target.src = '/placeholder.svg?height=300&width=400&text=加载失败'
|
||||||
|
event.target.classList.add('error')
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
const date = new Date(dateString)
|
||||||
|
return date.toLocaleDateString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const goToAlbum = (albumId) => {
|
||||||
|
router.push(`/detail/${albumId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.album-index {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
min-height: 100vh;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 3rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
color: var(--light-color);
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: 3px;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
text-shadow: 0 0 10px rgba(230, 57, 70, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 100px;
|
||||||
|
height: 3px;
|
||||||
|
background: var(--primary-color);
|
||||||
|
box-shadow: 0 0 10px rgba(230, 57, 70, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 300px;
|
||||||
|
color: var(--light-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 3px solid rgba(168, 218, 220, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: var(--secondary-color);
|
||||||
|
animation: spin 1s ease-in-out infinite;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-selection {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||||
|
gap: 3rem;
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-card {
|
||||||
|
background: rgba(29, 0, 0, 0.7);
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: var(--card-shadow);
|
||||||
|
transition: var(--transition);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
border: 1px solid rgba(230, 57, 70, 0.2);
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-card:hover {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
box-shadow: var(--card-hover-shadow);
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-cover {
|
||||||
|
height: 240px;
|
||||||
|
position: relative;
|
||||||
|
transition: var(--transition);
|
||||||
|
background-color: rgba(20, 0, 0, 0.6);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Added optimized image styles */
|
||||||
|
.cover-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-image.loaded {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-image.error {
|
||||||
|
opacity: 0.5;
|
||||||
|
filter: grayscale(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-card:hover .cover-image {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 2rem;
|
||||||
|
opacity: 1;
|
||||||
|
transition: var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-info {
|
||||||
|
padding: 2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: var(--light-color);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-date {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--secondary-color);
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Added photo count styling */
|
||||||
|
.album-count {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--secondary-color);
|
||||||
|
opacity: 0.8;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.container {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-selection {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-selection {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-cover {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.container {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album-selection {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ export default defineConfig({
|
|||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
// target: 'http://127.0.0.1:18007/api/',
|
// target: 'http://127.0.0.1:18007/api/',
|
||||||
target: 'http://127.0.0.1:18001/api/',
|
// target: 'http://127.0.0.1:18001/api/',
|
||||||
|
target: 'http://i.nailaoyun.cn/api/',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/api/, '')
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user