第1题-达人数据看板
小红书9月13日机考题目与解析
第一题 - 项目需求概览:达人数据看板
题目
项目名称:达人数据看板
本项目面向运营团队,目标是构建一个前后端分离的「达人数据分析看板」Web 应用,帮助运营人员从多维度了解平台达人的成长趋势、内容表现与粉丝画像。系统需预置不少于 500 条达人初始数据,并支持数据持久化与 API 通信。
核心功能包括:
- 数据概览:展示平台达人总数、本周新增达人、平均互动率、平均粉丝数等关键指标卡片,并显示环比升降百分比。
- 达人排行:支持按粉丝数、互动率、近 7 天涨粉数、笔记数排序,支持昵称搜索与达人等级筛选。
- 趋势分析:以折线图展示日活跃达人数、日均互动率、日新增笔记数,支持近 7 天 / 近 30 天切换与悬停交互。
- 粉丝画像:展示地域、年龄、兴趣标签等分布,支持切换不同达人查看。
- 内容分析:对比美妆、穿搭、美食、旅行、健身等品类的平均互动率、点赞数、收藏数。
- 数据导出:将当前筛选达人列表导出为 CSV,字段包括昵称、等级、粉丝数、互动率、涨粉数、笔记数。
- 实时更新:支持每 30 秒或自定义间隔自动刷新,图表平滑过渡,页面顶部显示最后更新时间。
- 图表下钻:点击品类或地域图表可逐级下钻,保留面包屑导航并支持返回上级。
- 达人对比:选择 2–5 个达人,用雷达图或多维柱状图对比粉丝数、互动率、涨粉数、笔记数。
- 自定义布局:支持拖拽调整图表卡片位置、显示/隐藏模块,布局配置自动保存。
- 高级筛选:支持多条件组合筛选,筛选方案可命名、保存、切换、增删改。
- 数据缓存:实现前端缓存策略,相同条件不重复请求,支持 5 分钟自动失效与手动强制刷新。
- 异常检测:自动标记互动率突增/突降超过 50% 的异常数据,红色高亮并在悬停时展示原因分析。
技术约束: 前后端分离、API 通信、使用图表库、数据持久化、首屏加载不超过 3 秒、筛选响应不超过 500ms、缓存命中率不低于 70%、提供一条命令启动与 README 说明。
1000ms尝试: 0已通过: 0难度: 5所属公司 :小红书
项目说明 赤帖内容运营组需要一块达人经营台,用来盯创作者体量变化、笔记互动、粉丝结构和品类对比。本题要求做成可预览的经营台 Web 应用,把多维展示、筛选和下钻接到同一套接口。
考试说明
- 允许借助 AI 辅助编码
- 目标:实现完整的达人经营台,支持可视化呈现与多维分析
一、功能要求
1.1 数据概览
- 页面顶部四张指标卡,选择器与字段如下:
| 选择器 | JSON 字段 | 口径 |
|---|---|---|
#kpi-total |
totalCreators |
当前达人条数 |
#kpi-week-new |
weekNew |
createdAt ≥ 2026-09-07(含)的人数 |
#kpi-avg-rate |
avgInteractionRate |
全量 interactionRate 算术平均,四舍五入到 4 位小数 |
#kpi-avg-followers |
avgFollowers |
全量 followers 算术平均,四舍五入到整数 |
- 每张卡旁展示环比:
#kpi-total-wow/#kpi-week-new-wow/#kpi-avg-rate-wow/#kpi-avg-followers-wow GET /api/overview返回上述四项,以及
{
"wow": {
"totalCreators": { "value": 2.1, "direction": "up" },
"weekNew": { "value": 0.0, "direction": "flat" },
"avgInteractionRate": { "value": -1.4, "direction": "down" },
"avgFollowers": { "value": 3.0, "direction": "up" }
},
"lastUpdated": "2026-09-13T10:00:00+08:00"
}- 环比公式:
value = round1((current - previous) / previous * 100);previous为 0 时value为0.0。direction为up/down/flat(value分别为正、负、零) - 启动后上期快照固定为:
totalCreators=490,weekNew=12,avgInteractionRate=0.0310,avgFollowers=72000 - 百分数展示一位小数,并带
%(例如2.1%)
1.2 达人排行
GET /api/creators查询参数:
| 参数 | 含义 |
|---|---|
sort |
followers / interactionRate / followerGrowth7d / posts,缺省 followers;其它值 → 400 invalid sort |
q |
按昵称包含匹配,大小写不敏感;缺省或空串不过滤 |
level |
初级 / 中级 / 高级 / 头部;缺省不过滤 |
category |
品类精确匹配 |
city |
城市精确匹配 |
schemeId |
使用已保存筛选方案;缺省则用「当前已应用方案」(若有) |
- 排序一律降序;主键能相等时按
nicknameUnicode 码点升序。rank从 1 连续编号(过滤之后) - 响应:
{ "items": [ ... ], "total": <过滤后条数> }。单条含rank,id,nickname,avatar,level,category,followers,interactionRate,followerGrowth7d,posts,city,createdAt,anomaly,anomalyReason interactionRate输出 4 位小数。anomaly为布尔;非异常时anomalyReason为null- 表体
#ranking-table tbody中每一行:[data-testid="creator-row"],带data-id;异常行再带data-anomaly="true" - 搜索框
#search-input,等级#level-filter,排序#sort-select(option 的value与sort参数相同)
1.3 趋势分析
GET /api/trends?range=7或range=30。其它值 →400invalid range- 点按
date升序;最后一天固定2026-09-13;range=7共 7 个点(2026-09-07~2026-09-13),range=30共 30 个点 - 每个点:
date, activeCreators, avgInteractionRate, newNotes - 页面
#trend-range(7/30),折线容器#trend-chart;悬停点用title写出该日三个数值
1.4 粉丝画像
GET /api/portraits/:id→{ "creatorId", "region", "age", "interests" },三个对象的取值均为比例且各自求和为1(允许1e-9误差)- 未知 id →
404creator not found #portrait-select切换达人;#portrait-region、#portrait-age用柱或扇区展示,扇区/柱带data-key
1.5 内容分析
GET /api/categories→{ "items": [ { "category", "avgInteractionRate", "avgLikes", "avgCollections", "creatorCount" } ] }- 品类顺序固定:
美妆、穿搭、美食、旅行、健身 - 三个均值只统计该品类下达人,分别对
interactionRate/likes/collections做算术平均;比率 4 位小数,点赞与收藏四舍五入到整数 #category-chart内每个品类:[data-testid="category-bar"][data-category="美妆"]
1.6 数据导出
GET /api/creators/export使用与列表相同的过滤参数(含已应用方案)Content-Type含text/csv;UTF-8;LF 换行;无 BOM- 表头恰好一行且顺序为:
nickname,level,followers,interactionRate,followerGrowth7d,posts interactionRate写成 4 位小数;行顺序与当前列表一致#export-btn触发下载
1.7 实时数据更新
- 页面顶部
#last-updated展示overview.lastUpdated(ISO-8601) #refresh-btn调用POST /api/refresh:先把当前四项概览写入上期快照,再对每条达人执行followers += max(1, followerGrowth7d // 7),然后将虚拟时钟推进 1 秒,把lastUpdated设为推进后的时刻,并清空列表缓存- 不要求浏览器定时器;刷新后卡片与图表按新数据重绘即可
1.8 图表下钻功能
- 点击品类柱:列表改为该
category,面包屑为概览 / <品类> - 点击地域柱:列表改为该
city,面包屑为概览 / <城市> - 再点击一名达人:面包屑为
概览 / <上一层名称> / <昵称>,画像切到该达人 #breadcrumb内节点[data-level="0"](概览)、[data-level="1"]、[data-level="2"];点击上级应回到对应层级- 下钻列表与
GET /api/creators?category=/?city=结果一致
1.9 达人对比分析
POST /api/compare体{ "ids": ["fix-mei", "fix-cmp-a"] }- 先按出现顺序去重;去重后数量不在
2~5→400compare size;任一 id 不存在 →404creator not found - 成功:
{ "items": [ { "id", "nickname", "followers", "interactionRate", "followerGrowth7d", "posts" } ] },顺序与去重后的ids一致 #compare-panel展示结果;行[data-testid="compare-row"][data-id];可用多维柱(每个度量一个[data-metric])- 面板内可加减达人,但提交前必须仍满足 2~5 人
1.10 自定义看板布局
- 不做拖拽。
GET /api/layout→{ "modules": { "overview": true, "ranking": true, "trend": true, "portrait": true, "category": true, "compare": true } } PUT /api/layout体可只带部分键,与现网状态合并;未知模块名或非布尔 →400invalid layout- 对应区块
[data-module="<name>"]必须带data-visible="true"或"false" - 勾选框
#layout-toggle-<name>(例如#layout-toggle-ranking)切换显隐;配置保存在服务端内存,刷新页面后应再拉接口恢复
1.11 高级筛选
- 方案体:
{ "name": "高粉美妆", "rules": [ { "field": "level", "op": "eq", "value": "高级" }, { "field": "category", "op": "eq", "value": "美妆" }, { "field": "followers", "op": "gt", "value": 100000 } ] } field:nickname/level/category/followers/interactionRate/followerGrowth7d/posts/cityop:eq/ne/gt/gte/lt/lte/contains(contains仅对字符串字段,大小写不敏感)- 多条规则之间是 AND
POST /api/filters创建,id形如flt-1起递增;GET /api/filters→{ "items": [...] }PUT /api/filters/:id整单替换name与rules;DELETE /api/filters/:idPOST /api/filters/:id/apply设为当前方案;POST /api/filters/clear清空当前方案- 列表在方案结果之上再叠加
q、level、category、city、sort name空 →400invalid filter;未知field/op→400invalid filter;创建时name与已有方案重复 →400duplicate filter;更新时与其它方案重名同样duplicate filter;未知 id →404filter not found#filter-name、#filter-save、#filter-schemes(每项[data-testid="filter-item"][data-id])、#filter-clear
1.12 数据缓存机制
- 仅
GET /api/creators缓存。键为影响结果的查询串(sort,q,level,category,city,schemeId)以及当前已应用方案 - 首次或失效后响应头
X-Cache: MISS;虚拟时钟 TTL 内的相同键X-Cache: HIT,正文与首次字节级一致 - TTL 为 300 虚拟秒
POST /api/cache/flush、POST /api/refresh、POST /api/reset均清空缓存POST /api/clock体{ "seconds": 301 }只推进虚拟时钟(不改达人数据);GET /api/clock→{ "now": "<ISO-8601>" }
1.13 异常数据检测
- 对每条达人:
change = (interactionRate - prevInteractionRate) / prevInteractionRate(分母为 0 则不标记) - 严格大于
0.5的绝对值才算异常;等于0.5不算 anomalyReason必须含突增或突降,以及一位小数的百分数- 异常行加红(class
is-anomaly),悬停title等于anomalyReason
二、技术约束
- 前后端分离:页面只请求
/api/*;预览栈会把/api反代到后端 - 图表用 SVG 或 DOM 绘制,工作区不能再装依赖
- 状态放在进程内存。
POST /api/reset恢复启动态(达人、快照、时钟2026-09-13T10:00:00+08:00、布局全显、方案清空、缓存清空),成功{ "ok": true } - 失败体统一
{ "error": "<关键字>" },关键字只能是:not implemented/invalid sort/invalid range/creator not found/compare size/invalid layout/invalid filter/duplicate filter/filter not found - 启动读环境变量
PORT,绑定0.0.0.0:$PORT,未设置时为8000 - 不要求登录、数据库、第三方开放平台
三、非功能要求
- 数据量:启动即有 500 条达人(预置生成,含下方固定样例行)
- 页面在 1280px 宽屏下各模块可同时看见,无需横向滚动才能读到四张指标卡
- 筛选、排序切换后列表与导出应对齐同一结果
- 统计口径按上文公式,四舍五入采用「一半远离 0」(与 Python
decimal.ROUND_HALF_UP相同) - 一条命令可启动后端;预览由平台拉起
backend/main.py与frontend/index.html - 虚拟时钟与缓存失效必须可复现,不依赖机器墙钟
四、数据描述
初始数据 应用启动时需预置以下数据(用生成逻辑即可,固定样例行的 id 不得改):
达人(共 500 条,字段如下):
{
"id": "fix-mei",
"nickname": "赤帖小美",
"avatar": "https://placeholder.local/100",
"level": "头部",
"category": "美妆",
"followers": 980000,
"following": 210,
"posts": 186,
"likes": 4200000,
"collections": 980000,
"interactionRate": 0.082,
"prevInteractionRate": 0.080,
"followerGrowth7d": 12600,
"createdAt": "2024-03-01",
"city": "上海",
"ageGroup": "18-24"
}等级只能是 初级 / 中级 / 高级 / 头部。品类只能是 美妆 / 穿搭 / 美食 / 旅行 / 健身。城市只能是 上海 / 北京 / 广东 / 浙江 / 其他。
固定样例行(必须原样存在,其余 487 条由生成器补齐):
| id | nickname | level | category | followers | 备注 |
|---|---|---|---|---|---|
fix-mei |
赤帖小美 | 头部 | 美妆 | 980000 | 高粉 |
fix-drop |
穿搭阿北 | 高级 | 穿搭 | 88000 | 互动率相对昨日下跌超过 50% |
fix-surge |
寻味阿广 | 中级 | 美食 | 56000 | 互动率相对昨日上涨超过 50% |
fix-edge |
旅行边沿 | 旅行 | 42000 | 相对昨日上涨 51% | |
fix-exact |
恰好五成 | 40000 | 相对昨日恰好 50%,不算异常 | ||
fix-safe |
健身稳当 | 初级 | 健身 | 9800 | 未过异常线 |
fix-new |
本周新人甲 | 美妆 | 860 | createdAt=2026-09-11 |
|
fix-case |
LimeLook | 高级 | 穿搭 | 64000 | 用于大小写搜索 |
fix-tie-a |
并列阿西 | 77777 | 与 fix-tie-b 粉丝相同 |
||
fix-tie-b |
并列阿东 | 昵称码点大于阿西 | |||
fix-cmp-a |
对照阿一 | 头部 | 健身 | 410000 | 对比用 |
fix-cmp-b |
对照阿二 | 高级 | 旅行 | 210000 | |
fix-cmp-c |
对照阿三 | 中级 | 美食 | 91000 |
fix-drop:interactionRate=0.0120,prevInteractionRate=0.0400。fix-surge:0.0900 / 0.0300。fix-edge:0.1510 / 0.1000。fix-exact:0.1500 / 0.1000。fix-safe:0.0450 / 0.0400。
趋势(近 30 天,含当天):
{
"date": "2026-08-15",
"activeCreators": 8000,
"avgInteractionRate": 0.0300,
"newNotes": 20000
}粉丝画像(每个达人一条):region / age / interests 为比例对象。本城在 region 中为 0.40,其余四城各 0.15。age 固定 18-24:0.35, 25-30:0.30, 31-35:0.20, 36+:0.15。interests 固定 美妆:0.30, 穿搭:0.25, 美食:0.20, 旅行:0.15, 其他:0.10。
品类接口的均值必须从达人列表现场汇总,启动示例里的品类数字只表示字段形状:
[
{"category": "美妆", "avgInteractionRate": 0.042, "avgLikes": 5600, "avgCollections": 2300}
]五、作答要求
- 代码提交:在工作区内改后端与页面,保持预览可打开
- README:以本文为规格;技术栈为 Python(Flask 已在镜像)+ 静态页
- 数据初始化:首次启动即有 500 条达人与 30 天趋势
- 代码规范:命名清楚,分区注释说明各块职责即可
六、启动方式
请从工作区根目录启动后端:
# 启动服务
PORT=8000 python3 backend/main.py未设置 PORT 时监听 8000。平台预览会注入 PORT 并托管 frontend/index.html。公开自测入口为 sample_testcase/run_sample_testcases.js(由平台拉起页面与接口,不计成绩)。
七、验证策略
提交结果将从以下维度进行验证:
- 功能完整性:概览、排行、趋势、画像、品类、导出、刷新、下钻、对比、布局显隐、筛选方案、缓存头、异常标记是否按契约工作
- 数据可视化:图表容器有可交互节点,下钻与对比区域可用
- 数据准确性:汇总、环比、品类均值、异常判定与题面公式一致
- 筛选功能:搜索、排序、等级、多规则 AND、方案切换与导出范围一致
- 实时性:刷新后
lastUpdated与环比快照更新,缓存按 TTL 与手动失效 - 代码质量:结构可维护
- 视觉呈现:1280px 下模块齐全,隐藏模块不再占主视区