算力功能

This commit is contained in:
wong
2025-12-06 17:13:07 +08:00
parent f06eb0e9d7
commit a557319b3e
13 changed files with 3100 additions and 735 deletions

View File

@@ -121,13 +121,13 @@ const SelectionPopup: React.FC<SelectionPopupProps> = ({
}
} else {
// 多选模式:原有的逻辑
if (tempSelectedOptions.some(v => v.id === device.id)) {
setTempSelectedOptions(
tempSelectedOptions.filter(v => v.id !== device.id),
);
} else {
const newSelectedOptions = [...tempSelectedOptions, device];
setTempSelectedOptions(newSelectedOptions);
if (tempSelectedOptions.some(v => v.id === device.id)) {
setTempSelectedOptions(
tempSelectedOptions.filter(v => v.id !== device.id),
);
} else {
const newSelectedOptions = [...tempSelectedOptions, device];
setTempSelectedOptions(newSelectedOptions);
}
}
};

View File

@@ -34,15 +34,15 @@ const PopupFooter: React.FC<PopupFooterProps> = ({
{/* 分页栏 */}
<div className={style.paginationRow}>
{onSelectAll && (
<div className={style.totalCount}>
<Checkbox
checked={isAllSelected}
onChange={e => onSelectAll(e.target.checked)}
className={style.selectAllCheckbox}
>
</Checkbox>
</div>
<div className={style.totalCount}>
<Checkbox
checked={isAllSelected}
onChange={e => onSelectAll(e.target.checked)}
className={style.selectAllCheckbox}
>
</Checkbox>
</div>
)}
<div className={style.paginationControls}>
<Button

View File

@@ -106,7 +106,7 @@ export default function ContentForm() {
setUseAI(data.aiEnabled === 1);
} else {
// 兼容旧数据,默认根据是否有 aiPrompt 判断
setUseAI(!!data.aiPrompt);
setUseAI(!!data.aiPrompt);
}
setEnabled(data.status === 1);
// 时间范围
@@ -151,7 +151,7 @@ export default function ContentForm() {
.map(s => s.trim())
.filter(Boolean),
catchType,
aiPrompt,
aiPrompt,
aiEnabled: useAI ? 1 : 0,
timeEnabled: dateRange[0] || dateRange[1] ? 1 : 0,
startTime: dateRange[0] ? formatDate(dateRange[0]) : "",
@@ -347,37 +347,37 @@ export default function ContentForm() {
<div className={style["form-card"]}>
<Collapse className={style["keyword-collapse"]}>
<Collapse.Panel
key="keywords"
<Collapse.Panel
key="keywords"
title={
<div className={style["keyword-header"]}>
<span className={style["keyword-title"]}></span>
<DownOutlined className={style["keyword-arrow"]} />
</div>
}
>
<div className={style["form-section"]}>
<label className={style["form-label"]}></label>
<TextArea
placeholder="多个关键词用逗号分隔"
value={keywordsInclude}
onChange={e => setKeywordsInclude(e.target.value)}
className={style["input"]}
autoSize={{ minRows: 2, maxRows: 4 }}
/>
</div>
<div className={style["form-section"]}>
<label className={style["form-label"]}></label>
<TextArea
placeholder="多个关键词用逗号分隔"
value={keywordsExclude}
onChange={e => setKeywordsExclude(e.target.value)}
className={style["input"]}
autoSize={{ minRows: 2, maxRows: 4 }}
/>
</div>
</Collapse.Panel>
</Collapse>
>
<div className={style["form-section"]}>
<label className={style["form-label"]}></label>
<TextArea
placeholder="多个关键词用逗号分隔"
value={keywordsInclude}
onChange={e => setKeywordsInclude(e.target.value)}
className={style["input"]}
autoSize={{ minRows: 2, maxRows: 4 }}
/>
</div>
<div className={style["form-section"]}>
<label className={style["form-label"]}></label>
<TextArea
placeholder="多个关键词用逗号分隔"
value={keywordsExclude}
onChange={e => setKeywordsExclude(e.target.value)}
className={style["input"]}
autoSize={{ minRows: 2, maxRows: 4 }}
/>
</div>
</Collapse.Panel>
</Collapse>
</div>
{/* 采集内容类型 */}
@@ -400,38 +400,38 @@ export default function ContentForm() {
);
}}
>
{type === "text"
? "文本"
: type === "image"
? "图片"
: "视频"}
{type === "text"
? "文本"
: type === "image"
? "图片"
: "视频"}
</button>
))}
</div>
</div>
<div className={style["form-card"]}>
<div
className={style["form-section"]}
style={{ display: "flex", alignItems: "center", gap: 12 }}
>
<Switch checked={useAI} onChange={setUseAI} />
<span className={style["ai-desc"]}>
<div
className={style["form-section"]}
style={{ display: "flex", alignItems: "center", gap: 12 }}
>
<Switch checked={useAI} onChange={setUseAI} />
<span className={style["ai-desc"]}>
,AI生成
</span>
</div>
{useAI && (
<div className={style["form-section"]}>
<label className={style["form-label"]}>AI提示词</label>
<TextArea
</span>
</div>
{useAI && (
<div className={style["form-section"]}>
<label className={style["form-label"]}>AI提示词</label>
<TextArea
placeholder="请输入AI提示词"
value={aiPrompt}
onChange={e => setAIPrompt(e.target.value)}
className={style["input"]}
autoSize={{ minRows: 4, maxRows: 10 }}
/>
</div>
)}
</div>
)}
</div>
<div className={style["form-card"]}>
@@ -441,51 +441,51 @@ export default function ContentForm() {
<div className={style["date-inputs"]}>
<div className={style["date-item"]}>
<label className={style["date-label"]}></label>
<AntdInput
readOnly
<AntdInput
readOnly
value={
dateRange[0]
? `${dateRange[0].getFullYear()}/${String(dateRange[0].getMonth() + 1).padStart(2, "0")}/${String(dateRange[0].getDate()).padStart(2, "0")}`
: ""
}
placeholder="年/月/日"
placeholder="年/月/日"
className={style["date-input"]}
onClick={() => setShowStartPicker(true)}
/>
<DatePicker
visible={showStartPicker}
title="开始时间"
value={dateRange[0]}
onClose={() => setShowStartPicker(false)}
onConfirm={val => {
setDateRange([val, dateRange[1]]);
setShowStartPicker(false);
}}
/>
</div>
onClick={() => setShowStartPicker(true)}
/>
<DatePicker
visible={showStartPicker}
title="开始时间"
value={dateRange[0]}
onClose={() => setShowStartPicker(false)}
onConfirm={val => {
setDateRange([val, dateRange[1]]);
setShowStartPicker(false);
}}
/>
</div>
<div className={style["date-item"]}>
<label className={style["date-label"]}></label>
<AntdInput
readOnly
<AntdInput
readOnly
value={
dateRange[1]
? `${dateRange[1].getFullYear()}/${String(dateRange[1].getMonth() + 1).padStart(2, "0")}/${String(dateRange[1].getDate()).padStart(2, "0")}`
: ""
}
placeholder="年/月/日"
placeholder="年/月/日"
className={style["date-input"]}
onClick={() => setShowEndPicker(true)}
/>
<DatePicker
visible={showEndPicker}
title="结束时间"
value={dateRange[1]}
onClose={() => setShowEndPicker(false)}
onConfirm={val => {
setDateRange([dateRange[0], val]);
setShowEndPicker(false);
}}
/>
onClick={() => setShowEndPicker(true)}
/>
<DatePicker
visible={showEndPicker}
title="结束时间"
value={dateRange[1]}
onClose={() => setShowEndPicker(false)}
onConfirm={val => {
setDateRange([dateRange[0], val]);
setShowEndPicker(false);
}}
/>
</div>
</div>
</div>
@@ -493,7 +493,7 @@ export default function ContentForm() {
<div className={style["form-card"]}>
<div className={style["enable-section"]}>
<span className={style["enable-label"]}></span>
<Switch checked={enabled} onChange={setEnabled} />
<Switch checked={enabled} onChange={setEnabled} />
</div>
</div>
</form>

View File

@@ -4,7 +4,7 @@ import request from "@/api/request";
export interface PowerPackage {
id: number;
name: string;
tokens: number; // 算力点数
tokens: number | string; // 算力点数(可能是字符串,如"2,800"
price: number; // 价格(分)
originalPrice: number; // 原价(分)
unitPrice: number; // 单价
@@ -13,7 +13,7 @@ export interface PowerPackage {
isRecommend: number; // 是否推荐
isHot: number; // 是否热门
isVip: number; // 是否VIP
features: string[]; // 功能特性
features?: string[]; // 功能特性(可选)
description: string[]; // 描述关键词
status: number;
createTime: string;

View File

@@ -6,6 +6,9 @@ export interface Statistics {
monthUsed: number; // 本月使用
remainingTokens: number; // 剩余算力
totalConsumed: number; // 总消耗
yesterdayUsed?: number; // 昨日消耗
historyConsumed?: number; // 历史消耗
estimatedDays?: number; // 预计可用天数
}
// 算力统计接口
export function getStatistics(): Promise<Statistics> {
@@ -143,3 +146,42 @@ export function buyPackage(params: { id: number; price: number }) {
export function buyCustomPower(params: { amount: number }) {
return request("/v1/power/buy-custom", params, "POST");
}
// 查询订单状态
export interface QueryOrderResponse {
id: number;
mchId: number;
companyId: number;
userId: number;
orderType: number;
status: number; // 0: 待支付, 1: 已支付
goodsId: number;
goodsName: string;
goodsSpecs: string;
money: number;
orderNo: string;
payType: number | null;
payTime: number | null;
payInfo: any;
createTime: number;
}
export function queryOrder(orderNo: string): Promise<QueryOrderResponse> {
return request("/v1/tokens/queryOrder", { orderNo }, "GET");
}
// 账号信息
export interface Account {
id: number;
userName: string;
realName: string;
nickname: string;
departmentId: number;
departmentName: string;
avatar: string;
}
// 获取账号列表
export function getAccountList(): Promise<{ list: Account[]; total: number }> {
return request("/v1/kefu/accounts/list", undefined, "GET");
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,7 @@ export interface TokensUseRecordItem {
export interface TokensUseRecordList {
list: TokensUseRecordItem[];
total?: number;
}
//算力使用明细

View File

@@ -339,8 +339,8 @@
height: 5px;
border-radius: 10px 10px 0 0;
background: #1677ff;
}
}
}
.stat-icon-chat {
width: 20px;
@@ -700,7 +700,7 @@
.adm-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
border-radius: 50%;
}
}
@@ -710,13 +710,13 @@
}
.friend-name-row {
display: flex;
align-items: center;
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 4px;
margin-bottom: 4px;
}
.friend-name {
.friend-name {
font-size: 15px;
font-weight: 600;
color: #111;
@@ -727,7 +727,7 @@
display: flex;
flex-wrap: wrap;
gap: 4px;
}
}
.friend-tag {
font-size: 11px;
@@ -735,17 +735,17 @@
border-radius: 999px;
background: #f5f5f5;
color: #666;
}
}
.friend-id-row {
font-size: 12px;
font-size: 12px;
color: #999;
margin-bottom: 6px;
}
}
.friend-status-row {
display: flex;
flex-wrap: wrap;
display: flex;
flex-wrap: wrap;
gap: 6px;
}
@@ -764,7 +764,7 @@
font-size: 11px;
color: #999;
margin-bottom: 4px;
}
}
.value-amount {
font-size: 14px;

View File

@@ -370,13 +370,13 @@ const ScenarioList: React.FC = () => {
title={scenarioName || ""}
right={
scenarioId !== "10" ? (
<Button
size="small"
color="primary"
onClick={handleCreateNewPlan}
>
<PlusOutlined />
</Button>
<Button
size="small"
color="primary"
onClick={handleCreateNewPlan}
>
<PlusOutlined />
</Button>
) : null
}
/>
@@ -427,13 +427,13 @@ const ScenarioList: React.FC = () => {
{searchTerm ? "没有找到匹配的计划" : "暂无计划"}
</div>
{scenarioId !== "10" && (
<Button
color="primary"
onClick={handleCreateNewPlan}
className={style["create-first-btn"]}
>
<PlusOutlined />
</Button>
<Button
color="primary"
onClick={handleCreateNewPlan}
className={style["create-first-btn"]}
>
<PlusOutlined />
</Button>
)}
</div>
) : (