|
|
@@ -14,7 +14,9 @@ import {
|
|
|
Spin,
|
|
|
Modal,
|
|
|
} from 'antd';
|
|
|
+import { CopyOutlined } from '@ant-design/icons';
|
|
|
import { SPACING } from '../../constants';
|
|
|
+import { RootState, useAppSelector } from '@/states/store';
|
|
|
|
|
|
const { Title } = Typography;
|
|
|
const { TextArea } = Input;
|
|
|
@@ -31,7 +33,7 @@ interface SiteInfoData {
|
|
|
|
|
|
/**
|
|
|
* 站点信息组件
|
|
|
- *
|
|
|
+ *
|
|
|
* 布局结构:
|
|
|
* - Layout Type: Vertical Stack Layout
|
|
|
* - Form Layout: Horizontal
|
|
|
@@ -42,7 +44,8 @@ const SiteInfo: React.FC = () => {
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
const [saving, setSaving] = useState(false);
|
|
|
const [initialValues, setInitialValues] = useState<SiteInfoData | null>(null);
|
|
|
-
|
|
|
+ const sn = useAppSelector((state: RootState) => state.product.sn);
|
|
|
+ const { Search } = Input;
|
|
|
// 模拟加载数据
|
|
|
useEffect(() => {
|
|
|
loadSiteInfo();
|
|
|
@@ -54,7 +57,7 @@ const SiteInfo: React.FC = () => {
|
|
|
try {
|
|
|
// TODO: 替换为实际的 API 调用
|
|
|
// const data = await getSiteInfo();
|
|
|
-
|
|
|
+
|
|
|
// 模拟数据
|
|
|
const mockData: SiteInfoData = {
|
|
|
siteName: 'Medical Imaging Center',
|
|
|
@@ -80,18 +83,18 @@ const SiteInfo: React.FC = () => {
|
|
|
try {
|
|
|
// 触发表单验证
|
|
|
const values = await form.validateFields();
|
|
|
-
|
|
|
+
|
|
|
setSaving(true);
|
|
|
-
|
|
|
+
|
|
|
// TODO: 替换为实际的 API 调用
|
|
|
// await updateSiteInfo(values);
|
|
|
-
|
|
|
+
|
|
|
// 模拟保存延迟
|
|
|
- await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
-
|
|
|
+ await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
|
+
|
|
|
message.success('保存成功');
|
|
|
setInitialValues(values);
|
|
|
-
|
|
|
+
|
|
|
// 提示用户可能需要重启服务
|
|
|
Modal.info({
|
|
|
title: '提示',
|
|
|
@@ -110,12 +113,13 @@ const SiteInfo: React.FC = () => {
|
|
|
};
|
|
|
|
|
|
// 重置表单
|
|
|
- const handleReset = () => {
|
|
|
+ const handleReset = (): void => {
|
|
|
if (initialValues) {
|
|
|
// 检查是否有未保存的更改
|
|
|
const currentValues = form.getFieldsValue();
|
|
|
- const hasChanges = JSON.stringify(currentValues) !== JSON.stringify(initialValues);
|
|
|
-
|
|
|
+ const hasChanges =
|
|
|
+ JSON.stringify(currentValues) !== JSON.stringify(initialValues);
|
|
|
+
|
|
|
if (hasChanges) {
|
|
|
Modal.confirm({
|
|
|
title: '确认重置',
|
|
|
@@ -133,11 +137,28 @@ const SiteInfo: React.FC = () => {
|
|
|
};
|
|
|
|
|
|
// AE Title 输入转大写
|
|
|
- const handleAETitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
+ const handleAETitleChange = (
|
|
|
+ e: React.ChangeEvent<HTMLInputElement>
|
|
|
+ ): void => {
|
|
|
const value = e.target.value.toUpperCase().replace(/[^A-Z0-9_]/g, '');
|
|
|
form.setFieldsValue({ aeTitle: value });
|
|
|
};
|
|
|
|
|
|
+ // 复制SN号码
|
|
|
+ const handleCopySN = async (): Promise<void> => {
|
|
|
+ if (sn) {
|
|
|
+ try {
|
|
|
+ await navigator.clipboard.writeText(sn);
|
|
|
+ message.success('SN码已复制到剪贴板');
|
|
|
+ } catch (error) {
|
|
|
+ message.error('复制失败,请手动复制');
|
|
|
+ console.error('Failed to copy SN:', error);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ message.warning('SN码为空');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
if (loading) {
|
|
|
return (
|
|
|
<div
|
|
|
@@ -166,6 +187,19 @@ const SiteInfo: React.FC = () => {
|
|
|
size="large"
|
|
|
style={{ marginTop: SPACING.LG }}
|
|
|
>
|
|
|
+ {/* SN码 */}
|
|
|
+ <Form.Item label="SN码">
|
|
|
+ <Space.Compact style={{ width: '100%' }}>
|
|
|
+ <Input style={{ width: '90%' }} disabled value={sn || ''} />
|
|
|
+ <Button
|
|
|
+ style={{ width: '10%', height: 'auto' }}
|
|
|
+ icon={<CopyOutlined />}
|
|
|
+ onClick={handleCopySN}
|
|
|
+ title="复制SN码"
|
|
|
+ />
|
|
|
+ </Space.Compact>
|
|
|
+ </Form.Item>
|
|
|
+
|
|
|
{/* 站点名称 */}
|
|
|
<Form.Item
|
|
|
label="站点名称"
|