feat(referral): 添加推荐客户功能及相关接口
- 新增小程序端推荐客户页面,实现客户信息报备功能 - 添加推荐客户统计与推荐记录展示,支持分页加载更多 - 实现手机号格式校验及报备表单提交逻辑 - 新增拨打客户电话功能 - 在分销商首页添加“推荐客户”入口菜单项 - 新增推荐客户相关API接口,包括报备、查询列表、统计及状态更新 - 完善推荐客户页面样式,提升用户体验
This commit is contained in:
@@ -11,7 +11,18 @@
|
|||||||
"usedAt": 1775709039214,
|
"usedAt": 1775709039214,
|
||||||
"industryId": "all"
|
"industryId": "all"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"2d8018ea3c7f4b92a608c23c2ee6211a": [
|
||||||
|
{
|
||||||
|
"expertId": "SeniorDeveloper",
|
||||||
|
"name": "Will",
|
||||||
|
"profession": "高级开发工程师",
|
||||||
|
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/SeniorDeveloper/SeniorDeveloper.png",
|
||||||
|
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/SeniorDeveloper/SeniorDeveloper_zh.md",
|
||||||
|
"usedAt": 1776102350082,
|
||||||
|
"industryId": "all"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lastUpdated": 1775713542885
|
"lastUpdated": 1776103090047
|
||||||
}
|
}
|
||||||
42
.workbuddy/memory/2026-04-14.md
Normal file
42
.workbuddy/memory/2026-04-14.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# 2026-04-14 日志
|
||||||
|
|
||||||
|
## 项目:客资管理系统(Customer Lead Management System)
|
||||||
|
|
||||||
|
### 需求背景
|
||||||
|
用户委托开发一个客资管理系统,具备以下功能:
|
||||||
|
1. **客资派单** - 管理员直接派单给业务员
|
||||||
|
2. **全民推荐** - 任何人可推荐客户赚取推荐费
|
||||||
|
3. **推荐人报备** - 注册用户可报备客户
|
||||||
|
4. **实时跟进** - 实时查看跟进情况和成交状态
|
||||||
|
5. **多管理员** - 支持多管理员设置
|
||||||
|
6. **数据统计导出** - 统计报表功能
|
||||||
|
|
||||||
|
### 涉及项目
|
||||||
|
- Java后端: `/Users/gxwebsoft/JAVA/mp-java`
|
||||||
|
- Vue后台管理: `/Users/gxwebsoft/VUE/mp-vue`
|
||||||
|
- 小程序端: `/Users/gxwebsoft/VUE/template-10582`
|
||||||
|
|
||||||
|
### 状态
|
||||||
|
- [x] 探索代码结构
|
||||||
|
- [x] 设计数据库schema
|
||||||
|
- [x] 设计API接口
|
||||||
|
- [x] 实施开发
|
||||||
|
|
||||||
|
### 实施成果
|
||||||
|
|
||||||
|
#### Java后端 (`/Users/gxwebsoft/JAVA/mp-java`)
|
||||||
|
- SQL脚本: `docs/sql/customer_lead_system.sql`
|
||||||
|
- Entity: CustomerLeadEntity, LeadDispatch, LeadFollowLog, LeadReferral, LeadStatistics, UserRoleExtend
|
||||||
|
- Mapper: CustomerLeadMapper, LeadDispatchMapper, LeadFollowLogMapper, LeadReferralMapper
|
||||||
|
- Service: CustomerLeadService, LeadReferralService
|
||||||
|
- Controller: CustomerLeadController, LeadReferralController
|
||||||
|
- 总结文档: `docs/ai/customer-lead-system-summary.md`
|
||||||
|
|
||||||
|
#### Vue后台 (`/Users/gxwebsoft/VUE/mp-vue`)
|
||||||
|
- API: `api/cms/customerLead/index.ts`, `model.ts`
|
||||||
|
- 页面: `views/cms/customerLead/index.vue`
|
||||||
|
|
||||||
|
#### 小程序端 (`/Users/gxwebsoft/VUE/template-10582`)
|
||||||
|
- API: `api/shop/referral.ts`
|
||||||
|
- 页面: `dealer/referral/index.tsx`
|
||||||
|
- 首页入口: 在分销商首页添加「推荐客户」功能
|
||||||
135
src/api/shop/referral.ts
Normal file
135
src/api/shop/referral.ts
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* 客资推荐人 API
|
||||||
|
* 小程序端调用
|
||||||
|
*/
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐人报备参数
|
||||||
|
*/
|
||||||
|
export interface ReferralParam {
|
||||||
|
customerName: string
|
||||||
|
customerPhone: string
|
||||||
|
customerCompany?: string
|
||||||
|
requirement?: string
|
||||||
|
appointmentTime?: string
|
||||||
|
remarks?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐人报备结果
|
||||||
|
*/
|
||||||
|
export interface ReferralResult {
|
||||||
|
referralId: number
|
||||||
|
referralCode: string
|
||||||
|
customerName: string
|
||||||
|
customerPhone: string
|
||||||
|
referralFee?: number
|
||||||
|
referralStatus: number
|
||||||
|
referralStatusText: string
|
||||||
|
createTime: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐人统计
|
||||||
|
*/
|
||||||
|
export interface ReferralStats {
|
||||||
|
totalCount: number
|
||||||
|
pendingCount: number
|
||||||
|
validCount: number
|
||||||
|
settledCount: number
|
||||||
|
pendingAmount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐人记录
|
||||||
|
*/
|
||||||
|
export interface ReferralRecord {
|
||||||
|
referralId: number
|
||||||
|
referredLeadId: number
|
||||||
|
customerName: string
|
||||||
|
customerPhone: string
|
||||||
|
referralFee: number
|
||||||
|
referralStatus: number
|
||||||
|
referralStatusText: string
|
||||||
|
leadStatus?: number
|
||||||
|
leadStatusText?: string
|
||||||
|
dealAmount?: number
|
||||||
|
createTime: string
|
||||||
|
settlementTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册用户报备客户
|
||||||
|
*/
|
||||||
|
export function addReferral(data: ReferralParam) {
|
||||||
|
return request.post<{ code: number; message: string; data: ReferralResult }>(
|
||||||
|
'/lead/referral/user',
|
||||||
|
data
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取推荐人的推荐记录
|
||||||
|
*/
|
||||||
|
export function getReferralList(params: { pageNum?: number; pageSize?: number }) {
|
||||||
|
return request.get<{ code: number; message: string; data: { list: ReferralRecord[]; total: number } }>(
|
||||||
|
'/lead/referral/page',
|
||||||
|
{ params }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取推荐人统计
|
||||||
|
*/
|
||||||
|
export function getReferralStats(userId: number) {
|
||||||
|
return request.get<{ code: number; message: string; data: ReferralStats }>(
|
||||||
|
`/lead/referral/stats/${userId}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成推荐码
|
||||||
|
*/
|
||||||
|
export function generateReferralCode() {
|
||||||
|
return request.get<{ code: number; message: string; data: string }>(
|
||||||
|
'/lead/referral/generateCode'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前用户的推荐码
|
||||||
|
*/
|
||||||
|
export function getMyReferralCode() {
|
||||||
|
return request.get<{ code: number; message: string; data: { referralCode: string } }>(
|
||||||
|
'/lead/referral/my/code'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认推荐有效(管理员)
|
||||||
|
*/
|
||||||
|
export function confirmReferral(referralId: number) {
|
||||||
|
return request.put<{ code: number; message: string }>(
|
||||||
|
`/lead/referral/confirm/${referralId}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作废推荐(管理员)
|
||||||
|
*/
|
||||||
|
export function invalidateReferral(referralId: number, reason?: string) {
|
||||||
|
return request.put<{ code: number; message: string }>(
|
||||||
|
`/lead/referral/invalidate/${referralId}`,
|
||||||
|
{ reason }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算推荐费(管理员)
|
||||||
|
*/
|
||||||
|
export function settleReferral(referralId: number) {
|
||||||
|
return request.put<{ code: number; message: string }>(
|
||||||
|
`/lead/referral/settle/${referralId}`
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@ import {
|
|||||||
QrCode,
|
QrCode,
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
Purse,
|
Purse,
|
||||||
People
|
People,
|
||||||
|
Service
|
||||||
} from '@nutui/icons-react-taro'
|
} from '@nutui/icons-react-taro'
|
||||||
import {useDealerUser} from '@/hooks/useDealerUser'
|
import {useDealerUser} from '@/hooks/useDealerUser'
|
||||||
import {useThemeStyles} from '@/hooks/useTheme'
|
import {useThemeStyles} from '@/hooks/useTheme'
|
||||||
@@ -250,6 +251,14 @@ const DealerIndex: React.FC = () => {
|
|||||||
</View>
|
</View>
|
||||||
</Grid.Item>
|
</Grid.Item>
|
||||||
|
|
||||||
|
<Grid.Item text={'推荐客户'} onClick={() => navigateToPage('/dealer/referral/index')}>
|
||||||
|
<View className="text-center">
|
||||||
|
<View className="w-12 h-12 bg-pink-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||||
|
<Service color="#ec4899" size="20"/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Grid.Item>
|
||||||
|
|
||||||
<Grid.Item text={'我的邀请码'} onClick={() => navigateToPage('/dealer/qrcode/index')}>
|
<Grid.Item text={'我的邀请码'} onClick={() => navigateToPage('/dealer/qrcode/index')}>
|
||||||
<View className="text-center">
|
<View className="text-center">
|
||||||
<View className="w-12 h-12 bg-orange-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
<View className="w-12 h-12 bg-orange-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||||
|
|||||||
3
src/dealer/referral/index.config.ts
Normal file
3
src/dealer/referral/index.config.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"navigationBarTitleText": "推荐客户赚佣金"
|
||||||
|
}
|
||||||
132
src/dealer/referral/index.scss
Normal file
132
src/dealer/referral/index.scss
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
.referral-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f5f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-section {
|
||||||
|
padding: 24px 16px;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.stats-title {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
padding: 0 16px 16px;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 8px 0;
|
||||||
|
|
||||||
|
.nut-input-text {
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 8px;
|
||||||
|
height: 44px;
|
||||||
|
line-height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips {
|
||||||
|
padding: 0 16px 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.records-section {
|
||||||
|
padding: 0 16px 16px;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 40px;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.record-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.customer-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-body {
|
||||||
|
.record-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-more {
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
323
src/dealer/referral/index.tsx
Normal file
323
src/dealer/referral/index.tsx
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
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, getReferralList, getReferralStats} from '@/api/shop/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 getReferralStats(dealerUser.userId)
|
||||||
|
if (statsRes.data.code === 0) {
|
||||||
|
setStats(statsRes.data.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取列表
|
||||||
|
const listRes = await getReferralList({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 getReferralList({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
|
||||||
Reference in New Issue
Block a user