feat(dealer): 实现客户报备功能
- 新增客户报备页面,包括表单提交和审核状态显示 - 修改客户列表页面,增加签约和取消操作- 更新客户状态标签样式 - 调整API基础URL
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
export const ENV_CONFIG = {
|
||||
// 开发环境
|
||||
development: {
|
||||
API_BASE_URL: 'https://cms-api.websoft.top/api',
|
||||
API_BASE_URL: 'http://127.0.0.1:9200/api',
|
||||
APP_NAME: '开发环境',
|
||||
DEBUG: 'true',
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PageParam } from '@/api/index';
|
||||
import type { PageParam } from '@/api';
|
||||
|
||||
/**
|
||||
* 分销商申请记录表
|
||||
@@ -10,6 +10,14 @@ export interface ShopDealerApply {
|
||||
userId?: number;
|
||||
// 姓名
|
||||
realName?: string;
|
||||
// 分销商名称
|
||||
dealerName?: string;
|
||||
// 分销商编号
|
||||
dealerCode?: string;
|
||||
// 详细地址
|
||||
address?: string;
|
||||
// 金额
|
||||
money?: number;
|
||||
// 手机号
|
||||
mobile?: string;
|
||||
// 推荐人用户ID
|
||||
|
||||
@@ -64,6 +64,7 @@ export default defineAppConfig({
|
||||
"invite-stats/index",
|
||||
"info",
|
||||
"customer/index",
|
||||
"customer/add"
|
||||
]
|
||||
},
|
||||
// {
|
||||
|
||||
4
src/dealer/customer/add.config.ts
Normal file
4
src/dealer/customer/add.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '客户报备',
|
||||
navigationBarTextStyle: 'black'
|
||||
})
|
||||
209
src/dealer/customer/add.tsx
Normal file
209
src/dealer/customer/add.tsx
Normal file
@@ -0,0 +1,209 @@
|
||||
import {useEffect, useState, useRef} from "react";
|
||||
import {Loading, CellGroup, Cell, Input, Form} from '@nutui/nutui-react-taro'
|
||||
import {Edit} from '@nutui/icons-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {View} from '@tarojs/components'
|
||||
import FixedButton from "@/components/FixedButton";
|
||||
import {useUser} from "@/hooks/useUser";
|
||||
import {ShopDealerApply} from "@/api/shop/shopDealerApply/model";
|
||||
import {
|
||||
addShopDealerApply,
|
||||
pageShopDealerApply,
|
||||
updateShopDealerApply
|
||||
} from "@/api/shop/shopDealerApply";
|
||||
import {getShopDealerUser} from "@/api/shop/shopDealerUser";
|
||||
|
||||
const AddUserAddress = () => {
|
||||
const {user} = useUser()
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
const [FormData, setFormData] = useState<ShopDealerApply>()
|
||||
const formRef = useRef<any>(null)
|
||||
const [isEditMode, setIsEditMode] = useState<boolean>(false)
|
||||
const [existingApply, setExistingApply] = useState<ShopDealerApply | null>(null)
|
||||
|
||||
// 获取审核状态文字
|
||||
const getApplyStatusText = (status?: number) => {
|
||||
switch (status) {
|
||||
case 10:
|
||||
return '待审核'
|
||||
case 20:
|
||||
return '审核通过'
|
||||
case 30:
|
||||
return '驳回'
|
||||
default:
|
||||
return '未知状态'
|
||||
}
|
||||
}
|
||||
|
||||
const reload = async () => {
|
||||
// 判断用户是否登录
|
||||
if (!user?.userId) {
|
||||
return false;
|
||||
}
|
||||
// 查询当前用户ID是否已有申请记录
|
||||
try {
|
||||
const res = await pageShopDealerApply({});
|
||||
if (res && res.count > 0) {
|
||||
setIsEditMode(true);
|
||||
setExistingApply(res.list[0]);
|
||||
// 如果有记录,填充表单数据
|
||||
setFormData(res.list[0]);
|
||||
setLoading(false)
|
||||
} else {
|
||||
setIsEditMode(false);
|
||||
setExistingApply(null);
|
||||
setLoading(false)
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(true)
|
||||
console.error('查询申请记录失败:', error);
|
||||
setIsEditMode(false);
|
||||
setExistingApply(null);
|
||||
}
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const submitSucceed = async (values: any) => {
|
||||
try {
|
||||
|
||||
// 准备提交的数据
|
||||
const submitData = {
|
||||
...values,
|
||||
realName: values.realName || user?.nickname,
|
||||
mobile: user?.phone,
|
||||
refereeId: values.refereeId || FormData?.refereeId,
|
||||
applyStatus: 10,
|
||||
auditTime: undefined
|
||||
};
|
||||
await getShopDealerUser(submitData.refereeId);
|
||||
|
||||
// 如果是编辑模式,添加现有申请的id
|
||||
if (isEditMode && existingApply?.applyId) {
|
||||
submitData.applyId = existingApply.applyId;
|
||||
}
|
||||
|
||||
// 执行新增或更新操作
|
||||
if (isEditMode) {
|
||||
await updateShopDealerApply(submitData);
|
||||
} else {
|
||||
await addShopDealerApply(submitData);
|
||||
}
|
||||
|
||||
Taro.showToast({
|
||||
title: `${isEditMode ? '提交' : '提交'}成功`,
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
Taro.navigateBack();
|
||||
}, 1000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('验证邀请人失败:', error);
|
||||
return Taro.showToast({
|
||||
title: '邀请人ID不存在',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 处理固定按钮点击事件
|
||||
const handleFixedButtonClick = () => {
|
||||
// 触发表单提交
|
||||
formRef.current?.submit();
|
||||
};
|
||||
|
||||
const submitFailed = (error: any) => {
|
||||
console.log(error, 'err...')
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
reload().then(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}, [user?.userId]); // 依赖用户ID,当用户变化时重新加载
|
||||
|
||||
if (loading) {
|
||||
return <Loading className={'px-2'}>加载中</Loading>
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form
|
||||
ref={formRef}
|
||||
divider
|
||||
initialValues={FormData}
|
||||
labelPosition="left"
|
||||
onFinish={(values) => submitSucceed(values)}
|
||||
onFinishFailed={(errors) => submitFailed(errors)}
|
||||
>
|
||||
<View className={'bg-gray-100 h-3'}></View>
|
||||
<CellGroup style={{padding: '4px 0'}}>
|
||||
<Form.Item name="dealerName" label="公司名称" initialValue={FormData?.dealerName} required>
|
||||
<Input placeholder="公司名称" maxLength={10}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="realName" label="联系人" initialValue={FormData?.realName} required>
|
||||
<Input placeholder="请输入联系人" disabled={true}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="mobile" label="联系方式" initialValue={FormData?.mobile} required>
|
||||
<Input placeholder="请输入手机号" disabled={true} maxLength={11}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="address" label="公司地址" initialValue={FormData?.address} required>
|
||||
<Input placeholder="请输入详细地址" disabled={true}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="dealerCode" label="户号" initialValue={FormData?.dealerCode} required>
|
||||
<Input placeholder="请填写户号" disabled={true}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="money" label="签约价格" initialValue={FormData?.money} required>
|
||||
<Input placeholder="请按合同填写签约价格" disabled={true}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="applyTime" label="签约时间" initialValue={FormData?.applyTime} required>
|
||||
<Input placeholder="请选择签约时间" disabled={true}/>
|
||||
</Form.Item>
|
||||
<Form.Item name="applyTime" label="合同日期" initialValue={FormData?.applyTime} required>
|
||||
<Input placeholder="请选择合同生效起止时间" disabled={true}/>
|
||||
</Form.Item>
|
||||
{/*<Form.Item name="refereeId" label="邀请人ID" initialValue={FormData?.refereeId} required>*/}
|
||||
{/* <Input placeholder="邀请人ID"/>*/}
|
||||
{/*</Form.Item>*/}
|
||||
</CellGroup>
|
||||
</Form>
|
||||
{/* 审核状态显示(仅在编辑模式下显示) */}
|
||||
{isEditMode && (
|
||||
<CellGroup>
|
||||
<Cell
|
||||
title={'审核状态'}
|
||||
extra={
|
||||
<span style={{
|
||||
color: FormData?.applyStatus === 20 ? '#52c41a' :
|
||||
FormData?.applyStatus === 30 ? '#ff4d4f' : '#faad14'
|
||||
}}>
|
||||
{getApplyStatusText(FormData?.applyStatus)}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
{FormData?.applyStatus === 20 && (
|
||||
<Cell title={'审核时间'} extra={FormData?.auditTime || '无'}/>
|
||||
)}
|
||||
{FormData?.applyStatus === 30 && (
|
||||
<Cell title={'驳回原因'} extra={FormData?.rejectReason || '无'}/>
|
||||
)}
|
||||
</CellGroup>
|
||||
)}
|
||||
|
||||
|
||||
{/* 底部浮动按钮 */}
|
||||
{(!isEditMode || FormData?.applyStatus === 10 || FormData?.applyStatus === 30) && (
|
||||
<FixedButton
|
||||
icon={<Edit/>}
|
||||
text={isEditMode ? '保存修改' : '提交申请'}
|
||||
disabled={FormData?.applyStatus === 10}
|
||||
onClick={handleFixedButtonClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddUserAddress;
|
||||
@@ -1,27 +1,29 @@
|
||||
import React, {useState, useEffect, useCallback} from 'react'
|
||||
import {useState, useEffect, useCallback} from 'react'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import {Loading, Tabs, TabPane, Tag} from '@nutui/nutui-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {Loading, Space, Tabs, TabPane, Tag, Button} from '@nutui/nutui-react-taro'
|
||||
import {Phone} from '@nutui/icons-react-taro'
|
||||
import {pageUsers} from "@/api/system/user";
|
||||
import type {User as UserType} from "@/api/system/user/model";
|
||||
import type {ShopDealerApply, ShopDealerApply as UserType} from "@/api/shop/shopDealerApply/model";
|
||||
import {
|
||||
CustomerStatus,
|
||||
getStatusText,
|
||||
getStatusTagType,
|
||||
getRandomStatus,
|
||||
getStatusOptions
|
||||
} from '@/utils/customerStatus';
|
||||
import FixedButton from "@/components/FixedButton";
|
||||
import navTo from "@/utils/common";
|
||||
import {pageShopDealerApply, updateShopDealerApply} from "@/api/shop/shopDealerApply";
|
||||
|
||||
// 扩展User类型,添加客户状态
|
||||
interface CustomerUser extends UserType {
|
||||
customerStatus?: CustomerStatus;
|
||||
}
|
||||
|
||||
const CustomerManagement: React.FC = () => {
|
||||
const CustomerIndex = () => {
|
||||
const [list, setList] = useState<CustomerUser[]>([])
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [activeTab, setActiveTab] = useState<CustomerStatus>('all')
|
||||
const [searchValue, setSearchValue] = useState<string>('')
|
||||
const [searchValue, _] = useState<string>('')
|
||||
|
||||
// Tab配置
|
||||
const tabList = getStatusOptions();
|
||||
@@ -30,15 +32,24 @@ const CustomerManagement: React.FC = () => {
|
||||
const fetchCustomerData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// 获取用户列表,status: 0 表示正常状态
|
||||
const res = await pageUsers({ status: 0 });
|
||||
const res = await pageShopDealerApply({});
|
||||
if (res?.list) {
|
||||
// 为每个用户添加随机的客户状态(实际项目中应该从后端获取真实状态)
|
||||
const customersWithStatus: CustomerUser[] = res.list.map(user => ({
|
||||
...user,
|
||||
customerStatus: getRandomStatus() // 临时使用随机状态,实际应该从数据库获取
|
||||
}));
|
||||
setList(customersWithStatus);
|
||||
list.map(d => {
|
||||
if(d.applyStatus == 10){
|
||||
d.customerStatus = 'pending'
|
||||
}
|
||||
if(d.applyStatus == 20){
|
||||
d.customerStatus = 'signed'
|
||||
}
|
||||
if(d.applyStatus == 30){
|
||||
d.customerStatus = 'cancelled'
|
||||
}
|
||||
return {
|
||||
...d,
|
||||
customerStatus: d.applyStatus == 10 ? 'pending' : 'signed'
|
||||
}
|
||||
})
|
||||
setList(res.list);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取客户数据失败:', error);
|
||||
@@ -48,13 +59,18 @@ const CustomerManagement: React.FC = () => {
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
// 根据当前Tab和搜索条件筛选数据
|
||||
const getFilteredList = () => {
|
||||
console.log('TABS',activeTab)
|
||||
let filteredList = list;
|
||||
|
||||
// 按状态筛选
|
||||
if (activeTab !== 'all') {
|
||||
console.log(filteredList,'customerStatus')
|
||||
filteredList.map(d => {
|
||||
console.log(d.applyStatus)
|
||||
})
|
||||
|
||||
filteredList = filteredList.filter(customer => customer.customerStatus === activeTab);
|
||||
}
|
||||
|
||||
@@ -63,9 +79,9 @@ const CustomerManagement: React.FC = () => {
|
||||
const keyword = searchValue.trim().toLowerCase();
|
||||
filteredList = filteredList.filter(customer =>
|
||||
(customer.realName && customer.realName.toLowerCase().includes(keyword)) ||
|
||||
(customer.nickname && customer.nickname.toLowerCase().includes(keyword)) ||
|
||||
(customer.username && customer.username.toLowerCase().includes(keyword)) ||
|
||||
(customer.phone && customer.phone.includes(keyword)) ||
|
||||
(customer.dealerName && customer.dealerName.toLowerCase().includes(keyword)) ||
|
||||
(customer.dealerCode && customer.dealerCode.toLowerCase().includes(keyword)) ||
|
||||
(customer.mobile && customer.mobile.includes(keyword)) ||
|
||||
(customer.userId && customer.userId.toString().includes(keyword))
|
||||
);
|
||||
}
|
||||
@@ -91,6 +107,16 @@ const CustomerManagement: React.FC = () => {
|
||||
return counts;
|
||||
};
|
||||
|
||||
// 取消操作
|
||||
const handleCancel = (customer: ShopDealerApply) => {
|
||||
updateShopDealerApply({
|
||||
...customer,
|
||||
applyStatus: 30
|
||||
}).then(r => {
|
||||
console.log(r)
|
||||
})
|
||||
};
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
fetchCustomerData();
|
||||
@@ -103,7 +129,7 @@ const CustomerManagement: React.FC = () => {
|
||||
<View className="flex-1">
|
||||
<View className="flex items-center justify-between mb-1">
|
||||
<Text className="font-semibold text-gray-800 mr-2">
|
||||
{customer.realName || customer.nickname || customer.username}
|
||||
{customer.realName || customer.dealerName || customer.dealerCode}
|
||||
</Text>
|
||||
{customer.customerStatus && (
|
||||
<Tag type={getStatusTagType(customer.customerStatus)}>
|
||||
@@ -112,16 +138,37 @@ const CustomerManagement: React.FC = () => {
|
||||
)}
|
||||
</View>
|
||||
<View className="flex items-center mb-1">
|
||||
<Phone size={12} className="mr-1" />
|
||||
<Text className="text-xs text-gray-500">
|
||||
{customer.phone || '未填写'}
|
||||
</Text>
|
||||
<Space direction="vertical">
|
||||
<Text className="text-xs text-gray-500">联系人:{customer.realName}</Text>
|
||||
<Text className="text-xs text-gray-500">联系电话:{customer.mobile}<Phone size={12}
|
||||
className="ml-1 text-green-500"/></Text>
|
||||
</Space>
|
||||
</View>
|
||||
<Text className="text-xs text-gray-500">
|
||||
注册时间:{customer.createTime}
|
||||
添加时间:{customer.createTime}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 跟进中状态显示操作按钮 */}
|
||||
{customer.applyStatus === 10 && (
|
||||
<Space className="flex justify-end">
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => navTo(`/dealer/customer/add?id=${customer.applyId}`, true)}
|
||||
style={{marginRight: '8px', backgroundColor: '#52c41a', color: 'white'}}
|
||||
>
|
||||
签约
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => handleCancel(customer)}
|
||||
style={{backgroundColor: '#ff4d4f', color: 'white'}}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</Space>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -131,10 +178,10 @@ const CustomerManagement: React.FC = () => {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View className="flex items-center justify-center py-8">
|
||||
<Loading />
|
||||
<Space className="flex items-center justify-center py-8">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||||
</View>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -155,6 +202,7 @@ const CustomerManagement: React.FC = () => {
|
||||
|
||||
return (
|
||||
<View className="min-h-screen bg-gray-50">
|
||||
|
||||
{/* 顶部Tabs */}
|
||||
<View className="bg-white">
|
||||
<Tabs
|
||||
@@ -177,8 +225,10 @@ const CustomerManagement: React.FC = () => {
|
||||
|
||||
{/* 客户列表 */}
|
||||
{renderCustomerList()}
|
||||
|
||||
<FixedButton text={'客户报备'} onClick={() => Taro.navigateTo({url: '/dealer/customer/add'})}/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomerManagement;
|
||||
export default CustomerIndex;
|
||||
|
||||
@@ -24,8 +24,8 @@ export const CUSTOMER_STATUS_CONFIG = {
|
||||
},
|
||||
cancelled: {
|
||||
label: '已取消',
|
||||
color: '#ff4d4f',
|
||||
tagType: 'danger' as const
|
||||
color: '#999999',
|
||||
tagType: 'default' as const
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user