接口调试

This commit is contained in:
speakeloudest 2025-12-30 01:25:08 -08:00
parent 11c05de565
commit de6dfb5e20
15 changed files with 468 additions and 85 deletions

1
.env.dev Normal file
View File

@ -0,0 +1 @@
VITE_APP_BASE_URL=https://api.hifast.biz/v1

1
.env.prod Normal file
View File

@ -0,0 +1 @@
VITE_APP_BASE_URL=

1
.env.test Normal file
View File

@ -0,0 +1 @@
VITE_APP_BASE_URL=

View File

@ -18,6 +18,21 @@ export default defineConfigWithVueTs(
...pluginVue.configs['flat/essential'], ...pluginVue.configs['flat/essential'],
vueTsConfigs.recommended, vueTsConfigs.recommended,
{
rules: {
// 1. 强制 Vue 文件内标签块的顺序
'vue/block-order': [
'error',
{
order: ['template', 'script', 'style'],
},
],
// 2. 自动关闭单单词组件名检查(根据需要可选)
'vue/multi-word-component-names': 'off',
// 3. 可以在这里添加更多 TypeScript 或 Vue 的自定义校验
'@typescript-eslint/no-explicit-any': 'warn',
},
},
skipFormatting, skipFormatting,
) )

View File

@ -7,10 +7,10 @@
"node": "^20.19.0 || >=22.12.0" "node": "^20.19.0 || >=22.12.0"
}, },
"scripts": { "scripts": {
"dev": "vite", "dev": "vite --mode dev",
"build": "run-p type-check \"build-only {@}\" --", "build:test": "vite build --mode test",
"build:prod": "vite build --mode pord",
"preview": "vite preview", "preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build", "type-check": "vue-tsc --build",
"lint": "eslint . --fix --cache", "lint": "eslint . --fix --cache",
"format": "prettier --write --experimental-cli src/" "format": "prettier --write --experimental-cli src/"
@ -18,8 +18,10 @@
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"@vueuse/core": "^14.1.0", "@vueuse/core": "^14.1.0",
"axios": "^1.13.2",
"class-variance-authority": "^0.7.1", "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"lucide-vue-next": "^0.562.0", "lucide-vue-next": "^0.562.0",
"reka-ui": "^2.7.0", "reka-ui": "^2.7.0",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",

198
pnpm-lock.yaml generated
View File

@ -14,12 +14,18 @@ importers:
'@vueuse/core': '@vueuse/core':
specifier: ^14.1.0 specifier: ^14.1.0
version: 14.1.0(vue@3.5.26(typescript@5.9.3)) version: 14.1.0(vue@3.5.26(typescript@5.9.3))
axios:
specifier: ^1.13.2
version: 1.13.2
class-variance-authority: class-variance-authority:
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1 version: 0.7.1
clsx: clsx:
specifier: ^2.1.1 specifier: ^2.1.1
version: 2.1.1 version: 2.1.1
crypto-js:
specifier: ^4.2.0
version: 4.2.0
lucide-vue-next: lucide-vue-next:
specifier: ^0.562.0 specifier: ^0.562.0
version: 0.562.0(vue@3.5.26(typescript@5.9.3)) version: 0.562.0(vue@3.5.26(typescript@5.9.3))
@ -957,6 +963,12 @@ packages:
resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
engines: {node: '>=10'} engines: {node: '>=10'}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
axios@1.13.2:
resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==}
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@ -989,6 +1001,10 @@ packages:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
engines: {node: '>=18'} engines: {node: '>=18'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
callsites@3.1.0: callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1014,6 +1030,10 @@ packages:
color-name@1.1.4: color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@7.2.0: commander@7.2.0:
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
@ -1032,6 +1052,9 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
css-select@5.2.2: css-select@5.2.2:
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
@ -1086,6 +1109,10 @@ packages:
defu@6.1.4: defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
detect-libc@2.1.2: detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -1103,6 +1130,10 @@ packages:
domutils@3.2.2: domutils@3.2.2:
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
electron-to-chromium@1.5.267: electron-to-chromium@1.5.267:
resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==}
@ -1121,6 +1152,22 @@ packages:
error-stack-parser-es@1.0.5: error-stack-parser-es@1.0.5:
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.1:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
esbuild@0.27.2: esbuild@0.27.2:
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -1260,15 +1307,39 @@ packages:
flatted@3.3.3: flatted@3.3.3:
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
follow-redirects@1.15.11:
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
fsevents@2.3.3: fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin] os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
gensync@1.0.0-beta.2: gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
glob-parent@5.1.2: glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -1281,6 +1352,10 @@ packages:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@ -1288,6 +1363,18 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
hookable@5.5.3: hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
@ -1476,6 +1563,10 @@ packages:
magic-string@0.30.21: magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
mdn-data@2.0.28: mdn-data@2.0.28:
resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
@ -1494,6 +1585,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
minimatch@3.1.2: minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@ -1674,6 +1773,9 @@ packages:
engines: {node: '>=14'} engines: {node: '>=14'}
hasBin: true hasBin: true
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
punycode@2.3.1: punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -2862,6 +2964,16 @@ snapshots:
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
asynckit@0.4.0: {}
axios@1.13.2:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.5
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
baseline-browser-mapping@2.9.11: {} baseline-browser-mapping@2.9.11: {}
@ -2895,6 +3007,11 @@ snapshots:
dependencies: dependencies:
run-applescript: 7.1.0 run-applescript: 7.1.0
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
callsites@3.1.0: {} callsites@3.1.0: {}
caniuse-lite@1.0.30001761: {} caniuse-lite@1.0.30001761: {}
@ -2916,6 +3033,10 @@ snapshots:
color-name@1.1.4: {} color-name@1.1.4: {}
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@7.2.0: {} commander@7.2.0: {}
concat-map@0.0.1: {} concat-map@0.0.1: {}
@ -2932,6 +3053,8 @@ snapshots:
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
crypto-js@4.2.0: {}
css-select@5.2.2: css-select@5.2.2:
dependencies: dependencies:
boolbase: 1.0.0 boolbase: 1.0.0
@ -2977,6 +3100,8 @@ snapshots:
defu@6.1.4: {} defu@6.1.4: {}
delayed-stream@1.0.0: {}
detect-libc@2.1.2: {} detect-libc@2.1.2: {}
dom-serializer@2.0.0: dom-serializer@2.0.0:
@ -2997,6 +3122,12 @@ snapshots:
domelementtype: 2.3.0 domelementtype: 2.3.0
domhandler: 5.0.3 domhandler: 5.0.3
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
electron-to-chromium@1.5.267: {} electron-to-chromium@1.5.267: {}
enhanced-resolve@5.18.4: enhanced-resolve@5.18.4:
@ -3010,6 +3141,21 @@ snapshots:
error-stack-parser-es@1.0.5: {} error-stack-parser-es@1.0.5: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.1:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.2
esbuild@0.27.2: esbuild@0.27.2:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.27.2 '@esbuild/aix-ppc64': 0.27.2
@ -3183,11 +3329,41 @@ snapshots:
flatted@3.3.3: {} flatted@3.3.3: {}
follow-redirects@1.15.11: {}
form-data@4.0.5:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.2
mime-types: 2.1.35
fsevents@2.3.3: fsevents@2.3.3:
optional: true optional: true
function-bind@1.1.2: {}
gensync@1.0.0-beta.2: {} gensync@1.0.0-beta.2: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.1
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.2
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.1
glob-parent@5.1.2: glob-parent@5.1.2:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
@ -3198,10 +3374,22 @@ snapshots:
globals@14.0.0: {} globals@14.0.0: {}
gopd@1.2.0: {}
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
has-flag@4.0.0: {} has-flag@4.0.0: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.2:
dependencies:
function-bind: 1.1.2
hookable@5.5.3: {} hookable@5.5.3: {}
ignore@5.3.2: {} ignore@5.3.2: {}
@ -3337,6 +3525,8 @@ snapshots:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
math-intrinsics@1.1.0: {}
mdn-data@2.0.28: {} mdn-data@2.0.28: {}
mdn-data@2.0.30: {} mdn-data@2.0.30: {}
@ -3350,6 +3540,12 @@ snapshots:
braces: 3.0.3 braces: 3.0.3
picomatch: 2.3.1 picomatch: 2.3.1
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
minimatch@3.1.2: minimatch@3.1.2:
dependencies: dependencies:
brace-expansion: 1.1.12 brace-expansion: 1.1.12
@ -3462,6 +3658,8 @@ snapshots:
prettier@3.7.4: {} prettier@3.7.4: {}
proxy-from-env@1.1.0: {}
punycode@2.3.1: {} punycode@2.3.1: {}
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}

View File

@ -7,7 +7,7 @@ import ArrowIcon from './arrow-icon2.svg?component'
const faqList = ref([ const faqList = ref([
{ {
id: 1, id: 1,
question: '登公共 Apple ID 时,出现“双重验证”提示,且要求输入验证码怎么办?', question: '登公共 Apple ID 时,出现“双重验证”提示,且要求输入验证码怎么办?',
answer: answer:
'这是由于有其他用户没有按照教程操作,将公共 Apple ID 绑定手机号码,开启了双重验证所导致。\n\n解决办法请您先清除浏览器缓存再刷新本页面获取新的公共 Apple ID接着请按照教程一步一步操作。', '这是由于有其他用户没有按照教程操作,将公共 Apple ID 绑定手机号码,开启了双重验证所导致。\n\n解决办法请您先清除浏览器缓存再刷新本页面获取新的公共 Apple ID接着请按照教程一步一步操作。',
}, },

View File

@ -52,7 +52,7 @@
</div> </div>
<div v-show="activeIndex === 1"> <div v-show="activeIndex === 1">
<div class="pt-[34px] pb-[15px] text-center font-[900]"> <div class="pt-[34px] pb-[15px] text-center font-[900]">
海外 Apple ID 后再点击下方下载按钮 海外 Apple ID 后再点击下方下载按钮
</div> </div>
</div> </div>
<!-- tab2 --> <!-- tab2 -->

View File

@ -0,0 +1,62 @@
<template>
<Teleport to="body">
<Transition name="fade">
<div
v-if="visible"
class="!pointer-events-auto fixed inset-0 z-[100] flex items-center justify-center p-4"
>
<div
class="backdrop-blur-[2px z-[110]] absolute inset-0 bg-black/40"
@click.stop="hide"
></div>
<div
class="relative z-10 w-full max-w-[280px] rounded-[40px] border border-white/10 bg-[#999999] p-8 shadow-2xl"
@click.stop
>
<div class="space-y-2 text-black">
<h3 class="flex items-start text-lg font-black"><span class="mr-1">*</span>重要提示</h3>
<p class="text-[15px] leading-relaxed font-bold tracking-tight">
验证邮件已发送至邮箱如无法找到请检查垃圾邮件箱或营销邮件箱
</p>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<script setup lang="ts">
import { ref, onBeforeUnmount } from 'vue'
const visible = ref(false)
const timer: ReturnType<typeof setTimeout> | null = null
const show = () => {
visible.value = true
}
const hide = () => {
console.log('hide')
visible.value = false
}
//
onBeforeUnmount(() => {
if (timer) clearTimeout(timer)
})
defineExpose({ show, hide })
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: scale(0.95);
}
</style>

View File

@ -1,31 +1,3 @@
<script setup lang="ts">
import { ref } from 'vue'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { toast } from 'vue-sonner'
const email = ref('')
const code = ref('')
const countdown = ref(0)
const handleGetCode = () => {
if (!email.value) {
toast('请输入邮箱')
return
}
//
countdown.value = 60
const timer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) clearInterval(timer)
}, 1000)
}
const handleLogin = () => {
console.log('登录提交', { email: email.value, code: code.value })
}
</script>
<template> <template>
<div class="flex flex-col gap-6 text-black"> <div class="flex flex-col gap-6 text-black">
<div class="overflow-hidden rounded-[20px] bg-[#78788029] px-4"> <div class="overflow-hidden rounded-[20px] bg-[#78788029] px-4">
@ -62,6 +34,7 @@ const handleLogin = () => {
<div class="flex gap-4 pt-2"> <div class="flex gap-4 pt-2">
<Button <Button
variant="secondary" variant="secondary"
@click="emit('close')"
class="h-[48px] flex-1 cursor-pointer rounded-[25px] bg-[#D1D1D1] text-lg font-medium text-[#757575] hover:bg-[#C1C1C1]" class="h-[48px] flex-1 cursor-pointer rounded-[25px] bg-[#D1D1D1] text-lg font-medium text-[#757575] hover:bg-[#C1C1C1]"
> >
取消 取消
@ -70,12 +43,44 @@ const handleLogin = () => {
@click="handleLogin" @click="handleLogin"
class="h-[48px] flex-1 cursor-pointer rounded-[25px] bg-[#A8FF53] text-lg font-medium text-black hover:bg-[#96E64A]" class="h-[48px] flex-1 cursor-pointer rounded-[25px] bg-[#A8FF53] text-lg font-medium text-black hover:bg-[#96E64A]"
> >
/注册 /注册
</Button> </Button>
</div> </div>
<CodeSentTip ref="CodeSentTipRef" />
</div> </div>
</template> </template>
<script setup lang="ts">
import { ref } from 'vue'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { toast } from 'vue-sonner'
import CodeSentTip from '@/pages/Home/components/CodeSentTip.vue'
const CodeSentTipRef = ref(null)
const email = ref('')
const code = ref('')
const countdown = ref(0)
const emit = defineEmits(['close'])
const handleGetCode = () => {
if (!email.value) {
toast('请输入邮箱')
return
}
CodeSentTipRef.value.show()
//
countdown.value = 60
const timer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) clearInterval(timer)
}, 1000)
}
const handleLogin = () => {
console.log('登录提交', { email: email.value, code: code.value })
}
</script>
<style scoped> <style scoped>
/* 移除 Shadcn Input 的默认边框阴影,保持纯净感 */ /* 移除 Shadcn Input 的默认边框阴影,保持纯净感 */
input:focus { input:focus {

View File

@ -7,12 +7,12 @@
:showCloseButton="false" :showCloseButton="false"
> >
<DialogHeader class="py-2 pl-2"> <DialogHeader class="py-2 pl-2">
<DialogTitle class="text-left">Hi快帐户</DialogTitle> <DialogTitle class="text-left">Hi快帐户</DialogTitle>
<DialogDescription class="text-left text-base text-black"> <DialogDescription class="text-left text-base text-black">
如使用新邮箱地址将自动为您创建Hi快帐户 如使用新邮箱地址将自动为您创建Hi快帐户
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<LoginForm /> <LoginForm @close="isOpen = false" />
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</template> </template>
@ -28,7 +28,7 @@ import {
} from '@/components/ui/dialog' } from '@/components/ui/dialog'
import LoginForm from './LoginForm.vue' import LoginForm from './LoginForm.vue'
const isOpen = ref(true) const isOpen = ref(false)
const setOpen = (value: boolean) => { const setOpen = (value: boolean) => {
isOpen.value = value isOpen.value = value

View File

@ -37,7 +37,7 @@
@click="openLoginModal" @click="openLoginModal"
class="flex h-[48px] items-center rounded-full bg-[#70C877] px-6 text-sm font-bold backdrop-blur-md transition hover:bg-white/30" class="flex h-[48px] items-center rounded-full bg-[#70C877] px-6 text-sm font-bold backdrop-blur-md transition hover:bg-white/30"
> >
/ 注册 / 注册
</button> </button>
</header> </header>
</div> </div>
@ -49,7 +49,7 @@
<div class="md:w-1/2"> <div class="md:w-1/2">
<div class="mb-[20px] ml-[42px]"> <div class="mb-[20px] ml-[42px]">
<h2 class="mb-2 text-5xl font-black italic md:text-7xl"> <h2 class="mb-2 text-5xl font-black italic md:text-7xl">
<img :src="Logo" alt="Hi快VPN" class="h-[34px] w-auto" /> <Logo />
</h2> </h2>
<p class="font-600 text-3xl md:text-4xl">网在我在, 网快我快</p> <p class="font-600 text-3xl md:text-4xl">网在我在, 网快我快</p>
</div> </div>

View File

@ -1,33 +1,3 @@
<script setup lang="ts">
import { ref } from 'vue'
import PlanCard from '@/components/user-center/PlanCard.vue'
import DeviceList from '@/components/user-center/DeviceList.vue'
import PaymentMethod from '@/components/user-center/PaymentMethod.vue'
import { Button } from '@/components/ui/button'
// --- Mock Data ---
const devices = [
{ id: '1', name: 'XXX的 MacBook Pro 15-inch', type: 'desktop' as const, deviceId: '87654321' },
{ id: '2', name: 'XXX的 iPhone 15 Pro Max', type: 'mobile' as const, deviceId: '12345678' },
]
const plans = [
{ id: 'p1', days: 7, price: 2.79, dailyPrice: '0.39' },
{ id: 'p2', days: 30, price: 5.99, dailyPrice: '0.19', discount: '50% off' },
{ id: 'p3', days: 90, price: 12.99, dailyPrice: '0.14', discount: '64% off' },
{ id: 'p4', days: 365, price: 44.99, dailyPrice: '0.12', discount: '70% off', inverted: true },
]
// --- State ---
const selectedPlanId = ref('p2')
const selectedPayment = ref('alipay')
// --- Handlers ---
const handlePlanSelect = (id: string) => {
selectedPlanId.value = id
}
const currentPlanIndex = ref(3)
</script>
<template> <template>
<!-- Main Neon Green Card --> <!-- Main Neon Green Card -->
<div class="pt-[35px]"> <div class="pt-[35px]">
@ -67,6 +37,37 @@ const currentPlanIndex = ref(3)
</div> </div>
</template> </template>
<script setup lang="ts">
import { ref } from 'vue'
import PlanCard from '@/components/user-center/PlanCard.vue'
import DeviceList from '@/components/user-center/DeviceList.vue'
import PaymentMethod from '@/components/user-center/PaymentMethod.vue'
import { Button } from '@/components/ui/button'
import request from '@/utils/request'
// --- Mock Data ---
const devices = [
{ id: '1', name: 'XXX的 MacBook Pro 15-inch', type: 'desktop' as const, deviceId: '87654321' },
{ id: '2', name: 'XXX的 iPhone 15 Pro Max', type: 'mobile' as const, deviceId: '12345678' },
]
const plans = [
{ id: 'p1', days: 7, price: 2.79, dailyPrice: '0.39' },
{ id: 'p2', days: 30, price: 5.99, dailyPrice: '0.19', discount: '50% off' },
{ id: 'p3', days: 90, price: 12.99, dailyPrice: '0.14', discount: '64% off' },
{ id: 'p4', days: 365, price: 44.99, dailyPrice: '0.12', discount: '70% off', inverted: true },
]
// --- State ---
const selectedPlanId = ref('p2')
const selectedPayment = ref('alipay')
// --- Handlers ---
const handlePlanSelect = (id: string) => {
selectedPlanId.value = id
}
const currentPlanIndex = ref(3)
</script>
<style scoped> <style scoped>
/* Simplified layout font */ /* Simplified layout font */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap');

View File

@ -1,19 +1,3 @@
<script setup lang="ts">
import { ref } from 'vue'
import MobileLayout from './MobileLayout/index.vue'
import Logo from '@/pages/Home/logo.svg?component'
import MobileLogo from '@/pages/Home/mobile-logo.svg?component'
// --- State ---
const selectedPlanId = ref('p2')
const selectedPayment = ref('alipay')
// --- Handlers ---
const handlePlanSelect = (id: string) => {
selectedPlanId.value = id
}
</script>
<template> <template>
<div class="min-h-screen bg-black text-black"> <div class="min-h-screen bg-black text-black">
<!-- Full Width Header --> <!-- Full Width Header -->
@ -41,6 +25,44 @@ const handlePlanSelect = (id: string) => {
</div> </div>
</template> </template>
<script setup lang="ts">
import { ref } from 'vue'
import MobileLayout from './MobileLayout/index.vue'
import Logo from '@/pages/Home/logo.svg?component'
import MobileLogo from '@/pages/Home/mobile-logo.svg?component'
import request from '@/utils/request'
// --- State ---
const selectedPlanId = ref('p2')
const selectedPayment = ref('alipay')
// --- Handlers ---
const handlePlanSelect = (id: string) => {
selectedPlanId.value = id
}
const devices = ref([])
function init() {
//
request.get('/public/user/devices').then((res) => {
devices.value = res.list
})
//
request.get('/public/subscribe/list').then((res) => {
console.log(222, res.list)
})
//
request.get('/public/payment/methods').then((res) => {
console.log(33, res)
})
//
request.get('/public/subscribe/list').then((res) => {
console.log(44, res)
})
}
init()
</script>
<style scoped> <style scoped>
/* Simplified layout font */ /* Simplified layout font */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700;900&display=swap');

View File

@ -0,0 +1,75 @@
import CryptoJS from 'crypto-js'
/**
* HiAesUtil - AES-256-CBC
* Dart 100%
*/
export class HiAesUtil {
/**
* 32 (SHA-256)
*/
static _generateKey(keyStr) {
return CryptoJS.SHA256(keyStr)
}
/**
* 16 IV
* 逻辑: SHA-256(MD5(nonce) + keyStr) -> 16
*/
static _generateIv(nonce, keyStr) {
// 1. MD5 处理 nonce
const md5Hash = CryptoJS.MD5(nonce)
// 2. 转为 16 进制字符串
const md5Hex = md5Hash.toString(CryptoJS.enc.Hex)
// 3. 拼接 md5Hex + keyStr 并做 SHA-256
const finalHash = CryptoJS.SHA256(md5Hex + keyStr)
// 4. 重要:截取前 16 字节 (128位)
// CryptoJS 的 WordArray 由 32 位整数组成16 字节即前 4 个 words
const iv = CryptoJS.lib.WordArray.create(finalHash.words.slice(0, 4), 16)
return iv
}
/**
*
* @param {string} plainText -
* @param {string} keyStr -
*/
static encryptData(plainText, keyStr) {
// 生成 ISO8601 时间戳 (与 Dart DateTime.now().toIso8601String() 对应)
const nonce = new Date().toISOString()
const key = this._generateKey(keyStr)
const iv = this._generateIv(nonce, keyStr)
const encrypted = CryptoJS.AES.encrypt(plainText, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
return {
data: encrypted.toString(), // Base64 字符串
time: nonce,
}
}
/**
*
* @param {string} encryptedData - Base64
* @param {string} nonce -
* @param {string} keyStr -
*/
static decryptData(encryptedData, nonce, keyStr) {
const key = this._generateKey(keyStr)
const iv = this._generateIv(nonce, keyStr)
const decrypted = CryptoJS.AES.decrypt(encryptedData, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
return decrypted.toString(CryptoJS.enc.Utf8)
}
}