diff --git a/src/assets/business_basic/recent_bg.png b/src/assets/business_basic/recent_bg.png new file mode 100644 index 0000000..73c491a Binary files /dev/null and b/src/assets/business_basic/recent_bg.png differ diff --git a/src/assets/business_basic/top_icon1.svg b/src/assets/business_basic/top_icon1.svg new file mode 100644 index 0000000..ecbf192 --- /dev/null +++ b/src/assets/business_basic/top_icon1.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/business_basic/top_icon2.svg b/src/assets/business_basic/top_icon2.svg new file mode 100644 index 0000000..cd00919 --- /dev/null +++ b/src/assets/business_basic/top_icon2.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/assets/business_basic/top_icon3.svg b/src/assets/business_basic/top_icon3.svg new file mode 100644 index 0000000..d3c9243 --- /dev/null +++ b/src/assets/business_basic/top_icon3.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/assets/business_basic/top_icon4.svg b/src/assets/business_basic/top_icon4.svg new file mode 100644 index 0000000..1a34110 --- /dev/null +++ b/src/assets/business_basic/top_icon4.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/pages/business_basic/components/CustomerInfoManagement.js b/src/pages/business_basic/components/CustomerInfoManagement.js index 4dcec02..0e66b33 100644 --- a/src/pages/business_basic/components/CustomerInfoManagement.js +++ b/src/pages/business_basic/components/CustomerInfoManagement.js @@ -1,16 +1,25 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useMemo, useLayoutEffect } from 'react'; import * as echarts from 'echarts'; import styles from './CustomerInfoManagement.less'; +import { Select, Space, Button, Input } from 'antd'; +import { PlusOutlined, SearchOutlined, ReloadOutlined } from '@ant-design/icons'; +import StandardTable from '@/components/StandardTable'; +import topIcon from '@/assets/business_basic/top_icon1.svg'; +import topIcon2 from '@/assets/business_basic/top_icon2.svg'; +import topIcon3 from '@/assets/business_basic/top_icon3.svg'; +import topIcon4 from '@/assets/business_basic/top_icon4.svg'; import CustomerInfoManagementDetail from './CustomerInfoManagementDetail'; - const CustomerInfoManagement = () => { const [searchKeyword, setSearchKeyword] = useState(''); - const [customerType, setCustomerType] = useState('全部'); - const [customerLevel, setCustomerLevel] = useState('全部'); - const [cooperationStatus, setCooperationStatus] = useState('全部'); const [selectedRows, setSelectedRows] = useState([]); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); + // 列表筛选与数据(演示数据,可替换为接口) + const [filters, setFilters] = useState({ + customerType: '', + customerGrade: '', + cooperationStatus: '', + }); // 新增:详情页面切换状态 const [showDetail, setShowDetail] = useState(false); const [detailData, setDetailData] = useState(null); @@ -32,21 +41,27 @@ const CustomerInfoManagement = () => { // 客户类型分布图表配置 const customerTypeChartOption = { - title: { - text: '客户类型分布', - left: 'left', - textStyle: { - fontSize: 16, - fontWeight: 600, - }, - }, + // title: { + // text: '客户类型分布', + // left: 'left', + // textStyle: { + // fontSize: 16, + // fontWeight: 600, + // color: '#333', + // }, + // }, tooltip: { trigger: 'axis', axisPointer: { type: 'shadow', }, + backgroundColor: 'rgba(255,255,255,0.95)', + borderColor: '#e0e0e0', + borderWidth: 1, + textStyle: { color: '#333' }, }, grid: { + top: 16, left: '3%', right: '4%', bottom: '3%', @@ -57,23 +72,44 @@ const CustomerInfoManagement = () => { data: ['客户', '供应商', '第3周', '第4周'], axisLabel: { rotate: 0, + color: '#4E5856', }, + axisLine: { + lineStyle: { color: '#C9E3DE' }, + }, + axisTick: { show: false }, }, yAxis: { type: 'value', max: 100, + axisLine: { show: false }, + axisTick: { show: false }, + axisLabel: { color: '#4E5856' }, + splitLine: { + show: true, + lineStyle: { color: '#E9F3F1', type: 'dashed' }, + }, }, series: [ { name: '数量', type: 'bar', data: [56, 32, 85, 15], + barWidth: 26, itemStyle: { - color: '#1890ff', + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#7FC8B6' }, + { offset: 1, color: '#008F8E' }, + ]), + // barBorderRadius: [6, 6, 0, 0], + shadowColor: 'rgba(0,0,0,0.08)', + shadowBlur: 6, + shadowOffsetY: 2, }, label: { show: true, position: 'top', + color: '#4E5856', }, }, ], @@ -81,81 +117,113 @@ const CustomerInfoManagement = () => { // 客户价值分布环形图配置 const customerValueChartOption = { - title: { - text: '客户价值分布', - left: 'left', - textStyle: { - fontSize: 16, - fontWeight: 600, - }, - }, + // title: { + // text: '客户价值分布', + // left: 'left', + // textStyle: { + // fontSize: 16, + // fontWeight: 600, + // }, + // }, tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)', }, legend: { orient: 'vertical', - left: 'right', - top: 'middle', + right: '6%', + top: '32%', + itemWidth: 16, + itemHeight: 4, + itemGap: 16, + textStyle: { + fontSize: 12, + color: '#666', + fontWeight: 'normal' + } }, series: [ { name: '客户价值', type: 'pie', - radius: ['40%', '70%'], - avoidLabelOverlap: false, + radius: ['40%', '65%'], + center: ['30%', '50%'], + // avoidLabelOverlap: false, itemStyle: { - borderRadius: 10, - borderColor: '#fff', - borderWidth: 2, + // borderRadius: 10, + // borderColor: '#fff', + // borderWidth: 2, }, label: { show: false, }, - emphasis: { - label: { - show: true, - fontSize: 16, - fontWeight: 'bold', - }, - }, + // emphasis: { + // label: { + // show: true, + // fontSize: 16, + // fontWeight: 'bold', + // }, + // }, data: [ - { value: 180, name: '高价值客户', itemStyle: { color: '#5B9BD5' } }, - { value: 120, name: '中等客户', itemStyle: { color: '#FFC000' } }, - { value: 89, name: '小客户', itemStyle: { color: '#9E7CC1' } }, + { value: 180, name: '高价值客户', itemStyle: { color: '#5CB3FF' } }, + { value: 120, name: '中等客户', itemStyle: { color: '#FFDE73' } }, + { value: 89, name: '小客户', itemStyle: { color: '#A990EA' } }, ], }, ], }; - // 初始化图表 + // 图表初始化与销毁:根据详情模式切换,返回列表后重新初始化 useEffect(() => { - // 初始化客户类型分布图表 - if (customerTypeChartRef.current) { - customerTypeChartInstance.current = echarts.init(customerTypeChartRef.current); - customerTypeChartInstance.current.setOption(customerTypeChartOption); - } - - // 初始化客户价值分布图表 - if (customerValueChartRef.current) { - customerValueChartInstance.current = echarts.init(customerValueChartRef.current); - customerValueChartInstance.current.setOption(customerValueChartOption); - } + if (!showDetail) { + if (customerTypeChartRef.current) { + customerTypeChartInstance.current = echarts.init(customerTypeChartRef.current); + customerTypeChartInstance.current.setOption(customerTypeChartOption); + // 额外一次 resize,确保初始化后尺寸正确 + requestAnimationFrame(() => { + customerTypeChartInstance.current?.resize(); + }); + } + if (customerValueChartRef.current) { + customerValueChartInstance.current = echarts.init(customerValueChartRef.current); + customerValueChartInstance.current.setOption(customerValueChartOption); + // 额外一次 resize,确保初始化后尺寸正确 + requestAnimationFrame(() => { + customerValueChartInstance.current?.resize(); + }); + } - // 响应式调整 - const handleResize = () => { - customerTypeChartInstance.current?.resize(); - customerValueChartInstance.current?.resize(); - }; - window.addEventListener('resize', handleResize); + const handleResize = () => { + customerTypeChartInstance.current?.resize(); + customerValueChartInstance.current?.resize(); + }; + window.addEventListener('resize', handleResize); - // 清理函数 - return () => { - window.removeEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + customerTypeChartInstance.current?.dispose(); + customerTypeChartInstance.current = null; + customerValueChartInstance.current?.dispose(); + customerValueChartInstance.current = null; + }; + } else { + // 进入详情时,释放实例以避免无容器绑定 customerTypeChartInstance.current?.dispose(); + customerTypeChartInstance.current = null; customerValueChartInstance.current?.dispose(); - }; - }, []); + customerValueChartInstance.current = null; + } + }, [showDetail]); + + // 返回列表时恢复滚动位置,确保布局稳定后再滚动 + useLayoutEffect(() => { + if (!showDetail) { + // 等待本帧布局完成 + requestAnimationFrame(() => { + window.scrollTo(0, prevScrollY || 0); + }); + } + }, [showDetail]); // 最近活动数据 const recentActivities = [ @@ -239,6 +307,48 @@ const CustomerInfoManagement = () => { }, ]; + // 列配置(用于 StandardTable) + const columns = useMemo(() => { + return [ + { title: '客户名称', dataIndex: 'customerName', key: 'customerName', width: 220 }, + { title: '联系人', dataIndex: 'contact', key: 'contact', width: 120 }, + { title: '联系电话', dataIndex: 'phone', key: 'phone', width: 140 }, + { + title: '分类', dataIndex: 'classification', key: 'classification', width: 110, + render: (val) => ( + {val} + ) + }, + { + title: '交易额度(月)', dataIndex: 'monthlyAmount', key: 'monthlyAmount', width: 150, + render: (v) => `¥${Number(v).toLocaleString()}` + }, + { + title: '合作状态', dataIndex: 'cooperationStatus', key: 'cooperationStatus', width: 110, + render: (val) => ( + {val} + ) + }, + { + title: '满意度', dataIndex: 'satisfaction', key: 'satisfaction', width: 120, + }, + { + title: '操作', key: 'action', fixed: 'right', width: 200, + render: (_, row) => ( + + + + + + ) + }, + ]; + }, []); + // 处理选择 const handleSelectRow = (id) => { if (selectedRows.includes(id)) { @@ -262,7 +372,7 @@ const CustomerInfoManagement = () => { const stars = []; const fullStars = Math.floor(rating); const hasHalfStar = rating % 1 !== 0; - + for (let i = 0; i < fullStars; i++) { stars.push(); } @@ -282,7 +392,7 @@ const CustomerInfoManagement = () => { if (showDetail) { return (
-
+
@@ -304,286 +414,198 @@ const CustomerInfoManagement = () => { return (
- {/* KPI卡片区域 */} -
-
-
👥
-
{kpiData.totalCustomers}
-
总客户数
-
-
-
👑
-
{kpiData.highValueCustomers}
-
高价值客户
-
-
-
🤝
-
{kpiData.inCooperation}
-
合作中
-
-
-
-
{kpiData.newThisMonth}
-
本月新增
-
-
- - {/* 图表和活动区域 */} -
- {/* 客户类型分布图表 */} -
-
-
客户类型分布
- +
+ {/* KPI卡片区域 */} +
+
+
+
{kpiData.totalCustomers}
+
总客户数
+
+ icon
-
-
- - {/* 客户价值分布图表 */} -
-
-
客户价值分布
+
+
+
{kpiData.highValueCustomers}
+
高价值客户
+
+ icon
-
-
- - {/* 最近活动列表 */} -
-
-
最近活动
+
+
+
{kpiData.inCooperation}
+
合作中
+
+ icon
-
- {recentActivities.map((activity) => ( -
-
- {activity.id === 1 && '📄'} - {activity.id === 2 && '✅'} - {activity.id === 3 && '💬'} - {activity.id === 4 && '👤'} -
-
-
{activity.title}
-
{activity.description}
-
🕐 {activity.time}
-
-
- ))} +
+
+
{kpiData.newThisMonth}
+
本月新增
+
+ icon
-
- {/* 客户列表区域 */} -
-
-
客户列表
-
+ {/* 图表和活动区域 */} +
+ {/* 客户类型分布图表 */} +
+
+
客户类型分布
+ setSearchKeyword(e.target.value)} + {/* 客户价值分布图表 */} +
+
+
客户价值分布
+
+
- - - - - - -
-
- {/* 表格 */} -
- - - - - - - - - - - - - - - - {tableData.map((row) => ( - - - - - - - - - - - + {/* 最近活动列表 */} +
+
+
最近活动
+
+
+ {recentActivities.map((activity) => ( +
+
+
{activity.title}
+
{activity.time}
+
+
{activity.description}
+
))} -
-
- - 客户名称联系人联系电话分类交易额度(月)合作状态满意度操作
- handleSelectRow(row.id)} - /> - {row.customerName}{row.contact}{row.phone} - - {row.classification} - - ¥{row.monthlyAmount.toLocaleString()} - - {row.cooperationStatus} - - -
- {renderStars(row.satisfaction)} -
-
-
- - - -
-
+
+
- {/* 分页 */} -
-
- 共85条 - + {/* 客户列表区域 */} +
+
+ + 客户列表
-
- - {currentPage > 3 && ( - <> - - ... - - )} - {Array.from({ length: Math.min(5, totalPages) }, (_, i) => { - let pageNum; - if (currentPage <= 3) { - pageNum = i + 1; - } else if (currentPage >= totalPages - 2) { - pageNum = totalPages - 4 + i; - } else { - pageNum = currentPage - 2 + i; - } - if (pageNum > totalPages) return null; - return ( - - ); - })} - {currentPage < totalPages - 2 && ( - <> - ... - - - )} - +
+
+ setSearchKeyword(e.target.value)} + onSearch={(val) => setSearchKeyword(val)} + style={{ minWidth: 150 }} + /> +
+
+ 客户类型: + setFilters({ ...filters, customerGrade: v })} + placeholder="全部" + options={[ + { label: '全部', value: '' }, + ]} + allowClear + /> +
+
+ 合作状态: +