openyida 2026.8.5 → 2026.8.12
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 +7 -3
- package/bin/yida.js +8 -1
- package/lib/app/app-lifecycle.js +128 -0
- package/lib/app/get-schema.js +123 -2
- package/lib/core/command-manifest.js +9 -3
- package/lib/core/locales/en.js +15 -0
- package/lib/core/locales/zh.js +15 -0
- package/package.json +1 -1
- package/yida-skills/SKILL.md +4 -3
- package/yida-skills/skills/yida-app-lifecycle/SKILL.md +56 -0
- package/yida-skills/skills/yida-design/references/asset-workflow.md +1 -1
- package/yida-skills/skills/yida-design/references/style-design-selection.md +48 -29
- package/yida-skills/skills/yida-design/references/style-designs/registry.md +56 -30
- package/yida-skills/skills-index.json +38 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
OpenYida connects AI coding agents with Yida's low-code platform, so developers can create apps, forms, workflows, custom pages, reports, integrations, and deployment configuration from a normal chat-driven development workflow.
|
|
10
10
|
|
|
11
|
-
[Quick Start](#quick-start) · [
|
|
11
|
+
[Quick Start](#quick-start) · [帮助网站&文档](https://demo.aliwork.com/o/openyida/helpCenter) · [Capabilities](#capabilities) · [Full Capability List](https://demo.aliwork.com/o/openyida/helpCenter?openyidaPath=capabilities) · [CLI Reference](https://demo.aliwork.com/o/openyida/helpCenter?openyidaPath=features/skills) · [Examples](https://demo.aliwork.com/o/openyida/helpCenter?openyidaRoute=showcase) · [Contributing](./CONTRIBUTING.md) · [Changelog](https://demo.aliwork.com/o/openyida/helpCenter?openyidaRoute=changelog)
|
|
12
12
|
|
|
13
13
|
[](https://www.npmjs.com/package/openyida)
|
|
14
14
|
[](https://www.npmjs.com/package/openyida)
|
|
@@ -16,7 +16,7 @@ OpenYida connects AI coding agents with Yida's low-code platform, so developers
|
|
|
16
16
|
[](./LICENSE)
|
|
17
17
|
[](https://nodejs.org)
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
**帮助网站&文档:** [帮助网站&文档](https://demo.aliwork.com/o/openyida/helpCenter)
|
|
20
20
|
|
|
21
21
|
[English README](./README.md) · [简体中文 README](./README_zhCN.md)
|
|
22
22
|
|
|
@@ -163,7 +163,7 @@ openyida/
|
|
|
163
163
|
|
|
164
164
|
## Capabilities
|
|
165
165
|
|
|
166
|
-
For a user-facing list of supported features and matching CLI commands, see [OpenYida 功能完整列表](
|
|
166
|
+
For a user-facing list of supported features and matching CLI commands, see [OpenYida 功能完整列表](https://demo.aliwork.com/o/openyida/helpCenter?openyidaPath=capabilities).
|
|
167
167
|
|
|
168
168
|
### Application and Form Management
|
|
169
169
|
|
|
@@ -194,6 +194,8 @@ Custom page source is authored directly from PRD and design guidance. Code Canva
|
|
|
194
194
|
|
|
195
195
|
For member, department, attachment, and image upload components, choose the page chain first. Code Canvas pages should follow `yida-canvas-custom-page/references/native-components-bridge.md` for feature detection, fallback, and value normalization. 普通自定义页面 JSX/Jsx pages should use `.oyd.jsx`, read `yida-custom-page/references/component-jsx-guide.md`, and read `attachment-upload-guide.md` when upload fields are involved.
|
|
196
196
|
|
|
197
|
+
For the current AI custom page native-component support matrix, see [Yida native components supported by AI custom pages](https://demo.aliwork.com/o/openyida/sample/canvas-native-components).
|
|
198
|
+
|
|
197
199
|
### Workflow, Data, and Permissions
|
|
198
200
|
|
|
199
201
|
```bash
|
|
@@ -369,6 +371,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
|
|
|
369
371
|
| `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency overview and detail reports |
|
|
370
372
|
| `openyida create-app "<name>"\|--name <name> [options] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a Yida app |
|
|
371
373
|
| `openyida update-app <appType> [--name "..."] [--layout slide\|ver] [--theme deepBlue]` | Update app info |
|
|
374
|
+
| `openyida app-online <appType> [--to-ding-app-center] [--show-app-center]` | Enable a Yida app |
|
|
375
|
+
| `openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]` | Disable a Yida app |
|
|
372
376
|
| `openyida nav-group <list\|create\|rename\|delete\|move\|order\|auto-order\|hide\|show> <appType> ...` | Manage app sidebar navigation groups |
|
|
373
377
|
| `openyida app-permission <get\|set\|add\|remove\|search-user> ...` | Manage app primary, data, and developer admins |
|
|
374
378
|
| `openyida i18n <overview\|config\|languages\|list\|upsert\|delete\|translate\|translate-all\|upgrade> <appType> ...` | Manage app multilingual copy and language config |
|
package/bin/yida.js
CHANGED
|
@@ -143,7 +143,7 @@ function printHelp() {
|
|
|
143
143
|
console.log(` ${DIM}${RESET} openyida create-form create APP_XXX "${t('help.quickstart_form_name')}" .cache/openyida/forms/fields.json`);
|
|
144
144
|
console.log(` ${DIM}${RESET} openyida dws contact user search --keyword "张三"`);
|
|
145
145
|
console.log('');
|
|
146
|
-
console.log(` ${DIM}${t('help.docs')} https://
|
|
146
|
+
console.log(` ${DIM}${t('help.docs')} https://demo.aliwork.com/o/openyida/helpCenter · https://github.com/openyida/openyida${RESET}`);
|
|
147
147
|
console.log('');
|
|
148
148
|
}
|
|
149
149
|
|
|
@@ -841,6 +841,13 @@ async function main() {
|
|
|
841
841
|
break;
|
|
842
842
|
}
|
|
843
843
|
|
|
844
|
+
case 'app-online':
|
|
845
|
+
case 'app-offline': {
|
|
846
|
+
const { run: runAppLifecycle } = require('../lib/app/app-lifecycle');
|
|
847
|
+
await runAppLifecycle(command === 'app-online' ? 'online' : 'offline', args);
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
|
|
844
851
|
case 'nav-group':
|
|
845
852
|
case 'group': {
|
|
846
853
|
const { run: runNavGroup } = require('../lib/app/nav-group');
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* app-lifecycle.js - 启用或停用宜搭应用
|
|
3
|
+
*
|
|
4
|
+
* 用法:
|
|
5
|
+
* openyida app-online <appType> [--to-ding-app-center] [--show-app-center]
|
|
6
|
+
* openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const querystring = require('querystring');
|
|
12
|
+
const { httpPost, requestWithAutoLogin } = require('../core/utils');
|
|
13
|
+
const { createAuthRef } = require('../core/yida-client');
|
|
14
|
+
const { t } = require('../core/i18n');
|
|
15
|
+
const { throwCommandError, throwUsage } = require('../core/command-errors');
|
|
16
|
+
|
|
17
|
+
const ACTIONS = Object.freeze({
|
|
18
|
+
online: Object.freeze({ endpoint: 'onlineApp', api: 'App.goOnline' }),
|
|
19
|
+
offline: Object.freeze({ endpoint: 'offlineApp', api: 'App.goOffline' }),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function parseArgs(args = []) {
|
|
23
|
+
const params = {
|
|
24
|
+
appType: null,
|
|
25
|
+
toDingAppCenter: false,
|
|
26
|
+
showAppCenter: false,
|
|
27
|
+
help: false,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
for (const arg of args) {
|
|
31
|
+
if (arg === '--help' || arg === '-h') {
|
|
32
|
+
params.help = true;
|
|
33
|
+
} else if (arg === '--to-ding-app-center') {
|
|
34
|
+
params.toDingAppCenter = true;
|
|
35
|
+
} else if (arg === '--show-app-center') {
|
|
36
|
+
params.showAppCenter = true;
|
|
37
|
+
} else if (!arg.startsWith('-') && !params.appType) {
|
|
38
|
+
params.appType = arg;
|
|
39
|
+
} else {
|
|
40
|
+
throwUsage(t('app_lifecycle.invalid_argument', arg));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return params;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function buildRequestPath(action, appType, stamp = Date.now()) {
|
|
48
|
+
const config = ACTIONS[action];
|
|
49
|
+
if (!config) {
|
|
50
|
+
throw new Error(t('app_lifecycle.invalid_action', action));
|
|
51
|
+
}
|
|
52
|
+
return `/dingtalk/web/${encodeURIComponent(appType)}/query/app/${config.endpoint}.json` +
|
|
53
|
+
`?_api=${encodeURIComponent(config.api)}&_mock=false&_stamp=${stamp}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function buildPostData(params, authRef) {
|
|
57
|
+
return querystring.stringify({
|
|
58
|
+
_csrf_token: authRef.csrfToken || '',
|
|
59
|
+
_locale_time_zone_offset: '28800000',
|
|
60
|
+
isToDingAppCenter: params.toDingAppCenter ? 'y' : 'n',
|
|
61
|
+
showAppCenter: params.showAppCenter ? 'y' : 'n',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function changeAppLifecycle(action, params, authRef = createAuthRef()) {
|
|
66
|
+
const response = await requestWithAutoLogin((auth) => httpPost(
|
|
67
|
+
auth.baseUrl,
|
|
68
|
+
buildRequestPath(action, params.appType),
|
|
69
|
+
buildPostData(params, auth),
|
|
70
|
+
auth.cookies
|
|
71
|
+
), authRef);
|
|
72
|
+
|
|
73
|
+
if (!response || response.success !== true || response.content !== true) {
|
|
74
|
+
const errorMsg = response && (response.errorMsg || response.message || response.errorCode);
|
|
75
|
+
throwCommandError(errorMsg || t('app_lifecycle.request_failed'), {
|
|
76
|
+
code: action === 'online' ? 'APP_ONLINE_FAILED' : 'APP_OFFLINE_FAILED',
|
|
77
|
+
details: { action, appType: params.appType },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
action,
|
|
84
|
+
appType: params.appType,
|
|
85
|
+
isToDingAppCenter: params.toDingAppCenter,
|
|
86
|
+
showAppCenter: params.showAppCenter,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function printUsage(action) {
|
|
91
|
+
const { usage } = require('../core/chalk');
|
|
92
|
+
usage(t(`app_lifecycle.${action}_usage`), t(`app_lifecycle.${action}_example`));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function run(action, args = []) {
|
|
96
|
+
if (!ACTIONS[action]) {
|
|
97
|
+
throwCommandError(t('app_lifecycle.invalid_action', action), {
|
|
98
|
+
code: 'APP_LIFECYCLE_INVALID_ACTION',
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const params = parseArgs(args);
|
|
103
|
+
if (params.help) {
|
|
104
|
+
printUsage(action);
|
|
105
|
+
return { success: true, help: true };
|
|
106
|
+
}
|
|
107
|
+
if (!params.appType) {
|
|
108
|
+
printUsage(action);
|
|
109
|
+
throwUsage(t('app_lifecycle.missing_app_type'), t(`app_lifecycle.${action}_usage`), {
|
|
110
|
+
code: 'APP_LIFECYCLE_USAGE',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const output = await changeAppLifecycle(action, params);
|
|
115
|
+
const { result } = require('../core/chalk');
|
|
116
|
+
result(true, t(`app_lifecycle.${action}_success`), [['appType', params.appType]]);
|
|
117
|
+
console.log(JSON.stringify(output));
|
|
118
|
+
return output;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = {
|
|
122
|
+
ACTIONS,
|
|
123
|
+
buildPostData,
|
|
124
|
+
buildRequestPath,
|
|
125
|
+
changeAppLifecycle,
|
|
126
|
+
parseArgs,
|
|
127
|
+
run,
|
|
128
|
+
};
|
package/lib/app/get-schema.js
CHANGED
|
@@ -187,6 +187,117 @@ function buildComponentAliasMaps(schemaResult) {
|
|
|
187
187
|
return { aliasByFieldId, fieldIdByAlias };
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
function parseJsonObject(value) {
|
|
191
|
+
if (typeof value !== 'string') {
|
|
192
|
+
return value && typeof value === 'object' ? value : null;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const parsed = JSON.parse(value);
|
|
196
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
197
|
+
} catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function resolveSchemaContent(schemaResult) {
|
|
203
|
+
if (!schemaResult) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
const content = schemaResult.content !== undefined ? schemaResult.content : schemaResult;
|
|
207
|
+
return parseJsonObject(content);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function addImportedModules(target, value) {
|
|
211
|
+
let modules = value;
|
|
212
|
+
if (typeof modules === 'string') {
|
|
213
|
+
const trimmed = modules.trim();
|
|
214
|
+
if (!trimmed) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
modules = JSON.parse(trimmed);
|
|
219
|
+
} catch {
|
|
220
|
+
modules = [trimmed];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (!Array.isArray(modules)) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
modules
|
|
227
|
+
.map(item => String(item || '').trim())
|
|
228
|
+
.filter(Boolean)
|
|
229
|
+
.forEach((item) => {
|
|
230
|
+
if (!target.includes(item)) {
|
|
231
|
+
target.push(item);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function codeBytes(value) {
|
|
237
|
+
return typeof value === 'string' ? Buffer.byteLength(value, 'utf8') : 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function isComponentInstance(node) {
|
|
241
|
+
return !!(node && typeof node === 'object' && (node.id || node.props || node.children));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function extractDisplayPageSummary(schemaResult) {
|
|
245
|
+
const content = resolveSchemaContent(schemaResult);
|
|
246
|
+
if (!content || typeof content !== 'object') {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const displayPage = {
|
|
251
|
+
hasYidaCodeCanvas: false,
|
|
252
|
+
hasNativeJsx: false,
|
|
253
|
+
runtimeCodeBytes: 0,
|
|
254
|
+
sourceCodeBytes: 0,
|
|
255
|
+
compiledCodeBytes: 0,
|
|
256
|
+
importedModules: [],
|
|
257
|
+
componentCount: 0,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
function traverse(node) {
|
|
261
|
+
if (!node) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(node)) {
|
|
265
|
+
node.forEach(traverse);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (typeof node !== 'object') {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (node.componentName === 'YidaCodeCanvas' && isComponentInstance(node)) {
|
|
273
|
+
const props = node.props || {};
|
|
274
|
+
displayPage.hasYidaCodeCanvas = true;
|
|
275
|
+
displayPage.componentCount++;
|
|
276
|
+
displayPage.runtimeCodeBytes += codeBytes(props.runtimeCode);
|
|
277
|
+
displayPage.sourceCodeBytes += codeBytes(props.code);
|
|
278
|
+
addImportedModules(displayPage.importedModules, props.importedModules);
|
|
279
|
+
} else if (node.componentName === 'Jsx' && isComponentInstance(node)) {
|
|
280
|
+
displayPage.hasNativeJsx = true;
|
|
281
|
+
displayPage.componentCount++;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
Object.keys(node).forEach((key) => traverse(node[key]));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
traverse(content.pages || content);
|
|
288
|
+
|
|
289
|
+
const module = content.actions && content.actions.module;
|
|
290
|
+
if (displayPage.hasNativeJsx && module && typeof module === 'object') {
|
|
291
|
+
displayPage.sourceCodeBytes += codeBytes(module.source);
|
|
292
|
+
displayPage.compiledCodeBytes += codeBytes(module.compiled);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (!displayPage.hasYidaCodeCanvas && !displayPage.hasNativeJsx) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return displayPage;
|
|
299
|
+
}
|
|
300
|
+
|
|
190
301
|
function parsePositiveInt(value, fallback, min, max) {
|
|
191
302
|
const parsed = Number.parseInt(value, 10);
|
|
192
303
|
if (!Number.isFinite(parsed) || parsed < min) {
|
|
@@ -402,7 +513,7 @@ function printFieldSummary(result) {
|
|
|
402
513
|
|
|
403
514
|
function buildSchemaSummary(appType, formUuid, schemaResult, meta = {}) {
|
|
404
515
|
const fields = extractFieldSummary(schemaResult);
|
|
405
|
-
|
|
516
|
+
const summary = {
|
|
406
517
|
success: true,
|
|
407
518
|
appType,
|
|
408
519
|
formUuid,
|
|
@@ -410,6 +521,11 @@ function buildSchemaSummary(appType, formUuid, schemaResult, meta = {}) {
|
|
|
410
521
|
fieldCount: fields.length,
|
|
411
522
|
fields,
|
|
412
523
|
};
|
|
524
|
+
const displayPage = extractDisplayPageSummary(schemaResult);
|
|
525
|
+
if (displayPage) {
|
|
526
|
+
summary.displayPage = displayPage;
|
|
527
|
+
}
|
|
528
|
+
return summary;
|
|
413
529
|
}
|
|
414
530
|
|
|
415
531
|
function filterForms(forms, keyword) {
|
|
@@ -454,7 +570,7 @@ async function fetchSchemaRecord(appType, form, authRef, retries) {
|
|
|
454
570
|
try {
|
|
455
571
|
const result = await fetchSchema(appType, form.formUuid, authRef);
|
|
456
572
|
if (isSuccessfulSchemaResult(result)) {
|
|
457
|
-
|
|
573
|
+
const record = {
|
|
458
574
|
formUuid: form.formUuid,
|
|
459
575
|
formName: form.formName,
|
|
460
576
|
formType: form.formType,
|
|
@@ -464,6 +580,11 @@ async function fetchSchemaRecord(appType, form, authRef, retries) {
|
|
|
464
580
|
fieldSummary: extractFieldSummary(result),
|
|
465
581
|
schema: result,
|
|
466
582
|
};
|
|
583
|
+
const displayPage = extractDisplayPageSummary(result);
|
|
584
|
+
if (displayPage) {
|
|
585
|
+
record.displayPage = displayPage;
|
|
586
|
+
}
|
|
587
|
+
return record;
|
|
467
588
|
}
|
|
468
589
|
lastError = new Error(result ? result.errorMsg || t('common.unknown_error') : t('common.request_failed'));
|
|
469
590
|
} catch (error) {
|
|
@@ -430,6 +430,8 @@ const COMMAND_SIDE_EFFECTS = new Map([
|
|
|
430
430
|
|
|
431
431
|
...sideEffectEntries([
|
|
432
432
|
'add-validation',
|
|
433
|
+
'app-offline',
|
|
434
|
+
'app-online',
|
|
433
435
|
'append-chart',
|
|
434
436
|
'cdn-refresh',
|
|
435
437
|
'cdn-upload',
|
|
@@ -596,7 +598,7 @@ const COMMAND_SIDE_EFFECTS = new Map([
|
|
|
596
598
|
mutates_yida: true,
|
|
597
599
|
mutates_local: false,
|
|
598
600
|
read_actions: ['list'],
|
|
599
|
-
mutating_actions: ['create', 'rename', 'delete', 'move', 'order', 'hide', 'show'],
|
|
601
|
+
mutating_actions: ['create', 'rename', 'delete', 'move', 'order', 'auto-order', 'hide', 'show'],
|
|
600
602
|
})],
|
|
601
603
|
['org', sideEffect('mixed', {
|
|
602
604
|
mutates_yida: false,
|
|
@@ -667,6 +669,7 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
667
669
|
|
|
668
670
|
...permissionEntries([
|
|
669
671
|
'add-validation',
|
|
672
|
+
'app-online',
|
|
670
673
|
'append-chart',
|
|
671
674
|
'build-page',
|
|
672
675
|
'cdn-config',
|
|
@@ -727,10 +730,11 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
727
730
|
})),
|
|
728
731
|
|
|
729
732
|
...permissionEntries([
|
|
733
|
+
'app-offline',
|
|
730
734
|
'connector.delete',
|
|
731
735
|
'connector.delete-action',
|
|
732
736
|
], permission('ask', 'destructive', {
|
|
733
|
-
reason: 'Deletes or
|
|
737
|
+
reason: 'Deletes, removes, or disables existing remote state.',
|
|
734
738
|
})),
|
|
735
739
|
|
|
736
740
|
...permissionEntries([
|
|
@@ -884,7 +888,7 @@ const COMMAND_PERMISSIONS = new Map([
|
|
|
884
888
|
...permissionEntries([
|
|
885
889
|
'nav-group',
|
|
886
890
|
], actionDependentPermission({
|
|
887
|
-
preauthorized_actions: ['create', 'rename', 'move', 'order', 'hide', 'show'],
|
|
891
|
+
preauthorized_actions: ['create', 'rename', 'move', 'order', 'auto-order', 'hide', 'show'],
|
|
888
892
|
ask_actions: ['delete'],
|
|
889
893
|
})),
|
|
890
894
|
|
|
@@ -1032,6 +1036,8 @@ const COMMAND_GROUPS = [
|
|
|
1032
1036
|
}),
|
|
1033
1037
|
command('create-app', ['create-app'], 'create-app "<name>"|--name <name> [options] [--locale zh_CN|en_US|ja_JP] [--open|--no-open]', 'help.cmd_create_app'),
|
|
1034
1038
|
command('update-app', ['update-app'], 'update-app <appType> [--name "..."] [--layout slide|ver] [--theme deepBlue]', 'help.cmd_update_app'),
|
|
1039
|
+
command('app-online', ['app-online'], 'app-online <appType> [--to-ding-app-center] [--show-app-center]', 'help.cmd_app_online'),
|
|
1040
|
+
command('app-offline', ['app-offline'], 'app-offline <appType> [--to-ding-app-center] [--show-app-center]', 'help.cmd_app_offline'),
|
|
1035
1041
|
command('nav-group', ['nav-group'], 'nav-group <list|create|rename|delete|move|order|auto-order|hide|show> <appType> ...', 'help.cmd_nav_group', {
|
|
1036
1042
|
output: 'json',
|
|
1037
1043
|
aliases: ['group'],
|
package/lib/core/locales/en.js
CHANGED
|
@@ -23,6 +23,8 @@ module.exports = {
|
|
|
23
23
|
cmd_corp_efficiency: 'Query enterprise efficiency overview and detail reports',
|
|
24
24
|
cmd_create_app: 'Create a Yida app',
|
|
25
25
|
cmd_update_app: 'Update app info',
|
|
26
|
+
cmd_app_online: 'Enable a Yida app',
|
|
27
|
+
cmd_app_offline: 'Disable a Yida app',
|
|
26
28
|
cmd_nav_group: 'Manage app sidebar navigation groups',
|
|
27
29
|
cmd_app_permission: 'Manage app primary, data, and developer admins',
|
|
28
30
|
cmd_i18n: 'Manage app multilingual copy and language config',
|
|
@@ -960,6 +962,19 @@ Examples:
|
|
|
960
962
|
layout_notice: 'Note: layoutDirection is consumed by the Yida app shell during creation/refresh. If the top action bar does not recover immediately after a backend switch, reopen the workbench or recreate the app with the target layout.',
|
|
961
963
|
},
|
|
962
964
|
|
|
965
|
+
app_lifecycle: {
|
|
966
|
+
online_usage: 'Usage: openyida app-online <appType> [--to-ding-app-center] [--show-app-center]',
|
|
967
|
+
online_example: 'Example: openyida app-online APP_XXX',
|
|
968
|
+
offline_usage: 'Usage: openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]',
|
|
969
|
+
offline_example: 'Example: openyida app-offline APP_XXX',
|
|
970
|
+
missing_app_type: 'Error: missing appType argument',
|
|
971
|
+
invalid_argument: 'Unsupported argument: {0}',
|
|
972
|
+
invalid_action: 'Unsupported app lifecycle action: {0}',
|
|
973
|
+
request_failed: 'App lifecycle operation failed',
|
|
974
|
+
online_success: 'App enabled',
|
|
975
|
+
offline_success: 'App disabled',
|
|
976
|
+
},
|
|
977
|
+
|
|
963
978
|
// ── lib/update-form-config.js ──────────────────────
|
|
964
979
|
update_form_config: {
|
|
965
980
|
usage: 'Usage: openyida update-form-config <appType> <formUuid> <isRenderNav> <title>',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -23,6 +23,8 @@ module.exports = {
|
|
|
23
23
|
cmd_corp_efficiency: '查询企业效能概览和明细报表',
|
|
24
24
|
cmd_create_app: '创建宜搭应用',
|
|
25
25
|
cmd_update_app: '更新应用信息',
|
|
26
|
+
cmd_app_online: '启用宜搭应用',
|
|
27
|
+
cmd_app_offline: '停用宜搭应用',
|
|
26
28
|
cmd_nav_group: '管理应用左侧导航分组',
|
|
27
29
|
cmd_app_permission: '管理应用主管理员、数据管理员和开发成员',
|
|
28
30
|
cmd_i18n: '管理应用多语言文案和语言配置',
|
|
@@ -889,6 +891,19 @@ openyida - 宜搭命令行工具
|
|
|
889
891
|
layout_notice: '提示:layoutDirection 由宜搭应用外壳在创建/刷新时消费;若后台切换后顶部操作栏未立即恢复,请重新打开工作台或使用目标 layout 重新创建应用。',
|
|
890
892
|
},
|
|
891
893
|
|
|
894
|
+
app_lifecycle: {
|
|
895
|
+
online_usage: '用法: openyida app-online <appType> [--to-ding-app-center] [--show-app-center]',
|
|
896
|
+
online_example: '示例: openyida app-online APP_XXX',
|
|
897
|
+
offline_usage: '用法: openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]',
|
|
898
|
+
offline_example: '示例: openyida app-offline APP_XXX',
|
|
899
|
+
missing_app_type: '错误: 缺少 appType 参数',
|
|
900
|
+
invalid_argument: '不支持的参数: {0}',
|
|
901
|
+
invalid_action: '不支持的应用生命周期操作: {0}',
|
|
902
|
+
request_failed: '应用生命周期操作失败',
|
|
903
|
+
online_success: '应用已启用',
|
|
904
|
+
offline_success: '应用已停用',
|
|
905
|
+
},
|
|
906
|
+
|
|
892
907
|
// ── lib/process/create-process.js ─────────────────
|
|
893
908
|
create_process: {
|
|
894
909
|
title: '宜搭流程表单一体化创建',
|
package/package.json
CHANGED
package/yida-skills/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openyida
|
|
3
3
|
description: >
|
|
4
|
-
|
|
4
|
+
宜搭应用开发总入口技能。通过具备代码生成能力的智能体(千问办公/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。
|
|
5
5
|
包含资源上下文解析、应用创建/复用、表单设计/更新、自定义页面开发、页面发布、登录态管理等完整开发流程。
|
|
6
6
|
当用户提到“宜搭”、“yida”、“低代码”、“创建应用”、“创建表单”、“发布页面”、“搭建”、“系统”等关键词时,使用此技能;以下情况不要触发:只是讨论通用前端/后端代码、非宜搭平台产品、或只需要解释概念而不操作宜搭资源。
|
|
7
7
|
重要路由规则:当用户首次创建完整应用/系统/平台时,如帮我搭建一个管理应用或者创建一个管理系统等,必须先加载 yida-app 子技能作为唯一编排入口,禁止直接调用 create-app/create-form/create-page 等子命令手动拼接。已有 app 且已有自定义页面的补齐或修改按常规路由即可。
|
|
@@ -9,7 +9,7 @@ description: >
|
|
|
9
9
|
|
|
10
10
|
# 宜搭应用开发指南
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
通过具备代码生成能力的智能体(千问办公/Claude/Open Code 等)+ 宜搭低代码平台,实现一句话搭建或修改完整应用。所有操作通过 **`openyida`** CLI 统一执行。登录态分流必须以 `openyida agent-capabilities --summary-json` 或 `openyida login --check-only --json` 返回的 OpenYida auth snapshot 为准;只有 snapshot 明确返回 `login.auth_source=env` 或 `failure_reason=env_token_missing` 时,才按运行环境注入 token 模式处理。其他未登录 token 场景走默认 OAuth token 登录,不要根据 agent 名称、运行环境类型或手写环境判断自行分流;禁止读取 `.cache/cookies*.json`。
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
@@ -165,7 +165,7 @@ OpenYida builder 默认使用 `create-app / create-form / create-page / publish`
|
|
|
165
165
|
| 大类目录 | 第一层意图信号 | 子技能 |
|
|
166
166
|
|------|------|------|
|
|
167
167
|
| `yida-skills/context` | 登录、退出、切换组织、组织版本/容量、Schema、fieldId、只读预检 | `yida-login`、`yida-logout`、`yida-basic-info`、`yida-get-schema`、`yida-corp-efficiency` |
|
|
168
|
-
| `yida-skills/app` |
|
|
168
|
+
| `yida-skills/app` | 从零搭应用、完整系统、应用启停、应用导航、多语言 | `yida-app`、`yida-create-app`、`yida-app-lifecycle`、`yida-nav-group`、`yida-i18n` |
|
|
169
169
|
| `yida-skills/design` | 完整应用产品设计、单页 UI 改造、主页面视觉设计、应用主题色、全局换肤、PRD 和 design.md | `yida-design` |
|
|
170
170
|
| `yida-skills/form` | 表单字段、公式、校验、业务关联规则、详情页、批量录入、数据记录 | `yida-create-form-page`、`yida-formula`、`yida-formula-evaluate`、`yida-business-rule`、`yida-form-detail`、`yida-canvas-table-form`、`yida-table-form`、`yida-data-management` |
|
|
171
171
|
| `yida-skills/process` | 审批、流程表单、流程规则、节点/分支/字段权限、流程代理 | `yida-create-process`、`yida-process-rule`、`yida-agent-center` |
|
|
@@ -186,6 +186,7 @@ OpenYida builder 默认使用 `create-app / create-form / create-page / publish`
|
|
|
186
186
|
| 用户给 taskUuid 并要求转 PRD | 先用 `yida-tingji` 读取听记内容,再把已有内容交给 `yida-flash-note-to-prd` 生成 PRD |
|
|
187
187
|
| 已有会议纪要/闪记内容转 PRD | `yida-flash-note-to-prd`,只处理已有内容,不负责按 taskUuid 拉取听记 |
|
|
188
188
|
| 只创建应用壳并拿 appType | `yida-create-app`;创建成功后把真实 `appType` 交给 `yida-design` 生成或更新 `prd/<项目名>/prd.md` 和 `prd/<项目名>/design.md`,后续表单、流程、页面和发布都消费这两份文件 |
|
|
189
|
+
| 启用/上线或停用/下线已有应用 | `yida-app-lifecycle`;只有用户明确要求时执行,`app-offline` 执行前需再次确认目标应用 |
|
|
189
190
|
| 创建自定义展示页资源 | `yida-create-page`,之后默认接 `yida-canvas-custom-page` 和 `yida-publish-page` |
|
|
190
191
|
| 开发表单字段结构 / 增删改字段 | 先加载 `yida-form-detail` 做表单视觉引导并合并 Divider 分割线,再用 `yida-create-form-page` 落地字段结构 |
|
|
191
192
|
| 创建带审批的流程表单 | `yida-create-process` |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yida-app-lifecycle
|
|
3
|
+
description: 宜搭应用启用与停用。仅当用户明确要求启用、停用、上线或下线某个已有应用时使用;不用于创建应用、发布页面或发布到钉钉应用中心。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 宜搭应用启用与停用
|
|
7
|
+
|
|
8
|
+
## 严格要求 (MUST DO)
|
|
9
|
+
|
|
10
|
+
- 只有用户明确说“启用应用 / 上线应用 / 停用应用 / 下线应用”时,才允许调用本技能的远程写命令;不得从“发布页面”“更新应用”“应用不可用”等间接描述推断执行。
|
|
11
|
+
- 执行前必须确认唯一的 `appType` 和当前登录组织;目标不明确时先询问用户。
|
|
12
|
+
- `app-offline` 会让现有应用停止服务,执行前必须向用户展示目标 `appType` 与完整命令并获得确认。
|
|
13
|
+
- 默认保持 `isToDingAppCenter=n`、`showAppCenter=n`。只有用户明确要求同步钉钉应用中心或显示应用中心时,才添加对应开关。
|
|
14
|
+
- 命令失败后完整展示错误并停止;不得无修改连续重试,也不得改用浏览器抓包中的 Cookie、token 或 `sec-*` header 绕过认证。
|
|
15
|
+
|
|
16
|
+
## 严格禁止 (NEVER DO)
|
|
17
|
+
|
|
18
|
+
- 不得把首次创建应用、表单/页面发布、应用信息更新自动升级为应用启用。
|
|
19
|
+
- 不得把“暂时隐藏页面”“禁用集成自动化”“关闭公开访问”路由为应用停用。
|
|
20
|
+
- 不得在测试、评测或默认 shared real E2E 中执行真实启用/停用。
|
|
21
|
+
- 不得把本能力扩展为钉钉应用中心完整发布流程。
|
|
22
|
+
|
|
23
|
+
## 意图与命令
|
|
24
|
+
|
|
25
|
+
启用或上线已有应用:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
openyida app-online <appType>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
停用或下线已有应用(需确认):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
openyida app-offline <appType>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
仅在用户明确要求应用中心相关行为时使用:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
openyida app-online <appType> --to-ding-app-center --show-app-center
|
|
41
|
+
openyida app-offline <appType> --to-ding-app-center --show-app-center
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 完成条件
|
|
45
|
+
|
|
46
|
+
- CLI 返回 `success: true`,且返回的 `action` 与用户意图一致。
|
|
47
|
+
- 向用户说明目标 `appType` 已启用或已停用;失败时不得宣称状态已改变。
|
|
48
|
+
|
|
49
|
+
## 异常处理
|
|
50
|
+
|
|
51
|
+
| 异常场景 | 处理方式 |
|
|
52
|
+
|---------|----------|
|
|
53
|
+
| 缺少或存在多个 appType 候选 | 停止并要求用户确认唯一目标 |
|
|
54
|
+
| 登录态失效 / 组织不符 | 重新登录或切换到目标组织后再执行 |
|
|
55
|
+
| 权限不足 | 停止并提示使用具备应用管理权限的账号 |
|
|
56
|
+
| 平台返回 `success: false` 或 `content: false` | 展示 `errorMsg` / `errorCode`,不得重试或宣称成功 |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# 生成 design.md 规则
|
|
2
2
|
|
|
3
|
-
本文件用于在 Step 5 为完整应用生成一份应用级 `prd/<项目名>/design.md
|
|
3
|
+
本文件用于在 Step 5 为完整应用生成一份应用级 `prd/<项目名>/design.md`。生成流程必须先从业务上下文判断内容兼容性,再推演视觉策略,选择唯一一个内置 `style-designs/*.md` 作为基础视觉母体,最后按主题色适配模板并输出自包含的 `design.md`。
|
|
4
4
|
|
|
5
|
-
业务对象、字段、表单、流程、导航、权限和页面结构都从当前 PRD 读取;模板只提供视觉 DNA
|
|
5
|
+
业务对象、字段、表单、流程、导航、权限和页面结构都从当前 PRD 读取;模板只提供视觉 DNA、布局机制、组件机制、质量锚点和主题换肤规则,不提供业务内容。指标卡、图表、表格、待办、筛选器、右侧栏、状态标签、快捷入口、时间线等常见内容组件只能判断模板是否可承载,不得作为风格模板的强匹配理由。
|
|
6
6
|
`style-designs/_design-md-template.md` 是最终结构模板,只约束章节结构、字段完整度和描述粒度;内置 style-design 模板只提供可复用视觉母体。真实项目的配色、业务内容、资源关系、页面结构和实现交接必须从当前 PRD、应用主题和用户要求生成。
|
|
7
7
|
|
|
8
8
|
## 何时使用
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
| --- | --- |
|
|
24
24
|
| 用户任务 | 判断状态、处理待办、追踪阶段、分析趋势、管理明细、展示成果、汇报经营 |
|
|
25
25
|
| 业务对象 | 订单、客户、库存、项目、任务、审批、线索、合同、员工、门店 |
|
|
26
|
-
|
|
|
26
|
+
| 内容兼容性 | 当前页面是否需要指标、图表、表格、待办、筛选、右侧栏、时间线、卡片目录、媒体卡片 |
|
|
27
|
+
| 布局兼容性 | 均衡工作台、重点舞台、右栏工作区、指挥台、趋势看板、进度叙事、目录网格 |
|
|
28
|
+
| 视觉策略 | 柔和办公、深色重点舞台、蓝色洞察、规整边框、清爽右栏、高能指挥、进度叙事、目录浏览 |
|
|
29
|
+
| 视觉强调 | 所有模块均衡、核心指标强强调、行动队列强强调、趋势图强强调、右侧洞察强强调、目录筛选强强调 |
|
|
27
30
|
| 交互重心 | 搜索筛选、待办处理、下钻详情、多入口跳转、趋势比较、异常处置 |
|
|
28
31
|
| 数据形态 | KPI、队列、趋势、排行、明细表、日程、快捷入口、预警、阶段节点 |
|
|
29
32
|
| 页面区块 | 顶部概览、搜索筛选、表格、图表、右侧详情、表单入口、空态 |
|
|
@@ -34,32 +37,48 @@
|
|
|
34
37
|
|
|
35
38
|
1. 读取 [style-designs/registry.md](style-designs/registry.md),了解可选模板和选择规则。
|
|
36
39
|
2. 读取 [style-designs/_design-md-template.md](style-designs/_design-md-template.md),用它作为最终 `design.md` 的结构基准。
|
|
37
|
-
3. 从业务上下文推演 `inferredUserTask`、`
|
|
38
|
-
4.
|
|
39
|
-
5.
|
|
40
|
-
6.
|
|
41
|
-
7.
|
|
42
|
-
8.
|
|
43
|
-
9.
|
|
44
|
-
10.
|
|
45
|
-
11.
|
|
46
|
-
12.
|
|
47
|
-
13.
|
|
48
|
-
14.
|
|
49
|
-
15. 写入 `
|
|
50
|
-
16.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
40
|
+
3. 从业务上下文推演 `inferredUserTask`、`contentCompatibility`、`layoutCompatibility`、`visualStyleIntent`、`visualEmphasis` 和 `interactionFocus`。用户通常不会主动描述视觉风格,agent 必须自行推演。
|
|
41
|
+
4. 先用内容组件做兼容性筛选:模板必须能承载当前页面已有内容,但不得因为“有指标卡 / 有图表 / 有表格 / 有右侧栏 / 有时间线”等公共组件直接胜出。
|
|
42
|
+
5. 再用视觉策略选择模板:判断页面需要柔和均衡、重点舞台、趋势洞察、行动指挥、常驻右栏、规整边框、进度叙事、目录浏览还是视觉陈列。
|
|
43
|
+
6. 对 registry 中的模板做硬过滤:纯表单、长文、品牌营销、移动端单任务等页面不选择明显不合适的分析工作台模板。不要因用户未明确说“深色”而过滤 `dark-stage-analytic-dashboard`;它是浅色画布上的局部深色重点舞台,不等于全页面深色沉浸。
|
|
44
|
+
7. 按 `视觉策略 45% + 视觉强调与密度 15% + 布局兼容性 15% + 内容兼容性 15% + 多样性或用户偏好 10%` 选择唯一模板。内容和布局合计不得超过 30%,避免常见工作台内容把结果塌缩到通用模板。
|
|
45
|
+
8. 做内部近邻比较:生成 `design.md` 前必须在工作记忆中比较最相近的 2-4 个模板;选择 `soft-analytic-workbench` 时必须确认其他更强视觉策略证据不足。近邻比较是选择校验,不默认写入最终 `design.md`。
|
|
46
|
+
9. 读取被选中的 `style-designs/*.md`,抽取 `visual_dna`、`theme_adaptation`、`layout_stability`、`quality_anchors`、`components` 和 `modules`。
|
|
47
|
+
10. 根据 Step 2 的主题色来源和主题色输入,按模板 `theme_adaptation` 执行换肤:替换 `replace_tokens`,派生 `derive_tokens`,保留 `preserve_tokens` 和 `visual_dna.invariant`。
|
|
48
|
+
11. 读取 [visual-scaffold-recipes.md](visual-scaffold-recipes.md),把当前页面组合映射到统一 `visualScaffold` 规则。
|
|
49
|
+
12. 读取 [page-quality-gates.md](page-quality-gates.md),把质量门禁补进 `acceptanceChecks`。
|
|
50
|
+
13. 需要判断详略时参考 `_design-md-template.md` 的字段粒度、registry 的输出记录和所选模板的质量锚点;只学习“写到多细”,不复制示例业务、色盘、字段、页面顺序或组件组合。
|
|
51
|
+
14. 根据行业、品牌、业务情绪、应用主题和用户偏好生成配色。不要固定使用蓝色、绿色、紫色或任何预置色,也不要复用历史样例色盘。
|
|
52
|
+
15. 写入 `densityRule`、`breathingRule`、`spacing` 和 `rounded` 的具体数值。默认业务工具页使用 high density + 圆润形状 + 有呼吸感的分组节奏:页面边距 20-28px,卡片与卡片 gap 12-18px 且必须小于 20px,卡片 padding 默认 22-28px 且必须大于 20px,卡片圆角范围 0-32px;只有品牌展示、官网或用户明确要求舒展时才降低密度。
|
|
53
|
+
16. 写入 `surfaceContrast`:页面背景与卡片背景必须形成明显层次对比,不可相近或相同;默认浅色背景保持清爽,但必须按“白色/浅色背景 + 有边框卡片、浅灰背景(如 `#F3F4F6`)+ 白色无边框卡片、浅彩色背景 + 白色无边框卡片、渐变背景 + 玻璃感卡片”四类方案选择。
|
|
54
|
+
17. 写入 `emptyStateRecipe` 和 `acceptanceChecks`:空态必须是薄行、面板内提示或右侧上下文,不使用 160px 以上大白卡;状态摘要不能是横跨整页且内容稀疏的空矩形。
|
|
55
|
+
18. 如果平台导航可见,页面主按钮、链接、选中态、重点标签和图表主序列默认跟随应用主题;自定义色盘只能作为辅助色、浅背景、图表第二序列或页面级独立主题。
|
|
56
|
+
|
|
57
|
+
## 内容兼容与视觉策略
|
|
58
|
+
|
|
59
|
+
公共内容组件只判断模板是否可承载,不决定最终风格。最终模板必须由视觉策略、视觉强调和近邻比较决定。
|
|
60
|
+
|
|
61
|
+
| 常见内容信号 | 只能用于判断 | 不得直接推出 |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| 指标卡 / KPI | 是否需要状态摘要、核心舞台、趋势入口、行动队列入口 | `soft-analytic-workbench` |
|
|
64
|
+
| 图表 | 是否需要轻量分布、大趋势图、进度图、纹理化洞察 | dashboard 模板 |
|
|
65
|
+
| 表格 / 明细 | 是否需要主工作区、详情沉淀、搜索结果、记录日志 | analytic 模板 |
|
|
66
|
+
| 右侧栏 | 是辅助上下文、常驻洞察栏还是行动队列 | rail 模板 |
|
|
67
|
+
| 时间线 / 阶段 | 是核心叙事骨架还是普通进度提示 | timeline 模板 |
|
|
68
|
+
| 筛选器 / 标签 | 是主导航还是表格辅助条件 | catalog 模板 |
|
|
69
|
+
|
|
70
|
+
| 视觉策略 | 适用判断 |
|
|
55
71
|
| --- | --- |
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
72
|
+
| `soft_neutral` | 低噪声、均衡、朴素办公感;没有强主舞台、强趋势、强指挥或强目录诉求 |
|
|
73
|
+
| `dark_accent_stage` | 浅色页面中需要一个局部深色重点舞台,突出核心判断、风险、目标或经营结果 |
|
|
74
|
+
| `blue_insight` | 需要更强分析感、趋势感、数据洞察感,主图表或趋势面板应成为记忆点 |
|
|
75
|
+
| `bordered_enterprise` | 需要规整、边界清晰、系统化的管理后台气质 |
|
|
76
|
+
| `teal_fresh_rail` | 需要清爽、服务感或常驻右侧洞察栏,右栏是页面稳定结构而非临时补充 |
|
|
77
|
+
| `action_command` | 需要今日行动、命令入口、推荐处理、任务队列或高能量指挥感 |
|
|
78
|
+
| `progress_narrative` | 需要阶段推进、周期节奏、服务进度或里程碑叙事 |
|
|
79
|
+
| `catalog_browse` | 需要以筛选、比较、挑选、卡片目录或视觉浏览作为主体验 |
|
|
80
|
+
|
|
81
|
+
选择 `soft_neutral` / `soft-analytic-workbench` 时必须满足:其他视觉策略都没有更强证据。它是均衡办公风格,不是所有工作台的默认答案。
|
|
63
82
|
|
|
64
83
|
## 主题色应用规则
|
|
65
84
|
|
|
@@ -89,7 +108,7 @@ Step 5 生成 `design.md`,并让 PRD 的每个自定义展示页只引用它
|
|
|
89
108
|
| 字段 | 写入位置 | 写法 |
|
|
90
109
|
| --- | --- | --- |
|
|
91
110
|
| baseDesignSource | design.md | `references/style-designs/<selected-template>.md`;所有模板不适用时才写 `generated-from-business-context` |
|
|
92
|
-
| styleDesignSelection | design.md |
|
|
111
|
+
| styleDesignSelection | design.md | 只记录模板来源、视觉策略、视觉强调、选中模板、实现约束和置信度;候选比较和拒绝理由默认不写入 |
|
|
93
112
|
| themeAdaptationResult | design.md | 记录输入主题色、换肤策略、替换 token、保留 DNA 和保留机制 |
|
|
94
113
|
| designFile | PRD pageSpecHandoff | `prd/<项目名>/design.md` |
|
|
95
114
|
| designRefs | PRD pageSpecHandoff | 当前页面引用 design.md 的章节 ID |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# style-design 内置模板注册表
|
|
2
2
|
|
|
3
|
-
本目录提供 `yida-design` Step 5 生成 `prd/<项目名>/design.md` 时可选择的内置视觉 DNA 模板。生成 `design.md`
|
|
3
|
+
本目录提供 `yida-design` Step 5 生成 `prd/<项目名>/design.md` 时可选择的内置视觉 DNA 模板。生成 `design.md` 时必须先判断内容兼容性,再根据视觉策略选择唯一一个 `style-designs/*.md` 作为基础视觉母体,最后结合主题色和当前 PRD 生成最终自包含的 `design.md`。
|
|
4
4
|
|
|
5
5
|
`_design-md-template.md` 仍是结构模板;它不参与视觉风格选择。实现阶段只读取当前项目的 `prd.md` 和 `design.md`,不回读本目录。
|
|
6
6
|
|
|
@@ -14,23 +14,23 @@
|
|
|
14
14
|
|
|
15
15
|
## 可选 style-design 模板
|
|
16
16
|
|
|
17
|
-
| 模板 |
|
|
17
|
+
| 模板 | 视觉策略 | 可承载内容 | 强选择触发 | 近邻边界 |
|
|
18
18
|
| --- | --- | --- | --- | --- |
|
|
19
|
-
| `soft-analytic-workbench.md` |
|
|
20
|
-
| `soft-bordered-analytic-workbench.md` |
|
|
21
|
-
| `soft-modular-analytic-workbench.md` |
|
|
22
|
-
| `soft-progress-analytics-workbench.md` |
|
|
23
|
-
| `soft-timeline-analytics-workbench.md` |
|
|
24
|
-
| `teal-rail-analytics-workbench.md` |
|
|
25
|
-
| `dark-stage-analytic-dashboard.md` |
|
|
26
|
-
| `contrast-command-analytics-workbench.md` |
|
|
27
|
-
| `blue-productivity-insight-workbench.md` |
|
|
28
|
-
| `aqua-service-progress-dashboard.md` |
|
|
29
|
-
| `blue-insight-operations-dashboard.md` |
|
|
30
|
-
| `green-timeline-progress-workbench.md` |
|
|
31
|
-
| `filterable-card-catalog.md` |
|
|
32
|
-
| `soft-curated-filter-gallery.md` |
|
|
33
|
-
| `command-filter-card-console.md` |
|
|
19
|
+
| `soft-analytic-workbench.md` | `soft_neutral` 均衡办公 | 指标、轻图表、右侧辅助列表、明细表、普通入口 | 用户明确需要低噪声、均衡、朴素办公感;所有模块视觉优先级接近 | 通用兜底,有泛化惩罚;若需要重点舞台、趋势洞察、行动队列、常驻右栏或规整边框,应输给对应模板 |
|
|
20
|
+
| `soft-bordered-analytic-workbench.md` | `bordered_enterprise` 规整控制台 | 命令栏、深色摘要区、图表洞察、分区明细 | 页面需要边界清晰、系统化、控制台感,搜索筛选和全局命令是稳定入口 | 若只是均衡办公输给 `soft-analytic`;若深色舞台是主记忆点输给 `dark-stage` |
|
|
21
|
+
| `soft-modular-analytic-workbench.md` | `bordered_enterprise` 模块化复杂工作台 | 多模块、多指标、趋势、洞察卡、明细表 | 页面模块很多,需要规整网格和混合尺度承载,不希望单一大舞台主导 | 若模块少且均衡输给 `soft-analytic`;若趋势图是主视觉输给 `blue-insight` |
|
|
22
|
+
| `soft-progress-analytics-workbench.md` | `progress_narrative` 进度分析 | 优先级指标、周期节点、趋势、明细表 | 阶段、周期、进度是核心体验,但整体仍偏分析工作台 | 若没有阶段推进语义输给非进度模板;若服务资源和媒体上下文更强输给 `aqua-service` |
|
|
23
|
+
| `soft-timeline-analytics-workbench.md` | `progress_narrative` 时间轴工作台 | 指标栈、时间轴、趋势、明细表 | 时间轴本身是页面骨架,用户需要按阶段/里程碑阅读 | 若时间轴只是辅助提示输给 `soft-progress` 或非进度模板 |
|
|
24
|
+
| `teal-rail-analytics-workbench.md` | `teal_fresh_rail` 常驻洞察右栏 | 左侧主工作区、右侧洞察栏、标签筛选、明细表 | 右侧洞察栏是持续结构,用于提醒、排名、状态、上下文,而非普通补充列表 | 若右栏只是辅助列表输给 `soft-analytic`;若行动队列更强输给 `blue-productivity` |
|
|
25
|
+
| `dark-stage-analytic-dashboard.md` | `dark_accent_stage` 局部深色重点舞台 | 指标、图表、表格、待办、右侧上下文 | 浅色页面中需要一个强记忆点,突出核心判断、风险、目标完成度或经营结果 | 不要求用户明确说深色;若只是全模块均衡扫描输给 `soft-analytic`,若命令处理更强输给 `contrast-command` |
|
|
26
|
+
| `contrast-command-analytics-workbench.md` | `action_command` 高对比指挥 | 大标题、表现图、事件流、深色命令面板、媒体化明细 | 页面需要指挥感、推荐处理、助手面板、日程协同或高能量主操作 | 若只是待办列表输给 `blue-productivity`;若只是核心指标舞台输给 `dark-stage` |
|
|
27
|
+
| `blue-productivity-insight-workbench.md` | `action_command` 生产力行动队列 | 指标、柱状图、右侧行动栏、记录表 | 指标之后立刻驱动今日处理、待办、跟进、确认、分派等动作 | 若主图表洞察更强输给 `blue-insight`;若右栏是洞察而非行动输给 `teal-rail` |
|
|
28
|
+
| `aqua-service-progress-dashboard.md` | `progress_narrative` 服务进度 | 状态头、时间轴、进度评分、渐变状态卡、媒体/上下文卡 | 服务、资源、场地、设备、交付进度或上下文媒体共同构成体验 | 若是密集后台或纯表格处理输给工作台模板;若只是阶段管理输给 timeline/progress 模板 |
|
|
29
|
+
| `blue-insight-operations-dashboard.md` | `blue_insight` 趋势洞察 | 火花线指标、主趋势图、洞察卡、活动表、进度列表 | 主要记忆点是趋势、分析、经营洞察,图表不只是轻量状态分布 | 若数据不足以支撑趋势图输给 `soft-analytic`;若行动队列更强输给 `blue-productivity` |
|
|
30
|
+
| `green-timeline-progress-workbench.md` | `progress_narrative` 清爽阶段推进 | 主摘要指标栈、浮动日期时间轴、趋势图、全宽表格 | 阶段推进明确,同时希望气质更清爽、轻运营、低压 | 若没有时间/阶段语义输给非进度模板;若需要更中性时间轴输给 `soft-timeline` |
|
|
31
|
+
| `filterable-card-catalog.md` | `catalog_browse` 高密筛选目录 | 左筛选栏、结果工具条、条件胶囊、等高卡片矩阵 | 主体验是搜索、筛选、比较、选择对象;卡片比表格更适合承载结果 | 若只是工作台里的辅助筛选输给 analytic 模板;若需要大图陈列输给 `soft-curated-filter-gallery` |
|
|
32
|
+
| `soft-curated-filter-gallery.md` | `catalog_browse` 视觉精选画廊 | 大标题、分类切换、柔和筛选、大图卡片、收藏/徽标 | 主体验是视觉浏览、候选挑选、精选展示,图片或视觉对象重要 | 若需要高密管理和批量操作输给 `command-filter-card-console` 或 `filterable-card-catalog` |
|
|
33
|
+
| `command-filter-card-console.md` | `catalog_browse` 管理型卡片控制台 | 边框筛选、状态标签、紧凑管理卡片、分页 | 主体验是对象管理、状态筛选、批量查看,卡片是管理单元而非展示物 | 若偏视觉陈列输给 `soft-curated-filter-gallery`;若偏普通结果浏览输给 `filterable-card-catalog` |
|
|
34
34
|
|
|
35
35
|
## 消费硬规则
|
|
36
36
|
|
|
@@ -43,40 +43,65 @@
|
|
|
43
43
|
|
|
44
44
|
## 选择原则
|
|
45
45
|
|
|
46
|
-
1.
|
|
46
|
+
1. 先从业务需求判断内容兼容性,再推演视觉策略、视觉强调、密度气质和交互重心;不要按行业、主题色或公共内容组件直接选模板。
|
|
47
47
|
2. 主题色只作为所选模板的 `theme_adaptation` 输入,用于替换强调色 token;主题色不是选择模板的主要依据。
|
|
48
|
-
3.
|
|
48
|
+
3. 指标卡、图表、表格、待办、筛选器、右侧栏、状态标签、快捷入口、时间线等公共组件只用于判断 `contentCompatibility`,不得作为模板强匹配理由。
|
|
49
49
|
4. 每次必须选择唯一一个 `style-designs/*.md` 作为 `baseDesignSource`。若所有模板都不适合,仍读取 `_design-md-template.md` 输出 `baseDesignSource=generated-from-business-context`,并在 `styleDesignSelection.rejectedStyleDesigns` 说明原因。
|
|
50
50
|
5. 不得为了套模板凭空创造 PRD 未要求的图表、右侧栏、时间轴、深色舞台或快捷入口;模板只能决定已有业务内容的视觉承载方式。
|
|
51
|
-
6.
|
|
51
|
+
6. `dark-stage-analytic-dashboard` 是局部深色重点舞台,不是全页面深色沉浸。不得仅以“用户未要求深色”为理由拒绝它;只能在页面不需要强视觉焦点时拒绝。
|
|
52
|
+
7. `soft-analytic-workbench` 是 `soft_neutral` 均衡办公风格,不是所有工作台的默认答案。选择它时必须在内部选择草稿中确认其他更强视觉策略证据不足。
|
|
53
|
+
8. 最终 `design.md` 必须自包含:包含模板来源、选择依据、主题换肤结果、视觉 DNA、token、组件、状态、响应式、可访问性和实现契约。
|
|
52
54
|
|
|
53
55
|
## 选择评分建议
|
|
54
56
|
|
|
55
57
|
| 维度 | 权重 | 判断方法 |
|
|
56
58
|
| --- | --- | --- |
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
59
|
+
| 视觉策略匹配 | 45% | 页面需要 `soft_neutral`、`dark_accent_stage`、`blue_insight`、`bordered_enterprise`、`teal_fresh_rail`、`action_command`、`progress_narrative` 还是 `catalog_browse` |
|
|
60
|
+
| 视觉强调与密度 | 15% | 首屏是均衡扫描、核心舞台、趋势洞察、行动队列、常驻右栏、阶段推进还是目录筛选;密度是高密、规整、舒展还是展示型 |
|
|
61
|
+
| 布局兼容性 | 15% | 当前页面是否能稳定承载该模板的舞台、右栏、命令栏、进度骨架、目录网格或趋势面板 |
|
|
62
|
+
| 内容兼容性 | 15% | 模板是否支持当前已有指标、图表、表格、待办、筛选、右栏、时间线、卡片和媒体内容 |
|
|
63
|
+
| 多样性或用户偏好 | 10% | 用户语气、品牌气质、应用主题和候选分差接近时,避免所有工作台都落到 `soft-analytic-workbench` |
|
|
64
|
+
| 风险扣分 | -5% | 是否会强行制造不存在的模块、过度依赖图表、右侧栏、时间轴、深色舞台或图片素材 |
|
|
65
|
+
|
|
66
|
+
内容兼容性和布局兼容性合计不得超过 30%。如果多个模板都能承载相同内容,必须让视觉策略、视觉强调和近邻边界决定最终选择。
|
|
62
67
|
|
|
63
68
|
## 输出记录
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
生成 `design.md` 前必须先形成内部选择草稿,用来防止公共组件误导模板选择。内部选择草稿不写入最终 `design.md`,除非用户要求调试或评估选择过程。
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
selectionScratchpad:
|
|
74
|
+
topCandidates:
|
|
75
|
+
- name: <template-name>
|
|
76
|
+
evidence: <短句或枚举,不写长解释>
|
|
77
|
+
rejectedCloseNeighbors:
|
|
78
|
+
- name: <template-name>
|
|
79
|
+
evidence: <短句或枚举>
|
|
80
|
+
softAnalyticCheck:
|
|
81
|
+
strongerVisualStrategyExists: <true / false>
|
|
82
|
+
result: <select_soft_analytic / choose_stronger_strategy>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
最终 `design.md` 只记录可交接给实现阶段的精简选择摘要:
|
|
66
86
|
|
|
67
87
|
```yaml
|
|
68
88
|
baseDesignSource: references/style-designs/<selected-template>.md
|
|
69
89
|
styleDesignSelection:
|
|
70
90
|
inferredUserTask: <判断 / 处理 / 追踪 / 分析 / 展示 / 汇报>
|
|
71
|
-
|
|
91
|
+
contentCompatibility:
|
|
92
|
+
supports: [<metrics / charts / tables / todos / filters / side_panel / timeline / catalog_cards / media_cards>]
|
|
93
|
+
commonComponentsAreWeakSignals: true
|
|
94
|
+
layoutCompatibility: <balanced_workbench / stage_workbench / rail_workspace / command_console / insight_dashboard / progress_narrative / catalog_grid>
|
|
95
|
+
visualStyleIntent: <soft_neutral / dark_accent_stage / blue_insight / bordered_enterprise / teal_fresh_rail / action_command / progress_narrative / catalog_browse>
|
|
96
|
+
visualEmphasis: <均衡扫描 / 核心舞台 / 趋势洞察 / 行动队列 / 常驻右栏 / 阶段推进 / 目录筛选>
|
|
72
97
|
requiredVisualDNA:
|
|
73
98
|
- <dna-id>
|
|
74
99
|
selectedStyleDesign:
|
|
75
100
|
name: <template-name>
|
|
76
101
|
source: references/style-designs/<template>.md
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
102
|
+
implementationConstraints:
|
|
103
|
+
- <必须保留的视觉约束,例如局部深色舞台 / 常驻右栏 / 行动队列 / 大趋势面板>
|
|
104
|
+
selectionNotes: <可选,一句话以内;默认省略>
|
|
80
105
|
selectionConfidence: <high / medium / low>
|
|
81
106
|
```
|
|
82
107
|
|
|
@@ -86,6 +111,7 @@ styleDesignSelection:
|
|
|
86
111
|
|
|
87
112
|
- front matter 中的 `template_type: visual_dna_preset`。
|
|
88
113
|
- `selection.best_for`、`selection.user_intent`、`selection.visual_tone`、`selection.avoid_for`。
|
|
114
|
+
- registry 中必须为新模板补充 `视觉策略`、`可承载内容`、`强选择触发` 和 `近邻边界`,避免只写宽泛适用场景。
|
|
89
115
|
- 2-5 个可稳定复用的 `visual_dna`,每个 DNA 要有 `id`、`hooks`、`invariant`、`variable`。
|
|
90
116
|
- `theme_adaptation`,明确 `replace_tokens`、`derive_tokens`、`preserve_tokens` 和换肤规则。
|
|
91
117
|
- `quality_anchors`、`layout_stability`、`components` 和 `modules`,让最终 `design.md` 能抽取为可实现规则。
|
|
@@ -102,6 +102,40 @@
|
|
|
102
102
|
"应用权限"
|
|
103
103
|
]
|
|
104
104
|
},
|
|
105
|
+
{
|
|
106
|
+
"name": "yida-app-lifecycle",
|
|
107
|
+
"path": "skills/yida-app-lifecycle/SKILL.md",
|
|
108
|
+
"display_name": "应用启用与停用",
|
|
109
|
+
"description": "宜搭应用启用与停用。仅当用户明确要求启用、停用、上线或下线某个已有应用时使用;不用于创建应用、发布页面或发布到钉钉应用中心。",
|
|
110
|
+
"category": "yida-skills/app",
|
|
111
|
+
"tags": [
|
|
112
|
+
"启用应用",
|
|
113
|
+
"停用应用",
|
|
114
|
+
"上线应用",
|
|
115
|
+
"下线应用"
|
|
116
|
+
],
|
|
117
|
+
"aliases": [
|
|
118
|
+
"应用生命周期",
|
|
119
|
+
"应用上下线"
|
|
120
|
+
],
|
|
121
|
+
"positive_signals": [
|
|
122
|
+
"启用应用",
|
|
123
|
+
"停用应用",
|
|
124
|
+
"上线应用",
|
|
125
|
+
"下线应用"
|
|
126
|
+
],
|
|
127
|
+
"negative_signals": [
|
|
128
|
+
"发布页面",
|
|
129
|
+
"更新应用信息",
|
|
130
|
+
"禁用集成自动化",
|
|
131
|
+
"关闭公开访问"
|
|
132
|
+
],
|
|
133
|
+
"command_ids": [
|
|
134
|
+
"app-online",
|
|
135
|
+
"app-offline"
|
|
136
|
+
],
|
|
137
|
+
"done_when": "CLI 返回 success:true 且 action 与用户明确意图一致;app-offline 执行前已确认目标 appType,失败时不得宣称状态改变。"
|
|
138
|
+
},
|
|
105
139
|
{
|
|
106
140
|
"name": "yida-basic-info",
|
|
107
141
|
"path": "skills/yida-basic-info/SKILL.md",
|
|
@@ -1160,6 +1194,10 @@
|
|
|
1160
1194
|
"创建应用",
|
|
1161
1195
|
"完整应用",
|
|
1162
1196
|
"管理系统",
|
|
1197
|
+
"启用应用",
|
|
1198
|
+
"停用应用",
|
|
1199
|
+
"上线应用",
|
|
1200
|
+
"下线应用",
|
|
1163
1201
|
"导航分组",
|
|
1164
1202
|
"多语言"
|
|
1165
1203
|
]
|