官网SDK技术文档

概述

FsYxt Web SDK 是一款面向营销官网的 JavaScript SDK,提供访客追踪、事件埋点、表单管理、会员体系等核心功能,帮助企业实现精准的营销数据采集与用户行为分析。

快速开始

方式一:推荐方式

步骤1: 引入SDK
<script> (function () { var s = document.createElement("script"); s.type = "text/javascript"; s.charset = "utf-8"; s.src = "https://www.fxiaoke.com/ec/kemai/release/static/marketing-website-access.js?id=" + Math.random(); document.getElementsByTagName("head")[0].appendChild(s); })(); </script>
步骤2: 初始化配置
window.addEventListener('load', function() { FsYxt.configure({ ea: "your-enterprise-ea", // 企业ea(必填) websiteId: "your-website-id", // 网站ID(必填) host: "your-host.com", // API HOST地址(必填) enableSpaTracking: false // 是否启用SPA单页应用埋点(可选) }); });

方式二:旧方式(不推荐)

注意: 此方式已过时,仅为兼容旧项目保留,新项目请使用方式一。
引入SDK并初始化配置(一步完成)
<script> (function () { var config = { ea: 'your-enterprise-ea', websiteId: 'your-website-id', host: 'your-host.com' }; var s = document.createElement("script"); s.type = "text/javascript"; s.charset = "utf-8"; s.src = "https://www.fxiaoke.com/ec/kemai/release/static/marketing-website-access.js?id=" + Math.random(); s.id = "fsMarketingWebsiteScript"; s.innerHTML = [ "FSscriptArgs.WebsiteEa='" + config.ea + "'", "FSscriptArgs.WebsiteId='" + config.websiteId + "'", "FSscriptArgs.host='" + config.host + "'" ].join(';'); window.FsYxtWebsiteEa = config.ea; window.FsYxtWebsiteId = config.websiteId; window.FsYxtHost = config.host; document.getElementsByTagName("head")[0].appendChild(s); })(); </script>
使用旧方式时,配置已在脚本加载时完成,无需再调用FsYxt.configure()

监听初始化状态

window.addEventListener('load', function() { // SDK初始化成功 FsYxt.on('onReady', function() { console.log('SDK已准备就绪'); }); // SDK初始化失败 FsYxt.on('onError', function(error) { console.error('SDK初始化失败:', error); }); });

核心API

1. configure(config)

初始化SDK配置,必须在使用其他功能前调用。

参数说明

参数名类型必填说明
eaString应用源ID
websiteIdString网站ID
hostString主机地址
enableSpaTrackingBoolean是否启用单页应用(SPA)埋点,默认false

使用示例

FsYxt.configure({ ea: "88146", websiteId: "8b28bec67afc42c281f078ff9bea7fec", host: "crm.example.com" });

2. track(params)

上报自定义事件埋点,用于追踪用户行为。

参数说明

参数名类型必填说明
eventIdString事件ID
attributesIdString/Array事件属性ID(传数组时取第一个)
marketingEventIdString市场活动ID
eventDescriptionString事件描述
successFunction成功回调函数
failFunction失败回调函数

使用示例

场景一:单一事件单一按钮上报
适用于单个按钮的埋点上报场景,直接在代码中调用 track 方法。
示例代码:
// 点击下载按钮时上报 document.getElementById('downloadBtn').addEventListener('click', function() { FsYxt.track({ eventId: 'button_click', attributesId: 'header_download_btn', eventDescription: '点击下载按钮', marketingEventId: 'xxx', success: function(data) { console.log('埋点上报成功', data); }, fail: function(error) { console.error('埋点上报失败', error); } }); });
场景二:多个按钮统一上报(推荐)
适用于页面上有多个按钮需要埋点的场景,通过 HTML 自定义属性配置埋点参数,统一绑定事件处理,减少重复代码。
实现思路:
  1. 页面上多个按钮使用统一的 class(如 .js-track-btn)标识需要埋点的按钮
  2. 每个按钮通过 data-* 属性配置埋点参数(eventIdattributesIdeventDescription 等)
  3. 统一绑定点击事件,从按钮属性中读取埋点参数并上报
  4. 所有埋点只需维护一段 JS 逻辑,易于维护和扩展
HTML 示例:
<!-- 下载按钮 --> <button class="js-track-btn" data-event-id="button_click" data-attributes-id="header_download_btn" data-event-desc="头部下载按钮" > 下载 </button> <!-- 查看更多按钮 --> <button class="js-track-btn" data-event-id="button_click" data-attributes-id="banner_more_btn" data-event-desc="Banner 查看更多按钮" > 查看更多 </button> <!-- 咨询按钮 --> <button class="js-track-btn" data-event-id="button_click" data-attributes-id="footer_consult_btn" data-event-desc="底部联系咨询按钮" > 咨询我们 </button>
JavaScript 统一绑定:
// 统一绑定所有按钮的埋点事件 document.addEventListener("click", function (e) { const btn = e.target.closest(".js-track-btn"); if (!btn) return; // 从按钮的 data 属性中读取埋点参数 const eventId = btn.dataset.eventId; const attributesId = btn.dataset.attributesId; const eventDescription = btn.dataset.eventDesc; const marketingEventId = btn.dataset.marketingEventId; // 可选 // 调用埋点上报 FsYxt.track({ eventId: eventId, attributesId: attributesId, eventDescription: eventDescription, marketingEventId: marketingEventId, success(data) { console.log("埋点上报成功", data); }, fail(error) { console.error("埋点上报失败", error); }, }); });
优势说明:
  • 易于维护:所有埋点只需维护一段 JS 逻辑
  • 灵活扩展:新增按钮只需添加 HTML 属性,无需修改 JS 代码
  • 自动区分:后台会自动根据 attributesId 区分不同按钮来源
  • 统一管理:所有埋点参数集中在 HTML 中,便于查看和管理

3. createForm(params)

动态创建表单iframe,用于在页面中嵌入营销表单。

参数说明

参数名类型必填说明
idString表单容器元素的ID
srcString表单页面URL
styleStringiframe样式(CSS字符串)
autoheightBoolean是否自动适应高度

使用示例

FsYxt.createForm({ id: 'form-container', src: 'https://crm.example.com/proj/page/marketing-page?id=xxx', style: 'width:100%;height:600px;border:none;', autoheight: true });<!-- 在页面中预留表单容器 --> <div id="form-container"></div>

4. generateQrcode(type, fanQrCodeId, options)

生成营销推广二维码(支持公众号/企业微信)。

参数说明

参数名类型必填说明
typeString二维码类型: "gzh"(公众号) 或 "qw"(企业微信)
fanQrCodeIdString场景ID或粉丝码ID
optionsObject配置选项
options.renderTypeString渲染类型: "auto"(自动渲染) 或 "manual"(手动渲染),默认"auto"
options.successFunction成功回调函数
options.failFunction失败回调函数

使用示例

// 自动渲染模式 FsYxt.generateQrcode('gzh', 'xxx', { renderType: 'auto', success: function(result) { console.log('二维码容器:', result.container); console.log('二维码URL:', result.qrUrl); }, fail: function(error) { console.error('生成失败:', error); } }); // 手动渲染模式 FsYxt.generateQrcode('qw', 'xxx', { renderType: 'manual', success: function(result) { // 自行处理二维码URL document.getElementById('my-qrcode').src = result.qrUrl; } });

5. memberOperationIntercept(params)

会员操作拦截,限制非会员访问特定功能。

参数说明

参数名类型必填说明
classNameString需要拦截的元素类名
onFormSubmitFunction表单提交回调函数
expiresNumber会员登录态过期时间(毫秒)

使用示例

FsYxt.memberOperationIntercept({ className: 'premium-download-btn', expires: 24 * 60 * 60 * 1000, // 24小时 onFormSubmit: function(result) { if (result.status === 'ok') { console.log('会员登录成功'); } } });<!-- 需要拦截的元素 --> <a href="download.zip" class="premium-download-btn">下载资源</a>

6. memberSignIn(params)

嵌入式会员登录表单(仅PC端)。

参数说明

参数名类型必填说明
classNameString登录表单容器元素类名
onFormSubmitFunction表单提交回调函数
expiresNumber会员登录态过期时间(毫秒)

使用示例

FsYxt.memberSignIn({ className: 'member-login-container', expires: 7 * 24 * 60 * 60 * 1000, // 7天 onFormSubmit: function(result) { if (result.status === 'ok') { console.log('登录成功'); // 跳转或刷新页面 location.reload(); } } });<div class="member-login-container"></div>

7. trackSinglePage()

为单页应用(SPA)启用路由变化埋点追踪。
注意: 使用 configure() 初始化时,推荐通过 enableSpaTracking: true 参数启用,无需单独调用此方法。

使用示例

// 方式一: 推荐 FsYxt.configure({ ea: "88146", websiteId: "xxx", host: "crm.example.com", enableSpaTracking: true // 启用SPA埋点 }); // 方式二: 手动调用 FsYxt.trackSinglePage();

8. getConfig()

获取SDK当前配置信息,包含访客ID、UTM参数等。

返回值

返回一个包含以下字段的对象:
字段名类型说明
visitorIdString访客唯一标识
fsWebsiteUidString网站访客ID
websiteIdString网站ID
hostString主机地址
eaString应用源ID
utmSourceStringUTM来源
utmMediumStringUTM媒介
utmCampaignStringUTM活动
utmContentStringUTM内容
utmTermStringUTM关键词
......其他扩展参数

使用示例

var config = FsYxt.getConfig(); console.log('访客ID:', config.visitorId); console.log('UTM来源:', config.utmSource); console.log('完整配置:', config);

9. on(eventName, handler)

绑定SDK事件回调。

支持的事件

事件名触发时机回调参数
onReadySDK初始化完成
onErrorSDK初始化失败(errorMessage: String)
onFormSubmit表单提交完成(result: Object)

使用示例

// SDK就绪事件 FsYxt.on('onReady', function() { console.log('SDK已准备就绪'); }); // 错误事件 FsYxt.on('onError', function(error) { console.error('初始化错误:', error); }); // 表单提交事件 FsYxt.on('onFormSubmit', function(result) { console.log('提交状态:', result.status); // 'ok' 或 'fail' console.log('表单数据:', result.formData); console.log('服务器响应:', result.response); });

FormSDK API

FsYxt.FormSDK 提供表单相关的高级功能,适用于自定义表单场景。

1. FormSDK.getFieldDescriptions(params)

获取表单字段配置信息,包括字段类型、选项值、验证规则等。

参数说明

参数名类型必填说明
formIdString表单ID
extendParamsObject扩展参数
successFunction成功回调函数
failFunction失败回调函数

返回数据结构

{ info: { name: "表单名称", title: "表单标题" }, fields: [ { apiName: "email", // 字段API名称,提交时使用此字段名 type: "email", // 字段类型 defineType: "custom", // 定义类型: "custom"(自定义) 或 "system"(系统字段) label: "Email", // 字段标签 isRequired: true, // 是否必填 isVerify: false, // 是否需要验证 helpText: "Business Email", // 帮助文本 dateFormat: "yyyy-MM-dd HH:mm", // 日期格式(仅日期类型字段) options: [ // 选项列表(仅单选/多选字段) { label: "选项显示文本", value: "选项值" // 提交时使用此值 } ] } ] }

字段类型说明

type 值字段类型说明
text单行文本普通文本输入
multi_text多行文本多行文本输入
email邮箱邮箱格式验证
phone_number手机号手机号格式验证
select_one单选需要从 options 中获取选项值
select_manny多选需要从 options 中获取选项值,提交时传数组
number数字数字类型
date_time日期时间日期时间类型,传值为时间戳(毫秒)
image图片图片上传
files文件附件文件上传

使用示例

// 获取表单字段配置 FsYxt.FormSDK.getFieldDescriptions({ formId: 'xxx', success: function(data) { console.log('表单名称:', data.info.name); console.log('表单标题:', data.info.title); // 遍历字段配置 data.fields.forEach(function(field) { console.log('字段名:', field.apiName); console.log('字段类型:', field.type); console.log('是否必填:', field.isRequired); // 如果是单选或多选,获取选项值 if (field.type === 'select_one' || field.type === 'select_manny') { console.log('选项列表:', field.options); // 构建下拉选项 field.options.forEach(function(option) { console.log('选项:', option.label, '值:', option.value); }); } }); }, fail: function(error) { console.error('获取失败:', error); } });

2. FormSDK.submitForm(params)

提交自定义表单数据。

参数说明

参数名类型必填说明
formIdString表单ID
enrollIdString报名ID(用于更新已有报名)
sceneTypeNumber场景类型: 0-当前页为转化页, 2-上一页为转化页
dataObject表单数据
extendParamsObject扩展参数
successFunction成功回调函数
failFunction失败回调函数

表单数据字段说明

重要提示:字段名称请使用 getFieldDescriptions 接口返回的 apiName 字段值对于单选(select_one)、多选(select_manny)字段,必须使用 getFieldDescriptions 接口返回的 options 中的 value 值系统字段(如 name、phone、email 等)和自定义字段(如 text5_xxx、text7_xxx 等)的传值方式相同
系统字段(常用)
apiName字段类型传值类型示例说明
name姓名Stringname: "张三"文本字符串
phone手机号Stringphone: "13800138000"手机号格式字符串
email邮箱Stringemail: "test@example.com"邮箱格式字符串
companyName公司Stringcompany: "XX科技有限公司"公司名称
position职位Stringposition: "产品经理"职位名称
country国家Stringcountry: "CN"国家编码,从 getAreaData 获取
provinceStringprovince: "110000"省份编码,从 getAreaData 获取
cityStringcity: "110100"城市编码,从 getAreaData 获取
districtStringdistrict: "110101"区县编码,从 getAreaData 获取
address详细地址Stringaddress: "XX街道XX号"详细地址文本
自定义字段类型
字段类型type 值传值类型传值说明示例
单行文本textString直接传文本值text5_xxx: "网站地址"
多行文本multi_textString直接传文本值text6_xxx: "这是一段描述\n换行内容"
邮箱emailString邮箱格式字符串email: "user@example.com"
手机号phone_numberString手机号格式字符串phone: "13800138000"
单选select_oneString必须使用 options 中的 value 值text7_xxx: "ae3748076b822385"
多选select_mannyArray必须使用 options 中的 value 值数组texts1_xxx: ["value1", "value2"]
数字numberNumber数字类型num1_xxx: 100
日期时间date_timeNumber时间戳(毫秒)num2_xxx: 1737360000000
图片imageString图片URL地址picMap_xxx: "https://example.com/image.jpg"
文件附件filesString文件URL地址fileAttachmentMap_xxx: "https://example.com/file.pdf"
字段传值注意事项
  1. 单选字段传值:
// ❌ 错误:使用选项的 label text7_xxx: "0-4" // ✅ 正确:使用选项的 value(从 getFieldDescriptions 获取) text7_xxx: "1"
  1. 多选字段传值(type 为 select_manny):
// ❌ 错误:使用选项的 label 数组 texts1_xxx: ["选项A", "选项B"] // ✅ 正确:使用选项的 value 数组 texts1_xxx: ["ae3748076b822385", "445dad1a25b6f5ff"]
  1. 日期时间字段传值(type 为 date_time):
// ❌ 错误:使用日期字符串 num2_xxx: "2025-01-20 14:30" // ✅ 正确:使用时间戳(毫秒) // 将日期转换为时间戳:new Date('2025-01-20 14:30').getTime() num2_xxx: 1737360000000 // 或者使用当前时间戳 num2_xxx: new Date().getTime()
  1. 地址字段传值(country、province、city、district):
// 地址字段需要传地址编码(字符串),可通过 getAreaData 获取 // getAreaData 返回的数据结构:{ country: { options: [...] }, province: { options: [...] }, ... } // 步骤1: 获取地址数据 FsYxt.FormSDK.getAreaData({ success: function(data) { // 步骤2: 从 options 中根据 label 查找对应的 value(编码) var provinceOption = data.province.options.find(function(p) { return p.label === "北京市"; }); var provinceCode = provinceOption ? provinceOption.value : ""; // 步骤3: 提交表单时使用编码 var formData = { country: "248", // 国家编码(从 data.country.options 获取) province: provinceCode, // 省份编码(使用 value,不是 label) city: "110100", // 城市编码(从选中省份的 child_options 获取) district: "110101", // 区县编码(从选中城市的 child_options 获取) address: "XX街道XX号" // 详细地址使用文本 }; } }); // ❌ 错误:使用地址名称 province: "北京市" // ✅ 正确:使用地址编码(从 options 中的 value 获取) province: "110000"
  1. 必填字段:
  2. 通过 getFieldDescriptions 获取字段配置,检查 isRequired 属性
  3. 所有 isRequired: true 的字段必须传值

使用示例

示例一:基础提交(已知字段配置)
FsYxt.FormSDK.submitForm({ formId: 'xxx', sceneType: 0, data: { name: '张三', phone: '13800138000', email: 'zhangsan@example.com', companyName: 'XX科技有限公司', position: '产品经理', }, success: function(result) { console.log('提交成功:', result); alert('提交成功!'); }, fail: function(error) { console.error('提交失败:', error); alert('提交失败,请重试'); } });
示例二:先获取字段配置再提交(推荐)
var formId = 'xxx'; var formFields = {}; // 存储字段配置 // 步骤1: 获取表单字段配置 FsYxt.FormSDK.getFieldDescriptions({ formId: formId, success: function(data) { // 保存字段配置,便于后续使用 formFields = data.fields; // 构建表单数据 var formData = { name: '张三', phone: '13800138000', email: 'zhangsan@example.com', companyName: 'XX科技有限公司', position: '产品经理' }; // 处理单选字段(必须使用 options 中的 value) var teamSizeField = formFields.find(function(f) { return f.apiName === 'text7_53804f9c6c384b3f'; }); if (teamSizeField && teamSizeField.options) { // 假设用户选择了 "10-19" 选项 var selectedOption = teamSizeField.options.find(function(opt) { return opt.label === '10-19'; }); if (selectedOption) { formData[teamSizeField.apiName] = selectedOption.value; // 使用 value } } // 处理多选字段(必须使用 options 中的 value 数组) var sourceField = formFields.find(function(f) { return f.type === 'select_manny'; }); if (sourceField && sourceField.options) { // 假设用户选择了多个选项 var selectedValues = sourceField.options .filter(function(opt) { return ['选项A', '选项B'].includes(opt.label); }) .map(function(opt) { return opt.value; // 使用 value }); if (selectedValues.length > 0) { formData[sourceField.apiName] = selectedValues; } } // 步骤2: 提交表单 FsYxt.FormSDK.submitForm({ formId: formId, sceneType: 0, data: formData, success: function(result) { console.log('提交成功:', result); alert('提交成功!'); }, fail: function(error) { console.error('提交失败:', error); alert('提交失败: ' + error.errMsg); } }); }, fail: function(error) { console.error('获取字段配置失败:', error); } });

3. FormSDK.sendSMCode(params)

发送短信验证码。

参数说明

参数名类型必填说明
formIdString表单ID
mobileString手机号码
extendParamsObject扩展参数
successFunction成功回调函数
failFunction失败回调函数

使用示例

FsYxt.FormSDK.sendSMCode({ formId: 'xxx', mobile: '13800138000', success: function(data) { console.log('验证码发送成功'); alert('验证码已发送'); }, fail: function(error) { console.error('验证码发送失败:', error); alert('发送失败,请稍后重试'); } });

4. FormSDK.getAreaData(params)

获取省市区三级联动数据,用于地址字段(country、province、city、district)的编码获取。

参数说明

参数名类型必填说明
extendParamsObject扩展参数
successFunction成功回调函数
failFunction失败回调函数

返回数据结构

返回一个对象(Map),包含 countryprovincecitydistrict 四个字段,每个字段包含对应的选项数据:
{ country: { api_name: "country", define_type: "package", is_required: false, is_index: false, label: "国家", options: [ { label: "中国", // 国家名称 value: "248", // 国家编码(提交时使用此值) child_options: [...], // 子选项(省份数据) resource_bundle_key: "", standard_code: "" }, { label: "阿尔巴尼亚", value: "0", child_options: [...] }, // ... 更多国家(共325个) ] }, province: { api_name: "province", options: [ { label: "北京市", value: "110000", // 省份编码(提交时使用此值) child_options: [...] // 子选项(城市数据) }, // ... 更多省份 ] }, city: { api_name: "city", options: [ { label: "北京市", value: "110100", // 城市编码(提交时使用此值) child_options: [...] // 子选项(区县数据) }, // ... 更多城市(共427个) ] }, district: { api_name: "district", options: [ { label: "东城区", value: "110101" // 区县编码(提交时使用此值) }, // ... 更多区县 ] } }
选项对象说明:
  • label: 显示文本,用于展示给用户
  • value: 选项值,提交表单时必须使用此值
  • child_options: 子选项数组(可选),用于级联选择

使用示例

基础用法
FsYxt.FormSDK.getAreaData({ success: function(data) { console.log('省市区数据:', data); // 访问国家选项 if (data.country && data.country.options) { data.country.options.forEach(function(country) { console.log('国家:', country.label, '编码:', country.value); }); } // 访问省份选项 if (data.province && data.province.options) { data.province.options.forEach(function(province) { console.log('省份:', province.label, '编码:', province.value); }); } // 访问城市选项 if (data.city && data.city.options) { console.log('城市总数:', data.city.options.length); } // 访问区县选项 if (data.district && data.district.options) { console.log('区县总数:', data.district.options.length); } }, fail: function(error) { console.error('获取失败:', error); } });
三级联动选择器实现
var areaData = null; var selectedCountry = null; var selectedProvince = null; var selectedCity = null; var selectedDistrict = null; // 获取省市区数据 FsYxt.FormSDK.getAreaData({ success: function(data) { areaData = data; // 初始化国家下拉框(可选) var countrySelect = document.getElementById('country'); if (data.country && data.country.options) { data.country.options.forEach(function(country) { var option = document.createElement('option'); option.value = country.value; // 使用 value option.textContent = country.label; // 显示 label countrySelect.appendChild(option); }); } // 初始化省份下拉框 var provinceSelect = document.getElementById('province'); if (data.province && data.province.options) { data.province.options.forEach(function(province) { var option = document.createElement('option'); option.value = province.value; // 使用 value option.textContent = province.label; // 显示 label provinceSelect.appendChild(option); }); } // 省份变化时更新城市 provinceSelect.addEventListener('change', function() { var provinceValue = this.value; if (data.province && data.province.options) { selectedProvince = data.province.options.find(function(p) { return p.value === provinceValue; }); } // 更新城市下拉框 var citySelect = document.getElementById('city'); citySelect.innerHTML = '<option value="">请选择城市</option>'; if (selectedProvince && selectedProvince.child_options) { selectedProvince.child_options.forEach(function(city) { var option = document.createElement('option'); option.value = city.value; // 使用 value option.textContent = city.label; // 显示 label citySelect.appendChild(option); }); } }); // 城市变化时更新区县 document.getElementById('city').addEventListener('change', function() { var cityValue = this.value; if (selectedProvince && selectedProvince.child_options) { selectedCity = selectedProvince.child_options.find(function(c) { return c.value === cityValue; }); } // 更新区县下拉框 var districtSelect = document.getElementById('district'); districtSelect.innerHTML = '<option value="">请选择区县</option>'; if (selectedCity && selectedCity.child_options) { selectedCity.child_options.forEach(function(district) { var option = document.createElement('option'); option.value = district.value; // 使用 value option.textContent = district.label; // 显示 label districtSelect.appendChild(option); }); } }); }, fail: function(error) { console.error('获取省市区数据失败:', error); } }); // 提交表单时使用编码 function submitForm() { var formData = { country: document.getElementById('country').value, // 国家编码(可选) province: document.getElementById('province').value, // 省份编码 city: document.getElementById('city').value, // 城市编码 district: document.getElementById('district').value, // 区县编码 address: document.getElementById('address').value // 详细地址文本 }; FsYxt.FormSDK.submitForm({ formId: 'xxx', sceneType: 0, data: formData, success: function(result) { alert('提交成功!'); }, fail: function(error) { alert('提交失败: ' + error.errMsg); } }); }
根据名称查找编码
// 如果用户选择了地址名称,需要查找对应的编码 FsYxt.FormSDK.getAreaData({ success: function(data) { // 根据省份名称查找编码 function findProvinceCode(provinceName) { if (data.province && data.province.options) { var province = data.province.options.find(function(p) { return p.label === provinceName; }); return province ? province.value : ''; } return ''; } // 使用示例 var provinceCode = findProvinceCode('北京市'); console.log('北京市的编码:', provinceCode); // 输出: "110000" // 提交表单 var formData = { province: provinceCode, // 使用编码,不是名称 // ... 其他字段 }; } });

完整示例

场景一: 营销活动落地页

<!DOCTYPE html> <html> <head> <title>产品活动页</title> <script> (function () { var s = document.createElement("script"); s.type = "text/javascript"; s.charset = "utf-8"; s.src = "https://www.fxiaoke.com/ec/kemai/release/static/marketing-website-access.js?id=" + Math.random(); document.getElementsByTagName("head")[0].appendChild(s); })(); </script> </head> <body> <!-- 页面内容 --> <button id="downloadBtn" class="premium-content">下载白皮书</button> <!-- 表单容器 --> <div id="marketing-form"></div> <!-- 二维码容器 --> <div id="qrcode"></div> <script> // 1. 初始化SDK window.addEventListener('load', function() { FsYxt.configure({ ea: "88146", websiteId: "8b28bec67afc42c281f078ff9bea7fec", host: "crm.example.com", enableSpaTracking: false }); // 2. 监听SDK就绪 FsYxt.on('onReady', function() { console.log('SDK初始化完成'); // 3. 上报页面访问埋点 FsYxt.track({ eventId: 'page_view', attributesId: 'landing_page', eventDescription: '访问活动落地页' }); // 4. 创建营销表单 FsYxt.createForm({ id: 'marketing-form', src: 'https://crm.example.com/form/xxxxx', style: 'width:100%;height:600px;', autoheight: true }); // 5. 生成推广二维码 FsYxt.generateQrcode('gzh', 'xxx', { renderType: 'auto', success: function(result) { console.log('二维码已生成'); } }); // 6. 设置会员拦截 FsYxt.memberOperationIntercept({ className: 'premium-content', expires: 7 * 24 * 60 * 60 * 1000 // 7天 }); }); // 7. 监听表单提交 FsYxt.on('onFormSubmit', function(result) { if (result.status === 'ok') { // 上报转化埋点 FsYxt.track({ eventId: 'form_submit', attributesId: 'marketing_form', eventDescription: '提交营销表单' }); alert('提交成功!'); } }); // 8. 按钮点击埋点 document.getElementById('downloadBtn').addEventListener('click', function() { FsYxt.track({ eventId: 'button_click', attributesId: 'download_whitepaper', eventDescription: '点击下载白皮书' }); }); }); </script> </body> </html>

场景二: 自定义表单提交(已知字段结构)

适用于已知表单字段结构的场景,手动构建表单并提交。
<!DOCTYPE html> <html> <head> <title>自定义表单</title> <script> (function () { var s = document.createElement("script"); s.type = "text/javascript"; s.charset = "utf-8"; s.src = "https://www.fxiaoke.com/ec/kemai/release/static/marketing-website-access.js?id=" + Math.random(); document.getElementsByTagName("head")[0].appendChild(s); })(); </script> </head> <body> <form id="customForm"> <div> <label>姓名 <span style="color:red">*</span></label> <input type="text" id="name" name="name" placeholder="请输入姓名" required> </div> <div> <label>手机号 <span style="color:red">*</span></label> <input type="tel" id="phone" name="phone" placeholder="请输入手机号" required> <button type="button" id="sendCodeBtn">发送验证码</button> </div> <div> <label>验证码 <span style="color:red">*</span></label> <input type="text" id="smscode" name="smscode" placeholder="请输入验证码" required> </div> <div> <label>邮箱</label> <input type="email" id="email" name="email" placeholder="请输入邮箱"> </div> <div> <label>公司名称</label> <input type="text" id="companyName" name="companyName" placeholder="请输入公司名称"> </div> <div> <label>职位</label> <input type="text" id="position" name="position" placeholder="请输入职位"> </div> <button type="submit">提交</button> </form> <script> var formId = 'xxx'; var countdown = 0; // 初始化SDK window.addEventListener('load', function() { FsYxt.configure({ ea: "88146", websiteId: "8b28bec67afc42c281f078ff9bea7fec", host: "crm.example.com" }); }); // 发送验证码 document.getElementById('sendCodeBtn').addEventListener('click', function() { if (countdown > 0) return; var phone = document.getElementById('phone').value; if (!phone) { alert('请输入手机号'); return; } FsYxt.FormSDK.sendSMCode({ formId: formId, mobile: phone, success: function() { alert('验证码已发送'); countdown = 60; var btn = document.getElementById('sendCodeBtn'); var timer = setInterval(function() { countdown--; btn.innerText = countdown + 's'; if (countdown <= 0) { clearInterval(timer); btn.innerText = '发送验证码'; } }, 1000); }, fail: function(error) { alert('发送失败: ' + error.errMsg); } }); }); // 提交表单 document.getElementById('customForm').addEventListener('submit', function(e) { e.preventDefault(); // 收集表单数据(使用字段的 apiName) var formData = { name: document.getElementById('name').value, phone: document.getElementById('phone').value, smscode: document.getElementById('smscode').value, email: document.getElementById('email').value, companyName: document.getElementById('companyName').value, position: document.getElementById('position').value }; FsYxt.FormSDK.submitForm({ formId: formId, sceneType: 0, data: formData, success: function(result) { alert('提交成功!'); document.getElementById('customForm').reset(); }, fail: function(error) { alert('提交失败: ' + error.errMsg); } }); }); </script> </body> </html>

场景三: 动态渲染表单(根据字段配置自动生成)

适用于需要根据表单配置动态生成表单的场景,无需手动编写HTML,完全由SDK字段配置驱动。
<!DOCTYPE html> <html> <head> <title>动态表单</title> <script> (function () { var s = document.createElement("script"); s.type = "text/javascript"; s.charset = "utf-8"; s.src = "https://www.fxiaoke.com/ec/kemai/release/static/marketing-website-access.js?id=" + Math.random(); document.getElementsByTagName("head")[0].appendChild(s); })(); </script> <style> .form-container { max-width: 600px; margin: 20px auto; padding: 20px; } .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; font-weight: bold; } .form-group input, .form-group select, .form-group textarea { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } .form-group textarea { min-height: 80px; } .form-group .help-text { font-size: 12px; color: #666; margin-top: 4px; } .required { color: red; } .checkbox-group { margin: 5px 0; } .checkbox-group label { font-weight: normal; margin-left: 5px; } .send-code-btn { margin-left: 10px; padding: 8px 15px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .send-code-btn:disabled { background: #ccc; cursor: not-allowed; } .submit-btn { width: 100%; padding: 12px; background: #28a745; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; } </style> </head> <body> <div class="form-container"> <h2 id="form-title">加载中...</h2> <form id="dynamicForm"></form> </div> <script> var formId = 'xxx'; var countdown = 0; var formFields = []; // 存储字段配置 // 初始化SDK window.addEventListener('load', function() { FsYxt.configure({ ea: "88146", websiteId: "8b28bec67afc42c281f078ff9bea7fec", host: "crm.example.com" }); // 等待SDK就绪后加载表单 FsYxt.on('onReady', function() { loadForm(); }); }); // 加载表单配置并渲染 function loadForm() { FsYxt.FormSDK.getFieldDescriptions({ formId: formId, success: function(data) { formFields = data.fields; // 设置表单标题 document.getElementById('form-title').textContent = data.info.title || data.info.name || '表单'; // 渲染表单 renderForm(data.fields); }, fail: function(error) { console.error('获取表单配置失败:', error); document.getElementById('form-title').textContent = '表单加载失败'; } }); } // 渲染表单字段 function renderForm(fields) { var form = document.getElementById('dynamicForm'); form.innerHTML = ''; // 清空表单 fields.forEach(function(field) { var formGroup = document.createElement('div'); formGroup.className = 'form-group'; // 创建标签 var label = document.createElement('label'); label.textContent = field.label; if (field.isRequired) { var required = document.createElement('span'); required.className = 'required'; required.textContent = ' *'; label.appendChild(required); } formGroup.appendChild(label); // 根据字段类型创建输入元素 var inputElement = null; if (field.type === 'text' || field.type === 'email' || field.type === 'phone_number') { inputElement = document.createElement('input'); inputElement.type = field.type === 'email' ? 'email' : field.type === 'phone_number' ? 'tel' : 'text'; inputElement.name = field.apiName; inputElement.placeholder = field.helpText || field.label; inputElement.required = field.isRequired; // 如果是手机号字段,添加发送验证码按钮 if (field.type === 'phone_number') { var phoneContainer = document.createElement('div'); phoneContainer.style.display = 'flex'; phoneContainer.style.alignItems = 'center'; inputElement.style.flex = '1'; phoneContainer.appendChild(inputElement); var sendCodeBtn = document.createElement('button'); sendCodeBtn.type = 'button'; sendCodeBtn.className = 'send-code-btn'; sendCodeBtn.textContent = '发送验证码'; sendCodeBtn.onclick = function() { sendSMCode(field.apiName, sendCodeBtn); }; phoneContainer.appendChild(sendCodeBtn); formGroup.appendChild(phoneContainer); } else { formGroup.appendChild(inputElement); } } else if (field.type === 'multi_text') { inputElement = document.createElement('textarea'); inputElement.name = field.apiName; inputElement.placeholder = field.helpText || field.label; inputElement.required = field.isRequired; formGroup.appendChild(inputElement); } else if (field.type === 'select_one') { inputElement = document.createElement('select'); inputElement.name = field.apiName; inputElement.required = field.isRequired; // 添加空选项 var emptyOption = document.createElement('option'); emptyOption.value = ''; emptyOption.textContent = '请选择'; inputElement.appendChild(emptyOption); // 添加选项(使用 value 作为选项值) if (field.options && field.options.length > 0) { field.options.forEach(function(option) { var optionElement = document.createElement('option'); optionElement.value = option.value; // 使用 value optionElement.textContent = option.label; inputElement.appendChild(optionElement); }); } formGroup.appendChild(inputElement); } else if (field.type === 'select_manny') { // 多选使用 checkbox if (field.options && field.options.length > 0) { field.options.forEach(function(option) { var checkboxContainer = document.createElement('div'); checkboxContainer.className = 'checkbox-group'; var checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.name = field.apiName; checkbox.value = option.value; // 使用 value checkbox.id = field.apiName + '_' + option.value; var checkboxLabel = document.createElement('label'); checkboxLabel.htmlFor = checkbox.id; checkboxLabel.textContent = option.label; checkboxContainer.appendChild(checkbox); checkboxContainer.appendChild(checkboxLabel); formGroup.appendChild(checkboxContainer); }); } } else if (field.type === 'number') { inputElement = document.createElement('input'); inputElement.type = 'number'; inputElement.name = field.apiName; inputElement.placeholder = field.helpText || field.label; inputElement.required = field.isRequired; formGroup.appendChild(inputElement); } else if (field.type === 'date_time') { inputElement = document.createElement('input'); inputElement.type = 'datetime-local'; inputElement.name = field.apiName; inputElement.required = field.isRequired; formGroup.appendChild(inputElement); } else if (field.type === 'image' || field.type === 'files') { // 图片或文件上传 inputElement = document.createElement('input'); inputElement.type = 'file'; inputElement.name = field.apiName; inputElement.required = field.isRequired; if (field.type === 'image') { inputElement.accept = 'image/*'; } formGroup.appendChild(inputElement); } // 添加帮助文本 if (field.helpText) { var helpText = document.createElement('div'); helpText.className = 'help-text'; helpText.textContent = field.helpText; formGroup.appendChild(helpText); } form.appendChild(formGroup); }); // 添加提交按钮 var submitBtn = document.createElement('button'); submitBtn.type = 'submit'; submitBtn.className = 'submit-btn'; submitBtn.textContent = '提交'; form.appendChild(submitBtn); // 绑定提交事件 form.addEventListener('submit', function(e) { e.preventDefault(); submitForm(); }); } // 发送验证码 function sendSMCode(phoneFieldName, btn) { if (countdown > 0) return; var phoneInput = document.querySelector('input[name="' + phoneFieldName + '"]'); var phone = phoneInput ? phoneInput.value : ''; if (!phone) { alert('请输入手机号'); return; } FsYxt.FormSDK.sendSMCode({ formId: formId, mobile: phone, success: function() { alert('验证码已发送'); countdown = 60; var timer = setInterval(function() { countdown--; btn.textContent = countdown + 's'; btn.disabled = true; if (countdown <= 0) { clearInterval(timer); btn.textContent = '发送验证码'; btn.disabled = false; } }, 1000); }, fail: function(error) { alert('发送失败: ' + error.errMsg); } }); } // 提交表单 function submitForm() { var form = document.getElementById('dynamicForm'); var formData = {}; var formElements = form.elements; // 收集表单数据 for (var i = 0; i < formElements.length; i++) { var element = formElements[i]; if (element.name && element.type !== 'button') { if (element.type === 'checkbox') { // 多选处理 if (!formData[element.name]) { formData[element.name] = []; } if (element.checked) { formData[element.name].push(element.value); } } else if (element.value) { var value = element.value; // 日期时间字段需要转换为时间戳(毫秒) var field = formFields.find(function(f) { return f.apiName === element.name; }); if (field && field.type === 'date_time') { // 将日期时间字符串转换为时间戳(毫秒) value = new Date(value).getTime(); } formData[element.name] = value; } } } // 验证必填字段 var missingFields = []; formFields.forEach(function(field) { if (field.isRequired) { var value = formData[field.apiName]; if (!value || (Array.isArray(value) && value.length === 0)) { missingFields.push(field.label); } } }); if (missingFields.length > 0) { alert('请填写必填字段: ' + missingFields.join('、')); return; } // 提交表单 FsYxt.FormSDK.submitForm({ formId: formId, sceneType: 0, data: formData, success: function(result) { alert('提交成功!'); form.reset(); }, fail: function(error) { alert('提交失败: ' + error.errMsg); } }); } </script> </body> </html>

场景四: React单页应用集成

import React, { useEffect } from 'react'; function App() { useEffect(() => { // 初始化SDK if (window.FsYxt) { window.FsYxt.configure({ ea: "88146", websiteId: "8b28bec67afc42c281f078ff9bea7fec", host: "crm.example.com", enableSpaTracking: true // 启用SPA路由埋点 }); // 监听SDK就绪 window.FsYxt.on('onReady', () => { console.log('FsYxt SDK Ready'); }); // 监听表单提交 window.FsYxt.on('onFormSubmit', (result) => { if (result.status === 'ok') { console.log('Form submitted successfully'); } }); } }, []); const handleButtonClick = () => { // 上报点击事件 window.FsYxt.track({ eventId: 'button_click', attributesId: 'cta_button', eventDescription: 'CTA按钮点击' }); }; return ( <div className="App"> <h1>React应用示例</h1> <button onClick={handleButtonClick}>立即咨询</button> </div> ); } export default App;

最佳实践

1. 初始化时机

  • 建议在 window.onloadDOMContentLoaded 事件后初始化
  • 确保DOM元素已加载完成再调用相关方法

2. 错误处理

FsYxt.on('onError', function(error) { // 记录错误日志 console.error('SDK Error:', error); // 可选: 上报到监控系统 });

3. 事件埋点规范

  • 使用清晰的事件ID命名规则,如 page_viewbutton_clickform_submit
  • 事件描述应简洁明了,便于后续数据分析
  • 关键业务节点务必添加埋点

4. 表单数据验证

function validateFormData(data) { if (!data.name || !data.phone) { alert('姓名和手机号不能为空'); return false; } if (!/^1[3-9]\d{9}$/.test(data.phone)) { alert('手机号格式不正确'); return false; } return true; } // 使用 if (validateFormData(formData)) { FsYxt.FormSDK.submitForm({ ... }); }

5. 性能优化

  • 避免频繁调用 track() 方法,建议对高频事件进行节流或防抖处理
  • 使用 createForm() 时,合理设置 iframe 尺寸,避免影响页面性能

常见问题

Q1: SDK初始化失败怎么办?

A: 检查以下几点:
  1. 确认 eawebsiteIdhost 参数正确
  2. 检查网络连接是否正常
  3. 查看浏览器控制台是否有报错信息
  4. 监听 onError 事件获取详细错误信息

Q2: 单页应用如何启用路由埋点?

A: 在 configure() 时设置 enableSpaTracking: true:
FsYxt.configure({ ea: "88146", websiteId: "xxx", host: "crm.example.com", enableSpaTracking: true // 关键配置 });

Q3: 如何获取访客ID?

A: 使用 getConfig() 方法:
var config = FsYxt.getConfig(); var visitorId = config.visitorId; // 或 config.fsWebsiteUid

Q4: 表单提交失败如何排查?

A:
  1. 确认 formId 是否正确
  2. 检查表单数据格式是否符合要求
  3. 查看 fail 回调中的错误信息
  4. 确认SDK已成功初始化(监听 onReady 事件)

Q5: 会员拦截功能不生效?

A:
  1. 确认元素类名设置正确
  2. 检查会员登录态是否已过期
  3. 确认后台会员配置是否正确

Q6: FsYxt报错 "FsYxt is not defined" 或方法调用失败?

A: 请确保SDK已完成加载后再执行相关方法:
// 推荐做法:在 window.onload 事件后执行 window.addEventListener('load', function() { FsYxt.configure({ ea: "88146", websiteId: "xxx", host: "crm.example.com" }); // 等待SDK初始化完成 FsYxt.on('onReady', function() { // 在此处调用其他SDK方法 FsYxt.track({ ... }); }); });
常见错误场景:
  • ❌ 在SDK脚本加载前就调用 FsYxt 对象
  • ❌ 在 <head> 中直接执行SDK方法
  • ✅ 使用 window.onloadDOMContentLoaded 事件
  • ✅ 监听 onReady 事件确保SDK初始化完成

技术支持

如有其他问题,请联系技术支持团队。
版本: v2.0
更新日期: 2025-12-05
2025-12-05
0 0