- 将公司相关页面重命名为客户管理页面 - 新增信用客户详情、编辑、跟进页面 - 实现客户状态跟踪和跟进流程 - 更新应用配置中的页面路由映射 - 优化订单详情页面的时间轴显示逻辑
166 lines
6.1 KiB
TypeScript
166 lines
6.1 KiB
TypeScript
import { useCallback, useMemo, useState } from 'react'
|
|
import Taro, { useDidShow } from '@tarojs/taro'
|
|
import { View, Text } from '@tarojs/components'
|
|
import { Button, Cell, CellGroup, ConfigProvider, Empty, Space } from '@nutui/nutui-react-taro'
|
|
import { ArrowRight, CheckNormal, Checked } from '@nutui/icons-react-taro'
|
|
|
|
import type { CreditMpCustomer } from '@/api/credit/creditMpCustomer/model'
|
|
import { pageCreditMpCustomer, removeCreditMpCustomer, updateCreditMpCustomer } from '@/api/credit/creditMpCustomer'
|
|
|
|
export default function CreditMpCustomerListPage() {
|
|
const [list, setList] = useState<CreditMpCustomer[]>([])
|
|
const [count, setCount] = useState(0)
|
|
const [page, setPage] = useState(1)
|
|
const limit = 20
|
|
const [loading, setLoading] = useState(false)
|
|
const [loadingMore, setLoadingMore] = useState(false)
|
|
|
|
const hasMore = useMemo(() => list.length < count, [count, list.length])
|
|
|
|
const fetchPage = useCallback(
|
|
async (opts: { nextPage: number; replace: boolean }) => {
|
|
try {
|
|
if (opts.replace) setLoading(true)
|
|
else setLoadingMore(true)
|
|
|
|
const res = await pageCreditMpCustomer({ page: opts.nextPage, limit } as any)
|
|
const incoming = (res?.list || []) as CreditMpCustomer[]
|
|
const total = Number(res?.count || 0)
|
|
setCount(Number.isFinite(total) ? total : 0)
|
|
setPage(opts.nextPage)
|
|
setList(prev => (opts.replace ? incoming : prev.concat(incoming)))
|
|
} catch (e) {
|
|
console.error('获取数据失败:', e)
|
|
Taro.showToast({ title: (e as any)?.message || '获取数据失败', icon: 'none' })
|
|
} finally {
|
|
setLoading(false)
|
|
setLoadingMore(false)
|
|
}
|
|
},
|
|
[limit]
|
|
)
|
|
|
|
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(() => {
|
|
reload()
|
|
})
|
|
|
|
const goAdd = () => Taro.navigateTo({ url: '/credit/creditMpCustomer/add' })
|
|
|
|
const goEdit = (id?: number) => {
|
|
if (!id) return
|
|
Taro.navigateTo({ url: `/credit/creditMpCustomer/add?id=${id}` })
|
|
}
|
|
|
|
const onToggleRecommend = async (row: CreditMpCustomer) => {
|
|
if (!row?.id) return
|
|
const next = row.recommend === 1 ? 0 : 1
|
|
try {
|
|
await updateCreditMpCustomer({ ...row, recommend: next })
|
|
Taro.showToast({ title: next === 1 ? '已设为推荐' : '已取消推荐', icon: 'success' })
|
|
reload()
|
|
} catch (e) {
|
|
console.error('更新失败:', e)
|
|
Taro.showToast({ title: (e as any)?.message || '更新失败', icon: 'none' })
|
|
}
|
|
}
|
|
|
|
const onDel = async (id?: number) => {
|
|
if (!id) return
|
|
const res = await Taro.showModal({ title: '提示', content: '确认删除该记录?' })
|
|
if (!res.confirm) return
|
|
|
|
try {
|
|
await removeCreditMpCustomer(id)
|
|
Taro.showToast({ title: '删除成功', icon: 'success' })
|
|
reload()
|
|
} catch (e) {
|
|
console.error('删除失败:', e)
|
|
Taro.showToast({ title: (e as any)?.message || '删除失败', icon: 'none' })
|
|
}
|
|
}
|
|
|
|
return (
|
|
<View className="bg-gray-50 min-h-screen">
|
|
<ConfigProvider>
|
|
<View className="px-3 pt-3">
|
|
<Space>
|
|
<Button type="primary" size="small" onClick={goAdd}>
|
|
新增小程序端客户
|
|
</Button>
|
|
<Button size="small" loading={loading} onClick={reload}>
|
|
刷新
|
|
</Button>
|
|
</Space>
|
|
</View>
|
|
|
|
{!list.length ? (
|
|
<View className="px-3 pt-10">
|
|
<Empty description={loading ? '加载中...' : '暂无数据'} />
|
|
</View>
|
|
) : (
|
|
<View className="px-3 pt-3 pb-6">
|
|
<View className="mb-2 text-xs text-gray-500 flex items-center justify-between">
|
|
<Text>共{count}条</Text>
|
|
<Text>
|
|
已加载{list.length}条
|
|
</Text>
|
|
</View>
|
|
<CellGroup>
|
|
{list.map(row => {
|
|
const recommended = row.recommend === 1
|
|
const title = row.toUser || '-'
|
|
const price = row.price ? `${row.price}元` : '-'
|
|
const years = row.years ? `${row.years}年` : '-'
|
|
const location = [row.province, row.city, row.region].filter(Boolean).join(' ')
|
|
const desc = `${price} · ${years}${location ? ` · ${location}` : ''}`
|
|
|
|
return (
|
|
<View key={row.id} onLongPress={() => onDel(row.id)}>
|
|
<Cell
|
|
title={title}
|
|
description={desc}
|
|
extra={
|
|
<View className="flex items-center gap-3">
|
|
<View
|
|
className="flex items-center"
|
|
onClick={e => {
|
|
e.stopPropagation()
|
|
onToggleRecommend(row)
|
|
}}
|
|
>
|
|
{recommended ? <Checked size={16} /> : <CheckNormal size={16} />}
|
|
<Text className="ml-1 text-xs text-gray-500">{recommended ? '推荐' : '未推荐'}</Text>
|
|
</View>
|
|
<ArrowRight color="#cccccc" />
|
|
</View>
|
|
}
|
|
onClick={() => goEdit(row.id)}
|
|
/>
|
|
</View>
|
|
)
|
|
})}
|
|
</CellGroup>
|
|
<View className="mt-3 flex justify-center">
|
|
<Button fill="none" size="small" style={{ color: '#bdbdbd' }} disabled={!hasMore || loadingMore} onClick={loadMore}>
|
|
{hasMore ? (loadingMore ? '加载中...' : '加载更多') : '没有更多了'}
|
|
</Button>
|
|
</View>
|
|
<View className="mt-2 text-xs text-gray-400">
|
|
长按任意一条可删除
|
|
</View>
|
|
</View>
|
|
)}
|
|
</ConfigProvider>
|
|
</View>
|
|
)
|
|
}
|