style: 将Tooltip组件替换为原生title属性,统一提示样式

This commit is contained in:
xiamuceer
2026-01-01 17:32:15 +08:00
parent 0ffa0ec4b5
commit fe22881194
19 changed files with 993 additions and 431 deletions
+40 -48
View File
@@ -12,7 +12,6 @@ import {
Select,
message,
Tag,
Tooltip,
Spin,
Empty,
Alert,
@@ -307,9 +306,7 @@ export default function MCPPluginsPage() {
return <Tag color="success" icon={<CheckCircleOutlined />}></Tag>;
case 'error':
return (
<Tooltip title={plugin.last_error}>
<Tag color="error" icon={<CloseCircleOutlined />}></Tag>
</Tooltip>
<Tag color="error" icon={<CloseCircleOutlined />} title={plugin.last_error}></Tag>
);
default:
return <Tag color="default"></Tag>;
@@ -553,50 +550,45 @@ export default function MCPPluginsPage() {
</div>
<Space size="small" wrap>
<Tooltip title={plugin.enabled ? '禁用插件' : '启用插件'}>
<Switch
checked={plugin.enabled}
onChange={(checked) => handleToggle(plugin, checked)}
size={isMobile ? 'small' : 'default'}
style={{
flexShrink: 0,
height: isMobile ? 16 : 22,
minHeight: isMobile ? 16 : 22,
lineHeight: isMobile ? '16px' : '22px'
}}
/>
</Tooltip>
<Tooltip title="测试连接">
<Button
icon={<ThunderboltOutlined />}
onClick={() => handleTest(plugin.id)}
loading={testingPluginId === plugin.id}
size={isMobile ? 'small' : 'middle'}
/>
</Tooltip>
<Tooltip title="查看工具">
<Button
icon={<ToolOutlined />}
onClick={() => handleViewTools(plugin.id)}
disabled={!plugin.enabled || plugin.status !== 'active'}
size={isMobile ? 'small' : 'middle'}
/>
</Tooltip>
<Tooltip title="编辑">
<Button
icon={<EditOutlined />}
onClick={() => handleEdit(plugin)}
size={isMobile ? 'small' : 'middle'}
/>
</Tooltip>
<Tooltip title="删除">
<Button
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(plugin)}
size={isMobile ? 'small' : 'middle'}
/>
</Tooltip>
<Switch
title={plugin.enabled ? '禁用插件' : '启用插件'}
checked={plugin.enabled}
onChange={(checked) => handleToggle(plugin, checked)}
size={isMobile ? 'small' : 'default'}
style={{
flexShrink: 0,
height: isMobile ? 16 : 22,
minHeight: isMobile ? 16 : 22,
lineHeight: isMobile ? '16px' : '22px'
}}
/>
<Button
title="测试连接"
icon={<ThunderboltOutlined />}
onClick={() => handleTest(plugin.id)}
loading={testingPluginId === plugin.id}
size={isMobile ? 'small' : 'middle'}
/>
<Button
title="查看工具"
icon={<ToolOutlined />}
onClick={() => handleViewTools(plugin.id)}
disabled={!plugin.enabled || plugin.status !== 'active'}
size={isMobile ? 'small' : 'middle'}
/>
<Button
title="编辑"
icon={<EditOutlined />}
onClick={() => handleEdit(plugin)}
size={isMobile ? 'small' : 'middle'}
/>
<Button
title="删除"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(plugin)}
size={isMobile ? 'small' : 'middle'}
/>
</Space>
</div>
</Card>
+28 -30
View File
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react';
import { Button, List, Modal, Form, Input, message, Empty, Space, Popconfirm, Card, Select, Radio, Tag, InputNumber, Tooltip, Tabs } from 'antd';
import { Button, List, Modal, Form, Input, message, Empty, Space, Popconfirm, Card, Select, Radio, Tag, InputNumber, Tabs } from 'antd';
import { EditOutlined, DeleteOutlined, ThunderboltOutlined, BranchesOutlined, AppstoreAddOutlined, CheckCircleOutlined, ExclamationCircleOutlined, PlusOutlined, FileTextOutlined } from '@ant-design/icons';
import { useStore } from '../store';
import { useOutlineSync } from '../store/hooks';
@@ -1932,16 +1932,15 @@ export default function Outline() {
{isMobile ? 'AI生成/续写' : 'AI生成/续写大纲'}
</Button>
{outlines.length > 0 && currentProject?.outline_mode === 'one-to-many' && (
<Tooltip title="将所有大纲展开为多章,实现从大纲到章节的一对多关系">
<Button
icon={<AppstoreAddOutlined />}
onClick={handleBatchExpandOutlines}
loading={isExpanding}
disabled={isGenerating}
>
{isMobile ? '批量展开' : '批量展开为多章'}
</Button>
</Tooltip>
<Button
icon={<AppstoreAddOutlined />}
onClick={handleBatchExpandOutlines}
loading={isExpanding}
disabled={isGenerating}
title="将所有大纲展开为多章,实现从大纲到章节的一对多关系"
>
{isMobile ? '批量展开' : '批量展开为多章'}
</Button>
)}
</Space>
</div>
@@ -1965,16 +1964,16 @@ export default function Outline() {
}}
actions={isMobile ? undefined : [
...(currentProject?.outline_mode === 'one-to-many' ? [
<Tooltip title="展开为多章">
<Button
type="text"
icon={<BranchesOutlined />}
onClick={() => handleExpandOutline(item.id, item.title)}
loading={isExpanding}
>
</Button>
</Tooltip>
<Button
key="expand"
type="text"
icon={<BranchesOutlined />}
onClick={() => handleExpandOutline(item.id, item.title)}
loading={isExpanding}
title="展开为多章"
>
</Button>
] : []), // 一对一模式:不显示任何展开/创建按钮
<Button
type="text"
@@ -2034,15 +2033,14 @@ export default function Outline() {
/>
{/* 一对多模式:显示展开按钮 */}
{currentProject?.outline_mode === 'one-to-many' && (
<Tooltip title="展开为多章">
<Button
type="text"
icon={<BranchesOutlined />}
onClick={() => handleExpandOutline(item.id, item.title)}
loading={isExpanding}
size="small"
/>
</Tooltip>
<Button
type="text"
icon={<BranchesOutlined />}
onClick={() => handleExpandOutline(item.id, item.title)}
loading={isExpanding}
size="small"
title="展开为多章"
/>
)}
{/* 一对一模式:不显示任何展开/创建按钮 */}
<Popconfirm
+6 -6
View File
@@ -95,6 +95,11 @@ export default function ProjectDetail() {
// Hook 内部已经更新了 store,不需要再次刷新
const menuItems = [
{
key: 'sponsor',
icon: <HeartOutlined />,
label: <Link to={`/project/${projectId}/sponsor`}></Link>,
},
{
key: 'world-setting',
icon: <GlobalOutlined />,
@@ -145,11 +150,6 @@ export default function ProjectDetail() {
// icon: <ToolOutlined />,
// label: <Link to={`/project/${projectId}/polish`}>AI去味</Link>,
// },
{
key: 'sponsor',
icon: <HeartOutlined />,
label: <Link to={`/project/${projectId}/sponsor`}></Link>,
},
];
// 根据当前路径动态确定选中的菜单项
@@ -166,7 +166,7 @@ export default function ProjectDetail() {
if (path.includes('/writing-styles')) return 'writing-styles';
if (path.includes('/sponsor')) return 'sponsor';
// if (path.includes('/polish')) return 'polish';
return 'world-setting'; // 默认选中世界设定
return 'sponsor'; // 默认选中赞助支持
}, [location.pathname]);
if (loading || !currentProject) {
+37 -39
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, Button, Empty, Modal, message, Spin, Row, Col, Statistic, Space, Tag, Progress, Typography, Tooltip, Badge, Alert, Upload, Checkbox, Divider, Switch, Dropdown, Form, Input, InputNumber } from 'antd';
import { Card, Button, Empty, Modal, message, Spin, Row, Col, Statistic, Space, Tag, Progress, Typography, Badge, Alert, Upload, Checkbox, Divider, Switch, Dropdown, Form, Input, InputNumber } from 'antd';
import { EditOutlined, DeleteOutlined, BookOutlined, RocketOutlined, CalendarOutlined, FileTextOutlined, TrophyOutlined, FireOutlined, SettingOutlined, InfoCircleOutlined, CloseOutlined, UploadOutlined, DownloadOutlined, ApiOutlined, MoreOutlined, BulbOutlined, LoadingOutlined, FileSearchOutlined } from '@ant-design/icons';
import { projectApi } from '../services/api';
import { useStore } from '../store';
@@ -1031,38 +1031,34 @@ export default function ProjectList() {
{formatDate(project.updated_at)}
</Text>
<Space size={4}>
<Tooltip title="编辑">
<Button
type="text"
size="small"
icon={<EditOutlined />}
onClick={(e) => {
e.stopPropagation();
handleEditProject(project);
}}
style={{
borderRadius: 8,
color: 'var(--color-primary)',
transition: 'all 0.2s ease'
}}
/>
</Tooltip>
<Tooltip title="删除">
<Button
type="text"
size="small"
danger
icon={<DeleteOutlined />}
onClick={(e) => {
e.stopPropagation();
handleDelete(project.id);
}}
style={{
borderRadius: 8,
transition: 'all 0.2s ease'
}}
/>
</Tooltip>
<Button
type="text"
size="small"
icon={<EditOutlined />}
onClick={(e) => {
e.stopPropagation();
handleEditProject(project);
}}
style={{
borderRadius: 8,
color: 'var(--color-primary)',
transition: 'all 0.2s ease'
}}
/>
<Button
type="text"
size="small"
danger
icon={<DeleteOutlined />}
onClick={(e) => {
e.stopPropagation();
handleDelete(project.id);
}}
style={{
borderRadius: 8,
transition: 'all 0.2s ease'
}}
/>
</Space>
</div>
</div>
@@ -1249,9 +1245,10 @@ export default function ProjectList() {
}}
/>
<Text style={{ fontSize: window.innerWidth <= 768 ? 13 : 14 }}></Text>
<Tooltip title="导出项目关联的写作风格数据">
<InfoCircleOutlined style={{ color: '#999', fontSize: window.innerWidth <= 768 ? 12 : 14 }} />
</Tooltip>
<InfoCircleOutlined
title="导出项目关联的写作风格数据"
style={{ color: '#999', fontSize: window.innerWidth <= 768 ? 12 : 14 }}
/>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Switch
@@ -1266,9 +1263,10 @@ export default function ProjectList() {
}}
/>
<Text style={{ fontSize: window.innerWidth <= 768 ? 13 : 14 }}></Text>
<Tooltip title="导出AI生成的历史记录(最多100条)">
<InfoCircleOutlined style={{ color: '#999', fontSize: window.innerWidth <= 768 ? 12 : 14 }} />
</Tooltip>
<InfoCircleOutlined
title="导出AI生成的历史记录(最多100条)"
style={{ color: '#999', fontSize: window.innerWidth <= 768 ? 12 : 14 }}
/>
</div>
</Space>
</Card>
+38 -32
View File
@@ -1,6 +1,6 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, Form, Input, Button, Select, Slider, InputNumber, message, Space, Typography, Spin, Modal, Tooltip, Alert, Grid, Tabs, List, Tag, Popconfirm, Empty, Row, Col } from 'antd';
import { Card, Form, Input, Button, Select, Slider, InputNumber, message, Space, Typography, Spin, Modal, Alert, Grid, Tabs, List, Tag, Popconfirm, Empty, Row, Col } from 'antd';
import { SettingOutlined, SaveOutlined, DeleteOutlined, ReloadOutlined, ArrowLeftOutlined, InfoCircleOutlined, CheckCircleOutlined, CloseCircleOutlined, ThunderboltOutlined, PlusOutlined, EditOutlined, CopyOutlined } from '@ant-design/icons';
import { settingsApi } from '../services/api';
import type { SettingsUpdate, APIKeyPreset, PresetCreateRequest, APIKeyPresetConfig } from '../types';
@@ -544,16 +544,15 @@ export default function SettingsPage() {
</Button>
),
<Tooltip title="测试连接">
<Button
type="link"
icon={<ThunderboltOutlined />}
loading={testingPresetId === preset.id}
onClick={() => handlePresetTest(preset.id)}
>
</Button>
</Tooltip>,
<Button
key="test"
type="link"
icon={<ThunderboltOutlined />}
loading={testingPresetId === preset.id}
onClick={() => handlePresetTest(preset.id)}
>
</Button>,
<Button
type="link"
icon={<EditOutlined />}
@@ -766,9 +765,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span>API </span>
<Tooltip title="选择你的AI服务提供商">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="选择你的AI服务提供商"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="api_provider"
@@ -787,9 +787,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span>API </span>
<Tooltip title="你的API密钥,将加密存储">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="你的API密钥,将加密存储"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="api_key"
@@ -806,9 +807,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span>API </span>
<Tooltip title="API的基础URL地址">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="API的基础URL地址"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="api_base_url"
@@ -827,9 +829,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span></span>
<Tooltip title="AI模型的名称,如 gpt-4, gpt-3.5-turbo">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="AI模型的名称,如 gpt-4, gpt-3.5-turbo"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="llm_model"
@@ -931,9 +934,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span></span>
<Tooltip title="控制输出的随机性,值越高越随机(0.0-2.0)">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="控制输出的随机性,值越高越随机(0.0-2.0)"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="temperature"
@@ -955,9 +959,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span> Token </span>
<Tooltip title="单次请求的最大token数量">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="单次请求的最大token数量"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="max_tokens"
@@ -978,9 +983,10 @@ export default function SettingsPage() {
label={
<Space size={4}>
<span></span>
<Tooltip title="设置全局系统提示词,每次AI调用时都会自动使用。可用于设定AI的角色、语言风格等">
<InfoCircleOutlined style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }} />
</Tooltip>
<InfoCircleOutlined
title="设置全局系统提示词,每次AI调用时都会自动使用。可用于设定AI的角色、语言风格等"
style={{ color: 'var(--color-text-secondary)', fontSize: isMobile ? '12px' : '14px' }}
/>
</Space>
}
name="system_prompt"
+2 -2
View File
@@ -21,9 +21,9 @@ interface SponsorOption {
const sponsorOptions: SponsorOption[] = [
{ amount: 5, label: '🌶️ 一包辣条', image: '/5.png', description: '¥5' },
{ amount: 10, label: '🍱 一顿拼好饭', image: '/10.png', description: '¥10' },
{ amount: 20, label: '🧋 一杯奶茶', image: '/20.png', description: '¥20' },
{ amount: 20, label: '🧋 一杯咖啡', image: '/20.png', description: '¥20' },
{ amount: 50, label: '🍖 一次烧烤', image: '/50.png', description: '¥50' },
{ amount: 'custom', label: '💰 任意金额', image: '/xx.png', description: '自定义' },
{ amount: 99, label: '🍲 一顿海底捞', image: '/99.png', description: '¥99' },
];
const benefits = [
+32 -41
View File
@@ -15,7 +15,6 @@ import {
Typography,
Badge,
InputNumber,
Tooltip,
Row,
Col,
Pagination,
@@ -350,27 +349,23 @@ export default function UserManagement() {
// 桌面端:保持原有按钮样式
return (
<Space size="small">
<Tooltip title="编辑用户">
<Button
type="link"
size="small"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
</Button>
</Tooltip>
<Button
type="link"
size="small"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
</Button>
<Tooltip title="重置密码">
<Button
type="link"
size="small"
icon={<KeyOutlined />}
onClick={() => handleResetPassword(record)}
>
</Button>
</Tooltip>
<Button
type="link"
size="small"
icon={<KeyOutlined />}
onClick={() => handleResetPassword(record)}
>
</Button>
<Popconfirm
title={`确定${isActive ? '禁用' : '启用'}该用户吗?`}
@@ -378,16 +373,14 @@ export default function UserManagement() {
okText="确定"
cancelText="取消"
>
<Tooltip title={isActive ? '禁用用户' : '启用用户'}>
<Button
type="link"
size="small"
danger={isActive}
icon={isActive ? <StopOutlined /> : <CheckCircleOutlined />}
>
{isActive ? '禁用' : '启用'}
</Button>
</Tooltip>
<Button
type="link"
size="small"
danger={isActive}
icon={isActive ? <StopOutlined /> : <CheckCircleOutlined />}
>
{isActive ? '禁用' : '启用'}
</Button>
</Popconfirm>
{!record.is_admin && (
@@ -398,16 +391,14 @@ export default function UserManagement() {
cancelText="取消"
okButtonProps={{ danger: true }}
>
<Tooltip title="删除用户">
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
>
</Button>
</Tooltip>
<Button
type="link"
size="small"
danger
icon={<DeleteOutlined />}
>
</Button>
</Popconfirm>
)}
</Space>
+28 -37
View File
@@ -12,8 +12,7 @@ import {
Empty,
Typography,
Row,
Col,
Tooltip
Col
} from 'antd';
import {
PlusOutlined,
@@ -232,28 +231,26 @@ export default function WritingStyles() {
padding: '16px',
}}
actions={[
<Tooltip key="default" title={style.is_default ? '当前默认' : '设为默认'}>
<span
onClick={() => !style.is_default && handleSetDefault(style.id)}
style={{ cursor: style.is_default ? 'default' : 'pointer' }}
>
{style.is_default ? (
<StarFilled style={{ color: '#faad14', fontSize: 18 }} />
) : (
<StarOutlined style={{ fontSize: 18 }} />
)}
</span>
</Tooltip>,
<Tooltip key="edit" title={style.user_id === null ? '预设风格不可编辑' : '编辑'}>
<EditOutlined
onClick={() => style.user_id !== null && handleEdit(style)}
style={{
fontSize: 18,
cursor: style.user_id === null ? 'not-allowed' : 'pointer',
color: style.user_id === null ? '#ccc' : undefined
}}
/>
</Tooltip>,
<span
key="default"
onClick={() => !style.is_default && handleSetDefault(style.id)}
style={{ cursor: style.is_default ? 'default' : 'pointer' }}
>
{style.is_default ? (
<StarFilled style={{ color: '#faad14', fontSize: 18 }} />
) : (
<StarOutlined style={{ fontSize: 18 }} />
)}
</span>,
<EditOutlined
key="edit"
onClick={() => style.user_id !== null && handleEdit(style)}
style={{
fontSize: 18,
cursor: style.user_id === null ? 'not-allowed' : 'pointer',
color: style.user_id === null ? '#ccc' : undefined
}}
/>,
<Popconfirm
key="delete"
title="确定删除这个风格吗?"
@@ -263,19 +260,13 @@ export default function WritingStyles() {
cancelText="取消"
disabled={style.user_id === null}
>
<Tooltip title={
style.user_id === null
? '预设风格不可删除'
: '删除'
}>
<DeleteOutlined
style={{
fontSize: 18,
color: style.user_id === null ? '#ccc' : undefined,
cursor: style.user_id === null ? 'not-allowed' : 'pointer'
}}
/>
</Tooltip>
<DeleteOutlined
style={{
fontSize: 18,
color: style.user_id === null ? '#ccc' : undefined,
cursor: style.user_id === null ? 'not-allowed' : 'pointer'
}}
/>
</Popconfirm>,
]}
>