feat(工单): 支持手动输入设备信息或从列表选择

添加设备来源选项,允许用户在创建工单时选择从设备列表选择或手动输入设备信息
后端接口适配处理两种设备来源方式
添加terser依赖用于前端代码压缩优化
This commit is contained in:
zhang1106
2025-12-26 16:28:15 +08:00
parent e1e78f83c9
commit 7e0bf42b03
4 changed files with 159 additions and 20 deletions
+80
View File
@@ -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",
+1
View File
@@ -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"
}
+43 -8
View File
@@ -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() {
<Input placeholder="请输入工单标题" />
</Form.Item>
<Form.Item name="deviceId" label="关联设备" rules={[{ required: true }]}>
<Select placeholder="选择设备" showSearch optionFilterProp="children">
{devices.map(device => (
<Option key={device.deviceId} value={device.deviceId}>
{device.name} - {device.serialNumber}
</Option>
))}
<Form.Item label="设备来源">
<Select value={deviceSource} onChange={setDeviceSource} style={{ width: 200 }}>
<Option value="select">从设备列表选择</Option>
<Option value="manual">手动输入设备信息</Option>
</Select>
</Form.Item>
{deviceSource === 'select' ? (
<Form.Item name="deviceId" label="关联设备" rules={[{ required: true }]}>
<Select placeholder="选择设备" showSearch optionFilterProp="children">
{devices.map(device => (
<Option key={device.deviceId} value={device.deviceId}>
{device.name} - {device.serialNumber}
</Option>
))}
</Select>
</Form.Item>
) : (
<>
<Form.Item name="deviceName" label="设备名称" rules={[{ required: true }]}>
<Input placeholder="请输入设备名称" />
</Form.Item>
<Form.Item name="serialNumber" label="设备序列号" rules={[{ required: true }]}>
<Input placeholder="请输入设备序列号" />
</Form.Item>
</>
)}
<Form.Item name="faultCategory" label="故障分类" rules={[{ required: true }]}>
<Select placeholder="选择故障分类">
{categories.map(cat => (