From 5e3015ba4f6f20d4bab5fe42cde40c2b4aa58040 Mon Sep 17 00:00:00 2001 From: sudomarcma Date: Thu, 26 Jun 2025 11:45:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(api):=20=E7=BB=9F=E4=B8=80=E5=89=8D?= =?UTF-8?q?=E7=AB=AFAPI=E8=B0=83=E7=94=A8=E4=BD=BF=E7=94=A8apiFetch?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 替换直接fetch调用为apiFetch以统一处理错误和响应 fix(server): 改进QR码验证的错误消息和密码哈希处理 --- backend/server.js | 18 +++- src/api.js | 7 +- src/components/AttendanceReporting.vue | 82 ++++++---------- src/components/QrCodeManagement.vue | 68 ++++++------- src/views/AttendanceRecordView.vue | 61 +++++------- src/views/LoginView.vue | 2 +- src/views/WorkerDashboardView.vue | 130 +++++++++++++------------ src/views/WorkerHistoryView.vue | 14 +-- 8 files changed, 184 insertions(+), 198 deletions(-) diff --git a/backend/server.js b/backend/server.js index 79cff17..7a57300 100644 --- a/backend/server.js +++ b/backend/server.js @@ -95,11 +95,21 @@ async function startServer() { app.post('/api/clock', authenticateJWT, async (req, res) => { try { const { userId, eventType, qrCodeValue, latitude, longitude } = req.body + const [qrRows] = await db.execute('SELECT name, is_active FROM qr_codes WHERE id = ?', [ qrCodeValue, ]) - if (qrRows.length === 0 || !qrRows[0].is_active) { - return res.status(400).json({ message: 'Invalid or inactive QR Code.' }) + + if (qrRows.length === 0) { + // This code is not in the database at all. + return res.status(400).json({ message: 'Invalid QR Code scanned.' }) + } + + if (!qrRows[0].is_active) { + // This code exists but has been deactivated. + return res + .status(400) + .json({ message: 'This QR Code has expired and is no longer active.' }) } const [lastEventRows] = await db.execute( 'SELECT event_type FROM clock_records WHERE worker_id = ? ORDER BY timestamp DESC LIMIT 1', @@ -204,8 +214,8 @@ async function startServer() { if (!username || !password || !fullName) { return res.status(400).json({ message: 'Username, password, and full name are required.' }) } - const saltRounds = 10; - const hashedPassword = await bcrypt.hash(password, saltRounds); + const saltRounds = 10 + const hashedPassword = await bcrypt.hash(password, saltRounds) const [result] = await db.execute( "INSERT INTO workers (username, password_hash, full_name, role) VALUES (?, ?, ?, 'worker')", [username, hashedPassword, fullName], diff --git a/src/api.js b/src/api.js index 1acb299..f6e6ec8 100644 --- a/src/api.js +++ b/src/api.js @@ -19,7 +19,12 @@ export async function apiFetch(endpoint, options = {}) { }) if (!response.ok) { - throw new Error(`API call failed with status: ${response.status}`) + // Try to parse the error response body from the server + const errorData = await response.json() + throw new Error(errorData.message || `API call failed with status: ${response.status}`) + } + if (response.status === 204) { + return null } return response.json() diff --git a/src/components/AttendanceReporting.vue b/src/components/AttendanceReporting.vue index d7888b5..8beda09 100644 --- a/src/components/AttendanceReporting.vue +++ b/src/components/AttendanceReporting.vue @@ -223,6 +223,8 @@