官网SDK技术文档

概述

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

快速开始

方式一:推荐方式

步骤1: 引入SDK

建议: 将以下脚本放在网页 <head> 中前置加载,确保 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配置,必须在使用其他功能前调用。

参数说明

参数名 类型 必填 说明
ea String 应用源ID
websiteId String 网站ID
host String 主机地址
enableSpaTracking Boolean 是否启用单页应用(SPA)埋点,默认false

使用示例

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

2. track(params)

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

参数说明

参数名 类型 必填 说明
eventId String 事件ID
attributesId String/Array 事件属性ID(传数组时取第一个)
marketingEventId String 市场活动ID
eventDescription String 事件描述
success Function 成功回调函数
fail Function 失败回调函数

使用示例

场景一:单一事件单一按钮上报

适用于单个按钮的埋点上报场景,直接在代码中调用 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 嵌入和 SDK 直接渲染两种模式。

参数说明

参数名 类型 必填 说明
id String 表单容器元素的ID
renderMode String 渲染模式: 'iframe'(默认) 或 'sdk'
src String 条件必填 表单页面URL(iframe模式必填;sdk模式下如未传formId/siteId/pageId,将自动从src提取参数)
style String iframe样式(CSS字符串,仅iframe模式)
autoheight Boolean 是否自动适应高度(仅iframe模式)
SDK 模式额外参数
参数名 类型 必填 说明
formId String 表单ID( 线索表单 ID)
siteId String 站点ID(微页面站点 ID)
pageId Number 微页面页面ID
sdkParams Object 透传给SDK初始化方法的额外参数
onMounted Function 挂载完成回调(仅SDK模式,表单渲染完成后触发)
fail Function 错误回调(仅SDK模式),参数为 { errCode, errMsg }。errCode: -1 SDK加载超时, -2 容器元素未找到

返回值(SDK 模式)

SDK 模式下 createForm 会返回一个 SDK 实例对象,支持调用 destroy() 方法销毁表单。在 SPA 单页应用中,页面切换时应调用 destroy() 释放资源。

// 创建表单,保存实例引用
var formInstance = FsYxt.createForm({
    id: 'form-container',
    renderMode: 'sdk',
    formId: 'xxx'
});

// 页面切换或不再需要时,销毁表单实例
if (formInstance) {
    formInstance.destroy();
}

注意: iframe 模式不返回实例,直接移除容器内的 iframe DOM 即可。

SDK 模式说明:

  • SDK 模式依赖表单 SDK 脚本(formSDK.js),需要使用侧自行加载createForm 仅检查 window.FsMarketingPageSDK 是否存在
  • 表单 SDK CDN 地址: https://a9.fspage.com/ec/h5-landing/release/formSDK-1.0.0.js,加载时需拼接随机字符串避免缓存,如: ?v= + Math.random()
  • 加载完成后会注册全局变量 window.FsMarketingPageSDK
  • 如果调用 createFormwindow.FsMarketingPageSDK 不存在,会打印警告并中止执行
  • 如果已传 formId/siteId/pageId 等参数,直接使用这些参数初始化
  • 如果未传上述参数但传了 src,会自动解析 src 链接上的 id/formId 等参数用于 SDK 初始化
  • 支持历史 iframe 使用方式无缝切换到 SDK 模式,只需增加 renderMode: 'sdk' 即可
  • SDK 模式下 sourceType 默认为 7,无需额外传递
加载表单 SDK 脚本

使用 SDK 模式前,需要先加载表单 SDK 脚本:

建议: 将以下脚本放在网页 <head> 中前置加载(与官网 SDK 一起),确保调用 createForm 时 SDK 已加载完成。

<script>
    (function () {
        var s = document.createElement("script");
        s.type = "text/javascript";
        s.charset = "utf-8";
        s.src = "https://a9.fspage.com/ec/h5-landing/release/formSDK-1.0.0.js?v=" + Math.random();
        document.getElementsByTagName("head")[0].appendChild(s);
    })();
</script>

确保表单 SDK 加载完成后再调用 createForm(即 window.FsMarketingPageSDK 已存在)。

使用示例

iframe 模式(默认,兼容旧用法)
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
});
SDK 模式 - 使用 formId 直接渲染表单
FsYxt.createForm({
    id: 'form-container',
    renderMode: 'sdk',
    formId: 'your-form-id',
    onMounted: function() {
        console.log('表单已渲染');
    },
    fail: function(err) {
        console.error('表单加载失败:', err.errCode, err.errMsg);
    }
});
SDK 模式 - 使用 siteId 渲染落地页
FsYxt.createForm({
    id: 'form-container',
    renderMode: 'sdk',
    siteId: 'xxx',
    onMounted: function() {
        console.log('落地页已渲染');
    }
});
SDK 模式 - 从 src 自动提取参数(兼容历史用法,仅需加 renderMode)

历史使用方式只需加一个 renderMode: 'sdk' 即可无缝切换到 SDK 渲染:

// 原有 iframe 方式
FsYxt.createForm({
    id: 'form-container-c',
    src: 'https://www.fxiaoke.com/proj/page/marketing-page?objectType=28&ea=your-ea&id=your-site-id&sourceType=7&objectId=your-object-id&type=1',
    style: 'width:100%;height:100%;'
});

// 切换为 SDK 模式,只需增加 renderMode: 'sdk'
FsYxt.createForm({
    id: 'form-container-c',
    renderMode: 'sdk',
    src: 'https://www.fxiaoke.com/proj/page/marketing-page?objectType=28&ea=your-ea&id=your-site-id&sourceType=7&objectId=your-object-id&type=1',
    style: 'width:100%;height:100%;'
});

// 也支持 formId 在 src 中的场景
FsYxt.createForm({
    id: 'form-container-c',
    renderMode: 'sdk',
    src: 'https://www.fxiaoke.com/proj/page/marketing-page?objectType=28&ea=your-ea&formId=your-form-id&sourceType=7&objectId=your-object-id&type=1',
    style: 'width:100%;height:100%;'
});
<!-- 在页面中预留表单容器 -->
<div id="form-container"></div>

4. generateQrcode(type, fanQrCodeId, options)

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

参数说明

参数名 类型 必填 说明
type String 二维码类型: "gzh"(公众号) 或 "qw"(企业微信)
fanQrCodeId String 场景ID或粉丝码ID
options Object 配置选项
options.renderType String 渲染类型: "auto"(自动渲染) 或 "manual"(手动渲染),默认"auto"
options.container String/HTMLElement auto模式二维码挂载容器,支持元素ID、CSS选择器或DOM元素
options.style String/Object auto模式二维码容器样式,不设置时使用默认固定定位样式
options.containerStyle String/Object auto模式二维码容器样式,会覆盖/补充style
options.qrCodeStyle String/Object auto模式二维码图片样式
options.imageStyle String/Object auto模式二维码图片样式,作用同qrCodeStyle
options.success Function 成功回调函数
options.fail Function 失败回调函数

使用示例

// 自动渲染模式
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('gzh', 'gzh-qr-code-id', {
    renderType: 'auto',
    container: 'gzh-qrcode',
    containerStyle: {
        width: '120px',
        height: '120px'
    },
    qrCodeStyle: {
        maxWidth: '120px',
        borderRadius: '8px'
    }
});

FsYxt.generateQrcode('qw', 'qw-qr-code-id', {
    renderType: 'auto',
    container: document.getElementById('qw-qrcode'),
    style: 'width:120px;height:120px;'
});

// 手动渲染模式
FsYxt.generateQrcode('qw', 'xxx', {
    renderType: 'manual',
    success: function(result) {
        // 自行处理二维码URL
        document.getElementById('my-qrcode').src = result.qrUrl;
    }
});

5. memberOperationIntercept(params)

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

参数说明

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

使用示例

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端)。

参数说明

参数名 类型 必填 说明
className String 登录表单容器元素类名
onFormSubmit Function 表单提交回调函数
expires Number 会员登录态过期时间(毫秒)

使用示例

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参数等。

返回值

返回一个包含以下字段的对象:

字段名 类型 说明
visitorId String 访客唯一标识
fsWebsiteUid String 网站访客ID
websiteId String 网站ID
host String 主机地址
ea String 应用源ID
utmSource String UTM来源
utmMedium String UTM媒介
utmCampaign String UTM活动
utmContent String UTM内容
utmTerm String UTM关键词
... ... 其他扩展参数

使用示例

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

9. on(eventName, handler)

绑定SDK事件回调。

支持的事件

事件名 触发时机 回调参数
onReady SDK初始化完成
onError SDK初始化失败 (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)

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

参数说明

参数名 类型 必填 说明
formId String 表单ID
extendParams Object 扩展参数
success Function 成功回调函数
fail Function 失败回调函数

返回数据结构

{
    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)

提交自定义表单数据。

参数说明

参数名 类型 必填 说明
formId String 表单ID
enrollId String 报名ID(用于更新已有报名)
sceneType Number 场景类型: 0-当前页为转化页, 2-上一页为转化页
data Object 表单数据
extendParams Object 扩展参数
success Function 成功回调函数
fail Function 失败回调函数

表单数据字段说明

重要提示:

  1. 字段名称请使用 getFieldDescriptions 接口返回的 apiName 字段值
  2. 对于单选(select_one)、多选(select_manny)字段,必须使用 getFieldDescriptions 接口返回的 options 中的 value
  3. 系统字段(如 name、phone、email 等)和自定义字段(如 text5_xxx、text7_xxx 等)的传值方式相同
系统字段(常用)
apiName 字段类型 传值类型 示例 说明
name 姓名 String name: "张三" 文本字符串
phone 手机号 String phone: "13800138000" 手机号格式字符串
email 邮箱 String email: "test@example.com" 邮箱格式字符串
companyName 公司 String company: "XX科技有限公司" 公司名称
position 职位 String position: "产品经理" 职位名称
country 国家 String country: "CN" 国家编码,从 getAreaData 获取
province String province: "110000" 省份编码,从 getAreaData 获取
city String city: "110100" 城市编码,从 getAreaData 获取
district String district: "110101" 区县编码,从 getAreaData 获取
address 详细地址 String address: "XX街道XX号" 详细地址文本
自定义字段类型
字段类型 type 值 传值类型 传值说明 示例
单行文本 text String 直接传文本值 text5_xxx: "网站地址"
多行文本 multi_text String 直接传文本值 text6_xxx: "这是一段描述\n换行内容"
邮箱 email String 邮箱格式字符串 email: "user@example.com"
手机号 phone_number String 手机号格式字符串 phone: "13800138000"
单选 select_one String 必须使用 options 中的 value 值 text7_xxx: "ae3748076b822385"
多选 select_manny Array 必须使用 options 中的 value 值数组 texts1_xxx: ["value1", "value2"]
数字 number Number 数字类型 num1_xxx: 100
日期时间 date_time Number 时间戳(毫秒) num2_xxx: 1737360000000
图片 image String 图片URL地址 picMap_xxx: "https://example.com/image.jpg"
文件附件 files String 文件URL地址 fileAttachmentMap_xxx: "https://example.com/file.pdf"
字段传值注意事项
  1. 单选字段传值

    // ❌ 错误:使用选项的 label
    text7_xxx: "0-4"
    
    // ✅ 正确:使用选项的 value(从 getFieldDescriptions 获取)
    text7_xxx: "1"
    
  2. 多选字段传值(type 为 select_manny):

    // ❌ 错误:使用选项的 label 数组
    texts1_xxx: ["选项A", "选项B"]
    
    // ✅ 正确:使用选项的 value 数组
    texts1_xxx: ["ae3748076b822385", "445dad1a25b6f5ff"]
    
  3. 日期时间字段传值(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()
    
  4. 地址字段传值(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"
    
  5. 必填字段

    • 通过 getFieldDescriptions 获取字段配置,检查 isRequired 属性
    • 所有 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)

发送短信验证码。

参数说明

参数名 类型 必填 说明
formId String 表单ID
mobile String 手机号码
extendParams Object 扩展参数
success Function 成功回调函数
fail Function 失败回调函数

使用示例

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)的编码获取。

参数说明

参数名 类型 必填 说明
extendParams Object 扩展参数
success Function 成功回调函数
fail Function 失败回调函数

返回数据结构

返回一个对象(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="gzh-qrcode"></div>
    <div id="qw-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',
                    container: 'gzh-qrcode',
                    containerStyle: {
                        width: '120px',
                        height: '120px'
                    },
                    success: function(result) {
                        console.log('二维码已生成');
                    }
                });

                FsYxt.generateQrcode('qw', 'yyy', {
                    renderType: 'auto',
                    container: document.getElementById('qw-qrcode'),
                    style: 'width:120px;height:120px;'
                });
                
                // 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初始化完成

Q7: SDK 模式报错 "window.FsMarketingPageSDK is not available"?

A: 这说明表单 SDK 脚本(formSDK.js)未加载或尚未加载完成。请检查:

  1. 确认页面中是否已引入表单 SDK 脚本:
    <script>
        (function () {
            var s = document.createElement("script");
            s.type = "text/javascript";
            s.charset = "utf-8";
            s.src = "https://a9.fspage.com/ec/h5-landing/release/formSDK-1.0.0.js?v=" + Math.random();
            document.getElementsByTagName("head")[0].appendChild(s);
        })();
    </script>
    
  2. 确认脚本放在 <head> 中前置加载
  3. 确认调用 createForm 时脚本已加载完成(可在 window.onload 后调用,或监听脚本 onload 事件)
  4. 检查浏览器控制台网络请求,确认 formSDK.js 是否返回 200

Q8: SDK 模式表单提交报错?

A: 需要确认当前官网域名是否已添加到营销通后台的官网列表中进行绑定。

排查步骤:

  1. 登录营销通后台,进入官网管理
  2. 确认当前官网域名已添加到官网列表中
  3. 确认官网与表单之间的绑定关系正确
  4. 如果是跨域场景,确认域名白名单配置正确

Q9: SDK 模式表单样式异常?

A: SDK 模式下表单直接渲染在页面 DOM 中(非 iframe 隔离),官网自身的 CSS 样式可能会影响表单控件内部样式。

排查和解决方法:

  1. 使用浏览器开发者工具检查表单元素,确认是否有外部样式覆盖了表单组件样式
  2. 常见影响:全局 inputselectbuttonlabel 等标签样式、CSS reset/normalize 样式
  3. 如果存在样式冲突,可自行编写覆盖样式进行修正,例如:
    /* 针对表单 SDK 容器内的元素重置样式 */
    #form-container input {
        /* 覆盖官网全局样式 */
        box-sizing: border-box;
        height: auto;
    }
    
  4. 建议为表单容器设置独立的作用域,避免全局样式污染

技术支持

如有其他问题,请联系技术支持团队。


版本: v2.0
更新日期: 2025-01-20

2026-07-25
0 0