From 2ec03705d105214ca95b986f2b8c96a37355d688 Mon Sep 17 00:00:00 2001 From: sudomarcma Date: Thu, 26 Jun 2025 17:57:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=A0=87=E7=AD=BE=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=87=E7=AD=BE=E5=88=A0=E9=99=A4=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E7=95=8C=E9=9D=A2=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在后端添加删除标签的API端点,包含权限检查和级联删除 - 在前端添加标签删除按钮和确认对话框 - 优化标签管理界面的样式和交互体验 - 改进导航标签栏的设计 --- backend/server.js | 27 ++++++++++- src/components/PersonnelManagement.vue | 67 ++++++++++++++++++++++---- src/views/ManagerDashboardView.vue | 26 +++++----- 3 files changed, 98 insertions(+), 22 deletions(-) diff --git a/backend/server.js b/backend/server.js index af1959b..c11e8fd 100644 --- a/backend/server.js +++ b/backend/server.js @@ -296,6 +296,32 @@ async function startServer() { } }) + // NEW: DELETE a tag + app.delete('/api/managers/tags/:id', authenticateJWT, async (req, res) => { + try { + const { id } = req.params + + // Optional: Check if the user is a manager before allowing deletion + if (req.user.role !== 'manager') { + return res.status(403).json({ message: 'Forbidden: Only managers can delete tags.' }) + } + + // Delete the tag from the 'tags' table. + // If 'worker_tags' table has ON DELETE CASCADE for tag_id, + // related entries in 'worker_tags' will automatically be removed. + const [result] = await db.execute('DELETE FROM tags WHERE id = ?', [id]) + + if (result.affectedRows === 0) { + return res.status(404).json({ message: 'Tag not found.' }) + } + + res.status(204).send() // 204 No Content for successful deletion + } catch (error) { + console.error('Delete tag error:', error) + res.status(500).json({ message: 'Database error deleting tag.' }) + } + }) + // POST to assign a tag to a worker app.post('/api/managers/workers/:workerId/tags', authenticateJWT, async (req, res) => { try { @@ -484,7 +510,6 @@ async function startServer() { return res.status(409).json({ message: `Worker is already clocked ${status}.` }) } // --- THIS IS THE FIX --- - // Sanitize the timestamp from "YYYY-MM-DDTHH:mm" to "YYYY-MM-DD HH:mm" const sanitizedTimestamp = timestamp.replace('T', ' ') await db.execute( diff --git a/src/components/PersonnelManagement.vue b/src/components/PersonnelManagement.vue index 4fe147a..50c0846 100644 --- a/src/components/PersonnelManagement.vue +++ b/src/components/PersonnelManagement.vue @@ -88,9 +88,23 @@ {{ tag.tag_name }} + @@ -273,15 +287,35 @@

{ } } +const deleteTag = async (tagId) => { + if (!confirm('Are you sure you want to delete this tag? This will remove it from all workers.')) + return + try { + await apiFetch(`/api/managers/tags/${tagId}`, { method: 'DELETE' }) + allTags.value = allTags.value.filter((tag) => tag.id !== tagId) + // Also re-fetch workers to update their tag display if any had this tag + fetchWorkers(currentPage.value) + alert('Tag deleted successfully.') + } catch (err) { + alert(err.message || 'Failed to delete tag.') + console.error(err) + } +} + const openTagEditor = (worker) => { editingWorker.value = worker isEditingTags.value = true diff --git a/src/views/ManagerDashboardView.vue b/src/views/ManagerDashboardView.vue index 71dfa87..b4c71b7 100644 --- a/src/views/ManagerDashboardView.vue +++ b/src/views/ManagerDashboardView.vue @@ -1,38 +1,41 @@