wangfumin преди 1 седмица
родител
ревизия
935de82798

+ 2 - 2
mobile/.env.development

@@ -9,8 +9,8 @@ VITE_AXIOS_BASE_URL = '/api'  # 用于代理
 # VITE_AXIOS_BASE_URL = 'https://mock.apipark.cn/m1/3776410-0-default'  # apifox云端mock
 # VITE_AXIOS_BASE_URL = 'http://192.168.0.73:8085'
 # 代理配置-target
-# VITE_PROXY_TARGET = 'http://192.168.0.73:8180'
-VITE_PROXY_TARGET = 'https://sit-huyaobangjng.4dage.com'
+VITE_PROXY_TARGET = 'http://192.168.0.73:8180'
+# VITE_PROXY_TARGET = 'https://sit-huyaobangjng.4dage.com'
 
 # 图片基础
 VITE_COS_BASE_URL = 'https://hybgc.4dage.com/ArtCMS/'

+ 3 - 2
mobile/package.json

@@ -18,11 +18,12 @@
     "axios": "^1.9.0",
     "element-plus": "^2.9.11",
     "lodash": "^4.17.21",
+    "qs": "^6.14.0",
     "sass-embedded": "^1.89.2",
+    "v-distpicker": "^2.1.0",
     "vue": "^3.5.18",
     "vue-router": "^4.5.1",
-    "vuex": "^4.1.0",
-    "v-distpicker": "^2.1.0"
+    "vuex": "^4.1.0"
   },
   "devDependencies": {
     "@eslint/js": "^9.31.0",

+ 208 - 0
mobile/pnpm-lock.yaml

@@ -17,9 +17,15 @@ importers:
       lodash:
         specifier: ^4.17.21
         version: 4.17.21
+      qs:
+        specifier: ^6.14.0
+        version: 6.14.0
       sass-embedded:
         specifier: ^1.89.2
         version: 1.89.2
+      v-distpicker:
+        specifier: ^2.1.0
+        version: 2.1.0
       vue:
         specifier: ^3.5.18
         version: 3.5.18(typescript@5.8.3)
@@ -771,15 +777,27 @@ packages:
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
+  '@vue/compiler-core@3.2.47':
+    resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==}
+
   '@vue/compiler-core@3.5.18':
     resolution: {integrity: sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==}
 
+  '@vue/compiler-dom@3.2.47':
+    resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==}
+
   '@vue/compiler-dom@3.5.18':
     resolution: {integrity: sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==}
 
+  '@vue/compiler-sfc@3.2.47':
+    resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==}
+
   '@vue/compiler-sfc@3.5.18':
     resolution: {integrity: sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==}
 
+  '@vue/compiler-ssr@3.2.47':
+    resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==}
+
   '@vue/compiler-ssr@3.5.18':
     resolution: {integrity: sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==}
 
@@ -803,20 +821,40 @@ packages:
       eslint: '>= 8.21.0'
       prettier: '>= 3.0.0'
 
+  '@vue/reactivity-transform@3.2.47':
+    resolution: {integrity: sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==}
+
+  '@vue/reactivity@3.2.47':
+    resolution: {integrity: sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==}
+
   '@vue/reactivity@3.5.18':
     resolution: {integrity: sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==}
 
+  '@vue/runtime-core@3.2.47':
+    resolution: {integrity: sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==}
+
   '@vue/runtime-core@3.5.18':
     resolution: {integrity: sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==}
 
+  '@vue/runtime-dom@3.2.47':
+    resolution: {integrity: sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==}
+
   '@vue/runtime-dom@3.5.18':
     resolution: {integrity: sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==}
 
+  '@vue/server-renderer@3.2.47':
+    resolution: {integrity: sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==}
+    peerDependencies:
+      vue: 3.2.47
+
   '@vue/server-renderer@3.5.18':
     resolution: {integrity: sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==}
     peerDependencies:
       vue: 3.5.18
 
+  '@vue/shared@3.2.47':
+    resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==}
+
   '@vue/shared@3.5.18':
     resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==}
 
@@ -928,6 +966,10 @@ packages:
     resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
     engines: {node: '>= 0.4'}
 
+  call-bound@1.0.4:
+    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+    engines: {node: '>= 0.4'}
+
   callsites@3.1.0:
     resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
     engines: {node: '>=6'}
@@ -991,6 +1033,9 @@ packages:
     resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
     engines: {node: '>=18'}
 
+  csstype@2.6.21:
+    resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
+
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
@@ -1508,6 +1553,9 @@ packages:
   lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
 
+  magic-string@0.25.9:
+    resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+
   magic-string@0.30.17:
     resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
 
@@ -1593,6 +1641,10 @@ packages:
   nwsapi@2.2.21:
     resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==}
 
+  object-inspect@1.13.4:
+    resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+    engines: {node: '>= 0.4'}
+
   ohash@2.0.11:
     resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
 
@@ -1698,6 +1750,10 @@ packages:
     resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
     engines: {node: '>=6'}
 
+  qs@6.14.0:
+    resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+    engines: {node: '>=0.6'}
+
   queue-microtask@1.2.3:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
 
@@ -1855,6 +1911,22 @@ packages:
     resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
     engines: {node: '>=8'}
 
+  side-channel-list@1.0.0:
+    resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-map@1.0.1:
+    resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-weakmap@1.0.2:
+    resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+    engines: {node: '>= 0.4'}
+
+  side-channel@1.1.0:
+    resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+    engines: {node: '>= 0.4'}
+
   siginfo@2.0.0:
     resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
 
@@ -1870,6 +1942,14 @@ packages:
     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
     engines: {node: '>=0.10.0'}
 
+  source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  sourcemap-codec@1.4.8:
+    resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+    deprecated: Please use @jridgewell/sourcemap-codec instead
+
   speakingurl@14.0.1:
     resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
     engines: {node: '>=0.10.0'}
@@ -2017,6 +2097,9 @@ packages:
   util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 
+  v-distpicker@2.1.0:
+    resolution: {integrity: sha512-xFUEZHtMXzYJKGiHlBFuzzqF1rEqQKsV8cPXYTzy3FeGJBO37HYnRz76vgw16buoGeqMnusxLRL8BqtaJlpzcg==}
+
   varint@6.0.0:
     resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
 
@@ -2149,6 +2232,9 @@ packages:
     peerDependencies:
       vue: ^3.2.0
 
+  vue@3.2.47:
+    resolution: {integrity: sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==}
+
   vue@3.5.18:
     resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==}
     peerDependencies:
@@ -2891,6 +2977,13 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@vue/compiler-core@3.2.47':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      source-map: 0.6.1
+
   '@vue/compiler-core@3.5.18':
     dependencies:
       '@babel/parser': 7.28.0
@@ -2899,11 +2992,29 @@ snapshots:
       estree-walker: 2.0.2
       source-map-js: 1.2.1
 
+  '@vue/compiler-dom@3.2.47':
+    dependencies:
+      '@vue/compiler-core': 3.2.47
+      '@vue/shared': 3.2.47
+
   '@vue/compiler-dom@3.5.18':
     dependencies:
       '@vue/compiler-core': 3.5.18
       '@vue/shared': 3.5.18
 
+  '@vue/compiler-sfc@3.2.47':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/compiler-core': 3.2.47
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-ssr': 3.2.47
+      '@vue/reactivity-transform': 3.2.47
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+      postcss: 8.5.6
+      source-map: 0.6.1
+
   '@vue/compiler-sfc@3.5.18':
     dependencies:
       '@babel/parser': 7.28.0
@@ -2916,6 +3027,11 @@ snapshots:
       postcss: 8.5.6
       source-map-js: 1.2.1
 
+  '@vue/compiler-ssr@3.2.47':
+    dependencies:
+      '@vue/compiler-dom': 3.2.47
+      '@vue/shared': 3.2.47
+
   '@vue/compiler-ssr@3.5.18':
     dependencies:
       '@vue/compiler-dom': 3.5.18
@@ -2958,15 +3074,38 @@ snapshots:
     transitivePeerDependencies:
       - '@types/eslint'
 
+  '@vue/reactivity-transform@3.2.47':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/compiler-core': 3.2.47
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+
+  '@vue/reactivity@3.2.47':
+    dependencies:
+      '@vue/shared': 3.2.47
+
   '@vue/reactivity@3.5.18':
     dependencies:
       '@vue/shared': 3.5.18
 
+  '@vue/runtime-core@3.2.47':
+    dependencies:
+      '@vue/reactivity': 3.2.47
+      '@vue/shared': 3.2.47
+
   '@vue/runtime-core@3.5.18':
     dependencies:
       '@vue/reactivity': 3.5.18
       '@vue/shared': 3.5.18
 
+  '@vue/runtime-dom@3.2.47':
+    dependencies:
+      '@vue/runtime-core': 3.2.47
+      '@vue/shared': 3.2.47
+      csstype: 2.6.21
+
   '@vue/runtime-dom@3.5.18':
     dependencies:
       '@vue/reactivity': 3.5.18
@@ -2974,12 +3113,20 @@ snapshots:
       '@vue/shared': 3.5.18
       csstype: 3.1.3
 
+  '@vue/server-renderer@3.2.47(vue@3.2.47)':
+    dependencies:
+      '@vue/compiler-ssr': 3.2.47
+      '@vue/shared': 3.2.47
+      vue: 3.2.47
+
   '@vue/server-renderer@3.5.18(vue@3.5.18(typescript@5.8.3))':
     dependencies:
       '@vue/compiler-ssr': 3.5.18
       '@vue/shared': 3.5.18
       vue: 3.5.18(typescript@5.8.3)
 
+  '@vue/shared@3.2.47': {}
+
   '@vue/shared@3.5.18': {}
 
   '@vue/test-utils@2.4.6':
@@ -3090,6 +3237,11 @@ snapshots:
       es-errors: 1.3.0
       function-bind: 1.1.2
 
+  call-bound@1.0.4:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      get-intrinsic: 1.3.0
+
   callsites@3.1.0: {}
 
   caniuse-lite@1.0.30001731: {}
@@ -3149,6 +3301,8 @@ snapshots:
       '@asamuzakjp/css-color': 3.2.0
       rrweb-cssom: 0.8.0
 
+  csstype@2.6.21: {}
+
   csstype@3.1.3: {}
 
   data-urls@5.0.0:
@@ -3688,6 +3842,10 @@ snapshots:
     dependencies:
       yallist: 3.1.1
 
+  magic-string@0.25.9:
+    dependencies:
+      sourcemap-codec: 1.4.8
+
   magic-string@0.30.17:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.5.4
@@ -3754,6 +3912,8 @@ snapshots:
 
   nwsapi@2.2.21: {}
 
+  object-inspect@1.13.4: {}
+
   ohash@2.0.11: {}
 
   open@10.2.0:
@@ -3844,6 +4004,10 @@ snapshots:
 
   punycode@2.3.1: {}
 
+  qs@6.14.0:
+    dependencies:
+      side-channel: 1.1.0
+
   queue-microtask@1.2.3: {}
 
   resolve-from@4.0.0: {}
@@ -3982,6 +4146,34 @@ snapshots:
 
   shebang-regex@3.0.0: {}
 
+  side-channel-list@1.0.0:
+    dependencies:
+      es-errors: 1.3.0
+      object-inspect: 1.13.4
+
+  side-channel-map@1.0.1:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      object-inspect: 1.13.4
+
+  side-channel-weakmap@1.0.2:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      object-inspect: 1.13.4
+      side-channel-map: 1.0.1
+
+  side-channel@1.1.0:
+    dependencies:
+      es-errors: 1.3.0
+      object-inspect: 1.13.4
+      side-channel-list: 1.0.0
+      side-channel-map: 1.0.1
+      side-channel-weakmap: 1.0.2
+
   siginfo@2.0.0: {}
 
   signal-exit@4.1.0: {}
@@ -3994,6 +4186,10 @@ snapshots:
 
   source-map-js@1.2.1: {}
 
+  source-map@0.6.1: {}
+
+  sourcemap-codec@1.4.8: {}
+
   speakingurl@14.0.1: {}
 
   stackback@0.0.2: {}
@@ -4118,6 +4314,10 @@ snapshots:
 
   util-deprecate@1.0.2: {}
 
+  v-distpicker@2.1.0:
+    dependencies:
+      vue: 3.2.47
+
   varint@6.0.0: {}
 
   vite-dev-rpc@1.1.0(vite@7.0.6(sass-embedded@1.89.2)):
@@ -4272,6 +4472,14 @@ snapshots:
       '@vue/devtools-api': 6.6.4
       vue: 3.5.18(typescript@5.8.3)
 
+  vue@3.2.47:
+    dependencies:
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-sfc': 3.2.47
+      '@vue/runtime-dom': 3.2.47
+      '@vue/server-renderer': 3.2.47(vue@3.2.47)
+      '@vue/shared': 3.2.47
+
   vue@3.5.18(typescript@5.8.3):
     dependencies:
       '@vue/compiler-dom': 3.5.18

+ 9 - 4
mobile/src/api/index.js

@@ -1,4 +1,5 @@
 import request from '@/utils/request';
+import qs from 'qs';
 
 const hhbangBookApi = {
   // 首页获取推荐列表
@@ -26,14 +27,18 @@ const hhbangBookApi = {
         searchText: params.keyword || '', // 关键词
         texture: params.material || '', // 材质
         ...params
+      },
+      //序列化
+      paramsSerializer: {
+        serialize: params => qs.stringify(params, {indices: false}),
       }
     })
   },
 
-  // 获取分类列表
-  getCategoryListApi() {
+  // 获取字典数据列表
+  getDictionaryListApi() {
     return request({
-      url: '/hyb/artArtworks/listCategory',
+      url: '/hyb/artArtworks/dictionary',
       method: 'get'
     })
   },
@@ -116,4 +121,4 @@ const hhbangBookApi = {
   }
 }
 
-export default hhbangBookApi;
+export default hhbangBookApi

BIN
mobile/src/assets/img/icon_voiceoff.png


BIN
mobile/src/assets/img/icon_voiceon.png


BIN
mobile/src/assets/img/title.png


+ 20 - 0
mobile/src/store/index.js

@@ -9,6 +9,9 @@ const store = createStore({
     categoryList: [], // 分类列表
     currentSearchParams: null, // 当前搜索参数
     homeSearchText: '', // 首页搜索关键词
+    // 排序相关参数
+    currentOrderBy: '', // 当前排序方式
+    currentOrderbyList: [], // 当前排序列表
   },
   mutations: {
     SET_IS_FROM(state, value) {
@@ -30,6 +33,13 @@ const store = createStore({
     SET_HOME_SEARCH_TEXT(state, text) {
       state.homeSearchText = text
     },
+    // 排序相关mutations
+    SET_ORDER_BY(state, orderBy) {
+      state.currentOrderBy = orderBy
+    },
+    SET_ORDERBY_LIST(state, orderbyList) {
+      state.currentOrderbyList = orderbyList
+    },
   },
   actions: {
     setIsFrom({ commit }, value) {
@@ -51,6 +61,13 @@ const store = createStore({
     setHomeSearchText({ commit }, text) {
       commit('SET_HOME_SEARCH_TEXT', text)
     },
+    // 排序相关actions
+    setOrderBy({ commit }, orderBy) {
+      commit('SET_ORDER_BY', orderBy)
+    },
+    setOrderbyList({ commit }, orderbyList) {
+      commit('SET_ORDERBY_LIST', orderbyList)
+    },
   },
   getters: {
     getIsFrom: (state) => state.isFrom,
@@ -68,6 +85,9 @@ const store = createStore({
       return state.allArtifacts.findIndex(artifact => artifact.id === id)
     },
     getHomeSearchText: (state) => state.homeSearchText,
+    // 排序相关getters
+    getCurrentOrderBy: (state) => state.currentOrderBy,
+    getCurrentOrderbyList: (state) => state.currentOrderbyList,
   },
 })
 

+ 1 - 1
mobile/src/views/Home/components/SearchPane.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="search-pane">
     <div class="search-pane-main">
-      <img class="logo" src="@/assets/images/title_01.png" />
+      <img class="logo" src="@/assets/img/title.png" />
 
       <!-- <search-input
         v-model="modelValue"

+ 86 - 11
mobile/src/views/collectpage/components/SearchPageComponent.vue

@@ -10,6 +10,18 @@
 
     <!-- 搜索表单 -->
     <div class="search-form">
+      <!-- 排序选择 -->
+      <div class="form-group">
+        <el-select v-model="searchForm.orderBy" class="cut-corner-select" placeholder="排序" clearable>
+          <el-option
+            v-for="item in orderByOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </div>
+
       <!-- 级别选择 -->
       <div class="form-group">
         <!-- <label>级别</label> -->
@@ -39,7 +51,7 @@
       <!-- 材质选择 -->
       <div class="form-group">
         <!-- <label>材质</label> -->
-        <el-select v-model="searchForm.material" class="cut-corner-select" placeholder="质" clearable>
+        <el-select v-model="searchForm.material" class="cut-corner-select" placeholder="质" clearable>
           <el-option
             v-for="item in materialOptions"
             :key="item.value"
@@ -77,16 +89,32 @@
 </template>
 
 <script setup>
-import { ref, reactive, watch } from 'vue'
+import { reactive, watch, computed } from 'vue'
 
 const props = defineProps({
   initialSearch: {
     type: Object,
-    default: () => ({searchText: '', dim: 3, level: '', category: '', material: '', era: ''})
+    default: () => ({searchText: '', dim: 3, orderBy: 'grade', level: '', category: '', material: '', era: ''})
   },
   categoryOptions: {
-    type: Object,
-    default: () => {return {}}
+    type: Array,
+    default: () => []
+  },
+  levelOptions: {
+    type: Array,
+    default: () => []
+  },
+  materialOptions: {
+    type: Array,
+    default: () => []
+  },
+  eraOptions: {
+    type: Array,
+    default: () => []
+  },
+  orderByOptions: {
+    type: Array,
+    default: () => []
   }
 })
 
@@ -95,14 +123,15 @@ const emit = defineEmits(['search', 'close'])
 // 搜索表单数据
 const searchForm = reactive({
   searchText: '',
+  orderBy: 'grade', // 默认按等级排序
   level: '',
   category: '',
   material: '',
   era: ''
 })
 
-// 选项数据 - 从Home页面的SearchPane中获取
-const levelOptions = ref([
+// 选项数据从 props 获取,如果没有则使用默认值
+const levelOptions = computed(() => props.levelOptions.length > 0 ? props.levelOptions : [
   { label: '一级', value: '一级' },
   { label: '二级', value: '二级' },
   { label: '三级', value: '三级' },
@@ -110,7 +139,7 @@ const levelOptions = ref([
   { label: '未定级', value: '未定级' }
 ])
 
-const materialOptions = ref([
+const materialOptions = computed(() => props.materialOptions.length > 0 ? props.materialOptions : [
   { label: '石', value: '石' },
   { label: '铜', value: '铜' },
   { label: '铜宝玉石', value: '铜宝玉石' },
@@ -121,19 +150,64 @@ const materialOptions = ref([
   { label: '其他', value: '其他' }
 ])
 
-const eraOptions = ref([
+const eraOptions = computed(() => props.eraOptions.length > 0 ? props.eraOptions : [
   { label: '近现代', value: '近现代' }
 ])
 
+const orderByOptions = computed(() => props.orderByOptions.length > 0 ? props.orderByOptions : [
+  { label: '等级', value: 'grade' },
+  { label: '类别', value: 'category' },
+  { label: '材质', value: 'material' },
+  { label: '年代', value: 'era' }
+])
+
+// 构建orderbyList的通用方法
+const buildOrderbyList = (orderByValue = searchForm.orderBy) => {
+  let orderbyList = [];
+  if (orderByValue) {
+    if (orderByValue === 'grade') {
+      levelOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    } else if (orderByValue === 'category') {
+      // 优先使用props中的分类选项,如果为空则使用默认值
+      const categoryOptionsToUse = props.categoryOptions.length > 0 ? props.categoryOptions : [];
+      categoryOptionsToUse.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    } else if (orderByValue === 'material') {
+      materialOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    } else if (orderByValue === 'era') {
+      eraOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    }
+  }
+  console.log('移动端buildOrderbyList:', orderByValue, orderbyList);
+  return orderbyList;
+};
+
 // 处理搜索
 const handleSearch = () => {
-  emit('search', { ...searchForm })
+  // 使用通用方法构建orderbyList
+  const orderbyList = buildOrderbyList();
+
+  emit('search', {
+    ...searchForm,
+    orderbyList: orderbyList
+  })
 }
 
 // 处理重置
 const handleReset = () => {
   Object.keys(searchForm).forEach(key => {
-    searchForm[key] = ''
+    if (key === 'orderBy') {
+      searchForm[key] = 'grade' // 重置时保持默认排序
+    } else {
+      searchForm[key] = ''
+    }
   })
 }
 
@@ -146,6 +220,7 @@ const handleClose = () => {
 watch(() => props.initialSearch, (newSearch) => {
   if (newSearch) {
     searchForm.searchText = newSearch.searchText
+    searchForm.orderBy = newSearch.orderBy || 'grade' // 如果没有orderBy则使用默认值
     searchForm.level = newSearch.level
     searchForm.category = newSearch.category
     searchForm.material = newSearch.material

+ 254 - 12
mobile/src/views/collectpage/components/collectDetail.vue

@@ -22,6 +22,13 @@
         >
           图片
         </div>
+        <div
+          class="tab-item"
+          :class="{ active: activeTab === 'video' }"
+          @click="switchTab('video')"
+        >
+          视频
+        </div>
       </div>
     </div>
 
@@ -88,6 +95,39 @@
           </div>
         </div>
 
+        <!-- 视频播放容器 -->
+        <div v-show="activeTab === 'video'" class="carousel-container">
+          <div class="video-container" v-if="artifactData && artifactData.videoFiles && artifactData.videoFiles.length > 0">
+            <div class="video-item">
+              <video
+                :src="videoList[0]?.src"
+                controls
+                :poster="videoList[0]?.poster"
+                preload="metadata"
+                class="single-video"
+                @loadstart="handleVideoLoadStart"
+                @loadeddata="handleVideoLoaded"
+              >
+                您的浏览器不支持视频播放。
+              </video>
+            </div>
+          </div>
+          <div v-else class="empty-state">
+            <div class="empty-content">
+              <div class="empty-text">暂无视频数据</div>
+            </div>
+          </div>
+        </div>
+
+        <!-- 音频播放按钮 -->
+        <div v-if="artifactData && artifactData.audioFiles && artifactData.audioFiles.length > 0" class="audio-control" @click="toggleAudio">
+          <img
+            :src="isAudioPlaying ? iconVoiceOn : iconVoiceOff"
+            alt="音频控制"
+            style="width: 24px; height: 24px;"
+          />
+        </div>
+
         <!-- 放大镜图标 -->
         <div v-if="activeTab === 'model' && artifactData && artifactData.modelFiles && artifactData.modelFiles.length > 0" class="zoom-icon" @click="toggleZoom">
           <el-icon style="color: #7C6444" :size="24">
@@ -95,6 +135,20 @@
             <ZoomOut v-else />
           </el-icon>
         </div>
+
+        <!-- 隐藏的音频元素 -->
+        <audio
+          v-if="artifactData && artifactData.audioFiles && artifactData.audioFiles.length > 0"
+          ref="audioRef"
+          :src="currentAudioSrc"
+          @ended="handleAudioEnded"
+          @pause="handleAudioPaused"
+          @play="handleAudioPlay"
+          @error="handleAudioError"
+          @loadstart="handleAudioLoadStart"
+          @canplay="handleAudioCanPlay"
+          style="display: none;"
+        ></audio>
       </div>
     </div>
 
@@ -131,7 +185,7 @@
             </div>
             <div class="info-label-container" v-if="getFieldValue(artifactData, 'texture')">
               <div class="info-label">
-                <span class="info-label-text">质</span>
+                <span class="info-label-text">质</span>
                 <span>{{ getFieldValue(artifactData, 'texture') }}</span>
               </div>
               <div class="bottom-img"></div>
@@ -165,6 +219,8 @@ import { ref, onMounted, nextTick } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import getBookCountApi from '@/api'
 import { ZoomIn, ZoomOut } from '@element-plus/icons-vue'
+import iconVoiceOff from '@/assets/img/icon_voiceoff.png'
+import iconVoiceOn from '@/assets/img/icon_voiceon.png'
 const modelUrl = import.meta.env.VITE_MODEL_URL
 
 const router = useRouter()
@@ -176,9 +232,14 @@ const isZoomed = ref(false)
 const isFrom = ref('')
 const autoplayEnabled = ref(true)
 const imageCarouselRef = ref(null)
+const audioRef = ref(null)
 const currentImageIndex = ref(1)
+const isAudioPlaying = ref(false)
+const currentAudioSrc = ref('')
 const modelList = ref([])
 const imageList = ref([])
+const videoList = ref([])
+const audioList = ref([])
 
 const imgUrl = import.meta.env.VITE_COS_BASE_URL
 
@@ -189,11 +250,13 @@ const getFieldValue = (item, fieldName) => {
 
 
 
-// 初始化模型和图片列表
+// 初始化模型、图片、视频和音频列表
 const initializeLists = () => {
   if (!artifactData.value) {
     modelList.value = []
     imageList.value = []
+    videoList.value = []
+    audioList.value = []
     return
   }
 
@@ -214,6 +277,34 @@ const initializeLists = () => {
     src: `${imgUrl}${imgFile}`,
     alt: `${artifactData.value.title || artifactData.value.name} 图片${index + 1}`
   }))
+
+  // 初始化视频列表
+  const videoFiles = artifactData.value.videoFiles || []
+  videoList.value = videoFiles.map((videoFile, index) => ({
+    type: 'video',
+    src: `${imgUrl}${videoFile}`,
+    poster: '', // 可以添加视频封面图
+    alt: `${artifactData.value.title || artifactData.value.name} 视频${index + 1}`
+  }))
+
+  // 初始化音频列表
+  const audioFiles = artifactData.value.audioFiles || []
+  console.log('音频文件列表:', audioFiles)
+  console.log('基础URL:', imgUrl)
+
+  audioList.value = audioFiles.map((audioFile, index) => ({
+    type: 'audio',
+    src: `${imgUrl}${audioFile}`,
+    alt: `${artifactData.value.title || artifactData.value.name} 音频${index + 1}`
+  }))
+
+  // 设置当前音频源
+  if (audioList.value.length > 0) {
+    currentAudioSrc.value = audioList.value[0].src
+    console.log('设置音频源:', currentAudioSrc.value)
+  } else {
+    console.log('没有音频文件')
+  }
 }
 
 // 返回上一页
@@ -248,17 +339,21 @@ const getArtifactDetail = async () => {
         id: response.id,
         title: response.name || response.title,
         name: response.name || response.title,
-        remark: response.description || response.desc || '暂无描述',
-        era: response.era || response.agetype || '近现代',
-        category: response.texturetype1 || '其他',
-        level: response.level || response.grade || '未定级',
-        texture: response.material || response.texture || '其他',
+        intro: response.intro || '暂无描述',
+        era: response.agetype1 || '--',
+        category: response.category || '--',
+        level: response.grade || '--',
+        texture: response.texture || '--',
         size: response.size || response.dimensions,
         imageFiles: response.imgFiles || [],
+        videoFiles: response.videoFiles || [],
+        audioFiles: response.audioFiles || [],
         modelFile: response.modelFiles && response.modelFiles.length > 0 ? response.modelFiles[0] : null,
         modelFiles: getModelList(response.modelFiles) || [],
         hasImage: response.hasImage !== false,
-        hasModel: response.hasModel !== false
+        hasModel: response.hasModel !== false,
+        hasVideo: response.hasVideo !== false,
+        hasAudio: response.hasAudio !== false
       }
 
       // 初始化列表
@@ -276,6 +371,85 @@ const handleImageCarouselChange = (index) => {
   currentImageIndex.value = imageList.value.length > 0 ? index + 1 : 0
 }
 
+
+// 暂停视频
+const pauseVideo = () => {
+  const video = document.querySelector('.single-video')
+  if (video && !video.paused) {
+    video.pause()
+  }
+}
+
+// 视频加载开始
+const handleVideoLoadStart = () => {
+  console.log('视频开始加载')
+}
+
+// 视频加载完成
+const handleVideoLoaded = () => {
+  console.log('视频加载完成')
+}
+
+// 切换音频播放状态
+const toggleAudio = () => {
+  if (!audioRef.value || !currentAudioSrc.value) {
+    console.log('音频元素或音频源不存在:', { audioRef: audioRef.value, currentAudioSrc: currentAudioSrc.value })
+    return
+  }
+
+  console.log('当前音频源:', currentAudioSrc.value)
+
+  if (isAudioPlaying.value) {
+    audioRef.value.pause()
+  } else {
+    // 添加错误处理
+    audioRef.value.play().catch(error => {
+      console.error('音频播放失败:', error)
+      console.log('音频文件URL:', currentAudioSrc.value)
+      console.log('环境变量 VITE_COS_BASE_URL:', import.meta.env.VITE_COS_BASE_URL)
+      isAudioPlaying.value = false
+    })
+  }
+}
+
+// 音频播放事件
+const handleAudioPlay = () => {
+  console.log('音频开始播放')
+  isAudioPlaying.value = true
+}
+
+// 音频错误处理
+const handleAudioError = (event) => {
+  console.error('音频加载错误:', event)
+  console.log('错误详情:', {
+    error: event.target.error,
+    src: event.target.src,
+    networkState: event.target.networkState,
+    readyState: event.target.readyState
+  })
+  isAudioPlaying.value = false
+}
+
+// 音频开始加载
+const handleAudioLoadStart = () => {
+  console.log('音频开始加载:', currentAudioSrc.value)
+}
+
+// 音频可以播放
+const handleAudioCanPlay = () => {
+  console.log('音频可以播放')
+}
+
+// 音频暂停事件
+const handleAudioPaused = () => {
+  isAudioPlaying.value = false
+}
+
+// 音频播放结束事件
+const handleAudioEnded = () => {
+  isAudioPlaying.value = false
+}
+
 // 切换标签页
 const switchTab = (tab) => {
   activeTab.value = tab
@@ -283,6 +457,12 @@ const switchTab = (tab) => {
     toggleZoom()
   }
 
+  // 暂停视频和音频
+  pauseVideo()
+  if (isAudioPlaying.value) {
+    toggleAudio()
+  }
+
   // 重置图片轮播索引
   if (tab === 'image') {
     currentImageIndex.value = imageList.value.length > 0 ? 1 : 0
@@ -487,7 +667,7 @@ onMounted(() => {
   flex: 1;
   display: flex;
   justify-content: center;
-  max-width: 200px;
+  max-width: 280px;
   margin: 0 auto;
 
   .tab-item {
@@ -556,6 +736,13 @@ onMounted(() => {
     height: 100%;
   }
 
+  .video-container{
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+
   .el-carousel {
     height: 100%;
 
@@ -591,7 +778,7 @@ onMounted(() => {
     max-width: 300px;
     background: rgba(0,0,0,0.2);
     text-align: center;
-    bottom: 16px;
+    bottom: 24px;
     border-radius: 50px;
     padding: 0px 4px 0px 8px;
     .el-carousel__indicator--horizontal{
@@ -607,7 +794,7 @@ onMounted(() => {
     justify-content: center;
   }
 
-  .model-item, .image-item {
+  .model-item, .image-item, .video-item {
     width: 100%;
     height: 100%;
     display: flex;
@@ -624,6 +811,12 @@ onMounted(() => {
       max-height: 100%;
       object-fit: contain;
     }
+
+    video {
+      max-width: 100%;
+      max-height: 100%;
+      object-fit: contain;
+    }
   }
 
   .carousel-image {
@@ -631,16 +824,65 @@ onMounted(() => {
     max-height: 100%;
     object-fit: contain;
   }
+
+  .single-video {
+    max-width: 100%;
+    max-height: 100%;
+    object-fit: contain;
+    background: #000;
+  }
 }
 
 
 
+.audio-control {
+  position: absolute;
+  bottom: 60px;
+  right: 16px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  // background: rgba(255, 255, 255, 0.9);
+  border-radius: 50%;
+  width: 40px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  // box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
+
+  // &:hover {
+  //   background: rgba(255, 255, 255, 1);
+  //   transform: scale(1.05);
+  // }
+
+  &:active {
+    transform: scale(0.95);
+  }
+}
+
 .zoom-icon {
   position: absolute;
-  bottom: 36px;
+  bottom: 26px;
   right: 16px;
   cursor: pointer;
   transition: all 0.3s ease;
+  // background: rgba(255, 255, 255, 0.9);
+  border-radius: 50%;
+  width: 40px;
+  height: 40px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  // box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
+
+  // &:hover {
+  //   background: rgba(255, 255, 255, 1);
+  //   transform: scale(1.05);
+  // }
+
+  // &:active {
+  //   transform: scale(0.95);
+  // }
 }
 
 .artifact-info-card {

+ 148 - 24
mobile/src/views/collectpage/index.vue

@@ -5,6 +5,10 @@
       <SearchPageComponent
         :initialSearch="searchParams"
         :categoryOptions="categoryOptions"
+        :levelOptions="levelOptions"
+        :materialOptions="materialOptions"
+        :eraOptions="eraOptions"
+        :orderByOptions="orderByOptions"
         @search="handleSearch"
         @close="closeSearchPage"
       />
@@ -86,7 +90,7 @@ const router = useRouter()
 
 // 响应式数据
 const showSearchPage = ref(false)
-const searchParams = ref({searchText: '', dim: 3, level: '', category: '', material: '', era: ''})
+const searchParams = ref({searchText: '', dim: 3, orderBy: 'grade', level: '', category: '', material: '', era: ''})
 const searchResults = ref([]) // 当前显示的搜索结果(分页显示)
 const searched = ref(false)
 const loading = ref(false)
@@ -101,14 +105,44 @@ const filters = ref({
   hasModel: false
 })
 
-// 分类选项 - 从接口获取
+// 所有选项列表 - 从接口获取
+const levelOptions = ref([])
 const categoryOptions = ref([])
+const materialOptions = ref([])
+const eraOptions = ref([])
+const orderByOptions = ref([])
 
 // 计算总页数
 const totalPages = computed(() => {
   return Math.ceil(allSearchResults.value.length / pageSize);
 })
 
+// 构建orderbyList的通用方法
+const buildOrderbyList = (orderByValue = searchParams.value.orderBy) => {
+  let orderbyList = [];
+  if (orderByValue) {
+    if (orderByValue === 'grade') {
+      levelOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    } else if (orderByValue === 'category') {
+      categoryOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    } else if (orderByValue === 'texture') {
+      materialOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    } else if (orderByValue === 'era') {
+      eraOptions.value.forEach(item => {
+        orderbyList.push(item.value);
+      });
+    }
+  }
+  console.log('移动端主页buildOrderbyList:', orderByValue, orderbyList);
+  return orderbyList;
+};
+
 // 打开搜索页
 const openSearchPage = () => {
   showSearchPage.value = true
@@ -122,8 +156,9 @@ const closeSearchPage = () => {
 // 快速搜索(回车键触发)
 const quickSearch = () => {
   searchParams.value.dim = getSelectedDim()
+  const orderbyList = buildOrderbyList()
   console.log('searchParams', searchParams.value)
-  handleSearch(searchParams.value)
+  handleSearch({...searchParams.value, orderbyList})
 }
 
 // 计算dim参数值
@@ -189,6 +224,14 @@ const handleSearch = async (searchFilters = {}) => {
   // 确保dim参数正确更新
   searchParams.value.dim = getSelectedDim()
 
+  // 存储排序参数到store
+  if (searchFilters.orderBy) {
+    store.dispatch('setOrderBy', searchFilters.orderBy)
+  }
+  if (searchFilters.orderbyList) {
+    store.dispatch('setOrderbyList', searchFilters.orderbyList)
+  }
+
   try {
     const searchObj = {
       dim: searchParams.value.dim,
@@ -196,7 +239,9 @@ const handleSearch = async (searchFilters = {}) => {
       grade: searchParams.value.level,
       category: searchParams.value.category,
       texture: searchParams.value.material,
-      agetype: searchParams.value.era
+      agetype: searchParams.value.era,
+      orderBy: searchParams.value.orderBy,
+      orderbyList: searchFilters.orderbyList || []
     }
     // 重置分页数据
     currentPage.value = 1;
@@ -218,7 +263,7 @@ const handleSearch = async (searchFilters = {}) => {
       era: item.era || item.agetype || '近现代',
       category: item.category || '其他',
       level: item.level || item.grade || '未定级',
-      material: item.material || item.texture || '其他',
+      material: item.texture || '其他',
       image: `${imgUrl}${item.thumbnail}`,
       hasImage: item.hasImage !== false,
       hasModel: item.hasModel !== false,
@@ -268,36 +313,115 @@ const handleScroll = async (event) => {
   }
 };
 
-// 获取分类列表
-const loadCategoryList = async () => {
+// 获取所有字典数据
+const loadDictionaryData = async () => {
   try {
-    const categories = await getBookCountApi.getCategoryListApi();
+    const dictionaryData = await getBookCountApi.getDictionaryListApi();
+    console.log('获取到字典数据:', dictionaryData);
+    // 处理等级数据
+    if (dictionaryData.grade) {
+      levelOptions.value = dictionaryData.grade.map(item => ({
+        label: item,
+        value: item
+      }));
+    }
+
+    // 处理分类数据
+    if (dictionaryData.category) {
+      const processedCategories = dictionaryData.category.map(item => ({
+        label: item,
+        value: item
+      }));
+      categoryOptions.value = processedCategories;
+    }
 
-    // 处理分类数据,确保有正确的格式
-    const processedCategories = categories.map(category => ({
-      label: category.name || category.label || category,
-      value: category.value || category.name || category
-    }));
+    // 处理材质数据
+    if (dictionaryData.texture) {
+      materialOptions.value = dictionaryData.texture.map(item => ({
+        label: item,
+        value: item
+      }));
+    }
 
-    categoryOptions.value = processedCategories;
+    // 处理年代数据
+    if (dictionaryData.agetype) {
+      eraOptions.value = dictionaryData.agetype.map(item => ({
+        label: item,
+        value: item
+      }));
+    }
 
-    console.log('获取到分类列表:', processedCategories);
+    // 处理排序数据
+    orderByOptions.value = [
+      { label: '等级', value: 'grade' },
+      { label: '类别', value: 'category' },
+      { label: '材质', value: 'texture' },
+      { label: '年代', value: 'era' }
+    ];
+
+    // 字典数据加载完成后,进行初始化搜索
+    console.log('移动端字典数据加载完成,开始初始化搜索');
+    performInitialSearch();
 
   } catch (error) {
-    console.error('获取分类列表失败:', error);
+    console.error('获取字典数据失败:', error);
+    // 如果接口失败,使用默认值
+    levelOptions.value = [
+      { label: '一级', value: '一级' },
+      { label: '二级', value: '二级' },
+      { label: '三级', value: '三级' },
+      { label: '一般', value: '一般' },
+      { label: '未定级', value: '未定级' }
+    ];
+    materialOptions.value = [
+      { label: '石', value: '石' },
+      { label: '铜', value: '铜' },
+      { label: '铜宝玉石', value: '铜宝玉石' },
+      { label: '瓷', value: '瓷' },
+      { label: '陶', value: '陶' },
+      { label: '宝玉石', value: '宝玉石' },
+      { label: '玻璃', value: '玻璃' },
+      { label: '其他', value: '其他' }
+    ];
+    eraOptions.value = [
+      { label: '近现代', value: '近现代' }
+    ];
+    orderByOptions.value = [
+      { label: '等级', value: 'grade' },
+      { label: '类别', value: 'category' },
+      { label: '材质', value: 'material' },
+      { label: '年代', value: 'era' }
+    ];
+
+    // 即使使用默认数据,也要进行初始化搜索
+    console.log('移动端使用默认字典数据,开始初始化搜索');
+    performInitialSearch();
   }
 };
 
+// 执行初始化搜索
+const performInitialSearch = () => {
+  // 检查是否有来自store的搜索关键词
+  const homeSearchText = store.getters.getHomeSearchText;
+  if (homeSearchText) {
+    searchParams.value.searchText = homeSearchText;
+    store.dispatch('setHomeSearchText', ''); // 清除store中的关键词
+  }
+
+  // 构建orderbyList(使用默认的grade排序)
+  const orderbyList = buildOrderbyList();
+
+  // 执行搜索
+  handleSearch({
+    ...searchParams.value,
+    orderbyList
+  });
+};
+
 // 组件挂载
 onMounted(() => {
-  // 优先加载分类列表
-  loadCategoryList();
-
-  // 初始化搜索
-  store.getters.getHomeSearchText
-  searchParams.value.searchText = store.getters.getHomeSearchText
-  handleSearch({searchText: store.getters.getHomeSearchText})
-  store.dispatch('setHomeSearchText', '')
+  // 加载字典数据,字典数据加载完成后会自动进行初始化搜索
+  loadDictionaryData();
 })
 </script>
 

+ 3 - 2
pc/package.json

@@ -18,11 +18,12 @@
     "axios": "^1.9.0",
     "element-plus": "^2.9.11",
     "lodash": "^4.17.21",
+    "qs": "^6.14.0",
     "sass-embedded": "^1.89.2",
+    "v-distpicker": "^2.1.0",
     "vue": "^3.5.18",
     "vue-router": "^4.5.1",
-    "vuex": "^4.1.0",
-    "v-distpicker": "^2.1.0"
+    "vuex": "^4.1.0"
   },
   "devDependencies": {
     "@eslint/js": "^9.31.0",

+ 208 - 0
pc/pnpm-lock.yaml

@@ -17,9 +17,15 @@ importers:
       lodash:
         specifier: ^4.17.21
         version: 4.17.21
+      qs:
+        specifier: ^6.14.0
+        version: 6.14.0
       sass-embedded:
         specifier: ^1.89.2
         version: 1.89.2
+      v-distpicker:
+        specifier: ^2.1.0
+        version: 2.1.0
       vue:
         specifier: ^3.5.18
         version: 3.5.18(typescript@5.8.3)
@@ -771,15 +777,27 @@ packages:
     peerDependencies:
       '@babel/core': ^7.0.0-0
 
+  '@vue/compiler-core@3.2.47':
+    resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==}
+
   '@vue/compiler-core@3.5.18':
     resolution: {integrity: sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==}
 
+  '@vue/compiler-dom@3.2.47':
+    resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==}
+
   '@vue/compiler-dom@3.5.18':
     resolution: {integrity: sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==}
 
+  '@vue/compiler-sfc@3.2.47':
+    resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==}
+
   '@vue/compiler-sfc@3.5.18':
     resolution: {integrity: sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==}
 
+  '@vue/compiler-ssr@3.2.47':
+    resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==}
+
   '@vue/compiler-ssr@3.5.18':
     resolution: {integrity: sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==}
 
@@ -803,20 +821,40 @@ packages:
       eslint: '>= 8.21.0'
       prettier: '>= 3.0.0'
 
+  '@vue/reactivity-transform@3.2.47':
+    resolution: {integrity: sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==}
+
+  '@vue/reactivity@3.2.47':
+    resolution: {integrity: sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==}
+
   '@vue/reactivity@3.5.18':
     resolution: {integrity: sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==}
 
+  '@vue/runtime-core@3.2.47':
+    resolution: {integrity: sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==}
+
   '@vue/runtime-core@3.5.18':
     resolution: {integrity: sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==}
 
+  '@vue/runtime-dom@3.2.47':
+    resolution: {integrity: sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==}
+
   '@vue/runtime-dom@3.5.18':
     resolution: {integrity: sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==}
 
+  '@vue/server-renderer@3.2.47':
+    resolution: {integrity: sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==}
+    peerDependencies:
+      vue: 3.2.47
+
   '@vue/server-renderer@3.5.18':
     resolution: {integrity: sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==}
     peerDependencies:
       vue: 3.5.18
 
+  '@vue/shared@3.2.47':
+    resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==}
+
   '@vue/shared@3.5.18':
     resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==}
 
@@ -928,6 +966,10 @@ packages:
     resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
     engines: {node: '>= 0.4'}
 
+  call-bound@1.0.4:
+    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+    engines: {node: '>= 0.4'}
+
   callsites@3.1.0:
     resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
     engines: {node: '>=6'}
@@ -991,6 +1033,9 @@ packages:
     resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
     engines: {node: '>=18'}
 
+  csstype@2.6.21:
+    resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==}
+
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
@@ -1508,6 +1553,9 @@ packages:
   lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
 
+  magic-string@0.25.9:
+    resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
+
   magic-string@0.30.17:
     resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
 
@@ -1593,6 +1641,10 @@ packages:
   nwsapi@2.2.21:
     resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==}
 
+  object-inspect@1.13.4:
+    resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+    engines: {node: '>= 0.4'}
+
   ohash@2.0.11:
     resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
 
@@ -1698,6 +1750,10 @@ packages:
     resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
     engines: {node: '>=6'}
 
+  qs@6.14.0:
+    resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+    engines: {node: '>=0.6'}
+
   queue-microtask@1.2.3:
     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
 
@@ -1855,6 +1911,22 @@ packages:
     resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
     engines: {node: '>=8'}
 
+  side-channel-list@1.0.0:
+    resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-map@1.0.1:
+    resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-weakmap@1.0.2:
+    resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+    engines: {node: '>= 0.4'}
+
+  side-channel@1.1.0:
+    resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+    engines: {node: '>= 0.4'}
+
   siginfo@2.0.0:
     resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
 
@@ -1870,6 +1942,14 @@ packages:
     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
     engines: {node: '>=0.10.0'}
 
+  source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  sourcemap-codec@1.4.8:
+    resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
+    deprecated: Please use @jridgewell/sourcemap-codec instead
+
   speakingurl@14.0.1:
     resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
     engines: {node: '>=0.10.0'}
@@ -2017,6 +2097,9 @@ packages:
   util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 
+  v-distpicker@2.1.0:
+    resolution: {integrity: sha512-xFUEZHtMXzYJKGiHlBFuzzqF1rEqQKsV8cPXYTzy3FeGJBO37HYnRz76vgw16buoGeqMnusxLRL8BqtaJlpzcg==}
+
   varint@6.0.0:
     resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==}
 
@@ -2149,6 +2232,9 @@ packages:
     peerDependencies:
       vue: ^3.2.0
 
+  vue@3.2.47:
+    resolution: {integrity: sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==}
+
   vue@3.5.18:
     resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==}
     peerDependencies:
@@ -2891,6 +2977,13 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@vue/compiler-core@3.2.47':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      source-map: 0.6.1
+
   '@vue/compiler-core@3.5.18':
     dependencies:
       '@babel/parser': 7.28.0
@@ -2899,11 +2992,29 @@ snapshots:
       estree-walker: 2.0.2
       source-map-js: 1.2.1
 
+  '@vue/compiler-dom@3.2.47':
+    dependencies:
+      '@vue/compiler-core': 3.2.47
+      '@vue/shared': 3.2.47
+
   '@vue/compiler-dom@3.5.18':
     dependencies:
       '@vue/compiler-core': 3.5.18
       '@vue/shared': 3.5.18
 
+  '@vue/compiler-sfc@3.2.47':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/compiler-core': 3.2.47
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-ssr': 3.2.47
+      '@vue/reactivity-transform': 3.2.47
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+      postcss: 8.5.6
+      source-map: 0.6.1
+
   '@vue/compiler-sfc@3.5.18':
     dependencies:
       '@babel/parser': 7.28.0
@@ -2916,6 +3027,11 @@ snapshots:
       postcss: 8.5.6
       source-map-js: 1.2.1
 
+  '@vue/compiler-ssr@3.2.47':
+    dependencies:
+      '@vue/compiler-dom': 3.2.47
+      '@vue/shared': 3.2.47
+
   '@vue/compiler-ssr@3.5.18':
     dependencies:
       '@vue/compiler-dom': 3.5.18
@@ -2958,15 +3074,38 @@ snapshots:
     transitivePeerDependencies:
       - '@types/eslint'
 
+  '@vue/reactivity-transform@3.2.47':
+    dependencies:
+      '@babel/parser': 7.28.0
+      '@vue/compiler-core': 3.2.47
+      '@vue/shared': 3.2.47
+      estree-walker: 2.0.2
+      magic-string: 0.25.9
+
+  '@vue/reactivity@3.2.47':
+    dependencies:
+      '@vue/shared': 3.2.47
+
   '@vue/reactivity@3.5.18':
     dependencies:
       '@vue/shared': 3.5.18
 
+  '@vue/runtime-core@3.2.47':
+    dependencies:
+      '@vue/reactivity': 3.2.47
+      '@vue/shared': 3.2.47
+
   '@vue/runtime-core@3.5.18':
     dependencies:
       '@vue/reactivity': 3.5.18
       '@vue/shared': 3.5.18
 
+  '@vue/runtime-dom@3.2.47':
+    dependencies:
+      '@vue/runtime-core': 3.2.47
+      '@vue/shared': 3.2.47
+      csstype: 2.6.21
+
   '@vue/runtime-dom@3.5.18':
     dependencies:
       '@vue/reactivity': 3.5.18
@@ -2974,12 +3113,20 @@ snapshots:
       '@vue/shared': 3.5.18
       csstype: 3.1.3
 
+  '@vue/server-renderer@3.2.47(vue@3.2.47)':
+    dependencies:
+      '@vue/compiler-ssr': 3.2.47
+      '@vue/shared': 3.2.47
+      vue: 3.2.47
+
   '@vue/server-renderer@3.5.18(vue@3.5.18(typescript@5.8.3))':
     dependencies:
       '@vue/compiler-ssr': 3.5.18
       '@vue/shared': 3.5.18
       vue: 3.5.18(typescript@5.8.3)
 
+  '@vue/shared@3.2.47': {}
+
   '@vue/shared@3.5.18': {}
 
   '@vue/test-utils@2.4.6':
@@ -3090,6 +3237,11 @@ snapshots:
       es-errors: 1.3.0
       function-bind: 1.1.2
 
+  call-bound@1.0.4:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      get-intrinsic: 1.3.0
+
   callsites@3.1.0: {}
 
   caniuse-lite@1.0.30001731: {}
@@ -3149,6 +3301,8 @@ snapshots:
       '@asamuzakjp/css-color': 3.2.0
       rrweb-cssom: 0.8.0
 
+  csstype@2.6.21: {}
+
   csstype@3.1.3: {}
 
   data-urls@5.0.0:
@@ -3688,6 +3842,10 @@ snapshots:
     dependencies:
       yallist: 3.1.1
 
+  magic-string@0.25.9:
+    dependencies:
+      sourcemap-codec: 1.4.8
+
   magic-string@0.30.17:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.5.4
@@ -3754,6 +3912,8 @@ snapshots:
 
   nwsapi@2.2.21: {}
 
+  object-inspect@1.13.4: {}
+
   ohash@2.0.11: {}
 
   open@10.2.0:
@@ -3844,6 +4004,10 @@ snapshots:
 
   punycode@2.3.1: {}
 
+  qs@6.14.0:
+    dependencies:
+      side-channel: 1.1.0
+
   queue-microtask@1.2.3: {}
 
   resolve-from@4.0.0: {}
@@ -3982,6 +4146,34 @@ snapshots:
 
   shebang-regex@3.0.0: {}
 
+  side-channel-list@1.0.0:
+    dependencies:
+      es-errors: 1.3.0
+      object-inspect: 1.13.4
+
+  side-channel-map@1.0.1:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      object-inspect: 1.13.4
+
+  side-channel-weakmap@1.0.2:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      object-inspect: 1.13.4
+      side-channel-map: 1.0.1
+
+  side-channel@1.1.0:
+    dependencies:
+      es-errors: 1.3.0
+      object-inspect: 1.13.4
+      side-channel-list: 1.0.0
+      side-channel-map: 1.0.1
+      side-channel-weakmap: 1.0.2
+
   siginfo@2.0.0: {}
 
   signal-exit@4.1.0: {}
@@ -3994,6 +4186,10 @@ snapshots:
 
   source-map-js@1.2.1: {}
 
+  source-map@0.6.1: {}
+
+  sourcemap-codec@1.4.8: {}
+
   speakingurl@14.0.1: {}
 
   stackback@0.0.2: {}
@@ -4118,6 +4314,10 @@ snapshots:
 
   util-deprecate@1.0.2: {}
 
+  v-distpicker@2.1.0:
+    dependencies:
+      vue: 3.2.47
+
   varint@6.0.0: {}
 
   vite-dev-rpc@1.1.0(vite@7.0.6(sass-embedded@1.89.2)):
@@ -4272,6 +4472,14 @@ snapshots:
       '@vue/devtools-api': 6.6.4
       vue: 3.5.18(typescript@5.8.3)
 
+  vue@3.2.47:
+    dependencies:
+      '@vue/compiler-dom': 3.2.47
+      '@vue/compiler-sfc': 3.2.47
+      '@vue/runtime-dom': 3.2.47
+      '@vue/server-renderer': 3.2.47(vue@3.2.47)
+      '@vue/shared': 3.2.47
+
   vue@3.5.18(typescript@5.8.3):
     dependencies:
       '@vue/compiler-dom': 3.5.18

+ 8 - 3
pc/src/api/index.js

@@ -1,4 +1,5 @@
 import request from '@/utils/request';
+import  qs from 'qs'
 
 const hhbangBookApi = {
   // 首页获取推荐列表
@@ -26,14 +27,18 @@ const hhbangBookApi = {
         searchText: params.keyword || '', // 关键词
         texture: params.material || '', // 材质
         ...params
+      },
+      //序列化
+      paramsSerializer: {
+        serialize: params => qs.stringify(params, {indices: false}),
       }
     })
   },
 
-  // 获取分类列表
-  getCategoryListApi() {
+  // 获取字典数据列表
+  getDictionaryListApi() {
     return request({
-      url: '/hyb/artArtworks/listCategory',
+      url: '/hyb/artArtworks/dictionary',
       method: 'get'
     })
   },

BIN
pc/src/assets/img/icon_voiceoff.png


BIN
pc/src/assets/img/icon_voiceon.png


BIN
pc/src/assets/img/title.png


+ 1 - 1
pc/src/views/Home/index.vue

@@ -16,7 +16,7 @@
       <img
         class="home-main__logo"
         draggable="false"
-        src="@/assets/images/title_01.png"
+        src="@/assets/img/title.png"
       />
 
       <div class="home-search">

+ 144 - 52
pc/src/views/collect/components/CollectionContent.vue

@@ -16,6 +16,21 @@
         <div class="search-main">
           <!-- 搜索框 -->
           <div class="search-inputs">
+            <!-- 排序可选 -->
+            <el-select
+              v-model="searchForm.orderBy"
+              placeholder="排序"
+              class="cut-corner-select"
+              size="default"
+            >
+              <el-option
+                v-for="item in orderByOptions"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+
             <el-select
               v-model="searchForm.level"
               placeholder="级别"
@@ -45,7 +60,7 @@
 
             <el-select
               v-model="searchForm.material"
-              placeholder="质"
+              placeholder="质"
               class="cut-corner-select"
               size="default"
             >
@@ -159,7 +174,8 @@ const searchForm = reactive({
   category: '',
   material: '',
   era: '',
-  searchText: ''
+  searchText: '',
+  orderBy: 'grade' // 默认按等级排序
 });
 
 // 过滤选项
@@ -204,38 +220,44 @@ const totalPages = computed(() => {
 // 文物列表 - 使用计算属性
 const artifactList = computed(() => displayedArtifacts.value);
 
-// 选项列表
-const levelOptions = ref([
-  { label: '一级', value: '一级' },
-  { label: '二级', value: '二级' },
-  { label: '三级', value: '三级' },
-  { label: '一般文物', value: '一般文物' },
-  { label: '未定级', value: '未定级' }
-]);
-
-// 分类选项 - 从接口获取
+// 选项列表 - 全部从接口获取
+const levelOptions = ref([]);
 const categoryOptions = ref([]);
-
-const materialOptions = ref([
-  { label: '石', value: '石' },
-  { label: '铜', value: '铜' },
-  { label: '铜宝玉石', value: '铜宝玉石' },
-  { label: '瓷', value: '瓷' },
-  { label: '陶', value: '陶' },
-  { label: '宝玉石', value: '宝玉石' },
-  { label: '玻璃', value: '玻璃' },
-  { label: '其他', value: '其他' }
-]);
-
-const eraOptions = ref([
-  { label: '近现代', value: '近现代' }
-]);
+const materialOptions = ref([]);
+const eraOptions = ref([]);
+const orderByOptions = ref([]);
 
 // 方法
 const toggleSearch = () => {
   searchCollapsed.value = !searchCollapsed.value;
 };
 
+// 构建orderbyList的通用方法
+const buildOrderbyList = (orderByValue = searchForm.orderBy) => {
+  let orderbyList = [];
+  if (orderByValue) {
+    if (orderByValue === 'grade') {
+      levelOptions.value.forEach(item => {
+        orderbyList.push(`${item.value}`);
+      });
+    } else if (orderByValue === 'category') {
+      categoryOptions.value.forEach(item => {
+        orderbyList.push(`${item.value}`);
+      });
+    } else if (orderByValue === 'texture') {
+      materialOptions.value.forEach(item => {
+        orderbyList.push(`${item.value}`);
+      });
+    } else if (orderByValue === 'era') {
+      eraOptions.value.forEach(item => {
+        orderbyList.push(`${item.value}`);
+      });
+    }
+  }
+  console.log('buildOrderbyList:', orderByValue, orderbyList);
+  return orderbyList;
+};
+
 // 搜索处理
 const handleSearch = () => {
   console.log('执行搜索:', searchForm, filters);
@@ -247,9 +269,13 @@ const handleSearch = () => {
     router.replace({ query });
   }
 
+  // 使用通用方法构建orderbyList
+  const orderbyList = buildOrderbyList();
+
   // 保存搜索参数到Vuex
   store.dispatch('setSearchParams', {
     ...searchForm,
+    orderbyList: orderbyList,
     ...filters
   });
 
@@ -258,7 +284,7 @@ const handleSearch = () => {
   displayedArtifacts.value = []; // 清空当前显示的数据
 
   // 通过API获取筛选后的数据
-  loadAllArtifacts();
+  loadAllArtifacts(orderbyList);
 };
 
 // 重置处理
@@ -270,6 +296,7 @@ const handleReset = () => {
   searchForm.material = '';
   searchForm.era = '';
   searchForm.searchText = '';
+  searchForm.orderBy = 'grade'; // 重置时保持默认排序
 
   // 重置过滤选项
   filters.hasImage = false;
@@ -279,8 +306,9 @@ const handleReset = () => {
   currentPage.value = 1;
   displayedArtifacts.value = []; // 清空当前显示的数据
 
-  // 重新从API加载数据(无筛选条件)
-  loadAllArtifacts();
+  // 重新从API加载数据(使用默认排序)
+  const orderbyList = buildOrderbyList();
+  loadAllArtifacts(orderbyList);
 };
 
 // 文物点击处理
@@ -294,29 +322,96 @@ const handleArtifactClick = (artifact) => {
   emit('show-details', artifact, allArtifacts.value);
 };
 
-// 获取分类列表
-const loadCategoryList = async () => {
+// 获取所有字典数据
+const loadDictionaryData = async () => {
   try {
-    const categories = await getBookCountApi.getCategoryListApi();
+    const dictionaryData = await getBookCountApi.getDictionaryListApi();
+    console.log('获取到字典数据:', dictionaryData);
+    // 处理等级数据
+    if (dictionaryData.grade) {
+      levelOptions.value = dictionaryData.grade.map(item => ({
+        label: item,
+        value: item
+      }));
+    }
 
-    // 处理分类数据,确保有正确的格式
-    const processedCategories = categories.map(category => ({
-      label: category.name || category.label || category,
-      value: category.value || category.name || category
-    }));
+    // 处理分类数据
+    if (dictionaryData.category) {
+      const processedCategories = dictionaryData.category.map(item => ({
+        label: item,
+        value: item
+      }));
+      categoryOptions.value = processedCategories;
+    }
+
+    // 处理材质数据
+    if (dictionaryData.texture) {
+      materialOptions.value = dictionaryData.texture.map(item => ({
+        label: item,
+        value: item
+      }));
+    }
+
+    // 处理年代数据
+    if (dictionaryData.agetype) {
+      eraOptions.value = dictionaryData.agetype.map(item => ({
+        label: item,
+        value: item
+      }));
+    }
 
-    categoryOptions.value = processedCategories;
+    // 处理排序数据
+    orderByOptions.value = [
+      { label: '等级', value: 'grade' },
+      { label: '类别', value: 'category' },
+      { label: '材质', value: 'texture' },
+      { label: '年代', value: 'era' }
+    ];
 
-    // 存储到Vuex
-    store.dispatch('setCategoryList', processedCategories);
+    // 字典数据加载完成后,立即加载文物数据(使用默认排序)
+    console.log('字典数据加载完成,开始加载文物数据');
+    const orderbyList = buildOrderbyList();
+    loadAllArtifacts(orderbyList);
 
   } catch (error) {
-    console.error('获取分类列表失败:', error);
+    console.error('获取字典数据失败:', error);
+    // 如果接口失败,使用默认值
+    levelOptions.value = [
+      { label: '一级', value: '一级' },
+      { label: '二级', value: '二级' },
+      { label: '三级', value: '三级' },
+      { label: '一般', value: '一般' },
+      { label: '未定级', value: '未定级' }
+    ];
+    materialOptions.value = [
+      { label: '石', value: '石' },
+      { label: '铜', value: '铜' },
+      { label: '铜宝玉石', value: '铜宝玉石' },
+      { label: '瓷', value: '瓷' },
+      { label: '陶', value: '陶' },
+      { label: '宝玉石', value: '宝玉石' },
+      { label: '玻璃', value: '玻璃' },
+      { label: '其他', value: '其他' }
+    ];
+    eraOptions.value = [
+      { label: '近现代', value: '近现代' }
+    ];
+    orderByOptions.value = [
+      { label: '等级', value: 'grade' },
+      { label: '类别', value: 'category' },
+      { label: '材质', value: 'texture' },
+      { label: '年代', value: 'era' }
+    ];
+
+    // 即使使用默认数据,也要加载文物数据
+    console.log('使用默认字典数据,开始加载文物数据');
+    const orderbyList = buildOrderbyList();
+    loadAllArtifacts(orderbyList);
   }
 };
 
 // 获取全部文物数据
-const loadAllArtifacts = async () => {
+const loadAllArtifacts = async (orderbyList) => {
   loading.value = true;
   try {
     console.log('开始获取全部文物数据...');
@@ -327,7 +422,9 @@ const loadAllArtifacts = async () => {
       level: searchForm.level,
       category: searchForm.category,
       material: searchForm.material,
-      era: searchForm.era
+      era: searchForm.era,
+      orderBy: searchForm.orderBy,
+      orderbyList: orderbyList ? orderbyList : []
     };
 
     console.log('API调用参数:', searchParams);
@@ -347,7 +444,7 @@ const loadAllArtifacts = async () => {
       era: item.era || item.agetype || '近现代',
       category: item.category || '其他',
       level: item.level || item.grade || '未定级',
-      material: item.material || item.texture || '其他',
+      material: item.texture || '其他',
       image: `${imgUrl}${item.thumbnail}`,
       hasImage: item.hasImage !== false,
       hasModel: item.hasModel !== false,
@@ -421,13 +518,8 @@ onMounted(() => {
     store.dispatch('setHomeSearchText', '');
   }
 
-  // 优先加载分类列表
-  loadCategoryList();
-
-  // 延迟加载全部文物数据
-  setTimeout(() => {
-    loadAllArtifacts();
-  }, 100);
+  // 加载字典数据,字典数据加载完成后会自动加载文物数据
+  loadDictionaryData();
 
   // 确保滚动容器存在并监听滚动事件
   setTimeout(() => {

+ 252 - 6
pc/src/views/collect/components/collectDetails.vue

@@ -39,6 +39,7 @@
                   width="100%"
                   height="100%"
                   allowfullscreen></iframe> -->
+                <!-- 音频播放控件 -->
                 <div class="fullscreen-icon">
                   <el-icon style="color: #7C6444" :size="24">
                     <ZoomIn/>
@@ -74,6 +75,18 @@
               </div>
             </el-carousel-item>
           </el-carousel>
+
+          <div
+              v-show="currentDisplayArtifact.audioFiles && currentDisplayArtifact.audioFiles.length > 0"
+              class="audio-control"
+              @click.stop="handleAudioClick"
+            >
+              <img
+                :src="isAudioPlaying ? iconVoiceOn : iconVoiceOff"
+                alt="音频控制"
+                style="width: 24px; height: 24px;"
+              />
+            </div>
         </div>
 
         <!-- 底部切换按钮 -->
@@ -97,6 +110,16 @@
             <img class="toggle-btn-icon" v-show="showModel" src="@/assets/img/icon_img_active.png" alt="模型图标" />
             图片{{ imageCount > 0 ? currentImageIndex : 0 }}/{{ imageCount }}
           </button>
+          <button
+            class="toggle-btn"
+            v-show="currentDisplayArtifact.videoFiles && currentDisplayArtifact.videoFiles.length > 0"
+            @click="handleVideoClick"
+          >
+            <el-icon class="toggle-btn-icon" style="color: #8B7355; font-size: 20px;">
+              <VideoPlay />
+            </el-icon>
+            视频
+          </button>
         </div>
       </div>
 
@@ -131,7 +154,7 @@
             </div>
             <div class="info-label-container">
               <div class="info-label">
-                <span>质</span>
+                <span>质</span>
                 <span>{{ currentDisplayArtifact.material }}</span>
               </div>
               <div class="bottom-img"></div>
@@ -186,6 +209,38 @@
       :title="modelLookTitle"
       @close="handleCloseModelLook"
     />
+
+    <!-- 视频播放弹窗 -->
+    <el-dialog
+      v-model="showVideoPlayer"
+      :title="videoPlayerTitle"
+      width="100vw"
+      :before-close="handleCloseVideoPlayer"
+      fullscreen
+      :show-close="false"
+      class="video-player-dialog"
+    >
+      <template #header>
+        <div class="custom-header">
+          <div class="video-title">{{ videoPlayerTitle }}</div>
+          <div class="close-button" @click="handleCloseVideoPlayer">
+            <el-icon :size="24">
+              <Close />
+            </el-icon>
+          </div>
+        </div>
+      </template>
+      <div class="video-container">
+        <video
+          v-if="currentVideoSrc"
+          :src="currentVideoSrc"
+          controls
+          preload="metadata"
+        >
+          您的浏览器不支持视频播放。
+        </video>
+      </div>
+    </el-dialog>
   </div>
 </template>
 
@@ -195,6 +250,9 @@ import { useStore } from 'vuex';
 import getBookCountApi from '@/api';
 import ModelLook from './modelLook.vue';
 import { useRoute } from 'vue-router';
+import { Close } from '@element-plus/icons-vue';
+import iconVoiceOff from '@/assets/img/icon_voiceoff.png';
+import iconVoiceOn from '@/assets/img/icon_voiceon.png';
 const route = useRoute();
 const imguRL =  import.meta.env.VITE_COS_BASE_URL
 const modelUrl = import.meta.env.VITE_MODEL_URL
@@ -231,6 +289,15 @@ const showModelLook = ref(false);
 const currentModelSrc = ref('');
 const modelLookTitle = ref('');
 
+// 音频播放相关
+const isAudioPlaying = ref(false);
+const audioElement = ref(null);
+
+// 视频播放相关
+const showVideoPlayer = ref(false);
+const currentVideoSrc = ref('');
+const videoPlayerTitle = ref('');
+
 // 从Vuex获取所有文物数据
 const allArtifacts = computed(() => store.getters.getAllArtifacts);
 const isFromHome = computed(() => route.query.showDetails);
@@ -329,17 +396,19 @@ const loadArtifactDetail = async (artifactId) => {
     artifactDetail.value = {
       id: detail.id,
       name: detail.name || detail.title,
-      description: detail.description || detail.desc || '暂无描述',
-      era: detail.era || detail.agetype || '近现代',
-      category: detail.category || '其他',
-      level: detail.grade,
-      material: detail.texturetype1,
+      description: detail.intro,
+      era: detail.era || detail.agetype1 || '--',
+      category: detail.category || '--',
+      level: detail.grade || '--',
+      material: detail.texture || '--',
       image: detail.image || detail.thumb || `/public/three/assets/${detail.id % 15}.jpg`,
       hasImage: detail.hasImage !== false,
       hasModel: detail.hasModel !== false,
       // 轮播数据
       imgFiles: detail.imgFiles || [],
       modelFiles: getModelList(detail.modelFiles) || [],
+      audioFiles: detail.audioFiles || [],
+      videoFiles: detail.videoFiles || [],
       // 可能的额外详情字段
       createTime: detail.createTime,
       updateTime: detail.updateTime,
@@ -413,6 +482,57 @@ const handleCloseModelLook = () => {
   modelLookTitle.value = '';
 };
 
+// 音频播放相关方法
+const handleAudioClick = () => {
+  if (!currentDisplayArtifact.value?.audioFiles?.length) return;
+
+  const audioUrl = `${imguRL}${currentDisplayArtifact.value.audioFiles[0]}`;
+
+  if (isAudioPlaying.value) {
+    // 停止播放
+    if (audioElement.value) {
+      audioElement.value.pause();
+      audioElement.value.currentTime = 0;
+    }
+    isAudioPlaying.value = false;
+  } else {
+    // 开始播放
+    if (audioElement.value) {
+      audioElement.value.pause();
+    }
+
+    audioElement.value = new Audio(audioUrl);
+    audioElement.value.play();
+    isAudioPlaying.value = true;
+
+    // 监听播放结束
+    audioElement.value.addEventListener('ended', () => {
+      isAudioPlaying.value = false;
+    });
+
+    // 监听播放错误
+    audioElement.value.addEventListener('error', () => {
+      isAudioPlaying.value = false;
+      console.error('音频播放失败');
+    });
+  }
+};
+
+// 视频播放相关方法
+const handleVideoClick = () => {
+  if (!currentDisplayArtifact.value?.videoFiles?.length) return;
+
+  currentVideoSrc.value = `${imguRL}${currentDisplayArtifact.value.videoFiles[0]}`;
+  videoPlayerTitle.value = `${currentDisplayArtifact.value.name}`;
+  showVideoPlayer.value = true;
+};
+
+const handleCloseVideoPlayer = () => {
+  showVideoPlayer.value = false;
+  currentVideoSrc.value = '';
+  videoPlayerTitle.value = '';
+};
+
 // 监听当前文物变化,保持模型模式并加载详情
 watch(() => props.currentArtifact, (newArtifact, oldArtifact) => {
   // 只有当文物真正变化时才重新加载详情(避免初始化时重复调用)
@@ -476,6 +596,7 @@ onMounted(() => {
 
 
   .carousel-container {
+    position: relative;
     height: 500px; // 增加高度为指示器留出空间
     border-radius: 8px;
     overflow: visible; // 改为visible让指示器显示
@@ -515,10 +636,26 @@ onMounted(() => {
           visibility: visible;
         }
       }
+
       .fullscreen-icon {
         position: absolute;
         right: 20px;
         bottom: 20px;
+        background: rgba(255, 255, 255, 0.9);
+        border-radius: 50%;
+        width: 40px;
+        height: 40px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        cursor: pointer;
+        transition: all 0.3s ease;
+        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+
+        &:hover {
+          background: rgba(255, 255, 255, 1);
+          // transform: scale(1.1);
+        }
       }
     }
 
@@ -578,6 +715,27 @@ onMounted(() => {
       }
     }
   }
+
+  .audio-control {
+    position: absolute;
+    right: 20px;
+    bottom: 90px;
+    background: rgba(255, 255, 255, 0.9);
+    border-radius: 50%;
+    width: 40px;
+    height: 40px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+
+    &:hover {
+      background: rgba(255, 255, 255, 1);
+      // transform: scale(1.1);
+    }
+  }
 }
 
 .info-section {
@@ -743,4 +901,92 @@ onMounted(() => {
     font-size: 18px;
   }
 }
+
+// 视频播放弹窗样式
+:deep(.video-player-dialog) {
+  background: rgba(0,0,0,0.7);
+  .el-overlay {
+    background: transparent;
+  }
+
+  .el-dialog {
+    margin: 0 !important;
+    background: transparent !important;
+    box-shadow: none !important;
+    border-radius: 0 !important;
+  }
+
+  .el-dialog__header {
+    background: transparent !important;
+    padding: 0 !important;
+    margin: 0 !important;
+    border: none !important;
+  }
+
+  .el-dialog__body {
+    padding: 0 !important;
+    background: transparent !important;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    height: 100vh;
+  }
+
+  .custom-header {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    z-index: 9999;
+    padding: 30px 30px;
+    background: transparent;
+
+    .video-title {
+      color: white;
+      font-size: 20px;
+      font-weight: bold;
+      text-align: center;
+    }
+
+    .close-button {
+      position: absolute;
+      right: 40px;
+      top: 50%;
+      transform: translateY(-50%);
+      border-radius: 50%;
+      width: 48px;
+      height: 48px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      background: transparent;
+
+      backdrop-filter: blur(10px);
+
+      .el-icon {
+        color: white;
+      }
+    }
+  }
+
+  .video-container {
+    display: flex;
+    justify-content: center;
+    // align-items: center;
+    width: 100%;
+    height: 100vh;
+    padding: 100px 50px 50px;
+    box-sizing: border-box;
+
+    video {
+      width: 80%;
+      height: 80%;
+      border-radius: 12px;
+      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
+      object-fit: contain;
+    }
+  }
+}
 </style>

+ 1 - 1
pc/src/views/collect/index.vue

@@ -15,7 +15,7 @@
       </div>
       <!-- 顶部图片 -->
       <div class="top-title" @click="goHome">
-        <img src="@/assets/img/title_02.png" alt="标题" />
+        <img src="@/assets/img/title.png" alt="标题" />
       </div>
     </div>