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 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);
@@ -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
- formPages = await fetchFormPageList(appType, authRef);
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
+ };
@@ -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',
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.04.14",
3
+ "version": "2026.04.15",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "./bin/yida.js",
@@ -2,7 +2,7 @@
2
2
  name: yida-skills
3
3
  description: "宜搭低代码平台 AI 开发助手。适用于一切业务数字化需求:创建登记表/申请表/信息收集表、设计审批流程、搭建数据报表/数据大屏、开发自定义页面、管理表单数据、闪记转PRD/会议纪要提取需求/需求文档生成、导出对话记录、编写公式/计算字段、配置连接器/外部API接入、设置权限/公开分享、集成自动化。当用户想要创建任何形式的表单、系统、页面、流程、报表,或提到员工管理、客户管理、费用报销、考勤打卡、项目管理等业务场景时触发。也适用于「宜搭」「yida」「低代码」「创建应用」「发布页面」「搭建系统」「PRD」「闪记」「会议记录」「对话导出」「公式」「连接器」「权限」「分享」「集成自动化」等关键词场景。"
4
4
  metadata:
5
- version: 2026.04.14
5
+ version: 2026.04.15
6
6
  ---
7
7
 
8
8
  # 宜搭 AI 应用开发指南