fix(notification): 优化移动端消息设置页面交互体验

- 修复移动端 Tooltip 与点击事件冲突导致变量无法复制的问题
- 添加移动端备用复制方法(textarea + execCommand)
- 移除变量标签中的复制图标
- 移动端模板输入框调整为 15 行
- 调整系统设置菜单顺序

Made-with: Cursor
This commit is contained in:
WrBug
2026-03-02 23:32:26 +08:00
parent 686d14b6e5
commit 46c32df421
2 changed files with 59 additions and 21 deletions
+5 -5
View File
@@ -207,6 +207,11 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
icon: <SettingOutlined />,
label: t('menu.systemOverview') || '通用设置'
},
{
key: '/system-settings/notification',
icon: <NotificationOutlined />,
label: t('menu.notifications') || '消息推送设置'
},
{
key: '/system-settings/rpc-nodes',
icon: <ApiOutlined />,
@@ -216,11 +221,6 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
key: '/system-settings/api-health',
icon: <CheckCircleOutlined />,
label: t('menu.apiHealth') || 'API健康'
},
{
key: '/system-settings/notification',
icon: <NotificationOutlined />,
label: t('menu.notifications') || '消息推送设置'
}
]
},
+54 -16
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react'
import { Card, Table, Button, Space, Tag, Popconfirm, message, Typography, Modal, Form, Input, Switch, Tooltip, Row, Col, Tabs } from 'antd'
import { PlusOutlined, EditOutlined, DeleteOutlined, SendOutlined, CopyOutlined, ReloadOutlined, CheckOutlined, RobotOutlined, FormOutlined } from '@ant-design/icons'
import { PlusOutlined, EditOutlined, DeleteOutlined, SendOutlined, ReloadOutlined, CheckOutlined, RobotOutlined, FormOutlined } from '@ant-design/icons'
import { useTranslation } from 'react-i18next'
import { apiService } from '../services/api'
import type { NotificationConfig, NotificationConfigRequest, NotificationConfigUpdateRequest, NotificationTemplate, TemplateTypeInfo, TemplateVariablesResponse, TemplateVariable } from '../types'
@@ -355,8 +355,35 @@ const NotificationSettingsPage: React.FC = () => {
}
const handleCopyVariable = useCallback((variable: string) => {
navigator.clipboard.writeText(`{{${variable}}}`)
message.success(t('notificationSettings.templates.copied'))
const text = `{{${variable}}}`
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text).then(() => {
message.success(t('notificationSettings.templates.copied'))
}).catch(() => {
fallbackCopy(text)
})
} else {
fallbackCopy(text)
}
function fallbackCopy(text: string) {
const textArea = document.createElement('textarea')
textArea.value = text
textArea.style.position = 'fixed'
textArea.style.left = '-9999px'
textArea.style.top = '-9999px'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
document.execCommand('copy')
message.success(t('notificationSettings.templates.copied'))
} catch {
message.error(t('common.copyFailed'))
}
document.body.removeChild(textArea)
}
}, [t])
const [variableHoverKey, setVariableHoverKey] = useState<string | null>(null)
@@ -365,20 +392,31 @@ const NotificationSettingsPage: React.FC = () => {
const isHover = variableHoverKey === variable.key
const label = t(`notificationSettings.templates.variableLabels.${variable.key}`)
const description = t(`notificationSettings.templates.variableDescriptions.${variable.key}`)
const variableElement = (
<span
role="button"
tabIndex={0}
style={{ ...variableTagStyle, ...(isHover && !isMobile ? variableTagHoverStyle : {}) }}
onClick={() => handleCopyVariable(variable.key)}
onMouseEnter={() => !isMobile && setVariableHoverKey(variable.key)}
onMouseLeave={() => !isMobile && setVariableHoverKey(null)}
onKeyDown={(e) => e.key === 'Enter' && handleCopyVariable(variable.key)}
>
<span style={{ fontFamily: 'monospace' }}>{label}</span>
</span>
)
if (isMobile) {
return (
<span key={variable.key} style={{ display: 'inline-block' }}>
{variableElement}
</span>
)
}
return (
<Tooltip key={variable.key} title={description || `{{${variable.key}}}`} placement="top">
<span
role="button"
tabIndex={0}
style={{ ...variableTagStyle, ...(isHover ? variableTagHoverStyle : {}) }}
onClick={() => handleCopyVariable(variable.key)}
onMouseEnter={() => setVariableHoverKey(variable.key)}
onMouseLeave={() => setVariableHoverKey(null)}
onKeyDown={(e) => e.key === 'Enter' && handleCopyVariable(variable.key)}
>
<CopyOutlined style={{ marginRight: 4, fontSize: 11, opacity: 0.6 }} />
<span style={{ fontFamily: 'monospace' }}>{label}</span>
</span>
{variableElement}
</Tooltip>
)
}
@@ -617,7 +655,7 @@ const NotificationSettingsPage: React.FC = () => {
<TextArea
value={templateContent}
onChange={handleTemplateContentChange}
rows={isMobile ? 10 : 16}
rows={isMobile ? 15 : 16}
style={{ fontFamily: 'monospace', fontSize: 13, borderRadius: 8, resize: 'none' }}
placeholder={t('notificationSettings.templates.contentPlaceholder')}
/>