Enhance Buy Power and Recharge components with loading states and pagination. Update styles for better layout and introduce new pagination UI in the Power Management section. Remove outdated AI knowledge interface documentation.

This commit is contained in:
超级老白兔
2025-10-30 16:08:43 +08:00
parent 6b3948d454
commit 515c85e600
5 changed files with 62 additions and 214 deletions

View File

@@ -25,12 +25,15 @@ const BuyPowerPage: React.FC = () => {
}, []);
const fetchPackages = async () => {
setLoading(true);
try {
const res = await getTaocanList();
setPackages(res.list || []);
} catch (error) {
console.error("获取套餐列表失败:", error);
Toast.show({ content: "获取套餐列表失败", position: "top" });
} finally {
setLoading(false);
}
};

View File

@@ -1,7 +1,6 @@
// 算力管理页面样式
.powerPage {
background: #f5f5f5;
min-height: 100vh;
padding: 16px;
}
.powerTabs {
@@ -338,3 +337,11 @@
color: #999;
margin-top: 12px;
}
.paginationWrap {
padding: 15px;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
}

View File

@@ -13,6 +13,7 @@ import NavCommon from "@/components/NavCommon";
import Layout from "@/components/Layout/Layout";
import { getPowerStats, getOrderList } from "./api";
import type { PowerStats } from "./api";
import { Pagination } from "antd";
type OrderRecordView = {
id: number;
@@ -34,6 +35,9 @@ const PowerManagement: React.FC = () => {
const [filterStatus, setFilterStatus] = useState<string>("all");
const [filterTypeVisible, setFilterTypeVisible] = useState(false);
const [filterStatusVisible, setFilterStatusVisible] = useState(false);
const [page, setPage] = useState(1);
const [pageSize] = useState(10);
const [total, setTotal] = useState(0);
const typeOptions = [
{ label: "全部类型", value: "all" },
@@ -57,7 +61,8 @@ const PowerManagement: React.FC = () => {
useEffect(() => {
if (activeTab === "records") {
fetchRecords();
setPage(1);
fetchRecords(1);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeTab, filterType, filterStatus]);
@@ -72,9 +77,10 @@ const PowerManagement: React.FC = () => {
}
};
const fetchRecords = async () => {
const fetchRecords = async (customPage?: number) => {
setLoading(true);
try {
const reqPage = customPage !== undefined ? customPage : page;
// 映射状态到订单状态0待支付 1已支付 2已取消 3已退款
const statusMap: Record<string, string | undefined> = {
all: undefined,
@@ -84,8 +90,8 @@ const PowerManagement: React.FC = () => {
};
const res = await getOrderList({
page: "1",
limit: "100",
page: String(reqPage),
limit: String(pageSize),
orderType: "1",
status: statusMap[filterStatus],
});
@@ -100,6 +106,7 @@ const PowerManagement: React.FC = () => {
createTime: o.createTime || "",
}));
setRecords(list);
setTotal(Number(res.total || 0));
} catch (error) {
console.error("获取消费记录失败:", error);
Toast.show({ content: "获取消费记录失败", position: "top" });
@@ -290,30 +297,47 @@ const PowerManagement: React.FC = () => {
return (
<Layout
loading={loading}
header={
<NavCommon
title="算力管理"
right={
<div className={style.refreshBtn} onClick={handleRefresh}>
<SyncOutlined spin={loading} />
</div>
}
/>
<>
<NavCommon
title="算力管理"
right={
<div className={style.refreshBtn} onClick={handleRefresh}>
<SyncOutlined spin={loading} />
</div>
}
/>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
className={style.powerTabs}
>
<Tabs.Tab title="概览" key="overview" />
<Tabs.Tab title="消费记录" key="records" />
</Tabs>
</>
}
footer={
activeTab === "records" && records.length > 0 ? (
<div className={style.paginationWrap}>
<Pagination
current={page}
pageSize={pageSize}
total={total}
showSizeChanger={false}
onChange={p => {
setPage(p);
fetchRecords(p);
}}
/>
</div>
) : null
}
>
<div className={style.powerPage}>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
className={style.powerTabs}
>
<Tabs.Tab title="概览" key="overview">
{renderOverview()}
</Tabs.Tab>
<Tabs.Tab title="消费记录" key="records">
{renderRecords()}
</Tabs.Tab>
</Tabs>
{activeTab === "overview" && renderOverview()}
{activeTab === "records" && renderRecords()}
</div>
</Layout>
);

View File

@@ -60,13 +60,10 @@ const AIKnowledgeList: React.FC = () => {
independentPrompt: item.prompt || "",
status: item.isDel === 0 ? 1 : 0, // 未删除即为启用
aiCallEnabled: true, // 默认启用
materialCount: 0, // 需要单独统计
materialCount: item.materialCount || 0, // 需要单独统计
}));
setList(transformedList);
setTotal(Number(res?.total) || 0);
setEnabledCount(
transformedList.filter((item: any) => item.status === 1).length,
);
} catch (e) {
message.error("获取知识库列表失败");
} finally {
@@ -226,7 +223,7 @@ const AIKnowledgeList: React.FC = () => {
<div className={style.cardStats}>
<div className={style.statItem}>
<div className={style.statItemValue}>{item.materialCount || 0}</div>
<div className={style.statItemValue}>{item.materialCount}</div>
<div className={style.statItemLabel}></div>
</div>
<div className={style.statItem}>

View File

@@ -1,183 +0,0 @@
# AI知识库接口对接说明
## ✅ 已对接接口
### 知识库类型管理
1. **获取知识库类型列表**
- 接口:`GET /v1/knowledge/typeList`
- 参数:`{ page, limit }`
- 状态:✅ 已对接
2. **添加知识库类型**
- 接口:`POST /v1/knowledge/addType`
- 参数:`{ name, description, label, prompt }`
- 状态:✅ 已对接
3. **编辑知识库类型**
- 接口:`POST /v1/knowledge/editType`
- 参数:`{ id, name, description, label, prompt }`
- 状态:✅ 已对接
4. **删除知识库类型**
- 接口:`DELETE /v1/knowledge/deleteType`
- 参数:`{ id }`
- 状态:✅ 已对接
### 知识库(素材)管理
5. **获取知识库列表(素材列表)**
- 接口:`GET /v1/knowledge/getList`
- 参数:`{ typeId, name, label, fileUrl, page, limit }`
- 状态:✅ 已对接
6. **添加知识库(素材)**
- 接口:`POST /v1/knowledge/add`
- 参数:`{ typeId, name, label, fileUrl }`
- 状态:✅ 已对接(需要补充文件上传接口)
7. **删除知识库(素材)**
- 接口:`DELETE /v1/knowledge/delete`
- 参数:`{ id }`
- 状态:✅ 已对接
### AI功能
8. **初始化AI功能**
- 接口:`GET /v1/knowledge/init`
- 状态:✅ 已对接(页面加载时自动调用)
9. **发布并应用AI工具**
- 接口:`GET /v1/knowledge/release`
- 参数:`{ id }`
- 状态:✅ 已对接暂未在UI中使用可在需要时调用
---
## ⚠️ 需要后端补充的接口
### 1. 知识库状态切换
- **功能**:启用/禁用知识库类型
- **当前实现**:前端使用 `isDel` 字段判断状态,但没有单独的切换接口
- **建议**
```
POST /v1/knowledge/toggleStatus
参数: { id: number, status: 0 | 1 }
```
### 2. 统一提示词配置
- **功能**配置全局AI提示词
- **当前实现**前端保留了UI但接口未提供
- **建议**
```
GET /v1/knowledge/globalPrompt
POST /v1/knowledge/globalPrompt
参数: { enabled: boolean, content: string }
```
### 3. 调用者列表
- **功能**:显示哪些用户在使用某个知识库
- **当前实现**前端已预留UI但接口未提供
- **建议**
```
GET /v1/knowledge/callers
参数: { typeId: number, page: number, limit: number }
返回: { list: [], total: number }
```
### 4. 文件上传
- **功能**:上传素材文件并返回 fileUrl
- **当前实现**:前端使用临时占位方案
- **建议**
```
POST /v1/knowledge/uploadFile
参数: FormData (file)
返回: { fileUrl: string, fileSize: number }
```
### 5. 知识库详情
- **功能**:获取单个知识库类型的详细信息
- **当前实现**:前端通过列表接口查找
- **建议**
```
GET /v1/knowledge/typeDetail
参数: { id: number }
```
### 6. 素材统计
- **功能**:获取每个知识库类型的素材数量
- **当前实现**前端设置为0需要单独统计
- **建议**:在 `typeList` 接口返回值中增加 `materialCount` 字段
---
## 📋 数据字段映射说明
### 前端 ➡️ 后端
| 前端字段 | 后端字段 | 说明 |
| -------------------- | ---------------- | ------------------------ |
| tags | label | 标签数组 |
| useIndependentPrompt | 根据 prompt 判断 | 是否有独立提示词 |
| independentPrompt | prompt | 独立提示词内容 |
| status | isDel 判断 | isDel=0 为启用 |
| materialCount | 需补充 | 素材数量 |
| fileName | name | 文件名 |
| filePath | fileUrl | 文件路径 |
| uploadTime | createTime | 上传时间(需转换时间戳) |
### 时间格式转换
- 后端返回Unix 时间戳(秒)
- 前端显示:`new Date(timestamp * 1000).toLocaleDateString('zh-CN')`
---
## 🔧 待优化项
1. **文件上传流程**
- 当前:上传文件 → 获取URL → 调用添加接口
- 建议:合并为一个接口,后端处理文件上传和记录创建
2. **批量操作**
- 建议增加批量删除接口
- 建议增加批量修改标签接口
3. **发布机制**
- 明确发布接口的触发时机
- 是否需要在新建/编辑后自动发布
4. **权限控制**
- 建议增加知识库的访问权限配置
- 建议增加素材的可见性控制
---
## ✨ 功能完成度
- ✅ 知识库类型的增删改查
- ✅ 素材的增删查(改功能可后续补充)
- ✅ 独立提示词配置
- ⚠️ AI调用配置UI完成接口需补充
- ⚠️ 统一提示词UI完成接口需补充
- ⚠️ 调用者管理UI预留接口需补充
- ⚠️ 文件上传(临时方案,需正式接口)
---
## 📝 使用注意事项
1. 初始化AI功能会在页面加载时自动调用
2. 文件上传当前使用临时方案,实际部署需要对接真实的文件上传接口
3. 部分接口因后端未提供,使用了 `console.warn` 提示,不影响核心功能
4. 知识库的启用/禁用状态暂时仅在前端维护
---
**最后更新时间**2024-10-28