openyida 2026.5.13-beta.1 → 2026.5.13

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/README.md CHANGED
@@ -296,6 +296,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
296
296
  | `openyida data <action> <resource> [args]` | Unified data management for forms, processes, tasks, and subforms |
297
297
  | `openyida data check <appType> <formUuid> <rules.json>` | Detect anomalous process-form records |
298
298
  | `openyida task-center <type> [options]` | Query todo, created, processed, CC, or proxy-submitted tasks |
299
+ | `openyida basic-info <overview\|commodity\|grant\|capacity\|quota\|abs-path\|dataflow\|i18n\|domain>` | Query organization basic info, capacity, quotas, fixed-domain records, and domain settings |
299
300
  | `openyida get-permission <appType> <formUuid>` | Query form permission configuration |
300
301
  | `openyida save-permission <appType> <formUuid> [options]` | Save form permission configuration |
301
302
  | `openyida corp-manager <sub-command>` | Manage platform admins, sub-admins, app admins, and address book visibility |
package/bin/yida.js CHANGED
@@ -123,7 +123,7 @@ function printHelp() {
123
123
  console.log(`\n ${BOLD}${CYAN}${t('help.quickstart_title')}${RESET}`);
124
124
  console.log(` ${DIM}${RESET} openyida login`);
125
125
  console.log(` ${DIM}${RESET} openyida create-app "${t('help.quickstart_app_name')}"`);
126
- console.log(` ${DIM}${RESET} openyida create-form create APP_XXX "${t('help.quickstart_form_name')}" fields.json`);
126
+ console.log(` ${DIM}${RESET} openyida create-form create APP_XXX "${t('help.quickstart_form_name')}" .cache/openyida/forms/fields.json`);
127
127
  console.log(` ${DIM}${RESET} openyida dws contact user search --keyword "张三"`);
128
128
  console.log('');
129
129
  console.log(` ${DIM}${t('help.docs')} https://openyida.ai · https://github.com/openyida/openyida${RESET}`);
@@ -655,6 +655,12 @@ async function main() {
655
655
  break;
656
656
  }
657
657
 
658
+ case 'basic-info': {
659
+ const { run: runBasicInfo } = require('../lib/basic-info/basic-info');
660
+ await runBasicInfo(args);
661
+ break;
662
+ }
663
+
658
664
  case 'doctor': {
659
665
  const { run } = require('../lib/core/doctor');
660
666
  await run(args);
@@ -0,0 +1,407 @@
1
+ 'use strict';
2
+
3
+ const querystring = require('querystring');
4
+ const {
5
+ loadCookieData,
6
+ triggerLogin,
7
+ resolveBaseUrl,
8
+ extractInfoFromCookies,
9
+ httpGet,
10
+ httpPost,
11
+ requestWithAutoLogin,
12
+ } = require('../core/utils');
13
+
14
+ const API = {
15
+ commodityInfo: '/query/commodity/getCommodityInfo.json',
16
+ isEduEdition: '/query/commodity/isEduEdition.json',
17
+ grantInfo: '/query/corpadmin/getCorpGrantInfo.json',
18
+ updateCorpDomain: '/query/corpadmin/updateCorpDomain.json',
19
+ absPathRecords: '/query/corpadmin/pageFormAbsPathRecord.json',
20
+ fileSummary: '/query/capacity/fileSummary.json',
21
+ dataSummary: '/query/capacity/dataSummary.json',
22
+ flowSummary: '/query/formLogicflowBinding/getCorpAllNum.json',
23
+ quota: '/query/commodity/queryResourceQuotaVo.json',
24
+ batchQuota: '/query/commodity/batchQueryResourceQuotaVo.json',
25
+ dataflowCost: '/query/dataflowInfo/getDataflowCostQuotaMap.json',
26
+ checkI18nAbility: '/query/commodity/checkI18nAbility.json',
27
+ i18nContext: '/query/commodity/i18nAbilityContext.json',
28
+ };
29
+
30
+ const DEFAULT_RESOURCE_KEYS = [
31
+ 'singleFormInstanceLimit',
32
+ 'ocrAmount',
33
+ 'portalAmount',
34
+ 'corpDataCardAmount',
35
+ 'corpDataCardPushAmount',
36
+ 'faasAmount',
37
+ 'corpVviewAmount',
38
+ 'ddDataSetAmount',
39
+ ];
40
+
41
+ function printUsage() {
42
+ console.error(`Usage:
43
+ openyida basic-info [overview] [--include-secrets]
44
+ openyida basic-info commodity [--include-secrets]
45
+ openyida basic-info grant
46
+ openyida basic-info capacity [--type file|data|flow|all]
47
+ openyida basic-info quota [--resource-key <key>|--resource-keys <a,b>]
48
+ openyida basic-info abs-path [--page N] [--size N]
49
+ openyida basic-info dataflow
50
+ openyida basic-info i18n
51
+ openyida basic-info domain
52
+ openyida basic-info domain set --target <domain> [--origin <domain>] --confirm`);
53
+ }
54
+
55
+ function getOption(args, names) {
56
+ const list = Array.isArray(names) ? names : [names];
57
+ for (const name of list) {
58
+ const index = args.indexOf(name);
59
+ if (index !== -1 && args[index + 1] && !args[index + 1].startsWith('--')) {
60
+ return args[index + 1];
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+
66
+ function hasFlag(args, names) {
67
+ const list = Array.isArray(names) ? names : [names];
68
+ return list.some(name => args.includes(name));
69
+ }
70
+
71
+ function getSubcommand(args) {
72
+ if (!args[0] || args[0].startsWith('--')) {
73
+ return 'overview';
74
+ }
75
+ return args[0];
76
+ }
77
+
78
+ function parsePositiveInt(value, fallback, optionName) {
79
+ if (value === null || value === undefined) {
80
+ return fallback;
81
+ }
82
+ const parsed = Number.parseInt(value, 10);
83
+ if (!Number.isInteger(parsed) || parsed <= 0) {
84
+ throw new Error(`${optionName} must be a positive integer`);
85
+ }
86
+ return parsed;
87
+ }
88
+
89
+ function parseResourceKeys(value) {
90
+ if (!value) {
91
+ return [];
92
+ }
93
+ return value.split(',').map(item => item.trim()).filter(Boolean);
94
+ }
95
+
96
+ function buildCommonParams(auth, extra = {}) {
97
+ return {
98
+ _api: 'nattyFetch',
99
+ _mock: 'false',
100
+ _csrf_token: auth.csrfToken,
101
+ _locale_time_zone_offset: String(-new Date().getTimezoneOffset() * 60 * 1000),
102
+ _stamp: Date.now(),
103
+ ...extra,
104
+ };
105
+ }
106
+
107
+ function unwrapResponse(response, actionName) {
108
+ if (response && (response.__needLogin || response.__csrfExpired)) {
109
+ throw new Error('Login state is invalid. Please run openyida login again.');
110
+ }
111
+ if (!response || response.success === false) {
112
+ throw new Error((response && response.errorMsg) || `${actionName} failed`);
113
+ }
114
+ return response.content;
115
+ }
116
+
117
+ async function requestGet(authRef, path, params = {}, actionName = path) {
118
+ const response = await requestWithAutoLogin(
119
+ auth => httpGet(auth.baseUrl, path, buildCommonParams(auth, params), auth.cookies),
120
+ authRef
121
+ );
122
+ return unwrapResponse(response, actionName);
123
+ }
124
+
125
+ async function requestPost(authRef, path, params = {}, actionName = path) {
126
+ const response = await requestWithAutoLogin((auth) => {
127
+ const body = querystring.stringify(buildCommonParams(auth, params));
128
+ return httpPost(auth.baseUrl, path, body, auth.cookies);
129
+ }, authRef);
130
+ return unwrapResponse(response, actionName);
131
+ }
132
+
133
+ async function loadAuth() {
134
+ let cookieData = loadCookieData();
135
+ if (!cookieData) {
136
+ cookieData = await triggerLogin();
137
+ }
138
+
139
+ const cookieInfo = extractInfoFromCookies(cookieData.cookies || []);
140
+ const csrfToken = cookieData.csrf_token || cookieInfo.csrfToken;
141
+ if (!csrfToken) {
142
+ throw new Error('Missing csrf token. Please run openyida login again.');
143
+ }
144
+
145
+ return {
146
+ cookieData,
147
+ cookies: cookieData.cookies || [],
148
+ csrfToken,
149
+ corpId: cookieInfo.corpId,
150
+ userId: cookieInfo.userId,
151
+ baseUrl: resolveBaseUrl(cookieData),
152
+ };
153
+ }
154
+
155
+ function sanitizeCommodityInfo(content, options = {}) {
156
+ if (!content || typeof content !== 'object') {
157
+ return content;
158
+ }
159
+ const result = { ...content };
160
+ if (!options.includeSecrets && Object.prototype.hasOwnProperty.call(result, 'corpToken')) {
161
+ result.corpToken = result.corpToken ? '[redacted]' : result.corpToken;
162
+ result.corpTokenRedacted = true;
163
+ }
164
+ return result;
165
+ }
166
+
167
+ async function fetchCommodityInfo(authRef, options = {}) {
168
+ const content = await requestGet(authRef, API.commodityInfo, {}, 'query commodity info');
169
+ return sanitizeCommodityInfo(content, options);
170
+ }
171
+
172
+ async function fetchGrantInfo(authRef) {
173
+ return requestGet(authRef, API.grantInfo, {}, 'query grant info');
174
+ }
175
+
176
+ async function fetchIsEduEdition(authRef) {
177
+ return requestGet(authRef, API.isEduEdition, {}, 'query education edition flag');
178
+ }
179
+
180
+ async function fetchAbsPathRecords(authRef, options = {}) {
181
+ const currentPage = parsePositiveInt(options.page, 1, '--page');
182
+ const pageSize = parsePositiveInt(options.size, 10, '--size');
183
+ const content = await requestPost(
184
+ authRef,
185
+ API.absPathRecords,
186
+ { currentPage, pageSize },
187
+ 'query absolute path records'
188
+ );
189
+ return {
190
+ currentPage: content.currentPage || currentPage,
191
+ pageSize,
192
+ totalCount: content.totalCount || 0,
193
+ hasMore: !!content.hasMore,
194
+ data: content.data || [],
195
+ };
196
+ }
197
+
198
+ async function fetchCapacity(authRef, type = 'all') {
199
+ const normalized = type || 'all';
200
+ const result = {};
201
+
202
+ if (normalized === 'all' || normalized === 'file') {
203
+ result.file = await requestGet(authRef, API.fileSummary, {}, 'query file capacity summary');
204
+ }
205
+ if (normalized === 'all' || normalized === 'data') {
206
+ result.data = await requestGet(authRef, API.dataSummary, {}, 'query data capacity summary');
207
+ }
208
+ if (normalized === 'all' || normalized === 'flow') {
209
+ result.flow = await requestGet(authRef, API.flowSummary, {}, 'query flow capacity summary');
210
+ }
211
+ if (!['all', 'file', 'data', 'flow'].includes(normalized)) {
212
+ throw new Error('--type must be one of file, data, flow, all');
213
+ }
214
+
215
+ return result;
216
+ }
217
+
218
+ async function fetchQuota(authRef, options = {}) {
219
+ const singleKey = options.resourceKey;
220
+ const resourceKeys = options.resourceKeys && options.resourceKeys.length
221
+ ? options.resourceKeys
222
+ : DEFAULT_RESOURCE_KEYS;
223
+
224
+ if (singleKey) {
225
+ return {
226
+ [singleKey]: await requestGet(
227
+ authRef,
228
+ API.quota,
229
+ { resourceKey: singleKey },
230
+ `query quota ${singleKey}`
231
+ ),
232
+ };
233
+ }
234
+
235
+ return requestGet(
236
+ authRef,
237
+ API.batchQuota,
238
+ { resourceKeys },
239
+ 'query resource quotas'
240
+ );
241
+ }
242
+
243
+ async function fetchDataflow(authRef) {
244
+ return requestGet(authRef, API.dataflowCost, {}, 'query dataflow quota map');
245
+ }
246
+
247
+ async function fetchI18n(authRef) {
248
+ const [enabled, context] = await Promise.all([
249
+ requestGet(authRef, API.checkI18nAbility, {}, 'check i18n ability'),
250
+ requestGet(authRef, API.i18nContext, {}, 'query i18n context'),
251
+ ]);
252
+ return { enabled, context };
253
+ }
254
+
255
+ async function tryFetch(name, fetcher) {
256
+ try {
257
+ return { name, ok: true, data: await fetcher() };
258
+ } catch (error) {
259
+ return { name, ok: false, error: error.message };
260
+ }
261
+ }
262
+
263
+ async function fetchOverview(authRef, options = {}) {
264
+ const results = await Promise.all([
265
+ tryFetch('commodityInfo', () => fetchCommodityInfo(authRef, options)),
266
+ tryFetch('isEduEdition', () => fetchIsEduEdition(authRef)),
267
+ tryFetch('grantInfo', () => fetchGrantInfo(authRef)),
268
+ tryFetch('capacity', () => fetchCapacity(authRef, 'all')),
269
+ tryFetch('resourceQuota', () => fetchQuota(authRef, {})),
270
+ tryFetch('dataflowCostQuotaMap', () => fetchDataflow(authRef)),
271
+ tryFetch('i18nAbility', () => fetchI18n(authRef)),
272
+ ]);
273
+
274
+ const overview = { success: true, errors: [] };
275
+ for (const item of results) {
276
+ if (item.ok) {
277
+ overview[item.name] = item.data;
278
+ } else {
279
+ overview[item.name] = null;
280
+ overview.errors.push({ name: item.name, message: item.error });
281
+ }
282
+ }
283
+ return overview;
284
+ }
285
+
286
+ function validateDomainValue(value, optionName) {
287
+ if (!value) {
288
+ throw new Error(`${optionName} is required`);
289
+ }
290
+ if (value.length > 10) {
291
+ throw new Error(`${optionName} must be at most 10 characters`);
292
+ }
293
+ if (!/^[a-z][a-z0-9-]*$/.test(value)) {
294
+ throw new Error(`${optionName} must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens`);
295
+ }
296
+ }
297
+
298
+ async function updateDomain(authRef, args) {
299
+ if (!hasFlag(args, '--confirm')) {
300
+ throw new Error('Refusing to update organization domain without --confirm');
301
+ }
302
+
303
+ const targetDomainValue = getOption(args, ['--target', '--domain', '--target-domain-value']);
304
+ validateDomainValue(targetDomainValue, '--target');
305
+
306
+ let originDomainValue = getOption(args, ['--origin', '--origin-domain-value']);
307
+ if (!originDomainValue) {
308
+ const commodityInfo = await fetchCommodityInfo(authRef, { includeSecrets: false });
309
+ originDomainValue = commodityInfo && commodityInfo.corpDomainVo && commodityInfo.corpDomainVo.domainValue;
310
+ }
311
+ validateDomainValue(originDomainValue, '--origin');
312
+
313
+ const content = await requestPost(
314
+ authRef,
315
+ API.updateCorpDomain,
316
+ { originDomainValue, targetDomainValue },
317
+ 'update organization domain'
318
+ );
319
+ return {
320
+ success: true,
321
+ originDomainValue,
322
+ targetDomainValue,
323
+ content,
324
+ };
325
+ }
326
+
327
+ function outputJson(value) {
328
+ console.log(JSON.stringify(value, null, 2));
329
+ }
330
+
331
+ async function run(args = []) {
332
+ if (hasFlag(args, ['--help', '-h'])) {
333
+ printUsage();
334
+ return;
335
+ }
336
+
337
+ const subcommand = getSubcommand(args);
338
+ const includeSecrets = hasFlag(args, '--include-secrets');
339
+ const authRef = await loadAuth();
340
+
341
+ switch (subcommand) {
342
+ case 'overview':
343
+ outputJson(await fetchOverview(authRef, { includeSecrets }));
344
+ break;
345
+ case 'commodity':
346
+ outputJson(await fetchCommodityInfo(authRef, { includeSecrets }));
347
+ break;
348
+ case 'grant':
349
+ outputJson(await fetchGrantInfo(authRef));
350
+ break;
351
+ case 'abs-path':
352
+ outputJson(await fetchAbsPathRecords(authRef, {
353
+ page: getOption(args, '--page'),
354
+ size: getOption(args, '--size'),
355
+ }));
356
+ break;
357
+ case 'capacity':
358
+ outputJson(await fetchCapacity(authRef, getOption(args, '--type') || 'all'));
359
+ break;
360
+ case 'quota':
361
+ outputJson(await fetchQuota(authRef, {
362
+ resourceKey: getOption(args, '--resource-key'),
363
+ resourceKeys: parseResourceKeys(getOption(args, '--resource-keys')),
364
+ }));
365
+ break;
366
+ case 'dataflow':
367
+ outputJson(await fetchDataflow(authRef));
368
+ break;
369
+ case 'i18n':
370
+ outputJson(await fetchI18n(authRef));
371
+ break;
372
+ case 'domain': {
373
+ const action = args.find((arg, index) => index > args.indexOf('domain') && !arg.startsWith('--'));
374
+ if (action === 'set') {
375
+ outputJson(await updateDomain(authRef, args));
376
+ } else {
377
+ const commodityInfo = await fetchCommodityInfo(authRef, { includeSecrets: false });
378
+ outputJson({
379
+ success: true,
380
+ corpDomainVo: commodityInfo && commodityInfo.corpDomainVo,
381
+ });
382
+ }
383
+ break;
384
+ }
385
+ default:
386
+ printUsage();
387
+ process.exit(1);
388
+ }
389
+ }
390
+
391
+ module.exports = {
392
+ API,
393
+ DEFAULT_RESOURCE_KEYS,
394
+ fetchAbsPathRecords,
395
+ fetchCapacity,
396
+ fetchCommodityInfo,
397
+ fetchDataflow,
398
+ fetchGrantInfo,
399
+ fetchI18n,
400
+ fetchIsEduEdition,
401
+ fetchOverview,
402
+ fetchQuota,
403
+ loadAuth,
404
+ run,
405
+ sanitizeCommodityInfo,
406
+ updateDomain,
407
+ };
@@ -70,6 +70,9 @@ const COMMAND_GROUPS = [
70
70
  commands: [
71
71
  command('data', ['data'], 'data <action> <resource> [args]', 'help.cmd_data'),
72
72
  command('task-center', ['task-center'], 'task-center <type> [options]', 'help.cmd_task_center'),
73
+ command('basic-info', ['basic-info'], 'basic-info <overview|commodity|grant|capacity|quota|abs-path|dataflow|i18n|domain>', 'help.cmd_basic_info', {
74
+ output: 'json',
75
+ }),
73
76
  command('get-permission', ['get-permission'], 'get-permission <appType> <formUuid>', 'help.cmd_get_permission'),
74
77
  command('save-permission', ['save-permission'], 'save-permission <appType> <formUuid> ...', 'help.cmd_save_permission'),
75
78
  command('corp-manager', ['corp-manager'], 'corp-manager <search-user|list|add|remove|address-book> ...', 'help.cmd_corp_manager', { output: 'json' }),
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'البيانات & الأذونات',
37
37
  cmd_data: 'إدارة البيانات الموحدة (نموذج/عملية/مهمة/نموذج فرعي)',
38
38
  cmd_task_center: 'مركز المهام العالمي (معلق/معالج/نسخة إلخ)',
39
+ cmd_basic_info: 'عرض معلومات المؤسسة والسعة والحصص والنطاق',
39
40
  cmd_get_permission: 'استعلام إعدادات أذونات النموذج',
40
41
  cmd_save_permission: 'حفظ إعدادات أذونات النموذج',
41
42
  cmd_corp_manager: 'إدارة أذونات منصة المؤسسة',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'مثال: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'Daten & Berechtigungen',
37
37
  cmd_data: 'Einheitliche Datenverwaltung (Formular/Prozess/Aufgabe/Unterformular)',
38
38
  cmd_task_center: 'Globales Aufgabenzentrum (Aufgaben/Bearbeitet/CC etc.)',
39
+ cmd_basic_info: 'Organisationsinfos, Kapazitaeten, Quoten und Domain-Einstellungen abfragen',
39
40
  cmd_get_permission: 'Formularberechtigungen abfragen',
40
41
  cmd_save_permission: 'Formularberechtigungen speichern',
41
42
  cmd_corp_manager: 'Plattformberechtigungen verwalten',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'Beispiel: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -39,6 +39,7 @@ module.exports = {
39
39
  group_data: 'Data & Permissions',
40
40
  cmd_data: 'Unified data management (form/process/task/subform)',
41
41
  cmd_task_center: 'Global task center (todo/processed/cc etc.)',
42
+ cmd_basic_info: 'Query organization basic info, capacity, quotas, and domain settings',
42
43
  cmd_get_permission: 'Query form permission config',
43
44
  cmd_save_permission: 'Save form permission config',
44
45
  cmd_corp_manager: 'Manage platform admins and address book permissions',
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'Datos & Permisos',
37
37
  cmd_data: 'Gestión unificada de datos (formulario/proceso/tarea/subformulario)',
38
38
  cmd_task_center: 'Centro de tareas global (pendiente/procesado/CC etc.)',
39
+ cmd_basic_info: 'Consultar informacion de organizacion, capacidad, cuotas y dominio',
39
40
  cmd_get_permission: 'Consultar configuración de permisos',
40
41
  cmd_save_permission: 'Guardar configuración de permisos',
41
42
  cmd_corp_manager: 'Gestionar permisos de plataforma',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'Ejemplo: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'Données & Permissions',
37
37
  cmd_data: 'Gestion unifiée des données (formulaire/processus/tâche/sous-formulaire)',
38
38
  cmd_task_center: 'Centre de tâches global (à faire/traité/CC etc.)',
39
+ cmd_basic_info: "Consulter les infos d'organisation, capacités, quotas et domaine",
39
40
  cmd_get_permission: 'Consulter la configuration des permissions',
40
41
  cmd_save_permission: 'Enregistrer la configuration des permissions',
41
42
  cmd_corp_manager: 'Gérer les permissions de plateforme',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'Exemple : openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'डेटा & अनुमतियां',
37
37
  cmd_data: 'एकीकृत डेटा प्रबंधन (फॉर्म/प्रक्रिया/कार्य/उप-फॉर्म)',
38
38
  cmd_task_center: 'वैश्विक कार्य केंद्र (लंबित/संसाधित/CC आदि)',
39
+ cmd_basic_info: 'संगठन की मूल जानकारी, क्षमता, कोटा और डोमेन देखें',
39
40
  cmd_get_permission: 'फॉर्म अनुमति कॉन्फ़िगरेशन पूछें',
40
41
  cmd_save_permission: 'फॉर्म अनुमति कॉन्फ़िगरेशन सहेजें',
41
42
  cmd_corp_manager: 'प्लेटफ़ॉर्म अनुमतियां प्रबंधित करें',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'उदाहरण: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -38,6 +38,7 @@ module.exports = {
38
38
  group_data: 'データ & 権限',
39
39
  cmd_data: '統合データ管理(フォーム/プロセス/タスク/サブフォーム)',
40
40
  cmd_task_center: 'グローバルタスクセンター(未処理/処理済/CC等)',
41
+ cmd_basic_info: '組織の基本情報、容量、クォータ、ドメイン設定を照会',
41
42
  cmd_get_permission: 'フォーム権限設定を照会',
42
43
  cmd_save_permission: 'フォーム権限設定を保存',
43
44
  cmd_corp_manager: 'プラットフォーム権限を管理',
@@ -169,7 +170,7 @@ openyida - Yida CLI ツール
169
170
  openyida create-app "勤怠管理"
170
171
  openyida create-app "勤怠管理" "従業員勤怠システム" "xian-daka" "#00B853" "deepBlue" "dark" "slide"
171
172
  openyida create-page APP_XXX "ゲームホーム"
172
- openyida create-form create APP_XXX "従業員情報" fields.json
173
+ openyida create-form create APP_XXX "従業員情報" .cache/openyida/forms/employee-fields.json
173
174
  openyida create-form update APP_XXX FORM-XXX '[{"action":"add","field":{"type":"TextField","label":"備考"}}]'
174
175
  openyida get-schema APP_XXX FORM-XXX
175
176
  openyida publish pages/src/home.oyd.jsx APP_XXX FORM-XXX
@@ -179,10 +180,10 @@ openyida - Yida CLI ツール
179
180
  openyida update-form-config APP_XXX FORM-XXX false "ページタイトル"
180
181
  openyida data query form APP_XXX FORM-XXX --page 1 --size 20
181
182
  openyida dws contact user search --keyword "wukong"
182
- openyida create-report APP_XXX "売上レポート" charts.json
183
- openyida append-chart APP_XXX REPORT-XXX charts.json
184
- openyida configure-process APP_XXX FORM-YYY process-def.json
185
- openyida create-process APP_XXX "注文処理フォーム" fields.json process-def.json
183
+ openyida create-report APP_XXX "売上レポート" .cache/openyida/reports/charts.json
184
+ openyida append-chart APP_XXX REPORT-XXX .cache/openyida/reports/charts.json
185
+ openyida configure-process APP_XXX FORM-YYY .cache/openyida/process/process-def.json
186
+ openyida create-process APP_XXX "注文処理フォーム" .cache/openyida/process/fields.json .cache/openyida/process/process-def.json
186
187
  openyida export APP_XXX
187
188
  openyida export APP_XXX ./my-app-backup.json
188
189
  openyida import ./yida-export.json
@@ -210,7 +211,7 @@ openyida - Yida CLI ツール
210
211
  compile_example: '例: openyida compile pages/src/home.oyd.jsx',
211
212
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
212
213
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
213
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
214
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
214
215
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
215
216
  publish_usage: '使用方法: openyida publish <ソースファイル> <appType> <formUuid> [--health-check]',
216
217
  publish_example: '例: openyida publish pages/src/home.oyd.jsx APP_XXX FORM-XXX --health-check',
@@ -511,7 +512,7 @@ openyida - Yida CLI ツール
511
512
  schema_saved_config_failed: ' Schema は保存されましたが、設定の更新に失敗しました',
512
513
  error: '\n❌ エラー: {0}',
513
514
  usage_create: '使用方法: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
514
- example_create: '例: openyida create-form create "APP_XXX" "従業員情報" fields.json',
515
+ example_create: '例: openyida create-form create "APP_XXX" "従業員情報" .cache/openyida/forms/employee-fields.json',
515
516
  usage_update: '使用方法: openyida create-form update <appType> <formUuid> <changesJsonOrFile>',
516
517
  example_update: '例: openyida create-form update "APP_XXX" "FORM-YYY" \'[{"action":"add","field":{"type":"TextField","label":"備考"}}]\'',
517
518
  usage_label: '使用方法:',
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: '데이터 & 권한',
37
37
  cmd_data: '통합 데이터 관리 (양식/프로세스/작업/하위양식)',
38
38
  cmd_task_center: '글로벌 작업 센터 (할일/처리됨/참조 등)',
39
+ cmd_basic_info: '조직 기본 정보, 용량, 할당량 및 도메인 설정 조회',
39
40
  cmd_get_permission: '양식 권한 설정 조회',
40
41
  cmd_save_permission: '양식 권한 설정 저장',
41
42
  cmd_corp_manager: '플랫폼 권한 관리',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: '예: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'Dados & Permissões',
37
37
  cmd_data: 'Gerenciamento unificado de dados (formulário/processo/tarefa/subformulário)',
38
38
  cmd_task_center: 'Centro de tarefas global (pendente/processado/CC etc.)',
39
+ cmd_basic_info: 'Consultar info da organizacao, capacidade, cotas e dominio',
39
40
  cmd_get_permission: 'Consultar configuração de permissões',
40
41
  cmd_save_permission: 'Salvar configuração de permissões',
41
42
  cmd_corp_manager: 'Gerenciar permissões da plataforma',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'Exemplo: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -36,6 +36,7 @@ module.exports = {
36
36
  group_data: 'Dữ liệu & Quyền',
37
37
  cmd_data: 'Quản lý dữ liệu thống nhất (biểu mẫu/quy trình/tác vụ/biểu mẫu con)',
38
38
  cmd_task_center: 'Trung tâm tác vụ toàn cầu (cần làm/đã xử lý/CC v.v.)',
39
+ cmd_basic_info: 'Truy van thong tin to chuc, dung luong, han muc va mien',
39
40
  cmd_get_permission: 'Truy vấn cấu hình quyền biểu mẫu',
40
41
  cmd_save_permission: 'Lưu cấu hình quyền biểu mẫu',
41
42
  cmd_corp_manager: 'Quản lý quyền nền tảng',
@@ -104,7 +105,7 @@ module.exports = {
104
105
  compile_example: 'Ví dụ: openyida compile pages/src/home.oyd.jsx',
105
106
  check_page_usage: 'Usage: openyida check-page <sourceFile> [--compat] [--json]',
106
107
  check_page_example: 'Example: openyida check-page pages/src/home.oyd.jsx --json',
107
- generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
108
+ generate_page_usage: 'Usage: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
108
109
  generate_page_example: 'Example: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
109
110
  },
110
111
 
@@ -38,6 +38,7 @@ module.exports = {
38
38
  group_data: '資料 & 權限',
39
39
  cmd_data: '統一資料管理(表單/流程/任務/子表單)',
40
40
  cmd_task_center: '全域任務中心(待辦/已處理/抄送等)',
41
+ cmd_basic_info: '查詢組織基本資訊、容量、額度和域名設定',
41
42
  cmd_get_permission: '查詢表單權限設定',
42
43
  cmd_save_permission: '儲存表單權限設定',
43
44
  cmd_corp_manager: '管理平台管理員與通訊錄權限',
@@ -169,7 +170,7 @@ openyida - 宜搭命令列工具
169
170
  openyida create-app "考勤管理"
170
171
  openyida create-app "考勤管理" "員工考勤系統" "xian-daka" "#00B853" "deepBlue" "dark" "slide"
171
172
  openyida create-page APP_XXX "遊戲主頁"
172
- openyida create-form create APP_XXX "員工資料" fields.json
173
+ openyida create-form create APP_XXX "員工資料" .cache/openyida/forms/employee-fields.json
173
174
  openyida create-form update APP_XXX FORM-XXX '[{"action":"add","field":{"type":"TextField","label":"備註"}}]'
174
175
  openyida get-schema APP_XXX FORM-XXX
175
176
  openyida publish pages/src/home.oyd.jsx APP_XXX FORM-XXX
@@ -179,10 +180,10 @@ openyida - 宜搭命令列工具
179
180
  openyida update-form-config APP_XXX FORM-XXX false "頁面標題"
180
181
  openyida data query form APP_XXX FORM-XXX --page 1 --size 20
181
182
  openyida dws contact user search --keyword "悟空"
182
- openyida create-report APP_XXX "銷售報表" charts.json
183
- openyida append-chart APP_XXX REPORT-XXX charts.json
184
- openyida configure-process APP_XXX FORM-YYY process-def.json
185
- openyida create-process APP_XXX "訂單處理表" fields.json process-def.json
183
+ openyida create-report APP_XXX "銷售報表" .cache/openyida/reports/charts.json
184
+ openyida append-chart APP_XXX REPORT-XXX .cache/openyida/reports/charts.json
185
+ openyida configure-process APP_XXX FORM-YYY .cache/openyida/process/process-def.json
186
+ openyida create-process APP_XXX "訂單處理表" .cache/openyida/process/fields.json .cache/openyida/process/process-def.json
186
187
  openyida export APP_XXX
187
188
  openyida export APP_XXX ./my-app-backup.json
188
189
  openyida import ./yida-export.json
@@ -209,7 +210,7 @@ openyida - 宜搭命令列工具
209
210
  compile_example: '範例:openyida compile pages/src/home.oyd.jsx',
210
211
  check_page_usage: '用法:openyida check-page <原始檔路徑> [--compat] [--json]',
211
212
  check_page_example: '範例:openyida check-page pages/src/home.oyd.jsx --json',
212
- generate_page_usage: '用法:openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
213
+ generate_page_usage: '用法:openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
213
214
  generate_page_example: '範例:openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
214
215
  publish_usage: '用法:openyida publish <原始檔路徑> <appType> <formUuid> [--health-check]',
215
216
  publish_example: '範例:openyida publish pages/src/home.oyd.jsx APP_XXX FORM-XXX --health-check',
@@ -228,9 +229,9 @@ openyida - 宜搭命令列工具
228
229
  import_example1: '範例:openyida import ./yida-export.json',
229
230
  import_example2: ' openyida import ./yida-export.json "品質追溯系統(正式環境)"',
230
231
  configure_process_usage: '用法:openyida configure-process <appType> <formUuid> <processDefinitionFile> [processCode]',
231
- configure_process_example: '範例:openyida configure-process "APP_XXX" "FORM-YYY" process-definition.json',
232
+ configure_process_example: '範例:openyida configure-process "APP_XXX" "FORM-YYY" .cache/openyida/process/process-definition.json',
232
233
  create_process_usage: '用法:openyida create-process <appType> <formTitle> <fieldsJsonFile> <processDefinitionFile>\n openyida create-process <appType> --formUuid <formUuid> <processDefinitionFile>',
233
- create_process_example: '範例:openyida create-process "APP_XXX" "訂單處理表" fields.json process-definition.json',
234
+ create_process_example: '範例:openyida create-process "APP_XXX" "訂單處理表" .cache/openyida/process/fields.json .cache/openyida/process/process-definition.json',
234
235
  process_usage: '用法:openyida process <子指令>\n\n子指令:\n preview <appType> <processInstanceId> [--output <path>] 預覽流程實例(產生視覺化流程圖)',
235
236
  process_preview_usage: '用法:openyida process preview <appType> <processInstanceId> [--output <path>]',
236
237
  process_preview_example: '範例:openyida process preview APP_XXX proc-inst-id-xxx',
@@ -433,7 +434,7 @@ openyida - 宜搭命令列工具
433
434
  create_form: {
434
435
  error: '\n❌ 錯誤:{0}',
435
436
  usage_create: '用法:openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
436
- example_create: '範例:openyida create-form create "APP_XXX" "員工資料登記" fields.json',
437
+ example_create: '範例:openyida create-form create "APP_XXX" "員工資料登記" .cache/openyida/forms/employee-fields.json',
437
438
  usage_update: '用法:openyida create-form update <appType> <formUuid> <changesJsonOrFile>',
438
439
  example_update: '範例:openyida create-form update "APP_XXX" "FORM-YYY" \'[{"action":"add","field":{"type":"TextField","label":"備註"}}]\'',
439
440
  usage_label: '用法:',
@@ -39,6 +39,7 @@ module.exports = {
39
39
  group_data: '数据 & 权限',
40
40
  cmd_data: '统一数据管理(表单/流程/任务/子表单)',
41
41
  cmd_task_center: '全局任务中心(待办/已处理/抄送等)',
42
+ cmd_basic_info: '查询组织基本信息、容量、额度和域名设置',
42
43
  cmd_get_permission: '查询表单权限配置',
43
44
  cmd_save_permission: '保存表单权限配置',
44
45
  cmd_corp_manager: '管理平台管理员与通讯录权限',
@@ -226,7 +227,7 @@ openyida - 宜搭命令行工具
226
227
  compile_example: '示例: openyida compile pages/src/home.oyd.jsx',
227
228
  check_page_usage: '用法: openyida check-page <源文件路径> [--compat] [--json]',
228
229
  check_page_example: '示例: openyida check-page pages/src/home.oyd.jsx --json',
229
- generate_page_usage: '用法: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec page.json] [--compile]',
230
+ generate_page_usage: '用法: openyida generate-page <template> --output pages/src/home.oyd.jsx [--spec .cache/openyida/page-specs/home.json] [--compile]',
230
231
  generate_page_example: '示例: openyida generate-page product-homepage --brand-name OpenKuma --brand-initials OK --output pages/src/home.oyd.jsx --compile',
231
232
  build_page_usage: '用法: openyida build-page <源文件路径> [--output pages/build/page.yida.jsx|--write] [--json]',
232
233
  build_page_example: '示例: openyida build-page pages/src/dashboard.oyd.jsx --output pages/build/dashboard.yida.jsx',
@@ -251,9 +252,9 @@ openyida - 宜搭命令行工具
251
252
  import_example1: '示例: openyida import ./yida-export.json',
252
253
  import_example2: ' openyida import ./yida-export.json "质量追溯系统(生产环境)"',
253
254
  configure_process_usage: '用法: openyida configure-process <appType> <formUuid> <processDefinitionFile> [processCode]',
254
- configure_process_example: '示例: openyida configure-process "APP_XXX" "FORM-YYY" process-definition.json',
255
+ configure_process_example: '示例: openyida configure-process "APP_XXX" "FORM-YYY" .cache/openyida/process/process-definition.json',
255
256
  create_process_usage: '用法: openyida create-process <appType> <formTitle> <fieldsJsonFile> <processDefinitionFile>\n openyida create-process <appType> --formUuid <formUuid> <processDefinitionFile>',
256
- create_process_example: '示例: openyida create-process "APP_XXX" "订单处理表" fields.json process-definition.json',
257
+ create_process_example: '示例: openyida create-process "APP_XXX" "订单处理表" .cache/openyida/process/fields.json .cache/openyida/process/process-definition.json',
257
258
  process_usage: '用法: openyida process <子命令>\n\n子命令:\n preview <appType> <processInstanceId> [--output <path>] 预览流程实例(生成可视化流程图)',
258
259
  process_preview_usage: '用法: openyida process preview <appType> <processInstanceId> [--output <path>]',
259
260
  process_preview_example: '示例: openyida process preview APP_XXX proc-inst-id-xxx',
@@ -745,8 +746,8 @@ openyida - 宜搭命令行工具
745
746
  url: '访问地址',
746
747
  usage: '用法: openyida create-process <appType> <formTitle> <fieldsJsonFile> <processDefinitionFile>',
747
748
  usage2: ' openyida create-process <appType> --formUuid <formUuid> <processDefinitionFile>',
748
- example: '示例: openyida create-process "APP_XXX" "订单处理表" fields.json process-definition.json',
749
- example2: ' openyida create-process "APP_XXX" --formUuid FORM-YYY process-definition.json',
749
+ example: '示例: openyida create-process "APP_XXX" "订单处理表" .cache/openyida/process/fields.json .cache/openyida/process/process-definition.json',
750
+ example2: ' openyida create-process "APP_XXX" --formUuid FORM-YYY .cache/openyida/process/process-definition.json',
750
751
  },
751
752
 
752
753
  // ── lib/update-form-config.js ──────────────────────
@@ -146,7 +146,7 @@ function readJsonOption(options, jsonKey, fileKey, label) {
146
146
  const fileValue = options[fileKey];
147
147
 
148
148
  if (jsonValue && fileValue) {
149
- parseError(`${label} 只能同时使用 --${jsonKey.replace(/_/g, '-')} --${fileKey.replace(/_/g, '-')} 之一`);
149
+ parseError(`${label} 不能同时使用 --${jsonKey.replace(/_/g, '-')} --${fileKey.replace(/_/g, '-')}`);
150
150
  }
151
151
 
152
152
  if (fileValue) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.5.13-beta.1",
3
+ "version": "2026.5.13",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "bin/yida.js",
@@ -166,8 +166,8 @@ export function setCustomState(newState) {
166
166
  }
167
167
  });
168
168
  this.forceUpdate();
169
- if (newState.activeNav && !skipUrlSync) {
170
- updateRouteNavKey(newState.activeNav);
169
+ if (!skipUrlSync && shouldSyncRoute(newState)) {
170
+ updateRouteState(newState);
171
171
  }
172
172
  }
173
173
 
@@ -278,12 +278,20 @@ export function getDashboardData() {
278
278
  }
279
279
 
280
280
  export function syncNavFromUrl() {
281
- var routeNav = getRouteNavKey();
282
- if (routeNav && routeNav !== _customState.activeNav) {
283
- this.setCustomState({
284
- activeNav: routeNav,
285
- __skipUrlSync: true
286
- });
281
+ var routeState = getRouteState();
282
+ var nextState = {};
283
+ if (routeState.activeNav && routeState.activeNav !== _customState.activeNav) {
284
+ nextState.activeNav = routeState.activeNav;
285
+ }
286
+ if (routeState.activeIndustry && routeState.activeIndustry !== _customState.activeIndustry) {
287
+ nextState.activeIndustry = routeState.activeIndustry;
288
+ }
289
+ if (routeState.selectedSolution && routeState.selectedSolution !== _customState.selectedSolution) {
290
+ nextState.selectedSolution = routeState.selectedSolution;
291
+ }
292
+ if (Object.keys(nextState).length > 0) {
293
+ nextState.__skipUrlSync = true;
294
+ this.setCustomState(nextState);
287
295
  }
288
296
  }
289
297
 
@@ -323,6 +331,53 @@ export function openIndustrySolution(key) {
323
331
  });
324
332
  }
325
333
 
334
+ export function prepareVisitPlan(item, action) {
335
+ if (!item) {
336
+ this.utils.toast({ title: '暂无可处理的拜访计划', type: 'warning' });
337
+ return;
338
+ }
339
+ var text = buildVisitPlanDiagnosisText(item);
340
+ var industryKey = inferIndustryKey(text);
341
+ var solutionKey = industryDefaultSolutions[industryKey] || 'inspection';
342
+ var result = buildDiagnosisResult(text, industryKey, findSolutionByKey(solutionKey));
343
+ this.setCustomState({
344
+ diagnosisText: text,
345
+ activeIndustry: industryKey,
346
+ selectedSolution: solutionKey,
347
+ diagnosisMode: 'generated',
348
+ diagnosisResult: result,
349
+ materialGenerated: false,
350
+ materialResult: null,
351
+ aiError: ''
352
+ });
353
+ if (action === 'build') {
354
+ this.createDemo();
355
+ return;
356
+ }
357
+ this.runDiagnosis();
358
+ }
359
+
360
+ export function prepareRiskCustomer(item) {
361
+ if (!item) {
362
+ this.utils.toast({ title: '暂无风险客户', type: 'warning' });
363
+ return;
364
+ }
365
+ var text = buildRiskCustomerDiagnosisText(item);
366
+ var industryKey = inferIndustryKey(text);
367
+ var solutionKey = industryDefaultSolutions[industryKey] || 'inspection';
368
+ this.setCustomState({
369
+ diagnosisText: text,
370
+ activeIndustry: industryKey,
371
+ selectedSolution: solutionKey,
372
+ diagnosisMode: 'ready',
373
+ diagnosisResult: null,
374
+ materialGenerated: false,
375
+ materialResult: null,
376
+ aiError: ''
377
+ });
378
+ this.runDiagnosis();
379
+ }
380
+
326
381
  export function handleDiagnosisChange(e) {
327
382
  if (_customState._isComposing) {
328
383
  return;
@@ -577,47 +632,125 @@ function isKnownNavKey(key) {
577
632
  return navItems.filter((item) => item.key === key).length > 0;
578
633
  }
579
634
 
580
- function getRouteNavKey() {
635
+ function isKnownIndustryKey(key) {
636
+ return industries.filter((item) => item.key === key).length > 0;
637
+ }
638
+
639
+ function isKnownSolutionKey(key) {
640
+ return solutionCards.filter((item) => item.key === key).length > 0;
641
+ }
642
+
643
+ function shouldSyncRoute(newState) {
644
+ return !!(newState.activeNav || newState.activeIndustry || newState.selectedSolution);
645
+ }
646
+
647
+ function getIndustryKeyForSolution(solutionKey) {
648
+ var matchedKey = '';
649
+ Object.keys(industryDefaultSolutions).forEach((industryKey) => {
650
+ if (industryDefaultSolutions[industryKey] === solutionKey) {
651
+ matchedKey = industryKey;
652
+ }
653
+ });
654
+ return matchedKey;
655
+ }
656
+
657
+ function readRouteParam(name) {
581
658
  if (typeof window === 'undefined' || !window.location) {
582
659
  return '';
583
660
  }
584
- var key = '';
661
+ var value = '';
585
662
  try {
586
663
  if (typeof URLSearchParams !== 'undefined') {
587
664
  var params = new URLSearchParams(window.location.search || '');
588
- key = params.get('tab') || params.get('nav') || '';
665
+ value = params.get(name) || '';
589
666
  }
590
667
  } catch (e) {
591
- key = '';
668
+ value = '';
669
+ }
670
+ if (!value) {
671
+ var matched = String(window.location.search || '').match(new RegExp('[?&]' + name + '=([^&]+)'));
672
+ value = matched && matched[1] ? decodeURIComponent(matched[1]) : '';
673
+ }
674
+ return value;
675
+ }
676
+
677
+ function getRouteState() {
678
+ var navKey = readRouteParam('tab') || readRouteParam('nav');
679
+ var industryKey = readRouteParam('industry');
680
+ var solutionKey = readRouteParam('solution');
681
+ navKey = isKnownNavKey(navKey) ? navKey : '';
682
+ industryKey = isKnownIndustryKey(industryKey) ? industryKey : '';
683
+ solutionKey = isKnownSolutionKey(solutionKey) ? solutionKey : '';
684
+ if (solutionKey && !industryKey) {
685
+ industryKey = getIndustryKeyForSolution(solutionKey);
592
686
  }
593
- if (!key) {
594
- var matched = String(window.location.search || '').match(/[?&](?:tab|nav)=([^&]+)/);
595
- key = matched && matched[1] ? decodeURIComponent(matched[1]) : '';
687
+ if (industryKey && !solutionKey) {
688
+ solutionKey = industryDefaultSolutions[industryKey] || '';
596
689
  }
597
- return isKnownNavKey(key) ? key : '';
690
+ return {
691
+ activeNav: navKey,
692
+ activeIndustry: industryKey,
693
+ selectedSolution: solutionKey
694
+ };
598
695
  }
599
696
 
600
- function updateRouteNavKey(key) {
601
- if (!isKnownNavKey(key) || typeof window === 'undefined' || !window.history || !window.history.pushState) {
697
+ function updateRouteState(nextState) {
698
+ if (typeof window === 'undefined' || !window.history || !window.history.pushState) {
699
+ return;
700
+ }
701
+ var navKey = nextState.activeNav || _customState.activeNav;
702
+ var industryKey = nextState.activeIndustry || _customState.activeIndustry;
703
+ var solutionKey = nextState.selectedSolution || _customState.selectedSolution;
704
+ if (!isKnownNavKey(navKey)) {
602
705
  return;
603
706
  }
707
+ if (!isKnownIndustryKey(industryKey)) {
708
+ industryKey = getIndustryKeyForSolution(solutionKey) || 'manufacturing';
709
+ }
710
+ if (!isKnownSolutionKey(solutionKey)) {
711
+ solutionKey = industryDefaultSolutions[industryKey] || 'inspection';
712
+ }
604
713
  try {
605
714
  var url = new URL(window.location.href);
606
- url.searchParams.set('tab', key);
715
+ url.searchParams.set('tab', navKey);
716
+ url.searchParams.set('industry', industryKey);
717
+ url.searchParams.set('solution', solutionKey);
607
718
  var nextUrl = url.toString();
608
719
  if (nextUrl !== window.location.href) {
609
- window.history.pushState({ tab: key }, '', nextUrl);
720
+ window.history.pushState({ tab: navKey, industry: industryKey, solution: solutionKey }, '', nextUrl);
610
721
  }
611
722
  } catch (e) {
612
723
  var hash = window.location.hash || '';
613
724
  var base = window.location.href.split('#')[0].split('?')[0];
614
- var fallbackUrl = base + '?tab=' + encodeURIComponent(key) + hash;
725
+ var fallbackUrl = base + '?tab=' + encodeURIComponent(navKey) + '&industry=' + encodeURIComponent(industryKey) + '&solution=' + encodeURIComponent(solutionKey) + hash;
615
726
  if (fallbackUrl !== window.location.href) {
616
- window.history.pushState({ tab: key }, '', fallbackUrl);
727
+ window.history.pushState({ tab: navKey, industry: industryKey, solution: solutionKey }, '', fallbackUrl);
617
728
  }
618
729
  }
619
730
  }
620
731
 
732
+ function buildVisitPlanDiagnosisText(item) {
733
+ return [
734
+ '客户:' + (item.customer || '未命名客户'),
735
+ '拜访时间:' + (item.time || '待确认'),
736
+ 'SA:' + (item.owner || '未分配'),
737
+ '当前阶段:' + (item.stage || '待确认'),
738
+ '拜访目标:' + (item.goal || '待补充'),
739
+ '推荐方向:' + (item.solution || '待匹配'),
740
+ 'Demo 状态:' + (item.demo || '待创建'),
741
+ '风险标签:' + (item.risk || '无')
742
+ ].join('\n');
743
+ }
744
+
745
+ function buildRiskCustomerDiagnosisText(item) {
746
+ return [
747
+ '客户:' + (item.customer || '未命名客户'),
748
+ '风险等级:' + (item.level || '待判断'),
749
+ '风险原因:' + (item.reason || '待补充'),
750
+ '请生成主管陪访方案,包含客户痛点、推荐 Demo、会前准备、现场确认问题和下一步推进动作。'
751
+ ].join('\n');
752
+ }
753
+
621
754
  function getCsrfToken() {
622
755
  if (typeof window !== 'undefined' && window.g_config && window.g_config._csrf_token) {
623
756
  return window.g_config._csrf_token;
@@ -1359,6 +1492,7 @@ export function renderVisitMetric(item) {
1359
1492
  }
1360
1493
 
1361
1494
  export function renderVisitPlan(item) {
1495
+ var self = this;
1362
1496
  return (
1363
1497
  <div key={item.customer} style={styles.visitPlanCard}>
1364
1498
  <div style={styles.visitPlanTop}>
@@ -1374,6 +1508,10 @@ export function renderVisitPlan(item) {
1374
1508
  <span style={styles.smallTag}>{item.demo}</span>
1375
1509
  <span style={Object.assign({}, styles.smallTag, item.risk ? styles.riskTag : {})}>{item.risk || '无风险'}</span>
1376
1510
  </div>
1511
+ <div style={styles.cardButtonRow}>
1512
+ <button style={styles.miniPrimaryButton} onClick={(e) => { self.prepareVisitPlan(item, 'diagnose'); }}>生成方案包</button>
1513
+ <button style={styles.miniSecondaryButton} onClick={(e) => { self.prepareVisitPlan(item, 'build'); }}>搭建 Demo</button>
1514
+ </div>
1377
1515
  </div>
1378
1516
  );
1379
1517
  }
@@ -1415,13 +1553,17 @@ export function renderTeamRow(item) {
1415
1553
  }
1416
1554
 
1417
1555
  export function renderRiskCustomer(item) {
1556
+ var self = this;
1418
1557
  return (
1419
1558
  <div key={item.customer} style={styles.riskRow}>
1420
1559
  <div>
1421
1560
  <div style={styles.riskTitle}>{item.customer}</div>
1422
1561
  <div style={styles.riskDesc}>{item.reason}</div>
1423
1562
  </div>
1424
- <span style={styles.riskLevel}>{item.level}</span>
1563
+ <div style={styles.riskActionColumn}>
1564
+ <span style={styles.riskLevel}>{item.level}</span>
1565
+ <button style={styles.miniSecondaryButton} onClick={(e) => { self.prepareRiskCustomer(item); }}>陪访方案</button>
1566
+ </div>
1425
1567
  </div>
1426
1568
  );
1427
1569
  }
@@ -1958,7 +2100,7 @@ export function renderVisitsView(isMobile) {
1958
2100
  <div style={styles.headerActions}>
1959
2101
  <span style={styles.statusPill}>{_customState.dataLoading ? '加载中' : _customState.dataSourceLabel}</span>
1960
2102
  <button style={styles.secondaryButton} onClick={(e) => { self.refreshDashboardData(); }}>刷新数据</button>
1961
- <button style={styles.primaryButton} onClick={(e) => { self.runDiagnosis(); }}>生成拜访方案包</button>
2103
+ <button style={styles.primaryButton} onClick={(e) => { self.prepareVisitPlan((dashboard.visitPlans || [])[0], 'diagnose'); }}>生成拜访方案包</button>
1962
2104
  </div>
1963
2105
  </div>
1964
2106
 
@@ -1993,6 +2135,10 @@ export function renderVisitsView(isMobile) {
1993
2135
  <div style={styles.aiAdviceBox}>
1994
2136
  <div style={styles.suggestionTitle}>AI 拜访建议</div>
1995
2137
  <div style={styles.suggestionText}>本周高价值拜访集中在制造和政企,建议优先准备设备巡检、督办闭环两个可演示 Demo;3 个客户缺少明确下一步,需要会后 24 小时内补齐 owner 和时间点。</div>
2138
+ <div style={styles.actionRow}>
2139
+ <button style={styles.miniPrimaryButton} onClick={(e) => { self.prepareVisitPlan((dashboard.visitPlans || [])[0], 'diagnose'); }}>准备首个拜访</button>
2140
+ <button style={styles.miniSecondaryButton} onClick={(e) => { self.prepareVisitPlan((dashboard.visitPlans || [])[0], 'build'); }}>创建首个 Demo</button>
2141
+ </div>
1996
2142
  </div>
1997
2143
  </section>
1998
2144
  </div>
@@ -2054,6 +2200,9 @@ export function renderManagerView(isMobile) {
2054
2200
  <div style={styles.aiAdviceBox}>
2055
2201
  <div style={styles.suggestionTitle}>AI 管理建议</div>
2056
2202
  <div style={styles.suggestionText}>建议主管本周陪访「华东精密制造」,并安排行业专家支持「政务督办项目」。有 5 个 Demo 创建后超过 7 天未完成演示,需要逐一确认客户反馈。</div>
2203
+ <div style={styles.actionRow}>
2204
+ <button style={styles.miniPrimaryButton} onClick={(e) => { self.prepareRiskCustomer((dashboard.riskCustomers || [])[0]); }}>生成重点陪访方案</button>
2205
+ </div>
2057
2206
  </div>
2058
2207
  </section>
2059
2208
  </div>
@@ -2679,6 +2828,30 @@ var styles = {
2679
2828
  cursor: 'pointer',
2680
2829
  whiteSpace: 'nowrap'
2681
2830
  },
2831
+ miniPrimaryButton: {
2832
+ height: '28px',
2833
+ border: '0',
2834
+ borderRadius: '7px',
2835
+ background: '#2563EB',
2836
+ color: '#FFFFFF',
2837
+ padding: '0 10px',
2838
+ fontSize: '12px',
2839
+ fontWeight: 850,
2840
+ cursor: 'pointer',
2841
+ whiteSpace: 'nowrap'
2842
+ },
2843
+ miniSecondaryButton: {
2844
+ height: '28px',
2845
+ border: '1px solid #CBD5E1',
2846
+ borderRadius: '7px',
2847
+ background: '#FFFFFF',
2848
+ color: '#334155',
2849
+ padding: '0 10px',
2850
+ fontSize: '12px',
2851
+ fontWeight: 850,
2852
+ cursor: 'pointer',
2853
+ whiteSpace: 'nowrap'
2854
+ },
2682
2855
  diagnosisPanel: {
2683
2856
  background: '#FFFFFF',
2684
2857
  border: '1px solid #DDE5F0',
@@ -3522,6 +3695,12 @@ var styles = {
3522
3695
  gap: '6px',
3523
3696
  flexWrap: 'wrap'
3524
3697
  },
3698
+ cardButtonRow: {
3699
+ display: 'flex',
3700
+ gap: '8px',
3701
+ flexWrap: 'wrap',
3702
+ marginTop: '12px'
3703
+ },
3525
3704
  riskTag: {
3526
3705
  background: '#FEF2F2',
3527
3706
  color: '#B91C1C'
@@ -3686,6 +3865,11 @@ var styles = {
3686
3865
  fontWeight: 900,
3687
3866
  whiteSpace: 'nowrap'
3688
3867
  },
3868
+ riskActionColumn: {
3869
+ display: 'grid',
3870
+ gap: '8px',
3871
+ justifyItems: 'end'
3872
+ },
3689
3873
  materialGrid: {
3690
3874
  display: 'grid',
3691
3875
  gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
@@ -11,6 +11,7 @@ const SKILLS_DIR = path.join(ROOT, 'yida-skills', 'skills');
11
11
  const SKILL_COVERAGE = {
12
12
  'large-file-write': { level: 'offline', tests: ['write fixture generation uses fs APIs in runner tests'] },
13
13
  'yida-app': { level: 'real-e2e', stages: ['app', 'form', 'page', 'data', 'report', 'dashboard'] },
14
+ 'yida-basic-info': { level: 'offline-unit', tests: ['tests/basic-info.test.js'], reason: 'basic-info reads org admin metadata and can update domains; unit coverage avoids mutating shared real org settings' },
14
15
  'yida-chart': { level: 'real-e2e', stages: ['report', 'dashboard'], tests: ['report chart config generation'] },
15
16
  'yida-connector': { level: 'offline', stages: ['connector-local'], commands: ['connector gen-template', 'connector parse-api'] },
16
17
  'yida-corp-manager': { level: 'offline-unit', tests: ['tests/corp-manager.test.js'], reason: 'enterprise admin mutations are not safe for shared real org E2E' },
@@ -170,6 +170,7 @@ openyida copy
170
170
  | `yida-custom-page` | `skills/yida-custom-page/SKILL.md` | 编写自定义页面 JSX 代码规范 | 详见 SKILL.md |
171
171
  | `yida-publish-page` | `skills/yida-publish-page/SKILL.md` | 编译并发布自定义页面 | `openyida publish <源文件路径> <appType> <formUuid> [--health-check]` |
172
172
  | `yida-page-config` | `skills/yida-page-config/SKILL.md` | 页面公开访问/组织内分享配置 | `openyida verify-short-url <appType> <formUuid> <url>` |
173
+ | `yida-basic-info` | `skills/yida-basic-info/SKILL.md` | 组织基本信息、资源容量、额度和域名设置查询 | `openyida basic-info overview` |
173
174
  | `yida-form-permission` | `skills/yida-form-permission/SKILL.md` | 表单权限查询与保存 | `openyida get-permission <appType> <formUuid>` |
174
175
  | `yida-corp-manager` | `skills/yida-corp-manager/SKILL.md` | 平台管理员、应用管理员、子管理员与通讯录权限 | `openyida corp-manager <子命令>` |
175
176
  | `yida-form-detail` | `skills/yida-form-detail/SKILL.md` | 表单详情页 formDetail 样式优化 | 详见 SKILL.md |
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: yida-basic-info
3
+ description: 宜搭平台管理 basicInfo 页面的组织基本信息、资源容量、额度和域名设置查询。适用于排查组织版本、Corp ID、授权人数、容量用量、固定域名引用和高级能力额度。不适用于:表单数据管理(应使用 yida-data-management)、组织管理员配置(应使用 yida-corp-manager)。
4
+ ---
5
+
6
+ # 组织基本信息
7
+
8
+ ## 严格禁止 (NEVER DO)
9
+
10
+ - 不要通过 Chrome UI 点击来封装 basicInfo 能力,优先使用 OpenYida CLI/API
11
+ - 不要默认输出 `corpToken`,除非用户明确要求并理解敏感性
12
+ - 不要修改企业域名,除非用户明确给出目标域名并确认影响范围
13
+ - 不要调用 `getTokenApi`、`getSeniorPrintTmpAuthCode` 等临时令牌接口来暴露敏感凭证
14
+
15
+ ## 严格要求 (MUST DO)
16
+
17
+ - 查询组织概览时先运行 `openyida basic-info overview`
18
+ - 检查域名修改风险时先运行 `openyida basic-info abs-path` 查看固定域名引用页面
19
+ - 修改域名必须使用 `openyida basic-info domain set --target <domain> --confirm`
20
+ - **本技能不读写 memory**:组织信息通过 CLI 命令实时查询宜搭平台
21
+
22
+ ## 适用场景
23
+
24
+ | 用户意图 | 命令 |
25
+ |---------|------|
26
+ | 查询 basicInfo 页面整体信息 | `openyida basic-info overview` |
27
+ | 查询组织名称、Corp ID、版本、企业域名 | `openyida basic-info commodity` |
28
+ | 查询授权人数和分配情况 | `openyida basic-info grant` |
29
+ | 查询附件/数据/自动化流容量 | `openyida basic-info capacity --type all` |
30
+ | 查询高级能力额度 | `openyida basic-info quota` |
31
+ | 检测固定域名引用页面 | `openyida basic-info abs-path --page 1 --size 10` |
32
+ | 查询数据准备额度 | `openyida basic-info dataflow` |
33
+ | 查询国际化能力 | `openyida basic-info i18n` |
34
+ | 查询当前企业域名 | `openyida basic-info domain` |
35
+
36
+ ## 命令
37
+
38
+ ### 概览
39
+
40
+ ```bash
41
+ openyida basic-info overview
42
+ ```
43
+
44
+ 默认输出会隐藏 `corpToken`。如用户明确要求完整凭证,才可以追加:
45
+
46
+ ```bash
47
+ openyida basic-info overview --include-secrets
48
+ ```
49
+
50
+ ### 组织信息
51
+
52
+ ```bash
53
+ openyida basic-info commodity
54
+ ```
55
+
56
+ 返回组织名称、Corp ID、版本、企业域名、版本权益等信息。
57
+
58
+ ### 授权信息
59
+
60
+ ```bash
61
+ openyida basic-info grant
62
+ ```
63
+
64
+ 返回授权总量、已分配组织成员、上下游伙伴授权等信息。
65
+
66
+ ### 资源容量
67
+
68
+ ```bash
69
+ openyida basic-info capacity --type all
70
+ openyida basic-info capacity --type file
71
+ openyida basic-info capacity --type data
72
+ openyida basic-info capacity --type flow
73
+ ```
74
+
75
+ ### 额度
76
+
77
+ ```bash
78
+ openyida basic-info quota
79
+ openyida basic-info quota --resource-key singleFormInstanceLimit
80
+ openyida basic-info quota --resource-keys portalAmount,faasAmount,ocrAmount
81
+ ```
82
+
83
+ 常见 `resourceKey`:
84
+
85
+ | key | 含义 |
86
+ |-----|------|
87
+ | `singleFormInstanceLimit` | 单表数据量上限 |
88
+ | `ocrAmount` | OCR 识别额度 |
89
+ | `portalAmount` | 门户额度 |
90
+ | `corpDataCardAmount` | 数据卡片额度 |
91
+ | `corpDataCardPushAmount` | 数据卡片推送额度 |
92
+ | `faasAmount` | FaaS 连接器调用额度 |
93
+ | `corpVviewAmount` | 数据大屏额度 |
94
+ | `ddDataSetAmount` | 钉钉数据集额度 |
95
+
96
+ ### 固定域名引用检测
97
+
98
+ ```bash
99
+ openyida basic-info abs-path --page 1 --size 10
100
+ ```
101
+
102
+ 域名修改前必须检查该列表;若有结果,应先修复相关页面里的固定域名引用。
103
+
104
+ ### 域名
105
+
106
+ 查询当前企业域名:
107
+
108
+ ```bash
109
+ openyida basic-info domain
110
+ ```
111
+
112
+ 修改企业域名:
113
+
114
+ ```bash
115
+ openyida basic-info domain set --target newname --confirm
116
+ ```
117
+
118
+ `--target` 只支持小写字母、数字、中划线,必须以小写字母开头,最长 10 个字符。修改后组织内所有应用访问地址会变化,旧域名访问可能要求重新登录。
119
+
120
+ ## 异常处理
121
+
122
+ | 异常场景 | 处理方式 |
123
+ |---------|----------|
124
+ | 权限不足 | 提示用户确认当前账号是否为主管理员或平台管理员 |
125
+ | 登录态失效 | 运行 `openyida login` 或 `openyida auth status` |
126
+ | `abs-path` 返回大量记录 | 先按应用/页面逐步修复固定域名引用,再修改域名 |
127
+ | 域名修改失败 | 检查剩余修改次数、域名格式和当前组织版本 |
128
+ | `overview.errors` 非空 | 展示成功部分,同时说明失败的子接口和错误信息 |
129
+
130
+ ## Agent 错误处理策略
131
+
132
+ | 错误类型 | 默认处理策略 |
133
+ |---------|-------------|
134
+ | 命令执行失败 | 停止执行,展示错误信息,不要猜测结果 |
135
+ | 参数缺失 | 主动询问用户补充,不要编造域名或 resourceKey |
136
+ | 修改域名未确认 | 停止执行,说明需要用户明确确认 |
137
+ | 敏感信息请求 | 先说明 `corpToken` 属于敏感凭证,再按用户确认决定是否追加 `--include-secrets` |