)
Strapi 后台 NPS 调查机制详解展示规则、本地持久化与数据提交流程源码级【免费下载链接】strapi Strapi is the leading open-source headless CMS. It’s 100% JavaScript/TypeScript, fully customizable, and developer-first.项目地址: https://gitcode.com/GitHub_Trending/st/strapi本文以 Strapi 官方文档docs/docs/docs/01-core/admin/04-features/nps.md为骨架结合管理端源码packages/core/admin/admin/src/components/NpsSurvey.tsx及其单元测试完整拆解后台 NPSNet Promoter Score净推荐值调查的功能定位、展示时机规则、评分交互、localStorage 持久化字段、useNpsSurveySettingsHook 在注册流程中的联动以及反馈数据上报的端点与请求体结构。读完后你可以准确回答NPS 问卷何时出现、为什么有时不出现、哪些数据被发送、以及如何在自建环境中通过 feature flag 关闭它。一、NPS 调查是什么、做什么官方文档 nps.md 对其定位一句话概括NPS 调查用于收集用户管理员对 Strapi 的反馈采用 0 到 10 的评分量表并邀请用户填写附加评论。从源码实现看NpsSurvey.tsx 中ratingArray由[...Array(11).keys()]生成即 0–10 共 11 个分值与文档描述一致。问卷主体包含一条固定问题文案i18n idapp.components.NpsSurvey.banner-titleHow likely are you to recommend Strapi to a friend or colleague?你有多大可能向朋友或同事推荐 Strapi两端分别标注 Not at all likely 与 Extremely likely桌面端渲染为 11 个可选数字方块隐藏 radio 输入 可见数字标签见 NpsSurvey.tsx移动端则降级为SingleSelect下拉选择NpsSurvey.tsx选中评分后才展开改进建议文本框Textarea与 Submit Feedback 按钮NpsSurvey.tsx右上角始终提供 Dismiss survey 关闭按钮NpsSurvey.tsx。整个表单由 Formik 驱动yup校验规则要求npsSurveyRating必填yup.number().required()评分未选择时提交按钮区域不会渲染从交互层面保证了文档所说的评分量表是强制项。二、什么时候展示问卷准入条件与冷却规则文档给出的展示规则是只对注册时勾选了 Keep me updated 复选框的管理员用户展示用户在后台活动一段时间后才展示文档表述为 after 5 minutes of activity重提频率规则用户响应过调查后90 天内不再重复展示首次未响应关闭后7 天后再展示第二次及以后未响应后90 天后再展示。源码中这些规则全部集中在纯函数checkIfShouldShowSurveyNpsSurvey.tsx与冷却常量delaysNpsSurvey.tsx中const delays { postResponse: 90 * 24 * 60 * 60 * 1000, // 90 days in ms postFirstDismissal: 14 * 24 * 60 * 60 * 1000, // 14 days in ms postSubsequentDismissal: 90 * 24 * 60 * 60 * 1000, // 90 days in ms display: 30 * 60 * 1000, // 30 minutes in ms };注意以当前仓库源码为准首次关闭后的冷却实际为14 天postFirstDismissal、展示前的会话延迟为30 分钟delays.display与文档描述的 7 天/5 分钟存在出入可推断文档记录的是早期版本的参数源码才是当前行为的事实依据。展示判定的五个分支checkIfShouldShowSurvey按优先级依次判断源码注释原文明确了这条决策链全局开关window.strapi.flags.nps false时直接不展示NpsSurvey.tsx用户级开关持久化设置中enabled false即注册时未接受 Keep me updated时不展示NpsSurvey.tsx已响应过存在lastResponseDate时距上次响应 ≥ 90 天才重新展示否则不展示NpsSurvey.tsx关闭过两次及以上存在lastDismissalDate时距上次关闭 ≥ 90 天才重新展示NpsSurvey.tsx只关闭过一次存在firstDismissalDate时距首次关闭 ≥ 14 天才重新展示NpsSurvey.tsx以上均不满足则展示。源码注释还特别说明了两点细节提交一次响应会重置关闭计数firstDismissalDate/lastDismissalDate被置空见下文第四节且分支 4、5 的判断顺序不能颠倒——关闭过两次的用户必然也有firstDismissalDate必须先按多次关闭分支处理。此外组件首次渲染时调用checkIfShouldShowSurvey的结果存入surveyIsShown状态且只在首次渲染时检查一次NpsSurvey.tsx随后用setTimeout(delays.display)设置一个展示冷却30 分钟计时结束前组件直接返回nullNpsSurvey.tsx。这解释了文档中活动一段时间后展示的机制——从当前实现看它是会话开始后的固定延迟而非逐字面的5 分钟活动量统计。三、问卷状态的本地持久化localStorage 结构与写入时机所有展示状态都通过usePersistentState持久化到浏览器 localStorage键名为STRAPI_NPS_SURVEY_SETTINGS。该 Hook 定义于 usePersistentState.ts初始值从 localStorage 的 JSON 反序列化读取随后在useLayoutEffect中同步写回——同步写入保证了同标签页跳转等场景下状态不丢失。NPS 专用的封装是useNpsSurveySettingsNpsSurvey.tsxfunction useNpsSurveySettings() { const [npsSurveySettings, setNpsSurveySettings] usePersistentStateNpsSurveySettings( STRAPI_NPS_SURVEY_SETTINGS, { enabled: true, lastResponseDate: null, firstDismissalDate: null, lastDismissalDate: null, } ); return { npsSurveySettings, setNpsSurveySettings }; }对应的NpsSurveySettings接口NpsSurvey.tsx四个字段含义如下字段类型含义写入时机enabledboolean用户是否接受接收调查注册时勾选 Keep me updated注册流程写入默认值为truelastResponseDatestring \| null上次成功提交响应的时间提交成功回调中写入firstDismissalDatestring \| null第一次关闭问卷的时间首次点击 Dismiss survey 时写入lastDismissalDatestring \| null最近一次关闭问卷的时间第二次及以后关闭时写入两个写状态的路径源码行为事实提交成功handleSubmitResponseNpsSurvey.tsx写入lastResponseDate同时把firstDismissalDate与lastDismissalDate重置为null——即文档隐含的提交响应重置关闭计数关闭问卷handleDismissNpsSurvey.tsx清空lastResponseDate若已有firstDismissalDate则写lastDismissalDate进入 90 天冷却否则写firstDismissalDate进入 14 天冷却。单元测试 NpsSurvey.test.tsx 对上述行为逐条做了验证saves user response、saves first user dismissal、saves subsequent user dismissal三个用例精确断言了 localStorage 中被写入的对象结构如响应后的{ enabled: true, lastResponseDate, firstDismissalDate: null, lastDismissalDate: null }。四、数据提交到哪端点、请求体与错误处理文档明确数据提交端点为https://analytics.strapi.io/submit-nps。源码中该地址支持环境变量覆盖NpsSurvey.tsxconst res await fetch( ${process.env.STRAPI_ANALYTICS_URL || https://analytics.strapi.io}/submit-nps, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(body), } );请求体结构由组件内的NpsSurveyMutationBody接口定义NpsSurvey.tsx各字段取值来源如下字段类型取值来源emailstring当前登录管理员邮箱useAuth的user.email非对象用户取空串ratingnumber \| null表单选中的 0–10 评分commentstring改进建议文本框内容environmentstring?useAppInfo读取的currentEnvironmentversionstring?useAppInfo读取的strapiVersionlicenseEnterprise \| Growth \| Community全局window.strapi.projectTypeisHostedOnStrapiCloudbooleanprocess.env.STRAPI_HOSTING strapi.cloud提交后的状态流转成功res.ok则更新本地持久化设置、显示 Thank you very much for your feedback! 感谢语并在 3 秒后收起问卷NpsSurvey.tsx失败则弹出 danger 通知 An error occurred 且问卷保持打开允许用户重试NpsSurvey.tsx。测试用例show error message if request fails and keep survey openNpsSurvey.test.tsx用 MSW 拦截该端点返回 500验证了错误通知出现且感谢语不出现。五、useNpsSurveySettings 在注册流程中的联动文档 Hooks 小节指出useNpsSurveySettings基于usePersistentState实现之所以导出该 Hook是为了在注册过程中判断用户是否勾选了 Keep me updated 复选框从而决定是否启用调查。这条链路在源码中的实际形态实现事实注册页 Register.tsx 渲染复选框文案为 Keep me updated about new features upcoming improvements (by doing this you accept the {terms} and the {policy}.)。创建管理员用户成功后若news为真则调用setNpsSurveySettings((s) ({ ...s, enabled: true }))Register.tsx并跳转/usecase收集使用场景未勾选则仅跳回首页enabled保持默认状态、问卷永远不会对该用户展示。创建普通用户的handleRegisterUser分支有完全相同的逻辑Register.tsx。需要说明一个语义细节enabled字段默认值本身就是true注册流程做的是显式确认写true源码注释写的是 Only enable EE survey if user accepted the newsletter。因此对存量用户在 NPS 功能上线前创建账号、没有机会勾选该复选框的人checkIfShouldShowSurvey的注释明确说明假设他们若有机会会选择开启即默认按开启处理。六、自建部署中的控制手段window.strapi.flags.npscheckIfShouldShowSurvey的第一个分支检查window.strapi.flags.nps。这个全局对象在 render.ts 中初始化projectType: Community, flags: { nps: false, promoteEE: true, docLinks: true, },可以看到flags.nps的默认值是false随后会在渲染初始化流程中依据项目/许可上下文覆写。因此从源码结构看自建非托管实例默认不会收到 NPS 问卷问卷主要出现在 Strapi 官方渠道创建的项目中——这一推断与文档只对勾选了 Keep me updated 的管理员展示的准入前提互为印证。对本地开发者而言实际可控的开关是注册时不勾选 Keep me updatedenabled不会为真问卷不出现构建期环境变量STRAPI_ANALYTICS_URL可替换上报域名全局 flagwindow.strapi.flags.nps服务端渲染注入的标志位置false后展示判定直接短路返回。七、测试矩阵展示规则如何被逐条验证NpsSurvey.test.tsx 以 localStorage mock键STRAPI_NPS_SURVEY_SETTINGS见 测试文件 Jest 假定时器构建了完整的规则验证矩阵与上文展示判定一一对应renders survey if enabled/renders survey if settings dont existenabled: true或设置不存在时问卷渲染does not render survey if disabledenabled: false时不渲染respects the delay after user submission以 2020-01-01 为响应时间30 天内不展示90 天2020-03-31后重新展示测试文件;respects the delay after first user dismissal首次关闭后 7 天内不展示、14 天后2020-01-15重新展示——该用例的时间点直接印证了源码中 14 天而非文档所述 7 天的冷却值测试文件respects the delay after subsequent user dismissal第二次关闭后 90 天才重新展示测试文件。八、小结NPS 调查的完整生命周期把文档与源码拼合起来一次 NPS 调查的完整生命周期是注册管理员勾选 Keep me updateduseNpsSurveySettings将enabled: true写入 localStorageRegister.tsx准入判定checkIfShouldShowSurvey依次检查全局 flag、enabled、响应/关闭冷却NpsSurvey.tsx延迟展示通过判定后再等待会话内的展示冷却当前源码为 30 分钟后在页面底部渲染固定问卷NpsSurvey.tsx交互用户选 0–10 评分 可选评论后提交或点击关闭两条路径分别更新lastResponseDate或first/lastDismissalDateNpsSurvey.tsx上报成功时 POST 邮箱、评分、评论、环境、版本、许可类型等到 analytics 端点随后展示感谢语并在 90/14/90 天冷却节奏中等待下一次触达。对维护 Strapi 后台或在其上开发自定义插件的工程师来说这套实现的价值不仅在于功能本身usePersistentState键名约定STRAPI_NPS_SURVEY_SETTINGS、注册即授权的数据合规做法以及纯函数判定 假定时器测试的规则验证方式都是可直接借鉴到自建管理端功能如使用引导、版本升级提示中的成熟模式。【免费下载链接】strapi Strapi is the leading open-source headless CMS. It’s 100% JavaScript/TypeScript, fully customizable, and developer-first.项目地址: https://gitcode.com/GitHub_Trending/st/strapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考