openyida 2026.4.14 → 2026.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/yida.js +6 -0
- package/lib/app/export-app.js +8 -40
- package/lib/app/form-navigation.js +65 -0
- package/lib/app/list-forms.js +105 -0
- package/lib/core/locales/en.js +19 -0
- package/lib/core/locales/zh.js +19 -0
- package/package.json +1 -1
- package/yida-skills/SKILL.md +1 -1
package/bin/yida.js
CHANGED
|
@@ -388,6 +388,12 @@ async function main() {
|
|
|
388
388
|
break;
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
case 'list-forms': {
|
|
392
|
+
const { run } = require('../lib/app/list-forms');
|
|
393
|
+
await run(args);
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
|
|
391
397
|
case 'get-schema': {
|
|
392
398
|
const { run } = require('../lib/app/get-schema');
|
|
393
399
|
await run(args);
|
package/lib/app/export-app.js
CHANGED
|
@@ -18,45 +18,7 @@ const {
|
|
|
18
18
|
requestWithAutoLogin,
|
|
19
19
|
} = require('../core/utils');
|
|
20
20
|
const { t } = require('../core/i18n');
|
|
21
|
-
|
|
22
|
-
// ── 获取应用下所有表单页面列表 ────────────────────────
|
|
23
|
-
|
|
24
|
-
async function fetchFormPageList(appType, authRef) {
|
|
25
|
-
const result = await requestWithAutoLogin((auth) => {
|
|
26
|
-
return httpGet(
|
|
27
|
-
auth.baseUrl,
|
|
28
|
-
`/dingtalk/web/${appType}/query/formnav/getFormNavigationListByOrder.json`,
|
|
29
|
-
{ _api: 'Nav.queryList', _mock: false },
|
|
30
|
-
auth.cookies
|
|
31
|
-
);
|
|
32
|
-
}, authRef);
|
|
33
|
-
|
|
34
|
-
if (!result || result.success === false) {
|
|
35
|
-
throw new Error(t('export.fetch_forms_failed') + ': ' + (result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed')));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const items = result.content || [];
|
|
39
|
-
const formPages = [];
|
|
40
|
-
|
|
41
|
-
for (const node of items) {
|
|
42
|
-
// 跳过系统导航项(待我处理、我已处理等)
|
|
43
|
-
if (node.navType === 'SYSTEM' || !node.formUuid) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 提取页面名称(title 是 i18n 对象)
|
|
48
|
-
const titleObj = node.title || node.i18nTitle || {};
|
|
49
|
-
const pageName = titleObj.zh_CN || titleObj.en_US || t('export.unnamed_form');
|
|
50
|
-
|
|
51
|
-
formPages.push({
|
|
52
|
-
formUuid: node.formUuid,
|
|
53
|
-
name: pageName,
|
|
54
|
-
formType: node.formType || '',
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return formPages;
|
|
59
|
-
}
|
|
21
|
+
const { fetchFormPageList } = require('./form-navigation');
|
|
60
22
|
|
|
61
23
|
// ── 获取单个表单 Schema ───────────────────────────────
|
|
62
24
|
|
|
@@ -114,7 +76,13 @@ async function run(args) {
|
|
|
114
76
|
step(2, t('export.step_get_forms'));
|
|
115
77
|
let formPages;
|
|
116
78
|
try {
|
|
117
|
-
|
|
79
|
+
const forms = await fetchFormPageList(appType, authRef);
|
|
80
|
+
formPages = forms.map((form) => ({
|
|
81
|
+
formUuid: form.formUuid,
|
|
82
|
+
name: form.formName,
|
|
83
|
+
formType: form.formType,
|
|
84
|
+
pathName: form.pathName,
|
|
85
|
+
}));
|
|
118
86
|
} catch (err) {
|
|
119
87
|
chalkFail(err.message);
|
|
120
88
|
process.exit(1);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
httpGet,
|
|
5
|
+
requestWithAutoLogin,
|
|
6
|
+
} = require('../core/utils');
|
|
7
|
+
const { t } = require('../core/i18n');
|
|
8
|
+
|
|
9
|
+
function resolveLocalizedText(value, fallback = '') {
|
|
10
|
+
if (!value) {
|
|
11
|
+
return fallback;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof value === 'string') {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (typeof value === 'object') {
|
|
19
|
+
return value.zh_CN || value.en_US || value.zh_TW || fallback;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return fallback;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function normalizeFormNavigationNode(node) {
|
|
26
|
+
if (!node || node.navType === 'SYSTEM' || !node.formUuid) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
formUuid: node.formUuid,
|
|
32
|
+
formName: resolveLocalizedText(node.title || node.i18nTitle || node.name, t('list_forms.unnamed_form')),
|
|
33
|
+
formType: node.formType || '',
|
|
34
|
+
pathName: node.pathName || '',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function fetchFormPageList(appType, authRef) {
|
|
39
|
+
const result = await requestWithAutoLogin((auth) => {
|
|
40
|
+
return httpGet(
|
|
41
|
+
auth.baseUrl,
|
|
42
|
+
`/dingtalk/web/${appType}/query/formnav/getFormNavigationListByOrder.json`,
|
|
43
|
+
{ _api: 'Nav.queryList', _mock: false },
|
|
44
|
+
auth.cookies
|
|
45
|
+
);
|
|
46
|
+
}, authRef);
|
|
47
|
+
|
|
48
|
+
if (!result || result.success === false) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
t('list_forms.fetch_failed') + ': ' +
|
|
51
|
+
(result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed'))
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const items = Array.isArray(result.content) ? result.content : [];
|
|
56
|
+
return items
|
|
57
|
+
.map(normalizeFormNavigationNode)
|
|
58
|
+
.filter(Boolean);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = {
|
|
62
|
+
fetchFormPageList,
|
|
63
|
+
normalizeFormNavigationNode,
|
|
64
|
+
resolveLocalizedText,
|
|
65
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
loadCookieData,
|
|
5
|
+
triggerLogin,
|
|
6
|
+
resolveBaseUrl,
|
|
7
|
+
} = require('../core/utils');
|
|
8
|
+
const { t } = require('../core/i18n');
|
|
9
|
+
const { fetchFormPageList } = require('./form-navigation');
|
|
10
|
+
|
|
11
|
+
function parseArgs(args) {
|
|
12
|
+
const parsed = {
|
|
13
|
+
appType: '',
|
|
14
|
+
keyword: '',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (args.length > 0) {
|
|
18
|
+
parsed.appType = args[0];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (let index = 1; index < args.length; index++) {
|
|
22
|
+
if (args[index] === '--keyword' && args[index + 1]) {
|
|
23
|
+
parsed.keyword = args[index + 1];
|
|
24
|
+
index++;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function filterForms(forms, keyword) {
|
|
32
|
+
if (!keyword) {
|
|
33
|
+
return forms;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const normalizedKeyword = keyword.toLowerCase();
|
|
37
|
+
return forms.filter((form) => {
|
|
38
|
+
return [form.formName, form.formUuid, form.formType, form.pathName]
|
|
39
|
+
.filter(Boolean)
|
|
40
|
+
.some((value) => String(value).toLowerCase().includes(normalizedKeyword));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function run(args) {
|
|
45
|
+
const parsed = parseArgs(args);
|
|
46
|
+
if (!parsed.appType) {
|
|
47
|
+
console.error(t('list_forms.usage'));
|
|
48
|
+
console.error(t('list_forms.example1'));
|
|
49
|
+
console.error(t('list_forms.example2'));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const SEP = '='.repeat(50);
|
|
54
|
+
console.error(SEP);
|
|
55
|
+
console.error(t('list_forms.title'));
|
|
56
|
+
console.error(SEP);
|
|
57
|
+
console.error(t('list_forms.app_id', parsed.appType));
|
|
58
|
+
if (parsed.keyword) {
|
|
59
|
+
console.error(t('list_forms.keyword', parsed.keyword));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.error(t('common.step_login', 1));
|
|
63
|
+
let cookieData = loadCookieData();
|
|
64
|
+
if (!cookieData) {
|
|
65
|
+
console.error(t('common.login_no_cache'));
|
|
66
|
+
cookieData = triggerLogin();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!cookieData || !cookieData.cookies) {
|
|
70
|
+
console.error(t('list_forms.no_login'));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const authRef = {
|
|
75
|
+
csrfToken: cookieData.csrf_token,
|
|
76
|
+
cookies: cookieData.cookies,
|
|
77
|
+
baseUrl: resolveBaseUrl(cookieData),
|
|
78
|
+
cookieData,
|
|
79
|
+
};
|
|
80
|
+
console.error(t('common.login_ready', authRef.baseUrl));
|
|
81
|
+
|
|
82
|
+
console.error(t('list_forms.step_get'));
|
|
83
|
+
let forms;
|
|
84
|
+
try {
|
|
85
|
+
forms = await fetchFormPageList(parsed.appType, authRef);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error(t('list_forms.failed', error.message));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const filteredForms = filterForms(forms, parsed.keyword);
|
|
92
|
+
console.error(t('list_forms.found', filteredForms.length));
|
|
93
|
+
|
|
94
|
+
if (filteredForms.length === 0) {
|
|
95
|
+
console.error(t('list_forms.empty'));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
console.log(JSON.stringify(filteredForms, null, 2));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
module.exports = {
|
|
102
|
+
filterForms,
|
|
103
|
+
parseArgs,
|
|
104
|
+
run,
|
|
105
|
+
};
|
package/lib/core/locales/en.js
CHANGED
|
@@ -84,6 +84,7 @@ Commands:
|
|
|
84
84
|
create-page <appType> "<pageName>" Create a custom page, output pageId
|
|
85
85
|
create-form create <appType> "<formName>" <fieldsJSON> [--layout <layout>] [--theme <theme>] [--label-align <align>] Create a form page
|
|
86
86
|
create-form update <appType> <formUuid> <changesJSON> Update a form page
|
|
87
|
+
list-forms <appType> [--keyword <text>] List forms/pages in an app
|
|
87
88
|
get-schema <appType> <formUuid> Get form Schema
|
|
88
89
|
publish <sourceFile> <appType> <formUuid> Compile and publish a custom page
|
|
89
90
|
verify-short-url <appType> <formUuid> <url> Verify if a short URL is available
|
|
@@ -147,6 +148,8 @@ Examples:
|
|
|
147
148
|
openyida create-page APP_XXX "Game Home"
|
|
148
149
|
openyida create-form create APP_XXX "Employee Info" fields.json
|
|
149
150
|
openyida create-form update APP_XXX FORM-XXX '[{"action":"add","field":{"type":"TextField","label":"Notes"}}]'
|
|
151
|
+
openyida list-forms APP_XXX
|
|
152
|
+
openyida list-forms APP_XXX --keyword customer
|
|
150
153
|
openyida get-schema APP_XXX FORM-XXX
|
|
151
154
|
openyida publish pages/src/home.jsx APP_XXX FORM-XXX
|
|
152
155
|
openyida verify-short-url APP_XXX FORM-XXX /o/myapp
|
|
@@ -424,6 +427,22 @@ Examples:
|
|
|
424
427
|
failed: ' ❌ Failed to get Schema: {0}',
|
|
425
428
|
},
|
|
426
429
|
|
|
430
|
+
list_forms: {
|
|
431
|
+
title: ' yidacli list-forms - App form/page list tool',
|
|
432
|
+
usage: 'Usage: openyida list-forms <appType> [--keyword <text>]',
|
|
433
|
+
example1: 'Example: openyida list-forms APP_XXX',
|
|
434
|
+
example2: ' openyida list-forms APP_XXX --keyword customer',
|
|
435
|
+
app_id: ' App ID: {0}',
|
|
436
|
+
keyword: ' Keyword: {0}',
|
|
437
|
+
step_get: '\n📋 Step 2: Fetch app forms/pages',
|
|
438
|
+
found: ' ✅ Found {0} matching items',
|
|
439
|
+
empty: ' ⚠️ No matching forms/pages found, outputting []',
|
|
440
|
+
unnamed_form: 'Unnamed page',
|
|
441
|
+
fetch_failed: 'Failed to fetch app navigation list',
|
|
442
|
+
failed: ' ❌ Query failed: {0}',
|
|
443
|
+
no_login: ' ❌ Unable to get valid login credentials',
|
|
444
|
+
},
|
|
445
|
+
|
|
427
446
|
// ── lib/create-form.js ─────────────────────────────
|
|
428
447
|
create_form: {
|
|
429
448
|
create_title: ' yida-create-form-page - Yida Form Page Creation Tool',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -84,6 +84,7 @@ openyida - 宜搭命令行工具
|
|
|
84
84
|
create-page <appType> "<页面名>" 创建自定义页面,输出 pageId
|
|
85
85
|
create-form create <appType> "<表单名>" <字段JSON> [--layout <布局>] [--theme <主题>] [--label-align <对齐>] 创建表单页面
|
|
86
86
|
create-form update <appType> <formUuid> <修改JSON> 更新表单页面
|
|
87
|
+
list-forms <appType> [--keyword <关键词>] 列出应用下的表单/页面
|
|
87
88
|
get-schema <appType> <formUuid> 获取表单 Schema
|
|
88
89
|
publish <源文件路径> <appType> <formUuid> 编译并发布自定义页面
|
|
89
90
|
verify-short-url <appType> <formUuid> <url> 验证短链接 URL 是否可用
|
|
@@ -148,6 +149,8 @@ openyida - 宜搭命令行工具
|
|
|
148
149
|
openyida create-page APP_XXX "游戏主页"
|
|
149
150
|
openyida create-form create APP_XXX "员工信息" fields.json
|
|
150
151
|
openyida create-form update APP_XXX FORM-XXX '[{"action":"add","field":{"type":"TextField","label":"备注"}}]'
|
|
152
|
+
openyida list-forms APP_XXX
|
|
153
|
+
openyida list-forms APP_XXX --keyword 客户
|
|
151
154
|
openyida get-schema APP_XXX FORM-XXX
|
|
152
155
|
openyida publish pages/src/home.jsx APP_XXX FORM-XXX
|
|
153
156
|
openyida verify-short-url APP_XXX FORM-XXX /o/myapp
|
|
@@ -396,6 +399,22 @@ openyida - 宜搭命令行工具
|
|
|
396
399
|
failed: ' ❌ 获取 Schema 失败: {0}',
|
|
397
400
|
},
|
|
398
401
|
|
|
402
|
+
list_forms: {
|
|
403
|
+
title: ' yidacli list-forms - 应用表单/页面列表查询工具',
|
|
404
|
+
usage: '用法: openyida list-forms <appType> [--keyword <关键词>]',
|
|
405
|
+
example1: '示例: openyida list-forms APP_XXX',
|
|
406
|
+
example2: ' openyida list-forms APP_XXX --keyword 客户',
|
|
407
|
+
app_id: ' 应用 ID: {0}',
|
|
408
|
+
keyword: ' 关键词: {0}',
|
|
409
|
+
step_get: '\n📋 步骤 2: 获取应用下的表单/页面列表',
|
|
410
|
+
found: ' ✅ 共找到 {0} 个匹配项',
|
|
411
|
+
empty: ' ⚠️ 当前应用下没有匹配的表单/页面,将输出 []',
|
|
412
|
+
unnamed_form: '未命名页面',
|
|
413
|
+
fetch_failed: '获取应用导航列表失败',
|
|
414
|
+
failed: ' ❌ 查询失败: {0}',
|
|
415
|
+
no_login: ' ❌ 无法获取有效登录态',
|
|
416
|
+
},
|
|
417
|
+
|
|
399
418
|
// ── lib/create-form.js ─────────────────────────────
|
|
400
419
|
create_form: {
|
|
401
420
|
create_title: ' yida-create-form-page - 宜搭表单页面创建工具',
|
package/package.json
CHANGED
package/yida-skills/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: yida-skills
|
|
3
3
|
description: "宜搭低代码平台 AI 开发助手。适用于一切业务数字化需求:创建登记表/申请表/信息收集表、设计审批流程、搭建数据报表/数据大屏、开发自定义页面、管理表单数据、闪记转PRD/会议纪要提取需求/需求文档生成、导出对话记录、编写公式/计算字段、配置连接器/外部API接入、设置权限/公开分享、集成自动化。当用户想要创建任何形式的表单、系统、页面、流程、报表,或提到员工管理、客户管理、费用报销、考勤打卡、项目管理等业务场景时触发。也适用于「宜搭」「yida」「低代码」「创建应用」「发布页面」「搭建系统」「PRD」「闪记」「会议记录」「对话导出」「公式」「连接器」「权限」「分享」「集成自动化」等关键词场景。"
|
|
4
4
|
metadata:
|
|
5
|
-
version: 2026.04.
|
|
5
|
+
version: 2026.04.15
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# 宜搭 AI 应用开发指南
|