- 将房号唯一键增加楼层字段,修改相关函数支持楼层处理 - 新增楼栋、单元、楼层、房号的选择状态和搜索过滤功能 - 实现楼栋、单元、楼层、房号的选择弹窗和清除按钮 - 表单改用选择控件替代输入框,隐藏字段同步表单数据 - 修改表单校验,验证楼栋、楼层、房号字段必填 - 编辑模式支持从dealerCode解析回填楼栋、单元、楼层、房号 - 优化房号规范化逻辑,去除楼层相关后缀 - 代码中统一使用规范化后的楼栋单元楼层房号构造唯一
324 lines
10 KiB
TypeScript
324 lines
10 KiB
TypeScript
import React, {useState, useEffect} from 'react'
|
||
import {View, Text, ScrollView, Input, Button} from '@tarojs/components'
|
||
import {ConfigProvider, Field, Cell, CellGroup, Toast} from '@nutui/nutui-react-taro'
|
||
import {useDealerUser} from '@/hooks/useDealerUser'
|
||
import Taro from '@tarojs/taro'
|
||
import {addReferral, getMyReferrals, getMyStats} from '@/api/app/referral'
|
||
import './index.scss'
|
||
|
||
// 状态映射
|
||
const STATUS_MAP: Record<number, { text: string; color: string }> = {
|
||
0: {text: '待确认', color: '#ff9800'},
|
||
1: {text: '有效', color: '#4caf50'},
|
||
2: {text: '无效', color: '#9e9e9e'},
|
||
3: {text: '已结算', color: '#2196f3'}
|
||
}
|
||
|
||
const ReferralPage: React.FC = () => {
|
||
const {dealerUser} = useDealerUser()
|
||
const [loading, setLoading] = useState(false)
|
||
const [submitting, setSubmitting] = useState(false)
|
||
|
||
// 表单数据
|
||
const [formData, setFormData] = useState({
|
||
customerName: '',
|
||
customerPhone: '',
|
||
customerCompany: '',
|
||
requirement: '',
|
||
remarks: ''
|
||
})
|
||
|
||
// 统计
|
||
const [stats, setStats] = useState({
|
||
totalCount: 0,
|
||
pendingCount: 0,
|
||
validCount: 0,
|
||
settledCount: 0,
|
||
pendingAmount: 0
|
||
})
|
||
|
||
// 记录列表
|
||
const [records, setRecords] = useState<any[]>([])
|
||
const [page, setPage] = useState(1)
|
||
const [hasMore, setHasMore] = useState(true)
|
||
|
||
// 加载数据
|
||
const loadData = async () => {
|
||
if (!dealerUser?.userId) return
|
||
|
||
try {
|
||
setLoading(true)
|
||
|
||
// 获取统计
|
||
const statsRes = await getMyStats()
|
||
if (statsRes.data.code === 0) {
|
||
setStats(statsRes.data.data)
|
||
}
|
||
|
||
// 获取列表
|
||
const listRes = await getMyReferrals({pageNum: 1, pageSize: 10})
|
||
if (listRes.data.code === 0) {
|
||
setRecords(listRes.data.data.list || [])
|
||
setHasMore(listRes.data.data.list?.length === 10)
|
||
}
|
||
} catch (error) {
|
||
console.error('加载失败', error)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
loadData()
|
||
}, [dealerUser])
|
||
|
||
// 输入处理
|
||
const handleInput = (field: string, value: string) => {
|
||
setFormData(prev => ({...prev, [field]: value}))
|
||
}
|
||
|
||
// 表单验证
|
||
const validateForm = () => {
|
||
if (!formData.customerName.trim()) {
|
||
Toast.text('请输入客户姓名')
|
||
return false
|
||
}
|
||
if (!formData.customerPhone.trim()) {
|
||
Toast.text('请输入客户电话')
|
||
return false
|
||
}
|
||
if (!/^1[3-9]\d{9}$/.test(formData.customerPhone)) {
|
||
Toast.text('请输入正确的手机号')
|
||
return false
|
||
}
|
||
return true
|
||
}
|
||
|
||
// 提交报备
|
||
const handleSubmit = async () => {
|
||
if (!validateForm()) return
|
||
|
||
try {
|
||
setSubmitting(true)
|
||
const res = await addReferral(formData)
|
||
|
||
if (res.data.code === 0) {
|
||
Toast.text('报备成功!')
|
||
// 清空表单
|
||
setFormData({
|
||
customerName: '',
|
||
customerPhone: '',
|
||
customerCompany: '',
|
||
requirement: '',
|
||
remarks: ''
|
||
})
|
||
// 刷新数据
|
||
loadData()
|
||
} else {
|
||
Toast.text(res.data.message || '报备失败')
|
||
}
|
||
} catch (error: any) {
|
||
Toast.text(error.message || '报备失败')
|
||
} finally {
|
||
setSubmitting(false)
|
||
}
|
||
}
|
||
|
||
// 拨打电话
|
||
const handleCall = (phone: string) => {
|
||
if (phone) {
|
||
Taro.makePhoneCall({phoneNumber: phone})
|
||
}
|
||
}
|
||
|
||
// 加载更多
|
||
const loadMore = async () => {
|
||
if (!hasMore || loading) return
|
||
|
||
try {
|
||
const nextPage = page + 1
|
||
const res = await getMyReferrals({pageNum: nextPage, pageSize: 10})
|
||
if (res.data.code === 0 && res.data.data.list) {
|
||
setRecords(prev => [...prev, ...res.data.data.list])
|
||
setPage(nextPage)
|
||
setHasMore(res.data.data.list.length === 10)
|
||
}
|
||
} catch (error) {
|
||
console.error('加载更多失败', error)
|
||
}
|
||
}
|
||
|
||
return (
|
||
<View className="referral-page">
|
||
{/* 头部统计 */}
|
||
<View className="stats-section" style={{background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'}}>
|
||
<View className="stats-title">
|
||
<Text className="text-white text-lg font-bold">我的推荐奖励</Text>
|
||
</View>
|
||
<View className="stats-grid">
|
||
<View className="stat-item">
|
||
<Text className="stat-value text-white">{stats.totalCount}</Text>
|
||
<Text className="stat-label" style={{color: 'rgba(255,255,255,0.8)'}}>总推荐</Text>
|
||
</View>
|
||
<View className="stat-item">
|
||
<Text className="stat-value text-white">{stats.pendingCount}</Text>
|
||
<Text className="stat-label" style={{color: 'rgba(255,255,255,0.8)'}}>待确认</Text>
|
||
</View>
|
||
<View className="stat-item">
|
||
<Text className="stat-value text-white">{stats.validCount}</Text>
|
||
<Text className="stat-label" style={{color: 'rgba(255,255,255,0.8)'}}>有效</Text>
|
||
</View>
|
||
<View className="stat-item">
|
||
<Text className="stat-value text-white">¥{stats.pendingAmount.toFixed(2)}</Text>
|
||
<Text className="stat-label" style={{color: 'rgba(255,255,255,0.8)'}}>待结算</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 报备表单 */}
|
||
<View className="form-section">
|
||
<View className="section-title">
|
||
<Text className="font-bold text-gray-800">推荐新客户</Text>
|
||
</View>
|
||
<View className="form-card">
|
||
<CellGroup>
|
||
<Cell title="客户姓名">
|
||
<Input
|
||
className="nut-input-text"
|
||
placeholder="请输入客户姓名"
|
||
value={formData.customerName}
|
||
onInput={(e) => handleInput('customerName', e.detail.value)}
|
||
/>
|
||
</Cell>
|
||
<Cell title="联系电话">
|
||
<Input
|
||
className="nut-input-text"
|
||
type="number"
|
||
maxlength={11}
|
||
placeholder="请输入客户电话"
|
||
value={formData.customerPhone}
|
||
onInput={(e) => handleInput('customerPhone', e.detail.value)}
|
||
/>
|
||
</Cell>
|
||
<Cell title="公司名称">
|
||
<Input
|
||
className="nut-input-text"
|
||
placeholder="请输入公司名称(选填)"
|
||
value={formData.customerCompany}
|
||
onInput={(e) => handleInput('customerCompany', e.detail.value)}
|
||
/>
|
||
</Cell>
|
||
<Cell title="需求描述">
|
||
<Input
|
||
className="nut-input-text"
|
||
type="textarea"
|
||
placeholder="请描述客户需求(选填)"
|
||
value={formData.requirement}
|
||
onInput={(e) => handleInput('requirement', e.detail.value)}
|
||
style={{height: '80px', textAlign: 'left'}}
|
||
/>
|
||
</Cell>
|
||
</CellGroup>
|
||
|
||
<View className="submit-btn">
|
||
<Button
|
||
type="primary"
|
||
loading={submitting}
|
||
onClick={handleSubmit}
|
||
style={{
|
||
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||
border: 'none'
|
||
}}
|
||
>
|
||
提交报备
|
||
</Button>
|
||
</View>
|
||
|
||
<View className="tips">
|
||
<Text className="text-gray-500 text-sm">
|
||
报备成功后,业务员会尽快联系您的客户。成交后您将获得相应佣金奖励。
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
|
||
{/* 推荐记录 */}
|
||
<View className="records-section">
|
||
<View className="section-title">
|
||
<Text className="font-bold text-gray-800">我的推荐记录</Text>
|
||
</View>
|
||
|
||
{records.length === 0 ? (
|
||
<View className="empty-state">
|
||
<Text className="text-gray-400">暂无推荐记录</Text>
|
||
<Text className="text-gray-400 text-sm">快去推荐客户吧</Text>
|
||
</View>
|
||
) : (
|
||
<ScrollView
|
||
scrollY
|
||
onScrollToLower={loadMore}
|
||
style={{height: '300px'}}
|
||
>
|
||
{records.map((item) => {
|
||
const statusInfo = STATUS_MAP[item.referralStatus] || STATUS_MAP[0]
|
||
return (
|
||
<View key={item.referralId} className="record-card">
|
||
<View className="record-header">
|
||
<View className="customer-info">
|
||
<Text className="font-bold text-gray-800">{item.customerName}</Text>
|
||
<Text
|
||
className="text-blue-500 text-sm ml-2"
|
||
onClick={() => handleCall(item.customerPhone)}
|
||
>
|
||
{item.customerPhone}
|
||
</Text>
|
||
</View>
|
||
<View
|
||
className="status-tag"
|
||
style={{backgroundColor: statusInfo.color + '20', color: statusInfo.color}}
|
||
>
|
||
{statusInfo.text}
|
||
</View>
|
||
</View>
|
||
|
||
<View className="record-body">
|
||
<View className="record-row">
|
||
<Text className="text-gray-500 text-sm">推荐时间</Text>
|
||
<Text className="text-gray-700 text-sm">{item.createTime}</Text>
|
||
</View>
|
||
{item.referralFee > 0 && (
|
||
<View className="record-row">
|
||
<Text className="text-gray-500 text-sm">奖励金额</Text>
|
||
<Text className="text-red-500 font-bold text-sm">
|
||
¥{item.referralFee.toFixed(2)}
|
||
</Text>
|
||
</View>
|
||
)}
|
||
{item.leadStatusText && (
|
||
<View className="record-row">
|
||
<Text className="text-gray-500 text-sm">客户状态</Text>
|
||
<Text className="text-gray-700 text-sm">{item.leadStatusText}</Text>
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>
|
||
)
|
||
})}
|
||
|
||
{!hasMore && records.length > 0 && (
|
||
<View className="no-more">
|
||
<Text className="text-gray-400 text-sm">没有更多了</Text>
|
||
</View>
|
||
)}
|
||
</ScrollView>
|
||
)}
|
||
</View>
|
||
|
||
{/* 底部安全区 */}
|
||
<View className="h-20"></View>
|
||
</View>
|
||
)
|
||
}
|
||
|
||
export default ReferralPage
|