diff --git a/nkebao/src/api/common.ts b/nkebao/src/api/common.ts index ebe966eb5..77a0e7dea 100644 --- a/nkebao/src/api/common.ts +++ b/nkebao/src/api/common.ts @@ -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 { try { // 创建 FormData 对象用于文件上传 diff --git a/nkebao/src/api/devices.ts b/nkebao/src/api/devices.ts index efadbc918..1a4534ab4 100644 --- a/nkebao/src/api/devices.ts +++ b/nkebao/src/api/devices.ts @@ -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"); // 更新设备任务配置 diff --git a/nkebao/src/api/request.ts b/nkebao/src/api/request.ts index 18173f8da..2235a5529 100644 --- a/nkebao/src/api/request.ts +++ b/nkebao/src/api/request.ts @@ -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 { const gap = typeof debounceGap === "number" ? debounceGap : DEFAULT_DEBOUNCE_GAP; diff --git a/nkebao/src/components/AccountSelection/index.tsx b/nkebao/src/components/AccountSelection/index.tsx index be8023b89..3f8aace6c 100644 --- a/nkebao/src/components/AccountSelection/index.tsx +++ b/nkebao/src/components/AccountSelection/index.tsx @@ -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), ); // 处理账号选择 diff --git a/nkebao/src/components/ContentLibrarySelection/index.tsx b/nkebao/src/components/ContentLibrarySelection/index.tsx index a7e8507c7..b053f1d98 100644 --- a/nkebao/src/components/ContentLibrarySelection/index.tsx +++ b/nkebao/src/components/ContentLibrarySelection/index.tsx @@ -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); } diff --git a/nkebao/src/components/DeviceSelection/selectionPopup.tsx b/nkebao/src/components/DeviceSelection/selectionPopup.tsx index d1e002f05..fc3ea3c21 100644 --- a/nkebao/src/components/DeviceSelection/selectionPopup.tsx +++ b/nkebao/src/components/DeviceSelection/selectionPopup.tsx @@ -61,7 +61,7 @@ const SelectionPopup: React.FC = ({ wxid: d.wechatId || "", nickname: d.nickname || "", usedInPlans: d.usedInPlans || 0, - })) + })), ); setTotal(res.total || 0); } @@ -71,7 +71,7 @@ const SelectionPopup: React.FC = ({ setLoading(false); } }, - [] + [], ); // 打开弹窗时获取第一页 diff --git a/nkebao/src/components/FriendSelection/index.tsx b/nkebao/src/components/FriendSelection/index.tsx index e2f37c363..c416d0114 100644 --- a/nkebao/src/components/FriendSelection/index.tsx +++ b/nkebao/src/components/FriendSelection/index.tsx @@ -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); } diff --git a/nkebao/src/components/GroupSelection/index.tsx b/nkebao/src/components/GroupSelection/index.tsx index fe027edfa..423cf142b 100644 --- a/nkebao/src/components/GroupSelection/index.tsx +++ b/nkebao/src/components/GroupSelection/index.tsx @@ -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); } diff --git a/nkebao/src/components/Layout/Layout.tsx b/nkebao/src/components/Layout/Layout.tsx index 43c51f1fc..160d993e4 100644 --- a/nkebao/src/components/Layout/Layout.tsx +++ b/nkebao/src/components/Layout/Layout.tsx @@ -20,7 +20,7 @@ const Layout: React.FC = ({ const setRealHeight = () => { document.documentElement.style.setProperty( "--real-vh", - `${window.innerHeight * 0.01}px` + `${window.innerHeight * 0.01}px`, ); }; setRealHeight(); diff --git a/nkebao/src/components/Upload/index.tsx b/nkebao/src/components/Upload/index.tsx index 73ec84a92..da1a2a211 100644 --- a/nkebao/src/components/Upload/index.tsx +++ b/nkebao/src/components/Upload/index.tsx @@ -68,7 +68,7 @@ const UploadComponent: React.FC = ({ Authorization: `Bearer ${localStorage.getItem("token")}`, }, body: formData, - } + }, ); if (!response.ok) { diff --git a/nkebao/src/pages/mobile/content/form/api.ts b/nkebao/src/pages/mobile/content/form/api.ts index 4cce9f260..bc136d885 100644 --- a/nkebao/src/pages/mobile/content/form/api.ts +++ b/nkebao/src/pages/mobile/content/form/api.ts @@ -12,14 +12,14 @@ export function getContentLibraryDetail(id: string): Promise { // 创建内容库 export function createContentLibrary( - params: CreateContentLibraryParams + params: CreateContentLibraryParams, ): Promise { return request("/v1/content/library/create", params, "POST"); } // 更新内容库 export function updateContentLibrary( - params: UpdateContentLibraryParams + params: UpdateContentLibraryParams, ): Promise { const { id, ...data } = params; return request(`/v1/content/library/update`, { id, ...data }, "POST"); diff --git a/nkebao/src/pages/mobile/content/list/api.ts b/nkebao/src/pages/mobile/content/list/api.ts index 7bb985ee2..51821b6f7 100644 --- a/nkebao/src/pages/mobile/content/list/api.ts +++ b/nkebao/src/pages/mobile/content/list/api.ts @@ -22,14 +22,14 @@ export function getContentLibraryDetail(id: string): Promise { // 创建内容库 export function createContentLibrary( - params: CreateContentLibraryParams + params: CreateContentLibraryParams, ): Promise { return request("/v1/content/library/create", params, "POST"); } // 更新内容库 export function updateContentLibrary( - params: UpdateContentLibraryParams + params: UpdateContentLibraryParams, ): Promise { const { id, ...data } = params; return request(`/v1/content/library/update`, { id, ...data }, "POST"); @@ -43,7 +43,7 @@ export function deleteContentLibrary(id: string): Promise { // 切换内容库状态 export function toggleContentLibraryStatus( id: string, - status: number + status: number, ): Promise { return request("/v1/content/library/update-status", { id, status }, "POST"); } diff --git a/nkebao/src/pages/mobile/content/list/index.tsx b/nkebao/src/pages/mobile/content/list/index.tsx index f3b0eb134..a601710cf 100644 --- a/nkebao/src/pages/mobile/content/list/index.tsx +++ b/nkebao/src/pages/mobile/content/list/index.tsx @@ -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 ( diff --git a/nkebao/src/pages/mobile/home/index.tsx b/nkebao/src/pages/mobile/home/index.tsx index f2029cdd4..25fadb073 100644 --- a/nkebao/src/pages/mobile/home/index.tsx +++ b/nkebao/src/pages/mobile/home/index.tsx @@ -213,8 +213,8 @@ const Home: React.FC = () => { onClick={() => navigate( `/scenarios/list/${scenario.id}/${encodeURIComponent( - scenario.name - )}` + scenario.name, + )}`, ) } > diff --git a/nkebao/src/pages/mobile/mine/consumption-records/api.ts b/nkebao/src/pages/mobile/mine/consumption-records/api.ts new file mode 100644 index 000000000..52f953377 --- /dev/null +++ b/nkebao/src/pages/mobile/mine/consumption-records/api.ts @@ -0,0 +1,17 @@ +import request from "@/api/request"; +import { ConsumptionRecordsResponse, ConsumptionRecordDetail } from "./data"; + +// 获取消费记录列表 +export function getConsumptionRecords(params: { + page: number; + limit: number; +}): Promise { + return request("/v1/consumption-records", params, "GET"); +} + +// 获取消费记录详情 +export function getConsumptionRecordDetail( + id: string, +): Promise { + return request(`/v1/consumption-records/${id}`, {}, "GET"); +} diff --git a/nkebao/src/pages/mobile/mine/consumption-records/data.ts b/nkebao/src/pages/mobile/mine/consumption-records/data.ts new file mode 100644 index 000000000..391b40dda --- /dev/null +++ b/nkebao/src/pages/mobile/mine/consumption-records/data.ts @@ -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; +} diff --git a/nkebao/src/pages/mobile/mine/consumption-records/index.module.scss b/nkebao/src/pages/mobile/mine/consumption-records/index.module.scss new file mode 100644 index 000000000..f244cccce --- /dev/null +++ b/nkebao/src/pages/mobile/mine/consumption-records/index.module.scss @@ -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; +} diff --git a/nkebao/src/pages/mobile/mine/consumption-records/index.tsx b/nkebao/src/pages/mobile/mine/consumption-records/index.tsx new file mode 100644 index 000000000..64e20ac58 --- /dev/null +++ b/nkebao/src/pages/mobile/mine/consumption-records/index.tsx @@ -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([]); + 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 ; + case "ai_service": + return ; + case "version_upgrade": + return ; + default: + return ; + } + }; + + 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) => ( + +
+
+
+ {getTypeIcon(record.type)} +
+
+
+ {record.description} +
+
+ + {formatTime(record.createTime)} +
+
+
+
+
+ {formatAmount(record.amount, record.type)} +
+ + {getStatusText(record.status)} + +
+
+ {record.balance !== undefined && ( +
+ 余额: ¥{record.balance.toFixed(2)} +
+ )} +
+ ); + + return ( + }> +
+ {records.length === 0 && !loading ? ( + } + /> + ) : ( +
+ {records.map(renderRecordItem)} + {loading && ( +
+ +
加载中...
+
+ )} + {!loading && hasMore && ( +
loadRecords()}> + 加载更多 +
+ )} +
+ )} +
+
+ ); +}; + +export default ConsumptionRecords; diff --git a/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx b/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx index 2f70309a1..0b9fadc39 100644 --- a/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx +++ b/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx @@ -23,7 +23,7 @@ const DeviceDetail: React.FC = () => { const [logs, setLogs] = useState([]); 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, ) } /> - ) + ), )} )} diff --git a/nkebao/src/pages/mobile/mine/devices/index.tsx b/nkebao/src/pages/mobile/mine/devices/index.tsx index 0fe789b9d..8fe74b537 100644 --- a/nkebao/src/pages/mobile/mine/devices/index.tsx +++ b/nkebao/src/pages/mobile/mine/devices/index.tsx @@ -10,7 +10,6 @@ import { ArrowLeftOutlined, } from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; -import MeauMobile from "@/components/MeauMobile/MeauMoible"; import { fetchDeviceList, fetchDeviceQRCode, @@ -20,9 +19,9 @@ import { import type { Device } from "@/types/device"; import { comfirm } from "@/utils/common"; import { useUserStore } from "@/store/module/user"; +import NavCommon from "@/components/NavCommon"; const Devices: React.FC = () => { - const { user } = useUserStore(); // 设备列表相关 const [devices, setDevices] = useState([]); const [loading, setLoading] = useState(false); @@ -49,6 +48,7 @@ const Devices: React.FC = () => { const [delLoading, setDelLoading] = useState(false); const navigate = useNavigate(); + const { user } = useUserStore(); // 加载设备列表 const loadDevices = useCallback( async (reset = false) => { @@ -70,7 +70,7 @@ const Devices: React.FC = () => { setLoading(false); } }, - [loading, search, page] + [loading, search, page], ); // 首次加载和搜索 @@ -88,7 +88,7 @@ const Devices: React.FC = () => { setPage(p => p + 1); } }, - { threshold: 0.5 } + { threshold: 0.5 }, ); if (observerRef.current) observer.observe(observerRef.current); return () => observer.disconnect(); @@ -114,10 +114,9 @@ const Devices: React.FC = () => { setQrLoading(true); setQrCode(null); try { - // 获取s2_accountId - const s2AccountId = user?.s2_accountId; - if (!s2AccountId) throw new Error("未获取到用户信息"); - const res = await fetchDeviceQRCode(s2AccountId); + const accountId = user.s2_accountId; + if (!accountId) throw new Error("未获取到用户信息"); + const res = await fetchDeviceQRCode(accountId); setQrCode(res.qrCode); } catch (e: any) { Toast.show({ content: e.message || "获取二维码失败", position: "top" }); @@ -125,10 +124,12 @@ const Devices: React.FC = () => { setQrLoading(false); } }; - const openAddDevice = async () => { + + const addDevice = async () => { await handleGetQr(); setAddVisible(true); }; + // 手动添加设备 const handleAddDevice = async () => { if (!imei.trim() || !name.trim()) { @@ -172,7 +173,7 @@ const Devices: React.FC = () => { try { await comfirm( `将删除${selected.length}个设备,删除后本设备配置的计划任务操作也将失效。确认删除?`, - { title: "确认删除", confirmText: "确认删除", cancelText: "取消" } + { title: "确认删除", confirmText: "确认删除", cancelText: "取消" }, ); handleDelete(); } catch { @@ -195,29 +196,15 @@ const Devices: React.FC = () => { - - navigate(-1)} - /> - - } - style={{ background: "#fff" }} + + } - > - - 设备管理 - - - + />
{/* 搜索栏 */}
@@ -303,7 +290,7 @@ const Devices: React.FC = () => { setSelected(prev => e.target.checked ? [...prev, device.id!] - : prev.filter(id => id !== device.id) + : prev.filter(id => id !== device.id), ); }} onClick={e => e.stopPropagation()} diff --git a/nkebao/src/pages/mobile/mine/main/index.tsx b/nkebao/src/pages/mobile/mine/main/index.tsx index 1e2f80609..605dc1ec5 100644 --- a/nkebao/src/pages/mobile/mine/main/index.tsx +++ b/nkebao/src/pages/mobile/mine/main/index.tsx @@ -106,7 +106,6 @@ const Mine: React.FC = () => { // 清除本地存储的用户信息 localStorage.removeItem("token"); localStorage.removeItem("token_expired"); - localStorage.removeItem("s2_accountId"); localStorage.removeItem("userInfo"); setShowLogoutDialog(false); navigate("/login"); @@ -120,30 +119,6 @@ const Mine: React.FC = () => { navigate(path); }; - // 渲染用户头像 - const renderUserAvatar = () => { - if (currentUserInfo.avatar) { - return 头像; - } - return ( -
- 售 -
- ); - }; - // 渲染功能模块图标 const renderModuleIcon = (module: any) => (
{ const navigate = useNavigate(); const { user } = useUserStore(); @@ -16,6 +125,7 @@ const Recharge: React.FC = () => { const [balance, setBalance] = useState(0); const [selected, setSelected] = useState(null); const [loading, setLoading] = useState(false); + const [activeTab, setActiveTab] = useState("account"); // 充值操作 const handleRecharge = async () => { @@ -31,68 +141,228 @@ const Recharge: React.FC = () => { }, 1200); }; - return ( - }> -
- -
- -
-
当前余额
-
- ¥{balance.toFixed(2)} + // 渲染账户充值tab内容 + const renderAccountRecharge = () => ( +
+ +
+ +
+
当前余额
+
+ ¥{balance.toFixed(2)} +
+
+
+
+ +
快捷充值
+
+ {quickAmounts.map(amt => ( + + ))} +
+ +
+ +
服务消耗
+
+ 使用以下服务将从余额中扣除相应费用。 +
+
+ {balance < 10 && ( + +
+ +
+
余额不足提醒
+
+ 当前余额较低,建议及时充值以免影响服务使用
- -
快捷充值
-
- {quickAmounts.map(amt => ( - - ))} -
- -
- -
服务消耗
-
- 使用以下服务将从余额中扣除相应费用。 -
-
- {balance < 10 && ( - -
- -
-
余额不足提醒
-
- 当前余额较低,建议及时充值以免影响服务使用 + )} +
+ ); + + // 渲染AI服务tab内容 + const renderAiServices = () => ( +
+
+
+ + AI智能服务收费 +
+
统一按次收费
+
+
+ 三项核心AI服务,按使用次数收费,每次1元 +
+ +
+ {aiServices.map(service => ( + +
+
+
{service.icon}
+
+
{service.name}
+
+ ¥{service.price}/次 +
+
+ {service.description} +
+
+ {service.features.map((feature, index) => ( +
+ + {feature} +
+ ))} +
+
+
今日使用进度
+
+
+
+
+ {service.usage.current} / {service.usage.total} +
+
- )} + ))} +
+
+ ); + + // 渲染版本套餐tab内容 + const renderVersionPackages = () => ( +
+
+ + 存客宝版本套餐 +
+
+ 选择适合的版本,享受不同级别的AI服务 +
+ +
+ {versionPackages.map(pkg => ( + +
+
+
{pkg.icon}
+
+
+ {pkg.name} + {pkg.tag && ( + + {pkg.tag} + + )} +
+
{pkg.price}
+
+
+
+
+ {pkg.description} +
+
+
包含功能:
+ {pkg.features.map((feature, index) => ( +
+ + {feature} +
+ ))} +
+ {pkg.status && ( +
{pkg.status}
+ )} + {pkg.buttonText && ( + + )} +
+ ))} +
+
+ ); + + return ( + navigate("/mine/consumption-records")} + > + +  记录 +
+ } + /> + } + > +
+ + + {renderAccountRecharge()} + + + {renderAiServices()} + + + {renderVersionPackages()} + +
); diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts b/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts index a31a1c345..0a0a1e92c 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts @@ -1,5 +1,31 @@ import request from "@/api/request"; +import type { + TrafficPoolUserDetail, + UserJourneyResponse, + UserTagsResponse, +} from "./data"; -export function getTrafficPoolDetail(id: string): Promise { - return request("/v1/workbench/detail", { id }, "GET"); +export function getTrafficPoolDetail( + wechatId: string, +): Promise { + return request("/v1/wechats/getWechatInfo", { wechatId }, "GET"); +} + +// 获取用户旅程记录 +export function getUserJourney(params: { + page: number; + pageSize: number; + userId: string; +}): Promise { + return request("/v1/traffic/pool/getUserJourney", params, "GET"); +} + +// 获取用户标签 +export function getUserTags(userId: string): Promise { + return request("/v1/traffic/pool/getUserTags", { userId }, "GET"); +} + +// 添加用户标签 +export function addUserTag(userId: string, tagData: any): Promise { + return request("/v1/user/tags", { userId, ...tagData }, "POST"); } diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss index e69de29bb..60165acbb 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.module.scss @@ -0,0 +1,420 @@ +.container { + padding: 0; + background: #f5f5f5; + min-height: 100vh; +} + +// 头部样式 +.header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px; + background: #fff; + border-bottom: 1px solid #f0f0f0; + + .title { + font-size: 18px; + font-weight: 600; + color: #333; + } + + .closeBtn { + padding: 8px; + border: none; + background: transparent; + color: #999; + font-size: 16px; + } +} + +// 用户卡片 +.userCard { + margin: 16px; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + .userInfo { + display: flex; + align-items: flex-start; + gap: 16px; + } + + .avatar { + width: 60px; + height: 60px; + border-radius: 50%; + flex-shrink: 0; + } + + .userDetails { + flex: 1; + min-width: 0; + } + + .nickname { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 4px; + } + + .wechatId { + font-size: 14px; + color: #666; + margin-bottom: 8px; + } + + .tags { + display: flex; + flex-wrap: wrap; + gap: 8px; + } + + .userTag { + font-size: 12px; + padding: 4px 8px; + border-radius: 12px; + } +} + +// 标签导航 +.tabNav { + display: flex; + background: #fff; + margin: 0 16px; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + + .tabItem { + flex: 1; + padding: 12px 16px; + text-align: center; + font-size: 14px; + color: #666; + cursor: pointer; + transition: all 0.3s ease; + border-bottom: 2px solid transparent; + + &.active { + color: var(--primary-color); + border-bottom-color: var(--primary-color); + background: rgba(24, 142, 238, 0.05); + } + + &:hover { + background: rgba(24, 142, 238, 0.05); + } + } +} + +// 内容区域 +.content { + padding: 16px; +} + +.tabContent { + display: flex; + flex-direction: column; + gap: 16px; +} + +// 信息卡片 +.infoCard { + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; + + :global(.adm-card-header) { + padding: 16px; + border-bottom: 1px solid #f0f0f0; + font-weight: 600; + color: #333; + } + + :global(.adm-card-body) { + padding: 0; + } +} + +// RFM评分网格 +.rfmGrid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; + padding: 16px; +} + +.rfmItem { + text-align: center; + padding: 12px; + background: #f8f9fa; + border-radius: 8px; +} + +.rfmLabel { + font-size: 12px; + color: #666; + margin-bottom: 4px; +} + +.rfmValue { + font-size: 18px; + font-weight: 600; +} + +// 流量池区域 +.poolSection { + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.currentPool, +.availablePools { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: wrap; +} + +.poolLabel { + font-size: 14px; + color: #666; + white-space: nowrap; +} + +// 统计数据网格 +.statsGrid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 16px; + padding: 16px; +} + +.statItem { + text-align: center; + padding: 12px; + background: #f8f9fa; + border-radius: 8px; +} + +.statValue { + font-size: 18px; + font-weight: 600; + margin-bottom: 4px; +} + +.statLabel { + font-size: 12px; + color: #666; +} + +// 用户旅程 +.journeyItem { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 12px; + color: #666; + margin-top: 4px; +} + +.timestamp { + color: #999; +} + +// 加载状态 +.loadingContainer { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 40px 16px; + text-align: center; +} + +.loadingText { + font-size: 14px; + color: #999; + margin-top: 8px; +} + +.loadingMore { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 16px; + color: #666; + font-size: 14px; +} + +.loadMoreBtn { + display: flex; + justify-content: center; + padding: 16px; +} + +// 标签区域 +.tagsSection { + padding: 16px; + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.valueTagsSection { + padding: 16px; + display: flex; + flex-direction: column; + gap: 12px; +} + +.tagItem { + font-size: 12px; + padding: 6px 12px; + border-radius: 16px; +} + +.valueTagContainer { + display: flex; + flex-direction: column; + gap: 8px; +} + +.valueTagRow { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; +} + +.rfmScoreText { + font-size: 12px; + color: #666; + white-space: nowrap; +} + +.valueLevelLabel { + font-size: 12px; + color: #666; + white-space: nowrap; +} + +.valueTagItem { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + border-bottom: 1px solid #f0f0f0; + + &:last-child { + border-bottom: none; + } +} + +.valueInfo { + display: flex; + align-items: center; + gap: 8px; + font-size: 12px; + color: #666; +} + +// 添加标签按钮 +.addTagBtn { + margin-top: 16px; + border-radius: 8px; + height: 48px; + font-size: 16px; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; +} + +// 空状态 +.emptyState { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60px 16px; + text-align: center; +} + +.emptyIcon { + margin-bottom: 16px; + opacity: 0.6; +} + +.emptyText { + font-size: 16px; + color: #666; + margin-bottom: 8px; + font-weight: 500; +} + +.emptyDesc { + font-size: 14px; + color: #999; + line-height: 1.4; +} + +// 限制记录样式 +.restrictionTitle { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + font-size: 14px; + font-weight: 500; + color: #333; + line-height: 1.4; +} + +.restrictionLevel { + font-size: 10px; + padding: 2px 6px; + border-radius: 8px; + flex-shrink: 0; +} + +.restrictionContent { + display: flex; + flex-direction: column; + gap: 4px; + font-size: 12px; + color: #666; + line-height: 1.4; + margin-top: 4px; +} + +// 响应式设计 +@media (max-width: 375px) { + .rfmGrid, + .statsGrid { + grid-template-columns: 1fr; + } + + .userInfo { + flex-direction: column; + text-align: center; + } + + .avatar { + align-self: center; + } + + .restrictionTitle { + font-size: 13px; + } + + .restrictionContent { + font-size: 11px; + } +} diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx index 1b89ca17c..88fd1c415 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx @@ -1,47 +1,285 @@ import React, { useEffect, useState } from "react"; import { useParams, useNavigate } from "react-router-dom"; +import { + Card, + Button, + Avatar, + Tag, + Tabs, + List, + Badge, + SpinLoading, +} from "antd-mobile"; +import { + UserOutlined, + CrownOutlined, + PlusOutlined, + CloseOutlined, + EyeOutlined, + DollarOutlined, + MobileOutlined, + TagOutlined, + FileTextOutlined, + UserAddOutlined, +} from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; -import { getTrafficPoolDetail } from "./api"; -import type { TrafficPoolUserDetail } from "./data"; -import { Card, Button, Avatar, Tag, Spin } from "antd"; - -const tabList = [ - { key: "base", label: "基本信息" }, - { key: "journey", label: "用户旅程" }, - { key: "tags", label: "用户标签" }, -]; +import NavCommon from "@/components/NavCommon"; +import { getTrafficPoolDetail, getUserJourney, getUserTags } from "./api"; +import type { + TrafficPoolUserDetail, + ExtendedUserDetail, + InteractionRecord, + UserJourneyRecord, + UserTagsResponse, + UserTagItem, +} from "./data"; +import styles from "./index.module.scss"; const TrafficPoolDetail: React.FC = () => { - const { id } = useParams(); + const { wxid, userId } = useParams(); const navigate = useNavigate(); const [loading, setLoading] = useState(true); - const [user, setUser] = useState(null); - const [activeTab, setActiveTab] = useState<"base" | "journey" | "tags">( - "base" - ); + const [user, setUser] = useState(null); + const [activeTab, setActiveTab] = useState("basic"); + + // 用户旅程相关状态 + const [journeyLoading, setJourneyLoading] = useState(false); + const [journeyList, setJourneyList] = useState([]); + const [journeyPage, setJourneyPage] = useState(1); + const [journeyTotal, setJourneyTotal] = useState(0); + const pageSize = 10; + + // 用户标签相关状态 + const [tagsLoading, setTagsLoading] = useState(false); + const [userTagsList, setUserTagsList] = useState([]); useEffect(() => { - if (!id) return; + if (!wxid) return; setLoading(true); - getTrafficPoolDetail(id as string) - .then(res => setUser(res)) + getTrafficPoolDetail(wxid as string) + .then(res => { + // 将API数据转换为扩展的用户详情数据 + const extendedUser: ExtendedUserDetail = { + ...res, + // 模拟RFM评分数据 + rfmScore: { + recency: 5, + frequency: 5, + monetary: 5, + totalScore: 15, + }, + // 模拟流量池数据 + trafficPools: { + currentPool: "新用户池", + availablePools: ["高价值客户池", "活跃用户池"], + }, + // 模拟用户标签数据 + userTags: [ + { id: "1", name: "近期活跃", color: "success", type: "user" }, + { id: "2", name: "高频互动", color: "primary", type: "user" }, + { id: "3", name: "高消费", color: "warning", type: "user" }, + { id: "4", name: "老客户", color: "danger", type: "user" }, + ], + // 模拟价值标签数据 + valueTags: [ + { + id: "1", + name: "重要保持客户", + color: "primary", + icon: "crown", + rfmScore: 14, + valueLevel: "高价值", + }, + ], + }; + setUser(extendedUser); + }) .finally(() => setLoading(false)); - }, [id]); + }, [wxid]); + + // 获取用户旅程数据 + const fetchUserJourney = async (page: number = 1) => { + if (!userId) return; + + setJourneyLoading(true); + try { + const response = await getUserJourney({ + page, + pageSize, + userId: userId, + }); + + if (page === 1) { + setJourneyList(response.list); + } else { + setJourneyList(prev => [...prev, ...response.list]); + } + setJourneyTotal(response.total); + setJourneyPage(page); + } catch (error) { + console.error("获取用户旅程失败:", error); + } finally { + setJourneyLoading(false); + } + }; + + // 获取用户标签数据 + const fetchUserTags = async () => { + if (!userId) return; + + setTagsLoading(true); + try { + const response: UserTagsResponse = await getUserTags(userId); + setUserTagsList(response.siteLabels || []); + } catch (error) { + console.error("获取用户标签失败:", error); + } finally { + setTagsLoading(false); + } + }; + + // 标签切换处理 + const handleTabChange = (tab: string) => { + setActiveTab(tab); + if (tab === "journey" && journeyList.length === 0) { + fetchUserJourney(1); + } + if (tab === "tags" && userTagsList.length === 0) { + fetchUserTags(); + } + }; + + const handleClose = () => { + navigate(-1); + }; + + const getJourneyTypeIcon = (type: number) => { + switch (type) { + case 0: // 浏览 + return ; + case 2: // 提交订单 + return ; + case 3: // 注册 + return ; + default: + return ; + } + }; + + const getJourneyTypeText = (type: number) => { + switch (type) { + case 0: + return "浏览行为"; + case 2: + return "提交订单"; + case 3: + return "注册行为"; + default: + return "其他行为"; + } + }; + + const formatDateTime = (dateTime: string) => { + try { + const date = new Date(dateTime); + return date.toLocaleString("zh-CN", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }); + } catch (error) { + return dateTime; + } + }; + + const getActionIcon = (type: string) => { + switch (type) { + case "click": + return ; + case "view": + return ; + case "purchase": + return ; + default: + return ; + } + }; + + const formatCurrency = (amount: number) => { + return `¥${amount.toLocaleString()}`; + }; + + const getGenderText = (gender: number) => { + switch (gender) { + case 1: + return "男"; + case 2: + return "女"; + default: + return "未知"; + } + }; + + const getGenderColor = (gender: number) => { + switch (gender) { + case 1: + return "#1677ff"; + case 2: + return "#eb2f96"; + default: + return "#999"; + } + }; + + const getRestrictionLevelText = (level: number) => { + switch (level) { + case 1: + return "轻微"; + case 2: + return "中等"; + case 3: + return "严重"; + default: + return "未知"; + } + }; + + const getRestrictionLevelColor = (level: number) => { + switch (level) { + case 1: + return "warning"; + case 2: + return "danger"; + case 3: + return "danger"; + default: + return "default"; + } + }; + + const formatDate = (timestamp: number | null) => { + if (!timestamp) return "--"; + try { + const date = new Date(timestamp * 1000); + return date.toLocaleDateString("zh-CN"); + } catch (error) { + return "--"; + } + }; + + // 获取标签颜色 + const getTagColor = (index: number): string => { + const colors = ["primary", "success", "warning", "danger", "default"]; + return colors[index % colors.length]; + }; - if (loading) { - return ( - -
- -
-
- ); - } if (!user) { return ( - -
- 未找到该用户 + } loading={loading}> +
+
未找到该用户
); @@ -49,249 +287,418 @@ const TrafficPoolDetail: React.FC = () => { return ( - -
用户详情
-
+ <> + + {/* 用户基本信息 */} + +
+ } + /> +
+
{user.userInfo.nickname}
+
{user.userInfo.wechatId}
+
+ + + 重要价值客户 + + + 优先添加 + +
+
+
+
+ {/* 导航标签 */} +
+
handleTabChange("basic")} + > + 基本信息 +
+
handleTabChange("journey")} + > + 用户旅程 +
+
handleTabChange("tags")} + > + 用户标签 +
+
+ } > -
- {/* 顶部信息 */} -
- -
-
{user.nickname}
-
- {user.wechatId} -
- {user.packages && - user.packages.length > 0 && - user.packages.map(pkg => ( - - {pkg} - - ))} -
-
- {/* Tab栏 */} -
- {tabList.map(tab => ( -
setActiveTab(tab.key as any)} - > - {tab.label} -
- ))} -
- {/* Tab内容 */} - {activeTab === "base" && ( - <> - -
-
设备:{user.deviceName || "--"}
-
微信号:{user.wechatAccountName || "--"}
-
客服:{user.customerServiceName || "--"}
-
添加时间:{user.addTime || "--"}
-
最近互动:{user.lastInteraction || "--"}
-
-
- -
-
-
- {user.rfmScore?.recency ?? "-"} -
-
最近性(R)
-
-
-
- {user.rfmScore?.frequency ?? "-"} -
-
频率(F)
-
-
-
- {user.rfmScore?.monetary ?? "-"} -
-
金额(M)
-
-
-
- -
-
-
- ¥{user.totalSpent ?? "-"} -
-
总消费
-
-
-
- {user.interactionCount ?? "-"} -
-
互动次数
-
-
-
- {user.conversionRate ?? "-"} -
-
转化率
-
-
-
- {user.status === "failed" - ? "添加失败" - : user.status === "added" - ? "添加成功" - : "未添加"} -
-
添加状态
-
-
-
- - )} - {activeTab === "journey" && ( - - {user.interactions && user.interactions.length > 0 ? ( - user.interactions.slice(0, 4).map(it => ( -
-
- {it.type === "click" && "📱"} - {it.type === "message" && "💬"} - {it.type === "purchase" && "💲"} - {it.type === "view" && "👁️"} -
-
-
- {it.type === "click" && "点击行为"} - {it.type === "message" && "消息互动"} - {it.type === "purchase" && "购买行为"} - {it.type === "view" && "页面浏览"} +
+ {/* 内容区域 */} +
+ {activeTab === "basic" && ( +
+ {/* 关联信息 */} + + + 设备 + 微信号 + 客服 + 添加时间 + 最近互动 + + + + {/* RFM评分 */} + {user.rfmScore && ( + +
+
+
最近性(R)
+
+ {user.rfmScore.recency} +
-
- {it.content} - {it.type === "purchase" && it.value && ( - - ¥{it.value} - - )} +
+
频率(F)
+
+ {user.rfmScore.frequency} +
+
+
+
金额(M)
+
+ {user.rfmScore.monetary} +
+
+
+
总分
+
+ {user.rfmScore.totalScore}/15 +
-
- {it.timestamp} -
-
- )) - ) : ( -
- 暂无互动记录 -
- )} -
- )} - {activeTab === "tags" && ( - -
- {user.tags && user.tags.length > 0 ? ( - user.tags.map(tag => ( - - {tag} - - )) - ) : ( - 暂无标签 + )} + + {/* 流量池 */} + {user.trafficPools && ( + +
+
+ 当前池: + + {user.trafficPools.currentPool} + +
+
+ 可选池: + {user.trafficPools.availablePools.map((pool, index) => ( + + {pool} + + ))} +
+
+
+ )} + + {/* 统计数据 */} + +
+
+
+ ¥9561 +
+
总消费
+
+
+
+ 6 +
+
互动次数
+
+
+
+ 3% +
+
转化率
+
+
+
+ 未添加 +
+
添加状态
+
+
+
+ + {/* 好友统计 */} + +
+
+
+ {user.userInfo.friendShip.totalFriend} +
+
总好友
+
+
+
+ {user.userInfo.friendShip.maleFriend} +
+
男性好友
+
+
+
+ {user.userInfo.friendShip.femaleFriend} +
+
女性好友
+
+
+
+ {user.userInfo.friendShip.unknowFriend} +
+
未知性别
+
+
+
+ + {/* 限制记录 */} + + {user.restrictions && user.restrictions.length > 0 ? ( + + {user.restrictions.map(restriction => ( + + {restriction.reason || "未知原因"} + + {getRestrictionLevelText(restriction.level)} + +
+ } + description={ +
+ 限制ID: {restriction.id} + {restriction.date && ( + + 限制时间: {formatDate(restriction.date)} + + )} +
+ } + /> + ))} + + ) : ( +
+
+ +
+
暂无限制记录
+
+ 该用户没有任何限制记录 +
+
+ )} +
- - - )} + )} + + {activeTab === "journey" && ( +
+ + {journeyLoading && journeyList.length === 0 ? ( +
+ +
加载中...
+
+ ) : journeyList.length === 0 ? ( +
+
+ +
+
暂无互动记录
+
+ 该用户还没有任何互动行为 +
+
+ ) : ( + + {journeyList.map(record => ( + + {record.remark} + + {formatDateTime(record.createTime)} + +
+ } + /> + ))} + {journeyLoading && journeyList.length > 0 && ( +
+ + 加载更多... +
+ )} + {!journeyLoading && journeyList.length < journeyTotal && ( +
+ +
+ )} + + )} + +
+ )} + + {activeTab === "tags" && ( +
+ {/* 用户标签 */} + + {tagsLoading && userTagsList.length === 0 ? ( +
+ +
加载中...
+
+ ) : userTagsList.length === 0 ? ( +
+
+ +
+
暂无用户标签
+
该用户还没有任何标签
+
+ ) : ( +
+ {userTagsList.map((tag, index) => ( + + {tag.name} + + ))} +
+ )} +
+ + {/* 价值标签 */} + + {user.valueTags && user.valueTags.length > 0 ? ( +
+ {user.valueTags.map(tag => ( +
+
+ + {tag.icon === "crown" && } + {tag.name} + + + RFM总分: {tag.rfmScore}/15 + +
+
+ + 价值等级: + + + {tag.valueLevel} + +
+
+ ))} +
+ ) : ( +
+
+ +
+
暂无价值标签
+
+ 该用户还没有任何价值标签 +
+
+ )} +
+ + {/* 添加新标签按钮 */} + +
+ )} +
); diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx b/nkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx index 2a5597a69..1cd11561b 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx @@ -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), ); }; diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx b/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx index a505ea41f..7e0005240 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/list/index.tsx @@ -191,7 +191,9 @@ const TrafficPoolList: React.FC = () => {
navigate(`/traffic-pool/detail/${item.id}`)} + onClick={() => + navigate(`/traffic-pool/detail/${item.sourceId}/${item.id}`) + } >
{ setIsFetchingFriends(false); } }, - [id] + [id], ); // 搜索好友 @@ -153,7 +153,7 @@ const WechatAccountDetail: React.FC = () => { setFriendsPage(page); fetchFriendsList(page, searchQuery); }, - [searchQuery, fetchFriendsList] + [searchQuery, fetchFriendsList], ); // 初始化数据 diff --git a/nkebao/src/pages/mobile/scenarios/list/index.tsx b/nkebao/src/pages/mobile/scenarios/list/index.tsx index eb21d3e28..6fc5d8da0 100644 --- a/nkebao/src/pages/mobile/scenarios/list/index.tsx +++ b/nkebao/src/pages/mobile/scenarios/list/index.tsx @@ -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)}`, ); }; diff --git a/nkebao/src/pages/mobile/scenarios/plan/list/index.tsx b/nkebao/src/pages/mobile/scenarios/plan/list/index.tsx index 68db5ee5b..f1bd371c3 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/list/index.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/list/index.tsx @@ -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 = () => { {item.icon} {item.text}
- ) + ), )}
diff --git a/nkebao/src/pages/mobile/scenarios/plan/list/planApi.tsx b/nkebao/src/pages/mobile/scenarios/plan/list/planApi.tsx index 386cf58a3..ee67b59c3 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/list/planApi.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/list/planApi.tsx @@ -317,7 +317,7 @@ HttpResponse response = client.send(request, HttpResponse.BodyHandlers.o onClick={() => handleCopy( codeExamples[activeLanguage as keyof typeof codeExamples], - "代码" + "代码", ) } className={style["copy-code-btn"]} diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/index.tsx b/nkebao/src/pages/mobile/scenarios/plan/new/index.tsx index 013b0218b..f75c6cc7c 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/index.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/new/index.tsx @@ -146,7 +146,7 @@ export default function NewPlan() { ? error : isEdit ? "更新计划失败,请重试" - : "创建计划失败,请重试" + : "创建计划失败,请重试", ); } }; diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx b/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx index 40431a5e7..eaec26cea 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/new/steps/BasicSettings.tsx @@ -105,10 +105,10 @@ const BasicSettings: React.FC = ({ const [accounts] = useState(generateRandomAccounts(50)); const [materials] = useState(generatePosterMaterials()); const [selectedAccounts, setSelectedAccounts] = useState( - formData.accounts?.length > 0 ? formData.accounts : [] + formData.accounts?.length > 0 ? formData.accounts : [], ); const [selectedMaterials, setSelectedMaterials] = useState( - 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 = ({ 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 = ({ // 群设置相关状态 const [weixinqunName, setWeixinqunName] = useState( - formData.weixinqunName || "" + formData.weixinqunName || "", ); const [weixinqunNotice, setWeixinqunNotice] = useState( - formData.weixinqunNotice || "" + formData.weixinqunNotice || "", ); // 新增:自定义海报相关状态 @@ -232,7 +232,7 @@ const BasicSettings: React.FC = ({ 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 = ({ // 账号多选切换 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 = ({ const [orderUploaded, setOrderUploaded] = useState(false); const handleOrderFileUpload = async ( - event: React.ChangeEvent + event: React.ChangeEvent, ) => { const file = event.target.files?.[0]; if (file) { @@ -518,7 +518,7 @@ const BasicSettings: React.FC = ({
{[...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 ( diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx b/nkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx index 42b89d4ff..01775fcc6 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/new/steps/FriendRequestSettings.tsx @@ -38,7 +38,7 @@ const FriendRequestSettings: React.FC = ({ const [isTemplateDialogOpen, setIsTemplateDialogOpen] = useState(false); const [hasWarnings, setHasWarnings] = useState(false); const [selectedDevices, setSelectedDevices] = useState( - formData.device || [] + formData.device || [], ); const [showRemarkTip, setShowRemarkTip] = useState(false); diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx b/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx index 29d7d1207..6ce86565f 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx +++ b/nkebao/src/pages/mobile/scenarios/plan/new/steps/MessageSettings.tsx @@ -125,7 +125,7 @@ const MessageSettings: React.FC = ({ const handleUpdateMessage = ( dayIndex: number, messageIndex: number, - updates: Partial + updates: Partial, ) => { const updatedPlans = [...dayPlans]; updatedPlans[dayIndex].messages[messageIndex] = { @@ -181,7 +181,7 @@ const MessageSettings: React.FC = ({ 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 = ({ const triggerUpload = ( dayIdx: number, msgIdx: number, - type: "miniprogram" | "link" + type: "miniprogram" | "link", ) => { setUploadingDay(dayIdx); setUploadingMsgIdx(msgIdx); @@ -539,7 +539,7 @@ const MessageSettings: React.FC = ({ handleFileUpload( dayIndex, messageIndex, - message.type as any + message.type as any, ) } > diff --git a/nkebao/src/pages/mobile/scenarios/plan/new/steps/step.api.ts b/nkebao/src/pages/mobile/scenarios/plan/new/steps/step.api.ts index 1f5a5150d..8c68b53fc 100644 --- a/nkebao/src/pages/mobile/scenarios/plan/new/steps/step.api.ts +++ b/nkebao/src/pages/mobile/scenarios/plan/new/steps/step.api.ts @@ -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", ); } diff --git a/nkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx b/nkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx index 73426064c..a0d88e7d8 100644 --- a/nkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx +++ b/nkebao/src/pages/mobile/workspace/auto-group/detail/index.tsx @@ -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(taskDetail.groups); const [currentGroupIndex, setCurrentGroupIndex] = useState( - taskDetail.currentGroupIndex + taskDetail.currentGroupIndex, ); const [status, setStatus] = useState( - taskDetail.status + taskDetail.status, ); useEffect(() => { @@ -207,7 +207,7 @@ const GroupCreationProgress: React.FC<{ }; } return group; - }) + }), ); }; diff --git a/nkebao/src/pages/mobile/workspace/auto-group/list/index.tsx b/nkebao/src/pages/mobile/workspace/auto-group/list/index.tsx index 0ef828615..1b0a9094e 100644 --- a/nkebao/src/pages/mobile/workspace/auto-group/list/index.tsx +++ b/nkebao/src/pages/mobile/workspace/auto-group/list/index.tsx @@ -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 ( diff --git a/nkebao/src/pages/mobile/workspace/auto-like/list/api.ts b/nkebao/src/pages/mobile/workspace/auto-like/list/api.ts index 23b89dc1c..7f828d56a 100644 --- a/nkebao/src/pages/mobile/workspace/auto-like/list/api.ts +++ b/nkebao/src/pages/mobile/workspace/auto-like/list/api.ts @@ -9,7 +9,7 @@ import { // 获取自动点赞任务列表 export function fetchAutoLikeTasks( - params = { type: 1, page: 1, limit: 100 } + params = { type: 1, page: 1, limit: 100 }, ): Promise { 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> { const params: any = { workbenchId, diff --git a/nkebao/src/pages/mobile/workspace/auto-like/list/index.tsx b/nkebao/src/pages/mobile/workspace/auto-like/list/index.tsx index 33cbb242a..a4910269f 100644 --- a/nkebao/src/pages/mobile/workspace/auto-like/list/index.tsx +++ b/nkebao/src/pages/mobile/workspace/auto-like/list/index.tsx @@ -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 ( diff --git a/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx b/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx index 4443b09b1..56cd6a5a6 100644 --- a/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx +++ b/nkebao/src/pages/mobile/workspace/auto-like/new/index.tsx @@ -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) { diff --git a/nkebao/src/pages/mobile/workspace/auto-like/record/api.ts b/nkebao/src/pages/mobile/workspace/auto-like/record/api.ts index 81a7c26be..6142fde86 100644 --- a/nkebao/src/pages/mobile/workspace/auto-like/record/api.ts +++ b/nkebao/src/pages/mobile/workspace/auto-like/record/api.ts @@ -9,7 +9,7 @@ import { // 获取自动点赞任务列表 export function fetchAutoLikeTasks( - params = { type: 1, page: 1, limit: 100 } + params = { type: 1, page: 1, limit: 100 }, ): Promise { 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> { const params: any = { workbenchId, diff --git a/nkebao/src/pages/mobile/workspace/group-push/detail/groupPush.ts b/nkebao/src/pages/mobile/workspace/group-push/detail/groupPush.ts index 8692db6e0..0295e2f96 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/detail/groupPush.ts +++ b/nkebao/src/pages/mobile/workspace/group-push/detail/groupPush.ts @@ -40,12 +40,12 @@ export async function deleteGroupPushTask(id: string): Promise { export async function toggleGroupPushTask( id: string, - status: string + status: string, ): Promise { return request( `/v1/workspace/group-push/tasks/${id}/toggle`, { status }, - "POST" + "POST", ); } @@ -54,20 +54,20 @@ export async function copyGroupPushTask(id: string): Promise { } export async function createGroupPushTask( - taskData: Partial + taskData: Partial, ): Promise { return request("/v1/workspace/group-push/tasks", taskData, "POST"); } export async function updateGroupPushTask( id: string, - taskData: Partial + taskData: Partial, ): Promise { return request(`/v1/workspace/group-push/tasks/${id}`, taskData, "PUT"); } export async function getGroupPushTaskDetail( - id: string + id: string, ): Promise { return request(`/v1/workspace/group-push/tasks/${id}`); } diff --git a/nkebao/src/pages/mobile/workspace/group-push/detail/index.tsx b/nkebao/src/pages/mobile/workspace/group-push/detail/index.tsx index 7ab430491..ab2a9a0f2 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/detail/index.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/detail/index.tsx @@ -226,7 +226,7 @@ const Detail: React.FC = () => {
diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx index c2d98bd84..34ba3f9ed 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/components/BasicSettings.tsx @@ -105,7 +105,7 @@ const BasicSettings: React.FC = ({ onChange={e => handleChange( "dailyPushCount", - Number.parseInt(e.target.value) || 1 + Number.parseInt(e.target.value) || 1, ) } style={{ width: 80, textAlign: "center" }} diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx index 2d35916e6..ebcb1b529 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/components/ContentSelector.tsx @@ -81,7 +81,7 @@ const ContentSelector: React.FC = ({ const [libraries] = useState(mockLibraries); const filteredLibraries = libraries.filter(library => - library.name.toLowerCase().includes(searchTerm.toLowerCase()) + library.name.toLowerCase().includes(searchTerm.toLowerCase()), ); const handleLibraryToggle = (library: ContentLibrary, checked: boolean) => { diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx b/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx index 016e76f6d..c75138458 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/form/components/GroupSelector.tsx @@ -101,7 +101,9 @@ const GroupSelector: React.FC = ({ 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) => { diff --git a/nkebao/src/pages/mobile/workspace/group-push/form/index.api.ts b/nkebao/src/pages/mobile/workspace/group-push/form/index.api.ts index 7b4b9ecce..15384c115 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/form/index.api.ts +++ b/nkebao/src/pages/mobile/workspace/group-push/form/index.api.ts @@ -1,6 +1,6 @@ import request from "@/api/request"; export async function createGroupPushTask( - taskData: Partial + taskData: Partial, ): Promise { return request("/v1/workspace/group-push/tasks", taskData, "POST"); } diff --git a/nkebao/src/pages/mobile/workspace/group-push/list/index.api.ts b/nkebao/src/pages/mobile/workspace/group-push/list/index.api.ts index 8692db6e0..0295e2f96 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/list/index.api.ts +++ b/nkebao/src/pages/mobile/workspace/group-push/list/index.api.ts @@ -40,12 +40,12 @@ export async function deleteGroupPushTask(id: string): Promise { export async function toggleGroupPushTask( id: string, - status: string + status: string, ): Promise { return request( `/v1/workspace/group-push/tasks/${id}/toggle`, { status }, - "POST" + "POST", ); } @@ -54,20 +54,20 @@ export async function copyGroupPushTask(id: string): Promise { } export async function createGroupPushTask( - taskData: Partial + taskData: Partial, ): Promise { return request("/v1/workspace/group-push/tasks", taskData, "POST"); } export async function updateGroupPushTask( id: string, - taskData: Partial + taskData: Partial, ): Promise { return request(`/v1/workspace/group-push/tasks/${id}`, taskData, "PUT"); } export async function getGroupPushTaskDetail( - id: string + id: string, ): Promise { return request(`/v1/workspace/group-push/tasks/${id}`); } diff --git a/nkebao/src/pages/mobile/workspace/group-push/list/index.tsx b/nkebao/src/pages/mobile/workspace/group-push/list/index.tsx index daf048be0..7634c769f 100644 --- a/nkebao/src/pages/mobile/workspace/group-push/list/index.tsx +++ b/nkebao/src/pages/mobile/workspace/group-push/list/index.tsx @@ -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 = () => {
diff --git a/nkebao/src/pages/mobile/workspace/main/index.tsx b/nkebao/src/pages/mobile/workspace/main/index.tsx index 612053d23..2f4431159 100644 --- a/nkebao/src/pages/mobile/workspace/main/index.tsx +++ b/nkebao/src/pages/mobile/workspace/main/index.tsx @@ -73,17 +73,6 @@ const Workspace: React.FC = () => { path: "/workspace/traffic-distribution", bgColor: "#e6f7ff", }, - { - id: "ai-assistant", - name: "AI对话助手", - description: "智能回复,提高互动质量", - icon: ( - - ), - path: "/workspace/ai-assistant", - bgColor: "#e6f7ff", - isNew: true, - }, ]; // AI智能助手 @@ -176,7 +165,7 @@ const Workspace: React.FC = () => {
{/* AI智能助手 */} -
+ {/*

AI 智能助手

{aiFeatures.map(feature => ( @@ -205,7 +194,7 @@ const Workspace: React.FC = () => { ))}
-
+
*/}
); diff --git a/nkebao/src/pages/mobile/workspace/moments-sync/Detail.tsx b/nkebao/src/pages/mobile/workspace/moments-sync/Detail.tsx index 5f3b6bff8..3b1f0ffd3 100644 --- a/nkebao/src/pages/mobile/workspace/moments-sync/Detail.tsx +++ b/nkebao/src/pages/mobile/workspace/moments-sync/Detail.tsx @@ -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 ? "任务已开启" : "任务已暂停"); diff --git a/nkebao/src/pages/mobile/workspace/moments-sync/MomentsSync.tsx b/nkebao/src/pages/mobile/workspace/moments-sync/MomentsSync.tsx index 0815f9548..15c5bcfc8 100644 --- a/nkebao/src/pages/mobile/workspace/moments-sync/MomentsSync.tsx +++ b/nkebao/src/pages/mobile/workspace/moments-sync/MomentsSync.tsx @@ -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()), ); // 菜单 diff --git a/nkebao/src/pages/mobile/workspace/traffic-distribution/form/api.ts b/nkebao/src/pages/mobile/workspace/traffic-distribution/form/api.ts index 4c8b968b5..db35a752f 100644 --- a/nkebao/src/pages/mobile/workspace/traffic-distribution/form/api.ts +++ b/nkebao/src/pages/mobile/workspace/traffic-distribution/form/api.ts @@ -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"); }; diff --git a/nkebao/src/pages/mobile/workspace/traffic-distribution/form/index.tsx b/nkebao/src/pages/mobile/workspace/traffic-distribution/form/index.tsx index 7ebd417fe..5155245cc 100644 --- a/nkebao/src/pages/mobile/workspace/traffic-distribution/form/index.tsx +++ b/nkebao/src/pages/mobile/workspace/traffic-distribution/form/index.tsx @@ -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), ); }} /> diff --git a/nkebao/src/pages/mobile/workspace/traffic-distribution/list/api.ts b/nkebao/src/pages/mobile/workspace/traffic-distribution/list/api.ts index 0a071cfd4..ceacca1c5 100644 --- a/nkebao/src/pages/mobile/workspace/traffic-distribution/list/api.ts +++ b/nkebao/src/pages/mobile/workspace/traffic-distribution/list/api.ts @@ -17,7 +17,7 @@ export function updateDistributionRule(data: any): Promise { // 暂停/启用计划 export function toggleDistributionRuleStatus( id: number, - status: 0 | 1 + status: 0 | 1, ): Promise { return request("/v1/workbench/update-status", { id, status }, "POST"); } diff --git a/nkebao/src/pages/mobile/workspace/traffic-distribution/list/index.tsx b/nkebao/src/pages/mobile/workspace/traffic-distribution/list/index.tsx index d38018ab8..5e9fd5a81 100644 --- a/nkebao/src/pages/mobile/workspace/traffic-distribution/list/index.tsx +++ b/nkebao/src/pages/mobile/workspace/traffic-distribution/list/index.tsx @@ -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("操作失败"); diff --git a/nkebao/src/router/config.ts b/nkebao/src/router/config.ts index b7c68c548..1b560e874 100644 --- a/nkebao/src/router/config.ts +++ b/nkebao/src/router/config.ts @@ -161,7 +161,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] || []; diff --git a/nkebao/src/router/index.tsx b/nkebao/src/router/index.tsx index 4a02716eb..117681a75 100644 --- a/nkebao/src/router/index.tsx +++ b/nkebao/src/router/index.tsx @@ -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 { diff --git a/nkebao/src/router/module/mine.tsx b/nkebao/src/router/module/mine.tsx index 7a190068b..46e852e8b 100644 --- a/nkebao/src/router/module/mine.tsx +++ b/nkebao/src/router/module/mine.tsx @@ -29,7 +29,7 @@ const routes = [ auth: true, }, { - path: "/traffic-pool/detail/:id", + path: "/traffic-pool/detail/:wxid/:userId", element: , auth: true, }, diff --git a/nkebao/src/store/createPersistStore.ts b/nkebao/src/store/createPersistStore.ts index cf2c80c71..79d7b6347 100644 --- a/nkebao/src/store/createPersistStore.ts +++ b/nkebao/src/store/createPersistStore.ts @@ -5,12 +5,12 @@ import { persist, PersistOptions } from "zustand/middleware"; export function createPersistStore( createState: (set: any, get: any) => T, name: string, - partialize?: (state: T) => Partial + partialize?: (state: T) => Partial, ) { return create()( persist(createState, { name, partialize, - } as PersistOptions) + } as PersistOptions), ); } diff --git a/nkebao/src/store/module/user.ts b/nkebao/src/store/module/user.ts index 6ecd32f74..a26c3e58d 100644 --- a/nkebao/src/store/module/user.ts +++ b/nkebao/src/store/module/user.ts @@ -70,5 +70,5 @@ export const useUserStore = createPersistStore( user: state.user, token: state.token, isLoggedIn: state.isLoggedIn, - }) + }), ); diff --git a/nkebao/src/utils/common.ts b/nkebao/src/utils/common.ts index 3c54d78e6..2dd200f89 100644 --- a/nkebao/src/utils/common.ts +++ b/nkebao/src/utils/common.ts @@ -12,7 +12,7 @@ export const comfirm = ( title?: string; cancelText?: string; confirmText?: string; - } + }, ): Promise => { return new Promise((resolve, reject) => { Modal.show({