This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
"dev:test:mp-weixin": "uni -p mp-weixin --mode test",
|
"dev:test:mp-weixin": "uni -p mp-weixin --mode test",
|
||||||
"build:test:mp-weixin": "uni build -p mp-weixin --mode test",
|
"build:test:mp-weixin": "uni build -p mp-weixin --mode test",
|
||||||
"build:mp-weixin": "uni build -p mp-weixin --mode production",
|
"build:mp-weixin": "uni build -p mp-weixin --mode production",
|
||||||
|
"verify:arrival-build": "node scripts/verify-arrival-navigation-build.cjs",
|
||||||
"test:unit": "vitest run",
|
"test:unit": "vitest run",
|
||||||
"type-check": "vue-tsc --noEmit",
|
"type-check": "vue-tsc --noEmit",
|
||||||
"lint": "eslint \"src/**/*.{ts,vue}\""
|
"lint": "eslint \"src/**/*.{ts,vue}\""
|
||||||
@@ -37,9 +38,12 @@
|
|||||||
"@types/three": "0.163.0",
|
"@types/three": "0.163.0",
|
||||||
"@typescript-eslint/eslint-plugin": "7.18.0",
|
"@typescript-eslint/eslint-plugin": "7.18.0",
|
||||||
"@typescript-eslint/parser": "7.18.0",
|
"@typescript-eslint/parser": "7.18.0",
|
||||||
|
"@vitejs/plugin-vue": "5.2.4",
|
||||||
"@vue/runtime-core": "3.4.21",
|
"@vue/runtime-core": "3.4.21",
|
||||||
|
"@vue/test-utils": "2.4.6",
|
||||||
"eslint": "8.57.1",
|
"eslint": "8.57.1",
|
||||||
"eslint-plugin-vue": "9.30.0",
|
"eslint-plugin-vue": "9.30.0",
|
||||||
|
"happy-dom": "14.12.3",
|
||||||
"sass": "1.99.0",
|
"sass": "1.99.0",
|
||||||
"sass-embedded": "1.99.0",
|
"sass-embedded": "1.99.0",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3",
|
||||||
|
|||||||
138
pnpm-lock.yaml
generated
138
pnpm-lock.yaml
generated
@@ -51,15 +51,24 @@ importers:
|
|||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: 7.18.0
|
specifier: 7.18.0
|
||||||
version: 7.18.0(eslint@8.57.1)(typescript@5.3.3)
|
version: 7.18.0(eslint@8.57.1)(typescript@5.3.3)
|
||||||
|
'@vitejs/plugin-vue':
|
||||||
|
specifier: 5.2.4
|
||||||
|
version: 5.2.4(vite@5.2.8(@types/node@25.9.1)(sass@1.99.0)(terser@5.47.1))(vue@3.4.21(typescript@5.3.3))
|
||||||
'@vue/runtime-core':
|
'@vue/runtime-core':
|
||||||
specifier: 3.4.21
|
specifier: 3.4.21
|
||||||
version: 3.4.21
|
version: 3.4.21
|
||||||
|
'@vue/test-utils':
|
||||||
|
specifier: 2.4.6
|
||||||
|
version: 2.4.6
|
||||||
eslint:
|
eslint:
|
||||||
specifier: 8.57.1
|
specifier: 8.57.1
|
||||||
version: 8.57.1
|
version: 8.57.1
|
||||||
eslint-plugin-vue:
|
eslint-plugin-vue:
|
||||||
specifier: 9.30.0
|
specifier: 9.30.0
|
||||||
version: 9.30.0(eslint@8.57.1)
|
version: 9.30.0(eslint@8.57.1)
|
||||||
|
happy-dom:
|
||||||
|
specifier: 14.12.3
|
||||||
|
version: 14.12.3
|
||||||
sass:
|
sass:
|
||||||
specifier: 1.99.0
|
specifier: 1.99.0
|
||||||
version: 1.99.0
|
version: 1.99.0
|
||||||
@@ -74,7 +83,7 @@ importers:
|
|||||||
version: 5.2.8(@types/node@25.9.1)(sass@1.99.0)(terser@5.47.1)
|
version: 5.2.8(@types/node@25.9.1)(sass@1.99.0)(terser@5.47.1)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: 1.6.1
|
specifier: 1.6.1
|
||||||
version: 1.6.1(@types/node@25.9.1)(jsdom@16.7.0)(sass@1.99.0)(terser@5.47.1)
|
version: 1.6.1(@types/node@25.9.1)(happy-dom@14.12.3)(jsdom@16.7.0)(sass@1.99.0)(terser@5.47.1)
|
||||||
vue-eslint-parser:
|
vue-eslint-parser:
|
||||||
specifier: 9.4.3
|
specifier: 9.4.3
|
||||||
version: 9.4.3(eslint@8.57.1)
|
version: 9.4.3(eslint@8.57.1)
|
||||||
@@ -1272,6 +1281,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
'@one-ini/wasm@0.1.1':
|
||||||
|
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.6':
|
'@parcel/watcher-android-arm64@2.5.6':
|
||||||
resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==}
|
resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
@@ -1764,10 +1776,16 @@ packages:
|
|||||||
'@vue/shared@3.5.34':
|
'@vue/shared@3.5.34':
|
||||||
resolution: {integrity: sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==}
|
resolution: {integrity: sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==}
|
||||||
|
|
||||||
|
'@vue/test-utils@2.4.6':
|
||||||
|
resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
|
||||||
|
|
||||||
abab@2.0.6:
|
abab@2.0.6:
|
||||||
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
|
||||||
deprecated: Use your platform's native atob() and btoa() methods instead
|
deprecated: Use your platform's native atob() and btoa() methods instead
|
||||||
|
|
||||||
|
abbrev@1.0.3:
|
||||||
|
resolution: {integrity: sha512-s07HMJf6O5iTLVDx9cH7c9VbOdrmzxE+AzWz9CPi94zVNBQQA3jIwIZKTrHQj4dGR1T/MdwMnVJzSpjaVEXtXw==}
|
||||||
|
|
||||||
accepts@1.3.8:
|
accepts@1.3.8:
|
||||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -2075,6 +2093,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
commander@10.0.0:
|
||||||
|
resolution: {integrity: sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
commander@2.20.3:
|
commander@2.20.3:
|
||||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||||
|
|
||||||
@@ -2093,6 +2115,9 @@ packages:
|
|||||||
confbox@0.2.4:
|
confbox@0.2.4:
|
||||||
resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==}
|
resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==}
|
||||||
|
|
||||||
|
config-chain@1.1.13:
|
||||||
|
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -2270,6 +2295,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
editorconfig@1.0.7:
|
||||||
|
resolution: {integrity: sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
ee-first@1.1.1:
|
ee-first@1.1.1:
|
||||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||||
|
|
||||||
@@ -2573,6 +2603,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==}
|
resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==}
|
||||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||||
|
|
||||||
|
glob@8.1.0:
|
||||||
|
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
deprecated: Glob versions prior to v9 are no longer supported
|
||||||
|
|
||||||
global@4.4.0:
|
global@4.4.0:
|
||||||
resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
|
resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
|
||||||
|
|
||||||
@@ -2594,6 +2629,10 @@ packages:
|
|||||||
graphemer@1.4.0:
|
graphemer@1.4.0:
|
||||||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||||
|
|
||||||
|
happy-dom@14.12.3:
|
||||||
|
resolution: {integrity: sha512-vsYlEs3E9gLwA1Hp+w3qzu+RUDFf4VTT8cyKqVICoZ2k7WM++Qyd2LwzyTi5bqMJFiIC/vNpTDYuxdreENRK/g==}
|
||||||
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
has-flag@3.0.0:
|
has-flag@3.0.0:
|
||||||
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
|
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -2695,6 +2734,10 @@ packages:
|
|||||||
inherits@2.0.4:
|
inherits@2.0.4:
|
||||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
|
ini@1.3.4:
|
||||||
|
resolution: {integrity: sha512-VUA7WAWNCWfm6/8f9kAb8Y6iGBWnmCfgFS5dTrv2C38LLm1KUmpY388mCVCJCsMKQomvOQ1oW8/edXdChd9ZXQ==}
|
||||||
|
deprecated: Please update to ini >=1.3.6 to avoid a prototype pollution issue
|
||||||
|
|
||||||
invert-kv@3.0.1:
|
invert-kv@3.0.1:
|
||||||
resolution: {integrity: sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==}
|
resolution: {integrity: sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -2926,6 +2969,11 @@ packages:
|
|||||||
jpeg-js@0.3.7:
|
jpeg-js@0.3.7:
|
||||||
resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==}
|
resolution: {integrity: sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==}
|
||||||
|
|
||||||
|
js-beautify@1.14.9:
|
||||||
|
resolution: {integrity: sha512-coM7xq1syLcMyuVGyToxcj2AlzhkDjmfklL8r0JgJ7A76wyGMpJ1oA35mr4APdYNO/o/4YY8H54NQIJzhMbhBg==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
js-tokens@4.0.0:
|
js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
@@ -3141,6 +3189,10 @@ packages:
|
|||||||
minimatch@3.1.5:
|
minimatch@3.1.5:
|
||||||
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
|
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
|
||||||
|
|
||||||
|
minimatch@5.1.9:
|
||||||
|
resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
minimatch@9.0.9:
|
minimatch@9.0.9:
|
||||||
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
|
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
@@ -3189,6 +3241,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==}
|
resolution: {integrity: sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
nopt@6.0.0:
|
||||||
|
resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
|
||||||
|
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
normalize-path@3.0.0:
|
normalize-path@3.0.0:
|
||||||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -3471,6 +3528,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
proto-list@1.2.4:
|
||||||
|
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
|
||||||
|
|
||||||
proxy-addr@2.0.7:
|
proxy-addr@2.0.7:
|
||||||
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
@@ -4172,6 +4232,9 @@ packages:
|
|||||||
jsdom:
|
jsdom:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
vue-component-type-helpers@2.0.0:
|
||||||
|
resolution: {integrity: sha512-r+lO2aYasxliE6I76dutaY0GBCnqM7Q/c3VO2MPxrJsIUwPZIESLfis9/1EXAMWajnpF+o0syJAIV6Y6/crKNw==}
|
||||||
|
|
||||||
vue-eslint-parser@9.4.3:
|
vue-eslint-parser@9.4.3:
|
||||||
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
|
resolution: {integrity: sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==}
|
||||||
engines: {node: ^14.17.0 || >=16.0.0}
|
engines: {node: ^14.17.0 || >=16.0.0}
|
||||||
@@ -4219,6 +4282,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==}
|
resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==}
|
||||||
engines: {node: '>=10.4'}
|
engines: {node: '>=10.4'}
|
||||||
|
|
||||||
|
webidl-conversions@7.0.0:
|
||||||
|
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
webpack-virtual-modules@0.6.2:
|
webpack-virtual-modules@0.6.2:
|
||||||
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
|
||||||
|
|
||||||
@@ -4228,6 +4295,10 @@ packages:
|
|||||||
whatwg-mimetype@2.3.0:
|
whatwg-mimetype@2.3.0:
|
||||||
resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==}
|
resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==}
|
||||||
|
|
||||||
|
whatwg-mimetype@3.0.0:
|
||||||
|
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
whatwg-url@8.7.0:
|
whatwg-url@8.7.0:
|
||||||
resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==}
|
resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -6245,6 +6316,8 @@ snapshots:
|
|||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.20.1
|
fastq: 1.20.1
|
||||||
|
|
||||||
|
'@one-ini/wasm@0.1.1': {}
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.6':
|
'@parcel/watcher-android-arm64@2.5.6':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -6759,8 +6832,15 @@ snapshots:
|
|||||||
|
|
||||||
'@vue/shared@3.5.34': {}
|
'@vue/shared@3.5.34': {}
|
||||||
|
|
||||||
|
'@vue/test-utils@2.4.6':
|
||||||
|
dependencies:
|
||||||
|
js-beautify: 1.14.9
|
||||||
|
vue-component-type-helpers: 2.0.0
|
||||||
|
|
||||||
abab@2.0.6: {}
|
abab@2.0.6: {}
|
||||||
|
|
||||||
|
abbrev@1.0.3: {}
|
||||||
|
|
||||||
accepts@1.3.8:
|
accepts@1.3.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
@@ -7106,6 +7186,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
|
commander@10.0.0: {}
|
||||||
|
|
||||||
commander@2.20.3: {}
|
commander@2.20.3: {}
|
||||||
|
|
||||||
compare-versions@3.6.0: {}
|
compare-versions@3.6.0: {}
|
||||||
@@ -7118,6 +7200,11 @@ snapshots:
|
|||||||
|
|
||||||
confbox@0.2.4: {}
|
confbox@0.2.4: {}
|
||||||
|
|
||||||
|
config-chain@1.1.13:
|
||||||
|
dependencies:
|
||||||
|
ini: 1.3.4
|
||||||
|
proto-list: 1.2.4
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@@ -7245,6 +7332,13 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
gopd: 1.2.0
|
gopd: 1.2.0
|
||||||
|
|
||||||
|
editorconfig@1.0.7:
|
||||||
|
dependencies:
|
||||||
|
'@one-ini/wasm': 0.1.1
|
||||||
|
commander: 10.0.0
|
||||||
|
minimatch: 9.0.9
|
||||||
|
semver: 7.8.0
|
||||||
|
|
||||||
ee-first@1.1.1: {}
|
ee-first@1.1.1: {}
|
||||||
|
|
||||||
electron-to-chromium@1.5.360: {}
|
electron-to-chromium@1.5.360: {}
|
||||||
@@ -7637,6 +7731,14 @@ snapshots:
|
|||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
path-is-absolute: 1.0.1
|
path-is-absolute: 1.0.1
|
||||||
|
|
||||||
|
glob@8.1.0:
|
||||||
|
dependencies:
|
||||||
|
fs.realpath: 1.0.0
|
||||||
|
inflight: 1.0.6
|
||||||
|
inherits: 2.0.4
|
||||||
|
minimatch: 5.1.9
|
||||||
|
once: 1.4.0
|
||||||
|
|
||||||
global@4.4.0:
|
global@4.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
min-document: 2.19.2
|
min-document: 2.19.2
|
||||||
@@ -7661,6 +7763,12 @@ snapshots:
|
|||||||
|
|
||||||
graphemer@1.4.0: {}
|
graphemer@1.4.0: {}
|
||||||
|
|
||||||
|
happy-dom@14.12.3:
|
||||||
|
dependencies:
|
||||||
|
entities: 4.5.0
|
||||||
|
webidl-conversions: 7.0.0
|
||||||
|
whatwg-mimetype: 3.0.0
|
||||||
|
|
||||||
has-flag@3.0.0: {}
|
has-flag@3.0.0: {}
|
||||||
|
|
||||||
has-flag@4.0.0: {}
|
has-flag@4.0.0: {}
|
||||||
@@ -7751,6 +7859,8 @@ snapshots:
|
|||||||
|
|
||||||
inherits@2.0.4: {}
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
|
ini@1.3.4: {}
|
||||||
|
|
||||||
invert-kv@3.0.1: {}
|
invert-kv@3.0.1: {}
|
||||||
|
|
||||||
ipaddr.js@1.9.1: {}
|
ipaddr.js@1.9.1: {}
|
||||||
@@ -8194,6 +8304,13 @@ snapshots:
|
|||||||
|
|
||||||
jpeg-js@0.3.7: {}
|
jpeg-js@0.3.7: {}
|
||||||
|
|
||||||
|
js-beautify@1.14.9:
|
||||||
|
dependencies:
|
||||||
|
config-chain: 1.1.13
|
||||||
|
editorconfig: 1.0.7
|
||||||
|
glob: 8.1.0
|
||||||
|
nopt: 6.0.0
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
|
|
||||||
js-tokens@9.0.1: {}
|
js-tokens@9.0.1: {}
|
||||||
@@ -8401,6 +8518,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 1.1.14
|
brace-expansion: 1.1.14
|
||||||
|
|
||||||
|
minimatch@5.1.9:
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: 2.1.0
|
||||||
|
|
||||||
minimatch@9.0.9:
|
minimatch@9.0.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 2.1.0
|
brace-expansion: 2.1.0
|
||||||
@@ -8439,6 +8560,10 @@ snapshots:
|
|||||||
|
|
||||||
node-releases@2.0.45: {}
|
node-releases@2.0.45: {}
|
||||||
|
|
||||||
|
nopt@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
abbrev: 1.0.3
|
||||||
|
|
||||||
normalize-path@3.0.0: {}
|
normalize-path@3.0.0: {}
|
||||||
|
|
||||||
normalize-range@0.1.2: {}
|
normalize-range@0.1.2: {}
|
||||||
@@ -8706,6 +8831,8 @@ snapshots:
|
|||||||
kleur: 3.0.3
|
kleur: 3.0.3
|
||||||
sisteransi: 1.0.5
|
sisteransi: 1.0.5
|
||||||
|
|
||||||
|
proto-list@1.2.4: {}
|
||||||
|
|
||||||
proxy-addr@2.0.7:
|
proxy-addr@2.0.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
forwarded: 0.2.0
|
forwarded: 0.2.0
|
||||||
@@ -9350,7 +9477,7 @@ snapshots:
|
|||||||
sass: 1.99.0
|
sass: 1.99.0
|
||||||
terser: 5.47.1
|
terser: 5.47.1
|
||||||
|
|
||||||
vitest@1.6.1(@types/node@25.9.1)(jsdom@16.7.0)(sass@1.99.0)(terser@5.47.1):
|
vitest@1.6.1(@types/node@25.9.1)(happy-dom@14.12.3)(jsdom@16.7.0)(sass@1.99.0)(terser@5.47.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 1.6.1
|
'@vitest/expect': 1.6.1
|
||||||
'@vitest/runner': 1.6.1
|
'@vitest/runner': 1.6.1
|
||||||
@@ -9374,6 +9501,7 @@ snapshots:
|
|||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 25.9.1
|
'@types/node': 25.9.1
|
||||||
|
happy-dom: 14.12.3
|
||||||
jsdom: 16.7.0
|
jsdom: 16.7.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- less
|
- less
|
||||||
@@ -9384,6 +9512,8 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- terser
|
- terser
|
||||||
|
|
||||||
|
vue-component-type-helpers@2.0.0: {}
|
||||||
|
|
||||||
vue-eslint-parser@9.4.3(eslint@8.57.1):
|
vue-eslint-parser@9.4.3(eslint@8.57.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
@@ -9440,6 +9570,8 @@ snapshots:
|
|||||||
|
|
||||||
webidl-conversions@6.1.0: {}
|
webidl-conversions@6.1.0: {}
|
||||||
|
|
||||||
|
webidl-conversions@7.0.0: {}
|
||||||
|
|
||||||
webpack-virtual-modules@0.6.2: {}
|
webpack-virtual-modules@0.6.2: {}
|
||||||
|
|
||||||
whatwg-encoding@1.0.5:
|
whatwg-encoding@1.0.5:
|
||||||
@@ -9448,6 +9580,8 @@ snapshots:
|
|||||||
|
|
||||||
whatwg-mimetype@2.3.0: {}
|
whatwg-mimetype@2.3.0: {}
|
||||||
|
|
||||||
|
whatwg-mimetype@3.0.0: {}
|
||||||
|
|
||||||
whatwg-url@8.7.0:
|
whatwg-url@8.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
lodash: 4.18.1
|
lodash: 4.18.1
|
||||||
|
|||||||
107
scripts/verify-arrival-navigation-build.cjs
Normal file
107
scripts/verify-arrival-navigation-build.cjs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
const fs = require('node:fs')
|
||||||
|
const path = require('node:path')
|
||||||
|
|
||||||
|
const projectRoot = path.resolve(__dirname, '..')
|
||||||
|
const h5Root = path.resolve(projectRoot, process.argv[2] || path.join('dist', 'build', 'h5'))
|
||||||
|
const mpRoot = path.resolve(projectRoot, process.argv[3] || path.join('dist', 'build', 'mp-weixin'))
|
||||||
|
|
||||||
|
const readText = (filePath) => fs.readFileSync(filePath, 'utf8')
|
||||||
|
|
||||||
|
const assertContains = (source, value, label) => {
|
||||||
|
if (!source.includes(value)) {
|
||||||
|
throw new Error(`${label} 缺少:${value}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const assertNotContains = (source, value, label) => {
|
||||||
|
if (source.includes(value)) {
|
||||||
|
throw new Error(`${label} 不应包含:${value}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectJavaScriptFiles = (root) => fs.readdirSync(root, { withFileTypes: true })
|
||||||
|
.flatMap((entry) => {
|
||||||
|
const entryPath = path.join(root, entry.name)
|
||||||
|
if (entry.isDirectory()) return collectJavaScriptFiles(entryPath)
|
||||||
|
return entry.isFile() && entry.name.endsWith('.js') ? [entryPath] : []
|
||||||
|
})
|
||||||
|
|
||||||
|
const htmlPath = path.join(h5Root, 'index.html')
|
||||||
|
const html = readText(htmlPath)
|
||||||
|
const entryMatch = html.match(/<script[^>]+src="([^"]+\.js)"/)
|
||||||
|
if (!entryMatch) throw new Error('H5 index.html 未找到入口 JS')
|
||||||
|
|
||||||
|
const entryPath = path.join(h5Root, entryMatch[1].replace(/^\//, ''))
|
||||||
|
const entryCode = readText(entryPath)
|
||||||
|
const pageChunkMatch = entryCode.match(/pages-index-index\.[A-Za-z0-9_-]+\.js/)
|
||||||
|
if (!pageChunkMatch) throw new Error('H5 入口 JS 未找到首页页面 chunk')
|
||||||
|
|
||||||
|
const pageChunkPath = path.join(path.dirname(entryPath), pageChunkMatch[0])
|
||||||
|
const pageChunkCode = readText(pageChunkPath)
|
||||||
|
const h5JavaScriptFiles = collectJavaScriptFiles(h5Root)
|
||||||
|
const h5JavaScriptCode = h5JavaScriptFiles
|
||||||
|
.map((filePath) => readText(filePath))
|
||||||
|
.join('\n')
|
||||||
|
|
||||||
|
for (const required of ['第三方导航', 'third-party-providers']) {
|
||||||
|
assertContains(pageChunkCode, required, 'H5 首页 chunk')
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const forbidden of [
|
||||||
|
'打开地图导航',
|
||||||
|
'native-location',
|
||||||
|
'jweixin',
|
||||||
|
'wx.miniProgram',
|
||||||
|
'宿主地图',
|
||||||
|
'/pages/open-location/index'
|
||||||
|
]) {
|
||||||
|
assertNotContains(h5JavaScriptCode, forbidden, 'H5 全量 JS')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h5JavaScriptFiles.some((filePath) => path.basename(filePath).includes('pages-open-location-index'))) {
|
||||||
|
throw new Error('H5 构建不应生成 open-location 页面 chunk')
|
||||||
|
}
|
||||||
|
|
||||||
|
const mpArrivalPanelPath = path.join(
|
||||||
|
mpRoot,
|
||||||
|
'components',
|
||||||
|
'navigation',
|
||||||
|
'ArrivalPanel.js'
|
||||||
|
)
|
||||||
|
const mpArrivalPanelCode = readText(mpArrivalPanelPath)
|
||||||
|
const mpArrivalPanelTemplatePath = path.join(
|
||||||
|
mpRoot,
|
||||||
|
'components',
|
||||||
|
'navigation',
|
||||||
|
'ArrivalPanel.wxml'
|
||||||
|
)
|
||||||
|
const mpArrivalPanelTemplate = readText(mpArrivalPanelTemplatePath)
|
||||||
|
assertContains(mpArrivalPanelCode, '打开地图导航', 'mp-weixin 来馆组件')
|
||||||
|
assertContains(
|
||||||
|
mpArrivalPanelCode,
|
||||||
|
'../../services/WechatOpenLocationService.js',
|
||||||
|
'mp-weixin 来馆组件'
|
||||||
|
)
|
||||||
|
assertNotContains(mpArrivalPanelCode, 'third-party-providers', 'mp-weixin 来馆组件')
|
||||||
|
assertNotContains(mpArrivalPanelTemplate, 'provider-sheet', 'mp-weixin 来馆模板')
|
||||||
|
assertNotContains(mpArrivalPanelTemplate, '第三方导航', 'mp-weixin 来馆模板')
|
||||||
|
|
||||||
|
const mpAppConfigPath = path.join(mpRoot, 'app.json')
|
||||||
|
const mpAppConfig = JSON.parse(readText(mpAppConfigPath))
|
||||||
|
if (!mpAppConfig.pages?.includes('pages/open-location/index')) {
|
||||||
|
throw new Error('mp-weixin app.json 未注册 open-location 页面')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(JSON.stringify({
|
||||||
|
h5: {
|
||||||
|
html: path.relative(projectRoot, htmlPath),
|
||||||
|
entry: path.relative(projectRoot, entryPath),
|
||||||
|
pageChunk: path.relative(projectRoot, pageChunkPath),
|
||||||
|
navigationMode: 'third-party-providers'
|
||||||
|
},
|
||||||
|
mpWeixin: {
|
||||||
|
component: path.relative(projectRoot, mpArrivalPanelPath),
|
||||||
|
template: path.relative(projectRoot, mpArrivalPanelTemplatePath),
|
||||||
|
navigationMode: 'native-location'
|
||||||
|
}
|
||||||
|
}, null, 2))
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
<view
|
<view
|
||||||
v-if="providerSheetVisible && selectedTarget"
|
v-if="providerSheetVisible && selectedTarget"
|
||||||
class="provider-scrim"
|
class="provider-scrim"
|
||||||
@@ -109,6 +110,24 @@
|
|||||||
<text class="provider-action">打开</text>
|
<text class="provider-action">打开</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view
|
||||||
|
v-if="buildDiagnostics"
|
||||||
|
class="arrival-build-diagnostics"
|
||||||
|
data-testid="arrival-build-diagnostics"
|
||||||
|
>
|
||||||
|
<text class="arrival-build-diagnostics-title">H5 构建诊断</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">构建 ID:{{ buildDiagnostics.buildId }}</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">Git commit:{{ buildDiagnostics.gitCommit }}</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">构建平台:{{ buildDiagnostics.platform }}</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">navigationMode:{{ buildDiagnostics.navigationMode }}</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">页面 chunk:{{ buildDiagnostics.chunkFileName }}</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">location.href:{{ buildDiagnostics.href }}</text>
|
||||||
|
<text class="arrival-build-diagnostics-line">UA:{{ buildDiagnostics.userAgent }}</text>
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -118,17 +137,19 @@ import {
|
|||||||
type ArrivalSearchTarget,
|
type ArrivalSearchTarget,
|
||||||
type ArrivalTargetType
|
type ArrivalTargetType
|
||||||
} from '@/data/arrivalSearchTargets'
|
} from '@/data/arrivalSearchTargets'
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
import {
|
import {
|
||||||
openThirdPartyMapSearch,
|
openThirdPartyMapSearch,
|
||||||
openWechatMiniProgramLocation,
|
|
||||||
THIRD_PARTY_MAP_PROVIDERS,
|
THIRD_PARTY_MAP_PROVIDERS,
|
||||||
type ThirdPartyMapProviderOption
|
type ThirdPartyMapProviderOption
|
||||||
} from '@/services/ThirdPartyMapSearchService'
|
} from '@/services/ThirdPartyMapSearchService'
|
||||||
import { isNativeWechatMiniProgram } from '@/utils/hostEnvironment'
|
// #endif
|
||||||
import {
|
// #ifdef MP-WEIXIN
|
||||||
getArrivalNavigationActionText,
|
import { openWechatHostLocation } from '@/services/WechatOpenLocationService'
|
||||||
resolveArrivalNavigationMode
|
import { validateWechatOpenLocationTarget } from '@/utils/wechatOpenLocationProtocol'
|
||||||
} from '@/components/navigation/arrivalNavigationPolicy'
|
// #endif
|
||||||
|
|
||||||
|
type ArrivalNavigationMode = 'third-party-providers' | 'native-location'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
visible?: boolean
|
visible?: boolean
|
||||||
@@ -151,17 +172,64 @@ const emit = defineEmits<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const typeOptions = computed(() => ARRIVAL_TARGET_TYPES)
|
const typeOptions = computed(() => ARRIVAL_TARGET_TYPES)
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
const mapProviders = computed(() => THIRD_PARTY_MAP_PROVIDERS)
|
const mapProviders = computed(() => THIRD_PARTY_MAP_PROVIDERS)
|
||||||
const navigationMode = resolveArrivalNavigationMode(isNativeWechatMiniProgram())
|
// #endif
|
||||||
const primaryActionText = computed(() => (
|
const navigationMode: ArrivalNavigationMode = __APP_BUILD_PLATFORM__ === 'mp-weixin'
|
||||||
getArrivalNavigationActionText(navigationMode, isOpeningNavigation.value)
|
? 'native-location'
|
||||||
))
|
: 'third-party-providers'
|
||||||
const arrivalPanelRef = ref<unknown>(null)
|
const arrivalPanelRef = ref<unknown>(null)
|
||||||
const isCollapsed = ref(false)
|
const isCollapsed = ref(false)
|
||||||
const providerSheetVisible = ref(false)
|
const providerSheetVisible = ref(false)
|
||||||
const isOpeningNavigation = ref(false)
|
const isOpeningNavigation = ref(false)
|
||||||
let resizeObserver: ResizeObserver | null = null
|
let resizeObserver: ResizeObserver | null = null
|
||||||
|
|
||||||
|
const primaryActionText = computed(() => {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
if (navigationMode === 'native-location') {
|
||||||
|
return isOpeningNavigation.value ? '正在打开...' : '打开地图导航'
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
return '第三方导航'
|
||||||
|
})
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
const hasDebugBuildFlag = () => {
|
||||||
|
if (typeof window === 'undefined') return false
|
||||||
|
|
||||||
|
const searchParams = new URLSearchParams(window.location.search)
|
||||||
|
if (searchParams.get('debug-build') === '1') return true
|
||||||
|
|
||||||
|
const hash = window.location.hash || ''
|
||||||
|
const hashQueryStart = hash.indexOf('?')
|
||||||
|
if (hashQueryStart < 0) return false
|
||||||
|
|
||||||
|
return new URLSearchParams(hash.slice(hashQueryStart + 1)).get('debug-build') === '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolveCurrentChunkFileName = () => {
|
||||||
|
try {
|
||||||
|
const pathname = new URL(import.meta.url).pathname
|
||||||
|
return decodeURIComponent(pathname.split('/').pop() || pathname)
|
||||||
|
} catch {
|
||||||
|
return import.meta.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildDiagnostics = hasDebugBuildFlag()
|
||||||
|
? {
|
||||||
|
buildId: __APP_BUILD_ID__,
|
||||||
|
gitCommit: __APP_GIT_COMMIT__,
|
||||||
|
platform: __APP_BUILD_PLATFORM__,
|
||||||
|
navigationMode,
|
||||||
|
chunkFileName: resolveCurrentChunkFileName(),
|
||||||
|
href: window.location.href,
|
||||||
|
userAgent: window.navigator.userAgent
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
// #endif
|
||||||
|
|
||||||
const activeTypeLabel = computed(() => (
|
const activeTypeLabel = computed(() => (
|
||||||
typeOptions.value.find((option) => option.type === props.activeType)?.label || '来馆'
|
typeOptions.value.find((option) => option.type === props.activeType)?.label || '来馆'
|
||||||
))
|
))
|
||||||
@@ -246,7 +314,8 @@ const startLayoutObserver = () => {
|
|||||||
|
|
||||||
const handleNavigateTap = async () => {
|
const handleNavigateTap = async () => {
|
||||||
if (isOpeningNavigation.value) return
|
if (isOpeningNavigation.value) return
|
||||||
if (!props.selectedTarget) {
|
const selectedTarget = props.selectedTarget
|
||||||
|
if (!selectedTarget) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '请先选择点位',
|
title: '请先选择点位',
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
@@ -254,26 +323,44 @@ const handleNavigateTap = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// H5(含小程序 web-view)统一由用户选择第三方地图。
|
// #ifndef MP-WEIXIN
|
||||||
if (navigationMode === 'third-party-providers') {
|
if (__APP_BUILD_PLATFORM__ !== 'mp-weixin') {
|
||||||
providerSheetVisible.value = true
|
providerSheetVisible.value = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
const target = {
|
// #ifdef MP-WEIXIN
|
||||||
latitude: props.selectedTarget.latitude,
|
const validation = validateWechatOpenLocationTarget({
|
||||||
longitude: props.selectedTarget.longitude,
|
latitude: selectedTarget.latitude,
|
||||||
name: props.selectedTarget.title,
|
longitude: selectedTarget.longitude,
|
||||||
address: props.selectedTarget.subtitle
|
name: selectedTarget.title,
|
||||||
|
address: selectedTarget.subtitle
|
||||||
|
})
|
||||||
|
if (!validation.ok) {
|
||||||
|
uni.showToast({
|
||||||
|
title: validation.message,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
isOpeningNavigation.value = true
|
isOpeningNavigation.value = true
|
||||||
try {
|
try {
|
||||||
await openWechatMiniProgramLocation(target)
|
const result = await openWechatHostLocation(validation.value)
|
||||||
|
if (result.status !== 'opened') {
|
||||||
|
uni.showToast({
|
||||||
|
title: result.reason === 'timeout' ? '微信地图响应超时' : '无法打开微信地图',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
isOpeningNavigation.value = false
|
isOpeningNavigation.value = false
|
||||||
}
|
}
|
||||||
|
// #endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
const handleProviderSelect = (provider: ThirdPartyMapProviderOption) => {
|
const handleProviderSelect = (provider: ThirdPartyMapProviderOption) => {
|
||||||
const target = props.selectedTarget
|
const target = props.selectedTarget
|
||||||
if (!target) return
|
if (!target) return
|
||||||
@@ -283,6 +370,7 @@ const handleProviderSelect = (provider: ThirdPartyMapProviderOption) => {
|
|||||||
region: target.region
|
region: target.region
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.visible,
|
() => props.visible,
|
||||||
@@ -722,4 +810,36 @@ defineExpose({
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #696962;
|
color: #696962;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.arrival-build-diagnostics {
|
||||||
|
position: fixed;
|
||||||
|
top: calc(env(safe-area-inset-top) + 8px);
|
||||||
|
left: 8px;
|
||||||
|
right: 8px;
|
||||||
|
z-index: 9999;
|
||||||
|
max-height: 42vh;
|
||||||
|
padding: 10px 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
overflow: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid rgba(224, 225, 0, 0.75);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: rgba(20, 22, 19, 0.94);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrival-build-diagnostics-title,
|
||||||
|
.arrival-build-diagnostics-line {
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 16px;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrival-build-diagnostics-title {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #e0e100;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
export type ArrivalNavigationMode = 'third-party-providers' | 'native-location'
|
|
||||||
|
|
||||||
export const resolveArrivalNavigationMode = (
|
|
||||||
isNativeWechatMiniProgram: boolean
|
|
||||||
): ArrivalNavigationMode => (
|
|
||||||
isNativeWechatMiniProgram ? 'native-location' : 'third-party-providers'
|
|
||||||
)
|
|
||||||
|
|
||||||
export const getArrivalNavigationActionText = (
|
|
||||||
mode: ArrivalNavigationMode,
|
|
||||||
isOpening: boolean
|
|
||||||
) => {
|
|
||||||
if (isOpening) return '正在打开...'
|
|
||||||
return mode === 'native-location' ? '打开地图导航' : '第三方导航'
|
|
||||||
}
|
|
||||||
6
src/env.d.ts
vendored
6
src/env.d.ts
vendored
@@ -1,7 +1,13 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
declare const __APP_BUILD_ID__: string
|
||||||
|
declare const __APP_GIT_COMMIT__: string
|
||||||
|
declare const __APP_BUILD_PLATFORM__: 'h5' | 'mp-weixin'
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_APP_PUBLIC_BASE?: string
|
readonly VITE_APP_PUBLIC_BASE?: string
|
||||||
|
readonly VITE_APP_BUILD_ID?: string
|
||||||
|
readonly VITE_APP_GIT_COMMIT?: string
|
||||||
readonly VITE_GUIDE_DATA_SOURCE_MODE?: 'static' | 'api' | 'sdk'
|
readonly VITE_GUIDE_DATA_SOURCE_MODE?: 'static' | 'api' | 'sdk'
|
||||||
readonly VITE_EXPLAIN_CONTENT_SOURCE_MODE?: 'static' | 'remote' | 'mock'
|
readonly VITE_EXPLAIN_CONTENT_SOURCE_MODE?: 'static' | 'remote' | 'mock'
|
||||||
readonly VITE_DATA_SOURCE_MODE?: 'static' | 'api' | 'sdk'
|
readonly VITE_DATA_SOURCE_MODE?: 'static' | 'api' | 'sdk'
|
||||||
|
|||||||
@@ -69,7 +69,9 @@
|
|||||||
"navigationBarBackgroundColor": "#FFFFFF",
|
"navigationBarBackgroundColor": "#FFFFFF",
|
||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
,
|
||||||
{
|
{
|
||||||
"path": "pages/open-location/index",
|
"path": "pages/open-location/index",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -77,6 +79,7 @@
|
|||||||
"navigationBarBackgroundColor": "#FFFFFF"
|
"navigationBarBackgroundColor": "#FFFFFF"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// #endif
|
||||||
],
|
],
|
||||||
"globalStyle": {
|
"globalStyle": {
|
||||||
"navigationBarTextStyle": "black",
|
"navigationBarTextStyle": "black",
|
||||||
|
|||||||
@@ -1,14 +1,3 @@
|
|||||||
import { openExternalNavigation } from '@/services/MapNavigationService'
|
|
||||||
import {
|
|
||||||
isEmbeddedInWechatMiniProgram,
|
|
||||||
isNativeWechatMiniProgram
|
|
||||||
} from '@/utils/hostEnvironment'
|
|
||||||
import {
|
|
||||||
buildWechatOpenLocationPageUrl,
|
|
||||||
validateWechatOpenLocationTarget,
|
|
||||||
type WechatOpenLocationTarget
|
|
||||||
} from '@/utils/wechatOpenLocationProtocol'
|
|
||||||
|
|
||||||
export type ThirdPartyMapProvider = 'amap' | 'baidu' | 'tencent'
|
export type ThirdPartyMapProvider = 'amap' | 'baidu' | 'tencent'
|
||||||
|
|
||||||
export interface ThirdPartyMapSearchTarget {
|
export interface ThirdPartyMapSearchTarget {
|
||||||
@@ -16,29 +5,6 @@ export interface ThirdPartyMapSearchTarget {
|
|||||||
region: string
|
region: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WechatMiniProgramLocationTarget = WechatOpenLocationTarget
|
|
||||||
|
|
||||||
interface WechatMiniProgramBridge {
|
|
||||||
getEnv?: (callback: (result: { miniprogram?: boolean }) => void) => void
|
|
||||||
navigateTo?: (options: {
|
|
||||||
url: string
|
|
||||||
success?: () => void
|
|
||||||
fail?: (error: unknown) => void
|
|
||||||
}) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WechatMiniProgramLocationOpenResult =
|
|
||||||
| { status: 'opened' }
|
|
||||||
| { status: 'not-embedded' }
|
|
||||||
| { status: 'failed'; reason: 'invalid-target' | 'bridge-unavailable' | 'not-in-mini-program' | 'navigation-failed' }
|
|
||||||
|
|
||||||
const BRIDGE_WAIT_TIMEOUT = 2500
|
|
||||||
const BRIDGE_POLL_INTERVAL = 50
|
|
||||||
const SDK_SCRIPT_LOAD_TIMEOUT = 10000
|
|
||||||
const GET_ENV_TIMEOUT = 1500
|
|
||||||
const NAVIGATION_TIMEOUT = 3000
|
|
||||||
let miniProgramNavigationPromise: Promise<WechatMiniProgramLocationOpenResult> | null = null
|
|
||||||
|
|
||||||
export interface ThirdPartyMapProviderOption {
|
export interface ThirdPartyMapProviderOption {
|
||||||
provider: ThirdPartyMapProvider
|
provider: ThirdPartyMapProvider
|
||||||
label: string
|
label: string
|
||||||
@@ -89,226 +55,3 @@ export const openThirdPartyMapSearch = (
|
|||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildWechatMiniProgramOpenLocationUrl = (
|
|
||||||
target: WechatMiniProgramLocationTarget
|
|
||||||
) => buildWechatOpenLocationPageUrl(target)
|
|
||||||
|
|
||||||
const getWechatMiniProgramBridge = (): WechatMiniProgramBridge | null => {
|
|
||||||
if (typeof window === 'undefined') return null
|
|
||||||
|
|
||||||
return (window as Window & {
|
|
||||||
wx?: {
|
|
||||||
miniProgram?: WechatMiniProgramBridge
|
|
||||||
}
|
|
||||||
}).wx?.miniProgram || null
|
|
||||||
}
|
|
||||||
|
|
||||||
const ensureWechatJsSdkScript = () => {
|
|
||||||
if (typeof document === 'undefined' || getWechatMiniProgramBridge()) return
|
|
||||||
const existingScript = document.querySelector<HTMLScriptElement>('script[data-wechat-js-sdk="true"]')
|
|
||||||
if (existingScript) {
|
|
||||||
const startedAt = Number(existingScript.dataset.wechatJsSdkStartedAt || 0)
|
|
||||||
const isExpiredLoading = existingScript.dataset.wechatJsSdkState === 'loading'
|
|
||||||
&& Date.now() - startedAt > SDK_SCRIPT_LOAD_TIMEOUT
|
|
||||||
if (existingScript.dataset.wechatJsSdkState !== 'error' && !isExpiredLoading) return
|
|
||||||
existingScript.remove()
|
|
||||||
}
|
|
||||||
|
|
||||||
const script = document.createElement('script')
|
|
||||||
script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js'
|
|
||||||
script.async = true
|
|
||||||
script.dataset.wechatJsSdk = 'true'
|
|
||||||
script.dataset.wechatJsSdkState = 'loading'
|
|
||||||
script.dataset.wechatJsSdkStartedAt = String(Date.now())
|
|
||||||
script.onload = () => {
|
|
||||||
script.dataset.wechatJsSdkState = 'loaded'
|
|
||||||
}
|
|
||||||
script.onerror = () => {
|
|
||||||
script.dataset.wechatJsSdkState = 'error'
|
|
||||||
script.remove()
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
document.head.appendChild(script)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载微信 JS SDK 失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isWechatBrowser = () => (
|
|
||||||
typeof window !== 'undefined'
|
|
||||||
&& /MicroMessenger/i.test(window.navigator?.userAgent || '')
|
|
||||||
)
|
|
||||||
|
|
||||||
const wait = (duration: number) => new Promise<void>((resolve) => {
|
|
||||||
setTimeout(resolve, duration)
|
|
||||||
})
|
|
||||||
|
|
||||||
const waitForWechatMiniProgramBridge = async () => {
|
|
||||||
const immediateBridge = getWechatMiniProgramBridge()
|
|
||||||
if (immediateBridge) return immediateBridge
|
|
||||||
|
|
||||||
ensureWechatJsSdkScript()
|
|
||||||
const startedAt = Date.now()
|
|
||||||
while (Date.now() - startedAt < BRIDGE_WAIT_TIMEOUT) {
|
|
||||||
await wait(BRIDGE_POLL_INTERVAL)
|
|
||||||
const bridge = getWechatMiniProgramBridge()
|
|
||||||
if (bridge) return bridge
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolveMiniProgramWebViewEnvironment = (
|
|
||||||
miniProgram: WechatMiniProgramBridge
|
|
||||||
) => {
|
|
||||||
if (isEmbeddedInWechatMiniProgram()) return Promise.resolve(true)
|
|
||||||
const getEnv = miniProgram.getEnv
|
|
||||||
if (!getEnv) return Promise.resolve(false)
|
|
||||||
|
|
||||||
return new Promise<boolean>((resolve) => {
|
|
||||||
let settled = false
|
|
||||||
const finish = (isMiniProgram: boolean) => {
|
|
||||||
if (settled) return
|
|
||||||
settled = true
|
|
||||||
clearTimeout(timeout)
|
|
||||||
resolve(isMiniProgram)
|
|
||||||
}
|
|
||||||
const timeout = setTimeout(() => finish(isEmbeddedInWechatMiniProgram()), GET_ENV_TIMEOUT)
|
|
||||||
|
|
||||||
try {
|
|
||||||
getEnv((result) => finish(Boolean(result?.miniprogram) || isEmbeddedInWechatMiniProgram()))
|
|
||||||
} catch (error) {
|
|
||||||
console.error('识别小程序 web-view 环境失败:', error)
|
|
||||||
// 保留超时重检,让延迟注入的宿主环境标识仍有机会生效。
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const navigateToMiniProgramLocationPage = (
|
|
||||||
miniProgram: WechatMiniProgramBridge,
|
|
||||||
target: WechatMiniProgramLocationTarget
|
|
||||||
) => new Promise<WechatMiniProgramLocationOpenResult>((resolve) => {
|
|
||||||
let settled = false
|
|
||||||
const finish = (result: WechatMiniProgramLocationOpenResult) => {
|
|
||||||
if (settled) return
|
|
||||||
settled = true
|
|
||||||
clearTimeout(timeout)
|
|
||||||
resolve(result)
|
|
||||||
}
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
uni.showToast({
|
|
||||||
title: '宿主地图页响应超时',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
finish({ status: 'failed', reason: 'navigation-failed' })
|
|
||||||
}, NAVIGATION_TIMEOUT)
|
|
||||||
|
|
||||||
if (!miniProgram.navigateTo) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '宿主地图桥接不可用',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
finish({ status: 'failed', reason: 'bridge-unavailable' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
miniProgram.navigateTo({
|
|
||||||
url: buildWechatMiniProgramOpenLocationUrl(target),
|
|
||||||
success: () => finish({ status: 'opened' }),
|
|
||||||
fail: (error) => {
|
|
||||||
if (settled) return
|
|
||||||
console.error('跳转小程序地图页失败:', error)
|
|
||||||
const errorMessage = typeof error === 'object' && error && 'errMsg' in error
|
|
||||||
? String(error.errMsg)
|
|
||||||
: ''
|
|
||||||
uni.showToast({
|
|
||||||
title: /page.*not found|not found.*page/i.test(errorMessage)
|
|
||||||
? '宿主小程序未配置地图页'
|
|
||||||
: '宿主地图页跳转失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
finish({ status: 'failed', reason: 'navigation-failed' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('调用小程序地图桥接失败:', error)
|
|
||||||
uni.showToast({
|
|
||||||
title: '宿主地图桥接调用失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
finish({ status: 'failed', reason: 'navigation-failed' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const openWechatMiniProgramLocationOnce = async (
|
|
||||||
target: WechatMiniProgramLocationTarget
|
|
||||||
): Promise<WechatMiniProgramLocationOpenResult> => {
|
|
||||||
const validation = validateWechatOpenLocationTarget(target)
|
|
||||||
if (!validation.ok) {
|
|
||||||
uni.showToast({
|
|
||||||
title: validation.message,
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return { status: 'failed', reason: 'invalid-target' }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNativeWechatMiniProgram()) {
|
|
||||||
try {
|
|
||||||
const opened = await openExternalNavigation(validation.value)
|
|
||||||
return opened
|
|
||||||
? { status: 'opened' }
|
|
||||||
: { status: 'failed', reason: 'navigation-failed' }
|
|
||||||
} catch (error) {
|
|
||||||
console.error('原生小程序地图能力调用失败:', error)
|
|
||||||
uni.showToast({
|
|
||||||
title: '无法打开微信地图',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return { status: 'failed', reason: 'navigation-failed' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEmbeddedInWechatMiniProgram() && !isWechatBrowser()) {
|
|
||||||
return { status: 'not-embedded' }
|
|
||||||
}
|
|
||||||
|
|
||||||
const miniProgram = await waitForWechatMiniProgramBridge()
|
|
||||||
if (!miniProgram?.navigateTo) {
|
|
||||||
if (isEmbeddedInWechatMiniProgram()) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '小程序地图桥接加载失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return { status: 'failed', reason: 'bridge-unavailable' }
|
|
||||||
}
|
|
||||||
return { status: 'not-embedded' }
|
|
||||||
}
|
|
||||||
|
|
||||||
const isMiniProgramWebView = await resolveMiniProgramWebViewEnvironment(miniProgram)
|
|
||||||
if (!isMiniProgramWebView) {
|
|
||||||
if (isEmbeddedInWechatMiniProgram()) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '当前页面未连接宿主小程序',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return { status: 'failed', reason: 'not-in-mini-program' }
|
|
||||||
}
|
|
||||||
return { status: 'not-embedded' }
|
|
||||||
}
|
|
||||||
|
|
||||||
return navigateToMiniProgramLocationPage(miniProgram, validation.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const openWechatMiniProgramLocation = (
|
|
||||||
target: WechatMiniProgramLocationTarget
|
|
||||||
) => {
|
|
||||||
if (miniProgramNavigationPromise) return miniProgramNavigationPromise
|
|
||||||
|
|
||||||
miniProgramNavigationPromise = openWechatMiniProgramLocationOnce(target)
|
|
||||||
.finally(() => {
|
|
||||||
miniProgramNavigationPromise = null
|
|
||||||
})
|
|
||||||
return miniProgramNavigationPromise
|
|
||||||
}
|
|
||||||
|
|||||||
87
tests/unit/ArrivalPanel.spec.ts
Normal file
87
tests/unit/ArrivalPanel.spec.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// @vitest-environment happy-dom
|
||||||
|
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import ArrivalPanel from '@/components/navigation/ArrivalPanel.vue'
|
||||||
|
import { ARRIVAL_TARGETS } from '@/data/arrivalSearchTargets'
|
||||||
|
|
||||||
|
const selectedTarget = ARRIVAL_TARGETS[0]
|
||||||
|
const defaultUserAgent = window.navigator.userAgent
|
||||||
|
|
||||||
|
const mountArrivalPanel = () => mount(ArrivalPanel, {
|
||||||
|
props: {
|
||||||
|
visible: true,
|
||||||
|
activeType: 'bus',
|
||||||
|
targets: [selectedTarget],
|
||||||
|
selectedTargetId: selectedTarget.id,
|
||||||
|
selectedTarget
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
window.history.replaceState({}, '', '/#/pages/index/index?tab=guide')
|
||||||
|
Object.defineProperty(window.navigator, 'userAgent', {
|
||||||
|
configurable: true,
|
||||||
|
value: 'Mozilla/5.0 MicroMessenger/8.0.50 miniProgram'
|
||||||
|
})
|
||||||
|
Object.assign(window, {
|
||||||
|
__wxjs_environment: 'miniprogram',
|
||||||
|
wx: {
|
||||||
|
miniProgram: {
|
||||||
|
navigateTo: vi.fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
vi.stubGlobal('uni', {
|
||||||
|
showToast: vi.fn()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
Object.defineProperty(window.navigator, 'userAgent', {
|
||||||
|
configurable: true,
|
||||||
|
value: defaultUserAgent
|
||||||
|
})
|
||||||
|
delete (window as Window & { __wxjs_environment?: string }).__wxjs_environment
|
||||||
|
delete (window as Window & { wx?: unknown }).wx
|
||||||
|
vi.unstubAllGlobals()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('来馆面板 H5 实际渲染', () => {
|
||||||
|
it('主按钮显示第三方导航,点击后展示三家地图选择层', async () => {
|
||||||
|
const wrapper = mountArrivalPanel()
|
||||||
|
const navigateTo = (
|
||||||
|
window as Window & {
|
||||||
|
wx?: { miniProgram?: { navigateTo?: ReturnType<typeof vi.fn> } }
|
||||||
|
}
|
||||||
|
).wx?.miniProgram?.navigateTo
|
||||||
|
|
||||||
|
expect(wrapper.get('.arrival-primary-text').text()).toBe('第三方导航')
|
||||||
|
expect(wrapper.text()).not.toContain('打开地图导航')
|
||||||
|
await wrapper.get('.arrival-primary').trigger('tap')
|
||||||
|
|
||||||
|
expect(wrapper.find('.provider-sheet').exists()).toBe(true)
|
||||||
|
expect(wrapper.findAll('.provider-row')).toHaveLength(3)
|
||||||
|
expect(wrapper.text()).toContain('高德地图')
|
||||||
|
expect(wrapper.text()).toContain('百度地图')
|
||||||
|
expect(wrapper.text()).toContain('腾讯地图')
|
||||||
|
expect(navigateTo).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('诊断信息默认隐藏,仅在 debug-build=1 时显示 H5 构建边界', () => {
|
||||||
|
const normalWrapper = mountArrivalPanel()
|
||||||
|
expect(normalWrapper.find('[data-testid="arrival-build-diagnostics"]').exists()).toBe(false)
|
||||||
|
normalWrapper.unmount()
|
||||||
|
|
||||||
|
window.location.hash = '#/pages/index/index?tab=guide&debug-build=1'
|
||||||
|
const debugWrapper = mountArrivalPanel()
|
||||||
|
const diagnostics = debugWrapper.get('[data-testid="arrival-build-diagnostics"]')
|
||||||
|
|
||||||
|
expect(diagnostics.text()).toContain('构建 ID:test-build')
|
||||||
|
expect(diagnostics.text()).toContain('Git commit:test-commit')
|
||||||
|
expect(diagnostics.text()).toContain('构建平台:h5')
|
||||||
|
expect(diagnostics.text()).toContain('navigationMode:third-party-providers')
|
||||||
|
expect(diagnostics.text()).toContain('location.href:')
|
||||||
|
expect(diagnostics.text()).toContain('UA:')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,230 +1,59 @@
|
|||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
vi.mock('@/utils/hostEnvironment', async (importOriginal) => {
|
|
||||||
const actual = await importOriginal<typeof import('@/utils/hostEnvironment')>()
|
|
||||||
return {
|
|
||||||
...actual,
|
|
||||||
isNativeWechatMiniProgram: () => false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
buildThirdPartyMapSearchUri,
|
buildThirdPartyMapSearchUri,
|
||||||
openWechatMiniProgramLocation
|
openThirdPartyMapSearch
|
||||||
} from '@/services/ThirdPartyMapSearchService'
|
} from '@/services/ThirdPartyMapSearchService'
|
||||||
|
|
||||||
const target = {
|
|
||||||
latitude: 22.604321,
|
|
||||||
longitude: 114.058765,
|
|
||||||
name: '深圳自然博物馆',
|
|
||||||
address: '深圳市龙华区民治街道'
|
|
||||||
}
|
|
||||||
|
|
||||||
const createWindow = (overrides: Record<string, unknown> = {}) => ({
|
|
||||||
location: { search: '', hash: '' },
|
|
||||||
navigator: { userAgent: 'Mozilla/5.0 MicroMessenger/8.0.50' },
|
|
||||||
...overrides
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
vi.useFakeTimers()
|
|
||||||
vi.stubGlobal('document', undefined)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.useRealTimers()
|
|
||||||
vi.unstubAllGlobals()
|
vi.unstubAllGlobals()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('微信小程序 web-view 地图桥接', () => {
|
describe('H5 第三方地图服务', () => {
|
||||||
it('桥接延迟注入时快速调用两次也只跳转一次', async () => {
|
it('安全编码中文、空格和特殊字符', () => {
|
||||||
const navigateTo = vi.fn((options: { success?: () => void }) => options.success?.())
|
const uri = buildThirdPartyMapSearchUri('amap', {
|
||||||
const testWindow = createWindow()
|
keyword: '深圳自然博物馆 A&B',
|
||||||
vi.stubGlobal('window', testWindow)
|
region: '深圳 市'
|
||||||
vi.stubGlobal('uni', { showToast: vi.fn() })
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
Object.assign(testWindow, {
|
|
||||||
__wxjs_environment: 'miniprogram',
|
|
||||||
wx: { miniProgram: { navigateTo } }
|
|
||||||
})
|
|
||||||
}, 100)
|
|
||||||
|
|
||||||
const first = openWechatMiniProgramLocation(target)
|
|
||||||
const second = openWechatMiniProgramLocation(target)
|
|
||||||
await vi.advanceTimersByTimeAsync(150)
|
|
||||||
|
|
||||||
await expect(first).resolves.toEqual({ status: 'opened' })
|
|
||||||
await expect(second).resolves.toEqual({ status: 'opened' })
|
|
||||||
expect(navigateTo).toHaveBeenCalledTimes(1)
|
|
||||||
|
|
||||||
const url = navigateTo.mock.calls[0]?.[0].url
|
|
||||||
const params = new URLSearchParams(url.split('?')[1])
|
|
||||||
expect(Object.fromEntries(params)).toEqual({
|
|
||||||
latitude: String(target.latitude),
|
|
||||||
longitude: String(target.longitude),
|
|
||||||
name: target.name,
|
|
||||||
address: target.address
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('普通浏览器返回 H5 分支并保留第三方地图 URI', async () => {
|
expect(uri).toContain('keyword=%E6%B7%B1%E5%9C%B3%E8%87%AA%E7%84%B6%E5%8D%9A%E7%89%A9%E9%A6%86%20A%26B')
|
||||||
const showToast = vi.fn()
|
expect(uri).toContain('city=%E6%B7%B1%E5%9C%B3%20%E5%B8%82')
|
||||||
vi.stubGlobal('window', createWindow({
|
})
|
||||||
navigator: { userAgent: 'Mozilla/5.0 Chrome/126.0' }
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
|
||||||
|
|
||||||
await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({ status: 'not-embedded' })
|
it.each([
|
||||||
expect(showToast).not.toHaveBeenCalled()
|
['amap', 'https://uri.amap.com/search?'],
|
||||||
expect(buildThirdPartyMapSearchUri('amap', {
|
['baidu', 'https://api.map.baidu.com/place/search?'],
|
||||||
|
['tencent', 'https://apis.map.qq.com/uri/v1/search?']
|
||||||
|
] as const)('%s 使用对应的地图网页入口', (provider, expectedPrefix) => {
|
||||||
|
expect(buildThirdPartyMapSearchUri(provider, {
|
||||||
keyword: '深圳自然博物馆',
|
keyword: '深圳自然博物馆',
|
||||||
region: '深圳市'
|
region: '深圳市'
|
||||||
})).toContain('https://uri.amap.com/search?')
|
})).toMatch(expectedPrefix)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('显式宿主环境缺少桥接时显示错误提示', async () => {
|
it('浏览器中直接跳转到选中的第三方地图', () => {
|
||||||
|
const location = { href: 'https://guide.example.com/' }
|
||||||
|
vi.stubGlobal('window', { location })
|
||||||
|
|
||||||
|
openThirdPartyMapSearch('tencent', {
|
||||||
|
keyword: '深圳自然博物馆',
|
||||||
|
region: '深圳市'
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(location.href).toContain('https://apis.map.qq.com/uri/v1/search?')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('缺少浏览器环境时提供可见提示', () => {
|
||||||
const showToast = vi.fn()
|
const showToast = vi.fn()
|
||||||
vi.stubGlobal('window', createWindow({
|
vi.stubGlobal('window', undefined)
|
||||||
location: { search: '?embedded=weapp', hash: '' }
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
vi.stubGlobal('uni', { showToast })
|
||||||
|
|
||||||
const result = openWechatMiniProgramLocation(target)
|
openThirdPartyMapSearch('baidu', {
|
||||||
await vi.advanceTimersByTimeAsync(2600)
|
keyword: '深圳自然博物馆',
|
||||||
|
region: '深圳市'
|
||||||
|
})
|
||||||
|
|
||||||
await expect(result).resolves.toEqual({ status: 'failed', reason: 'bridge-unavailable' })
|
|
||||||
expect(showToast).toHaveBeenCalledWith({
|
expect(showToast).toHaveBeenCalledWith({
|
||||||
title: '小程序地图桥接加载失败',
|
title: '请在 H5 浏览器中打开地图',
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('微信 SDK 首次加载失败后再次点击会重新创建脚本', async () => {
|
|
||||||
const showToast = vi.fn()
|
|
||||||
let currentScript: Record<string, unknown> | null = null
|
|
||||||
const appendChild = vi.fn((script: Record<string, unknown>) => {
|
|
||||||
currentScript = script
|
|
||||||
setTimeout(() => (script.onerror as (() => void) | undefined)?.(), 0)
|
|
||||||
})
|
|
||||||
vi.stubGlobal('window', createWindow({
|
|
||||||
location: { search: '?embedded=weapp', hash: '' }
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('document', {
|
|
||||||
querySelector: () => currentScript,
|
|
||||||
createElement: () => {
|
|
||||||
const script: Record<string, unknown> = { dataset: {} }
|
|
||||||
script.remove = () => {
|
|
||||||
if (currentScript === script) currentScript = null
|
|
||||||
}
|
|
||||||
return script
|
|
||||||
},
|
|
||||||
head: { appendChild }
|
|
||||||
})
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
|
||||||
|
|
||||||
const first = openWechatMiniProgramLocation(target)
|
|
||||||
await vi.advanceTimersByTimeAsync(2600)
|
|
||||||
await expect(first).resolves.toEqual({ status: 'failed', reason: 'bridge-unavailable' })
|
|
||||||
|
|
||||||
const second = openWechatMiniProgramLocation(target)
|
|
||||||
await vi.advanceTimersByTimeAsync(2600)
|
|
||||||
await expect(second).resolves.toEqual({ status: 'failed', reason: 'bridge-unavailable' })
|
|
||||||
expect(appendChild).toHaveBeenCalledTimes(2)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('宿主页跳转失败时给出缺页提示', async () => {
|
|
||||||
const showToast = vi.fn()
|
|
||||||
const navigateTo = vi.fn((options: { fail?: (error: unknown) => void }) => {
|
|
||||||
options.fail?.({ errMsg: 'navigateTo:fail page not found' })
|
|
||||||
})
|
|
||||||
vi.stubGlobal('window', createWindow({
|
|
||||||
location: { search: '?embedded=weapp', hash: '' },
|
|
||||||
wx: { miniProgram: { navigateTo } }
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
|
||||||
|
|
||||||
await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({
|
|
||||||
status: 'failed',
|
|
||||||
reason: 'navigation-failed'
|
|
||||||
})
|
|
||||||
expect(showToast).toHaveBeenCalledWith({
|
|
||||||
title: '宿主小程序未配置地图页',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('宿主页没有回调时超时返回并显示提示', async () => {
|
|
||||||
const showToast = vi.fn()
|
|
||||||
let navigateOptions: { fail?: (error: unknown) => void } | undefined
|
|
||||||
vi.stubGlobal('window', createWindow({
|
|
||||||
location: { search: '?embedded=weapp', hash: '' },
|
|
||||||
wx: {
|
|
||||||
miniProgram: {
|
|
||||||
navigateTo: vi.fn((options: { fail?: (error: unknown) => void }) => {
|
|
||||||
navigateOptions = options
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
|
||||||
|
|
||||||
const result = openWechatMiniProgramLocation(target)
|
|
||||||
await vi.advanceTimersByTimeAsync(3100)
|
|
||||||
|
|
||||||
await expect(result).resolves.toEqual({ status: 'failed', reason: 'navigation-failed' })
|
|
||||||
expect(showToast).toHaveBeenCalledWith({
|
|
||||||
title: '宿主地图页响应超时',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
navigateOptions?.fail?.({ errMsg: 'navigateTo:fail page not found' })
|
|
||||||
expect(showToast).toHaveBeenCalledTimes(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('非缺页类宿主跳转失败使用通用提示', async () => {
|
|
||||||
const showToast = vi.fn()
|
|
||||||
vi.stubGlobal('window', createWindow({
|
|
||||||
location: { search: '?embedded=weapp', hash: '' },
|
|
||||||
wx: {
|
|
||||||
miniProgram: {
|
|
||||||
navigateTo: vi.fn((options: { fail?: (error: unknown) => void }) => {
|
|
||||||
options.fail?.({ errMsg: 'navigateTo:fail page stack full' })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
|
||||||
|
|
||||||
await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({
|
|
||||||
status: 'failed',
|
|
||||||
reason: 'navigation-failed'
|
|
||||||
})
|
|
||||||
expect(showToast).toHaveBeenCalledWith({
|
|
||||||
title: '宿主地图页跳转失败',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('宿主桥接同步抛错时显示调用失败提示', async () => {
|
|
||||||
const showToast = vi.fn()
|
|
||||||
vi.stubGlobal('window', createWindow({
|
|
||||||
location: { search: '?embedded=weapp', hash: '' },
|
|
||||||
wx: {
|
|
||||||
miniProgram: {
|
|
||||||
navigateTo: vi.fn(() => {
|
|
||||||
throw new Error('bridge unavailable')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
vi.stubGlobal('uni', { showToast })
|
|
||||||
|
|
||||||
await expect(openWechatMiniProgramLocation(target)).resolves.toEqual({
|
|
||||||
status: 'failed',
|
|
||||||
reason: 'navigation-failed'
|
|
||||||
})
|
|
||||||
expect(showToast).toHaveBeenCalledWith({
|
|
||||||
title: '宿主地图桥接调用失败',
|
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import { describe, expect, it } from 'vitest'
|
|
||||||
import {
|
|
||||||
getArrivalNavigationActionText,
|
|
||||||
resolveArrivalNavigationMode
|
|
||||||
} from '@/components/navigation/arrivalNavigationPolicy'
|
|
||||||
|
|
||||||
describe('来馆导航入口策略', () => {
|
|
||||||
it('普通 H5 与小程序 web-view 都使用第三方地图选择层', () => {
|
|
||||||
const mode = resolveArrivalNavigationMode(false)
|
|
||||||
|
|
||||||
expect(mode).toBe('third-party-providers')
|
|
||||||
expect(getArrivalNavigationActionText(mode, false)).toBe('第三方导航')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('只有原生微信小程序使用微信位置能力', () => {
|
|
||||||
const mode = resolveArrivalNavigationMode(true)
|
|
||||||
|
|
||||||
expect(mode).toBe('native-location')
|
|
||||||
expect(getArrivalNavigationActionText(mode, false)).toBe('打开地图导航')
|
|
||||||
expect(getArrivalNavigationActionText(mode, true)).toBe('正在打开...')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { execFileSync } from 'node:child_process'
|
||||||
import { defineConfig, loadEnv } from 'vite'
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
import uni from '@dcloudio/vite-plugin-uni'
|
import uni from '@dcloudio/vite-plugin-uni'
|
||||||
|
|
||||||
@@ -6,8 +7,28 @@ const normalizeEnvUrl = (value: string | undefined, fallback: string) => {
|
|||||||
return normalized || fallback
|
return normalized || fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resolveGitCommit = () => {
|
||||||
|
try {
|
||||||
|
return execFileSync('git', ['rev-parse', '--short=12', 'HEAD'], {
|
||||||
|
encoding: 'utf8'
|
||||||
|
}).trim()
|
||||||
|
} catch {
|
||||||
|
return 'unknown'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createBuildTimestamp = () => (
|
||||||
|
new Date().toISOString().replace(/[-:.TZ]/g, '').slice(0, 14)
|
||||||
|
)
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
const env = loadEnv(mode, process.cwd(), '')
|
const env = loadEnv(mode, process.cwd(), '')
|
||||||
|
const gitCommit = normalizeEnvUrl(env.VITE_APP_GIT_COMMIT, resolveGitCommit())
|
||||||
|
const buildId = normalizeEnvUrl(
|
||||||
|
env.VITE_APP_BUILD_ID,
|
||||||
|
`${gitCommit}-${createBuildTimestamp()}`
|
||||||
|
)
|
||||||
|
const buildPlatform = process.env.UNI_PLATFORM === 'mp-weixin' ? 'mp-weixin' : 'h5'
|
||||||
const appApiProxyTarget = normalizeEnvUrl(env.DEV_PROXY_APP_API_TARGET, 'http://localhost:3001')
|
const appApiProxyTarget = normalizeEnvUrl(env.DEV_PROXY_APP_API_TARGET, 'http://localhost:3001')
|
||||||
const h5SdkProxyTarget = normalizeEnvUrl(env.DEV_PROXY_H5_SDK_TARGET, appApiProxyTarget)
|
const h5SdkProxyTarget = normalizeEnvUrl(env.DEV_PROXY_H5_SDK_TARGET, appApiProxyTarget)
|
||||||
const sdkProxyTarget = normalizeEnvUrl(env.DEV_PROXY_SDK_TARGET, appApiProxyTarget)
|
const sdkProxyTarget = normalizeEnvUrl(env.DEV_PROXY_SDK_TARGET, appApiProxyTarget)
|
||||||
@@ -18,6 +39,11 @@ export default defineConfig(({ mode }) => {
|
|||||||
return {
|
return {
|
||||||
base: normalizeEnvUrl(env.VITE_APP_PUBLIC_BASE, '/'),
|
base: normalizeEnvUrl(env.VITE_APP_PUBLIC_BASE, '/'),
|
||||||
plugins: [uni()],
|
plugins: [uni()],
|
||||||
|
define: {
|
||||||
|
__APP_BUILD_ID__: JSON.stringify(buildId),
|
||||||
|
__APP_GIT_COMMIT__: JSON.stringify(gitCommit),
|
||||||
|
__APP_BUILD_PLATFORM__: JSON.stringify(buildPlatform)
|
||||||
|
},
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
proxy: {
|
proxy: {
|
||||||
|
|||||||
@@ -1,7 +1,22 @@
|
|||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
import { defineConfig } from 'vitest/config'
|
import { defineConfig } from 'vitest/config'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
plugins: [
|
||||||
|
vue({
|
||||||
|
template: {
|
||||||
|
compilerOptions: {
|
||||||
|
isCustomElement: (tag) => ['view', 'text', 'scroll-view'].includes(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
define: {
|
||||||
|
__APP_BUILD_ID__: JSON.stringify('test-build'),
|
||||||
|
__APP_GIT_COMMIT__: JSON.stringify('test-commit'),
|
||||||
|
__APP_BUILD_PLATFORM__: JSON.stringify('h5')
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||||
|
|||||||
Reference in New Issue
Block a user