From ead384344f02bc70c0203e86823c7f68013ae219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 20 Mar 2026 00:45:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(credit):=20=E6=B7=BB=E5=8A=A0=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E5=91=98=E9=80=89=E6=8B=A9=E9=A1=B5=E9=9D=A2=E5=B9=B6?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=AE=A2=E6=88=B7=E5=88=86=E9=85=8D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在路由配置中添加 pageUser/index 页面路径 - 移除原有的员工弹窗选择组件 - 将权限判断从 superAdmin 改为 admin - 修改员工列表加载逻辑,查询条件从 isStaff 改为 isAdmin - 实现新的业务员选择页面,支持搜索、分页和下拉刷新 - 使用页面跳转方式替代弹窗进行业务员选择 - 更新客户分配逻辑以适配新的选择流程 --- src/app.config.ts | 1 + src/credit/mp-customer/index.tsx | 107 ++++++------------------ src/credit/pageUser/index.tsx | 139 +++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 80 deletions(-) create mode 100644 src/credit/pageUser/index.tsx diff --git a/src/app.config.ts b/src/app.config.ts index eed1052..7bd5180 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -49,6 +49,7 @@ export default { "creditMpCustomer/detail", "creditMpCustomer/follow-step1", "creditMpCustomer/edit", + "pageUser/index", "mp-customer/index", "mp-customer/add", "mp-customer/detail", diff --git a/src/credit/mp-customer/index.tsx b/src/credit/mp-customer/index.tsx index 8b2e6f2..3d6b102 100644 --- a/src/credit/mp-customer/index.tsx +++ b/src/credit/mp-customer/index.tsx @@ -129,10 +129,7 @@ export default function CreditCompanyPage() { 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 currentUser = useMemo(() => { @@ -141,10 +138,10 @@ export default function CreditCompanyPage() { const canAssign = useMemo(() => { // 超级管理员:允许分配并更改客户归属(userId) - if (currentUser?.isSuperAdmin) return true - if (hasRole('superAdmin')) return true + if (currentUser?.isAdmin) return true + if (hasRole('admin')) return true return false - }, [currentUser?.isSuperAdmin]) + }, [currentUser?.isAdmin]) const cityOptions = useMemo(() => { // NutUI Address options: [{ text, value, children }] @@ -338,10 +335,9 @@ export default function CreditCompanyPage() { if (staffList.length) return staffList if (staffLoadingPromiseRef.current) return staffLoadingPromiseRef.current - setStaffLoading(true) const p = (async () => { try { - const res = await listUsers({ isStaff: true } as any) + const res = await listUsers({ isAdmin: true } as any) const arr = (res || []) as User[] setStaffList(arr) return arr @@ -350,7 +346,6 @@ export default function CreditCompanyPage() { Taro.showToast({ title: '加载员工失败', icon: 'none' }) return [] } finally { - setStaffLoading(false) staffLoadingPromiseRef.current = null } })() @@ -374,19 +369,29 @@ export default function CreditCompanyPage() { Taro.showToast({ title: '请先勾选客户', icon: 'none' }) return } - const staff = await ensureStaffLoaded() - if (!staff.length) { - Taro.showToast({ title: '暂无可分配员工', icon: 'none' }) - return - } - setStaffPopupVisible(true) + Taro.navigateTo({ + url: '/credit/pageUser/index?isAdmin=1&title=选择业务员', + events: { + userSelected: (payload: any) => { + const uid = Number(payload?.userId ?? payload?.user?.userId) + if (!Number.isFinite(uid) || uid <= 0) return + const u = payload?.user as User | undefined + const pickedName = String( + payload?.realName || + payload?.nickname || + payload?.username || + u?.realName || + u?.nickname || + u?.username || + '' + ).trim() + submitAssign(uid, pickedName).then() + } + } + }) } - const submitAssign = async () => { - if (!staffSelectedId) { - Taro.showToast({ title: '请选择分配对象', icon: 'none' }) - return - } + const submitAssign = async (userId: number, userName?: string) => { if (!selectedIds.length) { Taro.showToast({ title: '请先勾选客户', icon: 'none' }) return @@ -394,7 +399,7 @@ export default function CreditCompanyPage() { setAssigning(true) try { - const staffName = staffNameMap.get(Number(staffSelectedId)) || `员工${staffSelectedId}` + const staffName = String(userName || '').trim() || staffNameMap.get(Number(userId)) || `员工${userId}` const confirmRes = await Taro.showModal({ title: '确认分配', content: `确定将 ${selectedIds.length} 个客户分配给「${staffName}」吗?` @@ -403,10 +408,9 @@ export default function CreditCompanyPage() { for (const id of selectedIds) { const detail = await getCreditMpCustomer(Number(id)) - await updateCreditMpCustomer({ ...(detail || {}), id, userId: staffSelectedId } as any) + await updateCreditMpCustomer({ ...(detail || {}), id, userId } as any) } Taro.showToast({ title: '分配成功', icon: 'success' }) - setStaffPopupVisible(false) setSelectMode(false) setSelectedIds([]) await reload(true) @@ -702,63 +706,6 @@ export default function CreditCompanyPage() { - { - if (assigning) return - setStaffPopupVisible(false) - }} - > - - - 选择分配对象 - !assigning && setStaffPopupVisible(false)}> - 关闭 - - - - - {staffLoading ? ( - - - 加载中... - - ) : ( - - {staffList.map(u => ( - - {u.realName || u.nickname || u.username || `员工${u.userId}`} - - } - description={u.phone || ''} - onClick={() => setStaffSelectedId(u.userId)} - /> - ))} - {!staffList.length && ( - 暂无员工数据} /> - )} - - )} - - - - - - - - ) diff --git a/src/credit/pageUser/index.tsx b/src/credit/pageUser/index.tsx new file mode 100644 index 0000000..bd6625e --- /dev/null +++ b/src/credit/pageUser/index.tsx @@ -0,0 +1,139 @@ +import { useCallback, useMemo, useState } from 'react' +import Taro, { useDidShow, useRouter } from '@tarojs/taro' +import { View, Text } from '@tarojs/components' +import { Cell, CellGroup, ConfigProvider, Empty, InfiniteLoading, Loading, PullToRefresh, SearchBar } from '@nutui/nutui-react-taro' + +import { pageUsers } from '@/api/system/user' +import type { User, UserParam } from '@/api/system/user/model' + +const PAGE_SIZE = 20 + +export default function PageUserSelectPage() { + const { params } = useRouter() + const isAdmin = useMemo(() => { + const n = Number(params?.isAdmin) + return Number.isFinite(n) ? n : undefined + }, [params?.isAdmin]) + + const [list, setList] = useState([]) + const [page, setPage] = useState(1) + const [hasMore, setHasMore] = useState(true) + const [keywords, setKeywords] = useState('') + const [loading, setLoading] = useState(false) + const [loadingMore, setLoadingMore] = useState(false) + + const fetchPage = useCallback( + async (opts: { nextPage: number; replace: boolean }) => { + try { + if (opts.replace) setLoading(true) + else setLoadingMore(true) + + const res = await pageUsers({ + page: opts.nextPage, + limit: PAGE_SIZE, + keywords: keywords.trim() || undefined, + isAdmin + } as UserParam) + + const incoming = (res?.list || []) as User[] + const total = Number(res?.count || 0) + setPage(opts.nextPage) + setList(prev => { + const nextList = opts.replace ? incoming : prev.concat(incoming) + if (Number.isFinite(total) && total > 0) setHasMore(nextList.length < total) + else setHasMore(incoming.length >= PAGE_SIZE) + return nextList + }) + } catch (e) { + console.error('加载业务员失败:', e) + Taro.showToast({ title: (e as any)?.message || '加载失败', icon: 'none' }) + } finally { + setLoading(false) + setLoadingMore(false) + } + }, + [isAdmin, keywords] + ) + + const reload = useCallback(async () => { + await fetchPage({ nextPage: 1, replace: true }) + }, [fetchPage]) + + const loadMore = useCallback(async () => { + if (loading || loadingMore || !hasMore) return + await fetchPage({ nextPage: page + 1, replace: false }) + }, [fetchPage, hasMore, loading, loadingMore, page]) + + useDidShow(() => { + Taro.setNavigationBarTitle({ title: String(params?.title || '选择业务员') }) + reload() + }) + + const onPick = (u: User) => { + if (!u?.userId) return + const pageInst: any = Taro.getCurrentInstance().page + const eventChannel = pageInst?.getOpenerEventChannel?.() + eventChannel?.emit('userSelected', { userId: u.userId, user: u }) + Taro.navigateBack() + } + + return ( + + + + + + + + + {list.length === 0 && !loading ? ( + + + + ) : ( + + + 加载中... + + } + loadMoreText={ + + {list.length === 0 ? '暂无数据' : '没有更多了'} + + } + > + + {list.map(u => ( + {u.realName || u.nickname || u.username || `用户${u.userId}`}} + description={u.phone || u.username || ''} + onClick={() => onPick(u)} + /> + ))} + + + )} + + {(loading || loadingMore) && list.length === 0 && ( + + + 加载中... + + )} + + + + + ) +}