diff --git a/nkebao/.env.development b/nkebao/.env.development index d130c9ed..9ac98215 100644 --- a/nkebao/.env.development +++ b/nkebao/.env.development @@ -1,4 +1,4 @@ # 基础环境变量示例 -VITE_API_BASE_URL=http://www.yishi.com -# VITE_API_BASE_URL=https://ckbapi.quwanzhi.com +# VITE_API_BASE_URL=http://www.yishi.com +VITE_API_BASE_URL=https://ckbapi.quwanzhi.com VITE_APP_TITLE=Nkebao Base diff --git a/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx b/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx index 9a70464c..71398a96 100644 --- a/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx +++ b/nkebao/src/pages/mobile/mine/devices/DeviceDetail.tsx @@ -1,7 +1,15 @@ import React, { useEffect, useState, useCallback, useRef } from "react"; import { useParams, useNavigate } from "react-router-dom"; -import { NavBar, Tabs, Switch, Toast, SpinLoading, Button } from "antd-mobile"; -import { SettingOutlined, RedoOutlined } from "@ant-design/icons"; +import { + NavBar, + Tabs, + Switch, + Toast, + SpinLoading, + Button, + Avatar, +} from "antd-mobile"; +import { SettingOutlined, RedoOutlined, UserOutlined } from "@ant-design/icons"; import Layout from "@/components/Layout/Layout"; import { fetchDeviceDetail, @@ -262,15 +270,32 @@ const DeviceDetail: React.FC = () => { navigate(`/wechat-accounts/detail/${acc.wechatId}`); }} > - {acc.nickname} + + + } />
{acc.nickname}
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 0a0a1e92..6d4c4b83 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/api.ts @@ -1,13 +1,7 @@ import request from "@/api/request"; -import type { - TrafficPoolUserDetail, - UserJourneyResponse, - UserTagsResponse, -} from "./data"; +import type { UserTagsResponse } from "./data"; -export function getTrafficPoolDetail( - wechatId: string, -): Promise { +export function getTrafficPoolDetail(wechatId: string) { return request("/v1/wechats/getWechatInfo", { wechatId }, "GET"); } @@ -16,7 +10,7 @@ export function getUserJourney(params: { page: number; pageSize: number; userId: string; -}): Promise { +}) { return request("/v1/traffic/pool/getUserJourney", params, "GET"); } diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts b/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts index fd55131e..43615992 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/data.ts @@ -30,3 +30,79 @@ export interface TrafficPoolUserDetail { value?: number; }>; } + +// 扩展的用户详情类型 +export interface ExtendedUserDetail extends TrafficPoolUserDetail { + userInfo: { + nickname: string; + avatar: string; + wechatId: string; + friendShip: { + totalFriend: number; + maleFriend: number; + femaleFriend: number; + unknowFriend: number; + }; + }; + rfmScore: { + recency: number; + frequency: number; + monetary: number; + totalScore: number; + }; + trafficPools: { + currentPool: string; + availablePools: string[]; + }; + userTags: Array<{ + id: string; + name: string; + color: string; + type: string; + }>; + valueTags: Array<{ + id: string; + name: string; + color: string; + icon: string; + rfmScore: number; + valueLevel: string; + }>; + restrictions?: Array<{ + id: string; + reason: string; + level: number; + date: number | null; + }>; +} + +// 互动记录类型 +export interface InteractionRecord { + id: string; + type: string; + content: string; + timestamp: string; + value?: number; +} + +// 用户旅程记录类型 +export interface UserJourneyRecord { + id: string; + type: number; + remark: string; + createTime: string; +} + +// 用户标签响应类型 +export interface UserTagsResponse { + wechat: string[]; + siteLabels: UserTagItem[]; +} + +// 用户标签项类型 +export interface UserTagItem { + id: string; + name: string; + color?: string; + type?: string; +} 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 60165acb..6b896216 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 @@ -47,6 +47,18 @@ flex-shrink: 0; } + .avatarFallback { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + font-size: 24px; + border-radius: 50%; + } + .userDetails { flex: 1; min-width: 0; @@ -343,7 +355,7 @@ flex-direction: column; align-items: center; justify-content: center; - padding: 60px 16px; + padding: 20px 16px; text-align: center; } @@ -353,14 +365,14 @@ } .emptyText { - font-size: 16px; + font-size: 14px; color: #666; - margin-bottom: 8px; + margin-bottom: 4px; font-weight: 500; } .emptyDesc { - font-size: 14px; + font-size: 12px; color: #999; line-height: 1.4; } 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 88fd1c41..4c7ce51b 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/detail/index.tsx @@ -1,20 +1,9 @@ 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 { Card, Button, Avatar, Tag, List, SpinLoading } from "antd-mobile"; import { UserOutlined, CrownOutlined, - PlusOutlined, - CloseOutlined, EyeOutlined, DollarOutlined, MobileOutlined, @@ -26,9 +15,7 @@ import Layout from "@/components/Layout/Layout"; import NavCommon from "@/components/NavCommon"; import { getTrafficPoolDetail, getUserJourney, getUserTags } from "./api"; import type { - TrafficPoolUserDetail, ExtendedUserDetail, - InteractionRecord, UserJourneyRecord, UserTagsResponse, UserTagItem, @@ -52,6 +39,7 @@ const TrafficPoolDetail: React.FC = () => { // 用户标签相关状态 const [tagsLoading, setTagsLoading] = useState(false); const [userTagsList, setUserTagsList] = useState([]); + const [wechatTagsList, setWechatTagsList] = useState([]); useEffect(() => { if (!wxid) return; @@ -61,6 +49,8 @@ const TrafficPoolDetail: React.FC = () => { // 将API数据转换为扩展的用户详情数据 const extendedUser: ExtendedUserDetail = { ...res, + // 添加userInfo属性 + userInfo: res.userInfo, // 模拟RFM评分数据 rfmScore: { recency: 5, @@ -92,6 +82,8 @@ const TrafficPoolDetail: React.FC = () => { }, ], }; + console.log(extendedUser); + setUser(extendedUser); }) .finally(() => setLoading(false)); @@ -131,6 +123,7 @@ const TrafficPoolDetail: React.FC = () => { try { const response: UserTagsResponse = await getUserTags(userId); setUserTagsList(response.siteLabels || []); + setWechatTagsList(response.wechat || []); } catch (error) { console.error("获取用户标签失败:", error); } finally { @@ -149,10 +142,6 @@ const TrafficPoolDetail: React.FC = () => { } }; - const handleClose = () => { - navigate(-1); - }; - const getJourneyTypeIcon = (type: number) => { switch (type) { case 0: // 浏览 @@ -207,32 +196,6 @@ const TrafficPoolDetail: React.FC = () => { } }; - 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: @@ -297,7 +260,11 @@ const TrafficPoolDetail: React.FC = () => { } + fallback={ +
+ +
+ } />
{user.userInfo.nickname}
@@ -617,20 +584,22 @@ const TrafficPoolDetail: React.FC = () => { {activeTab === "tags" && (
- {/* 用户标签 */} - + {/* 站内标签 */} + {tagsLoading && userTagsList.length === 0 ? (
- +
加载中...
) : userTagsList.length === 0 ? (
- + +
+
暂无站内标签
+
+ 该用户还没有任何站内标签
-
暂无用户标签
-
该用户还没有任何标签
) : (
@@ -648,6 +617,39 @@ const TrafficPoolDetail: React.FC = () => { )} + {/* 微信标签 */} + + {tagsLoading && wechatTagsList.length === 0 ? ( +
+ +
加载中...
+
+ ) : wechatTagsList.length === 0 ? ( +
+
+ +
+
暂无微信标签
+
+ 该用户还没有任何微信标签 +
+
+ ) : ( +
+ {wechatTagsList.map((tag, index) => ( + + {tag} + + ))} +
+ )} +
+ {/* 价值标签 */} {user.valueTags && user.valueTags.length > 0 ? ( diff --git a/nkebao/src/pages/mobile/mine/traffic-pool/list/api.ts b/nkebao/src/pages/mobile/mine/traffic-pool/list/api.ts index d8bc9af4..0a6162a8 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/list/api.ts +++ b/nkebao/src/pages/mobile/mine/traffic-pool/list/api.ts @@ -1,6 +1,4 @@ import request from "@/api/request"; -import type { TrafficPoolListResponse, DeviceOption } from "./data"; -import { fetchDeviceList } from "@/pages/guide/api"; // 获取流量池列表 export function fetchTrafficPoolList(params: { @@ -11,16 +9,6 @@ export function fetchTrafficPoolList(params: { return request("/v1/traffic/pool", params, "GET"); } -// 获取设备列表(真实接口) -export async function fetchDeviceOptions(): Promise { - const res = await fetchDeviceList({ page: 1, limit: 100 }); - // 假设返回 { list: [{ id, name, ... }], ... } - return (res.list || []).map((item: any) => ({ - id: String(item.id), - name: item.name, - })); -} - // 获取分组列表(如无真实接口可用mock) export async function fetchPackageOptions(): Promise { // TODO: 替换为真实接口 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 1cd11561..7a84040a 100644 --- a/nkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx +++ b/nkebao/src/pages/mobile/mine/traffic-pool/list/dataAnyx.tsx @@ -1,9 +1,5 @@ import { useState, useEffect, useMemo } from "react"; -import { - fetchTrafficPoolList, - fetchDeviceOptions, - fetchPackageOptions, -} from "./api"; +import { fetchTrafficPoolList, fetchPackageOptions } from "./api"; import type { TrafficPoolUser, DeviceOption, @@ -69,7 +65,6 @@ export function useTrafficPoolListLogic() { // 获取筛选项 useEffect(() => { - fetchDeviceOptions().then(setDeviceOptions); fetchPackageOptions().then(setPackageOptions); }, []);