refactor(credit): 重构客户列表筛选逻辑并优化性能

- 移除未使用的 Copy 图标导入
- 提取筛选逻辑到独立的 filterCustomers 函数
- 添加 FilterValues 类型定义
- 使用 useRef 保存筛选状态避免依赖循环
- 修改 reload 函数支持覆盖筛选参数
- 将筛选参数传递给 API 调用
- 修复复制电话按钮功能禁用
- 更新地区、步骤和状态筛选的重载逻辑
- 修改员工查询参数从 isAdmin 到 isStaff
This commit is contained in:
2026-03-20 00:55:30 +08:00
parent 495a9c8bbf
commit b14d85fb00

View File

@@ -16,7 +16,7 @@ import {
SearchBar, SearchBar,
Tag Tag
} from '@nutui/nutui-react-taro' } from '@nutui/nutui-react-taro'
import { Copy, Phone } from '@nutui/icons-react-taro' import { Phone } from '@nutui/icons-react-taro'
import RegionData from '@/api/json/regions-data.json' import RegionData from '@/api/json/regions-data.json'
import { getCreditMpCustomer, pageCreditMpCustomer, updateCreditMpCustomer } from '@/api/credit/creditMpCustomer' import { getCreditMpCustomer, pageCreditMpCustomer, updateCreditMpCustomer } from '@/api/credit/creditMpCustomer'
@@ -107,6 +107,39 @@ const getStepTagType = (code: number | null): any => {
return 'primary' return 'primary'
} }
type FilterValues = {
cityText: string
statusText: string
stepCode: number | null
}
const filterCustomers = (incoming: CreditMpCustomer[], filters: FilterValues) => {
const city = filters.cityText === '全部' ? '' : filters.cityText
const status = filters.statusText === '全部' ? '' : filters.statusText
const step = filters.stepCode == null ? null : filters.stepCode
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 (status) {
const txt = getRowStatus(c)
if (!txt.includes(status)) return false
}
if (step != null) {
const code = getStepCode(c)
if (code == null || code !== step) return false
}
return true
})
}
export default function CreditCompanyPage() { export default function CreditCompanyPage() {
const serverPageRef = useRef(1) const serverPageRef = useRef(1)
const staffLoadingPromiseRef = useRef<Promise<User[]> | null>(null) const staffLoadingPromiseRef = useRef<Promise<User[]> | null>(null)
@@ -120,12 +153,15 @@ export default function CreditCompanyPage() {
const [cityVisible, setCityVisible] = useState(false) const [cityVisible, setCityVisible] = useState(false)
const [cityText, setCityText] = useState<string>('全部') const [cityText, setCityText] = useState<string>('全部')
const cityTextRef = useRef(cityText)
const [stepVisible, setStepVisible] = useState(false) const [stepVisible, setStepVisible] = useState(false)
const [stepCode, setStepCode] = useState<number | null>(null) const [stepCode, setStepCode] = useState<number | null>(null)
const stepCodeRef = useRef(stepCode)
const [statusVisible, setStatusVisible] = useState(false) const [statusVisible, setStatusVisible] = useState(false)
const [statusText, setStatusText] = useState<string>('全部') const [statusText, setStatusText] = useState<string>('全部')
const statusTextRef = useRef(statusText)
const [selectMode, setSelectMode] = useState(false) const [selectMode, setSelectMode] = useState(false)
const [selectedIds, setSelectedIds] = useState<number[]>([]) const [selectedIds, setSelectedIds] = useState<number[]>([])
@@ -171,38 +207,12 @@ export default function CreditCompanyPage() {
return map return map
}, [staffList]) }, [staffList])
const applyFilters = useCallback( cityTextRef.current = cityText
(incoming: CreditMpCustomer[]) => { statusTextRef.current = statusText
const city = cityText === '全部' ? '' : cityText stepCodeRef.current = stepCode
const status = statusText === '全部' ? '' : statusText
const step = stepCode == null ? null : stepCode
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 (status) {
const txt = getRowStatus(c)
if (!txt.includes(status)) return false
}
if (step != null) {
const code = getStepCode(c)
if (code == null || code !== step) return false
}
return true
})
},
[cityText, statusText, stepCode]
)
const reload = useCallback( const reload = useCallback(
async (resetPage = false) => { async (resetPage = false, override?: Partial<FilterValues>) => {
if (loading) return if (loading) return
setLoading(true) setLoading(true)
setError(null) setError(null)
@@ -217,6 +227,11 @@ export default function CreditCompanyPage() {
let nextList = resetPage ? [] : list let nextList = resetPage ? [] : list
let page = serverPageRef.current let page = serverPageRef.current
let serverHasMore = true let serverHasMore = true
const filters: FilterValues = {
cityText: override?.cityText ?? cityTextRef.current,
statusText: override?.statusText ?? statusTextRef.current,
stepCode: override?.stepCode ?? stepCodeRef.current
}
// 当筛选条件较严格时,可能需要多拉几页才能拿到“至少一条匹配数据” // 当筛选条件较严格时,可能需要多拉几页才能拿到“至少一条匹配数据”
const MAX_PAGE_TRIES = 8 const MAX_PAGE_TRIES = 8
@@ -233,7 +248,7 @@ export default function CreditCompanyPage() {
const res = await pageCreditMpCustomer(params as CreditMpCustomerParam) const res = await pageCreditMpCustomer(params as CreditMpCustomerParam)
const incoming = (res?.list || []) as CreditMpCustomer[] const incoming = (res?.list || []) as CreditMpCustomer[]
const filtered = applyFilters(incoming) const filtered = filterCustomers(incoming, filters)
if (resetPage) { if (resetPage) {
nextList = filtered nextList = filtered
@@ -265,7 +280,7 @@ export default function CreditCompanyPage() {
setLoading(false) setLoading(false)
} }
}, },
[applyFilters, list, loading, searchValue] [list, loading, searchValue]
) )
const handleRefresh = useCallback(async () => { const handleRefresh = useCallback(async () => {
@@ -366,7 +381,7 @@ export default function CreditCompanyPage() {
const p = (async () => { const p = (async () => {
try { try {
const res = await listUsers({ isAdmin: true } as any) const res = await listUsers({ isStaff: true } as any)
const arr = (res || []) as User[] const arr = (res || []) as User[]
setStaffList(arr) setStaffList(arr)
return arr return arr
@@ -471,9 +486,9 @@ export default function CreditCompanyPage() {
{/* {statusText === '全部' ? '状态' : statusText}*/} {/* {statusText === '全部' ? '状态' : statusText}*/}
{/*</Button>*/} {/*</Button>*/}
<View className="flex-1" /> <View className="flex-1" />
<Button size="small" fill="outline" icon={<Copy />} onClick={copyPhones}> {/*<Button size="small" fill="outline" icon={<Copy />} onClick={copyPhones}>*/}
{/* 复制电话*/}
</Button> {/*</Button>*/}
</View> </View>
{!!error && ( {!!error && (
@@ -668,9 +683,10 @@ export default function CreditCompanyPage() {
title="选择地区(到城市)" title="选择地区(到城市)"
onChange={(value: any[]) => { onChange={(value: any[]) => {
const txt = value.filter(Boolean).slice(0, 2).join(' ') const txt = value.filter(Boolean).slice(0, 2).join(' ')
setCityText(txt || '全部') const nextCityText = txt || '全部'
setCityText(nextCityText)
setCityVisible(false) setCityVisible(false)
reload(true).then() reload(true, { cityText: nextCityText }).then()
}} }}
onClose={() => setCityVisible(false)} onClose={() => setCityVisible(false)}
/> />
@@ -688,9 +704,10 @@ export default function CreditCompanyPage() {
key="ALL" key="ALL"
title={<Text className={stepCode == null ? 'text-blue-600' : ''}></Text>} title={<Text className={stepCode == null ? 'text-blue-600' : ''}></Text>}
onClick={() => { onClick={() => {
setStepCode(null) const nextStep = null
setStepCode(nextStep)
setStepVisible(false) setStepVisible(false)
reload(true).then() reload(true, { stepCode: nextStep }).then()
}} }}
/> />
{STEP_OPTIONS.map(s => ( {STEP_OPTIONS.map(s => (
@@ -698,9 +715,10 @@ export default function CreditCompanyPage() {
key={s.code} key={s.code}
title={<Text className={s.code === stepCode ? 'text-blue-600' : ''}>{s.text}</Text>} title={<Text className={s.code === stepCode ? 'text-blue-600' : ''}>{s.text}</Text>}
onClick={() => { onClick={() => {
setStepCode(s.code) const nextStep = s.code
setStepCode(nextStep)
setStepVisible(false) setStepVisible(false)
reload(true).then() reload(true, { stepCode: nextStep }).then()
}} }}
/> />
))} ))}
@@ -722,9 +740,10 @@ export default function CreditCompanyPage() {
key={s} key={s}
title={<Text className={s === statusText ? 'text-blue-600' : ''}>{s}</Text>} title={<Text className={s === statusText ? 'text-blue-600' : ''}>{s}</Text>}
onClick={() => { onClick={() => {
setStatusText(s) const nextStatus = s
setStatusText(nextStatus)
setStatusVisible(false) setStatusVisible(false)
reload(true).then() reload(true, { statusText: nextStatus }).then()
}} }}
/> />
))} ))}