diff --git a/backend/.env b/backend/.env index 91b9c9d..f91754f 100644 --- a/backend/.env +++ b/backend/.env @@ -3,7 +3,7 @@ DB_HOST=129.211.213.226 DB_PORT=9527 DB_USERNAME=root DB_PASSWORD=aiotAiot123! -DB_NAME=jiebandata +DB_NAME=niumall # JWT配置 JWT_SECRET=niumall_jwt_secret_key_2024 diff --git a/backend/init_database.js b/backend/init_database.js new file mode 100644 index 0000000..6b0ea92 --- /dev/null +++ b/backend/init_database.js @@ -0,0 +1,135 @@ +const { sequelize } = require('./models'); +const { ApiUser, Order } = require('./models'); +const bcrypt = require('bcryptjs'); + +// 演示账号数据 +const demoUsers = [ + { + username: 'admin', + password: 'admin123', + phone: '13800138001', + email: 'admin@niumall.com', + user_type: 'admin', + status: 'active' + }, + { + username: 'buyer', + password: 'buyer123', + phone: '13800138002', + email: 'buyer@niumall.com', + user_type: 'client', + status: 'active' + }, + { + username: 'trader', + password: 'trader123', + phone: '13800138003', + email: 'trader@niumall.com', + user_type: 'supplier', + status: 'active' + } +]; + +// 演示订单数据 +const demoOrders = [ + { + orderNo: 'ORD20240520001', + buyerId: 2, // buyer用户 + buyerName: '采购商', + supplierId: 3, // trader用户 + supplierName: '供应商', + traderId: null, + traderName: null, + cattleBreed: '西门塔尔牛', + cattleCount: 10, + expectedWeight: 5000.00, + actualWeight: null, + unitPrice: 35.00, + totalAmount: 175000.00, + paidAmount: 50000.00, + remainingAmount: 125000.00, + status: 'pending', + deliveryAddress: '北京市朝阳区某某路123号', + expectedDeliveryDate: new Date('2024-06-01'), + actualDeliveryDate: null, + notes: '请按时交货,质量要保证' + }, + { + orderNo: 'ORD20240520002', + buyerId: 2, // buyer用户 + buyerName: '采购商', + supplierId: 3, // trader用户 + supplierName: '供应商', + traderId: null, + traderName: null, + cattleBreed: '夏洛来牛', + cattleCount: 5, + expectedWeight: 2500.00, + actualWeight: null, + unitPrice: 38.00, + totalAmount: 95000.00, + paidAmount: 95000.00, + remainingAmount: 0.00, + status: 'confirmed', + deliveryAddress: '北京市海淀区某某路456号', + expectedDeliveryDate: new Date('2024-05-28'), + actualDeliveryDate: null, + notes: '加急订单' + } +]; + +// 初始化数据库 +const initDatabase = async () => { + try { + console.log('开始初始化数据库...'); + + // 测试数据库连接 + await sequelize.authenticate(); + console.log('✅ 数据库连接成功'); + + // 删除并重新创建表结构 + console.log('正在创建表结构...'); + await sequelize.sync({ force: true }); + console.log('✅ 表结构创建完成'); + + // 添加演示用户 + console.log('正在添加演示用户...'); + for (const userData of demoUsers) { + // 加密密码 + const salt = await bcrypt.genSalt(10); + const passwordHash = await bcrypt.hash(userData.password, salt); + + try { + await ApiUser.create({ + ...userData, + password_hash: passwordHash + }); + console.log(`✅ 成功创建用户: ${userData.username} (${userData.user_type})`); + } catch (error) { + console.error(`❌ 创建用户 ${userData.username} 时出错:`, error.message); + } + } + + // 添加演示订单 + console.log('正在添加演示订单...'); + for (const orderData of demoOrders) { + try { + await Order.create(orderData); + console.log(`✅ 成功创建订单: ${orderData.orderNo}`); + } catch (error) { + console.error(`❌ 创建订单 ${orderData.orderNo} 时出错:`, error.message); + } + } + + console.log('✅ 数据库初始化完成'); + } catch (error) { + console.error('❌ 数据库初始化失败:', error.message); + console.error(error); + } finally { + // 关闭数据库连接 + await sequelize.close(); + } +}; + +// 执行初始化 +initDatabase(); \ No newline at end of file diff --git a/backend/middleware/auth.js b/backend/middleware/auth.js index b4aa555..fe20166 100644 --- a/backend/middleware/auth.js +++ b/backend/middleware/auth.js @@ -39,6 +39,7 @@ const jwt = require('jsonwebtoken') * example: 权限不足 */ +const jwt = require('jsonwebtoken') // 从环境变量或配置中获取JWT密钥 const JWT_SECRET = process.env.JWT_SECRET || 'your_jwt_secret_key' diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js index 6f5bbd0..16e2f2f 100644 --- a/backend/src/routes/auth.js +++ b/backend/src/routes/auth.js @@ -12,4 +12,23 @@ router.post('/mini-program/login', AuthController.miniProgramLogin); // 获取当前用户信息 router.get('/current', authenticate, AuthController.getCurrentUser); +// 用户登出 +router.post('/logout', authenticate, async (req, res) => { + try { + // JWT是无状态的,服务器端无法直接使token失效 + // 登出操作主要由客户端完成,如删除本地存储的token + // 这里只返回成功信息 + res.json({ + success: true, + message: '登出成功' + }); + } catch (error) { + console.error('用户登出失败:', error); + res.status(500).json({ + success: false, + message: '登出失败,请稍后再试' + }); + } +}); + module.exports = router; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index acf87df..f9c9181 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,13 +5,293 @@ "packages": { "": { "dependencies": { - "@dcloudio/uni-ui": "^1.5.11" + "@dcloudio/uni-ui": "^1.5.11", + "axios": "^1.12.2" } }, "node_modules/@dcloudio/uni-ui": { "version": "1.5.11", "resolved": "https://registry.npmjs.org/@dcloudio/uni-ui/-/uni-ui-1.5.11.tgz", "integrity": "sha512-DBtk046ofmeFd82zRI7d89SoEwrAxYzUN3WVPm1DIBkpLPG5F5QDNkHMnZGu2wNrMEmGBjBpUh3vqEY1L3jaMw==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" } } } diff --git a/package.json b/package.json index 654f7f9..87db393 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { - "@dcloudio/uni-ui": "^1.5.11" + "@dcloudio/uni-ui": "^1.5.11", + "axios": "^1.12.2" } } diff --git a/test_logout.js b/test_logout.js new file mode 100644 index 0000000..5e0d5bc --- /dev/null +++ b/test_logout.js @@ -0,0 +1,76 @@ +const axios = require('axios'); + +// 后端API基础URL +const API_BASE_URL = 'http://localhost:4330/api'; + +// 登录信息 +const loginData = { + username: 'admin', + password: 'admin123' +}; + +// 测试登出功能 +const testLogout = async () => { + try { + console.log('开始测试登出功能...'); + + // 1. 先登录获取token + console.log('1. 登录获取token...'); + const loginResponse = await axios.post(`${API_BASE_URL}/auth/login`, loginData); + + console.log('登录响应完整数据:', loginResponse.data); + + if (!loginResponse.data.success) { + console.error('登录失败:', loginResponse.data.message); + return; + } + + // 根据之前的修改,token应该在data对象中 + let token = null; + if (loginResponse.data.data && loginResponse.data.data.access_token) { + token = loginResponse.data.data.access_token; + } else if (loginResponse.data.token) { + token = loginResponse.data.token; + } + + if (!token) { + console.error('❌ 无法从登录响应中获取token'); + return; + } + + console.log('登录成功,获取到token:', token.substring(0, 20) + '...'); + + // 2. 调用登出接口 + console.log('\n2. 调用登出接口...'); + const logoutResponse = await axios.post( + `${API_BASE_URL}/auth/logout`, + {}, + { + headers: { + Authorization: `Bearer ${token}` + } + } + ); + + console.log('登出响应状态码:', logoutResponse.status); + console.log('登出响应数据:', logoutResponse.data); + + if (logoutResponse.status === 200 && logoutResponse.data.success) { + console.log('\n✅ 登出功能测试成功!'); + } else { + console.error('❌ 登出功能测试失败:', logoutResponse.data); + } + + } catch (error) { + console.error('❌ 测试过程中发生错误:', error.message); + if (error.response) { + console.error('错误状态码:', error.response.status); + console.error('错误响应数据:', error.response.data); + } + } +}; + +// 执行测试 +if (require.main === module) { + testLogout(); +} \ No newline at end of file