Skip to content

Commit 5e88d0b

Browse files
committed
chore: 更新项目版本号至 3.3.5
- 在 .env 文件中将 VITE_VERSION 更新至 3.3.5。 - 在 Assistant 页面中重构卡片组件,增加模型主题功能,优化卡片布局和样式,提升用户体验。 - 在 Storage 页面中调整存储配置卡片的样式,增强视觉一致性。
1 parent 1dbc1ac commit 5e88d0b

File tree

3 files changed

+188
-77
lines changed

3 files changed

+188
-77
lines changed

.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# 项目版本号
2-
VITE_VERSION=3.3.4
2+
VITE_VERSION=3.3.5
33

44
# 项目后端API地址
55
VITE_PROJECT_API=https://你的后端域名/api

src/pages/assistant/index.tsx

Lines changed: 183 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useState, useEffect, useRef } from 'react';
2-
import { Button, Card, Form, Input, List, Modal, Popconfirm, Select, Tooltip, Space, Skeleton } from 'antd';
3-
import { DeleteOutlined, FormOutlined, PlusOutlined, InfoCircleOutlined } from '@ant-design/icons';
2+
import { Button, Card, Form, Input, Modal, Select, Tooltip, Space, Skeleton, Avatar, Tag, Dropdown, MenuProps } from 'antd';
3+
import { DeleteOutlined, FormOutlined, PlusOutlined, InfoCircleOutlined, MoreOutlined, ApiOutlined, ThunderboltFilled } from '@ant-design/icons';
4+
import { ImSwitch } from 'react-icons/im';
45

56
import Title from '@/components/Title';
67
import useAssistant from '@/hooks/useAssistant';
@@ -47,6 +48,23 @@ const modelInfoMap: Record<string, { desc: string; label: string }> = {
4748
// 你可以继续添加更多模型
4849
};
4950

51+
// 获取模型主题(颜色和图标)
52+
const getModelTheme = (model: string): { color: string; icon: string } => {
53+
const themeMap: Record<string, { color: string; icon: string }> = {
54+
'deepseek-chat': { color: '#1890ff', icon: 'DS' },
55+
'deepseek-reasoner': { color: '#722ed1', icon: 'DR' },
56+
'moonshot-v1-128k': { color: '#13c2c2', icon: 'M' },
57+
'gpt-4o': { color: '#52c41a', icon: 'GPT4' },
58+
'gpt-3.5-turbo': { color: '#faad14', icon: 'GPT3' },
59+
'glm-4': { color: '#eb2f96', icon: 'GLM' },
60+
'qwen-turbo': { color: '#f5222d', icon: 'QW' },
61+
'ernie-bot': { color: '#fa8c16', icon: 'EB' },
62+
'doubao-chat': { color: '#2f54eb', icon: 'DB' },
63+
};
64+
65+
return themeMap[model] || { color: '#8c8c8c', icon: 'AI' };
66+
};
67+
5068
export default () => {
5169
const [form] = Form.useForm();
5270
const [isModalOpen, setIsModalOpen] = useState(false);
@@ -107,90 +125,173 @@ export default () => {
107125
</div>
108126
</Card>
109127

110-
{/* 列表卡片骨架屏 */}
111-
<Card className="border-stroke">
112-
{[1, 2, 3, 4, 5].map((item) => (
113-
<div key={item} className="py-4 border-b border-gray-100 last:border-b-0">
114-
<div className="flex items-center justify-between">
115-
<div className="flex-1 space-x-4">
116-
<Skeleton.Input active size="default" style={{ width: 200, height: 24, marginBottom: 8 }} />
117-
<Skeleton.Input active size="small" style={{ width: 150, height: 24 }} />
128+
{/* 卡片网格骨架屏 */}
129+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mt-3">
130+
{[1, 2, 3, 4, 5, 6].map((item) => (
131+
<Card key={item} className="border-stroke">
132+
<div className="flex items-start justify-between mb-4">
133+
<div className="flex items-center gap-3">
134+
<Skeleton.Avatar active size={48} shape="square" />
135+
<div>
136+
<Skeleton.Input active size="small" style={{ width: 80, height: 16 }} />
137+
</div>
118138
</div>
139+
<Skeleton.Button active size="small" style={{ width: 32, height: 32 }} />
140+
</div>
141+
<div className="bg-gray-100 rounded-md p-3 py-4 mb-4">
119142

120-
<div className="flex space-x-2">
121-
<Skeleton.Button active size="small" style={{ width: 80, height: 28 }} />
122-
<Skeleton.Button active size="small" style={{ width: 28, height: 28 }} />
123-
<Skeleton.Button active size="small" style={{ width: 28, height: 28 }} />
124-
<Skeleton.Button active size="small" style={{ width: 80, height: 28 }} />
125-
</div>
126143
</div>
127-
</div>
144+
<div className="pt-2 border-t border-gray-100">
145+
<Skeleton.Button active size="default" style={{ width: '100%', height: 32 }} />
146+
</div>
147+
</Card>
128148
))}
129-
</Card>
149+
</div>
130150
</div>
131151
);
132152
}
133153

134154
return (
135155
<div>
136156
<Title value="助手管理">
137-
<Button type="primary" icon={<PlusOutlined />} onClick={() => setIsModalOpen(true)}>
157+
<Button type="primary" onClick={() => setIsModalOpen(true)}>
138158
添加助手
139159
</Button>
140160
</Title>
141161

142-
<Card className="border-stroke">
143-
<List
144-
dataSource={list}
145-
renderItem={(item) => {
146-
const info = modelInfoMap[item.model];
147-
return (
148-
<List.Item
149-
actions={[
150-
<Button key="test" type="link" onClick={() => testConnection(item)} loading={testingMap[item.id]}>
151-
{testingMap[item.id] ? '测试中...' : '测试连接'}
152-
</Button>,
153-
<Button
154-
key="edit"
155-
type="text"
156-
onClick={() => {
157-
form.setFieldsValue(item);
158-
setInputModelValue(item.model);
159-
setAssistant(item);
160-
setIsModalOpen(true);
161-
}}
162-
icon={<FormOutlined className="text-primary" />}
163-
/>,
164-
<Popconfirm key="del" title="您确定要删除这个助手吗?" onConfirm={() => delAssistantData(+item.id)} okText="确定" cancelText="取消">
165-
<Button type="text" danger icon={<DeleteOutlined />} />
166-
</Popconfirm>,
167-
<Button key="default" type="text" onClick={() => setDefaultAssistant(+item.id)}>
168-
{item.isDefault ? '默认助手' : '设为默认'}
169-
</Button>,
170-
]}
171-
>
172-
<List.Item.Meta
173-
title={
174-
<Space>
175-
<span>{item.name}</span>
176-
</Space>
177-
}
178-
description={
179-
<span>
180-
模型: {info ? info.label : item.model}
162+
{/* 卡片网格区域 */}
163+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3 mt-3">
164+
{list.map((item) => {
165+
const info = modelInfoMap[item.model];
166+
const theme = getModelTheme(item.model);
167+
const isTesting = testingMap[item.id];
168+
const isDefault = !!item.isDefault;
169+
170+
// 下拉菜单项
171+
const menuItems: MenuProps['items'] = [
172+
{
173+
key: 'edit',
174+
label: '编辑配置',
175+
icon: <FormOutlined />,
176+
onClick: () => {
177+
form.setFieldsValue(item);
178+
setInputModelValue(item.model);
179+
setAssistant(item);
180+
setIsModalOpen(true);
181+
}
182+
},
183+
{
184+
key: 'default',
185+
label: isDefault ? '已开启' : '开启助手',
186+
icon: <ImSwitch />,
187+
disabled: isDefault,
188+
onClick: () => setDefaultAssistant(+item.id)
189+
},
190+
{
191+
type: 'divider',
192+
},
193+
{
194+
key: 'delete',
195+
label: '删除助手',
196+
danger: true,
197+
icon: <DeleteOutlined />,
198+
onClick: () => {
199+
Modal.confirm({
200+
title: '确认删除',
201+
content: `您确定要删除助手 "${item.name}" 吗?此操作无法撤销。`,
202+
okText: '删除',
203+
okType: 'danger',
204+
cancelText: '取消',
205+
onOk: () => delAssistantData(+item.id),
206+
});
207+
}
208+
}
209+
];
210+
211+
return (
212+
<Card
213+
key={item.id}
214+
className={`relative p-5 rounded-xl shadow-sm hover:shadow-md transition-all duration-300 overflow-hidden ${item.isDefault
215+
? 'border-2 border-blue-500 bg-gradient-to-br from-blue-50 via-white to-blue-50'
216+
: 'border border-gray-200 bg-gradient-to-br from-gray-50 via-white to-slate-50'
217+
}`}
218+
styles={{ body: { padding: '10px', flex: 1, display: 'flex', flexDirection: 'column' } }}
219+
>
220+
{/* 卡片头部:图标与名称 */}
221+
<div className="flex items-start justify-between mb-4">
222+
<div className="flex items-center gap-3">
223+
<Avatar
224+
shape="square"
225+
size={48}
226+
style={{ backgroundColor: theme.color, verticalAlign: 'middle' }}
227+
className="shadow-md text-lg font-bold"
228+
>
229+
{theme.icon}
230+
</Avatar>
231+
232+
<div>
233+
<div className="font-bold text-lg text-gray-800 leading-tight mb-1 truncate max-w-[160px] ml-[5px]">
234+
{item.name}
235+
</div>
236+
237+
<Space size={4}>
238+
<Tag bordered={false} className="text-xs bg-gray-100 text-gray-500 mr-0">
239+
{info ? info.label : item.model}
240+
</Tag>
241+
181242
{info && (
182243
<Tooltip title={info.desc}>
183-
<InfoCircleOutlined style={{ marginLeft: 8 }} />
244+
<InfoCircleOutlined className="text-gray-400 cursor-pointer hover:text-primary" />
184245
</Tooltip>
185246
)}
186-
</span>
187-
}
188-
/>
189-
</List.Item>
190-
);
191-
}}
192-
/>
193-
</Card>
247+
</Space>
248+
</div>
249+
</div>
250+
251+
{/* 更多操作菜单 */}
252+
<Dropdown menu={{ items: menuItems }} placement="bottomRight" arrow className="bg-gray-50">
253+
<Button type="text" icon={<MoreOutlined className="text-xl text-gray-400" />} />
254+
</Dropdown>
255+
</div>
256+
257+
{/* 卡片内容:URL显示 */}
258+
<div className="bg-gray-50 rounded-md px-3 py-2 mb-2 flex-1 border border-gray-100">
259+
<div className="flex items-center text-gray-400 text-xs uppercase font-bold mb-1">
260+
<ApiOutlined className="mr-1" /> API Endpoint
261+
</div>
262+
<div
263+
className="text-gray-600 font-mono text-sm m-0 break-all"
264+
>
265+
{item.url}
266+
</div>
267+
</div>
268+
269+
{/* 卡片底部:主要操作 */}
270+
<div className="mt-auto pt-2 border-t border-gray-100 flex justify-end">
271+
<Button
272+
type={isTesting ? 'default' : 'dashed'}
273+
className={`${isTesting ? '' : 'text-primary border-primary bg-blue-50/50'} w-full`}
274+
icon={isTesting ? <ThunderboltFilled spin /> : <ThunderboltFilled />}
275+
loading={isTesting}
276+
onClick={() => testConnection(item)}
277+
>
278+
{isTesting ? '连接测试中...' : '测试连接'}
279+
</Button>
280+
</div>
281+
</Card>
282+
);
283+
})}
284+
285+
{/* 空状态下的添加按钮(如果没有数据或者作为最后一个Card) */}
286+
<Button
287+
type="dashed"
288+
className="h-auto min-h-[200px] border-2 flex flex-col items-center justify-center gap-2 !bg-white text-gray-400 hover:text-primary hover:border-primary transition-colors rounded-lg bg-transparent"
289+
onClick={() => setIsModalOpen(true)}
290+
>
291+
<PlusOutlined style={{ fontSize: '24px' }} />
292+
<span className="font-medium">添加新助手</span>
293+
</Button>
294+
</div>
194295

195296
<Modal
196297
title={assistant.id ? '编辑助手' : '添加助手'}
@@ -204,16 +305,27 @@ export default () => {
204305
}}
205306
>
206307
<Form form={form} layout="vertical" size="large">
207-
<Form.Item name="name" label="助手名称" rules={[{ required: true, message: '请输入助手名称' }]}>
308+
<Form.Item name="name" label="名称" rules={[{ required: true, message: '请输入助手名称' }]}>
208309
<Input placeholder="例如:DeepSeek、OpenAI 等" />
209310
</Form.Item>
210311

211-
<Form.Item name="url" label="API 地址" tooltip="填写完整的 API 接口地址,如 https://api.deepseek.com/v1" rules={[{ required: true, message: '请输入 API 地址' }]}>
212-
<Input placeholder="https://api.deepseek.com/v1" />
312+
<Form.Item
313+
name="url"
314+
label="API 地址"
315+
tooltip="填写完整的 API 接口地址,如 https://api.deepseek.com/v1"
316+
rules={[
317+
{ required: true, message: '请输入 API 地址' },
318+
{
319+
pattern: /^https?:\/\//,
320+
message: '请输入正确的 API 地址'
321+
}
322+
]}
323+
>
324+
<Input placeholder="https://api.deepseek.com/v1" autoComplete="off" />
213325
</Form.Item>
214326

215327
<Form.Item name="key" label="API 密钥" rules={[{ required: true, message: '请输入 API 密钥' }]}>
216-
<Input.Password placeholder="请输入 API 密钥" />
328+
<Input.Password placeholder="请输入 API 密钥" autoComplete="new-password" />
217329
</Form.Item>
218330

219331
<Form.Item name="model" label="模型" rules={[{ required: true, message: '请选择或输入模型' }]}>

src/pages/storage/index.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export default () => {
236236
<div
237237
key={record.id}
238238
className={`relative p-5 rounded-xl shadow-sm hover:shadow-md transition-all duration-300 overflow-hidden ${record.isEnable
239-
? 'border-2 border-green-500 bg-gradient-to-br from-green-50 via-white to-blue-50'
239+
? 'border-2 border-blue-500 bg-gradient-to-br from-blue-50 via-white to-blue-50'
240240
: 'border border-gray-200 bg-gradient-to-br from-gray-50 via-white to-slate-50'
241241
}`}
242242
>
@@ -351,12 +351,11 @@ export default () => {
351351

352352
{/* 添加存储配置卡片 */}
353353
<div
354-
className="group flex flex-col justify-center items-center bg-white p-5 rounded-xl shadow-sm hover:shadow-md transition-shadow border-2 border-dashed border-gray-300 cursor-pointer hover:border-primary"
354+
className="group flex flex-col justify-center items-center text-gray-400 bg-white p-5 rounded-xl shadow-sm hover:shadow-md transition-shadow border-2 border-dashed border-gray-300 cursor-pointer hover:border-primary"
355355
onClick={addOssData}
356356
>
357-
<PlusOutlined className="text-4xl text-gray-400 mb-4 group-hover:text-primary" />
358-
<div className="text-lg font-semibold text-gray-600 mb-2 group-hover:text-primary">添加存储配置</div>
359-
<div className="text-sm text-gray-400 group-hover:text-primary">支持多种云存储服务</div>
357+
<PlusOutlined className="text-2xl text-gray-400 mb-2 group-hover:text-primary" />
358+
<div className="text-sm font-medium mb-2 group-hover:text-primary">添加新存储</div>
360359
</div>
361360
</div>
362361

0 commit comments

Comments
 (0)