diff --git a/src/X1.WebUI/src/constants/menuConfig.ts b/src/X1.WebUI/src/constants/menuConfig.ts
index bc29579..f9a80ca 100644
--- a/src/X1.WebUI/src/constants/menuConfig.ts
+++ b/src/X1.WebUI/src/constants/menuConfig.ts
@@ -173,7 +173,7 @@ export const menuItems: MenuItem[] = [
children: [
{
title: '设备列表',
- href: '/dashboard/instruments/devices',
+ href: '/dashboard/instruments/list',
permission: 'devices.view',
},
{
diff --git a/src/X1.WebUI/src/pages/instruments/ConfigsTable.tsx b/src/X1.WebUI/src/pages/configs/ConfigsTable.tsx
similarity index 99%
rename from src/X1.WebUI/src/pages/instruments/ConfigsTable.tsx
rename to src/X1.WebUI/src/pages/configs/ConfigsTable.tsx
index b51885d..6eb67fc 100644
--- a/src/X1.WebUI/src/pages/instruments/ConfigsTable.tsx
+++ b/src/X1.WebUI/src/pages/configs/ConfigsTable.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Button } from '@/components/ui/button';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
-import { Config, ConfigType } from '@/services/instrumentService';
+import { Config, ConfigType } from '@/services/configService';
import { Badge } from '@/components/ui/badge';
import { EyeOpenIcon, CheckIcon, PlayIcon } from '@radix-ui/react-icons';
diff --git a/src/X1.WebUI/src/pages/instruments/ConfigsView.tsx b/src/X1.WebUI/src/pages/configs/ConfigsView.tsx
similarity index 97%
rename from src/X1.WebUI/src/pages/instruments/ConfigsView.tsx
rename to src/X1.WebUI/src/pages/configs/ConfigsView.tsx
index 69f940e..37a31ae 100644
--- a/src/X1.WebUI/src/pages/instruments/ConfigsView.tsx
+++ b/src/X1.WebUI/src/pages/configs/ConfigsView.tsx
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import { instrumentService, Config } from '@/services/instrumentService';
+import { configService, Config } from '@/services/configService';
import ConfigsTable from './ConfigsTable';
import { Input } from '@/components/ui/input';
import PaginationBar from '@/components/ui/PaginationBar';
@@ -68,7 +68,7 @@ export default function ConfigsView() {
const fetchConfigs = async (params = {}) => {
setLoading(true);
- const result = await instrumentService.getAllConfigs({ configId, page, pageSize, ...params });
+ const result = await configService.getAllConfigs({ configId, page, pageSize, ...params });
if (result.isSuccess && result.data) {
setConfigs(result.data.configs || []);
setTotal(result.data.totalCount || 0);
diff --git a/src/X1.WebUI/src/pages/instruments/DevicesTable.tsx b/src/X1.WebUI/src/pages/instruments/DevicesTable.tsx
index c02668c..32cb927 100644
--- a/src/X1.WebUI/src/pages/instruments/DevicesTable.tsx
+++ b/src/X1.WebUI/src/pages/instruments/DevicesTable.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Button } from '@/components/ui/button';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
-import { Device, DeviceStatus, DeviceType } from '@/services/instrumentService';
+import { Device, DeviceStatus, DeviceType } from '@/services/deviceService';
import { Badge } from '@/components/ui/badge';
import { EyeOpenIcon, PlayIcon } from '@radix-ui/react-icons';
diff --git a/src/X1.WebUI/src/pages/instruments/DevicesView.tsx b/src/X1.WebUI/src/pages/instruments/DevicesView.tsx
index ff09a43..e304ffe 100644
--- a/src/X1.WebUI/src/pages/instruments/DevicesView.tsx
+++ b/src/X1.WebUI/src/pages/instruments/DevicesView.tsx
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import { instrumentService, Device } from '@/services/instrumentService';
+import { deviceService, Device } from '@/services/deviceService';
import DevicesTable from './DevicesTable';
import { Input } from '@/components/ui/input';
import PaginationBar from '@/components/ui/PaginationBar';
@@ -65,7 +65,7 @@ export default function DevicesView() {
const fetchDevices = async (params = {}) => {
setLoading(true);
- const result = await instrumentService.getAllDevices({ deviceId, page, pageSize, ...params });
+ const result = await deviceService.getAllDevices({ deviceId, page, pageSize, ...params });
if (result.isSuccess && result.data) {
setDevices(result.data.devices || []);
setTotal(result.data.totalCount || 0);
diff --git a/src/X1.WebUI/src/pages/instruments/ProtocolsTable.tsx b/src/X1.WebUI/src/pages/instruments/ProtocolsTable.tsx
deleted file mode 100644
index cbf4e1f..0000000
--- a/src/X1.WebUI/src/pages/instruments/ProtocolsTable.tsx
+++ /dev/null
@@ -1,254 +0,0 @@
-import React from 'react';
-import { Button } from '@/components/ui/button';
-import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
-import { Protocol, ProtocolType } from '@/services/instrumentService';
-import { Badge } from '@/components/ui/badge';
-import { EyeOpenIcon, FileTextIcon } from '@radix-ui/react-icons';
-
-interface ProtocolsTableProps {
- protocols: Protocol[];
- loading: boolean;
- onView: (protocol: Protocol) => void;
- onViewDocumentation: (protocol: Protocol) => void;
- page: number;
- pageSize: number;
- total: number;
- onPageChange: (page: number) => void;
- hideCard?: boolean;
- density?: 'compact' | 'default' | 'comfortable';
- columns?: { key: string; title: string; visible: boolean }[];
-}
-
-// 协议类型徽章组件
-const ProtocolTypeBadge: React.FC<{ type: ProtocolType }> = ({ type }) => {
- const typeConfig = {
- modbus: { label: 'Modbus', className: 'bg-blue-100 text-blue-800' },
- opcua: { label: 'OPC UA', className: 'bg-green-100 text-green-800' },
- mqtt: { label: 'MQTT', className: 'bg-purple-100 text-purple-800' },
- http: { label: 'HTTP', className: 'bg-orange-100 text-orange-800' },
- tcp: { label: 'TCP', className: 'bg-indigo-100 text-indigo-800' },
- udp: { label: 'UDP', className: 'bg-teal-100 text-teal-800' },
- serial: { label: 'Serial', className: 'bg-gray-100 text-gray-800' },
- };
-
- const config = typeConfig[type];
- return (
-
- {config.label}
-
- );
-};
-
-// 状态徽章组件
-const StatusBadge: React.FC<{ isActive: boolean }> = ({ isActive }) => {
- return (
-
- {isActive ? '启用' : '禁用'}
-
- );
-};
-
-// 安全级别徽章组件
-const SecurityLevelBadge: React.FC<{ level: 'low' | 'medium' | 'high' }> = ({ level }) => {
- const levelConfig = {
- low: { label: '低', className: 'bg-green-100 text-green-800' },
- medium: { label: '中', className: 'bg-yellow-100 text-yellow-800' },
- high: { label: '高', className: 'bg-red-100 text-red-800' },
- };
-
- const config = levelConfig[level];
- return (
-
- {config.label}
-
- );
-};
-
-// 加密类型徽章组件
-const EncryptionTypeBadge: React.FC<{ type: 'none' | 'ssl' | 'tls' | 'aes' }> = ({ type }) => {
- const typeConfig = {
- none: { label: '无', className: 'bg-gray-100 text-gray-800' },
- ssl: { label: 'SSL', className: 'bg-blue-100 text-blue-800' },
- tls: { label: 'TLS', className: 'bg-green-100 text-green-800' },
- aes: { label: 'AES', className: 'bg-purple-100 text-purple-800' },
- };
-
- const config = typeConfig[type];
- return (
-
- {config.label}
-
- );
-};
-
-// 认证类型徽章组件
-const AuthenticationTypeBadge: React.FC<{ type: 'none' | 'basic' | 'token' | 'certificate' }> = ({ type }) => {
- const typeConfig = {
- none: { label: '无', className: 'bg-gray-100 text-gray-800' },
- basic: { label: '基本', className: 'bg-blue-100 text-blue-800' },
- token: { label: '令牌', className: 'bg-green-100 text-green-800' },
- certificate: { label: '证书', className: 'bg-purple-100 text-purple-800' },
- };
-
- const config = typeConfig[type];
- return (
-
- {config.label}
-
- );
-};
-
-// 数据格式徽章组件
-const DataFormatBadge: React.FC<{ format: 'json' | 'xml' | 'binary' | 'csv' }> = ({ format }) => {
- const formatConfig = {
- json: { label: 'JSON', className: 'bg-blue-100 text-blue-800' },
- xml: { label: 'XML', className: 'bg-green-100 text-green-800' },
- binary: { label: 'Binary', className: 'bg-purple-100 text-purple-800' },
- csv: { label: 'CSV', className: 'bg-orange-100 text-orange-800' },
- };
-
- const config = formatConfig[format];
- return (
-
- {config.label}
-
- );
-};
-
-export default function ProtocolsTable({
- protocols,
- loading,
- onView,
- onViewDocumentation,
- page,
- pageSize,
- total,
- onPageChange,
- hideCard = false,
- density = 'default',
- columns = []
-}: ProtocolsTableProps) {
- const densityClasses = {
- compact: 'py-1',
- default: 'py-2',
- comfortable: 'py-3',
- };
-
- const visibleColumns = columns.filter(col => col.visible);
-
- const renderCell = (protocol: Protocol, columnKey: string) => {
- switch (columnKey) {
- case 'protocolId':
- return (
-
- {protocol.protocolId}
-
- );
- case 'protocolName':
- return (
-
- {protocol.protocolName}
-
- );
- case 'protocolType':
- return ;
- case 'version':
- return {protocol.version};
- case 'isActive':
- return ;
- case 'defaultPort':
- return {protocol.defaultPort};
- case 'securityLevel':
- return ;
- case 'encryptionType':
- return ;
- case 'authenticationType':
- return ;
- case 'connectionTimeout':
- return {protocol.connectionTimeout}ms;
- case 'dataFormat':
- return ;
- case 'createdBy':
- return {protocol.createdBy};
- case 'actions':
- return (
-
-
-
-
- );
- default:
- return null;
- }
- };
-
- if (loading) {
- return (
-
- );
- }
-
- if (protocols.length === 0) {
- return (
-
- );
- }
-
- const tableContent = (
-
-
-
- {visibleColumns.map((column) => (
-
- {column.title}
-
- ))}
-
-
-
- {protocols.map((protocol) => (
-
- {visibleColumns.map((column) => (
-
- {renderCell(protocol, column.key)}
-
- ))}
-
- ))}
-
-
- );
-
- if (hideCard) {
- return tableContent;
- }
-
- return (
-
- {tableContent}
-
- );
-}
\ No newline at end of file
diff --git a/src/X1.WebUI/src/pages/instruments/ProtocolsView.tsx b/src/X1.WebUI/src/pages/instruments/ProtocolsView.tsx
deleted file mode 100644
index ddcdd66..0000000
--- a/src/X1.WebUI/src/pages/instruments/ProtocolsView.tsx
+++ /dev/null
@@ -1,209 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { instrumentService, Protocol } from '@/services/instrumentService';
-import ProtocolsTable from './ProtocolsTable';
-import { Input } from '@/components/ui/input';
-import PaginationBar from '@/components/ui/PaginationBar';
-import TableToolbar, { DensityType } from '@/components/ui/TableToolbar';
-import { ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons';
-
-const defaultColumns = [
- { key: 'protocolId', title: '协议ID', visible: true },
- { key: 'protocolName', title: '协议名称', visible: true },
- { key: 'protocolType', title: '协议类型', visible: true },
- { key: 'version', title: '版本', visible: true },
- { key: 'isActive', title: '状态', visible: true },
- { key: 'defaultPort', title: '默认端口', visible: true },
- { key: 'securityLevel', title: '安全级别', visible: true },
- { key: 'encryptionType', title: '加密类型', visible: true },
- { key: 'authenticationType', title: '认证类型', visible: true },
- { key: 'connectionTimeout', title: '连接超时(ms)', visible: true },
- { key: 'dataFormat', title: '数据格式', visible: true },
- { key: 'createdBy', title: '创建人', visible: true },
- { key: 'actions', title: '操作', visible: true }
-];
-
-// 字段类型声明
-type SearchField =
- | { key: string; label: string; type: 'input'; placeholder: string }
- | { key: string; label: string; type: 'select'; options: { value: string; label: string }[] };
-
-// 第一行字段(收起时只显示这3个)
-const firstRowFields: SearchField[] = [
- { key: 'protocolId', label: '协议ID', type: 'input', placeholder: '请输入' },
- { key: 'protocolType', label: '协议类型', type: 'select', options: [
- { value: '', label: '请选择' },
- { value: 'modbus', label: 'Modbus' },
- { value: 'opcua', label: 'OPC UA' },
- { value: 'mqtt', label: 'MQTT' },
- { value: 'http', label: 'HTTP' },
- { value: 'tcp', label: 'TCP' },
- { value: 'udp', label: 'UDP' },
- { value: 'serial', label: 'Serial' },
- ] },
- { key: 'isActive', label: '状态', type: 'select', options: [
- { value: '', label: '请选择' },
- { value: 'true', label: '启用' },
- { value: 'false', label: '禁用' },
- ] },
-];
-
-// 高级字段(展开时才显示)
-const advancedFields: SearchField[] = [
- { key: 'version', label: '版本', type: 'input', placeholder: '请输入' },
- { key: 'createdBy', label: '创建人', type: 'input', placeholder: '请输入' },
-];
-
-export default function ProtocolsView() {
- const [protocols, setProtocols] = useState([]);
- const [loading, setLoading] = useState(false);
- const [total, setTotal] = useState(0);
- const [protocolId, setProtocolId] = useState('');
- const [page, setPage] = useState(1);
- const [pageSize, setPageSize] = useState(10);
- const [density, setDensity] = useState('default');
- const [columns, setColumns] = useState(defaultColumns);
- const [showAdvanced, setShowAdvanced] = useState(false);
-
- const fetchProtocols = async (params = {}) => {
- setLoading(true);
- const result = await instrumentService.getAllProtocols({ protocolId, page, pageSize, ...params });
- if (result.isSuccess && result.data) {
- setProtocols(result.data.protocols || []);
- setTotal(result.data.totalCount || 0);
- }
- setLoading(false);
- };
-
- useEffect(() => {
- fetchProtocols();
- // eslint-disable-next-line
- }, [page, pageSize]);
-
- const handleView = (protocol: Protocol) => {
- // 这里可以实现查看协议详情的逻辑
- console.log('查看协议:', protocol);
- };
-
- const handleViewDocumentation = (protocol: Protocol) => {
- // 这里可以实现查看协议文档的逻辑
- console.log('查看协议文档:', protocol);
- };
-
- // 查询按钮
- const handleQuery = () => {
- setPage(1);
- fetchProtocols({ page: 1 });
- };
-
- // 重置按钮
- const handleReset = () => {
- setProtocolId('');
- setPage(1);
- fetchProtocols({ protocolId: '', page: 1 });
- };
-
- // 每页条数选择
- const handlePageSizeChange = (size: number) => {
- setPageSize(size);
- setPage(1);
- };
-
- const totalPages = Math.ceil(total / pageSize);
-
- return (
-
-
- {/* 丰富美化后的搜索栏 */}
-
- {/* 表格整体卡片区域,包括工具栏、表格、分页 */}
-
- {/* 顶部工具栏 */}
-
-
fetchProtocols()}
- onDensityChange={setDensity}
- onColumnsChange={setColumns}
- onColumnsReset={() => setColumns(defaultColumns)}
- columns={columns}
- density={density}
- />
-
- {/* 表格区域 */}
-
- {/* 分页 */}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/src/X1.WebUI/src/pages/protocols/ProtocolForm.tsx b/src/X1.WebUI/src/pages/protocols/ProtocolForm.tsx
new file mode 100644
index 0000000..f25af5e
--- /dev/null
+++ b/src/X1.WebUI/src/pages/protocols/ProtocolForm.tsx
@@ -0,0 +1,109 @@
+import React from 'react';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import { Textarea } from '@/components/ui/textarea';
+import { Checkbox } from '@/components/ui/checkbox';
+import { CreateProtocolVersionRequest, UpdateProtocolVersionRequest } from '@/services/protocolService';
+
+interface ProtocolFormProps {
+ onSubmit: (data: CreateProtocolVersionRequest | UpdateProtocolVersionRequest) => void;
+ initialData?: Partial;
+ isEdit?: boolean;
+ isSubmitting?: boolean;
+}
+
+export default function ProtocolForm({ onSubmit, initialData, isEdit = false, isSubmitting = false }: ProtocolFormProps) {
+ const [formData, setFormData] = React.useState({
+ name: initialData?.name || '',
+ version: initialData?.version || '',
+ description: initialData?.description || '',
+ isEnabled: initialData?.isEnabled ?? true,
+ releaseDate: initialData?.releaseDate || '',
+ minimumSupportedVersion: initialData?.minimumSupportedVersion || ''
+ });
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ if (isSubmitting) return; // 防止重复提交
+ onSubmit(formData);
+ };
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/X1.WebUI/src/pages/protocols/ProtocolsTable.tsx b/src/X1.WebUI/src/pages/protocols/ProtocolsTable.tsx
new file mode 100644
index 0000000..2683ffe
--- /dev/null
+++ b/src/X1.WebUI/src/pages/protocols/ProtocolsTable.tsx
@@ -0,0 +1,167 @@
+import React from 'react';
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
+import { ProtocolVersion } from '@/services/protocolService';
+import { Badge } from '@/components/ui/badge';
+
+interface ProtocolsTableProps {
+ protocolVersions: ProtocolVersion[];
+ loading: boolean;
+ onEdit: (protocolVersion: ProtocolVersion) => void;
+ onDelete: (protocolVersion: ProtocolVersion) => void;
+ page: number;
+ pageSize: number;
+ total: number;
+ onPageChange: (page: number) => void;
+ hideCard?: boolean;
+ density?: 'relaxed' | 'default' | 'compact';
+ columns?: { key: string; title: string; visible: boolean }[];
+}
+
+// 状态徽章组件
+const StatusBadge: React.FC<{ isEnabled: boolean }> = ({ isEnabled }) => {
+ return (
+
+ {isEnabled ? '启用' : '禁用'}
+
+ );
+};
+
+// 日期格式化组件
+const DateDisplay: React.FC<{ date?: string }> = ({ date }) => {
+ if (!date) return -;
+
+ const formatDate = (dateString: string) => {
+ const date = new Date(dateString);
+ return date.toLocaleDateString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit'
+ });
+ };
+
+ return {formatDate(date)};
+};
+
+export default function ProtocolsTable({
+ protocolVersions,
+ loading,
+ onEdit,
+ onDelete,
+ page,
+ pageSize,
+ total,
+ onPageChange,
+ hideCard = false,
+ density = 'default',
+ columns = []
+}: ProtocolsTableProps) {
+ const densityClasses = {
+ relaxed: 'py-3',
+ default: 'py-2',
+ compact: 'py-1',
+ };
+
+ const visibleColumns = columns.filter(col => col.visible);
+
+ const renderCell = (protocolVersion: ProtocolVersion, columnKey: string) => {
+ switch (columnKey) {
+ case 'name':
+ return (
+
+ {protocolVersion.name}
+
+ );
+ case 'version':
+ return {protocolVersion.version};
+ case 'description':
+ return (
+
+ {protocolVersion.description || '-'}
+
+ );
+ case 'isEnabled':
+ return ;
+ case 'releaseDate':
+ return ;
+ case 'minimumSupportedVersion':
+ return (
+
+ {protocolVersion.minimumSupportedVersion || '-'}
+
+ );
+ case 'createdAt':
+ return ;
+ case 'actions':
+ return (
+
+ onEdit(protocolVersion)}
+ >
+ 修改
+
+ onDelete(protocolVersion)}
+ >
+ 删除
+
+
+ );
+ default:
+ return null;
+ }
+ };
+
+ const totalPages = Math.ceil(total / pageSize);
+ const Wrapper = hideCard ? React.Fragment : 'div';
+ const wrapperProps = hideCard ? {} : { className: 'rounded-md border bg-background' };
+ const rowClass = density === 'relaxed' ? 'h-20' : density === 'compact' ? 'h-8' : 'h-12';
+ const cellPadding = density === 'relaxed' ? 'py-5' : density === 'compact' ? 'py-1' : 'py-3';
+
+ return (
+
+
+
+
+ {visibleColumns.map(col => (
+
+ {col.title}
+
+ ))}
+
+
+
+ {loading ? (
+
+
+ 加载中...
+
+
+ ) : protocolVersions.length === 0 ? (
+
+
+ 暂无数据
+
+
+ ) : (
+ protocolVersions.map((protocolVersion) => (
+
+ {visibleColumns.map((column) => (
+
+ {renderCell(protocolVersion, column.key)}
+
+ ))}
+
+ ))
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/X1.WebUI/src/pages/protocols/ProtocolsView.tsx b/src/X1.WebUI/src/pages/protocols/ProtocolsView.tsx
new file mode 100644
index 0000000..76a7207
--- /dev/null
+++ b/src/X1.WebUI/src/pages/protocols/ProtocolsView.tsx
@@ -0,0 +1,360 @@
+import React, { useEffect, useState } from 'react';
+import { protocolService, ProtocolVersion, GetProtocolVersionsRequest, CreateProtocolVersionRequest, UpdateProtocolVersionRequest } from '@/services/protocolService';
+import ProtocolsTable from './ProtocolsTable';
+import ProtocolForm from './ProtocolForm';
+import { Input } from '@/components/ui/input';
+import PaginationBar from '@/components/ui/PaginationBar';
+import TableToolbar, { DensityType } from '@/components/ui/TableToolbar';
+import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog';
+import { Button } from '@/components/ui/button';
+import { ChevronDownIcon, ChevronUpIcon } from '@radix-ui/react-icons';
+import { useToast } from '@/components/ui/use-toast';
+
+const defaultColumns = [
+ { key: 'name', title: '版本名称', visible: true },
+ { key: 'version', title: '版本号', visible: true },
+ { key: 'description', title: '描述', visible: true },
+ { key: 'isEnabled', title: '状态', visible: true },
+ { key: 'releaseDate', title: '发布日期', visible: true },
+ { key: 'minimumSupportedVersion', title: '最低支持版本', visible: true },
+ { key: 'createdAt', title: '创建时间', visible: true },
+ { key: 'actions', title: '操作', visible: true }
+];
+
+// 字段类型声明
+type SearchField =
+ | { key: string; label: string; type: 'input'; placeholder: string }
+ | { key: string; label: string; type: 'select'; options: { value: string; label: string }[] };
+
+// 第一行字段(收起时只显示这3个)
+const firstRowFields: SearchField[] = [
+ { key: 'searchTerm', label: '搜索关键词', type: 'input', placeholder: '请输入版本名称或版本号' },
+ { key: 'isEnabled', label: '状态', type: 'select', options: [
+ { value: '', label: '请选择' },
+ { value: 'true', label: '启用' },
+ { value: 'false', label: '禁用' },
+ ] },
+];
+
+// 高级字段(展开时才显示)
+const advancedFields: SearchField[] = [
+ { key: 'pageSize', label: '每页数量', type: 'select', options: [
+ { value: '10', label: '10条/页' },
+ { value: '20', label: '20条/页' },
+ { value: '50', label: '50条/页' },
+ { value: '100', label: '100条/页' },
+ ] },
+];
+
+export default function ProtocolsView() {
+ const [protocolVersions, setProtocolVersions] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [total, setTotal] = useState(0);
+ const [pageNumber, setPageNumber] = useState(1);
+ const [pageSize, setPageSize] = useState(10);
+ const [density, setDensity] = useState('default');
+ const [columns, setColumns] = useState(defaultColumns);
+ const [showAdvanced, setShowAdvanced] = useState(false);
+
+ // 搜索参数
+ const [searchTerm, setSearchTerm] = useState('');
+ const [isEnabled, setIsEnabled] = useState(undefined);
+
+ // 表单对话框状态
+ const [open, setOpen] = useState(false);
+ const [editOpen, setEditOpen] = useState(false);
+ const [selectedProtocol, setSelectedProtocol] = useState(null);
+
+ // 提交状态
+ const [isSubmitting, setIsSubmitting] = useState(false);
+
+ // Toast 提示
+ const { toast } = useToast();
+
+ const fetchProtocolVersions = async (params: Partial = {}) => {
+ setLoading(true);
+ const queryParams: GetProtocolVersionsRequest = {
+ pageNumber,
+ pageSize,
+ searchTerm,
+ isEnabled,
+ ...params
+ };
+
+ const result = await protocolService.getProtocolVersions(queryParams);
+ if (result.isSuccess && result.data) {
+ setProtocolVersions(result.data.items || []);
+ setTotal(result.data.totalCount || 0);
+ }
+ setLoading(false);
+ };
+
+ useEffect(() => {
+ fetchProtocolVersions();
+ // eslint-disable-next-line
+ }, [pageNumber, pageSize]);
+
+
+
+ const handleEdit = (protocolVersion: ProtocolVersion) => {
+ setSelectedProtocol(protocolVersion);
+ setEditOpen(true);
+ };
+
+ const handleDelete = async (protocolVersion: ProtocolVersion) => {
+ if (confirm(`确定要删除协议版本 "${protocolVersion.name}" 吗?`)) {
+ try {
+ const result = await protocolService.deleteProtocolVersion(protocolVersion.protocolVersionId);
+ if (result.isSuccess) {
+ toast({
+ title: "删除成功",
+ description: `协议版本 "${protocolVersion.name}" 删除成功`,
+ });
+ fetchProtocolVersions();
+ } else {
+ const errorMessage = result.errorMessages?.join(', ') || "删除协议版本时发生错误";
+ console.error('删除协议版本失败:', errorMessage);
+ toast({
+ title: "删除失败",
+ description: errorMessage,
+ variant: "destructive",
+ });
+ }
+ } catch (error) {
+ console.error('删除协议版本异常:', error);
+ toast({
+ title: "删除失败",
+ description: "网络错误,请稍后重试",
+ variant: "destructive",
+ });
+ }
+ }
+ };
+
+ const handleCreate = async (data: CreateProtocolVersionRequest) => {
+ if (isSubmitting) return; // 防止重复提交
+
+ console.log('开始创建协议版本:', data);
+ setIsSubmitting(true);
+ try {
+ const result = await protocolService.createProtocolVersion(data);
+ console.log('创建协议版本结果:', result);
+
+ if (result.isSuccess) {
+ toast({
+ title: "创建成功",
+ description: `协议版本 "${data.name}" 创建成功`,
+ });
+ setOpen(false);
+ fetchProtocolVersions();
+ } else {
+ const errorMessage = result.errorMessages?.join(', ') || "创建协议版本时发生错误";
+ console.error('创建协议版本失败:', errorMessage, result);
+ toast({
+ title: "创建失败",
+ description: errorMessage,
+ variant: "destructive",
+ });
+ }
+ } catch (error) {
+ console.error('创建协议版本异常:', error);
+ toast({
+ title: "创建失败",
+ description: "网络错误,请稍后重试",
+ variant: "destructive",
+ });
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ const handleUpdate = async (data: UpdateProtocolVersionRequest) => {
+ if (!selectedProtocol || isSubmitting) return; // 防止重复提交
+
+ setIsSubmitting(true);
+ try {
+ const result = await protocolService.updateProtocolVersion(selectedProtocol.protocolVersionId, data);
+ if (result.isSuccess) {
+ toast({
+ title: "更新成功",
+ description: `协议版本 "${data.name}" 更新成功`,
+ });
+ setEditOpen(false);
+ setSelectedProtocol(null);
+ fetchProtocolVersions();
+ } else {
+ const errorMessage = result.errorMessages?.join(', ') || "更新协议版本时发生错误";
+ console.error('更新协议版本失败:', errorMessage);
+ toast({
+ title: "更新失败",
+ description: errorMessage,
+ variant: "destructive",
+ });
+ }
+ } catch (error) {
+ console.error('更新协议版本异常:', error);
+ toast({
+ title: "更新失败",
+ description: "网络错误,请稍后重试",
+ variant: "destructive",
+ });
+ } finally {
+ setIsSubmitting(false);
+ }
+ };
+
+ // 查询按钮
+ const handleQuery = () => {
+ setPageNumber(1);
+ fetchProtocolVersions({ pageNumber: 1 });
+ };
+
+ // 重置按钮
+ const handleReset = () => {
+ setSearchTerm('');
+ setIsEnabled(undefined);
+ setPageNumber(1);
+ fetchProtocolVersions({
+ searchTerm: '',
+ isEnabled: undefined,
+ pageNumber: 1
+ });
+ };
+
+ // 每页条数选择
+ const handlePageSizeChange = (size: number) => {
+ setPageSize(size);
+ setPageNumber(1);
+ };
+
+ const totalPages = Math.ceil(total / pageSize);
+
+ return (
+
+
+ {/* 丰富美化后的搜索栏 */}
+
+
+
+ {/* 表格整体卡片区域,包括工具栏、表格、分页 */}
+
+ {/* 顶部操作栏:添加协议版本+工具栏 */}
+
+
+
fetchProtocolVersions()}
+ onDensityChange={setDensity}
+ onColumnsChange={setColumns}
+ onColumnsReset={() => setColumns(defaultColumns)}
+ columns={columns}
+ density={density}
+ />
+
+ {/* 表格区域 */}
+
+ {/* 分页 */}
+
+
+
+
+ {/* 编辑协议版本对话框 */}
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/X1.WebUI/src/routes/AppRouter.tsx b/src/X1.WebUI/src/routes/AppRouter.tsx
index 3810d2b..96fa850 100644
--- a/src/X1.WebUI/src/routes/AppRouter.tsx
+++ b/src/X1.WebUI/src/routes/AppRouter.tsx
@@ -29,10 +29,12 @@ const PerformanceAnalysisView = lazy(() => import('@/pages/analysis/PerformanceA
const IssueAnalysisView = lazy(() => import('@/pages/analysis/IssueAnalysisView'));
const UEAnalysisView = lazy(() => import('@/pages/analysis/UEAnalysisView'));
-// 仪表管理页面
+// 设备管理页面
const DevicesView = lazy(() => import('@/pages/instruments/DevicesView'));
-const ProtocolsView = lazy(() => import('@/pages/instruments/ProtocolsView'));
-const ConfigsView = lazy(() => import('@/pages/instruments/ConfigsView'));
+// 协议管理页面
+const ProtocolsView = lazy(() => import('@/pages/protocols/ProtocolsView'));
+// 配置管理页面
+const ConfigsView = lazy(() => import('@/pages/configs/ConfigsView'));
// 加载中的占位组件
const LoadingFallback = () => (
@@ -184,8 +186,8 @@ export function AppRouter() {
{/* 仪表管理路由 */}
- } />
- } />
+
diff --git a/src/X1.WebUI/src/services/configService.ts b/src/X1.WebUI/src/services/configService.ts
new file mode 100644
index 0000000..b11e9af
--- /dev/null
+++ b/src/X1.WebUI/src/services/configService.ts
@@ -0,0 +1,119 @@
+import { httpClient } from '@/lib/http-client';
+import { OperationResult } from '@/types/auth';
+
+// 配置类型
+export type ConfigType = 'system' | 'network' | 'security' | 'communication' | 'monitoring';
+
+// 配置接口定义
+export interface Config {
+ id: string;
+ configId: string;
+ configName: string;
+ configType: ConfigType;
+ description: string;
+ isActive: boolean;
+ isDefault: boolean;
+ version: string;
+ parameters: {
+ [key: string]: any;
+ };
+ networkSettings: {
+ ipAddress: string;
+ subnet: string;
+ gateway: string;
+ dns: string[];
+ port: number;
+ };
+ securitySettings: {
+ encryptionEnabled: boolean;
+ authenticationRequired: boolean;
+ sslEnabled: boolean;
+ certificatePath: string;
+ keyPath: string;
+ };
+ communicationSettings: {
+ protocol: string;
+ timeout: number;
+ retryCount: number;
+ heartbeatInterval: number;
+ };
+ monitoringSettings: {
+ dataCollectionInterval: number;
+ alertThresholds: {
+ [key: string]: number;
+ };
+ logLevel: 'debug' | 'info' | 'warn' | 'error';
+ };
+ appliedTo: string[]; // 应用此配置的设备ID列表
+ createdAt: string;
+ updatedAt: string;
+ createdBy: string;
+ updatedBy: string;
+}
+
+// 获取配置列表请求接口
+export interface GetAllConfigsRequest {
+ configId?: string;
+ configName?: string;
+ configType?: ConfigType;
+ isActive?: boolean;
+ isDefault?: boolean;
+ version?: string;
+ createdBy?: string;
+ page?: number;
+ pageSize?: number;
+}
+
+// 获取配置列表响应接口
+export interface GetAllConfigsResponse {
+ configs: Config[];
+ totalCount: number;
+}
+
+class ConfigService {
+ private readonly baseUrl = '/api/instruments/configs';
+
+ // 获取所有配置
+ async getAllConfigs(params: GetAllConfigsRequest = {}): Promise> {
+ const queryParams = new URLSearchParams();
+
+ if (params.configId) queryParams.append('configId', params.configId);
+ if (params.configName) queryParams.append('configName', params.configName);
+ if (params.configType) queryParams.append('configType', params.configType);
+ if (params.isActive !== undefined) queryParams.append('isActive', params.isActive.toString());
+ if (params.isDefault !== undefined) queryParams.append('isDefault', params.isDefault.toString());
+ if (params.version) queryParams.append('version', params.version);
+ if (params.createdBy) queryParams.append('createdBy', params.createdBy);
+ if (params.page) queryParams.append('page', params.page.toString());
+ if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
+
+ const url = `${this.baseUrl}?${queryParams.toString()}`;
+ return httpClient.get(url);
+ }
+
+ // 根据ID获取配置
+ async getConfigById(id: string): Promise> {
+ return httpClient.get(`${this.baseUrl}/${id}`);
+ }
+
+ // 验证配置
+ async validateConfig(configId: string): Promise> {
+ return httpClient.post(`${this.baseUrl}/${configId}/validate`);
+ }
+
+ // 应用配置到设备
+ async applyConfigToDevice(configId: string, deviceIds: string[]): Promise> {
+ return httpClient.post(`${this.baseUrl}/${configId}/apply`, { deviceIds });
+ }
+
+ // 导出配置列表
+ async exportConfigs(format: 'pdf' | 'excel' | 'csv', filters?: any): Promise> {
+ return httpClient.post(`${this.baseUrl}/export`, { format, filters });
+ }
+}
+
+export const configService = new ConfigService();
\ No newline at end of file
diff --git a/src/X1.WebUI/src/services/deviceService.ts b/src/X1.WebUI/src/services/deviceService.ts
new file mode 100644
index 0000000..e52f4a2
--- /dev/null
+++ b/src/X1.WebUI/src/services/deviceService.ts
@@ -0,0 +1,113 @@
+import { httpClient } from '@/lib/http-client';
+import { OperationResult } from '@/types/auth';
+
+// 设备状态类型
+export type DeviceStatus = 'online' | 'offline' | 'maintenance' | 'error';
+
+// 设备类型
+export type DeviceType = 'sensor' | 'controller' | 'monitor' | 'actuator' | 'gateway';
+
+// 设备接口定义
+export interface Device {
+ id: string;
+ deviceId: string;
+ deviceName: string;
+ deviceType: DeviceType;
+ status: DeviceStatus;
+ protocolId: string;
+ protocolName: string;
+ ipAddress: string;
+ port: number;
+ location: string;
+ description: string;
+ manufacturer: string;
+ model: string;
+ serialNumber: string;
+ firmwareVersion: string;
+ lastHeartbeat: string;
+ lastDataUpdate: string;
+ configId: string;
+ configName: string;
+ tags: string[];
+ properties: {
+ [key: string]: any;
+ };
+ createdAt: string;
+ updatedAt: string;
+ createdBy: string;
+ updatedBy: string;
+}
+
+// 获取设备列表请求接口
+export interface GetAllDevicesRequest {
+ deviceId?: string;
+ deviceName?: string;
+ deviceType?: DeviceType;
+ status?: DeviceStatus;
+ protocolId?: string;
+ location?: string;
+ manufacturer?: string;
+ createdBy?: string;
+ page?: number;
+ pageSize?: number;
+}
+
+// 获取设备列表响应接口
+export interface GetAllDevicesResponse {
+ devices: Device[];
+ totalCount: number;
+}
+
+class DeviceService {
+ private readonly baseUrl = '/api/instruments/devices';
+
+ // 获取所有设备
+ async getAllDevices(params: GetAllDevicesRequest = {}): Promise> {
+ const queryParams = new URLSearchParams();
+
+ if (params.deviceId) queryParams.append('deviceId', params.deviceId);
+ if (params.deviceName) queryParams.append('deviceName', params.deviceName);
+ if (params.deviceType) queryParams.append('deviceType', params.deviceType);
+ if (params.status) queryParams.append('status', params.status);
+ if (params.protocolId) queryParams.append('protocolId', params.protocolId);
+ if (params.location) queryParams.append('location', params.location);
+ if (params.manufacturer) queryParams.append('manufacturer', params.manufacturer);
+ if (params.createdBy) queryParams.append('createdBy', params.createdBy);
+ if (params.page) queryParams.append('page', params.page.toString());
+ if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
+
+ const url = `${this.baseUrl}?${queryParams.toString()}`;
+ return httpClient.get(url);
+ }
+
+ // 根据ID获取设备
+ async getDeviceById(id: string): Promise> {
+ return httpClient.get(`${this.baseUrl}/${id}`);
+ }
+
+ // 获取设备状态
+ async getDeviceStatus(deviceId: string): Promise> {
+ return httpClient.get(`${this.baseUrl}/${deviceId}/status`);
+ }
+
+ // 测试设备连接
+ async testDeviceConnection(deviceId: string): Promise> {
+ return httpClient.post(`${this.baseUrl}/${deviceId}/test-connection`);
+ }
+
+ // 导出设备列表
+ async exportDevices(format: 'pdf' | 'excel' | 'csv', filters?: any): Promise> {
+ return httpClient.post(`${this.baseUrl}/export`, { format, filters });
+ }
+}
+
+export const deviceService = new DeviceService();
\ No newline at end of file
diff --git a/src/X1.WebUI/src/services/instrumentService.ts b/src/X1.WebUI/src/services/instrumentService.ts
index d17868f..2eacbd5 100644
--- a/src/X1.WebUI/src/services/instrumentService.ts
+++ b/src/X1.WebUI/src/services/instrumentService.ts
@@ -1,316 +1,7 @@
-import { httpClient } from '@/lib/http-client';
-import { OperationResult } from '@/types/auth';
+// 重新导出所有类型和服务,保持向后兼容
+export * from './deviceService';
+export * from './protocolService';
+export * from './configService';
-// 设备状态类型
-export type DeviceStatus = 'online' | 'offline' | 'maintenance' | 'error';
-
-// 设备类型
-export type DeviceType = 'sensor' | 'controller' | 'monitor' | 'actuator' | 'gateway';
-
-// 协议类型
-export type ProtocolType = 'modbus' | 'opcua' | 'mqtt' | 'http' | 'tcp' | 'udp' | 'serial';
-
-// 配置类型
-export type ConfigType = 'system' | 'network' | 'security' | 'communication' | 'monitoring';
-
-// 设备接口定义
-export interface Device {
- id: string;
- deviceId: string;
- deviceName: string;
- deviceType: DeviceType;
- status: DeviceStatus;
- protocolId: string;
- protocolName: string;
- ipAddress: string;
- port: number;
- location: string;
- description: string;
- manufacturer: string;
- model: string;
- serialNumber: string;
- firmwareVersion: string;
- lastHeartbeat: string;
- lastDataUpdate: string;
- configId: string;
- configName: string;
- tags: string[];
- properties: {
- [key: string]: any;
- };
- createdAt: string;
- updatedAt: string;
- createdBy: string;
- updatedBy: string;
-}
-
-// 协议接口定义
-export interface Protocol {
- id: string;
- protocolId: string;
- protocolName: string;
- protocolType: ProtocolType;
- version: string;
- description: string;
- isActive: boolean;
- defaultPort: number;
- supportedFeatures: string[];
- securityLevel: 'low' | 'medium' | 'high';
- encryptionType: 'none' | 'ssl' | 'tls' | 'aes';
- authenticationType: 'none' | 'basic' | 'token' | 'certificate';
- connectionTimeout: number;
- retryAttempts: number;
- heartbeatInterval: number;
- dataFormat: 'json' | 'xml' | 'binary' | 'csv';
- documentation: string;
- examples: string[];
- createdAt: string;
- updatedAt: string;
- createdBy: string;
- updatedBy: string;
-}
-
-// 配置接口定义
-export interface Config {
- id: string;
- configId: string;
- configName: string;
- configType: ConfigType;
- description: string;
- isActive: boolean;
- isDefault: boolean;
- version: string;
- parameters: {
- [key: string]: any;
- };
- networkSettings: {
- ipAddress: string;
- subnet: string;
- gateway: string;
- dns: string[];
- port: number;
- };
- securitySettings: {
- encryptionEnabled: boolean;
- authenticationRequired: boolean;
- sslEnabled: boolean;
- certificatePath: string;
- keyPath: string;
- };
- communicationSettings: {
- protocol: string;
- timeout: number;
- retryCount: number;
- heartbeatInterval: number;
- };
- monitoringSettings: {
- dataCollectionInterval: number;
- alertThresholds: {
- [key: string]: number;
- };
- logLevel: 'debug' | 'info' | 'warn' | 'error';
- };
- appliedTo: string[]; // 应用此配置的设备ID列表
- createdAt: string;
- updatedAt: string;
- createdBy: string;
- updatedBy: string;
-}
-
-// 获取设备列表请求接口
-export interface GetAllDevicesRequest {
- deviceId?: string;
- deviceName?: string;
- deviceType?: DeviceType;
- status?: DeviceStatus;
- protocolId?: string;
- location?: string;
- manufacturer?: string;
- createdBy?: string;
- page?: number;
- pageSize?: number;
-}
-
-// 获取设备列表响应接口
-export interface GetAllDevicesResponse {
- devices: Device[];
- totalCount: number;
-}
-
-// 获取协议列表请求接口
-export interface GetAllProtocolsRequest {
- protocolId?: string;
- protocolName?: string;
- protocolType?: ProtocolType;
- isActive?: boolean;
- version?: string;
- createdBy?: string;
- page?: number;
- pageSize?: number;
-}
-
-// 获取协议列表响应接口
-export interface GetAllProtocolsResponse {
- protocols: Protocol[];
- totalCount: number;
-}
-
-// 获取配置列表请求接口
-export interface GetAllConfigsRequest {
- configId?: string;
- configName?: string;
- configType?: ConfigType;
- isActive?: boolean;
- isDefault?: boolean;
- version?: string;
- createdBy?: string;
- page?: number;
- pageSize?: number;
-}
-
-// 获取配置列表响应接口
-export interface GetAllConfigsResponse {
- configs: Config[];
- totalCount: number;
-}
-
-class InstrumentService {
- private readonly baseUrl = '/api/instruments';
-
- // 获取所有设备
- async getAllDevices(params: GetAllDevicesRequest = {}): Promise> {
- const queryParams = new URLSearchParams();
-
- if (params.deviceId) queryParams.append('deviceId', params.deviceId);
- if (params.deviceName) queryParams.append('deviceName', params.deviceName);
- if (params.deviceType) queryParams.append('deviceType', params.deviceType);
- if (params.status) queryParams.append('status', params.status);
- if (params.protocolId) queryParams.append('protocolId', params.protocolId);
- if (params.location) queryParams.append('location', params.location);
- if (params.manufacturer) queryParams.append('manufacturer', params.manufacturer);
- if (params.createdBy) queryParams.append('createdBy', params.createdBy);
- if (params.page) queryParams.append('page', params.page.toString());
- if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
-
- const url = `${this.baseUrl}/devices?${queryParams.toString()}`;
- return httpClient.get(url);
- }
-
- // 根据ID获取设备
- async getDeviceById(id: string): Promise> {
- return httpClient.get(`${this.baseUrl}/devices/${id}`);
- }
-
- // 获取所有协议
- async getAllProtocols(params: GetAllProtocolsRequest = {}): Promise> {
- const queryParams = new URLSearchParams();
-
- if (params.protocolId) queryParams.append('protocolId', params.protocolId);
- if (params.protocolName) queryParams.append('protocolName', params.protocolName);
- if (params.protocolType) queryParams.append('protocolType', params.protocolType);
- if (params.isActive !== undefined) queryParams.append('isActive', params.isActive.toString());
- if (params.version) queryParams.append('version', params.version);
- if (params.createdBy) queryParams.append('createdBy', params.createdBy);
- if (params.page) queryParams.append('page', params.page.toString());
- if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
-
- const url = `${this.baseUrl}/protocols?${queryParams.toString()}`;
- return httpClient.get(url);
- }
-
- // 根据ID获取协议
- async getProtocolById(id: string): Promise> {
- return httpClient.get(`${this.baseUrl}/protocols/${id}`);
- }
-
- // 获取所有配置
- async getAllConfigs(params: GetAllConfigsRequest = {}): Promise> {
- const queryParams = new URLSearchParams();
-
- if (params.configId) queryParams.append('configId', params.configId);
- if (params.configName) queryParams.append('configName', params.configName);
- if (params.configType) queryParams.append('configType', params.configType);
- if (params.isActive !== undefined) queryParams.append('isActive', params.isActive.toString());
- if (params.isDefault !== undefined) queryParams.append('isDefault', params.isDefault.toString());
- if (params.version) queryParams.append('version', params.version);
- if (params.createdBy) queryParams.append('createdBy', params.createdBy);
- if (params.page) queryParams.append('page', params.page.toString());
- if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
-
- const url = `${this.baseUrl}/configs?${queryParams.toString()}`;
- return httpClient.get(url);
- }
-
- // 根据ID获取配置
- async getConfigById(id: string): Promise> {
- return httpClient.get(`${this.baseUrl}/configs/${id}`);
- }
-
- // 获取仪表统计信息
- async getInstrumentStatistics(): Promise> {
- return httpClient.get(`${this.baseUrl}/statistics`);
- }
-
- // 获取设备状态
- async getDeviceStatus(deviceId: string): Promise> {
- return httpClient.get(`${this.baseUrl}/devices/${deviceId}/status`);
- }
-
- // 测试设备连接
- async testDeviceConnection(deviceId: string): Promise> {
- return httpClient.post(`${this.baseUrl}/devices/${deviceId}/test-connection`);
- }
-
- // 获取协议文档
- async getProtocolDocumentation(protocolId: string): Promise> {
- return httpClient.get(`${this.baseUrl}/protocols/${protocolId}/documentation`);
- }
-
- // 验证配置
- async validateConfig(configId: string): Promise> {
- return httpClient.post(`${this.baseUrl}/configs/${configId}/validate`);
- }
-
- // 应用配置到设备
- async applyConfigToDevice(configId: string, deviceIds: string[]): Promise> {
- return httpClient.post(`${this.baseUrl}/configs/${configId}/apply`, { deviceIds });
- }
-
- // 导出设备列表
- async exportDevices(format: 'pdf' | 'excel' | 'csv', filters?: any): Promise> {
- return httpClient.post(`${this.baseUrl}/devices/export`, { format, filters });
- }
-
- // 导出协议列表
- async exportProtocols(format: 'pdf' | 'excel' | 'csv', filters?: any): Promise> {
- return httpClient.post(`${this.baseUrl}/protocols/export`, { format, filters });
- }
-
- // 导出配置列表
- async exportConfigs(format: 'pdf' | 'excel' | 'csv', filters?: any): Promise> {
- return httpClient.post(`${this.baseUrl}/configs/export`, { format, filters });
- }
-}
-
-export const instrumentService = new InstrumentService();
\ No newline at end of file
+// 为了向后兼容,保留原有的 instrumentService 导出
+export { deviceService as instrumentService } from './deviceService';
\ No newline at end of file
diff --git a/src/X1.WebUI/src/services/protocolService.ts b/src/X1.WebUI/src/services/protocolService.ts
new file mode 100644
index 0000000..8898f59
--- /dev/null
+++ b/src/X1.WebUI/src/services/protocolService.ts
@@ -0,0 +1,122 @@
+import { httpClient } from '@/lib/http-client';
+import { OperationResult } from '@/types/auth';
+
+
+
+// 协议版本接口定义
+export interface ProtocolVersion {
+ protocolVersionId: string;
+ name: string;
+ version: string;
+ description?: string;
+ isEnabled: boolean;
+ releaseDate?: string;
+ minimumSupportedVersion?: string;
+ createdAt: string;
+ updatedAt?: string;
+}
+
+// 获取协议版本列表请求接口
+export interface GetProtocolVersionsRequest {
+ pageNumber?: number;
+ pageSize?: number;
+ searchTerm?: string;
+ isEnabled?: boolean;
+}
+
+// 获取协议版本列表响应接口
+export interface GetProtocolVersionsResponse {
+ totalCount: number;
+ pageNumber: number;
+ pageSize: number;
+ totalPages: number;
+ hasPreviousPage: boolean;
+ hasNextPage: boolean;
+ items: ProtocolVersion[];
+}
+
+// 创建协议版本请求接口
+export interface CreateProtocolVersionRequest {
+ name: string;
+ version: string;
+ description?: string;
+ isEnabled?: boolean;
+ releaseDate?: string;
+ minimumSupportedVersion?: string;
+}
+
+// 创建协议版本响应接口
+export interface CreateProtocolVersionResponse {
+ protocolVersionId: string;
+ name: string;
+ version: string;
+ description?: string;
+ isEnabled: boolean;
+ releaseDate?: string;
+ minimumSupportedVersion?: string;
+ createdAt: string;
+}
+
+// 更新协议版本请求接口
+export interface UpdateProtocolVersionRequest {
+ protocolVersionId: string;
+ name: string;
+ version: string;
+ description?: string;
+ isEnabled?: boolean;
+ releaseDate?: string;
+ minimumSupportedVersion?: string;
+}
+
+// 更新协议版本响应接口
+export interface UpdateProtocolVersionResponse {
+ protocolVersionId: string;
+ name: string;
+ version: string;
+ description?: string;
+ isEnabled: boolean;
+ releaseDate?: string;
+ minimumSupportedVersion?: string;
+ updatedAt: string;
+}
+
+class ProtocolService {
+ private readonly baseUrl = '/protocolversions';
+
+
+
+ // 获取协议版本列表
+ async getProtocolVersions(params: GetProtocolVersionsRequest = {}): Promise> {
+ const queryParams = new URLSearchParams();
+
+ if (params.pageNumber) queryParams.append('pageNumber', params.pageNumber.toString());
+ if (params.pageSize) queryParams.append('pageSize', params.pageSize.toString());
+ if (params.searchTerm) queryParams.append('searchTerm', params.searchTerm);
+ if (params.isEnabled !== undefined) queryParams.append('isEnabled', params.isEnabled.toString());
+
+ const url = `${this.baseUrl}?${queryParams.toString()}`;
+ return httpClient.get(url);
+ }
+
+ // 根据ID获取协议版本详情
+ async getProtocolVersionById(id: string): Promise> {
+ return httpClient.get(`${this.baseUrl}/${id}`);
+ }
+
+ // 创建协议版本
+ async createProtocolVersion(data: CreateProtocolVersionRequest): Promise> {
+ return httpClient.post(this.baseUrl, data);
+ }
+
+ // 更新协议版本
+ async updateProtocolVersion(id: string, data: UpdateProtocolVersionRequest): Promise> {
+ return httpClient.put(`${this.baseUrl}/${id}`, data);
+ }
+
+ // 删除协议版本
+ async deleteProtocolVersion(id: string): Promise> {
+ return httpClient.delete(`${this.baseUrl}/${id}`);
+ }
+}
+
+export const protocolService = new ProtocolService();
\ No newline at end of file