This commit is contained in:
2025-09-26 14:33:31 +08:00
parent 0b48be15aa
commit 8e9313eafa
4 changed files with 871 additions and 38 deletions

View File

@@ -11,6 +11,7 @@
align-items: center;
min-height: 64px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
justify-content: space-between;
.headerLeft {
display: flex;

View File

@@ -13,6 +13,7 @@ export interface PowerNavigationProps {
onBackClick?: () => void;
className?: string;
style?: React.CSSProperties;
rightContent?: React.ReactNode;
}
const PowerNavigation: React.FC<PowerNavigationProps> = ({
@@ -23,6 +24,7 @@ const PowerNavigation: React.FC<PowerNavigationProps> = ({
onBackClick,
className,
style,
rightContent,
}) => {
const navigate = useNavigate();
@@ -57,6 +59,7 @@ const PowerNavigation: React.FC<PowerNavigationProps> = ({
{subtitle && <span className={styles.subtitle}>{subtitle}</span>}
</div>
</div>
<div className={styles.headerRight}>{rightContent}</div>
</div>
);
};

View File

@@ -3,41 +3,426 @@
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
min-height: 100vh;
}
// 头部样式
.header {
margin-bottom: 24px;
h1 {
font-size: 24px;
font-weight: 600;
color: #262626;
margin: 0 0 8px 0;
}
p {
font-size: 14px;
color: #8c8c8c;
margin: 0;
}
}
.content {
min-height: 400px;
}
.placeholder {
display: flex;
justify-content: space-between;
align-items: center;
justify-content: center;
height: 300px;
background: #fafafa;
border: 1px dashed #d9d9d9;
border-radius: 6px;
p {
font-size: 16px;
color: #8c8c8c;
margin: 0;
margin-bottom: 24px;
padding: 16px 0;
border-bottom: 1px solid #f0f0f0;
.headerLeft {
.computeBalance {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: #666;
.anticon {
color: #1890ff;
}
}
}
}
.headerRight {
.startTrainingButton {
height: 40px;
padding: 0 24px;
font-weight: 500;
}
}
}
// 内容区域
.content {
.tabs {
.ant-tabs-nav {
margin-bottom: 24px;
}
.ant-tabs-tab {
font-size: 16px;
font-weight: 500;
}
}
}
// 话术投喂样式
.utteranceFeeding {
display: flex;
gap: 24px;
min-height: 600px;
.leftPanel {
flex: 1;
max-width: 400px;
.addCard {
height: fit-content;
.cardHeader {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
.icon {
font-size: 20px;
color: #1890ff;
}
.title {
font-size: 18px;
font-weight: 600;
color: #262626;
}
}
.description {
color: #8c8c8c;
margin-bottom: 24px;
font-size: 14px;
}
.form {
.formItem {
margin-bottom: 20px;
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #262626;
}
.ant-input,
.ant-input-affix-wrapper {
border-radius: 6px;
}
.ant-input {
height: 40px;
}
}
.saveButton {
width: 100%;
height: 44px;
font-size: 16px;
font-weight: 500;
border-radius: 6px;
}
}
}
}
.rightPanel {
flex: 2;
.libraryCard {
.cardHeader {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
.title {
display: flex;
align-items: center;
gap: 12px;
font-size: 18px;
font-weight: 600;
color: #262626;
.icon {
font-size: 20px;
color: #1890ff;
}
}
.count {
color: #8c8c8c;
font-size: 14px;
}
}
.utteranceList {
.utteranceItem {
border: 1px solid #f0f0f0;
border-radius: 8px;
padding: 20px;
margin-bottom: 16px;
background: #fafafa;
transition: all 0.3s ease;
&:hover {
border-color: #1890ff;
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.1);
}
.utteranceHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.utteranceTitle {
font-size: 16px;
font-weight: 600;
color: #262626;
}
}
.utteranceCategory {
margin-bottom: 12px;
}
.utteranceContent {
color: #595959;
line-height: 1.6;
margin-bottom: 16px;
font-size: 14px;
}
.utteranceFooter {
display: flex;
justify-content: space-between;
align-items: center;
.timestamps {
display: flex;
gap: 16px;
font-size: 12px;
color: #8c8c8c;
}
.actions {
display: flex;
gap: 8px;
.ant-btn {
border: none;
box-shadow: none;
&:hover {
background: #f0f0f0;
}
}
}
}
}
}
}
}
}
// 模型管理样式
.modelManagement {
.cardHeader {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 24px;
.icon {
font-size: 20px;
color: #1890ff;
}
.title {
font-size: 18px;
font-weight: 600;
color: #262626;
}
}
.modelList {
.modelItem {
border: 1px solid #f0f0f0;
border-radius: 8px;
padding: 20px;
margin-bottom: 16px;
background: #fafafa;
transition: all 0.3s ease;
&:hover {
border-color: #1890ff;
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.1);
}
.modelInfo {
margin-bottom: 16px;
.modelName {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
.name {
font-size: 16px;
font-weight: 600;
color: #262626;
}
}
.modelStatus {
display: flex;
align-items: center;
gap: 16px;
.accuracy {
font-size: 14px;
color: #595959;
}
}
}
.modelActions {
display: flex;
gap: 12px;
margin-bottom: 12px;
.ant-btn {
border-radius: 6px;
}
}
.modelTimestamps {
display: flex;
gap: 16px;
font-size: 12px;
color: #8c8c8c;
}
}
}
}
// 训练分析样式
.trainingAnalysis {
.analysisCards {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-bottom: 24px;
.analysisCard {
.cardTitle {
font-size: 16px;
font-weight: 600;
color: #262626;
margin-bottom: 16px;
}
.cardContent {
.statItem {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.statLabel {
color: #8c8c8c;
font-size: 14px;
}
.statValue {
font-weight: 600;
color: #262626;
font-size: 16px;
}
}
}
}
}
.chartCard {
.cardTitle {
font-size: 16px;
font-weight: 600;
color: #262626;
margin-bottom: 16px;
}
.chartPlaceholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
background: #fafafa;
border: 1px dashed #d9d9d9;
border-radius: 6px;
.chartIcon {
font-size: 48px;
color: #d9d9d9;
margin-bottom: 16px;
}
p {
color: #8c8c8c;
font-size: 16px;
margin: 0;
}
}
}
}
// 响应式设计
@media (max-width: 1200px) {
.utteranceFeeding {
flex-direction: column;
.leftPanel {
max-width: none;
}
}
.trainingAnalysis {
.analysisCards {
grid-template-columns: 1fr;
}
}
}
@media (max-width: 768px) {
.container {
padding: 16px;
}
.header {
flex-direction: column;
gap: 16px;
align-items: stretch;
.headerLeft,
.headerRight {
text-align: center;
}
}
.utteranceFeeding {
.leftPanel,
.rightPanel {
.addCard,
.libraryCard {
.cardHeader {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
}
}
}
}

View File

@@ -1,21 +1,465 @@
import React from "react";
import React, { useState } from "react";
import { Button, Input, Tabs, Card, Tag, message, Modal, Tooltip } from "antd";
import {
PlusOutlined,
PlayCircleOutlined,
EyeOutlined,
EditOutlined,
DeleteOutlined,
ThunderboltOutlined,
FileTextOutlined,
DatabaseOutlined,
BarChartOutlined,
SaveOutlined,
} from "@ant-design/icons";
import PowerNavigation from "@/components/PowerNavtion";
import styles from "./index.module.scss";
const { TextArea } = Input;
const { TabPane } = Tabs;
// 话术数据类型
interface UtteranceData {
id: string;
title: string;
category: string;
content: string;
status: "active" | "pending";
createTime: string;
updateTime: string;
}
// 模型数据类型
interface ModelData {
id: string;
name: string;
version: string;
status: "training" | "completed" | "failed";
accuracy: number;
createTime: string;
lastTraining: string;
}
// 训练分析数据类型
interface TrainingAnalysis {
totalUtterances: number;
activeUtterances: number;
pendingUtterances: number;
trainingAccuracy: number;
lastTrainingTime: string;
nextTrainingTime: string;
}
const AiTraining: React.FC = () => {
const [activeTab, setActiveTab] = useState("utterance");
const [utteranceForm, setUtteranceForm] = useState({
title: "",
category: "",
content: "",
});
const [utterances, setUtterances] = useState<UtteranceData[]>([
{
id: "1",
title: "产品介绍话术",
category: "产品介绍",
content:
"我们的AI营销系统具有智能客服、精准营销、自动化运营等核心功能能够帮助您提升客户满意度和业务效率...",
status: "active",
createTime: "2024/3/1",
updateTime: "2024/3/5",
},
{
id: "2",
title: "价格咨询回复",
category: "价格咨询",
content:
"关于价格方面,我们提供多种套餐选择,可以根据您的具体需求定制。基础版适合小型企业,专业版适合中型企业...",
status: "active",
createTime: "2024/3/2",
updateTime: "2024/3/4",
},
{
id: "3",
title: "技术支持话术",
category: "技术支持",
content:
"我们提供7x24小时技术支持包括在线客服、电话支持、远程协助等多种方式确保您的问题得到及时解决...",
status: "pending",
createTime: "2024/3/3",
updateTime: "2024/3/3",
},
]);
const [models] = useState<ModelData[]>([
{
id: "1",
name: "智能客服模型",
version: "v2.1.0",
status: "completed",
accuracy: 94.5,
createTime: "2024/2/15",
lastTraining: "2024/3/5",
},
{
id: "2",
name: "营销推荐模型",
version: "v1.8.0",
status: "training",
accuracy: 89.2,
createTime: "2024/2/20",
lastTraining: "2024/3/4",
},
]);
const [trainingAnalysis] = useState<TrainingAnalysis>({
totalUtterances: 3,
activeUtterances: 2,
pendingUtterances: 1,
trainingAccuracy: 94.5,
lastTrainingTime: "2024/3/5 14:30:00",
nextTrainingTime: "2024/3/6 09:00:00",
});
// 保存话术
const handleSaveUtterance = () => {
if (
!utteranceForm.title ||
!utteranceForm.category ||
!utteranceForm.content
) {
message.warning("请填写完整的话术信息");
return;
}
const newUtterance: UtteranceData = {
id: Date.now().toString(),
title: utteranceForm.title,
category: utteranceForm.category,
content: utteranceForm.content,
status: "pending",
createTime: new Date().toLocaleDateString("zh-CN"),
updateTime: new Date().toLocaleDateString("zh-CN"),
};
setUtterances([...utterances, newUtterance]);
setUtteranceForm({ title: "", category: "", content: "" });
message.success("话术保存成功");
};
// 删除话术
const handleDeleteUtterance = (id: string) => {
Modal.confirm({
title: "确认删除",
content: "确定要删除这条话术吗?",
onOk: () => {
setUtterances(utterances.filter(item => item.id !== id));
message.success("删除成功");
},
});
};
// 开始训练
const handleStartTraining = () => {
Modal.confirm({
title: "开始训练",
content: "确定要开始AI模型训练吗训练过程可能需要几分钟时间。",
onOk: () => {
message.success("训练已开始,请稍候...");
// 这里可以添加实际的训练逻辑
},
});
};
// 话术投喂组件
const UtteranceFeeding = () => (
<div className={styles.utteranceFeeding}>
<div className={styles.leftPanel}>
<Card className={styles.addCard}>
<div className={styles.cardHeader}>
<PlusOutlined className={styles.icon} />
<span className={styles.title}></span>
</div>
<p className={styles.description}>AI模型</p>
<div className={styles.form}>
<div className={styles.formItem}>
<label></label>
<Input
placeholder="输入话术标题..."
value={utteranceForm.title}
onChange={e =>
setUtteranceForm({ ...utteranceForm, title: e.target.value })
}
/>
</div>
<div className={styles.formItem}>
<label></label>
<Input
placeholder="如:产品介绍、价格咨询等"
value={utteranceForm.category}
onChange={e =>
setUtteranceForm({
...utteranceForm,
category: e.target.value,
})
}
/>
</div>
<div className={styles.formItem}>
<label></label>
<TextArea
placeholder="输入详细的话术内容..."
rows={6}
value={utteranceForm.content}
onChange={e =>
setUtteranceForm({
...utteranceForm,
content: e.target.value,
})
}
/>
</div>
<Button
type="primary"
icon={<SaveOutlined />}
onClick={handleSaveUtterance}
className={styles.saveButton}
>
</Button>
</div>
</Card>
</div>
<div className={styles.rightPanel}>
<Card className={styles.libraryCard}>
<div className={styles.cardHeader}>
<DatabaseOutlined className={styles.icon} />
<span className={styles.title}></span>
<span className={styles.count}>{utterances.length}</span>
</div>
<div className={styles.utteranceList}>
{utterances.map(utterance => (
<div key={utterance.id} className={styles.utteranceItem}>
<div className={styles.utteranceHeader}>
<span className={styles.utteranceTitle}>
{utterance.title}
</span>
<Tag color={utterance.status === "active" ? "green" : "blue"}>
{utterance.status === "active" ? "已激活" : "待处理"}
</Tag>
</div>
<div className={styles.utteranceCategory}>
<Tag color="blue">{utterance.category}</Tag>
</div>
<div className={styles.utteranceContent}>
{utterance.content}
</div>
<div className={styles.utteranceFooter}>
<div className={styles.timestamps}>
<span>: {utterance.createTime}</span>
<span>: {utterance.updateTime}</span>
</div>
<div className={styles.actions}>
<Tooltip title="查看">
<Button type="text" icon={<EyeOutlined />} size="small" />
</Tooltip>
<Tooltip title="编辑">
<Button
type="text"
icon={<EditOutlined />}
size="small"
/>
</Tooltip>
<Tooltip title="删除">
<Button
type="text"
icon={<DeleteOutlined />}
size="small"
onClick={() => handleDeleteUtterance(utterance.id)}
/>
</Tooltip>
</div>
</div>
</div>
))}
</div>
</Card>
</div>
</div>
);
// 模型管理组件
const ModelManagement = () => (
<div className={styles.modelManagement}>
<Card>
<div className={styles.cardHeader}>
<FileTextOutlined className={styles.icon} />
<span className={styles.title}></span>
</div>
<div className={styles.modelList}>
{models.map(model => (
<div key={model.id} className={styles.modelItem}>
<div className={styles.modelInfo}>
<div className={styles.modelName}>
<span className={styles.name}>{model.name}</span>
<Tag color="blue">{model.version}</Tag>
</div>
<div className={styles.modelStatus}>
<Tag
color={
model.status === "completed"
? "green"
: model.status === "training"
? "orange"
: "red"
}
>
{model.status === "completed"
? "已完成"
: model.status === "training"
? "训练中"
: "失败"}
</Tag>
<span className={styles.accuracy}>
: {model.accuracy}%
</span>
</div>
</div>
<div className={styles.modelActions}>
<Button type="primary" size="small">
</Button>
<Button size="small"></Button>
<Button size="small"></Button>
</div>
<div className={styles.modelTimestamps}>
<span>: {model.createTime}</span>
<span>: {model.lastTraining}</span>
</div>
</div>
))}
</div>
</Card>
</div>
);
// 训练分析组件
const TrainingAnalysis = () => (
<div className={styles.trainingAnalysis}>
<div className={styles.analysisCards}>
<Card className={styles.analysisCard}>
<div className={styles.cardTitle}></div>
<div className={styles.cardContent}>
<div className={styles.statItem}>
<span className={styles.statLabel}></span>
<span className={styles.statValue}>
{trainingAnalysis.totalUtterances}
</span>
</div>
<div className={styles.statItem}>
<span className={styles.statLabel}></span>
<span className={styles.statValue}>
{trainingAnalysis.activeUtterances}
</span>
</div>
<div className={styles.statItem}>
<span className={styles.statLabel}></span>
<span className={styles.statValue}>
{trainingAnalysis.pendingUtterances}
</span>
</div>
</div>
</Card>
<Card className={styles.analysisCard}>
<div className={styles.cardTitle}></div>
<div className={styles.cardContent}>
<div className={styles.statItem}>
<span className={styles.statLabel}></span>
<span className={styles.statValue}>
{trainingAnalysis.trainingAccuracy}%
</span>
</div>
<div className={styles.statItem}>
<span className={styles.statLabel}></span>
<span className={styles.statValue}>
{trainingAnalysis.lastTrainingTime}
</span>
</div>
<div className={styles.statItem}>
<span className={styles.statLabel}></span>
<span className={styles.statValue}>
{trainingAnalysis.nextTrainingTime}
</span>
</div>
</div>
</Card>
</div>
<Card className={styles.chartCard}>
<div className={styles.cardTitle}></div>
<div className={styles.chartPlaceholder}>
<BarChartOutlined className={styles.chartIcon} />
<p></p>
</div>
</Card>
</div>
);
return (
<div className={styles.container}>
<PowerNavigation
title="AI模型训练"
subtitle="自定义AI模型训练打造专属智能客服助手"
subtitle="训练和优化AI模型提升智能服务质量"
showBackButton={true}
backButtonText="返回功能中心"
/>
<div className={styles.content}>
{/* 功能内容待开发 */}
<div className={styles.placeholder}>
<p>AI模型训练功能正在开发中...</p>
<div className={styles.header}>
<div className={styles.headerLeft}>
<div className={styles.computeBalance}>
<ThunderboltOutlined />
<span>算力余额: 9307.423</span>
</div>
</div>
<div className={styles.headerRight}>
<Button
type="primary"
icon={<PlayCircleOutlined />}
onClick={handleStartTraining}
className={styles.startTrainingButton}
>
</Button>
</div>
</div>
<div className={styles.content}>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
className={styles.tabs}
>
<TabPane tab="话术投喂" key="utterance">
<UtteranceFeeding />
</TabPane>
<TabPane tab="模型管理" key="model">
<ModelManagement />
</TabPane>
<TabPane tab="训练分析" key="analysis">
<TrainingAnalysis />
</TabPane>
</Tabs>
</div>
</div>
);