一、功能定位
该功能用于数据统计卡片的 "同比 / 环比比较展示",适配 "对话次数、发起需求、职位发布、平均时间、筛选次数、合格候选人、人才简历库"7 类核心业务数据,支持 "全部时间、周、月"3 种时间维度切换,最终在前端卡片中显示 "较上周 / 较上月" 的数值变化,并通过颜色区分数值正负,帮助用户快速识别数据趋势。
二、核心逻辑要点
1.时间维度适配规则
- 当时间维度选择 "all(全部时间)" 时:不显示任何比较数据(返回空字符串);
- 当选择 "week(本周)" 时:比较文案前缀固定为 "较上周";
- 当选择 "month(本月)" 时:比较文案前缀固定为 "较上月"。
2.数据类型与单位匹配
按数据类别区分数值类型、单位,确保展示符合业务认知:
|-------|-------------|-----|--------------|-------------|
| 数据类别 | 数据类型(比较值) | 单位 | 示例(正数) | 示例(负数) |
| 对话次数 | number | 次 | 较上周 +5 次 | 较上周 -3 次 |
| 发起需求 | number | 次 | 较上月 +5 次 | 较上周 -8 次 |
| 职位发布 | number | 个 | 较上周 +12 个 | 较上月 -30 个 |
| 平均时间 | string(含数值) | min | 较上周 +2.2 min | 较上周 -3.3min |
| 筛选次数 | number | 次 | 较上周 +6 次 | 较上周 -3 次 |
| 合格候选人 | number | 人 | 较上周 +1 人 | 较上月 -3 次 |
| 人才简历库 | number | 个 | 较上周 +5 个 | 较上周 -2 次 |
3.正负值处理规则
- 数值类型(前 3 类数据):
- 大于 0:前缀加 "+"(如 "较上周 +3 次"),显示绿色(rgb (22, 163, 74));
- 小于 0:直接显示负值(如 "较上周 -2 个"),显示红色(rgb (220, 38, 38));
- 等于0:直接显示(如"较上周 0 次"),显示绿色(默认正向色)
- 字符串类型(平均时间):
- 先将字符串转为数值判断正负,正数加 "+",显示(如"较上周 + 2.5min"),负数直接显示(如字符串 "-2.5" 转为 - 2.5,显示 "较上周 -2.5min",显示红色(rgb (220, 38, 38))),0直接显示"较上周 0min"。
三、组件交互与实现
在ShowCountCard组件调用时,需传入对应 "数据类型标识":
<Spin spinning={loading}>
{coreData && <Flex gap={10}>
<ShowCountCard title="对话次数" countTitle={`${coreData.conversationCount || 0}次`} JDCompareNum={getCompareNum(coreData, 'conversation')} />
<ShowCountCard title="发起需求" countTitle={`${coreData.demandInitiatedCount || 0}次`} JDCompareNum={getCompareNum(coreData, 'demand')} />
<ShowCountCard title="职位发布" countTitle={`${coreData.positionPostedCount || 0}个`} JDCompareNum={getCompareNum(coreData, 'position')} />
<ShowCountCard title="平均时间" countTitle={`${coreData.averageTime || '0'}min`} JDCompareNum={getCompareNum(coreData, 'time')} />
</Flex>}
</Spin>
<Spin spinning={loading}>
{coreData && <Flex gap={10}>
<ShowCountCard title="筛选次数" countTitle={`${coreData.screeningCount || 0}次`} resumeNum={getCompareNum(coreData, 'screening')} />
<ShowCountCard title="合格候选人" countTitle={`${coreData.qualifiedCandidateCount || 0}人`} resumeNum={getCompareNum(coreData, 'qualifiedCandidate')} />
<ShowCountCard title="人才库简历" countTitle={`${coreData.talentPoolResumeCount || 0}个`} resumeNum={getCompareNum(coreData, 'resume')} />
{/* <ShowCountCard title="面试汇总次数" countTitle={`${coreData.interviewSummariesTotal || 0}次`} /> */}
</Flex>}
</Spin>
数据传递 :通过getCompareNum
函数返回包含text
(显示文本)和color
(颜色值)的对象
const getCompareNum = (coreData: CoreModel, type: 'conversation' | 'demand' | 'position' | 'time' | 'screening' | 'qualifiedCandidate' | 'resume') => {
if (dateType === "all") {
return { text: "", color: "" };
}
let compareValue;
let unit;
switch (type) {
case 'conversation':
compareValue = coreData.conversationCountCompare;
unit = '次';
break;
case 'demand':
compareValue = coreData.demandInitiatedCountCompare;
unit = '次';
break;
case 'position':
compareValue = coreData.positionPostedCountCompare;
unit = '个';
break;
case 'time':
compareValue = coreData.averageTimeCompare;
break;
case 'screening':
compareValue = coreData.screeningCountCompare;
unit = '次';
break;
case 'qualifiedCandidate':
compareValue = coreData.qualifiedCandidateCountCompare;
unit = '个';
break;
case 'resume':
compareValue = coreData.talentPoolResumeCountCompare;
unit = '个';
break;
default:
return { text: "", color: "" };
}
const timePrefix = dateType === "week" ? "较上周" : "较上月";
let text = "";
let isNegative = false;
if (typeof compareValue === 'number') {
text = compareValue > 0
? `${timePrefix} +${compareValue}${unit}`
: `${timePrefix} ${compareValue}${unit}`;
isNegative = compareValue < 0;
}
if (typeof compareValue === 'string') {
const numValue = parseFloat(compareValue);
if (!isNaN(numValue)) {
text = numValue > 0
? `${timePrefix} +${compareValue}min`
: `${timePrefix} ${compareValue}min`;
isNegative = numValue < 0;
}
}
const color = isNegative ? "rgb(220, 38, 38)" : "rgb(22, 163, 74)";
return { text, color };
};
组件渲染 :ShowCountCard
组件接收上述对象,将颜色样式直接应用于比较数值元素
import styles from './styles.module.scss'
import { Card, Flex, Progress } from 'antd';
const ShowCountCard = ({ title, countTitle, compare, processTitle, processSubtitle, processTitleNum, processSubtitleNum, percent, modelNum, modelMonthNum, JDCompareNum, resumeNum }: { title: string, countTitle?: string, compare?: string, processTitle?: string, processSubtitle?: string, processTitleNum?: number, processSubtitleNum?: number, percent?: number, modelNum?: string, modelMonthNum?: string, JDCompareNum?: { text: string, color: string },resumeNum?: { text: string, color: string }}) => {
return (
<Flex vertical justify='space-between' className={styles.showCountCard}>
<div>{title}</div>
{countTitle && <div className={styles.cardCount}>{countTitle}</div>}
{compare && <div className={styles.cardCompare}>{compare}</div>}
{modelNum && <div className={styles.cardModelNum}>{modelNum}</div>}
{modelMonthNum && <div className={styles.cardModelMonthNum}>{modelMonthNum}</div>}
{JDCompareNum && JDCompareNum.text && (
<div
className={styles.cardJDCompareNum}
style={{ color: JDCompareNum.color }}
>
{JDCompareNum.text}
</div>
)}
{resumeNum && resumeNum.text && (
<div
className={styles.cardResumeNum}
style={{ color: resumeNum.color }}
>
{resumeNum.text}
</div>
)}
{processTitle && <Flex justify='space-between' className={styles.progressBox}>
<Flex gap={7} justify='flex-end' vertical className={styles.progressTitle}>
<Flex gap={14}>
<span>{processTitle}</span>
<span>{processTitleNum}</span>
</Flex>
<Flex gap={14}>
<span>{processSubtitle}</span>
<span style={{ color: '#D64595' }}>{processSubtitleNum}</span>
</Flex>
</Flex>
<Progress type="circle" percent={percent} size={56} strokeColor="#D64595" format={(percent)=> percent + '%'} />
</Flex>}
</Flex>
)
}
export default ShowCountCard
四、示例效果


该功能通过清晰的规则定义和样式区分,使数据变化趋势一目了然,提升了统计信息的可读性和实用性。