feat(小程序): 修复运行时与登录链路

This commit is contained in:
stu2not
2026-04-22 17:25:03 +08:00
parent 24b1d1025b
commit d7df6f565c
12 changed files with 297 additions and 426 deletions

View File

@@ -4,8 +4,8 @@ module.exports = {
},
defineConstants: {
__APP_ENV__: '"development"',
// Local backend for daily development.
__API_BASE_URL__: '"http://192.168.101.78:8001"'
// Update this to your LAN backend when testing on a real device.
__API_BASE_URL__: '"http://192.168.101.86:8001"',
},
mini: {},
h5: {}

View File

@@ -12,31 +12,38 @@ const config = {
sourceRoot: 'src',
outputRoot: 'dist',
plugins: [],
defineConstants: {},
alias: {
'@': path.resolve(__dirname, '..', 'src'),
react: path.resolve(__dirname, '..', 'node_modules/react')
},
defineConstants: {
},
copy: {
patterns: [
{ from: 'src/assets/tab-icons', to: 'dist/assets/tab-icons' }
],
options: {}
options: {
}
},
framework: 'react',
mini: {
webpackChain(chain) {
chain.resolve.alias.set('@', path.resolve(__dirname, '../src'))
},
postcss: {
pxtransform: {
enable: true,
config: {}
config: {
}
},
url: {
enable: true,
config: { limit: 1024 }
config: {
limit: 1024 // 设定转换尺寸上限
}
},
cssModules: {
enable: false,
enable: false, // 默认为 false如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module',
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
@@ -45,15 +52,16 @@ const config = {
h5: {
publicPath: '/',
staticDirectory: 'static',
webpackChain(chain) {
chain.resolve.alias.set('@', path.resolve(__dirname, '../src'))
},
postcss: {
autoprefixer: { enable: true, config: {} },
cssModules: {
enable: false,
autoprefixer: {
enable: true,
config: {
namingPattern: 'module',
}
},
cssModules: {
enable: false, // 默认为 false如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
@@ -62,10 +70,8 @@ const config = {
}
module.exports = function (merge) {
const envConfig =
process.env.NODE_ENV === 'development'
? require('./dev')
: require('./prod')
return merge({}, config, envConfig)
if (process.env.NODE_ENV === 'development') {
return merge({}, config, require('./dev'))
}
return merge({}, config, require('./prod'))
}

View File

@@ -4,8 +4,8 @@ module.exports = {
},
defineConstants: {
__APP_ENV__: '"production"',
// Replace with the production backend before publishing a release build.
__API_BASE_URL__: '"http://192.168.101.78:8001"'
// Replace with the production backend before release builds.
__API_BASE_URL__: '"http://192.168.101.86:8001"',
},
mini: {},
h5: {}

View File

@@ -13,8 +13,8 @@
"@tarojs/react": "^3.6.38",
"@tarojs/runtime": "^3.6.38",
"@tarojs/taro": "^3.6.38",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"webpack": "^4.47.0"
},
"devDependencies": {
@@ -25,7 +25,6 @@
"@types/react": "^18.0.0",
"@types/webpack-env": "^1.13.9",
"babel-preset-taro": "^3.6.38",
"cross-env": "^10.1.0",
"typescript": "^4.1.0"
}
},
@@ -165,10 +164,9 @@
}
},
"node_modules/@babel/helper-define-polyfill-provider": {
"version": "0.6.6",
"resolved": "https://registry.npmmirror.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz",
"integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==",
"license": "MIT",
"version": "0.6.8",
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz",
"integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==",
"dependencies": {
"@babel/helper-compilation-targets": "^7.28.6",
"@babel/helper-plugin-utils": "^7.28.6",
@@ -1866,12 +1864,11 @@
}
},
"node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": {
"version": "0.14.0",
"resolved": "https://registry.npmmirror.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz",
"integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==",
"license": "MIT",
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz",
"integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==",
"dependencies": {
"@babel/helper-define-polyfill-provider": "^0.6.6",
"@babel/helper-define-polyfill-provider": "^0.6.8",
"core-js-compat": "^3.48.0"
},
"peerDependencies": {
@@ -2028,13 +2025,6 @@
"stackframe": "^1.1.1"
}
},
"node_modules/@epic-web/invariant": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
"dev": true,
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.19.12",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
@@ -2457,11 +2447,10 @@
}
},
"node_modules/@eslint/js": {
"version": "8.57.1",
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.57.1.tgz",
"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
@@ -2489,14 +2478,13 @@
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
"deprecated": "Use @eslint/config-array instead",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanwhocodes/object-schema": "^2.0.3",
"@humanwhocodes/object-schema": "^2.0.2",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
@@ -2520,11 +2508,10 @@
},
"node_modules/@humanwhocodes/object-schema": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"deprecated": "Use @eslint/object-schema instead",
"dev": true,
"license": "BSD-3-Clause"
"dev": true
},
"node_modules/@inquirer/external-editor": {
"version": "1.0.3",
@@ -3979,117 +3966,15 @@
"node": ">= 10"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/@eslint/js": {
"version": "8.41.0",
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-8.41.0.tgz",
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
"deprecated": "Use @eslint/config-array instead",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@humanwhocodes/object-schema": "^2.0.2",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"engines": {
"node": ">=10.10.0"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
"integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/eslint": {
"version": "8.41.0",
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.41.0.tgz",
"integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.41.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.0",
"eslint-visitor-keys": "^3.4.1",
"espree": "^9.5.2",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
"strip-ansi": "^6.0.1",
"strip-json-comments": "^3.1.0",
"text-table": "^0.2.0"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/glob": {
"version": "10.2.6",
"resolved": "https://registry.npmmirror.com/glob/-/glob-10.2.6.tgz",
@@ -4113,25 +3998,11 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/@tarojs/plugin-doctor/node_modules/glob/node_modules/minimatch": {
"node_modules/@tarojs/plugin-doctor/node_modules/minimatch": {
"version": "9.0.9",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.2"
},
@@ -5066,13 +4937,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@ungap/structured-clone": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
"dev": true,
"license": "ISC"
},
"node_modules/@vue/compiler-core": {
"version": "3.5.29",
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.29.tgz",
@@ -6488,10 +6352,9 @@
}
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
"integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -7817,10 +7680,9 @@
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
},
"node_modules/cosmiconfig": {
"version": "7.1.0",
@@ -7892,24 +7754,6 @@
"sha.js": "^2.4.8"
}
},
"node_modules/cross-env": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz",
"integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@epic-web/invariant": "^1.0.0",
"cross-spawn": "^7.0.6"
},
"bin": {
"cross-env": "dist/bin/cross-env.js",
"cross-env-shell": "dist/bin/cross-env-shell.js"
},
"engines": {
"node": ">=20"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -8904,11 +8748,10 @@
}
},
"node_modules/depcheck/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
"integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -9837,30 +9680,28 @@
}
},
"node_modules/eslint": {
"version": "8.57.1",
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-8.57.1.tgz",
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
"integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4",
"@eslint/js": "8.57.1",
"@humanwhocodes/config-array": "^0.13.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.41.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.2",
"eslint-visitor-keys": "^3.4.3",
"espree": "^9.6.1",
"eslint-scope": "^7.2.0",
"eslint-visitor-keys": "^3.4.1",
"espree": "^9.5.2",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@@ -9870,6 +9711,7 @@
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
@@ -9879,8 +9721,9 @@
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3",
"optionator": "^0.9.1",
"strip-ansi": "^6.0.1",
"strip-json-comments": "^3.1.0",
"text-table": "^0.2.0"
},
"bin": {
@@ -13885,22 +13728,19 @@
}
},
"node_modules/less": {
"version": "4.5.1",
"resolved": "https://registry.npmmirror.com/less/-/less-4.5.1.tgz",
"integrity": "sha512-UKgI3/KON4u6ngSsnDADsUERqhZknsVZbnuzlRZXLQCmfC/MDld42fTydUE9B+Mla1AL6SJ/Pp6SlEFi/AVGfw==",
"version": "4.6.4",
"resolved": "https://registry.npmjs.org/less/-/less-4.6.4.tgz",
"integrity": "sha512-OJmO5+HxZLLw0RLzkqaNHzcgEAQG7C0y3aMbwtCzIUFZsLMNNq/1IdAdHEycQ58CwUO3jPTHmoN+tE5I7FQxNg==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"copy-anything": "^2.0.1",
"parse-node-version": "^1.0.1",
"tslib": "^2.3.0"
"copy-anything": "^3.0.5",
"parse-node-version": "^1.0.1"
},
"bin": {
"lessc": "bin/lessc"
},
"engines": {
"node": ">=14"
"node": ">=18"
},
"optionalDependencies": {
"errno": "^0.1.1",
@@ -13969,6 +13809,33 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/less/node_modules/copy-anything": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"dev": true,
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/less/node_modules/is-what": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
"dev": true,
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/less/node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@@ -14530,11 +14397,10 @@
}
},
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -14552,16 +14418,6 @@
"node": ">= 0.6"
}
},
"node_modules/mime-types/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -14727,13 +14583,12 @@
}
},
"node_modules/minipass": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/minipass/-/minipass-6.0.2.tgz",
"integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
"node": ">=8"
}
},
"node_modules/minipass-collect": {
@@ -16835,9 +16690,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"version": "8.5.10",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
"funding": [
{
"type": "opencollective",
@@ -16852,7 +16707,6 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -17516,7 +17370,6 @@
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -17528,7 +17381,6 @@
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
@@ -18728,7 +18580,6 @@
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
}
@@ -20268,16 +20119,6 @@
"node": ">=10"
}
},
"node_modules/tar/node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=8"
}
},
"node_modules/tar/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz",
@@ -21498,10 +21339,9 @@
"license": "MIT"
},
"node_modules/url/node_modules/qs": {
"version": "6.15.0",
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.0.tgz",
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
"license": "BSD-3-Clause",
"version": "6.15.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
"integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
"dependencies": {
"side-channel": "^1.1.0"
},
@@ -21627,13 +21467,6 @@
"extsprintf": "^1.2.0"
}
},
"node_modules/verror/node_modules/core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
"dev": true,
"license": "MIT"
},
"node_modules/vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/vm-browserify/-/vm-browserify-1.1.2.tgz",
@@ -23324,11 +23157,10 @@
}
},
"node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},

View File

@@ -4,8 +4,10 @@
"private": true,
"description": "伴伴微信小程序",
"scripts": {
"build:weapp": "cross-env NODE_OPTIONS=--openssl-legacy-provider taro build --type weapp",
"dev:weapp": "cross-env NODE_OPTIONS=--openssl-legacy-provider taro build --type weapp --watch"
"dev": "npm run dev:weapp",
"build": "npm run build:weapp",
"build:weapp": "NODE_OPTIONS=--openssl-legacy-provider taro build --type weapp",
"dev:weapp": "NODE_OPTIONS=--openssl-legacy-provider taro build --type weapp --watch"
},
"dependencies": {
"@tarojs/components": "^3.6.38",
@@ -13,8 +15,8 @@
"@tarojs/react": "^3.6.38",
"@tarojs/runtime": "^3.6.38",
"@tarojs/taro": "^3.6.38",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"webpack": "^4.47.0"
},
"devDependencies": {
@@ -25,7 +27,6 @@
"@types/react": "^18.0.0",
"@types/webpack-env": "^1.13.9",
"babel-preset-taro": "^3.6.38",
"cross-env": "^10.1.0",
"typescript": "^4.1.0"
}
}

View File

@@ -22,7 +22,7 @@
"uploadWithSourceMap": true,
"compileHotReLoad": false,
"lazyloadPlaceholderEnable": false,
"useMultiFrameRuntime": true,
"useMultiFrameRuntime": false,
"useApiHook": true,
"useApiHostProcess": true,
"babelSetting": {
@@ -30,7 +30,7 @@
"disablePlugins": [],
"outputPath": ""
},
"useIsolateContext": true,
"useIsolateContext": false,
"userConfirmedBundleSwitch": false,
"packNpmManually": false,
"packNpmRelationList": [],

View File

@@ -1,11 +1,7 @@
import { useLaunch } from '@tarojs/taro'
import './app.scss'
import { PropsWithChildren } from 'react'
function App(props) {
useLaunch(() => {
console.log('App launched.')
})
function App(props: PropsWithChildren) {
return props.children
}

View File

@@ -7,8 +7,8 @@ export interface AppConfig {
}
export const APP_CONFIG: AppConfig = {
appEnv: __APP_ENV__,
apiBaseUrl: __API_BASE_URL__,
appEnv: typeof __APP_ENV__ === 'undefined' ? 'development' : __APP_ENV__,
apiBaseUrl: typeof __API_BASE_URL__ === 'undefined' ? 'http://127.0.0.1:8001' : __API_BASE_URL__,
}
export const API_BASE_URL = APP_CONFIG.apiBaseUrl

View File

@@ -1,100 +1,76 @@
import { View, Text, Button } from '@tarojs/components'
import { useEffect } from 'react'
import { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import { wechatLogin } from '@/services/auth'
import { getToken, wechatLogin } from '@/services/auth'
import './index.scss'
export default function Login() {
const [submitting, setSubmitting] = useState(false)
useEffect(() => {
console.log('[Login] Page mounted, checking token...')
const token = Taro.getStorageSync('token')
console.log('[Login] Token exists:', !!token)
if (token) {
console.log('[Login] Already logged in, redirecting to device page')
if (getToken()) {
Taro.reLaunch({ url: '/pages/device/index' })
}
}, [])
const doWeChatLogin = async () => {
try {
console.log('[Login] Starting WeChat login...')
const handleLogin = async () => {
if (submitting) return
setSubmitting(true)
Taro.showLoading({ title: '登录中...' })
// 1. 调用微信登录获取 code
console.log('[Login] Step 1: Calling Taro.login()...')
try {
const loginRes = await Taro.login()
const code = loginRes.code
console.log('[Login] Got code:', code ? 'yes' : 'no')
if (!code) {
if (!loginRes.code) {
throw new Error('未获取到微信登录凭证')
}
// 2. 获取用户头像信息 (可选)
let userInfo = null
let userInfo:
| {
nickName?: string
avatarUrl?: string
}
| null = null
try {
console.log('[Login] Step 2: Calling Taro.getUserProfile()...')
const profileRes = await Taro.getUserProfile({
desc: '用于完善用户资料'
desc: '用于完善家长资料展示',
})
userInfo = profileRes.userInfo
console.log('[Login] Got userInfo:', !!userInfo)
} catch (e) {
console.log('[Login] getUserProfile failed (expected if user denied):', e)
userInfo = profileRes.userInfo || null
} catch (error) {
console.log('[login] getUserProfile skipped:', error)
}
// 3. 调用后端登录接口 (微信登录)
console.log('[Login] Step 3: Calling backend /auth/login...')
const res = await wechatLogin({
code,
await wechatLogin({
code: loginRes.code,
nickname: userInfo?.nickName,
avatar_url: userInfo?.avatarUrl
avatar_url: userInfo?.avatarUrl,
})
console.log('[Login] Backend login success, user_id:', res.user_id)
// 4. 保存用户信息用于显示
console.log('[Login] Step 4: Saving user info...')
if (userInfo) {
Taro.setStorageSync('userInfo', {
nickname: userInfo.nickName,
avatar_url: userInfo.avatarUrl
avatar_url: userInfo.avatarUrl,
})
} else {
Taro.removeStorageSync('userInfo')
}
Taro.hideLoading()
console.log('[Login] Step 5: Login complete, showing success toast')
Taro.showToast({ title: '登录成功', icon: 'success' })
// 6. 跳转到首页
console.log('[Login] Redirecting to /pages/device/index...')
setTimeout(() => {
Taro.reLaunch({ url: '/pages/device/index' })
}, 500)
} catch (err: any) {
}, 300)
} catch (error: any) {
console.error('[login] failed:', error)
Taro.showToast({
title: error?.message || '登录失败,请重试',
icon: 'none',
})
} finally {
Taro.hideLoading()
console.error('[Login] Login failed:', err)
// 401 通常表示微信 code 失效或已被使用,提示用户重试登录
if (err.status === 401) {
Taro.showToast({
title: '登录失败,请重试',
icon: 'none'
})
} else {
Taro.showToast({
title: err.message || '网络错误,请重试',
icon: 'none'
})
setSubmitting(false)
}
}
}
const handleLogin = () => {
console.log('Button clicked, starting login...')
doWeChatLogin()
}
return (
<View className='login-page'>
@@ -123,12 +99,9 @@ export default function Login() {
</View>
<View className='login-btn-wrapper'>
<Button
className='login-btn'
onClick={handleLogin}
>
<Button className='login-btn' loading={submitting} disabled={submitting} onClick={handleLogin}>
<Text className='btn-icon'>🌐</Text>
<Text className='btn-text'></Text>
<Text className='btn-text'>{submitting ? '登录中...' : '微信一键登录'}</Text>
</Button>
</View>

View File

@@ -1,7 +1,9 @@
import Taro from '@tarojs/taro'
import { API_BASE_URL } from '@/config/env'
import { getCurrentUserId, getToken, handleUnauthorized } from './session'
const BASE_URL = API_BASE_URL
const REQUEST_TIMEOUT_MS = 10000
class ApiError extends Error {
constructor(public status: number, message: string) {
@@ -9,6 +11,16 @@ class ApiError extends Error {
}
}
function getErrorDetail(data: any): string {
if (!data) return 'Request failed'
if (typeof data.detail === 'string') return data.detail
if (Array.isArray(data.detail)) {
return data.detail.map((item: any) => String(item?.msg || item)).join('; ')
}
if (typeof data.message === 'string') return data.message
return 'Request failed'
}
async function request<T>(
url: string,
options: {
@@ -17,40 +29,42 @@ async function request<T>(
headers?: Record<string, string>
} = {}
): Promise<T> {
const token = Taro.getStorageSync('token')
console.log(`[API] ${options.method || 'GET'} ${url}`, token ? 'with token' : 'no token')
const token = getToken()
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...options.headers,
}
if (token) {
headers['Authorization'] = `Bearer ${token}`
headers.Authorization = `Bearer ${token}`
}
const response = await Taro.request({
let response
try {
response = await Taro.request({
url: `${BASE_URL}${url}`,
method: options.method || 'GET',
data: options.data,
header: headers,
timeout: REQUEST_TIMEOUT_MS,
})
console.log(`[API] Response status:`, response.statusCode)
if (response.statusCode >= 400) {
const detail = response.data?.detail || 'Request failed'
throw new ApiError(response.statusCode, detail)
} catch (error: any) {
const message = String(error?.errMsg || error?.message || '')
const detail = message.includes('timeout')
? '请求超时,请检查后端服务是否可访问'
: '网络请求失败,请检查后端地址和网络连接'
throw new ApiError(0, detail)
}
return response.data
if (response.statusCode === 401) {
handleUnauthorized({ redirect: !url.startsWith('/auth/') })
}
if (response.statusCode >= 400) {
throw new ApiError(response.statusCode, getErrorDetail(response.data))
}
return response.data as T
}
export { request, ApiError, BASE_URL }
export function getToken(): string {
return Taro.getStorageSync('token') || ''
}
export function getCurrentUserId(): number {
return Taro.getStorageSync('user_id') || 0
}
export { getCurrentUserId, getToken }

View File

@@ -1,5 +1,9 @@
import Taro from '@tarojs/taro'
import {
clearLoginSession,
getCurrentUserId as getStoredCurrentUserId,
getToken as getStoredToken,
saveLoginSession,
} from './session'
import { request } from './api'
export interface WechatLoginPayload {
@@ -25,40 +29,19 @@ export interface Parent {
status: number
}
// 微信登录
export async function wechatLogin(data: WechatLoginPayload): Promise<LoginSession> {
const session = await request<LoginSession>('/auth/login', {
method: 'POST',
data,
})
Taro.setStorageSync('token', session.access_token)
Taro.setStorageSync('token_type', session.token_type)
Taro.setStorageSync('user_id', session.user_id)
Taro.setStorageSync('expires_in', session.expires_in)
saveLoginSession(session)
return session
}
// 创建家长
export async function createParent(data: {
openid: string
unionid?: string
nickname?: string
avatar_url?: string
}): Promise<Parent> {
return request<Parent>('/parents', {
method: 'POST',
data,
})
}
// 获取家长信息
export async function getParent(userId: number): Promise<Parent> {
return request<Parent>(`/parents/${userId}`)
}
// 更新家长信息
export async function updateParent(
userId: number,
data: { nickname?: string; avatar_url?: string; phone?: string }
@@ -69,20 +52,14 @@ export async function updateParent(
})
}
// 获取 token
export function getToken(): string {
return Taro.getStorageSync('token')
return getStoredToken()
}
// 清除 token
export function clearToken(): void {
Taro.removeStorageSync('token')
Taro.removeStorageSync('token_type')
Taro.removeStorageSync('user_id')
Taro.removeStorageSync('expires_in')
clearLoginSession()
}
// 获取当前用户ID
export function getCurrentUserId(): number {
return Taro.getStorageSync('user_id') || 0
return getStoredCurrentUserId()
}

View File

@@ -0,0 +1,72 @@
import Taro from '@tarojs/taro'
const TOKEN_KEY = 'token'
const TOKEN_TYPE_KEY = 'token_type'
const USER_ID_KEY = 'user_id'
const EXPIRES_IN_KEY = 'expires_in'
const TOKEN_EXPIRES_AT_KEY = 'token_expires_at'
const LOGIN_PAGE_URL = '/pages/login/index'
let redirectingToLogin = false
export interface StoredLoginSession {
access_token: string
token_type: string
expires_in: number
user_id: number
}
export function saveLoginSession(session: StoredLoginSession): void {
const expiresAt = Date.now() + Math.max(session.expires_in, 0) * 1000
Taro.setStorageSync(TOKEN_KEY, session.access_token)
Taro.setStorageSync(TOKEN_TYPE_KEY, session.token_type)
Taro.setStorageSync(USER_ID_KEY, session.user_id)
Taro.setStorageSync(EXPIRES_IN_KEY, session.expires_in)
Taro.setStorageSync(TOKEN_EXPIRES_AT_KEY, expiresAt)
}
export function clearLoginSession(): void {
Taro.removeStorageSync(TOKEN_KEY)
Taro.removeStorageSync(TOKEN_TYPE_KEY)
Taro.removeStorageSync(USER_ID_KEY)
Taro.removeStorageSync(EXPIRES_IN_KEY)
Taro.removeStorageSync(TOKEN_EXPIRES_AT_KEY)
}
function getTokenExpiresAt(): number {
const rawValue = Number(Taro.getStorageSync(TOKEN_EXPIRES_AT_KEY) || 0)
return Number.isFinite(rawValue) ? rawValue : 0
}
export function getToken(): string {
const token = Taro.getStorageSync(TOKEN_KEY) || ''
if (!token) return ''
const expiresAt = getTokenExpiresAt()
if (expiresAt > 0 && Date.now() >= expiresAt) {
clearLoginSession()
return ''
}
return token
}
export function getCurrentUserId(): number {
if (!getToken()) return 0
return Number(Taro.getStorageSync(USER_ID_KEY) || 0)
}
export function handleUnauthorized(options: { redirect?: boolean } = {}): void {
const { redirect = true } = options
clearLoginSession()
if (!redirect || redirectingToLogin) return
redirectingToLogin = true
setTimeout(() => {
Taro.reLaunch({ url: LOGIN_PAGE_URL })
setTimeout(() => {
redirectingToLogin = false
}, 600)
}, 120)
}