with one click
yida-custom-page
// 宜搭自定义页面开发技能,包含宜搭表单 JS API 调用(增删改查/流程/工具类共 27 个)、React 16 JSX 组件开发规范、状态管理模式与编码约束。
// 宜搭自定义页面开发技能,包含宜搭表单 JS API 调用(增删改查/流程/工具类共 27 个)、React 16 JSX 组件开发规范、状态管理模式与编码约束。
宜搭平台退出登录技能,清空本地 Cookie 缓存内容。
宜搭表单页面创建与更新技能,支持创建新表单(saveFormSchemaInfo + saveFormSchema + updateFormConfig)和更新已有表单(getFormSchema + saveFormSchema + updateFormConfig),支持 19 种字段类型(含 SerialNumberField 流水号)和字段增删改操作。
宜搭自定义页面创建技能,通过调用 saveFormSchemaInfo 接口快速创建自定义展示页面。
宜搭表单 Schema 获取技能,通过调用 getFormSchema 接口获取指定表单的完整 Schema 结构,用于分析字段定义、组件配置、确认字段 ID(fieldId)等。
宜搭自定义页面发布技能,将 JSX 源码经 Babel 编译、UglifyJS 压缩后构建 Schema,并通过 saveFormSchema 接口部署到宜搭平台。
宜搭完整应用开发技能,描述从零到一搭建一个完整宜搭应用的全流程,包括创建应用、创建页面、需求分析、编写代码、创建表单、发布部署。
| name | yida-custom-page |
| description | 宜搭自定义页面开发技能,包含宜搭表单 JS API 调用(增删改查/流程/工具类共 27 个)、React 16 JSX 组件开发规范、状态管理模式与编码约束。 |
| license | MIT |
| compatibility | ["opencode","claude-code"] |
| metadata | {"audience":"developers","workflow":"yida-development","version":"1.0.0","tags":["yida","low-code","react","custom-page"]} |
本技能提供在阿里宜搭低代码平台上开发自定义页面的完整能力,涵盖从编码到部署的全流程:
| 能力 | 说明 |
|---|---|
| 表单数据操作 | 通过宜搭前端 JS API(this.utils.yida.*)对表单数据进行增删改查 |
| JSX 组件开发 | 编写 React 16 兼容的 JSX 代码,实现个性化定制页面 |
| AI 能力集成 | 调用大模型 AI 接口(/query/intelligent/txtFromAI.json)实现智能文本生成 |
| 自动编译部署 | 通过工具链将源码编译、压缩,并自动合并到宜搭 Schema 中保存 |
当以下场景发生时使用此技能:
注意:编译和发布功能由
yida-publish-page技能提供,此处仅作流程说明。
场景:将 JSX 源码编译为宜搭可用的格式 依赖:需先安装 yida-publish-page 依赖 命令:
cd .claude/skills/yida-publish-page/scripts && npm install
node babel-transform/transform.js pages/src/my-page.js
场景:编译并发布自定义页面到宜搭平台 命令:
node .claude/skills/yida-publish-page/scripts/publish.js APP_XXX FORM-XXX pages/src/my-page.js
playwright(用于登录态管理)cd .claude/skills/yida-publish/scripts && npm install
pip install playwright && playwright install chromium
node scripts/babel-transform/transform.js <源文件路径>
编译流程:
源文件(.js) → @ali/vu-babel-transform (Babel 转换) → UglifyJS (压缩) → <name>.compile.js
cd .claude/skills/yida-publish-page/scripts
npm install # 首次需要安装依赖
node publish.js <appType> <formUuid> <源文件路径>
部署流程:
编译源码(Babel + UglifyJS) → 代码动态构建 Schema JSON(填入 source/compiled)
→ 调用 yida-login 获取登录态(Cookie 持久化) → 调用 saveFormSchema 接口保存
参数说明:
| 参数 | 说明 | 示例 |
|---|---|---|
appType | 应用 ID | APP_XXX |
formUuid | 表单 ID | FORM-XXX |
源文件路径 | 源码文件路径 | pages/src/xxx.js |
baseUrl无需手动传入,脚本会自动调用login.py获取登录态并从中读取base_url。
以下规范是编写宜搭自定义页面代码的核心约束,必须严格遵守。
宜搭自定义页面的 JSX 组件本质上是 React 类组件中的 render 方法,而非独立的 React 组件。因此存在以下关键约束:
| 约束 | 说明 |
|---|---|
| React 版本 | 必须兼容 React 16,禁止使用 Hooks(useState、useEffect 等) |
| 单文件 | 所有代码写在一个文件中(如 index.js) |
| 三方包引入 | 禁止使用 import/require 语法,如需使用第三方库,必须通过 this.utils.loadScript 加载 CDN 脚本,参考 yida-api.md 的「工具类 API」章节。 |
| 函数导出格式 | 使用 export function xxx() {} 格式导出函数 |
| 样式 | 所有 css 必须写在 renderJsx 的方法中,通过 style 的方式引入 |
this 上下文 | 所有导出函数中的 this 指向宜搭页面的 React 类实例 |
禁止使用 this.setState 管理业务状态 | this.setState 已被覆盖,仅用于 forceUpdate(通过更新 timestamp) |
| JavaScript 版本 | 使用 ES2015 (ES6) 语法,不能高于 ES2015 版本 |
| 必须定义 renderJsx 函数 | renderJsx 是宜搭自定义页面核心渲染函数,也是入口函数,必须严格定义,不要改为其他名称 |
一个完整的宜搭自定义页面源文件必须包含:
_customState 变量以下是一个完整自定义页面示例,包含状态管理、生命周期钩子、渲染函数
// ============================================================
// 状态管理
// ============================================================
const _customState = {
// 在此定义所有业务状态的初始值
count: 0,
loading: false,
};
/**
* 获取状态
* @param {string} [key] - 传入 key 返回单个值,不传返回全部状态的浅拷贝
*/
export function getCustomState(key) {
if (key) {
return _customState[key];
}
return { ..._customState };
}
/**
* 设置状态(合并更新,自动触发重新渲染)
* @param {Object} newState - 需要更新的状态键值对
*/
export function setCustomState(newState) {
Object.keys(newState).forEach(function(key) {
_customState[key] = newState[key];
});
this.forceUpdate();
}
/**
* 强制重新渲染(通过更新 timestamp 触发 React 重渲染)
*/
export function forceUpdate() {
this.setState({ timestamp: new Date().getTime() });
}
// ============================================================
// 生命周期
// ============================================================
/**
* 页面加载完成时调用
* 用于:初始化数据、启动定时器、绑定事件等
*/
export function didMount() {
// 初始化逻辑
}
/**
* 页面卸载时调用
* 用于:清理定时器、解绑事件、释放资源等
*/
export function didUnmount() {
// 清理逻辑
}
export function handleSubmit(e) {
this.setCustomState({ submitted: true });
this.utils.toast({ title: '提交成功', type: 'success' });
}
// ============================================================
// 渲染
// ============================================================
/**
* 页面渲染函数(等同于 React 类组件的 render 方法)
* 注意:必须包含隐藏的 timestamp div 以支持 forceUpdate 机制
*/
export function renderJsx() {
const { timestamp } = this.state;
return (
<div>
{/* 必须保留:用于触发重新渲染 */}
<div style={{ display: "none" }}>{timestamp}</div>
{/* 页面内容写在这里 */}
<div onClick={(e) => {this.handleSubmit(e)}>提交</div>
</div>
);
}
// 获取全部状态(返回浅拷贝)
const state = this.getCustomState();
// 获取单个状态值
const count = this.getCustomState('count');
// 设置状态并自动触发重新渲染
this.setCustomState({ count: count + 1, loading: true });
// 仅触发重新渲染(不修改状态)
this.forceUpdate();
| 钩子函数 | 触发时机 | 典型用途 |
|---|---|---|
didMount() | 页面 DOM 加载渲染完毕 | 初始化数据加载、启动定时器、绑定事件 |
didUnmount() | 页面节点从 DOM 移除 | 清理 setInterval / setTimeout、解绑事件 |
| 变量 | 类型 | 说明 |
|---|---|---|
window.g_config._csrf_token | String | CSRF Token,调用需认证的接口(如 AI 接口、Schema 保存)时必须携带 |
window.loginUser.userId | String | 当前登录用户的工号 |
window.loginUser.userName | String | 当前登录用户的姓名 |
this.state.urlParams | Object | 页面 URL 中的查询参数 |
自定义方法必须用 export function 定义:凡是需要在方法内部使用 this(包括 this.utils.yida.*、this.setCustomState 等)的自定义方法,必须且只能使用 export function 方法名() {} 的形式定义,调用时使用 this.方法名()。禁止使用 const fn = () => {}、const fn = function() {} 等形式定义需要访问 this 的方法,这些形式无法被宜搭运行时正确绑定 this:
// ✅ 正确:export function + this.方法名() 调用
export function didMount() {
this.loadStatistics();
}
export function loadStatistics() {
this.utils.yida.searchFormDatas({ formUuid: 'FORM-XXX', pageSize: 10 });
}
// ❌ 错误①:缺少 export,无法被宜搭运行时识别,this 丢失
export function didMount() {
loadStatistics(); // 直接调用,this 丢失
}
function loadStatistics() {
this.utils.yida.searchFormDatas(...); // 报错:this is undefined
}
// ❌ 错误②:箭头函数/函数表达式形式,缺少 export,无法被宜搭运行时绑定 this,禁止使用
const loadStatistics = () => {
this.utils.yida.searchFormDatas(...); // 报错:this is undefined
};
const loadStatistics = function() {
this.utils.yida.searchFormDatas(...); // 报错:this is undefined
};
【严格禁止】事件绑定必须使用箭头函数包裹:在 renderJsx 中绑定任何事件处理器(onClick、onChange、onSubmit 等)时,必须且只能使用箭头函数 (e) => { this.方法名(e) } 的形式,严禁直接写 this.方法名 作为事件处理器,否则 this 会丢失导致运行时报错:
export function handleSubmit(e) {
this.setCustomState({ submitted: true });
this.utils.toast({ title: '提交成功', type: 'success' });
}
// ✅ 正确:箭头函数包裹,this 正确捕获
export function renderJsx() {
return <button onClick={(e) => { this.handleSubmit(e); }}>提交</button>;
}
// ❌ 错误①:直接传方法引用,this 丢失,运行时报错,绝对禁止!
export function renderJsx() {
return <button onClick={this.handleSubmit}>提交</button>;
}
// ❌ 错误②:使用 .bind(this) 绑定,虽然能运行但不符合规范,禁止使用!
export function renderJsx() {
return <button onClick={function() { this.handleSubmit(); }.bind(this)}>提交</button>;
}
生成代码时的自检清单:检查
renderJsx中所有onClick、onChange、onSubmit等事件属性,确保每一个都是(e) => { this.xxx(e) }形式,不存在任何onClick={this.xxx}的写法。
输入法组合输入处理:使用 _isComposing 标记配合 compositionstart / compositionend 事件,正确处理中文输入法的组合输入状态,避免输入过程中触发提交
定时器清理:在 didUnmount 中必须清理所有通过 setInterval / setTimeout 创建的定时器,防止内存泄漏
错误处理:所有 API 调用(this.utils.yida.*、fetch)必须使用 .catch() 处理异常,并通过 this.utils.toast({ title: message, type: 'error' }) 向用户展示错误提示
样式方式:所有样式通过 JavaScript 对象定义(内联样式),在 renderJsx 中通过 style 属性应用,不使用外部 CSS 文件
异步操作:可以使用 async/await 语法,Babel 编译会自动转换为 ES5 兼容代码
pageSize 上限:调用 searchFormDatas、searchFormDataIds、getProcessInstances、getProcessInstanceIds 等分页接口时,pageSize 最大值为 100,超过会导致接口报错。禁止将 pageSize 设置为超过 100 的值,推荐使用 10~100 之间的合理值。
输入框使用非受控组件:在宜搭环境中,<input> 的 value 属性绑定状态后会触发重渲染导致输入异常。正确做法:使用 defaultValue,在 onChange 中更新 _customState 而不调用 setCustomState:
// ❌ 错误:受控组件,每次输入都触发重渲染导致无法输入
<input value={userAnswer} onChange={function(e) { this.setCustomState({ userAnswer: e.target.value }); }} />
// ✅ 正确:非受控组件,仅静默更新状态,不触发重渲染
<input id="my-input" defaultValue="" onChange={function(e) { _customState.userAnswer = e.target.value; }} />
// 需要清空时通过 DOM 操作
var inputEl = document.getElementById("my-input");
if (inputEl) { inputEl.value = ""; }
DateField 时间戳格式:保存日期字段时,值必须是 时间戳(毫秒),不能是字符串:
// ❌ 错误:字符串格式
dateField_xxx: '2024-01-15'
// ✅ 正确:时间戳格式
dateField_xxx: new Date().getTime()
多端适配:宜搭自定义页面会在 PC 端和移动端同时展示,使用 this.utils.isMobile() 判断设备类型:
const isMobile = this.utils.isMobile();
var styles = {
container: { padding: isMobile ? '12px' : '16px', minHeight: '100vh' },
card: { padding: isMobile ? '12px' : '16px', marginBottom: isMobile ? '8px' : '12px' },
};
清除默认样式:宜搭自定义页面容器有默认 padding 和圆角,需要强制覆盖:
var styles = {
container: { padding: '0 16px', borderRadius: '0 !important', minHeight: '100vh' },
};
性能优化:
onChange 都调用 setCustomState,可直接写入 _customState 静默更新forceUpdaterenderJsx 顶部定义事件处理函数,避免每次渲染都创建新的内联函数调试技巧:
// 打印当前状态到控制台
console.log('当前状态:', _customState);
// 弹窗提示(适合快速验证逻辑)
this.utils.toast({ title: '调试信息', type: 'info' });
iframe 嵌入表单 URL 规范:在自定义页面中通过 iframe 嵌入宜搭表单时,需使用正确的 URL 格式:
| 场景 | URL 格式 |
|---|---|
| 表单提交页 | {base_url}/{appType}/submission/{formUuid} |
| 数据管理页(列表) | {base_url}/{appType}/workbench/{formUuid}?iframe=true |
| 数据管理页(指定视图) | {base_url}/{appType}/workbench/{formUuid}?viewUuid={viewUuid}&iframe=true |
// ❌ 错误:formDetail 是表单详情页,不是数据列表
const wrongUrl = `${baseUrl}/${appType}/formDetail/${formUuid}`;
// ✅ 正确:workbench 是运行态数据管理页
const listUrl = `${baseUrl}/${appType}/workbench/${formUuid}?iframe=true`;
viewUuid可选,从宜搭「数据管理」→「报表视图」页面的 URL 中获取,不传则使用默认视图。
通过 this.utils.yida.<方法名>(params) 调用,所有接口返回 Promise。
| 方法 | 说明 | 必填参数 |
|---|---|---|
saveFormData | 新建表单实例 | formUuid, appType, formDataJson |
updateFormData | 更新表单实例 | formInstId, updateFormDataJson |
deleteFormData | 删除表单实例 | formUuid |
getFormDataById | 根据实例 ID 查询详情 | formInstId |
searchFormDatas | 按条件搜索表单实例详情列表 | formUuid |
searchFormDataIds | 按条件搜索表单实例 ID 列表 | formUuid |
getFormComponentDefinationList | 获取表单定义 | formUuid |
常用示例 — 新建表单数据:
this.utils.yida.saveFormData({
formUuid: 'FORM-XXX',
appType: window.pageConfig.appType,
formDataJson: JSON.stringify({
textField_xxx: '单行文本',
textareaField_xxx: '多行文本',
}),
}).then(function(res) {
console.log('新建成功,实例ID:', res.result);
}).catch(function(err) {
this.utils.toast({ title: err.message, type: 'error' });
}.bind(this));
常用示例 — 搜索表单数据:
this.utils.yida.searchFormDatas({
formUuid: 'FORM-XXX',
searchFieldJson: JSON.stringify({ textField_xxx: '查询值' }),
currentPage: 1,
pageSize: 10,
}).then(function(res) {
// res.data: [{ formUuid, formInstId, formData: { textField_xxx: '值' } }]
// res.totalCount: 符合条件的总数
console.log('查询结果:', res.data);
}).catch(function(err) {
this.utils.toast({ title: err.message, type: 'error' });
}.bind(this));
| 方法 | 说明 | 必填参数 |
|---|---|---|
startProcessInstance | 发起流程 | formUuid, processCode, formDataJson |
updateProcessInstance | 更新流程实例 | processInstanceId, updateFormDataJson |
deleteProcessInstance | 删除流程实例 | processInstanceId |
getProcessInstanceById | 根据实例 ID 查询流程详情 | processInstanceId |
getProcessInstances | 按条件搜索流程实例详情列表 | — |
getProcessInstanceIds | 按条件搜索流程实例 ID 列表 | — |
以下接口用于表单页面的创建和配置,通过 HTTP 请求调用:
| 方法 | 说明 | 调用方式 |
|---|---|---|
saveFormSchemaInfo | 创建空白表单 | POST /dingtalk/web/{appType}/query/formdesign/saveFormSchemaInfo.json |
getFormSchema | 获取表单 Schema | GET /alibaba/web/{appType}/_view/query/formdesign/getFormSchema.json |
saveFormSchema | 保存表单 Schema | POST /dingtalk/web/{appType}/_view/query/formdesign/saveFormSchema.json |
updateFormConfig | 更新表单配置 | POST /dingtalk/web/{appType}/query/formdesign/updateFormConfig.json |
完整参数说明请参考 yida-api.md 的「表单设计类 API」章节。
以下接口用于调用大模型 AI 文本生成能力:
| 方法 | 说明 | 调用方式 |
|---|---|---|
txtFromAI | AI 文本生成 | POST /query/intelligent/txtFromAI.json |
主要参数:_csrf_token(CSRF 令牌)、prompt(提示词)、skill(技能类型,如 ToText)、maxTokens(最大返回 token 数)
完整参数说明和示例请参考 model-api.md。
以下工具函数通过 this.utils.<方法名>() 调用,无需 yida 命名空间:
| 方法 | 用途 | 典型场景 |
|---|---|---|
toast | 轻提示 | 操作成功/失败提示、loading 状态 |
dialog | 对话框 | 确认操作、复杂内容展示 |
formatter | 格式化 | 日期、金额、手机号格式化 |
getDateTimeRange | 获取时间范围 | 按日/月/周筛选数据 |
getLoginUserId / getLoginUserName | 获取当前用户 | 记录操作人、数据权限控制 |
getLocale | 获取语言环境 | 多语言适配 |
isMobile | 判断移动端 | 响应式布局适配 |
isSubmissionPage | 判断是否提交页面 | 页面逻辑区分 |
isViewPage | 判断是否查看页面 | 页面逻辑区分 |
openPage | 打开新页面 | 页面跳转、外链打开 |
router.push | 页面路由跳转工具 | 页面路由跳转、避免新开页面 |
previewImage | 图片预览 | 图片查看、多图轮播 |
loadScript | 动态加载脚本 | 引入第三方库(如二维码生成) |
完整参数说明和示例请参考 yida-api.md 的「工具类 API」章节。
| Skill | 说明 | 用法 |
|---|---|---|
| yida-login | 登录态管理(Cookie 持久化 + 扫码登录) | python3 .claude/skills/yida-login/scripts/login.py |
| yida-publish-page | 编译源码 + 构建 Schema + 发布到宜搭 | node .claude/skills/yida-publish-page/scripts/publish.js <appType> <formUuid> <源文件路径> |
| yida-page-config | 页面配置(URL 验证、公开访问/分享配置) | node .claude/skills/yida-page-config/scripts/verify-short-url.js <appType> <formUuid> /o/xxx |
cd .claude/skills/yida-publish-page/scripts
npm install # 首次需要安装依赖
node publish.js <appType> <formUuid> <源文件路径>
处理流程:
@ali/vu-babel-transform 将 JSX 转换为 ES5 + UglifyJS 压缩source 和 compiled 填入 actions.moduleyida-login 获取登录态(Cookie 持久化,首次需扫码登录)saveFormSchema 接口保存 Schemanode .claude/skills/yida-publish-page/scripts/babel-transform/transform.js <源文件路径>
输入 JSX 源文件,输出编译压缩后的 <name>.compile.js(与源文件同目录)。