fix: Add missing commas in various TypeScript files to ensure proper syntax and prevent potential runtime errors.

This commit is contained in:
2025-07-30 09:29:32 +08:00
parent 035c0602b5
commit 0059c3ba3b
59 changed files with 1154 additions and 173 deletions

View File

@@ -7,7 +7,7 @@ import request from "./request";
*/
export async function uploadFile(
file: File,
uploadUrl: string = "/v1/attachment/upload"
uploadUrl: string = "/v1/attachment/upload",
): Promise<string> {
try {
// 创建 FormData 对象用于文件上传

View File

@@ -19,7 +19,7 @@ export const fetchDeviceRelatedAccounts = (id: string | number) =>
export const fetchDeviceHandleLogs = (
id: string | number,
page = 1,
limit = 10
limit = 10,
) => request(`/v1/devices/${id}/handle-logs`, { page, limit }, "GET");
// 更新设备任务配置

View File

@@ -47,7 +47,7 @@ instance.interceptors.response.use(
err => {
Toast.show({ content: err.message || "网络异常", position: "top" });
return Promise.reject(err);
}
},
);
export function request(
@@ -55,7 +55,7 @@ export function request(
data?: any,
method: Method = "GET",
config?: AxiosRequestConfig,
debounceGap?: number
debounceGap?: number,
): Promise<any> {
const gap =
typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP;

View File

@@ -117,7 +117,7 @@ export default function AccountSelection({
acc =>
acc.userName.includes(searchQuery) ||
acc.realName.includes(searchQuery) ||
acc.departmentName.includes(searchQuery)
acc.departmentName.includes(searchQuery),
);
// 处理账号选择

View File

@@ -58,7 +58,7 @@ interface ContentLibrarySelectionProps {
readonly?: boolean;
onConfirm?: (
selectedIds: string[],
selectedItems: ContentLibraryItem[]
selectedItems: ContentLibraryItem[],
) => void;
}
@@ -86,7 +86,7 @@ export default function ContentLibrarySelection({
// 获取已选内容库详细信息
const selectedLibraryObjs = libraries.filter(item =>
selectedLibraries.includes(item.id)
selectedLibraries.includes(item.id),
);
// 删除已选内容库
@@ -161,7 +161,7 @@ export default function ContentLibrarySelection({
onSelect(newSelected);
if (onSelectDetail) {
const selectedObjs = libraries.filter(item =>
newSelected.includes(item.id)
newSelected.includes(item.id),
);
onSelectDetail(selectedObjs);
}

View File

@@ -61,7 +61,7 @@ const SelectionPopup: React.FC<SelectionPopupProps> = ({
wxid: d.wechatId || "",
nickname: d.nickname || "",
usedInPlans: d.usedInPlans || 0,
}))
})),
);
setTotal(res.total || 0);
}
@@ -71,7 +71,7 @@ const SelectionPopup: React.FC<SelectionPopupProps> = ({
setLoading(false);
}
},
[]
[],
);
// 打开弹窗时获取第一页

View File

@@ -137,7 +137,7 @@ export default function FriendSelection({
// 如果有 onSelectDetail 回调,传递完整的好友对象
if (onSelectDetail) {
const selectedFriendObjs = friends.filter(friend =>
newSelectedFriends.includes(friend.id)
newSelectedFriends.includes(friend.id),
);
onSelectDetail(selectedFriendObjs);
}

View File

@@ -59,7 +59,7 @@ export default function GroupSelection({
// 获取已选群聊详细信息
const selectedGroupObjs = groups.filter(group =>
selectedGroups.includes(group.id)
selectedGroups.includes(group.id),
);
// 删除已选群聊
@@ -141,7 +141,7 @@ export default function GroupSelection({
// 如果有 onSelectDetail 回调,传递完整的群聊对象
if (onSelectDetail) {
const selectedGroupObjs = groups.filter(group =>
newSelectedGroups.includes(group.id)
newSelectedGroups.includes(group.id),
);
onSelectDetail(selectedGroupObjs);
}

View File

@@ -20,7 +20,7 @@ const Layout: React.FC<LayoutProps> = ({
const setRealHeight = () => {
document.documentElement.style.setProperty(
"--real-vh",
`${window.innerHeight * 0.01}px`
`${window.innerHeight * 0.01}px`,
);
};
setRealHeight();

View File

@@ -68,7 +68,7 @@ const UploadComponent: React.FC<UploadComponentProps> = ({
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
body: formData,
}
},
);
if (!response.ok) {

View File

@@ -12,14 +12,14 @@ export function getContentLibraryDetail(id: string): Promise<any> {
// 创建内容库
export function createContentLibrary(
params: CreateContentLibraryParams
params: CreateContentLibraryParams,
): Promise<any> {
return request("/v1/content/library/create", params, "POST");
}
// 更新内容库
export function updateContentLibrary(
params: UpdateContentLibraryParams
params: UpdateContentLibraryParams,
): Promise<any> {
const { id, ...data } = params;
return request(`/v1/content/library/update`, { id, ...data }, "POST");

View File

@@ -22,14 +22,14 @@ export function getContentLibraryDetail(id: string): Promise<any> {
// 创建内容库
export function createContentLibrary(
params: CreateContentLibraryParams
params: CreateContentLibraryParams,
): Promise<any> {
return request("/v1/content/library/create", params, "POST");
}
// 更新内容库
export function updateContentLibrary(
params: UpdateContentLibraryParams
params: UpdateContentLibraryParams,
): Promise<any> {
const { id, ...data } = params;
return request(`/v1/content/library/update`, { id, ...data }, "POST");
@@ -43,7 +43,7 @@ export function deleteContentLibrary(id: string): Promise<any> {
// 切换内容库状态
export function toggleContentLibraryStatus(
id: string,
status: number
status: number,
): Promise<any> {
return request("/v1/content/library/update-status", { id, status }, "POST");
}

View File

@@ -182,7 +182,7 @@ const ContentLibraryList: React.FC = () => {
const filteredLibraries = libraries.filter(
library =>
library.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
library.creatorName?.toLowerCase().includes(searchQuery.toLowerCase())
library.creatorName?.toLowerCase().includes(searchQuery.toLowerCase()),
);
return (

View File

@@ -206,8 +206,8 @@ const Home: React.FC = () => {
onClick={() =>
navigate(
`/scenarios/list/${scenario.id}/${encodeURIComponent(
scenario.name
)}`
scenario.name,
)}`,
)
}
>

View File

@@ -0,0 +1,17 @@
import request from "@/api/request";
import { ConsumptionRecordsResponse, ConsumptionRecordDetail } from "./data";
// 获取消费记录列表
export function getConsumptionRecords(params: {
page: number;
limit: number;
}): Promise<ConsumptionRecordsResponse> {
return request("/v1/consumption-records", params, "GET");
}
// 获取消费记录详情
export function getConsumptionRecordDetail(
id: string,
): Promise<ConsumptionRecordDetail> {
return request(`/v1/consumption-records/${id}`, {}, "GET");
}

View File

@@ -0,0 +1,26 @@
// 消费记录类型定义
export interface ConsumptionRecord {
id: string;
type: "recharge" | "ai_service" | "version_upgrade";
amount: number;
description: string;
createTime: string;
status: "success" | "pending" | "failed";
balance?: number;
}
// API响应类型
export interface ConsumptionRecordsResponse {
list: ConsumptionRecord[];
total: number;
page: number;
limit: number;
}
// 消费记录详情
export interface ConsumptionRecordDetail extends ConsumptionRecord {
orderNo?: string;
paymentMethod?: string;
remark?: string;
operator?: string;
}

View File

@@ -0,0 +1,141 @@
.records-page {
padding: 16px;
background: #f7f8fa;
min-height: 100vh;
}
.records-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.record-card {
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
background: #fff;
}
.record-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
}
.record-info {
display: flex;
align-items: flex-start;
gap: 12px;
flex: 1;
}
.type-icon-wrapper {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.type-icon {
font-size: 20px;
color: #666;
}
.record-details {
flex: 1;
min-width: 0;
}
.record-description {
font-size: 16px;
font-weight: 500;
color: #222;
margin-bottom: 4px;
line-height: 1.4;
}
.record-time {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: #999;
}
.time-icon {
font-size: 12px;
}
.record-amount {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
flex-shrink: 0;
}
.amount-text {
font-size: 16px;
font-weight: 600;
}
.status-tag {
font-size: 11px;
padding: 2px 6px;
border-radius: 8px;
}
.balance-info {
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
font-size: 12px;
color: #666;
}
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 20px;
}
.loading-text {
font-size: 14px;
color: #666;
}
.load-more {
text-align: center;
padding: 16px;
color: var(--primary-color);
font-size: 14px;
font-weight: 500;
cursor: pointer;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: background-color 0.2s ease;
&:hover {
background-color: #f8f9fa;
}
&:active {
background-color: #e9ecef;
}
}
.empty-state {
margin-top: 60px;
}
.empty-icon {
font-size: 48px;
color: #ccc;
}

View File

@@ -0,0 +1,212 @@
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { Card, List, Tag, SpinLoading, Empty } from "antd-mobile";
import { useUserStore } from "@/store/module/user";
import style from "./index.module.scss";
import {
WalletOutlined,
RobotOutlined,
CrownOutlined,
ClockCircleOutlined,
} from "@ant-design/icons";
import NavCommon from "@/components/NavCommon";
import Layout from "@/components/Layout/Layout";
import { getConsumptionRecords } from "./api";
import { ConsumptionRecord } from "./data";
const ConsumptionRecords: React.FC = () => {
const navigate = useNavigate();
const { user } = useUserStore();
const [records, setRecords] = useState<ConsumptionRecord[]>([]);
const [loading, setLoading] = useState(true);
const [hasMore, setHasMore] = useState(true);
const [page, setPage] = useState(1);
useEffect(() => {
loadRecords();
}, []);
const loadRecords = async (reset = false) => {
if (loading) return;
setLoading(true);
try {
const currentPage = reset ? 1 : page;
const response = await getConsumptionRecords({
page: currentPage,
limit: 20,
});
const newRecords = response.list || [];
setRecords(prev => (reset ? newRecords : [...prev, ...newRecords]));
setHasMore(newRecords.length === 20);
if (reset) setPage(1);
else setPage(currentPage + 1);
} catch (error) {
console.error("加载消费记录失败:", error);
} finally {
setLoading(false);
}
};
const getTypeIcon = (type: string) => {
switch (type) {
case "recharge":
return <WalletOutlined className={style["type-icon"]} />;
case "ai_service":
return <RobotOutlined className={style["type-icon"]} />;
case "version_upgrade":
return <CrownOutlined className={style["type-icon"]} />;
default:
return <WalletOutlined className={style["type-icon"]} />;
}
};
const getTypeColor = (type: string) => {
switch (type) {
case "recharge":
return "#52c41a";
case "ai_service":
return "#1890ff";
case "version_upgrade":
return "#722ed1";
default:
return "#666";
}
};
const getStatusText = (status: string) => {
switch (status) {
case "success":
return "成功";
case "pending":
return "处理中";
case "failed":
return "失败";
default:
return "未知";
}
};
const getStatusColor = (status: string) => {
switch (status) {
case "success":
return "#52c41a";
case "pending":
return "#faad14";
case "failed":
return "#ff4d4f";
default:
return "#666";
}
};
const formatAmount = (amount: number, type: string) => {
if (type === "recharge") {
return `+¥${amount.toFixed(2)}`;
} else {
return `-¥${amount.toFixed(2)}`;
}
};
const formatTime = (timeStr: string) => {
const date = new Date(timeStr);
const now = new Date();
const diff = now.getTime() - date.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
if (days === 0) {
return date.toLocaleTimeString("zh-CN", {
hour: "2-digit",
minute: "2-digit",
});
} else if (days === 1) {
return (
"昨天 " +
date.toLocaleTimeString("zh-CN", {
hour: "2-digit",
minute: "2-digit",
})
);
} else if (days < 7) {
return `${days}天前`;
} else {
return date.toLocaleDateString("zh-CN");
}
};
const renderRecordItem = (record: ConsumptionRecord) => (
<Card key={record.id} className={style["record-card"]}>
<div className={style["record-header"]}>
<div className={style["record-info"]}>
<div
className={style["type-icon-wrapper"]}
style={{ backgroundColor: `${getTypeColor(record.type)}20` }}
>
{getTypeIcon(record.type)}
</div>
<div className={style["record-details"]}>
<div className={style["record-description"]}>
{record.description}
</div>
<div className={style["record-time"]}>
<ClockCircleOutlined className={style["time-icon"]} />
{formatTime(record.createTime)}
</div>
</div>
</div>
<div className={style["record-amount"]}>
<div
className={style["amount-text"]}
style={{
color: record.type === "recharge" ? "#52c41a" : "#ff4d4f",
}}
>
{formatAmount(record.amount, record.type)}
</div>
<Tag
color={getStatusColor(record.status)}
className={style["status-tag"]}
>
{getStatusText(record.status)}
</Tag>
</div>
</div>
{record.balance !== undefined && (
<div className={style["balance-info"]}>
: {record.balance.toFixed(2)}
</div>
)}
</Card>
);
return (
<Layout header={<NavCommon title="消费记录" />}>
<div className={style["records-page"]}>
{records.length === 0 && !loading ? (
<Empty
className={style["empty-state"]}
description="暂无消费记录"
image={<WalletOutlined className={style["empty-icon"]} />}
/>
) : (
<div className={style["records-list"]}>
{records.map(renderRecordItem)}
{loading && (
<div className={style["loading-container"]}>
<SpinLoading color="primary" />
<div className={style["loading-text"]}>...</div>
</div>
)}
{!loading && hasMore && (
<div className={style["load-more"]} onClick={() => loadRecords()}>
</div>
)}
</div>
)}
</div>
</Layout>
);
};
export default ConsumptionRecords;

View File

@@ -23,7 +23,7 @@ const DeviceDetail: React.FC = () => {
const [logs, setLogs] = useState<HandleLog[]>([]);
const [logsLoading, setLogsLoading] = useState(false);
const [featureSaving, setFeatureSaving] = useState<{ [k: string]: boolean }>(
{}
{},
);
// 获取设备详情
@@ -82,7 +82,7 @@ const DeviceDetail: React.FC = () => {
// 功能开关
const handleFeatureChange = async (
feature: keyof Device["features"],
checked: boolean
checked: boolean,
) => {
if (!id) return;
setFeatureSaving(prev => ({ ...prev, [feature]: true }));
@@ -94,7 +94,7 @@ const DeviceDetail: React.FC = () => {
...prev,
features: { ...prev.features, [feature]: checked },
}
: prev
: prev,
);
Toast.show({
content: `${getFeatureName(feature)}${checked ? "开启" : "关闭"}`,
@@ -219,12 +219,12 @@ const DeviceDetail: React.FC = () => {
onChange={checked =>
handleFeatureChange(
f as keyof Device["features"],
checked
checked,
)
}
/>
</div>
)
),
)}
</div>
)}

View File

@@ -1,11 +1,52 @@
.recharge-page {
padding: 16px 0 60px 0;
background: #f7f8fa;
min-height: 100vh;
}
.record-btn {
color: var(--primary-color);
font-size: 14px;
font-weight: 500;
cursor: pointer;
padding: 4px 8px;
border-radius: 4px;
transition: background-color 0.2s ease;
&:hover {
background-color: rgba(24, 142, 238, 0.1);
}
&:active {
background-color: rgba(24, 142, 238, 0.2);
}
}
.recharge-tabs {
:global(.adm-tabs-header) {
background: #fff;
border-bottom: 1px solid #f0f0f0;
position: sticky;
top: 0;
z-index: 10;
}
:global(.adm-tabs-tab) {
font-size: 16px;
font-weight: 500;
}
:global(.adm-tabs-tab-active) {
color: var(--primary-color);
}
:global(.adm-tabs-tab-line) {
background: var(--primary-color);
}
}
.tab-content {
}
.balance-card {
margin: 16px;
margin-bottom: 16px;
background: #f6ffed;
border: 1px solid #b7eb8f;
border-radius: 12px;
@@ -43,24 +84,24 @@
}
.quick-card {
margin: 16px;
margin-bottom: 16px;
.quick-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
gap: 6px;
justify-content: flex-start;
margin-bottom: 8px;
}
}
.desc-card {
margin: 16px;
margin: 16px 0px;
background: #fffbe6;
border: 1px solid #ffe58f;
}
.warn-card {
margin: 16px;
margin: 16px 0;
background: #fff2e8;
border: 1px solid #ffbb96;
}
@@ -125,3 +166,275 @@
color: #faad14;
font-size: 14px;
}
// AI服务样式
.ai-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
}
.ai-title {
display: flex;
align-items: center;
font-size: 20px;
font-weight: 700;
color: #222;
}
.ai-icon {
font-size: 24px;
color: var(--primary-color);
margin-right: 8px;
}
.ai-tag {
background: #ff6b35;
color: #fff;
font-size: 12px;
padding: 4px 8px;
border-radius: 12px;
font-weight: 500;
}
.ai-description {
color: #666;
font-size: 14px;
margin-bottom: 20px;
}
.ai-services {
display: flex;
flex-direction: column;
gap: 16px;
}
.ai-service-card {
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.service-header {
margin-bottom: 12px;
}
.service-info {
display: flex;
align-items: center;
gap: 12px;
}
.service-icon {
font-size: 24px;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: #f0f0f0;
border-radius: 8px;
}
.service-details {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
}
.service-name {
font-size: 16px;
font-weight: 600;
color: #222;
}
.service-price {
font-size: 16px;
font-weight: 700;
color: #ff4d4f;
}
.service-description {
color: #666;
font-size: 14px;
margin-bottom: 12px;
line-height: 1.5;
}
.service-features {
margin-bottom: 16px;
}
.feature-item {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
font-size: 14px;
color: #333;
}
.feature-check {
color: #52c41a;
font-weight: bold;
font-size: 16px;
}
.usage-progress {
margin-top: 12px;
}
.usage-label {
font-size: 14px;
color: #666;
margin-bottom: 8px;
}
.progress-bar {
width: 100%;
height: 6px;
background: #f0f0f0;
border-radius: 3px;
overflow: hidden;
margin-bottom: 6px;
}
.progress-fill {
height: 100%;
background: var(--primary-color);
border-radius: 3px;
transition: width 0.3s ease;
}
.usage-text {
font-size: 12px;
color: #999;
text-align: right;
}
// 版本套餐样式
.version-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
font-size: 20px;
font-weight: 700;
color: #222;
}
.version-icon {
font-size: 24px;
color: #722ed1;
}
.version-description {
color: #666;
font-size: 14px;
margin-bottom: 20px;
}
.version-packages {
display: flex;
flex-direction: column;
gap: 16px;
}
.version-card {
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
position: relative;
}
.package-header {
margin-bottom: 12px;
}
.package-info {
display: flex;
align-items: center;
gap: 12px;
}
.package-icon {
font-size: 24px;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: #f0f0f0;
border-radius: 8px;
}
.package-details {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
}
.package-name {
display: flex;
align-items: center;
gap: 8px;
font-size: 16px;
font-weight: 600;
color: #222;
}
.package-tag {
font-size: 12px;
padding: 2px 8px;
border-radius: 10px;
font-weight: 500;
}
.tag-blue {
background: #e6f7ff;
color: #1890ff;
}
.tag-green {
background: #f6ffed;
color: #52c41a;
}
.package-price {
font-size: 18px;
font-weight: 700;
color: var(--primary-color);
}
.package-description {
color: #666;
font-size: 14px;
margin-bottom: 12px;
line-height: 1.5;
}
.package-features {
margin-bottom: 16px;
}
.features-title {
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.package-status {
text-align: center;
color: #52c41a;
font-size: 14px;
font-weight: 500;
margin-bottom: 12px;
}
.upgrade-btn {
border-radius: 8px;
font-size: 16px;
font-weight: 600;
}

View File

@@ -1,14 +1,123 @@
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Card, Button, Toast, NavBar } from "antd-mobile";
import { Card, Button, Toast, NavBar, Tabs } from "antd-mobile";
import { useUserStore } from "@/store/module/user";
import style from "./index.module.scss";
import { WalletOutlined, WarningOutlined } from "@ant-design/icons";
import {
WalletOutlined,
WarningOutlined,
ClockCircleOutlined,
RobotOutlined,
CrownOutlined,
} from "@ant-design/icons";
import NavCommon from "@/components/NavCommon";
import Layout from "@/components/Layout/Layout";
const quickAmounts = [50, 100, 200, 500, 1000];
// AI服务套餐数据
const aiServicePackages = [
{
id: 1,
name: "入门套餐",
tag: "推荐",
tagColor: "blue",
description: "适合个人用户体验AI服务",
usage: "可使用AI服务约110次",
price: 100,
originalPrice: 110,
gift: 10,
actualAmount: 110,
},
{
id: 2,
name: "标准套餐",
tag: "热门",
tagColor: "green",
description: "适合小团队日常使用",
usage: "可使用AI服务约580次",
price: 500,
originalPrice: 580,
gift: 80,
actualAmount: 580,
},
];
// AI服务列表数据
const aiServices = [
{
id: 1,
name: "添加好友及打招呼",
icon: "💬",
price: 1,
description: "AI智能添加好友并发送个性化打招呼消息",
features: ["智能筛选目标用户", "发送个性化打招呼消息", "自动记录添加结果"],
usage: { current: 15, total: 450 },
},
{
id: 2,
name: "小室AI内容生产",
icon: "⚡",
price: 1,
description: "AI智能创建朋友圈内容,智能配文与朋友圈内容",
features: ["智能生成朋友圈文案", "AI配文智能文案", "内容智能排版优化"],
usage: { current: 28, total: 680 },
},
{
id: 3,
name: "智能分发服务",
icon: "📤",
price: 1,
description: "AI智能分发内容到多个平台",
features: ["多平台智能分发", "内容智能优化", "分发效果分析"],
usage: { current: 12, total: 300 },
},
];
// 版本套餐数据
const versionPackages = [
{
id: 1,
name: "普通版本",
icon: "📦",
price: "免费",
description: "充值即可使用,包含基础AI功能",
features: ["基础AI服务", "标准客服支持", "基础数据统计"],
status: "当前使用中",
buttonText: null,
tagColor: undefined,
},
{
id: 2,
name: "标准版本",
icon: "👑",
price: "¥98/月",
tag: "推荐",
tagColor: "blue",
description: "适合中小企业,AI功能更丰富",
features: ["高级AI服务", "优先客服支持", "详细数据分析", "API接口访问"],
status: null,
buttonText: "立即升级",
},
{
id: 3,
name: "企业版本",
icon: "🏢",
price: "¥1980/月",
description: "适合大型企业,提供专属服务",
features: [
"专属AI服务",
"24小时专属客服",
"高级数据分析",
"API接口访问",
"专属技术支持",
],
status: null,
buttonText: "立即升级",
tagColor: undefined,
},
];
const Recharge: React.FC = () => {
const navigate = useNavigate();
const { user } = useUserStore();
@@ -16,6 +125,7 @@ const Recharge: React.FC = () => {
const [balance, setBalance] = useState(0);
const [selected, setSelected] = useState<number | null>(null);
const [loading, setLoading] = useState(false);
const [activeTab, setActiveTab] = useState("account");
// 充值操作
const handleRecharge = async () => {
@@ -31,68 +141,228 @@ const Recharge: React.FC = () => {
}, 1200);
};
return (
<Layout header={<NavCommon title="账户充值" />}>
<div className={style["recharge-page"]}>
<Card className={style["balance-card"]}>
<div className={style["balance-content"]}>
<WalletOutlined className={style["wallet-icon"]} />
<div className={style["balance-info"]}>
<div className={style["balance-label"]}></div>
<div className={style["balance-amount"]}>
{balance.toFixed(2)}
// 渲染账户充值tab内容
const renderAccountRecharge = () => (
<div className={style["tab-content"]}>
<Card className={style["balance-card"]}>
<div className={style["balance-content"]}>
<WalletOutlined className={style["wallet-icon"]} />
<div className={style["balance-info"]}>
<div className={style["balance-label"]}></div>
<div className={style["balance-amount"]}>
{balance.toFixed(2)}
</div>
</div>
</div>
</Card>
<Card className={style["quick-card"]}>
<div className={style["quick-title"]}></div>
<div className={style["quick-list"]}>
{quickAmounts.map(amt => (
<Button
key={amt}
color={selected === amt ? "primary" : "default"}
className={
selected === amt
? style["quick-btn-active"]
: style["quick-btn"]
}
onClick={() => setSelected(amt)}
>
{amt}
</Button>
))}
</div>
<Button
block
color="primary"
size="large"
className={style["recharge-main-btn"]}
loading={loading}
onClick={handleRecharge}
>
</Button>
</Card>
<Card className={style["desc-card"]}>
<div className={style["desc-title"]}></div>
<div className={style["desc-text"]}>
使
</div>
</Card>
{balance < 10 && (
<Card className={style["warn-card"]}>
<div className={style["warn-content"]}>
<WarningOutlined className={style["warn-icon"]} />
<div className={style["warn-info"]}>
<div className={style["warn-title"]}></div>
<div className={style["warn-text"]}>
使
</div>
</div>
</div>
</Card>
<Card className={style["quick-card"]}>
<div className={style["quick-title"]}></div>
<div className={style["quick-list"]}>
{quickAmounts.map(amt => (
<Button
key={amt}
color={selected === amt ? "primary" : "default"}
className={
selected === amt
? style["quick-btn-active"]
: style["quick-btn"]
}
onClick={() => setSelected(amt)}
>
{amt}
</Button>
))}
</div>
<Button
block
color="primary"
size="large"
className={style["recharge-main-btn"]}
loading={loading}
onClick={handleRecharge}
>
</Button>
</Card>
<Card className={style["desc-card"]}>
<div className={style["desc-title"]}></div>
<div className={style["desc-text"]}>
使
</div>
</Card>
{balance < 10 && (
<Card className={style["warn-card"]}>
<div className={style["warn-content"]}>
<WarningOutlined className={style["warn-icon"]} />
<div className={style["warn-info"]}>
<div className={style["warn-title"]}></div>
<div className={style["warn-text"]}>
使
)}
</div>
);
// 渲染AI服务tab内容
const renderAiServices = () => (
<div className={style["tab-content"]}>
<div className={style["ai-header"]}>
<div className={style["ai-title"]}>
<RobotOutlined className={style["ai-icon"]} />
AI智能服务收费
</div>
<div className={style["ai-tag"]}></div>
</div>
<div className={style["ai-description"]}>
AI服务,使,1
</div>
<div className={style["ai-services"]}>
{aiServices.map(service => (
<Card key={service.id} className={style["ai-service-card"]}>
<div className={style["service-header"]}>
<div className={style["service-info"]}>
<div className={style["service-icon"]}>{service.icon}</div>
<div className={style["service-details"]}>
<div className={style["service-name"]}>{service.name}</div>
<div className={style["service-price"]}>
¥{service.price}/
</div>
</div>
</div>
</div>
<div className={style["service-description"]}>
{service.description}
</div>
<div className={style["service-features"]}>
{service.features.map((feature, index) => (
<div key={index} className={style["feature-item"]}>
<span className={style["feature-check"]}></span>
{feature}
</div>
))}
</div>
<div className={style["usage-progress"]}>
<div className={style["usage-label"]}>使</div>
<div className={style["progress-bar"]}>
<div
className={style["progress-fill"]}
style={{
width: `${(service.usage.current / service.usage.total) * 100}%`,
}}
></div>
</div>
<div className={style["usage-text"]}>
{service.usage.current} / {service.usage.total}
</div>
</div>
</Card>
)}
))}
</div>
</div>
);
// 渲染版本套餐tab内容
const renderVersionPackages = () => (
<div className={style["tab-content"]}>
<div className={style["version-header"]}>
<CrownOutlined className={style["version-icon"]} />
<span></span>
</div>
<div className={style["version-description"]}>
,AI服务
</div>
<div className={style["version-packages"]}>
{versionPackages.map(pkg => (
<Card key={pkg.id} className={style["version-card"]}>
<div className={style["package-header"]}>
<div className={style["package-info"]}>
<div className={style["package-icon"]}>{pkg.icon}</div>
<div className={style["package-details"]}>
<div className={style["package-name"]}>
{pkg.name}
{pkg.tag && (
<span
className={`${style["package-tag"]} ${style[`tag-${pkg.tagColor || "blue"}`]}`}
>
{pkg.tag}
</span>
)}
</div>
<div className={style["package-price"]}>{pkg.price}</div>
</div>
</div>
</div>
<div className={style["package-description"]}>
{pkg.description}
</div>
<div className={style["package-features"]}>
<div className={style["features-title"]}>:</div>
{pkg.features.map((feature, index) => (
<div key={index} className={style["feature-item"]}>
<span className={style["feature-check"]}></span>
{feature}
</div>
))}
</div>
{pkg.status && (
<div className={style["package-status"]}>{pkg.status}</div>
)}
{pkg.buttonText && (
<Button
block
color="primary"
className={style["upgrade-btn"]}
onClick={() => {
Toast.show({ content: "升级功能开发中", position: "top" });
}}
>
{pkg.buttonText}
</Button>
)}
</Card>
))}
</div>
</div>
);
return (
<Layout
header={
<NavCommon
title="充值中心"
right={
<div
className={style["record-btn"]}
onClick={() => navigate("/mine/consumption-records")}
>
<ClockCircleOutlined />
&nbsp;
</div>
}
/>
}
>
<div className={style["recharge-page"]}>
<Tabs
activeKey={activeTab}
onChange={setActiveTab}
className={style["recharge-tabs"]}
>
<Tabs.Tab title="账户充值" key="account">
{renderAccountRecharge()}
</Tabs.Tab>
<Tabs.Tab title="AI服务" key="ai">
{renderAiServices()}
</Tabs.Tab>
<Tabs.Tab title="版本套餐" key="version">
{renderVersionPackages()}
</Tabs.Tab>
</Tabs>
</div>
</Layout>
);

View File

@@ -6,7 +6,7 @@ import type {
} from "./data";
export function getTrafficPoolDetail(
wechatId: string
wechatId: string,
): Promise<TrafficPoolUserDetail> {
return request("/v1/wechats/getWechatInfo", { wechatId }, "GET");
}

View File

@@ -520,7 +520,7 @@ const TrafficPoolDetail: React.FC = () => {
<span>{restriction.reason || "未知原因"}</span>
<Tag
color={getRestrictionLevelColor(
restriction.level
restriction.level,
)}
fill="outline"
className={styles.restrictionLevel}

View File

@@ -90,7 +90,7 @@ export function useTrafficPoolListLogic() {
// 单选
const handleSelect = (id: number, checked: boolean) => {
setSelectedIds(prev =>
checked ? [...prev, id] : prev.filter(i => i !== id)
checked ? [...prev, id] : prev.filter(i => i !== id),
);
};

View File

@@ -19,7 +19,7 @@ export function getWechatFriends(params: {
limit: params.limit,
keyword: params.keyword,
},
"GET"
"GET",
);
}

View File

@@ -133,7 +133,7 @@ const WechatAccountDetail: React.FC = () => {
setIsFetchingFriends(false);
}
},
[id]
[id],
);
// 搜索好友
@@ -153,7 +153,7 @@ const WechatAccountDetail: React.FC = () => {
setFriendsPage(page);
fetchFriendsList(page, searchQuery);
},
[searchQuery, fetchFriendsList]
[searchQuery, fetchFriendsList],
);
// 初始化数据

View File

@@ -69,7 +69,7 @@ const Scene: React.FC = () => {
const handleScenarioClick = (scenarioId: string, scenarioName: string) => {
navigate(
`/scenarios/list/${scenarioId}/${encodeURIComponent(scenarioName)}`
`/scenarios/list/${scenarioId}/${encodeURIComponent(scenarioName)}`,
);
};

View File

@@ -211,7 +211,7 @@ const ScenarioList: React.FC = () => {
if (response) {
// 处理webhook URL使用工具函数构建完整地址
const webhookUrl = buildApiUrl(
response.textUrl?.fullUrl || `webhook/${taskId}`
response.textUrl?.fullUrl || `webhook/${taskId}`,
);
setCurrentApiSettings({
@@ -286,7 +286,7 @@ const ScenarioList: React.FC = () => {
};
const filteredTasks = tasks.filter(task =>
task.name.toLowerCase().includes(searchTerm.toLowerCase())
task.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
// 生成操作菜单
@@ -537,7 +537,7 @@ const ScenarioList: React.FC = () => {
<span className={style["action-icon"]}>{item.icon}</span>
<span className={style["action-text"]}>{item.text}</span>
</div>
)
),
)}
</div>
</div>

View File

@@ -317,7 +317,7 @@ HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.o
onClick={() =>
handleCopy(
codeExamples[activeLanguage as keyof typeof codeExamples],
"代码"
"代码",
)
}
className={style["copy-code-btn"]}

View File

@@ -146,7 +146,7 @@ export default function NewPlan() {
? error
: isEdit
? "更新计划失败,请重试"
: "创建计划失败,请重试"
: "创建计划失败,请重试",
);
}
};

View File

@@ -105,10 +105,10 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
const [accounts] = useState<Account[]>(generateRandomAccounts(50));
const [materials] = useState<Material[]>(generatePosterMaterials());
const [selectedAccounts, setSelectedAccounts] = useState<Account[]>(
formData.accounts?.length > 0 ? formData.accounts : []
formData.accounts?.length > 0 ? formData.accounts : [],
);
const [selectedMaterials, setSelectedMaterials] = useState<Material[]>(
formData.materials?.length > 0 ? formData.materials : []
formData.materials?.length > 0 ? formData.materials : [],
);
// showAllScenarios 默认为 true
const [showAllScenarios, setShowAllScenarios] = useState(true);
@@ -128,7 +128,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
const [customTags, setCustomTags] = useState(formData.customTags || []);
const [tips, setTips] = useState(formData.tips || "");
const [selectedScenarioTags, setSelectedScenarioTags] = useState(
formData.scenarioTags || []
formData.scenarioTags || [],
);
// 电话获客相关状态
@@ -140,10 +140,10 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
// 群设置相关状态
const [weixinqunName, setWeixinqunName] = useState(
formData.weixinqunName || ""
formData.weixinqunName || "",
);
const [weixinqunNotice, setWeixinqunNotice] = useState(
formData.weixinqunNotice || ""
formData.weixinqunNotice || "",
);
// 新增:自定义海报相关状态
@@ -232,7 +232,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
onChange({ ...formData, customTags: updatedCustomTags });
// 同时从选中标签中移除
const updatedSelectedTags = selectedScenarioTags.filter(
(t: string) => t !== tagId
(t: string) => t !== tagId,
);
setSelectedScenarioTags(updatedSelectedTags);
onChange({
@@ -292,12 +292,12 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
// 账号多选切换
const handleAccountToggle = (account: Account) => {
const isSelected = selectedAccounts.some(
(a: Account) => a.id === account.id
(a: Account) => a.id === account.id,
);
let newSelected;
if (isSelected) {
newSelected = selectedAccounts.filter(
(a: Account) => a.id !== account.id
(a: Account) => a.id !== account.id,
);
} else {
newSelected = [...selectedAccounts, account];
@@ -362,7 +362,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
const [orderUploaded, setOrderUploaded] = useState(false);
const handleOrderFileUpload = async (
event: React.ChangeEvent<HTMLInputElement>
event: React.ChangeEvent<HTMLInputElement>,
) => {
const file = event.target.files?.[0];
if (file) {
@@ -518,7 +518,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
<div className={styles["basic-materials-grid"]}>
{[...materials, ...customPosters].map(material => {
const isSelected = selectedMaterials.some(
m => m.id === material.id
m => m.id === material.id,
);
const isCustom = material.id.startsWith("custom-");
return (

View File

@@ -38,7 +38,7 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
const [isTemplateDialogOpen, setIsTemplateDialogOpen] = useState(false);
const [hasWarnings, setHasWarnings] = useState(false);
const [selectedDevices, setSelectedDevices] = useState<string[]>(
formData.device || []
formData.device || [],
);
const [showRemarkTip, setShowRemarkTip] = useState(false);

View File

@@ -125,7 +125,7 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
const handleUpdateMessage = (
dayIndex: number,
messageIndex: number,
updates: Partial<MessageContent>
updates: Partial<MessageContent>,
) => {
const updatedPlans = [...dayPlans];
updatedPlans[dayIndex].messages[messageIndex] = {
@@ -181,7 +181,7 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
setSelectedGroupId(groupId);
setIsGroupSelectOpen(false);
message.success(
`已选择群组:${mockGroups.find(g => g.id === groupId)?.name}`
`已选择群组:${mockGroups.find(g => g.id === groupId)?.name}`,
);
};
@@ -189,7 +189,7 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
const triggerUpload = (
dayIdx: number,
msgIdx: number,
type: "miniprogram" | "link"
type: "miniprogram" | "link",
) => {
setUploadingDay(dayIdx);
setUploadingMsgIdx(msgIdx);
@@ -539,7 +539,7 @@ const MessageSettings: React.FC<MessageSettingsProps> = ({
handleFileUpload(
dayIndex,
messageIndex,
message.type as any
message.type as any,
)
}
>

View File

@@ -33,7 +33,7 @@ export function deleteScenario(id: string) {
export function getPlanList(
scenarioId: string,
page: number = 1,
limit: number = 20
limit: number = 20,
) {
return request(`/api/scenarios/${scenarioId}/plans`, { page, limit }, "GET");
}
@@ -214,7 +214,7 @@ export function deleteAutoLikeTask(taskId: string) {
return request(
`/api/workspace/auto-like/tasks/${taskId}`,
undefined,
"DELETE"
"DELETE",
);
}
@@ -240,7 +240,7 @@ export function deleteGroupPushTask(taskId: string) {
return request(
`/api/workspace/group-push/tasks/${taskId}`,
undefined,
"DELETE"
"DELETE",
);
}
@@ -266,7 +266,7 @@ export function deleteAutoGroupTask(taskId: string) {
return request(
`/api/workspace/auto-group/tasks/${taskId}`,
undefined,
"DELETE"
"DELETE",
);
}
@@ -287,7 +287,7 @@ export function getAIAnalysisReport() {
return request(
"/api/workspace/ai-assistant/analysis-report",
undefined,
"GET"
"GET",
);
}
@@ -379,6 +379,6 @@ export function markNotificationAsRead(notificationId: string) {
return request(
`/api/system/notifications/${notificationId}/read`,
undefined,
"PUT"
"PUT",
);
}

View File

@@ -59,7 +59,7 @@ const mockTaskDetail: GroupTaskDetail = {
nickname: `用户${mIndex + 1}`,
wechatId: `wx_${mIndex}`,
tags: [`标签${(mIndex % 3) + 1}`],
})
}),
),
})),
createTime: "2024-11-20 19:04:14",
@@ -169,10 +169,10 @@ const GroupCreationProgress: React.FC<{
}> = ({ taskDetail, onComplete }) => {
const [groups, setGroups] = useState<Group[]>(taskDetail.groups);
const [currentGroupIndex, setCurrentGroupIndex] = useState(
taskDetail.currentGroupIndex
taskDetail.currentGroupIndex,
);
const [status, setStatus] = useState<GroupTaskDetail["status"]>(
taskDetail.status
taskDetail.status,
);
useEffect(() => {
@@ -207,7 +207,7 @@ const GroupCreationProgress: React.FC<{
};
}
return group;
})
}),
);
};

View File

@@ -149,8 +149,8 @@ const AutoGroupList: React.FC = () => {
...task,
status: task.status === "running" ? "paused" : "running",
}
: task
)
: task,
),
);
Toast.show({ content: "状态已切换" });
};
@@ -160,7 +160,7 @@ const AutoGroupList: React.FC = () => {
};
const filteredTasks = tasks.filter(task =>
task.name.toLowerCase().includes(searchTerm.toLowerCase())
task.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
return (

View File

@@ -9,7 +9,7 @@ import {
// 获取自动点赞任务列表
export function fetchAutoLikeTasks(
params = { type: 1, page: 1, limit: 100 }
params = { type: 1, page: 1, limit: 100 },
): Promise<LikeTask[]> {
return request("/v1/workbench/list", params, "GET");
}
@@ -49,7 +49,7 @@ export function fetchLikeRecords(
workbenchId: string,
page: number = 1,
limit: number = 20,
keyword?: string
keyword?: string,
): Promise<PaginatedResponse<LikeRecord>> {
const params: any = {
workbenchId,

View File

@@ -224,7 +224,7 @@ const AutoLike: React.FC = () => {
// 过滤任务
const filteredTasks = tasks.filter(task =>
task.name.toLowerCase().includes(searchTerm.toLowerCase())
task.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
return (

View File

@@ -82,7 +82,7 @@ const NewAutoLike: React.FC = () => {
});
setAutoEnabled(
(taskDetail as any).status === 1 ||
(taskDetail as any).status === "running"
(taskDetail as any).status === "running",
);
}
} catch (error) {

View File

@@ -9,7 +9,7 @@ import {
// 获取自动点赞任务列表
export function fetchAutoLikeTasks(
params = { type: 1, page: 1, limit: 100 }
params = { type: 1, page: 1, limit: 100 },
): Promise<LikeTask[]> {
return request("/v1/workbench/list", params, "GET");
}
@@ -49,7 +49,7 @@ export function fetchLikeRecords(
workbenchId: string,
page: number = 1,
limit: number = 20,
keyword?: string
keyword?: string,
): Promise<PaginatedResponse<LikeRecord>> {
const params: any = {
workbenchId,

View File

@@ -40,12 +40,12 @@ export async function deleteGroupPushTask(id: string): Promise<ApiResponse> {
export async function toggleGroupPushTask(
id: string,
status: string
status: string,
): Promise<ApiResponse> {
return request(
`/v1/workspace/group-push/tasks/${id}/toggle`,
{ status },
"POST"
"POST",
);
}
@@ -54,20 +54,20 @@ export async function copyGroupPushTask(id: string): Promise<ApiResponse> {
}
export async function createGroupPushTask(
taskData: Partial<GroupPushTask>
taskData: Partial<GroupPushTask>,
): Promise<ApiResponse> {
return request("/v1/workspace/group-push/tasks", taskData, "POST");
}
export async function updateGroupPushTask(
id: string,
taskData: Partial<GroupPushTask>
taskData: Partial<GroupPushTask>,
): Promise<ApiResponse> {
return request(`/v1/workspace/group-push/tasks/${id}`, taskData, "PUT");
}
export async function getGroupPushTaskDetail(
id: string
id: string,
): Promise<GroupPushTask> {
return request(`/v1/workspace/group-push/tasks/${id}`);
}

View File

@@ -226,7 +226,7 @@ const Detail: React.FC = () => {
</div>
<Progress
percent={Math.round(
(task.pushCount / task.maxPushPerDay) * 100
(task.pushCount / task.maxPushPerDay) * 100,
)}
size="small"
/>

View File

@@ -105,7 +105,7 @@ const BasicSettings: React.FC<BasicSettingsProps> = ({
onChange={e =>
handleChange(
"dailyPushCount",
Number.parseInt(e.target.value) || 1
Number.parseInt(e.target.value) || 1,
)
}
style={{ width: 80, textAlign: "center" }}

View File

@@ -81,7 +81,7 @@ const ContentSelector: React.FC<ContentSelectorProps> = ({
const [libraries] = useState<ContentLibrary[]>(mockLibraries);
const filteredLibraries = libraries.filter(library =>
library.name.toLowerCase().includes(searchTerm.toLowerCase())
library.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
const handleLibraryToggle = (library: ContentLibrary, checked: boolean) => {

View File

@@ -101,7 +101,9 @@ const GroupSelector: React.FC<GroupSelectorProps> = ({
const filteredGroups = groups.filter(
group =>
group.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
group.serviceAccount.name.toLowerCase().includes(searchTerm.toLowerCase())
group.serviceAccount.name
.toLowerCase()
.includes(searchTerm.toLowerCase()),
);
const handleGroupToggle = (group: WechatGroup, checked: boolean) => {

View File

@@ -1,6 +1,6 @@
import request from "@/api/request";
export async function createGroupPushTask(
taskData: Partial<GroupPushTask>
taskData: Partial<GroupPushTask>,
): Promise<ApiResponse> {
return request("/v1/workspace/group-push/tasks", taskData, "POST");
}

View File

@@ -40,12 +40,12 @@ export async function deleteGroupPushTask(id: string): Promise<ApiResponse> {
export async function toggleGroupPushTask(
id: string,
status: string
status: string,
): Promise<ApiResponse> {
return request(
`/v1/workspace/group-push/tasks/${id}/toggle`,
{ status },
"POST"
"POST",
);
}
@@ -54,20 +54,20 @@ export async function copyGroupPushTask(id: string): Promise<ApiResponse> {
}
export async function createGroupPushTask(
taskData: Partial<GroupPushTask>
taskData: Partial<GroupPushTask>,
): Promise<ApiResponse> {
return request("/v1/workspace/group-push/tasks", taskData, "POST");
}
export async function updateGroupPushTask(
id: string,
taskData: Partial<GroupPushTask>
taskData: Partial<GroupPushTask>,
): Promise<ApiResponse> {
return request(`/v1/workspace/group-push/tasks/${id}`, taskData, "PUT");
}
export async function getGroupPushTaskDetail(
id: string
id: string,
): Promise<GroupPushTask> {
return request(`/v1/workspace/group-push/tasks/${id}`);
}

View File

@@ -97,7 +97,7 @@ const GroupPush: React.FC = () => {
};
const filteredTasks = tasks.filter(task =>
task.name.toLowerCase().includes(searchTerm.toLowerCase())
task.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
const getStatusColor = (status: number) => {
@@ -361,7 +361,7 @@ const GroupPush: React.FC = () => {
</div>
<Progress
percent={Math.round(
(task.pushCount / task.maxPushPerDay) * 100
(task.pushCount / task.maxPushPerDay) * 100,
)}
size="small"
/>

View File

@@ -73,7 +73,7 @@ const MomentsSyncDetail: React.FC = () => {
await request(
"/v1/workbench/update-status",
{ id, status: newStatus },
"POST"
"POST",
);
setTask({ ...task, status: newStatus });
message.success(newStatus === 1 ? "任务已开启" : "任务已暂停");

View File

@@ -55,7 +55,7 @@ const MomentsSync: React.FC = () => {
const res = await request(
"/v1/workbench/list",
{ type: 2, page: 1, limit: 100 },
"GET"
"GET",
);
setTasks(res.list || []);
} catch (e) {
@@ -96,10 +96,10 @@ const MomentsSync: React.FC = () => {
await request(
"/v1/workbench/update-status",
{ id, status: newStatus },
"POST"
"POST",
);
setTasks(prev =>
prev.map(t => (t.id === id ? { ...t, status: newStatus } : t))
prev.map(t => (t.id === id ? { ...t, status: newStatus } : t)),
);
message.success("操作成功");
} catch {
@@ -108,7 +108,7 @@ const MomentsSync: React.FC = () => {
};
const filteredTasks = tasks.filter(task =>
task.name.toLowerCase().includes(searchTerm.toLowerCase())
task.name.toLowerCase().includes(searchTerm.toLowerCase()),
);
// 菜单

View File

@@ -8,14 +8,14 @@ export const getTrafficDistributionDetail = (id: string) => {
// 更新流量分发
export const updateTrafficDistribution = (
data: TrafficDistributionFormData
data: TrafficDistributionFormData,
) => {
return request("/v1/workbench/update", data, "POST");
};
// 创建流量分发
export const createTrafficDistribution = (
data: TrafficDistributionFormData
data: TrafficDistributionFormData,
) => {
return request("/v1/workbench/create", data, "POST");
};

View File

@@ -393,7 +393,7 @@ const TrafficDistributionForm: React.FC = () => {
setSelectedPools(val =>
e.target.checked
? [...val, pool.id]
: val.filter(v => v !== pool.id)
: val.filter(v => v !== pool.id),
);
}}
/>

View File

@@ -17,7 +17,7 @@ export function updateDistributionRule(data: any): Promise<any> {
// 暂停/启用计划
export function toggleDistributionRuleStatus(
id: number,
status: 0 | 1
status: 0 | 1,
): Promise<any> {
return request("/v1/workbench/update-status", { id, status }, "POST");
}

View File

@@ -115,7 +115,7 @@ const TrafficDistributionList: React.FC = () => {
// 新增Switch点击切换计划状态
const handleSwitchChange = async (
checked: boolean,
item: DistributionRule
item: DistributionRule,
) => {
setMenuLoadingId(item.id);
try {
@@ -124,8 +124,8 @@ const TrafficDistributionList: React.FC = () => {
// 本地只更新当前item的status不刷新全列表
setList(prevList =>
prevList.map(rule =>
rule.id === item.id ? { ...rule, status: checked ? 1 : 0 } : rule
)
rule.id === item.id ? { ...rule, status: checked ? 1 : 0 } : rule,
),
);
} catch (e) {
message.error("操作失败");

View File

@@ -159,7 +159,7 @@ export const getRouteTitle = (path: string): string => {
// 检查路由权限
export const checkRoutePermission = (
path: string,
userRole: string = "user"
userRole: string = "user",
): boolean => {
const allowedRoutes =
routePermissions[userRole as keyof typeof routePermissions] || [];

View File

@@ -16,7 +16,7 @@ Object.values(modules).forEach((mod: any) => {
// 权限包装
function wrapWithPermission(
route: RouteObject & { auth?: boolean; requiredRole?: string }
route: RouteObject & { auth?: boolean; requiredRole?: string },
) {
if (route.auth) {
return {

View File

@@ -5,12 +5,12 @@ import { persist, PersistOptions } from "zustand/middleware";
export function createPersistStore<T>(
createState: (set: any, get: any) => T,
name: string,
partialize?: (state: T) => Partial<T>
partialize?: (state: T) => Partial<T>,
) {
return create<T>()(
persist(createState, {
name,
partialize,
} as PersistOptions<T>)
} as PersistOptions<T>),
);
}

View File

@@ -70,5 +70,5 @@ export const useUserStore = createPersistStore<UserState>(
user: state.user,
token: state.token,
isLoggedIn: state.isLoggedIn,
})
}),
);

View File

@@ -12,7 +12,7 @@ export const comfirm = (
title?: string;
cancelText?: string;
confirmText?: string;
}
},
): Promise<void> => {
return new Promise((resolve, reject) => {
Modal.show({