From 338edaac138aef246d0100b17de777412c0bb083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Mon, 16 Mar 2026 21:52:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(credit):=20=E9=87=8D=E6=9E=84=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E4=B8=BA=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在app.config.ts中添加creditMpCustomer相关页面配置 - 将src/credit/customer/index.config.ts中的标题从'客户联系人管理'改为'企业经办人订单管理' - 重写src/credit/customer/index.tsx文件,将原有客户列表功能替换为企业经办人订单列表 - 实现订单搜索、筛选和详情查看功能 - 添加mock数据用于展示企业经办人、企业名称和跟进人信息 - 创建新的API模型和接口文件用于小程序端客户管理功能 --- src/api/credit/creditMpCustomer/index.ts | 101 +++ .../credit/creditMpCustomer/model/index.ts | 57 ++ src/app.config.ts | 8 +- src/app.config.ts.backup.1773665957890 | 180 +++++ src/credit/customer/index.config.ts | 2 +- src/credit/customer/index.tsx | 693 ++---------------- 6 files changed, 420 insertions(+), 621 deletions(-) create mode 100644 src/api/credit/creditMpCustomer/index.ts create mode 100644 src/api/credit/creditMpCustomer/model/index.ts create mode 100644 src/app.config.ts.backup.1773665957890 diff --git a/src/api/credit/creditMpCustomer/index.ts b/src/api/credit/creditMpCustomer/index.ts new file mode 100644 index 0000000..d3d8edb --- /dev/null +++ b/src/api/credit/creditMpCustomer/index.ts @@ -0,0 +1,101 @@ +import request from '@/utils/request'; +import type { ApiResult, PageResult } from '@/api/index'; +import type { CreditMpCustomer, CreditMpCustomerParam } from './model'; + +/** + * 分页查询小程序端客户 + */ +export async function pageCreditMpCustomer(params: CreditMpCustomerParam) { + const res = await request.get>>( + '/credit/credit-mp-customer/page', + params + ); + if (res.code === 0) { + return res.data; + } + return Promise.reject(new Error(res.message)); +} + +/** + * 查询小程序端客户列表 + */ +export async function listCreditMpCustomer(params?: CreditMpCustomerParam) { + const res = await request.get>( + '/credit/credit-mp-customer', + params + ); + if (res.code === 0 && res.data) { + return res.data; + } + return Promise.reject(new Error(res.message)); +} + +/** + * 添加小程序端客户 + */ +export async function addCreditMpCustomer(data: CreditMpCustomer) { + const res = await request.post>( + '/credit/credit-mp-customer', + data + ); + if (res.code === 0) { + return res.message; + } + return Promise.reject(new Error(res.message)); +} + +/** + * 修改小程序端客户 + */ +export async function updateCreditMpCustomer(data: CreditMpCustomer) { + const res = await request.put>( + '/credit/credit-mp-customer', + data + ); + if (res.code === 0) { + return res.message; + } + return Promise.reject(new Error(res.message)); +} + +/** + * 删除小程序端客户 + */ +export async function removeCreditMpCustomer(id?: number) { + const res = await request.del>( + '/credit/credit-mp-customer/' + id + ); + if (res.code === 0) { + return res.message; + } + return Promise.reject(new Error(res.message)); +} + +/** + * 批量删除小程序端客户 + */ +export async function removeBatchCreditMpCustomer(data: (number | undefined)[]) { + const res = await request.del>( + '/credit/credit-mp-customer/batch', + { + data + } + ); + if (res.code === 0) { + return res.message; + } + return Promise.reject(new Error(res.message)); +} + +/** + * 根据id查询小程序端客户 + */ +export async function getCreditMpCustomer(id: number) { + const res = await request.get>( + '/credit/credit-mp-customer/' + id + ); + if (res.code === 0 && res.data) { + return res.data; + } + return Promise.reject(new Error(res.message)); +} diff --git a/src/api/credit/creditMpCustomer/model/index.ts b/src/api/credit/creditMpCustomer/model/index.ts new file mode 100644 index 0000000..ff41d8c --- /dev/null +++ b/src/api/credit/creditMpCustomer/model/index.ts @@ -0,0 +1,57 @@ +import type { PageParam } from '@/api/index'; + +/** + * 小程序端客户 + */ +export interface CreditMpCustomer { + // ID + id?: number; + // 拖欠方 + toUser?: string; + // 拖欠金额 + price?: string; + // 拖欠年数 + years?: string; + // 链接 + url?: string; + // 状态 + statusTxt?: string; + // 企业ID + companyId?: number; + // 所在省份 + province?: string; + // 所在城市 + city?: string; + // 所在辖区 + region?: string; + // 文件路径 + files?: string; + // 是否有数据 + hasData?: string; + // 备注 + comments?: string; + // 是否推荐 + recommend?: number; + // 排序(数字越小越靠前) + sortNumber?: number; + // 状态, 0正常, 1冻结 + status?: number; + // 是否删除, 0否, 1是 + deleted?: number; + // 用户ID + userId?: number; + // 租户id + tenantId?: number; + // 创建时间 + createTime?: string; + // 修改时间 + updateTime?: string; +} + +/** + * 小程序端客户搜索条件 + */ +export interface CreditMpCustomerParam extends PageParam { + id?: number; + keywords?: string; +} diff --git a/src/app.config.ts b/src/app.config.ts index 916103e..f4cc0fa 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -119,8 +119,7 @@ export default { }, { "root": "credit", - "pages": [ - "data/index", + "pages": ["data/index", "customer/index", "order/index", "order/add", @@ -128,8 +127,9 @@ export default { "company/add", "company/detail", "company/follow-step1", - "company/edit" - ] + "company/edit", +'creditMpCustomer/index', + 'creditMpCustomer/add',] } ], window: { diff --git a/src/app.config.ts.backup.1773665957890 b/src/app.config.ts.backup.1773665957890 new file mode 100644 index 0000000..916103e --- /dev/null +++ b/src/app.config.ts.backup.1773665957890 @@ -0,0 +1,180 @@ +export default { + pages: [ + 'pages/index/index', + 'pages/cart/cart', + 'pages/find/find', + 'pages/user/user' + ], + "subpackages": [ + { + "root": "passport", + "pages": [ + "login", + "register", + "forget", + "setting", + "agreement", + "sms-login", + 'qr-login/index', + 'qr-confirm/index', + 'unified-qr/index' + ] + }, + { + "root": "cms", + "pages": [ + 'category/index', + "detail/index" + ] + }, + { + "root": "coupon", + "pages": [ + "index" + ] + }, + { + "root": "user", + "pages": [ + "order/order", + "order/logistics/index", + "order/evaluate/index", + "order/refund/index", + "order/progress/index", + "company/company", + "profile/profile", + "setting/setting", + "userVerify/index", + "address/index", + "address/add", + "address/wxAddress", + "help/index", + "about/index", + "wallet/wallet", + "coupon/index", + "points/points", + "ticket/index", + "ticket/use", + "ticket/orders/index", + // "gift/index", + // "gift/redeem", + // "gift/detail", + // "gift/add", + "store/verification", + "store/orders/index", + "theme/index", + "poster/poster", + "chat/conversation/index", + "chat/message/index", + "chat/message/add", + "chat/message/detail" + ] + }, + { + "root": "dealer", + "pages": [ + "index", + "apply/add", + "withdraw/index", + "orders/index", + "capital/index", + "team/index", + "qrcode/index", + "invite-stats/index", + "info" + ] + }, + { + "root": "shop", + "pages": [ + 'category/index', + 'orderDetail/index', + 'goodsDetail/index', + 'orderConfirm/index', + 'orderConfirmCart/index', + 'comments/index', + 'search/index'] + }, + { + "root": "store", + "pages": [ + "index", + "orders/index" + ] + }, + { + "root": "rider", + "pages": [ + "index", + "orders/index", + "ticket/verification/index" + ] + }, + { + "root": "admin", + "pages": [ + "index", + "article/index", + ] + }, + { + "root": "credit", + "pages": [ + "data/index", + "customer/index", + "order/index", + "order/add", + "company/index", + "company/add", + "company/detail", + "company/follow-step1", + "company/edit" + ] + } + ], + window: { + backgroundTextStyle: 'dark', + navigationBarBackgroundColor: '#fff', + navigationBarTitleText: 'WeChat', + navigationBarTextStyle: 'black' + }, + tabBar: { + custom: false, + color: "#8a8a8a", + selectedColor: "#e60012", + backgroundColor: "#ffffff", + list: [ + { + pagePath: "pages/index/index", + iconPath: "assets/tabbar/home.png", + selectedIconPath: "assets/tabbar/home-active.png", + text: "首页", + }, + { + pagePath: "pages/find/find", + iconPath: "assets/tabbar/shop.png", + selectedIconPath: "assets/tabbar/shop-active.png", + text: "网点", + }, + { + pagePath: "pages/user/user", + iconPath: "assets/tabbar/user.png", + selectedIconPath: "assets/tabbar/user-active.png", + text: "我的", + }, + ], + }, + requiredPrivateInfos: [ + "getLocation", + "chooseLocation", + "chooseAddress" + ], + permission: { + "scope.userLocation": { + "desc": "你的位置信息将用于小程序位置接口的效果展示" + }, + "scope.writePhotosAlbum": { + "desc": "用于保存小程序码到相册,方便分享给好友" + } + } +} diff --git a/src/credit/customer/index.config.ts b/src/credit/customer/index.config.ts index 62147f0..5a3602c 100644 --- a/src/credit/customer/index.config.ts +++ b/src/credit/customer/index.config.ts @@ -1,5 +1,5 @@ export default definePageConfig({ - navigationBarTitleText: '客户联系人管理', + navigationBarTitleText: '企业经办人订单管理', navigationBarTextStyle: 'black', navigationBarBackgroundColor: '#ffffff' }) diff --git a/src/credit/customer/index.tsx b/src/credit/customer/index.tsx index 7ad9567..7e1e30a 100644 --- a/src/credit/customer/index.tsx +++ b/src/credit/customer/index.tsx @@ -1,654 +1,115 @@ -import { useCallback, useMemo, useRef, useState } from 'react' -import Taro, { useDidShow } from '@tarojs/taro' +import { useMemo, useState } from 'react' import { View, Text } from '@tarojs/components' -import { - Address, - Button, - Cell, - CellGroup, - Checkbox, - ConfigProvider, - Empty, - InfiniteLoading, - Loading, - Popup, - PullToRefresh, - SearchBar, - Tag -} from '@nutui/nutui-react-taro' -import { Copy, Phone } from '@nutui/icons-react-taro' +import { ConfigProvider, Empty, Popup, SearchBar } from '@nutui/nutui-react-taro' -import RegionData from '@/api/json/regions-data.json' -import { pageCreditCompany, updateCreditCompany } from '@/api/credit/creditCompany' -import type { CreditCompany } from '@/api/credit/creditCompany/model' -import { listUsers } from '@/api/system/user' -import type { User } from '@/api/system/user/model' -import { hasRole } from '@/utils/permission' - -const PAGE_SIZE = 10 - -type FollowStatus = '全部' | '未联系' | '加微前沟通' | '跟进中' | '已成交' | '无意向' - -const FOLLOW_STATUS_OPTIONS: FollowStatus[] = ['全部', '未联系', '加微前沟通', '跟进中', '已成交', '无意向'] - -const FOLLOW_MAP_STORAGE_KEY = 'credit_company_follow_status_map' - -const safeParseJSON = (v: any): T | null => { - try { - if (!v) return null - if (typeof v === 'object') return v as T - if (typeof v === 'string') return JSON.parse(v) as T - return null - } catch (_e) { - return null - } +type AgentOrderRow = { + id: string + agentName: string + companyName: string + follower: string + // 预留:若经办人为老板,可用于后续扩展“老板名下多企业订单” + isBoss?: boolean } -const getCompanyIdKey = (c: CreditCompany) => String(c?.id || '') - -const splitPhones = (raw?: string) => { - const text = String(raw || '').trim() - if (!text) return [] - // 常见分隔符:逗号/顿号/分号/换行/空格 - return text - .split(/[\s,,;;、\n\r]+/g) - .map(s => s.trim()) - .filter(Boolean) -} - -const getCompanyPhones = (c: CreditCompany) => { - const arr = [...splitPhones(c.tel), ...splitPhones(c.moreTel)] - return Array.from(new Set(arr)) -} - -const getCompanyIndustry = (c: CreditCompany) => { - // 兼容:不同数据源字段可能不一致,优先取更具体的大类 - return String( - c.nationalStandardIndustryCategories6 || - c.nationalStandardIndustryCategories2 || - c.nationalStandardIndustryCategories || - c.institutionType || - '' - ).trim() -} - -export default function CreditCompanyPage() { - const serverPageRef = useRef(1) - const [list, setList] = useState([]) - const [hasMore, setHasMore] = useState(true) - const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) +const MOCK_LIST: AgentOrderRow[] = [ + { id: '1', agentName: '邓莉莉', companyName: '网宿公司', follower: '章鱼' }, + { id: '2', agentName: '邓莉莉', companyName: '飞数公司', follower: '章鱼' } +] +export default function CreditCustomerPage() { const [searchValue, setSearchValue] = useState('') + const [detailVisible, setDetailVisible] = useState(false) + const [activeRow, setActiveRow] = useState(null) - const [cityVisible, setCityVisible] = useState(false) - const [cityText, setCityText] = useState('全部') + const filteredList = useMemo(() => { + const q = searchValue.trim() + if (!q) return MOCK_LIST + return MOCK_LIST.filter(r => String(r.agentName || '').includes(q)) + }, [searchValue]) - const [followVisible, setFollowVisible] = useState(false) - const [followStatus, setFollowStatus] = useState('全部') - - const [industryVisible, setIndustryVisible] = useState(false) - const [industryText, setIndustryText] = useState('全部') - - const [selectMode, setSelectMode] = useState(false) - const [selectedIds, setSelectedIds] = useState([]) - - const [staffPopupVisible, setStaffPopupVisible] = useState(false) - const [staffLoading, setStaffLoading] = useState(false) - const [staffList, setStaffList] = useState([]) - const [staffSelectedId, setStaffSelectedId] = useState(undefined) - const [assigning, setAssigning] = useState(false) - - const [followMap, setFollowMap] = useState>(() => { - const raw = Taro.getStorageSync(FOLLOW_MAP_STORAGE_KEY) - return safeParseJSON>(raw) || {} - }) - - const currentUser = useMemo(() => { - return safeParseJSON(Taro.getStorageSync('User')) || ({} as User) - }, []) - - const canAssign = useMemo(() => { - // 超级管理员:允许分配并更改客户归属(userId) - if (currentUser?.isSuperAdmin) return true - if (hasRole('superAdmin')) return true - return false - }, [currentUser?.isSuperAdmin]) - - const cityOptions = useMemo(() => { - // NutUI Address options: [{ text, value, children }] - // @ts-ignore - return (RegionData || []).map(a => ({ - value: a.label, - text: a.label, - children: (a.children || []).map(b => ({ - value: b.label, - text: b.label, - children: (b.children || []).map(c => ({ - value: c.label, - text: c.label - })) - })) - })) - }, []) - - const staffNameMap = useMemo(() => { - const map = new Map() - for (const u of staffList) { - if (!u?.userId) continue - const name = String(u.realName || u.nickname || u.username || `员工${u.userId}`) - map.set(u.userId, name) - } - return map - }, [staffList]) - - const getFollowStatus = useCallback( - (c: CreditCompany): FollowStatus => { - const k = getCompanyIdKey(c) - const stored = k ? followMap[k] : undefined - if (stored) return stored - return '未联系' - }, - [followMap] - ) - - const setFollowStatusFor = async (c: CreditCompany) => { - if (!c?.id) return - try { - const res = await Taro.showActionSheet({ - itemList: FOLLOW_STATUS_OPTIONS.filter(s => s !== '全部') - }) - const next = FOLLOW_STATUS_OPTIONS.filter(s => s !== '全部')[res.tapIndex] as FollowStatus | undefined - if (!next) return - - setFollowMap(prev => { - const k = getCompanyIdKey(c) - const merged = { ...prev, [k]: next } - Taro.setStorageSync(FOLLOW_MAP_STORAGE_KEY, merged) - return merged - }) - - // 若当前正在按状态筛选,则即时移除不匹配项,避免“改完状态但列表不变”的割裂感。 - if (followStatus !== '全部' && next !== followStatus && c.id) { - const cid = Number(c.id) - setList(prev => prev.filter(x => Number(x.id) !== cid)) - setSelectedIds(prev => prev.filter(id => id !== cid)) - } - } catch (e) { - const msg = String((e as any)?.errMsg || (e as any)?.message || e || '') - if (msg.includes('cancel')) return - } - } - - const applyFilters = useCallback( - (incoming: CreditCompany[]) => { - const city = cityText === '全部' ? '' : cityText - const industry = industryText === '全部' ? '' : industryText - const follow = followStatus === '全部' ? '' : followStatus - - return incoming.filter(c => { - if (c?.deleted === 1) return false - - if (city) { - const full = [c.province, c.city, c.region].filter(Boolean).join(' ') - if (!full.includes(city) && String(c.city || '') !== city) return false - } - - if (industry) { - const ind = getCompanyIndustry(c) - if (!ind.includes(industry)) return false - } - - if (follow) { - if (getFollowStatus(c) !== follow) return false - } - - return true - }) - }, - [cityText, followStatus, getFollowStatus, industryText] - ) - - const reload = useCallback( - async (resetPage = false) => { - if (loading) return - setLoading(true) - setError(null) - - if (resetPage) { - serverPageRef.current = 1 - setHasMore(true) - setSelectedIds([]) - setSelectMode(false) - } - - let nextList = resetPage ? [] : list - let page = serverPageRef.current - let serverHasMore = true - - // 当筛选条件较严格时,可能需要多拉几页才能拿到“至少一条匹配数据” - const MAX_PAGE_TRIES = 8 - let tries = 0 - - try { - while (tries < MAX_PAGE_TRIES) { - tries += 1 - const params: any = { - page, - limit: PAGE_SIZE, - keywords: searchValue?.trim() || undefined - } - - const res = await pageCreditCompany(params) - const incoming = (res?.list || []) as CreditCompany[] - const filtered = applyFilters(incoming) - - if (resetPage) { - nextList = filtered - resetPage = false - } else { - nextList = nextList.concat(filtered) - } - - page += 1 - - // 服务端无更多页:终止 - if (incoming.length < PAGE_SIZE) { - serverHasMore = false - break - } - - // 已拿到可展示数据:先返回,让用户继续滚动触发下一次加载 - if (filtered.length > 0) break - } - - serverPageRef.current = page - setList(nextList) - setHasMore(serverHasMore) - } catch (e) { - console.error('加载客户列表失败:', e) - setError('加载失败,请重试') - setHasMore(false) - } finally { - setLoading(false) - } - }, - [applyFilters, list, loading, searchValue] - ) - - const handleRefresh = useCallback(async () => { - await reload(true) - }, [reload]) - - const loadMore = useCallback(async () => { - if (loading || !hasMore) return - await reload(false) - }, [hasMore, loading, reload]) - - useDidShow(() => { - reload(true).then() - // 预加载员工列表,保证“跟进人(realName)”可展示 - ensureStaffLoaded().then() - }) - - const visibleIndustryOptions = useMemo(() => { - const uniq = new Set() - for (const m of list) { - const ind = getCompanyIndustry(m) - if (ind) uniq.add(ind) - } - const arr = Array.from(uniq) - arr.sort() - return ['全部'].concat(arr) - }, [list]) - - const toggleSelectId = (companyId?: number, checked?: boolean) => { - if (!companyId) return - setSelectedIds(prev => { - if (checked) return prev.includes(companyId) ? prev : prev.concat(companyId) - return prev.filter(id => id !== companyId) - }) - } - - const copyPhones = async () => { - const pool = selectMode && selectedIds.length ? list.filter(c => selectedIds.includes(Number(c.id))) : list - const phones = pool.flatMap(c => getCompanyPhones(c)) - const unique = Array.from(new Set(phones)).filter(Boolean) - if (!unique.length) { - Taro.showToast({ title: '暂无可复制的电话', icon: 'none' }) - return - } - await Taro.setClipboardData({ data: unique.join('\n') }) - Taro.showToast({ title: `已复制${unique.length}个电话`, icon: 'success' }) - } - - const callPhone = async (phone?: string) => { - const num = String(phone || '').trim() - if (!num) { - Taro.showToast({ title: '暂无电话', icon: 'none' }) - return - } - try { - await Taro.makePhoneCall({ phoneNumber: num }) - } catch (e) { - console.error('拨号失败:', e) - Taro.showToast({ title: '拨号失败', icon: 'none' }) - } - } - - const openAddCustomer = () => { - Taro.navigateTo({ url: '/credit/company/add' }) - } - - const ensureStaffLoaded = async () => { - if (staffLoading) return - if (staffList.length) return - setStaffLoading(true) - try { - const res = await listUsers({ isAdmin: true } as any) - setStaffList((res || []) as User[]) - } catch (e) { - console.error('加载员工列表失败:', e) - Taro.showToast({ title: '加载员工失败', icon: 'none' }) - } finally { - setStaffLoading(false) - } - } - - const openAssign = async () => { - if (!canAssign) { - Taro.showToast({ title: '当前角色无分配权限', icon: 'none' }) - return - } - if (!selectMode) { - setSelectMode(true) - setSelectedIds([]) - Taro.showToast({ title: '请选择要分配的客户', icon: 'none' }) - return - } - if (!selectedIds.length) { - Taro.showToast({ title: '请先勾选客户', icon: 'none' }) - return - } - await ensureStaffLoaded() - setStaffPopupVisible(true) - } - - const submitAssign = async () => { - if (!staffSelectedId) { - Taro.showToast({ title: '请选择分配对象', icon: 'none' }) - return - } - if (!selectedIds.length) { - Taro.showToast({ title: '请先勾选客户', icon: 'none' }) - return - } - - setAssigning(true) - try { - for (const id of selectedIds) { - await updateCreditCompany({ id, userId: staffSelectedId } as any) - } - Taro.showToast({ title: '分配成功', icon: 'success' }) - setStaffPopupVisible(false) - setSelectMode(false) - setSelectedIds([]) - await reload(true) - } catch (e) { - console.error('分配失败:', e) - Taro.showToast({ title: '分配失败,请重试', icon: 'none' }) - } finally { - setAssigning(false) - } - } + const totalText = useMemo(() => `${filteredList.length}个订单`, [filteredList.length]) return ( - - reload(true)} - /> + + - - - - - - - - - {!!error && ( - - {error} + + + 功能说明 + 可根据经办人姓名进行搜索; + 搜索结果以列表形式展示:企业经办人、企业名称、跟进人; + 点击任意一行可进入查看该订单的跟进详情内容; + 若某企业经办人是老板,则可通过此功能查看该老板名下关联的所有企业订单数量。 + zzl - )} + - - - {list.length === 0 && !loading ? ( - - + + 搜索结果 + {totalText} + + + + + + 企业经办人 + 企业名称 + 跟进人 + + + {filteredList.length === 0 ? ( + + ) : ( - - - 加载中... - - } - loadMoreText={ - - {list.length === 0 ? '暂无数据' : '没有更多了'} - - } - > - {list.map((c, idx) => { - const id = Number(c.id) - const selected = !!id && selectedIds.includes(id) - const follow = getFollowStatus(c) - const ownerName = - // 兼容后端可能直接下发跟进人字段 - (c as any)?.realName || - (c as any)?.userRealName || - (c as any)?.followRealName || - (c.userId ? staffNameMap.get(Number(c.userId)) : undefined) - const name = c.matchName || c.name || `企业${c.id || ''}` - const industry = getCompanyIndustry(c) - const phones = getCompanyPhones(c) - const primaryPhone = phones[0] - return ( - - { - if (selectMode) return - if (!c?.id) return - Taro.navigateTo({ url: `/credit/company/detail?id=${c.id}` }) - }} - > - - {selectMode && ( - { - e.stopPropagation() - }} - > - toggleSelectId(id, checked)} - /> - - )} - - - - - - {name} - - {!!industry && ( - - {industry} - - )} - - { - e?.stopPropagation?.() - setFollowStatusFor(c) - }} - > - {follow} - - - - - - - {primaryPhone ? primaryPhone : '暂无电话'} - - - 跟进人:{ownerName || '未分配'} - - - - - - - - - {!!(c.province || c.city || c.region) && ( - - {[c.province, c.city, c.region].filter(Boolean).join(' ')} - - )} - - - - - ) - })} - - )} - - - - - - - - - - {selectMode && ( - - 已选 {selectedIds.length} 个 - - copyPhones()} - > - 复制所选电话 - - ( + { - setSelectMode(false) - setSelectedIds([]) + setActiveRow(r) + setDetailVisible(true) }} > - 取消 - - - - )} + {r.agentName} + {r.companyName} + {r.follower} + + )) + )} + -
{ - const txt = value.filter(Boolean).slice(0, 2).join(' ') - setCityText(txt || '全部') - setCityVisible(false) - reload(true).then() - }} - onClose={() => setCityVisible(false)} - /> - setFollowVisible(false)} + onClose={() => setDetailVisible(false)} > - 跟进状态 - setFollowVisible(false)}> + 订单跟进详情 + setDetailVisible(false)}> 关闭 - - {FOLLOW_STATUS_OPTIONS.map(s => ( - {s}} - onClick={() => { - setFollowStatus(s) - setFollowVisible(false) - reload(true).then() - }} - /> - ))} - + {activeRow ? ( + + 企业经办人:{activeRow.agentName} + 企业名称:{activeRow.companyName} + 跟进人:{activeRow.follower} + 此处可接入真实“订单跟进详情”页面或接口返回内容。 + + ) : ( + 暂无详情 + )} - ) } +