From 7e0bf42b0346313ae8d5069f85eaee6e9fe2932a Mon Sep 17 00:00:00 2001 From: zhang1106 <849185023@qq.com> Date: Fri, 26 Dec 2025 16:28:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=B7=A5=E5=8D=95):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=89=8B=E5=8A=A8=E8=BE=93=E5=85=A5=E8=AE=BE=E5=A4=87=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=88=96=E4=BB=8E=E5=88=97=E8=A1=A8=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加设备来源选项,允许用户在创建工单时选择从设备列表选择或手动输入设备信息 后端接口适配处理两种设备来源方式 添加terser依赖用于前端代码压缩优化 --- backend/routes/tickets.js | 47 +++++++++++---- frontend/package-lock.json | 80 +++++++++++++++++++++++++ frontend/package.json | 1 + frontend/src/pages/TicketManagement.jsx | 51 +++++++++++++--- 4 files changed, 159 insertions(+), 20 deletions(-) diff --git a/backend/routes/tickets.js b/backend/routes/tickets.js index 220009f..98819d4 100644 --- a/backend/routes/tickets.js +++ b/backend/routes/tickets.js @@ -269,6 +269,8 @@ router.post('/', async (req, res) => { try { const { deviceId, + deviceName, + serialNumber, faultCategory, faultSubCategory, priority, @@ -279,23 +281,44 @@ router.post('/', async (req, res) => { tags } = req.body; - // 获取设备信息 - const device = await Device.findByPk(deviceId, { - include: [{ model: require('../models/Rack') }] - }); - if (!device) { - return res.status(404).json({ error: '设备不存在' }); + let device = null; + let ticketDeviceName = ''; + let ticketDeviceModel = ''; + let ticketSerialNumber = ''; + let ticketLocation = ''; + + // 判断是选择设备还是手动输入 + if (deviceId) { + // 从设备列表选择 + device = await Device.findByPk(deviceId, { + include: [{ model: require('../models/Rack') }] + }); + if (!device) { + return res.status(404).json({ error: '设备不存在' }); + } + ticketDeviceName = device.name; + ticketDeviceModel = device.model; + ticketSerialNumber = device.serialNumber; + ticketLocation = device.Rack ? `${device.Rack.name}` : '未知位置'; + } else if (deviceName && serialNumber) { + // 手动输入设备信息 + ticketDeviceName = deviceName; + ticketSerialNumber = serialNumber; + ticketDeviceModel = ''; + ticketLocation = '未知位置'; + } else { + return res.status(400).json({ error: '请选择设备或手动输入设备信息' }); } const ticketId = `TKT${Date.now().toString(36).toUpperCase()}${Math.random().toString(36).substr(2, 4).toUpperCase()}`; const ticket = await Ticket.create({ ticketId, - title: title || `${faultCategory} - ${device.name}`, - deviceId, - deviceName: device.name, - deviceModel: device.model, - serialNumber: device.serialNumber, + title: title || `${faultCategory} - ${ticketDeviceName}`, + deviceId: deviceId || null, + deviceName: ticketDeviceName, + deviceModel: ticketDeviceModel, + serialNumber: ticketSerialNumber, faultCategory, faultSubCategory, priority: priority || 'medium', @@ -303,7 +326,7 @@ router.post('/', async (req, res) => { expectedCompletionDate: expectedCompletionDate ? new Date(expectedCompletionDate) : null, reporterId: req.body.reporterId || 'USER001', reporterName: req.body.reporterName || '系统用户', - location: device.Rack ? `${device.Rack.name}` : '未知位置', + location: ticketLocation, attachments: attachments || [], tags: tags || [], status: 'pending' diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 677b0bf..ca2b948 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -24,6 +24,7 @@ "@testing-library/user-event": "^14.6.1", "@vitejs/plugin-react": "^4.0.3", "jsdom": "^27.3.0", + "terser": "^5.44.1", "vite": "^4.4.9", "vitest": "^4.0.16" } @@ -1126,6 +1127,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1908,6 +1920,19 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/adler-32": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", @@ -2127,6 +2152,13 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, "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", @@ -2220,6 +2252,13 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, "node_modules/compute-scroll-into-view": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", @@ -3890,6 +3929,16 @@ "dev": true, "license": "ISC" }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3900,6 +3949,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", @@ -3958,6 +4018,26 @@ "dev": true, "license": "MIT" }, + "node_modules/terser": { + "version": "5.44.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", + "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/three": { "version": "0.160.1", "resolved": "https://registry.npmjs.org/three/-/three-0.160.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 25df11d..d1734a1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,7 @@ "@testing-library/user-event": "^14.6.1", "@vitejs/plugin-react": "^4.0.3", "jsdom": "^27.3.0", + "terser": "^5.44.1", "vite": "^4.4.9", "vitest": "^4.0.16" } diff --git a/frontend/src/pages/TicketManagement.jsx b/frontend/src/pages/TicketManagement.jsx index d2903ba..2af3f87 100644 --- a/frontend/src/pages/TicketManagement.jsx +++ b/frontend/src/pages/TicketManagement.jsx @@ -74,6 +74,7 @@ function TicketManagement() { }); const [searchFilters, setSearchFilters] = useState({}); + const [deviceSource, setDeviceSource] = useState('select'); const fetchTickets = useCallback(async (page = 1, pageSize = 10, filters = {}) => { try { @@ -148,9 +149,18 @@ function TicketManagement() { if (ticketData.completionDate) { ticketData.completionDate = dayjs(ticketData.completionDate); } + if (ticket.deviceId) { + setDeviceSource('select'); + ticketData.deviceId = ticket.deviceId; + } else { + setDeviceSource('manual'); + ticketData.deviceName = ticket.deviceName; + ticketData.serialNumber = ticket.serialNumber; + } form.setFieldsValue(ticketData); } else { form.resetFields(); + setDeviceSource('select'); } setModalVisible(true); }, []); @@ -168,6 +178,12 @@ function TicketManagement() { completionDate: values.completionDate ? values.completionDate.format('YYYY-MM-DD HH:mm:ss') : null }; + if (deviceSource === 'manual') { + ticketData.deviceId = null; + ticketData.deviceName = values.deviceName; + ticketData.serialNumber = values.serialNumber; + } + if (editingTicket) { await axios.put(`/api/tickets/${editingTicket.ticketId}`, ticketData); message.success('工单更新成功'); @@ -182,11 +198,12 @@ function TicketManagement() { setModalVisible(false); fetchTickets(); setEditingTicket(null); + setDeviceSource('select'); } catch (error) { message.error(editingTicket ? '工单更新失败' : '工单创建失败'); console.error(error); } - }, [editingTicket, fetchTickets]); + }, [editingTicket, fetchTickets, deviceSource]); const handleDelete = useCallback(async (ticketId) => { Modal.confirm({ @@ -473,16 +490,34 @@ function TicketManagement() { -